blob: 5605933b505e04332a8b4fdfcf6e6b214049c302 [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 *
paul68980082003-03-25 05:07:42 +000052ospf_find_asbr_route (struct ospf *ospf,
53 struct route_table *rtrs, struct prefix_ipv4 *asbr)
paul718e3742002-12-13 20:15:29 +000054{
55 struct route_node *rn;
56 struct ospf_route *or, *best = NULL;
57 listnode node;
58 list chosen;
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. */
paul68980082003-03-25 05:07:42 +000073 if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE))
paul718e3742002-12-13 20:15:29 +000074 for (node = listhead ((list) rn->info); node; nextnode (node))
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 {
124 listnode node;
125 struct ospf_route *or;
126
127 route_unlock_node (rn);
128
129 for (node = listhead ((list) rn->info); node; nextnode (node))
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{
141 listnode node;
142 struct ospf_path *op;
143
144 for (node = listhead (ro->path); node; nextnode (node))
145 if ((op = getdata (node)) != NULL)
146 if (op->nexthop.s_addr == 0)
147 op->nexthop.s_addr = nexthop.s_addr;
148}
149
150int
paul68980082003-03-25 05:07:42 +0000151ospf_ase_forward_address_check (struct ospf *ospf, struct in_addr fwd_addr)
paul718e3742002-12-13 20:15:29 +0000152{
153 listnode ifn;
154 struct ospf_interface *oi;
155
paul68980082003-03-25 05:07:42 +0000156 for (ifn = listhead (ospf->oiflist); ifn; nextnode (ifn))
paul718e3742002-12-13 20:15:29 +0000157 if ((oi = getdata (ifn)) != NULL)
paul2e3b2e42002-12-13 21:03:13 +0000158 if (if_is_operative (oi->ifp))
paul718e3742002-12-13 20:15:29 +0000159 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 *
paul68980082003-03-25 05:07:42 +0000168ospf_ase_calculate_asbr_route (struct ospf *ospf,
169 struct route_table *rt_network,
paul718e3742002-12-13 20:15:29 +0000170 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
paul68980082003-03-25 05:07:42 +0000183 asbr_route = ospf_find_asbr_route (ospf, rt_router, &asbr);
paul718e3742002-12-13 20:15:29 +0000184
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
paul68980082003-03-25 05:07:42 +0000203 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000204 {
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;
271 new->path = list_new ();
272 new->u.ext.origin = lsa;
273 new->u.ext.tag = ntohl (al->e[0].route_tag);
274 new->u.ext.asbr = asbr_route;
275
276 assert (new != asbr_route);
277
278 return new;
279}
280
281#define OSPF_ASE_CALC_INTERVAL 1
282
283int
paul68980082003-03-25 05:07:42 +0000284ospf_ase_calculate_route (struct ospf *ospf, struct ospf_lsa * lsa)
paul718e3742002-12-13 20:15:29 +0000285{
286 u_int32_t metric;
287 struct as_external_lsa *al;
288 struct ospf_route *asbr_route;
289 struct prefix_ipv4 asbr, p;
290 struct route_node *rn;
291 struct ospf_route *new, *or;
292 int ret;
293
294 assert (lsa);
295 al = (struct as_external_lsa *) lsa->data;
296
297#ifdef HAVE_NSSA
298 if (lsa->data->type == OSPF_AS_NSSA_LSA)
299 if (IS_DEBUG_OSPF_NSSA)
300 zlog_info ("ospf_ase_calc(): Processing Type-7");
301
302 /* Stay away from any Local Translated Type-7 LSAs */
303 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
304 {
305 if (IS_DEBUG_OSPF_NSSA)
306 zlog_info ("ospf_ase_calc(): Rejecting Local Xlt'd");
307 return 0;
308 }
309#endif /* HAVE_NSSA */
310
311 zlog_info ("Route[External]: Calculate AS-external-LSA to %s/%d",
312 inet_ntoa (al->header.id), ip_masklen (al->mask));
313 /* (1) If the cost specified by the LSA is LSInfinity, or if the
314 LSA's LS age is equal to MaxAge, then examine the next LSA. */
315 if ((metric = GET_METRIC (al->e[0].metric)) >= OSPF_LS_INFINITY)
316 {
317 zlog_info ("Route[External]: Metric is OSPF_LS_INFINITY");
318 return 0;
319 }
320 if (IS_LSA_MAXAGE (lsa))
321 {
322 zlog_info ("Route[External]: AS-external-LSA is MAXAGE");
323 return 0;
324 }
325
326 /* (2) If the LSA was originated by the calculating router itself,
327 examine the next LSA. */
328 if (IS_LSA_SELF (lsa))
329 {
330 zlog_info ("Route[External]: AS-external-LSA is self originated");
331 return 0;
332 }
333
334 /* (3) Call the destination described by the LSA N. N's address is
335 obtained by masking the LSA's Link State ID with the
336 network/subnet mask contained in the body of the LSA. Look
337 up the routing table entries (potentially one per attached
338 area) for the AS boundary router (ASBR) that originated the
339 LSA. If no entries exist for router ASBR (i.e., ASBR is
340 unreachable), do nothing with this LSA and consider the next
341 in the list. */
342
343 asbr.family = AF_INET;
344 asbr.prefix = al->header.adv_router;
345 asbr.prefixlen = IPV4_MAX_BITLEN;
346 apply_mask_ipv4 (&asbr);
347
paul68980082003-03-25 05:07:42 +0000348 asbr_route = ospf_find_asbr_route (ospf, ospf->new_rtrs, &asbr);
paul718e3742002-12-13 20:15:29 +0000349 if (asbr_route == NULL)
350 {
351 zlog_info ("Route[External]: Can't find originating ASBR route");
352 return 0;
353 }
354 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
355 {
356 zlog_info ("Route[External]: Originating router is not an ASBR");
357 return 0;
358 }
359
360 /* Else, this LSA describes an AS external path to destination
361 N. Examine the forwarding address specified in the AS-
362 external-LSA. This indicates the IP address to which
363 packets for the destination should be forwarded. */
364
365 if (al->e[0].fwd_addr.s_addr == 0)
366 {
367 /* If the forwarding address is set to 0.0.0.0, packets should
368 be sent to the ASBR itself. Among the multiple routing table
369 entries for the ASBR, select the preferred entry as follows.
370 If RFC1583Compatibility is set to "disabled", prune the set
371 of routing table entries for the ASBR as described in
372 Section 16.4.1. In any case, among the remaining routing
373 table entries, select the routing table entry with the least
374 cost; when there are multiple least cost routing table
375 entries the entry whose associated area has the largest OSPF
376 Area ID (when considered as an unsigned 32-bit integer) is
377 chosen. */
378
379 /* asbr_route already contains the requested route */
380 }
381 else
382 {
383 /* If the forwarding address is non-zero, look up the
384 forwarding address in the routing table.[24] The matching
385 routing table entry must specify an intra-area or inter-area
386 path; if no such path exists, do nothing with the LSA and
387 consider the next in the list. */
paul68980082003-03-25 05:07:42 +0000388 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000389 {
390 zlog_info ("Route[External]: Forwarding address is our router address");
391 return 0;
392 }
393
394 asbr.family = AF_INET;
395 asbr.prefix = al->e[0].fwd_addr;
396 asbr.prefixlen = IPV4_MAX_BITLEN;
397
paul68980082003-03-25 05:07:42 +0000398 rn = route_node_match (ospf->new_table, (struct prefix *) &asbr);
paul718e3742002-12-13 20:15:29 +0000399
400 if (rn == NULL || (asbr_route = rn->info) == NULL)
401 {
402 zlog_info ("Route[External]: Can't find route to forwarding address");
403 if (rn)
404 route_unlock_node (rn);
405 return 0;
406 }
407
408 route_unlock_node (rn);
409 }
410
411 /* (4) Let X be the cost specified by the preferred routing table
412 entry for the ASBR/forwarding address, and Y the cost
413 specified in the LSA. X is in terms of the link state
414 metric, and Y is a type 1 or 2 external metric. */
415
416
417 /* (5) Look up the routing table entry for the destination N. If
418 no entry exists for N, install the AS external path to N,
419 with next hop equal to the list of next hops to the
420 forwarding address, and advertising router equal to ASBR.
421 If the external metric type is 1, then the path-type is set
422 to type 1 external and the cost is equal to X+Y. If the
423 external metric type is 2, the path-type is set to type 2
424 external, the link state component of the route's cost is X,
425 and the type 2 cost is Y. */
426 new = ospf_ase_calculate_new_route (lsa, asbr_route, metric);
427
428 /* (6) Compare the AS external path described by the LSA with the
429 existing paths in N's routing table entry, as follows. If
430 the new path is preferred, it replaces the present paths in
431 N's routing table entry. If the new path is of equal
432 preference, it is added to N's routing table entry's list of
433 paths. */
434
435 /* Set prefix. */
436 p.family = AF_INET;
437 p.prefix = al->header.id;
438 p.prefixlen = ip_masklen (al->mask);
439
440 /* if there is a Intra/Inter area route to the N
441 do not install external route */
paul68980082003-03-25 05:07:42 +0000442 if ((rn = route_node_lookup (ospf->new_table,
paul718e3742002-12-13 20:15:29 +0000443 (struct prefix *) &p)) != NULL
444 && (rn->info != NULL))
445 {
446 if (new)
447 ospf_route_free (new);
448 return 0;
449 }
450
451 /* Find a route to the same dest */
452 /* If there is no route, create new one. */
paul68980082003-03-25 05:07:42 +0000453 if ((rn = route_node_lookup (ospf->new_external_route,
paul718e3742002-12-13 20:15:29 +0000454 (struct prefix *) &p)) == NULL
455 || (or = rn->info) == NULL)
456 {
457 zlog_info ("Route[External]: Adding a new route %s/%d",
458 inet_ntoa (p.prefix), p.prefixlen);
459
paul68980082003-03-25 05:07:42 +0000460 ospf_route_add (ospf->new_external_route, &p, new, asbr_route);
paul718e3742002-12-13 20:15:29 +0000461
462 if (al->e[0].fwd_addr.s_addr)
463 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
464 return 0;
465 }
466 else
467 {
468 /* (a) Intra-area and inter-area paths are always preferred
469 over AS external paths.
470
471 (b) Type 1 external paths are always preferred over type 2
472 external paths. When all paths are type 2 external
473 paths, the paths with the smallest advertised type 2
474 metric are always preferred. */
paul68980082003-03-25 05:07:42 +0000475 ret = ospf_route_cmp (ospf, new, or);
paul718e3742002-12-13 20:15:29 +0000476
477 /* (c) If the new AS external path is still indistinguishable
478 from the current paths in the N's routing table entry,
479 and RFC1583Compatibility is set to "disabled", select
480 the preferred paths based on the intra-AS paths to the
481 ASBR/forwarding addresses, as specified in Section
482 16.4.1.
483
484 (d) If the new AS external path is still indistinguishable
485 from the current paths in the N's routing table entry,
486 select the preferred path based on a least cost
487 comparison. Type 1 external paths are compared by
488 looking at the sum of the distance to the forwarding
489 address and the advertised type 1 metric (X+Y). Type 2
490 external paths advertising equal type 2 metrics are
491 compared by looking at the distance to the forwarding
492 addresses.
493 */
494 /* New route is better */
495 if (ret < 0)
496 {
497 zlog_info ("Route[External]: New route is better");
498 ospf_route_subst (rn, new, asbr_route);
499 if (al->e[0].fwd_addr.s_addr)
500 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
501 or = new;
502 new = NULL;
503 }
504 /* Old route is better */
505 else if (ret > 0)
506 {
507 zlog_info ("Route[External]: Old route is better");
508 /* do nothing */
509 }
510 /* Routes are equal */
511 else
512 {
513 zlog_info ("Route[External]: Routes are equal");
514 ospf_route_copy_nexthops (or, asbr_route->path);
515 if (al->e[0].fwd_addr.s_addr)
516 ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr);
517 }
518 }
519 /* Make sure setting newly calculated ASBR route.*/
520 or->u.ext.asbr = asbr_route;
521 if (new)
522 ospf_route_free (new);
523
524 lsa->route = or;
525 return 0;
526}
527
528int
529ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix,
530 struct ospf_route *newor)
531{
532 struct route_node *rn;
533 struct ospf_route *or;
534 struct ospf_path *op;
535 struct ospf_path *newop;
536 listnode n1;
537 listnode n2;
538
539 if (! rt || ! prefix)
540 return 0;
541
542 rn = route_node_lookup (rt, prefix);
543 if (! rn)
544 return 0;
545
546 route_unlock_node (rn);
547
548 or = rn->info;
549 if (or->path_type != newor->path_type)
550 return 0;
551
552 switch (or->path_type)
553 {
554 case OSPF_PATH_TYPE1_EXTERNAL:
555 if (or->cost != newor->cost)
556 return 0;
557 break;
558 case OSPF_PATH_TYPE2_EXTERNAL:
559 if ((or->cost != newor->cost) ||
560 (or->u.ext.type2_cost != newor->u.ext.type2_cost))
561 return 0;
562 break;
563 default:
564 assert (0);
565 return 0;
566 }
567
568 if (or->path->count != newor->path->count)
569 return 0;
570
571 /* Check each path. */
572 for (n1 = listhead (or->path), n2 = listhead (newor->path);
573 n1 && n2; nextnode (n1), nextnode (n2))
574 {
575 op = getdata (n1);
576 newop = getdata (n2);
577
578 if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
579 return 0;
580 }
581 return 1;
582}
583
584int
585ospf_ase_compare_tables (struct route_table *new_external_route,
586 struct route_table *old_external_route)
587{
588 struct route_node *rn, *new_rn;
589 struct ospf_route *or;
590
591 /* Remove deleted routes */
592 for (rn = route_top (old_external_route); rn; rn = route_next (rn))
593 if ((or = rn->info))
594 {
595 if (! (new_rn = route_node_lookup (new_external_route, &rn->p)))
596 ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
597 else
598 route_unlock_node (new_rn);
599 }
600
601
602 /* Install new routes */
603 for (rn = route_top (new_external_route); rn; rn = route_next (rn))
604 if ((or = rn->info) != NULL)
605 if (! ospf_ase_route_match_same (old_external_route, &rn->p, or))
606 ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
607
608 return 0;
609}
610
611int
612ospf_ase_calculate_timer (struct thread *t)
613{
614 struct ospf *ospf;
paul68980082003-03-25 05:07:42 +0000615 struct ospf_lsa *lsa;
616 struct route_node *rn;
paul718e3742002-12-13 20:15:29 +0000617#ifdef HAVE_NSSA
paul68980082003-03-25 05:07:42 +0000618 listnode node;
619 struct ospf_area *area;
paul718e3742002-12-13 20:15:29 +0000620#endif /* HAVE_NSSA */
621
622 ospf = THREAD_ARG (t);
623 ospf->t_ase_calc = NULL;
624
625 if (ospf->ase_calc)
626 {
627 ospf->ase_calc = 0;
628
629 /* Calculate external route for each AS-external-LSA */
paul68980082003-03-25 05:07:42 +0000630 LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
631 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000632
633#ifdef HAVE_NSSA
634 /* This version simple adds to the table all NSSA areas */
paul68980082003-03-25 05:07:42 +0000635 if (ospf->anyNSSA)
636 for (node = listhead (ospf->areas); node; nextnode (node))
paul718e3742002-12-13 20:15:29 +0000637 {
638 area = getdata (node);
639 if (IS_DEBUG_OSPF_NSSA)
640 zlog_info ("ospf_ase_calculate_timer(): looking at area %s",
641 inet_ntoa (area->area_id));
642
643 if (area->external_routing == OSPF_AREA_NSSA)
paul68980082003-03-25 05:07:42 +0000644 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
645 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000646 }
paulf2c80652002-12-13 21:44:27 +0000647 /* kevinm: And add the NSSA routes in ospf_top */
paulf6386ee2003-04-07 04:29:27 +0000648 LSDB_LOOP (NSSA_LSDB (ospf),rn,lsa)
649 ospf_ase_calculate_route(ospf,lsa);
paulf2c80652002-12-13 21:44:27 +0000650
paul718e3742002-12-13 20:15:29 +0000651#endif /* HAVE_NSSA */
652
653 /* Compare old and new external routing table and install the
654 difference info zebra/kernel */
paul68980082003-03-25 05:07:42 +0000655 ospf_ase_compare_tables (ospf->new_external_route,
656 ospf->old_external_route);
paul718e3742002-12-13 20:15:29 +0000657
658 /* Delete old external routing table */
paul68980082003-03-25 05:07:42 +0000659 ospf_route_table_free (ospf->old_external_route);
660 ospf->old_external_route = ospf->new_external_route;
661 ospf->new_external_route = route_table_init ();
paul718e3742002-12-13 20:15:29 +0000662 }
663 return 0;
664}
665
666void
paul68980082003-03-25 05:07:42 +0000667ospf_ase_calculate_schedule (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000668{
paul68980082003-03-25 05:07:42 +0000669 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000670 return;
671
paul68980082003-03-25 05:07:42 +0000672 ospf->ase_calc = 1;
paul718e3742002-12-13 20:15:29 +0000673}
674
675void
paul68980082003-03-25 05:07:42 +0000676ospf_ase_calculate_timer_add (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000677{
paul68980082003-03-25 05:07:42 +0000678 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000679 return;
680
paul68980082003-03-25 05:07:42 +0000681 if (! ospf->t_ase_calc)
682 ospf->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer,
683 ospf, OSPF_ASE_CALC_INTERVAL);
paul718e3742002-12-13 20:15:29 +0000684}
685
686void
687ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
688{
689 struct route_node *rn;
690 struct prefix_ipv4 p;
691 list lst;
692 struct as_external_lsa *al;
693
694 al = (struct as_external_lsa *) lsa->data;
695 p.family = AF_INET;
696 p.prefix = lsa->data->id;
697 p.prefixlen = ip_masklen (al->mask);
698 apply_mask_ipv4 (&p);
699
700 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
701 if ((lst = rn->info) == NULL)
702 rn->info = lst = list_new();
703
704 /* We assume that if LSA is deleted from DB
705 is is also deleted from this RT */
706
707 listnode_add (lst, ospf_lsa_lock (lsa));
708}
709
710void
711ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
712{
713 struct route_node *rn;
714 struct prefix_ipv4 p;
715 list lst;
716 struct as_external_lsa *al;
717
718 al = (struct as_external_lsa *) lsa->data;
719 p.family = AF_INET;
720 p.prefix = lsa->data->id;
721 p.prefixlen = ip_masklen (al->mask);
722 apply_mask_ipv4 (&p);
723
724 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
725 lst = rn->info;
726#ifdef ORIGINAL_CODING
727 assert (lst);
728
729 listnode_delete (lst, lsa);
730 ospf_lsa_unlock (lsa);
731#else /* ORIGINAL_CODING */
732 /* XXX lst can be NULL */
733 if (lst) {
734 listnode_delete (lst, lsa);
735 ospf_lsa_unlock (lsa);
736 }
737#endif /* ORIGINAL_CODING */
738}
739
740void
741ospf_ase_external_lsas_finish (struct route_table *rt)
742{
743 struct route_node *rn;
744 struct ospf_lsa *lsa;
745 list lst;
746 listnode node;
747
748 for (rn = route_top (rt); rn; rn = route_next (rn))
749 if ((lst = rn->info) != NULL)
750 {
751 for (node = listhead (lst); node; node = nextnode (node))
752 if ((lsa = getdata (node)) != NULL)
753 ospf_lsa_unlock (lsa);
754 list_delete (lst);
755 }
756
757 route_table_finish (rt);
758}
759
760void
paul68980082003-03-25 05:07:42 +0000761ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa)
paul718e3742002-12-13 20:15:29 +0000762{
763 list lsas;
764 listnode node;
765 struct route_node *rn, *rn2;
766 struct prefix_ipv4 p;
767 struct route_table *tmp_old;
768 struct as_external_lsa *al;
769
770 al = (struct as_external_lsa *) lsa->data;
771 p.family = AF_INET;
772 p.prefix = lsa->data->id;
773 p.prefixlen = ip_masklen (al->mask);
774 apply_mask_ipv4 (&p);
775
776 /* if new_table is NULL, there was no spf calculation, thus
777 incremental update is unneeded */
paul68980082003-03-25 05:07:42 +0000778 if (!ospf->new_table)
paul718e3742002-12-13 20:15:29 +0000779 return;
780
781 /* If there is already an intra-area or inter-area route
782 to the destination, no recalculation is necessary
783 (internal routes take precedence). */
784
paul68980082003-03-25 05:07:42 +0000785 rn = route_node_lookup (ospf->new_table, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000786 if (rn && rn->info)
787 {
788 route_unlock_node (rn);
789 return;
790 }
791
paul68980082003-03-25 05:07:42 +0000792 rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000793 assert (rn && rn->info);
794 lsas = rn->info;
795
796 for (node = listhead (lsas); node; nextnode (node))
797 if ((lsa = getdata (node)) != NULL)
paul68980082003-03-25 05:07:42 +0000798 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000799
800 /* prepare temporary old routing table for compare */
801 tmp_old = route_table_init ();
paul68980082003-03-25 05:07:42 +0000802 rn = route_node_lookup (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000803 if (rn && rn->info)
804 {
805 rn2 = route_node_get (tmp_old, (struct prefix *) &p);
806 rn2->info = rn->info;
807 }
808
809 /* install changes to zebra */
paul68980082003-03-25 05:07:42 +0000810 ospf_ase_compare_tables (ospf->new_external_route, tmp_old);
paul718e3742002-12-13 20:15:29 +0000811
paul68980082003-03-25 05:07:42 +0000812 /* update ospf->old_external_route table */
paul718e3742002-12-13 20:15:29 +0000813 if (rn && rn->info)
814 ospf_route_free ((struct ospf_route *) rn->info);
815
paul68980082003-03-25 05:07:42 +0000816 rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p);
817 /* if new route exists, install it to ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000818 if (rn2 && rn2->info)
819 {
820 if (!rn)
paul68980082003-03-25 05:07:42 +0000821 rn = route_node_get (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000822 rn->info = rn2->info;
823 }
824 else
825 {
paul68980082003-03-25 05:07:42 +0000826 /* remove route node from ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000827 if (rn)
828 {
829 rn->info = NULL;
830 route_unlock_node (rn);
831 route_unlock_node (rn);
832 }
833 }
834
835 if (rn2)
836 {
paul68980082003-03-25 05:07:42 +0000837 /* rn2->info is stored in route node of ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000838 rn2->info = NULL;
839 route_unlock_node (rn2);
840 route_unlock_node (rn2);
841 }
842
843 route_table_finish (tmp_old);
844}