Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2023 Marvell.
3 : : */
4 : :
5 : : #include <rte_byteorder.h>
6 : : #include <rte_common.h>
7 : : #include <rte_cycles.h>
8 : : #include <rte_ether.h>
9 : : #include <rte_hexdump.h>
10 : : #include <rte_ip.h>
11 : : #include <rte_ip_frag.h>
12 : : #include <rte_mbuf.h>
13 : : #include <rte_mbuf_pool_ops.h>
14 : : #include <rte_os_shim.h>
15 : : #include <rte_random.h>
16 : : #include <rte_udp.h>
17 : :
18 : : #include "test.h"
19 : :
20 : : #define MAX_FLOWS (1024 * 32)
21 : : #define MAX_BKTS MAX_FLOWS
22 : : #define MAX_ENTRIES_PER_BKT 16
23 : : #define MAX_FRAGMENTS RTE_LIBRTE_IP_FRAG_MAX_FRAG
24 : : #define MIN_FRAGMENTS 2
25 : : #define MAX_PKTS (MAX_FLOWS * MAX_FRAGMENTS)
26 : :
27 : : #define MAX_PKT_LEN 2048
28 : : #define MAX_TTL_MS (5 * MS_PER_S)
29 : :
30 : : /* use RFC863 Discard Protocol */
31 : : #define UDP_SRC_PORT 9
32 : : #define UDP_DST_PORT 9
33 : :
34 : : /* use RFC5735 / RFC2544 reserved network test addresses */
35 : : #define IP_SRC_ADDR(x) ((198U << 24) | (18 << 16) | (0 << 8) | (x))
36 : : #define IP_DST_ADDR(x) ((198U << 24) | (18 << 16) | (1 << 15) | (x))
37 : :
38 : : /* 2001:0200::/48 is IANA reserved range for IPv6 benchmarking (RFC5180) */
39 : : static struct rte_ipv6_addr ip6_addr = RTE_IPV6(0x2001, 0x0200, 0, 0, 0, 0, 0, 0);
40 : : #define IP6_VERSION 6
41 : :
42 : : #define IP_DEFTTL 64 /* from RFC 1340. */
43 : :
44 : : static struct rte_ip_frag_tbl *frag_tbl;
45 : : static struct rte_mempool *pkt_pool;
46 : : static struct rte_mbuf *mbufs[MAX_FLOWS][MAX_FRAGMENTS];
47 : : static uint8_t frag_per_flow[MAX_FLOWS];
48 : : static uint32_t flow_cnt;
49 : :
50 : : #define FILL_MODE_LINEAR 0
51 : : #define FILL_MODE_RANDOM 1
52 : : #define FILL_MODE_INTERLEAVED 2
53 : :
54 : : static int
55 : 0 : reassembly_test_setup(void)
56 : : {
57 : 0 : uint64_t max_ttl_cyc = (MAX_TTL_MS * rte_get_timer_hz()) / 1E3;
58 : :
59 : 0 : frag_tbl = rte_ip_frag_table_create(MAX_BKTS, MAX_ENTRIES_PER_BKT,
60 : : MAX_BKTS * MAX_ENTRIES_PER_BKT, max_ttl_cyc,
61 : 0 : rte_socket_id());
62 [ # # ]: 0 : if (frag_tbl == NULL)
63 : : return TEST_FAILED;
64 : :
65 : 0 : rte_mbuf_set_user_mempool_ops("ring_mp_mc");
66 : 0 : pkt_pool = rte_pktmbuf_pool_create(
67 : : "reassembly_perf_pool", MAX_FLOWS * MAX_FRAGMENTS, 0, 0,
68 : 0 : RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
69 [ # # ]: 0 : if (pkt_pool == NULL) {
70 : : printf("[%s] Failed to create pkt pool\n", __func__);
71 : 0 : rte_ip_frag_table_destroy(frag_tbl);
72 : 0 : return TEST_FAILED;
73 : : }
74 : :
75 : : return TEST_SUCCESS;
76 : : }
77 : :
78 : : static void
79 : 0 : reassembly_test_teardown(void)
80 : : {
81 [ # # ]: 0 : if (frag_tbl != NULL)
82 : 0 : rte_ip_frag_table_destroy(frag_tbl);
83 : :
84 : 0 : rte_mempool_free(pkt_pool);
85 : 0 : }
86 : :
87 : : static void
88 : 0 : randomize_array_positions(void **array, uint8_t sz)
89 : : {
90 : : void *tmp;
91 : : int i, j;
92 : :
93 [ # # ]: 0 : if (sz == 2) {
94 : 0 : tmp = array[0];
95 : 0 : array[0] = array[1];
96 : 0 : array[1] = tmp;
97 : : } else {
98 [ # # ]: 0 : for (i = sz - 1; i > 0; i--) {
99 : 0 : j = rte_rand_max(i + 1);
100 : 0 : tmp = array[i];
101 : 0 : array[i] = array[j];
102 : 0 : array[j] = tmp;
103 : : }
104 : : }
105 : 0 : }
106 : :
107 : : static void
108 : 0 : reassembly_print_banner(const char *proto_str)
109 : : {
110 : : printf("+=============================================================="
111 : : "============================================+\n");
112 : : printf("| %-32s| %-3s : %-58d|\n", proto_str, "Flow Count", MAX_FLOWS);
113 : : printf("+================+================+=============+=============+"
114 : : "========================+===================+\n");
115 : : printf("%-17s%-17s%-14s%-14s%-25s%-20s\n", "| Fragment Order",
116 : : "| Fragments/Flow", "| Outstanding", "| Cycles/Flow",
117 : : "| Cycles/Fragment insert", "| Cycles/Reassembly |");
118 : : printf("+================+================+=============+=============+"
119 : : "========================+===================+\n");
120 : 0 : }
121 : :
122 : : static void
123 : 0 : ipv4_frag_fill_data(struct rte_mbuf **mbuf, uint8_t nb_frags, uint32_t flow_id,
124 : : uint8_t fill_mode)
125 : : {
126 : : struct rte_ether_hdr *eth_hdr;
127 : : struct rte_ipv4_hdr *ip_hdr;
128 : : struct rte_udp_hdr *udp_hdr;
129 : : uint16_t frag_len;
130 : : uint8_t i;
131 : :
132 : 0 : frag_len = MAX_PKT_LEN / nb_frags;
133 [ # # ]: 0 : if (frag_len % 8)
134 : 0 : frag_len = RTE_ALIGN_MUL_CEIL(frag_len, 8);
135 : :
136 [ # # ]: 0 : for (i = 0; i < nb_frags; i++) {
137 : 0 : struct rte_mbuf *frag = mbuf[i];
138 : : uint16_t frag_offset = 0;
139 : : uint16_t pkt_len;
140 : :
141 : 0 : frag_offset = i * (frag_len / 8);
142 : :
143 [ # # ]: 0 : if (i == nb_frags - 1)
144 : 0 : frag_len = MAX_PKT_LEN - (frag_len * (nb_frags - 1));
145 : : else
146 : 0 : frag_offset |= RTE_IPV4_HDR_MF_FLAG;
147 : :
148 : : rte_pktmbuf_reset_headroom(frag);
149 : 0 : eth_hdr = rte_pktmbuf_mtod(frag, struct rte_ether_hdr *);
150 : 0 : ip_hdr = rte_pktmbuf_mtod_offset(frag, struct rte_ipv4_hdr *,
151 : : sizeof(struct rte_ether_hdr));
152 : 0 : udp_hdr = rte_pktmbuf_mtod_offset(
153 : : frag, struct rte_udp_hdr *,
154 : : sizeof(struct rte_ether_hdr) +
155 : : sizeof(struct rte_ipv4_hdr));
156 : :
157 : 0 : rte_ether_unformat_addr("02:00:00:00:00:01",
158 : : ð_hdr->dst_addr);
159 : 0 : rte_ether_unformat_addr("02:00:00:00:00:00",
160 : : ð_hdr->src_addr);
161 : 0 : eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
162 : :
163 : : pkt_len = frag_len;
164 : : /*
165 : : * Initialize UDP header.
166 : : */
167 [ # # ]: 0 : if (i == 0) {
168 : 0 : udp_hdr->src_port = rte_cpu_to_be_16(UDP_SRC_PORT);
169 : 0 : udp_hdr->dst_port = rte_cpu_to_be_16(UDP_DST_PORT);
170 [ # # ]: 0 : udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_len);
171 : 0 : udp_hdr->dgram_cksum = 0; /* No UDP checksum. */
172 : : }
173 : :
174 : : /*
175 : : * Initialize IP header.
176 : : */
177 : 0 : pkt_len = (uint16_t)(pkt_len + sizeof(struct rte_ipv4_hdr));
178 : 0 : ip_hdr->version_ihl = RTE_IPV4_VHL_DEF;
179 : 0 : ip_hdr->type_of_service = 0;
180 [ # # ]: 0 : ip_hdr->fragment_offset = rte_cpu_to_be_16(frag_offset);
181 : 0 : ip_hdr->time_to_live = IP_DEFTTL;
182 : 0 : ip_hdr->next_proto_id = IPPROTO_UDP;
183 : 0 : ip_hdr->packet_id =
184 [ # # ]: 0 : rte_cpu_to_be_16((flow_id + 1) % UINT16_MAX);
185 [ # # ]: 0 : ip_hdr->total_length = rte_cpu_to_be_16(pkt_len);
186 : : /* Using more than 32K flows will modify the 2nd octet of the IP. */
187 [ # # ]: 0 : ip_hdr->src_addr = rte_cpu_to_be_32(IP_SRC_ADDR(flow_id));
188 [ # # ]: 0 : ip_hdr->dst_addr = rte_cpu_to_be_32(IP_DST_ADDR(flow_id));
189 : :
190 : 0 : ip_hdr->hdr_checksum = (uint16_t)rte_ipv4_cksum_simple(ip_hdr);
191 : :
192 : 0 : frag->data_len = sizeof(struct rte_ether_hdr) + pkt_len;
193 : 0 : frag->pkt_len = frag->data_len;
194 : 0 : frag->l2_len = sizeof(struct rte_ether_hdr);
195 : 0 : frag->l3_len = sizeof(struct rte_ipv4_hdr);
196 : : }
197 : :
198 [ # # ]: 0 : if (fill_mode == FILL_MODE_RANDOM)
199 : 0 : randomize_array_positions((void **)mbuf, nb_frags);
200 : 0 : }
201 : :
202 : : static uint8_t
203 : : get_rand_frags(uint8_t max_frag)
204 : : {
205 : 0 : uint8_t frags = rte_rand_max(max_frag + 1);
206 : :
207 : 0 : return frags <= 1 ? MIN_FRAGMENTS : frags;
208 : : }
209 : :
210 : : static int
211 : 0 : ipv4_rand_frag_pkt_setup(uint8_t fill_mode, uint8_t max_frag)
212 : : {
213 : : uint8_t nb_frag;
214 : : int i;
215 : :
216 [ # # ]: 0 : for (i = 0; i < MAX_FLOWS; i++) {
217 : 0 : nb_frag = get_rand_frags(max_frag);
218 [ # # # # ]: 0 : if (rte_mempool_get_bulk(pkt_pool, (void **)mbufs[i], nb_frag) <
219 : : 0)
220 : : return TEST_FAILED;
221 : 0 : ipv4_frag_fill_data(mbufs[i], nb_frag, i, fill_mode);
222 : 0 : frag_per_flow[i] = nb_frag;
223 : : }
224 : 0 : flow_cnt = i;
225 : :
226 : 0 : return TEST_SUCCESS;
227 : : }
228 : :
229 : : static int
230 : 0 : ipv4_frag_pkt_setup(uint8_t fill_mode, uint8_t nb_frag)
231 : : {
232 : : int i;
233 : :
234 [ # # ]: 0 : for (i = 0; i < MAX_FLOWS; i++) {
235 [ # # # # ]: 0 : if (rte_mempool_get_bulk(pkt_pool, (void **)mbufs[i], nb_frag) <
236 : : 0)
237 : : return TEST_FAILED;
238 : 0 : ipv4_frag_fill_data(mbufs[i], nb_frag, i, fill_mode);
239 : 0 : frag_per_flow[i] = nb_frag;
240 : : }
241 : 0 : flow_cnt = i;
242 : :
243 : 0 : return TEST_SUCCESS;
244 : : }
245 : :
246 : : static void
247 : 0 : ipv6_frag_fill_data(struct rte_mbuf **mbuf, uint8_t nb_frags, uint32_t flow_id,
248 : : uint8_t fill_mode)
249 : : {
250 : : struct ipv6_extension_fragment *frag_hdr;
251 : : struct rte_ether_hdr *eth_hdr;
252 : : struct rte_ipv6_hdr *ip_hdr;
253 : : struct rte_udp_hdr *udp_hdr;
254 : : uint16_t frag_len;
255 : : uint8_t i;
256 : :
257 : 0 : frag_len = MAX_PKT_LEN / nb_frags;
258 [ # # ]: 0 : if (frag_len % 8)
259 : 0 : frag_len = RTE_ALIGN_MUL_CEIL(frag_len, 8);
260 : :
261 [ # # ]: 0 : for (i = 0; i < nb_frags; i++) {
262 : 0 : struct rte_mbuf *frag = mbuf[i];
263 : : uint16_t frag_offset = 0;
264 : : uint16_t pkt_len;
265 : :
266 : 0 : frag_offset = i * (frag_len / 8);
267 : 0 : frag_offset <<= 3;
268 [ # # ]: 0 : if (i == nb_frags - 1) {
269 : 0 : frag_len = MAX_PKT_LEN - (frag_len * (nb_frags - 1));
270 : : frag_offset = RTE_IPV6_SET_FRAG_DATA(frag_offset, 0);
271 : : } else {
272 : 0 : frag_offset = RTE_IPV6_SET_FRAG_DATA(frag_offset, 1);
273 : : }
274 : :
275 : : rte_pktmbuf_reset_headroom(frag);
276 : 0 : eth_hdr = rte_pktmbuf_mtod(frag, struct rte_ether_hdr *);
277 : 0 : ip_hdr = rte_pktmbuf_mtod_offset(frag, struct rte_ipv6_hdr *,
278 : : sizeof(struct rte_ether_hdr));
279 : 0 : udp_hdr = rte_pktmbuf_mtod_offset(
280 : : frag, struct rte_udp_hdr *,
281 : : sizeof(struct rte_ether_hdr) +
282 : : sizeof(struct rte_ipv6_hdr) +
283 : : RTE_IPV6_FRAG_HDR_SIZE);
284 : 0 : frag_hdr = rte_pktmbuf_mtod_offset(
285 : : frag, struct ipv6_extension_fragment *,
286 : : sizeof(struct rte_ether_hdr) +
287 : : sizeof(struct rte_ipv6_hdr));
288 : :
289 : 0 : rte_ether_unformat_addr("02:00:00:00:00:01",
290 : : ð_hdr->dst_addr);
291 : 0 : rte_ether_unformat_addr("02:00:00:00:00:00",
292 : : ð_hdr->src_addr);
293 : 0 : eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
294 : :
295 : : pkt_len = frag_len;
296 : : /*
297 : : * Initialize UDP header.
298 : : */
299 [ # # ]: 0 : if (i == 0) {
300 : 0 : udp_hdr->src_port = rte_cpu_to_be_16(UDP_SRC_PORT);
301 : 0 : udp_hdr->dst_port = rte_cpu_to_be_16(UDP_DST_PORT);
302 [ # # ]: 0 : udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_len);
303 : 0 : udp_hdr->dgram_cksum = 0; /* No UDP checksum. */
304 : : }
305 : :
306 : : /*
307 : : * Initialize IP header.
308 : : */
309 : 0 : pkt_len = (uint16_t)(pkt_len + sizeof(struct rte_ipv6_hdr) +
310 : : RTE_IPV6_FRAG_HDR_SIZE);
311 : 0 : ip_hdr->vtc_flow = rte_cpu_to_be_32(IP6_VERSION << 28);
312 : 0 : ip_hdr->payload_len =
313 [ # # ]: 0 : rte_cpu_to_be_16(pkt_len - sizeof(struct rte_ipv6_hdr));
314 : 0 : ip_hdr->proto = IPPROTO_FRAGMENT;
315 : 0 : ip_hdr->hop_limits = IP_DEFTTL;
316 : 0 : ip_hdr->src_addr = ip6_addr;
317 : 0 : ip_hdr->dst_addr = ip6_addr;
318 : 0 : ip_hdr->src_addr.a[7] = (flow_id >> 16) & 0xf;
319 : 0 : ip_hdr->src_addr.a[7] |= 0x10;
320 : 0 : ip_hdr->src_addr.a[8] = (flow_id >> 8) & 0xff;
321 : 0 : ip_hdr->src_addr.a[9] = flow_id & 0xff;
322 : :
323 : : ip_hdr->dst_addr.a[7] = (flow_id >> 16) & 0xf;
324 : 0 : ip_hdr->dst_addr.a[7] |= 0x20;
325 : 0 : ip_hdr->dst_addr.a[8] = (flow_id >> 8) & 0xff;
326 : 0 : ip_hdr->dst_addr.a[9] = flow_id & 0xff;
327 : :
328 : 0 : frag_hdr->next_header = IPPROTO_UDP;
329 : 0 : frag_hdr->reserved = 0;
330 [ # # ]: 0 : frag_hdr->frag_data = rte_cpu_to_be_16(frag_offset);
331 [ # # ]: 0 : frag_hdr->id = rte_cpu_to_be_32(flow_id + 1);
332 : :
333 : 0 : frag->data_len = sizeof(struct rte_ether_hdr) + pkt_len;
334 : 0 : frag->pkt_len = frag->data_len;
335 : 0 : frag->l2_len = sizeof(struct rte_ether_hdr);
336 : 0 : frag->l3_len =
337 : : sizeof(struct rte_ipv6_hdr) + RTE_IPV6_FRAG_HDR_SIZE;
338 : : }
339 : :
340 [ # # ]: 0 : if (fill_mode == FILL_MODE_RANDOM)
341 : 0 : randomize_array_positions((void **)mbuf, nb_frags);
342 : 0 : }
343 : :
344 : : static int
345 : 0 : ipv6_rand_frag_pkt_setup(uint8_t fill_mode, uint8_t max_frag)
346 : : {
347 : : uint8_t nb_frag;
348 : : int i;
349 : :
350 [ # # ]: 0 : for (i = 0; i < MAX_FLOWS; i++) {
351 : 0 : nb_frag = get_rand_frags(max_frag);
352 [ # # # # ]: 0 : if (rte_mempool_get_bulk(pkt_pool, (void **)mbufs[i], nb_frag) <
353 : : 0)
354 : : return TEST_FAILED;
355 : 0 : ipv6_frag_fill_data(mbufs[i], nb_frag, i, fill_mode);
356 : 0 : frag_per_flow[i] = nb_frag;
357 : : }
358 : 0 : flow_cnt = i;
359 : :
360 : 0 : return TEST_SUCCESS;
361 : : }
362 : :
363 : : static int
364 : 0 : ipv6_frag_pkt_setup(uint8_t fill_mode, uint8_t nb_frag)
365 : : {
366 : : int i;
367 : :
368 [ # # ]: 0 : for (i = 0; i < MAX_FLOWS; i++) {
369 [ # # # # ]: 0 : if (rte_mempool_get_bulk(pkt_pool, (void **)mbufs[i], nb_frag) <
370 : : 0)
371 : : return TEST_FAILED;
372 : 0 : ipv6_frag_fill_data(mbufs[i], nb_frag, i, fill_mode);
373 : 0 : frag_per_flow[i] = nb_frag;
374 : : }
375 : 0 : flow_cnt = i;
376 : :
377 : 0 : return TEST_SUCCESS;
378 : : }
379 : :
380 : : static void
381 : : frag_pkt_teardown(void)
382 : : {
383 : : uint32_t i;
384 : :
385 [ # # # # ]: 0 : for (i = 0; i < flow_cnt; i++)
386 : 0 : rte_pktmbuf_free(mbufs[i][0]);
387 : : }
388 : :
389 : : static void
390 : 0 : reassembly_print_stats(int8_t nb_frags, uint8_t fill_order,
391 : : uint32_t outstanding, uint64_t cyc_per_flow,
392 : : uint64_t cyc_per_frag_insert,
393 : : uint64_t cyc_per_reassembly)
394 : : {
395 : : char frag_str[8], order_str[12];
396 : :
397 [ # # ]: 0 : if (nb_frags > 0)
398 : 0 : snprintf(frag_str, sizeof(frag_str), "%d", nb_frags);
399 : : else
400 : : snprintf(frag_str, sizeof(frag_str), "RANDOM");
401 : :
402 [ # # # # ]: 0 : switch (fill_order) {
403 : : case FILL_MODE_LINEAR:
404 : : snprintf(order_str, sizeof(order_str), "LINEAR");
405 : : break;
406 : : case FILL_MODE_RANDOM:
407 : : snprintf(order_str, sizeof(order_str), "RANDOM");
408 : : break;
409 : : case FILL_MODE_INTERLEAVED:
410 : : snprintf(order_str, sizeof(order_str), "INTERLEAVED");
411 : : break;
412 : : default:
413 : : break;
414 : : }
415 : :
416 : : printf("| %-14s | %-14s | %-11d | %-11" PRIu64 " | %-22" PRIu64
417 : : " | %-17" PRIu64 " |\n",
418 : : order_str, frag_str, outstanding, cyc_per_flow,
419 : : cyc_per_frag_insert, cyc_per_reassembly);
420 : : printf("+================+================+=============+=============+"
421 : : "========================+===================+\n");
422 : 0 : }
423 : :
424 : : static void
425 : : join_array(struct rte_mbuf **dest_arr, struct rte_mbuf **src_arr,
426 : : uint8_t offset, uint8_t sz)
427 : : {
428 : : int i, j;
429 : :
430 [ # # # # ]: 0 : for (i = offset, j = 0; j < sz; i++, j++)
431 : 0 : dest_arr[i] = src_arr[j];
432 : : }
433 : :
434 : : static int
435 : 0 : ipv4_reassembly_perf(int8_t nb_frags, uint8_t fill_order)
436 : : {
437 : : struct rte_ip_frag_death_row death_row;
438 : : uint64_t total_reassembled_cyc = 0;
439 : : uint64_t total_empty_cyc = 0;
440 : : uint64_t tstamp, flow_tstamp;
441 : : uint64_t frag_processed = 0;
442 : : uint64_t total_cyc = 0;
443 : : uint32_t i, j;
444 : :
445 [ # # ]: 0 : for (i = 0; i < flow_cnt; i++) {
446 : : struct rte_mbuf *buf_out = NULL;
447 : : uint8_t reassembled = 0;
448 : :
449 : : flow_tstamp = rte_rdtsc_precise();
450 [ # # ]: 0 : for (j = 0; j < frag_per_flow[i]; j++) {
451 : 0 : struct rte_mbuf *buf = mbufs[i][j];
452 : 0 : struct rte_ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset(
453 : : buf, struct rte_ipv4_hdr *, buf->l2_len);
454 : :
455 : : tstamp = rte_rdtsc_precise();
456 : 0 : buf_out = rte_ipv4_frag_reassemble_packet(
457 : : frag_tbl, &death_row, buf, flow_tstamp, ip_hdr);
458 : :
459 [ # # ]: 0 : if (buf_out == NULL) {
460 : 0 : total_empty_cyc += rte_rdtsc_precise() - tstamp;
461 : 0 : frag_processed++;
462 : 0 : continue;
463 : : } else {
464 : : /*Packet out*/
465 : 0 : total_reassembled_cyc +=
466 : 0 : rte_rdtsc_precise() - tstamp;
467 : : reassembled = 1;
468 : : }
469 : : }
470 : 0 : total_cyc += rte_rdtsc_precise() - flow_tstamp;
471 [ # # # # ]: 0 : if (!reassembled || buf_out->nb_segs != frag_per_flow[i])
472 : : return TEST_FAILED;
473 : 0 : memset(mbufs[i], 0, sizeof(struct rte_mbuf *) * MAX_FRAGMENTS);
474 : 0 : mbufs[i][0] = buf_out;
475 : : }
476 : :
477 : 0 : reassembly_print_stats(nb_frags, fill_order, 0, total_cyc / flow_cnt,
478 : : total_empty_cyc / frag_processed,
479 : : total_reassembled_cyc / flow_cnt);
480 : :
481 : 0 : return TEST_SUCCESS;
482 : : }
483 : :
484 : : static int
485 : 0 : ipv4_outstanding_reassembly_perf(int8_t nb_frags, uint8_t fill_order,
486 : : uint32_t outstanding)
487 : : {
488 : : struct rte_ip_frag_death_row death_row;
489 : : uint64_t total_reassembled_cyc = 0;
490 : : uint64_t total_empty_cyc = 0;
491 : : uint64_t tstamp, flow_tstamp;
492 : : uint64_t frag_processed = 0;
493 : : uint64_t total_cyc = 0;
494 : : uint32_t i, j, k;
495 : :
496 : : k = outstanding;
497 : : /* Insert outstanding fragments */
498 [ # # # # ]: 0 : for (i = 0; k && (i < flow_cnt); i++) {
499 : : struct rte_mbuf *buf_out = NULL;
500 : :
501 : : flow_tstamp = rte_rdtsc_precise();
502 [ # # ]: 0 : for (j = frag_per_flow[i] - 1; j > 0; j--) {
503 : 0 : struct rte_mbuf *buf = mbufs[i][j];
504 : 0 : struct rte_ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset(
505 : : buf, struct rte_ipv4_hdr *, buf->l2_len);
506 : :
507 : : tstamp = rte_rdtsc_precise();
508 : 0 : buf_out = rte_ipv4_frag_reassemble_packet(
509 : : frag_tbl, &death_row, buf, flow_tstamp, ip_hdr);
510 : 0 : total_empty_cyc += rte_rdtsc_precise() - tstamp;
511 : 0 : frag_processed++;
512 [ # # ]: 0 : if (buf_out != NULL)
513 : : return TEST_FAILED;
514 : :
515 : 0 : k--;
516 : : }
517 : 0 : frag_per_flow[i] = 1;
518 : : }
519 : :
520 [ # # ]: 0 : for (i = 0; i < flow_cnt; i++) {
521 : : struct rte_mbuf *buf_out = NULL;
522 : : uint8_t reassembled = 0;
523 : :
524 : : flow_tstamp = rte_rdtsc_precise();
525 [ # # ]: 0 : for (j = 0; j < frag_per_flow[i]; j++) {
526 : 0 : struct rte_mbuf *buf = mbufs[i][j];
527 : 0 : struct rte_ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset(
528 : : buf, struct rte_ipv4_hdr *, buf->l2_len);
529 : :
530 : : tstamp = rte_rdtsc_precise();
531 : 0 : buf_out = rte_ipv4_frag_reassemble_packet(
532 : : frag_tbl, &death_row, buf, flow_tstamp, ip_hdr);
533 : :
534 [ # # ]: 0 : if (buf_out == NULL) {
535 : 0 : total_empty_cyc += rte_rdtsc_precise() - tstamp;
536 : 0 : frag_processed++;
537 : 0 : continue;
538 : : } else {
539 : : /*Packet out*/
540 : 0 : total_reassembled_cyc +=
541 : 0 : rte_rdtsc_precise() - tstamp;
542 : : reassembled = 1;
543 : : }
544 : : }
545 : 0 : total_cyc += rte_rdtsc_precise() - flow_tstamp;
546 [ # # ]: 0 : if (!reassembled)
547 : : return TEST_FAILED;
548 : 0 : memset(mbufs[i], 0, sizeof(struct rte_mbuf *) * MAX_FRAGMENTS);
549 : 0 : mbufs[i][0] = buf_out;
550 : : }
551 : :
552 : 0 : reassembly_print_stats(nb_frags, fill_order, outstanding,
553 : : total_cyc / flow_cnt,
554 : : total_empty_cyc / frag_processed,
555 : : total_reassembled_cyc / flow_cnt);
556 : :
557 : 0 : return TEST_SUCCESS;
558 : : }
559 : :
560 : : #define TEST_REASSEMBLY_ITERATIONS 4
561 : :
562 : : static int
563 : 0 : ipv4_reassembly_interleaved_flows_perf(uint8_t nb_frags)
564 : : {
565 : : struct rte_ip_frag_death_row death_row;
566 : : uint64_t total_reassembled_cyc = 0;
567 : : uint64_t total_empty_cyc = 0;
568 : : uint64_t tstamp, flow_tstamp;
569 : : uint64_t frag_processed = 0;
570 : : uint64_t total_cyc = 0;
571 : : uint32_t i, j;
572 : :
573 [ # # ]: 0 : for (i = 0; i < flow_cnt; i += TEST_REASSEMBLY_ITERATIONS) {
574 : 0 : struct rte_mbuf *buf_out[4] = {NULL};
575 : : uint8_t reassembled = 0;
576 : : uint8_t nb_frags = 0;
577 : : uint8_t prev = 0;
578 : :
579 [ # # ]: 0 : for (j = 0; j < TEST_REASSEMBLY_ITERATIONS; j++)
580 : 0 : nb_frags += frag_per_flow[i + j];
581 : :
582 : : struct rte_mbuf *buf_arr[TEST_REASSEMBLY_ITERATIONS * MAX_FRAGMENTS];
583 [ # # ]: 0 : for (j = 0; j < TEST_REASSEMBLY_ITERATIONS; j++) {
584 : 0 : join_array(buf_arr, mbufs[i + j], prev,
585 : 0 : frag_per_flow[i + j]);
586 : 0 : prev += frag_per_flow[i + j];
587 : : }
588 : 0 : randomize_array_positions((void **)buf_arr, nb_frags);
589 : : flow_tstamp = rte_rdtsc_precise();
590 [ # # ]: 0 : for (j = 0; j < nb_frags; j++) {
591 : 0 : struct rte_mbuf *buf = buf_arr[j];
592 : 0 : struct rte_ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset(
593 : : buf, struct rte_ipv4_hdr *, buf->l2_len);
594 : :
595 : : tstamp = rte_rdtsc_precise();
596 : 0 : buf_out[reassembled] = rte_ipv4_frag_reassemble_packet(
597 : : frag_tbl, &death_row, buf, flow_tstamp, ip_hdr);
598 : :
599 [ # # ]: 0 : if (buf_out[reassembled] == NULL) {
600 : 0 : total_empty_cyc += rte_rdtsc_precise() - tstamp;
601 : 0 : frag_processed++;
602 : 0 : continue;
603 : : } else {
604 : : /*Packet out*/
605 : 0 : total_reassembled_cyc +=
606 : 0 : rte_rdtsc_precise() - tstamp;
607 : 0 : reassembled++;
608 : : }
609 : : }
610 : 0 : total_cyc += rte_rdtsc_precise() - flow_tstamp;
611 [ # # ]: 0 : if (reassembled != 4)
612 : 0 : return TEST_FAILED;
613 [ # # ]: 0 : for (j = 0; j < TEST_REASSEMBLY_ITERATIONS; j++) {
614 : 0 : memset(mbufs[i + j], 0,
615 : : sizeof(struct rte_mbuf *) * MAX_FRAGMENTS);
616 : 0 : mbufs[i + j][0] = buf_out[j];
617 : : }
618 : : }
619 : :
620 : 0 : reassembly_print_stats(nb_frags, FILL_MODE_INTERLEAVED, 0,
621 : : total_cyc / flow_cnt,
622 : : total_empty_cyc / frag_processed,
623 : : total_reassembled_cyc / flow_cnt);
624 : :
625 : 0 : return TEST_SUCCESS;
626 : : }
627 : :
628 : : static int
629 : 0 : ipv6_reassembly_perf(int8_t nb_frags, uint8_t fill_order)
630 : : {
631 : : struct rte_ip_frag_death_row death_row;
632 : : uint64_t total_reassembled_cyc = 0;
633 : : uint64_t total_empty_cyc = 0;
634 : : uint64_t tstamp, flow_tstamp;
635 : : uint64_t frag_processed = 0;
636 : : uint64_t total_cyc = 0;
637 : : uint32_t i, j;
638 : :
639 [ # # ]: 0 : for (i = 0; i < flow_cnt; i++) {
640 : : struct rte_mbuf *buf_out = NULL;
641 : : uint8_t reassembled = 0;
642 : :
643 : : flow_tstamp = rte_rdtsc_precise();
644 [ # # ]: 0 : for (j = 0; j < frag_per_flow[i]; j++) {
645 : 0 : struct rte_mbuf *buf = mbufs[i][j];
646 : 0 : struct rte_ipv6_hdr *ip_hdr = rte_pktmbuf_mtod_offset(
647 : : buf, struct rte_ipv6_hdr *, buf->l2_len);
648 : 0 : struct ipv6_extension_fragment *frag_hdr =
649 : 0 : rte_pktmbuf_mtod_offset(
650 : : buf, struct ipv6_extension_fragment *,
651 : : buf->l2_len +
652 : : sizeof(struct rte_ipv6_hdr));
653 : :
654 : : tstamp = rte_rdtsc_precise();
655 : 0 : buf_out = rte_ipv6_frag_reassemble_packet(
656 : : frag_tbl, &death_row, buf, flow_tstamp, ip_hdr,
657 : : frag_hdr);
658 : :
659 [ # # ]: 0 : if (buf_out == NULL) {
660 : 0 : total_empty_cyc += rte_rdtsc_precise() - tstamp;
661 : 0 : frag_processed++;
662 : 0 : continue;
663 : : } else {
664 : : /*Packet out*/
665 : 0 : total_reassembled_cyc +=
666 : 0 : rte_rdtsc_precise() - tstamp;
667 : : reassembled = 1;
668 : : }
669 : : }
670 : 0 : total_cyc += rte_rdtsc_precise() - flow_tstamp;
671 [ # # # # ]: 0 : if (!reassembled || buf_out->nb_segs != frag_per_flow[i])
672 : : return TEST_FAILED;
673 : 0 : memset(mbufs[i], 0, sizeof(struct rte_mbuf *) * MAX_FRAGMENTS);
674 : 0 : mbufs[i][0] = buf_out;
675 : : }
676 : :
677 : 0 : reassembly_print_stats(nb_frags, fill_order, 0, total_cyc / flow_cnt,
678 : : total_empty_cyc / frag_processed,
679 : : total_reassembled_cyc / flow_cnt);
680 : :
681 : 0 : return TEST_SUCCESS;
682 : : }
683 : :
684 : : static int
685 : 0 : ipv6_outstanding_reassembly_perf(int8_t nb_frags, uint8_t fill_order,
686 : : uint32_t outstanding)
687 : : {
688 : : struct rte_ip_frag_death_row death_row;
689 : : uint64_t total_reassembled_cyc = 0;
690 : : uint64_t total_empty_cyc = 0;
691 : : uint64_t tstamp, flow_tstamp;
692 : : uint64_t frag_processed = 0;
693 : : uint64_t total_cyc = 0;
694 : : uint32_t i, j, k;
695 : :
696 : : k = outstanding;
697 : : /* Insert outstanding fragments */
698 [ # # # # ]: 0 : for (i = 0; k && (i < flow_cnt); i++) {
699 : : struct rte_mbuf *buf_out = NULL;
700 : :
701 : : flow_tstamp = rte_rdtsc_precise();
702 [ # # ]: 0 : for (j = frag_per_flow[i] - 1; j > 0; j--) {
703 : 0 : struct rte_mbuf *buf = mbufs[i][j];
704 : 0 : struct rte_ipv6_hdr *ip_hdr = rte_pktmbuf_mtod_offset(
705 : : buf, struct rte_ipv6_hdr *, buf->l2_len);
706 : 0 : struct ipv6_extension_fragment *frag_hdr =
707 : 0 : rte_pktmbuf_mtod_offset(
708 : : buf, struct ipv6_extension_fragment *,
709 : : buf->l2_len +
710 : : sizeof(struct rte_ipv6_hdr));
711 : :
712 : : tstamp = rte_rdtsc_precise();
713 : 0 : buf_out = rte_ipv6_frag_reassemble_packet(
714 : : frag_tbl, &death_row, buf, flow_tstamp, ip_hdr,
715 : : frag_hdr);
716 : 0 : total_empty_cyc += rte_rdtsc_precise() - tstamp;
717 : 0 : frag_processed++;
718 : :
719 [ # # ]: 0 : if (buf_out != NULL)
720 : : return TEST_FAILED;
721 : :
722 : 0 : k--;
723 : : }
724 : 0 : frag_per_flow[i] = 1;
725 : : }
726 : :
727 [ # # ]: 0 : for (i = 0; i < flow_cnt; i++) {
728 : : struct rte_mbuf *buf_out = NULL;
729 : : uint8_t reassembled = 0;
730 : :
731 : : flow_tstamp = rte_rdtsc_precise();
732 [ # # ]: 0 : for (j = 0; j < frag_per_flow[i]; j++) {
733 : 0 : struct rte_mbuf *buf = mbufs[i][j];
734 : 0 : struct rte_ipv6_hdr *ip_hdr = rte_pktmbuf_mtod_offset(
735 : : buf, struct rte_ipv6_hdr *, buf->l2_len);
736 : 0 : struct ipv6_extension_fragment *frag_hdr =
737 : 0 : rte_pktmbuf_mtod_offset(
738 : : buf, struct ipv6_extension_fragment *,
739 : : buf->l2_len +
740 : : sizeof(struct rte_ipv6_hdr));
741 : :
742 : : tstamp = rte_rdtsc_precise();
743 : 0 : buf_out = rte_ipv6_frag_reassemble_packet(
744 : : frag_tbl, &death_row, buf, flow_tstamp, ip_hdr,
745 : : frag_hdr);
746 : :
747 [ # # ]: 0 : if (buf_out == NULL) {
748 : 0 : total_empty_cyc += rte_rdtsc_precise() - tstamp;
749 : 0 : frag_processed++;
750 : 0 : continue;
751 : : } else {
752 : : /*Packet out*/
753 : 0 : total_reassembled_cyc +=
754 : 0 : rte_rdtsc_precise() - tstamp;
755 : : reassembled = 1;
756 : : }
757 : : }
758 : 0 : total_cyc += rte_rdtsc_precise() - flow_tstamp;
759 [ # # ]: 0 : if (!reassembled)
760 : : return TEST_FAILED;
761 : 0 : memset(mbufs[i], 0, sizeof(struct rte_mbuf *) * MAX_FRAGMENTS);
762 : 0 : mbufs[i][0] = buf_out;
763 : : }
764 : :
765 : 0 : reassembly_print_stats(nb_frags, fill_order, outstanding,
766 : : total_cyc / flow_cnt,
767 : : total_empty_cyc / frag_processed,
768 : : total_reassembled_cyc / flow_cnt);
769 : :
770 : 0 : return TEST_SUCCESS;
771 : : }
772 : :
773 : : static int
774 : 0 : ipv6_reassembly_interleaved_flows_perf(int8_t nb_frags)
775 : : {
776 : : struct rte_ip_frag_death_row death_row;
777 : : uint64_t total_reassembled_cyc = 0;
778 : : uint64_t total_empty_cyc = 0;
779 : : uint64_t tstamp, flow_tstamp;
780 : : uint64_t frag_processed = 0;
781 : : uint64_t total_cyc = 0;
782 : : uint32_t i, j;
783 : :
784 [ # # ]: 0 : for (i = 0; i < flow_cnt; i += TEST_REASSEMBLY_ITERATIONS) {
785 : 0 : struct rte_mbuf *buf_out[4] = {NULL};
786 : : uint8_t reassembled = 0;
787 : : uint8_t nb_frags = 0;
788 : : uint8_t prev = 0;
789 : :
790 [ # # ]: 0 : for (j = 0; j < TEST_REASSEMBLY_ITERATIONS; j++)
791 : 0 : nb_frags += frag_per_flow[i + j];
792 : :
793 : : struct rte_mbuf *buf_arr[TEST_REASSEMBLY_ITERATIONS * MAX_FRAGMENTS];
794 [ # # ]: 0 : for (j = 0; j < TEST_REASSEMBLY_ITERATIONS; j++) {
795 : 0 : join_array(buf_arr, mbufs[i + j], prev,
796 : 0 : frag_per_flow[i + j]);
797 : 0 : prev += frag_per_flow[i + j];
798 : : }
799 : 0 : randomize_array_positions((void **)buf_arr, nb_frags);
800 : : flow_tstamp = rte_rdtsc_precise();
801 [ # # ]: 0 : for (j = 0; j < nb_frags; j++) {
802 : 0 : struct rte_mbuf *buf = buf_arr[j];
803 : 0 : struct rte_ipv6_hdr *ip_hdr = rte_pktmbuf_mtod_offset(
804 : : buf, struct rte_ipv6_hdr *, buf->l2_len);
805 : 0 : struct ipv6_extension_fragment *frag_hdr =
806 : 0 : rte_pktmbuf_mtod_offset(
807 : : buf, struct ipv6_extension_fragment *,
808 : : buf->l2_len +
809 : : sizeof(struct rte_ipv6_hdr));
810 : :
811 : : tstamp = rte_rdtsc_precise();
812 : 0 : buf_out[reassembled] = rte_ipv6_frag_reassemble_packet(
813 : : frag_tbl, &death_row, buf, flow_tstamp, ip_hdr,
814 : : frag_hdr);
815 : :
816 [ # # ]: 0 : if (buf_out[reassembled] == NULL) {
817 : 0 : total_empty_cyc += rte_rdtsc_precise() - tstamp;
818 : 0 : frag_processed++;
819 : 0 : continue;
820 : : } else {
821 : : /*Packet out*/
822 : 0 : total_reassembled_cyc +=
823 : 0 : rte_rdtsc_precise() - tstamp;
824 : 0 : reassembled++;
825 : : }
826 : : }
827 : 0 : total_cyc += rte_rdtsc_precise() - flow_tstamp;
828 [ # # ]: 0 : if (reassembled != 4)
829 : 0 : return TEST_FAILED;
830 [ # # ]: 0 : for (j = 0; j < TEST_REASSEMBLY_ITERATIONS; j++) {
831 : 0 : memset(mbufs[i + j], 0,
832 : : sizeof(struct rte_mbuf *) * MAX_FRAGMENTS);
833 : 0 : mbufs[i + j][0] = buf_out[j];
834 : : }
835 : : }
836 : :
837 : 0 : reassembly_print_stats(nb_frags, FILL_MODE_INTERLEAVED, 0,
838 : : total_cyc / flow_cnt,
839 : : total_empty_cyc / frag_processed,
840 : : total_reassembled_cyc / flow_cnt);
841 : :
842 : 0 : return TEST_SUCCESS;
843 : : }
844 : :
845 : : static int
846 : 0 : ipv4_reassembly_test(int8_t nb_frags, uint8_t fill_order, uint32_t outstanding)
847 : : {
848 : : int rc;
849 : :
850 [ # # ]: 0 : if (nb_frags > 0)
851 : 0 : rc = ipv4_frag_pkt_setup(fill_order, nb_frags);
852 : : else
853 : 0 : rc = ipv4_rand_frag_pkt_setup(fill_order, MAX_FRAGMENTS);
854 : :
855 [ # # ]: 0 : if (rc)
856 : : return rc;
857 : :
858 [ # # ]: 0 : if (outstanding)
859 : 0 : rc = ipv4_outstanding_reassembly_perf(nb_frags, fill_order,
860 : : outstanding);
861 [ # # ]: 0 : else if (fill_order == FILL_MODE_INTERLEAVED)
862 : 0 : rc = ipv4_reassembly_interleaved_flows_perf(nb_frags);
863 : : else
864 : 0 : rc = ipv4_reassembly_perf(nb_frags, fill_order);
865 : :
866 : : frag_pkt_teardown();
867 : :
868 : : return rc;
869 : : }
870 : :
871 : : static int
872 : 0 : ipv6_reassembly_test(int8_t nb_frags, uint8_t fill_order, uint32_t outstanding)
873 : : {
874 : : int rc;
875 : :
876 [ # # ]: 0 : if (nb_frags > 0)
877 : 0 : rc = ipv6_frag_pkt_setup(fill_order, nb_frags);
878 : : else
879 : 0 : rc = ipv6_rand_frag_pkt_setup(fill_order, MAX_FRAGMENTS);
880 : :
881 [ # # ]: 0 : if (rc)
882 : : return rc;
883 : :
884 [ # # ]: 0 : if (outstanding)
885 : 0 : rc = ipv6_outstanding_reassembly_perf(nb_frags, fill_order,
886 : : outstanding);
887 [ # # ]: 0 : else if (fill_order == FILL_MODE_INTERLEAVED)
888 : 0 : rc = ipv6_reassembly_interleaved_flows_perf(nb_frags);
889 : : else
890 : 0 : rc = ipv6_reassembly_perf(nb_frags, fill_order);
891 : :
892 : : frag_pkt_teardown();
893 : :
894 : : return rc;
895 : : }
896 : :
897 : : static int
898 : 0 : test_reassembly_perf(void)
899 : : {
900 : 0 : int8_t nb_fragments[] = {2, 3, MAX_FRAGMENTS, -1 /* Random */};
901 : 0 : uint8_t order_type[] = {FILL_MODE_LINEAR, FILL_MODE_RANDOM};
902 : 0 : uint32_t outstanding[] = {100, 500, 1000, 2000, 3000};
903 : : uint32_t i, j;
904 : : int rc;
905 : :
906 : 0 : rc = reassembly_test_setup();
907 [ # # ]: 0 : if (rc)
908 : : return rc;
909 : :
910 : 0 : reassembly_print_banner("IPV4");
911 : : /* Test variable fragment count and ordering. */
912 [ # # ]: 0 : for (i = 0; i < RTE_DIM(nb_fragments); i++) {
913 [ # # ]: 0 : for (j = 0; j < RTE_DIM(order_type); j++) {
914 : 0 : rc = ipv4_reassembly_test(nb_fragments[i],
915 : 0 : order_type[j], 0);
916 [ # # ]: 0 : if (rc)
917 : 0 : return rc;
918 : : }
919 : : }
920 : :
921 : : /* Test outstanding fragments in the table. */
922 [ # # ]: 0 : for (i = 0; i < RTE_DIM(outstanding); i++) {
923 : 0 : rc = ipv4_reassembly_test(2, 0, outstanding[i]);
924 [ # # ]: 0 : if (rc)
925 : 0 : return rc;
926 : : }
927 [ # # ]: 0 : for (i = 0; i < RTE_DIM(outstanding); i++) {
928 : 0 : rc = ipv4_reassembly_test(MAX_FRAGMENTS, 0, outstanding[i]);
929 [ # # ]: 0 : if (rc)
930 : 0 : return rc;
931 : : }
932 : :
933 : : /* Test interleaved flow reassembly perf */
934 [ # # ]: 0 : for (i = 0; i < RTE_DIM(nb_fragments); i++) {
935 : 0 : rc = ipv4_reassembly_test(nb_fragments[i],
936 : : FILL_MODE_INTERLEAVED, 0);
937 [ # # ]: 0 : if (rc)
938 : 0 : return rc;
939 : : }
940 : : printf("\n");
941 : 0 : reassembly_print_banner("IPV6");
942 : : /* Test variable fragment count and ordering. */
943 [ # # ]: 0 : for (i = 0; i < RTE_DIM(nb_fragments); i++) {
944 [ # # ]: 0 : for (j = 0; j < RTE_DIM(order_type); j++) {
945 : 0 : rc = ipv6_reassembly_test(nb_fragments[i],
946 : 0 : order_type[j], 0);
947 [ # # ]: 0 : if (rc)
948 : 0 : return rc;
949 : : }
950 : : }
951 : :
952 : : /* Test outstanding fragments in the table. */
953 [ # # ]: 0 : for (i = 0; i < RTE_DIM(outstanding); i++) {
954 : 0 : rc = ipv6_reassembly_test(2, 0, outstanding[i]);
955 [ # # ]: 0 : if (rc)
956 : 0 : return rc;
957 : : }
958 : :
959 [ # # ]: 0 : for (i = 0; i < RTE_DIM(outstanding); i++) {
960 : 0 : rc = ipv6_reassembly_test(MAX_FRAGMENTS, 0, outstanding[i]);
961 [ # # ]: 0 : if (rc)
962 : 0 : return rc;
963 : : }
964 : :
965 : : /* Test interleaved flow reassembly perf */
966 [ # # ]: 0 : for (i = 0; i < RTE_DIM(nb_fragments); i++) {
967 : 0 : rc = ipv6_reassembly_test(nb_fragments[i],
968 : : FILL_MODE_INTERLEAVED, 0);
969 [ # # ]: 0 : if (rc)
970 : 0 : return rc;
971 : : }
972 : 0 : reassembly_test_teardown();
973 : :
974 : 0 : return TEST_SUCCESS;
975 : : }
976 : :
977 : 252 : REGISTER_PERF_TEST(reassembly_perf_autotest, test_reassembly_perf);
|