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