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