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