]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/dpdk/app/pdump/main.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / dpdk / app / pdump / main.c
CommitLineData
11fdf7f2
TL
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2016 Intel Corporation
7c673cae
FG
3 */
4
5#include <stdio.h>
6#include <string.h>
7#include <stdint.h>
8#include <inttypes.h>
9#include <stdlib.h>
10#include <getopt.h>
11#include <signal.h>
12#include <stdbool.h>
13#include <net/if.h>
14
15#include <rte_eal.h>
16#include <rte_common.h>
17#include <rte_debug.h>
18#include <rte_ethdev.h>
19#include <rte_memory.h>
20#include <rte_lcore.h>
21#include <rte_branch_prediction.h>
22#include <rte_errno.h>
23#include <rte_dev.h>
24#include <rte_kvargs.h>
25#include <rte_mempool.h>
26#include <rte_ring.h>
11fdf7f2 27#include <rte_string_fns.h>
7c673cae
FG
28#include <rte_pdump.h>
29
30#define CMD_LINE_OPT_PDUMP "pdump"
9f95a23c
TL
31#define CMD_LINE_OPT_PDUMP_NUM 256
32#define CMD_LINE_OPT_MULTI "multi"
33#define CMD_LINE_OPT_MULTI_NUM 257
7c673cae
FG
34#define PDUMP_PORT_ARG "port"
35#define PDUMP_PCI_ARG "device_id"
36#define PDUMP_QUEUE_ARG "queue"
37#define PDUMP_DIR_ARG "dir"
38#define PDUMP_RX_DEV_ARG "rx-dev"
39#define PDUMP_TX_DEV_ARG "tx-dev"
40#define PDUMP_RING_SIZE_ARG "ring-size"
41#define PDUMP_MSIZE_ARG "mbuf-size"
42#define PDUMP_NUM_MBUFS_ARG "total-num-mbufs"
7c673cae 43
11fdf7f2
TL
44#define VDEV_NAME_FMT "net_pcap_%s_%d"
45#define VDEV_PCAP_ARGS_FMT "tx_pcap=%s"
46#define VDEV_IFACE_ARGS_FMT "tx_iface=%s"
7c673cae
FG
47#define TX_STREAM_SIZE 64
48
49#define MP_NAME "pdump_pool_%d"
50
51#define RX_RING "rx_ring_%d"
52#define TX_RING "tx_ring_%d"
53
54#define RX_STR "rx"
55#define TX_STR "tx"
56
57/* Maximum long option length for option parsing. */
58#define APP_ARG_TCPDUMP_MAX_TUPLES 54
59#define MBUF_POOL_CACHE_SIZE 250
60#define TX_DESC_PER_QUEUE 512
61#define RX_DESC_PER_QUEUE 128
62#define MBUFS_PER_POOL 65535
63#define MAX_LONG_OPT_SZ 64
64#define RING_SIZE 16384
65#define SIZE 256
66#define BURST_SIZE 32
67#define NUM_VDEVS 2
68
7c673cae
FG
69/* true if x is a power of 2 */
70#define POWEROF2(x) ((((x)-1) & (x)) == 0)
71
72enum pdump_en_dis {
73 DISABLE = 1,
74 ENABLE = 2
75};
76
77enum pcap_stream {
78 IFACE = 1,
79 PCAP = 2
80};
81
82enum pdump_by {
83 PORT_ID = 1,
84 DEVICE_ID = 2
85};
86
9f95a23c 87static const char * const valid_pdump_arguments[] = {
7c673cae
FG
88 PDUMP_PORT_ARG,
89 PDUMP_PCI_ARG,
90 PDUMP_QUEUE_ARG,
91 PDUMP_DIR_ARG,
92 PDUMP_RX_DEV_ARG,
93 PDUMP_TX_DEV_ARG,
94 PDUMP_RING_SIZE_ARG,
95 PDUMP_MSIZE_ARG,
96 PDUMP_NUM_MBUFS_ARG,
97 NULL
98};
99
100struct pdump_stats {
101 uint64_t dequeue_pkts;
102 uint64_t tx_pkts;
103 uint64_t freed_pkts;
104};
105
106struct pdump_tuples {
107 /* cli params */
11fdf7f2 108 uint16_t port;
7c673cae
FG
109 char *device_id;
110 uint16_t queue;
111 char rx_dev[TX_STREAM_SIZE];
112 char tx_dev[TX_STREAM_SIZE];
113 uint32_t ring_size;
114 uint16_t mbuf_data_size;
115 uint32_t total_num_mbufs;
116
117 /* params for library API call */
118 uint32_t dir;
119 struct rte_mempool *mp;
120 struct rte_ring *rx_ring;
121 struct rte_ring *tx_ring;
122
123 /* params for packet dumping */
124 enum pdump_by dump_by_type;
9f95a23c
TL
125 uint16_t rx_vdev_id;
126 uint16_t tx_vdev_id;
7c673cae
FG
127 enum pcap_stream rx_vdev_stream_type;
128 enum pcap_stream tx_vdev_stream_type;
129 bool single_pdump_dev;
130
131 /* stats */
132 struct pdump_stats stats;
133} __rte_cache_aligned;
134static struct pdump_tuples pdump_t[APP_ARG_TCPDUMP_MAX_TUPLES];
135
136struct parse_val {
137 uint64_t min;
138 uint64_t max;
139 uint64_t val;
140};
141
9f95a23c 142static int num_tuples;
7c673cae 143static struct rte_eth_conf port_conf_default;
9f95a23c
TL
144static volatile uint8_t quit_signal;
145static uint8_t multiple_core_capture;
7c673cae
FG
146
147/**< display usage */
148static void
149pdump_usage(const char *prgname)
150{
9f95a23c
TL
151 printf("usage: %s [EAL options]"
152 " --["CMD_LINE_OPT_MULTI"]\n"
153 " --"CMD_LINE_OPT_PDUMP" "
7c673cae
FG
154 "'(port=<port id> | device_id=<pci id or vdev name>),"
155 "(queue=<queue_id>),"
156 "(rx-dev=<iface or pcap file> |"
157 " tx-dev=<iface or pcap file>,"
158 "[ring-size=<ring size>default:16384],"
159 "[mbuf-size=<mbuf data size>default:2176],"
11fdf7f2 160 "[total-num-mbufs=<number of mbufs>default:65535]'\n",
7c673cae
FG
161 prgname);
162}
163
164static int
165parse_device_id(const char *key __rte_unused, const char *value,
166 void *extra_args)
167{
168 struct pdump_tuples *pt = extra_args;
169
170 pt->device_id = strdup(value);
171 pt->dump_by_type = DEVICE_ID;
172
173 return 0;
174}
175
176static int
177parse_queue(const char *key __rte_unused, const char *value, void *extra_args)
178{
179 unsigned long n;
180 struct pdump_tuples *pt = extra_args;
181
182 if (!strcmp(value, "*"))
183 pt->queue = RTE_PDUMP_ALL_QUEUES;
184 else {
185 n = strtoul(value, NULL, 10);
186 pt->queue = (uint16_t) n;
187 }
188 return 0;
189}
190
191static int
192parse_rxtxdev(const char *key, const char *value, void *extra_args)
193{
194
195 struct pdump_tuples *pt = extra_args;
196
197 if (!strcmp(key, PDUMP_RX_DEV_ARG)) {
9f95a23c 198 strlcpy(pt->rx_dev, value, sizeof(pt->rx_dev));
7c673cae
FG
199 /* identify the tx stream type for pcap vdev */
200 if (if_nametoindex(pt->rx_dev))
201 pt->rx_vdev_stream_type = IFACE;
202 } else if (!strcmp(key, PDUMP_TX_DEV_ARG)) {
9f95a23c 203 strlcpy(pt->tx_dev, value, sizeof(pt->tx_dev));
7c673cae
FG
204 /* identify the tx stream type for pcap vdev */
205 if (if_nametoindex(pt->tx_dev))
206 pt->tx_vdev_stream_type = IFACE;
207 }
208
209 return 0;
210}
211
212static int
213parse_uint_value(const char *key, const char *value, void *extra_args)
214{
215 struct parse_val *v;
216 unsigned long t;
217 char *end;
218 int ret = 0;
219
220 errno = 0;
221 v = extra_args;
222 t = strtoul(value, &end, 10);
223
224 if (errno != 0 || end[0] != 0 || t < v->min || t > v->max) {
225 printf("invalid value:\"%s\" for key:\"%s\", "
226 "value must be >= %"PRIu64" and <= %"PRIu64"\n",
227 value, key, v->min, v->max);
228 ret = -EINVAL;
229 }
230 if (!strcmp(key, PDUMP_RING_SIZE_ARG) && !POWEROF2(t)) {
231 printf("invalid value:\"%s\" for key:\"%s\", "
232 "value must be power of 2\n", value, key);
233 ret = -EINVAL;
234 }
235
236 if (ret != 0)
237 return ret;
238
239 v->val = t;
240 return 0;
241}
242
243static int
244parse_pdump(const char *optarg)
245{
246 struct rte_kvargs *kvlist;
247 int ret = 0, cnt1, cnt2;
248 struct pdump_tuples *pt;
249 struct parse_val v = {0};
250
251 pt = &pdump_t[num_tuples];
252
253 /* initial check for invalid arguments */
254 kvlist = rte_kvargs_parse(optarg, valid_pdump_arguments);
255 if (kvlist == NULL) {
256 printf("--pdump=\"%s\": invalid argument passed\n", optarg);
257 return -1;
258 }
259
260 /* port/device_id parsing and validation */
261 cnt1 = rte_kvargs_count(kvlist, PDUMP_PORT_ARG);
262 cnt2 = rte_kvargs_count(kvlist, PDUMP_PCI_ARG);
263 if (!((cnt1 == 1 && cnt2 == 0) || (cnt1 == 0 && cnt2 == 1))) {
264 printf("--pdump=\"%s\": must have either port or "
265 "device_id argument\n", optarg);
266 ret = -1;
267 goto free_kvlist;
268 } else if (cnt1 == 1) {
269 v.min = 0;
270 v.max = RTE_MAX_ETHPORTS-1;
271 ret = rte_kvargs_process(kvlist, PDUMP_PORT_ARG,
272 &parse_uint_value, &v);
273 if (ret < 0)
274 goto free_kvlist;
9f95a23c 275 pt->port = (uint16_t) v.val;
7c673cae
FG
276 pt->dump_by_type = PORT_ID;
277 } else if (cnt2 == 1) {
278 ret = rte_kvargs_process(kvlist, PDUMP_PCI_ARG,
279 &parse_device_id, pt);
280 if (ret < 0)
281 goto free_kvlist;
282 }
283
284 /* queue parsing and validation */
285 cnt1 = rte_kvargs_count(kvlist, PDUMP_QUEUE_ARG);
286 if (cnt1 != 1) {
287 printf("--pdump=\"%s\": must have queue argument\n", optarg);
288 ret = -1;
289 goto free_kvlist;
290 }
291 ret = rte_kvargs_process(kvlist, PDUMP_QUEUE_ARG, &parse_queue, pt);
292 if (ret < 0)
293 goto free_kvlist;
294
295 /* rx-dev and tx-dev parsing and validation */
296 cnt1 = rte_kvargs_count(kvlist, PDUMP_RX_DEV_ARG);
297 cnt2 = rte_kvargs_count(kvlist, PDUMP_TX_DEV_ARG);
298 if (cnt1 == 0 && cnt2 == 0) {
299 printf("--pdump=\"%s\": must have either rx-dev or "
300 "tx-dev argument\n", optarg);
301 ret = -1;
302 goto free_kvlist;
303 } else if (cnt1 == 1 && cnt2 == 1) {
304 ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG,
305 &parse_rxtxdev, pt);
306 if (ret < 0)
307 goto free_kvlist;
308 ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG,
309 &parse_rxtxdev, pt);
310 if (ret < 0)
311 goto free_kvlist;
312 /* if captured packets has to send to the same vdev */
313 if (!strcmp(pt->rx_dev, pt->tx_dev))
314 pt->single_pdump_dev = true;
315 pt->dir = RTE_PDUMP_FLAG_RXTX;
316 } else if (cnt1 == 1) {
317 ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG,
318 &parse_rxtxdev, pt);
319 if (ret < 0)
320 goto free_kvlist;
321 pt->dir = RTE_PDUMP_FLAG_RX;
322 } else if (cnt2 == 1) {
323 ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG,
324 &parse_rxtxdev, pt);
325 if (ret < 0)
326 goto free_kvlist;
327 pt->dir = RTE_PDUMP_FLAG_TX;
328 }
329
330 /* optional */
331 /* ring_size parsing and validation */
332 cnt1 = rte_kvargs_count(kvlist, PDUMP_RING_SIZE_ARG);
333 if (cnt1 == 1) {
334 v.min = 2;
335 v.max = RTE_RING_SZ_MASK-1;
336 ret = rte_kvargs_process(kvlist, PDUMP_RING_SIZE_ARG,
337 &parse_uint_value, &v);
338 if (ret < 0)
339 goto free_kvlist;
340 pt->ring_size = (uint32_t) v.val;
341 } else
342 pt->ring_size = RING_SIZE;
343
344 /* mbuf_data_size parsing and validation */
345 cnt1 = rte_kvargs_count(kvlist, PDUMP_MSIZE_ARG);
346 if (cnt1 == 1) {
347 v.min = 1;
348 v.max = UINT16_MAX;
349 ret = rte_kvargs_process(kvlist, PDUMP_MSIZE_ARG,
350 &parse_uint_value, &v);
351 if (ret < 0)
352 goto free_kvlist;
353 pt->mbuf_data_size = (uint16_t) v.val;
354 } else
355 pt->mbuf_data_size = RTE_MBUF_DEFAULT_BUF_SIZE;
356
357 /* total_num_mbufs parsing and validation */
358 cnt1 = rte_kvargs_count(kvlist, PDUMP_NUM_MBUFS_ARG);
359 if (cnt1 == 1) {
360 v.min = 1025;
361 v.max = UINT16_MAX;
362 ret = rte_kvargs_process(kvlist, PDUMP_NUM_MBUFS_ARG,
363 &parse_uint_value, &v);
364 if (ret < 0)
365 goto free_kvlist;
366 pt->total_num_mbufs = (uint16_t) v.val;
367 } else
368 pt->total_num_mbufs = MBUFS_PER_POOL;
369
370 num_tuples++;
371
372free_kvlist:
373 rte_kvargs_free(kvlist);
374 return ret;
375}
376
377/* Parse the argument given in the command line of the application */
378static int
379launch_args_parse(int argc, char **argv, char *prgname)
380{
381 int opt, ret;
382 int option_index;
383 static struct option long_option[] = {
9f95a23c
TL
384 {CMD_LINE_OPT_PDUMP, 1, 0, CMD_LINE_OPT_PDUMP_NUM},
385 {CMD_LINE_OPT_MULTI, 0, 0, CMD_LINE_OPT_MULTI_NUM},
7c673cae
FG
386 {NULL, 0, 0, 0}
387 };
388
389 if (argc == 1)
390 pdump_usage(prgname);
391
392 /* Parse command line */
393 while ((opt = getopt_long(argc, argv, " ",
394 long_option, &option_index)) != EOF) {
395 switch (opt) {
9f95a23c
TL
396 case CMD_LINE_OPT_PDUMP_NUM:
397 ret = parse_pdump(optarg);
398 if (ret) {
399 pdump_usage(prgname);
400 return -1;
7c673cae 401 }
7c673cae 402 break;
9f95a23c
TL
403 case CMD_LINE_OPT_MULTI_NUM:
404 multiple_core_capture = 1;
405 break;
7c673cae
FG
406 default:
407 pdump_usage(prgname);
408 return -1;
409 }
410 }
411
412 return 0;
413}
414
415static void
416print_pdump_stats(void)
417{
418 int i;
419 struct pdump_tuples *pt;
420
421 for (i = 0; i < num_tuples; i++) {
422 printf("##### PDUMP DEBUG STATS #####\n");
423 pt = &pdump_t[i];
424 printf(" -packets dequeued: %"PRIu64"\n",
425 pt->stats.dequeue_pkts);
426 printf(" -packets transmitted to vdev: %"PRIu64"\n",
427 pt->stats.tx_pkts);
428 printf(" -packets freed: %"PRIu64"\n",
429 pt->stats.freed_pkts);
430 }
431}
432
433static inline void
434disable_pdump(struct pdump_tuples *pt)
435{
436 if (pt->dump_by_type == DEVICE_ID)
437 rte_pdump_disable_by_deviceid(pt->device_id, pt->queue,
438 pt->dir);
439 else if (pt->dump_by_type == PORT_ID)
440 rte_pdump_disable(pt->port, pt->queue, pt->dir);
441}
442
443static inline void
9f95a23c 444pdump_rxtx(struct rte_ring *ring, uint16_t vdev_id, struct pdump_stats *stats)
7c673cae
FG
445{
446 /* write input packets of port to vdev for pdump */
447 struct rte_mbuf *rxtx_bufs[BURST_SIZE];
448
449 /* first dequeue packets from ring of primary process */
450 const uint16_t nb_in_deq = rte_ring_dequeue_burst(ring,
11fdf7f2 451 (void *)rxtx_bufs, BURST_SIZE, NULL);
7c673cae
FG
452 stats->dequeue_pkts += nb_in_deq;
453
454 if (nb_in_deq) {
455 /* then sent on vdev */
456 uint16_t nb_in_txd = rte_eth_tx_burst(
457 vdev_id,
458 0, rxtx_bufs, nb_in_deq);
459 stats->tx_pkts += nb_in_txd;
460
461 if (unlikely(nb_in_txd < nb_in_deq)) {
462 do {
463 rte_pktmbuf_free(rxtx_bufs[nb_in_txd]);
464 stats->freed_pkts++;
465 } while (++nb_in_txd < nb_in_deq);
466 }
467 }
468}
469
470static void
9f95a23c 471free_ring_data(struct rte_ring *ring, uint16_t vdev_id,
7c673cae
FG
472 struct pdump_stats *stats)
473{
474 while (rte_ring_count(ring))
475 pdump_rxtx(ring, vdev_id, stats);
476}
477
478static void
479cleanup_rings(void)
480{
481 int i;
482 struct pdump_tuples *pt;
483
484 for (i = 0; i < num_tuples; i++) {
485 pt = &pdump_t[i];
486
487 if (pt->device_id)
488 free(pt->device_id);
489
490 /* free the rings */
491 if (pt->rx_ring)
492 rte_ring_free(pt->rx_ring);
493 if (pt->tx_ring)
494 rte_ring_free(pt->tx_ring);
495 }
496}
497
498static void
499cleanup_pdump_resources(void)
500{
501 int i;
502 struct pdump_tuples *pt;
9f95a23c 503 char name[RTE_ETH_NAME_MAX_LEN];
7c673cae
FG
504
505 /* disable pdump and free the pdump_tuple resources */
506 for (i = 0; i < num_tuples; i++) {
507 pt = &pdump_t[i];
508
509 /* remove callbacks */
510 disable_pdump(pt);
511
512 /*
513 * transmit rest of the enqueued packets of the rings on to
514 * the vdev, in order to release mbufs to the mepool.
515 **/
516 if (pt->dir & RTE_PDUMP_FLAG_RX)
517 free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
518 if (pt->dir & RTE_PDUMP_FLAG_TX)
519 free_ring_data(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
9f95a23c
TL
520
521 /* Remove the vdev(s) created */
522 if (pt->dir & RTE_PDUMP_FLAG_RX) {
523 rte_eth_dev_get_name_by_port(pt->rx_vdev_id, name);
524 rte_eal_hotplug_remove("vdev", name);
525 }
526
527 if (pt->single_pdump_dev)
528 continue;
529
530 if (pt->dir & RTE_PDUMP_FLAG_TX) {
531 rte_eth_dev_get_name_by_port(pt->tx_vdev_id, name);
532 rte_eal_hotplug_remove("vdev", name);
533 }
534
7c673cae
FG
535 }
536 cleanup_rings();
537}
538
539static void
540signal_handler(int sig_num)
541{
542 if (sig_num == SIGINT) {
543 printf("\n\nSignal %d received, preparing to exit...\n",
544 sig_num);
545 quit_signal = 1;
546 }
547}
548
549static inline int
11fdf7f2 550configure_vdev(uint16_t port_id)
7c673cae
FG
551{
552 struct ether_addr addr;
553 const uint16_t rxRings = 0, txRings = 1;
7c673cae
FG
554 int ret;
555 uint16_t q;
556
11fdf7f2 557 if (!rte_eth_dev_is_valid_port(port_id))
7c673cae
FG
558 return -1;
559
560 ret = rte_eth_dev_configure(port_id, rxRings, txRings,
561 &port_conf_default);
562 if (ret != 0)
563 rte_exit(EXIT_FAILURE, "dev config failed\n");
564
565 for (q = 0; q < txRings; q++) {
566 ret = rte_eth_tx_queue_setup(port_id, q, TX_DESC_PER_QUEUE,
567 rte_eth_dev_socket_id(port_id), NULL);
568 if (ret < 0)
569 rte_exit(EXIT_FAILURE, "queue setup failed\n");
570 }
571
572 ret = rte_eth_dev_start(port_id);
573 if (ret < 0)
574 rte_exit(EXIT_FAILURE, "dev start failed\n");
575
576 rte_eth_macaddr_get(port_id, &addr);
577 printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
578 " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
11fdf7f2 579 port_id,
7c673cae
FG
580 addr.addr_bytes[0], addr.addr_bytes[1],
581 addr.addr_bytes[2], addr.addr_bytes[3],
582 addr.addr_bytes[4], addr.addr_bytes[5]);
583
584 rte_eth_promiscuous_enable(port_id);
585
586 return 0;
587}
588
589static void
590create_mp_ring_vdev(void)
591{
592 int i;
11fdf7f2 593 uint16_t portid;
7c673cae
FG
594 struct pdump_tuples *pt = NULL;
595 struct rte_mempool *mbuf_pool = NULL;
11fdf7f2 596 char vdev_name[SIZE];
7c673cae
FG
597 char vdev_args[SIZE];
598 char ring_name[SIZE];
599 char mempool_name[SIZE];
600
601 for (i = 0; i < num_tuples; i++) {
602 pt = &pdump_t[i];
603 snprintf(mempool_name, SIZE, MP_NAME, i);
604 mbuf_pool = rte_mempool_lookup(mempool_name);
605 if (mbuf_pool == NULL) {
606 /* create mempool */
607 mbuf_pool = rte_pktmbuf_pool_create(mempool_name,
608 pt->total_num_mbufs,
609 MBUF_POOL_CACHE_SIZE, 0,
610 pt->mbuf_data_size,
611 rte_socket_id());
612 if (mbuf_pool == NULL) {
613 cleanup_rings();
614 rte_exit(EXIT_FAILURE,
615 "Mempool creation failed: %s\n",
616 rte_strerror(rte_errno));
617 }
618 }
619 pt->mp = mbuf_pool;
620
621 if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
622 /* if captured packets has to send to the same vdev */
623 /* create rx_ring */
624 snprintf(ring_name, SIZE, RX_RING, i);
625 pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
626 rte_socket_id(), 0);
627 if (pt->rx_ring == NULL) {
628 cleanup_rings();
629 rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
630 rte_strerror(rte_errno),
631 __func__, __LINE__);
632 }
633
634 /* create tx_ring */
635 snprintf(ring_name, SIZE, TX_RING, i);
636 pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
637 rte_socket_id(), 0);
638 if (pt->tx_ring == NULL) {
639 cleanup_rings();
640 rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
641 rte_strerror(rte_errno),
642 __func__, __LINE__);
643 }
644
645 /* create vdevs */
11fdf7f2
TL
646 snprintf(vdev_name, sizeof(vdev_name),
647 VDEV_NAME_FMT, RX_STR, i);
7c673cae 648 (pt->rx_vdev_stream_type == IFACE) ?
11fdf7f2
TL
649 snprintf(vdev_args, sizeof(vdev_args),
650 VDEV_IFACE_ARGS_FMT, pt->rx_dev) :
651 snprintf(vdev_args, sizeof(vdev_args),
652 VDEV_PCAP_ARGS_FMT, pt->rx_dev);
653 if (rte_eal_hotplug_add("vdev", vdev_name,
654 vdev_args) < 0) {
7c673cae
FG
655 cleanup_rings();
656 rte_exit(EXIT_FAILURE,
657 "vdev creation failed:%s:%d\n",
658 __func__, __LINE__);
659 }
11fdf7f2
TL
660 if (rte_eth_dev_get_port_by_name(vdev_name,
661 &portid) != 0) {
662 rte_eal_hotplug_remove("vdev", vdev_name);
663 cleanup_rings();
664 rte_exit(EXIT_FAILURE,
665 "cannot find added vdev %s:%s:%d\n",
666 vdev_name, __func__, __LINE__);
667 }
7c673cae
FG
668 pt->rx_vdev_id = portid;
669
670 /* configure vdev */
671 configure_vdev(pt->rx_vdev_id);
672
673 if (pt->single_pdump_dev)
674 pt->tx_vdev_id = portid;
675 else {
11fdf7f2
TL
676 snprintf(vdev_name, sizeof(vdev_name),
677 VDEV_NAME_FMT, TX_STR, i);
678 (pt->rx_vdev_stream_type == IFACE) ?
679 snprintf(vdev_args, sizeof(vdev_args),
680 VDEV_IFACE_ARGS_FMT, pt->tx_dev) :
681 snprintf(vdev_args, sizeof(vdev_args),
682 VDEV_PCAP_ARGS_FMT, pt->tx_dev);
683 if (rte_eal_hotplug_add("vdev", vdev_name,
684 vdev_args) < 0) {
7c673cae
FG
685 cleanup_rings();
686 rte_exit(EXIT_FAILURE,
687 "vdev creation failed:"
688 "%s:%d\n", __func__, __LINE__);
689 }
11fdf7f2
TL
690 if (rte_eth_dev_get_port_by_name(vdev_name,
691 &portid) != 0) {
692 rte_eal_hotplug_remove("vdev",
693 vdev_name);
694 cleanup_rings();
695 rte_exit(EXIT_FAILURE,
696 "cannot find added vdev %s:%s:%d\n",
697 vdev_name, __func__, __LINE__);
698 }
7c673cae
FG
699 pt->tx_vdev_id = portid;
700
701 /* configure vdev */
702 configure_vdev(pt->tx_vdev_id);
703 }
704 } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
705
706 /* create rx_ring */
707 snprintf(ring_name, SIZE, RX_RING, i);
708 pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
709 rte_socket_id(), 0);
710 if (pt->rx_ring == NULL) {
711 cleanup_rings();
712 rte_exit(EXIT_FAILURE, "%s\n",
713 rte_strerror(rte_errno));
714 }
715
11fdf7f2
TL
716 snprintf(vdev_name, sizeof(vdev_name),
717 VDEV_NAME_FMT, RX_STR, i);
7c673cae 718 (pt->rx_vdev_stream_type == IFACE) ?
11fdf7f2
TL
719 snprintf(vdev_args, sizeof(vdev_args),
720 VDEV_IFACE_ARGS_FMT, pt->rx_dev) :
721 snprintf(vdev_args, sizeof(vdev_args),
722 VDEV_PCAP_ARGS_FMT, pt->rx_dev);
723 if (rte_eal_hotplug_add("vdev", vdev_name,
724 vdev_args) < 0) {
7c673cae
FG
725 cleanup_rings();
726 rte_exit(EXIT_FAILURE,
727 "vdev creation failed:%s:%d\n",
728 __func__, __LINE__);
729 }
11fdf7f2
TL
730 if (rte_eth_dev_get_port_by_name(vdev_name,
731 &portid) != 0) {
732 rte_eal_hotplug_remove("vdev", vdev_name);
733 cleanup_rings();
734 rte_exit(EXIT_FAILURE,
735 "cannot find added vdev %s:%s:%d\n",
736 vdev_name, __func__, __LINE__);
737 }
7c673cae
FG
738 pt->rx_vdev_id = portid;
739 /* configure vdev */
740 configure_vdev(pt->rx_vdev_id);
741 } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
742
743 /* create tx_ring */
744 snprintf(ring_name, SIZE, TX_RING, i);
745 pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
746 rte_socket_id(), 0);
747 if (pt->tx_ring == NULL) {
748 cleanup_rings();
749 rte_exit(EXIT_FAILURE, "%s\n",
750 rte_strerror(rte_errno));
751 }
752
11fdf7f2
TL
753 snprintf(vdev_name, sizeof(vdev_name),
754 VDEV_NAME_FMT, TX_STR, i);
7c673cae 755 (pt->tx_vdev_stream_type == IFACE) ?
11fdf7f2
TL
756 snprintf(vdev_args, sizeof(vdev_args),
757 VDEV_IFACE_ARGS_FMT, pt->tx_dev) :
758 snprintf(vdev_args, sizeof(vdev_args),
759 VDEV_PCAP_ARGS_FMT, pt->tx_dev);
760 if (rte_eal_hotplug_add("vdev", vdev_name,
761 vdev_args) < 0) {
7c673cae
FG
762 cleanup_rings();
763 rte_exit(EXIT_FAILURE,
764 "vdev creation failed\n");
765 }
11fdf7f2
TL
766 if (rte_eth_dev_get_port_by_name(vdev_name,
767 &portid) != 0) {
768 rte_eal_hotplug_remove("vdev", vdev_name);
769 cleanup_rings();
770 rte_exit(EXIT_FAILURE,
771 "cannot find added vdev %s:%s:%d\n",
772 vdev_name, __func__, __LINE__);
773 }
7c673cae
FG
774 pt->tx_vdev_id = portid;
775
776 /* configure vdev */
777 configure_vdev(pt->tx_vdev_id);
778 }
779 }
780}
781
782static void
783enable_pdump(void)
784{
785 int i;
786 struct pdump_tuples *pt;
787 int ret = 0, ret1 = 0;
788
7c673cae
FG
789 for (i = 0; i < num_tuples; i++) {
790 pt = &pdump_t[i];
791 if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
792 if (pt->dump_by_type == DEVICE_ID) {
793 ret = rte_pdump_enable_by_deviceid(
794 pt->device_id,
795 pt->queue,
796 RTE_PDUMP_FLAG_RX,
797 pt->rx_ring,
798 pt->mp, NULL);
799 ret1 = rte_pdump_enable_by_deviceid(
800 pt->device_id,
801 pt->queue,
802 RTE_PDUMP_FLAG_TX,
803 pt->tx_ring,
804 pt->mp, NULL);
805 } else if (pt->dump_by_type == PORT_ID) {
806 ret = rte_pdump_enable(pt->port, pt->queue,
807 RTE_PDUMP_FLAG_RX,
808 pt->rx_ring, pt->mp, NULL);
809 ret1 = rte_pdump_enable(pt->port, pt->queue,
810 RTE_PDUMP_FLAG_TX,
811 pt->tx_ring, pt->mp, NULL);
812 }
813 } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
814 if (pt->dump_by_type == DEVICE_ID)
815 ret = rte_pdump_enable_by_deviceid(
816 pt->device_id,
817 pt->queue,
818 pt->dir, pt->rx_ring,
819 pt->mp, NULL);
820 else if (pt->dump_by_type == PORT_ID)
821 ret = rte_pdump_enable(pt->port, pt->queue,
822 pt->dir,
823 pt->rx_ring, pt->mp, NULL);
824 } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
825 if (pt->dump_by_type == DEVICE_ID)
826 ret = rte_pdump_enable_by_deviceid(
827 pt->device_id,
828 pt->queue,
829 pt->dir,
830 pt->tx_ring, pt->mp, NULL);
831 else if (pt->dump_by_type == PORT_ID)
832 ret = rte_pdump_enable(pt->port, pt->queue,
833 pt->dir,
834 pt->tx_ring, pt->mp, NULL);
835 }
836 if (ret < 0 || ret1 < 0) {
837 cleanup_pdump_resources();
838 rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
839 }
840 }
841}
842
9f95a23c
TL
843static inline void
844pdump_packets(struct pdump_tuples *pt)
845{
846 if (pt->dir & RTE_PDUMP_FLAG_RX)
847 pdump_rxtx(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
848 if (pt->dir & RTE_PDUMP_FLAG_TX)
849 pdump_rxtx(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
850}
851
852static int
853dump_packets_core(void *arg)
854{
855 struct pdump_tuples *pt = (struct pdump_tuples *) arg;
856
857 printf(" core (%u); port %u device (%s) queue %u\n",
858 rte_lcore_id(), pt->port, pt->device_id, pt->queue);
859 fflush(stdout);
860
861 while (!quit_signal)
862 pdump_packets(pt);
863
864 return 0;
865}
866
7c673cae
FG
867static inline void
868dump_packets(void)
869{
870 int i;
9f95a23c
TL
871 uint32_t lcore_id = 0;
872
873 if (!multiple_core_capture) {
874 printf(" core (%u), capture for (%d) tuples\n",
875 rte_lcore_id(), num_tuples);
7c673cae 876
9f95a23c
TL
877 for (i = 0; i < num_tuples; i++)
878 printf(" - port %u device (%s) queue %u\n",
879 pdump_t[i].port,
880 pdump_t[i].device_id,
881 pdump_t[i].queue);
882
883 while (!quit_signal) {
884 for (i = 0; i < num_tuples; i++)
885 pdump_packets(&pdump_t[i]);
7c673cae 886 }
9f95a23c
TL
887
888 return;
7c673cae 889 }
9f95a23c
TL
890
891 /* check if there enough core */
892 if ((uint32_t)num_tuples >= rte_lcore_count()) {
893 printf("Insufficient cores to run parallel!\n");
894 return;
895 }
896
897 lcore_id = rte_get_next_lcore(lcore_id, 1, 0);
898
899 for (i = 0; i < num_tuples; i++) {
900 rte_eal_remote_launch(dump_packets_core,
901 &pdump_t[i], lcore_id);
902 lcore_id = rte_get_next_lcore(lcore_id, 1, 0);
903
904 if (rte_eal_wait_lcore(lcore_id) < 0)
905 rte_exit(EXIT_FAILURE, "failed to wait\n");
906 }
907
908 /* master core */
909 while (!quit_signal)
910 ;
7c673cae
FG
911}
912
913int
914main(int argc, char **argv)
915{
916 int diag;
917 int ret;
918 int i;
919
7c673cae
FG
920 char n_flag[] = "-n4";
921 char mp_flag[] = "--proc-type=secondary";
9f95a23c 922 char *argp[argc + 2];
7c673cae
FG
923
924 /* catch ctrl-c so we can print on exit */
925 signal(SIGINT, signal_handler);
926
927 argp[0] = argv[0];
9f95a23c
TL
928 argp[1] = n_flag;
929 argp[2] = mp_flag;
7c673cae
FG
930
931 for (i = 1; i < argc; i++)
9f95a23c 932 argp[i + 2] = argv[i];
7c673cae 933
9f95a23c 934 argc += 2;
7c673cae
FG
935
936 diag = rte_eal_init(argc, argp);
937 if (diag < 0)
938 rte_panic("Cannot init EAL\n");
939
11fdf7f2
TL
940 if (rte_eth_dev_count_avail() == 0)
941 rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
942
7c673cae 943 argc -= diag;
9f95a23c 944 argv += (diag - 2);
7c673cae
FG
945
946 /* parse app arguments */
947 if (argc > 1) {
948 ret = launch_args_parse(argc, argv, argp[0]);
949 if (ret < 0)
950 rte_exit(EXIT_FAILURE, "Invalid argument\n");
951 }
952
953 /* create mempool, ring and vdevs info */
954 create_mp_ring_vdev();
955 enable_pdump();
956 dump_packets();
957
958 cleanup_pdump_resources();
959 /* dump debug stats */
960 print_pdump_stats();
961
11fdf7f2
TL
962 ret = rte_eal_cleanup();
963 if (ret)
964 printf("Error from rte_eal_cleanup(), %d\n", ret);
965
7c673cae
FG
966 return 0;
967}