dpdk/examples/l3fwd/main.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2010-2021 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#include <signal.h>
  16#include <stdbool.h>
  17
  18#include <rte_common.h>
  19#include <rte_vect.h>
  20#include <rte_byteorder.h>
  21#include <rte_log.h>
  22#include <rte_malloc.h>
  23#include <rte_memory.h>
  24#include <rte_memcpy.h>
  25#include <rte_eal.h>
  26#include <rte_launch.h>
  27#include <rte_cycles.h>
  28#include <rte_prefetch.h>
  29#include <rte_lcore.h>
  30#include <rte_per_lcore.h>
  31#include <rte_branch_prediction.h>
  32#include <rte_interrupts.h>
  33#include <rte_random.h>
  34#include <rte_debug.h>
  35#include <rte_ether.h>
  36#include <rte_mempool.h>
  37#include <rte_mbuf.h>
  38#include <rte_ip.h>
  39#include <rte_tcp.h>
  40#include <rte_udp.h>
  41#include <rte_string_fns.h>
  42#include <rte_cpuflags.h>
  43
  44#include <cmdline_parse.h>
  45#include <cmdline_parse_etheraddr.h>
  46
  47#include "l3fwd.h"
  48#include "l3fwd_event.h"
  49#include "l3fwd_route.h"
  50
  51#define MAX_TX_QUEUE_PER_PORT RTE_MAX_LCORE
  52#define MAX_RX_QUEUE_PER_PORT 128
  53
  54#define MAX_LCORE_PARAMS 1024
  55
  56/* Static global variables used within this file. */
  57static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
  58static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
  59
  60/**< Ports set in promiscuous mode off by default. */
  61static int promiscuous_on;
  62
  63/* Select Longest-Prefix, Exact match or Forwarding Information Base. */
  64enum L3FWD_LOOKUP_MODE {
  65        L3FWD_LOOKUP_DEFAULT,
  66        L3FWD_LOOKUP_LPM,
  67        L3FWD_LOOKUP_EM,
  68        L3FWD_LOOKUP_FIB
  69};
  70static enum L3FWD_LOOKUP_MODE lookup_mode;
  71
  72/* Global variables. */
  73
  74static int numa_on = 1; /**< NUMA is enabled by default. */
  75static int parse_ptype; /**< Parse packet type using rx callback, and */
  76                        /**< disabled by default */
  77static int per_port_pool; /**< Use separate buffer pools per port; disabled */
  78                          /**< by default */
  79
  80volatile bool force_quit;
  81
  82/* ethernet addresses of ports */
  83uint64_t dest_eth_addr[RTE_MAX_ETHPORTS];
  84struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
  85
  86xmm_t val_eth[RTE_MAX_ETHPORTS];
  87
  88/* mask of enabled ports */
  89uint32_t enabled_port_mask;
  90
  91/* Used only in exact match mode. */
  92int ipv6; /**< ipv6 is false by default. */
  93uint32_t hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT;
  94
  95struct lcore_conf lcore_conf[RTE_MAX_LCORE];
  96
  97struct lcore_params {
  98        uint16_t port_id;
  99        uint8_t queue_id;
 100        uint8_t lcore_id;
 101} __rte_cache_aligned;
 102
 103static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS];
 104static struct lcore_params lcore_params_array_default[] = {
 105        {0, 0, 2},
 106        {0, 1, 2},
 107        {0, 2, 2},
 108        {1, 0, 2},
 109        {1, 1, 2},
 110        {1, 2, 2},
 111        {2, 0, 2},
 112        {3, 0, 3},
 113        {3, 1, 3},
 114};
 115
 116static struct lcore_params * lcore_params = lcore_params_array_default;
 117static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) /
 118                                sizeof(lcore_params_array_default[0]);
 119
 120static struct rte_eth_conf port_conf = {
 121        .rxmode = {
 122                .mq_mode = RTE_ETH_MQ_RX_RSS,
 123                .split_hdr_size = 0,
 124                .offloads = RTE_ETH_RX_OFFLOAD_CHECKSUM,
 125        },
 126        .rx_adv_conf = {
 127                .rss_conf = {
 128                        .rss_key = NULL,
 129                        .rss_hf = RTE_ETH_RSS_IP,
 130                },
 131        },
 132        .txmode = {
 133                .mq_mode = RTE_ETH_MQ_TX_NONE,
 134        },
 135};
 136
 137static uint32_t max_pkt_len;
 138
 139static struct rte_mempool *pktmbuf_pool[RTE_MAX_ETHPORTS][NB_SOCKETS];
 140static struct rte_mempool *vector_pool[RTE_MAX_ETHPORTS];
 141static uint8_t lkp_per_socket[NB_SOCKETS];
 142
 143struct l3fwd_lkp_mode {
 144        void  (*setup)(int);
 145        int   (*check_ptype)(int);
 146        rte_rx_callback_fn cb_parse_ptype;
 147        int   (*main_loop)(void *);
 148        void* (*get_ipv4_lookup_struct)(int);
 149        void* (*get_ipv6_lookup_struct)(int);
 150};
 151
 152static struct l3fwd_lkp_mode l3fwd_lkp;
 153
 154static struct l3fwd_lkp_mode l3fwd_em_lkp = {
 155        .setup                  = setup_hash,
 156        .check_ptype            = em_check_ptype,
 157        .cb_parse_ptype         = em_cb_parse_ptype,
 158        .main_loop              = em_main_loop,
 159        .get_ipv4_lookup_struct = em_get_ipv4_l3fwd_lookup_struct,
 160        .get_ipv6_lookup_struct = em_get_ipv6_l3fwd_lookup_struct,
 161};
 162
 163static struct l3fwd_lkp_mode l3fwd_lpm_lkp = {
 164        .setup                  = setup_lpm,
 165        .check_ptype            = lpm_check_ptype,
 166        .cb_parse_ptype         = lpm_cb_parse_ptype,
 167        .main_loop              = lpm_main_loop,
 168        .get_ipv4_lookup_struct = lpm_get_ipv4_l3fwd_lookup_struct,
 169        .get_ipv6_lookup_struct = lpm_get_ipv6_l3fwd_lookup_struct,
 170};
 171
 172static struct l3fwd_lkp_mode l3fwd_fib_lkp = {
 173        .setup                  = setup_fib,
 174        .check_ptype            = lpm_check_ptype,
 175        .cb_parse_ptype         = lpm_cb_parse_ptype,
 176        .main_loop              = fib_main_loop,
 177        .get_ipv4_lookup_struct = fib_get_ipv4_l3fwd_lookup_struct,
 178        .get_ipv6_lookup_struct = fib_get_ipv6_l3fwd_lookup_struct,
 179};
 180
 181/*
 182 * 198.18.0.0/16 are set aside for RFC2544 benchmarking (RFC5735).
 183 * 198.18.{0-15}.0/24 = Port {0-15}
 184 */
 185const struct ipv4_l3fwd_route ipv4_l3fwd_route_array[] = {
 186        {RTE_IPV4(198, 18, 0, 0), 24, 0},
 187        {RTE_IPV4(198, 18, 1, 0), 24, 1},
 188        {RTE_IPV4(198, 18, 2, 0), 24, 2},
 189        {RTE_IPV4(198, 18, 3, 0), 24, 3},
 190        {RTE_IPV4(198, 18, 4, 0), 24, 4},
 191        {RTE_IPV4(198, 18, 5, 0), 24, 5},
 192        {RTE_IPV4(198, 18, 6, 0), 24, 6},
 193        {RTE_IPV4(198, 18, 7, 0), 24, 7},
 194        {RTE_IPV4(198, 18, 8, 0), 24, 8},
 195        {RTE_IPV4(198, 18, 9, 0), 24, 9},
 196        {RTE_IPV4(198, 18, 10, 0), 24, 10},
 197        {RTE_IPV4(198, 18, 11, 0), 24, 11},
 198        {RTE_IPV4(198, 18, 12, 0), 24, 12},
 199        {RTE_IPV4(198, 18, 13, 0), 24, 13},
 200        {RTE_IPV4(198, 18, 14, 0), 24, 14},
 201        {RTE_IPV4(198, 18, 15, 0), 24, 15},
 202};
 203
 204/*
 205 * 2001:200::/48 is IANA reserved range for IPv6 benchmarking (RFC5180).
 206 * 2001:200:0:{0-f}::/64 = Port {0-15}
 207 */
 208const struct ipv6_l3fwd_route ipv6_l3fwd_route_array[] = {
 209        {{32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 0},
 210        {{32, 1, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 1},
 211        {{32, 1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 2},
 212        {{32, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 3},
 213        {{32, 1, 2, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 4},
 214        {{32, 1, 2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 5},
 215        {{32, 1, 2, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 6},
 216        {{32, 1, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 7},
 217        {{32, 1, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 8},
 218        {{32, 1, 2, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 9},
 219        {{32, 1, 2, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 10},
 220        {{32, 1, 2, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 11},
 221        {{32, 1, 2, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 12},
 222        {{32, 1, 2, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 13},
 223        {{32, 1, 2, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 14},
 224        {{32, 1, 2, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 15},
 225};
 226
 227/*
 228 * Setup lookup methods for forwarding.
 229 * Currently exact-match, longest-prefix-match and forwarding information
 230 * base are the supported ones.
 231 */
 232static void
 233setup_l3fwd_lookup_tables(void)
 234{
 235        /* Setup HASH lookup functions. */
 236        if (lookup_mode == L3FWD_LOOKUP_EM)
 237                l3fwd_lkp = l3fwd_em_lkp;
 238        /* Setup FIB lookup functions. */
 239        else if (lookup_mode == L3FWD_LOOKUP_FIB)
 240                l3fwd_lkp = l3fwd_fib_lkp;
 241        /* Setup LPM lookup functions. */
 242        else
 243                l3fwd_lkp = l3fwd_lpm_lkp;
 244}
 245
 246static int
 247check_lcore_params(void)
 248{
 249        uint8_t queue, lcore;
 250        uint16_t i;
 251        int socketid;
 252
 253        for (i = 0; i < nb_lcore_params; ++i) {
 254                queue = lcore_params[i].queue_id;
 255                if (queue >= MAX_RX_QUEUE_PER_PORT) {
 256                        printf("invalid queue number: %hhu\n", queue);
 257                        return -1;
 258                }
 259                lcore = lcore_params[i].lcore_id;
 260                if (!rte_lcore_is_enabled(lcore)) {
 261                        printf("error: lcore %hhu is not enabled in lcore mask\n", lcore);
 262                        return -1;
 263                }
 264                if ((socketid = rte_lcore_to_socket_id(lcore) != 0) &&
 265                        (numa_on == 0)) {
 266                        printf("warning: lcore %hhu is on socket %d with numa off \n",
 267                                lcore, socketid);
 268                }
 269        }
 270        return 0;
 271}
 272
 273static int
 274check_port_config(void)
 275{
 276        uint16_t portid;
 277        uint16_t i;
 278
 279        for (i = 0; i < nb_lcore_params; ++i) {
 280                portid = lcore_params[i].port_id;
 281                if ((enabled_port_mask & (1 << portid)) == 0) {
 282                        printf("port %u is not enabled in port mask\n", portid);
 283                        return -1;
 284                }
 285                if (!rte_eth_dev_is_valid_port(portid)) {
 286                        printf("port %u is not present on the board\n", portid);
 287                        return -1;
 288                }
 289        }
 290        return 0;
 291}
 292
 293static uint8_t
 294get_port_n_rx_queues(const uint16_t port)
 295{
 296        int queue = -1;
 297        uint16_t i;
 298
 299        for (i = 0; i < nb_lcore_params; ++i) {
 300                if (lcore_params[i].port_id == port) {
 301                        if (lcore_params[i].queue_id == queue+1)
 302                                queue = lcore_params[i].queue_id;
 303                        else
 304                                rte_exit(EXIT_FAILURE, "queue ids of the port %d must be"
 305                                                " in sequence and must start with 0\n",
 306                                                lcore_params[i].port_id);
 307                }
 308        }
 309        return (uint8_t)(++queue);
 310}
 311
 312static int
 313init_lcore_rx_queues(void)
 314{
 315        uint16_t i, nb_rx_queue;
 316        uint8_t lcore;
 317
 318        for (i = 0; i < nb_lcore_params; ++i) {
 319                lcore = lcore_params[i].lcore_id;
 320                nb_rx_queue = lcore_conf[lcore].n_rx_queue;
 321                if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) {
 322                        printf("error: too many queues (%u) for lcore: %u\n",
 323                                (unsigned)nb_rx_queue + 1, (unsigned)lcore);
 324                        return -1;
 325                } else {
 326                        lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id =
 327                                lcore_params[i].port_id;
 328                        lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id =
 329                                lcore_params[i].queue_id;
 330                        lcore_conf[lcore].n_rx_queue++;
 331                }
 332        }
 333        return 0;
 334}
 335
 336/* display usage */
 337static void
 338print_usage(const char *prgname)
 339{
 340        fprintf(stderr, "%s [EAL options] --"
 341                " -p PORTMASK"
 342                " [-P]"
 343                " [--lookup]"
 344                " --config (port,queue,lcore)[,(port,queue,lcore)]"
 345                " [--eth-dest=X,MM:MM:MM:MM:MM:MM]"
 346                " [--max-pkt-len PKTLEN]"
 347                " [--no-numa]"
 348                " [--hash-entry-num]"
 349                " [--ipv6]"
 350                " [--parse-ptype]"
 351                " [--per-port-pool]"
 352                " [--mode]"
 353                " [--eventq-sched]"
 354                " [--event-vector [--event-vector-size SIZE] [--event-vector-tmo NS]]"
 355                " [-E]"
 356                " [-L]\n\n"
 357
 358                "  -p PORTMASK: Hexadecimal bitmask of ports to configure\n"
 359                "  -P : Enable promiscuous mode\n"
 360                "  --lookup: Select the lookup method\n"
 361                "            Default: lpm\n"
 362                "            Accepted: em (Exact Match), lpm (Longest Prefix Match), fib (Forwarding Information Base)\n"
 363                "  --config (port,queue,lcore): Rx queue configuration\n"
 364                "  --eth-dest=X,MM:MM:MM:MM:MM:MM: Ethernet destination for port X\n"
 365                "  --max-pkt-len PKTLEN: maximum packet length in decimal (64-9600)\n"
 366                "  --no-numa: Disable numa awareness\n"
 367                "  --hash-entry-num: Specify the hash entry number in hexadecimal to be setup\n"
 368                "  --ipv6: Set if running ipv6 packets\n"
 369                "  --parse-ptype: Set to use software to analyze packet type\n"
 370                "  --per-port-pool: Use separate buffer pool per port\n"
 371                "  --mode: Packet transfer mode for I/O, poll or eventdev\n"
 372                "          Default mode = poll\n"
 373                "  --eventq-sched: Event queue synchronization method\n"
 374                "                  ordered, atomic or parallel.\n"
 375                "                  Default: atomic\n"
 376                "                  Valid only if --mode=eventdev\n"
 377                "  --event-eth-rxqs: Number of ethernet RX queues per device.\n"
 378                "                    Default: 1\n"
 379                "                    Valid only if --mode=eventdev\n"
 380                "  --event-vector:  Enable event vectorization.\n"
 381                "  --event-vector-size: Max vector size if event vectorization is enabled.\n"
 382                "  --event-vector-tmo: Max timeout to form vector in nanoseconds if event vectorization is enabled\n"
 383                "  -E : Enable exact match, legacy flag please use --lookup=em instead\n"
 384                "  -L : Enable longest prefix match, legacy flag please use --lookup=lpm instead\n\n",
 385                prgname);
 386}
 387
 388static int
 389parse_max_pkt_len(const char *pktlen)
 390{
 391        char *end = NULL;
 392        unsigned long len;
 393
 394        /* parse decimal string */
 395        len = strtoul(pktlen, &end, 10);
 396        if ((pktlen[0] == '\0') || (end == NULL) || (*end != '\0'))
 397                return -1;
 398
 399        if (len == 0)
 400                return -1;
 401
 402        return len;
 403}
 404
 405static int
 406parse_portmask(const char *portmask)
 407{
 408        char *end = NULL;
 409        unsigned long pm;
 410
 411        /* parse hexadecimal string */
 412        pm = strtoul(portmask, &end, 16);
 413        if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
 414                return 0;
 415
 416        return pm;
 417}
 418
 419static int
 420parse_hash_entry_number(const char *hash_entry_num)
 421{
 422        char *end = NULL;
 423        unsigned long hash_en;
 424        /* parse hexadecimal string */
 425        hash_en = strtoul(hash_entry_num, &end, 16);
 426        if ((hash_entry_num[0] == '\0') || (end == NULL) || (*end != '\0'))
 427                return -1;
 428
 429        if (hash_en == 0)
 430                return -1;
 431
 432        return hash_en;
 433}
 434
 435static int
 436parse_config(const char *q_arg)
 437{
 438        char s[256];
 439        const char *p, *p0 = q_arg;
 440        char *end;
 441        enum fieldnames {
 442                FLD_PORT = 0,
 443                FLD_QUEUE,
 444                FLD_LCORE,
 445                _NUM_FLD
 446        };
 447        unsigned long int_fld[_NUM_FLD];
 448        char *str_fld[_NUM_FLD];
 449        int i;
 450        unsigned size;
 451
 452        nb_lcore_params = 0;
 453
 454        while ((p = strchr(p0,'(')) != NULL) {
 455                ++p;
 456                if((p0 = strchr(p,')')) == NULL)
 457                        return -1;
 458
 459                size = p0 - p;
 460                if(size >= sizeof(s))
 461                        return -1;
 462
 463                snprintf(s, sizeof(s), "%.*s", size, p);
 464                if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD)
 465                        return -1;
 466                for (i = 0; i < _NUM_FLD; i++){
 467                        errno = 0;
 468                        int_fld[i] = strtoul(str_fld[i], &end, 0);
 469                        if (errno != 0 || end == str_fld[i] || int_fld[i] > 255)
 470                                return -1;
 471                }
 472                if (nb_lcore_params >= MAX_LCORE_PARAMS) {
 473                        printf("exceeded max number of lcore params: %hu\n",
 474                                nb_lcore_params);
 475                        return -1;
 476                }
 477                lcore_params_array[nb_lcore_params].port_id =
 478                        (uint8_t)int_fld[FLD_PORT];
 479                lcore_params_array[nb_lcore_params].queue_id =
 480                        (uint8_t)int_fld[FLD_QUEUE];
 481                lcore_params_array[nb_lcore_params].lcore_id =
 482                        (uint8_t)int_fld[FLD_LCORE];
 483                ++nb_lcore_params;
 484        }
 485        lcore_params = lcore_params_array;
 486        return 0;
 487}
 488
 489static void
 490parse_eth_dest(const char *optarg)
 491{
 492        uint16_t portid;
 493        char *port_end;
 494        uint8_t c, *dest, peer_addr[6];
 495
 496        errno = 0;
 497        portid = strtoul(optarg, &port_end, 10);
 498        if (errno != 0 || port_end == optarg || *port_end++ != ',')
 499                rte_exit(EXIT_FAILURE,
 500                "Invalid eth-dest: %s", optarg);
 501        if (portid >= RTE_MAX_ETHPORTS)
 502                rte_exit(EXIT_FAILURE,
 503                "eth-dest: port %d >= RTE_MAX_ETHPORTS(%d)\n",
 504                portid, RTE_MAX_ETHPORTS);
 505
 506        if (cmdline_parse_etheraddr(NULL, port_end,
 507                &peer_addr, sizeof(peer_addr)) < 0)
 508                rte_exit(EXIT_FAILURE,
 509                "Invalid ethernet address: %s\n",
 510                port_end);
 511        dest = (uint8_t *)&dest_eth_addr[portid];
 512        for (c = 0; c < 6; c++)
 513                dest[c] = peer_addr[c];
 514        *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid];
 515}
 516
 517static void
 518parse_mode(const char *optarg)
 519{
 520        struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
 521
 522        if (!strcmp(optarg, "poll"))
 523                evt_rsrc->enabled = false;
 524        else if (!strcmp(optarg, "eventdev"))
 525                evt_rsrc->enabled = true;
 526}
 527
 528static void
 529parse_eventq_sched(const char *optarg)
 530{
 531        struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
 532
 533        if (!strcmp(optarg, "ordered"))
 534                evt_rsrc->sched_type = RTE_SCHED_TYPE_ORDERED;
 535        if (!strcmp(optarg, "atomic"))
 536                evt_rsrc->sched_type = RTE_SCHED_TYPE_ATOMIC;
 537        if (!strcmp(optarg, "parallel"))
 538                evt_rsrc->sched_type = RTE_SCHED_TYPE_PARALLEL;
 539}
 540
 541static void
 542parse_event_eth_rx_queues(const char *eth_rx_queues)
 543{
 544        struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
 545        char *end = NULL;
 546        uint8_t num_eth_rx_queues;
 547
 548        /* parse decimal string */
 549        num_eth_rx_queues = strtoul(eth_rx_queues, &end, 10);
 550        if ((eth_rx_queues[0] == '\0') || (end == NULL) || (*end != '\0'))
 551                return;
 552
 553        if (num_eth_rx_queues == 0)
 554                return;
 555
 556        evt_rsrc->eth_rx_queues = num_eth_rx_queues;
 557}
 558
 559static int
 560parse_lookup(const char *optarg)
 561{
 562        if (!strcmp(optarg, "em"))
 563                lookup_mode = L3FWD_LOOKUP_EM;
 564        else if (!strcmp(optarg, "lpm"))
 565                lookup_mode = L3FWD_LOOKUP_LPM;
 566        else if (!strcmp(optarg, "fib"))
 567                lookup_mode = L3FWD_LOOKUP_FIB;
 568        else {
 569                fprintf(stderr, "Invalid lookup option! Accepted options: em, lpm, fib\n");
 570                return -1;
 571        }
 572        return 0;
 573}
 574
 575#define MAX_JUMBO_PKT_LEN  9600
 576
 577static const char short_options[] =
 578        "p:"  /* portmask */
 579        "P"   /* promiscuous */
 580        "L"   /* legacy enable long prefix match */
 581        "E"   /* legacy enable exact match */
 582        ;
 583
 584#define CMD_LINE_OPT_CONFIG "config"
 585#define CMD_LINE_OPT_ETH_DEST "eth-dest"
 586#define CMD_LINE_OPT_NO_NUMA "no-numa"
 587#define CMD_LINE_OPT_IPV6 "ipv6"
 588#define CMD_LINE_OPT_MAX_PKT_LEN "max-pkt-len"
 589#define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num"
 590#define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype"
 591#define CMD_LINE_OPT_PER_PORT_POOL "per-port-pool"
 592#define CMD_LINE_OPT_MODE "mode"
 593#define CMD_LINE_OPT_EVENTQ_SYNC "eventq-sched"
 594#define CMD_LINE_OPT_EVENT_ETH_RX_QUEUES "event-eth-rxqs"
 595#define CMD_LINE_OPT_LOOKUP "lookup"
 596#define CMD_LINE_OPT_ENABLE_VECTOR "event-vector"
 597#define CMD_LINE_OPT_VECTOR_SIZE "event-vector-size"
 598#define CMD_LINE_OPT_VECTOR_TMO_NS "event-vector-tmo"
 599
 600enum {
 601        /* long options mapped to a short option */
 602
 603        /* first long only option value must be >= 256, so that we won't
 604         * conflict with short options */
 605        CMD_LINE_OPT_MIN_NUM = 256,
 606        CMD_LINE_OPT_CONFIG_NUM,
 607        CMD_LINE_OPT_ETH_DEST_NUM,
 608        CMD_LINE_OPT_NO_NUMA_NUM,
 609        CMD_LINE_OPT_IPV6_NUM,
 610        CMD_LINE_OPT_MAX_PKT_LEN_NUM,
 611        CMD_LINE_OPT_HASH_ENTRY_NUM_NUM,
 612        CMD_LINE_OPT_PARSE_PTYPE_NUM,
 613        CMD_LINE_OPT_PARSE_PER_PORT_POOL,
 614        CMD_LINE_OPT_MODE_NUM,
 615        CMD_LINE_OPT_EVENTQ_SYNC_NUM,
 616        CMD_LINE_OPT_EVENT_ETH_RX_QUEUES_NUM,
 617        CMD_LINE_OPT_LOOKUP_NUM,
 618        CMD_LINE_OPT_ENABLE_VECTOR_NUM,
 619        CMD_LINE_OPT_VECTOR_SIZE_NUM,
 620        CMD_LINE_OPT_VECTOR_TMO_NS_NUM
 621};
 622
 623static const struct option lgopts[] = {
 624        {CMD_LINE_OPT_CONFIG, 1, 0, CMD_LINE_OPT_CONFIG_NUM},
 625        {CMD_LINE_OPT_ETH_DEST, 1, 0, CMD_LINE_OPT_ETH_DEST_NUM},
 626        {CMD_LINE_OPT_NO_NUMA, 0, 0, CMD_LINE_OPT_NO_NUMA_NUM},
 627        {CMD_LINE_OPT_IPV6, 0, 0, CMD_LINE_OPT_IPV6_NUM},
 628        {CMD_LINE_OPT_MAX_PKT_LEN, 1, 0, CMD_LINE_OPT_MAX_PKT_LEN_NUM},
 629        {CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, CMD_LINE_OPT_HASH_ENTRY_NUM_NUM},
 630        {CMD_LINE_OPT_PARSE_PTYPE, 0, 0, CMD_LINE_OPT_PARSE_PTYPE_NUM},
 631        {CMD_LINE_OPT_PER_PORT_POOL, 0, 0, CMD_LINE_OPT_PARSE_PER_PORT_POOL},
 632        {CMD_LINE_OPT_MODE, 1, 0, CMD_LINE_OPT_MODE_NUM},
 633        {CMD_LINE_OPT_EVENTQ_SYNC, 1, 0, CMD_LINE_OPT_EVENTQ_SYNC_NUM},
 634        {CMD_LINE_OPT_EVENT_ETH_RX_QUEUES, 1, 0,
 635                                        CMD_LINE_OPT_EVENT_ETH_RX_QUEUES_NUM},
 636        {CMD_LINE_OPT_LOOKUP, 1, 0, CMD_LINE_OPT_LOOKUP_NUM},
 637        {CMD_LINE_OPT_ENABLE_VECTOR, 0, 0, CMD_LINE_OPT_ENABLE_VECTOR_NUM},
 638        {CMD_LINE_OPT_VECTOR_SIZE, 1, 0, CMD_LINE_OPT_VECTOR_SIZE_NUM},
 639        {CMD_LINE_OPT_VECTOR_TMO_NS, 1, 0, CMD_LINE_OPT_VECTOR_TMO_NS_NUM},
 640        {NULL, 0, 0, 0}
 641};
 642
 643/*
 644 * This expression is used to calculate the number of mbufs needed
 645 * depending on user input, taking  into account memory for rx and
 646 * tx hardware rings, cache per lcore and mtable per port per lcore.
 647 * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum
 648 * value of 8192
 649 */
 650#define NB_MBUF(nports) RTE_MAX(        \
 651        (nports*nb_rx_queue*nb_rxd +            \
 652        nports*nb_lcores*MAX_PKT_BURST +        \
 653        nports*n_tx_queue*nb_txd +              \
 654        nb_lcores*MEMPOOL_CACHE_SIZE),          \
 655        (unsigned)8192)
 656
 657/* Parse the argument given in the command line of the application */
 658static int
 659parse_args(int argc, char **argv)
 660{
 661        int opt, ret;
 662        char **argvopt;
 663        int option_index;
 664        char *prgname = argv[0];
 665        uint8_t lcore_params = 0;
 666        uint8_t eventq_sched = 0;
 667        uint8_t eth_rx_q = 0;
 668        struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
 669
 670        argvopt = argv;
 671
 672        /* Error or normal output strings. */
 673        while ((opt = getopt_long(argc, argvopt, short_options,
 674                                lgopts, &option_index)) != EOF) {
 675
 676                switch (opt) {
 677                /* portmask */
 678                case 'p':
 679                        enabled_port_mask = parse_portmask(optarg);
 680                        if (enabled_port_mask == 0) {
 681                                fprintf(stderr, "Invalid portmask\n");
 682                                print_usage(prgname);
 683                                return -1;
 684                        }
 685                        break;
 686
 687                case 'P':
 688                        promiscuous_on = 1;
 689                        break;
 690
 691                case 'E':
 692                        if (lookup_mode != L3FWD_LOOKUP_DEFAULT) {
 693                                fprintf(stderr, "Only one lookup mode is allowed at a time!\n");
 694                                return -1;
 695                        }
 696                        lookup_mode = L3FWD_LOOKUP_EM;
 697                        break;
 698
 699                case 'L':
 700                        if (lookup_mode != L3FWD_LOOKUP_DEFAULT) {
 701                                fprintf(stderr, "Only one lookup mode is allowed at a time!\n");
 702                                return -1;
 703                        }
 704                        lookup_mode = L3FWD_LOOKUP_LPM;
 705                        break;
 706
 707                /* long options */
 708                case CMD_LINE_OPT_CONFIG_NUM:
 709                        ret = parse_config(optarg);
 710                        if (ret) {
 711                                fprintf(stderr, "Invalid config\n");
 712                                print_usage(prgname);
 713                                return -1;
 714                        }
 715                        lcore_params = 1;
 716                        break;
 717
 718                case CMD_LINE_OPT_ETH_DEST_NUM:
 719                        parse_eth_dest(optarg);
 720                        break;
 721
 722                case CMD_LINE_OPT_NO_NUMA_NUM:
 723                        numa_on = 0;
 724                        break;
 725
 726                case CMD_LINE_OPT_IPV6_NUM:
 727                        ipv6 = 1;
 728                        break;
 729
 730                case CMD_LINE_OPT_MAX_PKT_LEN_NUM:
 731                        max_pkt_len = parse_max_pkt_len(optarg);
 732                        break;
 733
 734                case CMD_LINE_OPT_HASH_ENTRY_NUM_NUM:
 735                        ret = parse_hash_entry_number(optarg);
 736                        if ((ret > 0) && (ret <= L3FWD_HASH_ENTRIES)) {
 737                                hash_entry_number = ret;
 738                        } else {
 739                                fprintf(stderr, "invalid hash entry number\n");
 740                                print_usage(prgname);
 741                                return -1;
 742                        }
 743                        break;
 744
 745                case CMD_LINE_OPT_PARSE_PTYPE_NUM:
 746                        printf("soft parse-ptype is enabled\n");
 747                        parse_ptype = 1;
 748                        break;
 749
 750                case CMD_LINE_OPT_PARSE_PER_PORT_POOL:
 751                        printf("per port buffer pool is enabled\n");
 752                        per_port_pool = 1;
 753                        break;
 754
 755                case CMD_LINE_OPT_MODE_NUM:
 756                        parse_mode(optarg);
 757                        break;
 758
 759                case CMD_LINE_OPT_EVENTQ_SYNC_NUM:
 760                        parse_eventq_sched(optarg);
 761                        eventq_sched = 1;
 762                        break;
 763
 764                case CMD_LINE_OPT_EVENT_ETH_RX_QUEUES_NUM:
 765                        parse_event_eth_rx_queues(optarg);
 766                        eth_rx_q = 1;
 767                        break;
 768
 769                case CMD_LINE_OPT_LOOKUP_NUM:
 770                        if (lookup_mode != L3FWD_LOOKUP_DEFAULT) {
 771                                fprintf(stderr, "Only one lookup mode is allowed at a time!\n");
 772                                return -1;
 773                        }
 774                        ret = parse_lookup(optarg);
 775                        /*
 776                         * If parse_lookup was passed an invalid lookup type
 777                         * then return -1. Error log included within
 778                         * parse_lookup for simplicity.
 779                         */
 780                        if (ret)
 781                                return -1;
 782                        break;
 783
 784                case CMD_LINE_OPT_ENABLE_VECTOR_NUM:
 785                        printf("event vectorization is enabled\n");
 786                        evt_rsrc->vector_enabled = 1;
 787                        break;
 788                case CMD_LINE_OPT_VECTOR_SIZE_NUM:
 789                        evt_rsrc->vector_size = strtol(optarg, NULL, 10);
 790                        break;
 791                case CMD_LINE_OPT_VECTOR_TMO_NS_NUM:
 792                        evt_rsrc->vector_tmo_ns = strtoull(optarg, NULL, 10);
 793                        break;
 794                default:
 795                        print_usage(prgname);
 796                        return -1;
 797                }
 798        }
 799
 800        if (evt_rsrc->enabled && lcore_params) {
 801                fprintf(stderr, "lcore config is not valid when event mode is selected\n");
 802                return -1;
 803        }
 804
 805        if (!evt_rsrc->enabled && eth_rx_q) {
 806                fprintf(stderr, "eth_rx_queues is valid only when event mode is selected\n");
 807                return -1;
 808        }
 809
 810        if (!evt_rsrc->enabled && eventq_sched) {
 811                fprintf(stderr, "eventq_sched is valid only when event mode is selected\n");
 812                return -1;
 813        }
 814
 815        if (evt_rsrc->vector_enabled && !evt_rsrc->vector_size) {
 816                evt_rsrc->vector_size = VECTOR_SIZE_DEFAULT;
 817                fprintf(stderr, "vector size set to default (%" PRIu16 ")\n",
 818                        evt_rsrc->vector_size);
 819        }
 820
 821        if (evt_rsrc->vector_enabled && !evt_rsrc->vector_tmo_ns) {
 822                evt_rsrc->vector_tmo_ns = VECTOR_TMO_NS_DEFAULT;
 823                fprintf(stderr,
 824                        "vector timeout set to default (%" PRIu64 " ns)\n",
 825                        evt_rsrc->vector_tmo_ns);
 826        }
 827
 828        /*
 829         * Nothing is selected, pick longest-prefix match
 830         * as default match.
 831         */
 832        if (lookup_mode == L3FWD_LOOKUP_DEFAULT) {
 833                fprintf(stderr, "Neither LPM, EM, or FIB selected, defaulting to LPM\n");
 834                lookup_mode = L3FWD_LOOKUP_LPM;
 835        }
 836
 837        /*
 838         * ipv6 and hash flags are valid only for
 839         * exact match, reset them to default for
 840         * longest-prefix match.
 841         */
 842        if (lookup_mode == L3FWD_LOOKUP_LPM) {
 843                ipv6 = 0;
 844                hash_entry_number = HASH_ENTRY_NUMBER_DEFAULT;
 845        }
 846
 847        if (optind >= 0)
 848                argv[optind-1] = prgname;
 849
 850        ret = optind-1;
 851        optind = 1; /* reset getopt lib */
 852        return ret;
 853}
 854
 855static void
 856print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr)
 857{
 858        char buf[RTE_ETHER_ADDR_FMT_SIZE];
 859        rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr);
 860        printf("%s%s", name, buf);
 861}
 862
 863int
 864init_mem(uint16_t portid, unsigned int nb_mbuf)
 865{
 866        struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
 867        struct lcore_conf *qconf;
 868        int socketid;
 869        unsigned lcore_id;
 870        char s[64];
 871
 872        for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
 873                if (rte_lcore_is_enabled(lcore_id) == 0)
 874                        continue;
 875
 876                if (numa_on)
 877                        socketid = rte_lcore_to_socket_id(lcore_id);
 878                else
 879                        socketid = 0;
 880
 881                if (socketid >= NB_SOCKETS) {
 882                        rte_exit(EXIT_FAILURE,
 883                                "Socket %d of lcore %u is out of range %d\n",
 884                                socketid, lcore_id, NB_SOCKETS);
 885                }
 886
 887                if (pktmbuf_pool[portid][socketid] == NULL) {
 888                        snprintf(s, sizeof(s), "mbuf_pool_%d:%d",
 889                                 portid, socketid);
 890                        pktmbuf_pool[portid][socketid] =
 891                                rte_pktmbuf_pool_create(s, nb_mbuf,
 892                                        MEMPOOL_CACHE_SIZE, 0,
 893                                        RTE_MBUF_DEFAULT_BUF_SIZE, socketid);
 894                        if (pktmbuf_pool[portid][socketid] == NULL)
 895                                rte_exit(EXIT_FAILURE,
 896                                        "Cannot init mbuf pool on socket %d\n",
 897                                        socketid);
 898                        else
 899                                printf("Allocated mbuf pool on socket %d\n",
 900                                        socketid);
 901
 902                        /* Setup LPM, EM(f.e Hash) or FIB. But, only once per
 903                         * available socket.
 904                         */
 905                        if (!lkp_per_socket[socketid]) {
 906                                l3fwd_lkp.setup(socketid);
 907                                lkp_per_socket[socketid] = 1;
 908                        }
 909                }
 910
 911                if (evt_rsrc->vector_enabled && vector_pool[portid] == NULL) {
 912                        unsigned int nb_vec;
 913
 914                        nb_vec = (nb_mbuf + evt_rsrc->vector_size - 1) /
 915                                 evt_rsrc->vector_size;
 916                        snprintf(s, sizeof(s), "vector_pool_%d", portid);
 917                        vector_pool[portid] = rte_event_vector_pool_create(
 918                                s, nb_vec, 0, evt_rsrc->vector_size, socketid);
 919                        if (vector_pool[portid] == NULL)
 920                                rte_exit(EXIT_FAILURE,
 921                                         "Failed to create vector pool for port %d\n",
 922                                         portid);
 923                        else
 924                                printf("Allocated vector pool for port %d\n",
 925                                       portid);
 926                }
 927
 928                qconf = &lcore_conf[lcore_id];
 929                qconf->ipv4_lookup_struct =
 930                        l3fwd_lkp.get_ipv4_lookup_struct(socketid);
 931                qconf->ipv6_lookup_struct =
 932                        l3fwd_lkp.get_ipv6_lookup_struct(socketid);
 933        }
 934        return 0;
 935}
 936
 937/* Check the link status of all ports in up to 9s, and print them finally */
 938static void
 939check_all_ports_link_status(uint32_t port_mask)
 940{
 941#define CHECK_INTERVAL 100 /* 100ms */
 942#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
 943        uint16_t portid;
 944        uint8_t count, all_ports_up, print_flag = 0;
 945        struct rte_eth_link link;
 946        int ret;
 947        char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
 948
 949        printf("\nChecking link status");
 950        fflush(stdout);
 951        for (count = 0; count <= MAX_CHECK_TIME; count++) {
 952                if (force_quit)
 953                        return;
 954                all_ports_up = 1;
 955                RTE_ETH_FOREACH_DEV(portid) {
 956                        if (force_quit)
 957                                return;
 958                        if ((port_mask & (1 << portid)) == 0)
 959                                continue;
 960                        memset(&link, 0, sizeof(link));
 961                        ret = rte_eth_link_get_nowait(portid, &link);
 962                        if (ret < 0) {
 963                                all_ports_up = 0;
 964                                if (print_flag == 1)
 965                                        printf("Port %u link get failed: %s\n",
 966                                                portid, rte_strerror(-ret));
 967                                continue;
 968                        }
 969                        /* print link status if flag set */
 970                        if (print_flag == 1) {
 971                                rte_eth_link_to_str(link_status_text,
 972                                        sizeof(link_status_text), &link);
 973                                printf("Port %d %s\n", portid,
 974                                       link_status_text);
 975                                continue;
 976                        }
 977                        /* clear all_ports_up flag if any link down */
 978                        if (link.link_status == RTE_ETH_LINK_DOWN) {
 979                                all_ports_up = 0;
 980                                break;
 981                        }
 982                }
 983                /* after finally printing all link status, get out */
 984                if (print_flag == 1)
 985                        break;
 986
 987                if (all_ports_up == 0) {
 988                        printf(".");
 989                        fflush(stdout);
 990                        rte_delay_ms(CHECK_INTERVAL);
 991                }
 992
 993                /* set the print_flag if all ports up or timeout */
 994                if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
 995                        print_flag = 1;
 996                        printf("done\n");
 997                }
 998        }
 999}
1000
1001static void
1002signal_handler(int signum)
1003{
1004        if (signum == SIGINT || signum == SIGTERM) {
1005                printf("\n\nSignal %d received, preparing to exit...\n",
1006                                signum);
1007                force_quit = true;
1008        }
1009}
1010
1011static int
1012prepare_ptype_parser(uint16_t portid, uint16_t queueid)
1013{
1014        if (parse_ptype) {
1015                printf("Port %d: softly parse packet type info\n", portid);
1016                if (rte_eth_add_rx_callback(portid, queueid,
1017                                            l3fwd_lkp.cb_parse_ptype,
1018                                            NULL))
1019                        return 1;
1020
1021                printf("Failed to add rx callback: port=%d\n", portid);
1022                return 0;
1023        }
1024
1025        if (l3fwd_lkp.check_ptype(portid))
1026                return 1;
1027
1028        printf("port %d cannot parse packet type, please add --%s\n",
1029               portid, CMD_LINE_OPT_PARSE_PTYPE);
1030        return 0;
1031}
1032
1033static uint32_t
1034eth_dev_get_overhead_len(uint32_t max_rx_pktlen, uint16_t max_mtu)
1035{
1036        uint32_t overhead_len;
1037
1038        if (max_mtu != UINT16_MAX && max_rx_pktlen > max_mtu)
1039                overhead_len = max_rx_pktlen - max_mtu;
1040        else
1041                overhead_len = RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN;
1042
1043        return overhead_len;
1044}
1045
1046static int
1047config_port_max_pkt_len(struct rte_eth_conf *conf,
1048                struct rte_eth_dev_info *dev_info)
1049{
1050        uint32_t overhead_len;
1051
1052        if (max_pkt_len == 0)
1053                return 0;
1054
1055        if (max_pkt_len < RTE_ETHER_MIN_LEN || max_pkt_len > MAX_JUMBO_PKT_LEN)
1056                return -1;
1057
1058        overhead_len = eth_dev_get_overhead_len(dev_info->max_rx_pktlen,
1059                        dev_info->max_mtu);
1060        conf->rxmode.mtu = max_pkt_len - overhead_len;
1061
1062        if (conf->rxmode.mtu > RTE_ETHER_MTU)
1063                conf->txmode.offloads |= RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
1064
1065        return 0;
1066}
1067
1068static void
1069l3fwd_poll_resource_setup(void)
1070{
1071        uint8_t nb_rx_queue, queue, socketid;
1072        struct rte_eth_dev_info dev_info;
1073        uint32_t n_tx_queue, nb_lcores;
1074        struct rte_eth_txconf *txconf;
1075        struct lcore_conf *qconf;
1076        uint16_t queueid, portid;
1077        unsigned int nb_ports;
1078        unsigned int lcore_id;
1079        int ret;
1080
1081        if (check_lcore_params() < 0)
1082                rte_exit(EXIT_FAILURE, "check_lcore_params failed\n");
1083
1084        ret = init_lcore_rx_queues();
1085        if (ret < 0)
1086                rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
1087
1088        nb_ports = rte_eth_dev_count_avail();
1089
1090        if (check_port_config() < 0)
1091                rte_exit(EXIT_FAILURE, "check_port_config failed\n");
1092
1093        nb_lcores = rte_lcore_count();
1094
1095        /* initialize all ports */
1096        RTE_ETH_FOREACH_DEV(portid) {
1097                struct rte_eth_conf local_port_conf = port_conf;
1098
1099                /* skip ports that are not enabled */
1100                if ((enabled_port_mask & (1 << portid)) == 0) {
1101                        printf("\nSkipping disabled port %d\n", portid);
1102                        continue;
1103                }
1104
1105                /* init port */
1106                printf("Initializing port %d ... ", portid );
1107                fflush(stdout);
1108
1109                nb_rx_queue = get_port_n_rx_queues(portid);
1110                n_tx_queue = nb_lcores;
1111                if (n_tx_queue > MAX_TX_QUEUE_PER_PORT)
1112                        n_tx_queue = MAX_TX_QUEUE_PER_PORT;
1113                printf("Creating queues: nb_rxq=%d nb_txq=%u... ",
1114                        nb_rx_queue, (unsigned)n_tx_queue );
1115
1116                ret = rte_eth_dev_info_get(portid, &dev_info);
1117                if (ret != 0)
1118                        rte_exit(EXIT_FAILURE,
1119                                "Error during getting device (port %u) info: %s\n",
1120                                portid, strerror(-ret));
1121
1122                ret = config_port_max_pkt_len(&local_port_conf, &dev_info);
1123                if (ret != 0)
1124                        rte_exit(EXIT_FAILURE,
1125                                "Invalid max packet length: %u (port %u)\n",
1126                                max_pkt_len, portid);
1127
1128                if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
1129                        local_port_conf.txmode.offloads |=
1130                                RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
1131
1132                local_port_conf.rx_adv_conf.rss_conf.rss_hf &=
1133                        dev_info.flow_type_rss_offloads;
1134
1135                if (dev_info.max_rx_queues == 1)
1136                        local_port_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_NONE;
1137
1138                if (local_port_conf.rx_adv_conf.rss_conf.rss_hf !=
1139                                port_conf.rx_adv_conf.rss_conf.rss_hf) {
1140                        printf("Port %u modified RSS hash function based on hardware support,"
1141                                "requested:%#"PRIx64" configured:%#"PRIx64"\n",
1142                                portid,
1143                                port_conf.rx_adv_conf.rss_conf.rss_hf,
1144                                local_port_conf.rx_adv_conf.rss_conf.rss_hf);
1145                }
1146
1147                ret = rte_eth_dev_configure(portid, nb_rx_queue,
1148                                        (uint16_t)n_tx_queue, &local_port_conf);
1149                if (ret < 0)
1150                        rte_exit(EXIT_FAILURE,
1151                                "Cannot configure device: err=%d, port=%d\n",
1152                                ret, portid);
1153
1154                ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
1155                                                       &nb_txd);
1156                if (ret < 0)
1157                        rte_exit(EXIT_FAILURE,
1158                                 "Cannot adjust number of descriptors: err=%d, "
1159                                 "port=%d\n", ret, portid);
1160
1161                ret = rte_eth_macaddr_get(portid, &ports_eth_addr[portid]);
1162                if (ret < 0)
1163                        rte_exit(EXIT_FAILURE,
1164                                 "Cannot get MAC address: err=%d, port=%d\n",
1165                                 ret, portid);
1166
1167                print_ethaddr(" Address:", &ports_eth_addr[portid]);
1168                printf(", ");
1169                print_ethaddr("Destination:",
1170                        (const struct rte_ether_addr *)&dest_eth_addr[portid]);
1171                printf(", ");
1172
1173                /*
1174                 * prepare src MACs for each port.
1175                 */
1176                rte_ether_addr_copy(&ports_eth_addr[portid],
1177                        (struct rte_ether_addr *)(val_eth + portid) + 1);
1178
1179                /* init memory */
1180                if (!per_port_pool) {
1181                        /* portid = 0; this is *not* signifying the first port,
1182                         * rather, it signifies that portid is ignored.
1183                         */
1184                        ret = init_mem(0, NB_MBUF(nb_ports));
1185                } else {
1186                        ret = init_mem(portid, NB_MBUF(1));
1187                }
1188                if (ret < 0)
1189                        rte_exit(EXIT_FAILURE, "init_mem failed\n");
1190
1191                /* init one TX queue per couple (lcore,port) */
1192                queueid = 0;
1193                for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1194                        if (rte_lcore_is_enabled(lcore_id) == 0)
1195                                continue;
1196
1197                        if (numa_on)
1198                                socketid =
1199                                (uint8_t)rte_lcore_to_socket_id(lcore_id);
1200                        else
1201                                socketid = 0;
1202
1203                        printf("txq=%u,%d,%d ", lcore_id, queueid, socketid);
1204                        fflush(stdout);
1205
1206                        txconf = &dev_info.default_txconf;
1207                        txconf->offloads = local_port_conf.txmode.offloads;
1208                        ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd,
1209                                                     socketid, txconf);
1210                        if (ret < 0)
1211                                rte_exit(EXIT_FAILURE,
1212                                        "rte_eth_tx_queue_setup: err=%d, "
1213                                        "port=%d\n", ret, portid);
1214
1215                        qconf = &lcore_conf[lcore_id];
1216                        qconf->tx_queue_id[portid] = queueid;
1217                        queueid++;
1218
1219                        qconf->tx_port_id[qconf->n_tx_port] = portid;
1220                        qconf->n_tx_port++;
1221                }
1222                printf("\n");
1223        }
1224
1225        for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1226                if (rte_lcore_is_enabled(lcore_id) == 0)
1227                        continue;
1228                qconf = &lcore_conf[lcore_id];
1229                printf("\nInitializing rx queues on lcore %u ... ", lcore_id );
1230                fflush(stdout);
1231                /* init RX queues */
1232                for(queue = 0; queue < qconf->n_rx_queue; ++queue) {
1233                        struct rte_eth_rxconf rxq_conf;
1234
1235                        portid = qconf->rx_queue_list[queue].port_id;
1236                        queueid = qconf->rx_queue_list[queue].queue_id;
1237
1238                        if (numa_on)
1239                                socketid =
1240                                (uint8_t)rte_lcore_to_socket_id(lcore_id);
1241                        else
1242                                socketid = 0;
1243
1244                        printf("rxq=%d,%d,%d ", portid, queueid, socketid);
1245                        fflush(stdout);
1246
1247                        ret = rte_eth_dev_info_get(portid, &dev_info);
1248                        if (ret != 0)
1249                                rte_exit(EXIT_FAILURE,
1250                                        "Error during getting device (port %u) info: %s\n",
1251                                        portid, strerror(-ret));
1252
1253                        rxq_conf = dev_info.default_rxconf;
1254                        rxq_conf.offloads = port_conf.rxmode.offloads;
1255                        if (!per_port_pool)
1256                                ret = rte_eth_rx_queue_setup(portid, queueid,
1257                                                nb_rxd, socketid,
1258                                                &rxq_conf,
1259                                                pktmbuf_pool[0][socketid]);
1260                        else
1261                                ret = rte_eth_rx_queue_setup(portid, queueid,
1262                                                nb_rxd, socketid,
1263                                                &rxq_conf,
1264                                                pktmbuf_pool[portid][socketid]);
1265                        if (ret < 0)
1266                                rte_exit(EXIT_FAILURE,
1267                                "rte_eth_rx_queue_setup: err=%d, port=%d\n",
1268                                ret, portid);
1269                }
1270        }
1271}
1272
1273static inline int
1274l3fwd_service_enable(uint32_t service_id)
1275{
1276        uint8_t min_service_count = UINT8_MAX;
1277        uint32_t slcore_array[RTE_MAX_LCORE];
1278        unsigned int slcore = 0;
1279        uint8_t service_count;
1280        int32_t slcore_count;
1281
1282        if (!rte_service_lcore_count())
1283                return -ENOENT;
1284
1285        slcore_count = rte_service_lcore_list(slcore_array, RTE_MAX_LCORE);
1286        if (slcore_count < 0)
1287                return -ENOENT;
1288        /* Get the core which has least number of services running. */
1289        while (slcore_count--) {
1290                /* Reset default mapping */
1291                if (rte_service_map_lcore_set(service_id,
1292                                slcore_array[slcore_count], 0) != 0)
1293                        return -ENOENT;
1294                service_count = rte_service_lcore_count_services(
1295                                slcore_array[slcore_count]);
1296                if (service_count < min_service_count) {
1297                        slcore = slcore_array[slcore_count];
1298                        min_service_count = service_count;
1299                }
1300        }
1301        if (rte_service_map_lcore_set(service_id, slcore, 1))
1302                return -ENOENT;
1303        rte_service_lcore_start(slcore);
1304
1305        return 0;
1306}
1307
1308static void
1309l3fwd_event_service_setup(void)
1310{
1311        struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
1312        struct rte_event_dev_info evdev_info;
1313        uint32_t service_id, caps;
1314        int ret, i;
1315
1316        rte_event_dev_info_get(evt_rsrc->event_d_id, &evdev_info);
1317        if (!(evdev_info.event_dev_cap & RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED)) {
1318                ret = rte_event_dev_service_id_get(evt_rsrc->event_d_id,
1319                                &service_id);
1320                if (ret != -ESRCH && ret != 0)
1321                        rte_exit(EXIT_FAILURE,
1322                                 "Error in starting eventdev service\n");
1323                l3fwd_service_enable(service_id);
1324        }
1325
1326        for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) {
1327                ret = rte_event_eth_rx_adapter_caps_get(evt_rsrc->event_d_id,
1328                                evt_rsrc->rx_adptr.rx_adptr[i], &caps);
1329                if (ret < 0)
1330                        rte_exit(EXIT_FAILURE,
1331                                 "Failed to get Rx adapter[%d] caps\n",
1332                                 evt_rsrc->rx_adptr.rx_adptr[i]);
1333                ret = rte_event_eth_rx_adapter_service_id_get(
1334                                evt_rsrc->event_d_id,
1335                                &service_id);
1336                if (ret != -ESRCH && ret != 0)
1337                        rte_exit(EXIT_FAILURE,
1338                                 "Error in starting Rx adapter[%d] service\n",
1339                                 evt_rsrc->rx_adptr.rx_adptr[i]);
1340                l3fwd_service_enable(service_id);
1341        }
1342
1343        for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++) {
1344                ret = rte_event_eth_tx_adapter_caps_get(evt_rsrc->event_d_id,
1345                                evt_rsrc->tx_adptr.tx_adptr[i], &caps);
1346                if (ret < 0)
1347                        rte_exit(EXIT_FAILURE,
1348                                 "Failed to get Rx adapter[%d] caps\n",
1349                                 evt_rsrc->tx_adptr.tx_adptr[i]);
1350                ret = rte_event_eth_tx_adapter_service_id_get(
1351                                evt_rsrc->event_d_id,
1352                                &service_id);
1353                if (ret != -ESRCH && ret != 0)
1354                        rte_exit(EXIT_FAILURE,
1355                                 "Error in starting Rx adapter[%d] service\n",
1356                                 evt_rsrc->tx_adptr.tx_adptr[i]);
1357                l3fwd_service_enable(service_id);
1358        }
1359}
1360
1361int
1362main(int argc, char **argv)
1363{
1364        struct l3fwd_event_resources *evt_rsrc;
1365        struct lcore_conf *qconf;
1366        uint16_t queueid, portid;
1367        unsigned int lcore_id;
1368        uint8_t queue;
1369        int i, ret;
1370
1371        /* init EAL */
1372        ret = rte_eal_init(argc, argv);
1373        if (ret < 0)
1374                rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
1375        argc -= ret;
1376        argv += ret;
1377
1378        force_quit = false;
1379        signal(SIGINT, signal_handler);
1380        signal(SIGTERM, signal_handler);
1381
1382        /* pre-init dst MACs for all ports to 02:00:00:00:00:xx */
1383        for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
1384                dest_eth_addr[portid] =
1385                        RTE_ETHER_LOCAL_ADMIN_ADDR + ((uint64_t)portid << 40);
1386                *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid];
1387        }
1388
1389        evt_rsrc = l3fwd_get_eventdev_rsrc();
1390        /* parse application arguments (after the EAL ones) */
1391        ret = parse_args(argc, argv);
1392        if (ret < 0)
1393                rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n");
1394
1395        /* Setup function pointers for lookup method. */
1396        setup_l3fwd_lookup_tables();
1397
1398        evt_rsrc->per_port_pool = per_port_pool;
1399        evt_rsrc->pkt_pool = pktmbuf_pool;
1400        evt_rsrc->vec_pool = vector_pool;
1401        evt_rsrc->port_mask = enabled_port_mask;
1402        /* Configure eventdev parameters if user has requested */
1403        if (evt_rsrc->enabled) {
1404                l3fwd_event_resource_setup(&port_conf);
1405                if (lookup_mode == L3FWD_LOOKUP_EM)
1406                        l3fwd_lkp.main_loop = evt_rsrc->ops.em_event_loop;
1407                else if (lookup_mode == L3FWD_LOOKUP_FIB)
1408                        l3fwd_lkp.main_loop = evt_rsrc->ops.fib_event_loop;
1409                else
1410                        l3fwd_lkp.main_loop = evt_rsrc->ops.lpm_event_loop;
1411                l3fwd_event_service_setup();
1412        } else
1413                l3fwd_poll_resource_setup();
1414
1415        /* start ports */
1416        RTE_ETH_FOREACH_DEV(portid) {
1417                if ((enabled_port_mask & (1 << portid)) == 0) {
1418                        continue;
1419                }
1420                /* Start device */
1421                ret = rte_eth_dev_start(portid);
1422                if (ret < 0)
1423                        rte_exit(EXIT_FAILURE,
1424                                "rte_eth_dev_start: err=%d, port=%d\n",
1425                                ret, portid);
1426
1427                /*
1428                 * If enabled, put device in promiscuous mode.
1429                 * This allows IO forwarding mode to forward packets
1430                 * to itself through 2 cross-connected  ports of the
1431                 * target machine.
1432                 */
1433                if (promiscuous_on) {
1434                        ret = rte_eth_promiscuous_enable(portid);
1435                        if (ret != 0)
1436                                rte_exit(EXIT_FAILURE,
1437                                        "rte_eth_promiscuous_enable: err=%s, port=%u\n",
1438                                        rte_strerror(-ret), portid);
1439                }
1440        }
1441
1442        printf("\n");
1443
1444        for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1445                if (rte_lcore_is_enabled(lcore_id) == 0)
1446                        continue;
1447                qconf = &lcore_conf[lcore_id];
1448                for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
1449                        portid = qconf->rx_queue_list[queue].port_id;
1450                        queueid = qconf->rx_queue_list[queue].queue_id;
1451                        if (prepare_ptype_parser(portid, queueid) == 0)
1452                                rte_exit(EXIT_FAILURE, "ptype check fails\n");
1453                }
1454        }
1455
1456        check_all_ports_link_status(enabled_port_mask);
1457
1458        ret = 0;
1459        /* launch per-lcore init on every lcore */
1460        rte_eal_mp_remote_launch(l3fwd_lkp.main_loop, NULL, CALL_MAIN);
1461        if (evt_rsrc->enabled) {
1462                for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++)
1463                        rte_event_eth_rx_adapter_stop(
1464                                        evt_rsrc->rx_adptr.rx_adptr[i]);
1465                for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++)
1466                        rte_event_eth_tx_adapter_stop(
1467                                        evt_rsrc->tx_adptr.tx_adptr[i]);
1468
1469                RTE_ETH_FOREACH_DEV(portid) {
1470                        if ((enabled_port_mask & (1 << portid)) == 0)
1471                                continue;
1472                        ret = rte_eth_dev_stop(portid);
1473                        if (ret != 0)
1474                                printf("rte_eth_dev_stop: err=%d, port=%u\n",
1475                                       ret, portid);
1476                }
1477
1478                rte_eal_mp_wait_lcore();
1479                RTE_ETH_FOREACH_DEV(portid) {
1480                        if ((enabled_port_mask & (1 << portid)) == 0)
1481                                continue;
1482                        rte_eth_dev_close(portid);
1483                }
1484
1485                rte_event_dev_stop(evt_rsrc->event_d_id);
1486                rte_event_dev_close(evt_rsrc->event_d_id);
1487
1488        } else {
1489                rte_eal_mp_wait_lcore();
1490
1491                RTE_ETH_FOREACH_DEV(portid) {
1492                        if ((enabled_port_mask & (1 << portid)) == 0)
1493                                continue;
1494                        printf("Closing port %d...", portid);
1495                        ret = rte_eth_dev_stop(portid);
1496                        if (ret != 0)
1497                                printf("rte_eth_dev_stop: err=%d, port=%u\n",
1498                                       ret, portid);
1499                        rte_eth_dev_close(portid);
1500                        printf(" Done\n");
1501                }
1502        }
1503
1504        /* clean up the EAL */
1505        rte_eal_cleanup();
1506
1507        printf("Bye...\n");
1508
1509        return ret;
1510}
1511