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