dpdk/examples/multi_process/client_server_mp/mp_server/init.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2010-2014 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
  35#include "common.h"
  36#include "args.h"
  37#include "init.h"
  38
  39#define MBUF_CACHE_SIZE 512
  40
  41#define RTE_MP_RX_DESC_DEFAULT 1024
  42#define RTE_MP_TX_DESC_DEFAULT 1024
  43#define CLIENT_QUEUE_RINGSIZE 128
  44
  45#define NO_FLAGS 0
  46
  47/* The mbuf pool for packet rx */
  48struct rte_mempool *pktmbuf_pool;
  49
  50/* array of info/queues for clients */
  51struct client *clients = NULL;
  52
  53/* the port details */
  54struct port_info *ports;
  55
  56/**
  57 * Initialise the mbuf pool for packet reception for the NIC, and any other
  58 * buffer pools needed by the app - currently none.
  59 */
  60static int
  61init_mbuf_pools(void)
  62{
  63        const unsigned int num_mbufs_server =
  64                RTE_MP_RX_DESC_DEFAULT * ports->num_ports;
  65        const unsigned int num_mbufs_client =
  66                num_clients * (CLIENT_QUEUE_RINGSIZE +
  67                               RTE_MP_TX_DESC_DEFAULT * ports->num_ports);
  68        const unsigned int num_mbufs_mp_cache =
  69                (num_clients + 1) * MBUF_CACHE_SIZE;
  70        const unsigned int num_mbufs =
  71                num_mbufs_server + num_mbufs_client + num_mbufs_mp_cache;
  72
  73        /* don't pass single-producer/single-consumer flags to mbuf create as it
  74         * seems faster to use a cache instead */
  75        printf("Creating mbuf pool '%s' [%u mbufs] ...\n",
  76                        PKTMBUF_POOL_NAME, num_mbufs);
  77        pktmbuf_pool = rte_pktmbuf_pool_create(PKTMBUF_POOL_NAME, num_mbufs,
  78                MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
  79
  80        return pktmbuf_pool == NULL; /* 0  on success */
  81}
  82
  83/**
  84 * Initialise an individual port:
  85 * - configure number of rx and tx rings
  86 * - set up each rx ring, to pull from the main mbuf pool
  87 * - set up each tx ring
  88 * - start the port and report its status to stdout
  89 */
  90static int
  91init_port(uint16_t port_num)
  92{
  93        /* for port configuration all features are off by default */
  94        const struct rte_eth_conf port_conf = {
  95                .rxmode = {
  96                        .mq_mode = RTE_ETH_MQ_RX_RSS
  97                }
  98        };
  99        const uint16_t rx_rings = 1, tx_rings = num_clients;
 100        uint16_t rx_ring_size = RTE_MP_RX_DESC_DEFAULT;
 101        uint16_t tx_ring_size = RTE_MP_TX_DESC_DEFAULT;
 102
 103        uint16_t q;
 104        int retval;
 105
 106        printf("Port %u init ... ", port_num);
 107        fflush(stdout);
 108
 109        /* Standard DPDK port initialisation - config port, then set up
 110         * rx and tx rings */
 111        if ((retval = rte_eth_dev_configure(port_num, rx_rings, tx_rings,
 112                &port_conf)) != 0)
 113                return retval;
 114
 115        retval = rte_eth_dev_adjust_nb_rx_tx_desc(port_num, &rx_ring_size,
 116                        &tx_ring_size);
 117        if (retval != 0)
 118                return retval;
 119
 120        for (q = 0; q < rx_rings; q++) {
 121                retval = rte_eth_rx_queue_setup(port_num, q, rx_ring_size,
 122                                rte_eth_dev_socket_id(port_num),
 123                                NULL, pktmbuf_pool);
 124                if (retval < 0) return retval;
 125        }
 126
 127        for ( q = 0; q < tx_rings; q ++ ) {
 128                retval = rte_eth_tx_queue_setup(port_num, q, tx_ring_size,
 129                                rte_eth_dev_socket_id(port_num),
 130                                NULL);
 131                if (retval < 0) return retval;
 132        }
 133
 134        retval = rte_eth_promiscuous_enable(port_num);
 135        if (retval < 0)
 136                return retval;
 137
 138        retval  = rte_eth_dev_start(port_num);
 139        if (retval < 0) return retval;
 140
 141        printf( "done: \n");
 142
 143        return 0;
 144}
 145
 146/**
 147 * Set up the DPDK rings which will be used to pass packets, via
 148 * pointers, between the multi-process server and client processes.
 149 * Each client needs one RX queue.
 150 */
 151static int
 152init_shm_rings(void)
 153{
 154        unsigned i;
 155        unsigned socket_id;
 156        const char * q_name;
 157        const unsigned ringsize = CLIENT_QUEUE_RINGSIZE;
 158
 159        clients = rte_malloc("client details",
 160                sizeof(*clients) * num_clients, 0);
 161        if (clients == NULL)
 162                rte_exit(EXIT_FAILURE, "Cannot allocate memory for client program details\n");
 163
 164        for (i = 0; i < num_clients; i++) {
 165                /* Create an RX queue for each client */
 166                socket_id = rte_socket_id();
 167                q_name = get_rx_queue_name(i);
 168                clients[i].rx_q = rte_ring_create(q_name,
 169                                ringsize, socket_id,
 170                                RING_F_SP_ENQ | RING_F_SC_DEQ ); /* single prod, single cons */
 171                if (clients[i].rx_q == NULL)
 172                        rte_exit(EXIT_FAILURE, "Cannot create rx ring queue for client %u\n", i);
 173        }
 174        return 0;
 175}
 176
 177/* Check the link status of all ports in up to 9s, and print them finally */
 178static void
 179check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
 180{
 181#define CHECK_INTERVAL 100 /* 100ms */
 182#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
 183        uint16_t portid;
 184        uint8_t count, all_ports_up, print_flag = 0;
 185        struct rte_eth_link link;
 186        int ret;
 187        char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
 188
 189        printf("\nChecking link status");
 190        fflush(stdout);
 191        for (count = 0; count <= MAX_CHECK_TIME; count++) {
 192                all_ports_up = 1;
 193                for (portid = 0; portid < port_num; portid++) {
 194                        if ((port_mask & (1 << ports->id[portid])) == 0)
 195                                continue;
 196                        memset(&link, 0, sizeof(link));
 197                        ret = rte_eth_link_get_nowait(ports->id[portid], &link);
 198                        if (ret < 0) {
 199                                all_ports_up = 0;
 200                                if (print_flag == 1)
 201                                        printf("Port %u link get failed: %s\n",
 202                                                portid, rte_strerror(-ret));
 203                                continue;
 204                        }
 205                        /* print link status if flag set */
 206                        if (print_flag == 1) {
 207                                rte_eth_link_to_str(link_status_text,
 208                                        sizeof(link_status_text), &link);
 209                                printf("Port %d %s\n",
 210                                       ports->id[portid],
 211                                       link_status_text);
 212                                continue;
 213                        }
 214                        /* clear all_ports_up flag if any link down */
 215                        if (link.link_status == RTE_ETH_LINK_DOWN) {
 216                                all_ports_up = 0;
 217                                break;
 218                        }
 219                }
 220                /* after finally printing all link status, get out */
 221                if (print_flag == 1)
 222                        break;
 223
 224                if (all_ports_up == 0) {
 225                        printf(".");
 226                        fflush(stdout);
 227                        rte_delay_ms(CHECK_INTERVAL);
 228                }
 229
 230                /* set the print_flag if all ports up or timeout */
 231                if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
 232                        print_flag = 1;
 233                        printf("done\n");
 234                }
 235        }
 236}
 237
 238/**
 239 * Main init function for the multi-process server app,
 240 * calls subfunctions to do each stage of the initialisation.
 241 */
 242int
 243init(int argc, char *argv[])
 244{
 245        int retval;
 246        const struct rte_memzone *mz;
 247        uint16_t i;
 248
 249        /* init EAL, parsing EAL args */
 250        retval = rte_eal_init(argc, argv);
 251        if (retval < 0)
 252                return -1;
 253        argc -= retval;
 254        argv += retval;
 255
 256        /* set up array for port data */
 257        mz = rte_memzone_reserve(MZ_PORT_INFO, sizeof(*ports),
 258                                rte_socket_id(), NO_FLAGS);
 259        if (mz == NULL)
 260                rte_exit(EXIT_FAILURE, "Cannot reserve memory zone for port information\n");
 261        memset(mz->addr, 0, sizeof(*ports));
 262        ports = mz->addr;
 263
 264        /* parse additional, application arguments */
 265        retval = parse_app_args(argc, argv);
 266        if (retval != 0)
 267                return -1;
 268
 269        /* initialise mbuf pools */
 270        retval = init_mbuf_pools();
 271        if (retval != 0)
 272                rte_exit(EXIT_FAILURE, "Cannot create needed mbuf pools\n");
 273
 274        /* now initialise the ports we will use */
 275        for (i = 0; i < ports->num_ports; i++) {
 276                retval = init_port(ports->id[i]);
 277                if (retval != 0)
 278                        rte_exit(EXIT_FAILURE, "Cannot initialise port %u\n",
 279                                        (unsigned)i);
 280        }
 281
 282        check_all_ports_link_status(ports->num_ports, (~0x0));
 283
 284        /* initialise the client queues/rings for inter-eu comms */
 285        init_shm_rings();
 286
 287        return 0;
 288}
 289