1
2
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
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
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