Annotation of embedaddon/quagga/ospfd/ospf_route.c, revision 1.1
1.1 ! misho 1: /*
! 2: * OSPF routing table.
! 3: * Copyright (C) 1999, 2000 Toshiaki Takada
! 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 "linklist.h"
! 29: #include "log.h"
! 30: #include "if.h"
! 31: #include "command.h"
! 32: #include "sockunion.h"
! 33:
! 34: #include "ospfd/ospfd.h"
! 35: #include "ospfd/ospf_interface.h"
! 36: #include "ospfd/ospf_asbr.h"
! 37: #include "ospfd/ospf_lsa.h"
! 38: #include "ospfd/ospf_route.h"
! 39: #include "ospfd/ospf_spf.h"
! 40: #include "ospfd/ospf_zebra.h"
! 41: #include "ospfd/ospf_dump.h"
! 42:
! 43: struct ospf_route *
! 44: ospf_route_new ()
! 45: {
! 46: struct ospf_route *new;
! 47:
! 48: new = XCALLOC (MTYPE_OSPF_ROUTE, sizeof (struct ospf_route));
! 49:
! 50: new->ctime = quagga_time (NULL);
! 51: new->mtime = new->ctime;
! 52: new->paths = list_new ();
! 53: new->paths->del = (void (*) (void *))ospf_path_free;
! 54:
! 55: return new;
! 56: }
! 57:
! 58: void
! 59: ospf_route_free (struct ospf_route *or)
! 60: {
! 61: if (or->paths)
! 62: list_delete (or->paths);
! 63:
! 64: XFREE (MTYPE_OSPF_ROUTE, or);
! 65: }
! 66:
! 67: struct ospf_path *
! 68: ospf_path_new ()
! 69: {
! 70: struct ospf_path *new;
! 71:
! 72: new = XCALLOC (MTYPE_OSPF_PATH, sizeof (struct ospf_path));
! 73:
! 74: return new;
! 75: }
! 76:
! 77: static struct ospf_path *
! 78: ospf_path_dup (struct ospf_path *path)
! 79: {
! 80: struct ospf_path *new;
! 81:
! 82: new = ospf_path_new ();
! 83: memcpy (new, path, sizeof (struct ospf_path));
! 84:
! 85: return new;
! 86: }
! 87:
! 88: void
! 89: ospf_path_free (struct ospf_path *op)
! 90: {
! 91: XFREE (MTYPE_OSPF_PATH, op);
! 92: }
! 93:
! 94: void
! 95: ospf_route_delete (struct route_table *rt)
! 96: {
! 97: struct route_node *rn;
! 98: struct ospf_route *or;
! 99:
! 100: for (rn = route_top (rt); rn; rn = route_next (rn))
! 101: if ((or = rn->info) != NULL)
! 102: {
! 103: if (or->type == OSPF_DESTINATION_NETWORK)
! 104: ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p,
! 105: or);
! 106: else if (or->type == OSPF_DESTINATION_DISCARD)
! 107: ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p);
! 108: }
! 109: }
! 110:
! 111: void
! 112: ospf_route_table_free (struct route_table *rt)
! 113: {
! 114: struct route_node *rn;
! 115: struct ospf_route *or;
! 116:
! 117: for (rn = route_top (rt); rn; rn = route_next (rn))
! 118: if ((or = rn->info) != NULL)
! 119: {
! 120: ospf_route_free (or);
! 121:
! 122: rn->info = NULL;
! 123: route_unlock_node (rn);
! 124: }
! 125:
! 126: route_table_finish (rt);
! 127: }
! 128:
! 129: /* If a prefix and a nexthop match any route in the routing table,
! 130: then return 1, otherwise return 0. */
! 131: int
! 132: ospf_route_match_same (struct route_table *rt, struct prefix_ipv4 *prefix,
! 133: struct ospf_route *newor)
! 134: {
! 135: struct route_node *rn;
! 136: struct ospf_route *or;
! 137: struct ospf_path *op;
! 138: struct ospf_path *newop;
! 139: struct listnode *n1;
! 140: struct listnode *n2;
! 141:
! 142: if (! rt || ! prefix)
! 143: return 0;
! 144:
! 145: rn = route_node_lookup (rt, (struct prefix *) prefix);
! 146: if (! rn || ! rn->info)
! 147: return 0;
! 148:
! 149: route_unlock_node (rn);
! 150:
! 151: or = rn->info;
! 152: if (or->type == newor->type && or->cost == newor->cost)
! 153: {
! 154: if (or->type == OSPF_DESTINATION_NETWORK)
! 155: {
! 156: if (or->paths->count != newor->paths->count)
! 157: return 0;
! 158:
! 159: /* Check each path. */
! 160: for (n1 = listhead (or->paths), n2 = listhead (newor->paths);
! 161: n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2))
! 162: {
! 163: op = listgetdata (n1);
! 164: newop = listgetdata (n2);
! 165:
! 166: if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
! 167: return 0;
! 168: if (op->ifindex != newop->ifindex)
! 169: return 0;
! 170: }
! 171: return 1;
! 172: }
! 173: else if (prefix_same (&rn->p, (struct prefix *) prefix))
! 174: return 1;
! 175: }
! 176: return 0;
! 177: }
! 178:
! 179: /* delete routes generated from AS-External routes if there is a inter/intra
! 180: * area route
! 181: */
! 182: static void
! 183: ospf_route_delete_same_ext(struct route_table *external_routes,
! 184: struct route_table *routes)
! 185: {
! 186: struct route_node *rn,
! 187: *ext_rn;
! 188:
! 189: if ( (external_routes == NULL) || (routes == NULL) )
! 190: return;
! 191:
! 192: /* Remove deleted routes */
! 193: for ( rn = route_top (routes); rn; rn = route_next (rn) )
! 194: {
! 195: if (rn && rn->info)
! 196: {
! 197: struct prefix_ipv4 *p = (struct prefix_ipv4 *)(&rn->p);
! 198: if ( (ext_rn = route_node_lookup (external_routes, (struct prefix *)p)) )
! 199: {
! 200: if (ext_rn->info)
! 201: {
! 202: ospf_zebra_delete (p, ext_rn->info);
! 203: ospf_route_free( ext_rn->info);
! 204: ext_rn->info = NULL;
! 205: }
! 206: route_unlock_node (ext_rn);
! 207: }
! 208: }
! 209: }
! 210: }
! 211:
! 212: /* rt: Old, cmprt: New */
! 213: static void
! 214: ospf_route_delete_uniq (struct route_table *rt, struct route_table *cmprt)
! 215: {
! 216: struct route_node *rn;
! 217: struct ospf_route *or;
! 218:
! 219: for (rn = route_top (rt); rn; rn = route_next (rn))
! 220: if ((or = rn->info) != NULL)
! 221: if (or->path_type == OSPF_PATH_INTRA_AREA ||
! 222: or->path_type == OSPF_PATH_INTER_AREA)
! 223: {
! 224: if (or->type == OSPF_DESTINATION_NETWORK)
! 225: {
! 226: if (! ospf_route_match_same (cmprt,
! 227: (struct prefix_ipv4 *) &rn->p, or))
! 228: ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
! 229: }
! 230: else if (or->type == OSPF_DESTINATION_DISCARD)
! 231: if (! ospf_route_match_same (cmprt,
! 232: (struct prefix_ipv4 *) &rn->p, or))
! 233: ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p);
! 234: }
! 235: }
! 236:
! 237: /* Install routes to table. */
! 238: void
! 239: ospf_route_install (struct ospf *ospf, struct route_table *rt)
! 240: {
! 241: struct route_node *rn;
! 242: struct ospf_route *or;
! 243:
! 244: /* rt contains new routing table, new_table contains an old one.
! 245: updating pointers */
! 246: if (ospf->old_table)
! 247: ospf_route_table_free (ospf->old_table);
! 248:
! 249: ospf->old_table = ospf->new_table;
! 250: ospf->new_table = rt;
! 251:
! 252: /* Delete old routes. */
! 253: if (ospf->old_table)
! 254: ospf_route_delete_uniq (ospf->old_table, rt);
! 255: if (ospf->old_external_route)
! 256: ospf_route_delete_same_ext (ospf->old_external_route, rt);
! 257:
! 258: /* Install new routes. */
! 259: for (rn = route_top (rt); rn; rn = route_next (rn))
! 260: if ((or = rn->info) != NULL)
! 261: {
! 262: if (or->type == OSPF_DESTINATION_NETWORK)
! 263: {
! 264: if (! ospf_route_match_same (ospf->old_table,
! 265: (struct prefix_ipv4 *)&rn->p, or))
! 266: ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
! 267: }
! 268: else if (or->type == OSPF_DESTINATION_DISCARD)
! 269: if (! ospf_route_match_same (ospf->old_table,
! 270: (struct prefix_ipv4 *) &rn->p, or))
! 271: ospf_zebra_add_discard ((struct prefix_ipv4 *) &rn->p);
! 272: }
! 273: }
! 274:
! 275: static void
! 276: ospf_intra_route_add (struct route_table *rt, struct vertex *v,
! 277: struct ospf_area *area)
! 278: {
! 279: struct route_node *rn;
! 280: struct ospf_route *or;
! 281: struct prefix_ipv4 p;
! 282: struct ospf_path *path;
! 283: struct vertex_parent *parent;
! 284: struct listnode *node, *nnode;
! 285:
! 286: p.family = AF_INET;
! 287: p.prefix = v->id;
! 288: if (v->type == OSPF_VERTEX_ROUTER)
! 289: p.prefixlen = IPV4_MAX_BITLEN;
! 290: else
! 291: {
! 292: struct network_lsa *lsa = (struct network_lsa *) v->lsa;
! 293: p.prefixlen = ip_masklen (lsa->mask);
! 294: }
! 295: apply_mask_ipv4 (&p);
! 296:
! 297: rn = route_node_get (rt, (struct prefix *) &p);
! 298: if (rn->info)
! 299: {
! 300: zlog_warn ("Same routing information exists for %s", inet_ntoa (v->id));
! 301: route_unlock_node (rn);
! 302: return;
! 303: }
! 304:
! 305: or = ospf_route_new ();
! 306:
! 307: if (v->type == OSPF_VERTEX_NETWORK)
! 308: {
! 309: or->type = OSPF_DESTINATION_NETWORK;
! 310:
! 311: for (ALL_LIST_ELEMENTS (v->parents, node, nnode, parent))
! 312: {
! 313: path = ospf_path_new ();
! 314: path->nexthop = parent->nexthop->router;
! 315: listnode_add (or->paths, path);
! 316: }
! 317: }
! 318: else
! 319: or->type = OSPF_DESTINATION_ROUTER;
! 320:
! 321: or->id = v->id;
! 322: or->u.std.area_id = area->area_id;
! 323: or->u.std.external_routing= area->external_routing;
! 324: or->path_type = OSPF_PATH_INTRA_AREA;
! 325: or->cost = v->distance;
! 326:
! 327: rn->info = or;
! 328: }
! 329:
! 330: /* RFC2328 16.1. (4). For "router". */
! 331: void
! 332: ospf_intra_add_router (struct route_table *rt, struct vertex *v,
! 333: struct ospf_area *area)
! 334: {
! 335: struct route_node *rn;
! 336: struct ospf_route *or;
! 337: struct prefix_ipv4 p;
! 338: struct router_lsa *lsa;
! 339:
! 340: if (IS_DEBUG_OSPF_EVENT)
! 341: zlog_debug ("ospf_intra_add_router: Start");
! 342:
! 343: lsa = (struct router_lsa *) v->lsa;
! 344:
! 345: if (IS_DEBUG_OSPF_EVENT)
! 346: zlog_debug ("ospf_intra_add_router: LS ID: %s",
! 347: inet_ntoa (lsa->header.id));
! 348:
! 349: if (!OSPF_IS_AREA_BACKBONE(area))
! 350: ospf_vl_up_check (area, lsa->header.id, v);
! 351:
! 352: if (!CHECK_FLAG (lsa->flags, ROUTER_LSA_SHORTCUT))
! 353: area->shortcut_capability = 0;
! 354:
! 355: /* If the newly added vertex is an area border router or AS boundary
! 356: router, a routing table entry is added whose destination type is
! 357: "router". */
! 358: if (! IS_ROUTER_LSA_BORDER (lsa) && ! IS_ROUTER_LSA_EXTERNAL (lsa))
! 359: {
! 360: if (IS_DEBUG_OSPF_EVENT)
! 361: zlog_debug ("ospf_intra_add_router: "
! 362: "this router is neither ASBR nor ABR, skipping it");
! 363: return;
! 364: }
! 365:
! 366: /* Update ABR and ASBR count in this area. */
! 367: if (IS_ROUTER_LSA_BORDER (lsa))
! 368: area->abr_count++;
! 369: if (IS_ROUTER_LSA_EXTERNAL (lsa))
! 370: area->asbr_count++;
! 371:
! 372: /* The Options field found in the associated router-LSA is copied
! 373: into the routing table entry's Optional capabilities field. Call
! 374: the newly added vertex Router X. */
! 375: or = ospf_route_new ();
! 376:
! 377: or->id = v->id;
! 378: or->u.std.area_id = area->area_id;
! 379: or->u.std.external_routing = area->external_routing;
! 380: or->path_type = OSPF_PATH_INTRA_AREA;
! 381: or->cost = v->distance;
! 382: or->type = OSPF_DESTINATION_ROUTER;
! 383: or->u.std.origin = (struct lsa_header *) lsa;
! 384: or->u.std.options = lsa->header.options;
! 385: or->u.std.flags = lsa->flags;
! 386:
! 387: /* If Router X is the endpoint of one of the calculating router's
! 388: virtual links, and the virtual link uses Area A as Transit area:
! 389: the virtual link is declared up, the IP address of the virtual
! 390: interface is set to the IP address of the outgoing interface
! 391: calculated above for Router X, and the virtual neighbor's IP
! 392: address is set to Router X's interface address (contained in
! 393: Router X's router-LSA) that points back to the root of the
! 394: shortest- path tree; equivalently, this is the interface that
! 395: points back to Router X's parent vertex on the shortest-path tree
! 396: (similar to the calculation in Section 16.1.1). */
! 397:
! 398: p.family = AF_INET;
! 399: p.prefix = v->id;
! 400: p.prefixlen = IPV4_MAX_BITLEN;
! 401:
! 402: if (IS_DEBUG_OSPF_EVENT)
! 403: zlog_debug ("ospf_intra_add_router: talking about %s/%d",
! 404: inet_ntoa (p.prefix), p.prefixlen);
! 405:
! 406: rn = route_node_get (rt, (struct prefix *) &p);
! 407:
! 408: /* Note that we keep all routes to ABRs and ASBRs, not only the best */
! 409: if (rn->info == NULL)
! 410: rn->info = list_new ();
! 411: else
! 412: route_unlock_node (rn);
! 413:
! 414: ospf_route_copy_nexthops_from_vertex (or, v);
! 415:
! 416: listnode_add (rn->info, or);
! 417:
! 418: if (IS_DEBUG_OSPF_EVENT)
! 419: zlog_debug ("ospf_intra_add_router: Stop");
! 420: }
! 421:
! 422: /* RFC2328 16.1. (4). For transit network. */
! 423: void
! 424: ospf_intra_add_transit (struct route_table *rt, struct vertex *v,
! 425: struct ospf_area *area)
! 426: {
! 427: struct route_node *rn;
! 428: struct ospf_route *or;
! 429: struct prefix_ipv4 p;
! 430: struct network_lsa *lsa;
! 431:
! 432: lsa = (struct network_lsa*) v->lsa;
! 433:
! 434: /* If the newly added vertex is a transit network, the routing table
! 435: entry for the network is located. The entry's Destination ID is
! 436: the IP network number, which can be obtained by masking the
! 437: Vertex ID (Link State ID) with its associated subnet mask (found
! 438: in the body of the associated network-LSA). */
! 439: p.family = AF_INET;
! 440: p.prefix = v->id;
! 441: p.prefixlen = ip_masklen (lsa->mask);
! 442: apply_mask_ipv4 (&p);
! 443:
! 444: rn = route_node_get (rt, (struct prefix *) &p);
! 445:
! 446: /* If the routing table entry already exists (i.e., there is already
! 447: an intra-area route to the destination installed in the routing
! 448: table), multiple vertices have mapped to the same IP network.
! 449: For example, this can occur when a new Designated Router is being
! 450: established. In this case, the current routing table entry
! 451: should be overwritten if and only if the newly found path is just
! 452: as short and the current routing table entry's Link State Origin
! 453: has a smaller Link State ID than the newly added vertex' LSA. */
! 454: if (rn->info)
! 455: {
! 456: struct ospf_route *cur_or;
! 457:
! 458: route_unlock_node (rn);
! 459: cur_or = rn->info;
! 460:
! 461: if (v->distance > cur_or->cost ||
! 462: IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) > 0)
! 463: return;
! 464:
! 465: ospf_route_free (rn->info);
! 466: }
! 467:
! 468: or = ospf_route_new ();
! 469:
! 470: or->id = v->id;
! 471: or->u.std.area_id = area->area_id;
! 472: or->u.std.external_routing = area->external_routing;
! 473: or->path_type = OSPF_PATH_INTRA_AREA;
! 474: or->cost = v->distance;
! 475: or->type = OSPF_DESTINATION_NETWORK;
! 476: or->u.std.origin = (struct lsa_header *) lsa;
! 477:
! 478: ospf_route_copy_nexthops_from_vertex (or, v);
! 479:
! 480: rn->info = or;
! 481: }
! 482:
! 483: /* RFC2328 16.1. second stage. */
! 484: void
! 485: ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link,
! 486: struct vertex *v, struct ospf_area *area,
! 487: int parent_is_root)
! 488: {
! 489: u_int32_t cost;
! 490: struct route_node *rn;
! 491: struct ospf_route *or;
! 492: struct prefix_ipv4 p;
! 493: struct router_lsa *lsa;
! 494: struct ospf_interface *oi;
! 495: struct ospf_path *path;
! 496:
! 497: if (IS_DEBUG_OSPF_EVENT)
! 498: zlog_debug ("ospf_intra_add_stub(): Start");
! 499:
! 500: lsa = (struct router_lsa *) v->lsa;
! 501:
! 502: p.family = AF_INET;
! 503: p.prefix = link->link_id;
! 504: p.prefixlen = ip_masklen (link->link_data);
! 505: apply_mask_ipv4 (&p);
! 506:
! 507: if (IS_DEBUG_OSPF_EVENT)
! 508: zlog_debug ("ospf_intra_add_stub(): processing route to %s/%d",
! 509: inet_ntoa (p.prefix), p.prefixlen);
! 510:
! 511: /* (1) Calculate the distance D of stub network from the root. D is
! 512: equal to the distance from the root to the router vertex
! 513: (calculated in stage 1), plus the stub network link's advertised
! 514: cost. */
! 515: cost = v->distance + ntohs (link->m[0].metric);
! 516:
! 517: if (IS_DEBUG_OSPF_EVENT)
! 518: zlog_debug ("ospf_intra_add_stub(): calculated cost is %d + %d = %d",
! 519: v->distance, ntohs(link->m[0].metric), cost);
! 520:
! 521: /* PtP links with /32 masks adds host routes to remote, directly
! 522: * connected hosts, see RFC 2328, 12.4.1.1, Option 1.
! 523: * Such routes can just be ignored for the sake of tidyness.
! 524: */
! 525: if (parent_is_root && link->link_data.s_addr == 0xffffffff &&
! 526: ospf_if_lookup_by_local_addr (area->ospf, NULL, link->link_id))
! 527: {
! 528: if (IS_DEBUG_OSPF_EVENT)
! 529: zlog_debug ("%s: ignoring host route %s/32 to self.",
! 530: __func__, inet_ntoa (link->link_id));
! 531: return;
! 532: }
! 533:
! 534: rn = route_node_get (rt, (struct prefix *) &p);
! 535:
! 536: /* Lookup current routing table. */
! 537: if (rn->info)
! 538: {
! 539: struct ospf_route *cur_or;
! 540:
! 541: route_unlock_node (rn);
! 542:
! 543: cur_or = rn->info;
! 544:
! 545: if (IS_DEBUG_OSPF_EVENT)
! 546: zlog_debug ("ospf_intra_add_stub(): "
! 547: "another route to the same prefix found with cost %u",
! 548: cur_or->cost);
! 549:
! 550: /* Compare this distance to the current best cost to the stub
! 551: network. This is done by looking up the stub network's
! 552: current routing table entry. If the calculated distance D is
! 553: larger, go on to examine the next stub network link in the
! 554: LSA. */
! 555: if (cost > cur_or->cost)
! 556: {
! 557: if (IS_DEBUG_OSPF_EVENT)
! 558: zlog_debug ("ospf_intra_add_stub(): old route is better, exit");
! 559: return;
! 560: }
! 561:
! 562: /* (2) If this step is reached, the stub network's routing table
! 563: entry must be updated. Calculate the set of next hops that
! 564: would result from using the stub network link. This
! 565: calculation is shown in Section 16.1.1; input to this
! 566: calculation is the destination (the stub network) and the
! 567: parent vertex (the router vertex). If the distance D is the
! 568: same as the current routing table cost, simply add this set
! 569: of next hops to the routing table entry's list of next hops.
! 570: In this case, the routing table already has a Link State
! 571: Origin. If this Link State Origin is a router-LSA whose Link
! 572: State ID is smaller than V's Router ID, reset the Link State
! 573: Origin to V's router-LSA. */
! 574:
! 575: if (cost == cur_or->cost)
! 576: {
! 577: if (IS_DEBUG_OSPF_EVENT)
! 578: zlog_debug ("ospf_intra_add_stub(): routes are equal, merge");
! 579:
! 580: ospf_route_copy_nexthops_from_vertex (cur_or, v);
! 581:
! 582: if (IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) < 0)
! 583: cur_or->u.std.origin = (struct lsa_header *) lsa;
! 584: return;
! 585: }
! 586:
! 587: /* Otherwise D is smaller than the routing table cost.
! 588: Overwrite the current routing table entry by setting the
! 589: routing table entry's cost to D, and by setting the entry's
! 590: list of next hops to the newly calculated set. Set the
! 591: routing table entry's Link State Origin to V's router-LSA.
! 592: Then go on to examine the next stub network link. */
! 593:
! 594: if (cost < cur_or->cost)
! 595: {
! 596: if (IS_DEBUG_OSPF_EVENT)
! 597: zlog_debug ("ospf_intra_add_stub(): new route is better, set it");
! 598:
! 599: cur_or->cost = cost;
! 600:
! 601: list_delete_all_node (cur_or->paths);
! 602:
! 603: ospf_route_copy_nexthops_from_vertex (cur_or, v);
! 604:
! 605: cur_or->u.std.origin = (struct lsa_header *) lsa;
! 606: return;
! 607: }
! 608: }
! 609:
! 610: if (IS_DEBUG_OSPF_EVENT)
! 611: zlog_debug ("ospf_intra_add_stub(): installing new route");
! 612:
! 613: or = ospf_route_new ();
! 614:
! 615: or->id = v->id;
! 616: or->u.std.area_id = area->area_id;
! 617: or->u.std.external_routing = area->external_routing;
! 618: or->path_type = OSPF_PATH_INTRA_AREA;
! 619: or->cost = cost;
! 620: or->type = OSPF_DESTINATION_NETWORK;
! 621: or->u.std.origin = (struct lsa_header *) lsa;
! 622:
! 623: /* Nexthop is depend on connection type. */
! 624: if (v != area->spf)
! 625: {
! 626: if (IS_DEBUG_OSPF_EVENT)
! 627: zlog_debug ("ospf_intra_add_stub(): this network is on remote router");
! 628: ospf_route_copy_nexthops_from_vertex (or, v);
! 629: }
! 630: else
! 631: {
! 632: if (IS_DEBUG_OSPF_EVENT)
! 633: zlog_debug ("ospf_intra_add_stub(): this network is on this router");
! 634:
! 635: if ((oi = ospf_if_lookup_by_prefix (area->ospf, &p)))
! 636: {
! 637: if (IS_DEBUG_OSPF_EVENT)
! 638: zlog_debug ("ospf_intra_add_stub(): the interface is %s",
! 639: IF_NAME (oi));
! 640:
! 641: path = ospf_path_new ();
! 642: path->nexthop.s_addr = 0;
! 643: path->ifindex = oi->ifp->ifindex;
! 644: listnode_add (or->paths, path);
! 645: }
! 646: else
! 647: {
! 648: if (IS_DEBUG_OSPF_EVENT)
! 649: zlog_debug ("ospf_intra_add_stub(): where's the interface ?");
! 650: }
! 651: }
! 652:
! 653: rn->info = or;
! 654:
! 655: if (IS_DEBUG_OSPF_EVENT)
! 656: zlog_debug("ospf_intra_add_stub(): Stop");
! 657: }
! 658:
! 659: const char *ospf_path_type_str[] =
! 660: {
! 661: "unknown-type",
! 662: "intra-area",
! 663: "inter-area",
! 664: "type1-external",
! 665: "type2-external"
! 666: };
! 667:
! 668: void
! 669: ospf_route_table_dump (struct route_table *rt)
! 670: {
! 671: struct route_node *rn;
! 672: struct ospf_route *or;
! 673: char buf1[BUFSIZ];
! 674: char buf2[BUFSIZ];
! 675: struct listnode *pnode;
! 676: struct ospf_path *path;
! 677:
! 678: #if 0
! 679: zlog_debug ("Type Dest Area Path Type Cost Next Adv.");
! 680: zlog_debug (" Hop(s) Router(s)");
! 681: #endif /* 0 */
! 682:
! 683: zlog_debug ("========== OSPF routing table ==========");
! 684: for (rn = route_top (rt); rn; rn = route_next (rn))
! 685: if ((or = rn->info) != NULL)
! 686: {
! 687: if (or->type == OSPF_DESTINATION_NETWORK)
! 688: {
! 689: zlog_debug ("N %s/%d\t%s\t%s\t%d",
! 690: inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ),
! 691: rn->p.prefixlen,
! 692: inet_ntop (AF_INET, &or->u.std.area_id, buf2,
! 693: BUFSIZ),
! 694: ospf_path_type_str[or->path_type],
! 695: or->cost);
! 696: for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path))
! 697: zlog_debug (" -> %s", inet_ntoa (path->nexthop));
! 698: }
! 699: else
! 700: zlog_debug ("R %s\t%s\t%s\t%d",
! 701: inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ),
! 702: inet_ntop (AF_INET, &or->u.std.area_id, buf2,
! 703: BUFSIZ),
! 704: ospf_path_type_str[or->path_type],
! 705: or->cost);
! 706: }
! 707: zlog_debug ("========================================");
! 708: }
! 709:
! 710: /* This is 16.4.1 implementation.
! 711: o Intra-area paths using non-backbone areas are always the most preferred.
! 712: o The other paths, intra-area backbone paths and inter-area paths,
! 713: are of equal preference. */
! 714: static int
! 715: ospf_asbr_route_cmp (struct ospf *ospf, struct ospf_route *r1,
! 716: struct ospf_route *r2)
! 717: {
! 718: u_char r1_type, r2_type;
! 719:
! 720: r1_type = r1->path_type;
! 721: r2_type = r2->path_type;
! 722:
! 723: /* r1/r2 itself is backbone, and it's Inter-area path. */
! 724: if (OSPF_IS_AREA_ID_BACKBONE (r1->u.std.area_id))
! 725: r1_type = OSPF_PATH_INTER_AREA;
! 726: if (OSPF_IS_AREA_ID_BACKBONE (r2->u.std.area_id))
! 727: r2_type = OSPF_PATH_INTER_AREA;
! 728:
! 729: return (r1_type - r2_type);
! 730: }
! 731:
! 732: /* Compare two routes.
! 733: ret < 0 -- r1 is better.
! 734: ret == 0 -- r1 and r2 are the same.
! 735: ret > 0 -- r2 is better. */
! 736: int
! 737: ospf_route_cmp (struct ospf *ospf, struct ospf_route *r1,
! 738: struct ospf_route *r2)
! 739: {
! 740: int ret = 0;
! 741:
! 742: /* Path types of r1 and r2 are not the same. */
! 743: if ((ret = (r1->path_type - r2->path_type)))
! 744: return ret;
! 745:
! 746: if (IS_DEBUG_OSPF_EVENT)
! 747: zlog_debug ("Route[Compare]: Path types are the same.");
! 748: /* Path types are the same, compare any cost. */
! 749: switch (r1->path_type)
! 750: {
! 751: case OSPF_PATH_INTRA_AREA:
! 752: case OSPF_PATH_INTER_AREA:
! 753: break;
! 754: case OSPF_PATH_TYPE1_EXTERNAL:
! 755: if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE))
! 756: {
! 757: ret = ospf_asbr_route_cmp (ospf, r1->u.ext.asbr, r2->u.ext.asbr);
! 758: if (ret != 0)
! 759: return ret;
! 760: }
! 761: break;
! 762: case OSPF_PATH_TYPE2_EXTERNAL:
! 763: if ((ret = (r1->u.ext.type2_cost - r2->u.ext.type2_cost)))
! 764: return ret;
! 765:
! 766: if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE))
! 767: {
! 768: ret = ospf_asbr_route_cmp (ospf, r1->u.ext.asbr, r2->u.ext.asbr);
! 769: if (ret != 0)
! 770: return ret;
! 771: }
! 772: break;
! 773: }
! 774:
! 775: /* Anyway, compare the costs. */
! 776: return (r1->cost - r2->cost);
! 777: }
! 778:
! 779: static int
! 780: ospf_path_exist (struct list *plist, struct in_addr nexthop,
! 781: struct ospf_interface *oi)
! 782: {
! 783: struct listnode *node, *nnode;
! 784: struct ospf_path *path;
! 785:
! 786: for (ALL_LIST_ELEMENTS (plist, node, nnode, path))
! 787: if (IPV4_ADDR_SAME (&path->nexthop, &nexthop) &&
! 788: path->ifindex == oi->ifp->ifindex)
! 789: return 1;
! 790:
! 791: return 0;
! 792: }
! 793:
! 794: void
! 795: ospf_route_copy_nexthops_from_vertex (struct ospf_route *to,
! 796: struct vertex *v)
! 797: {
! 798: struct listnode *node;
! 799: struct ospf_path *path;
! 800: struct vertex_nexthop *nexthop;
! 801: struct vertex_parent *vp;
! 802:
! 803: assert (to->paths);
! 804:
! 805: for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp))
! 806: {
! 807: nexthop = vp->nexthop;
! 808:
! 809: if (nexthop->oi != NULL)
! 810: {
! 811: if (! ospf_path_exist (to->paths, nexthop->router, nexthop->oi))
! 812: {
! 813: path = ospf_path_new ();
! 814: path->nexthop = nexthop->router;
! 815: path->ifindex = nexthop->oi->ifp->ifindex;
! 816: listnode_add (to->paths, path);
! 817: }
! 818: }
! 819: }
! 820: }
! 821:
! 822: struct ospf_path *
! 823: ospf_path_lookup (struct list *plist, struct ospf_path *path)
! 824: {
! 825: struct listnode *node;
! 826: struct ospf_path *op;
! 827:
! 828: for (ALL_LIST_ELEMENTS_RO (plist, node, op))
! 829: {
! 830: if (!IPV4_ADDR_SAME (&op->nexthop, &path->nexthop))
! 831: continue;
! 832: if (!IPV4_ADDR_SAME (&op->adv_router, &path->adv_router))
! 833: continue;
! 834: if (op->ifindex != path->ifindex)
! 835: continue;
! 836: return op;
! 837: }
! 838: return NULL;
! 839: }
! 840:
! 841: void
! 842: ospf_route_copy_nexthops (struct ospf_route *to, struct list *from)
! 843: {
! 844: struct listnode *node, *nnode;
! 845: struct ospf_path *path;
! 846:
! 847: assert (to->paths);
! 848:
! 849: for (ALL_LIST_ELEMENTS (from, node, nnode, path))
! 850: /* The same routes are just discarded. */
! 851: if (!ospf_path_lookup (to->paths, path))
! 852: listnode_add (to->paths, ospf_path_dup (path));
! 853: }
! 854:
! 855: void
! 856: ospf_route_subst_nexthops (struct ospf_route *to, struct list *from)
! 857: {
! 858:
! 859: list_delete_all_node (to->paths);
! 860: ospf_route_copy_nexthops (to, from);
! 861: }
! 862:
! 863: void
! 864: ospf_route_subst (struct route_node *rn, struct ospf_route *new_or,
! 865: struct ospf_route *over)
! 866: {
! 867: route_lock_node (rn);
! 868: ospf_route_free (rn->info);
! 869:
! 870: ospf_route_copy_nexthops (new_or, over->paths);
! 871: rn->info = new_or;
! 872: route_unlock_node (rn);
! 873: }
! 874:
! 875: void
! 876: ospf_route_add (struct route_table *rt, struct prefix_ipv4 *p,
! 877: struct ospf_route *new_or, struct ospf_route *over)
! 878: {
! 879: struct route_node *rn;
! 880:
! 881: rn = route_node_get (rt, (struct prefix *) p);
! 882:
! 883: ospf_route_copy_nexthops (new_or, over->paths);
! 884:
! 885: if (rn->info)
! 886: {
! 887: if (IS_DEBUG_OSPF_EVENT)
! 888: zlog_debug ("ospf_route_add(): something's wrong !");
! 889: route_unlock_node (rn);
! 890: return;
! 891: }
! 892:
! 893: rn->info = new_or;
! 894: }
! 895:
! 896: void
! 897: ospf_prune_unreachable_networks (struct route_table *rt)
! 898: {
! 899: struct route_node *rn, *next;
! 900: struct ospf_route *or;
! 901:
! 902: if (IS_DEBUG_OSPF_EVENT)
! 903: zlog_debug ("Pruning unreachable networks");
! 904:
! 905: for (rn = route_top (rt); rn; rn = next)
! 906: {
! 907: next = route_next (rn);
! 908: if (rn->info != NULL)
! 909: {
! 910: or = rn->info;
! 911: if (listcount (or->paths) == 0)
! 912: {
! 913: if (IS_DEBUG_OSPF_EVENT)
! 914: zlog_debug ("Pruning route to %s/%d",
! 915: inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
! 916:
! 917: ospf_route_free (or);
! 918: rn->info = NULL;
! 919: route_unlock_node (rn);
! 920: }
! 921: }
! 922: }
! 923: }
! 924:
! 925: void
! 926: ospf_prune_unreachable_routers (struct route_table *rtrs)
! 927: {
! 928: struct route_node *rn, *next;
! 929: struct ospf_route *or;
! 930: struct listnode *node, *nnode;
! 931: struct list *paths;
! 932:
! 933: if (IS_DEBUG_OSPF_EVENT)
! 934: zlog_debug ("Pruning unreachable routers");
! 935:
! 936: for (rn = route_top (rtrs); rn; rn = next)
! 937: {
! 938: next = route_next (rn);
! 939: if ((paths = rn->info) == NULL)
! 940: continue;
! 941:
! 942: for (ALL_LIST_ELEMENTS (paths, node, nnode, or))
! 943: {
! 944: if (listcount (or->paths) == 0)
! 945: {
! 946: if (IS_DEBUG_OSPF_EVENT)
! 947: {
! 948: zlog_debug ("Pruning route to rtr %s",
! 949: inet_ntoa (rn->p.u.prefix4));
! 950: zlog_debug (" via area %s",
! 951: inet_ntoa (or->u.std.area_id));
! 952: }
! 953:
! 954: listnode_delete (paths, or);
! 955: ospf_route_free (or);
! 956: }
! 957: }
! 958:
! 959: if (listcount (paths) == 0)
! 960: {
! 961: if (IS_DEBUG_OSPF_EVENT)
! 962: zlog_debug ("Pruning router node %s", inet_ntoa (rn->p.u.prefix4));
! 963:
! 964: list_delete (paths);
! 965: rn->info = NULL;
! 966: route_unlock_node (rn);
! 967: }
! 968: }
! 969: }
! 970:
! 971: int
! 972: ospf_add_discard_route (struct route_table *rt, struct ospf_area *area,
! 973: struct prefix_ipv4 *p)
! 974: {
! 975: struct route_node *rn;
! 976: struct ospf_route *or, *new_or;
! 977:
! 978: rn = route_node_get (rt, (struct prefix *) p);
! 979:
! 980: if (rn == NULL)
! 981: {
! 982: if (IS_DEBUG_OSPF_EVENT)
! 983: zlog_debug ("ospf_add_discard_route(): router installation error");
! 984: return 0;
! 985: }
! 986:
! 987: if (rn->info) /* If the route to the same destination is found */
! 988: {
! 989: route_unlock_node (rn);
! 990:
! 991: or = rn->info;
! 992:
! 993: if (or->path_type == OSPF_PATH_INTRA_AREA)
! 994: {
! 995: if (IS_DEBUG_OSPF_EVENT)
! 996: zlog_debug ("ospf_add_discard_route(): "
! 997: "an intra-area route exists");
! 998: return 0;
! 999: }
! 1000:
! 1001: if (or->type == OSPF_DESTINATION_DISCARD)
! 1002: {
! 1003: if (IS_DEBUG_OSPF_EVENT)
! 1004: zlog_debug ("ospf_add_discard_route(): "
! 1005: "discard entry already installed");
! 1006: return 0;
! 1007: }
! 1008:
! 1009: ospf_route_free (rn->info);
! 1010: }
! 1011:
! 1012: new_or = ospf_route_new ();
! 1013: new_or->type = OSPF_DESTINATION_DISCARD;
! 1014: new_or->id.s_addr = 0;
! 1015: new_or->cost = 0;
! 1016: new_or->u.std.area_id = area->area_id;
! 1017: new_or->u.std.external_routing = area->external_routing;
! 1018: new_or->path_type = OSPF_PATH_INTER_AREA;
! 1019: rn->info = new_or;
! 1020:
! 1021: ospf_zebra_add_discard (p);
! 1022:
! 1023: return 1;
! 1024: }
! 1025:
! 1026: void
! 1027: ospf_delete_discard_route (struct prefix_ipv4 *p)
! 1028: {
! 1029: ospf_zebra_delete_discard(p);
! 1030: }
! 1031:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>