dpdk/examples/server_node_efd/server/init.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2016-2017 Intel Corporation
   3 */
   4
   5#include <stdint.h>
   6#include <stdio.h>
   7#include <string.h>
   8#include <sys/queue.h>
   9#include <errno.h>
  10#include <stdarg.h>
  11#include <inttypes.h>
  12
  13#include <rte_common.h>
  14#include <rte_memory.h>
  15#include <rte_memzone.h>
  16#include <rte_eal.h>
  17#include <rte_byteorder.h>
  18#include <rte_launch.h>
  19#include <rte_per_lcore.h>
  20#include <rte_lcore.h>
  21#include <rte_branch_prediction.h>
  22#include <rte_debug.h>
  23#include <rte_ring.h>
  24#include <rte_log.h>
  25#include <rte_mempool.h>
  26#include <rte_memcpy.h>
  27#include <rte_mbuf.h>
  28#include <rte_interrupts.h>
  29#include <rte_ether.h>
  30#include <rte_ethdev.h>
  31#include <rte_malloc.h>
  32#include <rte_string_fns.h>
  33#include <rte_cycles.h>
  34#include <rte_efd.h>
  35#include <rte_hash.h>
  36
  37#include "common.h"
  38#include "args.h"
  39#include "init.h"
  40
  41#define MBUFS_PER_NODE 1536
  42#define MBUFS_PER_PORT 1536
  43#define MBUF_CACHE_SIZE 512
  44
  45#define RTE_MP_RX_DESC_DEFAULT 512
  46#define RTE_MP_TX_DESC_DEFAULT 512
  47#define NODE_QUEUE_RINGSIZE 128
  48
  49#define NO_FLAGS 0
  50
  51/* The mbuf pool for packet rx */
  52struct rte_mempool *pktmbuf_pool;
  53
  54/* array of info/queues for nodes */
  55struct node *nodes;
  56
  57/* EFD table */
  58struct rte_efd_table *efd_table;
  59
  60/* Shared info between server and nodes */
  61struct shared_info *info;
  62
  63/**
  64 * Initialise the mbuf pool for packet reception for the NIC, and any other
  65 * buffer pools needed by the app - currently none.
  66 */
  67static int
  68init_mbuf_pools(void)
  69{
  70        const unsigned int num_mbufs = (num_nodes * MBUFS_PER_NODE) +
  71                        (info->num_ports * MBUFS_PER_PORT);
  72
  73        /*
  74         * Don't pass single-producer/single-consumer flags to mbuf create as it
  75         * seems faster to use a cache instead
  76         */
  77        printf("Creating mbuf pool '%s' [%u mbufs] ...\n",
  78                        PKTMBUF_POOL_NAME, num_mbufs);
  79        pktmbuf_pool = rte_pktmbuf_pool_create(PKTMBUF_POOL_NAME, num_mbufs,
  80                MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
  81
  82        return pktmbuf_pool == NULL; /* 0  on success */
  83}
  84
  85/**
  86 * Initialise an individual port:
  87 * - configure number of rx and tx rings
  88 * - set up each rx ring, to pull from the main mbuf pool
  89 * - set up each tx ring
  90 * - start the port and report its status to stdout
  91 */
  92static int
  93init_port(uint16_t port_num)
  94{
  95        /* for port configuration all features are off by default */
  96        struct rte_eth_conf port_conf = {
  97                .rxmode = {
  98                        .mq_mode = RTE_ETH_MQ_RX_RSS,
  99                },
 100        };
 101        const uint16_t rx_rings = 1, tx_rings = num_nodes;
 102        uint16_t rx_ring_size = RTE_MP_RX_DESC_DEFAULT;
 103        uint16_t tx_ring_size = RTE_MP_TX_DESC_DEFAULT;
 104        struct rte_eth_dev_info dev_info;
 105        struct rte_eth_txconf txconf;
 106
 107        uint16_t q;
 108        int retval;
 109
 110        printf("Port %u init ... ", port_num);
 111        fflush(stdout);
 112
 113        retval = rte_eth_dev_info_get(port_num, &dev_info);
 114        if (retval != 0)
 115                return retval;
 116
 117        if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
 118                port_conf.txmode.offloads |=
 119                        RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
 120
 121        /*
 122         * Standard DPDK port initialisation - config port, then set up
 123         * rx and tx rings.
 124         */
 125        retval = rte_eth_dev_configure(port_num, rx_rings, tx_rings, &port_conf);
 126        if (retval != 0)
 127                return retval;
 128
 129        retval = rte_eth_dev_adjust_nb_rx_tx_desc(port_num, &rx_ring_size,
 130                        &tx_ring_size);
 131        if (retval != 0)
 132                return retval;
 133
 134        for (q = 0; q < rx_rings; q++) {
 135                retval = rte_eth_rx_queue_setup(port_num, q, rx_ring_size,
 136                                rte_eth_dev_socket_id(port_num),
 137                                NULL, pktmbuf_pool);
 138                if (retval < 0)
 139                        return retval;
 140        }
 141
 142        txconf = dev_info.default_txconf;
 143        txconf.offloads = port_conf.txmode.offloads;
 144        for (q = 0; q < tx_rings; q++) {
 145                retval = rte_eth_tx_queue_setup(port_num, q, tx_ring_size,
 146                                rte_eth_dev_socket_id(port_num),
 147                                &txconf);
 148                if (retval < 0)
 149                        return retval;
 150        }
 151
 152        retval = rte_eth_promiscuous_enable(port_num);
 153        if (retval != 0)
 154                return retval;
 155
 156        retval = rte_eth_dev_start(port_num);
 157        if (retval < 0)
 158                return retval;
 159
 160        printf("done:\n");
 161
 162        return 0;
 163}
 164
 165/**
 166 * Set up the DPDK rings which will be used to pass packets, via
 167 * pointers, between the multi-process server and node processes.
 168 * Each node needs one RX queue.
 169 */
 170static int
 171init_shm_rings(void)
 172{
 173        unsigned int i;
 174        unsigned int socket_id;
 175        const char *q_name;
 176        const unsigned int ringsize = NODE_QUEUE_RINGSIZE;
 177
 178        nodes = rte_malloc("node details",
 179                sizeof(*nodes) * num_nodes, 0);
 180        if (nodes == NULL)
 181                rte_exit(EXIT_FAILURE, "Cannot allocate memory for "
 182                                "node program details\n");
 183
 184        for (i = 0; i < num_nodes; i++) {
 185                /* Create an RX queue for each node */
 186                socket_id = rte_socket_id();
 187                q_name = get_rx_queue_name(i);
 188                nodes[i].rx_q = rte_ring_create(q_name,
 189                                ringsize, socket_id,
 190                                RING_F_SP_ENQ | RING_F_SC_DEQ);
 191                if (nodes[i].rx_q == NULL)
 192                        rte_exit(EXIT_FAILURE, "Cannot create rx ring queue "
 193                                        "for node %u\n", i);
 194        }
 195        return 0;
 196}
 197
 198/*
 199 * Create EFD table which will contain all the flows
 200 * that will be distributed among the nodes
 201 */
 202
 203/* Create EFD table. 8< */
 204static void
 205create_efd_table(void)
 206{
 207        uint8_t socket_id = rte_socket_id();
 208
 209        /* create table */
 210        efd_table = rte_efd_create("flow table", num_flows * 2, sizeof(uint32_t),
 211                        1 << socket_id, socket_id);
 212
 213        if (efd_table == NULL)
 214                rte_exit(EXIT_FAILURE, "Problem creating the flow table\n");
 215}
 216
 217static void
 218populate_efd_table(void)
 219{
 220        unsigned int i;
 221        int32_t ret;
 222        uint32_t ip_dst;
 223        uint8_t socket_id = rte_socket_id();
 224        uint64_t node_id;
 225
 226        /* Add flows in table */
 227        for (i = 0; i < num_flows; i++) {
 228                node_id = i % num_nodes;
 229
 230                ip_dst = rte_cpu_to_be_32(i);
 231                ret = rte_efd_update(efd_table, socket_id,
 232                                (void *)&ip_dst, (efd_value_t)node_id);
 233                if (ret < 0)
 234                        rte_exit(EXIT_FAILURE, "Unable to add entry %u in "
 235                                        "EFD table\n", i);
 236        }
 237
 238        printf("EFD table: Adding 0x%x keys\n", num_flows);
 239}
 240/* >8 End of creation EFD table. */
 241
 242/* Check the link status of all ports in up to 9s, and print them finally */
 243static void
 244check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 245{
 246#define CHECK_INTERVAL 100 /* 100ms */
 247#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
 248        uint8_t count, all_ports_up, print_flag = 0;
 249        uint16_t portid;
 250        struct rte_eth_link link;
 251        int ret;
 252        char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
 253
 254        printf("\nChecking link status");
 255        fflush(stdout);
 256        for (count = 0; count <= MAX_CHECK_TIME; count++) {
 257                all_ports_up = 1;
 258                for (portid = 0; portid < port_num; portid++) {
 259                        if ((port_mask & (1 << info->id[portid])) == 0)
 260                                continue;
 261                        memset(&link, 0, sizeof(link));
 262                        ret = rte_eth_link_get_nowait(info->id[portid], &link);
 263                        if (ret < 0) {
 264                                all_ports_up = 0;
 265                                if (print_flag == 1)
 266                                        printf("Port %u link get failed: %s\n",
 267                                                portid, rte_strerror(-ret));
 268                                continue;
 269                        }
 270                        /* print link status if flag set */
 271                        if (print_flag == 1) {
 272                                rte_eth_link_to_str(link_status_text,
 273                                        sizeof(link_status_text), &link);
 274                                printf("Port %d %s\n", info->id[portid],
 275                                       link_status_text);
 276                                continue;
 277                        }
 278                        /* clear all_ports_up flag if any link down */
 279                        if (link.link_status == RTE_ETH_LINK_DOWN) {
 280                                all_ports_up = 0;
 281                                break;
 282                        }
 283                }
 284                /* after finally printing all link status, get out */
 285                if (print_flag == 1)
 286                        break;
 287
 288                if (all_ports_up == 0) {
 289                        printf(".");
 290                        fflush(stdout);
 291                        rte_delay_ms(CHECK_INTERVAL);
 292                }
 293
 294                /* set the print_flag if all ports up or timeout */
 295                if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
 296                        print_flag = 1;
 297                        printf("done\n");
 298                }
 299        }
 300}
 301
 302/**
 303 * Main init function for the multi-process server app,
 304 * calls subfunctions to do each stage of the initialisation.
 305 */
 306int
 307init(int argc, char *argv[])
 308{
 309        int retval;
 310        const struct rte_memzone *mz;
 311        uint8_t i, total_ports;
 312
 313        /* init EAL, parsing EAL args */
 314        retval = rte_eal_init(argc, argv);
 315        if (retval < 0)
 316                return -1;
 317        argc -= retval;
 318        argv += retval;
 319
 320        /* get total number of ports */
 321        total_ports = rte_eth_dev_count_avail();
 322
 323        /* set up array for port data */
 324        mz = rte_memzone_reserve(MZ_SHARED_INFO, sizeof(*info),
 325                                rte_socket_id(), NO_FLAGS);
 326        if (mz == NULL)
 327                rte_exit(EXIT_FAILURE, "Cannot reserve memory zone "
 328                                "for port information\n");
 329        memset(mz->addr, 0, sizeof(*info));
 330        info = mz->addr;
 331
 332        /* parse additional, application arguments */
 333        retval = parse_app_args(total_ports, argc, argv);
 334        if (retval != 0)
 335                return -1;
 336
 337        /* initialise mbuf pools */
 338        retval = init_mbuf_pools();
 339        if (retval != 0)
 340                rte_exit(EXIT_FAILURE, "Cannot create needed mbuf pools\n");
 341
 342        /* now initialise the ports we will use */
 343        for (i = 0; i < info->num_ports; i++) {
 344                retval = init_port(info->id[i]);
 345                if (retval != 0)
 346                        rte_exit(EXIT_FAILURE, "Cannot initialise port %u\n",
 347                                        (unsigned int) i);
 348        }
 349
 350        check_all_ports_link_status(info->num_ports, (~0x0));
 351
 352        /* initialise the node queues/rings for inter-eu comms */
 353        init_shm_rings();
 354
 355        /* Create the EFD table */
 356        create_efd_table();
 357
 358        /* Populate the EFD table */
 359        populate_efd_table();
 360
 361        /* Share the total number of nodes */
 362        info->num_nodes = num_nodes;
 363
 364        /* Share the total number of flows */
 365        info->num_flows = num_flows;
 366        return 0;
 367}
 368