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_pdump.h> 28 29 #define CMD_LINE_OPT_PDUMP "pdump" 30 #define PDUMP_PORT_ARG "port" 31 #define PDUMP_PCI_ARG "device_id" 32 #define PDUMP_QUEUE_ARG "queue" 33 #define PDUMP_DIR_ARG "dir" 34 #define PDUMP_RX_DEV_ARG "rx-dev" 35 #define PDUMP_TX_DEV_ARG "tx-dev" 36 #define PDUMP_RING_SIZE_ARG "ring-size" 37 #define PDUMP_MSIZE_ARG "mbuf-size" 38 #define PDUMP_NUM_MBUFS_ARG "total-num-mbufs" 39 #define CMD_LINE_OPT_SER_SOCK_PATH "server-socket-path" 40 #define CMD_LINE_OPT_CLI_SOCK_PATH "client-socket-path" 41 42 #define VDEV_PCAP "net_pcap_%s_%d,tx_pcap=%s" 43 #define VDEV_IFACE "net_pcap_%s_%d,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 const char *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 int rx_vdev_id; 123 int 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 int num_tuples; 140 static struct rte_eth_conf port_conf_default; 141 volatile uint8_t quit_signal; 142 static char server_socket_path[PATH_MAX]; 143 static char client_socket_path[PATH_MAX]; 144 145 /**< display usage */ 146 static void 147 pdump_usage(const char *prgname) 148 { 149 printf("usage: %s [EAL options] -- --pdump " 150 "'(port=<port id> | device_id=<pci id or vdev name>)," 151 "(queue=<queue_id>)," 152 "(rx-dev=<iface or pcap file> |" 153 " tx-dev=<iface or pcap file>," 154 "[ring-size=<ring size>default:16384]," 155 "[mbuf-size=<mbuf data size>default:2176]," 156 "[total-num-mbufs=<number of mbufs>default:65535]'\n" 157 "[--server-socket-path=<server socket dir>" 158 "default:/var/run/.dpdk/ (or) ~/.dpdk/]\n" 159 "[--client-socket-path=<client socket dir>" 160 "default:/var/run/.dpdk/ (or) ~/.dpdk/]\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 snprintf(pt->rx_dev, sizeof(pt->rx_dev), "%s", value); 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 snprintf(pt->tx_dev, sizeof(pt->tx_dev), "%s", value); 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 = (uint8_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 {"pdump", 1, 0, 0}, 385 {"server-socket-path", 1, 0, 0}, 386 {"client-socket-path", 1, 0, 0}, 387 {NULL, 0, 0, 0} 388 }; 389 390 if (argc == 1) 391 pdump_usage(prgname); 392 393 /* Parse command line */ 394 while ((opt = getopt_long(argc, argv, " ", 395 long_option, &option_index)) != EOF) { 396 switch (opt) { 397 case 0: 398 if (!strncmp(long_option[option_index].name, 399 CMD_LINE_OPT_PDUMP, 400 sizeof(CMD_LINE_OPT_PDUMP))) { 401 ret = parse_pdump(optarg); 402 if (ret) { 403 pdump_usage(prgname); 404 return -1; 405 } 406 } 407 408 if (!strncmp(long_option[option_index].name, 409 CMD_LINE_OPT_SER_SOCK_PATH, 410 sizeof(CMD_LINE_OPT_SER_SOCK_PATH))) { 411 snprintf(server_socket_path, 412 sizeof(server_socket_path), "%s", 413 optarg); 414 } 415 416 if (!strncmp(long_option[option_index].name, 417 CMD_LINE_OPT_CLI_SOCK_PATH, 418 sizeof(CMD_LINE_OPT_CLI_SOCK_PATH))) { 419 snprintf(client_socket_path, 420 sizeof(client_socket_path), "%s", 421 optarg); 422 } 423 424 break; 425 default: 426 pdump_usage(prgname); 427 return -1; 428 } 429 } 430 431 return 0; 432 } 433 434 static void 435 print_pdump_stats(void) 436 { 437 int i; 438 struct pdump_tuples *pt; 439 440 for (i = 0; i < num_tuples; i++) { 441 printf("##### PDUMP DEBUG STATS #####\n"); 442 pt = &pdump_t[i]; 443 printf(" -packets dequeued: %"PRIu64"\n", 444 pt->stats.dequeue_pkts); 445 printf(" -packets transmitted to vdev: %"PRIu64"\n", 446 pt->stats.tx_pkts); 447 printf(" -packets freed: %"PRIu64"\n", 448 pt->stats.freed_pkts); 449 } 450 } 451 452 static inline void 453 disable_pdump(struct pdump_tuples *pt) 454 { 455 if (pt->dump_by_type == DEVICE_ID) 456 rte_pdump_disable_by_deviceid(pt->device_id, pt->queue, 457 pt->dir); 458 else if (pt->dump_by_type == PORT_ID) 459 rte_pdump_disable(pt->port, pt->queue, pt->dir); 460 } 461 462 static inline void 463 pdump_rxtx(struct rte_ring *ring, uint8_t vdev_id, struct pdump_stats *stats) 464 { 465 /* write input packets of port to vdev for pdump */ 466 struct rte_mbuf *rxtx_bufs[BURST_SIZE]; 467 468 /* first dequeue packets from ring of primary process */ 469 const uint16_t nb_in_deq = rte_ring_dequeue_burst(ring, 470 (void *)rxtx_bufs, BURST_SIZE, NULL); 471 stats->dequeue_pkts += nb_in_deq; 472 473 if (nb_in_deq) { 474 /* then sent on vdev */ 475 uint16_t nb_in_txd = rte_eth_tx_burst( 476 vdev_id, 477 0, rxtx_bufs, nb_in_deq); 478 stats->tx_pkts += nb_in_txd; 479 480 if (unlikely(nb_in_txd < nb_in_deq)) { 481 do { 482 rte_pktmbuf_free(rxtx_bufs[nb_in_txd]); 483 stats->freed_pkts++; 484 } while (++nb_in_txd < nb_in_deq); 485 } 486 } 487 } 488 489 static void 490 free_ring_data(struct rte_ring *ring, uint8_t vdev_id, 491 struct pdump_stats *stats) 492 { 493 while (rte_ring_count(ring)) 494 pdump_rxtx(ring, vdev_id, stats); 495 } 496 497 static void 498 cleanup_rings(void) 499 { 500 int i; 501 struct pdump_tuples *pt; 502 503 for (i = 0; i < num_tuples; i++) { 504 pt = &pdump_t[i]; 505 506 if (pt->device_id) 507 free(pt->device_id); 508 509 /* free the rings */ 510 if (pt->rx_ring) 511 rte_ring_free(pt->rx_ring); 512 if (pt->tx_ring) 513 rte_ring_free(pt->tx_ring); 514 } 515 } 516 517 static void 518 cleanup_pdump_resources(void) 519 { 520 int i; 521 struct pdump_tuples *pt; 522 523 /* disable pdump and free the pdump_tuple resources */ 524 for (i = 0; i < num_tuples; i++) { 525 pt = &pdump_t[i]; 526 527 /* remove callbacks */ 528 disable_pdump(pt); 529 530 /* 531 * transmit rest of the enqueued packets of the rings on to 532 * the vdev, in order to release mbufs to the mepool. 533 **/ 534 if (pt->dir & RTE_PDUMP_FLAG_RX) 535 free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats); 536 if (pt->dir & RTE_PDUMP_FLAG_TX) 537 free_ring_data(pt->tx_ring, pt->tx_vdev_id, &pt->stats); 538 } 539 cleanup_rings(); 540 } 541 542 static void 543 signal_handler(int sig_num) 544 { 545 if (sig_num == SIGINT) { 546 printf("\n\nSignal %d received, preparing to exit...\n", 547 sig_num); 548 quit_signal = 1; 549 } 550 } 551 552 static inline int 553 configure_vdev(uint16_t port_id) 554 { 555 struct ether_addr addr; 556 const uint16_t rxRings = 0, txRings = 1; 557 const uint8_t nb_ports = rte_eth_dev_count(); 558 int ret; 559 uint16_t q; 560 561 if (port_id > nb_ports) 562 return -1; 563 564 ret = rte_eth_dev_configure(port_id, rxRings, txRings, 565 &port_conf_default); 566 if (ret != 0) 567 rte_exit(EXIT_FAILURE, "dev config failed\n"); 568 569 for (q = 0; q < txRings; q++) { 570 ret = rte_eth_tx_queue_setup(port_id, q, TX_DESC_PER_QUEUE, 571 rte_eth_dev_socket_id(port_id), NULL); 572 if (ret < 0) 573 rte_exit(EXIT_FAILURE, "queue setup failed\n"); 574 } 575 576 ret = rte_eth_dev_start(port_id); 577 if (ret < 0) 578 rte_exit(EXIT_FAILURE, "dev start failed\n"); 579 580 rte_eth_macaddr_get(port_id, &addr); 581 printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8 582 " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", 583 port_id, 584 addr.addr_bytes[0], addr.addr_bytes[1], 585 addr.addr_bytes[2], addr.addr_bytes[3], 586 addr.addr_bytes[4], addr.addr_bytes[5]); 587 588 rte_eth_promiscuous_enable(port_id); 589 590 return 0; 591 } 592 593 static void 594 create_mp_ring_vdev(void) 595 { 596 int i; 597 uint16_t portid; 598 struct pdump_tuples *pt = NULL; 599 struct rte_mempool *mbuf_pool = NULL; 600 char vdev_args[SIZE]; 601 char ring_name[SIZE]; 602 char mempool_name[SIZE]; 603 604 for (i = 0; i < num_tuples; i++) { 605 pt = &pdump_t[i]; 606 snprintf(mempool_name, SIZE, MP_NAME, i); 607 mbuf_pool = rte_mempool_lookup(mempool_name); 608 if (mbuf_pool == NULL) { 609 /* create mempool */ 610 mbuf_pool = rte_pktmbuf_pool_create(mempool_name, 611 pt->total_num_mbufs, 612 MBUF_POOL_CACHE_SIZE, 0, 613 pt->mbuf_data_size, 614 rte_socket_id()); 615 if (mbuf_pool == NULL) { 616 cleanup_rings(); 617 rte_exit(EXIT_FAILURE, 618 "Mempool creation failed: %s\n", 619 rte_strerror(rte_errno)); 620 } 621 } 622 pt->mp = mbuf_pool; 623 624 if (pt->dir == RTE_PDUMP_FLAG_RXTX) { 625 /* if captured packets has to send to the same vdev */ 626 /* create rx_ring */ 627 snprintf(ring_name, SIZE, RX_RING, i); 628 pt->rx_ring = rte_ring_create(ring_name, pt->ring_size, 629 rte_socket_id(), 0); 630 if (pt->rx_ring == NULL) { 631 cleanup_rings(); 632 rte_exit(EXIT_FAILURE, "%s:%s:%d\n", 633 rte_strerror(rte_errno), 634 __func__, __LINE__); 635 } 636 637 /* create tx_ring */ 638 snprintf(ring_name, SIZE, TX_RING, i); 639 pt->tx_ring = rte_ring_create(ring_name, pt->ring_size, 640 rte_socket_id(), 0); 641 if (pt->tx_ring == NULL) { 642 cleanup_rings(); 643 rte_exit(EXIT_FAILURE, "%s:%s:%d\n", 644 rte_strerror(rte_errno), 645 __func__, __LINE__); 646 } 647 648 /* create vdevs */ 649 (pt->rx_vdev_stream_type == IFACE) ? 650 snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i, 651 pt->rx_dev) : 652 snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i, 653 pt->rx_dev); 654 if (rte_eth_dev_attach(vdev_args, &portid) < 0) { 655 cleanup_rings(); 656 rte_exit(EXIT_FAILURE, 657 "vdev creation failed:%s:%d\n", 658 __func__, __LINE__); 659 } 660 pt->rx_vdev_id = portid; 661 662 /* configure vdev */ 663 configure_vdev(pt->rx_vdev_id); 664 665 if (pt->single_pdump_dev) 666 pt->tx_vdev_id = portid; 667 else { 668 (pt->tx_vdev_stream_type == IFACE) ? 669 snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i, 670 pt->tx_dev) : 671 snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i, 672 pt->tx_dev); 673 if (rte_eth_dev_attach(vdev_args, 674 &portid) < 0) { 675 cleanup_rings(); 676 rte_exit(EXIT_FAILURE, 677 "vdev creation failed:" 678 "%s:%d\n", __func__, __LINE__); 679 } 680 pt->tx_vdev_id = portid; 681 682 /* configure vdev */ 683 configure_vdev(pt->tx_vdev_id); 684 } 685 } else if (pt->dir == RTE_PDUMP_FLAG_RX) { 686 687 /* create rx_ring */ 688 snprintf(ring_name, SIZE, RX_RING, i); 689 pt->rx_ring = rte_ring_create(ring_name, pt->ring_size, 690 rte_socket_id(), 0); 691 if (pt->rx_ring == NULL) { 692 cleanup_rings(); 693 rte_exit(EXIT_FAILURE, "%s\n", 694 rte_strerror(rte_errno)); 695 } 696 697 (pt->rx_vdev_stream_type == IFACE) ? 698 snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i, 699 pt->rx_dev) : 700 snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i, 701 pt->rx_dev); 702 if (rte_eth_dev_attach(vdev_args, &portid) < 0) { 703 cleanup_rings(); 704 rte_exit(EXIT_FAILURE, 705 "vdev creation failed:%s:%d\n", 706 __func__, __LINE__); 707 } 708 pt->rx_vdev_id = portid; 709 /* configure vdev */ 710 configure_vdev(pt->rx_vdev_id); 711 } else if (pt->dir == RTE_PDUMP_FLAG_TX) { 712 713 /* create tx_ring */ 714 snprintf(ring_name, SIZE, TX_RING, i); 715 pt->tx_ring = rte_ring_create(ring_name, pt->ring_size, 716 rte_socket_id(), 0); 717 if (pt->tx_ring == NULL) { 718 cleanup_rings(); 719 rte_exit(EXIT_FAILURE, "%s\n", 720 rte_strerror(rte_errno)); 721 } 722 723 (pt->tx_vdev_stream_type == IFACE) ? 724 snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i, 725 pt->tx_dev) : 726 snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i, 727 pt->tx_dev); 728 if (rte_eth_dev_attach(vdev_args, &portid) < 0) { 729 cleanup_rings(); 730 rte_exit(EXIT_FAILURE, 731 "vdev creation failed\n"); 732 } 733 pt->tx_vdev_id = portid; 734 735 /* configure vdev */ 736 configure_vdev(pt->tx_vdev_id); 737 } 738 } 739 } 740 741 static void 742 enable_pdump(void) 743 { 744 int i; 745 struct pdump_tuples *pt; 746 int ret = 0, ret1 = 0; 747 748 if (server_socket_path[0] != 0) 749 ret = rte_pdump_set_socket_dir(server_socket_path, 750 RTE_PDUMP_SOCKET_SERVER); 751 if (ret == 0 && client_socket_path[0] != 0) { 752 ret = rte_pdump_set_socket_dir(client_socket_path, 753 RTE_PDUMP_SOCKET_CLIENT); 754 } 755 if (ret < 0) { 756 cleanup_pdump_resources(); 757 rte_exit(EXIT_FAILURE, 758 "failed to set socket paths of server:%s, " 759 "client:%s\n", 760 server_socket_path, 761 client_socket_path); 762 } 763 764 for (i = 0; i < num_tuples; i++) { 765 pt = &pdump_t[i]; 766 if (pt->dir == RTE_PDUMP_FLAG_RXTX) { 767 if (pt->dump_by_type == DEVICE_ID) { 768 ret = rte_pdump_enable_by_deviceid( 769 pt->device_id, 770 pt->queue, 771 RTE_PDUMP_FLAG_RX, 772 pt->rx_ring, 773 pt->mp, NULL); 774 ret1 = rte_pdump_enable_by_deviceid( 775 pt->device_id, 776 pt->queue, 777 RTE_PDUMP_FLAG_TX, 778 pt->tx_ring, 779 pt->mp, NULL); 780 } else if (pt->dump_by_type == PORT_ID) { 781 ret = rte_pdump_enable(pt->port, pt->queue, 782 RTE_PDUMP_FLAG_RX, 783 pt->rx_ring, pt->mp, NULL); 784 ret1 = rte_pdump_enable(pt->port, pt->queue, 785 RTE_PDUMP_FLAG_TX, 786 pt->tx_ring, pt->mp, NULL); 787 } 788 } else if (pt->dir == RTE_PDUMP_FLAG_RX) { 789 if (pt->dump_by_type == DEVICE_ID) 790 ret = rte_pdump_enable_by_deviceid( 791 pt->device_id, 792 pt->queue, 793 pt->dir, pt->rx_ring, 794 pt->mp, NULL); 795 else if (pt->dump_by_type == PORT_ID) 796 ret = rte_pdump_enable(pt->port, pt->queue, 797 pt->dir, 798 pt->rx_ring, pt->mp, NULL); 799 } else if (pt->dir == RTE_PDUMP_FLAG_TX) { 800 if (pt->dump_by_type == DEVICE_ID) 801 ret = rte_pdump_enable_by_deviceid( 802 pt->device_id, 803 pt->queue, 804 pt->dir, 805 pt->tx_ring, pt->mp, NULL); 806 else if (pt->dump_by_type == PORT_ID) 807 ret = rte_pdump_enable(pt->port, pt->queue, 808 pt->dir, 809 pt->tx_ring, pt->mp, NULL); 810 } 811 if (ret < 0 || ret1 < 0) { 812 cleanup_pdump_resources(); 813 rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno)); 814 } 815 } 816 } 817 818 static inline void 819 dump_packets(void) 820 { 821 int i; 822 struct pdump_tuples *pt; 823 824 while (!quit_signal) { 825 for (i = 0; i < num_tuples; i++) { 826 pt = &pdump_t[i]; 827 if (pt->dir & RTE_PDUMP_FLAG_RX) 828 pdump_rxtx(pt->rx_ring, pt->rx_vdev_id, 829 &pt->stats); 830 if (pt->dir & RTE_PDUMP_FLAG_TX) 831 pdump_rxtx(pt->tx_ring, pt->tx_vdev_id, 832 &pt->stats); 833 } 834 } 835 } 836 837 int 838 main(int argc, char **argv) 839 { 840 int diag; 841 int ret; 842 int i; 843 844 char c_flag[] = "-c1"; 845 char n_flag[] = "-n4"; 846 char mp_flag[] = "--proc-type=secondary"; 847 char *argp[argc + 3]; 848 849 /* catch ctrl-c so we can print on exit */ 850 signal(SIGINT, signal_handler); 851 852 argp[0] = argv[0]; 853 argp[1] = c_flag; 854 argp[2] = n_flag; 855 argp[3] = mp_flag; 856 857 for (i = 1; i < argc; i++) 858 argp[i + 3] = argv[i]; 859 860 argc += 3; 861 862 diag = rte_eal_init(argc, argp); 863 if (diag < 0) 864 rte_panic("Cannot init EAL\n"); 865 866 argc -= diag; 867 argv += (diag - 3); 868 869 /* parse app arguments */ 870 if (argc > 1) { 871 ret = launch_args_parse(argc, argv, argp[0]); 872 if (ret < 0) 873 rte_exit(EXIT_FAILURE, "Invalid argument\n"); 874 } 875 876 /* create mempool, ring and vdevs info */ 877 create_mp_ring_vdev(); 878 enable_pdump(); 879 dump_packets(); 880 881 cleanup_pdump_resources(); 882 /* dump debug stats */ 883 print_pdump_stats(); 884 885 ret = rte_eal_cleanup(); 886 if (ret) 887 printf("Error from rte_eal_cleanup(), %d\n", ret); 888 889 return 0; 890 } 891