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
,