app/testpmd: add async flow create/destroy operations
[dpdk.git] / app / test / test_fib.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_ip.h>
11 #include <rte_log.h>
12
13 #include "test.h"
14
15 #ifdef RTE_EXEC_ENV_WINDOWS
16 static int
17 test_fib(void)
18 {
19         printf("fib not supported on Windows, skipping test\n");
20         return TEST_SKIPPED;
21 }
22
23 static int
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
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
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
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
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
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
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
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
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
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
425 test_fib(void)
426 {
427         return unit_test_suite_runner(&fib_fast_tests);
428 }
429
430 static int
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);