xref: /dpdk/app/test/test_rib.c (revision 97b914f4e715565d53d38ac6e04815b9be5e58a9)
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 "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
16 test_rib(void)
17 {
18 	printf("rib not supported on Windows, skipping test\n");
19 	return TEST_SKIPPED;
20 }
21 
22 static int
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
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
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
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
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
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
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
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
372 test_rib(void)
373 {
374 	return unit_test_suite_runner(&rib_tests);
375 }
376 
377 static int
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