test/security: add inline inbound IPsec cases
[dpdk.git] / app / test / test_fib6.c
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
13 #include "test.h"
14
15 #ifdef RTE_EXEC_ENV_WINDOWS
16 static int
17 test_fib6(void)
18 {
19         printf("fib not supported on Windows, skipping test\n");
20         return TEST_SKIPPED;
21 }
22
23 static int
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
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
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
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
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
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
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
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
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
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
434 test_fib6(void)
435 {
436         return unit_test_suite_runner(&fib6_fast_tests);
437 }
438
439 static int
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);