blob: f9f79e3c16552d6851cc2f6bf75756a489021097 [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
49#define DEBUG
50
51struct ospf_route *
paul68980082003-03-25 05:07:42 +000052ospf_find_asbr_route (struct ospf *ospf,
53 struct route_table *rtrs, struct prefix_ipv4 *asbr)
paul718e3742002-12-13 20:15:29 +000054{
55 struct route_node *rn;
56 struct ospf_route *or, *best = NULL;
hasso52dc7ee2004-09-23 19:18:23 +000057 struct listnode *node;
58 struct list *chosen;
paul718e3742002-12-13 20:15:29 +000059
60 /* Sanity check. */
61 if (rtrs == NULL)
62 return NULL;
63
64 rn = route_node_lookup (rtrs, (struct prefix *) asbr);
65 if (! rn)
66 return NULL;
67
68 route_unlock_node (rn);
69
70 chosen = list_new ();
71
72 /* First try to find intra-area non-bb paths. */
paul68980082003-03-25 05:07:42 +000073 if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE))
paul1eb8ef22005-04-07 07:30:20 +000074 for (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or))
75 if (or->cost < OSPF_LS_INFINITY)
76 if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id) &&
77 or->path_type == OSPF_PATH_INTRA_AREA)
78 listnode_add (chosen, or);
paul718e3742002-12-13 20:15:29 +000079
80 /* If none is found -- look through all. */
81 if (listcount (chosen) == 0)
82 {
83 list_free (chosen);
84 chosen = rn->info;
85 }
86
87 /* Now find the route with least cost. */
paul1eb8ef22005-04-07 07:30:20 +000088 for (ALL_LIST_ELEMENTS_RO (chosen, node, or))
89 if (or->cost < OSPF_LS_INFINITY)
90 {
91 if (best == NULL)
92 best = or;
93 else if (best->cost > or->cost)
94 best = or;
95 else if (best->cost == or->cost &&
96 IPV4_ADDR_CMP (&best->u.std.area_id,
97 &or->u.std.area_id) < 0)
98 best = or;
99 }
paul718e3742002-12-13 20:15:29 +0000100
101 if (chosen != rn->info)
102 list_delete (chosen);
103
104 return best;
105}
106
107struct ospf_route *
108ospf_find_asbr_route_through_area (struct route_table *rtrs,
109 struct prefix_ipv4 *asbr,
110 struct ospf_area *area)
111{
112 struct route_node *rn;
113
114 /* Sanity check. */
115 if (rtrs == NULL)
116 return NULL;
117
118 rn = route_node_lookup (rtrs, (struct prefix *) asbr);
119
120 if (rn)
121 {
hasso52dc7ee2004-09-23 19:18:23 +0000122 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000123 struct ospf_route *or;
124
125 route_unlock_node (rn);
126
paul1eb8ef22005-04-07 07:30:20 +0000127 for (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or))
128 if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id))
129 return or;
paul718e3742002-12-13 20:15:29 +0000130 }
131
132 return NULL;
133}
134
135void
136ospf_ase_complete_direct_routes (struct ospf_route *ro, struct in_addr nexthop)
137{
hasso52dc7ee2004-09-23 19:18:23 +0000138 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000139 struct ospf_path *op;
140
paul1eb8ef22005-04-07 07:30:20 +0000141 for (ALL_LIST_ELEMENTS_RO (ro->paths, node, op))
142 if (op->nexthop.s_addr == 0)
143 op->nexthop.s_addr = nexthop.s_addr;
paul718e3742002-12-13 20:15:29 +0000144}
145
146int
paul68980082003-03-25 05:07:42 +0000147ospf_ase_forward_address_check (struct ospf *ospf, struct in_addr fwd_addr)
paul718e3742002-12-13 20:15:29 +0000148{
hasso52dc7ee2004-09-23 19:18:23 +0000149 struct listnode *ifn;
paul718e3742002-12-13 20:15:29 +0000150 struct ospf_interface *oi;
151
paul1eb8ef22005-04-07 07:30:20 +0000152 for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, ifn, oi))
153 if (if_is_operative (oi->ifp))
154 if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
155 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &fwd_addr))
156 return 0;
paul718e3742002-12-13 20:15:29 +0000157
158 return 1;
159}
160
161/* Calculate ASBR route. */
162struct 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}
241
242struct ospf_route *
243ospf_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 */
paul68980082003-03-25 05:07:42 +0000453 if ((rn = route_node_lookup (ospf->new_table,
paul718e3742002-12-13 20:15:29 +0000454 (struct prefix *) &p)) != NULL
455 && (rn->info != NULL))
456 {
457 if (new)
458 ospf_route_free (new);
459 return 0;
460 }
461
462 /* Find a route to the same dest */
463 /* If there is no route, create new one. */
paul68980082003-03-25 05:07:42 +0000464 if ((rn = route_node_lookup (ospf->new_external_route,
paul718e3742002-12-13 20:15:29 +0000465 (struct prefix *) &p)) == NULL
466 || (or = rn->info) == NULL)
467 {
hassoe40dcce2005-02-21 14:58:42 +0000468 if (IS_DEBUG_OSPF (lsa, LSA))
469 zlog_debug ("Route[External]: Adding a new route %s/%d",
470 inet_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000471
paul68980082003-03-25 05:07:42 +0000472 ospf_route_add (ospf->new_external_route, &p, new, asbr_route);
paul718e3742002-12-13 20:15:29 +0000473
474 if (al->e[0].fwd_addr.s_addr)
475 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
476 return 0;
477 }
478 else
479 {
480 /* (a) Intra-area and inter-area paths are always preferred
481 over AS external paths.
482
483 (b) Type 1 external paths are always preferred over type 2
484 external paths. When all paths are type 2 external
485 paths, the paths with the smallest advertised type 2
486 metric are always preferred. */
paul68980082003-03-25 05:07:42 +0000487 ret = ospf_route_cmp (ospf, new, or);
paul718e3742002-12-13 20:15:29 +0000488
489 /* (c) If the new AS external path is still indistinguishable
490 from the current paths in the N's routing table entry,
491 and RFC1583Compatibility is set to "disabled", select
492 the preferred paths based on the intra-AS paths to the
493 ASBR/forwarding addresses, as specified in Section
494 16.4.1.
495
496 (d) If the new AS external path is still indistinguishable
497 from the current paths in the N's routing table entry,
498 select the preferred path based on a least cost
499 comparison. Type 1 external paths are compared by
500 looking at the sum of the distance to the forwarding
501 address and the advertised type 1 metric (X+Y). Type 2
502 external paths advertising equal type 2 metrics are
503 compared by looking at the distance to the forwarding
504 addresses.
505 */
506 /* New route is better */
507 if (ret < 0)
508 {
hassoe40dcce2005-02-21 14:58:42 +0000509 if (IS_DEBUG_OSPF (lsa, LSA))
510 zlog_debug ("Route[External]: New route is better");
paul718e3742002-12-13 20:15:29 +0000511 ospf_route_subst (rn, new, asbr_route);
512 if (al->e[0].fwd_addr.s_addr)
513 ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr);
514 or = new;
515 new = NULL;
516 }
517 /* Old route is better */
518 else if (ret > 0)
519 {
hassoe40dcce2005-02-21 14:58:42 +0000520 if (IS_DEBUG_OSPF (lsa, LSA))
521 zlog_debug ("Route[External]: Old route is better");
paul718e3742002-12-13 20:15:29 +0000522 /* do nothing */
523 }
524 /* Routes are equal */
525 else
526 {
hassoe40dcce2005-02-21 14:58:42 +0000527 if (IS_DEBUG_OSPF (lsa, LSA))
528 zlog_debug ("Route[External]: Routes are equal");
paul96735ee2003-08-10 02:51:22 +0000529 ospf_route_copy_nexthops (or, asbr_route->paths);
paul718e3742002-12-13 20:15:29 +0000530 if (al->e[0].fwd_addr.s_addr)
531 ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr);
532 }
533 }
534 /* Make sure setting newly calculated ASBR route.*/
535 or->u.ext.asbr = asbr_route;
536 if (new)
537 ospf_route_free (new);
538
539 lsa->route = or;
540 return 0;
541}
542
543int
544ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix,
545 struct ospf_route *newor)
546{
547 struct route_node *rn;
548 struct ospf_route *or;
549 struct ospf_path *op;
550 struct ospf_path *newop;
hasso52dc7ee2004-09-23 19:18:23 +0000551 struct listnode *n1;
552 struct listnode *n2;
paul718e3742002-12-13 20:15:29 +0000553
554 if (! rt || ! prefix)
555 return 0;
556
557 rn = route_node_lookup (rt, prefix);
558 if (! rn)
559 return 0;
560
561 route_unlock_node (rn);
562
563 or = rn->info;
564 if (or->path_type != newor->path_type)
565 return 0;
566
567 switch (or->path_type)
568 {
569 case OSPF_PATH_TYPE1_EXTERNAL:
570 if (or->cost != newor->cost)
571 return 0;
572 break;
573 case OSPF_PATH_TYPE2_EXTERNAL:
574 if ((or->cost != newor->cost) ||
575 (or->u.ext.type2_cost != newor->u.ext.type2_cost))
576 return 0;
577 break;
578 default:
579 assert (0);
580 return 0;
581 }
582
paul96735ee2003-08-10 02:51:22 +0000583 if (or->paths->count != newor->paths->count)
paul718e3742002-12-13 20:15:29 +0000584 return 0;
585
586 /* Check each path. */
paul96735ee2003-08-10 02:51:22 +0000587 for (n1 = listhead (or->paths), n2 = listhead (newor->paths);
paul1eb8ef22005-04-07 07:30:20 +0000588 n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2))
paul718e3742002-12-13 20:15:29 +0000589 {
paul1eb8ef22005-04-07 07:30:20 +0000590 op = listgetdata (n1);
591 newop = listgetdata (n2);
paul718e3742002-12-13 20:15:29 +0000592
593 if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
594 return 0;
595 }
596 return 1;
597}
598
599int
600ospf_ase_compare_tables (struct route_table *new_external_route,
601 struct route_table *old_external_route)
602{
603 struct route_node *rn, *new_rn;
604 struct ospf_route *or;
605
606 /* Remove deleted routes */
607 for (rn = route_top (old_external_route); rn; rn = route_next (rn))
608 if ((or = rn->info))
609 {
610 if (! (new_rn = route_node_lookup (new_external_route, &rn->p)))
611 ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
612 else
613 route_unlock_node (new_rn);
614 }
615
616
617 /* Install new routes */
618 for (rn = route_top (new_external_route); rn; rn = route_next (rn))
619 if ((or = rn->info) != NULL)
620 if (! ospf_ase_route_match_same (old_external_route, &rn->p, or))
621 ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
622
623 return 0;
624}
625
626int
627ospf_ase_calculate_timer (struct thread *t)
628{
629 struct ospf *ospf;
paul68980082003-03-25 05:07:42 +0000630 struct ospf_lsa *lsa;
631 struct route_node *rn;
hasso52dc7ee2004-09-23 19:18:23 +0000632 struct listnode *node;
paul68980082003-03-25 05:07:42 +0000633 struct ospf_area *area;
paul718e3742002-12-13 20:15:29 +0000634
635 ospf = THREAD_ARG (t);
636 ospf->t_ase_calc = NULL;
637
638 if (ospf->ase_calc)
639 {
640 ospf->ase_calc = 0;
641
642 /* Calculate external route for each AS-external-LSA */
paul68980082003-03-25 05:07:42 +0000643 LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
644 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000645
paul718e3742002-12-13 20:15:29 +0000646 /* This version simple adds to the table all NSSA areas */
paul68980082003-03-25 05:07:42 +0000647 if (ospf->anyNSSA)
paul1eb8ef22005-04-07 07:30:20 +0000648 for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area))
paul718e3742002-12-13 20:15:29 +0000649 {
paul718e3742002-12-13 20:15:29 +0000650 if (IS_DEBUG_OSPF_NSSA)
ajse84cc642004-12-08 17:28:56 +0000651 zlog_debug ("ospf_ase_calculate_timer(): looking at area %s",
paul718e3742002-12-13 20:15:29 +0000652 inet_ntoa (area->area_id));
653
654 if (area->external_routing == OSPF_AREA_NSSA)
paul68980082003-03-25 05:07:42 +0000655 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
656 ospf_ase_calculate_route (ospf, lsa);
paul718e3742002-12-13 20:15:29 +0000657 }
paulf2c80652002-12-13 21:44:27 +0000658 /* kevinm: And add the NSSA routes in ospf_top */
paulf6386ee2003-04-07 04:29:27 +0000659 LSDB_LOOP (NSSA_LSDB (ospf),rn,lsa)
660 ospf_ase_calculate_route(ospf,lsa);
paulf2c80652002-12-13 21:44:27 +0000661
paul718e3742002-12-13 20:15:29 +0000662 /* Compare old and new external routing table and install the
663 difference info zebra/kernel */
paul68980082003-03-25 05:07:42 +0000664 ospf_ase_compare_tables (ospf->new_external_route,
665 ospf->old_external_route);
paul718e3742002-12-13 20:15:29 +0000666
667 /* Delete old external routing table */
paul68980082003-03-25 05:07:42 +0000668 ospf_route_table_free (ospf->old_external_route);
669 ospf->old_external_route = ospf->new_external_route;
670 ospf->new_external_route = route_table_init ();
paul718e3742002-12-13 20:15:29 +0000671 }
672 return 0;
673}
674
675void
paul68980082003-03-25 05:07:42 +0000676ospf_ase_calculate_schedule (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000677{
paul68980082003-03-25 05:07:42 +0000678 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000679 return;
680
paul68980082003-03-25 05:07:42 +0000681 ospf->ase_calc = 1;
paul718e3742002-12-13 20:15:29 +0000682}
683
684void
paul68980082003-03-25 05:07:42 +0000685ospf_ase_calculate_timer_add (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +0000686{
paul68980082003-03-25 05:07:42 +0000687 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +0000688 return;
689
paul68980082003-03-25 05:07:42 +0000690 if (! ospf->t_ase_calc)
691 ospf->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer,
692 ospf, OSPF_ASE_CALC_INTERVAL);
paul718e3742002-12-13 20:15:29 +0000693}
694
695void
696ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
697{
698 struct route_node *rn;
699 struct prefix_ipv4 p;
hasso52dc7ee2004-09-23 19:18:23 +0000700 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000701 struct as_external_lsa *al;
702
703 al = (struct as_external_lsa *) lsa->data;
704 p.family = AF_INET;
705 p.prefix = lsa->data->id;
706 p.prefixlen = ip_masklen (al->mask);
707 apply_mask_ipv4 (&p);
708
709 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
710 if ((lst = rn->info) == NULL)
711 rn->info = lst = list_new();
712
713 /* We assume that if LSA is deleted from DB
714 is is also deleted from this RT */
715
716 listnode_add (lst, ospf_lsa_lock (lsa));
717}
718
719void
720ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
721{
722 struct route_node *rn;
723 struct prefix_ipv4 p;
hasso52dc7ee2004-09-23 19:18:23 +0000724 struct list *lst;
paul718e3742002-12-13 20:15:29 +0000725 struct as_external_lsa *al;
726
727 al = (struct as_external_lsa *) lsa->data;
728 p.family = AF_INET;
729 p.prefix = lsa->data->id;
730 p.prefixlen = ip_masklen (al->mask);
731 apply_mask_ipv4 (&p);
732
733 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
734 lst = rn->info;
735#ifdef ORIGINAL_CODING
736 assert (lst);
737
738 listnode_delete (lst, lsa);
739 ospf_lsa_unlock (lsa);
740#else /* ORIGINAL_CODING */
741 /* XXX lst can be NULL */
742 if (lst) {
743 listnode_delete (lst, lsa);
744 ospf_lsa_unlock (lsa);
745 }
746#endif /* ORIGINAL_CODING */
747}
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))
761 ospf_lsa_unlock (lsa);
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);
paul718e3742002-12-13 20:15:29 +0000794 if (rn && rn->info)
795 {
796 route_unlock_node (rn);
797 return;
798 }
799
paul68980082003-03-25 05:07:42 +0000800 rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000801 assert (rn && rn->info);
802 lsas = rn->info;
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}