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