1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Vladimir Medvedkin <[email protected]>
3 * Copyright(c) 2019 Intel Corporation
4 */
5
6 #include "test.h"
7
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11
12 #include <rte_ip.h>
13
14 #ifdef RTE_EXEC_ENV_WINDOWS
15 static int
test_rib(void)16 test_rib(void)
17 {
18 printf("rib not supported on Windows, skipping test\n");
19 return TEST_SKIPPED;
20 }
21
22 static int
test_slow_rib(void)23 test_slow_rib(void)
24 {
25 printf("slow_rib not supported on Windows, skipping test\n");
26 return TEST_SKIPPED;
27 }
28 #else
29
30 #include <rte_rib.h>
31
32 typedef int32_t (*rte_rib_test)(void);
33
34 static int32_t test_create_invalid(void);
35 static int32_t test_multiple_create(void);
36 static int32_t test_free_null(void);
37 static int32_t test_insert_invalid(void);
38 static int32_t test_get_fn(void);
39 static int32_t test_basic(void);
40 static int32_t test_tree_traversal(void);
41
42 #define MAX_DEPTH 32
43 #define MAX_RULES (1 << 22)
44
45 /*
46 * Check that rte_rib_create fails gracefully for incorrect user input
47 * arguments
48 */
49 int32_t
test_create_invalid(void)50 test_create_invalid(void)
51 {
52 struct rte_rib *rib = NULL;
53 struct rte_rib_conf config;
54
55 config.max_nodes = MAX_RULES;
56 config.ext_sz = 0;
57
58 /* rte_rib_create: rib name == NULL */
59 rib = rte_rib_create(NULL, SOCKET_ID_ANY, &config);
60 RTE_TEST_ASSERT(rib == NULL,
61 "Call succeeded with invalid parameters\n");
62
63 /* rte_rib_create: config == NULL */
64 rib = rte_rib_create(__func__, SOCKET_ID_ANY, NULL);
65 RTE_TEST_ASSERT(rib == NULL,
66 "Call succeeded with invalid parameters\n");
67
68 /* socket_id < -1 is invalid */
69 rib = rte_rib_create(__func__, -2, &config);
70 RTE_TEST_ASSERT(rib == NULL,
71 "Call succeeded with invalid parameters\n");
72
73 /* rte_rib_create: max_nodes = 0 */
74 config.max_nodes = 0;
75 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config);
76 RTE_TEST_ASSERT(rib == NULL,
77 "Call succeeded with invalid parameters\n");
78 config.max_nodes = MAX_RULES;
79
80 return TEST_SUCCESS;
81 }
82
83 /*
84 * Create rib table then delete rib table 10 times
85 * Use a slightly different rules size each time
86 */
87 int32_t
test_multiple_create(void)88 test_multiple_create(void)
89 {
90 struct rte_rib *rib = NULL;
91 struct rte_rib_conf config;
92 int32_t i;
93
94 config.ext_sz = 0;
95
96 for (i = 0; i < 100; i++) {
97 config.max_nodes = MAX_RULES - i;
98 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config);
99 RTE_TEST_ASSERT(rib != NULL, "Failed to create RIB\n");
100 rte_rib_free(rib);
101 }
102 /* Can not test free so return success */
103 return TEST_SUCCESS;
104 }
105
106 /*
107 * Call rte_rib_free for NULL pointer user input. Note: free has no return and
108 * therefore it is impossible to check for failure but this test is added to
109 * increase function coverage metrics and to validate that freeing null does
110 * not crash.
111 */
112 int32_t
test_free_null(void)113 test_free_null(void)
114 {
115 struct rte_rib *rib = NULL;
116 struct rte_rib_conf config;
117
118 config.max_nodes = MAX_RULES;
119 config.ext_sz = 0;
120
121 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config);
122 RTE_TEST_ASSERT(rib != NULL, "Failed to create RIB\n");
123
124 rte_rib_free(rib);
125 rte_rib_free(NULL);
126 return TEST_SUCCESS;
127 }
128
129 /*
130 * Check that rte_rib_insert fails gracefully for incorrect user input arguments
131 */
132 int32_t
test_insert_invalid(void)133 test_insert_invalid(void)
134 {
135 struct rte_rib *rib = NULL;
136 struct rte_rib_node *node, *node1;
137 struct rte_rib_conf config;
138 uint32_t ip = RTE_IPV4(0, 0, 0, 0);
139 uint8_t depth = 24;
140
141 config.max_nodes = MAX_RULES;
142 config.ext_sz = 0;
143
144 /* rte_rib_insert: rib == NULL */
145 node = rte_rib_insert(NULL, ip, depth);
146 RTE_TEST_ASSERT(node == NULL,
147 "Call succeeded with invalid parameters\n");
148
149 /*Create valid rib to use in rest of test. */
150 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config);
151 RTE_TEST_ASSERT(rib != NULL, "Failed to create RIB\n");
152
153 /* rte_rib_insert: depth > MAX_DEPTH */
154 node = rte_rib_insert(rib, ip, MAX_DEPTH + 1);
155 RTE_TEST_ASSERT(node == NULL,
156 "Call succeeded with invalid parameters\n");
157
158 /* insert the same ip/depth twice*/
159 node = rte_rib_insert(rib, ip, depth);
160 RTE_TEST_ASSERT(node != NULL, "Failed to insert rule\n");
161 node1 = rte_rib_insert(rib, ip, depth);
162 RTE_TEST_ASSERT(node1 == NULL,
163 "Call succeeded with invalid parameters\n");
164
165 rte_rib_free(rib);
166
167 return TEST_SUCCESS;
168 }
169
170 /*
171 * Call rte_rib_node access functions with incorrect input.
172 * After call rte_rib_node access functions with correct args
173 * and check the return values for correctness
174 */
175 int32_t
test_get_fn(void)176 test_get_fn(void)
177 {
178 struct rte_rib *rib = NULL;
179 struct rte_rib_node *node;
180 struct rte_rib_conf config;
181 void *ext;
182 uint32_t ip = RTE_IPV4(192, 0, 2, 0);
183 uint32_t ip_ret;
184 uint64_t nh_set = 10;
185 uint64_t nh_ret;
186 uint8_t depth = 24;
187 uint8_t depth_ret;
188 int ret;
189
190 config.max_nodes = MAX_RULES;
191 config.ext_sz = 0;
192
193 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config);
194 RTE_TEST_ASSERT(rib != NULL, "Failed to create RIB\n");
195
196 node = rte_rib_insert(rib, ip, depth);
197 RTE_TEST_ASSERT(node != NULL, "Failed to insert rule\n");
198
199 /* test rte_rib_get_ip() with incorrect args */
200 ret = rte_rib_get_ip(NULL, &ip_ret);
201 RTE_TEST_ASSERT(ret < 0,
202 "Call succeeded with invalid parameters\n");
203 ret = rte_rib_get_ip(node, NULL);
204 RTE_TEST_ASSERT(ret < 0,
205 "Call succeeded with invalid parameters\n");
206
207 /* test rte_rib_get_depth() with incorrect args */
208 ret = rte_rib_get_depth(NULL, &depth_ret);
209 RTE_TEST_ASSERT(ret < 0,
210 "Call succeeded with invalid parameters\n");
211 ret = rte_rib_get_depth(node, NULL);
212 RTE_TEST_ASSERT(ret < 0,
213 "Call succeeded with invalid parameters\n");
214
215 /* test rte_rib_set_nh() with incorrect args */
216 ret = rte_rib_set_nh(NULL, nh_set);
217 RTE_TEST_ASSERT(ret < 0,
218 "Call succeeded with invalid parameters\n");
219
220 /* test rte_rib_get_nh() with incorrect args */
221 ret = rte_rib_get_nh(NULL, &nh_ret);
222 RTE_TEST_ASSERT(ret < 0,
223 "Call succeeded with invalid parameters\n");
224 ret = rte_rib_get_nh(node, NULL);
225 RTE_TEST_ASSERT(ret < 0,
226 "Call succeeded with invalid parameters\n");
227
228 /* test rte_rib_get_ext() with incorrect args */
229 ext = rte_rib_get_ext(NULL);
230 RTE_TEST_ASSERT(ext == NULL,
231 "Call succeeded with invalid parameters\n");
232
233 /* check the return values */
234 ret = rte_rib_get_ip(node, &ip_ret);
235 RTE_TEST_ASSERT((ret == 0) && (ip_ret == ip),
236 "Failed to get proper node ip\n");
237 ret = rte_rib_get_depth(node, &depth_ret);
238 RTE_TEST_ASSERT((ret == 0) && (depth_ret == depth),
239 "Failed to get proper node depth\n");
240 ret = rte_rib_set_nh(node, nh_set);
241 RTE_TEST_ASSERT(ret == 0,
242 "Failed to set rte_rib_node nexthop\n");
243 ret = rte_rib_get_nh(node, &nh_ret);
244 RTE_TEST_ASSERT((ret == 0) && (nh_ret == nh_set),
245 "Failed to get proper nexthop\n");
246
247 rte_rib_free(rib);
248
249 return TEST_SUCCESS;
250 }
251
252 /*
253 * Call insert, lookup/lookup_exact and delete for a single rule
254 */
255 int32_t
test_basic(void)256 test_basic(void)
257 {
258 struct rte_rib *rib = NULL;
259 struct rte_rib_node *node;
260 struct rte_rib_conf config;
261
262 uint32_t ip = RTE_IPV4(192, 0, 2, 0);
263 uint64_t next_hop_add = 10;
264 uint64_t next_hop_return;
265 uint8_t depth = 24;
266 int ret;
267
268 config.max_nodes = MAX_RULES;
269 config.ext_sz = 0;
270
271 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config);
272 RTE_TEST_ASSERT(rib != NULL, "Failed to create RIB\n");
273
274 node = rte_rib_insert(rib, ip, depth);
275 RTE_TEST_ASSERT(node != NULL, "Failed to insert rule\n");
276
277 ret = rte_rib_set_nh(node, next_hop_add);
278 RTE_TEST_ASSERT(ret == 0,
279 "Failed to set rte_rib_node field\n");
280
281 node = rte_rib_lookup(rib, ip);
282 RTE_TEST_ASSERT(node != NULL, "Failed to lookup\n");
283
284 ret = rte_rib_get_nh(node, &next_hop_return);
285 RTE_TEST_ASSERT((ret == 0) && (next_hop_add == next_hop_return),
286 "Failed to get proper nexthop\n");
287
288 node = rte_rib_lookup_exact(rib, ip, depth);
289 RTE_TEST_ASSERT(node != NULL,
290 "Failed to lookup\n");
291
292 ret = rte_rib_get_nh(node, &next_hop_return);
293 RTE_TEST_ASSERT((ret == 0) && (next_hop_add == next_hop_return),
294 "Failed to get proper nexthop\n");
295
296 rte_rib_remove(rib, ip, depth);
297
298 node = rte_rib_lookup(rib, ip);
299 RTE_TEST_ASSERT(node == NULL,
300 "Lookup returns non existent rule\n");
301 node = rte_rib_lookup_exact(rib, ip, depth);
302 RTE_TEST_ASSERT(node == NULL,
303 "Lookup returns non existent rule\n");
304
305 rte_rib_free(rib);
306
307 return TEST_SUCCESS;
308 }
309
310 int32_t
test_tree_traversal(void)311 test_tree_traversal(void)
312 {
313 struct rte_rib *rib = NULL;
314 struct rte_rib_node *node;
315 struct rte_rib_conf config;
316
317 uint32_t ip1 = RTE_IPV4(10, 10, 10, 0);
318 uint32_t ip2 = RTE_IPV4(10, 10, 130, 80);
319 uint8_t depth = 30;
320
321 config.max_nodes = MAX_RULES;
322 config.ext_sz = 0;
323
324 rib = rte_rib_create(__func__, SOCKET_ID_ANY, &config);
325 RTE_TEST_ASSERT(rib != NULL, "Failed to create RIB\n");
326
327 node = rte_rib_insert(rib, ip1, depth);
328 RTE_TEST_ASSERT(node != NULL, "Failed to insert rule\n");
329
330 node = rte_rib_insert(rib, ip2, depth);
331 RTE_TEST_ASSERT(node != NULL, "Failed to insert rule\n");
332
333 node = NULL;
334 node = rte_rib_get_nxt(rib, RTE_IPV4(10, 10, 130, 0), 24, node,
335 RTE_RIB_GET_NXT_ALL);
336 RTE_TEST_ASSERT(node != NULL, "Failed to get rib_node\n");
337
338 rte_rib_free(rib);
339
340 return TEST_SUCCESS;
341 }
342
343 static struct unit_test_suite rib_tests = {
344 .suite_name = "rib autotest",
345 .setup = NULL,
346 .teardown = NULL,
347 .unit_test_cases = {
348 TEST_CASE(test_create_invalid),
349 TEST_CASE(test_free_null),
350 TEST_CASE(test_insert_invalid),
351 TEST_CASE(test_get_fn),
352 TEST_CASE(test_basic),
353 TEST_CASE(test_tree_traversal),
354 TEST_CASES_END()
355 }
356 };
357
358 static struct unit_test_suite rib_slow_tests = {
359 .suite_name = "rib slow autotest",
360 .setup = NULL,
361 .teardown = NULL,
362 .unit_test_cases = {
363 TEST_CASE(test_multiple_create),
364 TEST_CASES_END()
365 }
366 };
367
368 /*
369 * Do all unit tests.
370 */
371 static int
test_rib(void)372 test_rib(void)
373 {
374 return unit_test_suite_runner(&rib_tests);
375 }
376
377 static int
test_slow_rib(void)378 test_slow_rib(void)
379 {
380 return unit_test_suite_runner(&rib_slow_tests);
381 }
382
383 #endif /* !RTE_EXEC_ENV_WINDOWS */
384
385 REGISTER_TEST_COMMAND(rib_autotest, test_rib);
386 REGISTER_TEST_COMMAND(rib_slow_autotest, test_slow_rib);
387