dpdk/examples/ipv4_multicast/main.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2010-2014 Intel Corporation
   3 */
   4
   5#include <stdio.h>
   6#include <stdlib.h>
   7#include <stdint.h>
   8#include <inttypes.h>
   9#include <sys/types.h>
  10#include <string.h>
  11#include <sys/queue.h>
  12#include <stdarg.h>
  13#include <errno.h>
  14#include <getopt.h>
  15
  16#include <rte_common.h>
  17#include <rte_byteorder.h>
  18#include <rte_log.h>
  19#include <rte_memory.h>
  20#include <rte_memcpy.h>
  21#include <rte_eal.h>
  22#include <rte_launch.h>
  23#include <rte_atomic.h>
  24#include <rte_cycles.h>
  25#include <rte_prefetch.h>
  26#include <rte_lcore.h>
  27#include <rte_per_lcore.h>
  28#include <rte_branch_prediction.h>
  29#include <rte_interrupts.h>
  30#include <rte_random.h>
  31#include <rte_debug.h>
  32#include <rte_ether.h>
  33#include <rte_ethdev.h>
  34#include <rte_mempool.h>
  35#include <rte_mbuf.h>
  36#include <rte_malloc.h>
  37#include <rte_fbk_hash.h>
  38#include <rte_ip.h>
  39
  40#define RTE_LOGTYPE_IPv4_MULTICAST RTE_LOGTYPE_USER1
  41
  42#define MAX_PORTS 16
  43
  44#define MCAST_CLONE_PORTS       2
  45#define MCAST_CLONE_SEGS        2
  46
  47#define PKT_MBUF_DATA_SIZE      RTE_MBUF_DEFAULT_BUF_SIZE
  48#define NB_PKT_MBUF     8192
  49
  50#define HDR_MBUF_DATA_SIZE      (2 * RTE_PKTMBUF_HEADROOM)
  51#define NB_HDR_MBUF     (NB_PKT_MBUF * MAX_PORTS)
  52
  53#define NB_CLONE_MBUF   (NB_PKT_MBUF * MCAST_CLONE_PORTS * MCAST_CLONE_SEGS * 2)
  54
  55/* allow max jumbo frame 9.5 KB */
  56#define JUMBO_FRAME_MAX_SIZE    0x2600
  57
  58#define MAX_PKT_BURST 32
  59#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
  60
  61/* Configure how many packets ahead to prefetch, when reading packets */
  62#define PREFETCH_OFFSET 3
  63
  64/*
  65 * Construct Ethernet multicast address from IPv4 multicast address.
  66 * Citing RFC 1112, section 6.4:
  67 * "An IP host group address is mapped to an Ethernet multicast address
  68 * by placing the low-order 23-bits of the IP address into the low-order
  69 * 23 bits of the Ethernet multicast address 01-00-5E-00-00-00 (hex)."
  70 */
  71#define ETHER_ADDR_FOR_IPV4_MCAST(x)    \
  72        (rte_cpu_to_be_64(0x01005e000000ULL | ((x) & 0x7fffff)) >> 16)
  73
  74/*
  75 * Configurable number of RX/TX ring descriptors
  76 */
  77#define RTE_TEST_RX_DESC_DEFAULT 1024
  78#define RTE_TEST_TX_DESC_DEFAULT 1024
  79static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
  80static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
  81
  82/* ethernet addresses of ports */
  83static struct rte_ether_addr ports_eth_addr[MAX_PORTS];
  84
  85/* mask of enabled ports */
  86static uint32_t enabled_port_mask = 0;
  87
  88static uint16_t nb_ports;
  89
  90static int rx_queue_per_lcore = 1;
  91
  92struct mbuf_table {
  93        uint16_t len;
  94        struct rte_mbuf *m_table[MAX_PKT_BURST];
  95};
  96
  97#define MAX_RX_QUEUE_PER_LCORE 16
  98#define MAX_TX_QUEUE_PER_PORT 16
  99struct lcore_queue_conf {
 100        uint64_t tx_tsc;
 101        uint16_t n_rx_queue;
 102        uint8_t rx_queue_list[MAX_RX_QUEUE_PER_LCORE];
 103        uint16_t tx_queue_id[MAX_PORTS];
 104        struct mbuf_table tx_mbufs[MAX_PORTS];
 105} __rte_cache_aligned;
 106static struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
 107
 108static struct rte_eth_conf port_conf = {
 109        .rxmode = {
 110                .max_rx_pkt_len = JUMBO_FRAME_MAX_SIZE,
 111                .split_hdr_size = 0,
 112                .offloads = DEV_RX_OFFLOAD_JUMBO_FRAME,
 113        },
 114        .txmode = {
 115                .mq_mode = ETH_MQ_TX_NONE,
 116                .offloads = DEV_TX_OFFLOAD_MULTI_SEGS,
 117        },
 118};
 119
 120static struct rte_mempool *packet_pool, *header_pool, *clone_pool;
 121
 122
 123/* Multicast */
 124static struct rte_fbk_hash_params mcast_hash_params = {
 125        .name = "MCAST_HASH",
 126        .entries = 1024,
 127        .entries_per_bucket = 4,
 128        .socket_id = 0,
 129        .hash_func = NULL,
 130        .init_val = 0,
 131};
 132
 133struct rte_fbk_hash_table *mcast_hash = NULL;
 134
 135struct mcast_group_params {
 136        uint32_t ip;
 137        uint16_t port_mask;
 138};
 139
 140static struct mcast_group_params mcast_group_table[] = {
 141                {RTE_IPV4(224,0,0,101), 0x1},
 142                {RTE_IPV4(224,0,0,102), 0x2},
 143                {RTE_IPV4(224,0,0,103), 0x3},
 144                {RTE_IPV4(224,0,0,104), 0x4},
 145                {RTE_IPV4(224,0,0,105), 0x5},
 146                {RTE_IPV4(224,0,0,106), 0x6},
 147                {RTE_IPV4(224,0,0,107), 0x7},
 148                {RTE_IPV4(224,0,0,108), 0x8},
 149                {RTE_IPV4(224,0,0,109), 0x9},
 150                {RTE_IPV4(224,0,0,110), 0xA},
 151                {RTE_IPV4(224,0,0,111), 0xB},
 152                {RTE_IPV4(224,0,0,112), 0xC},
 153                {RTE_IPV4(224,0,0,113), 0xD},
 154                {RTE_IPV4(224,0,0,114), 0xE},
 155                {RTE_IPV4(224,0,0,115), 0xF},
 156};
 157
 158/* Send burst of packets on an output interface */
 159static void
 160send_burst(struct lcore_queue_conf *qconf, uint16_t port)
 161{
 162        struct rte_mbuf **m_table;
 163        uint16_t n, queueid;
 164        int ret;
 165
 166        queueid = qconf->tx_queue_id[port];
 167        m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
 168        n = qconf->tx_mbufs[port].len;
 169
 170        ret = rte_eth_tx_burst(port, queueid, m_table, n);
 171        while (unlikely (ret < n)) {
 172                rte_pktmbuf_free(m_table[ret]);
 173                ret++;
 174        }
 175
 176        qconf->tx_mbufs[port].len = 0;
 177}
 178
 179/* Get number of bits set. */
 180static inline uint32_t
 181bitcnt(uint32_t v)
 182{
 183        uint32_t n;
 184
 185        for (n = 0; v != 0; v &= v - 1, n++)
 186                ;
 187
 188        return n;
 189}
 190
 191/**
 192 * Create the output multicast packet based on the given input packet.
 193 * There are two approaches for creating outgoing packet, though both
 194 * are based on data zero-copy idea, they differ in few details:
 195 * First one creates a clone of the input packet, e.g - walk though all
 196 * segments of the input packet, and for each of them create a new packet
 197 * mbuf and attach that new mbuf to the segment (refer to rte_pktmbuf_clone()
 198 * for more details). Then new mbuf is allocated for the packet header
 199 * and is prepended to the 'clone' mbuf.
 200 * Second approach doesn't make a clone, it just increment refcnt for all
 201 * input packet segments. Then it allocates new mbuf for the packet header
 202 * and prepends it to the input packet.
 203 * Basically first approach reuses only input packet's data, but creates
 204 * it's own copy of packet's metadata. Second approach reuses both input's
 205 * packet data and metadata.
 206 * The advantage of first approach - is that each outgoing packet has it's
 207 * own copy of metadata, so we can safely modify data pointer of the
 208 * input packet. That allows us to skip creation if the output packet for
 209 * the last destination port, but instead modify input packet's header inplace,
 210 * e.g: for N destination ports we need to invoke mcast_out_pkt (N-1) times.
 211 * The advantage of second approach - less work for each outgoing packet,
 212 * e.g: we skip "clone" operation completely. Though it comes with a price -
 213 * input packet's metadata has to be intact. So for N destination ports we
 214 * need to invoke mcast_out_pkt N times.
 215 * So for small number of outgoing ports (and segments in the input packet)
 216 * first approach will be faster.
 217 * As number of outgoing ports (and/or input segments) will grow,
 218 * second way will become more preferable.
 219 *
 220 *  @param pkt
 221 *  Input packet mbuf.
 222 *  @param use_clone
 223 *  Control which of the two approaches described above should be used:
 224 *  - 0 - use second approach:
 225 *    Don't "clone" input packet.
 226 *    Prepend new header directly to the input packet
 227 *  - 1 - use first approach:
 228 *    Make a "clone" of input packet first.
 229 *    Prepend new header to the clone of the input packet
 230 *  @return
 231 *  - The pointer to the new outgoing packet.
 232 *  - NULL if operation failed.
 233 */
 234static inline struct rte_mbuf *
 235mcast_out_pkt(struct rte_mbuf *pkt, int use_clone)
 236{
 237        struct rte_mbuf *hdr;
 238
 239        /* Create new mbuf for the header. */
 240        if (unlikely ((hdr = rte_pktmbuf_alloc(header_pool)) == NULL))
 241                return NULL;
 242
 243        /* If requested, then make a new clone packet. */
 244        if (use_clone != 0 &&
 245            unlikely ((pkt = rte_pktmbuf_clone(pkt, clone_pool)) == NULL)) {
 246                rte_pktmbuf_free(hdr);
 247                return NULL;
 248        }
 249
 250        /* prepend new header */
 251        hdr->next = pkt;
 252
 253        /* update header's fields */
 254        hdr->pkt_len = (uint16_t)(hdr->data_len + pkt->pkt_len);
 255        hdr->nb_segs = pkt->nb_segs + 1;
 256
 257        __rte_mbuf_sanity_check(hdr, 1);
 258        return hdr;
 259}
 260
 261/*
 262 * Write new Ethernet header to the outgoing packet,
 263 * and put it into the outgoing queue for the given port.
 264 */
 265static inline void
 266mcast_send_pkt(struct rte_mbuf *pkt, struct rte_ether_addr *dest_addr,
 267                struct lcore_queue_conf *qconf, uint16_t port)
 268{
 269        struct rte_ether_hdr *ethdr;
 270        uint16_t len;
 271
 272        /* Construct Ethernet header. */
 273        ethdr = (struct rte_ether_hdr *)
 274                rte_pktmbuf_prepend(pkt, (uint16_t)sizeof(*ethdr));
 275        RTE_ASSERT(ethdr != NULL);
 276
 277        rte_ether_addr_copy(dest_addr, &ethdr->d_addr);
 278        rte_ether_addr_copy(&ports_eth_addr[port], &ethdr->s_addr);
 279        ethdr->ether_type = rte_be_to_cpu_16(RTE_ETHER_TYPE_IPV4);
 280
 281        /* Put new packet into the output queue */
 282        len = qconf->tx_mbufs[port].len;
 283        qconf->tx_mbufs[port].m_table[len] = pkt;
 284        qconf->tx_mbufs[port].len = ++len;
 285
 286        /* Transmit packets */
 287        if (unlikely(MAX_PKT_BURST == len))
 288                send_burst(qconf, port);
 289}
 290
 291/* Multicast forward of the input packet */
 292static inline void
 293mcast_forward(struct rte_mbuf *m, struct lcore_queue_conf *qconf)
 294{
 295        struct rte_mbuf *mc;
 296        struct rte_ipv4_hdr *iphdr;
 297        uint32_t dest_addr, port_mask, port_num, use_clone;
 298        int32_t hash;
 299        uint16_t port;
 300        union {
 301                uint64_t as_int;
 302                struct rte_ether_addr as_addr;
 303        } dst_eth_addr;
 304
 305        /* Remove the Ethernet header from the input packet */
 306        iphdr = (struct rte_ipv4_hdr *)
 307                rte_pktmbuf_adj(m, (uint16_t)sizeof(struct rte_ether_hdr));
 308        RTE_ASSERT(iphdr != NULL);
 309
 310        dest_addr = rte_be_to_cpu_32(iphdr->dst_addr);
 311
 312        /*
 313         * Check that it is a valid multicast address and
 314         * we have some active ports assigned to it.
 315         */
 316        if (!RTE_IS_IPV4_MCAST(dest_addr) ||
 317            (hash = rte_fbk_hash_lookup(mcast_hash, dest_addr)) <= 0 ||
 318            (port_mask = hash & enabled_port_mask) == 0) {
 319                rte_pktmbuf_free(m);
 320                return;
 321        }
 322
 323        /* Calculate number of destination ports. */
 324        port_num = bitcnt(port_mask);
 325
 326        /* Should we use rte_pktmbuf_clone() or not. */
 327        use_clone = (port_num <= MCAST_CLONE_PORTS &&
 328            m->nb_segs <= MCAST_CLONE_SEGS);
 329
 330        /* Mark all packet's segments as referenced port_num times */
 331        if (use_clone == 0)
 332                rte_pktmbuf_refcnt_update(m, (uint16_t)port_num);
 333
 334        /* construct destination ethernet address */
 335        dst_eth_addr.as_int = ETHER_ADDR_FOR_IPV4_MCAST(dest_addr);
 336
 337        for (port = 0; use_clone != port_mask; port_mask >>= 1, port++) {
 338
 339                /* Prepare output packet and send it out. */
 340                if ((port_mask & 1) != 0) {
 341                        if (likely ((mc = mcast_out_pkt(m, use_clone)) != NULL))
 342                                mcast_send_pkt(mc, &dst_eth_addr.as_addr,
 343                                                qconf, port);
 344                        else if (use_clone == 0)
 345                                rte_pktmbuf_free(m);
 346                }
 347        }
 348
 349        /*
 350         * If we making clone packets, then, for the last destination port,
 351         * we can overwrite input packet's metadata.
 352         */
 353        if (use_clone != 0)
 354                mcast_send_pkt(m, &dst_eth_addr.as_addr, qconf, port);
 355        else
 356                rte_pktmbuf_free(m);
 357}
 358
 359/* Send burst of outgoing packet, if timeout expires. */
 360static inline void
 361send_timeout_burst(struct lcore_queue_conf *qconf)
 362{
 363        uint64_t cur_tsc;
 364        uint16_t portid;
 365        const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
 366
 367        cur_tsc = rte_rdtsc();
 368        if (likely (cur_tsc < qconf->tx_tsc + drain_tsc))
 369                return;
 370
 371        for (portid = 0; portid < MAX_PORTS; portid++) {
 372                if (qconf->tx_mbufs[portid].len != 0)
 373                        send_burst(qconf, portid);
 374        }
 375        qconf->tx_tsc = cur_tsc;
 376}
 377
 378/* main processing loop */
 379static int
 380main_loop(__rte_unused void *dummy)
 381{
 382        struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
 383        unsigned lcore_id;
 384        int i, j, nb_rx;
 385        uint16_t portid;
 386        struct lcore_queue_conf *qconf;
 387
 388        lcore_id = rte_lcore_id();
 389        qconf = &lcore_queue_conf[lcore_id];
 390
 391
 392        if (qconf->n_rx_queue == 0) {
 393                RTE_LOG(INFO, IPv4_MULTICAST, "lcore %u has nothing to do\n",
 394                    lcore_id);
 395                return 0;
 396        }
 397
 398        RTE_LOG(INFO, IPv4_MULTICAST, "entering main loop on lcore %u\n",
 399            lcore_id);
 400
 401        for (i = 0; i < qconf->n_rx_queue; i++) {
 402
 403                portid = qconf->rx_queue_list[i];
 404                RTE_LOG(INFO, IPv4_MULTICAST, " -- lcoreid=%u portid=%d\n",
 405                    lcore_id, portid);
 406        }
 407
 408        while (1) {
 409
 410                /*
 411                 * Read packet from RX queues
 412                 */
 413                for (i = 0; i < qconf->n_rx_queue; i++) {
 414
 415                        portid = qconf->rx_queue_list[i];
 416                        nb_rx = rte_eth_rx_burst(portid, 0, pkts_burst,
 417                                                 MAX_PKT_BURST);
 418
 419                        /* Prefetch first packets */
 420                        for (j = 0; j < PREFETCH_OFFSET && j < nb_rx; j++) {
 421                                rte_prefetch0(rte_pktmbuf_mtod(
 422                                                pkts_burst[j], void *));
 423                        }
 424
 425                        /* Prefetch and forward already prefetched packets */
 426                        for (j = 0; j < (nb_rx - PREFETCH_OFFSET); j++) {
 427                                rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[
 428                                                j + PREFETCH_OFFSET], void *));
 429                                mcast_forward(pkts_burst[j], qconf);
 430                        }
 431
 432                        /* Forward remaining prefetched packets */
 433                        for (; j < nb_rx; j++) {
 434                                mcast_forward(pkts_burst[j], qconf);
 435                        }
 436                }
 437
 438                /* Send out packets from TX queues */
 439                send_timeout_burst(qconf);
 440        }
 441}
 442
 443/* display usage */
 444static void
 445print_usage(const char *prgname)
 446{
 447        printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
 448            "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
 449            "  -q NQ: number of queue (=ports) per lcore (default is 1)\n",
 450            prgname);
 451}
 452
 453static uint32_t
 454parse_portmask(const char *portmask)
 455{
 456        char *end = NULL;
 457        unsigned long pm;
 458
 459        /* parse hexadecimal string */
 460        pm = strtoul(portmask, &end, 16);
 461        if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
 462                return 0;
 463
 464        return (uint32_t)pm;
 465}
 466
 467static int
 468parse_nqueue(const char *q_arg)
 469{
 470        char *end = NULL;
 471        unsigned long n;
 472
 473        /* parse numerical string */
 474        errno = 0;
 475        n = strtoul(q_arg, &end, 0);
 476        if (errno != 0 || end == NULL || *end != '\0' ||
 477                        n == 0 || n >= MAX_RX_QUEUE_PER_LCORE)
 478                return -1;
 479
 480        return n;
 481}
 482
 483/* Parse the argument given in the command line of the application */
 484static int
 485parse_args(int argc, char **argv)
 486{
 487        int opt, ret;
 488        char **argvopt;
 489        int option_index;
 490        char *prgname = argv[0];
 491        static struct option lgopts[] = {
 492                {NULL, 0, 0, 0}
 493        };
 494
 495        argvopt = argv;
 496
 497        while ((opt = getopt_long(argc, argvopt, "p:q:",
 498                                  lgopts, &option_index)) != EOF) {
 499
 500                switch (opt) {
 501                /* portmask */
 502                case 'p':
 503                        enabled_port_mask = parse_portmask(optarg);
 504                        if (enabled_port_mask == 0) {
 505                                printf("invalid portmask\n");
 506                                print_usage(prgname);
 507                                return -1;
 508                        }
 509                        break;
 510
 511                /* nqueue */
 512                case 'q':
 513                        rx_queue_per_lcore = parse_nqueue(optarg);
 514                        if (rx_queue_per_lcore < 0) {
 515                                printf("invalid queue number\n");
 516                                print_usage(prgname);
 517                                return -1;
 518                        }
 519                        break;
 520
 521                default:
 522                        print_usage(prgname);
 523                        return -1;
 524                }
 525        }
 526
 527        if (optind >= 0)
 528                argv[optind-1] = prgname;
 529
 530        ret = optind-1;
 531        optind = 1; /* reset getopt lib */
 532        return ret;
 533}
 534
 535static void
 536print_ethaddr(const char *name, struct rte_ether_addr *eth_addr)
 537{
 538        char buf[RTE_ETHER_ADDR_FMT_SIZE];
 539        rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr);
 540        printf("%s%s", name, buf);
 541}
 542
 543static int
 544init_mcast_hash(void)
 545{
 546        uint32_t i;
 547
 548        mcast_hash_params.socket_id = rte_socket_id();
 549        mcast_hash = rte_fbk_hash_create(&mcast_hash_params);
 550        if (mcast_hash == NULL){
 551                return -1;
 552        }
 553
 554        for (i = 0; i < RTE_DIM(mcast_group_table); i++) {
 555                if (rte_fbk_hash_add_key(mcast_hash,
 556                        mcast_group_table[i].ip,
 557                        mcast_group_table[i].port_mask) < 0) {
 558                        return -1;
 559                }
 560        }
 561
 562        return 0;
 563}
 564
 565/* Check the link status of all ports in up to 9s, and print them finally */
 566static void
 567check_all_ports_link_status(uint32_t port_mask)
 568{
 569#define CHECK_INTERVAL 100 /* 100ms */
 570#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
 571        uint16_t portid;
 572        uint8_t count, all_ports_up, print_flag = 0;
 573        struct rte_eth_link link;
 574        int ret;
 575        char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
 576
 577        printf("\nChecking link status");
 578        fflush(stdout);
 579        for (count = 0; count <= MAX_CHECK_TIME; count++) {
 580                all_ports_up = 1;
 581                RTE_ETH_FOREACH_DEV(portid) {
 582                        if ((port_mask & (1 << portid)) == 0)
 583                                continue;
 584                        memset(&link, 0, sizeof(link));
 585                        ret = rte_eth_link_get_nowait(portid, &link);
 586                        if (ret < 0) {
 587                                all_ports_up = 0;
 588                                if (print_flag == 1)
 589                                        printf("Port %u link get failed: %s\n",
 590                                                portid, rte_strerror(-ret));
 591                                continue;
 592                        }
 593                        /* print link status if flag set */
 594                        if (print_flag == 1) {
 595                                rte_eth_link_to_str(link_status_text,
 596                                        sizeof(link_status_text),
 597                                        &link);
 598                                printf("Port %d %s\n", portid,
 599                                       link_status_text);
 600                                continue;
 601                        }
 602                        /* clear all_ports_up flag if any link down */
 603                        if (link.link_status == ETH_LINK_DOWN) {
 604                                all_ports_up = 0;
 605                                break;
 606                        }
 607                }
 608                /* after finally printing all link status, get out */
 609                if (print_flag == 1)
 610                        break;
 611
 612                if (all_ports_up == 0) {
 613                        printf(".");
 614                        fflush(stdout);
 615                        rte_delay_ms(CHECK_INTERVAL);
 616                }
 617
 618                /* set the print_flag if all ports up or timeout */
 619                if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
 620                        print_flag = 1;
 621                        printf("done\n");
 622                }
 623        }
 624}
 625
 626int
 627main(int argc, char **argv)
 628{
 629        struct lcore_queue_conf *qconf;
 630        struct rte_eth_dev_info dev_info;
 631        struct rte_eth_txconf *txconf;
 632        int ret;
 633        uint16_t queueid;
 634        unsigned lcore_id = 0, rx_lcore_id = 0;
 635        uint32_t n_tx_queue, nb_lcores;
 636        uint16_t portid;
 637
 638        /* init EAL */
 639        ret = rte_eal_init(argc, argv);
 640        if (ret < 0)
 641                rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
 642        argc -= ret;
 643        argv += ret;
 644
 645        /* parse application arguments (after the EAL ones) */
 646        ret = parse_args(argc, argv);
 647        if (ret < 0)
 648                rte_exit(EXIT_FAILURE, "Invalid IPV4_MULTICAST parameters\n");
 649
 650        /* create the mbuf pools */
 651        packet_pool = rte_pktmbuf_pool_create("packet_pool", NB_PKT_MBUF, 32,
 652                0, PKT_MBUF_DATA_SIZE, rte_socket_id());
 653
 654        if (packet_pool == NULL)
 655                rte_exit(EXIT_FAILURE, "Cannot init packet mbuf pool\n");
 656
 657        header_pool = rte_pktmbuf_pool_create("header_pool", NB_HDR_MBUF, 32,
 658                0, HDR_MBUF_DATA_SIZE, rte_socket_id());
 659
 660        if (header_pool == NULL)
 661                rte_exit(EXIT_FAILURE, "Cannot init header mbuf pool\n");
 662
 663        clone_pool = rte_pktmbuf_pool_create("clone_pool", NB_CLONE_MBUF, 32,
 664                0, 0, rte_socket_id());
 665
 666        if (clone_pool == NULL)
 667                rte_exit(EXIT_FAILURE, "Cannot init clone mbuf pool\n");
 668
 669        nb_ports = rte_eth_dev_count_avail();
 670        if (nb_ports == 0)
 671                rte_exit(EXIT_FAILURE, "No physical ports!\n");
 672        if (nb_ports > MAX_PORTS)
 673                nb_ports = MAX_PORTS;
 674
 675        nb_lcores = rte_lcore_count();
 676
 677        /* initialize all ports */
 678        RTE_ETH_FOREACH_DEV(portid) {
 679                struct rte_eth_rxconf rxq_conf;
 680                struct rte_eth_conf local_port_conf = port_conf;
 681
 682                /* skip ports that are not enabled */
 683                if ((enabled_port_mask & (1 << portid)) == 0) {
 684                        printf("Skipping disabled port %d\n", portid);
 685                        continue;
 686                }
 687
 688                qconf = &lcore_queue_conf[rx_lcore_id];
 689
 690                /* limit the frame size to the maximum supported by NIC */
 691                ret = rte_eth_dev_info_get(portid, &dev_info);
 692                if (ret != 0)
 693                        rte_exit(EXIT_FAILURE,
 694                                "Error during getting device (port %u) info: %s\n",
 695                                portid, strerror(-ret));
 696
 697                local_port_conf.rxmode.max_rx_pkt_len = RTE_MIN(
 698                    dev_info.max_rx_pktlen,
 699                    local_port_conf.rxmode.max_rx_pkt_len);
 700
 701                /* get the lcore_id for this port */
 702                while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
 703                       qconf->n_rx_queue == (unsigned)rx_queue_per_lcore) {
 704
 705                        rx_lcore_id ++;
 706                        qconf = &lcore_queue_conf[rx_lcore_id];
 707
 708                        if (rx_lcore_id >= RTE_MAX_LCORE)
 709                                rte_exit(EXIT_FAILURE, "Not enough cores\n");
 710                }
 711                qconf->rx_queue_list[qconf->n_rx_queue] = portid;
 712                qconf->n_rx_queue++;
 713
 714                /* init port */
 715                printf("Initializing port %d on lcore %u... ", portid,
 716                       rx_lcore_id);
 717                fflush(stdout);
 718
 719                n_tx_queue = nb_lcores;
 720                if (n_tx_queue > MAX_TX_QUEUE_PER_PORT)
 721                        n_tx_queue = MAX_TX_QUEUE_PER_PORT;
 722
 723                ret = rte_eth_dev_configure(portid, 1, (uint16_t)n_tx_queue,
 724                                            &local_port_conf);
 725                if (ret < 0)
 726                        rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%d\n",
 727                                  ret, portid);
 728
 729                ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
 730                                                       &nb_txd);
 731                if (ret < 0)
 732                        rte_exit(EXIT_FAILURE,
 733                                 "Cannot adjust number of descriptors: err=%d, port=%d\n",
 734                                 ret, portid);
 735
 736                ret = rte_eth_macaddr_get(portid, &ports_eth_addr[portid]);
 737                if (ret < 0)
 738                        rte_exit(EXIT_FAILURE,
 739                                 "Cannot get MAC address: err=%d, port=%d\n",
 740                                 ret, portid);
 741
 742                print_ethaddr(" Address:", &ports_eth_addr[portid]);
 743                printf(", ");
 744
 745                /* init one RX queue */
 746                queueid = 0;
 747                printf("rxq=%hu ", queueid);
 748                fflush(stdout);
 749                rxq_conf = dev_info.default_rxconf;
 750                rxq_conf.offloads = local_port_conf.rxmode.offloads;
 751                ret = rte_eth_rx_queue_setup(portid, queueid, nb_rxd,
 752                                             rte_eth_dev_socket_id(portid),
 753                                             &rxq_conf,
 754                                             packet_pool);
 755                if (ret < 0)
 756                        rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d, port=%d\n",
 757                                  ret, portid);
 758
 759                /* init one TX queue per couple (lcore,port) */
 760                queueid = 0;
 761
 762                RTE_LCORE_FOREACH(lcore_id) {
 763                        if (rte_lcore_is_enabled(lcore_id) == 0)
 764                                continue;
 765                        printf("txq=%u,%hu ", lcore_id, queueid);
 766                        fflush(stdout);
 767
 768                        txconf = &dev_info.default_txconf;
 769                        txconf->offloads = local_port_conf.txmode.offloads;
 770                        ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd,
 771                                                     rte_lcore_to_socket_id(lcore_id), txconf);
 772                        if (ret < 0)
 773                                rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d, "
 774                                          "port=%d\n", ret, portid);
 775
 776                        qconf = &lcore_queue_conf[lcore_id];
 777                        qconf->tx_queue_id[portid] = queueid;
 778                        queueid++;
 779                }
 780                ret = rte_eth_allmulticast_enable(portid);
 781                if (ret < 0)
 782                        rte_exit(EXIT_FAILURE,
 783                                "rte_eth_allmulticast_enable: err=%d, port=%d\n",
 784                                ret, portid);
 785                /* Start device */
 786                ret = rte_eth_dev_start(portid);
 787                if (ret < 0)
 788                        rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, port=%d\n",
 789                                  ret, portid);
 790
 791                printf("done:\n");
 792        }
 793
 794        check_all_ports_link_status(enabled_port_mask);
 795
 796        /* initialize the multicast hash */
 797        int retval = init_mcast_hash();
 798        if (retval != 0)
 799                rte_exit(EXIT_FAILURE, "Cannot build the multicast hash\n");
 800
 801        /* launch per-lcore init on every lcore */
 802        rte_eal_mp_remote_launch(main_loop, NULL, CALL_MAIN);
 803        RTE_LCORE_FOREACH_WORKER(lcore_id) {
 804                if (rte_eal_wait_lcore(lcore_id) < 0)
 805                        return -1;
 806        }
 807
 808        return 0;
 809}
 810