dpdk/app/test-pmd/noisy_vnf.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2018 Red Hat Corp.
   3 */
   4
   5#include <stdarg.h>
   6#include <stdio.h>
   7#include <stdbool.h>
   8#include <string.h>
   9#include <errno.h>
  10#include <stdint.h>
  11#include <unistd.h>
  12#include <inttypes.h>
  13
  14#include <sys/queue.h>
  15#include <sys/stat.h>
  16
  17#include <rte_common.h>
  18#include <rte_log.h>
  19#include <rte_debug.h>
  20#include <rte_cycles.h>
  21#include <rte_memory.h>
  22#include <rte_launch.h>
  23#include <rte_eal.h>
  24#include <rte_per_lcore.h>
  25#include <rte_lcore.h>
  26#include <rte_memcpy.h>
  27#include <rte_mempool.h>
  28#include <rte_mbuf.h>
  29#include <rte_ethdev.h>
  30#include <rte_flow.h>
  31#include <rte_malloc.h>
  32
  33#include "testpmd.h"
  34
  35struct noisy_config {
  36        struct rte_ring *f;
  37        uint64_t prev_time;
  38        char *vnf_mem;
  39        bool do_buffering;
  40        bool do_flush;
  41        bool do_sim;
  42};
  43
  44struct noisy_config *noisy_cfg[RTE_MAX_ETHPORTS];
  45
  46static inline void
  47do_write(char *vnf_mem)
  48{
  49        uint64_t i = rte_rand();
  50        uint64_t w = rte_rand();
  51
  52        vnf_mem[i % ((noisy_lkup_mem_sz * 1024 * 1024) /
  53                        RTE_CACHE_LINE_SIZE)] = w;
  54}
  55
  56static inline void
  57do_read(char *vnf_mem)
  58{
  59        uint64_t i = rte_rand();
  60        uint64_t r;
  61
  62        r = vnf_mem[i % ((noisy_lkup_mem_sz * 1024 * 1024) /
  63                        RTE_CACHE_LINE_SIZE)];
  64        r++;
  65}
  66
  67static inline void
  68do_readwrite(char *vnf_mem)
  69{
  70        do_read(vnf_mem);
  71        do_write(vnf_mem);
  72}
  73
  74/*
  75 * Simulate route lookups as defined by commandline parameters
  76 */
  77static void
  78sim_memory_lookups(struct noisy_config *ncf, uint16_t nb_pkts)
  79{
  80        uint16_t i, j;
  81
  82        if (!ncf->do_sim)
  83                return;
  84
  85        for (i = 0; i < nb_pkts; i++) {
  86                for (j = 0; j < noisy_lkup_num_writes; j++)
  87                        do_write(ncf->vnf_mem);
  88                for (j = 0; j < noisy_lkup_num_reads; j++)
  89                        do_read(ncf->vnf_mem);
  90                for (j = 0; j < noisy_lkup_num_reads_writes; j++)
  91                        do_readwrite(ncf->vnf_mem);
  92        }
  93}
  94
  95static uint16_t
  96do_retry(uint16_t nb_rx, uint16_t nb_tx, struct rte_mbuf **pkts,
  97         struct fwd_stream *fs)
  98{
  99        uint32_t retry = 0;
 100
 101        while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
 102                rte_delay_us(burst_tx_delay_time);
 103                nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
 104                                &pkts[nb_tx], nb_rx - nb_tx);
 105        }
 106
 107        return nb_tx;
 108}
 109
 110static uint32_t
 111drop_pkts(struct rte_mbuf **pkts, uint16_t nb_rx, uint16_t nb_tx)
 112{
 113        if (nb_tx < nb_rx) {
 114                do {
 115                        rte_pktmbuf_free(pkts[nb_tx]);
 116                } while (++nb_tx < nb_rx);
 117        }
 118
 119        return nb_rx - nb_tx;
 120}
 121
 122/*
 123 * Forwarding of packets in noisy VNF mode.  Forward packets but perform
 124 * memory operations first as specified on cmdline.
 125 *
 126 * Depending on which commandline parameters are specified we have
 127 * different cases to handle:
 128 *
 129 * 1. No FIFO size was given, so we don't do buffering of incoming
 130 *    packets.  This case is pretty much what iofwd does but in this case
 131 *    we also do simulation of memory accesses (depending on which
 132 *    parameters were specified for it).
 133 * 2. User wants do buffer packets in a FIFO and sent out overflowing
 134 *    packets.
 135 * 3. User wants a FIFO and specifies a time in ms to flush all packets
 136 *    out of the FIFO
 137 * 4. Cases 2 and 3 combined
 138 */
 139static void
 140pkt_burst_noisy_vnf(struct fwd_stream *fs)
 141{
 142        const uint64_t freq_khz = rte_get_timer_hz() / 1000;
 143        struct noisy_config *ncf = noisy_cfg[fs->rx_port];
 144        struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
 145        struct rte_mbuf *tmp_pkts[MAX_PKT_BURST];
 146        uint16_t nb_deqd = 0;
 147        uint16_t nb_rx = 0;
 148        uint16_t nb_tx = 0;
 149        uint16_t nb_enqd;
 150        unsigned int fifo_free;
 151        uint64_t delta_ms;
 152        bool needs_flush = false;
 153        uint64_t now;
 154
 155        nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
 156                        pkts_burst, nb_pkt_per_burst);
 157        inc_rx_burst_stats(fs, nb_rx);
 158        if (unlikely(nb_rx == 0))
 159                goto flush;
 160        fs->rx_packets += nb_rx;
 161
 162        if (!ncf->do_buffering) {
 163                sim_memory_lookups(ncf, nb_rx);
 164                nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
 165                                pkts_burst, nb_rx);
 166                if (unlikely(nb_tx < nb_rx) && fs->retry_enabled)
 167                        nb_tx += do_retry(nb_rx, nb_tx, pkts_burst, fs);
 168                inc_tx_burst_stats(fs, nb_tx);
 169                fs->tx_packets += nb_tx;
 170                fs->fwd_dropped += drop_pkts(pkts_burst, nb_rx, nb_tx);
 171                return;
 172        }
 173
 174        fifo_free = rte_ring_free_count(ncf->f);
 175        if (fifo_free >= nb_rx) {
 176                nb_enqd = rte_ring_enqueue_burst(ncf->f,
 177                                (void **) pkts_burst, nb_rx, NULL);
 178                if (nb_enqd < nb_rx)
 179                        fs->fwd_dropped += drop_pkts(pkts_burst,
 180                                                     nb_rx, nb_enqd);
 181        } else {
 182                nb_deqd = rte_ring_dequeue_burst(ncf->f,
 183                                (void **) tmp_pkts, nb_rx, NULL);
 184                nb_enqd = rte_ring_enqueue_burst(ncf->f,
 185                                (void **) pkts_burst, nb_deqd, NULL);
 186                if (nb_deqd > 0) {
 187                        nb_tx = rte_eth_tx_burst(fs->tx_port,
 188                                        fs->tx_queue, tmp_pkts,
 189                                        nb_deqd);
 190                        if (unlikely(nb_tx < nb_rx) && fs->retry_enabled)
 191                                nb_tx += do_retry(nb_rx, nb_tx, tmp_pkts, fs);
 192                        inc_tx_burst_stats(fs, nb_tx);
 193                        fs->fwd_dropped += drop_pkts(tmp_pkts, nb_deqd, nb_tx);
 194                }
 195        }
 196
 197        sim_memory_lookups(ncf, nb_enqd);
 198
 199flush:
 200        if (ncf->do_flush) {
 201                if (!ncf->prev_time)
 202                        now = ncf->prev_time = rte_get_timer_cycles();
 203                else
 204                        now = rte_get_timer_cycles();
 205                delta_ms = (now - ncf->prev_time) / freq_khz;
 206                needs_flush = delta_ms >= noisy_tx_sw_buf_flush_time &&
 207                                noisy_tx_sw_buf_flush_time > 0 && !nb_tx;
 208        }
 209        while (needs_flush && !rte_ring_empty(ncf->f)) {
 210                unsigned int sent;
 211                nb_deqd = rte_ring_dequeue_burst(ncf->f, (void **)tmp_pkts,
 212                                MAX_PKT_BURST, NULL);
 213                sent = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
 214                                         tmp_pkts, nb_deqd);
 215                if (unlikely(sent < nb_deqd) && fs->retry_enabled)
 216                        nb_tx += do_retry(nb_rx, nb_tx, tmp_pkts, fs);
 217                inc_tx_burst_stats(fs, nb_tx);
 218                fs->fwd_dropped += drop_pkts(tmp_pkts, nb_deqd, sent);
 219                ncf->prev_time = rte_get_timer_cycles();
 220        }
 221}
 222
 223#define NOISY_STRSIZE 256
 224#define NOISY_RING "noisy_ring_%d\n"
 225
 226static void
 227noisy_fwd_end(portid_t pi)
 228{
 229        rte_ring_free(noisy_cfg[pi]->f);
 230        rte_free(noisy_cfg[pi]->vnf_mem);
 231        rte_free(noisy_cfg[pi]);
 232}
 233
 234static void
 235noisy_fwd_begin(portid_t pi)
 236{
 237        struct noisy_config *n;
 238        char name[NOISY_STRSIZE];
 239
 240        noisy_cfg[pi] = rte_zmalloc("testpmd noisy fifo and timers",
 241                                sizeof(struct noisy_config),
 242                                RTE_CACHE_LINE_SIZE);
 243        if (noisy_cfg[pi] == NULL) {
 244                rte_exit(EXIT_FAILURE,
 245                         "rte_zmalloc(%d) struct noisy_config) failed\n",
 246                         (int) pi);
 247        }
 248        n = noisy_cfg[pi];
 249        n->do_buffering = noisy_tx_sw_bufsz > 0;
 250        n->do_sim = noisy_lkup_num_writes + noisy_lkup_num_reads +
 251                    noisy_lkup_num_reads_writes;
 252        n->do_flush = noisy_tx_sw_buf_flush_time > 0;
 253
 254        if (n->do_buffering) {
 255                snprintf(name, NOISY_STRSIZE, NOISY_RING, pi);
 256                n->f = rte_ring_create(name, noisy_tx_sw_bufsz,
 257                                rte_socket_id(), 0);
 258                if (!n->f)
 259                        rte_exit(EXIT_FAILURE,
 260                                 "rte_ring_create(%d), size %d) failed\n",
 261                                 (int) pi,
 262                                 noisy_tx_sw_bufsz);
 263        }
 264        if (noisy_lkup_mem_sz > 0) {
 265                n->vnf_mem = (char *) rte_zmalloc("vnf sim memory",
 266                                 noisy_lkup_mem_sz * 1024 * 1024,
 267                                 RTE_CACHE_LINE_SIZE);
 268                if (!n->vnf_mem)
 269                        rte_exit(EXIT_FAILURE,
 270                           "rte_zmalloc(%" PRIu64 ") for vnf memory) failed\n",
 271                           noisy_lkup_mem_sz);
 272        } else if (n->do_sim) {
 273                rte_exit(EXIT_FAILURE,
 274                         "--noisy-lkup-memory-size must be > 0\n");
 275        }
 276}
 277
 278struct fwd_engine noisy_vnf_engine = {
 279        .fwd_mode_name  = "noisy",
 280        .port_fwd_begin = noisy_fwd_begin,
 281        .port_fwd_end   = noisy_fwd_end,
 282        .packet_fwd     = pkt_burst_noisy_vnf,
 283};
 284