blob: f4b285bb0db61fab8683a9653096bcdbdd8fcb88 [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
paul718e3742002-12-13 20:15:29 +000049struct ospf_route *
paul68980082003-03-25 05:07:42 +000050ospf_find_asbr_route (struct ospf *ospf,
51 struct route_table *rtrs, struct prefix_ipv4 *asbr)
paul718e3742002-12-13 20:15:29 +000052{
53 struct route_node *rn;
54 struct ospf_route *or, *best = NULL;
hasso52dc7ee2004-09-23 19:18:23 +000055 struct listnode *node;
56 struct list *chosen;
paul718e3742002-12-13 20:15:29 +000057
58 /* Sanity check. */
59 if (rtrs == NULL)
60 return NULL;
61
62 rn = route_node_lookup (rtrs, (struct prefix *) asbr);
63 if (! rn)
64 return NULL;
65
66 route_unlock_node (rn);
67
68 chosen = list_new ();
69
70 /* First try to find intra-area non-bb paths. */
paul68980082003-03-25 05:07:42 +000071 if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE))
paul1eb8ef22005-04-07 07:30:20 +000072 for (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or))
73 if (or->cost < OSPF_LS_INFINITY)
74 if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id) &&
75 or->path_type == OSPF_PATH_INTRA_AREA)
76 listnode_add (chosen, or);
paul718e3742002-12-13 20:15:29 +000077
78 /* If none is found -- look through all. */
79 if (listcount (chosen) == 0)
80 {
81 list_free (chosen);
82 chosen = rn->info;
83 }
84
85 /* Now find the route with least cost. */
paul1eb8ef22005-04-07 07:30:20 +000086 for (ALL_LIST_ELEMENTS_RO (chosen, node, or))
87 if (or->cost < OSPF_LS_INFINITY)
88 {
89 if (best == NULL)
90 best = or;
91 else if (best->cost > or->cost)
92 best = or;
93 else if (best->cost == or->cost &&
94 IPV4_ADDR_CMP (&best->u.std.area_id,
95 &or->u.std.area_id) < 0)
96 best = or;
97 }
paul718e3742002-12-13 20:15:29 +000098
99 if (chosen != rn->info)
100 list_delete (chosen);
101
102 return best;
103}
104
105struct ospf_route *
106ospf_find_asbr_route_through_area (struct route_table *rtrs,
107 struct prefix_ipv4 *asbr,
108 struct ospf_area *area)
109{
110 struct route_node *rn;
111
112 /* Sanity check. */
113 if (rtrs == NULL)
114 return NULL;
115
116 rn = route_node_lookup (rtrs, (struct prefix *) asbr);
117
118 if (rn)
119 {
hasso52dc7ee2004-09-23 19:18:23 +0000120 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000121 struct ospf_route *or;
122
123 route_unlock_node (rn);
124
paul1eb8ef22005-04-07 07:30:20 +0000125 for (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or))
126 if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id))
127 return or;
paul718e3742002-12-13 20:15:29 +0000128 }
129
130 return NULL;
131}
132
paul4dadc292005-05-06 21:37:42 +0000133static void
paul718e3742002-12-13 20:15:29 +0000134ospf_ase_complete_direct_routes (struct ospf_route *ro, struct in_addr nexthop)
135{
hasso52dc7ee2004-09-23 19:18:23 +0000136 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000137 struct ospf_path *op;
138
paul1eb8ef22005-04-07 07:30:20 +0000139 for (ALL_LIST_ELEMENTS_RO (ro->paths, node, op))
140 if (op->nexthop.s_addr == 0)
141 op->nexthop.s_addr = nexthop.s_addr;
paul718e3742002-12-13 20:15:29 +0000142}
143
paul4dadc292005-05-06 21:37:42 +0000144static int
paul68980082003-03-25 05:07:42 +0000145ospf_ase_forward_address_check (struct ospf *ospf, struct in_addr fwd_addr)
paul718e3742002-12-13 20:15:29 +0000146{
hasso52dc7ee2004-09-23 19:18:23 +0000147 struct listnode *ifn;
paul718e3742002-12-13 20:15:29 +0000148 struct ospf_interface *oi;
149
paul1eb8ef22005-04-07 07:30:20 +0000150 for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, ifn, oi))
151 if (if_is_operative (oi->ifp))
152 if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
153 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &fwd_addr))
154 return 0;
paul718e3742002-12-13 20:15:29 +0000155
156 return 1;
157}
158
159/* Calculate ASBR route. */
paul4dadc292005-05-06 21:37:42 +0000160static struct ospf_route *
paul68980082003-03-25 05:07:42 +0000161ospf_ase_calculate_asbr_route (struct ospf *ospf,
162 struct route_table *rt_network,
paul718e3742002-12-13 20:15:29 +0000163 struct route_table *rt_router,
164 struct as_external_lsa *al)
165{
166 struct prefix_ipv4 asbr;
167 struct ospf_route *asbr_route;
168 struct route_node *rn;
169
170 /* Find ASBR route from Router routing table. */
171 asbr.family = AF_INET;
172 asbr.prefix = al->header.adv_router;
173 asbr.prefixlen = IPV4_MAX_BITLEN;
174 apply_mask_ipv4 (&asbr);
175
paul68980082003-03-25 05:07:42 +0000176 asbr_route = ospf_find_asbr_route (ospf, rt_router, &asbr);
paul718e3742002-12-13 20:15:29 +0000177
178 if (asbr_route == NULL)
179 {
hassoe40dcce2005-02-21 14:58:42 +0000180 if (IS_DEBUG_OSPF (lsa, LSA))
181 zlog_debug ("ospf_ase_calculate(): Route to ASBR %s not found",
182 inet_ntoa (asbr.prefix));
paul718e3742002-12-13 20:15:29 +0000183 return NULL;
184 }
185
186 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
187 {
hassoe40dcce2005-02-21 14:58:42 +0000188 if (IS_DEBUG_OSPF (lsa, LSA))
189 zlog_debug ("ospf_ase_calculate(): Originating router is not an ASBR");
paul718e3742002-12-13 20:15:29 +0000190 return NULL;
191 }
192
193 if (al->e[0].fwd_addr.s_addr != 0)
194 {
hassoe40dcce2005-02-21 14:58:42 +0000195 if (IS_DEBUG_OSPF (lsa, LSA))
196 zlog_debug ("ospf_ase_calculate(): "
197 "Forwarding address is not 0.0.0.0.");
paul718e3742002-12-13 20:15:29 +0000198
paul68980082003-03-25 05:07:42 +0000199 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000200 {
hassoe40dcce2005-02-21 14:58:42 +0000201 if (IS_DEBUG_OSPF (lsa, LSA))
202 zlog_debug ("ospf_ase_calculate(): "
203 "Forwarding address is one of our addresses, Ignore.");
paul718e3742002-12-13 20:15:29 +0000204 return NULL;
205 }
206
hassoe40dcce2005-02-21 14:58:42 +0000207 if (IS_DEBUG_OSPF (lsa, LSA))
208 zlog_debug ("ospf_ase_calculate(): "
209 "Looking up in the Network Routing Table.");
paul718e3742002-12-13 20:15:29 +0000210
211 /* Looking up the path to the fwd_addr from Network route. */
212 asbr.family = AF_INET;
213 asbr.prefix = al->e[0].fwd_addr;
214 asbr.prefixlen = IPV4_MAX_BITLEN;
215
216 rn = route_node_match (rt_network, (struct prefix *) &asbr);
217
218 if (rn == NULL)
219 {
hassoe40dcce2005-02-21 14:58:42 +0000220 if (IS_DEBUG_OSPF (lsa, LSA))
221 zlog_debug ("ospf_ase_calculate(): "
222 "Couldn't find a route to the forwarding address.");
paul718e3742002-12-13 20:15:29 +0000223 return NULL;
224 }
225
226 route_unlock_node (rn);
227
228 if ((asbr_route = rn->info) == NULL)
229 {
hassoe40dcce2005-02-21 14:58:42 +0000230 if (IS_DEBUG_OSPF (lsa, LSA))
231 zlog_debug ("ospf_ase_calculate(): "
232 "Somehow OSPF route to ASBR is lost");
paul718e3742002-12-13 20:15:29 +0000233 return NULL;
234 }
235 }
236
237 return asbr_route;
238}
239
paul4dadc292005-05-06 21:37:42 +0000240static struct ospf_route *
paul718e3742002-12-13 20:15:29 +0000241ospf_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 {
hassoe40dcce2005-02-21 14:58:42 +0000258 if (IS_DEBUG_OSPF (lsa, LSA))
259 zlog_debug ("Route[External]: type-1 created.");
paul718e3742002-12-13 20:15:29 +0000260 new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
261 new->cost = asbr_route->cost + metric; /* X + Y */
262 }
263 else
264 {
hassoe40dcce2005-02-21 14:58:42 +0000265 if (IS_DEBUG_OSPF (lsa, LSA))
266 zlog_debug ("Route[External]: type-2 created.");
paul718e3742002-12-13 20:15:29 +0000267 new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
268 new->cost = asbr_route->cost; /* X */
269 new->u.ext.type2_cost = metric; /* Y */
270 }
271
272 new->type = OSPF_DESTINATION_NETWORK;
paul718e3742002-12-13 20:15:29 +0000273 new->u.ext.origin = lsa;
274 new->u.ext.tag = ntohl (al->e[0].route_tag);
275 new->u.ext.asbr = asbr_route;
276
277 assert (new != asbr_route);
278
279 return new;
280}
281
282#define OSPF_ASE_CALC_INTERVAL 1
283
284int
paul68980082003-03-25 05:07:42 +0000285ospf_ase_calculate_route (struct ospf *ospf, struct ospf_lsa * lsa)
paul718e3742002-12-13 20:15:29 +0000286{
287 u_int32_t metric;
288 struct as_external_lsa *al;
289 struct ospf_route *asbr_route;
290 struct prefix_ipv4 asbr, p;
291 struct route_node *rn;
292 struct ospf_route *new, *or;
293 int ret;
294
295 assert (lsa);
296 al = (struct as_external_lsa *) lsa->data;
297
paul718e3742002-12-13 20:15:29 +0000298 if (lsa->data->type == OSPF_AS_NSSA_LSA)
299 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000300 zlog_debug ("ospf_ase_calc(): Processing Type-7");
paul718e3742002-12-13 20:15:29 +0000301
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)
ajse84cc642004-12-08 17:28:56 +0000306 zlog_debug ("ospf_ase_calc(): Rejecting Local Xlt'd");
paul718e3742002-12-13 20:15:29 +0000307 return 0;
308 }
paul718e3742002-12-13 20:15:29 +0000309
hassoe40dcce2005-02-21 14:58:42 +0000310 if (IS_DEBUG_OSPF (lsa, LSA))
311 zlog_debug ("Route[External]: Calculate AS-external-LSA to %s/%d",
312 inet_ntoa (al->header.id), ip_masklen (al->mask));
paul718e3742002-12-13 20:15:29 +0000313 /* (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 {
hassoe40dcce2005-02-21 14:58:42 +0000317 if (IS_DEBUG_OSPF (lsa, LSA))
318 zlog_debug ("Route[External]: Metric is OSPF_LS_INFINITY");
paul718e3742002-12-13 20:15:29 +0000319 return 0;
320 }
321 if (IS_LSA_MAXAGE (lsa))
322 {
hassoe40dcce2005-02-21 14:58:42 +0000323 if (IS_DEBUG_OSPF (lsa, LSA))
324 zlog_debug ("Route[External]: AS-external-LSA is MAXAGE");
paul718e3742002-12-13 20:15:29 +0000325 return 0;
326 }
327
328 /* (2) If the LSA was originated by the calculating router itself,
329 examine the next LSA. */
330 if (IS_LSA_SELF (lsa))
331 {
hassoe40dcce2005-02-21 14:58:42 +0000332 if (IS_DEBUG_OSPF (lsa, LSA))
333 zlog_debug ("Route[External]: AS-external-LSA is self originated");
paul718e3742002-12-13 20:15:29 +0000334 return 0;
335 }
336
337 /* (3) Call the destination described by the LSA N. N's address is
338 obtained by masking the LSA's Link State ID with the
339 network/subnet mask contained in the body of the LSA. Look
340 up the routing table entries (potentially one per attached
341 area) for the AS boundary router (ASBR) that originated the
342 LSA. If no entries exist for router ASBR (i.e., ASBR is
343 unreachable), do nothing with this LSA and consider the next
344 in the list. */
345
346 asbr.family = AF_INET;
347 asbr.prefix = al->header.adv_router;
348 asbr.prefixlen = IPV4_MAX_BITLEN;
349 apply_mask_ipv4 (&asbr);
350
paul68980082003-03-25 05:07:42 +0000351 asbr_route = ospf_find_asbr_route (ospf, ospf->new_rtrs, &asbr);
paul718e3742002-12-13 20:15:29 +0000352 if (asbr_route == NULL)
353 {
hassoe40dcce2005-02-21 14:58:42 +0000354 if (IS_DEBUG_OSPF (lsa, LSA))
355 zlog_debug ("Route[External]: Can't find originating ASBR route");
paul718e3742002-12-13 20:15:29 +0000356 return 0;
357 }
358 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
359 {
hassoe40dcce2005-02-21 14:58:42 +0000360 if (IS_DEBUG_OSPF (lsa, LSA))
361 zlog_debug ("Route[External]: Originating router is not an ASBR");
paul718e3742002-12-13 20:15:29 +0000362 return 0;
363 }
364
365 /* Else, this LSA describes an AS external path to destination
366 N. Examine the forwarding address specified in the AS-
367 external-LSA. This indicates the IP address to which
368 packets for the destination should be forwarded. */
369
370 if (al->e[0].fwd_addr.s_addr == 0)
371 {
372 /* If the forwarding address is set to 0.0.0.0, packets should
373 be sent to the ASBR itself. Among the multiple routing table
374 entries for the ASBR, select the preferred entry as follows.
375 If RFC1583Compatibility is set to "disabled", prune the set
376 of routing table entries for the ASBR as described in
377 Section 16.4.1. In any case, among the remaining routing
378 table entries, select the routing table entry with the least
379 cost; when there are multiple least cost routing table
380 entries the entry whose associated area has the largest OSPF
381 Area ID (when considered as an unsigned 32-bit integer) is
382 chosen. */
383
384 /* asbr_route already contains the requested route */
385 }
386 else
387 {
388 /* If the forwarding address is non-zero, look up the
389 forwarding address in the routing table.[24] The matching
390 routing table entry must specify an intra-area or inter-area
391 path; if no such path exists, do nothing with the LSA and
392 consider the next in the list. */
paul68980082003-03-25 05:07:42 +0000393 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000394 {
hassoe40dcce2005-02-21 14:58:42 +0000395 if (IS_DEBUG_OSPF (lsa, LSA))
396 zlog_debug ("Route[External]: Forwarding address is our router "
397 "address");
paul718e3742002-12-13 20:15:29 +0000398 return 0;
399 }
400
401 asbr.family = AF_INET;
402 asbr.prefix = al->e[0].fwd_addr;
403 asbr.prefixlen = IPV4_MAX_BITLEN;
404
paul68980082003-03-25 05:07:42 +0000405 rn = route_node_match (ospf->new_table, (struct prefix *) &asbr);
paul718e3742002-12-13 20:15:29 +0000406
407 if (rn == NULL || (asbr_route = rn->info) == NULL)
408 {
hassoe40dcce2005-02-21 14:58:42 +0000409 if (IS_DEBUG_OSPF (lsa, LSA))
410 zlog_debug ("Route[External]: Can't find route to forwarding "
411 "address");
paul718e3742002-12-13 20:15:29 +0000412 if (rn)
413 route_unlock_node (rn);
414 return 0;
415 }
416
417 route_unlock_node (rn);
418 }
419
420 /* (4) Let X be the cost specified by the preferred routing table
421 entry for the ASBR/forwarding address, and Y the cost
422 specified in the LSA. X is in terms of the link state
423 metric, and Y is a type 1 or 2 external metric. */
424
425
426 /* (5) Look up the routing table entry for the destination N. If
427 no entry exists for N, install the AS external path to N,
428 with next hop equal to the list of next hops to the
429 forwarding address, and advertising router equal to ASBR.
430 If the external metric type is 1, then the path-type is set
431 to type 1 external and the cost is equal to X+Y. If the
432 external metric type is 2, the path-type is set to type 2
433 external, the link state component of the route's cost is X,
434 and the type 2 cost is Y. */
435 new = ospf_ase_calculate_new_route (lsa, asbr_route, metric);
436
437 /* (6) Compare the AS external path described by the LSA with the
438 existing paths in N's routing table entry, as follows. If
439 the new path is preferred, it replaces the present paths in
440 N's routing table entry. If the new path is of equal
441 preference, it is added to N's routing table entry's list of
442 paths. */
443
444 /* Set prefix. */
445 p.family = AF_INET;
446 p.prefix = al->header.id;
447 p.prefixlen = ip_masklen (al->mask);
448
449 /* if there is a Intra/Inter area route to the N
450 do not install external route */
paul68980082003-03-25 05:07:42 +0000451 if ((rn = route_node_lookup (ospf->new_table,
paul718e3742002-12-13 20:15:29 +0000452 (struct prefix *) &p)) != NULL
453 && (rn->info != NULL))
454 {
455 if (new)
456 ospf_route_free (new);
457 return 0;
458 }
459
460 /* Find a route to the same dest */
461 /* If there is no route, create new one. */
paul68980082003-03-25 05:07:42 +0000462 if ((rn = route_node_lookup (ospf->new_external_route,
paul718e3742002-12-13 20:15:29 +0000463 (struct prefix *) &p)) == NULL
464 || (or = rn->info) == NULL)
465 {
hassoe40dcce2005-02-21 14:58:42 +0000466 if (IS_DEBUG_OSPF (lsa, LSA))
467 zlog_debug ("Route[External]: Adding a new route %s/%d",
468 inet_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000469
paul68980082003-03-25 05:07:42 +0000470 ospf_route_add (ospf->new_external_route, &p, new, asbr_route);
paul718e3742002-12-13 20:15:29 +0000471
472 if (al->e[0].fwd_addr.s_addr)
473 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
474 return 0;
475 }
476 else
477 {
478 /* (a) Intra-area and inter-area paths are always preferred
479 over AS external paths.
480
481 (b) Type 1 external paths are always preferred over type 2
482 external paths. When all paths are type 2 external
483 paths, the paths with the smallest advertised type 2
484 metric are always preferred. */
paul68980082003-03-25 05:07:42 +0000485 ret = ospf_route_cmp (ospf, new, or);
paul718e3742002-12-13 20:15:29 +0000486
487 /* (c) If the new AS external path is still indistinguishable
488 from the current paths in the N's routing table entry,
489 and RFC1583Compatibility is set to "disabled", select
490 the preferred paths based on the intra-AS paths to the
491 ASBR/forwarding addresses, as specified in Section
492 16.4.1.
493
494 (d) If the new AS external path is still indistinguishable
495 from the current paths in the N's routing table entry,
496 select the preferred path based on a least cost
497 comparison. Type 1 external paths are compared by
498 looking at the sum of the distance to the forwarding
499 address and the advertised type 1 metric (X+Y). Type 2
500 external paths advertising equal type 2 metrics are
501 compared by looking at the distance to the forwarding
502 addresses.
503 */
504 /* New route is better */
505 if (ret < 0)
506 {
hassoe40dcce2005-02-21 14:58:42 +0000507 if (IS_DEBUG_OSPF (lsa, LSA))
508 zlog_debug ("Route[External]: New route is better");
paul718e3742002-12-13 20:15:29 +0000509 ospf_route_subst (rn, new, asbr_route);
510 if (al->e[0].fwd_addr.s_addr)
511 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
512 or = new;
513 new = NULL;
514 }
515 /* Old route is better */
516 else if (ret > 0)
517 {
hassoe40dcce2005-02-21 14:58:42 +0000518 if (IS_DEBUG_OSPF (lsa, LSA))
519 zlog_debug ("Route[External]: Old route is better");
paul718e3742002-12-13 20:15:29 +0000520 /* do nothing */
521 }
522 /* Routes are equal */
523 else
524 {
hassoe40dcce2005-02-21 14:58:42 +0000525 if (IS_DEBUG_OSPF (lsa, LSA))
526 zlog_debug ("Route[External]: Routes are equal");
paul96735ee2003-08-10 02:51:22 +0000527 ospf_route_copy_nexthops (or, asbr_route->paths);
paul718e3742002-12-13 20:15:29 +0000528 if (al->e[0].fwd_addr.s_addr)
529 ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr);
530 }
531 }
532 /* Make sure setting newly calculated ASBR route.*/
533 or->u.ext.asbr = asbr_route;
534 if (new)
535 ospf_route_free (new);
536
537 lsa->route = or;
538 return 0;
539}
540
paul4dadc292005-05-06 21:37:42 +0000541static int
paul718e3742002-12-13 20:15:29 +0000542ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix,
543 struct ospf_route *newor)
544{
545 struct route_node *rn;
546 struct ospf_route *or;
547 struct ospf_path *op;
548 struct ospf_path *newop;
hasso52dc7ee2004-09-23 19:18:23 +0000549 struct listnode *n1;
550 struct listnode *n2;
paul718e3742002-12-13 20:15:29 +0000551
552 if (! rt || ! prefix)
553 return 0;
554
555 rn = route_node_lookup (rt, prefix);
556 if (! rn)
557 return 0;
558
559 route_unlock_node (rn);
560
561 or = rn->info;
562 if (or->path_type != newor->path_type)
563 return 0;
564
565 switch (or->path_type)
566 {
567 case OSPF_PATH_TYPE1_EXTERNAL:
568 if (or->cost != newor->cost)
569 return 0;
570 break;
571 case OSPF_PATH_TYPE2_EXTERNAL:
572 if ((or->cost != newor->cost) ||
573 (or->u.ext.type2_cost != newor->u.ext.type2_cost))
574 return 0;
575 break;
576 default:
577 assert (0);
578 return 0;
579 }
580
paul96735ee2003-08-10 02:51:22 +0000581 if (or->paths->count != newor->paths->count)
paul718e3742002-12-13 20:15:29 +0000582 return 0;
583
584 /* Check each path. */
paul96735ee2003-08-10 02:51:22 +0000585 for (n1 = listhead (or->paths), n2 = listhead (newor->paths);
paul1eb8ef22005-04-07 07:30:20 +0000586 n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2))
paul718e3742002-12-13 20:15:29 +0000587 {
paul1eb8ef22005-04-07 07:30:20 +0000588 op = listgetdata (n1);
589 newop = listgetdata (n2);
paul718e3742002-12-13 20:15:29 +0000590
591 if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
592 return 0;
593 }
594 return 1;
595}
596
paul4dadc292005-05-06 21:37:42 +0000597static int
paul718e3742002-12-13 20:15:29 +0000598ospf_ase_compare_tables (struct route_table *new_external_route,
599 struct route_table *old_external_route)
600{
601 struct route_node *rn, *new_rn;
602 struct ospf_route *or;
603
604 /* Remove deleted routes */
605 for (rn = route_top (old_external_route); rn; rn = route_next (rn))
606 if ((or = rn->info))
607 {
608 if (! (new_rn = route_node_lookup (new_external_route, &rn->p)))
609 ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
610 else
611 route_unlock_node (new_rn);
612 }
613
614
615 /* Install new routes */
616 for (rn = route_top (new_external_route); rn; rn = route_next (rn))
617 if ((or = rn->info) != NULL)
618 if (! ospf_ase_route_match_same (old_external_route, &rn->p, or))
619 ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
620
621 return 0;
622}
623
paul4dadc292005-05-06 21:37:42 +0000624static int
paul718e3742002-12-13 20:15:29 +0000625ospf_ase_calculate_timer (struct thread *t)
626{
627 struct ospf *ospf;
paul68980082003-03-25 05:07:42 +0000628 struct ospf_lsa *lsa;
629 struct route_node *rn;
hasso52dc7ee2004-09-23 19:18:23 +0000630 struct listnode *node;
paul68980082003-03-25 05:07:42 +0000631 struct ospf_area *area;
paul718e3742002-12-13 20:15:29 +0000632
633 ospf = THREAD_ARG (t);
634 ospf->t_ase_calc = NULL;
635
636 if (ospf->ase_calc)
637 {
638 ospf->ase_calc = 0;
639
640 /* Calculate external route for each AS-external-LSA */
paul68980082003-03-25 05:07:42 +0000641 LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
642 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000643
paul718e3742002-12-13 20:15:29 +0000644 /* This version simple adds to the table all NSSA areas */
paul68980082003-03-25 05:07:42 +0000645 if (ospf->anyNSSA)
paul1eb8ef22005-04-07 07:30:20 +0000646 for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area))
paul718e3742002-12-13 20:15:29 +0000647 {
paul718e3742002-12-13 20:15:29 +0000648 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000649 zlog_debug ("ospf_ase_calculate_timer(): looking at area %s",
paul718e3742002-12-13 20:15:29 +0000650 inet_ntoa (area->area_id));
651
652 if (area->external_routing == OSPF_AREA_NSSA)
paul68980082003-03-25 05:07:42 +0000653 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
654 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000655 }
paulf2c80652002-12-13 21:44:27 +0000656 /* kevinm: And add the NSSA routes in ospf_top */
paulf6386ee2003-04-07 04:29:27 +0000657 LSDB_LOOP (NSSA_LSDB (ospf),rn,lsa)
658 ospf_ase_calculate_route(ospf,lsa);
paulf2c80652002-12-13 21:44:27 +0000659
paul718e3742002-12-13 20:15:29 +0000660 /* Compare old and new external routing table and install the
661 difference info zebra/kernel */
paul68980082003-03-25 05:07:42 +0000662 ospf_ase_compare_tables (ospf->new_external_route,
663 ospf->old_external_route);
paul718e3742002-12-13 20:15:29 +0000664
665 /* Delete old external routing table */
paul68980082003-03-25 05:07:42 +0000666 ospf_route_table_free (ospf->old_external_route);
667 ospf->old_external_route = ospf->new_external_route;
668 ospf->new_external_route = route_table_init ();
paul718e3742002-12-13 20:15:29 +0000669 }
670 return 0;
671}
672
673void
paul68980082003-03-25 05:07:42 +0000674ospf_ase_calculate_schedule (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000675{
paul68980082003-03-25 05:07:42 +0000676 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000677 return;
678
paul68980082003-03-25 05:07:42 +0000679 ospf->ase_calc = 1;
paul718e3742002-12-13 20:15:29 +0000680}
681
682void
paul68980082003-03-25 05:07:42 +0000683ospf_ase_calculate_timer_add (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000684{
paul68980082003-03-25 05:07:42 +0000685 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000686 return;
687
paul68980082003-03-25 05:07:42 +0000688 if (! ospf->t_ase_calc)
689 ospf->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer,
690 ospf, OSPF_ASE_CALC_INTERVAL);
paul718e3742002-12-13 20:15:29 +0000691}
692
693void
694ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
695{
696 struct route_node *rn;
697 struct prefix_ipv4 p;
hasso52dc7ee2004-09-23 19:18:23 +0000698 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000699 struct as_external_lsa *al;
700
701 al = (struct as_external_lsa *) lsa->data;
702 p.family = AF_INET;
703 p.prefix = lsa->data->id;
704 p.prefixlen = ip_masklen (al->mask);
705 apply_mask_ipv4 (&p);
706
707 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
708 if ((lst = rn->info) == NULL)
709 rn->info = lst = list_new();
710
711 /* We assume that if LSA is deleted from DB
712 is is also deleted from this RT */
713
714 listnode_add (lst, ospf_lsa_lock (lsa));
715}
716
717void
718ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
719{
720 struct route_node *rn;
721 struct prefix_ipv4 p;
hasso52dc7ee2004-09-23 19:18:23 +0000722 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000723 struct as_external_lsa *al;
724
725 al = (struct as_external_lsa *) lsa->data;
726 p.family = AF_INET;
727 p.prefix = lsa->data->id;
728 p.prefixlen = ip_masklen (al->mask);
729 apply_mask_ipv4 (&p);
730
731 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
732 lst = rn->info;
733#ifdef ORIGINAL_CODING
734 assert (lst);
735
736 listnode_delete (lst, lsa);
737 ospf_lsa_unlock (lsa);
738#else /* ORIGINAL_CODING */
739 /* XXX lst can be NULL */
740 if (lst) {
741 listnode_delete (lst, lsa);
742 ospf_lsa_unlock (lsa);
743 }
744#endif /* ORIGINAL_CODING */
745}
746
747void
748ospf_ase_external_lsas_finish (struct route_table *rt)
749{
750 struct route_node *rn;
751 struct ospf_lsa *lsa;
hasso52dc7ee2004-09-23 19:18:23 +0000752 struct list *lst;
paul1eb8ef22005-04-07 07:30:20 +0000753 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000754
755 for (rn = route_top (rt); rn; rn = route_next (rn))
756 if ((lst = rn->info) != NULL)
757 {
paul1eb8ef22005-04-07 07:30:20 +0000758 for (ALL_LIST_ELEMENTS (lst, node, nnode, lsa))
759 ospf_lsa_unlock (lsa);
paul718e3742002-12-13 20:15:29 +0000760 list_delete (lst);
761 }
paul1eb8ef22005-04-07 07:30:20 +0000762
paul718e3742002-12-13 20:15:29 +0000763 route_table_finish (rt);
764}
765
766void
paul68980082003-03-25 05:07:42 +0000767ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa)
paul718e3742002-12-13 20:15:29 +0000768{
hasso52dc7ee2004-09-23 19:18:23 +0000769 struct list *lsas;
770 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000771 struct route_node *rn, *rn2;
772 struct prefix_ipv4 p;
773 struct route_table *tmp_old;
774 struct as_external_lsa *al;
775
776 al = (struct as_external_lsa *) lsa->data;
777 p.family = AF_INET;
778 p.prefix = lsa->data->id;
779 p.prefixlen = ip_masklen (al->mask);
780 apply_mask_ipv4 (&p);
781
782 /* if new_table is NULL, there was no spf calculation, thus
783 incremental update is unneeded */
paul68980082003-03-25 05:07:42 +0000784 if (!ospf->new_table)
paul718e3742002-12-13 20:15:29 +0000785 return;
786
787 /* If there is already an intra-area or inter-area route
788 to the destination, no recalculation is necessary
789 (internal routes take precedence). */
790
paul68980082003-03-25 05:07:42 +0000791 rn = route_node_lookup (ospf->new_table, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000792 if (rn && rn->info)
793 {
794 route_unlock_node (rn);
795 return;
796 }
797
paul68980082003-03-25 05:07:42 +0000798 rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000799 assert (rn && rn->info);
800 lsas = rn->info;
801
paul1eb8ef22005-04-07 07:30:20 +0000802 for (ALL_LIST_ELEMENTS_RO (lsas, node, lsa))
803 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000804
805 /* prepare temporary old routing table for compare */
806 tmp_old = route_table_init ();
paul68980082003-03-25 05:07:42 +0000807 rn = route_node_lookup (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000808 if (rn && rn->info)
809 {
810 rn2 = route_node_get (tmp_old, (struct prefix *) &p);
811 rn2->info = rn->info;
812 }
813
814 /* install changes to zebra */
paul68980082003-03-25 05:07:42 +0000815 ospf_ase_compare_tables (ospf->new_external_route, tmp_old);
paul718e3742002-12-13 20:15:29 +0000816
paul68980082003-03-25 05:07:42 +0000817 /* update ospf->old_external_route table */
paul718e3742002-12-13 20:15:29 +0000818 if (rn && rn->info)
819 ospf_route_free ((struct ospf_route *) rn->info);
820
paul68980082003-03-25 05:07:42 +0000821 rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p);
822 /* if new route exists, install it to ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000823 if (rn2 && rn2->info)
824 {
825 if (!rn)
paul68980082003-03-25 05:07:42 +0000826 rn = route_node_get (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000827 rn->info = rn2->info;
828 }
829 else
830 {
paul68980082003-03-25 05:07:42 +0000831 /* remove route node from ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000832 if (rn)
833 {
834 rn->info = NULL;
835 route_unlock_node (rn);
836 route_unlock_node (rn);
837 }
838 }
839
840 if (rn2)
841 {
paul68980082003-03-25 05:07:42 +0000842 /* rn2->info is stored in route node of ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000843 rn2->info = NULL;
844 route_unlock_node (rn2);
845 route_unlock_node (rn2);
846 }
847
848 route_table_finish (tmp_old);
849}