1 /* $QuaggaId: Format:%an, %ai, %h$ $
4 * Copyright (C) 2012 OSR.
6 * This file is part of Quagga
8 * Quagga is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
13 * Quagga is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with Quagga; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
32 * Information that is kept for each node in the radix tree.
34 typedef struct test_node_t_
38 * Human readable representation of the string. Allocated using
44 struct thread_master *master;
49 * Add the given prefix (passed in as a string) to the given table.
52 add_node (struct route_table *table, const char *prefix_str)
56 struct route_node *rn;
60 if (str2prefix_ipv4 (prefix_str, &p) <= 0)
65 rn = route_node_get (table, (struct prefix *) &p);
72 node = malloc (sizeof (test_node_t));
74 node->prefix_str = strdup (prefix_str);
75 assert (node->prefix_str);
82 * Convenience function to add a bunch of nodes together.
84 * The arguments must be prefixes in string format, with a NULL as the
88 add_nodes (struct route_table *table, ...)
93 va_start (arglist, table);
95 prefix = va_arg (arglist, char *);
98 add_node (table, prefix);
99 prefix = va_arg (arglist, char *);
108 * Recursive function to print a route node and its children.
113 print_subtree (struct route_node *rn, const char *legend, int indent_level)
115 char buf[INET_ADDRSTRLEN + 4];
119 * Print this node first.
121 for (i = 0; i < indent_level; i++)
126 prefix2str (&rn->p, buf, sizeof (buf));
127 printf ("%s: %s", legend, buf);
130 printf (" (internal)");
135 print_subtree (rn->l_left, "Left", indent_level + 1);
139 print_subtree (rn->l_right, "Right", indent_level + 1);
146 * Function that prints out the internal structure of a route table.
149 print_table (struct route_table *table)
151 struct route_node *rn;
157 printf ("<Empty Table>\n");
161 print_subtree (rn, "Top", 0);
167 * Remove all nodes from the given table.
170 clear_table (struct route_table *table)
172 route_table_iter_t iter;
173 struct route_node *rn;
176 route_table_iter_init (&iter, table);
178 while ((rn = route_table_iter_next (&iter)))
186 route_unlock_node (rn);
187 free (node->prefix_str);
191 route_table_iter_cleanup (&iter);
193 assert (table->top == NULL);
197 * verify_next_by_iterating
199 * Iterate over the tree to make sure that the first prefix after
200 * target_pfx is the expected one. Note that target_pfx may not be
201 * present in the tree.
204 verify_next_by_iterating (struct route_table *table,
205 struct prefix *target_pfx, struct prefix *next_pfx)
207 route_table_iter_t iter;
208 struct route_node *rn;
210 route_table_iter_init (&iter, table);
211 while ((rn = route_table_iter_next (&iter)))
213 if (route_table_prefix_iter_cmp (&rn->p, target_pfx) > 0)
215 assert (!prefix_cmp (&rn->p, next_pfx));
225 route_table_iter_cleanup (&iter);
231 * Verifies that route_table_get_next() returns the expected result
232 * (result) for the prefix string 'target'.
235 verify_next (struct route_table *table, const char *target, const char *next)
237 struct prefix_ipv4 target_pfx, next_pfx;
238 struct route_node *rn;
239 char result_buf[INET_ADDRSTRLEN + 4];
241 if (str2prefix_ipv4 (target, &target_pfx) <= 0)
246 rn = route_table_get_next (table, (struct prefix *) &target_pfx);
249 prefix2str (&rn->p, result_buf, sizeof (result_buf));
253 snprintf (result_buf, sizeof (result_buf), "(Null)");
258 printf ("Verifying successor of %s. Expected: %s, Result: %s\n", target,
259 next ? next : "(Null)", result_buf);
264 verify_next_by_iterating (table, (struct prefix *) &target_pfx, NULL);
270 if (str2prefix_ipv4 (next, &next_pfx) <= 0)
275 if (prefix_cmp (&rn->p, (struct prefix *) &next_pfx))
279 route_unlock_node (rn);
281 verify_next_by_iterating (table, (struct prefix *) &target_pfx,
282 (struct prefix *) &next_pfx);
291 struct route_table *table;
293 printf ("\n\nTesting route_table_get_next()\n");
294 table = route_table_init ();
297 * Target exists in tree, but has no successor.
299 add_nodes (table, "1.0.1.0/24", NULL);
300 verify_next (table, "1.0.1.0/24", NULL);
304 * Target exists in tree, and there is a node in its left subtree.
306 add_nodes (table, "1.0.1.0/24", "1.0.1.0/25", NULL);
307 verify_next (table, "1.0.1.0/24", "1.0.1.0/25");
311 * Target exists in tree, and there is a node in its right subtree.
313 add_nodes (table, "1.0.1.0/24", "1.0.1.128/25", NULL);
314 verify_next (table, "1.0.1.0/24", "1.0.1.128/25");
318 * Target exists in the tree, next node is outside subtree.
320 add_nodes (table, "1.0.1.0/24", "1.1.0.0/16", NULL);
321 verify_next (table, "1.0.1.0/24", "1.1.0.0/16");
325 * The target node does not exist in the tree for all the test cases
330 * There is no successor in the tree.
332 add_nodes (table, "1.0.0.0/16", NULL);
333 verify_next (table, "1.0.1.0/24", NULL);
337 * There exists a node that would be in the target's left subtree.
339 add_nodes (table, "1.0.0.0/16", "1.0.1.0/25", NULL);
340 verify_next (table, "1.0.1.0/24", "1.0.1.0/25");
344 * There exists a node would be in the target's right subtree.
346 add_nodes (table, "1.0.0.0/16", "1.0.1.128/25", NULL);
347 verify_next (table, "1.0.1.0/24", "1.0.1.128/25");
351 * A search for the target reaches a node where there are no child
352 * nodes in the direction of the target (left), but the node has a
355 add_nodes (table, "1.0.0.0/16", "1.0.128.0/17", NULL);
356 verify_next (table, "1.0.0.0/17", "1.0.128.0/17");
360 * A search for the target reaches a node with no children. We have
361 * to go upwards in the tree to find a successor.
363 add_nodes (table, "1.0.0.0/16", "1.0.0.0/24", "1.0.1.0/24",
364 "1.0.128.0/17", NULL);
365 verify_next (table, "1.0.1.0/25", "1.0.128.0/17");
369 * A search for the target reaches a node where neither the node nor
370 * the target prefix contain each other.
372 * In first case below the node succeeds the target.
374 * In the second case, the node comes before the target, so we have
375 * to go up the tree looking for a successor.
377 add_nodes (table, "1.0.0.0/16", "1.0.1.0/24", NULL);
378 verify_next (table, "1.0.0.0/24", "1.0.1.0/24");
381 add_nodes (table, "1.0.0.0/16", "1.0.0.0/24", "1.0.1.0/25",
382 "1.0.128.0/17", NULL);
383 verify_next (table, "1.0.1.128/25", "1.0.128.0/17");
386 route_table_finish (table);
390 * verify_prefix_iter_cmp
393 verify_prefix_iter_cmp (const char *p1, const char *p2, int exp_result)
395 struct prefix_ipv4 p1_pfx, p2_pfx;
398 if (str2prefix_ipv4 (p1, &p1_pfx) <= 0)
403 if (str2prefix_ipv4 (p2, &p2_pfx) <= 0)
408 result = route_table_prefix_iter_cmp ((struct prefix *) &p1_pfx,
409 (struct prefix *) &p2_pfx);
411 printf ("Verifying cmp(%s, %s) returns %d\n", p1, p2, exp_result);
413 assert (exp_result == result);
416 * Also check the reverse comparision.
418 result = route_table_prefix_iter_cmp ((struct prefix *) &p2_pfx,
419 (struct prefix *) &p1_pfx);
423 exp_result = -exp_result;
426 printf ("Verifying cmp(%s, %s) returns %d\n", p1, p2, exp_result);
427 assert (result == exp_result);
431 * test_prefix_iter_cmp
433 * Tests comparision of prefixes according to order of iteration.
436 test_prefix_iter_cmp ()
438 printf ("\n\nTesting route_table_prefix_iter_cmp()\n");
440 verify_prefix_iter_cmp ("1.0.0.0/8", "1.0.0.0/8", 0);
442 verify_prefix_iter_cmp ("1.0.0.0/8", "1.0.0.0/16", -1);
444 verify_prefix_iter_cmp ("1.0.0.0/16", "1.128.0.0/16", -1);
448 * verify_iter_with_pause
450 * Iterates over a tree using two methods: 'normal' iteration, and an
451 * iterator that pauses at each node. Verifies that the two methods
452 * yield the same results.
455 verify_iter_with_pause (struct route_table *table)
457 unsigned long num_nodes;
458 struct route_node *rn, *iter_rn;
459 route_table_iter_t iter_space;
460 route_table_iter_t *iter = &iter_space;
462 route_table_iter_init (iter, table);
465 for (rn = route_top (table); rn; rn = route_next (rn))
468 route_table_iter_pause (iter);
470 assert (iter->current == NULL);
471 if (route_table_iter_started (iter))
473 assert (iter->state == RT_ITER_STATE_PAUSED);
477 assert (rn == table->top);
478 assert (iter->state == RT_ITER_STATE_INIT);
481 iter_rn = route_table_iter_next (iter);
484 * Make sure both iterations return the same node.
486 assert (rn == iter_rn);
489 assert (num_nodes == route_table_count (table));
491 route_table_iter_pause (iter);
492 iter_rn = route_table_iter_next (iter);
494 assert (iter_rn == NULL);
495 assert (iter->state == RT_ITER_STATE_DONE);
497 assert (route_table_iter_next (iter) == NULL);
498 assert (iter->state == RT_ITER_STATE_DONE);
500 route_table_iter_cleanup (iter);
503 printf ("Verified pausing iteration on tree with %lu nodes\n", num_nodes);
510 test_iter_pause (void)
512 struct route_table *table;
514 const char *prefixes[] = {
522 num_prefixes = sizeof (prefixes) / sizeof (prefixes[0]);
524 printf ("\n\nTesting that route_table_iter_pause() works as expected\n");
525 table = route_table_init ();
526 for (i = 0; i < num_prefixes; i++)
528 add_nodes (table, prefixes[i], NULL);
531 verify_iter_with_pause (table);
534 route_table_finish (table);
543 test_prefix_iter_cmp ();