pdump: replace constant for device name size
[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 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                                         "failed to add rx callback for port=%d "
135                                         "and queue=%d, callback already exists\n",
136                                         port, qid);
137                                 return -EEXIST;
138                         }
139                         cbs->ring = ring;
140                         cbs->mp = mp;
141                         cbs->cb = rte_eth_add_first_rx_callback(port, qid,
142                                                                 pdump_rx, cbs);
143                         if (cbs->cb == NULL) {
144                                 PDUMP_LOG(ERR,
145                                         "failed to add rx callback, errno=%d\n",
146                                         rte_errno);
147                                 return rte_errno;
148                         }
149                 }
150                 if (cbs && operation == DISABLE) {
151                         int ret;
152
153                         if (cbs->cb == NULL) {
154                                 PDUMP_LOG(ERR,
155                                         "failed to delete non existing rx "
156                                         "callback for port=%d and queue=%d\n",
157                                         port, qid);
158                                 return -EINVAL;
159                         }
160                         ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
161                         if (ret < 0) {
162                                 PDUMP_LOG(ERR,
163                                         "failed to remove rx callback, errno=%d\n",
164                                         -ret);
165                                 return ret;
166                         }
167                         cbs->cb = NULL;
168                 }
169         }
170
171         return 0;
172 }
173
174 static int
175 pdump_register_tx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue,
176                                 struct rte_ring *ring, struct rte_mempool *mp,
177                                 uint16_t operation)
178 {
179
180         uint16_t qid;
181         struct pdump_rxtx_cbs *cbs = NULL;
182
183         qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
184         for (; qid < end_q; qid++) {
185                 cbs = &tx_cbs[port][qid];
186                 if (cbs && operation == ENABLE) {
187                         if (cbs->cb) {
188                                 PDUMP_LOG(ERR,
189                                         "failed to add tx callback for port=%d "
190                                         "and queue=%d, callback already exists\n",
191                                         port, qid);
192                                 return -EEXIST;
193                         }
194                         cbs->ring = ring;
195                         cbs->mp = mp;
196                         cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
197                                                                 cbs);
198                         if (cbs->cb == NULL) {
199                                 PDUMP_LOG(ERR,
200                                         "failed to add tx callback, errno=%d\n",
201                                         rte_errno);
202                                 return rte_errno;
203                         }
204                 }
205                 if (cbs && operation == DISABLE) {
206                         int ret;
207
208                         if (cbs->cb == NULL) {
209                                 PDUMP_LOG(ERR,
210                                         "failed to delete non existing tx "
211                                         "callback for port=%d and queue=%d\n",
212                                         port, qid);
213                                 return -EINVAL;
214                         }
215                         ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
216                         if (ret < 0) {
217                                 PDUMP_LOG(ERR,
218                                         "failed to remove tx callback, errno=%d\n",
219                                         -ret);
220                                 return ret;
221                         }
222                         cbs->cb = NULL;
223                 }
224         }
225
226         return 0;
227 }
228
229 static int
230 set_pdump_rxtx_cbs(const struct pdump_request *p)
231 {
232         uint16_t nb_rx_q = 0, nb_tx_q = 0, end_q, queue;
233         uint16_t port;
234         int ret = 0;
235         uint32_t flags;
236         uint16_t operation;
237         struct rte_ring *ring;
238         struct rte_mempool *mp;
239
240         flags = p->flags;
241         operation = p->op;
242         if (operation == ENABLE) {
243                 ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device,
244                                 &port);
245                 if (ret < 0) {
246                         PDUMP_LOG(ERR,
247                                 "failed to get port id for device id=%s\n",
248                                 p->data.en_v1.device);
249                         return -EINVAL;
250                 }
251                 queue = p->data.en_v1.queue;
252                 ring = p->data.en_v1.ring;
253                 mp = p->data.en_v1.mp;
254         } else {
255                 ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device,
256                                 &port);
257                 if (ret < 0) {
258                         PDUMP_LOG(ERR,
259                                 "failed to get port id for device id=%s\n",
260                                 p->data.dis_v1.device);
261                         return -EINVAL;
262                 }
263                 queue = p->data.dis_v1.queue;
264                 ring = p->data.dis_v1.ring;
265                 mp = p->data.dis_v1.mp;
266         }
267
268         /* validation if packet capture is for all queues */
269         if (queue == RTE_PDUMP_ALL_QUEUES) {
270                 struct rte_eth_dev_info dev_info;
271
272                 ret = rte_eth_dev_info_get(port, &dev_info);
273                 if (ret != 0) {
274                         PDUMP_LOG(ERR,
275                                 "Error during getting device (port %u) info: %s\n",
276                                 port, strerror(-ret));
277                         return ret;
278                 }
279
280                 nb_rx_q = dev_info.nb_rx_queues;
281                 nb_tx_q = dev_info.nb_tx_queues;
282                 if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
283                         PDUMP_LOG(ERR,
284                                 "number of rx queues cannot be 0\n");
285                         return -EINVAL;
286                 }
287                 if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
288                         PDUMP_LOG(ERR,
289                                 "number of tx queues cannot be 0\n");
290                         return -EINVAL;
291                 }
292                 if ((nb_tx_q == 0 || nb_rx_q == 0) &&
293                         flags == RTE_PDUMP_FLAG_RXTX) {
294                         PDUMP_LOG(ERR,
295                                 "both tx&rx queues must be non zero\n");
296                         return -EINVAL;
297                 }
298         }
299
300         /* register RX callback */
301         if (flags & RTE_PDUMP_FLAG_RX) {
302                 end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
303                 ret = pdump_register_rx_callbacks(end_q, port, queue, ring, mp,
304                                                         operation);
305                 if (ret < 0)
306                         return ret;
307         }
308
309         /* register TX callback */
310         if (flags & RTE_PDUMP_FLAG_TX) {
311                 end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
312                 ret = pdump_register_tx_callbacks(end_q, port, queue, ring, mp,
313                                                         operation);
314                 if (ret < 0)
315                         return ret;
316         }
317
318         return ret;
319 }
320
321 static int
322 pdump_server(const struct rte_mp_msg *mp_msg, const void *peer)
323 {
324         struct rte_mp_msg mp_resp;
325         const struct pdump_request *cli_req;
326         struct pdump_response *resp = (struct pdump_response *)&mp_resp.param;
327
328         /* recv client requests */
329         if (mp_msg->len_param != sizeof(*cli_req)) {
330                 PDUMP_LOG(ERR, "failed to recv from client\n");
331                 resp->err_value = -EINVAL;
332         } else {
333                 cli_req = (const struct pdump_request *)mp_msg->param;
334                 resp->ver = cli_req->ver;
335                 resp->res_op = cli_req->op;
336                 resp->err_value = set_pdump_rxtx_cbs(cli_req);
337         }
338
339         strlcpy(mp_resp.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
340         mp_resp.len_param = sizeof(*resp);
341         mp_resp.num_fds = 0;
342         if (rte_mp_reply(&mp_resp, peer) < 0) {
343                 PDUMP_LOG(ERR, "failed to send to client:%s\n",
344                           strerror(rte_errno));
345                 return -1;
346         }
347
348         return 0;
349 }
350
351 int
352 rte_pdump_init(void)
353 {
354         int ret = rte_mp_action_register(PDUMP_MP, pdump_server);
355         if (ret && rte_errno != ENOTSUP)
356                 return -1;
357         return 0;
358 }
359
360 int
361 rte_pdump_uninit(void)
362 {
363         rte_mp_action_unregister(PDUMP_MP);
364
365         return 0;
366 }
367
368 static int
369 pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
370 {
371         if (ring == NULL || mp == NULL) {
372                 PDUMP_LOG(ERR, "NULL ring or mempool\n");
373                 rte_errno = EINVAL;
374                 return -1;
375         }
376         if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
377                 PDUMP_LOG(ERR, "mempool with either SP or SC settings"
378                 " is not valid for pdump, should have MP and MC settings\n");
379                 rte_errno = EINVAL;
380                 return -1;
381         }
382         if (rte_ring_is_prod_single(ring) || rte_ring_is_cons_single(ring)) {
383                 PDUMP_LOG(ERR, "ring with either SP or SC settings"
384                 " is not valid for pdump, should have MP and MC settings\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 }