1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2012 OSR.
6 * This file is part of Quagga
17 * Information that is kept for each node in the radix tree.
19 typedef struct test_node_t_
{
22 * Human readable representation of the string. Allocated using
28 struct thread_master
*master
;
33 * Add the given prefix (passed in as a string) to the given table.
35 static void add_node(struct route_table
*table
, const char *prefix_str
)
39 struct route_node
*rn
;
43 if (str2prefix_ipv4(prefix_str
, &p
) <= 0) {
47 rn
= route_node_get(table
, (struct prefix
*)&p
);
53 node
= malloc(sizeof(test_node_t
));
55 node
->prefix_str
= strdup(prefix_str
);
56 assert(node
->prefix_str
);
63 * Convenience function to add a bunch of nodes together.
65 * The arguments must be prefixes in string format, with a NULL as the
68 static void add_nodes(struct route_table
*table
, ...)
73 va_start(arglist
, table
);
75 prefix
= va_arg(arglist
, char *);
77 add_node(table
, prefix
);
78 prefix
= va_arg(arglist
, char *);
87 * Recursive function to print a route node and its children.
91 static void print_subtree(struct route_node
*rn
, const char *legend
,
97 * Print this node first.
99 for (i
= 0; i
< indent_level
; i
++) {
103 printfrr("%s: %pFX", legend
, &rn
->p
);
105 printf(" (internal)");
109 print_subtree(rn
->l_left
, "Left", indent_level
+ 1);
112 print_subtree(rn
->l_right
, "Right", indent_level
+ 1);
119 * Function that prints out the internal structure of a route table.
121 static void print_table(struct route_table
*table
)
123 struct route_node
*rn
;
128 printf("<Empty Table>\n");
132 print_subtree(rn
, "Top", 0);
138 * Remove all nodes from the given table.
140 static void clear_table(struct route_table
*table
)
142 route_table_iter_t iter
;
143 struct route_node
*rn
;
146 route_table_iter_init(&iter
, table
);
148 while ((rn
= route_table_iter_next(&iter
))) {
154 route_unlock_node(rn
);
155 free(node
->prefix_str
);
159 route_table_iter_cleanup(&iter
);
161 assert(table
->top
== NULL
);
165 * verify_next_by_iterating
167 * Iterate over the tree to make sure that the first prefix after
168 * target_pfx is the expected one. Note that target_pfx may not be
169 * present in the tree.
171 static void verify_next_by_iterating(struct route_table
*table
,
172 struct prefix
*target_pfx
,
173 struct prefix
*next_pfx
)
175 route_table_iter_t iter
;
176 struct route_node
*rn
;
178 route_table_iter_init(&iter
, table
);
179 while ((rn
= route_table_iter_next(&iter
))) {
180 if (route_table_prefix_iter_cmp(&rn
->p
, target_pfx
) > 0) {
181 assert(!prefix_cmp(&rn
->p
, next_pfx
));
190 route_table_iter_cleanup(&iter
);
196 * Verifies that route_table_get_next() returns the expected result
197 * (result) for the prefix string 'target'.
199 static void verify_next(struct route_table
*table
, const char *target
,
202 struct prefix_ipv4 target_pfx
, next_pfx
;
203 struct route_node
*rn
;
204 char result_buf
[PREFIX2STR_BUFFER
];
206 if (str2prefix_ipv4(target
, &target_pfx
) <= 0) {
210 rn
= route_table_get_next(table
, (struct prefix
*)&target_pfx
);
212 prefix2str(&rn
->p
, result_buf
, sizeof(result_buf
));
214 snprintf(result_buf
, sizeof(result_buf
), "(Null)");
219 printf("Verifying successor of %s. Expected: %s, Result: %s\n", target
,
220 next
? next
: "(Null)", result_buf
);
224 verify_next_by_iterating(table
, (struct prefix
*)&target_pfx
,
231 if (str2prefix_ipv4(next
, &next_pfx
) <= 0) {
235 if (prefix_cmp(&rn
->p
, (struct prefix
*)&next_pfx
)) {
238 route_unlock_node(rn
);
240 verify_next_by_iterating(table
, (struct prefix
*)&target_pfx
,
241 (struct prefix
*)&next_pfx
);
247 static void test_get_next(void)
249 struct route_table
*table
;
251 printf("\n\nTesting route_table_get_next()\n");
252 table
= route_table_init();
255 * Target exists in tree, but has no successor.
257 add_nodes(table
, "1.0.1.0/24", NULL
);
258 verify_next(table
, "1.0.1.0/24", NULL
);
262 * Target exists in tree, and there is a node in its left subtree.
264 add_nodes(table
, "1.0.1.0/24", "1.0.1.0/25", NULL
);
265 verify_next(table
, "1.0.1.0/24", "1.0.1.0/25");
269 * Target exists in tree, and there is a node in its right subtree.
271 add_nodes(table
, "1.0.1.0/24", "1.0.1.128/25", NULL
);
272 verify_next(table
, "1.0.1.0/24", "1.0.1.128/25");
276 * Target exists in the tree, next node is outside subtree.
278 add_nodes(table
, "1.0.1.0/24", "1.1.0.0/16", NULL
);
279 verify_next(table
, "1.0.1.0/24", "1.1.0.0/16");
283 * The target node does not exist in the tree for all the test cases
288 * There is no successor in the tree.
290 add_nodes(table
, "1.0.0.0/16", NULL
);
291 verify_next(table
, "1.0.1.0/24", NULL
);
295 * There exists a node that would be in the target's left subtree.
297 add_nodes(table
, "1.0.0.0/16", "1.0.1.0/25", NULL
);
298 verify_next(table
, "1.0.1.0/24", "1.0.1.0/25");
302 * There exists a node would be in the target's right subtree.
304 add_nodes(table
, "1.0.0.0/16", "1.0.1.128/25", NULL
);
305 verify_next(table
, "1.0.1.0/24", "1.0.1.128/25");
309 * A search for the target reaches a node where there are no child
310 * nodes in the direction of the target (left), but the node has a
313 add_nodes(table
, "1.0.0.0/16", "1.0.128.0/17", NULL
);
314 verify_next(table
, "1.0.0.0/17", "1.0.128.0/17");
318 * A search for the target reaches a node with no children. We have
319 * to go upwards in the tree to find a successor.
321 add_nodes(table
, "1.0.0.0/16", "1.0.0.0/24", "1.0.1.0/24",
322 "1.0.128.0/17", NULL
);
323 verify_next(table
, "1.0.1.0/25", "1.0.128.0/17");
327 * A search for the target reaches a node where neither the node nor
328 * the target prefix contain each other.
330 * In first case below the node succeeds the target.
332 * In the second case, the node comes before the target, so we have
333 * to go up the tree looking for a successor.
335 add_nodes(table
, "1.0.0.0/16", "1.0.1.0/24", NULL
);
336 verify_next(table
, "1.0.0.0/24", "1.0.1.0/24");
339 add_nodes(table
, "1.0.0.0/16", "1.0.0.0/24", "1.0.1.0/25",
340 "1.0.128.0/17", NULL
);
341 verify_next(table
, "1.0.1.128/25", "1.0.128.0/17");
344 route_table_finish(table
);
348 * verify_prefix_iter_cmp
350 static void verify_prefix_iter_cmp(const char *p1
, const char *p2
,
353 struct prefix_ipv4 p1_pfx
, p2_pfx
;
356 if (str2prefix_ipv4(p1
, &p1_pfx
) <= 0) {
360 if (str2prefix_ipv4(p2
, &p2_pfx
) <= 0) {
364 result
= route_table_prefix_iter_cmp((struct prefix
*)&p1_pfx
,
365 (struct prefix
*)&p2_pfx
);
367 printf("Verifying cmp(%s, %s) returns %d\n", p1
, p2
, exp_result
);
369 assert(exp_result
== result
);
372 * Also check the reverse comparison.
374 result
= route_table_prefix_iter_cmp((struct prefix
*)&p2_pfx
,
375 (struct prefix
*)&p1_pfx
);
378 exp_result
= -exp_result
;
381 printf("Verifying cmp(%s, %s) returns %d\n", p1
, p2
, exp_result
);
382 assert(result
== exp_result
);
386 * test_prefix_iter_cmp
388 * Tests comparison of prefixes according to order of iteration.
390 static void test_prefix_iter_cmp(void)
392 printf("\n\nTesting route_table_prefix_iter_cmp()\n");
394 verify_prefix_iter_cmp("1.0.0.0/8", "1.0.0.0/8", 0);
396 verify_prefix_iter_cmp("1.0.0.0/8", "1.0.0.0/16", -1);
398 verify_prefix_iter_cmp("1.0.0.0/16", "1.128.0.0/16", -1);
402 * verify_iter_with_pause
404 * Iterates over a tree using two methods: 'normal' iteration, and an
405 * iterator that pauses at each node. Verifies that the two methods
406 * yield the same results.
408 static void verify_iter_with_pause(struct route_table
*table
)
410 unsigned long num_nodes
;
411 struct route_node
*rn
, *iter_rn
;
412 route_table_iter_t iter_space
;
413 route_table_iter_t
*iter
= &iter_space
;
415 route_table_iter_init(iter
, table
);
418 for (rn
= route_top(table
); rn
; rn
= route_next(rn
)) {
420 route_table_iter_pause(iter
);
422 assert(iter
->current
== NULL
);
423 if (route_table_iter_started(iter
)) {
424 assert(iter
->state
== RT_ITER_STATE_PAUSED
);
426 assert(rn
== table
->top
);
427 assert(iter
->state
== RT_ITER_STATE_INIT
);
430 iter_rn
= route_table_iter_next(iter
);
433 * Make sure both iterations return the same node.
435 assert(rn
== iter_rn
);
438 assert(num_nodes
== route_table_count(table
));
440 route_table_iter_pause(iter
);
441 iter_rn
= route_table_iter_next(iter
);
443 assert(iter_rn
== NULL
);
444 assert(iter
->state
== RT_ITER_STATE_DONE
);
446 assert(route_table_iter_next(iter
) == NULL
);
447 assert(iter
->state
== RT_ITER_STATE_DONE
);
449 route_table_iter_cleanup(iter
);
452 printf("Verified pausing iteration on tree with %lu nodes\n",
459 static void test_iter_pause(void)
461 struct route_table
*table
;
463 const char *prefixes
[] = {"1.0.1.0/24", "1.0.1.0/25", "1.0.1.128/25",
464 "1.0.2.0/24", "2.0.0.0/8"};
466 num_prefixes
= array_size(prefixes
);
468 printf("\n\nTesting that route_table_iter_pause() works as expected\n");
469 table
= route_table_init();
470 for (i
= 0; i
< num_prefixes
; i
++) {
471 add_nodes(table
, prefixes
[i
], NULL
);
474 verify_iter_with_pause(table
);
477 route_table_finish(table
);
483 static void run_tests(void)
485 test_prefix_iter_cmp();