File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / tests / table_test.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:54:40 2013 UTC (11 years, 3 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, v0_99_22p0, v0_99_22, HEAD
0.99.22

    1: /* $QuaggaId: Format:%an, %ai, %h$ $
    2:  *
    3:  * Routing table test
    4:  * Copyright (C) 2012 OSR.
    5:  *
    6:  * This file is part of Quagga
    7:  *
    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
   11:  * later version.
   12:  *
   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.
   17:  *
   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
   21:  * 02111-1307, USA.
   22:  */
   23: 
   24: #include <zebra.h>
   25: 
   26: #include "prefix.h"
   27: #include "table.h"
   28: 
   29: /*
   30:  * test_node_t
   31:  *
   32:  * Information that is kept for each node in the radix tree.
   33:  */
   34: typedef struct test_node_t_
   35: {
   36: 
   37:   /*
   38:    * Human readable representation of the string. Allocated using
   39:    * malloc()/dup().
   40:    */
   41:   char *prefix_str;
   42: } test_node_t;
   43: 
   44: struct thread_master *master;
   45: 
   46: /*
   47:  * add_node
   48:  *
   49:  * Add the given prefix (passed in as a string) to the given table.
   50:  */
   51: static void
   52: add_node (struct route_table *table, const char *prefix_str)
   53: {
   54:   struct prefix_ipv4 p;
   55:   test_node_t *node;
   56:   struct route_node *rn;
   57: 
   58:   assert (prefix_str);
   59: 
   60:   if (str2prefix_ipv4 (prefix_str, &p) <= 0)
   61:     {
   62:       assert (0);
   63:     }
   64: 
   65:   rn = route_node_get (table, (struct prefix *) &p);
   66:   if (rn->info)
   67:     {
   68:       assert (0);
   69:       return;
   70:     }
   71: 
   72:   node = malloc (sizeof (test_node_t));
   73:   assert (node);
   74:   node->prefix_str = strdup (prefix_str);
   75:   assert (node->prefix_str);
   76:   rn->info = node;
   77: }
   78: 
   79: /*
   80:  * add_nodes
   81:  *
   82:  * Convenience function to add a bunch of nodes together.
   83:  *
   84:  * The arguments must be prefixes in string format, with a NULL as the
   85:  * last argument.
   86:  */
   87: static void
   88: add_nodes (struct route_table *table, ...)
   89: {
   90:   va_list arglist;
   91:   char *prefix;
   92: 
   93:   va_start (arglist, table);
   94: 
   95:   prefix = va_arg (arglist, char *);
   96:   while (prefix)
   97:     {
   98:       add_node (table, prefix);
   99:       prefix = va_arg (arglist, char *);
  100:     }
  101: 
  102:   va_end (arglist);
  103: }
  104: 
  105: /*
  106:  * print_subtree
  107:  *
  108:  * Recursive function to print a route node and its children.
  109:  *
  110:  * @see print_table
  111:  */
  112: static void
  113: print_subtree (struct route_node *rn, const char *legend, int indent_level)
  114: {
  115:   char buf[INET_ADDRSTRLEN + 4];
  116:   int i;
  117: 
  118:   /*
  119:    * Print this node first.
  120:    */
  121:   for (i = 0; i < indent_level; i++)
  122:     {
  123:       printf ("  ");
  124:     }
  125: 
  126:   prefix2str (&rn->p, buf, sizeof (buf));
  127:   printf ("%s: %s", legend, buf);
  128:   if (!rn->info)
  129:     {
  130:       printf (" (internal)");
  131:     }
  132:   printf ("\n");
  133:   if (rn->l_left)
  134:     {
  135:       print_subtree (rn->l_left, "Left", indent_level + 1);
  136:     }
  137:   if (rn->l_right)
  138:     {
  139:       print_subtree (rn->l_right, "Right", indent_level + 1);
  140:     }
  141: }
  142: 
  143: /*
  144:  * print_table
  145:  *
  146:  * Function that prints out the internal structure of a route table.
  147:  */
  148: static void
  149: print_table (struct route_table *table)
  150: {
  151:   struct route_node *rn;
  152: 
  153:   rn = table->top;
  154: 
  155:   if (!rn)
  156:     {
  157:       printf ("<Empty Table>\n");
  158:       return;
  159:     }
  160: 
  161:   print_subtree (rn, "Top", 0);
  162: }
  163: 
  164: /*
  165:  * clear_table
  166:  *
  167:  * Remove all nodes from the given table.
  168:  */
  169: static void
  170: clear_table (struct route_table *table)
  171: {
  172:   route_table_iter_t iter;
  173:   struct route_node *rn;
  174:   test_node_t *node;
  175: 
  176:   route_table_iter_init (&iter, table);
  177: 
  178:   while ((rn = route_table_iter_next (&iter)))
  179:     {
  180:       node = rn->info;
  181:       if (!node)
  182: 	{
  183: 	  continue;
  184: 	}
  185:       rn->info = NULL;
  186:       route_unlock_node (rn);
  187:       free (node->prefix_str);
  188:       free (node);
  189:     }
  190: 
  191:   route_table_iter_cleanup (&iter);
  192: 
  193:   assert (table->top == NULL);
  194: }
  195: 
  196: /*
  197:  * verify_next_by_iterating
  198:  *
  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.
  202:  */
  203: static void
  204: verify_next_by_iterating (struct route_table *table,
  205: 			  struct prefix *target_pfx, struct prefix *next_pfx)
  206: {
  207:   route_table_iter_t iter;
  208:   struct route_node *rn;
  209: 
  210:   route_table_iter_init (&iter, table);
  211:   while ((rn = route_table_iter_next (&iter)))
  212:     {
  213:       if (route_table_prefix_iter_cmp (&rn->p, target_pfx) > 0)
  214: 	{
  215: 	  assert (!prefix_cmp (&rn->p, next_pfx));
  216: 	  break;
  217: 	}
  218:     }
  219: 
  220:   if (!rn)
  221:     {
  222:       assert (!next_pfx);
  223:     }
  224: 
  225:   route_table_iter_cleanup (&iter);
  226: }
  227: 
  228: /*
  229:  * verify_next
  230:  *
  231:  * Verifies that route_table_get_next() returns the expected result
  232:  * (result) for the prefix string 'target'.
  233:  */
  234: static void
  235: verify_next (struct route_table *table, const char *target, const char *next)
  236: {
  237:   struct prefix_ipv4 target_pfx, next_pfx;
  238:   struct route_node *rn;
  239:   char result_buf[INET_ADDRSTRLEN + 4];
  240: 
  241:   if (str2prefix_ipv4 (target, &target_pfx) <= 0)
  242:     {
  243:       assert (0);
  244:     }
  245: 
  246:   rn = route_table_get_next (table, (struct prefix *) &target_pfx);
  247:   if (rn)
  248:     {
  249:       prefix2str (&rn->p, result_buf, sizeof (result_buf));
  250:     }
  251:   else
  252:     {
  253:       snprintf (result_buf, sizeof (result_buf), "(Null)");
  254:     }
  255: 
  256:   printf ("\n");
  257:   print_table (table);
  258:   printf ("Verifying successor of %s. Expected: %s, Result: %s\n", target,
  259: 	  next ? next : "(Null)", result_buf);
  260: 
  261:   if (!rn)
  262:     {
  263:       assert (!next);
  264:       verify_next_by_iterating (table, (struct prefix *) &target_pfx, NULL);
  265:       return;
  266:     }
  267: 
  268:   assert (next);
  269: 
  270:   if (str2prefix_ipv4 (next, &next_pfx) <= 0)
  271:     {
  272:       assert (0);
  273:     }
  274: 
  275:   if (prefix_cmp (&rn->p, (struct prefix *) &next_pfx))
  276:     {
  277:       assert (0);
  278:     }
  279:   route_unlock_node (rn);
  280: 
  281:   verify_next_by_iterating (table, (struct prefix *) &target_pfx,
  282: 			    (struct prefix *) &next_pfx);
  283: }
  284: 
  285: /*
  286:  * test_get_next
  287:  */
  288: static void
  289: test_get_next (void)
  290: {
  291:   struct route_table *table;
  292: 
  293:   printf ("\n\nTesting route_table_get_next()\n");
  294:   table = route_table_init ();
  295: 
  296:   /*
  297:    * Target exists in tree, but has no successor.
  298:    */
  299:   add_nodes (table, "1.0.1.0/24", NULL);
  300:   verify_next (table, "1.0.1.0/24", NULL);
  301:   clear_table (table);
  302: 
  303:   /*
  304:    * Target exists in tree, and there is a node in its left subtree.
  305:    */
  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");
  308:   clear_table (table);
  309: 
  310:   /*
  311:    * Target exists in tree, and there is a node in its right subtree.
  312:    */
  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");
  315:   clear_table (table);
  316: 
  317:   /*
  318:    * Target exists in the tree, next node is outside subtree.
  319:    */
  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");
  322:   clear_table (table);
  323: 
  324:   /*
  325:    * The target node does not exist in the tree for all the test cases
  326:    * below this point.
  327:    */
  328: 
  329:   /*
  330:    * There is no successor in the tree.
  331:    */
  332:   add_nodes (table, "1.0.0.0/16", NULL);
  333:   verify_next (table, "1.0.1.0/24", NULL);
  334:   clear_table (table);
  335: 
  336:   /*
  337:    * There exists a node that would be in the target's left subtree.
  338:    */
  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");
  341:   clear_table (table);
  342: 
  343:   /*
  344:    * There exists a node would be in the target's right subtree.
  345:    */
  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");
  348:   clear_table (table);
  349: 
  350:   /*
  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
  353:    * right child.
  354:    */
  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");
  357:   clear_table (table);
  358: 
  359:   /*
  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.
  362:    */
  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");
  366:   clear_table (table);
  367: 
  368:   /*
  369:    * A search for the target reaches a node where neither the node nor
  370:    * the target prefix contain each other.
  371:    *
  372:    * In first case below the node succeeds the target.
  373:    *
  374:    * In the second case, the node comes before the target, so we have
  375:    * to go up the tree looking for a successor.
  376:    */
  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");
  379:   clear_table (table);
  380: 
  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");
  384:   clear_table (table);
  385: 
  386:   route_table_finish (table);
  387: }
  388: 
  389: /*
  390:  * verify_prefix_iter_cmp
  391:  */
  392: static void
  393: verify_prefix_iter_cmp (const char *p1, const char *p2, int exp_result)
  394: {
  395:   struct prefix_ipv4 p1_pfx, p2_pfx;
  396:   int result;
  397: 
  398:   if (str2prefix_ipv4 (p1, &p1_pfx) <= 0)
  399:     {
  400:       assert (0);
  401:     }
  402: 
  403:   if (str2prefix_ipv4 (p2, &p2_pfx) <= 0)
  404:     {
  405:       assert (0);
  406:     }
  407: 
  408:   result = route_table_prefix_iter_cmp ((struct prefix *) &p1_pfx,
  409: 					(struct prefix *) &p2_pfx);
  410: 
  411:   printf ("Verifying cmp(%s, %s) returns %d\n", p1, p2, exp_result);
  412: 
  413:   assert (exp_result == result);
  414: 
  415:   /*
  416:    * Also check the reverse comparision.
  417:    */
  418:   result = route_table_prefix_iter_cmp ((struct prefix *) &p2_pfx,
  419: 					(struct prefix *) &p1_pfx);
  420: 
  421:   if (exp_result)
  422:     {
  423:       exp_result = -exp_result;
  424:     }
  425: 
  426:   printf ("Verifying cmp(%s, %s) returns %d\n", p1, p2, exp_result);
  427:   assert (result == exp_result);
  428: }
  429: 
  430: /*
  431:  * test_prefix_iter_cmp
  432:  *
  433:  * Tests comparision of prefixes according to order of iteration.
  434:  */
  435: static void
  436: test_prefix_iter_cmp ()
  437: {
  438:   printf ("\n\nTesting route_table_prefix_iter_cmp()\n");
  439: 
  440:   verify_prefix_iter_cmp ("1.0.0.0/8", "1.0.0.0/8", 0);
  441: 
  442:   verify_prefix_iter_cmp ("1.0.0.0/8", "1.0.0.0/16", -1);
  443: 
  444:   verify_prefix_iter_cmp ("1.0.0.0/16", "1.128.0.0/16", -1);
  445: }
  446: 
  447: /*
  448:  * verify_iter_with_pause
  449:  *
  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.
  453:  */
  454: static void
  455: verify_iter_with_pause (struct route_table *table)
  456: {
  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;
  461: 
  462:   route_table_iter_init (iter, table);
  463:   num_nodes = 0;
  464: 
  465:   for (rn = route_top (table); rn; rn = route_next (rn))
  466:     {
  467:       num_nodes++;
  468:       route_table_iter_pause (iter);
  469: 
  470:       assert (iter->current == NULL);
  471:       if (route_table_iter_started (iter))
  472: 	{
  473: 	  assert (iter->state == RT_ITER_STATE_PAUSED);
  474: 	}
  475:       else
  476: 	{
  477: 	  assert (rn == table->top);
  478: 	  assert (iter->state == RT_ITER_STATE_INIT);
  479: 	}
  480: 
  481:       iter_rn = route_table_iter_next (iter);
  482: 
  483:       /*
  484:        * Make sure both iterations return the same node.
  485:        */
  486:       assert (rn == iter_rn);
  487:     }
  488: 
  489:   assert (num_nodes == route_table_count (table));
  490: 
  491:   route_table_iter_pause (iter);
  492:   iter_rn = route_table_iter_next (iter);
  493: 
  494:   assert (iter_rn == NULL);
  495:   assert (iter->state == RT_ITER_STATE_DONE);
  496: 
  497:   assert (route_table_iter_next (iter) == NULL);
  498:   assert (iter->state == RT_ITER_STATE_DONE);
  499: 
  500:   route_table_iter_cleanup (iter);
  501: 
  502:   print_table (table);
  503:   printf ("Verified pausing iteration on tree with %lu nodes\n", num_nodes);
  504: }
  505: 
  506: /*
  507:  * test_iter_pause
  508:  */
  509: static void
  510: test_iter_pause (void)
  511: {
  512:   struct route_table *table;
  513:   int i, num_prefixes;
  514:   const char *prefixes[] = {
  515:     "1.0.1.0/24",
  516:     "1.0.1.0/25",
  517:     "1.0.1.128/25",
  518:     "1.0.2.0/24",
  519:     "2.0.0.0/8"
  520:   };
  521: 
  522:   num_prefixes = sizeof (prefixes) / sizeof (prefixes[0]);
  523: 
  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++)
  527:     {
  528:       add_nodes (table, prefixes[i], NULL);
  529:     }
  530: 
  531:   verify_iter_with_pause (table);
  532: 
  533:   clear_table (table);
  534:   route_table_finish (table);
  535: }
  536: 
  537: /*
  538:  * run_tests
  539:  */
  540: static void
  541: run_tests (void)
  542: {
  543:   test_prefix_iter_cmp ();
  544:   test_get_next ();
  545:   test_iter_pause ();
  546: }
  547: 
  548: /*
  549:  * main
  550:  */
  551: int
  552: main (void)
  553: {
  554:   run_tests ();
  555: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>