blob: db43e10221a88172671810e3f917429786c502a1 [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
paul96735ee2003-08-10 02:51:22 +0000144 for (node = listhead (ro->paths); node; nextnode (node))
paul718e3742002-12-13 20:15:29 +0000145 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;
paul718e3742002-12-13 20:15:29 +0000271 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
paul68980082003-03-25 05:07:42 +0000283ospf_ase_calculate_route (struct ospf *ospf, struct ospf_lsa * lsa)
paul718e3742002-12-13 20:15:29 +0000284{
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
296#ifdef HAVE_NSSA
297 if (lsa->data->type == OSPF_AS_NSSA_LSA)
298 if (IS_DEBUG_OSPF_NSSA)
299 zlog_info ("ospf_ase_calc(): Processing Type-7");
300
301 /* Stay away from any Local Translated Type-7 LSAs */
302 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
303 {
304 if (IS_DEBUG_OSPF_NSSA)
305 zlog_info ("ospf_ase_calc(): Rejecting Local Xlt'd");
306 return 0;
307 }
308#endif /* HAVE_NSSA */
309
310 zlog_info ("Route[External]: Calculate AS-external-LSA to %s/%d",
311 inet_ntoa (al->header.id), ip_masklen (al->mask));
312 /* (1) If the cost specified by the LSA is LSInfinity, or if the
313 LSA's LS age is equal to MaxAge, then examine the next LSA. */
314 if ((metric = GET_METRIC (al->e[0].metric)) >= OSPF_LS_INFINITY)
315 {
316 zlog_info ("Route[External]: Metric is OSPF_LS_INFINITY");
317 return 0;
318 }
319 if (IS_LSA_MAXAGE (lsa))
320 {
321 zlog_info ("Route[External]: AS-external-LSA is MAXAGE");
322 return 0;
323 }
324
325 /* (2) If the LSA was originated by the calculating router itself,
326 examine the next LSA. */
327 if (IS_LSA_SELF (lsa))
328 {
329 zlog_info ("Route[External]: AS-external-LSA is self originated");
330 return 0;
331 }
332
333 /* (3) Call the destination described by the LSA N. N's address is
334 obtained by masking the LSA's Link State ID with the
335 network/subnet mask contained in the body of the LSA. Look
336 up the routing table entries (potentially one per attached
337 area) for the AS boundary router (ASBR) that originated the
338 LSA. If no entries exist for router ASBR (i.e., ASBR is
339 unreachable), do nothing with this LSA and consider the next
340 in the list. */
341
342 asbr.family = AF_INET;
343 asbr.prefix = al->header.adv_router;
344 asbr.prefixlen = IPV4_MAX_BITLEN;
345 apply_mask_ipv4 (&asbr);
346
paul68980082003-03-25 05:07:42 +0000347 asbr_route = ospf_find_asbr_route (ospf, ospf->new_rtrs, &asbr);
paul718e3742002-12-13 20:15:29 +0000348 if (asbr_route == NULL)
349 {
350 zlog_info ("Route[External]: Can't find originating ASBR route");
351 return 0;
352 }
353 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
354 {
355 zlog_info ("Route[External]: Originating router is not an ASBR");
356 return 0;
357 }
358
359 /* Else, this LSA describes an AS external path to destination
360 N. Examine the forwarding address specified in the AS-
361 external-LSA. This indicates the IP address to which
362 packets for the destination should be forwarded. */
363
364 if (al->e[0].fwd_addr.s_addr == 0)
365 {
366 /* If the forwarding address is set to 0.0.0.0, packets should
367 be sent to the ASBR itself. Among the multiple routing table
368 entries for the ASBR, select the preferred entry as follows.
369 If RFC1583Compatibility is set to "disabled", prune the set
370 of routing table entries for the ASBR as described in
371 Section 16.4.1. In any case, among the remaining routing
372 table entries, select the routing table entry with the least
373 cost; when there are multiple least cost routing table
374 entries the entry whose associated area has the largest OSPF
375 Area ID (when considered as an unsigned 32-bit integer) is
376 chosen. */
377
378 /* asbr_route already contains the requested route */
379 }
380 else
381 {
382 /* If the forwarding address is non-zero, look up the
383 forwarding address in the routing table.[24] The matching
384 routing table entry must specify an intra-area or inter-area
385 path; if no such path exists, do nothing with the LSA and
386 consider the next in the list. */
paul68980082003-03-25 05:07:42 +0000387 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000388 {
389 zlog_info ("Route[External]: Forwarding address is our router address");
390 return 0;
391 }
392
393 asbr.family = AF_INET;
394 asbr.prefix = al->e[0].fwd_addr;
395 asbr.prefixlen = IPV4_MAX_BITLEN;
396
paul68980082003-03-25 05:07:42 +0000397 rn = route_node_match (ospf->new_table, (struct prefix *) &asbr);
paul718e3742002-12-13 20:15:29 +0000398
399 if (rn == NULL || (asbr_route = rn->info) == NULL)
400 {
401 zlog_info ("Route[External]: Can't find route to forwarding address");
402 if (rn)
403 route_unlock_node (rn);
404 return 0;
405 }
406
407 route_unlock_node (rn);
408 }
409
410 /* (4) Let X be the cost specified by the preferred routing table
411 entry for the ASBR/forwarding address, and Y the cost
412 specified in the LSA. X is in terms of the link state
413 metric, and Y is a type 1 or 2 external metric. */
414
415
416 /* (5) Look up the routing table entry for the destination N. If
417 no entry exists for N, install the AS external path to N,
418 with next hop equal to the list of next hops to the
419 forwarding address, and advertising router equal to ASBR.
420 If the external metric type is 1, then the path-type is set
421 to type 1 external and the cost is equal to X+Y. If the
422 external metric type is 2, the path-type is set to type 2
423 external, the link state component of the route's cost is X,
424 and the type 2 cost is Y. */
425 new = ospf_ase_calculate_new_route (lsa, asbr_route, metric);
426
427 /* (6) Compare the AS external path described by the LSA with the
428 existing paths in N's routing table entry, as follows. If
429 the new path is preferred, it replaces the present paths in
430 N's routing table entry. If the new path is of equal
431 preference, it is added to N's routing table entry's list of
432 paths. */
433
434 /* Set prefix. */
435 p.family = AF_INET;
436 p.prefix = al->header.id;
437 p.prefixlen = ip_masklen (al->mask);
438
439 /* if there is a Intra/Inter area route to the N
440 do not install external route */
paul68980082003-03-25 05:07:42 +0000441 if ((rn = route_node_lookup (ospf->new_table,
paul718e3742002-12-13 20:15:29 +0000442 (struct prefix *) &p)) != NULL
443 && (rn->info != NULL))
444 {
445 if (new)
446 ospf_route_free (new);
447 return 0;
448 }
449
450 /* Find a route to the same dest */
451 /* If there is no route, create new one. */
paul68980082003-03-25 05:07:42 +0000452 if ((rn = route_node_lookup (ospf->new_external_route,
paul718e3742002-12-13 20:15:29 +0000453 (struct prefix *) &p)) == NULL
454 || (or = rn->info) == NULL)
455 {
456 zlog_info ("Route[External]: Adding a new route %s/%d",
457 inet_ntoa (p.prefix), p.prefixlen);
458
paul68980082003-03-25 05:07:42 +0000459 ospf_route_add (ospf->new_external_route, &p, new, asbr_route);
paul718e3742002-12-13 20:15:29 +0000460
461 if (al->e[0].fwd_addr.s_addr)
462 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
463 return 0;
464 }
465 else
466 {
467 /* (a) Intra-area and inter-area paths are always preferred
468 over AS external paths.
469
470 (b) Type 1 external paths are always preferred over type 2
471 external paths. When all paths are type 2 external
472 paths, the paths with the smallest advertised type 2
473 metric are always preferred. */
paul68980082003-03-25 05:07:42 +0000474 ret = ospf_route_cmp (ospf, new, or);
paul718e3742002-12-13 20:15:29 +0000475
476 /* (c) If the new AS external path is still indistinguishable
477 from the current paths in the N's routing table entry,
478 and RFC1583Compatibility is set to "disabled", select
479 the preferred paths based on the intra-AS paths to the
480 ASBR/forwarding addresses, as specified in Section
481 16.4.1.
482
483 (d) If the new AS external path is still indistinguishable
484 from the current paths in the N's routing table entry,
485 select the preferred path based on a least cost
486 comparison. Type 1 external paths are compared by
487 looking at the sum of the distance to the forwarding
488 address and the advertised type 1 metric (X+Y). Type 2
489 external paths advertising equal type 2 metrics are
490 compared by looking at the distance to the forwarding
491 addresses.
492 */
493 /* New route is better */
494 if (ret < 0)
495 {
496 zlog_info ("Route[External]: New route is better");
497 ospf_route_subst (rn, new, asbr_route);
498 if (al->e[0].fwd_addr.s_addr)
499 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
500 or = new;
501 new = NULL;
502 }
503 /* Old route is better */
504 else if (ret > 0)
505 {
506 zlog_info ("Route[External]: Old route is better");
507 /* do nothing */
508 }
509 /* Routes are equal */
510 else
511 {
512 zlog_info ("Route[External]: Routes are equal");
paul96735ee2003-08-10 02:51:22 +0000513 ospf_route_copy_nexthops (or, asbr_route->paths);
paul718e3742002-12-13 20:15:29 +0000514 if (al->e[0].fwd_addr.s_addr)
515 ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr);
516 }
517 }
518 /* Make sure setting newly calculated ASBR route.*/
519 or->u.ext.asbr = asbr_route;
520 if (new)
521 ospf_route_free (new);
522
523 lsa->route = or;
524 return 0;
525}
526
527int
528ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix,
529 struct ospf_route *newor)
530{
531 struct route_node *rn;
532 struct ospf_route *or;
533 struct ospf_path *op;
534 struct ospf_path *newop;
535 listnode n1;
536 listnode n2;
537
538 if (! rt || ! prefix)
539 return 0;
540
541 rn = route_node_lookup (rt, prefix);
542 if (! rn)
543 return 0;
544
545 route_unlock_node (rn);
546
547 or = rn->info;
548 if (or->path_type != newor->path_type)
549 return 0;
550
551 switch (or->path_type)
552 {
553 case OSPF_PATH_TYPE1_EXTERNAL:
554 if (or->cost != newor->cost)
555 return 0;
556 break;
557 case OSPF_PATH_TYPE2_EXTERNAL:
558 if ((or->cost != newor->cost) ||
559 (or->u.ext.type2_cost != newor->u.ext.type2_cost))
560 return 0;
561 break;
562 default:
563 assert (0);
564 return 0;
565 }
566
paul96735ee2003-08-10 02:51:22 +0000567 if (or->paths->count != newor->paths->count)
paul718e3742002-12-13 20:15:29 +0000568 return 0;
569
570 /* Check each path. */
paul96735ee2003-08-10 02:51:22 +0000571 for (n1 = listhead (or->paths), n2 = listhead (newor->paths);
paul718e3742002-12-13 20:15:29 +0000572 n1 && n2; nextnode (n1), nextnode (n2))
573 {
574 op = getdata (n1);
575 newop = getdata (n2);
576
577 if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
578 return 0;
579 }
580 return 1;
581}
582
583int
584ospf_ase_compare_tables (struct route_table *new_external_route,
585 struct route_table *old_external_route)
586{
587 struct route_node *rn, *new_rn;
588 struct ospf_route *or;
589
590 /* Remove deleted routes */
591 for (rn = route_top (old_external_route); rn; rn = route_next (rn))
592 if ((or = rn->info))
593 {
594 if (! (new_rn = route_node_lookup (new_external_route, &rn->p)))
595 ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
596 else
597 route_unlock_node (new_rn);
598 }
599
600
601 /* Install new routes */
602 for (rn = route_top (new_external_route); rn; rn = route_next (rn))
603 if ((or = rn->info) != NULL)
604 if (! ospf_ase_route_match_same (old_external_route, &rn->p, or))
605 ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
606
607 return 0;
608}
609
610int
611ospf_ase_calculate_timer (struct thread *t)
612{
613 struct ospf *ospf;
paul68980082003-03-25 05:07:42 +0000614 struct ospf_lsa *lsa;
615 struct route_node *rn;
paul718e3742002-12-13 20:15:29 +0000616#ifdef HAVE_NSSA
paul68980082003-03-25 05:07:42 +0000617 listnode node;
618 struct ospf_area *area;
paul718e3742002-12-13 20:15:29 +0000619#endif /* HAVE_NSSA */
620
621 ospf = THREAD_ARG (t);
622 ospf->t_ase_calc = NULL;
623
624 if (ospf->ase_calc)
625 {
626 ospf->ase_calc = 0;
627
628 /* Calculate external route for each AS-external-LSA */
paul68980082003-03-25 05:07:42 +0000629 LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
630 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000631
632#ifdef HAVE_NSSA
633 /* This version simple adds to the table all NSSA areas */
paul68980082003-03-25 05:07:42 +0000634 if (ospf->anyNSSA)
635 for (node = listhead (ospf->areas); node; nextnode (node))
paul718e3742002-12-13 20:15:29 +0000636 {
637 area = getdata (node);
638 if (IS_DEBUG_OSPF_NSSA)
639 zlog_info ("ospf_ase_calculate_timer(): looking at area %s",
640 inet_ntoa (area->area_id));
641
642 if (area->external_routing == OSPF_AREA_NSSA)
paul68980082003-03-25 05:07:42 +0000643 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
644 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000645 }
paulf2c80652002-12-13 21:44:27 +0000646 /* kevinm: And add the NSSA routes in ospf_top */
paulf6386ee2003-04-07 04:29:27 +0000647 LSDB_LOOP (NSSA_LSDB (ospf),rn,lsa)
648 ospf_ase_calculate_route(ospf,lsa);
paulf2c80652002-12-13 21:44:27 +0000649
paul718e3742002-12-13 20:15:29 +0000650#endif /* HAVE_NSSA */
651
652 /* Compare old and new external routing table and install the
653 difference info zebra/kernel */
paul68980082003-03-25 05:07:42 +0000654 ospf_ase_compare_tables (ospf->new_external_route,
655 ospf->old_external_route);
paul718e3742002-12-13 20:15:29 +0000656
657 /* Delete old external routing table */
paul68980082003-03-25 05:07:42 +0000658 ospf_route_table_free (ospf->old_external_route);
659 ospf->old_external_route = ospf->new_external_route;
660 ospf->new_external_route = route_table_init ();
paul718e3742002-12-13 20:15:29 +0000661 }
662 return 0;
663}
664
665void
paul68980082003-03-25 05:07:42 +0000666ospf_ase_calculate_schedule (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000667{
paul68980082003-03-25 05:07:42 +0000668 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000669 return;
670
paul68980082003-03-25 05:07:42 +0000671 ospf->ase_calc = 1;
paul718e3742002-12-13 20:15:29 +0000672}
673
674void
paul68980082003-03-25 05:07:42 +0000675ospf_ase_calculate_timer_add (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000676{
paul68980082003-03-25 05:07:42 +0000677 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000678 return;
679
paul68980082003-03-25 05:07:42 +0000680 if (! ospf->t_ase_calc)
681 ospf->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer,
682 ospf, OSPF_ASE_CALC_INTERVAL);
paul718e3742002-12-13 20:15:29 +0000683}
684
685void
686ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
687{
688 struct route_node *rn;
689 struct prefix_ipv4 p;
690 list lst;
691 struct as_external_lsa *al;
692
693 al = (struct as_external_lsa *) lsa->data;
694 p.family = AF_INET;
695 p.prefix = lsa->data->id;
696 p.prefixlen = ip_masklen (al->mask);
697 apply_mask_ipv4 (&p);
698
699 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
700 if ((lst = rn->info) == NULL)
701 rn->info = lst = list_new();
702
703 /* We assume that if LSA is deleted from DB
704 is is also deleted from this RT */
705
706 listnode_add (lst, ospf_lsa_lock (lsa));
707}
708
709void
710ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
711{
712 struct route_node *rn;
713 struct prefix_ipv4 p;
714 list lst;
715 struct as_external_lsa *al;
716
717 al = (struct as_external_lsa *) lsa->data;
718 p.family = AF_INET;
719 p.prefix = lsa->data->id;
720 p.prefixlen = ip_masklen (al->mask);
721 apply_mask_ipv4 (&p);
722
723 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
724 lst = rn->info;
725#ifdef ORIGINAL_CODING
726 assert (lst);
727
728 listnode_delete (lst, lsa);
729 ospf_lsa_unlock (lsa);
730#else /* ORIGINAL_CODING */
731 /* XXX lst can be NULL */
732 if (lst) {
733 listnode_delete (lst, lsa);
734 ospf_lsa_unlock (lsa);
735 }
736#endif /* ORIGINAL_CODING */
737}
738
739void
740ospf_ase_external_lsas_finish (struct route_table *rt)
741{
742 struct route_node *rn;
743 struct ospf_lsa *lsa;
744 list lst;
745 listnode node;
746
747 for (rn = route_top (rt); rn; rn = route_next (rn))
748 if ((lst = rn->info) != NULL)
749 {
750 for (node = listhead (lst); node; node = nextnode (node))
751 if ((lsa = getdata (node)) != NULL)
752 ospf_lsa_unlock (lsa);
753 list_delete (lst);
754 }
755
756 route_table_finish (rt);
757}
758
759void
paul68980082003-03-25 05:07:42 +0000760ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa)
paul718e3742002-12-13 20:15:29 +0000761{
762 list lsas;
763 listnode node;
764 struct route_node *rn, *rn2;
765 struct prefix_ipv4 p;
766 struct route_table *tmp_old;
767 struct as_external_lsa *al;
768
769 al = (struct as_external_lsa *) lsa->data;
770 p.family = AF_INET;
771 p.prefix = lsa->data->id;
772 p.prefixlen = ip_masklen (al->mask);
773 apply_mask_ipv4 (&p);
774
775 /* if new_table is NULL, there was no spf calculation, thus
776 incremental update is unneeded */
paul68980082003-03-25 05:07:42 +0000777 if (!ospf->new_table)
paul718e3742002-12-13 20:15:29 +0000778 return;
779
780 /* If there is already an intra-area or inter-area route
781 to the destination, no recalculation is necessary
782 (internal routes take precedence). */
783
paul68980082003-03-25 05:07:42 +0000784 rn = route_node_lookup (ospf->new_table, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000785 if (rn && rn->info)
786 {
787 route_unlock_node (rn);
788 return;
789 }
790
paul68980082003-03-25 05:07:42 +0000791 rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000792 assert (rn && rn->info);
793 lsas = rn->info;
794
795 for (node = listhead (lsas); node; nextnode (node))
796 if ((lsa = getdata (node)) != NULL)
paul68980082003-03-25 05:07:42 +0000797 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000798
799 /* prepare temporary old routing table for compare */
800 tmp_old = route_table_init ();
paul68980082003-03-25 05:07:42 +0000801 rn = route_node_lookup (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000802 if (rn && rn->info)
803 {
804 rn2 = route_node_get (tmp_old, (struct prefix *) &p);
805 rn2->info = rn->info;
806 }
807
808 /* install changes to zebra */
paul68980082003-03-25 05:07:42 +0000809 ospf_ase_compare_tables (ospf->new_external_route, tmp_old);
paul718e3742002-12-13 20:15:29 +0000810
paul68980082003-03-25 05:07:42 +0000811 /* update ospf->old_external_route table */
paul718e3742002-12-13 20:15:29 +0000812 if (rn && rn->info)
813 ospf_route_free ((struct ospf_route *) rn->info);
814
paul68980082003-03-25 05:07:42 +0000815 rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p);
816 /* if new route exists, install it to ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000817 if (rn2 && rn2->info)
818 {
819 if (!rn)
paul68980082003-03-25 05:07:42 +0000820 rn = route_node_get (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000821 rn->info = rn2->info;
822 }
823 else
824 {
paul68980082003-03-25 05:07:42 +0000825 /* remove route node from ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000826 if (rn)
827 {
828 rn->info = NULL;
829 route_unlock_node (rn);
830 route_unlock_node (rn);
831 }
832 }
833
834 if (rn2)
835 {
paul68980082003-03-25 05:07:42 +0000836 /* rn2->info is stored in route node of ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000837 rn2->info = NULL;
838 route_unlock_node (rn2);
839 route_unlock_node (rn2);
840 }
841
842 route_table_finish (tmp_old);
843}