1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2016 Intel Corporation
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>
24 #include <rte_kvargs.h>
25 #include <rte_mempool.h>
27 #include <rte_string_fns.h>
28 #include <rte_pdump.h>
30 #define CMD_LINE_OPT_PDUMP "pdump"
31 #define PDUMP_PORT_ARG "port"
32 #define PDUMP_PCI_ARG "device_id"
33 #define PDUMP_QUEUE_ARG "queue"
34 #define PDUMP_DIR_ARG "dir"
35 #define PDUMP_RX_DEV_ARG "rx-dev"
36 #define PDUMP_TX_DEV_ARG "tx-dev"
37 #define PDUMP_RING_SIZE_ARG "ring-size"
38 #define PDUMP_MSIZE_ARG "mbuf-size"
39 #define PDUMP_NUM_MBUFS_ARG "total-num-mbufs"
40 #define CMD_LINE_OPT_SER_SOCK_PATH "server-socket-path"
41 #define CMD_LINE_OPT_CLI_SOCK_PATH "client-socket-path"
43 #define VDEV_PCAP "net_pcap_%s_%d,tx_pcap=%s"
44 #define VDEV_IFACE "net_pcap_%s_%d,tx_iface=%s"
45 #define TX_STREAM_SIZE 64
47 #define MP_NAME "pdump_pool_%d"
49 #define RX_RING "rx_ring_%d"
50 #define TX_RING "tx_ring_%d"
55 /* Maximum long option length for option parsing. */
56 #define APP_ARG_TCPDUMP_MAX_TUPLES 54
57 #define MBUF_POOL_CACHE_SIZE 250
58 #define TX_DESC_PER_QUEUE 512
59 #define RX_DESC_PER_QUEUE 128
60 #define MBUFS_PER_POOL 65535
61 #define MAX_LONG_OPT_SZ 64
62 #define RING_SIZE 16384
67 /* true if x is a power of 2 */
68 #define POWEROF2(x) ((((x)-1) & (x)) == 0)
85 const char *valid_pdump_arguments[] = {
99 uint64_t dequeue_pkts;
104 struct pdump_tuples {
109 char rx_dev[TX_STREAM_SIZE];
110 char tx_dev[TX_STREAM_SIZE];
112 uint16_t mbuf_data_size;
113 uint32_t total_num_mbufs;
115 /* params for library API call */
117 struct rte_mempool *mp;
118 struct rte_ring *rx_ring;
119 struct rte_ring *tx_ring;
121 /* params for packet dumping */
122 enum pdump_by dump_by_type;
125 enum pcap_stream rx_vdev_stream_type;
126 enum pcap_stream tx_vdev_stream_type;
127 bool single_pdump_dev;
130 struct pdump_stats stats;
131 } __rte_cache_aligned;
132 static struct pdump_tuples pdump_t[APP_ARG_TCPDUMP_MAX_TUPLES];
141 static struct rte_eth_conf port_conf_default;
142 volatile uint8_t quit_signal;
143 static char server_socket_path[PATH_MAX];
144 static char client_socket_path[PATH_MAX];
146 /**< display usage */
148 pdump_usage(const char *prgname)
150 printf("usage: %s [EAL options] -- --pdump "
151 "'(port=<port id> | device_id=<pci id or vdev name>),"
152 "(queue=<queue_id>),"
153 "(rx-dev=<iface or pcap file> |"
154 " tx-dev=<iface or pcap file>,"
155 "[ring-size=<ring size>default:16384],"
156 "[mbuf-size=<mbuf data size>default:2176],"
157 "[total-num-mbufs=<number of mbufs>default:65535]'\n"
158 "[--server-socket-path=<server socket dir>"
159 " which is deprecated and will be removed soon,"
160 " default:/var/run/.dpdk/ (or) ~/.dpdk/]\n"
161 "[--client-socket-path=<client socket dir>"
162 " which is deprecated and will be removed soon,"
163 " default:/var/run/.dpdk/ (or) ~/.dpdk/]\n",
168 parse_device_id(const char *key __rte_unused, const char *value,
171 struct pdump_tuples *pt = extra_args;
173 pt->device_id = strdup(value);
174 pt->dump_by_type = DEVICE_ID;
180 parse_queue(const char *key __rte_unused, const char *value, void *extra_args)
183 struct pdump_tuples *pt = extra_args;
185 if (!strcmp(value, "*"))
186 pt->queue = RTE_PDUMP_ALL_QUEUES;
188 n = strtoul(value, NULL, 10);
189 pt->queue = (uint16_t) n;
195 parse_rxtxdev(const char *key, const char *value, void *extra_args)
198 struct pdump_tuples *pt = extra_args;
200 if (!strcmp(key, PDUMP_RX_DEV_ARG)) {
201 snprintf(pt->rx_dev, sizeof(pt->rx_dev), "%s", value);
202 /* identify the tx stream type for pcap vdev */
203 if (if_nametoindex(pt->rx_dev))
204 pt->rx_vdev_stream_type = IFACE;
205 } else if (!strcmp(key, PDUMP_TX_DEV_ARG)) {
206 snprintf(pt->tx_dev, sizeof(pt->tx_dev), "%s", value);
207 /* identify the tx stream type for pcap vdev */
208 if (if_nametoindex(pt->tx_dev))
209 pt->tx_vdev_stream_type = IFACE;
216 parse_uint_value(const char *key, const char *value, void *extra_args)
225 t = strtoul(value, &end, 10);
227 if (errno != 0 || end[0] != 0 || t < v->min || t > v->max) {
228 printf("invalid value:\"%s\" for key:\"%s\", "
229 "value must be >= %"PRIu64" and <= %"PRIu64"\n",
230 value, key, v->min, v->max);
233 if (!strcmp(key, PDUMP_RING_SIZE_ARG) && !POWEROF2(t)) {
234 printf("invalid value:\"%s\" for key:\"%s\", "
235 "value must be power of 2\n", value, key);
247 parse_pdump(const char *optarg)
249 struct rte_kvargs *kvlist;
250 int ret = 0, cnt1, cnt2;
251 struct pdump_tuples *pt;
252 struct parse_val v = {0};
254 pt = &pdump_t[num_tuples];
256 /* initial check for invalid arguments */
257 kvlist = rte_kvargs_parse(optarg, valid_pdump_arguments);
258 if (kvlist == NULL) {
259 printf("--pdump=\"%s\": invalid argument passed\n", optarg);
263 /* port/device_id parsing and validation */
264 cnt1 = rte_kvargs_count(kvlist, PDUMP_PORT_ARG);
265 cnt2 = rte_kvargs_count(kvlist, PDUMP_PCI_ARG);
266 if (!((cnt1 == 1 && cnt2 == 0) || (cnt1 == 0 && cnt2 == 1))) {
267 printf("--pdump=\"%s\": must have either port or "
268 "device_id argument\n", optarg);
271 } else if (cnt1 == 1) {
273 v.max = RTE_MAX_ETHPORTS-1;
274 ret = rte_kvargs_process(kvlist, PDUMP_PORT_ARG,
275 &parse_uint_value, &v);
278 pt->port = (uint8_t) v.val;
279 pt->dump_by_type = PORT_ID;
280 } else if (cnt2 == 1) {
281 ret = rte_kvargs_process(kvlist, PDUMP_PCI_ARG,
282 &parse_device_id, pt);
287 /* queue parsing and validation */
288 cnt1 = rte_kvargs_count(kvlist, PDUMP_QUEUE_ARG);
290 printf("--pdump=\"%s\": must have queue argument\n", optarg);
294 ret = rte_kvargs_process(kvlist, PDUMP_QUEUE_ARG, &parse_queue, pt);
298 /* rx-dev and tx-dev parsing and validation */
299 cnt1 = rte_kvargs_count(kvlist, PDUMP_RX_DEV_ARG);
300 cnt2 = rte_kvargs_count(kvlist, PDUMP_TX_DEV_ARG);
301 if (cnt1 == 0 && cnt2 == 0) {
302 printf("--pdump=\"%s\": must have either rx-dev or "
303 "tx-dev argument\n", optarg);
306 } else if (cnt1 == 1 && cnt2 == 1) {
307 ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG,
311 ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG,
315 /* if captured packets has to send to the same vdev */
316 if (!strcmp(pt->rx_dev, pt->tx_dev))
317 pt->single_pdump_dev = true;
318 pt->dir = RTE_PDUMP_FLAG_RXTX;
319 } else if (cnt1 == 1) {
320 ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG,
324 pt->dir = RTE_PDUMP_FLAG_RX;
325 } else if (cnt2 == 1) {
326 ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG,
330 pt->dir = RTE_PDUMP_FLAG_TX;
334 /* ring_size parsing and validation */
335 cnt1 = rte_kvargs_count(kvlist, PDUMP_RING_SIZE_ARG);
338 v.max = RTE_RING_SZ_MASK-1;
339 ret = rte_kvargs_process(kvlist, PDUMP_RING_SIZE_ARG,
340 &parse_uint_value, &v);
343 pt->ring_size = (uint32_t) v.val;
345 pt->ring_size = RING_SIZE;
347 /* mbuf_data_size parsing and validation */
348 cnt1 = rte_kvargs_count(kvlist, PDUMP_MSIZE_ARG);
352 ret = rte_kvargs_process(kvlist, PDUMP_MSIZE_ARG,
353 &parse_uint_value, &v);
356 pt->mbuf_data_size = (uint16_t) v.val;
358 pt->mbuf_data_size = RTE_MBUF_DEFAULT_BUF_SIZE;
360 /* total_num_mbufs parsing and validation */
361 cnt1 = rte_kvargs_count(kvlist, PDUMP_NUM_MBUFS_ARG);
365 ret = rte_kvargs_process(kvlist, PDUMP_NUM_MBUFS_ARG,
366 &parse_uint_value, &v);
369 pt->total_num_mbufs = (uint16_t) v.val;
371 pt->total_num_mbufs = MBUFS_PER_POOL;
376 rte_kvargs_free(kvlist);
380 /* Parse the argument given in the command line of the application */
382 launch_args_parse(int argc, char **argv, char *prgname)
386 static struct option long_option[] = {
388 {"server-socket-path", 1, 0, 0},
389 {"client-socket-path", 1, 0, 0},
394 pdump_usage(prgname);
396 /* Parse command line */
397 while ((opt = getopt_long(argc, argv, " ",
398 long_option, &option_index)) != EOF) {
401 if (!strncmp(long_option[option_index].name,
403 sizeof(CMD_LINE_OPT_PDUMP))) {
404 ret = parse_pdump(optarg);
406 pdump_usage(prgname);
411 if (!strncmp(long_option[option_index].name,
412 CMD_LINE_OPT_SER_SOCK_PATH,
413 sizeof(CMD_LINE_OPT_SER_SOCK_PATH))) {
414 strlcpy(server_socket_path, optarg,
415 sizeof(server_socket_path));
418 if (!strncmp(long_option[option_index].name,
419 CMD_LINE_OPT_CLI_SOCK_PATH,
420 sizeof(CMD_LINE_OPT_CLI_SOCK_PATH))) {
421 strlcpy(client_socket_path, optarg,
422 sizeof(client_socket_path));
427 pdump_usage(prgname);
436 print_pdump_stats(void)
439 struct pdump_tuples *pt;
441 for (i = 0; i < num_tuples; i++) {
442 printf("##### PDUMP DEBUG STATS #####\n");
444 printf(" -packets dequeued: %"PRIu64"\n",
445 pt->stats.dequeue_pkts);
446 printf(" -packets transmitted to vdev: %"PRIu64"\n",
448 printf(" -packets freed: %"PRIu64"\n",
449 pt->stats.freed_pkts);
454 disable_pdump(struct pdump_tuples *pt)
456 if (pt->dump_by_type == DEVICE_ID)
457 rte_pdump_disable_by_deviceid(pt->device_id, pt->queue,
459 else if (pt->dump_by_type == PORT_ID)
460 rte_pdump_disable(pt->port, pt->queue, pt->dir);
464 pdump_rxtx(struct rte_ring *ring, uint8_t vdev_id, struct pdump_stats *stats)
466 /* write input packets of port to vdev for pdump */
467 struct rte_mbuf *rxtx_bufs[BURST_SIZE];
469 /* first dequeue packets from ring of primary process */
470 const uint16_t nb_in_deq = rte_ring_dequeue_burst(ring,
471 (void *)rxtx_bufs, BURST_SIZE, NULL);
472 stats->dequeue_pkts += nb_in_deq;
475 /* then sent on vdev */
476 uint16_t nb_in_txd = rte_eth_tx_burst(
478 0, rxtx_bufs, nb_in_deq);
479 stats->tx_pkts += nb_in_txd;
481 if (unlikely(nb_in_txd < nb_in_deq)) {
483 rte_pktmbuf_free(rxtx_bufs[nb_in_txd]);
485 } while (++nb_in_txd < nb_in_deq);
491 free_ring_data(struct rte_ring *ring, uint8_t vdev_id,
492 struct pdump_stats *stats)
494 while (rte_ring_count(ring))
495 pdump_rxtx(ring, vdev_id, stats);
502 struct pdump_tuples *pt;
504 for (i = 0; i < num_tuples; i++) {
512 rte_ring_free(pt->rx_ring);
514 rte_ring_free(pt->tx_ring);
519 cleanup_pdump_resources(void)
522 struct pdump_tuples *pt;
524 /* disable pdump and free the pdump_tuple resources */
525 for (i = 0; i < num_tuples; i++) {
528 /* remove callbacks */
532 * transmit rest of the enqueued packets of the rings on to
533 * the vdev, in order to release mbufs to the mepool.
535 if (pt->dir & RTE_PDUMP_FLAG_RX)
536 free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
537 if (pt->dir & RTE_PDUMP_FLAG_TX)
538 free_ring_data(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
544 signal_handler(int sig_num)
546 if (sig_num == SIGINT) {
547 printf("\n\nSignal %d received, preparing to exit...\n",
554 configure_vdev(uint16_t port_id)
556 struct ether_addr addr;
557 const uint16_t rxRings = 0, txRings = 1;
561 if (!rte_eth_dev_is_valid_port(port_id))
564 ret = rte_eth_dev_configure(port_id, rxRings, txRings,
567 rte_exit(EXIT_FAILURE, "dev config failed\n");
569 for (q = 0; q < txRings; q++) {
570 ret = rte_eth_tx_queue_setup(port_id, q, TX_DESC_PER_QUEUE,
571 rte_eth_dev_socket_id(port_id), NULL);
573 rte_exit(EXIT_FAILURE, "queue setup failed\n");
576 ret = rte_eth_dev_start(port_id);
578 rte_exit(EXIT_FAILURE, "dev start failed\n");
580 rte_eth_macaddr_get(port_id, &addr);
581 printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
582 " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
584 addr.addr_bytes[0], addr.addr_bytes[1],
585 addr.addr_bytes[2], addr.addr_bytes[3],
586 addr.addr_bytes[4], addr.addr_bytes[5]);
588 rte_eth_promiscuous_enable(port_id);
594 create_mp_ring_vdev(void)
598 struct pdump_tuples *pt = NULL;
599 struct rte_mempool *mbuf_pool = NULL;
600 char vdev_args[SIZE];
601 char ring_name[SIZE];
602 char mempool_name[SIZE];
604 for (i = 0; i < num_tuples; i++) {
606 snprintf(mempool_name, SIZE, MP_NAME, i);
607 mbuf_pool = rte_mempool_lookup(mempool_name);
608 if (mbuf_pool == NULL) {
610 mbuf_pool = rte_pktmbuf_pool_create(mempool_name,
612 MBUF_POOL_CACHE_SIZE, 0,
615 if (mbuf_pool == NULL) {
617 rte_exit(EXIT_FAILURE,
618 "Mempool creation failed: %s\n",
619 rte_strerror(rte_errno));
624 if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
625 /* if captured packets has to send to the same vdev */
627 snprintf(ring_name, SIZE, RX_RING, i);
628 pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
630 if (pt->rx_ring == NULL) {
632 rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
633 rte_strerror(rte_errno),
638 snprintf(ring_name, SIZE, TX_RING, i);
639 pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
641 if (pt->tx_ring == NULL) {
643 rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
644 rte_strerror(rte_errno),
649 (pt->rx_vdev_stream_type == IFACE) ?
650 snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i,
652 snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i,
654 if (rte_eth_dev_attach(vdev_args, &portid) < 0) {
656 rte_exit(EXIT_FAILURE,
657 "vdev creation failed:%s:%d\n",
660 pt->rx_vdev_id = portid;
663 configure_vdev(pt->rx_vdev_id);
665 if (pt->single_pdump_dev)
666 pt->tx_vdev_id = portid;
668 (pt->tx_vdev_stream_type == IFACE) ?
669 snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i,
671 snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i,
673 if (rte_eth_dev_attach(vdev_args,
676 rte_exit(EXIT_FAILURE,
677 "vdev creation failed:"
678 "%s:%d\n", __func__, __LINE__);
680 pt->tx_vdev_id = portid;
683 configure_vdev(pt->tx_vdev_id);
685 } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
688 snprintf(ring_name, SIZE, RX_RING, i);
689 pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
691 if (pt->rx_ring == NULL) {
693 rte_exit(EXIT_FAILURE, "%s\n",
694 rte_strerror(rte_errno));
697 (pt->rx_vdev_stream_type == IFACE) ?
698 snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i,
700 snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i,
702 if (rte_eth_dev_attach(vdev_args, &portid) < 0) {
704 rte_exit(EXIT_FAILURE,
705 "vdev creation failed:%s:%d\n",
708 pt->rx_vdev_id = portid;
710 configure_vdev(pt->rx_vdev_id);
711 } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
714 snprintf(ring_name, SIZE, TX_RING, i);
715 pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
717 if (pt->tx_ring == NULL) {
719 rte_exit(EXIT_FAILURE, "%s\n",
720 rte_strerror(rte_errno));
723 (pt->tx_vdev_stream_type == IFACE) ?
724 snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i,
726 snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i,
728 if (rte_eth_dev_attach(vdev_args, &portid) < 0) {
730 rte_exit(EXIT_FAILURE,
731 "vdev creation failed\n");
733 pt->tx_vdev_id = portid;
736 configure_vdev(pt->tx_vdev_id);
745 struct pdump_tuples *pt;
746 int ret = 0, ret1 = 0;
748 for (i = 0; i < num_tuples; i++) {
750 if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
751 if (pt->dump_by_type == DEVICE_ID) {
752 ret = rte_pdump_enable_by_deviceid(
758 ret1 = rte_pdump_enable_by_deviceid(
764 } else if (pt->dump_by_type == PORT_ID) {
765 ret = rte_pdump_enable(pt->port, pt->queue,
767 pt->rx_ring, pt->mp, NULL);
768 ret1 = rte_pdump_enable(pt->port, pt->queue,
770 pt->tx_ring, pt->mp, NULL);
772 } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
773 if (pt->dump_by_type == DEVICE_ID)
774 ret = rte_pdump_enable_by_deviceid(
777 pt->dir, pt->rx_ring,
779 else if (pt->dump_by_type == PORT_ID)
780 ret = rte_pdump_enable(pt->port, pt->queue,
782 pt->rx_ring, pt->mp, NULL);
783 } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
784 if (pt->dump_by_type == DEVICE_ID)
785 ret = rte_pdump_enable_by_deviceid(
789 pt->tx_ring, pt->mp, NULL);
790 else if (pt->dump_by_type == PORT_ID)
791 ret = rte_pdump_enable(pt->port, pt->queue,
793 pt->tx_ring, pt->mp, NULL);
795 if (ret < 0 || ret1 < 0) {
796 cleanup_pdump_resources();
797 rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
806 struct pdump_tuples *pt;
808 while (!quit_signal) {
809 for (i = 0; i < num_tuples; i++) {
811 if (pt->dir & RTE_PDUMP_FLAG_RX)
812 pdump_rxtx(pt->rx_ring, pt->rx_vdev_id,
814 if (pt->dir & RTE_PDUMP_FLAG_TX)
815 pdump_rxtx(pt->tx_ring, pt->tx_vdev_id,
822 main(int argc, char **argv)
828 char c_flag[] = "-c1";
829 char n_flag[] = "-n4";
830 char mp_flag[] = "--proc-type=secondary";
831 char *argp[argc + 3];
833 /* catch ctrl-c so we can print on exit */
834 signal(SIGINT, signal_handler);
841 for (i = 1; i < argc; i++)
842 argp[i + 3] = argv[i];
846 diag = rte_eal_init(argc, argp);
848 rte_panic("Cannot init EAL\n");
850 if (rte_eth_dev_count_avail() == 0)
851 rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
856 /* parse app arguments */
858 ret = launch_args_parse(argc, argv, argp[0]);
860 rte_exit(EXIT_FAILURE, "Invalid argument\n");
863 /* create mempool, ring and vdevs info */
864 create_mp_ring_vdev();
868 cleanup_pdump_resources();
869 /* dump debug stats */
872 ret = rte_eal_cleanup();
874 printf("Error from rte_eal_cleanup(), %d\n", ret);