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