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