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