Annotation of embedaddon/quagga/isisd/isis_route.c, revision 1.1
1.1 ! misho 1: /*
! 2: * IS-IS Rout(e)ing protocol - isis_route.c
! 3: * Copyright (C) 2001,2002 Sampo Saaristo
! 4: * Tampere University of Technology
! 5: * Institute of Communications Engineering
! 6: *
! 7: * based on ../ospf6d/ospf6_route.[ch]
! 8: * by Yasuhiro Ohara
! 9: *
! 10: * This program is free software; you can redistribute it and/or modify it
! 11: * under the terms of the GNU General Public Licenseas published by the Free
! 12: * Software Foundation; either version 2 of the License, or (at your option)
! 13: * any later version.
! 14: *
! 15: * This program is distributed in the hope that it will be useful,but WITHOUT
! 16: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
! 17: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
! 18: * more details.
! 19:
! 20: * You should have received a copy of the GNU General Public License along
! 21: * with this program; if not, write to the Free Software Foundation, Inc.,
! 22: * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
! 23: */
! 24:
! 25: #include <zebra.h>
! 26:
! 27: #include "thread.h"
! 28: #include "linklist.h"
! 29: #include "vty.h"
! 30: #include "log.h"
! 31: #include "memory.h"
! 32: #include "prefix.h"
! 33: #include "hash.h"
! 34: #include "if.h"
! 35: #include "table.h"
! 36:
! 37: #include "isis_constants.h"
! 38: #include "isis_common.h"
! 39: #include "dict.h"
! 40: #include "isisd.h"
! 41: #include "isis_misc.h"
! 42: #include "isis_adjacency.h"
! 43: #include "isis_circuit.h"
! 44: #include "isis_tlv.h"
! 45: #include "isis_pdu.h"
! 46: #include "isis_lsp.h"
! 47: #include "isis_spf.h"
! 48: #include "isis_route.h"
! 49: #include "isis_zebra.h"
! 50:
! 51: extern struct isis *isis;
! 52: extern struct thread_master *master;
! 53:
! 54: static struct isis_nexthop *
! 55: isis_nexthop_create (struct in_addr *ip, unsigned int ifindex)
! 56: {
! 57: struct listnode *node;
! 58: struct isis_nexthop *nexthop;
! 59:
! 60: for (ALL_LIST_ELEMENTS_RO (isis->nexthops, node, nexthop))
! 61: {
! 62: if (nexthop->ifindex != ifindex)
! 63: continue;
! 64: if (ip && memcmp (&nexthop->ip, ip, sizeof (struct in_addr)) != 0)
! 65: continue;
! 66:
! 67: nexthop->lock++;
! 68: return nexthop;
! 69: }
! 70:
! 71: nexthop = XCALLOC (MTYPE_ISIS_NEXTHOP, sizeof (struct isis_nexthop));
! 72: if (!nexthop)
! 73: {
! 74: zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!");
! 75: }
! 76:
! 77: nexthop->ifindex = ifindex;
! 78: memcpy (&nexthop->ip, ip, sizeof (struct in_addr));
! 79: listnode_add (isis->nexthops, nexthop);
! 80: nexthop->lock++;
! 81:
! 82: return nexthop;
! 83: }
! 84:
! 85: static void
! 86: isis_nexthop_delete (struct isis_nexthop *nexthop)
! 87: {
! 88: nexthop->lock--;
! 89: if (nexthop->lock == 0)
! 90: {
! 91: listnode_delete (isis->nexthops, nexthop);
! 92: XFREE (MTYPE_ISIS_NEXTHOP, nexthop);
! 93: }
! 94:
! 95: return;
! 96: }
! 97:
! 98: static int
! 99: nexthoplookup (struct list *nexthops, struct in_addr *ip,
! 100: unsigned int ifindex)
! 101: {
! 102: struct listnode *node;
! 103: struct isis_nexthop *nh;
! 104:
! 105: for (ALL_LIST_ELEMENTS_RO (nexthops, node, nh))
! 106: {
! 107: if (!(memcmp (ip, &nh->ip, sizeof (struct in_addr))) &&
! 108: ifindex == nh->ifindex)
! 109: return 1;
! 110: }
! 111:
! 112: return 0;
! 113: }
! 114:
! 115: #ifdef EXTREME_DEBUG
! 116: static void
! 117: nexthop_print (struct isis_nexthop *nh)
! 118: {
! 119: u_char buf[BUFSIZ];
! 120:
! 121: inet_ntop (AF_INET, &nh->ip, (char *) buf, BUFSIZ);
! 122:
! 123: zlog_debug (" %s %u", buf, nh->ifindex);
! 124: }
! 125:
! 126: static void
! 127: nexthops_print (struct list *nhs)
! 128: {
! 129: struct listnode *node;
! 130: struct isis_nexthop *nh;
! 131:
! 132: for (ALL_LIST_ELEMENTS_RO (nhs, node, nh))
! 133: nexthop_print (nh);
! 134: }
! 135: #endif /* EXTREME_DEBUG */
! 136:
! 137: #ifdef HAVE_IPV6
! 138: static struct isis_nexthop6 *
! 139: isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex)
! 140: {
! 141: struct isis_nexthop6 *nexthop6;
! 142:
! 143: nexthop6 = XCALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6));
! 144: if (!nexthop6)
! 145: {
! 146: zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!");
! 147: }
! 148:
! 149: nexthop6->ifindex = ifindex;
! 150: memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr));
! 151: nexthop6->lock++;
! 152:
! 153: return nexthop6;
! 154: }
! 155:
! 156: static struct isis_nexthop6 *
! 157: isis_nexthop6_create (struct in6_addr *ip6, unsigned int ifindex)
! 158: {
! 159: struct listnode *node;
! 160: struct isis_nexthop6 *nexthop6;
! 161:
! 162: for (ALL_LIST_ELEMENTS_RO (isis->nexthops6, node, nexthop6))
! 163: {
! 164: if (nexthop6->ifindex != ifindex)
! 165: continue;
! 166: if (ip6 && memcmp (&nexthop6->ip6, ip6, sizeof (struct in6_addr)) != 0)
! 167: continue;
! 168:
! 169: nexthop6->lock++;
! 170: return nexthop6;
! 171: }
! 172:
! 173: nexthop6 = isis_nexthop6_new (ip6, ifindex);
! 174:
! 175: return nexthop6;
! 176: }
! 177:
! 178: static void
! 179: isis_nexthop6_delete (struct isis_nexthop6 *nexthop6)
! 180: {
! 181:
! 182: nexthop6->lock--;
! 183: if (nexthop6->lock == 0)
! 184: {
! 185: listnode_delete (isis->nexthops6, nexthop6);
! 186: XFREE (MTYPE_ISIS_NEXTHOP6, nexthop6);
! 187: }
! 188:
! 189: return;
! 190: }
! 191:
! 192: static int
! 193: nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6,
! 194: unsigned int ifindex)
! 195: {
! 196: struct listnode *node;
! 197: struct isis_nexthop6 *nh6;
! 198:
! 199: for (ALL_LIST_ELEMENTS_RO (nexthops6, node, nh6))
! 200: {
! 201: if (!(memcmp (ip6, &nh6->ip6, sizeof (struct in6_addr))) &&
! 202: ifindex == nh6->ifindex)
! 203: return 1;
! 204: }
! 205:
! 206: return 0;
! 207: }
! 208:
! 209: #ifdef EXTREME_DEBUG
! 210: static void
! 211: nexthop6_print (struct isis_nexthop6 *nh6)
! 212: {
! 213: u_char buf[BUFSIZ];
! 214:
! 215: inet_ntop (AF_INET6, &nh6->ip6, (char *) buf, BUFSIZ);
! 216:
! 217: zlog_debug (" %s %u", buf, nh6->ifindex);
! 218: }
! 219:
! 220: static void
! 221: nexthops6_print (struct list *nhs6)
! 222: {
! 223: struct listnode *node;
! 224: struct isis_nexthop6 *nh6;
! 225:
! 226: for (ALL_LIST_ELEMENTS_RO (nhs6, node, nh6))
! 227: nexthop6_print (nh6);
! 228: }
! 229: #endif /* EXTREME_DEBUG */
! 230: #endif /* HAVE_IPV6 */
! 231:
! 232: static void
! 233: adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj)
! 234: {
! 235: struct isis_nexthop *nh;
! 236: struct listnode *node;
! 237: struct in_addr *ipv4_addr;
! 238:
! 239: if (adj->ipv4_addrs == NULL)
! 240: return;
! 241:
! 242: for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
! 243: {
! 244: if (!nexthoplookup (nexthops, ipv4_addr,
! 245: adj->circuit->interface->ifindex))
! 246: {
! 247: nh = isis_nexthop_create (ipv4_addr,
! 248: adj->circuit->interface->ifindex);
! 249: listnode_add (nexthops, nh);
! 250: }
! 251: }
! 252: }
! 253:
! 254: #ifdef HAVE_IPV6
! 255: static void
! 256: adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj)
! 257: {
! 258: struct listnode *node;
! 259: struct in6_addr *ipv6_addr;
! 260: struct isis_nexthop6 *nh6;
! 261:
! 262: if (!adj->ipv6_addrs)
! 263: return;
! 264:
! 265: for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
! 266: {
! 267: if (!nexthop6lookup (nexthops6, ipv6_addr,
! 268: adj->circuit->interface->ifindex))
! 269: {
! 270: nh6 = isis_nexthop6_create (ipv6_addr,
! 271: adj->circuit->interface->ifindex);
! 272: listnode_add (nexthops6, nh6);
! 273: }
! 274: }
! 275: }
! 276: #endif /* HAVE_IPV6 */
! 277:
! 278: static struct isis_route_info *
! 279: isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
! 280: struct list *adjacencies)
! 281: {
! 282: struct isis_route_info *rinfo;
! 283: struct isis_adjacency *adj;
! 284: struct listnode *node;
! 285:
! 286: rinfo = XCALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info));
! 287: if (!rinfo)
! 288: {
! 289: zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!");
! 290: return NULL;
! 291: }
! 292:
! 293: if (family == AF_INET)
! 294: {
! 295: rinfo->nexthops = list_new ();
! 296: for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
! 297: adjinfo2nexthop (rinfo->nexthops, adj);
! 298: }
! 299: #ifdef HAVE_IPV6
! 300: if (family == AF_INET6)
! 301: {
! 302: rinfo->nexthops6 = list_new ();
! 303: for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
! 304: adjinfo2nexthop6 (rinfo->nexthops6, adj);
! 305: }
! 306:
! 307: #endif /* HAVE_IPV6 */
! 308:
! 309: rinfo->cost = cost;
! 310: rinfo->depth = depth;
! 311:
! 312: return rinfo;
! 313: }
! 314:
! 315: static void
! 316: isis_route_info_delete (struct isis_route_info *route_info)
! 317: {
! 318: if (route_info->nexthops)
! 319: {
! 320: route_info->nexthops->del = (void (*)(void *)) isis_nexthop_delete;
! 321: list_delete (route_info->nexthops);
! 322: }
! 323:
! 324: #ifdef HAVE_IPV6
! 325: if (route_info->nexthops6)
! 326: {
! 327: route_info->nexthops6->del = (void (*)(void *)) isis_nexthop6_delete;
! 328: list_delete (route_info->nexthops6);
! 329: }
! 330: #endif /* HAVE_IPV6 */
! 331:
! 332: XFREE (MTYPE_ISIS_ROUTE_INFO, route_info);
! 333: }
! 334:
! 335: static int
! 336: isis_route_info_same_attrib (struct isis_route_info *new,
! 337: struct isis_route_info *old)
! 338: {
! 339: if (new->cost != old->cost)
! 340: return 0;
! 341: if (new->depth != old->depth)
! 342: return 0;
! 343:
! 344: return 1;
! 345: }
! 346:
! 347: static int
! 348: isis_route_info_same (struct isis_route_info *new,
! 349: struct isis_route_info *old, u_char family)
! 350: {
! 351: struct listnode *node;
! 352: struct isis_nexthop *nexthop;
! 353: #ifdef HAVE_IPV6
! 354: struct isis_nexthop6 *nexthop6;
! 355: #endif /* HAVE_IPV6 */
! 356: if (!isis_route_info_same_attrib (new, old))
! 357: return 0;
! 358:
! 359: if (family == AF_INET)
! 360: {
! 361: for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop))
! 362: if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex)
! 363: == 0)
! 364: return 0;
! 365:
! 366: for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop))
! 367: if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex)
! 368: == 0)
! 369: return 0;
! 370: }
! 371: #ifdef HAVE_IPV6
! 372: else if (family == AF_INET6)
! 373: {
! 374: for (ALL_LIST_ELEMENTS_RO (new->nexthops6, node, nexthop6))
! 375: if (nexthop6lookup (old->nexthops6, &nexthop6->ip6,
! 376: nexthop6->ifindex) == 0)
! 377: return 0;
! 378:
! 379: for (ALL_LIST_ELEMENTS_RO (old->nexthops6, node, nexthop6))
! 380: if (nexthop6lookup (new->nexthops6, &nexthop6->ip6,
! 381: nexthop6->ifindex) == 0)
! 382: return 0;
! 383: }
! 384: #endif /* HAVE_IPV6 */
! 385:
! 386: return 1;
! 387: }
! 388:
! 389: static void
! 390: isis_nexthops_merge (struct list *new, struct list *old)
! 391: {
! 392: struct listnode *node;
! 393: struct isis_nexthop *nexthop;
! 394:
! 395: for (ALL_LIST_ELEMENTS_RO (new, node, nexthop))
! 396: {
! 397: if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex))
! 398: continue;
! 399: listnode_add (old, nexthop);
! 400: nexthop->lock++;
! 401: }
! 402: }
! 403:
! 404: #ifdef HAVE_IPV6
! 405: static void
! 406: isis_nexthops6_merge (struct list *new, struct list *old)
! 407: {
! 408: struct listnode *node;
! 409: struct isis_nexthop6 *nexthop6;
! 410:
! 411: for (ALL_LIST_ELEMENTS_RO (new, node, nexthop6))
! 412: {
! 413: if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex))
! 414: continue;
! 415: listnode_add (old, nexthop6);
! 416: nexthop6->lock++;
! 417: }
! 418: }
! 419: #endif /* HAVE_IPV6 */
! 420:
! 421: static void
! 422: isis_route_info_merge (struct isis_route_info *new,
! 423: struct isis_route_info *old, u_char family)
! 424: {
! 425: if (family == AF_INET)
! 426: isis_nexthops_merge (new->nexthops, old->nexthops);
! 427: #ifdef HAVE_IPV6
! 428: else if (family == AF_INET6)
! 429: isis_nexthops6_merge (new->nexthops6, old->nexthops6);
! 430: #endif /* HAVE_IPV6 */
! 431:
! 432: return;
! 433: }
! 434:
! 435: static int
! 436: isis_route_info_prefer_new (struct isis_route_info *new,
! 437: struct isis_route_info *old)
! 438: {
! 439: if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE))
! 440: return 1;
! 441:
! 442: if (new->cost < old->cost)
! 443: return 1;
! 444:
! 445: return 0;
! 446: }
! 447:
! 448: struct isis_route_info *
! 449: isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
! 450: struct list *adjacencies, struct isis_area *area,
! 451: int level)
! 452: {
! 453: struct route_node *route_node;
! 454: struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
! 455: u_char buff[BUFSIZ];
! 456: u_char family;
! 457:
! 458: family = prefix->family;
! 459: /* for debugs */
! 460: prefix2str (prefix, (char *) buff, BUFSIZ);
! 461:
! 462: rinfo_new = isis_route_info_new (cost, depth, family, adjacencies);
! 463: if (!rinfo_new)
! 464: {
! 465: zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
! 466: area->area_tag);
! 467: return NULL;
! 468: }
! 469:
! 470: if (family == AF_INET)
! 471: route_node = route_node_get (area->route_table[level - 1], prefix);
! 472: #ifdef HAVE_IPV6
! 473: else if (family == AF_INET6)
! 474: route_node = route_node_get (area->route_table6[level - 1], prefix);
! 475: #endif /* HAVE_IPV6 */
! 476: else
! 477: return NULL;
! 478: rinfo_old = route_node->info;
! 479: if (!rinfo_old)
! 480: {
! 481: if (isis->debugs & DEBUG_RTE_EVENTS)
! 482: zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
! 483: SET_FLAG (rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE);
! 484: route_node->info = rinfo_new;
! 485: return rinfo_new;
! 486: }
! 487:
! 488: if (isis->debugs & DEBUG_RTE_EVENTS)
! 489: zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag,
! 490: buff);
! 491:
! 492: if (isis_route_info_same (rinfo_new, rinfo_old, family))
! 493: {
! 494: if (isis->debugs & DEBUG_RTE_EVENTS)
! 495: zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff);
! 496: isis_route_info_delete (rinfo_new);
! 497: route_info = rinfo_old;
! 498: }
! 499: else if (isis_route_info_same_attrib (rinfo_new, rinfo_old))
! 500: {
! 501: /* merge the nexthop lists */
! 502: if (isis->debugs & DEBUG_RTE_EVENTS)
! 503: zlog_debug ("ISIS-Rte (%s) route changed (same attribs): %s",
! 504: area->area_tag, buff);
! 505: #ifdef EXTREME_DEBUG
! 506: if (family == AF_INET)
! 507: {
! 508: zlog_debug ("Old nexthops");
! 509: nexthops_print (rinfo_old->nexthops);
! 510: zlog_debug ("New nexthops");
! 511: nexthops_print (rinfo_new->nexthops);
! 512: }
! 513: else if (family == AF_INET6)
! 514: {
! 515: zlog_debug ("Old nexthops");
! 516: nexthops6_print (rinfo_old->nexthops6);
! 517: zlog_debug ("New nexthops");
! 518: nexthops6_print (rinfo_new->nexthops6);
! 519: }
! 520: #endif /* EXTREME_DEBUG */
! 521: isis_route_info_merge (rinfo_new, rinfo_old, family);
! 522: isis_route_info_delete (rinfo_new);
! 523: route_info = rinfo_old;
! 524: UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
! 525: }
! 526: else
! 527: {
! 528: if (isis_route_info_prefer_new (rinfo_new, rinfo_old))
! 529: {
! 530: if (isis->debugs & DEBUG_RTE_EVENTS)
! 531: zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag,
! 532: buff);
! 533: isis_route_info_delete (rinfo_old);
! 534: route_info = rinfo_new;
! 535: }
! 536: else
! 537: {
! 538: if (isis->debugs & DEBUG_RTE_EVENTS)
! 539: zlog_debug ("ISIS-Rte (%s) route rejected: %s", area->area_tag,
! 540: buff);
! 541: isis_route_info_delete (rinfo_new);
! 542: route_info = rinfo_old;
! 543: }
! 544: }
! 545:
! 546: SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
! 547: route_node->info = route_info;
! 548:
! 549: return route_info;
! 550: }
! 551:
! 552: static void
! 553: isis_route_delete (struct prefix *prefix, struct route_table *table)
! 554: {
! 555: struct route_node *rode;
! 556: struct isis_route_info *rinfo;
! 557: char buff[BUFSIZ];
! 558:
! 559: /* for log */
! 560: prefix2str (prefix, buff, BUFSIZ);
! 561:
! 562:
! 563: rode = route_node_get (table, prefix);
! 564: rinfo = rode->info;
! 565:
! 566: if (rinfo == NULL)
! 567: {
! 568: if (isis->debugs & DEBUG_RTE_EVENTS)
! 569: zlog_debug ("ISIS-Rte: tried to delete non-existant route %s", buff);
! 570: return;
! 571: }
! 572:
! 573: if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
! 574: {
! 575: UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
! 576: if (isis->debugs & DEBUG_RTE_EVENTS)
! 577: zlog_debug ("ISIS-Rte: route delete %s", buff);
! 578: isis_zebra_route_update (prefix, rinfo);
! 579: }
! 580: isis_route_info_delete (rinfo);
! 581: rode->info = NULL;
! 582:
! 583: return;
! 584: }
! 585:
! 586: /* Validating routes in particular table. */
! 587: static void
! 588: isis_route_validate_table (struct isis_area *area, struct route_table *table)
! 589: {
! 590: struct route_node *rnode, *drnode;
! 591: struct isis_route_info *rinfo;
! 592: u_char buff[BUFSIZ];
! 593:
! 594: for (rnode = route_top (table); rnode; rnode = route_next (rnode))
! 595: {
! 596: if (rnode->info == NULL)
! 597: continue;
! 598: rinfo = rnode->info;
! 599:
! 600: if (isis->debugs & DEBUG_RTE_EVENTS)
! 601: {
! 602: prefix2str (&rnode->p, (char *) buff, BUFSIZ);
! 603: zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s",
! 604: area->area_tag,
! 605: (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ?
! 606: "sync'ed" : "nosync"),
! 607: (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ?
! 608: "active" : "inactive"), buff);
! 609: }
! 610:
! 611: isis_zebra_route_update (&rnode->p, rinfo);
! 612: if (!CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
! 613: {
! 614: /* Area is either L1 or L2 => we use level route tables directly for
! 615: * validating => no problems with deleting routes. */
! 616: if (area->is_type != IS_LEVEL_1_AND_2)
! 617: {
! 618: isis_route_delete (&rnode->p, table);
! 619: continue;
! 620: }
! 621: /* If area is L1L2, we work with merge table and therefore must
! 622: * delete node from level tables as well before deleting route info.
! 623: * FIXME: Is it performance problem? There has to be the better way.
! 624: * Like not to deal with it here at all (see the next comment)? */
! 625: if (rnode->p.family == AF_INET)
! 626: {
! 627: drnode = route_node_get (area->route_table[0], &rnode->p);
! 628: if (drnode->info == rnode->info)
! 629: drnode->info = NULL;
! 630: drnode = route_node_get (area->route_table[1], &rnode->p);
! 631: if (drnode->info == rnode->info)
! 632: drnode->info = NULL;
! 633: }
! 634:
! 635: #ifdef HAVE_IPV6
! 636: if (rnode->p.family == AF_INET6)
! 637: {
! 638: drnode = route_node_get (area->route_table6[0], &rnode->p);
! 639: if (drnode->info == rnode->info)
! 640: drnode->info = NULL;
! 641: drnode = route_node_get (area->route_table6[1], &rnode->p);
! 642: if (drnode->info == rnode->info)
! 643: drnode->info = NULL;
! 644: }
! 645: #endif
! 646:
! 647: isis_route_delete (&rnode->p, table);
! 648: }
! 649: }
! 650: }
! 651:
! 652: /* Function to validate route tables for L1L2 areas. In this case we can't use
! 653: * level route tables directly, we have to merge them at first. L1 routes are
! 654: * preferred over the L2 ones.
! 655: *
! 656: * Merge algorithm is trivial (at least for now). All L1 paths are copied into
! 657: * merge table at first, then L2 paths are added if L1 path for same prefix
! 658: * doesn't already exists there.
! 659: *
! 660: * FIXME: Is it right place to do it at all? Maybe we should push both levels
! 661: * to the RIB with different zebra route types and let RIB handle this? */
! 662: static void
! 663: isis_route_validate_merge (struct isis_area *area, int family)
! 664: {
! 665: struct route_table *table = NULL;
! 666: struct route_table *merge;
! 667: struct route_node *rnode, *mrnode;
! 668:
! 669: merge = route_table_init ();
! 670:
! 671: if (family == AF_INET)
! 672: table = area->route_table[0];
! 673: #ifdef HAVE_IPV6
! 674: else if (family == AF_INET6)
! 675: table = area->route_table6[0];
! 676: #endif
! 677:
! 678: for (rnode = route_top (table); rnode; rnode = route_next (rnode))
! 679: {
! 680: if (rnode->info == NULL)
! 681: continue;
! 682: mrnode = route_node_get (merge, &rnode->p);
! 683: mrnode->info = rnode->info;
! 684: }
! 685:
! 686: if (family == AF_INET)
! 687: table = area->route_table[1];
! 688: #ifdef HAVE_IPV6
! 689: else if (family == AF_INET6)
! 690: table = area->route_table6[1];
! 691: #endif
! 692:
! 693: for (rnode = route_top (table); rnode; rnode = route_next (rnode))
! 694: {
! 695: if (rnode->info == NULL)
! 696: continue;
! 697: mrnode = route_node_get (merge, &rnode->p);
! 698: if (mrnode->info != NULL)
! 699: continue;
! 700: mrnode->info = rnode->info;
! 701: }
! 702:
! 703: isis_route_validate_table (area, merge);
! 704: route_table_finish (merge);
! 705: }
! 706:
! 707: /* Walk through route tables and propagate necessary changes into RIB. In case
! 708: * of L1L2 area, level tables have to be merged at first. */
! 709: int
! 710: isis_route_validate (struct thread *thread)
! 711: {
! 712: struct isis_area *area;
! 713:
! 714: area = THREAD_ARG (thread);
! 715:
! 716: if (area->is_type == IS_LEVEL_1)
! 717: {
! 718: isis_route_validate_table (area, area->route_table[0]);
! 719: goto validate_ipv6;
! 720: }
! 721: if (area->is_type == IS_LEVEL_2)
! 722: {
! 723: isis_route_validate_table (area, area->route_table[1]);
! 724: goto validate_ipv6;
! 725: }
! 726:
! 727: isis_route_validate_merge (area, AF_INET);
! 728:
! 729: validate_ipv6:
! 730: #ifdef HAVE_IPV6
! 731: if (area->is_type == IS_LEVEL_1)
! 732: {
! 733: isis_route_validate_table (area, area->route_table6[0]);
! 734: return ISIS_OK;
! 735: }
! 736: if (area->is_type == IS_LEVEL_2)
! 737: {
! 738: isis_route_validate_table (area, area->route_table6[1]);
! 739: return ISIS_OK;
! 740: }
! 741:
! 742: isis_route_validate_merge (area, AF_INET6);
! 743: #endif
! 744:
! 745: return ISIS_OK;
! 746: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>