dpdk/examples/multi_process/client_server_mp/mp_client/client.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2010-2016 Intel Corporation
   3 */
   4
   5#include <stdint.h>
   6#include <stdio.h>
   7#include <inttypes.h>
   8#include <stdarg.h>
   9#include <errno.h>
  10#include <sys/queue.h>
  11#include <stdlib.h>
  12#include <getopt.h>
  13#include <string.h>
  14
  15#include <rte_common.h>
  16#include <rte_malloc.h>
  17#include <rte_memory.h>
  18#include <rte_memzone.h>
  19#include <rte_eal.h>
  20#include <rte_branch_prediction.h>
  21#include <rte_log.h>
  22#include <rte_per_lcore.h>
  23#include <rte_lcore.h>
  24#include <rte_ring.h>
  25#include <rte_launch.h>
  26#include <rte_debug.h>
  27#include <rte_mempool.h>
  28#include <rte_mbuf.h>
  29#include <rte_interrupts.h>
  30#include <rte_ether.h>
  31#include <rte_ethdev.h>
  32#include <rte_string_fns.h>
  33
  34#include "common.h"
  35
  36/* Number of packets to attempt to read from queue */
  37#define PKT_READ_SIZE  ((uint16_t)32)
  38
  39/* our client id number - tells us which rx queue to read, and NIC TX
  40 * queue to write to. */
  41static uint8_t client_id = 0;
  42
  43#define MBQ_CAPACITY 32
  44
  45/* maps input ports to output ports for packets */
  46static uint16_t output_ports[RTE_MAX_ETHPORTS];
  47
  48/* buffers up a set of packet that are ready to send */
  49struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
  50
  51/* shared data from server. We update statistics here */
  52static volatile struct tx_stats *tx_stats;
  53
  54
  55/*
  56 * print a usage message
  57 */
  58static void
  59usage(const char *progname)
  60{
  61        printf("Usage: %s [EAL args] -- -n <client_id>\n\n", progname);
  62}
  63
  64/*
  65 * Convert the client id number from a string to an int.
  66 */
  67static int
  68parse_client_num(const char *client)
  69{
  70        char *end = NULL;
  71        unsigned long temp;
  72
  73        if (client == NULL || *client == '\0')
  74                return -1;
  75
  76        temp = strtoul(client, &end, 10);
  77        if (end == NULL || *end != '\0')
  78                return -1;
  79
  80        client_id = (uint8_t)temp;
  81        return 0;
  82}
  83
  84/*
  85 * Parse the application arguments to the client app.
  86 */
  87static int
  88parse_app_args(int argc, char *argv[])
  89{
  90        int option_index, opt;
  91        char **argvopt = argv;
  92        const char *progname = NULL;
  93        static struct option lgopts[] = { /* no long options */
  94                {NULL, 0, 0, 0 }
  95        };
  96        progname = argv[0];
  97
  98        while ((opt = getopt_long(argc, argvopt, "n:", lgopts,
  99                &option_index)) != EOF){
 100                switch (opt){
 101                        case 'n':
 102                                if (parse_client_num(optarg) != 0){
 103                                        usage(progname);
 104                                        return -1;
 105                                }
 106                                break;
 107                        default:
 108                                usage(progname);
 109                                return -1;
 110                }
 111        }
 112        return 0;
 113}
 114
 115/*
 116 * Tx buffer error callback
 117 */
 118static void
 119flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count,
 120                void *userdata) {
 121        int i;
 122        uint16_t port_id = (uintptr_t)userdata;
 123
 124        tx_stats->tx_drop[port_id] += count;
 125
 126        /* free the mbufs which failed from transmit */
 127        for (i = 0; i < count; i++)
 128                rte_pktmbuf_free(unsent[i]);
 129
 130}
 131
 132static void
 133configure_tx_buffer(uint16_t port_id, uint16_t size)
 134{
 135        int ret;
 136
 137        /* Initialize TX buffers */
 138        tx_buffer[port_id] = rte_zmalloc_socket("tx_buffer",
 139                        RTE_ETH_TX_BUFFER_SIZE(size), 0,
 140                        rte_eth_dev_socket_id(port_id));
 141        if (tx_buffer[port_id] == NULL)
 142                rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
 143                         port_id);
 144
 145        rte_eth_tx_buffer_init(tx_buffer[port_id], size);
 146
 147        ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[port_id],
 148                        flush_tx_error_callback, (void *)(intptr_t)port_id);
 149        if (ret < 0)
 150                rte_exit(EXIT_FAILURE,
 151                "Cannot set error callback for tx buffer on port %u\n",
 152                         port_id);
 153}
 154
 155/*
 156 * set up output ports so that all traffic on port gets sent out
 157 * its paired port. Index using actual port numbers since that is
 158 * what comes in the mbuf structure.
 159 */
 160static void
 161configure_output_ports(const struct port_info *ports)
 162{
 163        int i;
 164        if (ports->num_ports > RTE_MAX_ETHPORTS)
 165                rte_exit(EXIT_FAILURE, "Too many ethernet ports. RTE_MAX_ETHPORTS = %u\n",
 166                                (unsigned)RTE_MAX_ETHPORTS);
 167        for (i = 0; i < ports->num_ports - 1; i+=2){
 168                uint16_t p1 = ports->id[i];
 169                uint16_t p2 = ports->id[i+1];
 170                output_ports[p1] = p2;
 171                output_ports[p2] = p1;
 172
 173                configure_tx_buffer(p1, MBQ_CAPACITY);
 174                configure_tx_buffer(p2, MBQ_CAPACITY);
 175
 176        }
 177}
 178
 179/*
 180 * This function performs routing of packets
 181 * Just sends each input packet out an output port based solely on the input
 182 * port it arrived on.
 183 */
 184static void
 185handle_packet(struct rte_mbuf *buf)
 186{
 187        int sent;
 188        const uint16_t in_port = buf->port;
 189        const uint16_t out_port = output_ports[in_port];
 190        struct rte_eth_dev_tx_buffer *buffer = tx_buffer[out_port];
 191
 192        sent = rte_eth_tx_buffer(out_port, client_id, buffer, buf);
 193        if (sent)
 194                tx_stats->tx[out_port] += sent;
 195
 196}
 197
 198/*
 199 * Application main function - loops through
 200 * receiving and processing packets. Never returns
 201 */
 202int
 203main(int argc, char *argv[])
 204{
 205        const struct rte_memzone *mz;
 206        struct rte_ring *rx_ring;
 207        struct rte_mempool *mp;
 208        struct port_info *ports;
 209        int need_flush = 0; /* indicates whether we have unsent packets */
 210        int retval;
 211        void *pkts[PKT_READ_SIZE];
 212        uint16_t sent;
 213
 214        if ((retval = rte_eal_init(argc, argv)) < 0)
 215                return -1;
 216        argc -= retval;
 217        argv += retval;
 218
 219        if (parse_app_args(argc, argv) < 0)
 220                rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n");
 221
 222        if (rte_eth_dev_count_avail() == 0)
 223                rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
 224
 225        rx_ring = rte_ring_lookup(get_rx_queue_name(client_id));
 226        if (rx_ring == NULL)
 227                rte_exit(EXIT_FAILURE, "Cannot get RX ring - is server process running?\n");
 228
 229        mp = rte_mempool_lookup(PKTMBUF_POOL_NAME);
 230        if (mp == NULL)
 231                rte_exit(EXIT_FAILURE, "Cannot get mempool for mbufs\n");
 232
 233        mz = rte_memzone_lookup(MZ_PORT_INFO);
 234        if (mz == NULL)
 235                rte_exit(EXIT_FAILURE, "Cannot get port info structure\n");
 236        ports = mz->addr;
 237        tx_stats = &(ports->tx_stats[client_id]);
 238
 239        configure_output_ports(ports);
 240
 241        RTE_LOG(INFO, APP, "Finished Process Init.\n");
 242
 243        printf("\nClient process %d handling packets\n", client_id);
 244        printf("[Press Ctrl-C to quit ...]\n");
 245
 246        for (;;) {
 247                uint16_t i, rx_pkts;
 248
 249                rx_pkts = rte_ring_dequeue_burst(rx_ring, pkts,
 250                                PKT_READ_SIZE, NULL);
 251
 252                if (rx_pkts == 0 && need_flush) {
 253                        for (i = 0; i < ports->num_ports; i++) {
 254                                uint16_t port = ports->id[i];
 255
 256                                sent = rte_eth_tx_buffer_flush(port,
 257                                                               client_id,
 258                                                               tx_buffer[port]);
 259                                tx_stats->tx[port] += sent;
 260                        }
 261                        need_flush = 0;
 262                        continue;
 263                }
 264
 265                for (i = 0; i < rx_pkts; i++)
 266                        handle_packet(pkts[i]);
 267
 268                need_flush = 1;
 269        }
 270
 271        /* clean up the EAL */
 272        rte_eal_cleanup();
 273}
 274