blob: 9194c5662b49ee0844507b371903dd5ed2f51861 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
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}