]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_ase.c
zebra: Allow ns delete to happen after under/over flow checks
[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
d62a17ae 48struct ospf_route *ospf_find_asbr_route(struct ospf *ospf,
49 struct route_table *rtrs,
50 struct prefix_ipv4 *asbr)
718e3744 51{
d62a17ae 52 struct route_node *rn;
53 struct ospf_route * or, *best = NULL;
54 struct listnode *node;
55 struct list *chosen;
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. */
70 if (!CHECK_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE))
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 &&
75 or->path_type == OSPF_PATH_INTRA_AREA)
76 listnode_add(chosen, or);
77
78 /* If none is found -- look through all. */
79 if (listcount(chosen) == 0) {
6a154c88 80 list_delete(&chosen);
d62a17ae 81 chosen = rn->info;
82 }
718e3744 83
d62a17ae 84 /* Now find the route with least cost. */
85 for (ALL_LIST_ELEMENTS_RO(chosen, node, or))
86 if (or->cost < OSPF_LS_INFINITY) {
87 if (best == NULL)
88 best = or ;
89 else if (best->cost > or->cost)
90 best = or ;
91 else if (best->cost ==
92 or->cost
93 && IPV4_ADDR_CMP(
94 &best->u.std.area_id,
95 & or->u.std.area_id)
96 < 0)
97 best = or ;
98 }
99
100 if (chosen != rn->info)
6a154c88 101 list_delete(&chosen);
d62a17ae 102
103 return best;
718e3744 104}
105
d62a17ae 106struct ospf_route *ospf_find_asbr_route_through_area(struct route_table *rtrs,
107 struct prefix_ipv4 *asbr,
108 struct ospf_area *area)
718e3744 109{
d62a17ae 110 struct route_node *rn;
718e3744 111
d62a17ae 112 /* Sanity check. */
113 if (rtrs == NULL)
114 return NULL;
718e3744 115
d62a17ae 116 rn = route_node_lookup(rtrs, (struct prefix *)asbr);
718e3744 117
d62a17ae 118 if (rn) {
119 struct listnode *node;
120 struct ospf_route * or ;
718e3744 121
d62a17ae 122 route_unlock_node(rn);
123
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 ;
127 }
718e3744 128
d62a17ae 129 return NULL;
718e3744 130}
131
d62a17ae 132static void ospf_ase_complete_direct_routes(struct ospf_route *ro,
133 struct in_addr nexthop)
718e3744 134{
d62a17ae 135 struct listnode *node;
136 struct ospf_path *op;
718e3744 137
d62a17ae 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
d62a17ae 143static int ospf_ase_forward_address_check(struct ospf *ospf,
144 struct in_addr fwd_addr)
718e3744 145{
d62a17ae 146 struct listnode *ifn;
147 struct ospf_interface *oi;
148
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,
153 &fwd_addr))
154 return 0;
155
156 return 1;
718e3744 157}
158
3408afe2 159#if 0
718e3744 160/* Calculate ASBR route. */
4dadc291 161static struct ospf_route *
68980084 162ospf_ase_calculate_asbr_route (struct ospf *ospf,
163 struct route_table *rt_network,
718e3744 164 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
68980084 177 asbr_route = ospf_find_asbr_route (ospf, rt_router, &asbr);
718e3744 178
179 if (asbr_route == NULL)
180 {
e40dcce1 181 if (IS_DEBUG_OSPF (lsa, LSA))
182 zlog_debug ("ospf_ase_calculate(): Route to ASBR %s not found",
183 inet_ntoa (asbr.prefix));
718e3744 184 return NULL;
185 }
186
187 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL))
188 {
e40dcce1 189 if (IS_DEBUG_OSPF (lsa, LSA))
190 zlog_debug ("ospf_ase_calculate(): Originating router is not an ASBR");
718e3744 191 return NULL;
192 }
193
194 if (al->e[0].fwd_addr.s_addr != 0)
195 {
e40dcce1 196 if (IS_DEBUG_OSPF (lsa, LSA))
197 zlog_debug ("ospf_ase_calculate(): "
198 "Forwarding address is not 0.0.0.0.");
718e3744 199
68980084 200 if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr))
718e3744 201 {
e40dcce1 202 if (IS_DEBUG_OSPF (lsa, LSA))
203 zlog_debug ("ospf_ase_calculate(): "
204 "Forwarding address is one of our addresses, Ignore.");
718e3744 205 return NULL;
206 }
207
e40dcce1 208 if (IS_DEBUG_OSPF (lsa, LSA))
209 zlog_debug ("ospf_ase_calculate(): "
210 "Looking up in the Network Routing Table.");
718e3744 211
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 {
e40dcce1 221 if (IS_DEBUG_OSPF (lsa, LSA))
222 zlog_debug ("ospf_ase_calculate(): "
223 "Couldn't find a route to the forwarding address.");
718e3744 224 return NULL;
225 }
226
227 route_unlock_node (rn);
228
229 if ((asbr_route = rn->info) == NULL)
230 {
e40dcce1 231 if (IS_DEBUG_OSPF (lsa, LSA))
232 zlog_debug ("ospf_ase_calculate(): "
233 "Somehow OSPF route to ASBR is lost");
718e3744 234 return NULL;
235 }
236 }
237
238 return asbr_route;
239}
3408afe2 240#endif
718e3744 241
4dadc291 242static struct ospf_route *
d62a17ae 243ospf_ase_calculate_new_route(struct ospf_lsa *lsa,
d7c0a89a 244 struct ospf_route *asbr_route, uint32_t metric)
718e3744 245{
d62a17ae 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 if (IS_DEBUG_OSPF(lsa, LSA))
260 zlog_debug("Route[External]: type-1 created.");
261 new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
262 new->cost = asbr_route->cost + metric; /* X + Y */
263 } else {
264 if (IS_DEBUG_OSPF(lsa, LSA))
265 zlog_debug("Route[External]: type-2 created.");
266 new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
267 new->cost = asbr_route->cost; /* X */
268 new->u.ext.type2_cost = metric; /* Y */
269 }
718e3744 270
d62a17ae 271 new->type = OSPF_DESTINATION_NETWORK;
272 new->u.ext.origin = lsa;
273 new->u.ext.tag = ntohl(al->e[0].route_tag);
274 new->u.ext.asbr = asbr_route;
718e3744 275
d62a17ae 276 assert(new != asbr_route);
718e3744 277
d62a17ae 278 return new;
718e3744 279}
280
281#define OSPF_ASE_CALC_INTERVAL 1
282
d62a17ae 283int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa)
718e3744 284{
d7c0a89a 285 uint32_t metric;
d62a17ae 286 struct as_external_lsa *al;
287 struct ospf_route *asbr_route;
288 struct prefix_ipv4 asbr, p;
289 struct route_node *rn;
290 struct ospf_route *new, * or ;
96065dc3 291 char buf1[INET_ADDRSTRLEN];
d62a17ae 292 int ret;
293
294 assert(lsa);
295 al = (struct as_external_lsa *)lsa->data;
296
297 if (lsa->data->type == OSPF_AS_NSSA_LSA)
298 if (IS_DEBUG_OSPF_NSSA)
299 zlog_debug("ospf_ase_calc(): Processing Type-7");
300
301 /* Stay away from any Local Translated Type-7 LSAs */
302 if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) {
303 if (IS_DEBUG_OSPF_NSSA)
304 zlog_debug("ospf_ase_calc(): Rejecting Local Xlt'd");
305 return 0;
718e3744 306 }
718e3744 307
96065dc3
CS
308 if (IS_DEBUG_OSPF(lsa, LSA)) {
309 snprintf(buf1, INET_ADDRSTRLEN, "%s",
310 inet_ntoa(al->header.adv_router));
d62a17ae 311 zlog_debug(
96065dc3
CS
312 "Route[External]: Calculate AS-external-LSA to %s/%d adv_router %s",
313 inet_ntoa(al->header.id), ip_masklen(al->mask), buf1);
314 }
315
d62a17ae 316 /* (1) If the cost specified by the LSA is LSInfinity, or if the
317 LSA's LS age is equal to MaxAge, then examine the next LSA. */
318 if ((metric = GET_METRIC(al->e[0].metric)) >= OSPF_LS_INFINITY) {
319 if (IS_DEBUG_OSPF(lsa, LSA))
320 zlog_debug(
321 "Route[External]: Metric is OSPF_LS_INFINITY");
322 return 0;
323 }
324 if (IS_LSA_MAXAGE(lsa)) {
325 if (IS_DEBUG_OSPF(lsa, LSA))
326 zlog_debug(
327 "Route[External]: AS-external-LSA is MAXAGE");
328 return 0;
718e3744 329 }
330
d62a17ae 331 /* (2) If the LSA was originated by the calculating router itself,
332 examine the next LSA. */
333 if (IS_LSA_SELF(lsa)) {
334 if (IS_DEBUG_OSPF(lsa, LSA))
335 zlog_debug(
336 "Route[External]: AS-external-LSA is self originated");
337 return 0;
338 }
718e3744 339
d62a17ae 340 /* (3) Call the destination described by the LSA N. N's address is
341 obtained by masking the LSA's Link State ID with the
342 network/subnet mask contained in the body of the LSA. Look
343 up the routing table entries (potentially one per attached
344 area) for the AS boundary router (ASBR) that originated the
345 LSA. If no entries exist for router ASBR (i.e., ASBR is
346 unreachable), do nothing with this LSA and consider the next
347 in the list. */
348
349 asbr.family = AF_INET;
350 asbr.prefix = al->header.adv_router;
351 asbr.prefixlen = IPV4_MAX_BITLEN;
352 apply_mask_ipv4(&asbr);
353
354 asbr_route = ospf_find_asbr_route(ospf, ospf->new_rtrs, &asbr);
355 if (asbr_route == NULL) {
356 if (IS_DEBUG_OSPF(lsa, LSA))
357 zlog_debug(
358 "Route[External]: Can't find originating ASBR route");
359 return 0;
360 }
361 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) {
362 if (IS_DEBUG_OSPF(lsa, LSA))
363 zlog_debug(
364 "Route[External]: Originating router is not an ASBR");
365 return 0;
366 }
718e3744 367
d62a17ae 368 /* Else, this LSA describes an AS external path to destination
369 N. Examine the forwarding address specified in the AS-
370 external-LSA. This indicates the IP address to which
371 packets for the destination should be forwarded. */
372
373 if (al->e[0].fwd_addr.s_addr == 0) {
374 /* 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 } else {
388 /* If the forwarding address is non-zero, look up the
389 forwarding address in the routing table.[24] The matching
390 routing table entry must specify an intra-area or inter-area
391 path; if no such path exists, do nothing with the LSA and
392 consider the next in the list. */
393 if (!ospf_ase_forward_address_check(ospf, al->e[0].fwd_addr)) {
394 if (IS_DEBUG_OSPF(lsa, LSA))
395 zlog_debug(
396 "Route[External]: Forwarding address is our router "
397 "address");
398 return 0;
399 }
400
401 asbr.family = AF_INET;
402 asbr.prefix = al->e[0].fwd_addr;
403 asbr.prefixlen = IPV4_MAX_BITLEN;
404
405 rn = route_node_match(ospf->new_table, (struct prefix *)&asbr);
406
407 if (rn == NULL || (asbr_route = rn->info) == NULL) {
408 if (IS_DEBUG_OSPF(lsa, LSA))
409 zlog_debug(
410 "Route[External]: Can't find route to forwarding "
411 "address");
412 if (rn)
413 route_unlock_node(rn);
414 return 0;
415 }
416
417 route_unlock_node(rn);
718e3744 418 }
d62a17ae 419
420 /* (4) Let X be the cost specified by the preferred routing table
421 entry for the ASBR/forwarding address, and Y the cost
422 specified in the LSA. X is in terms of the link state
423 metric, and Y is a type 1 or 2 external metric. */
424
425
426 /* (5) Look up the routing table entry for the destination N. If
427 no entry exists for N, install the AS external path to N,
428 with next hop equal to the list of next hops to the
429 forwarding address, and advertising router equal to ASBR.
430 If the external metric type is 1, then the path-type is set
431 to type 1 external and the cost is equal to X+Y. If the
432 external metric type is 2, the path-type is set to type 2
433 external, the link state component of the route's cost is X,
434 and the type 2 cost is Y. */
435 new = ospf_ase_calculate_new_route(lsa, asbr_route, metric);
436
437 /* (6) Compare the AS external path described by the LSA with the
438 existing paths in N's routing table entry, as follows. If
439 the new path is preferred, it replaces the present paths in
440 N's routing table entry. If the new path is of equal
441 preference, it is added to N's routing table entry's list of
442 paths. */
443
444 /* Set prefix. */
445 p.family = AF_INET;
446 p.prefix = al->header.id;
447 p.prefixlen = ip_masklen(al->mask);
448
449 /* if there is a Intra/Inter area route to the N
450 do not install external route */
451 if ((rn = route_node_lookup(ospf->new_table, (struct prefix *)&p))) {
452 route_unlock_node(rn);
453 if (rn->info == NULL)
454 zlog_info("Route[External]: rn->info NULL");
455 if (new)
456 ospf_route_free(new);
457 return 0;
718e3744 458 }
d62a17ae 459 /* Find a route to the same dest */
460 /* If there is no route, create new one. */
461 if ((rn = route_node_lookup(ospf->new_external_route,
462 (struct prefix *)&p)))
463 route_unlock_node(rn);
464
465 if (!rn || (or = rn->info) == NULL) {
466 if (IS_DEBUG_OSPF(lsa, LSA))
96065dc3
CS
467 zlog_debug("Route[External]: Adding a new route %s/%d with paths %u",
468 inet_ntoa(p.prefix), p.prefixlen,
469 listcount(asbr_route->paths));
d62a17ae 470
471 ospf_route_add(ospf->new_external_route, &p, new, asbr_route);
472
473 if (al->e[0].fwd_addr.s_addr)
474 ospf_ase_complete_direct_routes(new, al->e[0].fwd_addr);
475 return 0;
476 } else {
477 /* (a) Intra-area and inter-area paths are always preferred
478 over AS external paths.
479
480 (b) Type 1 external paths are always preferred over type 2
481 external paths. When all paths are type 2 external
482 paths, the paths with the smallest advertised type 2
483 metric are always preferred. */
484 ret = ospf_route_cmp(ospf, new, or);
485
486 /* (c) If the new AS external path is still
487 indistinguishable
488 from the current paths in the N's routing table
489 entry,
490 and RFC1583Compatibility is set to "disabled", select
491 the preferred paths based on the intra-AS paths to
492 the
493 ASBR/forwarding addresses, as specified in Section
494 16.4.1.
495
496 (d) If the new AS external path is still
497 indistinguishable
498 from the current paths in the N's routing table
499 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
504 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 if (IS_DEBUG_OSPF(lsa, LSA))
512 zlog_debug(
513 "Route[External]: New route is better");
514 ospf_route_subst(rn, new, asbr_route);
515 if (al->e[0].fwd_addr.s_addr)
516 ospf_ase_complete_direct_routes(
517 new, al->e[0].fwd_addr);
518 or = new;
519 new = NULL;
520 }
521 /* Old route is better */
522 else if (ret > 0) {
523 if (IS_DEBUG_OSPF(lsa, LSA))
524 zlog_debug(
525 "Route[External]: Old route is better");
526 /* do nothing */
527 }
528 /* Routes are equal */
529 else {
530 if (IS_DEBUG_OSPF(lsa, LSA))
531 zlog_debug("Route[External]: Routes are equal");
532 ospf_route_copy_nexthops(or, asbr_route->paths);
533 if (al->e[0].fwd_addr.s_addr)
534 ospf_ase_complete_direct_routes(
535 or, al->e[0].fwd_addr);
536 }
718e3744 537 }
d62a17ae 538 /* Make sure setting newly calculated ASBR route.*/
539 or->u.ext.asbr = asbr_route;
540 if (new)
541 ospf_route_free(new);
718e3744 542
d62a17ae 543 lsa->route = or ;
544 return 0;
718e3744 545}
546
d62a17ae 547static int ospf_ase_route_match_same(struct route_table *rt,
548 struct prefix *prefix,
549 struct ospf_route *newor)
718e3744 550{
d62a17ae 551 struct route_node *rn;
2ffc213b 552 struct ospf_route *or;
d62a17ae 553 struct ospf_path *op;
554 struct ospf_path *newop;
555 struct listnode *n1;
556 struct listnode *n2;
557
558 if (!rt || !prefix)
559 return 0;
560
561 rn = route_node_lookup(rt, prefix);
562 if (!rn)
563 return 0;
564
565 route_unlock_node(rn);
566
567 or = rn->info;
2ffc213b
A
568
569 assert(or);
570
d62a17ae 571 if (or->path_type != newor->path_type)
572 return 0;
573
574 switch (or->path_type) {
575 case OSPF_PATH_TYPE1_EXTERNAL:
576 if (or->cost != newor->cost)
577 return 0;
578 break;
579 case OSPF_PATH_TYPE2_EXTERNAL:
580 if ((or->cost != newor->cost)
581 || (or->u.ext.type2_cost != newor->u.ext.type2_cost))
582 return 0;
583 break;
584 default:
585 assert(0);
586 return 0;
587 }
588
2ffc213b
A
589 assert(or->paths);
590
d62a17ae 591 if (or->paths->count != newor->paths->count)
592 return 0;
593
594 /* Check each path. */
595 for (n1 = listhead(or->paths), n2 = listhead(newor->paths); n1 && n2;
39050c7e 596 n1 = listnextnode_unchecked(n1), n2 = listnextnode_unchecked(n2)) {
d62a17ae 597 op = listgetdata(n1);
598 newop = listgetdata(n2);
599
600 if (!IPV4_ADDR_SAME(&op->nexthop, &newop->nexthop))
601 return 0;
602 if (op->ifindex != newop->ifindex)
603 return 0;
604 }
605
606 if (or->u.ext.tag != newor->u.ext.tag)
607 return 0;
608
609 return 1;
718e3744 610}
611
b5a8894d
CS
612static int ospf_ase_compare_tables(struct ospf *ospf,
613 struct route_table *new_external_route,
d62a17ae 614 struct route_table *old_external_route)
718e3744 615{
d62a17ae 616 struct route_node *rn, *new_rn;
617 struct ospf_route * or ;
618
619 /* Remove deleted routes */
620 for (rn = route_top(old_external_route); rn; rn = route_next(rn))
621 if ((or = rn->info)) {
622 if (!(new_rn = route_node_lookup(new_external_route,
623 &rn->p)))
996c9314
LB
624 ospf_zebra_delete(
625 ospf, (struct prefix_ipv4 *)&rn->p, or);
d62a17ae 626 else
627 route_unlock_node(new_rn);
628 }
629
630
631 /* Install new routes */
632 for (rn = route_top(new_external_route); rn; rn = route_next(rn))
633 if ((or = rn->info) != NULL)
634 if (!ospf_ase_route_match_same(old_external_route,
635 &rn->p, or))
996c9314
LB
636 ospf_zebra_add(
637 ospf, (struct prefix_ipv4 *)&rn->p, or);
d62a17ae 638
639 return 0;
718e3744 640}
641
d62a17ae 642static int ospf_ase_calculate_timer(struct thread *t)
718e3744 643{
d62a17ae 644 struct ospf *ospf;
645 struct ospf_lsa *lsa;
646 struct route_node *rn;
647 struct listnode *node;
648 struct ospf_area *area;
649 struct timeval start_time, stop_time;
650
651 ospf = THREAD_ARG(t);
652 ospf->t_ase_calc = NULL;
653
654 if (ospf->ase_calc) {
655 ospf->ase_calc = 0;
656
657 monotime(&start_time);
658
659 /* Calculate external route for each AS-external-LSA */
996c9314 660 LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa)
044506e7 661 ospf_ase_calculate_route(ospf, lsa);
d62a17ae 662
663 /* This version simple adds to the table all NSSA areas */
664 if (ospf->anyNSSA)
665 for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
666 if (IS_DEBUG_OSPF_NSSA)
667 zlog_debug(
668 "ospf_ase_calculate_timer(): looking at area %s",
669 inet_ntoa(area->area_id));
670
671 if (area->external_routing == OSPF_AREA_NSSA)
996c9314 672 LSDB_LOOP (NSSA_LSDB(area), rn, lsa)
044506e7
DS
673 ospf_ase_calculate_route(ospf,
674 lsa);
d62a17ae 675 }
676 /* kevinm: And add the NSSA routes in ospf_top */
996c9314 677 LSDB_LOOP (NSSA_LSDB(ospf), rn, lsa)
044506e7 678 ospf_ase_calculate_route(ospf, lsa);
d62a17ae 679
680 /* Compare old and new external routing table and install the
681 difference info zebra/kernel */
b5a8894d 682 ospf_ase_compare_tables(ospf, ospf->new_external_route,
d62a17ae 683 ospf->old_external_route);
684
685 /* Delete old external routing table */
686 ospf_route_table_free(ospf->old_external_route);
687 ospf->old_external_route = ospf->new_external_route;
688 ospf->new_external_route = route_table_init();
689
690 monotime(&stop_time);
691
05ba78e4 692 if (IS_DEBUG_OSPF_EVENT)
996c9314
LB
693 zlog_info(
694 "SPF Processing Time(usecs): External Routes: %lld\n",
695 (stop_time.tv_sec - start_time.tv_sec)
696 * 1000000LL
697 + (stop_time.tv_usec
698 - start_time.tv_usec));
d62a17ae 699 }
700 return 0;
718e3744 701}
702
d62a17ae 703void ospf_ase_calculate_schedule(struct ospf *ospf)
718e3744 704{
d62a17ae 705 if (ospf == NULL)
706 return;
718e3744 707
d62a17ae 708 ospf->ase_calc = 1;
718e3744 709}
710
d62a17ae 711void ospf_ase_calculate_timer_add(struct ospf *ospf)
718e3744 712{
d62a17ae 713 if (ospf == NULL)
714 return;
718e3744 715
d62a17ae 716 thread_add_timer(master, ospf_ase_calculate_timer, ospf,
717 OSPF_ASE_CALC_INTERVAL, &ospf->t_ase_calc);
718e3744 718}
719
d62a17ae 720void ospf_ase_register_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
718e3744 721{
d62a17ae 722 struct route_node *rn;
723 struct prefix_ipv4 p;
724 struct list *lst;
725 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 if ((lst = rn->info) == NULL)
735 rn->info = lst = list_new();
736 else
737 route_unlock_node(rn);
738
739 /* We assume that if LSA is deleted from DB
740 is is also deleted from this RT */
741 listnode_add(lst, ospf_lsa_lock(lsa)); /* external_lsas lst */
718e3744 742}
743
d62a17ae 744void ospf_ase_unregister_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
718e3744 745{
d62a17ae 746 struct route_node *rn;
747 struct prefix_ipv4 p;
748 struct list *lst;
749 struct as_external_lsa *al;
750
751 al = (struct as_external_lsa *)lsa->data;
752 p.family = AF_INET;
753 p.prefix = lsa->data->id;
754 p.prefixlen = ip_masklen(al->mask);
755 apply_mask_ipv4(&p);
756
757 rn = route_node_lookup(top->external_lsas, (struct prefix *)&p);
758
759 if (rn) {
760 lst = rn->info;
761 listnode_delete(lst, lsa);
762 ospf_lsa_unlock(&lsa); /* external_lsas list */
763 route_unlock_node(rn);
764 }
718e3744 765}
766
d62a17ae 767void ospf_ase_external_lsas_finish(struct route_table *rt)
718e3744 768{
d62a17ae 769 struct route_node *rn;
770 struct ospf_lsa *lsa;
771 struct list *lst;
772 struct listnode *node, *nnode;
773
774 for (rn = route_top(rt); rn; rn = route_next(rn))
775 if ((lst = rn->info) != NULL) {
776 for (ALL_LIST_ELEMENTS(lst, node, nnode, lsa))
777 ospf_lsa_unlock(&lsa); /* external_lsas lst */
6a154c88 778 list_delete(&lst);
d62a17ae 779 }
780
781 route_table_finish(rt);
718e3744 782}
783
d62a17ae 784void ospf_ase_incremental_update(struct ospf *ospf, struct ospf_lsa *lsa)
718e3744 785{
d62a17ae 786 struct list *lsas;
787 struct listnode *node;
788 struct route_node *rn, *rn2;
789 struct prefix_ipv4 p;
790 struct route_table *tmp_old;
791 struct as_external_lsa *al;
792
793 al = (struct as_external_lsa *)lsa->data;
794 p.family = AF_INET;
795 p.prefix = lsa->data->id;
796 p.prefixlen = ip_masklen(al->mask);
797 apply_mask_ipv4(&p);
798
799 /* if new_table is NULL, there was no spf calculation, thus
800 incremental update is unneeded */
801 if (!ospf->new_table)
802 return;
803
804 /* If there is already an intra-area or inter-area route
805 to the destination, no recalculation is necessary
806 (internal routes take precedence). */
807
808 rn = route_node_lookup(ospf->new_table, (struct prefix *)&p);
809 if (rn) {
810 route_unlock_node(rn);
811 if (rn->info)
812 return;
813 }
718e3744 814
d62a17ae 815 rn = route_node_lookup(ospf->external_lsas, (struct prefix *)&p);
816 assert(rn);
817 assert(rn->info);
818 lsas = rn->info;
819 route_unlock_node(rn);
820
821 for (ALL_LIST_ELEMENTS_RO(lsas, node, lsa))
822 ospf_ase_calculate_route(ospf, lsa);
823
824 /* prepare temporary old routing table for compare */
825 tmp_old = route_table_init();
826 rn = route_node_lookup(ospf->old_external_route, (struct prefix *)&p);
827 if (rn && rn->info) {
828 rn2 = route_node_get(tmp_old, (struct prefix *)&p);
829 rn2->info = rn->info;
830 route_unlock_node(rn);
831 }
718e3744 832
d62a17ae 833 /* install changes to zebra */
b5a8894d 834 ospf_ase_compare_tables(ospf, ospf->new_external_route, tmp_old);
d62a17ae 835
836 /* update ospf->old_external_route table */
837 if (rn && rn->info)
838 ospf_route_free((struct ospf_route *)rn->info);
839
840 rn2 = route_node_lookup(ospf->new_external_route, (struct prefix *)&p);
841 /* if new route exists, install it to ospf->old_external_route */
842 if (rn2 && rn2->info) {
843 if (!rn)
844 rn = route_node_get(ospf->old_external_route,
845 (struct prefix *)&p);
846 rn->info = rn2->info;
847 } else {
848 /* remove route node from ospf->old_external_route */
849 if (rn) {
850 rn->info = NULL;
851 route_unlock_node(rn);
852 }
718e3744 853 }
718e3744 854
d62a17ae 855 if (rn2) {
856 /* rn2->info is stored in route node of ospf->old_external_route
857 */
858 rn2->info = NULL;
859 route_unlock_node(rn2);
860 route_unlock_node(rn2);
861 }
718e3744 862
d62a17ae 863 route_table_finish(tmp_old);
718e3744 864}