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