1/* 2 * OSPF AS external route calculation. 3 * Copyright (C) 1999, 2000 Alex Zinin, 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 "thread.h" 26#include "memory.h" 27#include "hash.h" 28#include "linklist.h" 29#include "prefix.h" 30#include "if.h" 31#include "table.h" 32#include "vty.h" 33#include "log.h" 34 35#include "ospfd/ospfd.h" 36#include "ospfd/ospf_interface.h" 37#include "ospfd/ospf_ism.h" 38#include "ospfd/ospf_asbr.h" 39#include "ospfd/ospf_lsa.h" 40#include "ospfd/ospf_lsdb.h" 41#include "ospfd/ospf_neighbor.h" 42#include "ospfd/ospf_nsm.h" 43#include "ospfd/ospf_spf.h" 44#include "ospfd/ospf_route.h" 45#include "ospfd/ospf_ase.h" 46#include "ospfd/ospf_zebra.h" 47#include "ospfd/ospf_dump.h" 48 49#define DEBUG 50 51struct ospf_route * 52ospf_find_asbr_route (struct route_table *rtrs, struct prefix_ipv4 *asbr) 53{ 54 struct route_node *rn; 55 struct ospf_route *or, *best = NULL; 56 listnode node; 57 list chosen; 58 59 /* Sanity check. */ 60 if (rtrs == NULL) 61 return NULL; 62 63 rn = route_node_lookup (rtrs, (struct prefix *) asbr); 64 if (! rn) 65 return NULL; 66 67 route_unlock_node (rn); 68 69 chosen = list_new (); 70 71 /* First try to find intra-area non-bb paths. */ 72 if (!CHECK_FLAG (ospf_top->config, OSPF_RFC1583_COMPATIBLE)) 73 for (node = listhead ((list) rn->info); node; nextnode (node)) 74 if ((or = getdata (node)) != NULL) 75 if (or->cost < OSPF_LS_INFINITY) 76 if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id) && 77 or->path_type == OSPF_PATH_INTRA_AREA) 78 listnode_add (chosen, or); 79 80 /* If none is found -- look through all. */ 81 if (listcount (chosen) == 0) 82 { 83 list_free (chosen); 84 chosen = rn->info; 85 } 86 87 /* Now find the route with least cost. */ 88 for (node = listhead (chosen); node; nextnode (node)) 89 if ((or = getdata (node)) != NULL) 90 if (or->cost < OSPF_LS_INFINITY) 91 { 92 if (best == NULL) 93 best = or; 94 else if (best->cost > or->cost) 95 best = or; 96 else if (best->cost == or->cost && 97 IPV4_ADDR_CMP (&best->u.std.area_id, 98 &or->u.std.area_id) < 0) 99 best = or; 100 } 101 102 if (chosen != rn->info) 103 list_delete (chosen); 104 105 return best; 106} 107 108struct ospf_route * 109ospf_find_asbr_route_through_area (struct route_table *rtrs, 110 struct prefix_ipv4 *asbr, 111 struct ospf_area *area) 112{ 113 struct route_node *rn; 114 115 /* Sanity check. */ 116 if (rtrs == NULL) 117 return NULL; 118 119 rn = route_node_lookup (rtrs, (struct prefix *) asbr); 120 121 if (rn) 122 { 123 listnode node; 124 struct ospf_route *or; 125 126 route_unlock_node (rn); 127 128 for (node = listhead ((list) rn->info); node; nextnode (node)) 129 if ((or = getdata (node)) != NULL) 130 if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) 131 return or; 132 } 133 134 return NULL; 135} 136 137void 138ospf_ase_complete_direct_routes (struct ospf_route *ro, struct in_addr nexthop) 139{ 140 listnode node; 141 struct ospf_path *op; 142 143 for (node = listhead (ro->path); node; nextnode (node)) 144 if ((op = getdata (node)) != NULL) 145 if (op->nexthop.s_addr == 0) 146 op->nexthop.s_addr = nexthop.s_addr; 147} 148 149int 150ospf_ase_forward_address_check (struct in_addr fwd_addr) 151{ 152 listnode ifn; 153 struct ospf_interface *oi; 154 155 for (ifn = listhead (ospf_top->oiflist); ifn; nextnode (ifn)) 156 if ((oi = getdata (ifn)) != NULL) 157 if (if_is_up (oi->ifp)) 158 if (oi->type != OSPF_IFTYPE_VIRTUALLINK) 159 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &fwd_addr)) 160 return 0; 161 162 return 1; 163} 164 165/* Calculate ASBR route. */ 166struct ospf_route * 167ospf_ase_calculate_asbr_route (struct route_table *rt_network, 168 struct route_table *rt_router, 169 struct as_external_lsa *al) 170{ 171 struct prefix_ipv4 asbr; 172 struct ospf_route *asbr_route; 173 struct route_node *rn; 174 175 /* Find ASBR route from Router routing table. */ 176 asbr.family = AF_INET; 177 asbr.prefix = al->header.adv_router; 178 asbr.prefixlen = IPV4_MAX_BITLEN; 179 apply_mask_ipv4 (&asbr); 180 181 asbr_route = ospf_find_asbr_route (rt_router, &asbr); 182 183 if (asbr_route == NULL) 184 { 185 zlog_info ("ospf_ase_calculate(): Route to ASBR %s not found", 186 inet_ntoa (asbr.prefix)); 187 return NULL; 188 } 189 190 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) 191 { 192 zlog_info ("ospf_ase_calculate(): Originating router is not an ASBR"); 193 return NULL; 194 } 195 196 if (al->e[0].fwd_addr.s_addr != 0) 197 { 198 zlog_info ("ospf_ase_calculate(): " 199 "Forwarding address is not 0.0.0.0."); 200 201 if (! ospf_ase_forward_address_check (al->e[0].fwd_addr)) 202 { 203 zlog_info ("ospf_ase_calculate(): " 204 "Forwarding address is one of our addresses, Ignore."); 205 return NULL; 206 } 207 208 zlog_info ("ospf_ase_calculate(): " 209 "Looking up in the Network Routing Table."); 210 211 /* Looking up the path to the fwd_addr from Network route. */ 212 asbr.family = AF_INET; 213 asbr.prefix = al->e[0].fwd_addr; 214 asbr.prefixlen = IPV4_MAX_BITLEN; 215 216 rn = route_node_match (rt_network, (struct prefix *) &asbr); 217 218 if (rn == NULL) 219 { 220 zlog_info ("ospf_ase_calculate(): " 221 "Couldn't find a route to the forwarding address."); 222 return NULL; 223 } 224 225 route_unlock_node (rn); 226 227 if ((asbr_route = rn->info) == NULL) 228 { 229 zlog_info ("ospf_ase_calculate(): " 230 "Somehow OSPF route to ASBR is lost"); 231 return NULL; 232 } 233 } 234 235 return asbr_route; 236} 237 238struct ospf_route * 239ospf_ase_calculate_new_route (struct ospf_lsa *lsa, 240 struct ospf_route *asbr_route, u_int32_t metric) 241{ 242 struct as_external_lsa *al; 243 struct ospf_route *new; 244 245 al = (struct as_external_lsa *) lsa->data; 246 247 new = ospf_route_new (); 248 249 /* Set redistributed type -- does make sense? */ 250 /* new->type = type; */ 251 new->id = al->header.id; 252 new->mask = al->mask; 253 254 if (!IS_EXTERNAL_METRIC (al->e[0].tos)) 255 { 256 zlog_info ("Route[External]: type-1 created."); 257 new->path_type = OSPF_PATH_TYPE1_EXTERNAL; 258 new->cost = asbr_route->cost + metric; /* X + Y */ 259 } 260 else 261 { 262 zlog_info ("Route[External]: type-2 created."); 263 new->path_type = OSPF_PATH_TYPE2_EXTERNAL; 264 new->cost = asbr_route->cost; /* X */ 265 new->u.ext.type2_cost = metric; /* Y */ 266 } 267 268 new->type = OSPF_DESTINATION_NETWORK; 269 new->path = list_new (); 270 new->u.ext.origin = lsa; 271 new->u.ext.tag = ntohl (al->e[0].route_tag); 272 new->u.ext.asbr = asbr_route; 273 274 assert (new != asbr_route); 275 276 return new; 277} 278 279#define OSPF_ASE_CALC_INTERVAL 1 280 281int 282ospf_ase_calculate_route (struct ospf_lsa * lsa, void * p_arg, int n_arg) 283{ 284 u_int32_t metric; 285 struct as_external_lsa *al; 286 struct ospf_route *asbr_route; 287 struct prefix_ipv4 asbr, p; 288 struct route_node *rn; 289 struct ospf_route *new, *or; 290 int ret; 291 292 assert (lsa); 293 al = (struct as_external_lsa *) lsa->data; 294 295#ifdef HAVE_NSSA 296 if (lsa->data->type == OSPF_AS_NSSA_LSA) 297 if (IS_DEBUG_OSPF_NSSA) 298 zlog_info ("ospf_ase_calc(): Processing Type-7"); 299 300 /* Stay away from any Local Translated Type-7 LSAs */ 301 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) 302 { 303 if (IS_DEBUG_OSPF_NSSA) 304 zlog_info ("ospf_ase_calc(): Rejecting Local Xlt'd"); 305 return 0; 306 } 307#endif /* HAVE_NSSA */ 308 309 zlog_info ("Route[External]: Calculate AS-external-LSA to %s/%d", 310 inet_ntoa (al->header.id), ip_masklen (al->mask)); 311 /* (1) If the cost specified by the LSA is LSInfinity, or if the 312 LSA's LS age is equal to MaxAge, then examine the next LSA. */ 313 if ((metric = GET_METRIC (al->e[0].metric)) >= OSPF_LS_INFINITY) 314 { 315 zlog_info ("Route[External]: Metric is OSPF_LS_INFINITY"); 316 return 0; 317 } 318 if (IS_LSA_MAXAGE (lsa)) 319 { 320 zlog_info ("Route[External]: AS-external-LSA is MAXAGE"); 321 return 0; 322 } 323 324 /* (2) If the LSA was originated by the calculating router itself, 325 examine the next LSA. */ 326 if (IS_LSA_SELF (lsa)) 327 { 328 zlog_info ("Route[External]: AS-external-LSA is self originated"); 329 return 0; 330 } 331 332 /* (3) Call the destination described by the LSA N. N's address is 333 obtained by masking the LSA's Link State ID with the 334 network/subnet mask contained in the body of the LSA. Look 335 up the routing table entries (potentially one per attached 336 area) for the AS boundary router (ASBR) that originated the 337 LSA. If no entries exist for router ASBR (i.e., ASBR is 338 unreachable), do nothing with this LSA and consider the next 339 in the list. */ 340 341 asbr.family = AF_INET; 342 asbr.prefix = al->header.adv_router; 343 asbr.prefixlen = IPV4_MAX_BITLEN; 344 apply_mask_ipv4 (&asbr); 345 346 asbr_route = ospf_find_asbr_route (ospf_top->new_rtrs, &asbr); 347 if (asbr_route == NULL) 348 { 349 zlog_info ("Route[External]: Can't find originating ASBR route"); 350 return 0; 351 } 352 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) 353 { 354 zlog_info ("Route[External]: Originating router is not an ASBR"); 355 return 0; 356 } 357 358 /* Else, this LSA describes an AS external path to destination 359 N. Examine the forwarding address specified in the AS- 360 external-LSA. This indicates the IP address to which 361 packets for the destination should be forwarded. */ 362 363 if (al->e[0].fwd_addr.s_addr == 0) 364 { 365 /* If the forwarding address is set to 0.0.0.0, packets should 366 be sent to the ASBR itself. Among the multiple routing table 367 entries for the ASBR, select the preferred entry as follows. 368 If RFC1583Compatibility is set to "disabled", prune the set 369 of routing table entries for the ASBR as described in 370 Section 16.4.1. In any case, among the remaining routing 371 table entries, select the routing table entry with the least 372 cost; when there are multiple least cost routing table 373 entries the entry whose associated area has the largest OSPF 374 Area ID (when considered as an unsigned 32-bit integer) is 375 chosen. */ 376 377 /* asbr_route already contains the requested route */ 378 } 379 else 380 { 381 /* If the forwarding address is non-zero, look up the 382 forwarding address in the routing table.[24] The matching 383 routing table entry must specify an intra-area or inter-area 384 path; if no such path exists, do nothing with the LSA and 385 consider the next in the list. */ 386 if (! ospf_ase_forward_address_check (al->e[0].fwd_addr)) 387 { 388 zlog_info ("Route[External]: Forwarding address is our router address"); 389 return 0; 390 } 391 392 asbr.family = AF_INET; 393 asbr.prefix = al->e[0].fwd_addr; 394 asbr.prefixlen = IPV4_MAX_BITLEN; 395 396 rn = route_node_match (ospf_top->new_table, (struct prefix *) &asbr); 397 398 if (rn == NULL || (asbr_route = rn->info) == NULL) 399 { 400 zlog_info ("Route[External]: Can't find route to forwarding address"); 401 if (rn) 402 route_unlock_node (rn); 403 return 0; 404 } 405 406 route_unlock_node (rn); 407 } 408 409 /* (4) Let X be the cost specified by the preferred routing table 410 entry for the ASBR/forwarding address, and Y the cost 411 specified in the LSA. X is in terms of the link state 412 metric, and Y is a type 1 or 2 external metric. */ 413 414 415 /* (5) Look up the routing table entry for the destination N. If 416 no entry exists for N, install the AS external path to N, 417 with next hop equal to the list of next hops to the 418 forwarding address, and advertising router equal to ASBR. 419 If the external metric type is 1, then the path-type is set 420 to type 1 external and the cost is equal to X+Y. If the 421 external metric type is 2, the path-type is set to type 2 422 external, the link state component of the route's cost is X, 423 and the type 2 cost is Y. */ 424 new = ospf_ase_calculate_new_route (lsa, asbr_route, metric); 425 426 /* (6) Compare the AS external path described by the LSA with the 427 existing paths in N's routing table entry, as follows. If 428 the new path is preferred, it replaces the present paths in 429 N's routing table entry. If the new path is of equal 430 preference, it is added to N's routing table entry's list of 431 paths. */ 432 433 /* Set prefix. */ 434 p.family = AF_INET; 435 p.prefix = al->header.id; 436 p.prefixlen = ip_masklen (al->mask); 437 438 /* if there is a Intra/Inter area route to the N 439 do not install external route */ 440 if ((rn = route_node_lookup (ospf_top->new_table, 441 (struct prefix *) &p)) != NULL 442 && (rn->info != NULL)) 443 { 444 if (new) 445 ospf_route_free (new); 446 return 0; 447 } 448 449 /* Find a route to the same dest */ 450 /* If there is no route, create new one. */ 451 if ((rn = route_node_lookup (ospf_top->new_external_route, 452 (struct prefix *) &p)) == NULL 453 || (or = rn->info) == NULL) 454 { 455 zlog_info ("Route[External]: Adding a new route %s/%d", 456 inet_ntoa (p.prefix), p.prefixlen); 457 458 ospf_route_add (ospf_top->new_external_route, &p, new, asbr_route); 459 460 if (al->e[0].fwd_addr.s_addr) 461 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr); 462 return 0; 463 } 464 else 465 { 466 /* (a) Intra-area and inter-area paths are always preferred 467 over AS external paths. 468 469 (b) Type 1 external paths are always preferred over type 2 470 external paths. When all paths are type 2 external 471 paths, the paths with the smallest advertised type 2 472 metric are always preferred. */ 473 ret = ospf_route_cmp (new, or); 474 475 /* (c) If the new AS external path is still indistinguishable 476 from the current paths in the N's routing table entry, 477 and RFC1583Compatibility is set to "disabled", select 478 the preferred paths based on the intra-AS paths to the 479 ASBR/forwarding addresses, as specified in Section 480 16.4.1. 481 482 (d) If the new AS external path is still indistinguishable 483 from the current paths in the N's routing table entry, 484 select the preferred path based on a least cost 485 comparison. Type 1 external paths are compared by 486 looking at the sum of the distance to the forwarding 487 address and the advertised type 1 metric (X+Y). Type 2 488 external paths advertising equal type 2 metrics are 489 compared by looking at the distance to the forwarding 490 addresses. 491 */ 492 /* New route is better */ 493 if (ret < 0) 494 { 495 zlog_info ("Route[External]: New route is better"); 496 ospf_route_subst (rn, new, asbr_route); 497 if (al->e[0].fwd_addr.s_addr) 498 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr); 499 or = new; 500 new = NULL; 501 } 502 /* Old route is better */ 503 else if (ret > 0) 504 { 505 zlog_info ("Route[External]: Old route is better"); 506 /* do nothing */ 507 } 508 /* Routes are equal */ 509 else 510 { 511 zlog_info ("Route[External]: Routes are equal"); 512 ospf_route_copy_nexthops (or, asbr_route->path); 513 if (al->e[0].fwd_addr.s_addr) 514 ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr); 515 } 516 } 517 /* Make sure setting newly calculated ASBR route.*/ 518 or->u.ext.asbr = asbr_route; 519 if (new) 520 ospf_route_free (new); 521 522 lsa->route = or; 523 return 0; 524} 525 526int 527ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix, 528 struct ospf_route *newor) 529{ 530 struct route_node *rn; 531 struct ospf_route *or; 532 struct ospf_path *op; 533 struct ospf_path *newop; 534 listnode n1; 535 listnode n2; 536 537 if (! rt || ! prefix) 538 return 0; 539 540 rn = route_node_lookup (rt, prefix); 541 if (! rn) 542 return 0; 543 544 route_unlock_node (rn); 545 546 or = rn->info; 547 if (or->path_type != newor->path_type) 548 return 0; 549 550 switch (or->path_type) 551 { 552 case OSPF_PATH_TYPE1_EXTERNAL: 553 if (or->cost != newor->cost) 554 return 0; 555 break; 556 case OSPF_PATH_TYPE2_EXTERNAL: 557 if ((or->cost != newor->cost) || 558 (or->u.ext.type2_cost != newor->u.ext.type2_cost)) 559 return 0; 560 break; 561 default: 562 assert (0); 563 return 0; 564 } 565 566 if (or->path->count != newor->path->count) 567 return 0; 568 569 /* Check each path. */ 570 for (n1 = listhead (or->path), n2 = listhead (newor->path); 571 n1 && n2; nextnode (n1), nextnode (n2)) 572 { 573 op = getdata (n1); 574 newop = getdata (n2); 575 576 if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop)) 577 return 0; 578 } 579 return 1; 580} 581 582int 583ospf_ase_compare_tables (struct route_table *new_external_route, 584 struct route_table *old_external_route) 585{ 586 struct route_node *rn, *new_rn; 587 struct ospf_route *or; 588 589 /* Remove deleted routes */ 590 for (rn = route_top (old_external_route); rn; rn = route_next (rn)) 591 if ((or = rn->info)) 592 { 593 if (! (new_rn = route_node_lookup (new_external_route, &rn->p))) 594 ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); 595 else 596 route_unlock_node (new_rn); 597 } 598 599 600 /* Install new routes */ 601 for (rn = route_top (new_external_route); rn; rn = route_next (rn)) 602 if ((or = rn->info) != NULL) 603 if (! ospf_ase_route_match_same (old_external_route, &rn->p, or)) 604 ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or); 605 606 return 0; 607} 608 609int 610ospf_ase_calculate_timer (struct thread *t) 611{ 612 struct ospf *ospf; 613 614#ifdef HAVE_NSSA 615 listnode node; 616 struct ospf_area *area; 617#endif /* HAVE_NSSA */ 618 619 ospf = THREAD_ARG (t); 620 ospf->t_ase_calc = NULL; 621 622 if (ospf->ase_calc) 623 { 624 ospf->ase_calc = 0; 625 626 /* Calculate external route for each AS-external-LSA */ 627 foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0, 628 ospf_ase_calculate_route); 629 630#ifdef HAVE_NSSA 631 /* This version simple adds to the table all NSSA areas */ 632 if (ospf_top->anyNSSA) 633 for (node = listhead (ospf_top->areas); node; nextnode (node)) 634 { 635 area = getdata (node); 636 if (IS_DEBUG_OSPF_NSSA) 637 zlog_info ("ospf_ase_calculate_timer(): looking at area %s", 638 inet_ntoa (area->area_id)); 639 640 if (area->external_routing == OSPF_AREA_NSSA) 641 642 foreach_lsa (NSSA_LSDB (area), NULL, 0, 643 ospf_ase_calculate_route); 644 } 645#endif /* HAVE_NSSA */ 646 647 /* Compare old and new external routing table and install the 648 difference info zebra/kernel */ 649 ospf_ase_compare_tables (ospf_top->new_external_route, 650 ospf_top->old_external_route); 651 652 /* Delete old external routing table */ 653 ospf_route_table_free (ospf_top->old_external_route); 654 ospf_top->old_external_route = ospf_top->new_external_route; 655 ospf_top->new_external_route = route_table_init (); 656 } 657 return 0; 658} 659 660void 661ospf_ase_calculate_schedule () 662{ 663 if (! ospf_top) 664 return; 665 666 ospf_top->ase_calc = 1; 667} 668 669void 670ospf_ase_calculate_timer_add () 671{ 672 if (! ospf_top) 673 return; 674 675 if (! ospf_top->t_ase_calc) 676 ospf_top->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer, 677 ospf_top, OSPF_ASE_CALC_INTERVAL); 678} 679 680void 681ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top) 682{ 683 struct route_node *rn; 684 struct prefix_ipv4 p; 685 list lst; 686 struct as_external_lsa *al; 687 688 al = (struct as_external_lsa *) lsa->data; 689 p.family = AF_INET; 690 p.prefix = lsa->data->id; 691 p.prefixlen = ip_masklen (al->mask); 692 apply_mask_ipv4 (&p); 693 694 rn = route_node_get (top->external_lsas, (struct prefix *) &p); 695 if ((lst = rn->info) == NULL) 696 rn->info = lst = list_new(); 697 698 /* We assume that if LSA is deleted from DB 699 is is also deleted from this RT */ 700 701 listnode_add (lst, ospf_lsa_lock (lsa)); 702} 703 704void 705ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top) 706{ 707 struct route_node *rn; 708 struct prefix_ipv4 p; 709 list lst; 710 struct as_external_lsa *al; 711 712 al = (struct as_external_lsa *) lsa->data; 713 p.family = AF_INET; 714 p.prefix = lsa->data->id; 715 p.prefixlen = ip_masklen (al->mask); 716 apply_mask_ipv4 (&p); 717 718 rn = route_node_get (top->external_lsas, (struct prefix *) &p); 719 lst = rn->info; 720#ifdef ORIGINAL_CODING 721 assert (lst); 722 723 listnode_delete (lst, lsa); 724 ospf_lsa_unlock (lsa); 725#else /* ORIGINAL_CODING */ 726 /* XXX lst can be NULL */ 727 if (lst) { 728 listnode_delete (lst, lsa); 729 ospf_lsa_unlock (lsa); 730 } 731#endif /* ORIGINAL_CODING */ 732} 733 734void 735ospf_ase_external_lsas_finish (struct route_table *rt) 736{ 737 struct route_node *rn; 738 struct ospf_lsa *lsa; 739 list lst; 740 listnode node; 741 742 for (rn = route_top (rt); rn; rn = route_next (rn)) 743 if ((lst = rn->info) != NULL) 744 { 745 for (node = listhead (lst); node; node = nextnode (node)) 746 if ((lsa = getdata (node)) != NULL) 747 ospf_lsa_unlock (lsa); 748 list_delete (lst); 749 } 750 751 route_table_finish (rt); 752} 753 754void 755ospf_ase_incremental_update (struct ospf_lsa *lsa, struct ospf *top) 756{ 757 list lsas; 758 listnode node; 759 struct route_node *rn, *rn2; 760 struct prefix_ipv4 p; 761 struct route_table *tmp_old; 762 struct as_external_lsa *al; 763 764 al = (struct as_external_lsa *) lsa->data; 765 p.family = AF_INET; 766 p.prefix = lsa->data->id; 767 p.prefixlen = ip_masklen (al->mask); 768 apply_mask_ipv4 (&p); 769 770 /* if new_table is NULL, there was no spf calculation, thus 771 incremental update is unneeded */ 772 if (!top->new_table) 773 return; 774 775 /* If there is already an intra-area or inter-area route 776 to the destination, no recalculation is necessary 777 (internal routes take precedence). */ 778 779 rn = route_node_lookup (top->new_table, (struct prefix *) &p); 780 if (rn && rn->info) 781 { 782 route_unlock_node (rn); 783 return; 784 } 785 786 rn = route_node_lookup (top->external_lsas, (struct prefix *) &p); 787 assert (rn && rn->info); 788 lsas = rn->info; 789 790 for (node = listhead (lsas); node; nextnode (node)) 791 if ((lsa = getdata (node)) != NULL) 792 ospf_ase_calculate_route (lsa, NULL, 0); 793 794 /* prepare temporary old routing table for compare */ 795 tmp_old = route_table_init (); 796 rn = route_node_lookup (top->old_external_route, (struct prefix *) &p); 797 if (rn && rn->info) 798 { 799 rn2 = route_node_get (tmp_old, (struct prefix *) &p); 800 rn2->info = rn->info; 801 } 802 803 /* install changes to zebra */ 804 ospf_ase_compare_tables (top->new_external_route, tmp_old); 805 806 /* update top->old_external_route table */ 807 if (rn && rn->info) 808 ospf_route_free ((struct ospf_route *) rn->info); 809 810 rn2 = route_node_lookup (top->new_external_route, (struct prefix *) &p); 811 /* if new route exists, install it to top->old_external_route */ 812 if (rn2 && rn2->info) 813 { 814 if (!rn) 815 rn = route_node_get (top->old_external_route, (struct prefix *) &p); 816 rn->info = rn2->info; 817 } 818 else 819 { 820 /* remove route node from top->old_external_route */ 821 if (rn) 822 { 823 rn->info = NULL; 824 route_unlock_node (rn); 825 route_unlock_node (rn); 826 } 827 } 828 829 if (rn2) 830 { 831 /* rn2->info is stored in route node of top->old_external_route */ 832 rn2->info = NULL; 833 route_unlock_node (rn2); 834 route_unlock_node (rn2); 835 } 836 837 route_table_finish (tmp_old); 838} 839