1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2016 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <string.h> 7 #include <stdint.h> 8 #include <inttypes.h> 9 #include <stdlib.h> 10 #include <getopt.h> 11 #include <signal.h> 12 #include <stdbool.h> 13 #include <net/if.h> 14 15 #include <rte_eal.h> 16 #include <rte_common.h> 17 #include <rte_debug.h> 18 #include <rte_ethdev.h> 19 #include <rte_memory.h> 20 #include <rte_lcore.h> 21 #include <rte_branch_prediction.h> 22 #include <rte_errno.h> 23 #include <rte_dev.h> 24 #include <rte_kvargs.h> 25 #include <rte_mempool.h> 26 #include <rte_ring.h> 27 #include <rte_string_fns.h> 28 #include <rte_pdump.h> 29 30 #define CMD_LINE_OPT_PDUMP "pdump" 31 #define PDUMP_PORT_ARG "port" 32 #define PDUMP_PCI_ARG "device_id" 33 #define PDUMP_QUEUE_ARG "queue" 34 #define PDUMP_DIR_ARG "dir" 35 #define PDUMP_RX_DEV_ARG "rx-dev" 36 #define PDUMP_TX_DEV_ARG "tx-dev" 37 #define PDUMP_RING_SIZE_ARG "ring-size" 38 #define PDUMP_MSIZE_ARG "mbuf-size" 39 #define PDUMP_NUM_MBUFS_ARG "total-num-mbufs" 40 #define CMD_LINE_OPT_SER_SOCK_PATH "server-socket-path" 41 #define CMD_LINE_OPT_CLI_SOCK_PATH "client-socket-path" 42 43 #define VDEV_PCAP "net_pcap_%s_%d,tx_pcap=%s" 44 #define VDEV_IFACE "net_pcap_%s_%d,tx_iface=%s" 45 #define TX_STREAM_SIZE 64 46 47 #define MP_NAME "pdump_pool_%d" 48 49 #define RX_RING "rx_ring_%d" 50 #define TX_RING "tx_ring_%d" 51 52 #define RX_STR "rx" 53 #define TX_STR "tx" 54 55 /* Maximum long option length for option parsing. */ 56 #define APP_ARG_TCPDUMP_MAX_TUPLES 54 57 #define MBUF_POOL_CACHE_SIZE 250 58 #define TX_DESC_PER_QUEUE 512 59 #define RX_DESC_PER_QUEUE 128 60 #define MBUFS_PER_POOL 65535 61 #define MAX_LONG_OPT_SZ 64 62 #define RING_SIZE 16384 63 #define SIZE 256 64 #define BURST_SIZE 32 65 #define NUM_VDEVS 2 66 67 /* true if x is a power of 2 */ 68 #define POWEROF2(x) ((((x)-1) & (x)) == 0) 69 70 enum pdump_en_dis { 71 DISABLE = 1, 72 ENABLE = 2 73 }; 74 75 enum pcap_stream { 76 IFACE = 1, 77 PCAP = 2 78 }; 79 80 enum pdump_by { 81 PORT_ID = 1, 82 DEVICE_ID = 2 83 }; 84 85 const char *valid_pdump_arguments[] = { 86 PDUMP_PORT_ARG, 87 PDUMP_PCI_ARG, 88 PDUMP_QUEUE_ARG, 89 PDUMP_DIR_ARG, 90 PDUMP_RX_DEV_ARG, 91 PDUMP_TX_DEV_ARG, 92 PDUMP_RING_SIZE_ARG, 93 PDUMP_MSIZE_ARG, 94 PDUMP_NUM_MBUFS_ARG, 95 NULL 96 }; 97 98 struct pdump_stats { 99 uint64_t dequeue_pkts; 100 uint64_t tx_pkts; 101 uint64_t freed_pkts; 102 }; 103 104 struct pdump_tuples { 105 /* cli params */ 106 uint16_t port; 107 char *device_id; 108 uint16_t queue; 109 char rx_dev[TX_STREAM_SIZE]; 110 char tx_dev[TX_STREAM_SIZE]; 111 uint32_t ring_size; 112 uint16_t mbuf_data_size; 113 uint32_t total_num_mbufs; 114 115 /* params for library API call */ 116 uint32_t dir; 117 struct rte_mempool *mp; 118 struct rte_ring *rx_ring; 119 struct rte_ring *tx_ring; 120 121 /* params for packet dumping */ 122 enum pdump_by dump_by_type; 123 int rx_vdev_id; 124 int tx_vdev_id; 125 enum pcap_stream rx_vdev_stream_type; 126 enum pcap_stream tx_vdev_stream_type; 127 bool single_pdump_dev; 128 129 /* stats */ 130 struct pdump_stats stats; 131 } __rte_cache_aligned; 132 static struct pdump_tuples pdump_t[APP_ARG_TCPDUMP_MAX_TUPLES]; 133 134 struct parse_val { 135 uint64_t min; 136 uint64_t max; 137 uint64_t val; 138 }; 139 140 int num_tuples; 141 static struct rte_eth_conf port_conf_default; 142 volatile uint8_t quit_signal; 143 static char server_socket_path[PATH_MAX]; 144 static char client_socket_path[PATH_MAX]; 145 146 /**< display usage */ 147 static void 148 pdump_usage(const char *prgname) 149 { 150 printf("usage: %s [EAL options] -- --pdump " 151 "'(port=<port id> | device_id=<pci id or vdev name>)," 152 "(queue=<queue_id>)," 153 "(rx-dev=<iface or pcap file> |" 154 " tx-dev=<iface or pcap file>," 155 "[ring-size=<ring size>default:16384]," 156 "[mbuf-size=<mbuf data size>default:2176]," 157 "[total-num-mbufs=<number of mbufs>default:65535]'\n" 158 "[--server-socket-path=<server socket dir>" 159 "default:/var/run/.dpdk/ (or) ~/.dpdk/]\n" 160 "[--client-socket-path=<client socket dir>" 161 "default:/var/run/.dpdk/ (or) ~/.dpdk/]\n", 162 prgname); 163 } 164 165 static int 166 parse_device_id(const char *key __rte_unused, const char *value, 167 void *extra_args) 168 { 169 struct pdump_tuples *pt = extra_args; 170 171 pt->device_id = strdup(value); 172 pt->dump_by_type = DEVICE_ID; 173 174 return 0; 175 } 176 177 static int 178 parse_queue(const char *key __rte_unused, const char *value, void *extra_args) 179 { 180 unsigned long n; 181 struct pdump_tuples *pt = extra_args; 182 183 if (!strcmp(value, "*")) 184 pt->queue = RTE_PDUMP_ALL_QUEUES; 185 else { 186 n = strtoul(value, NULL, 10); 187 pt->queue = (uint16_t) n; 188 } 189 return 0; 190 } 191 192 static int 193 parse_rxtxdev(const char *key, const char *value, void *extra_args) 194 { 195 196 struct pdump_tuples *pt = extra_args; 197 198 if (!strcmp(key, PDUMP_RX_DEV_ARG)) { 199 snprintf(pt->rx_dev, sizeof(pt->rx_dev), "%s", value); 200 /* identify the tx stream type for pcap vdev */ 201 if (if_nametoindex(pt->rx_dev)) 202 pt->rx_vdev_stream_type = IFACE; 203 } else if (!strcmp(key, PDUMP_TX_DEV_ARG)) { 204 snprintf(pt->tx_dev, sizeof(pt->tx_dev), "%s", value); 205 /* identify the tx stream type for pcap vdev */ 206 if (if_nametoindex(pt->tx_dev)) 207 pt->tx_vdev_stream_type = IFACE; 208 } 209 210 return 0; 211 } 212 213 static int 214 parse_uint_value(const char *key, const char *value, void *extra_args) 215 { 216 struct parse_val *v; 217 unsigned long t; 218 char *end; 219 int ret = 0; 220 221 errno = 0; 222 v = extra_args; 223 t = strtoul(value, &end, 10); 224 225 if (errno != 0 || end[0] != 0 || t < v->min || t > v->max) { 226 printf("invalid value:\"%s\" for key:\"%s\", " 227 "value must be >= %"PRIu64" and <= %"PRIu64"\n", 228 value, key, v->min, v->max); 229 ret = -EINVAL; 230 } 231 if (!strcmp(key, PDUMP_RING_SIZE_ARG) && !POWEROF2(t)) { 232 printf("invalid value:\"%s\" for key:\"%s\", " 233 "value must be power of 2\n", value, key); 234 ret = -EINVAL; 235 } 236 237 if (ret != 0) 238 return ret; 239 240 v->val = t; 241 return 0; 242 } 243 244 static int 245 parse_pdump(const char *optarg) 246 { 247 struct rte_kvargs *kvlist; 248 int ret = 0, cnt1, cnt2; 249 struct pdump_tuples *pt; 250 struct parse_val v = {0}; 251 252 pt = &pdump_t[num_tuples]; 253 254 /* initial check for invalid arguments */ 255 kvlist = rte_kvargs_parse(optarg, valid_pdump_arguments); 256 if (kvlist == NULL) { 257 printf("--pdump=\"%s\": invalid argument passed\n", optarg); 258 return -1; 259 } 260 261 /* port/device_id parsing and validation */ 262 cnt1 = rte_kvargs_count(kvlist, PDUMP_PORT_ARG); 263 cnt2 = rte_kvargs_count(kvlist, PDUMP_PCI_ARG); 264 if (!((cnt1 == 1 && cnt2 == 0) || (cnt1 == 0 && cnt2 == 1))) { 265 printf("--pdump=\"%s\": must have either port or " 266 "device_id argument\n", optarg); 267 ret = -1; 268 goto free_kvlist; 269 } else if (cnt1 == 1) { 270 v.min = 0; 271 v.max = RTE_MAX_ETHPORTS-1; 272 ret = rte_kvargs_process(kvlist, PDUMP_PORT_ARG, 273 &parse_uint_value, &v); 274 if (ret < 0) 275 goto free_kvlist; 276 pt->port = (uint8_t) v.val; 277 pt->dump_by_type = PORT_ID; 278 } else if (cnt2 == 1) { 279 ret = rte_kvargs_process(kvlist, PDUMP_PCI_ARG, 280 &parse_device_id, pt); 281 if (ret < 0) 282 goto free_kvlist; 283 } 284 285 /* queue parsing and validation */ 286 cnt1 = rte_kvargs_count(kvlist, PDUMP_QUEUE_ARG); 287 if (cnt1 != 1) { 288 printf("--pdump=\"%s\": must have queue argument\n", optarg); 289 ret = -1; 290 goto free_kvlist; 291 } 292 ret = rte_kvargs_process(kvlist, PDUMP_QUEUE_ARG, &parse_queue, pt); 293 if (ret < 0) 294 goto free_kvlist; 295 296 /* rx-dev and tx-dev parsing and validation */ 297 cnt1 = rte_kvargs_count(kvlist, PDUMP_RX_DEV_ARG); 298 cnt2 = rte_kvargs_count(kvlist, PDUMP_TX_DEV_ARG); 299 if (cnt1 == 0 && cnt2 == 0) { 300 printf("--pdump=\"%s\": must have either rx-dev or " 301 "tx-dev argument\n", optarg); 302 ret = -1; 303 goto free_kvlist; 304 } else if (cnt1 == 1 && cnt2 == 1) { 305 ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG, 306 &parse_rxtxdev, pt); 307 if (ret < 0) 308 goto free_kvlist; 309 ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG, 310 &parse_rxtxdev, pt); 311 if (ret < 0) 312 goto free_kvlist; 313 /* if captured packets has to send to the same vdev */ 314 if (!strcmp(pt->rx_dev, pt->tx_dev)) 315 pt->single_pdump_dev = true; 316 pt->dir = RTE_PDUMP_FLAG_RXTX; 317 } else if (cnt1 == 1) { 318 ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG, 319 &parse_rxtxdev, pt); 320 if (ret < 0) 321 goto free_kvlist; 322 pt->dir = RTE_PDUMP_FLAG_RX; 323 } else if (cnt2 == 1) { 324 ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG, 325 &parse_rxtxdev, pt); 326 if (ret < 0) 327 goto free_kvlist; 328 pt->dir = RTE_PDUMP_FLAG_TX; 329 } 330 331 /* optional */ 332 /* ring_size parsing and validation */ 333 cnt1 = rte_kvargs_count(kvlist, PDUMP_RING_SIZE_ARG); 334 if (cnt1 == 1) { 335 v.min = 2; 336 v.max = RTE_RING_SZ_MASK-1; 337 ret = rte_kvargs_process(kvlist, PDUMP_RING_SIZE_ARG, 338 &parse_uint_value, &v); 339 if (ret < 0) 340 goto free_kvlist; 341 pt->ring_size = (uint32_t) v.val; 342 } else 343 pt->ring_size = RING_SIZE; 344 345 /* mbuf_data_size parsing and validation */ 346 cnt1 = rte_kvargs_count(kvlist, PDUMP_MSIZE_ARG); 347 if (cnt1 == 1) { 348 v.min = 1; 349 v.max = UINT16_MAX; 350 ret = rte_kvargs_process(kvlist, PDUMP_MSIZE_ARG, 351 &parse_uint_value, &v); 352 if (ret < 0) 353 goto free_kvlist; 354 pt->mbuf_data_size = (uint16_t) v.val; 355 } else 356 pt->mbuf_data_size = RTE_MBUF_DEFAULT_BUF_SIZE; 357 358 /* total_num_mbufs parsing and validation */ 359 cnt1 = rte_kvargs_count(kvlist, PDUMP_NUM_MBUFS_ARG); 360 if (cnt1 == 1) { 361 v.min = 1025; 362 v.max = UINT16_MAX; 363 ret = rte_kvargs_process(kvlist, PDUMP_NUM_MBUFS_ARG, 364 &parse_uint_value, &v); 365 if (ret < 0) 366 goto free_kvlist; 367 pt->total_num_mbufs = (uint16_t) v.val; 368 } else 369 pt->total_num_mbufs = MBUFS_PER_POOL; 370 371 num_tuples++; 372 373 free_kvlist: 374 rte_kvargs_free(kvlist); 375 return ret; 376 } 377 378 /* Parse the argument given in the command line of the application */ 379 static int 380 launch_args_parse(int argc, char **argv, char *prgname) 381 { 382 int opt, ret; 383 int option_index; 384 static struct option long_option[] = { 385 {"pdump", 1, 0, 0}, 386 {"server-socket-path", 1, 0, 0}, 387 {"client-socket-path", 1, 0, 0}, 388 {NULL, 0, 0, 0} 389 }; 390 391 if (argc == 1) 392 pdump_usage(prgname); 393 394 /* Parse command line */ 395 while ((opt = getopt_long(argc, argv, " ", 396 long_option, &option_index)) != EOF) { 397 switch (opt) { 398 case 0: 399 if (!strncmp(long_option[option_index].name, 400 CMD_LINE_OPT_PDUMP, 401 sizeof(CMD_LINE_OPT_PDUMP))) { 402 ret = parse_pdump(optarg); 403 if (ret) { 404 pdump_usage(prgname); 405 return -1; 406 } 407 } 408 409 if (!strncmp(long_option[option_index].name, 410 CMD_LINE_OPT_SER_SOCK_PATH, 411 sizeof(CMD_LINE_OPT_SER_SOCK_PATH))) { 412 strlcpy(server_socket_path, optarg, 413 sizeof(server_socket_path)); 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 strlcpy(client_socket_path, optarg, 420 sizeof(client_socket_path)); 421 } 422 423 break; 424 default: 425 pdump_usage(prgname); 426 return -1; 427 } 428 } 429 430 return 0; 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, uint8_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 do { 481 rte_pktmbuf_free(rxtx_bufs[nb_in_txd]); 482 stats->freed_pkts++; 483 } while (++nb_in_txd < nb_in_deq); 484 } 485 } 486 } 487 488 static void 489 free_ring_data(struct rte_ring *ring, uint8_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 if (pt->device_id) 506 free(pt->device_id); 507 508 /* free the rings */ 509 if (pt->rx_ring) 510 rte_ring_free(pt->rx_ring); 511 if (pt->tx_ring) 512 rte_ring_free(pt->tx_ring); 513 } 514 } 515 516 static void 517 cleanup_pdump_resources(void) 518 { 519 int i; 520 struct pdump_tuples *pt; 521 522 /* disable pdump and free the pdump_tuple resources */ 523 for (i = 0; i < num_tuples; i++) { 524 pt = &pdump_t[i]; 525 526 /* remove callbacks */ 527 disable_pdump(pt); 528 529 /* 530 * transmit rest of the enqueued packets of the rings on to 531 * the vdev, in order to release mbufs to the mepool. 532 **/ 533 if (pt->dir & RTE_PDUMP_FLAG_RX) 534 free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats); 535 if (pt->dir & RTE_PDUMP_FLAG_TX) 536 free_ring_data(pt->tx_ring, pt->tx_vdev_id, &pt->stats); 537 } 538 cleanup_rings(); 539 } 540 541 static void 542 signal_handler(int sig_num) 543 { 544 if (sig_num == SIGINT) { 545 printf("\n\nSignal %d received, preparing to exit...\n", 546 sig_num); 547 quit_signal = 1; 548 } 549 } 550 551 static inline int 552 configure_vdev(uint16_t port_id) 553 { 554 struct ether_addr addr; 555 const uint16_t rxRings = 0, txRings = 1; 556 const uint8_t nb_ports = rte_eth_dev_count(); 557 int ret; 558 uint16_t q; 559 560 if (port_id > nb_ports) 561 return -1; 562 563 ret = rte_eth_dev_configure(port_id, rxRings, txRings, 564 &port_conf_default); 565 if (ret != 0) 566 rte_exit(EXIT_FAILURE, "dev config failed\n"); 567 568 for (q = 0; q < txRings; q++) { 569 ret = rte_eth_tx_queue_setup(port_id, q, TX_DESC_PER_QUEUE, 570 rte_eth_dev_socket_id(port_id), NULL); 571 if (ret < 0) 572 rte_exit(EXIT_FAILURE, "queue setup failed\n"); 573 } 574 575 ret = rte_eth_dev_start(port_id); 576 if (ret < 0) 577 rte_exit(EXIT_FAILURE, "dev start failed\n"); 578 579 rte_eth_macaddr_get(port_id, &addr); 580 printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8 581 " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", 582 port_id, 583 addr.addr_bytes[0], addr.addr_bytes[1], 584 addr.addr_bytes[2], addr.addr_bytes[3], 585 addr.addr_bytes[4], addr.addr_bytes[5]); 586 587 rte_eth_promiscuous_enable(port_id); 588 589 return 0; 590 } 591 592 static void 593 create_mp_ring_vdev(void) 594 { 595 int i; 596 uint16_t portid; 597 struct pdump_tuples *pt = NULL; 598 struct rte_mempool *mbuf_pool = NULL; 599 char vdev_args[SIZE]; 600 char ring_name[SIZE]; 601 char mempool_name[SIZE]; 602 603 for (i = 0; i < num_tuples; i++) { 604 pt = &pdump_t[i]; 605 snprintf(mempool_name, SIZE, MP_NAME, i); 606 mbuf_pool = rte_mempool_lookup(mempool_name); 607 if (mbuf_pool == NULL) { 608 /* create mempool */ 609 mbuf_pool = rte_pktmbuf_pool_create(mempool_name, 610 pt->total_num_mbufs, 611 MBUF_POOL_CACHE_SIZE, 0, 612 pt->mbuf_data_size, 613 rte_socket_id()); 614 if (mbuf_pool == NULL) { 615 cleanup_rings(); 616 rte_exit(EXIT_FAILURE, 617 "Mempool creation failed: %s\n", 618 rte_strerror(rte_errno)); 619 } 620 } 621 pt->mp = mbuf_pool; 622 623 if (pt->dir == RTE_PDUMP_FLAG_RXTX) { 624 /* if captured packets has to send to the same vdev */ 625 /* create rx_ring */ 626 snprintf(ring_name, SIZE, RX_RING, i); 627 pt->rx_ring = rte_ring_create(ring_name, pt->ring_size, 628 rte_socket_id(), 0); 629 if (pt->rx_ring == NULL) { 630 cleanup_rings(); 631 rte_exit(EXIT_FAILURE, "%s:%s:%d\n", 632 rte_strerror(rte_errno), 633 __func__, __LINE__); 634 } 635 636 /* create tx_ring */ 637 snprintf(ring_name, SIZE, TX_RING, i); 638 pt->tx_ring = rte_ring_create(ring_name, pt->ring_size, 639 rte_socket_id(), 0); 640 if (pt->tx_ring == NULL) { 641 cleanup_rings(); 642 rte_exit(EXIT_FAILURE, "%s:%s:%d\n", 643 rte_strerror(rte_errno), 644 __func__, __LINE__); 645 } 646 647 /* create vdevs */ 648 (pt->rx_vdev_stream_type == IFACE) ? 649 snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i, 650 pt->rx_dev) : 651 snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i, 652 pt->rx_dev); 653 if (rte_eth_dev_attach(vdev_args, &portid) < 0) { 654 cleanup_rings(); 655 rte_exit(EXIT_FAILURE, 656 "vdev creation failed:%s:%d\n", 657 __func__, __LINE__); 658 } 659 pt->rx_vdev_id = portid; 660 661 /* configure vdev */ 662 configure_vdev(pt->rx_vdev_id); 663 664 if (pt->single_pdump_dev) 665 pt->tx_vdev_id = portid; 666 else { 667 (pt->tx_vdev_stream_type == IFACE) ? 668 snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i, 669 pt->tx_dev) : 670 snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i, 671 pt->tx_dev); 672 if (rte_eth_dev_attach(vdev_args, 673 &portid) < 0) { 674 cleanup_rings(); 675 rte_exit(EXIT_FAILURE, 676 "vdev creation failed:" 677 "%s:%d\n", __func__, __LINE__); 678 } 679 pt->tx_vdev_id = portid; 680 681 /* configure vdev */ 682 configure_vdev(pt->tx_vdev_id); 683 } 684 } else if (pt->dir == RTE_PDUMP_FLAG_RX) { 685 686 /* create rx_ring */ 687 snprintf(ring_name, SIZE, RX_RING, i); 688 pt->rx_ring = rte_ring_create(ring_name, pt->ring_size, 689 rte_socket_id(), 0); 690 if (pt->rx_ring == NULL) { 691 cleanup_rings(); 692 rte_exit(EXIT_FAILURE, "%s\n", 693 rte_strerror(rte_errno)); 694 } 695 696 (pt->rx_vdev_stream_type == IFACE) ? 697 snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i, 698 pt->rx_dev) : 699 snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i, 700 pt->rx_dev); 701 if (rte_eth_dev_attach(vdev_args, &portid) < 0) { 702 cleanup_rings(); 703 rte_exit(EXIT_FAILURE, 704 "vdev creation failed:%s:%d\n", 705 __func__, __LINE__); 706 } 707 pt->rx_vdev_id = portid; 708 /* configure vdev */ 709 configure_vdev(pt->rx_vdev_id); 710 } else if (pt->dir == RTE_PDUMP_FLAG_TX) { 711 712 /* create tx_ring */ 713 snprintf(ring_name, SIZE, TX_RING, i); 714 pt->tx_ring = rte_ring_create(ring_name, pt->ring_size, 715 rte_socket_id(), 0); 716 if (pt->tx_ring == NULL) { 717 cleanup_rings(); 718 rte_exit(EXIT_FAILURE, "%s\n", 719 rte_strerror(rte_errno)); 720 } 721 722 (pt->tx_vdev_stream_type == IFACE) ? 723 snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i, 724 pt->tx_dev) : 725 snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i, 726 pt->tx_dev); 727 if (rte_eth_dev_attach(vdev_args, &portid) < 0) { 728 cleanup_rings(); 729 rte_exit(EXIT_FAILURE, 730 "vdev creation failed\n"); 731 } 732 pt->tx_vdev_id = portid; 733 734 /* configure vdev */ 735 configure_vdev(pt->tx_vdev_id); 736 } 737 } 738 } 739 740 static void 741 enable_pdump(void) 742 { 743 int i; 744 struct pdump_tuples *pt; 745 int ret = 0, ret1 = 0; 746 747 if (server_socket_path[0] != 0) 748 ret = rte_pdump_set_socket_dir(server_socket_path, 749 RTE_PDUMP_SOCKET_SERVER); 750 if (ret == 0 && client_socket_path[0] != 0) { 751 ret = rte_pdump_set_socket_dir(client_socket_path, 752 RTE_PDUMP_SOCKET_CLIENT); 753 } 754 if (ret < 0) { 755 cleanup_pdump_resources(); 756 rte_exit(EXIT_FAILURE, 757 "failed to set socket paths of server:%s, " 758 "client:%s\n", 759 server_socket_path, 760 client_socket_path); 761 } 762 763 for (i = 0; i < num_tuples; i++) { 764 pt = &pdump_t[i]; 765 if (pt->dir == RTE_PDUMP_FLAG_RXTX) { 766 if (pt->dump_by_type == DEVICE_ID) { 767 ret = rte_pdump_enable_by_deviceid( 768 pt->device_id, 769 pt->queue, 770 RTE_PDUMP_FLAG_RX, 771 pt->rx_ring, 772 pt->mp, NULL); 773 ret1 = rte_pdump_enable_by_deviceid( 774 pt->device_id, 775 pt->queue, 776 RTE_PDUMP_FLAG_TX, 777 pt->tx_ring, 778 pt->mp, NULL); 779 } else if (pt->dump_by_type == PORT_ID) { 780 ret = rte_pdump_enable(pt->port, pt->queue, 781 RTE_PDUMP_FLAG_RX, 782 pt->rx_ring, pt->mp, NULL); 783 ret1 = rte_pdump_enable(pt->port, pt->queue, 784 RTE_PDUMP_FLAG_TX, 785 pt->tx_ring, pt->mp, NULL); 786 } 787 } else if (pt->dir == RTE_PDUMP_FLAG_RX) { 788 if (pt->dump_by_type == DEVICE_ID) 789 ret = rte_pdump_enable_by_deviceid( 790 pt->device_id, 791 pt->queue, 792 pt->dir, pt->rx_ring, 793 pt->mp, NULL); 794 else if (pt->dump_by_type == PORT_ID) 795 ret = rte_pdump_enable(pt->port, pt->queue, 796 pt->dir, 797 pt->rx_ring, pt->mp, NULL); 798 } else if (pt->dir == RTE_PDUMP_FLAG_TX) { 799 if (pt->dump_by_type == DEVICE_ID) 800 ret = rte_pdump_enable_by_deviceid( 801 pt->device_id, 802 pt->queue, 803 pt->dir, 804 pt->tx_ring, pt->mp, NULL); 805 else if (pt->dump_by_type == PORT_ID) 806 ret = rte_pdump_enable(pt->port, pt->queue, 807 pt->dir, 808 pt->tx_ring, pt->mp, NULL); 809 } 810 if (ret < 0 || ret1 < 0) { 811 cleanup_pdump_resources(); 812 rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno)); 813 } 814 } 815 } 816 817 static inline void 818 dump_packets(void) 819 { 820 int i; 821 struct pdump_tuples *pt; 822 823 while (!quit_signal) { 824 for (i = 0; i < num_tuples; i++) { 825 pt = &pdump_t[i]; 826 if (pt->dir & RTE_PDUMP_FLAG_RX) 827 pdump_rxtx(pt->rx_ring, pt->rx_vdev_id, 828 &pt->stats); 829 if (pt->dir & RTE_PDUMP_FLAG_TX) 830 pdump_rxtx(pt->tx_ring, pt->tx_vdev_id, 831 &pt->stats); 832 } 833 } 834 } 835 836 int 837 main(int argc, char **argv) 838 { 839 int diag; 840 int ret; 841 int i; 842 843 char c_flag[] = "-c1"; 844 char n_flag[] = "-n4"; 845 char mp_flag[] = "--proc-type=secondary"; 846 char *argp[argc + 3]; 847 848 /* catch ctrl-c so we can print on exit */ 849 signal(SIGINT, signal_handler); 850 851 argp[0] = argv[0]; 852 argp[1] = c_flag; 853 argp[2] = n_flag; 854 argp[3] = mp_flag; 855 856 for (i = 1; i < argc; i++) 857 argp[i + 3] = argv[i]; 858 859 argc += 3; 860 861 diag = rte_eal_init(argc, argp); 862 if (diag < 0) 863 rte_panic("Cannot init EAL\n"); 864 865 argc -= diag; 866 argv += (diag - 3); 867 868 /* parse app arguments */ 869 if (argc > 1) { 870 ret = launch_args_parse(argc, argv, argp[0]); 871 if (ret < 0) 872 rte_exit(EXIT_FAILURE, "Invalid argument\n"); 873 } 874 875 /* create mempool, ring and vdevs info */ 876 create_mp_ring_vdev(); 877 enable_pdump(); 878 dump_packets(); 879 880 cleanup_pdump_resources(); 881 /* dump debug stats */ 882 print_pdump_stats(); 883 884 ret = rte_eal_cleanup(); 885 if (ret) 886 printf("Error from rte_eal_cleanup(), %d\n", ret); 887 888 return 0; 889 } 890