blob: c4f4dd3db006f7cd37ddc266faaecda34e391545 [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 {
hassoe40dcce2005-02-21 14:58:42 +0000187 if (IS_DEBUG_OSPF (lsa, LSA))
188 zlog_debug ("ospf_ase_calculate(): Route to ASBR %s not found",
189 inet_ntoa (asbr.prefix));
paul718e3742002-12-13 20:15:29 +0000190 return NULL;
191 }
192
193 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
194 {
hassoe40dcce2005-02-21 14:58:42 +0000195 if (IS_DEBUG_OSPF (lsa, LSA))
196 zlog_debug ("ospf_ase_calculate(): Originating router is not an ASBR");
paul718e3742002-12-13 20:15:29 +0000197 return NULL;
198 }
199
200 if (al->e[0].fwd_addr.s_addr != 0)
201 {
hassoe40dcce2005-02-21 14:58:42 +0000202 if (IS_DEBUG_OSPF (lsa, LSA))
203 zlog_debug ("ospf_ase_calculate(): "
204 "Forwarding address is not 0.0.0.0.");
paul718e3742002-12-13 20:15:29 +0000205
paul68980082003-03-25 05:07:42 +0000206 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000207 {
hassoe40dcce2005-02-21 14:58:42 +0000208 if (IS_DEBUG_OSPF (lsa, LSA))
209 zlog_debug ("ospf_ase_calculate(): "
210 "Forwarding address is one of our addresses, Ignore.");
paul718e3742002-12-13 20:15:29 +0000211 return NULL;
212 }
213
hassoe40dcce2005-02-21 14:58:42 +0000214 if (IS_DEBUG_OSPF (lsa, LSA))
215 zlog_debug ("ospf_ase_calculate(): "
216 "Looking up in the Network Routing Table.");
paul718e3742002-12-13 20:15:29 +0000217
218 /* Looking up the path to the fwd_addr from Network route. */
219 asbr.family = AF_INET;
220 asbr.prefix = al->e[0].fwd_addr;
221 asbr.prefixlen = IPV4_MAX_BITLEN;
222
223 rn = route_node_match (rt_network, (struct prefix *) &asbr);
224
225 if (rn == NULL)
226 {
hassoe40dcce2005-02-21 14:58:42 +0000227 if (IS_DEBUG_OSPF (lsa, LSA))
228 zlog_debug ("ospf_ase_calculate(): "
229 "Couldn't find a route to the forwarding address.");
paul718e3742002-12-13 20:15:29 +0000230 return NULL;
231 }
232
233 route_unlock_node (rn);
234
235 if ((asbr_route = rn->info) == NULL)
236 {
hassoe40dcce2005-02-21 14:58:42 +0000237 if (IS_DEBUG_OSPF (lsa, LSA))
238 zlog_debug ("ospf_ase_calculate(): "
239 "Somehow OSPF route to ASBR is lost");
paul718e3742002-12-13 20:15:29 +0000240 return NULL;
241 }
242 }
243
244 return asbr_route;
245}
246
247struct ospf_route *
248ospf_ase_calculate_new_route (struct ospf_lsa *lsa,
249 struct ospf_route *asbr_route, u_int32_t metric)
250{
251 struct as_external_lsa *al;
252 struct ospf_route *new;
253
254 al = (struct as_external_lsa *) lsa->data;
255
256 new = ospf_route_new ();
257
258 /* Set redistributed type -- does make sense? */
259 /* new->type = type; */
260 new->id = al->header.id;
261 new->mask = al->mask;
262
263 if (!IS_EXTERNAL_METRIC (al->e[0].tos))
264 {
hassoe40dcce2005-02-21 14:58:42 +0000265 if (IS_DEBUG_OSPF (lsa, LSA))
266 zlog_debug ("Route[External]: type-1 created.");
paul718e3742002-12-13 20:15:29 +0000267 new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
268 new->cost = asbr_route->cost + metric; /* X + Y */
269 }
270 else
271 {
hassoe40dcce2005-02-21 14:58:42 +0000272 if (IS_DEBUG_OSPF (lsa, LSA))
273 zlog_debug ("Route[External]: type-2 created.");
paul718e3742002-12-13 20:15:29 +0000274 new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
275 new->cost = asbr_route->cost; /* X */
276 new->u.ext.type2_cost = metric; /* Y */
277 }
278
279 new->type = OSPF_DESTINATION_NETWORK;
paul718e3742002-12-13 20:15:29 +0000280 new->u.ext.origin = lsa;
281 new->u.ext.tag = ntohl (al->e[0].route_tag);
282 new->u.ext.asbr = asbr_route;
283
284 assert (new != asbr_route);
285
286 return new;
287}
288
289#define OSPF_ASE_CALC_INTERVAL 1
290
291int
paul68980082003-03-25 05:07:42 +0000292ospf_ase_calculate_route (struct ospf *ospf, struct ospf_lsa * lsa)
paul718e3742002-12-13 20:15:29 +0000293{
294 u_int32_t metric;
295 struct as_external_lsa *al;
296 struct ospf_route *asbr_route;
297 struct prefix_ipv4 asbr, p;
298 struct route_node *rn;
299 struct ospf_route *new, *or;
300 int ret;
301
302 assert (lsa);
303 al = (struct as_external_lsa *) lsa->data;
304
paul718e3742002-12-13 20:15:29 +0000305 if (lsa->data->type == OSPF_AS_NSSA_LSA)
306 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000307 zlog_debug ("ospf_ase_calc(): Processing Type-7");
paul718e3742002-12-13 20:15:29 +0000308
309 /* Stay away from any Local Translated Type-7 LSAs */
310 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
311 {
312 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000313 zlog_debug ("ospf_ase_calc(): Rejecting Local Xlt'd");
paul718e3742002-12-13 20:15:29 +0000314 return 0;
315 }
paul718e3742002-12-13 20:15:29 +0000316
hassoe40dcce2005-02-21 14:58:42 +0000317 if (IS_DEBUG_OSPF (lsa, LSA))
318 zlog_debug ("Route[External]: Calculate AS-external-LSA to %s/%d",
319 inet_ntoa (al->header.id), ip_masklen (al->mask));
paul718e3742002-12-13 20:15:29 +0000320 /* (1) If the cost specified by the LSA is LSInfinity, or if the
321 LSA's LS age is equal to MaxAge, then examine the next LSA. */
322 if ((metric = GET_METRIC (al->e[0].metric)) >= OSPF_LS_INFINITY)
323 {
hassoe40dcce2005-02-21 14:58:42 +0000324 if (IS_DEBUG_OSPF (lsa, LSA))
325 zlog_debug ("Route[External]: Metric is OSPF_LS_INFINITY");
paul718e3742002-12-13 20:15:29 +0000326 return 0;
327 }
328 if (IS_LSA_MAXAGE (lsa))
329 {
hassoe40dcce2005-02-21 14:58:42 +0000330 if (IS_DEBUG_OSPF (lsa, LSA))
331 zlog_debug ("Route[External]: AS-external-LSA is MAXAGE");
paul718e3742002-12-13 20:15:29 +0000332 return 0;
333 }
334
335 /* (2) If the LSA was originated by the calculating router itself,
336 examine the next LSA. */
337 if (IS_LSA_SELF (lsa))
338 {
hassoe40dcce2005-02-21 14:58:42 +0000339 if (IS_DEBUG_OSPF (lsa, LSA))
340 zlog_debug ("Route[External]: AS-external-LSA is self originated");
paul718e3742002-12-13 20:15:29 +0000341 return 0;
342 }
343
344 /* (3) Call the destination described by the LSA N. N's address is
345 obtained by masking the LSA's Link State ID with the
346 network/subnet mask contained in the body of the LSA. Look
347 up the routing table entries (potentially one per attached
348 area) for the AS boundary router (ASBR) that originated the
349 LSA. If no entries exist for router ASBR (i.e., ASBR is
350 unreachable), do nothing with this LSA and consider the next
351 in the list. */
352
353 asbr.family = AF_INET;
354 asbr.prefix = al->header.adv_router;
355 asbr.prefixlen = IPV4_MAX_BITLEN;
356 apply_mask_ipv4 (&asbr);
357
paul68980082003-03-25 05:07:42 +0000358 asbr_route = ospf_find_asbr_route (ospf, ospf->new_rtrs, &asbr);
paul718e3742002-12-13 20:15:29 +0000359 if (asbr_route == NULL)
360 {
hassoe40dcce2005-02-21 14:58:42 +0000361 if (IS_DEBUG_OSPF (lsa, LSA))
362 zlog_debug ("Route[External]: Can't find originating ASBR route");
paul718e3742002-12-13 20:15:29 +0000363 return 0;
364 }
365 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
366 {
hassoe40dcce2005-02-21 14:58:42 +0000367 if (IS_DEBUG_OSPF (lsa, LSA))
368 zlog_debug ("Route[External]: Originating router is not an ASBR");
paul718e3742002-12-13 20:15:29 +0000369 return 0;
370 }
371
372 /* Else, this LSA describes an AS external path to destination
373 N. Examine the forwarding address specified in the AS-
374 external-LSA. This indicates the IP address to which
375 packets for the destination should be forwarded. */
376
377 if (al->e[0].fwd_addr.s_addr == 0)
378 {
379 /* If the forwarding address is set to 0.0.0.0, packets should
380 be sent to the ASBR itself. Among the multiple routing table
381 entries for the ASBR, select the preferred entry as follows.
382 If RFC1583Compatibility is set to "disabled", prune the set
383 of routing table entries for the ASBR as described in
384 Section 16.4.1. In any case, among the remaining routing
385 table entries, select the routing table entry with the least
386 cost; when there are multiple least cost routing table
387 entries the entry whose associated area has the largest OSPF
388 Area ID (when considered as an unsigned 32-bit integer) is
389 chosen. */
390
391 /* asbr_route already contains the requested route */
392 }
393 else
394 {
395 /* If the forwarding address is non-zero, look up the
396 forwarding address in the routing table.[24] The matching
397 routing table entry must specify an intra-area or inter-area
398 path; if no such path exists, do nothing with the LSA and
399 consider the next in the list. */
paul68980082003-03-25 05:07:42 +0000400 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000401 {
hassoe40dcce2005-02-21 14:58:42 +0000402 if (IS_DEBUG_OSPF (lsa, LSA))
403 zlog_debug ("Route[External]: Forwarding address is our router "
404 "address");
paul718e3742002-12-13 20:15:29 +0000405 return 0;
406 }
407
408 asbr.family = AF_INET;
409 asbr.prefix = al->e[0].fwd_addr;
410 asbr.prefixlen = IPV4_MAX_BITLEN;
411
paul68980082003-03-25 05:07:42 +0000412 rn = route_node_match (ospf->new_table, (struct prefix *) &asbr);
paul718e3742002-12-13 20:15:29 +0000413
414 if (rn == NULL || (asbr_route = rn->info) == NULL)
415 {
hassoe40dcce2005-02-21 14:58:42 +0000416 if (IS_DEBUG_OSPF (lsa, LSA))
417 zlog_debug ("Route[External]: Can't find route to forwarding "
418 "address");
paul718e3742002-12-13 20:15:29 +0000419 if (rn)
420 route_unlock_node (rn);
421 return 0;
422 }
423
424 route_unlock_node (rn);
425 }
426
427 /* (4) Let X be the cost specified by the preferred routing table
428 entry for the ASBR/forwarding address, and Y the cost
429 specified in the LSA. X is in terms of the link state
430 metric, and Y is a type 1 or 2 external metric. */
431
432
433 /* (5) Look up the routing table entry for the destination N. If
434 no entry exists for N, install the AS external path to N,
435 with next hop equal to the list of next hops to the
436 forwarding address, and advertising router equal to ASBR.
437 If the external metric type is 1, then the path-type is set
438 to type 1 external and the cost is equal to X+Y. If the
439 external metric type is 2, the path-type is set to type 2
440 external, the link state component of the route's cost is X,
441 and the type 2 cost is Y. */
442 new = ospf_ase_calculate_new_route (lsa, asbr_route, metric);
443
444 /* (6) Compare the AS external path described by the LSA with the
445 existing paths in N's routing table entry, as follows. If
446 the new path is preferred, it replaces the present paths in
447 N's routing table entry. If the new path is of equal
448 preference, it is added to N's routing table entry's list of
449 paths. */
450
451 /* Set prefix. */
452 p.family = AF_INET;
453 p.prefix = al->header.id;
454 p.prefixlen = ip_masklen (al->mask);
455
456 /* if there is a Intra/Inter area route to the N
457 do not install external route */
paul68980082003-03-25 05:07:42 +0000458 if ((rn = route_node_lookup (ospf->new_table,
paul718e3742002-12-13 20:15:29 +0000459 (struct prefix *) &p)) != NULL
460 && (rn->info != NULL))
461 {
462 if (new)
463 ospf_route_free (new);
464 return 0;
465 }
466
467 /* Find a route to the same dest */
468 /* If there is no route, create new one. */
paul68980082003-03-25 05:07:42 +0000469 if ((rn = route_node_lookup (ospf->new_external_route,
paul718e3742002-12-13 20:15:29 +0000470 (struct prefix *) &p)) == NULL
471 || (or = rn->info) == NULL)
472 {
hassoe40dcce2005-02-21 14:58:42 +0000473 if (IS_DEBUG_OSPF (lsa, LSA))
474 zlog_debug ("Route[External]: Adding a new route %s/%d",
475 inet_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000476
paul68980082003-03-25 05:07:42 +0000477 ospf_route_add (ospf->new_external_route, &p, new, asbr_route);
paul718e3742002-12-13 20:15:29 +0000478
479 if (al->e[0].fwd_addr.s_addr)
480 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
481 return 0;
482 }
483 else
484 {
485 /* (a) Intra-area and inter-area paths are always preferred
486 over AS external paths.
487
488 (b) Type 1 external paths are always preferred over type 2
489 external paths. When all paths are type 2 external
490 paths, the paths with the smallest advertised type 2
491 metric are always preferred. */
paul68980082003-03-25 05:07:42 +0000492 ret = ospf_route_cmp (ospf, new, or);
paul718e3742002-12-13 20:15:29 +0000493
494 /* (c) If the new AS external path is still indistinguishable
495 from the current paths in the N's routing table entry,
496 and RFC1583Compatibility is set to "disabled", select
497 the preferred paths based on the intra-AS paths to the
498 ASBR/forwarding addresses, as specified in Section
499 16.4.1.
500
501 (d) If the new AS external path is still indistinguishable
502 from the current paths in the N's routing table entry,
503 select the preferred path based on a least cost
504 comparison. Type 1 external paths are compared by
505 looking at the sum of the distance to the forwarding
506 address and the advertised type 1 metric (X+Y). Type 2
507 external paths advertising equal type 2 metrics are
508 compared by looking at the distance to the forwarding
509 addresses.
510 */
511 /* New route is better */
512 if (ret < 0)
513 {
hassoe40dcce2005-02-21 14:58:42 +0000514 if (IS_DEBUG_OSPF (lsa, LSA))
515 zlog_debug ("Route[External]: New route is better");
paul718e3742002-12-13 20:15:29 +0000516 ospf_route_subst (rn, new, asbr_route);
517 if (al->e[0].fwd_addr.s_addr)
518 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
519 or = new;
520 new = NULL;
521 }
522 /* Old route is better */
523 else if (ret > 0)
524 {
hassoe40dcce2005-02-21 14:58:42 +0000525 if (IS_DEBUG_OSPF (lsa, LSA))
526 zlog_debug ("Route[External]: Old route is better");
paul718e3742002-12-13 20:15:29 +0000527 /* do nothing */
528 }
529 /* Routes are equal */
530 else
531 {
hassoe40dcce2005-02-21 14:58:42 +0000532 if (IS_DEBUG_OSPF (lsa, LSA))
533 zlog_debug ("Route[External]: Routes are equal");
paul96735ee2003-08-10 02:51:22 +0000534 ospf_route_copy_nexthops (or, asbr_route->paths);
paul718e3742002-12-13 20:15:29 +0000535 if (al->e[0].fwd_addr.s_addr)
536 ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr);
537 }
538 }
539 /* Make sure setting newly calculated ASBR route.*/
540 or->u.ext.asbr = asbr_route;
541 if (new)
542 ospf_route_free (new);
543
544 lsa->route = or;
545 return 0;
546}
547
548int
549ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix,
550 struct ospf_route *newor)
551{
552 struct route_node *rn;
553 struct ospf_route *or;
554 struct ospf_path *op;
555 struct ospf_path *newop;
hasso52dc7ee2004-09-23 19:18:23 +0000556 struct listnode *n1;
557 struct listnode *n2;
paul718e3742002-12-13 20:15:29 +0000558
559 if (! rt || ! prefix)
560 return 0;
561
562 rn = route_node_lookup (rt, prefix);
563 if (! rn)
564 return 0;
565
566 route_unlock_node (rn);
567
568 or = rn->info;
569 if (or->path_type != newor->path_type)
570 return 0;
571
572 switch (or->path_type)
573 {
574 case OSPF_PATH_TYPE1_EXTERNAL:
575 if (or->cost != newor->cost)
576 return 0;
577 break;
578 case OSPF_PATH_TYPE2_EXTERNAL:
579 if ((or->cost != newor->cost) ||
580 (or->u.ext.type2_cost != newor->u.ext.type2_cost))
581 return 0;
582 break;
583 default:
584 assert (0);
585 return 0;
586 }
587
paul96735ee2003-08-10 02:51:22 +0000588 if (or->paths->count != newor->paths->count)
paul718e3742002-12-13 20:15:29 +0000589 return 0;
590
591 /* Check each path. */
paul96735ee2003-08-10 02:51:22 +0000592 for (n1 = listhead (or->paths), n2 = listhead (newor->paths);
paul718e3742002-12-13 20:15:29 +0000593 n1 && n2; nextnode (n1), nextnode (n2))
594 {
595 op = getdata (n1);
596 newop = getdata (n2);
597
598 if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
599 return 0;
600 }
601 return 1;
602}
603
604int
605ospf_ase_compare_tables (struct route_table *new_external_route,
606 struct route_table *old_external_route)
607{
608 struct route_node *rn, *new_rn;
609 struct ospf_route *or;
610
611 /* Remove deleted routes */
612 for (rn = route_top (old_external_route); rn; rn = route_next (rn))
613 if ((or = rn->info))
614 {
615 if (! (new_rn = route_node_lookup (new_external_route, &rn->p)))
616 ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
617 else
618 route_unlock_node (new_rn);
619 }
620
621
622 /* Install new routes */
623 for (rn = route_top (new_external_route); rn; rn = route_next (rn))
624 if ((or = rn->info) != NULL)
625 if (! ospf_ase_route_match_same (old_external_route, &rn->p, or))
626 ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
627
628 return 0;
629}
630
631int
632ospf_ase_calculate_timer (struct thread *t)
633{
634 struct ospf *ospf;
paul68980082003-03-25 05:07:42 +0000635 struct ospf_lsa *lsa;
636 struct route_node *rn;
hasso52dc7ee2004-09-23 19:18:23 +0000637 struct listnode *node;
paul68980082003-03-25 05:07:42 +0000638 struct ospf_area *area;
paul718e3742002-12-13 20:15:29 +0000639
640 ospf = THREAD_ARG (t);
641 ospf->t_ase_calc = NULL;
642
643 if (ospf->ase_calc)
644 {
645 ospf->ase_calc = 0;
646
647 /* Calculate external route for each AS-external-LSA */
paul68980082003-03-25 05:07:42 +0000648 LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
649 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000650
paul718e3742002-12-13 20:15:29 +0000651 /* This version simple adds to the table all NSSA areas */
paul68980082003-03-25 05:07:42 +0000652 if (ospf->anyNSSA)
653 for (node = listhead (ospf->areas); node; nextnode (node))
paul718e3742002-12-13 20:15:29 +0000654 {
655 area = getdata (node);
656 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000657 zlog_debug ("ospf_ase_calculate_timer(): looking at area %s",
paul718e3742002-12-13 20:15:29 +0000658 inet_ntoa (area->area_id));
659
660 if (area->external_routing == OSPF_AREA_NSSA)
paul68980082003-03-25 05:07:42 +0000661 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
662 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000663 }
paulf2c80652002-12-13 21:44:27 +0000664 /* kevinm: And add the NSSA routes in ospf_top */
paulf6386ee2003-04-07 04:29:27 +0000665 LSDB_LOOP (NSSA_LSDB (ospf),rn,lsa)
666 ospf_ase_calculate_route(ospf,lsa);
paulf2c80652002-12-13 21:44:27 +0000667
paul718e3742002-12-13 20:15:29 +0000668 /* Compare old and new external routing table and install the
669 difference info zebra/kernel */
paul68980082003-03-25 05:07:42 +0000670 ospf_ase_compare_tables (ospf->new_external_route,
671 ospf->old_external_route);
paul718e3742002-12-13 20:15:29 +0000672
673 /* Delete old external routing table */
paul68980082003-03-25 05:07:42 +0000674 ospf_route_table_free (ospf->old_external_route);
675 ospf->old_external_route = ospf->new_external_route;
676 ospf->new_external_route = route_table_init ();
paul718e3742002-12-13 20:15:29 +0000677 }
678 return 0;
679}
680
681void
paul68980082003-03-25 05:07:42 +0000682ospf_ase_calculate_schedule (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000683{
paul68980082003-03-25 05:07:42 +0000684 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000685 return;
686
paul68980082003-03-25 05:07:42 +0000687 ospf->ase_calc = 1;
paul718e3742002-12-13 20:15:29 +0000688}
689
690void
paul68980082003-03-25 05:07:42 +0000691ospf_ase_calculate_timer_add (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000692{
paul68980082003-03-25 05:07:42 +0000693 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000694 return;
695
paul68980082003-03-25 05:07:42 +0000696 if (! ospf->t_ase_calc)
697 ospf->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer,
698 ospf, OSPF_ASE_CALC_INTERVAL);
paul718e3742002-12-13 20:15:29 +0000699}
700
701void
702ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
703{
704 struct route_node *rn;
705 struct prefix_ipv4 p;
hasso52dc7ee2004-09-23 19:18:23 +0000706 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000707 struct as_external_lsa *al;
708
709 al = (struct as_external_lsa *) lsa->data;
710 p.family = AF_INET;
711 p.prefix = lsa->data->id;
712 p.prefixlen = ip_masklen (al->mask);
713 apply_mask_ipv4 (&p);
714
715 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
716 if ((lst = rn->info) == NULL)
717 rn->info = lst = list_new();
718
719 /* We assume that if LSA is deleted from DB
720 is is also deleted from this RT */
721
722 listnode_add (lst, ospf_lsa_lock (lsa));
723}
724
725void
726ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
727{
728 struct route_node *rn;
729 struct prefix_ipv4 p;
hasso52dc7ee2004-09-23 19:18:23 +0000730 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000731 struct as_external_lsa *al;
732
733 al = (struct as_external_lsa *) lsa->data;
734 p.family = AF_INET;
735 p.prefix = lsa->data->id;
736 p.prefixlen = ip_masklen (al->mask);
737 apply_mask_ipv4 (&p);
738
739 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
740 lst = rn->info;
741#ifdef ORIGINAL_CODING
742 assert (lst);
743
744 listnode_delete (lst, lsa);
745 ospf_lsa_unlock (lsa);
746#else /* ORIGINAL_CODING */
747 /* XXX lst can be NULL */
748 if (lst) {
749 listnode_delete (lst, lsa);
750 ospf_lsa_unlock (lsa);
751 }
752#endif /* ORIGINAL_CODING */
753}
754
755void
756ospf_ase_external_lsas_finish (struct route_table *rt)
757{
758 struct route_node *rn;
759 struct ospf_lsa *lsa;
hasso52dc7ee2004-09-23 19:18:23 +0000760 struct list *lst;
761 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000762
763 for (rn = route_top (rt); rn; rn = route_next (rn))
764 if ((lst = rn->info) != NULL)
765 {
766 for (node = listhead (lst); node; node = nextnode (node))
767 if ((lsa = getdata (node)) != NULL)
768 ospf_lsa_unlock (lsa);
769 list_delete (lst);
770 }
771
772 route_table_finish (rt);
773}
774
775void
paul68980082003-03-25 05:07:42 +0000776ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa)
paul718e3742002-12-13 20:15:29 +0000777{
hasso52dc7ee2004-09-23 19:18:23 +0000778 struct list *lsas;
779 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000780 struct route_node *rn, *rn2;
781 struct prefix_ipv4 p;
782 struct route_table *tmp_old;
783 struct as_external_lsa *al;
784
785 al = (struct as_external_lsa *) lsa->data;
786 p.family = AF_INET;
787 p.prefix = lsa->data->id;
788 p.prefixlen = ip_masklen (al->mask);
789 apply_mask_ipv4 (&p);
790
791 /* if new_table is NULL, there was no spf calculation, thus
792 incremental update is unneeded */
paul68980082003-03-25 05:07:42 +0000793 if (!ospf->new_table)
paul718e3742002-12-13 20:15:29 +0000794 return;
795
796 /* If there is already an intra-area or inter-area route
797 to the destination, no recalculation is necessary
798 (internal routes take precedence). */
799
paul68980082003-03-25 05:07:42 +0000800 rn = route_node_lookup (ospf->new_table, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000801 if (rn && rn->info)
802 {
803 route_unlock_node (rn);
804 return;
805 }
806
paul68980082003-03-25 05:07:42 +0000807 rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000808 assert (rn && rn->info);
809 lsas = rn->info;
810
811 for (node = listhead (lsas); node; nextnode (node))
812 if ((lsa = getdata (node)) != NULL)
paul68980082003-03-25 05:07:42 +0000813 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000814
815 /* prepare temporary old routing table for compare */
816 tmp_old = route_table_init ();
paul68980082003-03-25 05:07:42 +0000817 rn = route_node_lookup (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000818 if (rn && rn->info)
819 {
820 rn2 = route_node_get (tmp_old, (struct prefix *) &p);
821 rn2->info = rn->info;
822 }
823
824 /* install changes to zebra */
paul68980082003-03-25 05:07:42 +0000825 ospf_ase_compare_tables (ospf->new_external_route, tmp_old);
paul718e3742002-12-13 20:15:29 +0000826
paul68980082003-03-25 05:07:42 +0000827 /* update ospf->old_external_route table */
paul718e3742002-12-13 20:15:29 +0000828 if (rn && rn->info)
829 ospf_route_free ((struct ospf_route *) rn->info);
830
paul68980082003-03-25 05:07:42 +0000831 rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p);
832 /* if new route exists, install it to ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000833 if (rn2 && rn2->info)
834 {
835 if (!rn)
paul68980082003-03-25 05:07:42 +0000836 rn = route_node_get (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000837 rn->info = rn2->info;
838 }
839 else
840 {
paul68980082003-03-25 05:07:42 +0000841 /* remove route node from ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000842 if (rn)
843 {
844 rn->info = NULL;
845 route_unlock_node (rn);
846 route_unlock_node (rn);
847 }
848 }
849
850 if (rn2)
851 {
paul68980082003-03-25 05:07:42 +0000852 /* rn2->info is stored in route node of ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000853 rn2->info = NULL;
854 route_unlock_node (rn2);
855 route_unlock_node (rn2);
856 }
857
858 route_table_finish (tmp_old);
859}