]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_ase.c
*: add indent control files
[mirror_frr.git] / ospfd / ospf_ase.c
CommitLineData
718e3744 1/*
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 *
896014f4
DL
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
718e3744 20 */
21
22#include <zebra.h>
23
24#include "thread.h"
25#include "memory.h"
26#include "hash.h"
27#include "linklist.h"
28#include "prefix.h"
29#include "if.h"
30#include "table.h"
31#include "vty.h"
32#include "log.h"
33
34#include "ospfd/ospfd.h"
35#include "ospfd/ospf_interface.h"
36#include "ospfd/ospf_ism.h"
37#include "ospfd/ospf_asbr.h"
38#include "ospfd/ospf_lsa.h"
39#include "ospfd/ospf_lsdb.h"
40#include "ospfd/ospf_neighbor.h"
41#include "ospfd/ospf_nsm.h"
42#include "ospfd/ospf_spf.h"
43#include "ospfd/ospf_route.h"
44#include "ospfd/ospf_ase.h"
45#include "ospfd/ospf_zebra.h"
46#include "ospfd/ospf_dump.h"
47
718e3744 48struct ospf_route *
68980084 49ospf_find_asbr_route (struct ospf *ospf,
50 struct route_table *rtrs, struct prefix_ipv4 *asbr)
718e3744 51{
52 struct route_node *rn;
53 struct ospf_route *or, *best = NULL;
52dc7ee6 54 struct listnode *node;
55 struct list *chosen;
718e3744 56
57 /* Sanity check. */
58 if (rtrs == NULL)
59 return NULL;
60
61 rn = route_node_lookup (rtrs, (struct prefix *) asbr);
62 if (! rn)
63 return NULL;
64
65 route_unlock_node (rn);
66
67 chosen = list_new ();
68
69 /* First try to find intra-area non-bb paths. */
68980084 70 if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE))
1eb8ef25 71 for (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or))
72 if (or->cost < OSPF_LS_INFINITY)
73 if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id) &&
74 or->path_type == OSPF_PATH_INTRA_AREA)
75 listnode_add (chosen, or);
718e3744 76
77 /* If none is found -- look through all. */
78 if (listcount (chosen) == 0)
79 {
80 list_free (chosen);
81 chosen = rn->info;
82 }
83
84 /* Now find the route with least cost. */
1eb8ef25 85 for (ALL_LIST_ELEMENTS_RO (chosen, node, or))
86 if (or->cost < OSPF_LS_INFINITY)
87 {
88 if (best == NULL)
89 best = or;
90 else if (best->cost > or->cost)
91 best = or;
92 else if (best->cost == or->cost &&
93 IPV4_ADDR_CMP (&best->u.std.area_id,
94 &or->u.std.area_id) < 0)
95 best = or;
96 }
718e3744 97
98 if (chosen != rn->info)
99 list_delete (chosen);
100
101 return best;
102}
103
104struct ospf_route *
105ospf_find_asbr_route_through_area (struct route_table *rtrs,
106 struct prefix_ipv4 *asbr,
107 struct ospf_area *area)
108{
109 struct route_node *rn;
110
111 /* Sanity check. */
112 if (rtrs == NULL)
113 return NULL;
114
115 rn = route_node_lookup (rtrs, (struct prefix *) asbr);
116
117 if (rn)
118 {
52dc7ee6 119 struct listnode *node;
718e3744 120 struct ospf_route *or;
121
122 route_unlock_node (rn);
123
1eb8ef25 124 for (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or))
125 if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id))
126 return or;
718e3744 127 }
128
129 return NULL;
130}
131
4dadc291 132static void
718e3744 133ospf_ase_complete_direct_routes (struct ospf_route *ro, struct in_addr nexthop)
134{
52dc7ee6 135 struct listnode *node;
718e3744 136 struct ospf_path *op;
137
1eb8ef25 138 for (ALL_LIST_ELEMENTS_RO (ro->paths, node, op))
139 if (op->nexthop.s_addr == 0)
140 op->nexthop.s_addr = nexthop.s_addr;
718e3744 141}
142
4dadc291 143static int
68980084 144ospf_ase_forward_address_check (struct ospf *ospf, struct in_addr fwd_addr)
718e3744 145{
52dc7ee6 146 struct listnode *ifn;
718e3744 147 struct ospf_interface *oi;
148
1eb8ef25 149 for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, ifn, oi))
150 if (if_is_operative (oi->ifp))
151 if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
152 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &fwd_addr))
153 return 0;
718e3744 154
155 return 1;
156}
157
3408afe2 158#if 0
718e3744 159/* Calculate ASBR route. */
4dadc291 160static struct ospf_route *
68980084 161ospf_ase_calculate_asbr_route (struct ospf *ospf,
162 struct route_table *rt_network,
718e3744 163 struct route_table *rt_router,
164 struct as_external_lsa *al)
165{
166 struct prefix_ipv4 asbr;
167 struct ospf_route *asbr_route;
168 struct route_node *rn;
169
170 /* Find ASBR route from Router routing table. */
171 asbr.family = AF_INET;
172 asbr.prefix = al->header.adv_router;
173 asbr.prefixlen = IPV4_MAX_BITLEN;
174 apply_mask_ipv4 (&asbr);
175
68980084 176 asbr_route = ospf_find_asbr_route (ospf, rt_router, &asbr);
718e3744 177
178 if (asbr_route == NULL)
179 {
e40dcce1 180 if (IS_DEBUG_OSPF (lsa, LSA))
181 zlog_debug ("ospf_ase_calculate(): Route to ASBR %s not found",
182 inet_ntoa (asbr.prefix));
718e3744 183 return NULL;
184 }
185
186 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
187 {
e40dcce1 188 if (IS_DEBUG_OSPF (lsa, LSA))
189 zlog_debug ("ospf_ase_calculate(): Originating router is not an ASBR");
718e3744 190 return NULL;
191 }
192
193 if (al->e[0].fwd_addr.s_addr != 0)
194 {
e40dcce1 195 if (IS_DEBUG_OSPF (lsa, LSA))
196 zlog_debug ("ospf_ase_calculate(): "
197 "Forwarding address is not 0.0.0.0.");
718e3744 198
68980084 199 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
718e3744 200 {
e40dcce1 201 if (IS_DEBUG_OSPF (lsa, LSA))
202 zlog_debug ("ospf_ase_calculate(): "
203 "Forwarding address is one of our addresses, Ignore.");
718e3744 204 return NULL;
205 }
206
e40dcce1 207 if (IS_DEBUG_OSPF (lsa, LSA))
208 zlog_debug ("ospf_ase_calculate(): "
209 "Looking up in the Network Routing Table.");
718e3744 210
211 /* Looking up the path to the fwd_addr from Network route. */
212 asbr.family = AF_INET;
213 asbr.prefix = al->e[0].fwd_addr;
214 asbr.prefixlen = IPV4_MAX_BITLEN;
215
216 rn = route_node_match (rt_network, (struct prefix *) &asbr);
217
218 if (rn == NULL)
219 {
e40dcce1 220 if (IS_DEBUG_OSPF (lsa, LSA))
221 zlog_debug ("ospf_ase_calculate(): "
222 "Couldn't find a route to the forwarding address.");
718e3744 223 return NULL;
224 }
225
226 route_unlock_node (rn);
227
228 if ((asbr_route = rn->info) == NULL)
229 {
e40dcce1 230 if (IS_DEBUG_OSPF (lsa, LSA))
231 zlog_debug ("ospf_ase_calculate(): "
232 "Somehow OSPF route to ASBR is lost");
718e3744 233 return NULL;
234 }
235 }
236
237 return asbr_route;
238}
3408afe2 239#endif
718e3744 240
4dadc291 241static struct ospf_route *
718e3744 242ospf_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 {
e40dcce1 259 if (IS_DEBUG_OSPF (lsa, LSA))
260 zlog_debug ("Route[External]: type-1 created.");
718e3744 261 new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
262 new->cost = asbr_route->cost + metric; /* X + Y */
263 }
264 else
265 {
e40dcce1 266 if (IS_DEBUG_OSPF (lsa, LSA))
267 zlog_debug ("Route[External]: type-2 created.");
718e3744 268 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;
718e3744 274 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
68980084 286ospf_ase_calculate_route (struct ospf *ospf, struct ospf_lsa * lsa)
718e3744 287{
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
718e3744 299 if (lsa->data->type == OSPF_AS_NSSA_LSA)
300 if (IS_DEBUG_OSPF_NSSA)
e84cc647 301 zlog_debug ("ospf_ase_calc(): Processing Type-7");
718e3744 302
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)
e84cc647 307 zlog_debug ("ospf_ase_calc(): Rejecting Local Xlt'd");
718e3744 308 return 0;
309 }
718e3744 310
e40dcce1 311 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));
718e3744 314 /* (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 {
e40dcce1 318 if (IS_DEBUG_OSPF (lsa, LSA))
319 zlog_debug ("Route[External]: Metric is OSPF_LS_INFINITY");
718e3744 320 return 0;
321 }
322 if (IS_LSA_MAXAGE (lsa))
323 {
e40dcce1 324 if (IS_DEBUG_OSPF (lsa, LSA))
325 zlog_debug ("Route[External]: AS-external-LSA is MAXAGE");
718e3744 326 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 {
e40dcce1 333 if (IS_DEBUG_OSPF (lsa, LSA))
334 zlog_debug ("Route[External]: AS-external-LSA is self originated");
718e3744 335 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
68980084 352 asbr_route = ospf_find_asbr_route (ospf, ospf->new_rtrs, &asbr);
718e3744 353 if (asbr_route == NULL)
354 {
e40dcce1 355 if (IS_DEBUG_OSPF (lsa, LSA))
356 zlog_debug ("Route[External]: Can't find originating ASBR route");
718e3744 357 return 0;
358 }
359 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
360 {
e40dcce1 361 if (IS_DEBUG_OSPF (lsa, LSA))
362 zlog_debug ("Route[External]: Originating router is not an ASBR");
718e3744 363 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. */
68980084 394 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
718e3744 395 {
e40dcce1 396 if (IS_DEBUG_OSPF (lsa, LSA))
397 zlog_debug ("Route[External]: Forwarding address is our router "
398 "address");
718e3744 399 return 0;
400 }
401
402 asbr.family = AF_INET;
403 asbr.prefix = al->e[0].fwd_addr;
404 asbr.prefixlen = IPV4_MAX_BITLEN;
405
68980084 406 rn = route_node_match (ospf->new_table, (struct prefix *) &asbr);
718e3744 407
408 if (rn == NULL || (asbr_route = rn->info) == NULL)
409 {
e40dcce1 410 if (IS_DEBUG_OSPF (lsa, LSA))
411 zlog_debug ("Route[External]: Can't find route to forwarding "
412 "address");
718e3744 413 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 */
e8f22261
PJ
452 if ((rn = route_node_lookup (ospf->new_table,
453 (struct prefix *) &p)))
718e3744 454 {
3d8617b8
JT
455 route_unlock_node(rn);
456 if (rn->info == NULL)
457 zlog_info ("Route[External]: rn->info NULL");
718e3744 458 if (new)
459 ospf_route_free (new);
460 return 0;
461 }
718e3744 462 /* Find a route to the same dest */
463 /* If there is no route, create new one. */
e8f22261
PJ
464 if ((rn = route_node_lookup (ospf->new_external_route,
465 (struct prefix *) &p)))
3d8617b8
JT
466 route_unlock_node(rn);
467
468 if (!rn || (or = rn->info) == NULL)
718e3744 469 {
e40dcce1 470 if (IS_DEBUG_OSPF (lsa, LSA))
471 zlog_debug ("Route[External]: Adding a new route %s/%d",
472 inet_ntoa (p.prefix), p.prefixlen);
718e3744 473
68980084 474 ospf_route_add (ospf->new_external_route, &p, new, asbr_route);
718e3744 475
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. */
68980084 489 ret = ospf_route_cmp (ospf, new, or);
718e3744 490
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 {
e40dcce1 511 if (IS_DEBUG_OSPF (lsa, LSA))
512 zlog_debug ("Route[External]: New route is better");
718e3744 513 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 {
e40dcce1 522 if (IS_DEBUG_OSPF (lsa, LSA))
523 zlog_debug ("Route[External]: Old route is better");
718e3744 524 /* do nothing */
525 }
526 /* Routes are equal */
527 else
528 {
e40dcce1 529 if (IS_DEBUG_OSPF (lsa, LSA))
530 zlog_debug ("Route[External]: Routes are equal");
96735eea 531 ospf_route_copy_nexthops (or, asbr_route->paths);
718e3744 532 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
4dadc291 545static int
718e3744 546ospf_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;
52dc7ee6 553 struct listnode *n1;
554 struct listnode *n2;
718e3744 555
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
96735eea 585 if (or->paths->count != newor->paths->count)
718e3744 586 return 0;
587
588 /* Check each path. */
96735eea 589 for (n1 = listhead (or->paths), n2 = listhead (newor->paths);
1eb8ef25 590 n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2))
718e3744 591 {
1eb8ef25 592 op = listgetdata (n1);
593 newop = listgetdata (n2);
718e3744 594
595 if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
596 return 0;
a8ba847f 597 if (op->ifindex != newop->ifindex)
77a1c4e0 598 return 0;
718e3744 599 }
e7331dea
CF
600
601 if (or->u.ext.tag != newor->u.ext.tag)
602 return 0;
603
718e3744 604 return 1;
605}
606
4dadc291 607static int
718e3744 608ospf_ase_compare_tables (struct route_table *new_external_route,
609 struct route_table *old_external_route)
610{
611 struct route_node *rn, *new_rn;
612 struct ospf_route *or;
613
614 /* Remove deleted routes */
615 for (rn = route_top (old_external_route); rn; rn = route_next (rn))
616 if ((or = rn->info))
617 {
618 if (! (new_rn = route_node_lookup (new_external_route, &rn->p)))
619 ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
620 else
621 route_unlock_node (new_rn);
622 }
623
624
625 /* Install new routes */
626 for (rn = route_top (new_external_route); rn; rn = route_next (rn))
627 if ((or = rn->info) != NULL)
628 if (! ospf_ase_route_match_same (old_external_route, &rn->p, or))
629 ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
630
631 return 0;
632}
633
4dadc291 634static int
718e3744 635ospf_ase_calculate_timer (struct thread *t)
636{
637 struct ospf *ospf;
68980084 638 struct ospf_lsa *lsa;
639 struct route_node *rn;
52dc7ee6 640 struct listnode *node;
68980084 641 struct ospf_area *area;
cf744958 642 struct timeval start_time, stop_time;
718e3744 643
644 ospf = THREAD_ARG (t);
645 ospf->t_ase_calc = NULL;
646
647 if (ospf->ase_calc)
648 {
649 ospf->ase_calc = 0;
650
cf672a86 651 monotime(&start_time);
cf744958 652
718e3744 653 /* Calculate external route for each AS-external-LSA */
68980084 654 LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
655 ospf_ase_calculate_route (ospf, lsa);
718e3744 656
718e3744 657 /* This version simple adds to the table all NSSA areas */
68980084 658 if (ospf->anyNSSA)
1eb8ef25 659 for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area))
718e3744 660 {
718e3744 661 if (IS_DEBUG_OSPF_NSSA)
e84cc647 662 zlog_debug ("ospf_ase_calculate_timer(): looking at area %s",
718e3744 663 inet_ntoa (area->area_id));
664
665 if (area->external_routing == OSPF_AREA_NSSA)
68980084 666 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
667 ospf_ase_calculate_route (ospf, lsa);
718e3744 668 }
f2c80652 669 /* kevinm: And add the NSSA routes in ospf_top */
f6386eeb 670 LSDB_LOOP (NSSA_LSDB (ospf),rn,lsa)
671 ospf_ase_calculate_route(ospf,lsa);
f2c80652 672
718e3744 673 /* Compare old and new external routing table and install the
674 difference info zebra/kernel */
68980084 675 ospf_ase_compare_tables (ospf->new_external_route,
676 ospf->old_external_route);
718e3744 677
678 /* Delete old external routing table */
68980084 679 ospf_route_table_free (ospf->old_external_route);
680 ospf->old_external_route = ospf->new_external_route;
681 ospf->new_external_route = route_table_init ();
cf744958 682
cf672a86 683 monotime(&stop_time);
cf744958 684
8f2c16aa
DL
685 zlog_info ("SPF Processing Time(usecs): External Routes: %lld\n",
686 (stop_time.tv_sec - start_time.tv_sec)*1000000LL+
cf744958 687 (stop_time.tv_usec - start_time.tv_usec));
718e3744 688 }
689 return 0;
690}
691
692void
68980084 693ospf_ase_calculate_schedule (struct ospf *ospf)
718e3744 694{
68980084 695 if (ospf == NULL)
718e3744 696 return;
697
68980084 698 ospf->ase_calc = 1;
718e3744 699}
700
701void
68980084 702ospf_ase_calculate_timer_add (struct ospf *ospf)
718e3744 703{
68980084 704 if (ospf == NULL)
718e3744 705 return;
706
ffa2c898
QY
707 thread_add_timer(master, ospf_ase_calculate_timer, ospf,
708 OSPF_ASE_CALC_INTERVAL, &ospf->t_ase_calc);
718e3744 709}
710
711void
712ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
713{
714 struct route_node *rn;
715 struct prefix_ipv4 p;
52dc7ee6 716 struct list *lst;
718e3744 717 struct as_external_lsa *al;
718
719 al = (struct as_external_lsa *) lsa->data;
720 p.family = AF_INET;
721 p.prefix = lsa->data->id;
722 p.prefixlen = ip_masklen (al->mask);
723 apply_mask_ipv4 (&p);
724
725 rn = route_node_get (top->external_lsas, (struct prefix *) &p);
726 if ((lst = rn->info) == NULL)
727 rn->info = lst = list_new();
d8d939a6
JT
728 else
729 route_unlock_node (rn);
718e3744 730
731 /* We assume that if LSA is deleted from DB
732 is is also deleted from this RT */
1fe6ed38 733 listnode_add (lst, ospf_lsa_lock (lsa)); /* external_lsas lst */
718e3744 734}
735
736void
737ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top)
738{
739 struct route_node *rn;
740 struct prefix_ipv4 p;
52dc7ee6 741 struct list *lst;
718e3744 742 struct as_external_lsa *al;
743
744 al = (struct as_external_lsa *) lsa->data;
745 p.family = AF_INET;
746 p.prefix = lsa->data->id;
747 p.prefixlen = ip_masklen (al->mask);
748 apply_mask_ipv4 (&p);
749
d8d939a6 750 rn = route_node_lookup (top->external_lsas, (struct prefix *) &p);
718e3744 751
d8d939a6
JT
752 if (rn) {
753 lst = rn->info;
718e3744 754 listnode_delete (lst, lsa);
1fe6ed38 755 ospf_lsa_unlock (&lsa); /* external_lsas list */
d8d939a6 756 route_unlock_node (rn);
718e3744 757 }
718e3744 758}
759
760void
761ospf_ase_external_lsas_finish (struct route_table *rt)
762{
763 struct route_node *rn;
764 struct ospf_lsa *lsa;
52dc7ee6 765 struct list *lst;
1eb8ef25 766 struct listnode *node, *nnode;
718e3744 767
768 for (rn = route_top (rt); rn; rn = route_next (rn))
769 if ((lst = rn->info) != NULL)
770 {
1eb8ef25 771 for (ALL_LIST_ELEMENTS (lst, node, nnode, lsa))
1fe6ed38 772 ospf_lsa_unlock (&lsa); /* external_lsas lst */
718e3744 773 list_delete (lst);
774 }
1eb8ef25 775
718e3744 776 route_table_finish (rt);
777}
778
779void
68980084 780ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa)
718e3744 781{
52dc7ee6 782 struct list *lsas;
783 struct listnode *node;
718e3744 784 struct route_node *rn, *rn2;
785 struct prefix_ipv4 p;
786 struct route_table *tmp_old;
787 struct as_external_lsa *al;
788
789 al = (struct as_external_lsa *) lsa->data;
790 p.family = AF_INET;
791 p.prefix = lsa->data->id;
792 p.prefixlen = ip_masklen (al->mask);
793 apply_mask_ipv4 (&p);
794
795 /* if new_table is NULL, there was no spf calculation, thus
796 incremental update is unneeded */
68980084 797 if (!ospf->new_table)
718e3744 798 return;
799
800 /* If there is already an intra-area or inter-area route
801 to the destination, no recalculation is necessary
802 (internal routes take precedence). */
803
68980084 804 rn = route_node_lookup (ospf->new_table, (struct prefix *) &p);
3d8617b8 805 if (rn)
718e3744 806 {
807 route_unlock_node (rn);
3d8617b8
JT
808 if (rn->info)
809 return;
718e3744 810 }
811
68980084 812 rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p);
e8f22261
PJ
813 assert (rn);
814 assert (rn->info);
718e3744 815 lsas = rn->info;
3d8617b8
JT
816 route_unlock_node (rn);
817
1eb8ef25 818 for (ALL_LIST_ELEMENTS_RO (lsas, node, lsa))
819 ospf_ase_calculate_route (ospf, lsa);
718e3744 820
821 /* prepare temporary old routing table for compare */
822 tmp_old = route_table_init ();
68980084 823 rn = route_node_lookup (ospf->old_external_route, (struct prefix *) &p);
718e3744 824 if (rn && rn->info)
825 {
826 rn2 = route_node_get (tmp_old, (struct prefix *) &p);
827 rn2->info = rn->info;
58a1e062 828 route_unlock_node (rn);
718e3744 829 }
830
831 /* install changes to zebra */
68980084 832 ospf_ase_compare_tables (ospf->new_external_route, tmp_old);
718e3744 833
68980084 834 /* update ospf->old_external_route table */
718e3744 835 if (rn && rn->info)
836 ospf_route_free ((struct ospf_route *) rn->info);
837
68980084 838 rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p);
839 /* if new route exists, install it to ospf->old_external_route */
718e3744 840 if (rn2 && rn2->info)
841 {
842 if (!rn)
68980084 843 rn = route_node_get (ospf->old_external_route, (struct prefix *) &p);
718e3744 844 rn->info = rn2->info;
845 }
846 else
847 {
68980084 848 /* remove route node from ospf->old_external_route */
718e3744 849 if (rn)
850 {
851 rn->info = NULL;
852 route_unlock_node (rn);
718e3744 853 }
854 }
855
856 if (rn2)
857 {
68980084 858 /* rn2->info is stored in route node of ospf->old_external_route */
718e3744 859 rn2->info = NULL;
860 route_unlock_node (rn2);
861 route_unlock_node (rn2);
862 }
863
864 route_table_finish (tmp_old);
865}