blob: fe40b10171988d8c15876e75443098dcfdee247d [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
Stephen Hemminger3408afe2009-12-03 19:18:26 +0300159#if 0
paul718e3742002-12-13 20:15:29 +0000160/* 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}
Stephen Hemminger3408afe2009-12-03 19:18:26 +0300240#endif
paul718e3742002-12-13 20:15:29 +0000241
paul4dadc292005-05-06 21:37:42 +0000242static struct ospf_route *
paul718e3742002-12-13 20:15:29 +0000243ospf_ase_calculate_new_route (struct ospf_lsa *lsa,
244 struct ospf_route *asbr_route, u_int32_t metric)
245{
246 struct as_external_lsa *al;
247 struct ospf_route *new;
248
249 al = (struct as_external_lsa *) lsa->data;
250
251 new = ospf_route_new ();
252
253 /* Set redistributed type -- does make sense? */
254 /* new->type = type; */
255 new->id = al->header.id;
256 new->mask = al->mask;
257
258 if (!IS_EXTERNAL_METRIC (al->e[0].tos))
259 {
hassoe40dcce2005-02-21 14:58:42 +0000260 if (IS_DEBUG_OSPF (lsa, LSA))
261 zlog_debug ("Route[External]: type-1 created.");
paul718e3742002-12-13 20:15:29 +0000262 new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
263 new->cost = asbr_route->cost + metric; /* X + Y */
264 }
265 else
266 {
hassoe40dcce2005-02-21 14:58:42 +0000267 if (IS_DEBUG_OSPF (lsa, LSA))
268 zlog_debug ("Route[External]: type-2 created.");
paul718e3742002-12-13 20:15:29 +0000269 new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
270 new->cost = asbr_route->cost; /* X */
271 new->u.ext.type2_cost = metric; /* Y */
272 }
273
274 new->type = OSPF_DESTINATION_NETWORK;
paul718e3742002-12-13 20:15:29 +0000275 new->u.ext.origin = lsa;
276 new->u.ext.tag = ntohl (al->e[0].route_tag);
277 new->u.ext.asbr = asbr_route;
278
279 assert (new != asbr_route);
280
281 return new;
282}
283
284#define OSPF_ASE_CALC_INTERVAL 1
285
286int
paul68980082003-03-25 05:07:42 +0000287ospf_ase_calculate_route (struct ospf *ospf, struct ospf_lsa * lsa)
paul718e3742002-12-13 20:15:29 +0000288{
289 u_int32_t metric;
290 struct as_external_lsa *al;
291 struct ospf_route *asbr_route;
292 struct prefix_ipv4 asbr, p;
293 struct route_node *rn;
294 struct ospf_route *new, *or;
295 int ret;
296
297 assert (lsa);
298 al = (struct as_external_lsa *) lsa->data;
299
paul718e3742002-12-13 20:15:29 +0000300 if (lsa->data->type == OSPF_AS_NSSA_LSA)
301 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000302 zlog_debug ("ospf_ase_calc(): Processing Type-7");
paul718e3742002-12-13 20:15:29 +0000303
304 /* Stay away from any Local Translated Type-7 LSAs */
305 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
306 {
307 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000308 zlog_debug ("ospf_ase_calc(): Rejecting Local Xlt'd");
paul718e3742002-12-13 20:15:29 +0000309 return 0;
310 }
paul718e3742002-12-13 20:15:29 +0000311
hassoe40dcce2005-02-21 14:58:42 +0000312 if (IS_DEBUG_OSPF (lsa, LSA))
313 zlog_debug ("Route[External]: Calculate AS-external-LSA to %s/%d",
314 inet_ntoa (al->header.id), ip_masklen (al->mask));
paul718e3742002-12-13 20:15:29 +0000315 /* (1) If the cost specified by the LSA is LSInfinity, or if the
316 LSA's LS age is equal to MaxAge, then examine the next LSA. */
317 if ((metric = GET_METRIC (al->e[0].metric)) >= OSPF_LS_INFINITY)
318 {
hassoe40dcce2005-02-21 14:58:42 +0000319 if (IS_DEBUG_OSPF (lsa, LSA))
320 zlog_debug ("Route[External]: Metric is OSPF_LS_INFINITY");
paul718e3742002-12-13 20:15:29 +0000321 return 0;
322 }
323 if (IS_LSA_MAXAGE (lsa))
324 {
hassoe40dcce2005-02-21 14:58:42 +0000325 if (IS_DEBUG_OSPF (lsa, LSA))
326 zlog_debug ("Route[External]: AS-external-LSA is MAXAGE");
paul718e3742002-12-13 20:15:29 +0000327 return 0;
328 }
329
330 /* (2) If the LSA was originated by the calculating router itself,
331 examine the next LSA. */
332 if (IS_LSA_SELF (lsa))
333 {
hassoe40dcce2005-02-21 14:58:42 +0000334 if (IS_DEBUG_OSPF (lsa, LSA))
335 zlog_debug ("Route[External]: AS-external-LSA is self originated");
paul718e3742002-12-13 20:15:29 +0000336 return 0;
337 }
338
339 /* (3) Call the destination described by the LSA N. N's address is
340 obtained by masking the LSA's Link State ID with the
341 network/subnet mask contained in the body of the LSA. Look
342 up the routing table entries (potentially one per attached
343 area) for the AS boundary router (ASBR) that originated the
344 LSA. If no entries exist for router ASBR (i.e., ASBR is
345 unreachable), do nothing with this LSA and consider the next
346 in the list. */
347
348 asbr.family = AF_INET;
349 asbr.prefix = al->header.adv_router;
350 asbr.prefixlen = IPV4_MAX_BITLEN;
351 apply_mask_ipv4 (&asbr);
352
paul68980082003-03-25 05:07:42 +0000353 asbr_route = ospf_find_asbr_route (ospf, ospf->new_rtrs, &asbr);
paul718e3742002-12-13 20:15:29 +0000354 if (asbr_route == NULL)
355 {
hassoe40dcce2005-02-21 14:58:42 +0000356 if (IS_DEBUG_OSPF (lsa, LSA))
357 zlog_debug ("Route[External]: Can't find originating ASBR route");
paul718e3742002-12-13 20:15:29 +0000358 return 0;
359 }
360 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
361 {
hassoe40dcce2005-02-21 14:58:42 +0000362 if (IS_DEBUG_OSPF (lsa, LSA))
363 zlog_debug ("Route[External]: Originating router is not an ASBR");
paul718e3742002-12-13 20:15:29 +0000364 return 0;
365 }
366
367 /* Else, this LSA describes an AS external path to destination
368 N. Examine the forwarding address specified in the AS-
369 external-LSA. This indicates the IP address to which
370 packets for the destination should be forwarded. */
371
372 if (al->e[0].fwd_addr.s_addr == 0)
373 {
374 /* If the forwarding address is set to 0.0.0.0, packets should
375 be sent to the ASBR itself. Among the multiple routing table
376 entries for the ASBR, select the preferred entry as follows.
377 If RFC1583Compatibility is set to "disabled", prune the set
378 of routing table entries for the ASBR as described in
379 Section 16.4.1. In any case, among the remaining routing
380 table entries, select the routing table entry with the least
381 cost; when there are multiple least cost routing table
382 entries the entry whose associated area has the largest OSPF
383 Area ID (when considered as an unsigned 32-bit integer) is
384 chosen. */
385
386 /* asbr_route already contains the requested route */
387 }
388 else
389 {
390 /* If the forwarding address is non-zero, look up the
391 forwarding address in the routing table.[24] The matching
392 routing table entry must specify an intra-area or inter-area
393 path; if no such path exists, do nothing with the LSA and
394 consider the next in the list. */
paul68980082003-03-25 05:07:42 +0000395 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
paul718e3742002-12-13 20:15:29 +0000396 {
hassoe40dcce2005-02-21 14:58:42 +0000397 if (IS_DEBUG_OSPF (lsa, LSA))
398 zlog_debug ("Route[External]: Forwarding address is our router "
399 "address");
paul718e3742002-12-13 20:15:29 +0000400 return 0;
401 }
402
403 asbr.family = AF_INET;
404 asbr.prefix = al->e[0].fwd_addr;
405 asbr.prefixlen = IPV4_MAX_BITLEN;
406
paul68980082003-03-25 05:07:42 +0000407 rn = route_node_match (ospf->new_table, (struct prefix *) &asbr);
paul718e3742002-12-13 20:15:29 +0000408
409 if (rn == NULL || (asbr_route = rn->info) == NULL)
410 {
hassoe40dcce2005-02-21 14:58:42 +0000411 if (IS_DEBUG_OSPF (lsa, LSA))
412 zlog_debug ("Route[External]: Can't find route to forwarding "
413 "address");
paul718e3742002-12-13 20:15:29 +0000414 if (rn)
415 route_unlock_node (rn);
416 return 0;
417 }
418
419 route_unlock_node (rn);
420 }
421
422 /* (4) Let X be the cost specified by the preferred routing table
423 entry for the ASBR/forwarding address, and Y the cost
424 specified in the LSA. X is in terms of the link state
425 metric, and Y is a type 1 or 2 external metric. */
426
427
428 /* (5) Look up the routing table entry for the destination N. If
429 no entry exists for N, install the AS external path to N,
430 with next hop equal to the list of next hops to the
431 forwarding address, and advertising router equal to ASBR.
432 If the external metric type is 1, then the path-type is set
433 to type 1 external and the cost is equal to X+Y. If the
434 external metric type is 2, the path-type is set to type 2
435 external, the link state component of the route's cost is X,
436 and the type 2 cost is Y. */
437 new = ospf_ase_calculate_new_route (lsa, asbr_route, metric);
438
439 /* (6) Compare the AS external path described by the LSA with the
440 existing paths in N's routing table entry, as follows. If
441 the new path is preferred, it replaces the present paths in
442 N's routing table entry. If the new path is of equal
443 preference, it is added to N's routing table entry's list of
444 paths. */
445
446 /* Set prefix. */
447 p.family = AF_INET;
448 p.prefix = al->header.id;
449 p.prefixlen = ip_masklen (al->mask);
450
451 /* if there is a Intra/Inter area route to the N
452 do not install external route */
Paul Jakmae8f22262010-04-13 22:43:34 +0100453 if ((rn = route_node_lookup (ospf->new_table,
454 (struct prefix *) &p)))
paul718e3742002-12-13 20:15:29 +0000455 {
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100456 route_unlock_node(rn);
457 if (rn->info == NULL)
458 zlog_info ("Route[External]: rn->info NULL");
paul718e3742002-12-13 20:15:29 +0000459 if (new)
460 ospf_route_free (new);
461 return 0;
462 }
paul718e3742002-12-13 20:15:29 +0000463 /* Find a route to the same dest */
464 /* If there is no route, create new one. */
Paul Jakmae8f22262010-04-13 22:43:34 +0100465 if ((rn = route_node_lookup (ospf->new_external_route,
466 (struct prefix *) &p)))
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100467 route_unlock_node(rn);
468
469 if (!rn || (or = rn->info) == NULL)
paul718e3742002-12-13 20:15:29 +0000470 {
hassoe40dcce2005-02-21 14:58:42 +0000471 if (IS_DEBUG_OSPF (lsa, LSA))
472 zlog_debug ("Route[External]: Adding a new route %s/%d",
473 inet_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000474
paul68980082003-03-25 05:07:42 +0000475 ospf_route_add (ospf->new_external_route, &p, new, asbr_route);
paul718e3742002-12-13 20:15:29 +0000476
477 if (al->e[0].fwd_addr.s_addr)
478 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
479 return 0;
480 }
481 else
482 {
483 /* (a) Intra-area and inter-area paths are always preferred
484 over AS external paths.
485
486 (b) Type 1 external paths are always preferred over type 2
487 external paths. When all paths are type 2 external
488 paths, the paths with the smallest advertised type 2
489 metric are always preferred. */
paul68980082003-03-25 05:07:42 +0000490 ret = ospf_route_cmp (ospf, new, or);
paul718e3742002-12-13 20:15:29 +0000491
492 /* (c) If the new AS external path is still indistinguishable
493 from the current paths in the N's routing table entry,
494 and RFC1583Compatibility is set to "disabled", select
495 the preferred paths based on the intra-AS paths to the
496 ASBR/forwarding addresses, as specified in Section
497 16.4.1.
498
499 (d) If the new AS external path is still indistinguishable
500 from the current paths in the N's routing table entry,
501 select the preferred path based on a least cost
502 comparison. Type 1 external paths are compared by
503 looking at the sum of the distance to the forwarding
504 address and the advertised type 1 metric (X+Y). Type 2
505 external paths advertising equal type 2 metrics are
506 compared by looking at the distance to the forwarding
507 addresses.
508 */
509 /* New route is better */
510 if (ret < 0)
511 {
hassoe40dcce2005-02-21 14:58:42 +0000512 if (IS_DEBUG_OSPF (lsa, LSA))
513 zlog_debug ("Route[External]: New route is better");
paul718e3742002-12-13 20:15:29 +0000514 ospf_route_subst (rn, new, asbr_route);
515 if (al->e[0].fwd_addr.s_addr)
516 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
517 or = new;
518 new = NULL;
519 }
520 /* Old route is better */
521 else if (ret > 0)
522 {
hassoe40dcce2005-02-21 14:58:42 +0000523 if (IS_DEBUG_OSPF (lsa, LSA))
524 zlog_debug ("Route[External]: Old route is better");
paul718e3742002-12-13 20:15:29 +0000525 /* do nothing */
526 }
527 /* Routes are equal */
528 else
529 {
hassoe40dcce2005-02-21 14:58:42 +0000530 if (IS_DEBUG_OSPF (lsa, LSA))
531 zlog_debug ("Route[External]: Routes are equal");
paul96735ee2003-08-10 02:51:22 +0000532 ospf_route_copy_nexthops (or, asbr_route->paths);
paul718e3742002-12-13 20:15:29 +0000533 if (al->e[0].fwd_addr.s_addr)
534 ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr);
535 }
536 }
537 /* Make sure setting newly calculated ASBR route.*/
538 or->u.ext.asbr = asbr_route;
539 if (new)
540 ospf_route_free (new);
541
542 lsa->route = or;
543 return 0;
544}
545
paul4dadc292005-05-06 21:37:42 +0000546static int
paul718e3742002-12-13 20:15:29 +0000547ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix,
548 struct ospf_route *newor)
549{
550 struct route_node *rn;
551 struct ospf_route *or;
552 struct ospf_path *op;
553 struct ospf_path *newop;
hasso52dc7ee2004-09-23 19:18:23 +0000554 struct listnode *n1;
555 struct listnode *n2;
paul718e3742002-12-13 20:15:29 +0000556
557 if (! rt || ! prefix)
558 return 0;
559
560 rn = route_node_lookup (rt, prefix);
561 if (! rn)
562 return 0;
563
564 route_unlock_node (rn);
565
566 or = rn->info;
567 if (or->path_type != newor->path_type)
568 return 0;
569
570 switch (or->path_type)
571 {
572 case OSPF_PATH_TYPE1_EXTERNAL:
573 if (or->cost != newor->cost)
574 return 0;
575 break;
576 case OSPF_PATH_TYPE2_EXTERNAL:
577 if ((or->cost != newor->cost) ||
578 (or->u.ext.type2_cost != newor->u.ext.type2_cost))
579 return 0;
580 break;
581 default:
582 assert (0);
583 return 0;
584 }
585
paul96735ee2003-08-10 02:51:22 +0000586 if (or->paths->count != newor->paths->count)
paul718e3742002-12-13 20:15:29 +0000587 return 0;
588
589 /* Check each path. */
paul96735ee2003-08-10 02:51:22 +0000590 for (n1 = listhead (or->paths), n2 = listhead (newor->paths);
paul1eb8ef22005-04-07 07:30:20 +0000591 n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2))
paul718e3742002-12-13 20:15:29 +0000592 {
paul1eb8ef22005-04-07 07:30:20 +0000593 op = listgetdata (n1);
594 newop = listgetdata (n2);
paul718e3742002-12-13 20:15:29 +0000595
596 if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
597 return 0;
Joakim Tjernlunda8ba8472009-07-27 12:42:34 +0200598 if (op->ifindex != newop->ifindex)
Joakim Tjernlund77a1c4e2009-02-01 11:12:11 +0100599 return 0;
paul718e3742002-12-13 20:15:29 +0000600 }
Christian Franke5958b8f2016-10-01 04:06:03 +0200601
602 if (or->u.ext.tag != newor->u.ext.tag)
603 return 0;
604
paul718e3742002-12-13 20:15:29 +0000605 return 1;
606}
607
paul4dadc292005-05-06 21:37:42 +0000608static int
paul718e3742002-12-13 20:15:29 +0000609ospf_ase_compare_tables (struct route_table *new_external_route,
610 struct route_table *old_external_route)
611{
612 struct route_node *rn, *new_rn;
613 struct ospf_route *or;
614
615 /* Remove deleted routes */
616 for (rn = route_top (old_external_route); rn; rn = route_next (rn))
617 if ((or = rn->info))
618 {
619 if (! (new_rn = route_node_lookup (new_external_route, &rn->p)))
620 ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
621 else
622 route_unlock_node (new_rn);
623 }
624
625
626 /* Install new routes */
627 for (rn = route_top (new_external_route); rn; rn = route_next (rn))
628 if ((or = rn->info) != NULL)
629 if (! ospf_ase_route_match_same (old_external_route, &rn->p, or))
630 ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
631
632 return 0;
633}
634
paul4dadc292005-05-06 21:37:42 +0000635static int
paul718e3742002-12-13 20:15:29 +0000636ospf_ase_calculate_timer (struct thread *t)
637{
638 struct ospf *ospf;
paul68980082003-03-25 05:07:42 +0000639 struct ospf_lsa *lsa;
640 struct route_node *rn;
hasso52dc7ee2004-09-23 19:18:23 +0000641 struct listnode *node;
paul68980082003-03-25 05:07:42 +0000642 struct ospf_area *area;
Dinesh G Dutt50f38b32014-09-30 12:53:28 -0700643 struct timeval start_time, stop_time;
paul718e3742002-12-13 20:15:29 +0000644
645 ospf = THREAD_ARG (t);
646 ospf->t_ase_calc = NULL;
647
648 if (ospf->ase_calc)
649 {
650 ospf->ase_calc = 0;
651
Dinesh G Dutt50f38b32014-09-30 12:53:28 -0700652 quagga_gettime(QUAGGA_CLK_MONOTONIC, &start_time);
653
paul718e3742002-12-13 20:15:29 +0000654 /* Calculate external route for each AS-external-LSA */
paul68980082003-03-25 05:07:42 +0000655 LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
656 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000657
paul718e3742002-12-13 20:15:29 +0000658 /* This version simple adds to the table all NSSA areas */
paul68980082003-03-25 05:07:42 +0000659 if (ospf->anyNSSA)
paul1eb8ef22005-04-07 07:30:20 +0000660 for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area))
paul718e3742002-12-13 20:15:29 +0000661 {
paul718e3742002-12-13 20:15:29 +0000662 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000663 zlog_debug ("ospf_ase_calculate_timer(): looking at area %s",
paul718e3742002-12-13 20:15:29 +0000664 inet_ntoa (area->area_id));
665
666 if (area->external_routing == OSPF_AREA_NSSA)
paul68980082003-03-25 05:07:42 +0000667 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
668 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000669 }
paulf2c80652002-12-13 21:44:27 +0000670 /* kevinm: And add the NSSA routes in ospf_top */
paulf6386ee2003-04-07 04:29:27 +0000671 LSDB_LOOP (NSSA_LSDB (ospf),rn,lsa)
672 ospf_ase_calculate_route(ospf,lsa);
paulf2c80652002-12-13 21:44:27 +0000673
paul718e3742002-12-13 20:15:29 +0000674 /* Compare old and new external routing table and install the
675 difference info zebra/kernel */
paul68980082003-03-25 05:07:42 +0000676 ospf_ase_compare_tables (ospf->new_external_route,
677 ospf->old_external_route);
paul718e3742002-12-13 20:15:29 +0000678
679 /* Delete old external routing table */
paul68980082003-03-25 05:07:42 +0000680 ospf_route_table_free (ospf->old_external_route);
681 ospf->old_external_route = ospf->new_external_route;
682 ospf->new_external_route = route_table_init ();
Dinesh G Dutt50f38b32014-09-30 12:53:28 -0700683
684 quagga_gettime(QUAGGA_CLK_MONOTONIC, &stop_time);
685
David Lamparteref008d22015-03-03 08:48:11 +0100686 zlog_info ("SPF Processing Time(usecs): External Routes: %lld\n",
687 (stop_time.tv_sec - start_time.tv_sec)*1000000LL+
Dinesh G Dutt50f38b32014-09-30 12:53:28 -0700688 (stop_time.tv_usec - start_time.tv_usec));
paul718e3742002-12-13 20:15:29 +0000689 }
690 return 0;
691}
692
693void
paul68980082003-03-25 05:07:42 +0000694ospf_ase_calculate_schedule (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000695{
paul68980082003-03-25 05:07:42 +0000696 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000697 return;
698
paul68980082003-03-25 05:07:42 +0000699 ospf->ase_calc = 1;
paul718e3742002-12-13 20:15:29 +0000700}
701
702void
paul68980082003-03-25 05:07:42 +0000703ospf_ase_calculate_timer_add (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000704{
paul68980082003-03-25 05:07:42 +0000705 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000706 return;
707
paul68980082003-03-25 05:07:42 +0000708 if (! ospf->t_ase_calc)
709 ospf->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer,
710 ospf, OSPF_ASE_CALC_INTERVAL);
paul718e3742002-12-13 20:15:29 +0000711}
712
713void
714ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
715{
716 struct route_node *rn;
717 struct prefix_ipv4 p;
hasso52dc7ee2004-09-23 19:18:23 +0000718 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000719 struct as_external_lsa *al;
720
721 al = (struct as_external_lsa *) lsa->data;
722 p.family = AF_INET;
723 p.prefix = lsa->data->id;
724 p.prefixlen = ip_masklen (al->mask);
725 apply_mask_ipv4 (&p);
726
727 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
728 if ((lst = rn->info) == NULL)
729 rn->info = lst = list_new();
Joakim Tjernlundfc363cd2010-03-08 13:58:12 +0100730 else
731 route_unlock_node (rn);
paul718e3742002-12-13 20:15:29 +0000732
733 /* We assume that if LSA is deleted from DB
734 is is also deleted from this RT */
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000735 listnode_add (lst, ospf_lsa_lock (lsa)); /* external_lsas lst */
paul718e3742002-12-13 20:15:29 +0000736}
737
738void
739ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
740{
741 struct route_node *rn;
742 struct prefix_ipv4 p;
hasso52dc7ee2004-09-23 19:18:23 +0000743 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000744 struct as_external_lsa *al;
745
746 al = (struct as_external_lsa *) lsa->data;
747 p.family = AF_INET;
748 p.prefix = lsa->data->id;
749 p.prefixlen = ip_masklen (al->mask);
750 apply_mask_ipv4 (&p);
751
Joakim Tjernlundfc363cd2010-03-08 13:58:12 +0100752 rn = route_node_lookup (top->external_lsas, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000753
Joakim Tjernlundfc363cd2010-03-08 13:58:12 +0100754 if (rn) {
755 lst = rn->info;
paul718e3742002-12-13 20:15:29 +0000756 listnode_delete (lst, lsa);
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000757 ospf_lsa_unlock (&lsa); /* external_lsas list */
Joakim Tjernlundfc363cd2010-03-08 13:58:12 +0100758 route_unlock_node (rn);
paul718e3742002-12-13 20:15:29 +0000759 }
paul718e3742002-12-13 20:15:29 +0000760}
761
762void
763ospf_ase_external_lsas_finish (struct route_table *rt)
764{
765 struct route_node *rn;
766 struct ospf_lsa *lsa;
hasso52dc7ee2004-09-23 19:18:23 +0000767 struct list *lst;
paul1eb8ef22005-04-07 07:30:20 +0000768 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000769
770 for (rn = route_top (rt); rn; rn = route_next (rn))
771 if ((lst = rn->info) != NULL)
772 {
paul1eb8ef22005-04-07 07:30:20 +0000773 for (ALL_LIST_ELEMENTS (lst, node, nnode, lsa))
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000774 ospf_lsa_unlock (&lsa); /* external_lsas lst */
paul718e3742002-12-13 20:15:29 +0000775 list_delete (lst);
776 }
paul1eb8ef22005-04-07 07:30:20 +0000777
paul718e3742002-12-13 20:15:29 +0000778 route_table_finish (rt);
779}
780
781void
paul68980082003-03-25 05:07:42 +0000782ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa)
paul718e3742002-12-13 20:15:29 +0000783{
hasso52dc7ee2004-09-23 19:18:23 +0000784 struct list *lsas;
785 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000786 struct route_node *rn, *rn2;
787 struct prefix_ipv4 p;
788 struct route_table *tmp_old;
789 struct as_external_lsa *al;
790
791 al = (struct as_external_lsa *) lsa->data;
792 p.family = AF_INET;
793 p.prefix = lsa->data->id;
794 p.prefixlen = ip_masklen (al->mask);
795 apply_mask_ipv4 (&p);
796
797 /* if new_table is NULL, there was no spf calculation, thus
798 incremental update is unneeded */
paul68980082003-03-25 05:07:42 +0000799 if (!ospf->new_table)
paul718e3742002-12-13 20:15:29 +0000800 return;
801
802 /* If there is already an intra-area or inter-area route
803 to the destination, no recalculation is necessary
804 (internal routes take precedence). */
805
paul68980082003-03-25 05:07:42 +0000806 rn = route_node_lookup (ospf->new_table, (struct prefix *) &p);
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100807 if (rn)
paul718e3742002-12-13 20:15:29 +0000808 {
809 route_unlock_node (rn);
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100810 if (rn->info)
811 return;
paul718e3742002-12-13 20:15:29 +0000812 }
813
paul68980082003-03-25 05:07:42 +0000814 rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p);
Paul Jakmae8f22262010-04-13 22:43:34 +0100815 assert (rn);
816 assert (rn->info);
paul718e3742002-12-13 20:15:29 +0000817 lsas = rn->info;
Joakim Tjernlund3d8617b2009-02-04 15:05:19 +0100818 route_unlock_node (rn);
819
paul1eb8ef22005-04-07 07:30:20 +0000820 for (ALL_LIST_ELEMENTS_RO (lsas, node, lsa))
821 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000822
823 /* prepare temporary old routing table for compare */
824 tmp_old = route_table_init ();
paul68980082003-03-25 05:07:42 +0000825 rn = route_node_lookup (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000826 if (rn && rn->info)
827 {
828 rn2 = route_node_get (tmp_old, (struct prefix *) &p);
829 rn2->info = rn->info;
Joakim Tjernlundd5643f52010-03-08 13:58:10 +0100830 route_unlock_node (rn);
paul718e3742002-12-13 20:15:29 +0000831 }
832
833 /* install changes to zebra */
paul68980082003-03-25 05:07:42 +0000834 ospf_ase_compare_tables (ospf->new_external_route, tmp_old);
paul718e3742002-12-13 20:15:29 +0000835
paul68980082003-03-25 05:07:42 +0000836 /* update ospf->old_external_route table */
paul718e3742002-12-13 20:15:29 +0000837 if (rn && rn->info)
838 ospf_route_free ((struct ospf_route *) rn->info);
839
paul68980082003-03-25 05:07:42 +0000840 rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p);
841 /* if new route exists, install it to ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000842 if (rn2 && rn2->info)
843 {
844 if (!rn)
paul68980082003-03-25 05:07:42 +0000845 rn = route_node_get (ospf->old_external_route, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000846 rn->info = rn2->info;
847 }
848 else
849 {
paul68980082003-03-25 05:07:42 +0000850 /* remove route node from ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000851 if (rn)
852 {
853 rn->info = NULL;
854 route_unlock_node (rn);
paul718e3742002-12-13 20:15:29 +0000855 }
856 }
857
858 if (rn2)
859 {
paul68980082003-03-25 05:07:42 +0000860 /* rn2->info is stored in route node of ospf->old_external_route */
paul718e3742002-12-13 20:15:29 +0000861 rn2->info = NULL;
862 route_unlock_node (rn2);
863 route_unlock_node (rn2);
864 }
865
866 route_table_finish (tmp_old);
867}