Annotation of embedaddon/quagga/tests/table_test.c, revision 1.1.1.1

1.1       misho       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>