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