xref: /dpdk/app/pdump/main.c (revision 200bc52e5aa0d72e70464c9cd22b55cf536ed13c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016 Intel Corporation
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>
27 #include <rte_string_fns.h>
28 #include <rte_pdump.h>
29 
30 #define CMD_LINE_OPT_PDUMP "pdump"
31 #define CMD_LINE_OPT_PDUMP_NUM 256
32 #define CMD_LINE_OPT_MULTI "multi"
33 #define CMD_LINE_OPT_MULTI_NUM 257
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"
43 
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"
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 
69 /* true if x is a power of 2 */
70 #define POWEROF2(x) ((((x)-1) & (x)) == 0)
71 
72 enum pdump_en_dis {
73 	DISABLE = 1,
74 	ENABLE = 2
75 };
76 
77 enum pcap_stream {
78 	IFACE = 1,
79 	PCAP = 2
80 };
81 
82 enum pdump_by {
83 	PORT_ID = 1,
84 	DEVICE_ID = 2
85 };
86 
87 static const char * const valid_pdump_arguments[] = {
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 
100 struct pdump_stats {
101 	uint64_t dequeue_pkts;
102 	uint64_t tx_pkts;
103 	uint64_t freed_pkts;
104 };
105 
106 struct pdump_tuples {
107 	/* cli params */
108 	uint16_t port;
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;
125 	uint16_t rx_vdev_id;
126 	uint16_t tx_vdev_id;
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;
134 static struct pdump_tuples pdump_t[APP_ARG_TCPDUMP_MAX_TUPLES];
135 
136 struct parse_val {
137 	uint64_t min;
138 	uint64_t max;
139 	uint64_t val;
140 };
141 
142 static int num_tuples;
143 static struct rte_eth_conf port_conf_default;
144 static volatile uint8_t quit_signal;
145 static uint8_t multiple_core_capture;
146 
147 /**< display usage */
148 static void
149 pdump_usage(const char *prgname)
150 {
151 	printf("usage: %s [EAL options]"
152 			" --["CMD_LINE_OPT_MULTI"]\n"
153 			" --"CMD_LINE_OPT_PDUMP" "
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],"
160 			"[total-num-mbufs=<number of mbufs>default:65535]'\n",
161 			prgname);
162 }
163 
164 static int
165 parse_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 
176 static int
177 parse_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 
191 static int
192 parse_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)) {
198 		strlcpy(pt->rx_dev, value, sizeof(pt->rx_dev));
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)) {
203 		strlcpy(pt->tx_dev, value, sizeof(pt->tx_dev));
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 
212 static int
213 parse_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 
243 static int
244 parse_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;
275 		pt->port = (uint16_t) v.val;
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 
372 free_kvlist:
373 	rte_kvargs_free(kvlist);
374 	return ret;
375 }
376 
377 /* Parse the argument given in the command line of the application */
378 static int
379 launch_args_parse(int argc, char **argv, char *prgname)
380 {
381 	int opt, ret;
382 	int option_index;
383 	static struct option long_option[] = {
384 		{CMD_LINE_OPT_PDUMP, 1, 0, CMD_LINE_OPT_PDUMP_NUM},
385 		{CMD_LINE_OPT_MULTI, 0, 0, CMD_LINE_OPT_MULTI_NUM},
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) {
396 		case CMD_LINE_OPT_PDUMP_NUM:
397 			ret = parse_pdump(optarg);
398 			if (ret) {
399 				pdump_usage(prgname);
400 				return -1;
401 			}
402 			break;
403 		case CMD_LINE_OPT_MULTI_NUM:
404 			multiple_core_capture = 1;
405 			break;
406 		default:
407 			pdump_usage(prgname);
408 			return -1;
409 		}
410 	}
411 
412 	return 0;
413 }
414 
415 static void
416 print_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 
433 static inline void
434 disable_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 
443 static inline void
444 pdump_rxtx(struct rte_ring *ring, uint16_t vdev_id, struct pdump_stats *stats)
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,
451 			(void *)rxtx_bufs, BURST_SIZE, NULL);
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 
470 static void
471 free_ring_data(struct rte_ring *ring, uint16_t vdev_id,
472 		struct pdump_stats *stats)
473 {
474 	while (rte_ring_count(ring))
475 		pdump_rxtx(ring, vdev_id, stats);
476 }
477 
478 static void
479 cleanup_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 
498 static void
499 cleanup_pdump_resources(void)
500 {
501 	int i;
502 	struct pdump_tuples *pt;
503 	char name[RTE_ETH_NAME_MAX_LEN];
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);
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 
535 	}
536 	cleanup_rings();
537 }
538 
539 static void
540 signal_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 
549 static inline int
550 configure_vdev(uint16_t port_id)
551 {
552 	struct rte_ether_addr addr;
553 	const uint16_t rxRings = 0, txRings = 1;
554 	int ret;
555 	uint16_t q;
556 
557 	if (!rte_eth_dev_is_valid_port(port_id))
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",
579 			port_id,
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 
589 static void
590 create_mp_ring_vdev(void)
591 {
592 	int i;
593 	uint16_t portid;
594 	struct pdump_tuples *pt = NULL;
595 	struct rte_mempool *mbuf_pool = NULL;
596 	char vdev_name[SIZE];
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 */
646 			snprintf(vdev_name, sizeof(vdev_name),
647 				 VDEV_NAME_FMT, RX_STR, i);
648 			(pt->rx_vdev_stream_type == IFACE) ?
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) {
655 				cleanup_rings();
656 				rte_exit(EXIT_FAILURE,
657 					"vdev creation failed:%s:%d\n",
658 					__func__, __LINE__);
659 			}
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 			}
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 {
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) {
685 					cleanup_rings();
686 					rte_exit(EXIT_FAILURE,
687 						"vdev creation failed:"
688 						"%s:%d\n", __func__, __LINE__);
689 				}
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 				}
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 
716 			snprintf(vdev_name, sizeof(vdev_name),
717 				 VDEV_NAME_FMT, RX_STR, i);
718 			(pt->rx_vdev_stream_type == IFACE) ?
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) {
725 				cleanup_rings();
726 				rte_exit(EXIT_FAILURE,
727 					"vdev creation failed:%s:%d\n",
728 					__func__, __LINE__);
729 			}
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 			}
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 
753 			snprintf(vdev_name, sizeof(vdev_name),
754 				 VDEV_NAME_FMT, TX_STR, i);
755 			(pt->tx_vdev_stream_type == IFACE) ?
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) {
762 				cleanup_rings();
763 				rte_exit(EXIT_FAILURE,
764 					"vdev creation failed\n");
765 			}
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 			}
774 			pt->tx_vdev_id = portid;
775 
776 			/* configure vdev */
777 			configure_vdev(pt->tx_vdev_id);
778 		}
779 	}
780 }
781 
782 static void
783 enable_pdump(void)
784 {
785 	int i;
786 	struct pdump_tuples *pt;
787 	int ret = 0, ret1 = 0;
788 
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 
843 static inline void
844 pdump_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 
852 static int
853 dump_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 
867 static inline void
868 dump_packets(void)
869 {
870 	int i;
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);
876 
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]);
886 		}
887 
888 		return;
889 	}
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 		;
911 }
912 
913 int
914 main(int argc, char **argv)
915 {
916 	int diag;
917 	int ret;
918 	int i;
919 
920 	char n_flag[] = "-n4";
921 	char mp_flag[] = "--proc-type=secondary";
922 	char *argp[argc + 2];
923 
924 	/* catch ctrl-c so we can print on exit */
925 	signal(SIGINT, signal_handler);
926 
927 	argp[0] = argv[0];
928 	argp[1] = n_flag;
929 	argp[2] = mp_flag;
930 
931 	for (i = 1; i < argc; i++)
932 		argp[i + 2] = argv[i];
933 
934 	argc += 2;
935 
936 	diag = rte_eal_init(argc, argp);
937 	if (diag < 0)
938 		rte_panic("Cannot init EAL\n");
939 
940 	if (rte_eth_dev_count_avail() == 0)
941 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
942 
943 	argc -= diag;
944 	argv += (diag - 2);
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 
962 	ret = rte_eal_cleanup();
963 	if (ret)
964 		printf("Error from rte_eal_cleanup(), %d\n", ret);
965 
966 	return 0;
967 }
968