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