New upstream version 18.11-rc1
[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         int rx_vdev_id;
123         int 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 = (uint8_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, uint8_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, uint8_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
498         /* disable pdump and free the pdump_tuple resources */
499         for (i = 0; i < num_tuples; i++) {
500                 pt = &pdump_t[i];
501
502                 /* remove callbacks */
503                 disable_pdump(pt);
504
505                 /*
506                 * transmit rest of the enqueued packets of the rings on to
507                 * the vdev, in order to release mbufs to the mepool.
508                 **/
509                 if (pt->dir & RTE_PDUMP_FLAG_RX)
510                         free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
511                 if (pt->dir & RTE_PDUMP_FLAG_TX)
512                         free_ring_data(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
513         }
514         cleanup_rings();
515 }
516
517 static void
518 signal_handler(int sig_num)
519 {
520         if (sig_num == SIGINT) {
521                 printf("\n\nSignal %d received, preparing to exit...\n",
522                                 sig_num);
523                 quit_signal = 1;
524         }
525 }
526
527 static inline int
528 configure_vdev(uint16_t port_id)
529 {
530         struct ether_addr addr;
531         const uint16_t rxRings = 0, txRings = 1;
532         int ret;
533         uint16_t q;
534
535         if (!rte_eth_dev_is_valid_port(port_id))
536                 return -1;
537
538         ret = rte_eth_dev_configure(port_id, rxRings, txRings,
539                                         &port_conf_default);
540         if (ret != 0)
541                 rte_exit(EXIT_FAILURE, "dev config failed\n");
542
543          for (q = 0; q < txRings; q++) {
544                 ret = rte_eth_tx_queue_setup(port_id, q, TX_DESC_PER_QUEUE,
545                                 rte_eth_dev_socket_id(port_id), NULL);
546                 if (ret < 0)
547                         rte_exit(EXIT_FAILURE, "queue setup failed\n");
548         }
549
550         ret = rte_eth_dev_start(port_id);
551         if (ret < 0)
552                 rte_exit(EXIT_FAILURE, "dev start failed\n");
553
554         rte_eth_macaddr_get(port_id, &addr);
555         printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
556                         " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
557                         port_id,
558                         addr.addr_bytes[0], addr.addr_bytes[1],
559                         addr.addr_bytes[2], addr.addr_bytes[3],
560                         addr.addr_bytes[4], addr.addr_bytes[5]);
561
562         rte_eth_promiscuous_enable(port_id);
563
564         return 0;
565 }
566
567 static void
568 create_mp_ring_vdev(void)
569 {
570         int i;
571         uint16_t portid;
572         struct pdump_tuples *pt = NULL;
573         struct rte_mempool *mbuf_pool = NULL;
574         char vdev_name[SIZE];
575         char vdev_args[SIZE];
576         char ring_name[SIZE];
577         char mempool_name[SIZE];
578
579         for (i = 0; i < num_tuples; i++) {
580                 pt = &pdump_t[i];
581                 snprintf(mempool_name, SIZE, MP_NAME, i);
582                 mbuf_pool = rte_mempool_lookup(mempool_name);
583                 if (mbuf_pool == NULL) {
584                         /* create mempool */
585                         mbuf_pool = rte_pktmbuf_pool_create(mempool_name,
586                                         pt->total_num_mbufs,
587                                         MBUF_POOL_CACHE_SIZE, 0,
588                                         pt->mbuf_data_size,
589                                         rte_socket_id());
590                         if (mbuf_pool == NULL) {
591                                 cleanup_rings();
592                                 rte_exit(EXIT_FAILURE,
593                                         "Mempool creation failed: %s\n",
594                                         rte_strerror(rte_errno));
595                         }
596                 }
597                 pt->mp = mbuf_pool;
598
599                 if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
600                         /* if captured packets has to send to the same vdev */
601                         /* create rx_ring */
602                         snprintf(ring_name, SIZE, RX_RING, i);
603                         pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
604                                         rte_socket_id(), 0);
605                         if (pt->rx_ring == NULL) {
606                                 cleanup_rings();
607                                 rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
608                                                 rte_strerror(rte_errno),
609                                                 __func__, __LINE__);
610                         }
611
612                         /* create tx_ring */
613                         snprintf(ring_name, SIZE, TX_RING, i);
614                         pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
615                                         rte_socket_id(), 0);
616                         if (pt->tx_ring == NULL) {
617                                 cleanup_rings();
618                                 rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
619                                                 rte_strerror(rte_errno),
620                                                 __func__, __LINE__);
621                         }
622
623                         /* create vdevs */
624                         snprintf(vdev_name, sizeof(vdev_name),
625                                  VDEV_NAME_FMT, RX_STR, i);
626                         (pt->rx_vdev_stream_type == IFACE) ?
627                         snprintf(vdev_args, sizeof(vdev_args),
628                                  VDEV_IFACE_ARGS_FMT, pt->rx_dev) :
629                         snprintf(vdev_args, sizeof(vdev_args),
630                                  VDEV_PCAP_ARGS_FMT, pt->rx_dev);
631                         if (rte_eal_hotplug_add("vdev", vdev_name,
632                                                 vdev_args) < 0) {
633                                 cleanup_rings();
634                                 rte_exit(EXIT_FAILURE,
635                                         "vdev creation failed:%s:%d\n",
636                                         __func__, __LINE__);
637                         }
638                         if (rte_eth_dev_get_port_by_name(vdev_name,
639                                                          &portid) != 0) {
640                                 rte_eal_hotplug_remove("vdev", vdev_name);
641                                 cleanup_rings();
642                                 rte_exit(EXIT_FAILURE,
643                                         "cannot find added vdev %s:%s:%d\n",
644                                         vdev_name, __func__, __LINE__);
645                         }
646                         pt->rx_vdev_id = portid;
647
648                         /* configure vdev */
649                         configure_vdev(pt->rx_vdev_id);
650
651                         if (pt->single_pdump_dev)
652                                 pt->tx_vdev_id = portid;
653                         else {
654                                 snprintf(vdev_name, sizeof(vdev_name),
655                                          VDEV_NAME_FMT, TX_STR, i);
656                                 (pt->rx_vdev_stream_type == IFACE) ?
657                                 snprintf(vdev_args, sizeof(vdev_args),
658                                          VDEV_IFACE_ARGS_FMT, pt->tx_dev) :
659                                 snprintf(vdev_args, sizeof(vdev_args),
660                                          VDEV_PCAP_ARGS_FMT, pt->tx_dev);
661                                 if (rte_eal_hotplug_add("vdev", vdev_name,
662                                                         vdev_args) < 0) {
663                                         cleanup_rings();
664                                         rte_exit(EXIT_FAILURE,
665                                                 "vdev creation failed:"
666                                                 "%s:%d\n", __func__, __LINE__);
667                                 }
668                                 if (rte_eth_dev_get_port_by_name(vdev_name,
669                                                 &portid) != 0) {
670                                         rte_eal_hotplug_remove("vdev",
671                                                                vdev_name);
672                                         cleanup_rings();
673                                         rte_exit(EXIT_FAILURE,
674                                                 "cannot find added vdev %s:%s:%d\n",
675                                                 vdev_name, __func__, __LINE__);
676                                 }
677                                 pt->tx_vdev_id = portid;
678
679                                 /* configure vdev */
680                                 configure_vdev(pt->tx_vdev_id);
681                         }
682                 } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
683
684                         /* create rx_ring */
685                         snprintf(ring_name, SIZE, RX_RING, i);
686                         pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
687                                         rte_socket_id(), 0);
688                         if (pt->rx_ring == NULL) {
689                                 cleanup_rings();
690                                 rte_exit(EXIT_FAILURE, "%s\n",
691                                         rte_strerror(rte_errno));
692                         }
693
694                         snprintf(vdev_name, sizeof(vdev_name),
695                                  VDEV_NAME_FMT, RX_STR, i);
696                         (pt->rx_vdev_stream_type == IFACE) ?
697                         snprintf(vdev_args, sizeof(vdev_args),
698                                  VDEV_IFACE_ARGS_FMT, pt->rx_dev) :
699                         snprintf(vdev_args, sizeof(vdev_args),
700                                  VDEV_PCAP_ARGS_FMT, pt->rx_dev);
701                         if (rte_eal_hotplug_add("vdev", vdev_name,
702                                                 vdev_args) < 0) {
703                                 cleanup_rings();
704                                 rte_exit(EXIT_FAILURE,
705                                         "vdev creation failed:%s:%d\n",
706                                         __func__, __LINE__);
707                         }
708                         if (rte_eth_dev_get_port_by_name(vdev_name,
709                                                          &portid) != 0) {
710                                 rte_eal_hotplug_remove("vdev", vdev_name);
711                                 cleanup_rings();
712                                 rte_exit(EXIT_FAILURE,
713                                         "cannot find added vdev %s:%s:%d\n",
714                                         vdev_name, __func__, __LINE__);
715                         }
716                         pt->rx_vdev_id = portid;
717                         /* configure vdev */
718                         configure_vdev(pt->rx_vdev_id);
719                 } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
720
721                         /* create tx_ring */
722                         snprintf(ring_name, SIZE, TX_RING, i);
723                         pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
724                                         rte_socket_id(), 0);
725                         if (pt->tx_ring == NULL) {
726                                 cleanup_rings();
727                                 rte_exit(EXIT_FAILURE, "%s\n",
728                                         rte_strerror(rte_errno));
729                         }
730
731                         snprintf(vdev_name, sizeof(vdev_name),
732                                  VDEV_NAME_FMT, TX_STR, i);
733                         (pt->tx_vdev_stream_type == IFACE) ?
734                         snprintf(vdev_args, sizeof(vdev_args),
735                                  VDEV_IFACE_ARGS_FMT, pt->tx_dev) :
736                         snprintf(vdev_args, sizeof(vdev_args),
737                                  VDEV_PCAP_ARGS_FMT, pt->tx_dev);
738                         if (rte_eal_hotplug_add("vdev", vdev_name,
739                                                 vdev_args) < 0) {
740                                 cleanup_rings();
741                                 rte_exit(EXIT_FAILURE,
742                                         "vdev creation failed\n");
743                         }
744                         if (rte_eth_dev_get_port_by_name(vdev_name,
745                                                          &portid) != 0) {
746                                 rte_eal_hotplug_remove("vdev", vdev_name);
747                                 cleanup_rings();
748                                 rte_exit(EXIT_FAILURE,
749                                         "cannot find added vdev %s:%s:%d\n",
750                                         vdev_name, __func__, __LINE__);
751                         }
752                         pt->tx_vdev_id = portid;
753
754                         /* configure vdev */
755                         configure_vdev(pt->tx_vdev_id);
756                 }
757         }
758 }
759
760 static void
761 enable_pdump(void)
762 {
763         int i;
764         struct pdump_tuples *pt;
765         int ret = 0, ret1 = 0;
766
767         for (i = 0; i < num_tuples; i++) {
768                 pt = &pdump_t[i];
769                 if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
770                         if (pt->dump_by_type == DEVICE_ID) {
771                                 ret = rte_pdump_enable_by_deviceid(
772                                                 pt->device_id,
773                                                 pt->queue,
774                                                 RTE_PDUMP_FLAG_RX,
775                                                 pt->rx_ring,
776                                                 pt->mp, NULL);
777                                 ret1 = rte_pdump_enable_by_deviceid(
778                                                 pt->device_id,
779                                                 pt->queue,
780                                                 RTE_PDUMP_FLAG_TX,
781                                                 pt->tx_ring,
782                                                 pt->mp, NULL);
783                         } else if (pt->dump_by_type == PORT_ID) {
784                                 ret = rte_pdump_enable(pt->port, pt->queue,
785                                                 RTE_PDUMP_FLAG_RX,
786                                                 pt->rx_ring, pt->mp, NULL);
787                                 ret1 = rte_pdump_enable(pt->port, pt->queue,
788                                                 RTE_PDUMP_FLAG_TX,
789                                                 pt->tx_ring, pt->mp, NULL);
790                         }
791                 } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
792                         if (pt->dump_by_type == DEVICE_ID)
793                                 ret = rte_pdump_enable_by_deviceid(
794                                                 pt->device_id,
795                                                 pt->queue,
796                                                 pt->dir, pt->rx_ring,
797                                                 pt->mp, NULL);
798                         else if (pt->dump_by_type == PORT_ID)
799                                 ret = rte_pdump_enable(pt->port, pt->queue,
800                                                 pt->dir,
801                                                 pt->rx_ring, pt->mp, NULL);
802                 } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
803                         if (pt->dump_by_type == DEVICE_ID)
804                                 ret = rte_pdump_enable_by_deviceid(
805                                                 pt->device_id,
806                                                 pt->queue,
807                                                 pt->dir,
808                                                 pt->tx_ring, pt->mp, NULL);
809                         else if (pt->dump_by_type == PORT_ID)
810                                 ret = rte_pdump_enable(pt->port, pt->queue,
811                                                 pt->dir,
812                                                 pt->tx_ring, pt->mp, NULL);
813                 }
814                 if (ret < 0 || ret1 < 0) {
815                         cleanup_pdump_resources();
816                         rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
817                 }
818         }
819 }
820
821 static inline void
822 dump_packets(void)
823 {
824         int i;
825         struct pdump_tuples *pt;
826
827         while (!quit_signal) {
828                 for (i = 0; i < num_tuples; i++) {
829                         pt = &pdump_t[i];
830                         if (pt->dir & RTE_PDUMP_FLAG_RX)
831                                 pdump_rxtx(pt->rx_ring, pt->rx_vdev_id,
832                                         &pt->stats);
833                         if (pt->dir & RTE_PDUMP_FLAG_TX)
834                                 pdump_rxtx(pt->tx_ring, pt->tx_vdev_id,
835                                         &pt->stats);
836                 }
837         }
838 }
839
840 int
841 main(int argc, char **argv)
842 {
843         int diag;
844         int ret;
845         int i;
846
847         char c_flag[] = "-c1";
848         char n_flag[] = "-n4";
849         char mp_flag[] = "--proc-type=secondary";
850         char *argp[argc + 3];
851
852         /* catch ctrl-c so we can print on exit */
853         signal(SIGINT, signal_handler);
854
855         argp[0] = argv[0];
856         argp[1] = c_flag;
857         argp[2] = n_flag;
858         argp[3] = mp_flag;
859
860         for (i = 1; i < argc; i++)
861                 argp[i + 3] = argv[i];
862
863         argc += 3;
864
865         diag = rte_eal_init(argc, argp);
866         if (diag < 0)
867                 rte_panic("Cannot init EAL\n");
868
869         if (rte_eth_dev_count_avail() == 0)
870                 rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
871
872         argc -= diag;
873         argv += (diag - 3);
874
875         /* parse app arguments */
876         if (argc > 1) {
877                 ret = launch_args_parse(argc, argv, argp[0]);
878                 if (ret < 0)
879                         rte_exit(EXIT_FAILURE, "Invalid argument\n");
880         }
881
882         /* create mempool, ring and vdevs info */
883         create_mp_ring_vdev();
884         enable_pdump();
885         dump_packets();
886
887         cleanup_pdump_resources();
888         /* dump debug stats */
889         print_pdump_stats();
890
891         ret = rte_eal_cleanup();
892         if (ret)
893                 printf("Error from rte_eal_cleanup(), %d\n", ret);
894
895         return 0;
896 }