blob: 3eb29f8acfc777868d974f4a041a6b33ff5552da [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 */
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100451 if (rn = route_node_lookup (ospf->new_table,
452 (struct prefix *) &p))
paul718e3742002-12-13 20:15:29 +0000453 {
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100454 route_unlock_node(rn);
455 if (rn->info == NULL)
456 zlog_info ("Route[External]: rn->info NULL");
paul718e3742002-12-13 20:15:29 +0000457 if (new)
458 ospf_route_free (new);
459 return 0;
460 }
paul718e3742002-12-13 20:15:29 +0000461 /* Find a route to the same dest */
462 /* If there is no route, create new one. */
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100463 if (rn = route_node_lookup (ospf->new_external_route,
464 (struct prefix *) &p))
465 route_unlock_node(rn);
466
467 if (!rn || (or = rn->info) == NULL)
paul718e3742002-12-13 20:15:29 +0000468 {
hassoe40dcce2005-02-21 14:58:42 +0000469 if (IS_DEBUG_OSPF (lsa, LSA))
470 zlog_debug ("Route[External]: Adding a new route %s/%d",
471 inet_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000472
paul68980082003-03-25 05:07:42 +0000473 ospf_route_add (ospf->new_external_route, &p, new, asbr_route);
paul718e3742002-12-13 20:15:29 +0000474
475 if (al->e[0].fwd_addr.s_addr)
476 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
477 return 0;
478 }
479 else
480 {
481 /* (a) Intra-area and inter-area paths are always preferred
482 over AS external paths.
483
484 (b) Type 1 external paths are always preferred over type 2
485 external paths. When all paths are type 2 external
486 paths, the paths with the smallest advertised type 2
487 metric are always preferred. */
paul68980082003-03-25 05:07:42 +0000488 ret = ospf_route_cmp (ospf, new, or);
paul718e3742002-12-13 20:15:29 +0000489
490 /* (c) If the new AS external path is still indistinguishable
491 from the current paths in the N's routing table entry,
492 and RFC1583Compatibility is set to "disabled", select
493 the preferred paths based on the intra-AS paths to the
494 ASBR/forwarding addresses, as specified in Section
495 16.4.1.
496
497 (d) If the new AS external path is still indistinguishable
498 from the current paths in the N's routing table entry,
499 select the preferred path based on a least cost
500 comparison. Type 1 external paths are compared by
501 looking at the sum of the distance to the forwarding
502 address and the advertised type 1 metric (X+Y). Type 2
503 external paths advertising equal type 2 metrics are
504 compared by looking at the distance to the forwarding
505 addresses.
506 */
507 /* New route is better */
508 if (ret < 0)
509 {
hassoe40dcce2005-02-21 14:58:42 +0000510 if (IS_DEBUG_OSPF (lsa, LSA))
511 zlog_debug ("Route[External]: New route is better");
paul718e3742002-12-13 20:15:29 +0000512 ospf_route_subst (rn, new, asbr_route);
513 if (al->e[0].fwd_addr.s_addr)
514 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
515 or = new;
516 new = NULL;
517 }
518 /* Old route is better */
519 else if (ret > 0)
520 {
hassoe40dcce2005-02-21 14:58:42 +0000521 if (IS_DEBUG_OSPF (lsa, LSA))
522 zlog_debug ("Route[External]: Old route is better");
paul718e3742002-12-13 20:15:29 +0000523 /* do nothing */
524 }
525 /* Routes are equal */
526 else
527 {
hassoe40dcce2005-02-21 14:58:42 +0000528 if (IS_DEBUG_OSPF (lsa, LSA))
529 zlog_debug ("Route[External]: Routes are equal");
paul96735ee2003-08-10 02:51:22 +0000530 ospf_route_copy_nexthops (or, asbr_route->paths);
paul718e3742002-12-13 20:15:29 +0000531 if (al->e[0].fwd_addr.s_addr)
532 ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr);
533 }
534 }
535 /* Make sure setting newly calculated ASBR route.*/
536 or->u.ext.asbr = asbr_route;
537 if (new)
538 ospf_route_free (new);
539
540 lsa->route = or;
541 return 0;
542}
543
paul4dadc292005-05-06 21:37:42 +0000544static int
paul718e3742002-12-13 20:15:29 +0000545ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix,
546 struct ospf_route *newor)
547{
548 struct route_node *rn;
549 struct ospf_route *or;
550 struct ospf_path *op;
551 struct ospf_path *newop;
hasso52dc7ee2004-09-23 19:18:23 +0000552 struct listnode *n1;
553 struct listnode *n2;
paul718e3742002-12-13 20:15:29 +0000554
555 if (! rt || ! prefix)
556 return 0;
557
558 rn = route_node_lookup (rt, prefix);
559 if (! rn)
560 return 0;
561
562 route_unlock_node (rn);
563
564 or = rn->info;
565 if (or->path_type != newor->path_type)
566 return 0;
567
568 switch (or->path_type)
569 {
570 case OSPF_PATH_TYPE1_EXTERNAL:
571 if (or->cost != newor->cost)
572 return 0;
573 break;
574 case OSPF_PATH_TYPE2_EXTERNAL:
575 if ((or->cost != newor->cost) ||
576 (or->u.ext.type2_cost != newor->u.ext.type2_cost))
577 return 0;
578 break;
579 default:
580 assert (0);
581 return 0;
582 }
583
paul96735ee2003-08-10 02:51:22 +0000584 if (or->paths->count != newor->paths->count)
paul718e3742002-12-13 20:15:29 +0000585 return 0;
586
587 /* Check each path. */
paul96735ee2003-08-10 02:51:22 +0000588 for (n1 = listhead (or->paths), n2 = listhead (newor->paths);
paul1eb8ef22005-04-07 07:30:20 +0000589 n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2))
paul718e3742002-12-13 20:15:29 +0000590 {
paul1eb8ef22005-04-07 07:30:20 +0000591 op = listgetdata (n1);
592 newop = listgetdata (n2);
paul718e3742002-12-13 20:15:29 +0000593
594 if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
595 return 0;
596 }
597 return 1;
598}
599
paul4dadc292005-05-06 21:37:42 +0000600static int
paul718e3742002-12-13 20:15:29 +0000601ospf_ase_compare_tables (struct route_table *new_external_route,
602 struct route_table *old_external_route)
603{
604 struct route_node *rn, *new_rn;
605 struct ospf_route *or;
606
607 /* Remove deleted routes */
608 for (rn = route_top (old_external_route); rn; rn = route_next (rn))
609 if ((or = rn->info))
610 {
611 if (! (new_rn = route_node_lookup (new_external_route, &rn->p)))
612 ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
613 else
614 route_unlock_node (new_rn);
615 }
616
617
618 /* Install new routes */
619 for (rn = route_top (new_external_route); rn; rn = route_next (rn))
620 if ((or = rn->info) != NULL)
621 if (! ospf_ase_route_match_same (old_external_route, &rn->p, or))
622 ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
623
624 return 0;
625}
626
paul4dadc292005-05-06 21:37:42 +0000627static int
paul718e3742002-12-13 20:15:29 +0000628ospf_ase_calculate_timer (struct thread *t)
629{
630 struct ospf *ospf;
paul68980082003-03-25 05:07:42 +0000631 struct ospf_lsa *lsa;
632 struct route_node *rn;
hasso52dc7ee2004-09-23 19:18:23 +0000633 struct listnode *node;
paul68980082003-03-25 05:07:42 +0000634 struct ospf_area *area;
paul718e3742002-12-13 20:15:29 +0000635
636 ospf = THREAD_ARG (t);
637 ospf->t_ase_calc = NULL;
638
639 if (ospf->ase_calc)
640 {
641 ospf->ase_calc = 0;
642
643 /* Calculate external route for each AS-external-LSA */
paul68980082003-03-25 05:07:42 +0000644 LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
645 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000646
paul718e3742002-12-13 20:15:29 +0000647 /* This version simple adds to the table all NSSA areas */
paul68980082003-03-25 05:07:42 +0000648 if (ospf->anyNSSA)
paul1eb8ef22005-04-07 07:30:20 +0000649 for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area))
paul718e3742002-12-13 20:15:29 +0000650 {
paul718e3742002-12-13 20:15:29 +0000651 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000652 zlog_debug ("ospf_ase_calculate_timer(): looking at area %s",
paul718e3742002-12-13 20:15:29 +0000653 inet_ntoa (area->area_id));
654
655 if (area->external_routing == OSPF_AREA_NSSA)
paul68980082003-03-25 05:07:42 +0000656 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
657 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000658 }
paulf2c80652002-12-13 21:44:27 +0000659 /* kevinm: And add the NSSA routes in ospf_top */
paulf6386ee2003-04-07 04:29:27 +0000660 LSDB_LOOP (NSSA_LSDB (ospf),rn,lsa)
661 ospf_ase_calculate_route(ospf,lsa);
paulf2c80652002-12-13 21:44:27 +0000662
paul718e3742002-12-13 20:15:29 +0000663 /* Compare old and new external routing table and install the
664 difference info zebra/kernel */
paul68980082003-03-25 05:07:42 +0000665 ospf_ase_compare_tables (ospf->new_external_route,
666 ospf->old_external_route);
paul718e3742002-12-13 20:15:29 +0000667
668 /* Delete old external routing table */
paul68980082003-03-25 05:07:42 +0000669 ospf_route_table_free (ospf->old_external_route);
670 ospf->old_external_route = ospf->new_external_route;
671 ospf->new_external_route = route_table_init ();
paul718e3742002-12-13 20:15:29 +0000672 }
673 return 0;
674}
675
676void
paul68980082003-03-25 05:07:42 +0000677ospf_ase_calculate_schedule (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000678{
paul68980082003-03-25 05:07:42 +0000679 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000680 return;
681
paul68980082003-03-25 05:07:42 +0000682 ospf->ase_calc = 1;
paul718e3742002-12-13 20:15:29 +0000683}
684
685void
paul68980082003-03-25 05:07:42 +0000686ospf_ase_calculate_timer_add (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000687{
paul68980082003-03-25 05:07:42 +0000688 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000689 return;
690
paul68980082003-03-25 05:07:42 +0000691 if (! ospf->t_ase_calc)
692 ospf->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer,
693 ospf, OSPF_ASE_CALC_INTERVAL);
paul718e3742002-12-13 20:15:29 +0000694}
695
696void
697ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
698{
699 struct route_node *rn;
700 struct prefix_ipv4 p;
hasso52dc7ee2004-09-23 19:18:23 +0000701 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000702 struct as_external_lsa *al;
703
704 al = (struct as_external_lsa *) lsa->data;
705 p.family = AF_INET;
706 p.prefix = lsa->data->id;
707 p.prefixlen = ip_masklen (al->mask);
708 apply_mask_ipv4 (&p);
709
710 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
711 if ((lst = rn->info) == NULL)
712 rn->info = lst = list_new();
713
714 /* We assume that if LSA is deleted from DB
715 is is also deleted from this RT */
716
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000717 listnode_add (lst, ospf_lsa_lock (lsa)); /* external_lsas lst */
paul718e3742002-12-13 20:15:29 +0000718}
719
720void
721ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
722{
723 struct route_node *rn;
724 struct prefix_ipv4 p;
hasso52dc7ee2004-09-23 19:18:23 +0000725 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000726 struct as_external_lsa *al;
727
728 al = (struct as_external_lsa *) lsa->data;
729 p.family = AF_INET;
730 p.prefix = lsa->data->id;
731 p.prefixlen = ip_masklen (al->mask);
732 apply_mask_ipv4 (&p);
733
734 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
735 lst = rn->info;
paul718e3742002-12-13 20:15:29 +0000736
paul718e3742002-12-13 20:15:29 +0000737 /* XXX lst can be NULL */
738 if (lst) {
739 listnode_delete (lst, lsa);
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000740 ospf_lsa_unlock (&lsa); /* external_lsas list */
paul718e3742002-12-13 20:15:29 +0000741 }
paul718e3742002-12-13 20:15:29 +0000742}
743
744void
745ospf_ase_external_lsas_finish (struct route_table *rt)
746{
747 struct route_node *rn;
748 struct ospf_lsa *lsa;
hasso52dc7ee2004-09-23 19:18:23 +0000749 struct list *lst;
paul1eb8ef22005-04-07 07:30:20 +0000750 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000751
752 for (rn = route_top (rt); rn; rn = route_next (rn))
753 if ((lst = rn->info) != NULL)
754 {
paul1eb8ef22005-04-07 07:30:20 +0000755 for (ALL_LIST_ELEMENTS (lst, node, nnode, lsa))
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000756 ospf_lsa_unlock (&lsa); /* external_lsas lst */
paul718e3742002-12-13 20:15:29 +0000757 list_delete (lst);
758 }
paul1eb8ef22005-04-07 07:30:20 +0000759
paul718e3742002-12-13 20:15:29 +0000760 route_table_finish (rt);
761}
762
763void
paul68980082003-03-25 05:07:42 +0000764ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa)
paul718e3742002-12-13 20:15:29 +0000765{
hasso52dc7ee2004-09-23 19:18:23 +0000766 struct list *lsas;
767 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000768 struct route_node *rn, *rn2;
769 struct prefix_ipv4 p;
770 struct route_table *tmp_old;
771 struct as_external_lsa *al;
772
773 al = (struct as_external_lsa *) lsa->data;
774 p.family = AF_INET;
775 p.prefix = lsa->data->id;
776 p.prefixlen = ip_masklen (al->mask);
777 apply_mask_ipv4 (&p);
778
779 /* if new_table is NULL, there was no spf calculation, thus
780 incremental update is unneeded */
paul68980082003-03-25 05:07:42 +0000781 if (!ospf->new_table)
paul718e3742002-12-13 20:15:29 +0000782 return;
783
784 /* If there is already an intra-area or inter-area route
785 to the destination, no recalculation is necessary
786 (internal routes take precedence). */
787
paul68980082003-03-25 05:07:42 +0000788 rn = route_node_lookup (ospf->new_table, (struct prefix *) &p);
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100789 if (rn)
paul718e3742002-12-13 20:15:29 +0000790 {
791 route_unlock_node (rn);
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100792 if (rn->info)
793 return;
paul718e3742002-12-13 20:15:29 +0000794 }
795
paul68980082003-03-25 05:07:42 +0000796 rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000797 assert (rn && rn->info);
798 lsas = rn->info;
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100799 route_unlock_node (rn);
800
paul1eb8ef22005-04-07 07:30:20 +0000801 for (ALL_LIST_ELEMENTS_RO (lsas, node, lsa))
802 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000803
804 /* prepare temporary old routing table for compare */
805 tmp_old = route_table_init ();
paul68980082003-03-25 05:07:42 +0000806 rn = route_node_lookup (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000807 if (rn && rn->info)
808 {
809 rn2 = route_node_get (tmp_old, (struct prefix *) &p);
810 rn2->info = rn->info;
811 }
812
813 /* install changes to zebra */
paul68980082003-03-25 05:07:42 +0000814 ospf_ase_compare_tables (ospf->new_external_route, tmp_old);
paul718e3742002-12-13 20:15:29 +0000815
paul68980082003-03-25 05:07:42 +0000816 /* update ospf->old_external_route table */
paul718e3742002-12-13 20:15:29 +0000817 if (rn && rn->info)
818 ospf_route_free ((struct ospf_route *) rn->info);
819
paul68980082003-03-25 05:07:42 +0000820 rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p);
821 /* if new route exists, install it to ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000822 if (rn2 && rn2->info)
823 {
824 if (!rn)
paul68980082003-03-25 05:07:42 +0000825 rn = route_node_get (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000826 rn->info = rn2->info;
827 }
828 else
829 {
paul68980082003-03-25 05:07:42 +0000830 /* remove route node from ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000831 if (rn)
832 {
833 rn->info = NULL;
834 route_unlock_node (rn);
835 route_unlock_node (rn);
836 }
837 }
838
839 if (rn2)
840 {
paul68980082003-03-25 05:07:42 +0000841 /* rn2->info is stored in route node of ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000842 rn2->info = NULL;
843 route_unlock_node (rn2);
844 route_unlock_node (rn2);
845 }
846
847 route_table_finish (tmp_old);
848}