Annotation of embedaddon/quagga/lib/table.c, revision 1.1
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:
! 30: void route_node_delete (struct route_node *);
! 31: void route_table_free (struct route_table *);
! 32:
! 33: struct route_table *
! 34: route_table_init (void)
! 35: {
! 36: struct route_table *rt;
! 37:
! 38: rt = XCALLOC (MTYPE_ROUTE_TABLE, sizeof (struct route_table));
! 39: return rt;
! 40: }
! 41:
! 42: void
! 43: route_table_finish (struct route_table *rt)
! 44: {
! 45: route_table_free (rt);
! 46: }
! 47:
! 48: /* Allocate new route node. */
! 49: static struct route_node *
! 50: route_node_new (void)
! 51: {
! 52: struct route_node *node;
! 53: node = XCALLOC (MTYPE_ROUTE_NODE, sizeof (struct route_node));
! 54: return node;
! 55: }
! 56:
! 57: /* Allocate new route node with prefix set. */
! 58: static struct route_node *
! 59: route_node_set (struct route_table *table, struct prefix *prefix)
! 60: {
! 61: struct route_node *node;
! 62:
! 63: node = route_node_new ();
! 64:
! 65: prefix_copy (&node->p, prefix);
! 66: node->table = table;
! 67:
! 68: return node;
! 69: }
! 70:
! 71: /* Free route node. */
! 72: static void
! 73: route_node_free (struct route_node *node)
! 74: {
! 75: XFREE (MTYPE_ROUTE_NODE, node);
! 76: }
! 77:
! 78: /* Free route table. */
! 79: void
! 80: route_table_free (struct route_table *rt)
! 81: {
! 82: struct route_node *tmp_node;
! 83: struct route_node *node;
! 84:
! 85: if (rt == NULL)
! 86: return;
! 87:
! 88: node = rt->top;
! 89:
! 90: while (node)
! 91: {
! 92: if (node->l_left)
! 93: {
! 94: node = node->l_left;
! 95: continue;
! 96: }
! 97:
! 98: if (node->l_right)
! 99: {
! 100: node = node->l_right;
! 101: continue;
! 102: }
! 103:
! 104: tmp_node = node;
! 105: node = node->parent;
! 106:
! 107: if (node != NULL)
! 108: {
! 109: if (node->l_left == tmp_node)
! 110: node->l_left = NULL;
! 111: else
! 112: node->l_right = NULL;
! 113:
! 114: route_node_free (tmp_node);
! 115: }
! 116: else
! 117: {
! 118: route_node_free (tmp_node);
! 119: break;
! 120: }
! 121: }
! 122:
! 123: XFREE (MTYPE_ROUTE_TABLE, rt);
! 124: return;
! 125: }
! 126:
! 127: /* Utility mask array. */
! 128: static const u_char maskbit[] =
! 129: {
! 130: 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
! 131: };
! 132:
! 133: /* Common prefix route genaration. */
! 134: static void
! 135: route_common (struct prefix *n, struct prefix *p, struct prefix *new)
! 136: {
! 137: int i;
! 138: u_char diff;
! 139: u_char mask;
! 140:
! 141: u_char *np = (u_char *)&n->u.prefix;
! 142: u_char *pp = (u_char *)&p->u.prefix;
! 143: u_char *newp = (u_char *)&new->u.prefix;
! 144:
! 145: for (i = 0; i < p->prefixlen / 8; i++)
! 146: {
! 147: if (np[i] == pp[i])
! 148: newp[i] = np[i];
! 149: else
! 150: break;
! 151: }
! 152:
! 153: new->prefixlen = i * 8;
! 154:
! 155: if (new->prefixlen != p->prefixlen)
! 156: {
! 157: diff = np[i] ^ pp[i];
! 158: mask = 0x80;
! 159: while (new->prefixlen < p->prefixlen && !(mask & diff))
! 160: {
! 161: mask >>= 1;
! 162: new->prefixlen++;
! 163: }
! 164: newp[i] = np[i] & maskbit[new->prefixlen % 8];
! 165: }
! 166: }
! 167:
! 168: static void
! 169: set_link (struct route_node *node, struct route_node *new)
! 170: {
! 171: unsigned int bit = prefix_bit (&new->p.u.prefix, node->p.prefixlen);
! 172:
! 173: node->link[bit] = new;
! 174: new->parent = node;
! 175: }
! 176:
! 177: /* Lock node. */
! 178: struct route_node *
! 179: route_lock_node (struct route_node *node)
! 180: {
! 181: node->lock++;
! 182: return node;
! 183: }
! 184:
! 185: /* Unlock node. */
! 186: void
! 187: route_unlock_node (struct route_node *node)
! 188: {
! 189: node->lock--;
! 190:
! 191: if (node->lock == 0)
! 192: route_node_delete (node);
! 193: }
! 194:
! 195: /* Find matched prefix. */
! 196: struct route_node *
! 197: route_node_match (const struct route_table *table, const struct prefix *p)
! 198: {
! 199: struct route_node *node;
! 200: struct route_node *matched;
! 201:
! 202: matched = NULL;
! 203: node = table->top;
! 204:
! 205: /* Walk down tree. If there is matched route then store it to
! 206: matched. */
! 207: while (node && node->p.prefixlen <= p->prefixlen &&
! 208: prefix_match (&node->p, p))
! 209: {
! 210: if (node->info)
! 211: matched = node;
! 212:
! 213: if (node->p.prefixlen == p->prefixlen)
! 214: break;
! 215:
! 216: node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
! 217: }
! 218:
! 219: /* If matched route found, return it. */
! 220: if (matched)
! 221: return route_lock_node (matched);
! 222:
! 223: return NULL;
! 224: }
! 225:
! 226: struct route_node *
! 227: route_node_match_ipv4 (const struct route_table *table,
! 228: const struct in_addr *addr)
! 229: {
! 230: struct prefix_ipv4 p;
! 231:
! 232: memset (&p, 0, sizeof (struct prefix_ipv4));
! 233: p.family = AF_INET;
! 234: p.prefixlen = IPV4_MAX_PREFIXLEN;
! 235: p.prefix = *addr;
! 236:
! 237: return route_node_match (table, (struct prefix *) &p);
! 238: }
! 239:
! 240: #ifdef HAVE_IPV6
! 241: struct route_node *
! 242: route_node_match_ipv6 (const struct route_table *table,
! 243: const struct in6_addr *addr)
! 244: {
! 245: struct prefix_ipv6 p;
! 246:
! 247: memset (&p, 0, sizeof (struct prefix_ipv6));
! 248: p.family = AF_INET6;
! 249: p.prefixlen = IPV6_MAX_PREFIXLEN;
! 250: p.prefix = *addr;
! 251:
! 252: return route_node_match (table, (struct prefix *) &p);
! 253: }
! 254: #endif /* HAVE_IPV6 */
! 255:
! 256: /* Lookup same prefix node. Return NULL when we can't find route. */
! 257: struct route_node *
! 258: route_node_lookup (struct route_table *table, struct prefix *p)
! 259: {
! 260: struct route_node *node;
! 261:
! 262: node = table->top;
! 263:
! 264: while (node && node->p.prefixlen <= p->prefixlen &&
! 265: prefix_match (&node->p, p))
! 266: {
! 267: if (node->p.prefixlen == p->prefixlen)
! 268: return node->info ? route_lock_node (node) : NULL;
! 269:
! 270: node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
! 271: }
! 272:
! 273: return NULL;
! 274: }
! 275:
! 276: /* Add node to routing table. */
! 277: struct route_node *
! 278: route_node_get (struct route_table *table, struct prefix *p)
! 279: {
! 280: struct route_node *new;
! 281: struct route_node *node;
! 282: struct route_node *match;
! 283:
! 284: match = NULL;
! 285: node = table->top;
! 286: while (node && node->p.prefixlen <= p->prefixlen &&
! 287: prefix_match (&node->p, p))
! 288: {
! 289: if (node->p.prefixlen == p->prefixlen)
! 290: return route_lock_node (node);
! 291:
! 292: match = node;
! 293: node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
! 294: }
! 295:
! 296: if (node == NULL)
! 297: {
! 298: new = route_node_set (table, p);
! 299: if (match)
! 300: set_link (match, new);
! 301: else
! 302: table->top = new;
! 303: }
! 304: else
! 305: {
! 306: new = route_node_new ();
! 307: route_common (&node->p, p, &new->p);
! 308: new->p.family = p->family;
! 309: new->table = table;
! 310: set_link (new, node);
! 311:
! 312: if (match)
! 313: set_link (match, new);
! 314: else
! 315: table->top = new;
! 316:
! 317: if (new->p.prefixlen != p->prefixlen)
! 318: {
! 319: match = new;
! 320: new = route_node_set (table, p);
! 321: set_link (match, new);
! 322: }
! 323: }
! 324: route_lock_node (new);
! 325:
! 326: return new;
! 327: }
! 328:
! 329: /* Delete node from the routing table. */
! 330: void
! 331: route_node_delete (struct route_node *node)
! 332: {
! 333: struct route_node *child;
! 334: struct route_node *parent;
! 335:
! 336: assert (node->lock == 0);
! 337: assert (node->info == NULL);
! 338:
! 339: if (node->l_left && node->l_right)
! 340: return;
! 341:
! 342: if (node->l_left)
! 343: child = node->l_left;
! 344: else
! 345: child = node->l_right;
! 346:
! 347: parent = node->parent;
! 348:
! 349: if (child)
! 350: child->parent = parent;
! 351:
! 352: if (parent)
! 353: {
! 354: if (parent->l_left == node)
! 355: parent->l_left = child;
! 356: else
! 357: parent->l_right = child;
! 358: }
! 359: else
! 360: node->table->top = child;
! 361:
! 362: route_node_free (node);
! 363:
! 364: /* If parent node is stub then delete it also. */
! 365: if (parent && parent->lock == 0)
! 366: route_node_delete (parent);
! 367: }
! 368:
! 369: /* Get fist node and lock it. This function is useful when one want
! 370: to lookup all the node exist in the routing table. */
! 371: struct route_node *
! 372: route_top (struct route_table *table)
! 373: {
! 374: /* If there is no node in the routing table return NULL. */
! 375: if (table->top == NULL)
! 376: return NULL;
! 377:
! 378: /* Lock the top node and return it. */
! 379: route_lock_node (table->top);
! 380: return table->top;
! 381: }
! 382:
! 383: /* Unlock current node and lock next node then return it. */
! 384: struct route_node *
! 385: route_next (struct route_node *node)
! 386: {
! 387: struct route_node *next;
! 388: struct route_node *start;
! 389:
! 390: /* Node may be deleted from route_unlock_node so we have to preserve
! 391: next node's pointer. */
! 392:
! 393: if (node->l_left)
! 394: {
! 395: next = node->l_left;
! 396: route_lock_node (next);
! 397: route_unlock_node (node);
! 398: return next;
! 399: }
! 400: if (node->l_right)
! 401: {
! 402: next = node->l_right;
! 403: route_lock_node (next);
! 404: route_unlock_node (node);
! 405: return next;
! 406: }
! 407:
! 408: start = node;
! 409: while (node->parent)
! 410: {
! 411: if (node->parent->l_left == node && node->parent->l_right)
! 412: {
! 413: next = node->parent->l_right;
! 414: route_lock_node (next);
! 415: route_unlock_node (start);
! 416: return next;
! 417: }
! 418: node = node->parent;
! 419: }
! 420: route_unlock_node (start);
! 421: return NULL;
! 422: }
! 423:
! 424: /* Unlock current node and lock next node until limit. */
! 425: struct route_node *
! 426: route_next_until (struct route_node *node, struct route_node *limit)
! 427: {
! 428: struct route_node *next;
! 429: struct route_node *start;
! 430:
! 431: /* Node may be deleted from route_unlock_node so we have to preserve
! 432: next node's pointer. */
! 433:
! 434: if (node->l_left)
! 435: {
! 436: next = node->l_left;
! 437: route_lock_node (next);
! 438: route_unlock_node (node);
! 439: return next;
! 440: }
! 441: if (node->l_right)
! 442: {
! 443: next = node->l_right;
! 444: route_lock_node (next);
! 445: route_unlock_node (node);
! 446: return next;
! 447: }
! 448:
! 449: start = node;
! 450: while (node->parent && node != limit)
! 451: {
! 452: if (node->parent->l_left == node && node->parent->l_right)
! 453: {
! 454: next = node->parent->l_right;
! 455: route_lock_node (next);
! 456: route_unlock_node (start);
! 457: return next;
! 458: }
! 459: node = node->parent;
! 460: }
! 461: route_unlock_node (start);
! 462: return NULL;
! 463: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>