blob: 5d0cae42d69cb113fcdb9391f2085e2c2865fcfa [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;
Joakim Tjernlunda8ba8472009-07-27 12:42:34 +0200138 struct interface *ifp;
paul718e3742002-12-13 20:15:29 +0000139
paul1eb8ef22005-04-07 07:30:20 +0000140 for (ALL_LIST_ELEMENTS_RO (ro->paths, node, op))
141 if (op->nexthop.s_addr == 0)
142 op->nexthop.s_addr = nexthop.s_addr;
paul718e3742002-12-13 20:15:29 +0000143}
144
paul4dadc292005-05-06 21:37:42 +0000145static int
paul68980082003-03-25 05:07:42 +0000146ospf_ase_forward_address_check (struct ospf *ospf, struct in_addr fwd_addr)
paul718e3742002-12-13 20:15:29 +0000147{
hasso52dc7ee2004-09-23 19:18:23 +0000148 struct listnode *ifn;
paul718e3742002-12-13 20:15:29 +0000149 struct ospf_interface *oi;
150
paul1eb8ef22005-04-07 07:30:20 +0000151 for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, ifn, oi))
152 if (if_is_operative (oi->ifp))
153 if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
154 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &fwd_addr))
155 return 0;
paul718e3742002-12-13 20:15:29 +0000156
157 return 1;
158}
159
Stephen Hemminger3408afe2009-12-03 19:18:26 +0300160#if 0
paul718e3742002-12-13 20:15:29 +0000161/* Calculate ASBR route. */
paul4dadc292005-05-06 21:37:42 +0000162static struct ospf_route *
paul68980082003-03-25 05:07:42 +0000163ospf_ase_calculate_asbr_route (struct ospf *ospf,
164 struct route_table *rt_network,
paul718e3742002-12-13 20:15:29 +0000165 struct route_table *rt_router,
166 struct as_external_lsa *al)
167{
168 struct prefix_ipv4 asbr;
169 struct ospf_route *asbr_route;
170 struct route_node *rn;
171
172 /* Find ASBR route from Router routing table. */
173 asbr.family = AF_INET;
174 asbr.prefix = al->header.adv_router;
175 asbr.prefixlen = IPV4_MAX_BITLEN;
176 apply_mask_ipv4 (&asbr);
177
paul68980082003-03-25 05:07:42 +0000178 asbr_route = ospf_find_asbr_route (ospf, rt_router, &asbr);
paul718e3742002-12-13 20:15:29 +0000179
180 if (asbr_route == NULL)
181 {
hassoe40dcce2005-02-21 14:58:42 +0000182 if (IS_DEBUG_OSPF (lsa, LSA))
183 zlog_debug ("ospf_ase_calculate(): Route to ASBR %s not found",
184 inet_ntoa (asbr.prefix));
paul718e3742002-12-13 20:15:29 +0000185 return NULL;
186 }
187
188 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
189 {
hassoe40dcce2005-02-21 14:58:42 +0000190 if (IS_DEBUG_OSPF (lsa, LSA))
191 zlog_debug ("ospf_ase_calculate(): Originating router is not an ASBR");
paul718e3742002-12-13 20:15:29 +0000192 return NULL;
193 }
194
195 if (al->e[0].fwd_addr.s_addr != 0)
196 {
hassoe40dcce2005-02-21 14:58:42 +0000197 if (IS_DEBUG_OSPF (lsa, LSA))
198 zlog_debug ("ospf_ase_calculate(): "
199 "Forwarding address is not 0.0.0.0.");
paul718e3742002-12-13 20:15:29 +0000200
paul68980082003-03-25 05:07:42 +0000201 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000202 {
hassoe40dcce2005-02-21 14:58:42 +0000203 if (IS_DEBUG_OSPF (lsa, LSA))
204 zlog_debug ("ospf_ase_calculate(): "
205 "Forwarding address is one of our addresses, Ignore.");
paul718e3742002-12-13 20:15:29 +0000206 return NULL;
207 }
208
hassoe40dcce2005-02-21 14:58:42 +0000209 if (IS_DEBUG_OSPF (lsa, LSA))
210 zlog_debug ("ospf_ase_calculate(): "
211 "Looking up in the Network Routing Table.");
paul718e3742002-12-13 20:15:29 +0000212
213 /* Looking up the path to the fwd_addr from Network route. */
214 asbr.family = AF_INET;
215 asbr.prefix = al->e[0].fwd_addr;
216 asbr.prefixlen = IPV4_MAX_BITLEN;
217
218 rn = route_node_match (rt_network, (struct prefix *) &asbr);
219
220 if (rn == NULL)
221 {
hassoe40dcce2005-02-21 14:58:42 +0000222 if (IS_DEBUG_OSPF (lsa, LSA))
223 zlog_debug ("ospf_ase_calculate(): "
224 "Couldn't find a route to the forwarding address.");
paul718e3742002-12-13 20:15:29 +0000225 return NULL;
226 }
227
228 route_unlock_node (rn);
229
230 if ((asbr_route = rn->info) == NULL)
231 {
hassoe40dcce2005-02-21 14:58:42 +0000232 if (IS_DEBUG_OSPF (lsa, LSA))
233 zlog_debug ("ospf_ase_calculate(): "
234 "Somehow OSPF route to ASBR is lost");
paul718e3742002-12-13 20:15:29 +0000235 return NULL;
236 }
237 }
238
239 return asbr_route;
240}
Stephen Hemminger3408afe2009-12-03 19:18:26 +0300241#endif
paul718e3742002-12-13 20:15:29 +0000242
paul4dadc292005-05-06 21:37:42 +0000243static struct ospf_route *
paul718e3742002-12-13 20:15:29 +0000244ospf_ase_calculate_new_route (struct ospf_lsa *lsa,
245 struct ospf_route *asbr_route, u_int32_t metric)
246{
247 struct as_external_lsa *al;
248 struct ospf_route *new;
249
250 al = (struct as_external_lsa *) lsa->data;
251
252 new = ospf_route_new ();
253
254 /* Set redistributed type -- does make sense? */
255 /* new->type = type; */
256 new->id = al->header.id;
257 new->mask = al->mask;
258
259 if (!IS_EXTERNAL_METRIC (al->e[0].tos))
260 {
hassoe40dcce2005-02-21 14:58:42 +0000261 if (IS_DEBUG_OSPF (lsa, LSA))
262 zlog_debug ("Route[External]: type-1 created.");
paul718e3742002-12-13 20:15:29 +0000263 new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
264 new->cost = asbr_route->cost + metric; /* X + Y */
265 }
266 else
267 {
hassoe40dcce2005-02-21 14:58:42 +0000268 if (IS_DEBUG_OSPF (lsa, LSA))
269 zlog_debug ("Route[External]: type-2 created.");
paul718e3742002-12-13 20:15:29 +0000270 new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
271 new->cost = asbr_route->cost; /* X */
272 new->u.ext.type2_cost = metric; /* Y */
273 }
274
275 new->type = OSPF_DESTINATION_NETWORK;
paul718e3742002-12-13 20:15:29 +0000276 new->u.ext.origin = lsa;
277 new->u.ext.tag = ntohl (al->e[0].route_tag);
278 new->u.ext.asbr = asbr_route;
279
280 assert (new != asbr_route);
281
282 return new;
283}
284
285#define OSPF_ASE_CALC_INTERVAL 1
286
287int
paul68980082003-03-25 05:07:42 +0000288ospf_ase_calculate_route (struct ospf *ospf, struct ospf_lsa * lsa)
paul718e3742002-12-13 20:15:29 +0000289{
290 u_int32_t metric;
291 struct as_external_lsa *al;
292 struct ospf_route *asbr_route;
293 struct prefix_ipv4 asbr, p;
294 struct route_node *rn;
295 struct ospf_route *new, *or;
296 int ret;
297
298 assert (lsa);
299 al = (struct as_external_lsa *) lsa->data;
300
paul718e3742002-12-13 20:15:29 +0000301 if (lsa->data->type == OSPF_AS_NSSA_LSA)
302 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000303 zlog_debug ("ospf_ase_calc(): Processing Type-7");
paul718e3742002-12-13 20:15:29 +0000304
305 /* Stay away from any Local Translated Type-7 LSAs */
306 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
307 {
308 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000309 zlog_debug ("ospf_ase_calc(): Rejecting Local Xlt'd");
paul718e3742002-12-13 20:15:29 +0000310 return 0;
311 }
paul718e3742002-12-13 20:15:29 +0000312
hassoe40dcce2005-02-21 14:58:42 +0000313 if (IS_DEBUG_OSPF (lsa, LSA))
314 zlog_debug ("Route[External]: Calculate AS-external-LSA to %s/%d",
315 inet_ntoa (al->header.id), ip_masklen (al->mask));
paul718e3742002-12-13 20:15:29 +0000316 /* (1) If the cost specified by the LSA is LSInfinity, or if the
317 LSA's LS age is equal to MaxAge, then examine the next LSA. */
318 if ((metric = GET_METRIC (al->e[0].metric)) >= OSPF_LS_INFINITY)
319 {
hassoe40dcce2005-02-21 14:58:42 +0000320 if (IS_DEBUG_OSPF (lsa, LSA))
321 zlog_debug ("Route[External]: Metric is OSPF_LS_INFINITY");
paul718e3742002-12-13 20:15:29 +0000322 return 0;
323 }
324 if (IS_LSA_MAXAGE (lsa))
325 {
hassoe40dcce2005-02-21 14:58:42 +0000326 if (IS_DEBUG_OSPF (lsa, LSA))
327 zlog_debug ("Route[External]: AS-external-LSA is MAXAGE");
paul718e3742002-12-13 20:15:29 +0000328 return 0;
329 }
330
331 /* (2) If the LSA was originated by the calculating router itself,
332 examine the next LSA. */
333 if (IS_LSA_SELF (lsa))
334 {
hassoe40dcce2005-02-21 14:58:42 +0000335 if (IS_DEBUG_OSPF (lsa, LSA))
336 zlog_debug ("Route[External]: AS-external-LSA is self originated");
paul718e3742002-12-13 20:15:29 +0000337 return 0;
338 }
339
340 /* (3) Call the destination described by the LSA N. N's address is
341 obtained by masking the LSA's Link State ID with the
342 network/subnet mask contained in the body of the LSA. Look
343 up the routing table entries (potentially one per attached
344 area) for the AS boundary router (ASBR) that originated the
345 LSA. If no entries exist for router ASBR (i.e., ASBR is
346 unreachable), do nothing with this LSA and consider the next
347 in the list. */
348
349 asbr.family = AF_INET;
350 asbr.prefix = al->header.adv_router;
351 asbr.prefixlen = IPV4_MAX_BITLEN;
352 apply_mask_ipv4 (&asbr);
353
paul68980082003-03-25 05:07:42 +0000354 asbr_route = ospf_find_asbr_route (ospf, ospf->new_rtrs, &asbr);
paul718e3742002-12-13 20:15:29 +0000355 if (asbr_route == NULL)
356 {
hassoe40dcce2005-02-21 14:58:42 +0000357 if (IS_DEBUG_OSPF (lsa, LSA))
358 zlog_debug ("Route[External]: Can't find originating ASBR route");
paul718e3742002-12-13 20:15:29 +0000359 return 0;
360 }
361 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
362 {
hassoe40dcce2005-02-21 14:58:42 +0000363 if (IS_DEBUG_OSPF (lsa, LSA))
364 zlog_debug ("Route[External]: Originating router is not an ASBR");
paul718e3742002-12-13 20:15:29 +0000365 return 0;
366 }
367
368 /* Else, this LSA describes an AS external path to destination
369 N. Examine the forwarding address specified in the AS-
370 external-LSA. This indicates the IP address to which
371 packets for the destination should be forwarded. */
372
373 if (al->e[0].fwd_addr.s_addr == 0)
374 {
375 /* If the forwarding address is set to 0.0.0.0, packets should
376 be sent to the ASBR itself. Among the multiple routing table
377 entries for the ASBR, select the preferred entry as follows.
378 If RFC1583Compatibility is set to "disabled", prune the set
379 of routing table entries for the ASBR as described in
380 Section 16.4.1. In any case, among the remaining routing
381 table entries, select the routing table entry with the least
382 cost; when there are multiple least cost routing table
383 entries the entry whose associated area has the largest OSPF
384 Area ID (when considered as an unsigned 32-bit integer) is
385 chosen. */
386
387 /* asbr_route already contains the requested route */
388 }
389 else
390 {
391 /* If the forwarding address is non-zero, look up the
392 forwarding address in the routing table.[24] The matching
393 routing table entry must specify an intra-area or inter-area
394 path; if no such path exists, do nothing with the LSA and
395 consider the next in the list. */
paul68980082003-03-25 05:07:42 +0000396 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000397 {
hassoe40dcce2005-02-21 14:58:42 +0000398 if (IS_DEBUG_OSPF (lsa, LSA))
399 zlog_debug ("Route[External]: Forwarding address is our router "
400 "address");
paul718e3742002-12-13 20:15:29 +0000401 return 0;
402 }
403
404 asbr.family = AF_INET;
405 asbr.prefix = al->e[0].fwd_addr;
406 asbr.prefixlen = IPV4_MAX_BITLEN;
407
paul68980082003-03-25 05:07:42 +0000408 rn = route_node_match (ospf->new_table, (struct prefix *) &asbr);
paul718e3742002-12-13 20:15:29 +0000409
410 if (rn == NULL || (asbr_route = rn->info) == NULL)
411 {
hassoe40dcce2005-02-21 14:58:42 +0000412 if (IS_DEBUG_OSPF (lsa, LSA))
413 zlog_debug ("Route[External]: Can't find route to forwarding "
414 "address");
paul718e3742002-12-13 20:15:29 +0000415 if (rn)
416 route_unlock_node (rn);
417 return 0;
418 }
419
420 route_unlock_node (rn);
421 }
422
423 /* (4) Let X be the cost specified by the preferred routing table
424 entry for the ASBR/forwarding address, and Y the cost
425 specified in the LSA. X is in terms of the link state
426 metric, and Y is a type 1 or 2 external metric. */
427
428
429 /* (5) Look up the routing table entry for the destination N. If
430 no entry exists for N, install the AS external path to N,
431 with next hop equal to the list of next hops to the
432 forwarding address, and advertising router equal to ASBR.
433 If the external metric type is 1, then the path-type is set
434 to type 1 external and the cost is equal to X+Y. If the
435 external metric type is 2, the path-type is set to type 2
436 external, the link state component of the route's cost is X,
437 and the type 2 cost is Y. */
438 new = ospf_ase_calculate_new_route (lsa, asbr_route, metric);
439
440 /* (6) Compare the AS external path described by the LSA with the
441 existing paths in N's routing table entry, as follows. If
442 the new path is preferred, it replaces the present paths in
443 N's routing table entry. If the new path is of equal
444 preference, it is added to N's routing table entry's list of
445 paths. */
446
447 /* Set prefix. */
448 p.family = AF_INET;
449 p.prefix = al->header.id;
450 p.prefixlen = ip_masklen (al->mask);
451
452 /* if there is a Intra/Inter area route to the N
453 do not install external route */
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100454 if (rn = route_node_lookup (ospf->new_table,
455 (struct prefix *) &p))
paul718e3742002-12-13 20:15:29 +0000456 {
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100457 route_unlock_node(rn);
458 if (rn->info == NULL)
459 zlog_info ("Route[External]: rn->info NULL");
paul718e3742002-12-13 20:15:29 +0000460 if (new)
461 ospf_route_free (new);
462 return 0;
463 }
paul718e3742002-12-13 20:15:29 +0000464 /* Find a route to the same dest */
465 /* If there is no route, create new one. */
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100466 if (rn = route_node_lookup (ospf->new_external_route,
467 (struct prefix *) &p))
468 route_unlock_node(rn);
469
470 if (!rn || (or = rn->info) == NULL)
paul718e3742002-12-13 20:15:29 +0000471 {
hassoe40dcce2005-02-21 14:58:42 +0000472 if (IS_DEBUG_OSPF (lsa, LSA))
473 zlog_debug ("Route[External]: Adding a new route %s/%d",
474 inet_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000475
paul68980082003-03-25 05:07:42 +0000476 ospf_route_add (ospf->new_external_route, &p, new, asbr_route);
paul718e3742002-12-13 20:15:29 +0000477
478 if (al->e[0].fwd_addr.s_addr)
479 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
480 return 0;
481 }
482 else
483 {
484 /* (a) Intra-area and inter-area paths are always preferred
485 over AS external paths.
486
487 (b) Type 1 external paths are always preferred over type 2
488 external paths. When all paths are type 2 external
489 paths, the paths with the smallest advertised type 2
490 metric are always preferred. */
paul68980082003-03-25 05:07:42 +0000491 ret = ospf_route_cmp (ospf, new, or);
paul718e3742002-12-13 20:15:29 +0000492
493 /* (c) If the new AS external path is still indistinguishable
494 from the current paths in the N's routing table entry,
495 and RFC1583Compatibility is set to "disabled", select
496 the preferred paths based on the intra-AS paths to the
497 ASBR/forwarding addresses, as specified in Section
498 16.4.1.
499
500 (d) If the new AS external path is still indistinguishable
501 from the current paths in the N's routing table entry,
502 select the preferred path based on a least cost
503 comparison. Type 1 external paths are compared by
504 looking at the sum of the distance to the forwarding
505 address and the advertised type 1 metric (X+Y). Type 2
506 external paths advertising equal type 2 metrics are
507 compared by looking at the distance to the forwarding
508 addresses.
509 */
510 /* New route is better */
511 if (ret < 0)
512 {
hassoe40dcce2005-02-21 14:58:42 +0000513 if (IS_DEBUG_OSPF (lsa, LSA))
514 zlog_debug ("Route[External]: New route is better");
paul718e3742002-12-13 20:15:29 +0000515 ospf_route_subst (rn, new, asbr_route);
516 if (al->e[0].fwd_addr.s_addr)
517 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
518 or = new;
519 new = NULL;
520 }
521 /* Old route is better */
522 else if (ret > 0)
523 {
hassoe40dcce2005-02-21 14:58:42 +0000524 if (IS_DEBUG_OSPF (lsa, LSA))
525 zlog_debug ("Route[External]: Old route is better");
paul718e3742002-12-13 20:15:29 +0000526 /* do nothing */
527 }
528 /* Routes are equal */
529 else
530 {
hassoe40dcce2005-02-21 14:58:42 +0000531 if (IS_DEBUG_OSPF (lsa, LSA))
532 zlog_debug ("Route[External]: Routes are equal");
paul96735ee2003-08-10 02:51:22 +0000533 ospf_route_copy_nexthops (or, asbr_route->paths);
paul718e3742002-12-13 20:15:29 +0000534 if (al->e[0].fwd_addr.s_addr)
535 ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr);
536 }
537 }
538 /* Make sure setting newly calculated ASBR route.*/
539 or->u.ext.asbr = asbr_route;
540 if (new)
541 ospf_route_free (new);
542
543 lsa->route = or;
544 return 0;
545}
546
paul4dadc292005-05-06 21:37:42 +0000547static int
paul718e3742002-12-13 20:15:29 +0000548ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix,
549 struct ospf_route *newor)
550{
551 struct route_node *rn;
552 struct ospf_route *or;
553 struct ospf_path *op;
554 struct ospf_path *newop;
hasso52dc7ee2004-09-23 19:18:23 +0000555 struct listnode *n1;
556 struct listnode *n2;
paul718e3742002-12-13 20:15:29 +0000557
558 if (! rt || ! prefix)
559 return 0;
560
561 rn = route_node_lookup (rt, prefix);
562 if (! rn)
563 return 0;
564
565 route_unlock_node (rn);
566
567 or = rn->info;
568 if (or->path_type != newor->path_type)
569 return 0;
570
571 switch (or->path_type)
572 {
573 case OSPF_PATH_TYPE1_EXTERNAL:
574 if (or->cost != newor->cost)
575 return 0;
576 break;
577 case OSPF_PATH_TYPE2_EXTERNAL:
578 if ((or->cost != newor->cost) ||
579 (or->u.ext.type2_cost != newor->u.ext.type2_cost))
580 return 0;
581 break;
582 default:
583 assert (0);
584 return 0;
585 }
586
paul96735ee2003-08-10 02:51:22 +0000587 if (or->paths->count != newor->paths->count)
paul718e3742002-12-13 20:15:29 +0000588 return 0;
589
590 /* Check each path. */
paul96735ee2003-08-10 02:51:22 +0000591 for (n1 = listhead (or->paths), n2 = listhead (newor->paths);
paul1eb8ef22005-04-07 07:30:20 +0000592 n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2))
paul718e3742002-12-13 20:15:29 +0000593 {
paul1eb8ef22005-04-07 07:30:20 +0000594 op = listgetdata (n1);
595 newop = listgetdata (n2);
paul718e3742002-12-13 20:15:29 +0000596
597 if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
598 return 0;
Joakim Tjernlunda8ba8472009-07-27 12:42:34 +0200599 if (op->ifindex != newop->ifindex)
Joakim Tjernlund77a1c4e2009-02-01 11:12:11 +0100600 return 0;
paul718e3742002-12-13 20:15:29 +0000601 }
602 return 1;
603}
604
paul4dadc292005-05-06 21:37:42 +0000605static int
paul718e3742002-12-13 20:15:29 +0000606ospf_ase_compare_tables (struct route_table *new_external_route,
607 struct route_table *old_external_route)
608{
609 struct route_node *rn, *new_rn;
610 struct ospf_route *or;
611
612 /* Remove deleted routes */
613 for (rn = route_top (old_external_route); rn; rn = route_next (rn))
614 if ((or = rn->info))
615 {
616 if (! (new_rn = route_node_lookup (new_external_route, &rn->p)))
617 ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
618 else
619 route_unlock_node (new_rn);
620 }
621
622
623 /* Install new routes */
624 for (rn = route_top (new_external_route); rn; rn = route_next (rn))
625 if ((or = rn->info) != NULL)
626 if (! ospf_ase_route_match_same (old_external_route, &rn->p, or))
627 ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
628
629 return 0;
630}
631
paul4dadc292005-05-06 21:37:42 +0000632static int
paul718e3742002-12-13 20:15:29 +0000633ospf_ase_calculate_timer (struct thread *t)
634{
635 struct ospf *ospf;
paul68980082003-03-25 05:07:42 +0000636 struct ospf_lsa *lsa;
637 struct route_node *rn;
hasso52dc7ee2004-09-23 19:18:23 +0000638 struct listnode *node;
paul68980082003-03-25 05:07:42 +0000639 struct ospf_area *area;
paul718e3742002-12-13 20:15:29 +0000640
641 ospf = THREAD_ARG (t);
642 ospf->t_ase_calc = NULL;
643
644 if (ospf->ase_calc)
645 {
646 ospf->ase_calc = 0;
647
648 /* Calculate external route for each AS-external-LSA */
paul68980082003-03-25 05:07:42 +0000649 LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
650 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000651
paul718e3742002-12-13 20:15:29 +0000652 /* This version simple adds to the table all NSSA areas */
paul68980082003-03-25 05:07:42 +0000653 if (ospf->anyNSSA)
paul1eb8ef22005-04-07 07:30:20 +0000654 for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area))
paul718e3742002-12-13 20:15:29 +0000655 {
paul718e3742002-12-13 20:15:29 +0000656 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
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000722 listnode_add (lst, ospf_lsa_lock (lsa)); /* external_lsas lst */
paul718e3742002-12-13 20:15:29 +0000723}
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;
paul718e3742002-12-13 20:15:29 +0000741
paul718e3742002-12-13 20:15:29 +0000742 /* XXX lst can be NULL */
743 if (lst) {
744 listnode_delete (lst, lsa);
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000745 ospf_lsa_unlock (&lsa); /* external_lsas list */
paul718e3742002-12-13 20:15:29 +0000746 }
paul718e3742002-12-13 20:15:29 +0000747}
748
749void
750ospf_ase_external_lsas_finish (struct route_table *rt)
751{
752 struct route_node *rn;
753 struct ospf_lsa *lsa;
hasso52dc7ee2004-09-23 19:18:23 +0000754 struct list *lst;
paul1eb8ef22005-04-07 07:30:20 +0000755 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000756
757 for (rn = route_top (rt); rn; rn = route_next (rn))
758 if ((lst = rn->info) != NULL)
759 {
paul1eb8ef22005-04-07 07:30:20 +0000760 for (ALL_LIST_ELEMENTS (lst, node, nnode, lsa))
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000761 ospf_lsa_unlock (&lsa); /* external_lsas lst */
paul718e3742002-12-13 20:15:29 +0000762 list_delete (lst);
763 }
paul1eb8ef22005-04-07 07:30:20 +0000764
paul718e3742002-12-13 20:15:29 +0000765 route_table_finish (rt);
766}
767
768void
paul68980082003-03-25 05:07:42 +0000769ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa)
paul718e3742002-12-13 20:15:29 +0000770{
hasso52dc7ee2004-09-23 19:18:23 +0000771 struct list *lsas;
772 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000773 struct route_node *rn, *rn2;
774 struct prefix_ipv4 p;
775 struct route_table *tmp_old;
776 struct as_external_lsa *al;
777
778 al = (struct as_external_lsa *) lsa->data;
779 p.family = AF_INET;
780 p.prefix = lsa->data->id;
781 p.prefixlen = ip_masklen (al->mask);
782 apply_mask_ipv4 (&p);
783
784 /* if new_table is NULL, there was no spf calculation, thus
785 incremental update is unneeded */
paul68980082003-03-25 05:07:42 +0000786 if (!ospf->new_table)
paul718e3742002-12-13 20:15:29 +0000787 return;
788
789 /* If there is already an intra-area or inter-area route
790 to the destination, no recalculation is necessary
791 (internal routes take precedence). */
792
paul68980082003-03-25 05:07:42 +0000793 rn = route_node_lookup (ospf->new_table, (struct prefix *) &p);
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100794 if (rn)
paul718e3742002-12-13 20:15:29 +0000795 {
796 route_unlock_node (rn);
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100797 if (rn->info)
798 return;
paul718e3742002-12-13 20:15:29 +0000799 }
800
paul68980082003-03-25 05:07:42 +0000801 rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000802 assert (rn && rn->info);
803 lsas = rn->info;
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100804 route_unlock_node (rn);
805
paul1eb8ef22005-04-07 07:30:20 +0000806 for (ALL_LIST_ELEMENTS_RO (lsas, node, lsa))
807 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000808
809 /* prepare temporary old routing table for compare */
810 tmp_old = route_table_init ();
paul68980082003-03-25 05:07:42 +0000811 rn = route_node_lookup (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000812 if (rn && rn->info)
813 {
814 rn2 = route_node_get (tmp_old, (struct prefix *) &p);
815 rn2->info = rn->info;
816 }
817
818 /* install changes to zebra */
paul68980082003-03-25 05:07:42 +0000819 ospf_ase_compare_tables (ospf->new_external_route, tmp_old);
paul718e3742002-12-13 20:15:29 +0000820
paul68980082003-03-25 05:07:42 +0000821 /* update ospf->old_external_route table */
paul718e3742002-12-13 20:15:29 +0000822 if (rn && rn->info)
823 ospf_route_free ((struct ospf_route *) rn->info);
824
paul68980082003-03-25 05:07:42 +0000825 rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p);
826 /* if new route exists, install it to ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000827 if (rn2 && rn2->info)
828 {
829 if (!rn)
paul68980082003-03-25 05:07:42 +0000830 rn = route_node_get (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000831 rn->info = rn2->info;
832 }
833 else
834 {
paul68980082003-03-25 05:07:42 +0000835 /* remove route node from ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000836 if (rn)
837 {
838 rn->info = NULL;
839 route_unlock_node (rn);
840 route_unlock_node (rn);
841 }
842 }
843
844 if (rn2)
845 {
paul68980082003-03-25 05:07:42 +0000846 /* rn2->info is stored in route node of ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000847 rn2->info = NULL;
848 route_unlock_node (rn2);
849 route_unlock_node (rn2);
850 }
851
852 route_table_finish (tmp_old);
853}