blob: e44a8e9af6afb2523ae8ee8ec492dd86270333be [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;
hasso52dc7ee2004-09-23 19:18:23 +000057 struct listnode *node;
58 struct list *chosen;
paul718e3742002-12-13 20:15:29 +000059
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))
hasso52dc7ee2004-09-23 19:18:23 +000074 for (node = listhead ((struct list *) rn->info); node; nextnode (node))
paul718e3742002-12-13 20:15:29 +000075 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 {
hasso52dc7ee2004-09-23 19:18:23 +0000124 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000125 struct ospf_route *or;
126
127 route_unlock_node (rn);
128
hasso52dc7ee2004-09-23 19:18:23 +0000129 for (node = listhead ((struct list *) rn->info); node; nextnode (node))
paul718e3742002-12-13 20:15:29 +0000130 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{
hasso52dc7ee2004-09-23 19:18:23 +0000141 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000142 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{
hasso52dc7ee2004-09-23 19:18:23 +0000153 struct listnode *ifn;
paul718e3742002-12-13 20:15:29 +0000154 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
paul718e3742002-12-13 20:15:29 +0000296 if (lsa->data->type == OSPF_AS_NSSA_LSA)
297 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000298 zlog_debug ("ospf_ase_calc(): Processing Type-7");
paul718e3742002-12-13 20:15:29 +0000299
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)
ajse84cc642004-12-08 17:28:56 +0000304 zlog_debug ("ospf_ase_calc(): Rejecting Local Xlt'd");
paul718e3742002-12-13 20:15:29 +0000305 return 0;
306 }
paul718e3742002-12-13 20:15:29 +0000307
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
paul68980082003-03-25 05:07:42 +0000345 asbr_route = ospf_find_asbr_route (ospf, ospf->new_rtrs, &asbr);
paul718e3742002-12-13 20:15:29 +0000346 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. */
paul68980082003-03-25 05:07:42 +0000385 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000386 {
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
paul68980082003-03-25 05:07:42 +0000395 rn = route_node_match (ospf->new_table, (struct prefix *) &asbr);
paul718e3742002-12-13 20:15:29 +0000396
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 */
paul68980082003-03-25 05:07:42 +0000439 if ((rn = route_node_lookup (ospf->new_table,
paul718e3742002-12-13 20:15:29 +0000440 (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. */
paul68980082003-03-25 05:07:42 +0000450 if ((rn = route_node_lookup (ospf->new_external_route,
paul718e3742002-12-13 20:15:29 +0000451 (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
paul68980082003-03-25 05:07:42 +0000457 ospf_route_add (ospf->new_external_route, &p, new, asbr_route);
paul718e3742002-12-13 20:15:29 +0000458
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. */
paul68980082003-03-25 05:07:42 +0000472 ret = ospf_route_cmp (ospf, new, or);
paul718e3742002-12-13 20:15:29 +0000473
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");
paul96735ee2003-08-10 02:51:22 +0000511 ospf_route_copy_nexthops (or, asbr_route->paths);
paul718e3742002-12-13 20:15:29 +0000512 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;
hasso52dc7ee2004-09-23 19:18:23 +0000533 struct listnode *n1;
534 struct listnode *n2;
paul718e3742002-12-13 20:15:29 +0000535
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
paul96735ee2003-08-10 02:51:22 +0000565 if (or->paths->count != newor->paths->count)
paul718e3742002-12-13 20:15:29 +0000566 return 0;
567
568 /* Check each path. */
paul96735ee2003-08-10 02:51:22 +0000569 for (n1 = listhead (or->paths), n2 = listhead (newor->paths);
paul718e3742002-12-13 20:15:29 +0000570 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;
paul68980082003-03-25 05:07:42 +0000612 struct ospf_lsa *lsa;
613 struct route_node *rn;
hasso52dc7ee2004-09-23 19:18:23 +0000614 struct listnode *node;
paul68980082003-03-25 05:07:42 +0000615 struct ospf_area *area;
paul718e3742002-12-13 20:15:29 +0000616
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 */
paul68980082003-03-25 05:07:42 +0000625 LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
626 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000627
paul718e3742002-12-13 20:15:29 +0000628 /* This version simple adds to the table all NSSA areas */
paul68980082003-03-25 05:07:42 +0000629 if (ospf->anyNSSA)
630 for (node = listhead (ospf->areas); node; nextnode (node))
paul718e3742002-12-13 20:15:29 +0000631 {
632 area = getdata (node);
633 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000634 zlog_debug ("ospf_ase_calculate_timer(): looking at area %s",
paul718e3742002-12-13 20:15:29 +0000635 inet_ntoa (area->area_id));
636
637 if (area->external_routing == OSPF_AREA_NSSA)
paul68980082003-03-25 05:07:42 +0000638 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
639 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000640 }
paulf2c80652002-12-13 21:44:27 +0000641 /* kevinm: And add the NSSA routes in ospf_top */
paulf6386ee2003-04-07 04:29:27 +0000642 LSDB_LOOP (NSSA_LSDB (ospf),rn,lsa)
643 ospf_ase_calculate_route(ospf,lsa);
paulf2c80652002-12-13 21:44:27 +0000644
paul718e3742002-12-13 20:15:29 +0000645 /* Compare old and new external routing table and install the
646 difference info zebra/kernel */
paul68980082003-03-25 05:07:42 +0000647 ospf_ase_compare_tables (ospf->new_external_route,
648 ospf->old_external_route);
paul718e3742002-12-13 20:15:29 +0000649
650 /* Delete old external routing table */
paul68980082003-03-25 05:07:42 +0000651 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 ();
paul718e3742002-12-13 20:15:29 +0000654 }
655 return 0;
656}
657
658void
paul68980082003-03-25 05:07:42 +0000659ospf_ase_calculate_schedule (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000660{
paul68980082003-03-25 05:07:42 +0000661 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000662 return;
663
paul68980082003-03-25 05:07:42 +0000664 ospf->ase_calc = 1;
paul718e3742002-12-13 20:15:29 +0000665}
666
667void
paul68980082003-03-25 05:07:42 +0000668ospf_ase_calculate_timer_add (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000669{
paul68980082003-03-25 05:07:42 +0000670 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000671 return;
672
paul68980082003-03-25 05:07:42 +0000673 if (! ospf->t_ase_calc)
674 ospf->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer,
675 ospf, OSPF_ASE_CALC_INTERVAL);
paul718e3742002-12-13 20:15:29 +0000676}
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;
hasso52dc7ee2004-09-23 19:18:23 +0000683 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000684 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;
hasso52dc7ee2004-09-23 19:18:23 +0000707 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000708 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;
hasso52dc7ee2004-09-23 19:18:23 +0000737 struct list *lst;
738 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000739
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
paul68980082003-03-25 05:07:42 +0000753ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa)
paul718e3742002-12-13 20:15:29 +0000754{
hasso52dc7ee2004-09-23 19:18:23 +0000755 struct list *lsas;
756 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000757 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 */
paul68980082003-03-25 05:07:42 +0000770 if (!ospf->new_table)
paul718e3742002-12-13 20:15:29 +0000771 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
paul68980082003-03-25 05:07:42 +0000777 rn = route_node_lookup (ospf->new_table, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000778 if (rn && rn->info)
779 {
780 route_unlock_node (rn);
781 return;
782 }
783
paul68980082003-03-25 05:07:42 +0000784 rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000785 assert (rn && rn->info);
786 lsas = rn->info;
787
788 for (node = listhead (lsas); node; nextnode (node))
789 if ((lsa = getdata (node)) != NULL)
paul68980082003-03-25 05:07:42 +0000790 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000791
792 /* prepare temporary old routing table for compare */
793 tmp_old = route_table_init ();
paul68980082003-03-25 05:07:42 +0000794 rn = route_node_lookup (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000795 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 */
paul68980082003-03-25 05:07:42 +0000802 ospf_ase_compare_tables (ospf->new_external_route, tmp_old);
paul718e3742002-12-13 20:15:29 +0000803
paul68980082003-03-25 05:07:42 +0000804 /* update ospf->old_external_route table */
paul718e3742002-12-13 20:15:29 +0000805 if (rn && rn->info)
806 ospf_route_free ((struct ospf_route *) rn->info);
807
paul68980082003-03-25 05:07:42 +0000808 rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p);
809 /* if new route exists, install it to ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000810 if (rn2 && rn2->info)
811 {
812 if (!rn)
paul68980082003-03-25 05:07:42 +0000813 rn = route_node_get (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000814 rn->info = rn2->info;
815 }
816 else
817 {
paul68980082003-03-25 05:07:42 +0000818 /* remove route node from ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000819 if (rn)
820 {
821 rn->info = NULL;
822 route_unlock_node (rn);
823 route_unlock_node (rn);
824 }
825 }
826
827 if (rn2)
828 {
paul68980082003-03-25 05:07:42 +0000829 /* rn2->info is stored in route node of ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000830 rn2->info = NULL;
831 route_unlock_node (rn2);
832 route_unlock_node (rn2);
833 }
834
835 route_table_finish (tmp_old);
836}