back to topotato report
topotato coverage report
Current view: top level - lib - table.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 204 316 64.6 %
Date: 2023-11-16 17:19:14 Functions: 25 67 37.3 %

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

Generated by: LCOV version v1.16-topotato