Annotation of embedaddon/quagga/lib/table.c, revision 1.1.1.2

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>