3 * Copyright (C) 2012 OSR.
5 * This file is part of Quagga
7 * Quagga is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
12 * Quagga is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 * Information that is kept for each node in the radix tree.
32 typedef struct test_node_t_
{
35 * Human readable representation of the string. Allocated using
41 struct thread_master
*master
;
46 * Add the given prefix (passed in as a string) to the given table.
48 static void add_node(struct route_table
*table
, const char *prefix_str
)
52 struct route_node
*rn
;
56 if (str2prefix_ipv4(prefix_str
, &p
) <= 0) {
60 rn
= route_node_get(table
, (struct prefix
*)&p
);
66 node
= malloc(sizeof(test_node_t
));
68 node
->prefix_str
= strdup(prefix_str
);
69 assert(node
->prefix_str
);
76 * Convenience function to add a bunch of nodes together.
78 * The arguments must be prefixes in string format, with a NULL as the
81 static void add_nodes(struct route_table
*table
, ...)
86 va_start(arglist
, table
);
88 prefix
= va_arg(arglist
, char *);
90 add_node(table
, prefix
);
91 prefix
= va_arg(arglist
, char *);
100 * Recursive function to print a route node and its children.
104 static void print_subtree(struct route_node
*rn
, const char *legend
,
107 char buf
[PREFIX2STR_BUFFER
];
111 * Print this node first.
113 for (i
= 0; i
< indent_level
; i
++) {
117 prefix2str(&rn
->p
, buf
, sizeof(buf
));
118 printf("%s: %s", legend
, buf
);
120 printf(" (internal)");
124 print_subtree(rn
->l_left
, "Left", indent_level
+ 1);
127 print_subtree(rn
->l_right
, "Right", indent_level
+ 1);
134 * Function that prints out the internal structure of a route table.
136 static void print_table(struct route_table
*table
)
138 struct route_node
*rn
;
143 printf("<Empty Table>\n");
147 print_subtree(rn
, "Top", 0);
153 * Remove all nodes from the given table.
155 static void clear_table(struct route_table
*table
)
157 route_table_iter_t iter
;
158 struct route_node
*rn
;
161 route_table_iter_init(&iter
, table
);
163 while ((rn
= route_table_iter_next(&iter
))) {
169 route_unlock_node(rn
);
170 free(node
->prefix_str
);
174 route_table_iter_cleanup(&iter
);
176 assert(table
->top
== NULL
);
180 * verify_next_by_iterating
182 * Iterate over the tree to make sure that the first prefix after
183 * target_pfx is the expected one. Note that target_pfx may not be
184 * present in the tree.
186 static void verify_next_by_iterating(struct route_table
*table
,
187 struct prefix
*target_pfx
,
188 struct prefix
*next_pfx
)
190 route_table_iter_t iter
;
191 struct route_node
*rn
;
193 route_table_iter_init(&iter
, table
);
194 while ((rn
= route_table_iter_next(&iter
))) {
195 if (route_table_prefix_iter_cmp(&rn
->p
, target_pfx
) > 0) {
196 assert(!prefix_cmp(&rn
->p
, next_pfx
));
205 route_table_iter_cleanup(&iter
);
211 * Verifies that route_table_get_next() returns the expected result
212 * (result) for the prefix string 'target'.
214 static void verify_next(struct route_table
*table
, const char *target
,
217 struct prefix_ipv4 target_pfx
, next_pfx
;
218 struct route_node
*rn
;
219 char result_buf
[PREFIX2STR_BUFFER
];
221 if (str2prefix_ipv4(target
, &target_pfx
) <= 0) {
225 rn
= route_table_get_next(table
, (struct prefix
*)&target_pfx
);
227 prefix2str(&rn
->p
, result_buf
, sizeof(result_buf
));
229 snprintf(result_buf
, sizeof(result_buf
), "(Null)");
234 printf("Verifying successor of %s. Expected: %s, Result: %s\n", target
,
235 next
? next
: "(Null)", result_buf
);
239 verify_next_by_iterating(table
, (struct prefix
*)&target_pfx
,
246 if (str2prefix_ipv4(next
, &next_pfx
) <= 0) {
250 if (prefix_cmp(&rn
->p
, (struct prefix
*)&next_pfx
)) {
253 route_unlock_node(rn
);
255 verify_next_by_iterating(table
, (struct prefix
*)&target_pfx
,
256 (struct prefix
*)&next_pfx
);
262 static void test_get_next(void)
264 struct route_table
*table
;
266 printf("\n\nTesting route_table_get_next()\n");
267 table
= route_table_init();
270 * Target exists in tree, but has no successor.
272 add_nodes(table
, "1.0.1.0/24", NULL
);
273 verify_next(table
, "1.0.1.0/24", NULL
);
277 * Target exists in tree, and there is a node in its left subtree.
279 add_nodes(table
, "1.0.1.0/24", "1.0.1.0/25", NULL
);
280 verify_next(table
, "1.0.1.0/24", "1.0.1.0/25");
284 * Target exists in tree, and there is a node in its right subtree.
286 add_nodes(table
, "1.0.1.0/24", "1.0.1.128/25", NULL
);
287 verify_next(table
, "1.0.1.0/24", "1.0.1.128/25");
291 * Target exists in the tree, next node is outside subtree.
293 add_nodes(table
, "1.0.1.0/24", "1.1.0.0/16", NULL
);
294 verify_next(table
, "1.0.1.0/24", "1.1.0.0/16");
298 * The target node does not exist in the tree for all the test cases
303 * There is no successor in the tree.
305 add_nodes(table
, "1.0.0.0/16", NULL
);
306 verify_next(table
, "1.0.1.0/24", NULL
);
310 * There exists a node that would be in the target's left subtree.
312 add_nodes(table
, "1.0.0.0/16", "1.0.1.0/25", NULL
);
313 verify_next(table
, "1.0.1.0/24", "1.0.1.0/25");
317 * There exists a node would be in the target's right subtree.
319 add_nodes(table
, "1.0.0.0/16", "1.0.1.128/25", NULL
);
320 verify_next(table
, "1.0.1.0/24", "1.0.1.128/25");
324 * A search for the target reaches a node where there are no child
325 * nodes in the direction of the target (left), but the node has a
328 add_nodes(table
, "1.0.0.0/16", "1.0.128.0/17", NULL
);
329 verify_next(table
, "1.0.0.0/17", "1.0.128.0/17");
333 * A search for the target reaches a node with no children. We have
334 * to go upwards in the tree to find a successor.
336 add_nodes(table
, "1.0.0.0/16", "1.0.0.0/24", "1.0.1.0/24",
337 "1.0.128.0/17", NULL
);
338 verify_next(table
, "1.0.1.0/25", "1.0.128.0/17");
342 * A search for the target reaches a node where neither the node nor
343 * the target prefix contain each other.
345 * In first case below the node succeeds the target.
347 * In the second case, the node comes before the target, so we have
348 * to go up the tree looking for a successor.
350 add_nodes(table
, "1.0.0.0/16", "1.0.1.0/24", NULL
);
351 verify_next(table
, "1.0.0.0/24", "1.0.1.0/24");
354 add_nodes(table
, "1.0.0.0/16", "1.0.0.0/24", "1.0.1.0/25",
355 "1.0.128.0/17", NULL
);
356 verify_next(table
, "1.0.1.128/25", "1.0.128.0/17");
359 route_table_finish(table
);
363 * verify_prefix_iter_cmp
365 static void verify_prefix_iter_cmp(const char *p1
, const char *p2
,
368 struct prefix_ipv4 p1_pfx
, p2_pfx
;
371 if (str2prefix_ipv4(p1
, &p1_pfx
) <= 0) {
375 if (str2prefix_ipv4(p2
, &p2_pfx
) <= 0) {
379 result
= route_table_prefix_iter_cmp((struct prefix
*)&p1_pfx
,
380 (struct prefix
*)&p2_pfx
);
382 printf("Verifying cmp(%s, %s) returns %d\n", p1
, p2
, exp_result
);
384 assert(exp_result
== result
);
387 * Also check the reverse comparision.
389 result
= route_table_prefix_iter_cmp((struct prefix
*)&p2_pfx
,
390 (struct prefix
*)&p1_pfx
);
393 exp_result
= -exp_result
;
396 printf("Verifying cmp(%s, %s) returns %d\n", p1
, p2
, exp_result
);
397 assert(result
== exp_result
);
401 * test_prefix_iter_cmp
403 * Tests comparision of prefixes according to order of iteration.
405 static void test_prefix_iter_cmp(void)
407 printf("\n\nTesting route_table_prefix_iter_cmp()\n");
409 verify_prefix_iter_cmp("1.0.0.0/8", "1.0.0.0/8", 0);
411 verify_prefix_iter_cmp("1.0.0.0/8", "1.0.0.0/16", -1);
413 verify_prefix_iter_cmp("1.0.0.0/16", "1.128.0.0/16", -1);
417 * verify_iter_with_pause
419 * Iterates over a tree using two methods: 'normal' iteration, and an
420 * iterator that pauses at each node. Verifies that the two methods
421 * yield the same results.
423 static void verify_iter_with_pause(struct route_table
*table
)
425 unsigned long num_nodes
;
426 struct route_node
*rn
, *iter_rn
;
427 route_table_iter_t iter_space
;
428 route_table_iter_t
*iter
= &iter_space
;
430 route_table_iter_init(iter
, table
);
433 for (rn
= route_top(table
); rn
; rn
= route_next(rn
)) {
435 route_table_iter_pause(iter
);
437 assert(iter
->current
== NULL
);
438 if (route_table_iter_started(iter
)) {
439 assert(iter
->state
== RT_ITER_STATE_PAUSED
);
441 assert(rn
== table
->top
);
442 assert(iter
->state
== RT_ITER_STATE_INIT
);
445 iter_rn
= route_table_iter_next(iter
);
448 * Make sure both iterations return the same node.
450 assert(rn
== iter_rn
);
453 assert(num_nodes
== route_table_count(table
));
455 route_table_iter_pause(iter
);
456 iter_rn
= route_table_iter_next(iter
);
458 assert(iter_rn
== NULL
);
459 assert(iter
->state
== RT_ITER_STATE_DONE
);
461 assert(route_table_iter_next(iter
) == NULL
);
462 assert(iter
->state
== RT_ITER_STATE_DONE
);
464 route_table_iter_cleanup(iter
);
467 printf("Verified pausing iteration on tree with %lu nodes\n",
474 static void test_iter_pause(void)
476 struct route_table
*table
;
478 const char *prefixes
[] = {"1.0.1.0/24", "1.0.1.0/25", "1.0.1.128/25",
479 "1.0.2.0/24", "2.0.0.0/8"};
481 num_prefixes
= sizeof(prefixes
) / sizeof(prefixes
[0]);
483 printf("\n\nTesting that route_table_iter_pause() works as expected\n");
484 table
= route_table_init();
485 for (i
= 0; i
< num_prefixes
; i
++) {
486 add_nodes(table
, prefixes
[i
], NULL
);
489 verify_iter_with_pause(table
);
492 route_table_finish(table
);
498 static void run_tests(void)
500 test_prefix_iter_cmp();