]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_ase.c
Amir Guindehi <amir@datacore.ch>:
[mirror_frr.git] / ospfd / ospf_ase.c
CommitLineData
718e3744 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)
2e3b2e47 157 if (if_is_operative (oi->ifp))
718e3744 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 }
f2c80652 645 /* kevinm: And add the NSSA routes in ospf_top */
646 foreach_lsa(NSSA_LSDB (ospf_top), NULL, 0,
647 ospf_ase_calculate_route);
648
718e3744 649#endif /* HAVE_NSSA */
650
651 /* Compare old and new external routing table and install the
652 difference info zebra/kernel */
653 ospf_ase_compare_tables (ospf_top->new_external_route,
654 ospf_top->old_external_route);
655
656 /* Delete old external routing table */
657 ospf_route_table_free (ospf_top->old_external_route);
658 ospf_top->old_external_route = ospf_top->new_external_route;
659 ospf_top->new_external_route = route_table_init ();
660 }
661 return 0;
662}
663
664void
665ospf_ase_calculate_schedule ()
666{
667 if (! ospf_top)
668 return;
669
670 ospf_top->ase_calc = 1;
671}
672
673void
674ospf_ase_calculate_timer_add ()
675{
676 if (! ospf_top)
677 return;
678
679 if (! ospf_top->t_ase_calc)
680 ospf_top->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer,
681 ospf_top, OSPF_ASE_CALC_INTERVAL);
682}
683
684void
685ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
686{
687 struct route_node *rn;
688 struct prefix_ipv4 p;
689 list lst;
690 struct as_external_lsa *al;
691
692 al = (struct as_external_lsa *) lsa->data;
693 p.family = AF_INET;
694 p.prefix = lsa->data->id;
695 p.prefixlen = ip_masklen (al->mask);
696 apply_mask_ipv4 (&p);
697
698 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
699 if ((lst = rn->info) == NULL)
700 rn->info = lst = list_new();
701
702 /* We assume that if LSA is deleted from DB
703 is is also deleted from this RT */
704
705 listnode_add (lst, ospf_lsa_lock (lsa));
706}
707
708void
709ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
710{
711 struct route_node *rn;
712 struct prefix_ipv4 p;
713 list lst;
714 struct as_external_lsa *al;
715
716 al = (struct as_external_lsa *) lsa->data;
717 p.family = AF_INET;
718 p.prefix = lsa->data->id;
719 p.prefixlen = ip_masklen (al->mask);
720 apply_mask_ipv4 (&p);
721
722 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
723 lst = rn->info;
724#ifdef ORIGINAL_CODING
725 assert (lst);
726
727 listnode_delete (lst, lsa);
728 ospf_lsa_unlock (lsa);
729#else /* ORIGINAL_CODING */
730 /* XXX lst can be NULL */
731 if (lst) {
732 listnode_delete (lst, lsa);
733 ospf_lsa_unlock (lsa);
734 }
735#endif /* ORIGINAL_CODING */
736}
737
738void
739ospf_ase_external_lsas_finish (struct route_table *rt)
740{
741 struct route_node *rn;
742 struct ospf_lsa *lsa;
743 list lst;
744 listnode node;
745
746 for (rn = route_top (rt); rn; rn = route_next (rn))
747 if ((lst = rn->info) != NULL)
748 {
749 for (node = listhead (lst); node; node = nextnode (node))
750 if ((lsa = getdata (node)) != NULL)
751 ospf_lsa_unlock (lsa);
752 list_delete (lst);
753 }
754
755 route_table_finish (rt);
756}
757
758void
759ospf_ase_incremental_update (struct ospf_lsa *lsa, struct ospf *top)
760{
761 list lsas;
762 listnode node;
763 struct route_node *rn, *rn2;
764 struct prefix_ipv4 p;
765 struct route_table *tmp_old;
766 struct as_external_lsa *al;
767
768 al = (struct as_external_lsa *) lsa->data;
769 p.family = AF_INET;
770 p.prefix = lsa->data->id;
771 p.prefixlen = ip_masklen (al->mask);
772 apply_mask_ipv4 (&p);
773
774 /* if new_table is NULL, there was no spf calculation, thus
775 incremental update is unneeded */
776 if (!top->new_table)
777 return;
778
779 /* If there is already an intra-area or inter-area route
780 to the destination, no recalculation is necessary
781 (internal routes take precedence). */
782
783 rn = route_node_lookup (top->new_table, (struct prefix *) &p);
784 if (rn && rn->info)
785 {
786 route_unlock_node (rn);
787 return;
788 }
789
790 rn = route_node_lookup (top->external_lsas, (struct prefix *) &p);
791 assert (rn && rn->info);
792 lsas = rn->info;
793
794 for (node = listhead (lsas); node; nextnode (node))
795 if ((lsa = getdata (node)) != NULL)
796 ospf_ase_calculate_route (lsa, NULL, 0);
797
798 /* prepare temporary old routing table for compare */
799 tmp_old = route_table_init ();
800 rn = route_node_lookup (top->old_external_route, (struct prefix *) &p);
801 if (rn && rn->info)
802 {
803 rn2 = route_node_get (tmp_old, (struct prefix *) &p);
804 rn2->info = rn->info;
805 }
806
807 /* install changes to zebra */
808 ospf_ase_compare_tables (top->new_external_route, tmp_old);
809
810 /* update top->old_external_route table */
811 if (rn && rn->info)
812 ospf_route_free ((struct ospf_route *) rn->info);
813
814 rn2 = route_node_lookup (top->new_external_route, (struct prefix *) &p);
815 /* if new route exists, install it to top->old_external_route */
816 if (rn2 && rn2->info)
817 {
818 if (!rn)
819 rn = route_node_get (top->old_external_route, (struct prefix *) &p);
820 rn->info = rn2->info;
821 }
822 else
823 {
824 /* remove route node from top->old_external_route */
825 if (rn)
826 {
827 rn->info = NULL;
828 route_unlock_node (rn);
829 route_unlock_node (rn);
830 }
831 }
832
833 if (rn2)
834 {
835 /* rn2->info is stored in route node of top->old_external_route */
836 rn2->info = NULL;
837 route_unlock_node (rn2);
838 route_unlock_node (rn2);
839 }
840
841 route_table_finish (tmp_old);
842}