back to topotato report
topotato coverage report
Current view: top level - lib - table.c (source / functions) Hit Total Coverage
Test: test_bgp_rmap_extcommunity_none.py::TestBGPExtCommunity Lines: 208 320 65.0 %
Date: 2023-02-24 18:37:31 Functions: 25 36 69.4 %

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

Generated by: LCOV version v1.16-topotato