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