LCOV - code coverage report
Current view: top level - lib - table.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 268 303 88.4 %
Date: 2015-11-19 Functions: 28 31 90.3 %

          Line data    Source code
       1             : /*
       2             :  * Routing Table functions.
       3             :  * Copyright (C) 1998 Kunihiro Ishiguro
       4             :  *
       5             :  * This file is part of GNU Zebra.
       6             :  *
       7             :  * GNU Zebra 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
      10             :  * later version.
      11             :  *
      12             :  * GNU Zebra 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.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License
      18             :  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
      19             :  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      20             :  * 02111-1307, USA.  
      21             :  */
      22             : 
      23             : #include <zebra.h>
      24             : 
      25             : #include "prefix.h"
      26             : #include "table.h"
      27             : #include "memory.h"
      28             : #include "sockunion.h"
      29             : 
      30             : static void route_node_delete (struct route_node *);
      31             : static void route_table_free (struct route_table *);
      32             : 
      33             : 
      34             : /*
      35             :  * route_table_init_with_delegate
      36             :  */
      37             : struct route_table *
      38         926 : route_table_init_with_delegate (route_table_delegate_t *delegate)
      39             : {
      40             :   struct route_table *rt;
      41             : 
      42         926 :   rt = XCALLOC (MTYPE_ROUTE_TABLE, sizeof (struct route_table));
      43         926 :   rt->delegate = delegate;
      44         926 :   return rt;
      45             : }
      46             : 
      47             : void
      48        1336 : route_table_finish (struct route_table *rt)
      49             : {
      50        1336 :   route_table_free (rt);
      51        1336 : }
      52             : 
      53             : /* Allocate new route node. */
      54             : static struct route_node *
      55        2341 : route_node_new (struct route_table *table)
      56             : {
      57        2341 :   return table->delegate->create_node (table->delegate, table);
      58             : }
      59             : 
      60             : /* Allocate new route node with prefix set. */
      61             : static struct route_node *
      62        1486 : route_node_set (struct route_table *table, struct prefix *prefix)
      63             : {
      64             :   struct route_node *node;
      65             :   
      66        1486 :   node = route_node_new (table);
      67             : 
      68        1486 :   prefix_copy (&node->p, prefix);
      69        1486 :   node->table = table;
      70             : 
      71        1486 :   return node;
      72             : }
      73             : 
      74             : /* Free route node. */
      75             : static void
      76        1624 : route_node_free (struct route_table *table, struct route_node *node)
      77             : {
      78        1624 :   table->delegate->destroy_node (table->delegate, table, node);
      79        1624 : }
      80             : 
      81             : /* Free route table. */
      82             : static void
      83        1336 : route_table_free (struct route_table *rt)
      84             : {
      85             :   struct route_node *tmp_node;
      86             :   struct route_node *node;
      87             :  
      88        1336 :   if (rt == NULL)
      89         952 :     return;
      90             : 
      91         384 :   node = rt->top;
      92             : 
      93             :   /* Bulk deletion of nodes remaining in this table.  This function is not
      94             :      called until workers have completed their dependency on this table.
      95             :      A final route_unlock_node() will not be called for these nodes. */
      96        1840 :   while (node)
      97             :     {
      98        1251 :       if (node->l_left)
      99             :         {
     100         270 :           node = node->l_left;
     101         270 :           continue;
     102             :         }
     103             : 
     104         981 :       if (node->l_right)
     105             :         {
     106         266 :           node = node->l_right;
     107         266 :           continue;
     108             :         }
     109             : 
     110         715 :       tmp_node = node;
     111         715 :       node = node->parent;
     112             : 
     113         715 :       tmp_node->table->count--;
     114         715 :       tmp_node->lock = 0;  /* to cause assert if unlocked after this */
     115         715 :       route_node_free (rt, tmp_node);
     116             : 
     117         715 :       if (node != NULL)
     118             :         {
     119         536 :           if (node->l_left == tmp_node)
     120         270 :             node->l_left = NULL;
     121             :           else
     122         266 :             node->l_right = NULL;
     123             :         }
     124             :       else
     125             :         {
     126         179 :           break;
     127             :         }
     128             :     }
     129             :  
     130         384 :   assert (rt->count == 0);
     131             : 
     132         384 :   XFREE (MTYPE_ROUTE_TABLE, rt);
     133         384 :   return;
     134             : }
     135             : 
     136             : /* Utility mask array. */
     137             : static const u_char maskbit[] =
     138             : {
     139             :   0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
     140             : };
     141             : 
     142             : /* Common prefix route genaration. */
     143             : static void
     144         875 : route_common (struct prefix *n, struct prefix *p, struct prefix *new)
     145             : {
     146             :   int i;
     147             :   u_char diff;
     148             :   u_char mask;
     149             : 
     150         875 :   u_char *np = (u_char *)&n->u.prefix;
     151         875 :   u_char *pp = (u_char *)&p->u.prefix;
     152         875 :   u_char *newp = (u_char *)&new->u.prefix;
     153             : 
     154        1715 :   for (i = 0; i < p->prefixlen / 8; i++)
     155             :     {
     156        1604 :       if (np[i] == pp[i])
     157         840 :         newp[i] = np[i];
     158             :       else
     159         764 :         break;
     160             :     }
     161             : 
     162         875 :   new->prefixlen = i * 8;
     163             : 
     164         875 :   if (new->prefixlen != p->prefixlen)
     165             :     {
     166         874 :       diff = np[i] ^ pp[i];
     167         874 :       mask = 0x80;
     168        4558 :       while (new->prefixlen < p->prefixlen && !(mask & diff))
     169             :         {
     170        2810 :           mask >>= 1;
     171        2810 :           new->prefixlen++;
     172             :         }
     173         874 :       newp[i] = np[i] & maskbit[new->prefixlen % 8];
     174             :     }
     175         875 : }
     176             : 
     177             : static void
     178        2441 : set_link (struct route_node *node, struct route_node *new)
     179             : {
     180        2441 :   unsigned int bit = prefix_bit (&new->p.u.prefix, node->p.prefixlen);
     181             : 
     182        2441 :   node->link[bit] = new;
     183        2441 :   new->parent = node;
     184        2441 : }
     185             : 
     186             : /* Lock node. */
     187             : struct route_node *
     188      786794 : route_lock_node (struct route_node *node)
     189             : {
     190      786794 :   node->lock++;
     191      786794 :   return node;
     192             : }
     193             : 
     194             : /* Unlock node. */
     195             : void
     196      785708 : route_unlock_node (struct route_node *node)
     197             : {
     198      785708 :   assert (node->lock > 0);
     199      785708 :   node->lock--;
     200             : 
     201      785708 :   if (node->lock == 0)
     202      148615 :     route_node_delete (node);
     203      785708 : }
     204             : 
     205             : /* Find matched prefix. */
     206             : struct route_node *
     207         554 : route_node_match (const struct route_table *table, const struct prefix *p)
     208             : {
     209             :   struct route_node *node;
     210             :   struct route_node *matched;
     211             : 
     212         554 :   matched = NULL;
     213         554 :   node = table->top;
     214             : 
     215             :   /* Walk down tree.  If there is matched route then store it to
     216             :      matched. */
     217        5828 :   while (node && node->p.prefixlen <= p->prefixlen && 
     218        2364 :          prefix_match (&node->p, p))
     219             :     {
     220        2358 :       if (node->info)
     221         548 :         matched = node;
     222             :       
     223        2358 :       if (node->p.prefixlen == p->prefixlen)
     224           2 :         break;
     225             :       
     226        2356 :       node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
     227             :     }
     228             : 
     229             :   /* If matched route found, return it. */
     230         554 :   if (matched)
     231         548 :     return route_lock_node (matched);
     232             : 
     233           6 :   return NULL;
     234             : }
     235             : 
     236             : struct route_node *
     237           0 : route_node_match_ipv4 (const struct route_table *table,
     238             :                        const struct in_addr *addr)
     239             : {
     240             :   struct prefix_ipv4 p;
     241             : 
     242           0 :   memset (&p, 0, sizeof (struct prefix_ipv4));
     243           0 :   p.family = AF_INET;
     244           0 :   p.prefixlen = IPV4_MAX_PREFIXLEN;
     245           0 :   p.prefix = *addr;
     246             : 
     247           0 :   return route_node_match (table, (struct prefix *) &p);
     248             : }
     249             : 
     250             : #ifdef HAVE_IPV6
     251             : struct route_node *
     252           0 : route_node_match_ipv6 (const struct route_table *table,
     253             :                        const struct in6_addr *addr)
     254             : {
     255             :   struct prefix_ipv6 p;
     256             : 
     257           0 :   memset (&p, 0, sizeof (struct prefix_ipv6));
     258           0 :   p.family = AF_INET6;
     259           0 :   p.prefixlen = IPV6_MAX_PREFIXLEN;
     260           0 :   p.prefix = *addr;
     261             : 
     262           0 :   return route_node_match (table, (struct prefix *) &p);
     263             : }
     264             : #endif /* HAVE_IPV6 */
     265             : 
     266             : /* Lookup same prefix node.  Return NULL when we can't find route. */
     267             : struct route_node *
     268       97916 : route_node_lookup (const struct route_table *table, struct prefix *p)
     269             : {
     270             :   struct route_node *node;
     271       97916 :   u_char prefixlen = p->prefixlen;
     272       97916 :   const u_char *prefix = &p->u.prefix;
     273             : 
     274       97916 :   node = table->top;
     275             : 
     276      305952 :   while (node && node->p.prefixlen <= prefixlen &&
     277      104018 :          prefix_match (&node->p, p))
     278             :     {
     279      104016 :       if (node->p.prefixlen == prefixlen)
     280       97914 :         return node->info ? route_lock_node (node) : NULL;
     281             : 
     282        6102 :       node = node->link[prefix_bit(prefix, node->p.prefixlen)];
     283             :     }
     284             : 
     285           2 :   return NULL;
     286             : }
     287             : 
     288             : /* Lookup same prefix node.  Return NULL when we can't find route. */
     289             : struct route_node *
     290      145727 : route_node_lookup_maynull (const struct route_table *table, struct prefix *p)
     291             : {
     292             :   struct route_node *node;
     293      145727 :   u_char prefixlen = p->prefixlen;
     294      145727 :   const u_char *prefix = &p->u.prefix;
     295             : 
     296      145727 :   node = table->top;
     297             : 
     298     2590152 :   while (node && node->p.prefixlen <= prefixlen &&
     299     1222178 :          prefix_match (&node->p, p))
     300             :     {
     301     1222060 :       if (node->p.prefixlen == prefixlen)
     302      145540 :         return route_lock_node (node);
     303             : 
     304     1076520 :       node = node->link[prefix_bit(prefix, node->p.prefixlen)];
     305             :     }
     306             : 
     307         187 :   return NULL;
     308             : }
     309             : 
     310             : /* Add node to routing table. */
     311             : struct route_node *
     312        1617 : route_node_get (struct route_table *const table, struct prefix *p)
     313             : {
     314             :   struct route_node *new;
     315             :   struct route_node *node;
     316             :   struct route_node *match;
     317        1617 :   u_char prefixlen = p->prefixlen;
     318        1617 :   const u_char *prefix = &p->u.prefix;
     319             : 
     320        1617 :   match = NULL;
     321        1617 :   node = table->top;
     322       11073 :   while (node && node->p.prefixlen <= prefixlen &&
     323        4251 :          prefix_match (&node->p, p))
     324             :     {
     325        3710 :       if (node->p.prefixlen == prefixlen)
     326         122 :         return route_lock_node (node);
     327             : 
     328        3588 :       match = node;
     329        3588 :       node = node->link[prefix_bit(prefix, node->p.prefixlen)];
     330             :     }
     331             : 
     332        1495 :   if (node == NULL)
     333             :     {
     334         640 :       new = route_node_set (table, p);
     335         640 :       if (match)
     336          20 :         set_link (match, new);
     337             :       else
     338         620 :         table->top = new;
     339             :     }
     340             :   else
     341             :     {
     342         855 :       new = route_node_new (table);
     343         855 :       route_common (&node->p, p, &new->p);
     344         855 :       new->p.family = p->family;
     345         855 :       new->table = table;
     346         855 :       set_link (new, node);
     347             : 
     348         855 :       if (match)
     349         720 :         set_link (match, new);
     350             :       else
     351         135 :         table->top = new;
     352             : 
     353         855 :       if (new->p.prefixlen != p->prefixlen)
     354             :         {
     355         846 :           match = new;
     356         846 :           new = route_node_set (table, p);
     357         846 :           set_link (match, new);
     358         846 :           table->count++;
     359             :         }
     360             :     }
     361        1495 :   table->count++;
     362        1495 :   route_lock_node (new);
     363             :   
     364        1495 :   return new;
     365             : }
     366             : 
     367             : /* Delete node from the routing table. */
     368             : static void
     369      149285 : route_node_delete (struct route_node *node)
     370             : {
     371             :   struct route_node *child;
     372             :   struct route_node *parent;
     373             : 
     374      149285 :   assert (node->lock == 0);
     375      149285 :   assert (node->info == NULL);
     376             : 
     377      149285 :   if (node->l_left && node->l_right)
     378      148376 :     return;
     379             : 
     380         909 :   if (node->l_left)
     381         224 :     child = node->l_left;
     382             :   else
     383         685 :     child = node->l_right;
     384             : 
     385         909 :   parent = node->parent;
     386             : 
     387         909 :   if (child)
     388         358 :     child->parent = parent;
     389             : 
     390         909 :   if (parent)
     391             :     {
     392         690 :       if (parent->l_left == node)
     393         261 :         parent->l_left = child;
     394             :       else
     395         429 :         parent->l_right = child;
     396             :     }
     397             :   else
     398         219 :     node->table->top = child;
     399             : 
     400         909 :   node->table->count--;
     401             : 
     402             :   /* WARNING: FRAGILE CODE!
     403             :    * route_node_free may have the side effect of free'ing the entire table.
     404             :    * this is permitted only if table->count got decremented to zero above,
     405             :    * because in that case parent will also be NULL, so that we won't try to
     406             :    * delete a now-stale parent below.
     407             :    *
     408             :    * cf. srcdest_srcnode_destroy() in zebra/zebra_rib.c */
     409             : 
     410         909 :   route_node_free (node->table, node);
     411             : 
     412             :   /* If parent node is stub then delete it also. */
     413         909 :   if (parent && parent->lock == 0)
     414         670 :     route_node_delete (parent);
     415             : }
     416             : 
     417             : /* Get fist node and lock it.  This function is useful when one want
     418             :    to lookup all the node exist in the routing table. */
     419             : struct route_node *
     420      111335 : route_top (struct route_table *table)
     421             : {
     422             :   /* If there is no node in the routing table return NULL. */
     423      111335 :   if (table->top == NULL)
     424         119 :     return NULL;
     425             : 
     426             :   /* Lock the top node and return it. */
     427      111216 :   route_lock_node (table->top);
     428      111216 :   return table->top;
     429             : }
     430             : 
     431             : /* Unlock current node and lock next node then return it. */
     432             : struct route_node *
     433      424957 : route_next (struct route_node *node)
     434             : {
     435             :   struct route_node *next;
     436             :   struct route_node *start;
     437             : 
     438             :   /* Node may be deleted from route_unlock_node so we have to preserve
     439             :      next node's pointer. */
     440             : 
     441      424957 :   if (node->l_left)
     442             :     {
     443      157757 :       next = node->l_left;
     444      157757 :       route_lock_node (next);
     445      157757 :       route_unlock_node (node);
     446      157757 :       return next;
     447             :     }
     448      267200 :   if (node->l_right)
     449             :     {
     450        1575 :       next = node->l_right;
     451        1575 :       route_lock_node (next);
     452        1575 :       route_unlock_node (node);
     453        1575 :       return next;
     454             :     }
     455             : 
     456      265625 :   start = node;
     457      688816 :   while (node->parent)
     458             :     {
     459      312422 :       if (node->parent->l_left == node && node->parent->l_right)
     460             :         {
     461      154856 :           next = node->parent->l_right;
     462      154856 :           route_lock_node (next);
     463      154856 :           route_unlock_node (start);
     464      154856 :           return next;
     465             :         }
     466      157566 :       node = node->parent;
     467             :     }
     468      110769 :   route_unlock_node (start);
     469      110769 :   return NULL;
     470             : }
     471             : 
     472             : /* Unlock current node and lock next node until limit. */
     473             : struct route_node *
     474           0 : route_next_until (struct route_node *node, struct route_node *limit)
     475             : {
     476             :   struct route_node *next;
     477             :   struct route_node *start;
     478             : 
     479             :   /* Node may be deleted from route_unlock_node so we have to preserve
     480             :      next node's pointer. */
     481             : 
     482           0 :   if (node->l_left)
     483             :     {
     484           0 :       next = node->l_left;
     485           0 :       route_lock_node (next);
     486           0 :       route_unlock_node (node);
     487           0 :       return next;
     488             :     }
     489           0 :   if (node->l_right)
     490             :     {
     491           0 :       next = node->l_right;
     492           0 :       route_lock_node (next);
     493           0 :       route_unlock_node (node);
     494           0 :       return next;
     495             :     }
     496             : 
     497           0 :   start = node;
     498           0 :   while (node->parent && node != limit)
     499             :     {
     500           0 :       if (node->parent->l_left == node && node->parent->l_right)
     501             :         {
     502           0 :           next = node->parent->l_right;
     503           0 :           route_lock_node (next);
     504           0 :           route_unlock_node (start);
     505           0 :           return next;
     506             :         }
     507           0 :       node = node->parent;
     508             :     }
     509           0 :   route_unlock_node (start);
     510           0 :   return NULL;
     511             : }
     512             : 
     513             : unsigned long
     514         192 : route_table_count (const struct route_table *table)
     515             : {
     516         192 :   return table->count;
     517             : }
     518             : 
     519             : /**
     520             :  * route_node_create
     521             :  *
     522             :  * Default function for creating a route node.
     523             :  */
     524             : static struct route_node *
     525         621 : route_node_create (route_table_delegate_t *delegate,
     526             :                    struct route_table *table)
     527             : {
     528             :   struct route_node *node;
     529         621 :   node = XCALLOC (MTYPE_ROUTE_NODE, sizeof (struct route_node));
     530         621 :   return node;
     531             : }
     532             : 
     533             : /**
     534             :  * route_node_destroy
     535             :  *
     536             :  * Default function for destroying a route node.
     537             :  */
     538             : static void
     539         119 : route_node_destroy (route_table_delegate_t *delegate,
     540             :                     struct route_table *table, struct route_node *node)
     541             : {
     542         119 :   XFREE (MTYPE_ROUTE_NODE, node);
     543         119 : }
     544             : 
     545             : /*
     546             :  * Default delegate.
     547             :  */
     548             : static route_table_delegate_t default_delegate = {
     549             :   .create_node = route_node_create,
     550             :   .destroy_node = route_node_destroy
     551             : };
     552             : 
     553             : /*
     554             :  * route_table_init
     555             :  */
     556             : struct route_table *
     557         361 : route_table_init (void)
     558             : {
     559         361 :   return route_table_init_with_delegate (&default_delegate);
     560             : }
     561             : 
     562             : /**
     563             :  * route_table_prefix_iter_cmp
     564             :  *
     565             :  * Compare two prefixes according to the order in which they appear in
     566             :  * an iteration over a tree.
     567             :  * 
     568             :  * @return -1 if p1 occurs before p2 (p1 < p2)
     569             :  *          0 if the prefixes are identical (p1 == p2)
     570             :  *         +1 if p1 occurs after p2 (p1 > p2)
     571             :  */
     572             : int
     573          50 : route_table_prefix_iter_cmp (struct prefix *p1, struct prefix *p2)
     574             : {
     575             :   struct prefix common_space;
     576          50 :   struct prefix *common = &common_space;
     577             : 
     578          50 :   if (p1->prefixlen <= p2->prefixlen)
     579             :     {
     580          38 :       if (prefix_match (p1, p2))
     581             :         {
     582             : 
     583             :           /*
     584             :            * p1 contains p2, or is equal to it.
     585             :            */
     586          18 :           return (p1->prefixlen == p2->prefixlen) ? 0 : -1;
     587             :         }
     588             :     }
     589             :   else
     590             :     {
     591             : 
     592             :       /*
     593             :        * Check if p2 contains p1.
     594             :        */
     595          12 :       if (prefix_match (p2, p1))
     596          12 :           return 1;
     597             :     }
     598             : 
     599          20 :   route_common (p1, p2, common);
     600          20 :   assert (common->prefixlen < p1->prefixlen);
     601          20 :   assert (common->prefixlen < p2->prefixlen);
     602             : 
     603             :   /*
     604             :    * Both prefixes are longer than the common prefix.
     605             :    *
     606             :    * We need to check the bit after the common prefixlen to determine
     607             :    * which one comes later.
     608             :    */
     609          20 :   if (prefix_bit (&p1->u.prefix, common->prefixlen))
     610             :     {
     611             : 
     612             :       /*
     613             :        * We branch to the right to get to p1 from the common prefix.
     614             :        */
     615          15 :       assert (!prefix_bit (&p2->u.prefix, common->prefixlen));
     616          15 :       return 1;
     617             :     }
     618             : 
     619             :   /*
     620             :    * We branch to the right to get to p2 from the common prefix.
     621             :    */
     622           5 :   assert (prefix_bit (&p2->u.prefix, common->prefixlen));
     623           5 :   return -1;
     624             : }
     625             : 
     626             : /*
     627             :  * route_get_subtree_next
     628             :  *
     629             :  * Helper function that returns the first node that follows the nodes
     630             :  * in the sub-tree under 'node' in iteration order.
     631             :  */
     632             : static struct route_node *
     633           3 : route_get_subtree_next (struct route_node *node)
     634             : {
     635           5 :   while (node->parent)
     636             :     {
     637           4 :       if (node->parent->l_left == node && node->parent->l_right)
     638           2 :         return node->parent->l_right;
     639             : 
     640           2 :       node = node->parent;
     641             :     }
     642             : 
     643           1 :   return NULL;
     644             : }
     645             : 
     646             : /**
     647             :  * route_table_get_next_internal
     648             :  *
     649             :  * Helper function to find the node that occurs after the given prefix in
     650             :  * order of iteration.
     651             :  *
     652             :  * @see route_table_get_next
     653             :  */
     654             : static struct route_node *
     655          18 : route_table_get_next_internal (const struct route_table *table,
     656             :                                struct prefix *p)
     657             : {
     658             :   struct route_node *node, *tmp_node;
     659             :   u_char prefixlen;
     660             :   int cmp;
     661             : 
     662          18 :   prefixlen = p->prefixlen;
     663             : 
     664          18 :   node = table->top;
     665             : 
     666          56 :   while (node)
     667             :     {
     668             :       int match;
     669             : 
     670          38 :       if (node->p.prefixlen < p->prefixlen)
     671          23 :         match = prefix_match (&node->p, p);
     672             :       else
     673          15 :         match = prefix_match (p, &node->p);
     674             : 
     675          38 :       if (match)
     676             :         {
     677          36 :           if (node->p.prefixlen == p->prefixlen)
     678             :             {
     679             : 
     680             :               /*
     681             :                * The prefix p exists in the tree, just return the next
     682             :                * node.
     683             :                */
     684          11 :               route_lock_node (node);
     685          11 :               node = route_next (node);
     686          11 :               if (node)
     687           9 :                 route_unlock_node (node);
     688             : 
     689          11 :               return (node);
     690             :             }
     691             : 
     692          25 :           if (node->p.prefixlen > p->prefixlen)
     693             :             {
     694             : 
     695             :               /*
     696             :                * Node is in the subtree of p, and hence greater than p.
     697             :                */
     698           2 :               return node;
     699             :             }
     700             : 
     701             :           /*
     702             :            * p is in the sub-tree under node.
     703             :            */
     704          23 :           tmp_node = node->link[prefix_bit (&p->u.prefix, node->p.prefixlen)];
     705             : 
     706          23 :           if (tmp_node)
     707             :             {
     708          20 :               node = tmp_node;
     709          20 :               continue;
     710             :             }
     711             : 
     712             :           /*
     713             :            * There are no nodes in the direction where p should be. If
     714             :            * node has a right child, then it must be greater than p.
     715             :            */
     716           3 :           if (node->l_right)
     717           1 :             return node->l_right;
     718             : 
     719             :           /*
     720             :            * No more children to follow, go upwards looking for the next
     721             :            * node.
     722             :            */
     723           2 :           return route_get_subtree_next (node);
     724             :         }
     725             : 
     726             :       /*
     727             :        * Neither node prefix nor 'p' contains the other.
     728             :        */
     729           2 :       cmp = route_table_prefix_iter_cmp (&node->p, p);
     730           2 :       if (cmp > 0)
     731             :         {
     732             : 
     733             :           /*
     734             :            * Node follows p in iteration order. Return it.
     735             :            */
     736           1 :           return node;
     737             :         }
     738             : 
     739           1 :       assert (cmp < 0);
     740             : 
     741             :       /*
     742             :        * Node and the subtree under it come before prefix p in
     743             :        * iteration order. Prefix p and its sub-tree are not present in
     744             :        * the tree. Go upwards and find the first node that follows the
     745             :        * subtree. That node will also succeed p.
     746             :        */
     747           1 :       return route_get_subtree_next (node);
     748             :     }
     749             : 
     750           0 :   return NULL;
     751             : }
     752             : 
     753             : /**
     754             :  * route_table_get_next
     755             :  *
     756             :  * Find the node that occurs after the given prefix in order of
     757             :  * iteration.
     758             :  */
     759             : struct route_node *
     760          18 : route_table_get_next (const struct route_table *table, struct prefix *p)
     761             : {
     762             :   struct route_node *node;
     763             : 
     764          18 :   node = route_table_get_next_internal (table, p);
     765          18 :   if (node)
     766             :     {
     767          15 :       assert (route_table_prefix_iter_cmp (&node->p, p) > 0);
     768          15 :       route_lock_node (node);
     769             :     }
     770          18 :   return node;
     771             : }
     772             : 
     773             : /*
     774             :  * route_table_iter_init
     775             :  */
     776             : void
     777          24 : route_table_iter_init (route_table_iter_t * iter, struct route_table *table)
     778             : {
     779          24 :   memset (iter, 0, sizeof (*iter));
     780          24 :   iter->state = RT_ITER_STATE_INIT;
     781          24 :   iter->table = table;
     782          24 : }
     783             : 
     784             : /*
     785             :  * route_table_iter_pause
     786             :  *
     787             :  * Pause an iteration over the table. This allows the iteration to be
     788             :  * resumed point after arbitrary additions/deletions from the table.
     789             :  * An iteration can be resumed by just calling route_table_iter_next()
     790             :  * on the iterator.
     791             :  */
     792             : void
     793           8 : route_table_iter_pause (route_table_iter_t * iter)
     794             : {
     795           8 :   switch (iter->state)
     796             :     {
     797             : 
     798             :     case RT_ITER_STATE_INIT:
     799             :     case RT_ITER_STATE_PAUSED:
     800             :     case RT_ITER_STATE_DONE:
     801           1 :       return;
     802             : 
     803             :     case RT_ITER_STATE_ITERATING:
     804             : 
     805             :       /*
     806             :        * Save the prefix that we are currently at. The next call to
     807             :        * route_table_iter_next() will return the node after this prefix
     808             :        * in the tree.
     809             :        */
     810           7 :       prefix_copy (&iter->pause_prefix, &iter->current->p);
     811           7 :       route_unlock_node (iter->current);
     812           7 :       iter->current = NULL;
     813           7 :       iter->state = RT_ITER_STATE_PAUSED;
     814           7 :       return;
     815             : 
     816             :     default:
     817           0 :       assert (0);
     818             :     }
     819             : 
     820             : }
     821             : 
     822             : /*
     823             :  * route_table_iter_cleanup
     824             :  *
     825             :  * Release any resources held by the iterator.
     826             :  */
     827             : void
     828          24 : route_table_iter_cleanup (route_table_iter_t * iter)
     829             : {
     830          24 :   if (iter->state == RT_ITER_STATE_ITERATING)
     831             :     {
     832           9 :       route_unlock_node (iter->current);
     833           9 :       iter->current = NULL;
     834             :     }
     835          24 :   assert (!iter->current);
     836             : 
     837             :   /*
     838             :    * Set the state to RT_ITER_STATE_DONE to make any
     839             :    * route_table_iter_next() calls on this iterator return NULL.
     840             :    */
     841          24 :   iter->state = RT_ITER_STATE_DONE;
     842          24 : }

Generated by: LCOV version 1.10