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