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 } 906