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 : : #include <rte_malloc.h>
15 : :
16 : : #include "test.h"
17 : :
18 : : typedef int32_t (*rte_fib6_test)(void);
19 : :
20 : : static int32_t test_create_invalid(void);
21 : : static int32_t test_multiple_create(void);
22 : : static int32_t test_free_null(void);
23 : : static int32_t test_add_del_invalid(void);
24 : : static int32_t test_get_invalid(void);
25 : : static int32_t test_lookup(void);
26 : : static int32_t test_invalid_rcu(void);
27 : : static int32_t test_fib_rcu_sync_rw(void);
28 : :
29 : : #define MAX_ROUTES (1 << 16)
30 : : /** Maximum number of tbl8 for 2-byte entries */
31 : : #define MAX_TBL8 (1 << 15)
32 : :
33 : : /*
34 : : * Check that rte_fib6_create fails gracefully for incorrect user input
35 : : * arguments
36 : : */
37 : : int32_t
38 : 1 : test_create_invalid(void)
39 : : {
40 : : struct rte_fib6 *fib = NULL;
41 : : struct rte_fib6_conf config;
42 : :
43 : 1 : config.max_routes = MAX_ROUTES;
44 : 1 : config.rib_ext_sz = 0;
45 : 1 : config.default_nh = 0;
46 : 1 : config.type = RTE_FIB6_DUMMY;
47 : :
48 : : /* rte_fib6_create: fib name == NULL */
49 : 1 : fib = rte_fib6_create(NULL, SOCKET_ID_ANY, &config);
50 [ - + ]: 1 : RTE_TEST_ASSERT(fib == NULL,
51 : : "Call succeeded with invalid parameters\n");
52 : :
53 : : /* rte_fib6_create: config == NULL */
54 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, NULL);
55 [ - + ]: 1 : RTE_TEST_ASSERT(fib == NULL,
56 : : "Call succeeded with invalid parameters\n");
57 : :
58 : : /* socket_id < -1 is invalid */
59 : 1 : fib = rte_fib6_create(__func__, -2, &config);
60 [ - + ]: 1 : RTE_TEST_ASSERT(fib == NULL,
61 : : "Call succeeded with invalid parameters\n");
62 : :
63 : : /* rte_fib6_create: max_routes = 0 */
64 : 1 : config.max_routes = 0;
65 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
66 [ - + ]: 1 : RTE_TEST_ASSERT(fib == NULL,
67 : : "Call succeeded with invalid parameters\n");
68 : 1 : config.max_routes = MAX_ROUTES;
69 : :
70 : 1 : config.type = RTE_FIB6_TRIE + 1;
71 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
72 [ - + ]: 1 : RTE_TEST_ASSERT(fib == NULL,
73 : : "Call succeeded with invalid parameters\n");
74 : :
75 : 1 : config.type = RTE_FIB6_TRIE;
76 : 1 : config.trie.num_tbl8 = MAX_TBL8;
77 : :
78 : 1 : config.trie.nh_sz = RTE_FIB6_TRIE_8B + 1;
79 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
80 [ - + ]: 1 : RTE_TEST_ASSERT(fib == NULL,
81 : : "Call succeeded with invalid parameters\n");
82 : 1 : config.trie.nh_sz = RTE_FIB6_TRIE_8B;
83 : :
84 : 1 : config.trie.num_tbl8 = 0;
85 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
86 [ - + ]: 1 : RTE_TEST_ASSERT(fib == NULL,
87 : : "Call succeeded with invalid parameters\n");
88 : :
89 : : return TEST_SUCCESS;
90 : : }
91 : :
92 : : /*
93 : : * Create fib table then delete fib table 10 times
94 : : * Use a slightly different rules size each time
95 : : */
96 : : int32_t
97 : 0 : test_multiple_create(void)
98 : : {
99 : : struct rte_fib6 *fib = NULL;
100 : : struct rte_fib6_conf config;
101 : : int32_t i;
102 : :
103 : 0 : config.rib_ext_sz = 0;
104 : 0 : config.default_nh = 0;
105 : 0 : config.type = RTE_FIB6_DUMMY;
106 : :
107 [ # # ]: 0 : for (i = 0; i < 100; i++) {
108 : 0 : config.max_routes = MAX_ROUTES - i;
109 : 0 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
110 [ # # ]: 0 : RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
111 : 0 : rte_fib6_free(fib);
112 : : }
113 : : /* Can not test free so return success */
114 : : return TEST_SUCCESS;
115 : : }
116 : :
117 : : /*
118 : : * Call rte_fib6_free for NULL pointer user input. Note: free has no return and
119 : : * therefore it is impossible to check for failure but this test is added to
120 : : * increase function coverage metrics and to validate that freeing null does
121 : : * not crash.
122 : : */
123 : : int32_t
124 : 1 : test_free_null(void)
125 : : {
126 : : struct rte_fib6 *fib = NULL;
127 : : struct rte_fib6_conf config;
128 : :
129 : 1 : config.max_routes = MAX_ROUTES;
130 : 1 : config.rib_ext_sz = 0;
131 : 1 : config.default_nh = 0;
132 : 1 : config.type = RTE_FIB6_DUMMY;
133 : :
134 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
135 [ - + ]: 1 : RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
136 : :
137 : 1 : rte_fib6_free(fib);
138 : 1 : rte_fib6_free(NULL);
139 : :
140 : 1 : return TEST_SUCCESS;
141 : : }
142 : :
143 : : /*
144 : : * Check that rte_fib6_add and rte_fib6_delete fails gracefully
145 : : * for incorrect user input arguments
146 : : */
147 : : int32_t
148 : 1 : test_add_del_invalid(void)
149 : : {
150 : : struct rte_fib6 *fib = NULL;
151 : : struct rte_fib6_conf config;
152 : : uint64_t nh = 100;
153 : 1 : struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC;
154 : : int ret;
155 : : uint8_t depth = 24;
156 : :
157 : 1 : config.max_routes = MAX_ROUTES;
158 : 1 : config.rib_ext_sz = 0;
159 : 1 : config.default_nh = 0;
160 : 1 : config.type = RTE_FIB6_DUMMY;
161 : :
162 : : /* rte_fib6_add: fib == NULL */
163 : 1 : ret = rte_fib6_add(NULL, &ip, depth, nh);
164 [ - + ]: 1 : RTE_TEST_ASSERT(ret < 0,
165 : : "Call succeeded with invalid parameters\n");
166 : :
167 : : /* rte_fib6_delete: fib == NULL */
168 : 1 : ret = rte_fib6_delete(NULL, &ip, depth);
169 [ - + ]: 1 : RTE_TEST_ASSERT(ret < 0,
170 : : "Call succeeded with invalid parameters\n");
171 : :
172 : : /*Create valid fib to use in rest of test. */
173 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
174 [ - + ]: 1 : RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
175 : :
176 : : /* rte_fib6_add: depth > RTE_IPV6_MAX_DEPTH */
177 : 1 : ret = rte_fib6_add(fib, &ip, RTE_IPV6_MAX_DEPTH + 1, nh);
178 [ - + ]: 1 : RTE_TEST_ASSERT(ret < 0,
179 : : "Call succeeded with invalid parameters\n");
180 : :
181 : : /* rte_fib6_delete: depth > RTE_IPV6_MAX_DEPTH */
182 : 1 : ret = rte_fib6_delete(fib, &ip, RTE_IPV6_MAX_DEPTH + 1);
183 [ - + ]: 1 : RTE_TEST_ASSERT(ret < 0,
184 : : "Call succeeded with invalid parameters\n");
185 : :
186 : 1 : rte_fib6_free(fib);
187 : :
188 : 1 : return TEST_SUCCESS;
189 : : }
190 : :
191 : : /*
192 : : * Check that rte_fib6_get_dp and rte_fib6_get_rib fails gracefully
193 : : * for incorrect user input arguments
194 : : */
195 : : int32_t
196 : 1 : test_get_invalid(void)
197 : : {
198 : : void *p;
199 : :
200 : 1 : p = rte_fib6_get_dp(NULL);
201 [ - + ]: 1 : RTE_TEST_ASSERT(p == NULL,
202 : : "Call succeeded with invalid parameters\n");
203 : :
204 : 1 : p = rte_fib6_get_rib(NULL);
205 [ - + ]: 1 : RTE_TEST_ASSERT(p == NULL,
206 : : "Call succeeded with invalid parameters\n");
207 : :
208 : : return TEST_SUCCESS;
209 : : }
210 : :
211 : : /*
212 : : * Add routes for one supernet with all possible depths and do lookup
213 : : * on each step
214 : : * After delete routes with doing lookup on each step
215 : : */
216 : : static int
217 : 1020 : lookup_and_check_asc(struct rte_fib6 *fib,
218 : : struct rte_ipv6_addr *ip_arr,
219 : : struct rte_ipv6_addr *ip_missing, uint64_t def_nh,
220 : : uint32_t n)
221 : : {
222 : : uint64_t nh_arr[RTE_IPV6_MAX_DEPTH];
223 : : int ret;
224 : : uint32_t i = 0;
225 : :
226 : 1020 : ret = rte_fib6_lookup_bulk(fib, ip_arr, nh_arr, RTE_IPV6_MAX_DEPTH);
227 [ - + ]: 1020 : RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n");
228 : :
229 [ + + ]: 67064 : for (; i <= RTE_IPV6_MAX_DEPTH - n; i++)
230 [ - + ]: 66044 : RTE_TEST_ASSERT(nh_arr[i] == n,
231 : : "Failed to get proper nexthop\n");
232 : :
233 [ + + ]: 65536 : for (; i < RTE_IPV6_MAX_DEPTH; i++)
234 [ - + ]: 64516 : RTE_TEST_ASSERT(nh_arr[i] == --n,
235 : : "Failed to get proper nexthop\n");
236 : :
237 : 1020 : ret = rte_fib6_lookup_bulk(fib, ip_missing, nh_arr, 1);
238 [ + - - + ]: 1020 : RTE_TEST_ASSERT((ret == 0) && (nh_arr[0] == def_nh),
239 : : "Failed to get proper nexthop\n");
240 : :
241 : : return TEST_SUCCESS;
242 : : }
243 : :
244 : : static int
245 : 1032 : lookup_and_check_desc(struct rte_fib6 *fib,
246 : : struct rte_ipv6_addr *ip_arr,
247 : : struct rte_ipv6_addr *ip_missing, uint64_t def_nh,
248 : : uint32_t n)
249 : : {
250 : : uint64_t nh_arr[RTE_IPV6_MAX_DEPTH];
251 : : int ret;
252 : : uint32_t i = 0;
253 : :
254 : 1032 : ret = rte_fib6_lookup_bulk(fib, ip_arr, nh_arr, RTE_IPV6_MAX_DEPTH);
255 [ - + ]: 1032 : RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n");
256 : :
257 [ + + ]: 66568 : for (; i < n; i++)
258 [ - + ]: 65536 : RTE_TEST_ASSERT(nh_arr[i] == RTE_IPV6_MAX_DEPTH - i,
259 : : "Failed to get proper nexthop\n");
260 : :
261 [ + + ]: 67592 : for (; i < RTE_IPV6_MAX_DEPTH; i++)
262 [ - + ]: 66560 : RTE_TEST_ASSERT(nh_arr[i] == def_nh,
263 : : "Failed to get proper nexthop\n");
264 : :
265 : 1032 : ret = rte_fib6_lookup_bulk(fib, ip_missing, nh_arr, 1);
266 [ + - - + ]: 1032 : RTE_TEST_ASSERT((ret == 0) && (nh_arr[0] == def_nh),
267 : : "Failed to get proper nexthop\n");
268 : :
269 : : return TEST_SUCCESS;
270 : : }
271 : :
272 : : static int
273 : 4 : check_fib(struct rte_fib6 *fib)
274 : : {
275 : : uint64_t def_nh = 100;
276 : : struct rte_ipv6_addr ip_arr[RTE_IPV6_MAX_DEPTH];
277 : 4 : struct rte_ipv6_addr ip_add = RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0);
278 : 4 : struct rte_ipv6_addr ip_missing =
279 : : RTE_IPV6(0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff);
280 : : uint32_t i, j;
281 : : int ret;
282 : :
283 [ + + ]: 516 : for (i = 0; i < RTE_IPV6_MAX_DEPTH; i++) {
284 : 512 : ip_arr[i] = ip_add;
285 : 512 : j = (RTE_IPV6_MAX_DEPTH - i) / CHAR_BIT;
286 [ + + ]: 512 : if (j < RTE_IPV6_ADDR_SIZE) {
287 : 508 : ip_arr[i].a[j] |= UINT8_MAX >> ((RTE_IPV6_MAX_DEPTH - i) % CHAR_BIT);
288 [ + + ]: 4288 : for (j++; j < RTE_IPV6_ADDR_SIZE; j++)
289 : 3780 : ip_arr[i].a[j] = 0xff;
290 : : }
291 : : }
292 : :
293 : 4 : ret = lookup_and_check_desc(fib, ip_arr, &ip_missing, def_nh, 0);
294 [ - + ]: 4 : RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n");
295 : :
296 [ + + ]: 516 : for (i = 1; i <= RTE_IPV6_MAX_DEPTH; i++) {
297 : 512 : ret = rte_fib6_add(fib, &ip_add, i, i);
298 [ - + ]: 512 : RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n");
299 : 512 : ret = lookup_and_check_asc(fib, ip_arr, &ip_missing, def_nh, i);
300 [ - + ]: 512 : RTE_TEST_ASSERT(ret == TEST_SUCCESS,
301 : : "Lookup and check fails\n");
302 : : }
303 : :
304 [ + + ]: 512 : for (i = RTE_IPV6_MAX_DEPTH; i > 1; i--) {
305 : 508 : ret = rte_fib6_delete(fib, &ip_add, i);
306 [ - + ]: 508 : RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n");
307 : 508 : ret = lookup_and_check_asc(fib, ip_arr, &ip_missing,
308 : : def_nh, i - 1);
309 : :
310 [ - + ]: 508 : RTE_TEST_ASSERT(ret == TEST_SUCCESS,
311 : : "Lookup and check fails\n");
312 : : }
313 : 4 : ret = rte_fib6_delete(fib, &ip_add, i);
314 [ - + ]: 4 : RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n");
315 : 4 : ret = lookup_and_check_desc(fib, ip_arr, &ip_missing, def_nh, 0);
316 [ - + ]: 4 : RTE_TEST_ASSERT(ret == TEST_SUCCESS,
317 : : "Lookup and check fails\n");
318 : :
319 [ + + ]: 516 : for (i = 0; i < RTE_IPV6_MAX_DEPTH; i++) {
320 : 512 : ret = rte_fib6_add(fib, &ip_add, RTE_IPV6_MAX_DEPTH - i,
321 : 512 : RTE_IPV6_MAX_DEPTH - i);
322 [ - + ]: 512 : RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n");
323 : 512 : ret = lookup_and_check_desc(fib, ip_arr, &ip_missing,
324 : : def_nh, i + 1);
325 [ - + ]: 512 : RTE_TEST_ASSERT(ret == TEST_SUCCESS,
326 : : "Lookup and check fails\n");
327 : : }
328 : :
329 [ + + ]: 516 : for (i = 1; i <= RTE_IPV6_MAX_DEPTH; i++) {
330 : 512 : ret = rte_fib6_delete(fib, &ip_add, i);
331 [ - + ]: 512 : RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n");
332 : 512 : ret = lookup_and_check_desc(fib, ip_arr, &ip_missing, def_nh,
333 : : RTE_IPV6_MAX_DEPTH - i);
334 [ - + ]: 512 : RTE_TEST_ASSERT(ret == TEST_SUCCESS,
335 : : "Lookup and check fails\n");
336 : : }
337 : :
338 : : return TEST_SUCCESS;
339 : : }
340 : :
341 : : int32_t
342 : 1 : test_lookup(void)
343 : : {
344 : : struct rte_fib6 *fib = NULL;
345 : : struct rte_fib6_conf config;
346 : : uint64_t def_nh = 100;
347 : : int ret;
348 : :
349 : 1 : config.max_routes = MAX_ROUTES;
350 : 1 : config.rib_ext_sz = 0;
351 : 1 : config.default_nh = def_nh;
352 : 1 : config.type = RTE_FIB6_DUMMY;
353 : :
354 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
355 [ - + ]: 1 : RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
356 : 1 : ret = check_fib(fib);
357 [ - + ]: 1 : RTE_TEST_ASSERT(ret == TEST_SUCCESS,
358 : : "Check_fib fails for DUMMY type\n");
359 : 1 : rte_fib6_free(fib);
360 : :
361 : 1 : config.type = RTE_FIB6_TRIE;
362 : :
363 : 1 : config.trie.nh_sz = RTE_FIB6_TRIE_2B;
364 : 1 : config.trie.num_tbl8 = MAX_TBL8 - 1;
365 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
366 [ - + ]: 1 : RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
367 : 1 : ret = check_fib(fib);
368 [ - + ]: 1 : RTE_TEST_ASSERT(ret == TEST_SUCCESS,
369 : : "Check_fib fails for TRIE_2B type\n");
370 : 1 : rte_fib6_free(fib);
371 : :
372 : 1 : config.trie.nh_sz = RTE_FIB6_TRIE_4B;
373 : 1 : config.trie.num_tbl8 = MAX_TBL8;
374 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
375 [ - + ]: 1 : RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
376 : 1 : ret = check_fib(fib);
377 [ - + ]: 1 : RTE_TEST_ASSERT(ret == TEST_SUCCESS,
378 : : "Check_fib fails for TRIE_4B type\n");
379 : 1 : rte_fib6_free(fib);
380 : :
381 : 1 : config.trie.nh_sz = RTE_FIB6_TRIE_8B;
382 : 1 : config.trie.num_tbl8 = MAX_TBL8;
383 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
384 [ - + ]: 1 : RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
385 : 1 : ret = check_fib(fib);
386 [ - + ]: 1 : RTE_TEST_ASSERT(ret == TEST_SUCCESS,
387 : : "Check_fib fails for TRIE_8B type\n");
388 : 1 : rte_fib6_free(fib);
389 : :
390 : 1 : return TEST_SUCCESS;
391 : : }
392 : :
393 : : /*
394 : : * rte_fib6_rcu_qsbr_add positive and negative tests.
395 : : * - Add RCU QSBR variable to FIB
396 : : * - Add another RCU QSBR variable to FIB
397 : : * - Check returns
398 : : */
399 : : int32_t
400 : 1 : test_invalid_rcu(void)
401 : : {
402 : : struct rte_fib6 *fib = NULL;
403 : 1 : struct rte_fib6_conf config = { 0 };
404 : : size_t sz;
405 : : struct rte_rcu_qsbr *qsv;
406 : : struct rte_rcu_qsbr *qsv2;
407 : : int32_t status;
408 : 1 : struct rte_fib6_rcu_config rcu_cfg = {0};
409 : : uint64_t def_nh = 100;
410 : :
411 : 1 : config.max_routes = MAX_ROUTES;
412 : : config.rib_ext_sz = 0;
413 : 1 : config.default_nh = def_nh;
414 : :
415 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
416 [ - + ]: 1 : RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
417 : :
418 : : /* Create RCU QSBR variable */
419 : 1 : sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
420 : 1 : qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE,
421 : : SOCKET_ID_ANY);
422 [ - + ]: 1 : RTE_TEST_ASSERT(qsv != NULL, "Can not allocate memory for RCU\n");
423 : :
424 : 1 : status = rte_rcu_qsbr_init(qsv, RTE_MAX_LCORE);
425 [ - + ]: 1 : RTE_TEST_ASSERT(status == 0, "Can not initialize RCU\n");
426 : :
427 : 1 : rcu_cfg.v = qsv;
428 : :
429 : : /* adding rcu to RTE_FIB6_DUMMY FIB type */
430 : 1 : config.type = RTE_FIB6_DUMMY;
431 : 1 : rcu_cfg.mode = RTE_FIB6_QSBR_MODE_SYNC;
432 : 1 : status = rte_fib6_rcu_qsbr_add(fib, &rcu_cfg);
433 [ - + ]: 1 : RTE_TEST_ASSERT(status == -ENOTSUP,
434 : : "rte_fib6_rcu_qsbr_add returned wrong error status when called with DUMMY type FIB\n");
435 : 1 : rte_fib6_free(fib);
436 : :
437 : 1 : config.type = RTE_FIB6_TRIE;
438 : 1 : config.trie.nh_sz = RTE_FIB6_TRIE_4B;
439 : 1 : config.trie.num_tbl8 = MAX_TBL8;
440 : 1 : fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
441 [ - + ]: 1 : RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
442 : :
443 : : /* Call rte_fib6_rcu_qsbr_add without fib or config */
444 : 1 : status = rte_fib6_rcu_qsbr_add(NULL, &rcu_cfg);
445 [ - + ]: 1 : RTE_TEST_ASSERT(status == -EINVAL, "RCU added without fib\n");
446 : 1 : status = rte_fib6_rcu_qsbr_add(fib, NULL);
447 [ - + ]: 1 : RTE_TEST_ASSERT(status == -EINVAL, "RCU added without config\n");
448 : :
449 : : /* Invalid QSBR mode */
450 : 1 : rcu_cfg.mode = 2;
451 : 1 : status = rte_fib6_rcu_qsbr_add(fib, &rcu_cfg);
452 [ - + ]: 1 : RTE_TEST_ASSERT(status == -EINVAL, "RCU added with incorrect mode\n");
453 : :
454 : 1 : rcu_cfg.mode = RTE_FIB6_QSBR_MODE_DQ;
455 : :
456 : : /* Attach RCU QSBR to FIB to check for double attach */
457 : 1 : status = rte_fib6_rcu_qsbr_add(fib, &rcu_cfg);
458 [ - + ]: 1 : RTE_TEST_ASSERT(status == 0, "Can not attach RCU to FIB\n");
459 : :
460 : : /* Create and attach another RCU QSBR to FIB table */
461 : 1 : qsv2 = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE,
462 : : SOCKET_ID_ANY);
463 [ - + ]: 1 : RTE_TEST_ASSERT(qsv2 != NULL, "Can not allocate memory for RCU\n");
464 : :
465 : 1 : rcu_cfg.v = qsv2;
466 : 1 : rcu_cfg.mode = RTE_FIB6_QSBR_MODE_SYNC;
467 : 1 : status = rte_fib6_rcu_qsbr_add(fib, &rcu_cfg);
468 [ - + ]: 1 : RTE_TEST_ASSERT(status == -EEXIST, "Secondary RCU was mistakenly attached\n");
469 : :
470 : 1 : rte_fib6_free(fib);
471 : 1 : rte_free(qsv);
472 : 1 : rte_free(qsv2);
473 : :
474 : 1 : return TEST_SUCCESS;
475 : : }
476 : :
477 : : static struct rte_fib6 *g_fib;
478 : : static struct rte_rcu_qsbr *g_v;
479 : : static struct rte_ipv6_addr g_ip = RTE_IPV6(0x2001, 0xabcd, 0, 0, 0, 0, 0, 1);
480 : : static volatile uint8_t writer_done;
481 : : /* Report quiescent state interval every 1024 lookups. Larger critical
482 : : * sections in reader will result in writer polling multiple times.
483 : : */
484 : : #define QSBR_REPORTING_INTERVAL 1024
485 : : #define WRITER_ITERATIONS 512
486 : :
487 : : /*
488 : : * Reader thread using rte_fib6 data structure with RCU.
489 : : */
490 : : static int
491 : 1 : test_fib_rcu_qsbr_reader(void *arg)
492 : : {
493 : : int i;
494 : 1 : uint64_t next_hop_return = 0;
495 : :
496 : : RTE_SET_USED(arg);
497 : : /* Register this thread to report quiescent state */
498 : 1 : rte_rcu_qsbr_thread_register(g_v, 0);
499 : 1 : rte_rcu_qsbr_thread_online(g_v, 0);
500 : :
501 : : do {
502 [ + + ]: 526850 : for (i = 0; i < QSBR_REPORTING_INTERVAL; i++)
503 : 526336 : rte_fib6_lookup_bulk(g_fib, &g_ip, &next_hop_return, 1);
504 : :
505 : : /* Update quiescent state */
506 [ + + ]: 514 : rte_rcu_qsbr_quiescent(g_v, 0);
507 [ + + ]: 514 : } while (!writer_done);
508 : :
509 : 1 : rte_rcu_qsbr_thread_offline(g_v, 0);
510 : 1 : rte_rcu_qsbr_thread_unregister(g_v, 0);
511 : :
512 : 1 : return 0;
513 : : }
514 : :
515 : : /*
516 : : * rte_fib6_rcu_qsbr_add sync mode functional test.
517 : : * 1 Reader and 1 writer. They cannot be in the same thread in this test.
518 : : * - Create FIB which supports 1 tbl8 group at max
519 : : * - Add RCU QSBR variable with sync mode to FIB
520 : : * - Register a reader thread. Reader keeps looking up a specific rule.
521 : : * - Writer keeps adding and deleting a specific rule with depth=28 (> 24)
522 : : */
523 : : int32_t
524 : 1 : test_fib_rcu_sync_rw(void)
525 : : {
526 : 1 : struct rte_fib6_conf config = { 0 };
527 : : size_t sz;
528 : : int32_t status;
529 : : uint32_t i, next_hop;
530 : : uint8_t depth;
531 : 1 : struct rte_fib6_rcu_config rcu_cfg = {0};
532 : : uint64_t def_nh = 100;
533 : :
534 [ - + ]: 1 : if (rte_lcore_count() < 2) {
535 : : printf("Not enough cores for %s, expecting at least 2\n", __func__);
536 : 0 : return TEST_SKIPPED;
537 : : }
538 : :
539 : 1 : config.max_routes = MAX_ROUTES;
540 : 1 : config.rib_ext_sz = 0;
541 : 1 : config.default_nh = def_nh;
542 : 1 : config.type = RTE_FIB6_TRIE;
543 : 1 : config.trie.nh_sz = RTE_FIB6_TRIE_4B;
544 : 1 : config.trie.num_tbl8 = 1;
545 : :
546 : 1 : g_fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
547 [ - + ]: 1 : RTE_TEST_ASSERT(g_fib != NULL, "Failed to create FIB\n");
548 : :
549 : : /* Create RCU QSBR variable */
550 : 1 : sz = rte_rcu_qsbr_get_memsize(1);
551 : 1 : g_v = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE,
552 : : SOCKET_ID_ANY);
553 [ - + ]: 1 : RTE_TEST_ASSERT(g_v != NULL, "Can not allocate memory for RCU\n");
554 : :
555 : 1 : status = rte_rcu_qsbr_init(g_v, 1);
556 [ - + ]: 1 : RTE_TEST_ASSERT(status == 0, "Can not initialize RCU\n");
557 : :
558 : 1 : rcu_cfg.v = g_v;
559 : 1 : rcu_cfg.mode = RTE_FIB6_QSBR_MODE_SYNC;
560 : : /* Attach RCU QSBR to FIB table */
561 : 1 : status = rte_fib6_rcu_qsbr_add(g_fib, &rcu_cfg);
562 [ - + ]: 1 : RTE_TEST_ASSERT(status == 0, "Can not attach RCU to FIB\n");
563 : :
564 : 1 : writer_done = 0;
565 : : /* Launch reader thread */
566 : 1 : rte_eal_remote_launch(test_fib_rcu_qsbr_reader, NULL, rte_get_next_lcore(-1, 1, 0));
567 : :
568 : : depth = 28;
569 : : next_hop = 1;
570 : 1 : status = rte_fib6_add(g_fib, &g_ip, depth, next_hop);
571 [ - + ]: 1 : if (status != 0) {
572 : : printf("%s: Failed to add rule\n", __func__);
573 : 0 : goto error;
574 : : }
575 : :
576 : : /* Writer update */
577 [ + + ]: 513 : for (i = 0; i < WRITER_ITERATIONS; i++) {
578 : 512 : status = rte_fib6_delete(g_fib, &g_ip, depth);
579 [ - + ]: 512 : if (status != 0) {
580 : : printf("%s: Failed to delete rule at iteration %d\n", __func__, i);
581 : 0 : goto error;
582 : : }
583 : :
584 : 512 : status = rte_fib6_add(g_fib, &g_ip, depth, next_hop);
585 [ - + ]: 512 : if (status != 0) {
586 : : printf("%s: Failed to add rule at iteration %d\n", __func__, i);
587 : 0 : goto error;
588 : : }
589 : : }
590 : :
591 : 1 : error:
592 : 1 : writer_done = 1;
593 : : /* Wait until reader exited. */
594 : 1 : rte_eal_mp_wait_lcore();
595 : :
596 : 1 : rte_fib6_free(g_fib);
597 : 1 : rte_free(g_v);
598 : :
599 [ - + ]: 1 : return status == 0 ? TEST_SUCCESS : TEST_FAILED;
600 : : }
601 : :
602 : : static struct unit_test_suite fib6_fast_tests = {
603 : : .suite_name = "fib6 autotest",
604 : : .setup = NULL,
605 : : .teardown = NULL,
606 : : .unit_test_cases = {
607 : : TEST_CASE(test_create_invalid),
608 : : TEST_CASE(test_free_null),
609 : : TEST_CASE(test_add_del_invalid),
610 : : TEST_CASE(test_get_invalid),
611 : : TEST_CASE(test_lookup),
612 : : TEST_CASE(test_invalid_rcu),
613 : : TEST_CASE(test_fib_rcu_sync_rw),
614 : : TEST_CASES_END()
615 : : }
616 : : };
617 : :
618 : : static struct unit_test_suite fib6_slow_tests = {
619 : : .suite_name = "fib6 slow autotest",
620 : : .setup = NULL,
621 : : .teardown = NULL,
622 : : .unit_test_cases = {
623 : : TEST_CASE(test_multiple_create),
624 : : TEST_CASES_END()
625 : : }
626 : : };
627 : :
628 : : /*
629 : : * Do all unit tests.
630 : : */
631 : : static int
632 : 1 : test_fib6(void)
633 : : {
634 : 1 : return unit_test_suite_runner(&fib6_fast_tests);
635 : : }
636 : :
637 : : static int
638 : 0 : test_slow_fib6(void)
639 : : {
640 : 0 : return unit_test_suite_runner(&fib6_slow_tests);
641 : : }
642 : :
643 : 254 : REGISTER_FAST_TEST(fib6_autotest, true, true, test_fib6);
644 : 254 : REGISTER_PERF_TEST(fib6_slow_autotest, test_slow_fib6);
|