Annotation of embedaddon/quagga/bgpd/bgp_table.c, revision 1.1
1.1 ! misho 1: /* BGP routing table
! 2: Copyright (C) 1998, 2001 Kunihiro Ishiguro
! 3:
! 4: This file is part of GNU Zebra.
! 5:
! 6: GNU Zebra is free software; you can redistribute it and/or modify it
! 7: under the terms of the GNU General Public License as published by the
! 8: Free Software Foundation; either version 2, or (at your option) any
! 9: later version.
! 10:
! 11: GNU Zebra is distributed in the hope that it will be useful, but
! 12: WITHOUT ANY WARRANTY; without even the implied warranty of
! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 14: General Public License for more details.
! 15:
! 16: You should have received a copy of the GNU General Public License
! 17: along with GNU Zebra; see the file COPYING. If not, write to the Free
! 18: Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
! 19: 02111-1307, USA. */
! 20:
! 21: #include <zebra.h>
! 22:
! 23: #include "prefix.h"
! 24: #include "memory.h"
! 25: #include "sockunion.h"
! 26: #include "vty.h"
! 27:
! 28: #include "bgpd/bgpd.h"
! 29: #include "bgpd/bgp_table.h"
! 30:
! 31: static void bgp_node_delete (struct bgp_node *);
! 32: static void bgp_table_free (struct bgp_table *);
! 33:
! 34: struct bgp_table *
! 35: bgp_table_init (afi_t afi, safi_t safi)
! 36: {
! 37: struct bgp_table *rt;
! 38:
! 39: rt = XCALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table));
! 40:
! 41: bgp_table_lock(rt);
! 42: rt->type = BGP_TABLE_MAIN;
! 43: rt->afi = afi;
! 44: rt->safi = safi;
! 45:
! 46: return rt;
! 47: }
! 48:
! 49: void
! 50: bgp_table_lock (struct bgp_table *rt)
! 51: {
! 52: rt->lock++;
! 53: }
! 54:
! 55: void
! 56: bgp_table_unlock (struct bgp_table *rt)
! 57: {
! 58: assert (rt->lock > 0);
! 59: rt->lock--;
! 60:
! 61: if (rt->lock == 0)
! 62: bgp_table_free (rt);
! 63: }
! 64:
! 65: void
! 66: bgp_table_finish (struct bgp_table **rt)
! 67: {
! 68: if (*rt != NULL)
! 69: {
! 70: bgp_table_unlock(*rt);
! 71: *rt = NULL;
! 72: }
! 73: }
! 74:
! 75: static struct bgp_node *
! 76: bgp_node_create (void)
! 77: {
! 78: return XCALLOC (MTYPE_BGP_NODE, sizeof (struct bgp_node));
! 79: }
! 80:
! 81: /* Allocate new route node with prefix set. */
! 82: static struct bgp_node *
! 83: bgp_node_set (struct bgp_table *table, struct prefix *prefix)
! 84: {
! 85: struct bgp_node *node;
! 86:
! 87: node = bgp_node_create ();
! 88:
! 89: prefix_copy (&node->p, prefix);
! 90: node->table = table;
! 91:
! 92: return node;
! 93: }
! 94:
! 95: /* Free route node. */
! 96: static void
! 97: bgp_node_free (struct bgp_node *node)
! 98: {
! 99: XFREE (MTYPE_BGP_NODE, node);
! 100: }
! 101:
! 102: /* Free route table. */
! 103: static void
! 104: bgp_table_free (struct bgp_table *rt)
! 105: {
! 106: struct bgp_node *tmp_node;
! 107: struct bgp_node *node;
! 108:
! 109: if (rt == NULL)
! 110: return;
! 111:
! 112: node = rt->top;
! 113:
! 114: /* Bulk deletion of nodes remaining in this table. This function is not
! 115: called until workers have completed their dependency on this table.
! 116: A final bgp_unlock_node() will not be called for these nodes. */
! 117: while (node)
! 118: {
! 119: if (node->l_left)
! 120: {
! 121: node = node->l_left;
! 122: continue;
! 123: }
! 124:
! 125: if (node->l_right)
! 126: {
! 127: node = node->l_right;
! 128: continue;
! 129: }
! 130:
! 131: tmp_node = node;
! 132: node = node->parent;
! 133:
! 134: tmp_node->table->count--;
! 135: tmp_node->lock = 0; /* to cause assert if unlocked after this */
! 136: bgp_node_free (tmp_node);
! 137:
! 138: if (node != NULL)
! 139: {
! 140: if (node->l_left == tmp_node)
! 141: node->l_left = NULL;
! 142: else
! 143: node->l_right = NULL;
! 144: }
! 145: else
! 146: {
! 147: break;
! 148: }
! 149: }
! 150:
! 151: assert (rt->count == 0);
! 152:
! 153: if (rt->owner)
! 154: {
! 155: peer_unlock (rt->owner);
! 156: rt->owner = NULL;
! 157: }
! 158:
! 159: XFREE (MTYPE_BGP_TABLE, rt);
! 160: return;
! 161: }
! 162:
! 163: /* Utility mask array. */
! 164: static u_char maskbit[] =
! 165: {
! 166: 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
! 167: };
! 168:
! 169: /* Common prefix route genaration. */
! 170: static void
! 171: route_common (struct prefix *n, struct prefix *p, struct prefix *new)
! 172: {
! 173: int i;
! 174: u_char diff;
! 175: u_char mask;
! 176:
! 177: u_char *np = (u_char *)&n->u.prefix;
! 178: u_char *pp = (u_char *)&p->u.prefix;
! 179: u_char *newp = (u_char *)&new->u.prefix;
! 180:
! 181: for (i = 0; i < p->prefixlen / 8; i++)
! 182: {
! 183: if (np[i] == pp[i])
! 184: newp[i] = np[i];
! 185: else
! 186: break;
! 187: }
! 188:
! 189: new->prefixlen = i * 8;
! 190:
! 191: if (new->prefixlen != p->prefixlen)
! 192: {
! 193: diff = np[i] ^ pp[i];
! 194: mask = 0x80;
! 195: while (new->prefixlen < p->prefixlen && !(mask & diff))
! 196: {
! 197: mask >>= 1;
! 198: new->prefixlen++;
! 199: }
! 200: newp[i] = np[i] & maskbit[new->prefixlen % 8];
! 201: }
! 202: }
! 203:
! 204: static void
! 205: set_link (struct bgp_node *node, struct bgp_node *new)
! 206: {
! 207: unsigned int bit = prefix_bit (&new->p.u.prefix, node->p.prefixlen);
! 208:
! 209: node->link[bit] = new;
! 210: new->parent = node;
! 211: }
! 212:
! 213: /* Lock node. */
! 214: struct bgp_node *
! 215: bgp_lock_node (struct bgp_node *node)
! 216: {
! 217: node->lock++;
! 218: return node;
! 219: }
! 220:
! 221: /* Unlock node. */
! 222: void
! 223: bgp_unlock_node (struct bgp_node *node)
! 224: {
! 225: assert (node->lock > 0);
! 226: node->lock--;
! 227:
! 228: if (node->lock == 0)
! 229: bgp_node_delete (node);
! 230: }
! 231:
! 232: /* Find matched prefix. */
! 233: struct bgp_node *
! 234: bgp_node_match (const struct bgp_table *table, struct prefix *p)
! 235: {
! 236: struct bgp_node *node;
! 237: struct bgp_node *matched;
! 238:
! 239: matched = NULL;
! 240: node = table->top;
! 241:
! 242: /* Walk down tree. If there is matched route then store it to
! 243: matched. */
! 244: while (node && node->p.prefixlen <= p->prefixlen &&
! 245: prefix_match (&node->p, p))
! 246: {
! 247: if (node->info)
! 248: matched = node;
! 249: node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
! 250: }
! 251:
! 252: /* If matched route found, return it. */
! 253: if (matched)
! 254: return bgp_lock_node (matched);
! 255:
! 256: return NULL;
! 257: }
! 258:
! 259: struct bgp_node *
! 260: bgp_node_match_ipv4 (const struct bgp_table *table, struct in_addr *addr)
! 261: {
! 262: struct prefix_ipv4 p;
! 263:
! 264: memset (&p, 0, sizeof (struct prefix_ipv4));
! 265: p.family = AF_INET;
! 266: p.prefixlen = IPV4_MAX_PREFIXLEN;
! 267: p.prefix = *addr;
! 268:
! 269: return bgp_node_match (table, (struct prefix *) &p);
! 270: }
! 271:
! 272: #ifdef HAVE_IPV6
! 273: struct bgp_node *
! 274: bgp_node_match_ipv6 (const struct bgp_table *table, struct in6_addr *addr)
! 275: {
! 276: struct prefix_ipv6 p;
! 277:
! 278: memset (&p, 0, sizeof (struct prefix_ipv6));
! 279: p.family = AF_INET6;
! 280: p.prefixlen = IPV6_MAX_PREFIXLEN;
! 281: p.prefix = *addr;
! 282:
! 283: return bgp_node_match (table, (struct prefix *) &p);
! 284: }
! 285: #endif /* HAVE_IPV6 */
! 286:
! 287: /* Lookup same prefix node. Return NULL when we can't find route. */
! 288: struct bgp_node *
! 289: bgp_node_lookup (const struct bgp_table *table, struct prefix *p)
! 290: {
! 291: struct bgp_node *node;
! 292:
! 293: node = table->top;
! 294:
! 295: while (node && node->p.prefixlen <= p->prefixlen &&
! 296: prefix_match (&node->p, p))
! 297: {
! 298: if (node->p.prefixlen == p->prefixlen && node->info)
! 299: return bgp_lock_node (node);
! 300:
! 301: node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
! 302: }
! 303:
! 304: return NULL;
! 305: }
! 306:
! 307: /* Add node to routing table. */
! 308: struct bgp_node *
! 309: bgp_node_get (struct bgp_table *const table, struct prefix *p)
! 310: {
! 311: struct bgp_node *new;
! 312: struct bgp_node *node;
! 313: struct bgp_node *match;
! 314:
! 315: match = NULL;
! 316: node = table->top;
! 317: while (node && node->p.prefixlen <= p->prefixlen &&
! 318: prefix_match (&node->p, p))
! 319: {
! 320: if (node->p.prefixlen == p->prefixlen)
! 321: {
! 322: bgp_lock_node (node);
! 323: return node;
! 324: }
! 325: match = node;
! 326: node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
! 327: }
! 328:
! 329: if (node == NULL)
! 330: {
! 331: new = bgp_node_set (table, p);
! 332: if (match)
! 333: set_link (match, new);
! 334: else
! 335: table->top = new;
! 336: }
! 337: else
! 338: {
! 339: new = bgp_node_create ();
! 340: route_common (&node->p, p, &new->p);
! 341: new->p.family = p->family;
! 342: new->table = table;
! 343: set_link (new, node);
! 344:
! 345: if (match)
! 346: set_link (match, new);
! 347: else
! 348: table->top = new;
! 349:
! 350: if (new->p.prefixlen != p->prefixlen)
! 351: {
! 352: match = new;
! 353: new = bgp_node_set (table, p);
! 354: set_link (match, new);
! 355: table->count++;
! 356: }
! 357: }
! 358: table->count++;
! 359: bgp_lock_node (new);
! 360:
! 361: return new;
! 362: }
! 363:
! 364: /* Delete node from the routing table. */
! 365: static void
! 366: bgp_node_delete (struct bgp_node *node)
! 367: {
! 368: struct bgp_node *child;
! 369: struct bgp_node *parent;
! 370:
! 371: assert (node->lock == 0);
! 372: assert (node->info == NULL);
! 373:
! 374: if (node->l_left && node->l_right)
! 375: return;
! 376:
! 377: if (node->l_left)
! 378: child = node->l_left;
! 379: else
! 380: child = node->l_right;
! 381:
! 382: parent = node->parent;
! 383:
! 384: if (child)
! 385: child->parent = parent;
! 386:
! 387: if (parent)
! 388: {
! 389: if (parent->l_left == node)
! 390: parent->l_left = child;
! 391: else
! 392: parent->l_right = child;
! 393: }
! 394: else
! 395: node->table->top = child;
! 396:
! 397: node->table->count--;
! 398:
! 399: bgp_node_free (node);
! 400:
! 401: /* If parent node is stub then delete it also. */
! 402: if (parent && parent->lock == 0)
! 403: bgp_node_delete (parent);
! 404: }
! 405:
! 406: /* Get fist node and lock it. This function is useful when one want
! 407: to lookup all the node exist in the routing table. */
! 408: struct bgp_node *
! 409: bgp_table_top (const struct bgp_table *const table)
! 410: {
! 411: /* If there is no node in the routing table return NULL. */
! 412: if (table->top == NULL)
! 413: return NULL;
! 414:
! 415: /* Lock the top node and return it. */
! 416: bgp_lock_node (table->top);
! 417: return table->top;
! 418: }
! 419:
! 420: /* Unlock current node and lock next node then return it. */
! 421: struct bgp_node *
! 422: bgp_route_next (struct bgp_node *node)
! 423: {
! 424: struct bgp_node *next;
! 425: struct bgp_node *start;
! 426:
! 427: /* Node may be deleted from bgp_unlock_node so we have to preserve
! 428: next node's pointer. */
! 429:
! 430: if (node->l_left)
! 431: {
! 432: next = node->l_left;
! 433: bgp_lock_node (next);
! 434: bgp_unlock_node (node);
! 435: return next;
! 436: }
! 437: if (node->l_right)
! 438: {
! 439: next = node->l_right;
! 440: bgp_lock_node (next);
! 441: bgp_unlock_node (node);
! 442: return next;
! 443: }
! 444:
! 445: start = node;
! 446: while (node->parent)
! 447: {
! 448: if (node->parent->l_left == node && node->parent->l_right)
! 449: {
! 450: next = node->parent->l_right;
! 451: bgp_lock_node (next);
! 452: bgp_unlock_node (start);
! 453: return next;
! 454: }
! 455: node = node->parent;
! 456: }
! 457: bgp_unlock_node (start);
! 458: return NULL;
! 459: }
! 460:
! 461: /* Unlock current node and lock next node until limit. */
! 462: struct bgp_node *
! 463: bgp_route_next_until (struct bgp_node *node, struct bgp_node *limit)
! 464: {
! 465: struct bgp_node *next;
! 466: struct bgp_node *start;
! 467:
! 468: /* Node may be deleted from bgp_unlock_node so we have to preserve
! 469: next node's pointer. */
! 470:
! 471: if (node->l_left)
! 472: {
! 473: next = node->l_left;
! 474: bgp_lock_node (next);
! 475: bgp_unlock_node (node);
! 476: return next;
! 477: }
! 478: if (node->l_right)
! 479: {
! 480: next = node->l_right;
! 481: bgp_lock_node (next);
! 482: bgp_unlock_node (node);
! 483: return next;
! 484: }
! 485:
! 486: start = node;
! 487: while (node->parent && node != limit)
! 488: {
! 489: if (node->parent->l_left == node && node->parent->l_right)
! 490: {
! 491: next = node->parent->l_right;
! 492: bgp_lock_node (next);
! 493: bgp_unlock_node (start);
! 494: return next;
! 495: }
! 496: node = node->parent;
! 497: }
! 498: bgp_unlock_node (start);
! 499: return NULL;
! 500: }
! 501:
! 502: unsigned long
! 503: bgp_table_count (const struct bgp_table *table)
! 504: {
! 505: return table->count;
! 506: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>