LCOV - code coverage report
Current view: top level - tests/testcases/zebra - test_table.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 176 185 95.1 %
Date: 2015-11-19 Functions: 14 14 100.0 %

          Line data    Source code
       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          29 : 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          29 :   assert (prefix_str);
      59             : 
      60          29 :   if (str2prefix_ipv4 (prefix_str, &p) <= 0)
      61             :     {
      62           0 :       assert (0);
      63             :     }
      64             : 
      65          29 :   rn = route_node_get (table, (struct prefix *) &p);
      66          29 :   if (rn->info)
      67             :     {
      68           0 :       assert (0);
      69             :       return;
      70             :     }
      71             : 
      72          29 :   node = malloc (sizeof (test_node_t));
      73          29 :   assert (node);
      74          29 :   node->prefix_str = strdup (prefix_str);
      75          29 :   assert (node->prefix_str);
      76          29 :   rn->info = node;
      77          29 : }
      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          16 : add_nodes (struct route_table *table, ...)
      89             : {
      90             :   va_list arglist;
      91             :   char *prefix;
      92             : 
      93          16 :   va_start (arglist, table);
      94             : 
      95          16 :   prefix = va_arg (arglist, char *);
      96          61 :   while (prefix)
      97             :     {
      98          29 :       add_node (table, prefix);
      99          29 :       prefix = va_arg (arglist, char *);
     100             :     }
     101             : 
     102          16 :   va_end (arglist);
     103          16 : }
     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          34 : 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          66 :   for (i = 0; i < indent_level; i++)
     122             :     {
     123          32 :       printf ("  ");
     124             :     }
     125             : 
     126          34 :   prefix2str (&rn->p, buf, sizeof (buf));
     127          34 :   printf ("%s: %s", legend, buf);
     128          34 :   if (!rn->info)
     129             :     {
     130           5 :       printf (" (internal)");
     131             :     }
     132          34 :   printf ("\n");
     133          34 :   if (rn->l_left)
     134             :     {
     135          12 :       print_subtree (rn->l_left, "Left", indent_level + 1);
     136             :     }
     137          34 :   if (rn->l_right)
     138             :     {
     139          10 :       print_subtree (rn->l_right, "Right", indent_level + 1);
     140             :     }
     141          34 : }
     142             : 
     143             : /*
     144             :  * print_table
     145             :  *
     146             :  * Function that prints out the internal structure of a route table.
     147             :  */
     148             : static void
     149          12 : print_table (struct route_table *table)
     150             : {
     151             :   struct route_node *rn;
     152             : 
     153          12 :   rn = table->top;
     154             : 
     155          12 :   if (!rn)
     156             :     {
     157           0 :       printf ("<Empty Table>\n");
     158           0 :       return;
     159             :     }
     160             : 
     161          12 :   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          12 : 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          12 :   route_table_iter_init (&iter, table);
     177             : 
     178          58 :   while ((rn = route_table_iter_next (&iter)))
     179             :     {
     180          34 :       node = rn->info;
     181          34 :       if (!node)
     182             :         {
     183           5 :           continue;
     184             :         }
     185          29 :       rn->info = NULL;
     186          29 :       route_unlock_node (rn);
     187          29 :       free (node->prefix_str);
     188          29 :       free (node);
     189             :     }
     190             : 
     191          12 :   route_table_iter_cleanup (&iter);
     192             : 
     193          12 :   assert (table->top == NULL);
     194          12 : }
     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          11 : 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          11 :   route_table_iter_init (&iter, table);
     211          11 :   while ((rn = route_table_iter_next (&iter)))
     212             :     {
     213          27 :       if (route_table_prefix_iter_cmp (&rn->p, target_pfx) > 0)
     214             :         {
     215           9 :           assert (!prefix_cmp (&rn->p, next_pfx));
     216           9 :           break;
     217             :         }
     218             :     }
     219             : 
     220          11 :   if (!rn)
     221             :     {
     222           2 :       assert (!next_pfx);
     223             :     }
     224             : 
     225          11 :   route_table_iter_cleanup (&iter);
     226          11 : }
     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          11 : 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          11 :   if (str2prefix_ipv4 (target, &target_pfx) <= 0)
     242             :     {
     243           0 :       assert (0);
     244             :     }
     245             : 
     246          11 :   rn = route_table_get_next (table, (struct prefix *) &target_pfx);
     247          11 :   if (rn)
     248             :     {
     249           9 :       prefix2str (&rn->p, result_buf, sizeof (result_buf));
     250             :     }
     251             :   else
     252             :     {
     253           2 :       snprintf (result_buf, sizeof (result_buf), "(Null)");
     254             :     }
     255             : 
     256          11 :   printf ("\n");
     257          11 :   print_table (table);
     258          11 :   printf ("Verifying successor of %s. Expected: %s, Result: %s\n", target,
     259             :           next ? next : "(Null)", result_buf);
     260             : 
     261          11 :   if (!rn)
     262             :     {
     263           2 :       assert (!next);
     264           2 :       verify_next_by_iterating (table, (struct prefix *) &target_pfx, NULL);
     265           2 :       return;
     266             :     }
     267             : 
     268           9 :   assert (next);
     269             : 
     270           9 :   if (str2prefix_ipv4 (next, &next_pfx) <= 0)
     271             :     {
     272           0 :       assert (0);
     273             :     }
     274             : 
     275           9 :   if (prefix_cmp (&rn->p, (struct prefix *) &next_pfx))
     276             :     {
     277           0 :       assert (0);
     278             :     }
     279           9 :   route_unlock_node (rn);
     280             : 
     281           9 :   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           1 : test_get_next (void)
     290             : {
     291             :   struct route_table *table;
     292             : 
     293           1 :   printf ("\n\nTesting route_table_get_next()\n");
     294           1 :   table = route_table_init ();
     295             : 
     296             :   /*
     297             :    * Target exists in tree, but has no successor.
     298             :    */
     299           1 :   add_nodes (table, "1.0.1.0/24", NULL);
     300           1 :   verify_next (table, "1.0.1.0/24", NULL);
     301           1 :   clear_table (table);
     302             : 
     303             :   /*
     304             :    * Target exists in tree, and there is a node in its left subtree.
     305             :    */
     306           1 :   add_nodes (table, "1.0.1.0/24", "1.0.1.0/25", NULL);
     307           1 :   verify_next (table, "1.0.1.0/24", "1.0.1.0/25");
     308           1 :   clear_table (table);
     309             : 
     310             :   /*
     311             :    * Target exists in tree, and there is a node in its right subtree.
     312             :    */
     313           1 :   add_nodes (table, "1.0.1.0/24", "1.0.1.128/25", NULL);
     314           1 :   verify_next (table, "1.0.1.0/24", "1.0.1.128/25");
     315           1 :   clear_table (table);
     316             : 
     317             :   /*
     318             :    * Target exists in the tree, next node is outside subtree.
     319             :    */
     320           1 :   add_nodes (table, "1.0.1.0/24", "1.1.0.0/16", NULL);
     321           1 :   verify_next (table, "1.0.1.0/24", "1.1.0.0/16");
     322           1 :   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           1 :   add_nodes (table, "1.0.0.0/16", NULL);
     333           1 :   verify_next (table, "1.0.1.0/24", NULL);
     334           1 :   clear_table (table);
     335             : 
     336             :   /*
     337             :    * There exists a node that would be in the target's left subtree.
     338             :    */
     339           1 :   add_nodes (table, "1.0.0.0/16", "1.0.1.0/25", NULL);
     340           1 :   verify_next (table, "1.0.1.0/24", "1.0.1.0/25");
     341           1 :   clear_table (table);
     342             : 
     343             :   /*
     344             :    * There exists a node would be in the target's right subtree.
     345             :    */
     346           1 :   add_nodes (table, "1.0.0.0/16", "1.0.1.128/25", NULL);
     347           1 :   verify_next (table, "1.0.1.0/24", "1.0.1.128/25");
     348           1 :   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           1 :   add_nodes (table, "1.0.0.0/16", "1.0.128.0/17", NULL);
     356           1 :   verify_next (table, "1.0.0.0/17", "1.0.128.0/17");
     357           1 :   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           1 :   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           1 :   verify_next (table, "1.0.1.0/25", "1.0.128.0/17");
     366           1 :   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           1 :   add_nodes (table, "1.0.0.0/16", "1.0.1.0/24", NULL);
     378           1 :   verify_next (table, "1.0.0.0/24", "1.0.1.0/24");
     379           1 :   clear_table (table);
     380             : 
     381           1 :   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           1 :   verify_next (table, "1.0.1.128/25", "1.0.128.0/17");
     384           1 :   clear_table (table);
     385             : 
     386           1 :   route_table_finish (table);
     387           1 : }
     388             : 
     389             : /*
     390             :  * verify_prefix_iter_cmp
     391             :  */
     392             : static void
     393           3 : 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           3 :   if (str2prefix_ipv4 (p1, &p1_pfx) <= 0)
     399             :     {
     400           0 :       assert (0);
     401             :     }
     402             : 
     403           3 :   if (str2prefix_ipv4 (p2, &p2_pfx) <= 0)
     404             :     {
     405           0 :       assert (0);
     406             :     }
     407             : 
     408           3 :   result = route_table_prefix_iter_cmp ((struct prefix *) &p1_pfx,
     409             :                                         (struct prefix *) &p2_pfx);
     410             : 
     411           3 :   printf ("Verifying cmp(%s, %s) returns %d\n", p1, p2, exp_result);
     412             : 
     413           3 :   assert (exp_result == result);
     414             : 
     415             :   /*
     416             :    * Also check the reverse comparision.
     417             :    */
     418           3 :   result = route_table_prefix_iter_cmp ((struct prefix *) &p2_pfx,
     419             :                                         (struct prefix *) &p1_pfx);
     420             : 
     421           3 :   if (exp_result)
     422             :     {
     423           2 :       exp_result = -exp_result;
     424             :     }
     425             : 
     426           3 :   printf ("Verifying cmp(%s, %s) returns %d\n", p1, p2, exp_result);
     427           3 :   assert (result == exp_result);
     428           3 : }
     429             : 
     430             : /*
     431             :  * test_prefix_iter_cmp
     432             :  *
     433             :  * Tests comparision of prefixes according to order of iteration.
     434             :  */
     435             : static void
     436           1 : test_prefix_iter_cmp ()
     437             : {
     438           1 :   printf ("\n\nTesting route_table_prefix_iter_cmp()\n");
     439             : 
     440           1 :   verify_prefix_iter_cmp ("1.0.0.0/8", "1.0.0.0/8", 0);
     441             : 
     442           1 :   verify_prefix_iter_cmp ("1.0.0.0/8", "1.0.0.0/16", -1);
     443             : 
     444           1 :   verify_prefix_iter_cmp ("1.0.0.0/16", "1.128.0.0/16", -1);
     445           1 : }
     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           1 : 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           1 :   route_table_iter_t *iter = &iter_space;
     461             : 
     462           1 :   route_table_iter_init (iter, table);
     463           1 :   num_nodes = 0;
     464             : 
     465           8 :   for (rn = route_top (table); rn; rn = route_next (rn))
     466             :     {
     467           7 :       num_nodes++;
     468           7 :       route_table_iter_pause (iter);
     469             : 
     470           7 :       assert (iter->current == NULL);
     471           7 :       if (route_table_iter_started (iter))
     472             :         {
     473           6 :           assert (iter->state == RT_ITER_STATE_PAUSED);
     474             :         }
     475             :       else
     476             :         {
     477           1 :           assert (rn == table->top);
     478           1 :           assert (iter->state == RT_ITER_STATE_INIT);
     479             :         }
     480             : 
     481           7 :       iter_rn = route_table_iter_next (iter);
     482             : 
     483             :       /*
     484             :        * Make sure both iterations return the same node.
     485             :        */
     486           7 :       assert (rn == iter_rn);
     487             :     }
     488             : 
     489           1 :   assert (num_nodes == route_table_count (table));
     490             : 
     491           1 :   route_table_iter_pause (iter);
     492           1 :   iter_rn = route_table_iter_next (iter);
     493             : 
     494           1 :   assert (iter_rn == NULL);
     495           1 :   assert (iter->state == RT_ITER_STATE_DONE);
     496             : 
     497           1 :   assert (route_table_iter_next (iter) == NULL);
     498           1 :   assert (iter->state == RT_ITER_STATE_DONE);
     499             : 
     500           1 :   route_table_iter_cleanup (iter);
     501             : 
     502           1 :   print_table (table);
     503           1 :   printf ("Verified pausing iteration on tree with %lu nodes\n", num_nodes);
     504           1 : }
     505             : 
     506             : /*
     507             :  * test_iter_pause
     508             :  */
     509             : static void
     510           1 : test_iter_pause (void)
     511             : {
     512             :   struct route_table *table;
     513             :   int i, num_prefixes;
     514           1 :   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           1 :   num_prefixes = sizeof (prefixes) / sizeof (prefixes[0]);
     523             : 
     524           1 :   printf ("\n\nTesting that route_table_iter_pause() works as expected\n");
     525           1 :   table = route_table_init ();
     526           6 :   for (i = 0; i < num_prefixes; i++)
     527             :     {
     528           5 :       add_nodes (table, prefixes[i], NULL);
     529             :     }
     530             : 
     531           1 :   verify_iter_with_pause (table);
     532             : 
     533           1 :   clear_table (table);
     534           1 :   route_table_finish (table);
     535           1 : }
     536             : 
     537             : /*
     538             :  * run_tests
     539             :  */
     540             : static void
     541           1 : run_tests (void)
     542             : {
     543           1 :   test_prefix_iter_cmp ();
     544           1 :   test_get_next ();
     545           1 :   test_iter_pause ();
     546           1 : }
     547             : 
     548             : /*
     549             :  * main
     550             :  */
     551             : int
     552           1 : main (void)
     553             : {
     554           1 :   run_tests ();
     555             : }

Generated by: LCOV version 1.10