xref: /dpdk/app/test/test_ipfrag.c (revision 89b5642d0d45c22c0ceab57efe3fab3b49ff4324)
106d63eb5SAaron Conole /* SPDX-License-Identifier: BSD-3-Clause
206d63eb5SAaron Conole  * Copyright(c) 2020 Red Hat, Inc.
306d63eb5SAaron Conole  */
406d63eb5SAaron Conole 
53c60274cSJie Zhou #include "test.h"
63c60274cSJie Zhou 
706d63eb5SAaron Conole #include <time.h>
806d63eb5SAaron Conole 
906d63eb5SAaron Conole #include <rte_common.h>
1006d63eb5SAaron Conole #include <rte_cycles.h>
1106d63eb5SAaron Conole #include <rte_hexdump.h>
1206d63eb5SAaron Conole #include <rte_ip.h>
1306d63eb5SAaron Conole #include <rte_ip_frag.h>
1406d63eb5SAaron Conole #include <rte_mbuf.h>
1506d63eb5SAaron Conole #include <rte_random.h>
1606d63eb5SAaron Conole 
1706d63eb5SAaron Conole #define NUM_MBUFS 128
1806d63eb5SAaron Conole #define BURST 32
1906d63eb5SAaron Conole 
20b50a14a8SHuichao Cai uint8_t expected_first_frag_ipv4_opts_copied[] = {
21b50a14a8SHuichao Cai 	0x07, 0x0b, 0x04, 0x00,
22b50a14a8SHuichao Cai 	0x00, 0x00, 0x00, 0x00,
23b50a14a8SHuichao Cai 	0x00, 0x00, 0x00, 0x83,
24b50a14a8SHuichao Cai 	0x07, 0x04, 0xc0, 0xa8,
25b50a14a8SHuichao Cai 	0xe3, 0x96, 0x00, 0x00,
26b50a14a8SHuichao Cai };
27b50a14a8SHuichao Cai 
28b50a14a8SHuichao Cai uint8_t expected_sub_frag_ipv4_opts_copied[] = {
29b50a14a8SHuichao Cai 	0x83, 0x07, 0x04, 0xc0,
30b50a14a8SHuichao Cai 	0xa8, 0xe3, 0x96, 0x00,
31b50a14a8SHuichao Cai };
32b50a14a8SHuichao Cai 
33b50a14a8SHuichao Cai uint8_t expected_first_frag_ipv4_opts_nocopied[] = {
34b50a14a8SHuichao Cai 	0x07, 0x0b, 0x04, 0x00,
35b50a14a8SHuichao Cai 	0x00, 0x00, 0x00, 0x00,
36b50a14a8SHuichao Cai 	0x00, 0x00, 0x00, 0x00,
37b50a14a8SHuichao Cai };
38b50a14a8SHuichao Cai 
39b50a14a8SHuichao Cai uint8_t expected_sub_frag_ipv4_opts_nocopied[0];
40b50a14a8SHuichao Cai 
41b50a14a8SHuichao Cai struct test_opt_data {
42b50a14a8SHuichao Cai 	bool is_first_frag;		 /**< offset is 0 */
43b50a14a8SHuichao Cai 	bool opt_copied;		 /**< ip option copied flag */
44b50a14a8SHuichao Cai 	uint16_t len;			 /**< option data len */
45b50a14a8SHuichao Cai 	uint8_t data[RTE_IPV4_HDR_OPT_MAX_LEN]; /**< option data */
46b50a14a8SHuichao Cai };
47b50a14a8SHuichao Cai 
4806d63eb5SAaron Conole static struct rte_mempool *pkt_pool,
4906d63eb5SAaron Conole 			  *direct_pool,
5006d63eb5SAaron Conole 			  *indirect_pool;
5106d63eb5SAaron Conole 
52b50a14a8SHuichao Cai static inline void
53b50a14a8SHuichao Cai hex_to_str(uint8_t *hex, uint16_t len, char *str)
54b50a14a8SHuichao Cai {
55b50a14a8SHuichao Cai 	int i;
56b50a14a8SHuichao Cai 
57b50a14a8SHuichao Cai 	for (i = 0; i < len; i++) {
58b50a14a8SHuichao Cai 		sprintf(str, "%02x", hex[i]);
59b50a14a8SHuichao Cai 		str += 2;
60b50a14a8SHuichao Cai 	}
61b50a14a8SHuichao Cai 	*str = 0;
62b50a14a8SHuichao Cai }
63b50a14a8SHuichao Cai 
6406d63eb5SAaron Conole static int
6506d63eb5SAaron Conole setup_buf_pool(void)
6606d63eb5SAaron Conole {
6706d63eb5SAaron Conole 	pkt_pool = rte_pktmbuf_pool_create("FRAG_MBUF_POOL",
6806d63eb5SAaron Conole 					   NUM_MBUFS, BURST, 0,
6906d63eb5SAaron Conole 					   RTE_MBUF_DEFAULT_BUF_SIZE,
7006d63eb5SAaron Conole 					   SOCKET_ID_ANY);
7106d63eb5SAaron Conole 	if (pkt_pool == NULL) {
7206d63eb5SAaron Conole 		printf("%s: Error creating pkt mempool\n", __func__);
7306d63eb5SAaron Conole 		goto bad_setup;
7406d63eb5SAaron Conole 	}
7506d63eb5SAaron Conole 
7606d63eb5SAaron Conole 	direct_pool = rte_pktmbuf_pool_create("FRAG_D_MBUF_POOL",
7706d63eb5SAaron Conole 					      NUM_MBUFS, BURST, 0,
7806d63eb5SAaron Conole 					      RTE_MBUF_DEFAULT_BUF_SIZE,
7906d63eb5SAaron Conole 					      SOCKET_ID_ANY);
8006d63eb5SAaron Conole 	if (direct_pool == NULL) {
8106d63eb5SAaron Conole 		printf("%s: Error creating direct mempool\n", __func__);
8206d63eb5SAaron Conole 		goto bad_setup;
8306d63eb5SAaron Conole 	}
8406d63eb5SAaron Conole 
8506d63eb5SAaron Conole 	indirect_pool = rte_pktmbuf_pool_create("FRAG_I_MBUF_POOL",
8606d63eb5SAaron Conole 						NUM_MBUFS, BURST, 0,
8706d63eb5SAaron Conole 						0, SOCKET_ID_ANY);
8806d63eb5SAaron Conole 	if (indirect_pool == NULL) {
8906d63eb5SAaron Conole 		printf("%s: Error creating indirect mempool\n", __func__);
9006d63eb5SAaron Conole 		goto bad_setup;
9106d63eb5SAaron Conole 	}
9206d63eb5SAaron Conole 
9306d63eb5SAaron Conole 	return TEST_SUCCESS;
9406d63eb5SAaron Conole 
9506d63eb5SAaron Conole bad_setup:
9606d63eb5SAaron Conole 	rte_mempool_free(pkt_pool);
9706d63eb5SAaron Conole 	pkt_pool = NULL;
9806d63eb5SAaron Conole 
9906d63eb5SAaron Conole 	rte_mempool_free(direct_pool);
10006d63eb5SAaron Conole 	direct_pool = NULL;
10106d63eb5SAaron Conole 
10206d63eb5SAaron Conole 	return TEST_FAILED;
10306d63eb5SAaron Conole }
10406d63eb5SAaron Conole 
10506d63eb5SAaron Conole static int testsuite_setup(void)
10606d63eb5SAaron Conole {
10706d63eb5SAaron Conole 	return setup_buf_pool();
10806d63eb5SAaron Conole }
10906d63eb5SAaron Conole 
11006d63eb5SAaron Conole static void testsuite_teardown(void)
11106d63eb5SAaron Conole {
11206d63eb5SAaron Conole 	rte_mempool_free(pkt_pool);
11306d63eb5SAaron Conole 	rte_mempool_free(direct_pool);
11406d63eb5SAaron Conole 	rte_mempool_free(indirect_pool);
11506d63eb5SAaron Conole 
11606d63eb5SAaron Conole 	pkt_pool = NULL;
11706d63eb5SAaron Conole 	direct_pool = NULL;
11806d63eb5SAaron Conole 	indirect_pool = NULL;
11906d63eb5SAaron Conole }
12006d63eb5SAaron Conole 
12106d63eb5SAaron Conole static int ut_setup(void)
12206d63eb5SAaron Conole {
12306d63eb5SAaron Conole 	return TEST_SUCCESS;
12406d63eb5SAaron Conole }
12506d63eb5SAaron Conole 
12606d63eb5SAaron Conole static void ut_teardown(void)
12706d63eb5SAaron Conole {
12806d63eb5SAaron Conole }
12906d63eb5SAaron Conole 
130b50a14a8SHuichao Cai static inline void
131b50a14a8SHuichao Cai test_get_ipv4_opt(bool is_first_frag, bool opt_copied,
132b50a14a8SHuichao Cai 	struct test_opt_data *expected_opt)
133b50a14a8SHuichao Cai {
134b50a14a8SHuichao Cai 	if (is_first_frag) {
135b50a14a8SHuichao Cai 		if (opt_copied) {
136b50a14a8SHuichao Cai 			expected_opt->len =
137b50a14a8SHuichao Cai 				sizeof(expected_first_frag_ipv4_opts_copied);
138e1522b32SHuichao Cai 			memcpy(expected_opt->data,
139b50a14a8SHuichao Cai 				expected_first_frag_ipv4_opts_copied,
140b50a14a8SHuichao Cai 				sizeof(expected_first_frag_ipv4_opts_copied));
141b50a14a8SHuichao Cai 		} else {
142b50a14a8SHuichao Cai 			expected_opt->len =
143b50a14a8SHuichao Cai 				sizeof(expected_first_frag_ipv4_opts_nocopied);
144e1522b32SHuichao Cai 			memcpy(expected_opt->data,
145b50a14a8SHuichao Cai 				expected_first_frag_ipv4_opts_nocopied,
146b50a14a8SHuichao Cai 				sizeof(expected_first_frag_ipv4_opts_nocopied));
147b50a14a8SHuichao Cai 		}
148b50a14a8SHuichao Cai 	} else {
149b50a14a8SHuichao Cai 		if (opt_copied) {
150b50a14a8SHuichao Cai 			expected_opt->len =
151b50a14a8SHuichao Cai 				sizeof(expected_sub_frag_ipv4_opts_copied);
152e1522b32SHuichao Cai 			memcpy(expected_opt->data,
153b50a14a8SHuichao Cai 				expected_sub_frag_ipv4_opts_copied,
154b50a14a8SHuichao Cai 				sizeof(expected_sub_frag_ipv4_opts_copied));
155b50a14a8SHuichao Cai 		} else {
156b50a14a8SHuichao Cai 			expected_opt->len =
157b50a14a8SHuichao Cai 				sizeof(expected_sub_frag_ipv4_opts_nocopied);
158e1522b32SHuichao Cai 			memcpy(expected_opt->data,
159b50a14a8SHuichao Cai 				expected_sub_frag_ipv4_opts_nocopied,
160b50a14a8SHuichao Cai 				sizeof(expected_sub_frag_ipv4_opts_nocopied));
161b50a14a8SHuichao Cai 		}
162b50a14a8SHuichao Cai 	}
163b50a14a8SHuichao Cai }
164b50a14a8SHuichao Cai 
16506d63eb5SAaron Conole static void
166b50a14a8SHuichao Cai v4_allocate_packet_of(struct rte_mbuf *b, int fill, size_t s,
167b50a14a8SHuichao Cai 	int df, uint8_t mf, uint16_t off, uint8_t ttl, uint8_t proto,
168b50a14a8SHuichao Cai 	uint16_t pktid, bool have_opt, bool is_first_frag, bool opt_copied)
16906d63eb5SAaron Conole {
17006d63eb5SAaron Conole 	/* Create a packet, 2k bytes long */
17106d63eb5SAaron Conole 	b->data_off = 0;
17206d63eb5SAaron Conole 	char *data = rte_pktmbuf_mtod(b, char *);
173b50a14a8SHuichao Cai 	rte_be16_t fragment_offset = 0;	/* fragmentation offset */
174b50a14a8SHuichao Cai 	uint16_t iph_len;
175b50a14a8SHuichao Cai 	struct test_opt_data opt;
17606d63eb5SAaron Conole 
177b50a14a8SHuichao Cai 	opt.len = 0;
178b50a14a8SHuichao Cai 
179b50a14a8SHuichao Cai 	if (have_opt)
180b50a14a8SHuichao Cai 		test_get_ipv4_opt(is_first_frag, opt_copied, &opt);
181b50a14a8SHuichao Cai 
182b50a14a8SHuichao Cai 	iph_len = sizeof(struct rte_ipv4_hdr) + opt.len;
183b50a14a8SHuichao Cai 	memset(data, fill, iph_len + s);
18406d63eb5SAaron Conole 
18506d63eb5SAaron Conole 	struct rte_ipv4_hdr *hdr = (struct rte_ipv4_hdr *)data;
18606d63eb5SAaron Conole 
187b50a14a8SHuichao Cai 	hdr->version_ihl = 0x40; /* ipv4 */
188b50a14a8SHuichao Cai 	hdr->version_ihl += (iph_len / 4);
18906d63eb5SAaron Conole 	hdr->type_of_service = 0;
190b50a14a8SHuichao Cai 	b->pkt_len = s + iph_len;
19106d63eb5SAaron Conole 	b->data_len = b->pkt_len;
19206d63eb5SAaron Conole 	hdr->total_length = rte_cpu_to_be_16(b->pkt_len);
19306d63eb5SAaron Conole 	hdr->packet_id = rte_cpu_to_be_16(pktid);
194e3999afdSHuichao Cai 
19506d63eb5SAaron Conole 	if (df)
196e3999afdSHuichao Cai 		fragment_offset |= 0x4000;
197e3999afdSHuichao Cai 
198e3999afdSHuichao Cai 	if (mf)
199e3999afdSHuichao Cai 		fragment_offset |= 0x2000;
200e3999afdSHuichao Cai 
201e3999afdSHuichao Cai 	if (off)
202e3999afdSHuichao Cai 		fragment_offset |= off;
203e3999afdSHuichao Cai 
204e3999afdSHuichao Cai 	hdr->fragment_offset = rte_cpu_to_be_16(fragment_offset);
20506d63eb5SAaron Conole 
20606d63eb5SAaron Conole 	if (!ttl)
20706d63eb5SAaron Conole 		ttl = 64; /* default to 64 */
20806d63eb5SAaron Conole 
20906d63eb5SAaron Conole 	if (!proto)
21006d63eb5SAaron Conole 		proto = 1; /* icmp */
21106d63eb5SAaron Conole 
21206d63eb5SAaron Conole 	hdr->time_to_live = ttl;
21306d63eb5SAaron Conole 	hdr->next_proto_id = proto;
21406d63eb5SAaron Conole 	hdr->hdr_checksum = 0;
21506d63eb5SAaron Conole 	hdr->src_addr = rte_cpu_to_be_32(0x8080808);
21606d63eb5SAaron Conole 	hdr->dst_addr = rte_cpu_to_be_32(0x8080404);
217b50a14a8SHuichao Cai 
218e1522b32SHuichao Cai 	memcpy(hdr + 1, opt.data, opt.len);
21906d63eb5SAaron Conole }
22006d63eb5SAaron Conole 
22106d63eb5SAaron Conole static void
22206d63eb5SAaron Conole v6_allocate_packet_of(struct rte_mbuf *b, int fill, size_t s, uint8_t ttl,
22306d63eb5SAaron Conole 		      uint8_t proto, uint16_t pktid)
22406d63eb5SAaron Conole {
22506d63eb5SAaron Conole 	/* Create a packet, 2k bytes long */
22606d63eb5SAaron Conole 	b->data_off = 0;
22706d63eb5SAaron Conole 	char *data = rte_pktmbuf_mtod(b, char *);
22806d63eb5SAaron Conole 
22906d63eb5SAaron Conole 	memset(data, fill, sizeof(struct rte_ipv6_hdr) + s);
23006d63eb5SAaron Conole 
23106d63eb5SAaron Conole 	struct rte_ipv6_hdr *hdr = (struct rte_ipv6_hdr *)data;
23206d63eb5SAaron Conole 	b->pkt_len = s + sizeof(struct rte_ipv6_hdr);
23306d63eb5SAaron Conole 	b->data_len = b->pkt_len;
23406d63eb5SAaron Conole 
23506d63eb5SAaron Conole 	/* basic v6 header */
23606d63eb5SAaron Conole 	hdr->vtc_flow = rte_cpu_to_be_32(0x60 << 24 | pktid);
23706d63eb5SAaron Conole 	hdr->payload_len = rte_cpu_to_be_16(b->pkt_len);
23806d63eb5SAaron Conole 	hdr->proto = proto;
23906d63eb5SAaron Conole 	hdr->hop_limits = ttl;
24006d63eb5SAaron Conole 
241*89b5642dSRobin Jarry 	memset(&hdr->src_addr, 0x08, sizeof(hdr->src_addr));
242*89b5642dSRobin Jarry 	memset(&hdr->dst_addr, 0x04, sizeof(hdr->src_addr));
24306d63eb5SAaron Conole }
24406d63eb5SAaron Conole 
24506d63eb5SAaron Conole static inline void
24606d63eb5SAaron Conole test_free_fragments(struct rte_mbuf *mb[], uint32_t num)
24706d63eb5SAaron Conole {
24806d63eb5SAaron Conole 	uint32_t i;
24906d63eb5SAaron Conole 	for (i = 0; i < num; i++)
25006d63eb5SAaron Conole 		rte_pktmbuf_free(mb[i]);
25106d63eb5SAaron Conole }
25206d63eb5SAaron Conole 
253e3999afdSHuichao Cai static inline void
254e3999afdSHuichao Cai test_get_offset(struct rte_mbuf **mb, int32_t len,
255e3999afdSHuichao Cai 	uint16_t *offset, int ipv)
256e3999afdSHuichao Cai {
257e3999afdSHuichao Cai 	int32_t i;
258e3999afdSHuichao Cai 
259e3999afdSHuichao Cai 	for (i = 0; i < len; i++) {
260e3999afdSHuichao Cai 		if (ipv == 4) {
261e3999afdSHuichao Cai 			struct rte_ipv4_hdr *iph =
262e3999afdSHuichao Cai 			    rte_pktmbuf_mtod(mb[i], struct rte_ipv4_hdr *);
263e3999afdSHuichao Cai 			offset[i] = iph->fragment_offset;
264e3999afdSHuichao Cai 		} else if (ipv == 6) {
265e3999afdSHuichao Cai 			struct ipv6_extension_fragment *fh =
266e3999afdSHuichao Cai 			    rte_pktmbuf_mtod_offset(
267e3999afdSHuichao Cai 					mb[i],
268e3999afdSHuichao Cai 					struct ipv6_extension_fragment *,
269e3999afdSHuichao Cai 					sizeof(struct rte_ipv6_hdr));
270e3999afdSHuichao Cai 			offset[i] = fh->frag_data;
271e3999afdSHuichao Cai 		}
272e3999afdSHuichao Cai 	}
273e3999afdSHuichao Cai }
274e3999afdSHuichao Cai 
275b50a14a8SHuichao Cai static inline void
276b50a14a8SHuichao Cai test_get_frag_opt(struct rte_mbuf **mb, int32_t num,
277b50a14a8SHuichao Cai 	struct test_opt_data *opt, int ipv, bool opt_copied)
278b50a14a8SHuichao Cai {
279b50a14a8SHuichao Cai 	int32_t i;
280b50a14a8SHuichao Cai 
281b50a14a8SHuichao Cai 	for (i = 0; i < num; i++) {
282b50a14a8SHuichao Cai 		if (ipv == 4) {
283b50a14a8SHuichao Cai 			struct rte_ipv4_hdr *iph =
284b50a14a8SHuichao Cai 			    rte_pktmbuf_mtod(mb[i], struct rte_ipv4_hdr *);
285b50a14a8SHuichao Cai 			uint16_t header_len = (iph->version_ihl &
286b50a14a8SHuichao Cai 				RTE_IPV4_HDR_IHL_MASK) *
287b50a14a8SHuichao Cai 				RTE_IPV4_IHL_MULTIPLIER;
288b50a14a8SHuichao Cai 			uint16_t opt_len = header_len -
289b50a14a8SHuichao Cai 				sizeof(struct rte_ipv4_hdr);
290b50a14a8SHuichao Cai 
291b50a14a8SHuichao Cai 			opt->opt_copied = opt_copied;
292b50a14a8SHuichao Cai 
293b50a14a8SHuichao Cai 			if ((rte_be_to_cpu_16(iph->fragment_offset) &
294b50a14a8SHuichao Cai 				    RTE_IPV4_HDR_OFFSET_MASK) == 0)
295b50a14a8SHuichao Cai 				opt->is_first_frag = true;
296b50a14a8SHuichao Cai 			else
297b50a14a8SHuichao Cai 				opt->is_first_frag = false;
298b50a14a8SHuichao Cai 
299b50a14a8SHuichao Cai 			if (likely(opt_len <= RTE_IPV4_HDR_OPT_MAX_LEN)) {
300b50a14a8SHuichao Cai 				char *iph_opt = rte_pktmbuf_mtod_offset(mb[i],
301b50a14a8SHuichao Cai 				    char *, sizeof(struct rte_ipv4_hdr));
302b50a14a8SHuichao Cai 				opt->len = opt_len;
303e1522b32SHuichao Cai 				memcpy(opt->data, iph_opt, opt_len);
304b50a14a8SHuichao Cai 			} else {
305b50a14a8SHuichao Cai 				opt->len = RTE_IPV4_HDR_OPT_MAX_LEN;
306b50a14a8SHuichao Cai 				memset(opt->data, RTE_IPV4_HDR_OPT_EOL,
307b50a14a8SHuichao Cai 				    sizeof(opt->data));
308b50a14a8SHuichao Cai 			}
309b50a14a8SHuichao Cai 			opt++;
310b50a14a8SHuichao Cai 		}
311b50a14a8SHuichao Cai 	}
312b50a14a8SHuichao Cai }
313b50a14a8SHuichao Cai 
31406d63eb5SAaron Conole static int
31506d63eb5SAaron Conole test_ip_frag(void)
31606d63eb5SAaron Conole {
31706d63eb5SAaron Conole 	static const uint16_t RND_ID = UINT16_MAX;
31806d63eb5SAaron Conole 	int result = TEST_SUCCESS;
319e3999afdSHuichao Cai 	size_t i, j;
32006d63eb5SAaron Conole 
32106d63eb5SAaron Conole 	struct test_ip_frags {
32206d63eb5SAaron Conole 		int      ipv;
32306d63eb5SAaron Conole 		size_t   mtu_size;
32406d63eb5SAaron Conole 		size_t   pkt_size;
32506d63eb5SAaron Conole 		int      set_df;
326e3999afdSHuichao Cai 		uint8_t  set_mf;
327e3999afdSHuichao Cai 		uint16_t set_of;
32806d63eb5SAaron Conole 		uint8_t  ttl;
32906d63eb5SAaron Conole 		uint8_t  proto;
33006d63eb5SAaron Conole 		uint16_t pkt_id;
33106d63eb5SAaron Conole 		int      expected_frags;
332e3999afdSHuichao Cai 		uint16_t expected_fragment_offset[BURST];
333b50a14a8SHuichao Cai 		bool have_opt;
334b50a14a8SHuichao Cai 		bool is_first_frag;
335b50a14a8SHuichao Cai 		bool opt_copied;
33606d63eb5SAaron Conole 	} tests[] = {
337e3999afdSHuichao Cai 		 {4, 1280, 1400, 0, 0, 0, 64, IPPROTO_ICMP, RND_ID,       2,
338b50a14a8SHuichao Cai 		  {0x2000, 0x009D}, false},
339e3999afdSHuichao Cai 		 {4, 1280, 1400, 0, 0, 0, 64, IPPROTO_ICMP, 0,            2,
340b50a14a8SHuichao Cai 		  {0x2000, 0x009D}, false},
341e3999afdSHuichao Cai 		 {4,  600, 1400, 0, 0, 0, 64, IPPROTO_ICMP, RND_ID,       3,
342b50a14a8SHuichao Cai 		  {0x2000, 0x2048, 0x0090}, false},
343e3999afdSHuichao Cai 		 {4, 4, 1400, 0, 0, 0, 64, IPPROTO_ICMP, RND_ID,    -EINVAL},
344e3999afdSHuichao Cai 		 {4, 600, 1400, 1, 0, 0, 64, IPPROTO_ICMP, RND_ID, -ENOTSUP},
345e3999afdSHuichao Cai 		 {4, 600, 1400, 0, 0, 0, 0, IPPROTO_ICMP, RND_ID,         3,
346b50a14a8SHuichao Cai 		  {0x2000, 0x2046, 0x008C}, true, true, true},
347b50a14a8SHuichao Cai 		 /* The first fragment */
348b50a14a8SHuichao Cai 		 {4, 68, 104, 0, 1, 0, 0, IPPROTO_ICMP, RND_ID,           5,
349b50a14a8SHuichao Cai 		  {0x2000, 0x2003, 0x2006, 0x2009, 0x200C}, true, true, true},
350b50a14a8SHuichao Cai 		 /* The middle fragment */
351e3999afdSHuichao Cai 		 {4, 68, 104, 0, 1, 13, 0, IPPROTO_ICMP, RND_ID,          3,
352b50a14a8SHuichao Cai 		  {0x200D, 0x2012, 0x2017}, true, false, true},
353b50a14a8SHuichao Cai 		 /* The last fragment */
354b50a14a8SHuichao Cai 		 {4, 68, 104, 0, 0, 26, 0, IPPROTO_ICMP, RND_ID,          3,
355b50a14a8SHuichao Cai 		  {0x201A, 0x201F, 0x0024}, true, false, true},
356b50a14a8SHuichao Cai 		 /* The first fragment */
357b50a14a8SHuichao Cai 		 {4, 68, 104, 0, 1, 0, 0, IPPROTO_ICMP, RND_ID,           4,
358b50a14a8SHuichao Cai 		  {0x2000, 0x2004, 0x2008, 0x200C}, true, true, false},
359b50a14a8SHuichao Cai 		 /* The middle fragment */
360b50a14a8SHuichao Cai 		 {4, 68, 104, 0, 1, 13, 0, IPPROTO_ICMP, RND_ID,          3,
361b50a14a8SHuichao Cai 		  {0x200D, 0x2013, 0x2019}, true, false, false},
362b50a14a8SHuichao Cai 		 /* The last fragment */
363b50a14a8SHuichao Cai 		 {4, 68, 104, 0, 0, 26, 0, IPPROTO_ICMP, RND_ID,          3,
364b50a14a8SHuichao Cai 		  {0x201A, 0x2020, 0x0026}, true, false, false},
365e3999afdSHuichao Cai 		 {6, 1280, 1400, 0, 0, 0, 64, IPPROTO_ICMP, RND_ID,       2,
366b50a14a8SHuichao Cai 		  {0x0001, 0x04D0}, false},
367e3999afdSHuichao Cai 		 {6, 1300, 1400, 0, 0, 0, 64, IPPROTO_ICMP, RND_ID,       2,
368b50a14a8SHuichao Cai 		  {0x0001, 0x04E0}, false},
369e3999afdSHuichao Cai 		 {6, 4, 1400, 0, 0, 0, 64, IPPROTO_ICMP, RND_ID,    -EINVAL},
370e3999afdSHuichao Cai 		 {6, 1300, 1400, 0, 0, 0, 0, IPPROTO_ICMP, RND_ID,        2,
371b50a14a8SHuichao Cai 		  {0x0001, 0x04E0}, false},
37206d63eb5SAaron Conole 	};
37306d63eb5SAaron Conole 
37406d63eb5SAaron Conole 	for (i = 0; i < RTE_DIM(tests); i++) {
37506d63eb5SAaron Conole 		int32_t len = 0;
376e3999afdSHuichao Cai 		uint16_t fragment_offset[BURST];
377b50a14a8SHuichao Cai 		struct test_opt_data opt_res[BURST];
378b50a14a8SHuichao Cai 		struct test_opt_data opt_exp;
37906d63eb5SAaron Conole 		uint16_t pktid = tests[i].pkt_id;
38006d63eb5SAaron Conole 		struct rte_mbuf *pkts_out[BURST];
38106d63eb5SAaron Conole 		struct rte_mbuf *b = rte_pktmbuf_alloc(pkt_pool);
38206d63eb5SAaron Conole 
38306d63eb5SAaron Conole 		RTE_TEST_ASSERT_NOT_EQUAL(b, NULL,
38406d63eb5SAaron Conole 					  "Failed to allocate pkt.");
38506d63eb5SAaron Conole 
38606d63eb5SAaron Conole 		if (tests[i].pkt_id == RND_ID)
38706d63eb5SAaron Conole 			pktid = rte_rand_max(UINT16_MAX);
38806d63eb5SAaron Conole 
38906d63eb5SAaron Conole 		if (tests[i].ipv == 4) {
39006d63eb5SAaron Conole 			v4_allocate_packet_of(b, 0x41414141,
39106d63eb5SAaron Conole 					      tests[i].pkt_size,
39206d63eb5SAaron Conole 					      tests[i].set_df,
393e3999afdSHuichao Cai 					      tests[i].set_mf,
394e3999afdSHuichao Cai 					      tests[i].set_of,
39506d63eb5SAaron Conole 					      tests[i].ttl,
39606d63eb5SAaron Conole 					      tests[i].proto,
397b50a14a8SHuichao Cai 					      pktid,
398b50a14a8SHuichao Cai 					      tests[i].have_opt,
399b50a14a8SHuichao Cai 					      tests[i].is_first_frag,
400b50a14a8SHuichao Cai 					      tests[i].opt_copied);
40106d63eb5SAaron Conole 		} else if (tests[i].ipv == 6) {
40206d63eb5SAaron Conole 			v6_allocate_packet_of(b, 0x41414141,
40306d63eb5SAaron Conole 					      tests[i].pkt_size,
40406d63eb5SAaron Conole 					      tests[i].ttl,
40506d63eb5SAaron Conole 					      tests[i].proto,
40606d63eb5SAaron Conole 					      pktid);
40706d63eb5SAaron Conole 		}
40806d63eb5SAaron Conole 
40906d63eb5SAaron Conole 		if (tests[i].ipv == 4)
4104aee6110SHuichao Cai 			if (i % 2)
41106d63eb5SAaron Conole 				len = rte_ipv4_fragment_packet(b, pkts_out, BURST,
41206d63eb5SAaron Conole 						       tests[i].mtu_size,
41306d63eb5SAaron Conole 						       direct_pool,
41406d63eb5SAaron Conole 						       indirect_pool);
4154aee6110SHuichao Cai 			else
4164aee6110SHuichao Cai 				len = rte_ipv4_fragment_copy_nonseg_packet(b,
4174aee6110SHuichao Cai 						       pkts_out,
4184aee6110SHuichao Cai 						       BURST,
4194aee6110SHuichao Cai 						       tests[i].mtu_size,
4204aee6110SHuichao Cai 						       direct_pool);
42106d63eb5SAaron Conole 		else if (tests[i].ipv == 6)
42206d63eb5SAaron Conole 			len = rte_ipv6_fragment_packet(b, pkts_out, BURST,
42306d63eb5SAaron Conole 						       tests[i].mtu_size,
42406d63eb5SAaron Conole 						       direct_pool,
42506d63eb5SAaron Conole 						       indirect_pool);
42606d63eb5SAaron Conole 
42706d63eb5SAaron Conole 		rte_pktmbuf_free(b);
42806d63eb5SAaron Conole 
429e3999afdSHuichao Cai 		if (len > 0) {
430e3999afdSHuichao Cai 			test_get_offset(pkts_out, len,
431e3999afdSHuichao Cai 			    fragment_offset, tests[i].ipv);
432b50a14a8SHuichao Cai 			if (tests[i].have_opt)
433b50a14a8SHuichao Cai 				test_get_frag_opt(pkts_out, len, opt_res,
434b50a14a8SHuichao Cai 					tests[i].ipv, tests[i].opt_copied);
43506d63eb5SAaron Conole 			test_free_fragments(pkts_out, len);
436e3999afdSHuichao Cai 		}
43706d63eb5SAaron Conole 
438b50a14a8SHuichao Cai 		printf("[check frag number]%zd: checking %d with %d\n", i, len,
43906d63eb5SAaron Conole 		       tests[i].expected_frags);
44006d63eb5SAaron Conole 		RTE_TEST_ASSERT_EQUAL(len, tests[i].expected_frags,
44106d63eb5SAaron Conole 				      "Failed case %zd.\n", i);
44206d63eb5SAaron Conole 
443e3999afdSHuichao Cai 		if (len > 0) {
444e3999afdSHuichao Cai 			for (j = 0; j < (size_t)len; j++) {
445b50a14a8SHuichao Cai 				printf("[check offset]%zd-%zd: checking %d with %d\n",
446e3999afdSHuichao Cai 				    i, j, fragment_offset[j],
447e3999afdSHuichao Cai 				    rte_cpu_to_be_16(
448e3999afdSHuichao Cai 					tests[i].expected_fragment_offset[j]));
449e3999afdSHuichao Cai 				RTE_TEST_ASSERT_EQUAL(fragment_offset[j],
450e3999afdSHuichao Cai 				    rte_cpu_to_be_16(
451e3999afdSHuichao Cai 					tests[i].expected_fragment_offset[j]),
452e3999afdSHuichao Cai 				    "Failed case %zd.\n", i);
453e3999afdSHuichao Cai 			}
454b50a14a8SHuichao Cai 
455b50a14a8SHuichao Cai 			if (tests[i].have_opt && (tests[i].ipv == 4)) {
456b50a14a8SHuichao Cai 				for (j = 0; j < (size_t)len; j++) {
457b50a14a8SHuichao Cai 					char opt_res_str[2 *
458b50a14a8SHuichao Cai 						RTE_IPV4_HDR_OPT_MAX_LEN + 1];
459b50a14a8SHuichao Cai 					char opt_exp_str[2 *
460b50a14a8SHuichao Cai 						RTE_IPV4_HDR_OPT_MAX_LEN + 1];
461b50a14a8SHuichao Cai 
462b50a14a8SHuichao Cai 					test_get_ipv4_opt(
463b50a14a8SHuichao Cai 						opt_res[j].is_first_frag,
464b50a14a8SHuichao Cai 						opt_res[j].opt_copied,
465b50a14a8SHuichao Cai 						&opt_exp);
466b50a14a8SHuichao Cai 					hex_to_str(opt_res[j].data,
467b50a14a8SHuichao Cai 						opt_res[j].len,
468b50a14a8SHuichao Cai 						opt_res_str);
469b50a14a8SHuichao Cai 					hex_to_str(opt_exp.data,
470b50a14a8SHuichao Cai 						opt_exp.len,
471b50a14a8SHuichao Cai 						opt_exp_str);
472b50a14a8SHuichao Cai 
473b50a14a8SHuichao Cai 					printf(
474b50a14a8SHuichao Cai 						"[check ipv4 option]%zd-%zd: checking (len:%u)%s with (len:%u)%s\n",
475b50a14a8SHuichao Cai 						i, j,
476b50a14a8SHuichao Cai 						opt_res[j].len, opt_res_str,
477b50a14a8SHuichao Cai 						opt_exp.len, opt_exp_str);
478b50a14a8SHuichao Cai 						RTE_TEST_ASSERT_SUCCESS(
479b50a14a8SHuichao Cai 							strcmp(opt_res_str,
480b50a14a8SHuichao Cai 								opt_exp_str),
481b50a14a8SHuichao Cai 						"Failed case %zd.\n", i);
482b50a14a8SHuichao Cai 				}
483b50a14a8SHuichao Cai 			}
484e3999afdSHuichao Cai 		}
485e3999afdSHuichao Cai 
48606d63eb5SAaron Conole 	}
48706d63eb5SAaron Conole 
48806d63eb5SAaron Conole 	return result;
48906d63eb5SAaron Conole }
49006d63eb5SAaron Conole 
49106d63eb5SAaron Conole static struct unit_test_suite ipfrag_testsuite  = {
49206d63eb5SAaron Conole 	.suite_name = "IP Frag Unit Test Suite",
49306d63eb5SAaron Conole 	.setup = testsuite_setup,
49406d63eb5SAaron Conole 	.teardown = testsuite_teardown,
49506d63eb5SAaron Conole 	.unit_test_cases = {
49606d63eb5SAaron Conole 		TEST_CASE_ST(ut_setup, ut_teardown,
49706d63eb5SAaron Conole 			     test_ip_frag),
49806d63eb5SAaron Conole 
49906d63eb5SAaron Conole 		TEST_CASES_END() /**< NULL terminate unit test array */
50006d63eb5SAaron Conole 	}
50106d63eb5SAaron Conole };
50206d63eb5SAaron Conole 
50306d63eb5SAaron Conole static int
50406d63eb5SAaron Conole test_ipfrag(void)
50506d63eb5SAaron Conole {
50606d63eb5SAaron Conole 	rte_log_set_global_level(RTE_LOG_DEBUG);
50706d63eb5SAaron Conole 	rte_log_set_level(RTE_LOGTYPE_EAL, RTE_LOG_DEBUG);
50806d63eb5SAaron Conole 
50906d63eb5SAaron Conole 	return unit_test_suite_runner(&ipfrag_testsuite);
51006d63eb5SAaron Conole }
51106d63eb5SAaron Conole 
5123c60274cSJie Zhou 
513e0a8442cSBruce Richardson REGISTER_FAST_TEST(ipfrag_autotest, false, true, test_ipfrag);
514