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