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