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