1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Red Hat Corp.
14 #include <sys/queue.h>
17 #include <rte_common.h>
19 #include <rte_debug.h>
20 #include <rte_cycles.h>
21 #include <rte_memory.h>
22 #include <rte_launch.h>
24 #include <rte_per_lcore.h>
25 #include <rte_lcore.h>
26 #include <rte_memcpy.h>
27 #include <rte_mempool.h>
29 #include <rte_ethdev.h>
31 #include <rte_malloc.h>
44 struct noisy_config *noisy_cfg[RTE_MAX_ETHPORTS];
47 do_write(char *vnf_mem)
49 uint64_t i = rte_rand();
50 uint64_t w = rte_rand();
52 vnf_mem[i % ((noisy_lkup_mem_sz * 1024 * 1024) /
53 RTE_CACHE_LINE_SIZE)] = w;
57 do_read(char *vnf_mem)
59 uint64_t i = rte_rand();
62 r = vnf_mem[i % ((noisy_lkup_mem_sz * 1024 * 1024) /
63 RTE_CACHE_LINE_SIZE)];
68 do_readwrite(char *vnf_mem)
75 * Simulate route lookups as defined by commandline parameters
78 sim_memory_lookups(struct noisy_config *ncf, uint16_t nb_pkts)
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);
96 do_retry(uint16_t nb_rx, uint16_t nb_tx, struct rte_mbuf **pkts,
97 struct fwd_stream *fs)
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);
111 drop_pkts(struct rte_mbuf **pkts, uint16_t nb_rx, uint16_t nb_tx)
115 rte_pktmbuf_free(pkts[nb_tx]);
116 } while (++nb_tx < nb_rx);
119 return nb_rx - nb_tx;
123 * Forwarding of packets in noisy VNF mode. Forward packets but perform
124 * memory operations first as specified on cmdline.
126 * Depending on which commandline parameters are specified we have
127 * different cases to handle:
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
135 * 3. User wants a FIFO and specifies a time in ms to flush all packets
137 * 4. Cases 2 and 3 combined
140 pkt_burst_noisy_vnf(struct fwd_stream *fs)
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;
150 unsigned int fifo_free;
152 bool needs_flush = false;
155 nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
156 pkts_burst, nb_pkt_per_burst);
157 if (unlikely(nb_rx == 0))
159 fs->rx_packets += nb_rx;
161 if (!ncf->do_buffering) {
162 sim_memory_lookups(ncf, nb_rx);
163 nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
165 if (unlikely(nb_tx < nb_rx) && fs->retry_enabled)
166 nb_tx += do_retry(nb_rx, nb_tx, pkts_burst, fs);
167 fs->tx_packets += nb_tx;
168 fs->fwd_dropped += drop_pkts(pkts_burst, nb_rx, nb_tx);
172 fifo_free = rte_ring_free_count(ncf->f);
173 if (fifo_free >= nb_rx) {
174 nb_enqd = rte_ring_enqueue_burst(ncf->f,
175 (void **) pkts_burst, nb_rx, NULL);
177 fs->fwd_dropped += drop_pkts(pkts_burst,
180 nb_deqd = rte_ring_dequeue_burst(ncf->f,
181 (void **) tmp_pkts, nb_rx, NULL);
182 nb_enqd = rte_ring_enqueue_burst(ncf->f,
183 (void **) pkts_burst, nb_deqd, NULL);
185 nb_tx = rte_eth_tx_burst(fs->tx_port,
186 fs->tx_queue, tmp_pkts,
188 if (unlikely(nb_tx < nb_rx) && fs->retry_enabled)
189 nb_tx += do_retry(nb_rx, nb_tx, tmp_pkts, fs);
190 fs->fwd_dropped += drop_pkts(tmp_pkts, nb_deqd, nb_tx);
194 sim_memory_lookups(ncf, nb_enqd);
199 now = ncf->prev_time = rte_get_timer_cycles();
201 now = rte_get_timer_cycles();
202 delta_ms = (now - ncf->prev_time) / freq_khz;
203 needs_flush = delta_ms >= noisy_tx_sw_buf_flush_time &&
204 noisy_tx_sw_buf_flush_time > 0 && !nb_tx;
206 while (needs_flush && !rte_ring_empty(ncf->f)) {
208 nb_deqd = rte_ring_dequeue_burst(ncf->f, (void **)tmp_pkts,
209 MAX_PKT_BURST, NULL);
210 sent = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
212 if (unlikely(sent < nb_deqd) && fs->retry_enabled)
213 nb_tx += do_retry(nb_rx, nb_tx, tmp_pkts, fs);
214 fs->fwd_dropped += drop_pkts(tmp_pkts, nb_deqd, sent);
215 ncf->prev_time = rte_get_timer_cycles();
219 #define NOISY_STRSIZE 256
220 #define NOISY_RING "noisy_ring_%d\n"
223 noisy_fwd_end(portid_t pi)
225 rte_ring_free(noisy_cfg[pi]->f);
226 rte_free(noisy_cfg[pi]->vnf_mem);
227 rte_free(noisy_cfg[pi]);
231 noisy_fwd_begin(portid_t pi)
233 struct noisy_config *n;
234 char name[NOISY_STRSIZE];
236 noisy_cfg[pi] = rte_zmalloc("testpmd noisy fifo and timers",
237 sizeof(struct noisy_config),
238 RTE_CACHE_LINE_SIZE);
239 if (noisy_cfg[pi] == NULL) {
240 rte_exit(EXIT_FAILURE,
241 "rte_zmalloc(%d) struct noisy_config) failed\n",
245 n->do_buffering = noisy_tx_sw_bufsz > 0;
246 n->do_sim = noisy_lkup_num_writes + noisy_lkup_num_reads +
247 noisy_lkup_num_reads_writes;
248 n->do_flush = noisy_tx_sw_buf_flush_time > 0;
250 if (n->do_buffering) {
251 snprintf(name, NOISY_STRSIZE, NOISY_RING, pi);
252 n->f = rte_ring_create(name, noisy_tx_sw_bufsz,
255 rte_exit(EXIT_FAILURE,
256 "rte_ring_create(%d), size %d) failed\n",
260 if (noisy_lkup_mem_sz > 0) {
261 n->vnf_mem = (char *) rte_zmalloc("vnf sim memory",
262 noisy_lkup_mem_sz * 1024 * 1024,
263 RTE_CACHE_LINE_SIZE);
265 rte_exit(EXIT_FAILURE,
266 "rte_zmalloc(%" PRIu64 ") for vnf memory) failed\n",
268 } else if (n->do_sim) {
269 rte_exit(EXIT_FAILURE,
270 "--noisy-lkup-memory-size must be > 0\n");
274 struct fwd_engine noisy_vnf_engine = {
275 .fwd_mode_name = "noisy",
276 .port_fwd_begin = noisy_fwd_begin,
277 .port_fwd_end = noisy_fwd_end,
278 .packet_fwd = pkt_burst_noisy_vnf,