xref: /dpdk/app/test/test_fib6.c (revision 3c60274c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Vladimir Medvedkin <[email protected]>
3  * Copyright(c) 2019 Intel Corporation
4  */
5 
6 #include <stdio.h>
7 #include <stdint.h>
8 #include <stdlib.h>
9 
10 #include <rte_memory.h>
11 #include <rte_log.h>
12 
13 #include "test.h"
14 
15 #ifdef RTE_EXEC_ENV_WINDOWS
16 static int
test_fib6(void)17 test_fib6(void)
18 {
19 	printf("fib not supported on Windows, skipping test\n");
20 	return TEST_SKIPPED;
21 }
22 
23 static int
test_slow_fib6(void)24 test_slow_fib6(void)
25 {
26 	printf("slow_fib not supported on Windows, skipping test\n");
27 	return TEST_SKIPPED;
28 }
29 
30 #else
31 
32 #include <rte_rib6.h>
33 #include <rte_fib6.h>
34 
35 typedef int32_t (*rte_fib6_test)(void);
36 
37 static int32_t test_create_invalid(void);
38 static int32_t test_multiple_create(void);
39 static int32_t test_free_null(void);
40 static int32_t test_add_del_invalid(void);
41 static int32_t test_get_invalid(void);
42 static int32_t test_lookup(void);
43 
44 #define MAX_ROUTES	(1 << 16)
45 /** Maximum number of tbl8 for 2-byte entries */
46 #define MAX_TBL8	(1 << 15)
47 
48 /*
49  * Check that rte_fib6_create fails gracefully for incorrect user input
50  * arguments
51  */
52 int32_t
test_create_invalid(void)53 test_create_invalid(void)
54 {
55 	struct rte_fib6 *fib = NULL;
56 	struct rte_fib6_conf config;
57 
58 	config.max_routes = MAX_ROUTES;
59 	config.rib_ext_sz = 0;
60 	config.default_nh = 0;
61 	config.type = RTE_FIB6_DUMMY;
62 
63 	/* rte_fib6_create: fib name == NULL */
64 	fib = rte_fib6_create(NULL, SOCKET_ID_ANY, &config);
65 	RTE_TEST_ASSERT(fib == NULL,
66 		"Call succeeded with invalid parameters\n");
67 
68 	/* rte_fib6_create: config == NULL */
69 	fib = rte_fib6_create(__func__, SOCKET_ID_ANY, NULL);
70 	RTE_TEST_ASSERT(fib == NULL,
71 		"Call succeeded with invalid parameters\n");
72 
73 	/* socket_id < -1 is invalid */
74 	fib = rte_fib6_create(__func__, -2, &config);
75 	RTE_TEST_ASSERT(fib == NULL,
76 		"Call succeeded with invalid parameters\n");
77 
78 	/* rte_fib6_create: max_routes = 0 */
79 	config.max_routes = 0;
80 	fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
81 	RTE_TEST_ASSERT(fib == NULL,
82 		"Call succeeded with invalid parameters\n");
83 	config.max_routes = MAX_ROUTES;
84 
85 	config.type = RTE_FIB6_TRIE + 1;
86 	fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
87 	RTE_TEST_ASSERT(fib == NULL,
88 		"Call succeeded with invalid parameters\n");
89 
90 	config.type = RTE_FIB6_TRIE;
91 	config.trie.num_tbl8 = MAX_TBL8;
92 
93 	config.trie.nh_sz = RTE_FIB6_TRIE_8B + 1;
94 	fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
95 	RTE_TEST_ASSERT(fib == NULL,
96 		"Call succeeded with invalid parameters\n");
97 	config.trie.nh_sz = RTE_FIB6_TRIE_8B;
98 
99 	config.trie.num_tbl8 = 0;
100 	fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
101 	RTE_TEST_ASSERT(fib == NULL,
102 		"Call succeeded with invalid parameters\n");
103 
104 	return TEST_SUCCESS;
105 }
106 
107 /*
108  * Create fib table then delete fib table 10 times
109  * Use a slightly different rules size each time
110  */
111 int32_t
test_multiple_create(void)112 test_multiple_create(void)
113 {
114 	struct rte_fib6 *fib = NULL;
115 	struct rte_fib6_conf config;
116 	int32_t i;
117 
118 	config.rib_ext_sz = 0;
119 	config.default_nh = 0;
120 	config.type = RTE_FIB6_DUMMY;
121 
122 	for (i = 0; i < 100; i++) {
123 		config.max_routes = MAX_ROUTES - i;
124 		fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
125 		RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
126 		rte_fib6_free(fib);
127 	}
128 	/* Can not test free so return success */
129 	return TEST_SUCCESS;
130 }
131 
132 /*
133  * Call rte_fib6_free for NULL pointer user input. Note: free has no return and
134  * therefore it is impossible to check for failure but this test is added to
135  * increase function coverage metrics and to validate that freeing null does
136  * not crash.
137  */
138 int32_t
test_free_null(void)139 test_free_null(void)
140 {
141 	struct rte_fib6 *fib = NULL;
142 	struct rte_fib6_conf config;
143 
144 	config.max_routes = MAX_ROUTES;
145 	config.rib_ext_sz = 0;
146 	config.default_nh = 0;
147 	config.type = RTE_FIB6_DUMMY;
148 
149 	fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
150 	RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
151 
152 	rte_fib6_free(fib);
153 	rte_fib6_free(NULL);
154 
155 	return TEST_SUCCESS;
156 }
157 
158 /*
159  * Check that rte_fib6_add and rte_fib6_delete fails gracefully
160  * for incorrect user input arguments
161  */
162 int32_t
test_add_del_invalid(void)163 test_add_del_invalid(void)
164 {
165 	struct rte_fib6 *fib = NULL;
166 	struct rte_fib6_conf config;
167 	uint64_t nh = 100;
168 	uint8_t ip[RTE_FIB6_IPV6_ADDR_SIZE] = {0};
169 	int ret;
170 	uint8_t depth = 24;
171 
172 	config.max_routes = MAX_ROUTES;
173 	config.rib_ext_sz = 0;
174 	config.default_nh = 0;
175 	config.type = RTE_FIB6_DUMMY;
176 
177 	/* rte_fib6_add: fib == NULL */
178 	ret = rte_fib6_add(NULL, ip, depth, nh);
179 	RTE_TEST_ASSERT(ret < 0,
180 		"Call succeeded with invalid parameters\n");
181 
182 	/* rte_fib6_delete: fib == NULL */
183 	ret = rte_fib6_delete(NULL, ip, depth);
184 	RTE_TEST_ASSERT(ret < 0,
185 		"Call succeeded with invalid parameters\n");
186 
187 	/*Create valid fib to use in rest of test. */
188 	fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
189 	RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
190 
191 	/* rte_fib6_add: depth > RTE_FIB6_MAXDEPTH */
192 	ret = rte_fib6_add(fib, ip, RTE_FIB6_MAXDEPTH + 1, nh);
193 	RTE_TEST_ASSERT(ret < 0,
194 		"Call succeeded with invalid parameters\n");
195 
196 	/* rte_fib6_delete: depth > RTE_FIB6_MAXDEPTH */
197 	ret = rte_fib6_delete(fib, ip, RTE_FIB6_MAXDEPTH + 1);
198 	RTE_TEST_ASSERT(ret < 0,
199 		"Call succeeded with invalid parameters\n");
200 
201 	rte_fib6_free(fib);
202 
203 	return TEST_SUCCESS;
204 }
205 
206 /*
207  * Check that rte_fib6_get_dp and rte_fib6_get_rib fails gracefully
208  * for incorrect user input arguments
209  */
210 int32_t
test_get_invalid(void)211 test_get_invalid(void)
212 {
213 	void *p;
214 
215 	p = rte_fib6_get_dp(NULL);
216 	RTE_TEST_ASSERT(p == NULL,
217 		"Call succeeded with invalid parameters\n");
218 
219 	p = rte_fib6_get_rib(NULL);
220 	RTE_TEST_ASSERT(p == NULL,
221 		"Call succeeded with invalid parameters\n");
222 
223 	return TEST_SUCCESS;
224 }
225 
226 /*
227  * Add routes for one supernet with all possible depths and do lookup
228  * on each step
229  * After delete routes with doing lookup on each step
230  */
231 static int
lookup_and_check_asc(struct rte_fib6 * fib,uint8_t ip_arr[RTE_FIB6_MAXDEPTH][RTE_FIB6_IPV6_ADDR_SIZE],uint8_t ip_missing[][RTE_FIB6_IPV6_ADDR_SIZE],uint64_t def_nh,uint32_t n)232 lookup_and_check_asc(struct rte_fib6 *fib,
233 	uint8_t ip_arr[RTE_FIB6_MAXDEPTH][RTE_FIB6_IPV6_ADDR_SIZE],
234 	uint8_t ip_missing[][RTE_FIB6_IPV6_ADDR_SIZE], uint64_t def_nh,
235 	uint32_t n)
236 {
237 	uint64_t nh_arr[RTE_FIB6_MAXDEPTH];
238 	int ret;
239 	uint32_t i = 0;
240 
241 	ret = rte_fib6_lookup_bulk(fib, ip_arr, nh_arr, RTE_FIB6_MAXDEPTH);
242 	RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n");
243 
244 	for (; i <= RTE_FIB6_MAXDEPTH - n; i++)
245 		RTE_TEST_ASSERT(nh_arr[i] == n,
246 			"Failed to get proper nexthop\n");
247 
248 	for (; i < RTE_FIB6_MAXDEPTH; i++)
249 		RTE_TEST_ASSERT(nh_arr[i] == --n,
250 			"Failed to get proper nexthop\n");
251 
252 	ret = rte_fib6_lookup_bulk(fib, ip_missing, nh_arr, 1);
253 	RTE_TEST_ASSERT((ret == 0) && (nh_arr[0] == def_nh),
254 		"Failed to get proper nexthop\n");
255 
256 	return TEST_SUCCESS;
257 }
258 
259 static int
lookup_and_check_desc(struct rte_fib6 * fib,uint8_t ip_arr[RTE_FIB6_MAXDEPTH][RTE_FIB6_IPV6_ADDR_SIZE],uint8_t ip_missing[][RTE_FIB6_IPV6_ADDR_SIZE],uint64_t def_nh,uint32_t n)260 lookup_and_check_desc(struct rte_fib6 *fib,
261 	uint8_t ip_arr[RTE_FIB6_MAXDEPTH][RTE_FIB6_IPV6_ADDR_SIZE],
262 	uint8_t ip_missing[][RTE_FIB6_IPV6_ADDR_SIZE], uint64_t def_nh,
263 	uint32_t n)
264 {
265 	uint64_t nh_arr[RTE_FIB6_MAXDEPTH];
266 	int ret;
267 	uint32_t i = 0;
268 
269 	ret = rte_fib6_lookup_bulk(fib, ip_arr, nh_arr, RTE_FIB6_MAXDEPTH);
270 	RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n");
271 
272 	for (; i < n; i++)
273 		RTE_TEST_ASSERT(nh_arr[i] == RTE_FIB6_MAXDEPTH - i,
274 			"Failed to get proper nexthop\n");
275 
276 	for (; i < RTE_FIB6_MAXDEPTH; i++)
277 		RTE_TEST_ASSERT(nh_arr[i] == def_nh,
278 			"Failed to get proper nexthop\n");
279 
280 	ret = rte_fib6_lookup_bulk(fib, ip_missing, nh_arr, 1);
281 	RTE_TEST_ASSERT((ret == 0) && (nh_arr[0] == def_nh),
282 		"Failed to get proper nexthop\n");
283 
284 	return TEST_SUCCESS;
285 }
286 
287 static int
check_fib(struct rte_fib6 * fib)288 check_fib(struct rte_fib6 *fib)
289 {
290 	uint64_t def_nh = 100;
291 	uint8_t ip_arr[RTE_FIB6_MAXDEPTH][RTE_FIB6_IPV6_ADDR_SIZE];
292 	uint8_t ip_add[RTE_FIB6_IPV6_ADDR_SIZE] = {0};
293 	uint8_t ip_missing[1][RTE_FIB6_IPV6_ADDR_SIZE] = { {255} };
294 	uint32_t i, j;
295 	int ret;
296 
297 	ip_add[0] = 128;
298 	ip_missing[0][0] = 127;
299 	for (i = 0; i < RTE_FIB6_MAXDEPTH; i++) {
300 		for (j = 0; j < RTE_FIB6_IPV6_ADDR_SIZE; j++) {
301 			ip_arr[i][j] = ip_add[j] |
302 				~get_msk_part(RTE_FIB6_MAXDEPTH - i, j);
303 		}
304 	}
305 
306 	ret = lookup_and_check_desc(fib, ip_arr, ip_missing, def_nh, 0);
307 	RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n");
308 
309 	for (i = 1; i <= RTE_FIB6_MAXDEPTH; i++) {
310 		ret = rte_fib6_add(fib, ip_add, i, i);
311 		RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n");
312 		ret = lookup_and_check_asc(fib, ip_arr, ip_missing, def_nh, i);
313 		RTE_TEST_ASSERT(ret == TEST_SUCCESS,
314 			"Lookup and check fails\n");
315 	}
316 
317 	for (i = RTE_FIB6_MAXDEPTH; i > 1; i--) {
318 		ret = rte_fib6_delete(fib, ip_add, i);
319 		RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n");
320 		ret = lookup_and_check_asc(fib, ip_arr, ip_missing,
321 			def_nh, i - 1);
322 
323 		RTE_TEST_ASSERT(ret == TEST_SUCCESS,
324 			"Lookup and check fails\n");
325 	}
326 	ret = rte_fib6_delete(fib, ip_add, i);
327 	RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n");
328 	ret = lookup_and_check_desc(fib, ip_arr, ip_missing, def_nh, 0);
329 	RTE_TEST_ASSERT(ret == TEST_SUCCESS,
330 		"Lookup and check fails\n");
331 
332 	for (i = 0; i < RTE_FIB6_MAXDEPTH; i++) {
333 		ret = rte_fib6_add(fib, ip_add, RTE_FIB6_MAXDEPTH - i,
334 			RTE_FIB6_MAXDEPTH - i);
335 		RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n");
336 		ret = lookup_and_check_desc(fib, ip_arr, ip_missing,
337 			def_nh, i + 1);
338 		RTE_TEST_ASSERT(ret == TEST_SUCCESS,
339 			"Lookup and check fails\n");
340 	}
341 
342 	for (i = 1; i <= RTE_FIB6_MAXDEPTH; i++) {
343 		ret = rte_fib6_delete(fib, ip_add, i);
344 		RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n");
345 		ret = lookup_and_check_desc(fib, ip_arr, ip_missing, def_nh,
346 			RTE_FIB6_MAXDEPTH - i);
347 		RTE_TEST_ASSERT(ret == TEST_SUCCESS,
348 			"Lookup and check fails\n");
349 	}
350 
351 	return TEST_SUCCESS;
352 }
353 
354 int32_t
test_lookup(void)355 test_lookup(void)
356 {
357 	struct rte_fib6 *fib = NULL;
358 	struct rte_fib6_conf config;
359 	uint64_t def_nh = 100;
360 	int ret;
361 
362 	config.max_routes = MAX_ROUTES;
363 	config.rib_ext_sz = 0;
364 	config.default_nh = def_nh;
365 	config.type = RTE_FIB6_DUMMY;
366 
367 	fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
368 	RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
369 	ret = check_fib(fib);
370 	RTE_TEST_ASSERT(ret == TEST_SUCCESS,
371 		"Check_fib fails for DUMMY type\n");
372 	rte_fib6_free(fib);
373 
374 	config.type = RTE_FIB6_TRIE;
375 
376 	config.trie.nh_sz = RTE_FIB6_TRIE_2B;
377 	config.trie.num_tbl8 = MAX_TBL8 - 1;
378 	fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
379 	RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
380 	ret = check_fib(fib);
381 	RTE_TEST_ASSERT(ret == TEST_SUCCESS,
382 		"Check_fib fails for TRIE_2B type\n");
383 	rte_fib6_free(fib);
384 
385 	config.trie.nh_sz = RTE_FIB6_TRIE_4B;
386 	config.trie.num_tbl8 = MAX_TBL8;
387 	fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
388 	RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
389 	ret = check_fib(fib);
390 	RTE_TEST_ASSERT(ret == TEST_SUCCESS,
391 		"Check_fib fails for TRIE_4B type\n");
392 	rte_fib6_free(fib);
393 
394 	config.trie.nh_sz = RTE_FIB6_TRIE_8B;
395 	config.trie.num_tbl8 = MAX_TBL8;
396 	fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
397 	RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
398 	ret = check_fib(fib);
399 	RTE_TEST_ASSERT(ret == TEST_SUCCESS,
400 		"Check_fib fails for TRIE_8B type\n");
401 	rte_fib6_free(fib);
402 
403 	return TEST_SUCCESS;
404 }
405 
406 static struct unit_test_suite fib6_fast_tests = {
407 	.suite_name = "fib6 autotest",
408 	.setup = NULL,
409 	.teardown = NULL,
410 	.unit_test_cases = {
411 	TEST_CASE(test_create_invalid),
412 	TEST_CASE(test_free_null),
413 	TEST_CASE(test_add_del_invalid),
414 	TEST_CASE(test_get_invalid),
415 	TEST_CASE(test_lookup),
416 	TEST_CASES_END()
417 	}
418 };
419 
420 static struct unit_test_suite fib6_slow_tests = {
421 	.suite_name = "fib6 slow autotest",
422 	.setup = NULL,
423 	.teardown = NULL,
424 	.unit_test_cases = {
425 	TEST_CASE(test_multiple_create),
426 	TEST_CASES_END()
427 	}
428 };
429 
430 /*
431  * Do all unit tests.
432  */
433 static int
test_fib6(void)434 test_fib6(void)
435 {
436 	return unit_test_suite_runner(&fib6_fast_tests);
437 }
438 
439 static int
test_slow_fib6(void)440 test_slow_fib6(void)
441 {
442 	return unit_test_suite_runner(&fib6_slow_tests);
443 }
444 
445 #endif /* !RTE_EXEC_ENV_WINDOWS */
446 
447 REGISTER_TEST_COMMAND(fib6_autotest, test_fib6);
448 REGISTER_TEST_COMMAND(fib6_slow_autotest, test_slow_fib6);
449