blob: 7bddf3f4db2a17d549463ca4f1855ce280dd9182 [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
160/* Calculate ASBR route. */
paul4dadc292005-05-06 21:37:42 +0000161static struct ospf_route *
paul68980082003-03-25 05:07:42 +0000162ospf_ase_calculate_asbr_route (struct ospf *ospf,
163 struct route_table *rt_network,
paul718e3742002-12-13 20:15:29 +0000164 struct route_table *rt_router,
165 struct as_external_lsa *al)
166{
167 struct prefix_ipv4 asbr;
168 struct ospf_route *asbr_route;
169 struct route_node *rn;
170
171 /* Find ASBR route from Router routing table. */
172 asbr.family = AF_INET;
173 asbr.prefix = al->header.adv_router;
174 asbr.prefixlen = IPV4_MAX_BITLEN;
175 apply_mask_ipv4 (&asbr);
176
paul68980082003-03-25 05:07:42 +0000177 asbr_route = ospf_find_asbr_route (ospf, rt_router, &asbr);
paul718e3742002-12-13 20:15:29 +0000178
179 if (asbr_route == NULL)
180 {
hassoe40dcce2005-02-21 14:58:42 +0000181 if (IS_DEBUG_OSPF (lsa, LSA))
182 zlog_debug ("ospf_ase_calculate(): Route to ASBR %s not found",
183 inet_ntoa (asbr.prefix));
paul718e3742002-12-13 20:15:29 +0000184 return NULL;
185 }
186
187 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
188 {
hassoe40dcce2005-02-21 14:58:42 +0000189 if (IS_DEBUG_OSPF (lsa, LSA))
190 zlog_debug ("ospf_ase_calculate(): Originating router is not an ASBR");
paul718e3742002-12-13 20:15:29 +0000191 return NULL;
192 }
193
194 if (al->e[0].fwd_addr.s_addr != 0)
195 {
hassoe40dcce2005-02-21 14:58:42 +0000196 if (IS_DEBUG_OSPF (lsa, LSA))
197 zlog_debug ("ospf_ase_calculate(): "
198 "Forwarding address is not 0.0.0.0.");
paul718e3742002-12-13 20:15:29 +0000199
paul68980082003-03-25 05:07:42 +0000200 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000201 {
hassoe40dcce2005-02-21 14:58:42 +0000202 if (IS_DEBUG_OSPF (lsa, LSA))
203 zlog_debug ("ospf_ase_calculate(): "
204 "Forwarding address is one of our addresses, Ignore.");
paul718e3742002-12-13 20:15:29 +0000205 return NULL;
206 }
207
hassoe40dcce2005-02-21 14:58:42 +0000208 if (IS_DEBUG_OSPF (lsa, LSA))
209 zlog_debug ("ospf_ase_calculate(): "
210 "Looking up in the Network Routing Table.");
paul718e3742002-12-13 20:15:29 +0000211
212 /* Looking up the path to the fwd_addr from Network route. */
213 asbr.family = AF_INET;
214 asbr.prefix = al->e[0].fwd_addr;
215 asbr.prefixlen = IPV4_MAX_BITLEN;
216
217 rn = route_node_match (rt_network, (struct prefix *) &asbr);
218
219 if (rn == NULL)
220 {
hassoe40dcce2005-02-21 14:58:42 +0000221 if (IS_DEBUG_OSPF (lsa, LSA))
222 zlog_debug ("ospf_ase_calculate(): "
223 "Couldn't find a route to the forwarding address.");
paul718e3742002-12-13 20:15:29 +0000224 return NULL;
225 }
226
227 route_unlock_node (rn);
228
229 if ((asbr_route = rn->info) == NULL)
230 {
hassoe40dcce2005-02-21 14:58:42 +0000231 if (IS_DEBUG_OSPF (lsa, LSA))
232 zlog_debug ("ospf_ase_calculate(): "
233 "Somehow OSPF route to ASBR is lost");
paul718e3742002-12-13 20:15:29 +0000234 return NULL;
235 }
236 }
237
238 return asbr_route;
239}
240
paul4dadc292005-05-06 21:37:42 +0000241static struct ospf_route *
paul718e3742002-12-13 20:15:29 +0000242ospf_ase_calculate_new_route (struct ospf_lsa *lsa,
243 struct ospf_route *asbr_route, u_int32_t metric)
244{
245 struct as_external_lsa *al;
246 struct ospf_route *new;
247
248 al = (struct as_external_lsa *) lsa->data;
249
250 new = ospf_route_new ();
251
252 /* Set redistributed type -- does make sense? */
253 /* new->type = type; */
254 new->id = al->header.id;
255 new->mask = al->mask;
256
257 if (!IS_EXTERNAL_METRIC (al->e[0].tos))
258 {
hassoe40dcce2005-02-21 14:58:42 +0000259 if (IS_DEBUG_OSPF (lsa, LSA))
260 zlog_debug ("Route[External]: type-1 created.");
paul718e3742002-12-13 20:15:29 +0000261 new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
262 new->cost = asbr_route->cost + metric; /* X + Y */
263 }
264 else
265 {
hassoe40dcce2005-02-21 14:58:42 +0000266 if (IS_DEBUG_OSPF (lsa, LSA))
267 zlog_debug ("Route[External]: type-2 created.");
paul718e3742002-12-13 20:15:29 +0000268 new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
269 new->cost = asbr_route->cost; /* X */
270 new->u.ext.type2_cost = metric; /* Y */
271 }
272
273 new->type = OSPF_DESTINATION_NETWORK;
paul718e3742002-12-13 20:15:29 +0000274 new->u.ext.origin = lsa;
275 new->u.ext.tag = ntohl (al->e[0].route_tag);
276 new->u.ext.asbr = asbr_route;
277
278 assert (new != asbr_route);
279
280 return new;
281}
282
283#define OSPF_ASE_CALC_INTERVAL 1
284
285int
paul68980082003-03-25 05:07:42 +0000286ospf_ase_calculate_route (struct ospf *ospf, struct ospf_lsa * lsa)
paul718e3742002-12-13 20:15:29 +0000287{
288 u_int32_t metric;
289 struct as_external_lsa *al;
290 struct ospf_route *asbr_route;
291 struct prefix_ipv4 asbr, p;
292 struct route_node *rn;
293 struct ospf_route *new, *or;
294 int ret;
295
296 assert (lsa);
297 al = (struct as_external_lsa *) lsa->data;
298
paul718e3742002-12-13 20:15:29 +0000299 if (lsa->data->type == OSPF_AS_NSSA_LSA)
300 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000301 zlog_debug ("ospf_ase_calc(): Processing Type-7");
paul718e3742002-12-13 20:15:29 +0000302
303 /* Stay away from any Local Translated Type-7 LSAs */
304 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
305 {
306 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000307 zlog_debug ("ospf_ase_calc(): Rejecting Local Xlt'd");
paul718e3742002-12-13 20:15:29 +0000308 return 0;
309 }
paul718e3742002-12-13 20:15:29 +0000310
hassoe40dcce2005-02-21 14:58:42 +0000311 if (IS_DEBUG_OSPF (lsa, LSA))
312 zlog_debug ("Route[External]: Calculate AS-external-LSA to %s/%d",
313 inet_ntoa (al->header.id), ip_masklen (al->mask));
paul718e3742002-12-13 20:15:29 +0000314 /* (1) If the cost specified by the LSA is LSInfinity, or if the
315 LSA's LS age is equal to MaxAge, then examine the next LSA. */
316 if ((metric = GET_METRIC (al->e[0].metric)) >= OSPF_LS_INFINITY)
317 {
hassoe40dcce2005-02-21 14:58:42 +0000318 if (IS_DEBUG_OSPF (lsa, LSA))
319 zlog_debug ("Route[External]: Metric is OSPF_LS_INFINITY");
paul718e3742002-12-13 20:15:29 +0000320 return 0;
321 }
322 if (IS_LSA_MAXAGE (lsa))
323 {
hassoe40dcce2005-02-21 14:58:42 +0000324 if (IS_DEBUG_OSPF (lsa, LSA))
325 zlog_debug ("Route[External]: AS-external-LSA is MAXAGE");
paul718e3742002-12-13 20:15:29 +0000326 return 0;
327 }
328
329 /* (2) If the LSA was originated by the calculating router itself,
330 examine the next LSA. */
331 if (IS_LSA_SELF (lsa))
332 {
hassoe40dcce2005-02-21 14:58:42 +0000333 if (IS_DEBUG_OSPF (lsa, LSA))
334 zlog_debug ("Route[External]: AS-external-LSA is self originated");
paul718e3742002-12-13 20:15:29 +0000335 return 0;
336 }
337
338 /* (3) Call the destination described by the LSA N. N's address is
339 obtained by masking the LSA's Link State ID with the
340 network/subnet mask contained in the body of the LSA. Look
341 up the routing table entries (potentially one per attached
342 area) for the AS boundary router (ASBR) that originated the
343 LSA. If no entries exist for router ASBR (i.e., ASBR is
344 unreachable), do nothing with this LSA and consider the next
345 in the list. */
346
347 asbr.family = AF_INET;
348 asbr.prefix = al->header.adv_router;
349 asbr.prefixlen = IPV4_MAX_BITLEN;
350 apply_mask_ipv4 (&asbr);
351
paul68980082003-03-25 05:07:42 +0000352 asbr_route = ospf_find_asbr_route (ospf, ospf->new_rtrs, &asbr);
paul718e3742002-12-13 20:15:29 +0000353 if (asbr_route == NULL)
354 {
hassoe40dcce2005-02-21 14:58:42 +0000355 if (IS_DEBUG_OSPF (lsa, LSA))
356 zlog_debug ("Route[External]: Can't find originating ASBR route");
paul718e3742002-12-13 20:15:29 +0000357 return 0;
358 }
359 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
360 {
hassoe40dcce2005-02-21 14:58:42 +0000361 if (IS_DEBUG_OSPF (lsa, LSA))
362 zlog_debug ("Route[External]: Originating router is not an ASBR");
paul718e3742002-12-13 20:15:29 +0000363 return 0;
364 }
365
366 /* Else, this LSA describes an AS external path to destination
367 N. Examine the forwarding address specified in the AS-
368 external-LSA. This indicates the IP address to which
369 packets for the destination should be forwarded. */
370
371 if (al->e[0].fwd_addr.s_addr == 0)
372 {
373 /* If the forwarding address is set to 0.0.0.0, packets should
374 be sent to the ASBR itself. Among the multiple routing table
375 entries for the ASBR, select the preferred entry as follows.
376 If RFC1583Compatibility is set to "disabled", prune the set
377 of routing table entries for the ASBR as described in
378 Section 16.4.1. In any case, among the remaining routing
379 table entries, select the routing table entry with the least
380 cost; when there are multiple least cost routing table
381 entries the entry whose associated area has the largest OSPF
382 Area ID (when considered as an unsigned 32-bit integer) is
383 chosen. */
384
385 /* asbr_route already contains the requested route */
386 }
387 else
388 {
389 /* If the forwarding address is non-zero, look up the
390 forwarding address in the routing table.[24] The matching
391 routing table entry must specify an intra-area or inter-area
392 path; if no such path exists, do nothing with the LSA and
393 consider the next in the list. */
paul68980082003-03-25 05:07:42 +0000394 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000395 {
hassoe40dcce2005-02-21 14:58:42 +0000396 if (IS_DEBUG_OSPF (lsa, LSA))
397 zlog_debug ("Route[External]: Forwarding address is our router "
398 "address");
paul718e3742002-12-13 20:15:29 +0000399 return 0;
400 }
401
402 asbr.family = AF_INET;
403 asbr.prefix = al->e[0].fwd_addr;
404 asbr.prefixlen = IPV4_MAX_BITLEN;
405
paul68980082003-03-25 05:07:42 +0000406 rn = route_node_match (ospf->new_table, (struct prefix *) &asbr);
paul718e3742002-12-13 20:15:29 +0000407
408 if (rn == NULL || (asbr_route = rn->info) == NULL)
409 {
hassoe40dcce2005-02-21 14:58:42 +0000410 if (IS_DEBUG_OSPF (lsa, LSA))
411 zlog_debug ("Route[External]: Can't find route to forwarding "
412 "address");
paul718e3742002-12-13 20:15:29 +0000413 if (rn)
414 route_unlock_node (rn);
415 return 0;
416 }
417
418 route_unlock_node (rn);
419 }
420
421 /* (4) Let X be the cost specified by the preferred routing table
422 entry for the ASBR/forwarding address, and Y the cost
423 specified in the LSA. X is in terms of the link state
424 metric, and Y is a type 1 or 2 external metric. */
425
426
427 /* (5) Look up the routing table entry for the destination N. If
428 no entry exists for N, install the AS external path to N,
429 with next hop equal to the list of next hops to the
430 forwarding address, and advertising router equal to ASBR.
431 If the external metric type is 1, then the path-type is set
432 to type 1 external and the cost is equal to X+Y. If the
433 external metric type is 2, the path-type is set to type 2
434 external, the link state component of the route's cost is X,
435 and the type 2 cost is Y. */
436 new = ospf_ase_calculate_new_route (lsa, asbr_route, metric);
437
438 /* (6) Compare the AS external path described by the LSA with the
439 existing paths in N's routing table entry, as follows. If
440 the new path is preferred, it replaces the present paths in
441 N's routing table entry. If the new path is of equal
442 preference, it is added to N's routing table entry's list of
443 paths. */
444
445 /* Set prefix. */
446 p.family = AF_INET;
447 p.prefix = al->header.id;
448 p.prefixlen = ip_masklen (al->mask);
449
450 /* if there is a Intra/Inter area route to the N
451 do not install external route */
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100452 if (rn = route_node_lookup (ospf->new_table,
453 (struct prefix *) &p))
paul718e3742002-12-13 20:15:29 +0000454 {
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100455 route_unlock_node(rn);
456 if (rn->info == NULL)
457 zlog_info ("Route[External]: rn->info NULL");
paul718e3742002-12-13 20:15:29 +0000458 if (new)
459 ospf_route_free (new);
460 return 0;
461 }
paul718e3742002-12-13 20:15:29 +0000462 /* Find a route to the same dest */
463 /* If there is no route, create new one. */
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100464 if (rn = route_node_lookup (ospf->new_external_route,
465 (struct prefix *) &p))
466 route_unlock_node(rn);
467
468 if (!rn || (or = rn->info) == NULL)
paul718e3742002-12-13 20:15:29 +0000469 {
hassoe40dcce2005-02-21 14:58:42 +0000470 if (IS_DEBUG_OSPF (lsa, LSA))
471 zlog_debug ("Route[External]: Adding a new route %s/%d",
472 inet_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000473
paul68980082003-03-25 05:07:42 +0000474 ospf_route_add (ospf->new_external_route, &p, new, asbr_route);
paul718e3742002-12-13 20:15:29 +0000475
476 if (al->e[0].fwd_addr.s_addr)
477 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
478 return 0;
479 }
480 else
481 {
482 /* (a) Intra-area and inter-area paths are always preferred
483 over AS external paths.
484
485 (b) Type 1 external paths are always preferred over type 2
486 external paths. When all paths are type 2 external
487 paths, the paths with the smallest advertised type 2
488 metric are always preferred. */
paul68980082003-03-25 05:07:42 +0000489 ret = ospf_route_cmp (ospf, new, or);
paul718e3742002-12-13 20:15:29 +0000490
491 /* (c) If the new AS external path is still indistinguishable
492 from the current paths in the N's routing table entry,
493 and RFC1583Compatibility is set to "disabled", select
494 the preferred paths based on the intra-AS paths to the
495 ASBR/forwarding addresses, as specified in Section
496 16.4.1.
497
498 (d) If the new AS external path is still indistinguishable
499 from the current paths in the N's routing table entry,
500 select the preferred path based on a least cost
501 comparison. Type 1 external paths are compared by
502 looking at the sum of the distance to the forwarding
503 address and the advertised type 1 metric (X+Y). Type 2
504 external paths advertising equal type 2 metrics are
505 compared by looking at the distance to the forwarding
506 addresses.
507 */
508 /* New route is better */
509 if (ret < 0)
510 {
hassoe40dcce2005-02-21 14:58:42 +0000511 if (IS_DEBUG_OSPF (lsa, LSA))
512 zlog_debug ("Route[External]: New route is better");
paul718e3742002-12-13 20:15:29 +0000513 ospf_route_subst (rn, new, asbr_route);
514 if (al->e[0].fwd_addr.s_addr)
515 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
516 or = new;
517 new = NULL;
518 }
519 /* Old route is better */
520 else if (ret > 0)
521 {
hassoe40dcce2005-02-21 14:58:42 +0000522 if (IS_DEBUG_OSPF (lsa, LSA))
523 zlog_debug ("Route[External]: Old route is better");
paul718e3742002-12-13 20:15:29 +0000524 /* do nothing */
525 }
526 /* Routes are equal */
527 else
528 {
hassoe40dcce2005-02-21 14:58:42 +0000529 if (IS_DEBUG_OSPF (lsa, LSA))
530 zlog_debug ("Route[External]: Routes are equal");
paul96735ee2003-08-10 02:51:22 +0000531 ospf_route_copy_nexthops (or, asbr_route->paths);
paul718e3742002-12-13 20:15:29 +0000532 if (al->e[0].fwd_addr.s_addr)
533 ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr);
534 }
535 }
536 /* Make sure setting newly calculated ASBR route.*/
537 or->u.ext.asbr = asbr_route;
538 if (new)
539 ospf_route_free (new);
540
541 lsa->route = or;
542 return 0;
543}
544
paul4dadc292005-05-06 21:37:42 +0000545static int
paul718e3742002-12-13 20:15:29 +0000546ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix,
547 struct ospf_route *newor)
548{
549 struct route_node *rn;
550 struct ospf_route *or;
551 struct ospf_path *op;
552 struct ospf_path *newop;
hasso52dc7ee2004-09-23 19:18:23 +0000553 struct listnode *n1;
554 struct listnode *n2;
paul718e3742002-12-13 20:15:29 +0000555
556 if (! rt || ! prefix)
557 return 0;
558
559 rn = route_node_lookup (rt, prefix);
560 if (! rn)
561 return 0;
562
563 route_unlock_node (rn);
564
565 or = rn->info;
566 if (or->path_type != newor->path_type)
567 return 0;
568
569 switch (or->path_type)
570 {
571 case OSPF_PATH_TYPE1_EXTERNAL:
572 if (or->cost != newor->cost)
573 return 0;
574 break;
575 case OSPF_PATH_TYPE2_EXTERNAL:
576 if ((or->cost != newor->cost) ||
577 (or->u.ext.type2_cost != newor->u.ext.type2_cost))
578 return 0;
579 break;
580 default:
581 assert (0);
582 return 0;
583 }
584
paul96735ee2003-08-10 02:51:22 +0000585 if (or->paths->count != newor->paths->count)
paul718e3742002-12-13 20:15:29 +0000586 return 0;
587
588 /* Check each path. */
paul96735ee2003-08-10 02:51:22 +0000589 for (n1 = listhead (or->paths), n2 = listhead (newor->paths);
paul1eb8ef22005-04-07 07:30:20 +0000590 n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2))
paul718e3742002-12-13 20:15:29 +0000591 {
paul1eb8ef22005-04-07 07:30:20 +0000592 op = listgetdata (n1);
593 newop = listgetdata (n2);
paul718e3742002-12-13 20:15:29 +0000594
595 if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
596 return 0;
Joakim Tjernlunda8ba8472009-07-27 12:42:34 +0200597 if (op->ifindex != newop->ifindex)
Joakim Tjernlund77a1c4e2009-02-01 11:12:11 +0100598 return 0;
paul718e3742002-12-13 20:15:29 +0000599 }
600 return 1;
601}
602
paul4dadc292005-05-06 21:37:42 +0000603static int
paul718e3742002-12-13 20:15:29 +0000604ospf_ase_compare_tables (struct route_table *new_external_route,
605 struct route_table *old_external_route)
606{
607 struct route_node *rn, *new_rn;
608 struct ospf_route *or;
609
610 /* Remove deleted routes */
611 for (rn = route_top (old_external_route); rn; rn = route_next (rn))
612 if ((or = rn->info))
613 {
614 if (! (new_rn = route_node_lookup (new_external_route, &rn->p)))
615 ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
616 else
617 route_unlock_node (new_rn);
618 }
619
620
621 /* Install new routes */
622 for (rn = route_top (new_external_route); rn; rn = route_next (rn))
623 if ((or = rn->info) != NULL)
624 if (! ospf_ase_route_match_same (old_external_route, &rn->p, or))
625 ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
626
627 return 0;
628}
629
paul4dadc292005-05-06 21:37:42 +0000630static int
paul718e3742002-12-13 20:15:29 +0000631ospf_ase_calculate_timer (struct thread *t)
632{
633 struct ospf *ospf;
paul68980082003-03-25 05:07:42 +0000634 struct ospf_lsa *lsa;
635 struct route_node *rn;
hasso52dc7ee2004-09-23 19:18:23 +0000636 struct listnode *node;
paul68980082003-03-25 05:07:42 +0000637 struct ospf_area *area;
paul718e3742002-12-13 20:15:29 +0000638
639 ospf = THREAD_ARG (t);
640 ospf->t_ase_calc = NULL;
641
642 if (ospf->ase_calc)
643 {
644 ospf->ase_calc = 0;
645
646 /* Calculate external route for each AS-external-LSA */
paul68980082003-03-25 05:07:42 +0000647 LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
648 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000649
paul718e3742002-12-13 20:15:29 +0000650 /* This version simple adds to the table all NSSA areas */
paul68980082003-03-25 05:07:42 +0000651 if (ospf->anyNSSA)
paul1eb8ef22005-04-07 07:30:20 +0000652 for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area))
paul718e3742002-12-13 20:15:29 +0000653 {
paul718e3742002-12-13 20:15:29 +0000654 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000655 zlog_debug ("ospf_ase_calculate_timer(): looking at area %s",
paul718e3742002-12-13 20:15:29 +0000656 inet_ntoa (area->area_id));
657
658 if (area->external_routing == OSPF_AREA_NSSA)
paul68980082003-03-25 05:07:42 +0000659 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
660 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000661 }
paulf2c80652002-12-13 21:44:27 +0000662 /* kevinm: And add the NSSA routes in ospf_top */
paulf6386ee2003-04-07 04:29:27 +0000663 LSDB_LOOP (NSSA_LSDB (ospf),rn,lsa)
664 ospf_ase_calculate_route(ospf,lsa);
paulf2c80652002-12-13 21:44:27 +0000665
paul718e3742002-12-13 20:15:29 +0000666 /* Compare old and new external routing table and install the
667 difference info zebra/kernel */
paul68980082003-03-25 05:07:42 +0000668 ospf_ase_compare_tables (ospf->new_external_route,
669 ospf->old_external_route);
paul718e3742002-12-13 20:15:29 +0000670
671 /* Delete old external routing table */
paul68980082003-03-25 05:07:42 +0000672 ospf_route_table_free (ospf->old_external_route);
673 ospf->old_external_route = ospf->new_external_route;
674 ospf->new_external_route = route_table_init ();
paul718e3742002-12-13 20:15:29 +0000675 }
676 return 0;
677}
678
679void
paul68980082003-03-25 05:07:42 +0000680ospf_ase_calculate_schedule (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000681{
paul68980082003-03-25 05:07:42 +0000682 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000683 return;
684
paul68980082003-03-25 05:07:42 +0000685 ospf->ase_calc = 1;
paul718e3742002-12-13 20:15:29 +0000686}
687
688void
paul68980082003-03-25 05:07:42 +0000689ospf_ase_calculate_timer_add (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000690{
paul68980082003-03-25 05:07:42 +0000691 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000692 return;
693
paul68980082003-03-25 05:07:42 +0000694 if (! ospf->t_ase_calc)
695 ospf->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer,
696 ospf, OSPF_ASE_CALC_INTERVAL);
paul718e3742002-12-13 20:15:29 +0000697}
698
699void
700ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
701{
702 struct route_node *rn;
703 struct prefix_ipv4 p;
hasso52dc7ee2004-09-23 19:18:23 +0000704 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000705 struct as_external_lsa *al;
706
707 al = (struct as_external_lsa *) lsa->data;
708 p.family = AF_INET;
709 p.prefix = lsa->data->id;
710 p.prefixlen = ip_masklen (al->mask);
711 apply_mask_ipv4 (&p);
712
713 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
714 if ((lst = rn->info) == NULL)
715 rn->info = lst = list_new();
716
717 /* We assume that if LSA is deleted from DB
718 is is also deleted from this RT */
719
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000720 listnode_add (lst, ospf_lsa_lock (lsa)); /* external_lsas lst */
paul718e3742002-12-13 20:15:29 +0000721}
722
723void
724ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
725{
726 struct route_node *rn;
727 struct prefix_ipv4 p;
hasso52dc7ee2004-09-23 19:18:23 +0000728 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000729 struct as_external_lsa *al;
730
731 al = (struct as_external_lsa *) lsa->data;
732 p.family = AF_INET;
733 p.prefix = lsa->data->id;
734 p.prefixlen = ip_masklen (al->mask);
735 apply_mask_ipv4 (&p);
736
737 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
738 lst = rn->info;
paul718e3742002-12-13 20:15:29 +0000739
paul718e3742002-12-13 20:15:29 +0000740 /* XXX lst can be NULL */
741 if (lst) {
742 listnode_delete (lst, lsa);
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000743 ospf_lsa_unlock (&lsa); /* external_lsas list */
paul718e3742002-12-13 20:15:29 +0000744 }
paul718e3742002-12-13 20:15:29 +0000745}
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))
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000759 ospf_lsa_unlock (&lsa); /* external_lsas lst */
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);
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100792 if (rn)
paul718e3742002-12-13 20:15:29 +0000793 {
794 route_unlock_node (rn);
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100795 if (rn->info)
796 return;
paul718e3742002-12-13 20:15:29 +0000797 }
798
paul68980082003-03-25 05:07:42 +0000799 rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000800 assert (rn && rn->info);
801 lsas = rn->info;
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100802 route_unlock_node (rn);
803
paul1eb8ef22005-04-07 07:30:20 +0000804 for (ALL_LIST_ELEMENTS_RO (lsas, node, lsa))
805 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000806
807 /* prepare temporary old routing table for compare */
808 tmp_old = route_table_init ();
paul68980082003-03-25 05:07:42 +0000809 rn = route_node_lookup (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000810 if (rn && rn->info)
811 {
812 rn2 = route_node_get (tmp_old, (struct prefix *) &p);
813 rn2->info = rn->info;
814 }
815
816 /* install changes to zebra */
paul68980082003-03-25 05:07:42 +0000817 ospf_ase_compare_tables (ospf->new_external_route, tmp_old);
paul718e3742002-12-13 20:15:29 +0000818
paul68980082003-03-25 05:07:42 +0000819 /* update ospf->old_external_route table */
paul718e3742002-12-13 20:15:29 +0000820 if (rn && rn->info)
821 ospf_route_free ((struct ospf_route *) rn->info);
822
paul68980082003-03-25 05:07:42 +0000823 rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p);
824 /* if new route exists, install it to ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000825 if (rn2 && rn2->info)
826 {
827 if (!rn)
paul68980082003-03-25 05:07:42 +0000828 rn = route_node_get (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000829 rn->info = rn2->info;
830 }
831 else
832 {
paul68980082003-03-25 05:07:42 +0000833 /* remove route node from ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000834 if (rn)
835 {
836 rn->info = NULL;
837 route_unlock_node (rn);
838 route_unlock_node (rn);
839 }
840 }
841
842 if (rn2)
843 {
paul68980082003-03-25 05:07:42 +0000844 /* rn2->info is stored in route node of ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000845 rn2->info = NULL;
846 route_unlock_node (rn2);
847 route_unlock_node (rn2);
848 }
849
850 route_table_finish (tmp_old);
851}