]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_ase.c
*: Rename thread.[ch] to event.[ch]
[mirror_frr.git] / ospfd / ospf_ase.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
718e3744 2/*
3 * OSPF AS external route calculation.
4 * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada
718e3744 5 */
6
7#include <zebra.h>
8
cb37cb33 9#include "event.h"
718e3744 10#include "memory.h"
11#include "hash.h"
12#include "linklist.h"
13#include "prefix.h"
14#include "if.h"
15#include "table.h"
16#include "vty.h"
17#include "log.h"
18
19#include "ospfd/ospfd.h"
20#include "ospfd/ospf_interface.h"
21#include "ospfd/ospf_ism.h"
22#include "ospfd/ospf_asbr.h"
23#include "ospfd/ospf_lsa.h"
24#include "ospfd/ospf_lsdb.h"
25#include "ospfd/ospf_neighbor.h"
26#include "ospfd/ospf_nsm.h"
27#include "ospfd/ospf_spf.h"
28#include "ospfd/ospf_route.h"
29#include "ospfd/ospf_ase.h"
30#include "ospfd/ospf_zebra.h"
31#include "ospfd/ospf_dump.h"
32
d62a17ae 33struct ospf_route *ospf_find_asbr_route(struct ospf *ospf,
34 struct route_table *rtrs,
35 struct prefix_ipv4 *asbr)
718e3744 36{
d62a17ae 37 struct route_node *rn;
38 struct ospf_route * or, *best = NULL;
39 struct listnode *node;
40 struct list *chosen;
41
42 /* Sanity check. */
43 if (rtrs == NULL)
44 return NULL;
45
46 rn = route_node_lookup(rtrs, (struct prefix *)asbr);
47 if (!rn)
48 return NULL;
49
50 route_unlock_node(rn);
51
52 chosen = list_new();
53
54 /* First try to find intra-area non-bb paths. */
55 if (!CHECK_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE))
56 for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, or))
57 if (or->cost < OSPF_LS_INFINITY)
58 if (!OSPF_IS_AREA_ID_BACKBONE(or->u.std.area_id)
59 &&
60 or->path_type == OSPF_PATH_INTRA_AREA)
61 listnode_add(chosen, or);
62
63 /* If none is found -- look through all. */
64 if (listcount(chosen) == 0) {
6a154c88 65 list_delete(&chosen);
d62a17ae 66 chosen = rn->info;
67 }
718e3744 68
d62a17ae 69 /* Now find the route with least cost. */
70 for (ALL_LIST_ELEMENTS_RO(chosen, node, or))
71 if (or->cost < OSPF_LS_INFINITY) {
72 if (best == NULL)
73 best = or ;
74 else if (best->cost > or->cost)
75 best = or ;
76 else if (best->cost ==
77 or->cost
78 && IPV4_ADDR_CMP(
79 &best->u.std.area_id,
80 & or->u.std.area_id)
81 < 0)
82 best = or ;
83 }
84
85 if (chosen != rn->info)
6a154c88 86 list_delete(&chosen);
d62a17ae 87
88 return best;
718e3744 89}
90
d62a17ae 91struct ospf_route *ospf_find_asbr_route_through_area(struct route_table *rtrs,
92 struct prefix_ipv4 *asbr,
93 struct ospf_area *area)
718e3744 94{
d62a17ae 95 struct route_node *rn;
718e3744 96
d62a17ae 97 /* Sanity check. */
98 if (rtrs == NULL)
99 return NULL;
718e3744 100
d62a17ae 101 rn = route_node_lookup(rtrs, (struct prefix *)asbr);
718e3744 102
d62a17ae 103 if (rn) {
104 struct listnode *node;
105 struct ospf_route * or ;
718e3744 106
d62a17ae 107 route_unlock_node(rn);
108
109 for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, or))
110 if (IPV4_ADDR_SAME(& or->u.std.area_id, &area->area_id))
111 return or ;
112 }
718e3744 113
d62a17ae 114 return NULL;
718e3744 115}
116
d62a17ae 117static void ospf_ase_complete_direct_routes(struct ospf_route *ro,
118 struct in_addr nexthop)
718e3744 119{
d62a17ae 120 struct listnode *node;
121 struct ospf_path *op;
718e3744 122
d62a17ae 123 for (ALL_LIST_ELEMENTS_RO(ro->paths, node, op))
3a6290bd 124 if (op->nexthop.s_addr == INADDR_ANY)
d62a17ae 125 op->nexthop.s_addr = nexthop.s_addr;
718e3744 126}
127
d62a17ae 128static int ospf_ase_forward_address_check(struct ospf *ospf,
129 struct in_addr fwd_addr)
718e3744 130{
d62a17ae 131 struct listnode *ifn;
132 struct ospf_interface *oi;
133
134 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, ifn, oi))
135 if (if_is_operative(oi->ifp))
136 if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
137 if (IPV4_ADDR_SAME(&oi->address->u.prefix4,
138 &fwd_addr))
139 return 0;
140
141 return 1;
718e3744 142}
143
4dadc291 144static struct ospf_route *
d62a17ae 145ospf_ase_calculate_new_route(struct ospf_lsa *lsa,
d7c0a89a 146 struct ospf_route *asbr_route, uint32_t metric)
718e3744 147{
d62a17ae 148 struct as_external_lsa *al;
149 struct ospf_route *new;
150
151 al = (struct as_external_lsa *)lsa->data;
152
153 new = ospf_route_new();
154
155 /* Set redistributed type -- does make sense? */
156 /* new->type = type; */
157 new->id = al->header.id;
158 new->mask = al->mask;
159
160 if (!IS_EXTERNAL_METRIC(al->e[0].tos)) {
161 if (IS_DEBUG_OSPF(lsa, LSA))
162 zlog_debug("Route[External]: type-1 created.");
163 new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
164 new->cost = asbr_route->cost + metric; /* X + Y */
165 } else {
166 if (IS_DEBUG_OSPF(lsa, LSA))
167 zlog_debug("Route[External]: type-2 created.");
168 new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
169 new->cost = asbr_route->cost; /* X */
170 new->u.ext.type2_cost = metric; /* Y */
171 }
718e3744 172
d62a17ae 173 new->type = OSPF_DESTINATION_NETWORK;
174 new->u.ext.origin = lsa;
175 new->u.ext.tag = ntohl(al->e[0].route_tag);
176 new->u.ext.asbr = asbr_route;
718e3744 177
d62a17ae 178 assert(new != asbr_route);
718e3744 179
d62a17ae 180 return new;
718e3744 181}
182
183#define OSPF_ASE_CALC_INTERVAL 1
184
d62a17ae 185int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa)
718e3744 186{
d7c0a89a 187 uint32_t metric;
d62a17ae 188 struct as_external_lsa *al;
189 struct ospf_route *asbr_route;
190 struct prefix_ipv4 asbr, p;
191 struct route_node *rn;
192 struct ospf_route *new, * or ;
193 int ret;
194
195 assert(lsa);
196 al = (struct as_external_lsa *)lsa->data;
197
198 if (lsa->data->type == OSPF_AS_NSSA_LSA)
199 if (IS_DEBUG_OSPF_NSSA)
70ad0b66 200 zlog_debug("%s: Processing Type-7", __func__);
d62a17ae 201
202 /* Stay away from any Local Translated Type-7 LSAs */
203 if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) {
204 if (IS_DEBUG_OSPF_NSSA)
70ad0b66 205 zlog_debug("%s: Rejecting Local Xlt'd", __func__);
d62a17ae 206 return 0;
718e3744 207 }
718e3744 208
96065dc3 209 if (IS_DEBUG_OSPF(lsa, LSA)) {
d62a17ae 210 zlog_debug(
96b663a3
MS
211 "Route[External]: Calculate AS-external-LSA to %pI4/%d adv_router %pI4",
212 &al->header.id, ip_masklen(al->mask),
213 &al->header.adv_router);
96065dc3
CS
214 }
215
d62a17ae 216 /* (1) If the cost specified by the LSA is LSInfinity, or if the
217 LSA's LS age is equal to MaxAge, then examine the next LSA. */
218 if ((metric = GET_METRIC(al->e[0].metric)) >= OSPF_LS_INFINITY) {
219 if (IS_DEBUG_OSPF(lsa, LSA))
220 zlog_debug(
221 "Route[External]: Metric is OSPF_LS_INFINITY");
222 return 0;
223 }
224 if (IS_LSA_MAXAGE(lsa)) {
225 if (IS_DEBUG_OSPF(lsa, LSA))
226 zlog_debug(
227 "Route[External]: AS-external-LSA is MAXAGE");
228 return 0;
718e3744 229 }
230
d62a17ae 231 /* (2) If the LSA was originated by the calculating router itself,
232 examine the next LSA. */
233 if (IS_LSA_SELF(lsa)) {
234 if (IS_DEBUG_OSPF(lsa, LSA))
235 zlog_debug(
236 "Route[External]: AS-external-LSA is self originated");
237 return 0;
238 }
718e3744 239
d62a17ae 240 /* (3) Call the destination described by the LSA N. N's address is
241 obtained by masking the LSA's Link State ID with the
242 network/subnet mask contained in the body of the LSA. Look
243 up the routing table entries (potentially one per attached
244 area) for the AS boundary router (ASBR) that originated the
245 LSA. If no entries exist for router ASBR (i.e., ASBR is
246 unreachable), do nothing with this LSA and consider the next
247 in the list. */
248
249 asbr.family = AF_INET;
250 asbr.prefix = al->header.adv_router;
251 asbr.prefixlen = IPV4_MAX_BITLEN;
252 apply_mask_ipv4(&asbr);
253
254 asbr_route = ospf_find_asbr_route(ospf, ospf->new_rtrs, &asbr);
255 if (asbr_route == NULL) {
256 if (IS_DEBUG_OSPF(lsa, LSA))
257 zlog_debug(
258 "Route[External]: Can't find originating ASBR route");
259 return 0;
260 }
261 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) {
262 if (IS_DEBUG_OSPF(lsa, LSA))
263 zlog_debug(
264 "Route[External]: Originating router is not an ASBR");
265 return 0;
266 }
718e3744 267
bf4b7559 268 /* Type-5 shouldn't be calculated if it is originated from NSSA ASBR.
269 * As per RFC 3101, expectation is to receive type-7 lsas from
270 * NSSA ASBR. Ignore calculation, if the current LSA is type-5 and
271 * originated ASBR's area is NSSA.
272 */
273 if ((lsa->data->type == OSPF_AS_EXTERNAL_LSA)
274 && (asbr_route->u.std.external_routing != OSPF_AREA_DEFAULT)) {
275 if (IS_DEBUG_OSPF(lsa, LSA))
276 zlog_debug(
277 "Route[External]: Ignore, If type-5 LSA from NSSA area.");
278 return 0;
279 }
280
d62a17ae 281 /* Else, this LSA describes an AS external path to destination
282 N. Examine the forwarding address specified in the AS-
283 external-LSA. This indicates the IP address to which
284 packets for the destination should be forwarded. */
285
975a328e 286 if (al->e[0].fwd_addr.s_addr == INADDR_ANY) {
d62a17ae 287 /* If the forwarding address is set to 0.0.0.0, packets should
288 be sent to the ASBR itself. Among the multiple routing table
289 entries for the ASBR, select the preferred entry as follows.
290 If RFC1583Compatibility is set to "disabled", prune the set
291 of routing table entries for the ASBR as described in
292 Section 16.4.1. In any case, among the remaining routing
293 table entries, select the routing table entry with the least
294 cost; when there are multiple least cost routing table
295 entries the entry whose associated area has the largest OSPF
296 Area ID (when considered as an unsigned 32-bit integer) is
297 chosen. */
298
299 /* asbr_route already contains the requested route */
300 } else {
301 /* If the forwarding address is non-zero, look up the
302 forwarding address in the routing table.[24] The matching
303 routing table entry must specify an intra-area or inter-area
304 path; if no such path exists, do nothing with the LSA and
305 consider the next in the list. */
306 if (!ospf_ase_forward_address_check(ospf, al->e[0].fwd_addr)) {
307 if (IS_DEBUG_OSPF(lsa, LSA))
308 zlog_debug(
3efd0893 309 "Route[External]: Forwarding address is our router address");
d62a17ae 310 return 0;
311 }
312
313 asbr.family = AF_INET;
314 asbr.prefix = al->e[0].fwd_addr;
315 asbr.prefixlen = IPV4_MAX_BITLEN;
316
317 rn = route_node_match(ospf->new_table, (struct prefix *)&asbr);
318
319 if (rn == NULL || (asbr_route = rn->info) == NULL) {
320 if (IS_DEBUG_OSPF(lsa, LSA))
321 zlog_debug(
3efd0893 322 "Route[External]: Can't find route to forwarding address");
d62a17ae 323 if (rn)
324 route_unlock_node(rn);
325 return 0;
326 }
327
328 route_unlock_node(rn);
718e3744 329 }
d62a17ae 330
331 /* (4) Let X be the cost specified by the preferred routing table
332 entry for the ASBR/forwarding address, and Y the cost
333 specified in the LSA. X is in terms of the link state
334 metric, and Y is a type 1 or 2 external metric. */
335
336
337 /* (5) Look up the routing table entry for the destination N. If
338 no entry exists for N, install the AS external path to N,
339 with next hop equal to the list of next hops to the
340 forwarding address, and advertising router equal to ASBR.
341 If the external metric type is 1, then the path-type is set
342 to type 1 external and the cost is equal to X+Y. If the
343 external metric type is 2, the path-type is set to type 2
344 external, the link state component of the route's cost is X,
345 and the type 2 cost is Y. */
346 new = ospf_ase_calculate_new_route(lsa, asbr_route, metric);
347
348 /* (6) Compare the AS external path described by the LSA with the
349 existing paths in N's routing table entry, as follows. If
350 the new path is preferred, it replaces the present paths in
351 N's routing table entry. If the new path is of equal
352 preference, it is added to N's routing table entry's list of
353 paths. */
354
355 /* Set prefix. */
356 p.family = AF_INET;
357 p.prefix = al->header.id;
358 p.prefixlen = ip_masklen(al->mask);
359
360 /* if there is a Intra/Inter area route to the N
361 do not install external route */
362 if ((rn = route_node_lookup(ospf->new_table, (struct prefix *)&p))) {
363 route_unlock_node(rn);
364 if (rn->info == NULL)
365 zlog_info("Route[External]: rn->info NULL");
366 if (new)
367 ospf_route_free(new);
368 return 0;
718e3744 369 }
d62a17ae 370 /* Find a route to the same dest */
371 /* If there is no route, create new one. */
372 if ((rn = route_node_lookup(ospf->new_external_route,
373 (struct prefix *)&p)))
374 route_unlock_node(rn);
375
376 if (!rn || (or = rn->info) == NULL) {
377 if (IS_DEBUG_OSPF(lsa, LSA))
96b663a3
MS
378 zlog_debug("Route[External]: Adding a new route %pFX with paths %u",
379 &p, listcount(asbr_route->paths));
d62a17ae 380
381 ospf_route_add(ospf->new_external_route, &p, new, asbr_route);
382
975a328e 383 if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
d62a17ae 384 ospf_ase_complete_direct_routes(new, al->e[0].fwd_addr);
385 return 0;
386 } else {
387 /* (a) Intra-area and inter-area paths are always preferred
388 over AS external paths.
389
390 (b) Type 1 external paths are always preferred over type 2
391 external paths. When all paths are type 2 external
392 paths, the paths with the smallest advertised type 2
393 metric are always preferred. */
394 ret = ospf_route_cmp(ospf, new, or);
395
396 /* (c) If the new AS external path is still
397 indistinguishable
398 from the current paths in the N's routing table
399 entry,
400 and RFC1583Compatibility is set to "disabled", select
401 the preferred paths based on the intra-AS paths to
402 the
403 ASBR/forwarding addresses, as specified in Section
404 16.4.1.
405
406 (d) If the new AS external path is still
407 indistinguishable
408 from the current paths in the N's routing table
409 entry,
410 select the preferred path based on a least cost
411 comparison. Type 1 external paths are compared by
412 looking at the sum of the distance to the forwarding
413 address and the advertised type 1 metric (X+Y). Type
414 2
415 external paths advertising equal type 2 metrics are
416 compared by looking at the distance to the forwarding
417 addresses.
418 */
419 /* New route is better */
420 if (ret < 0) {
421 if (IS_DEBUG_OSPF(lsa, LSA))
422 zlog_debug(
423 "Route[External]: New route is better");
424 ospf_route_subst(rn, new, asbr_route);
975a328e 425 if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
d62a17ae 426 ospf_ase_complete_direct_routes(
427 new, al->e[0].fwd_addr);
428 or = new;
429 new = NULL;
430 }
431 /* Old route is better */
432 else if (ret > 0) {
433 if (IS_DEBUG_OSPF(lsa, LSA))
434 zlog_debug(
435 "Route[External]: Old route is better");
436 /* do nothing */
437 }
438 /* Routes are equal */
439 else {
440 if (IS_DEBUG_OSPF(lsa, LSA))
441 zlog_debug("Route[External]: Routes are equal");
442 ospf_route_copy_nexthops(or, asbr_route->paths);
975a328e 443 if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
d62a17ae 444 ospf_ase_complete_direct_routes(
445 or, al->e[0].fwd_addr);
446 }
718e3744 447 }
d62a17ae 448 /* Make sure setting newly calculated ASBR route.*/
449 or->u.ext.asbr = asbr_route;
450 if (new)
451 ospf_route_free(new);
718e3744 452
d62a17ae 453 lsa->route = or ;
454 return 0;
718e3744 455}
456
d62a17ae 457static int ospf_ase_route_match_same(struct route_table *rt,
458 struct prefix *prefix,
459 struct ospf_route *newor)
718e3744 460{
d62a17ae 461 struct route_node *rn;
2ffc213b 462 struct ospf_route *or;
d62a17ae 463 struct ospf_path *op;
464 struct ospf_path *newop;
465 struct listnode *n1;
466 struct listnode *n2;
467
468 if (!rt || !prefix)
469 return 0;
470
471 rn = route_node_lookup(rt, prefix);
472 if (!rn)
473 return 0;
474
475 route_unlock_node(rn);
476
477 or = rn->info;
2ffc213b
A
478
479 assert(or);
480
d62a17ae 481 if (or->path_type != newor->path_type)
482 return 0;
483
484 switch (or->path_type) {
485 case OSPF_PATH_TYPE1_EXTERNAL:
486 if (or->cost != newor->cost)
487 return 0;
488 break;
489 case OSPF_PATH_TYPE2_EXTERNAL:
490 if ((or->cost != newor->cost)
491 || (or->u.ext.type2_cost != newor->u.ext.type2_cost))
492 return 0;
493 break;
494 default:
495 assert(0);
496 return 0;
497 }
498
2ffc213b
A
499 assert(or->paths);
500
d62a17ae 501 if (or->paths->count != newor->paths->count)
502 return 0;
503
504 /* Check each path. */
505 for (n1 = listhead(or->paths), n2 = listhead(newor->paths); n1 && n2;
39050c7e 506 n1 = listnextnode_unchecked(n1), n2 = listnextnode_unchecked(n2)) {
d62a17ae 507 op = listgetdata(n1);
508 newop = listgetdata(n2);
509
510 if (!IPV4_ADDR_SAME(&op->nexthop, &newop->nexthop))
511 return 0;
512 if (op->ifindex != newop->ifindex)
513 return 0;
514 }
515
516 if (or->u.ext.tag != newor->u.ext.tag)
517 return 0;
518
519 return 1;
718e3744 520}
521
b5a8894d
CS
522static int ospf_ase_compare_tables(struct ospf *ospf,
523 struct route_table *new_external_route,
d62a17ae 524 struct route_table *old_external_route)
718e3744 525{
d62a17ae 526 struct route_node *rn, *new_rn;
527 struct ospf_route * or ;
528
529 /* Remove deleted routes */
530 for (rn = route_top(old_external_route); rn; rn = route_next(rn))
531 if ((or = rn->info)) {
532 if (!(new_rn = route_node_lookup(new_external_route,
533 &rn->p)))
996c9314
LB
534 ospf_zebra_delete(
535 ospf, (struct prefix_ipv4 *)&rn->p, or);
d62a17ae 536 else
537 route_unlock_node(new_rn);
538 }
539
540
541 /* Install new routes */
542 for (rn = route_top(new_external_route); rn; rn = route_next(rn))
543 if ((or = rn->info) != NULL)
544 if (!ospf_ase_route_match_same(old_external_route,
545 &rn->p, or))
996c9314
LB
546 ospf_zebra_add(
547 ospf, (struct prefix_ipv4 *)&rn->p, or);
d62a17ae 548
549 return 0;
718e3744 550}
551
cc9f21da 552static void ospf_ase_calculate_timer(struct thread *t)
718e3744 553{
d62a17ae 554 struct ospf *ospf;
555 struct ospf_lsa *lsa;
556 struct route_node *rn;
557 struct listnode *node;
558 struct ospf_area *area;
559 struct timeval start_time, stop_time;
560
561 ospf = THREAD_ARG(t);
562 ospf->t_ase_calc = NULL;
563
564 if (ospf->ase_calc) {
565 ospf->ase_calc = 0;
566
567 monotime(&start_time);
568
569 /* Calculate external route for each AS-external-LSA */
996c9314 570 LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa)
044506e7 571 ospf_ase_calculate_route(ospf, lsa);
d62a17ae 572
573 /* This version simple adds to the table all NSSA areas */
574 if (ospf->anyNSSA)
575 for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
576 if (IS_DEBUG_OSPF_NSSA)
70ad0b66 577 zlog_debug("%s: looking at area %pI4",
578 __func__, &area->area_id);
d62a17ae 579
580 if (area->external_routing == OSPF_AREA_NSSA)
996c9314 581 LSDB_LOOP (NSSA_LSDB(area), rn, lsa)
044506e7
DS
582 ospf_ase_calculate_route(ospf,
583 lsa);
d62a17ae 584 }
585 /* kevinm: And add the NSSA routes in ospf_top */
996c9314 586 LSDB_LOOP (NSSA_LSDB(ospf), rn, lsa)
044506e7 587 ospf_ase_calculate_route(ospf, lsa);
d62a17ae 588
589 /* Compare old and new external routing table and install the
590 difference info zebra/kernel */
b5a8894d 591 ospf_ase_compare_tables(ospf, ospf->new_external_route,
d62a17ae 592 ospf->old_external_route);
593
594 /* Delete old external routing table */
595 ospf_route_table_free(ospf->old_external_route);
596 ospf->old_external_route = ospf->new_external_route;
597 ospf->new_external_route = route_table_init();
598
599 monotime(&stop_time);
600
05ba78e4 601 if (IS_DEBUG_OSPF_EVENT)
996c9314 602 zlog_info(
63efca0e 603 "SPF Processing Time(usecs): External Routes: %lld",
996c9314
LB
604 (stop_time.tv_sec - start_time.tv_sec)
605 * 1000000LL
606 + (stop_time.tv_usec
607 - start_time.tv_usec));
d62a17ae 608 }
10514170
RW
609
610 /*
611 * Uninstall remnant routes that were installed before the restart, but
612 * that are no longer valid.
613 */
614 if (ospf->gr_info.finishing_restart) {
615 ospf_zebra_gr_disable(ospf);
616 ospf->gr_info.finishing_restart = false;
617 }
718e3744 618}
619
d62a17ae 620void ospf_ase_calculate_schedule(struct ospf *ospf)
718e3744 621{
d62a17ae 622 if (ospf == NULL)
623 return;
718e3744 624
d62a17ae 625 ospf->ase_calc = 1;
718e3744 626}
627
d62a17ae 628void ospf_ase_calculate_timer_add(struct ospf *ospf)
718e3744 629{
d62a17ae 630 if (ospf == NULL)
631 return;
718e3744 632
d62a17ae 633 thread_add_timer(master, ospf_ase_calculate_timer, ospf,
634 OSPF_ASE_CALC_INTERVAL, &ospf->t_ase_calc);
718e3744 635}
636
d62a17ae 637void ospf_ase_register_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
718e3744 638{
d62a17ae 639 struct route_node *rn;
640 struct prefix_ipv4 p;
641 struct list *lst;
642 struct as_external_lsa *al;
643
644 al = (struct as_external_lsa *)lsa->data;
645 p.family = AF_INET;
646 p.prefix = lsa->data->id;
647 p.prefixlen = ip_masklen(al->mask);
648 apply_mask_ipv4(&p);
649
650 rn = route_node_get(top->external_lsas, (struct prefix *)&p);
651 if ((lst = rn->info) == NULL)
652 rn->info = lst = list_new();
653 else
654 route_unlock_node(rn);
655
656 /* We assume that if LSA is deleted from DB
657 is is also deleted from this RT */
658 listnode_add(lst, ospf_lsa_lock(lsa)); /* external_lsas lst */
718e3744 659}
660
d62a17ae 661void ospf_ase_unregister_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
718e3744 662{
d62a17ae 663 struct route_node *rn;
664 struct prefix_ipv4 p;
665 struct list *lst;
666 struct as_external_lsa *al;
667
668 al = (struct as_external_lsa *)lsa->data;
669 p.family = AF_INET;
670 p.prefix = lsa->data->id;
671 p.prefixlen = ip_masklen(al->mask);
672 apply_mask_ipv4(&p);
673
674 rn = route_node_lookup(top->external_lsas, (struct prefix *)&p);
675
676 if (rn) {
677 lst = rn->info;
87627de6
MR
678 struct listnode *node = listnode_lookup(lst, lsa);
679 /* Unlock lsa only if node is present in the list */
680 if (node) {
681 listnode_delete(lst, lsa);
682 ospf_lsa_unlock(&lsa); /* external_lsas list */
683 }
f91ce319 684
d62a17ae 685 route_unlock_node(rn);
686 }
718e3744 687}
688
d62a17ae 689void ospf_ase_external_lsas_finish(struct route_table *rt)
718e3744 690{
d62a17ae 691 struct route_node *rn;
692 struct ospf_lsa *lsa;
693 struct list *lst;
694 struct listnode *node, *nnode;
695
696 for (rn = route_top(rt); rn; rn = route_next(rn))
697 if ((lst = rn->info) != NULL) {
698 for (ALL_LIST_ELEMENTS(lst, node, nnode, lsa))
699 ospf_lsa_unlock(&lsa); /* external_lsas lst */
6a154c88 700 list_delete(&lst);
d62a17ae 701 }
702
703 route_table_finish(rt);
718e3744 704}
705
d62a17ae 706void ospf_ase_incremental_update(struct ospf *ospf, struct ospf_lsa *lsa)
718e3744 707{
d62a17ae 708 struct list *lsas;
709 struct listnode *node;
710 struct route_node *rn, *rn2;
711 struct prefix_ipv4 p;
712 struct route_table *tmp_old;
713 struct as_external_lsa *al;
714
715 al = (struct as_external_lsa *)lsa->data;
716 p.family = AF_INET;
717 p.prefix = lsa->data->id;
718 p.prefixlen = ip_masklen(al->mask);
719 apply_mask_ipv4(&p);
720
721 /* if new_table is NULL, there was no spf calculation, thus
722 incremental update is unneeded */
723 if (!ospf->new_table)
724 return;
725
726 /* If there is already an intra-area or inter-area route
727 to the destination, no recalculation is necessary
728 (internal routes take precedence). */
729
730 rn = route_node_lookup(ospf->new_table, (struct prefix *)&p);
731 if (rn) {
732 route_unlock_node(rn);
733 if (rn->info)
734 return;
735 }
718e3744 736
d62a17ae 737 rn = route_node_lookup(ospf->external_lsas, (struct prefix *)&p);
738 assert(rn);
739 assert(rn->info);
740 lsas = rn->info;
741 route_unlock_node(rn);
742
743 for (ALL_LIST_ELEMENTS_RO(lsas, node, lsa))
744 ospf_ase_calculate_route(ospf, lsa);
745
746 /* prepare temporary old routing table for compare */
747 tmp_old = route_table_init();
748 rn = route_node_lookup(ospf->old_external_route, (struct prefix *)&p);
749 if (rn && rn->info) {
750 rn2 = route_node_get(tmp_old, (struct prefix *)&p);
751 rn2->info = rn->info;
752 route_unlock_node(rn);
753 }
718e3744 754
d62a17ae 755 /* install changes to zebra */
b5a8894d 756 ospf_ase_compare_tables(ospf, ospf->new_external_route, tmp_old);
d62a17ae 757
758 /* update ospf->old_external_route table */
759 if (rn && rn->info)
760 ospf_route_free((struct ospf_route *)rn->info);
761
762 rn2 = route_node_lookup(ospf->new_external_route, (struct prefix *)&p);
763 /* if new route exists, install it to ospf->old_external_route */
764 if (rn2 && rn2->info) {
765 if (!rn)
766 rn = route_node_get(ospf->old_external_route,
767 (struct prefix *)&p);
768 rn->info = rn2->info;
769 } else {
770 /* remove route node from ospf->old_external_route */
771 if (rn) {
772 rn->info = NULL;
773 route_unlock_node(rn);
774 }
718e3744 775 }
718e3744 776
d62a17ae 777 if (rn2) {
778 /* rn2->info is stored in route node of ospf->old_external_route
779 */
780 rn2->info = NULL;
781 route_unlock_node(rn2);
782 route_unlock_node(rn2);
783 }
718e3744 784
d62a17ae 785 route_table_finish(tmp_old);
718e3744 786}