ring: prepare ring to allow new sync schemes
[dpdk.git] / lib / librte_pdump / rte_pdump.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016-2018 Intel Corporation
3  */
4
5 #include <rte_memcpy.h>
6 #include <rte_mbuf.h>
7 #include <rte_ethdev.h>
8 #include <rte_lcore.h>
9 #include <rte_log.h>
10 #include <rte_errno.h>
11 #include <rte_string_fns.h>
12
13 #include "rte_pdump.h"
14
15 #define DEVICE_ID_SIZE 64
16
17 /* Macro for printing using RTE_LOG */
18 static int pdump_logtype;
19 #define PDUMP_LOG(level, fmt, args...)                          \
20         rte_log(RTE_LOG_ ## level, pdump_logtype, "%s(): " fmt, \
21                 __func__, ## args)
22
23 /* Used for the multi-process communication */
24 #define PDUMP_MP        "mp_pdump"
25
26 enum pdump_operation {
27         DISABLE = 1,
28         ENABLE = 2
29 };
30
31 enum pdump_version {
32         V1 = 1
33 };
34
35 struct pdump_request {
36         uint16_t ver;
37         uint16_t op;
38         uint32_t flags;
39         union pdump_data {
40                 struct enable_v1 {
41                         char device[DEVICE_ID_SIZE];
42                         uint16_t queue;
43                         struct rte_ring *ring;
44                         struct rte_mempool *mp;
45                         void *filter;
46                 } en_v1;
47                 struct disable_v1 {
48                         char device[DEVICE_ID_SIZE];
49                         uint16_t queue;
50                         struct rte_ring *ring;
51                         struct rte_mempool *mp;
52                         void *filter;
53                 } dis_v1;
54         } data;
55 };
56
57 struct pdump_response {
58         uint16_t ver;
59         uint16_t res_op;
60         int32_t err_value;
61 };
62
63 static struct pdump_rxtx_cbs {
64         struct rte_ring *ring;
65         struct rte_mempool *mp;
66         const struct rte_eth_rxtx_callback *cb;
67         void *filter;
68 } rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
69 tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
70
71
72 static inline void
73 pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
74 {
75         unsigned i;
76         int ring_enq;
77         uint16_t d_pkts = 0;
78         struct rte_mbuf *dup_bufs[nb_pkts];
79         struct pdump_rxtx_cbs *cbs;
80         struct rte_ring *ring;
81         struct rte_mempool *mp;
82         struct rte_mbuf *p;
83
84         cbs  = user_params;
85         ring = cbs->ring;
86         mp = cbs->mp;
87         for (i = 0; i < nb_pkts; i++) {
88                 p = rte_pktmbuf_copy(pkts[i], mp, 0, UINT32_MAX);
89                 if (p)
90                         dup_bufs[d_pkts++] = p;
91         }
92
93         ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts, NULL);
94         if (unlikely(ring_enq < d_pkts)) {
95                 PDUMP_LOG(DEBUG,
96                         "only %d of packets enqueued to ring\n", ring_enq);
97                 do {
98                         rte_pktmbuf_free(dup_bufs[ring_enq]);
99                 } while (++ring_enq < d_pkts);
100         }
101 }
102
103 static uint16_t
104 pdump_rx(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
105         struct rte_mbuf **pkts, uint16_t nb_pkts,
106         uint16_t max_pkts __rte_unused,
107         void *user_params)
108 {
109         pdump_copy(pkts, nb_pkts, user_params);
110         return nb_pkts;
111 }
112
113 static uint16_t
114 pdump_tx(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
115                 struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
116 {
117         pdump_copy(pkts, nb_pkts, user_params);
118         return nb_pkts;
119 }
120
121 static int
122 pdump_register_rx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue,
123                                 struct rte_ring *ring, struct rte_mempool *mp,
124                                 uint16_t operation)
125 {
126         uint16_t qid;
127         struct pdump_rxtx_cbs *cbs = NULL;
128
129         qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
130         for (; qid < end_q; qid++) {
131                 cbs = &rx_cbs[port][qid];
132                 if (cbs && operation == ENABLE) {
133                         if (cbs->cb) {
134                                 PDUMP_LOG(ERR,
135                                         "failed to add rx callback for port=%d "
136                                         "and queue=%d, callback already exists\n",
137                                         port, qid);
138                                 return -EEXIST;
139                         }
140                         cbs->ring = ring;
141                         cbs->mp = mp;
142                         cbs->cb = rte_eth_add_first_rx_callback(port, qid,
143                                                                 pdump_rx, cbs);
144                         if (cbs->cb == NULL) {
145                                 PDUMP_LOG(ERR,
146                                         "failed to add rx callback, errno=%d\n",
147                                         rte_errno);
148                                 return rte_errno;
149                         }
150                 }
151                 if (cbs && operation == DISABLE) {
152                         int ret;
153
154                         if (cbs->cb == NULL) {
155                                 PDUMP_LOG(ERR,
156                                         "failed to delete non existing rx "
157                                         "callback for port=%d and queue=%d\n",
158                                         port, qid);
159                                 return -EINVAL;
160                         }
161                         ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
162                         if (ret < 0) {
163                                 PDUMP_LOG(ERR,
164                                         "failed to remove rx callback, errno=%d\n",
165                                         -ret);
166                                 return ret;
167                         }
168                         cbs->cb = NULL;
169                 }
170         }
171
172         return 0;
173 }
174
175 static int
176 pdump_register_tx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue,
177                                 struct rte_ring *ring, struct rte_mempool *mp,
178                                 uint16_t operation)
179 {
180
181         uint16_t qid;
182         struct pdump_rxtx_cbs *cbs = NULL;
183
184         qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
185         for (; qid < end_q; qid++) {
186                 cbs = &tx_cbs[port][qid];
187                 if (cbs && operation == ENABLE) {
188                         if (cbs->cb) {
189                                 PDUMP_LOG(ERR,
190                                         "failed to add tx callback for port=%d "
191                                         "and queue=%d, callback already exists\n",
192                                         port, qid);
193                                 return -EEXIST;
194                         }
195                         cbs->ring = ring;
196                         cbs->mp = mp;
197                         cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
198                                                                 cbs);
199                         if (cbs->cb == NULL) {
200                                 PDUMP_LOG(ERR,
201                                         "failed to add tx callback, errno=%d\n",
202                                         rte_errno);
203                                 return rte_errno;
204                         }
205                 }
206                 if (cbs && operation == DISABLE) {
207                         int ret;
208
209                         if (cbs->cb == NULL) {
210                                 PDUMP_LOG(ERR,
211                                         "failed to delete non existing tx "
212                                         "callback for port=%d and queue=%d\n",
213                                         port, qid);
214                                 return -EINVAL;
215                         }
216                         ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
217                         if (ret < 0) {
218                                 PDUMP_LOG(ERR,
219                                         "failed to remove tx callback, errno=%d\n",
220                                         -ret);
221                                 return ret;
222                         }
223                         cbs->cb = NULL;
224                 }
225         }
226
227         return 0;
228 }
229
230 static int
231 set_pdump_rxtx_cbs(const struct pdump_request *p)
232 {
233         uint16_t nb_rx_q = 0, nb_tx_q = 0, end_q, queue;
234         uint16_t port;
235         int ret = 0;
236         uint32_t flags;
237         uint16_t operation;
238         struct rte_ring *ring;
239         struct rte_mempool *mp;
240
241         flags = p->flags;
242         operation = p->op;
243         if (operation == ENABLE) {
244                 ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device,
245                                 &port);
246                 if (ret < 0) {
247                         PDUMP_LOG(ERR,
248                                 "failed to get port id for device id=%s\n",
249                                 p->data.en_v1.device);
250                         return -EINVAL;
251                 }
252                 queue = p->data.en_v1.queue;
253                 ring = p->data.en_v1.ring;
254                 mp = p->data.en_v1.mp;
255         } else {
256                 ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device,
257                                 &port);
258                 if (ret < 0) {
259                         PDUMP_LOG(ERR,
260                                 "failed to get port id for device id=%s\n",
261                                 p->data.dis_v1.device);
262                         return -EINVAL;
263                 }
264                 queue = p->data.dis_v1.queue;
265                 ring = p->data.dis_v1.ring;
266                 mp = p->data.dis_v1.mp;
267         }
268
269         /* validation if packet capture is for all queues */
270         if (queue == RTE_PDUMP_ALL_QUEUES) {
271                 struct rte_eth_dev_info dev_info;
272
273                 ret = rte_eth_dev_info_get(port, &dev_info);
274                 if (ret != 0) {
275                         PDUMP_LOG(ERR,
276                                 "Error during getting device (port %u) info: %s\n",
277                                 port, strerror(-ret));
278                         return ret;
279                 }
280
281                 nb_rx_q = dev_info.nb_rx_queues;
282                 nb_tx_q = dev_info.nb_tx_queues;
283                 if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
284                         PDUMP_LOG(ERR,
285                                 "number of rx queues cannot be 0\n");
286                         return -EINVAL;
287                 }
288                 if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
289                         PDUMP_LOG(ERR,
290                                 "number of tx queues cannot be 0\n");
291                         return -EINVAL;
292                 }
293                 if ((nb_tx_q == 0 || nb_rx_q == 0) &&
294                         flags == RTE_PDUMP_FLAG_RXTX) {
295                         PDUMP_LOG(ERR,
296                                 "both tx&rx queues must be non zero\n");
297                         return -EINVAL;
298                 }
299         }
300
301         /* register RX callback */
302         if (flags & RTE_PDUMP_FLAG_RX) {
303                 end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
304                 ret = pdump_register_rx_callbacks(end_q, port, queue, ring, mp,
305                                                         operation);
306                 if (ret < 0)
307                         return ret;
308         }
309
310         /* register TX callback */
311         if (flags & RTE_PDUMP_FLAG_TX) {
312                 end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
313                 ret = pdump_register_tx_callbacks(end_q, port, queue, ring, mp,
314                                                         operation);
315                 if (ret < 0)
316                         return ret;
317         }
318
319         return ret;
320 }
321
322 static int
323 pdump_server(const struct rte_mp_msg *mp_msg, const void *peer)
324 {
325         struct rte_mp_msg mp_resp;
326         const struct pdump_request *cli_req;
327         struct pdump_response *resp = (struct pdump_response *)&mp_resp.param;
328
329         /* recv client requests */
330         if (mp_msg->len_param != sizeof(*cli_req)) {
331                 PDUMP_LOG(ERR, "failed to recv from client\n");
332                 resp->err_value = -EINVAL;
333         } else {
334                 cli_req = (const struct pdump_request *)mp_msg->param;
335                 resp->ver = cli_req->ver;
336                 resp->res_op = cli_req->op;
337                 resp->err_value = set_pdump_rxtx_cbs(cli_req);
338         }
339
340         strlcpy(mp_resp.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
341         mp_resp.len_param = sizeof(*resp);
342         mp_resp.num_fds = 0;
343         if (rte_mp_reply(&mp_resp, peer) < 0) {
344                 PDUMP_LOG(ERR, "failed to send to client:%s\n",
345                           strerror(rte_errno));
346                 return -1;
347         }
348
349         return 0;
350 }
351
352 int
353 rte_pdump_init(void)
354 {
355         int ret = rte_mp_action_register(PDUMP_MP, pdump_server);
356         if (ret && rte_errno != ENOTSUP)
357                 return -1;
358         return 0;
359 }
360
361 int
362 rte_pdump_uninit(void)
363 {
364         rte_mp_action_unregister(PDUMP_MP);
365
366         return 0;
367 }
368
369 static int
370 pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
371 {
372         if (ring == NULL || mp == NULL) {
373                 PDUMP_LOG(ERR, "NULL ring or mempool\n");
374                 rte_errno = EINVAL;
375                 return -1;
376         }
377         if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
378                 PDUMP_LOG(ERR, "mempool with either SP or SC settings"
379                 " is not valid for pdump, should have MP and MC settings\n");
380                 rte_errno = EINVAL;
381                 return -1;
382         }
383         if (rte_ring_is_prod_single(ring) || rte_ring_is_cons_single(ring)) {
384                 PDUMP_LOG(ERR, "ring with either SP or SC settings"
385                 " is not valid for pdump, should have MP and MC settings\n");
386                 rte_errno = EINVAL;
387                 return -1;
388         }
389
390         return 0;
391 }
392
393 static int
394 pdump_validate_flags(uint32_t flags)
395 {
396         if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX &&
397                 flags != RTE_PDUMP_FLAG_RXTX) {
398                 PDUMP_LOG(ERR,
399                         "invalid flags, should be either rx/tx/rxtx\n");
400                 rte_errno = EINVAL;
401                 return -1;
402         }
403
404         return 0;
405 }
406
407 static int
408 pdump_validate_port(uint16_t port, char *name)
409 {
410         int ret = 0;
411
412         if (port >= RTE_MAX_ETHPORTS) {
413                 PDUMP_LOG(ERR, "Invalid port id %u\n", port);
414                 rte_errno = EINVAL;
415                 return -1;
416         }
417
418         ret = rte_eth_dev_get_name_by_port(port, name);
419         if (ret < 0) {
420                 PDUMP_LOG(ERR, "port %u to name mapping failed\n",
421                           port);
422                 rte_errno = EINVAL;
423                 return -1;
424         }
425
426         return 0;
427 }
428
429 static int
430 pdump_prepare_client_request(char *device, uint16_t queue,
431                                 uint32_t flags,
432                                 uint16_t operation,
433                                 struct rte_ring *ring,
434                                 struct rte_mempool *mp,
435                                 void *filter)
436 {
437         int ret = -1;
438         struct rte_mp_msg mp_req, *mp_rep;
439         struct rte_mp_reply mp_reply;
440         struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
441         struct pdump_request *req = (struct pdump_request *)mp_req.param;
442         struct pdump_response *resp;
443
444         req->ver = 1;
445         req->flags = flags;
446         req->op = operation;
447         if ((operation & ENABLE) != 0) {
448                 strlcpy(req->data.en_v1.device, device,
449                         sizeof(req->data.en_v1.device));
450                 req->data.en_v1.queue = queue;
451                 req->data.en_v1.ring = ring;
452                 req->data.en_v1.mp = mp;
453                 req->data.en_v1.filter = filter;
454         } else {
455                 strlcpy(req->data.dis_v1.device, device,
456                         sizeof(req->data.dis_v1.device));
457                 req->data.dis_v1.queue = queue;
458                 req->data.dis_v1.ring = NULL;
459                 req->data.dis_v1.mp = NULL;
460                 req->data.dis_v1.filter = NULL;
461         }
462
463         strlcpy(mp_req.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
464         mp_req.len_param = sizeof(*req);
465         mp_req.num_fds = 0;
466         if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0) {
467                 mp_rep = &mp_reply.msgs[0];
468                 resp = (struct pdump_response *)mp_rep->param;
469                 rte_errno = resp->err_value;
470                 if (!resp->err_value)
471                         ret = 0;
472                 free(mp_reply.msgs);
473         }
474
475         if (ret < 0)
476                 PDUMP_LOG(ERR,
477                         "client request for pdump enable/disable failed\n");
478         return ret;
479 }
480
481 int
482 rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags,
483                         struct rte_ring *ring,
484                         struct rte_mempool *mp,
485                         void *filter)
486 {
487
488         int ret = 0;
489         char name[DEVICE_ID_SIZE];
490
491         ret = pdump_validate_port(port, name);
492         if (ret < 0)
493                 return ret;
494         ret = pdump_validate_ring_mp(ring, mp);
495         if (ret < 0)
496                 return ret;
497         ret = pdump_validate_flags(flags);
498         if (ret < 0)
499                 return ret;
500
501         ret = pdump_prepare_client_request(name, queue, flags,
502                                                 ENABLE, ring, mp, filter);
503
504         return ret;
505 }
506
507 int
508 rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
509                                 uint32_t flags,
510                                 struct rte_ring *ring,
511                                 struct rte_mempool *mp,
512                                 void *filter)
513 {
514         int ret = 0;
515
516         ret = pdump_validate_ring_mp(ring, mp);
517         if (ret < 0)
518                 return ret;
519         ret = pdump_validate_flags(flags);
520         if (ret < 0)
521                 return ret;
522
523         ret = pdump_prepare_client_request(device_id, queue, flags,
524                                                 ENABLE, ring, mp, filter);
525
526         return ret;
527 }
528
529 int
530 rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags)
531 {
532         int ret = 0;
533         char name[DEVICE_ID_SIZE];
534
535         ret = pdump_validate_port(port, name);
536         if (ret < 0)
537                 return ret;
538         ret = pdump_validate_flags(flags);
539         if (ret < 0)
540                 return ret;
541
542         ret = pdump_prepare_client_request(name, queue, flags,
543                                                 DISABLE, NULL, NULL, NULL);
544
545         return ret;
546 }
547
548 int
549 rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
550                                 uint32_t flags)
551 {
552         int ret = 0;
553
554         ret = pdump_validate_flags(flags);
555         if (ret < 0)
556                 return ret;
557
558         ret = pdump_prepare_client_request(device_id, queue, flags,
559                                                 DISABLE, NULL, NULL, NULL);
560
561         return ret;
562 }
563
564 RTE_INIT(pdump_log)
565 {
566         pdump_logtype = rte_log_register("lib.pdump");
567         if (pdump_logtype >= 0)
568                 rte_log_set_level(pdump_logtype, RTE_LOG_NOTICE);
569 }