xref: /dpdk/app/test-pmd/noisy_vnf.c (revision 68a03efeed657e6e05f281479b33b51102797e15)
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 
35 struct 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 
44 struct noisy_config *noisy_cfg[RTE_MAX_ETHPORTS];
45 
46 static inline void
47 do_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 
56 static inline void
57 do_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 
67 static inline void
68 do_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  */
77 static void
78 sim_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 
95 static uint16_t
96 do_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 
110 static uint32_t
111 drop_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  */
139 static void
140 pkt_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 
199 flush:
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 
226 static void
227 noisy_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 
234 static void
235 noisy_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 
278 struct 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