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