]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_ase.c
Merge pull request #8983 from mobash-rasool/pim-upstreaming-activity
[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
4dadc291 159static struct ospf_route *
d62a17ae 160ospf_ase_calculate_new_route(struct ospf_lsa *lsa,
d7c0a89a 161 struct ospf_route *asbr_route, uint32_t metric)
718e3744 162{
d62a17ae 163 struct as_external_lsa *al;
164 struct ospf_route *new;
165
166 al = (struct as_external_lsa *)lsa->data;
167
168 new = ospf_route_new();
169
170 /* Set redistributed type -- does make sense? */
171 /* new->type = type; */
172 new->id = al->header.id;
173 new->mask = al->mask;
174
175 if (!IS_EXTERNAL_METRIC(al->e[0].tos)) {
176 if (IS_DEBUG_OSPF(lsa, LSA))
177 zlog_debug("Route[External]: type-1 created.");
178 new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
179 new->cost = asbr_route->cost + metric; /* X + Y */
180 } else {
181 if (IS_DEBUG_OSPF(lsa, LSA))
182 zlog_debug("Route[External]: type-2 created.");
183 new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
184 new->cost = asbr_route->cost; /* X */
185 new->u.ext.type2_cost = metric; /* Y */
186 }
718e3744 187
d62a17ae 188 new->type = OSPF_DESTINATION_NETWORK;
189 new->u.ext.origin = lsa;
190 new->u.ext.tag = ntohl(al->e[0].route_tag);
191 new->u.ext.asbr = asbr_route;
718e3744 192
d62a17ae 193 assert(new != asbr_route);
718e3744 194
d62a17ae 195 return new;
718e3744 196}
197
198#define OSPF_ASE_CALC_INTERVAL 1
199
d62a17ae 200int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa)
718e3744 201{
d7c0a89a 202 uint32_t metric;
d62a17ae 203 struct as_external_lsa *al;
204 struct ospf_route *asbr_route;
205 struct prefix_ipv4 asbr, p;
206 struct route_node *rn;
207 struct ospf_route *new, * or ;
208 int ret;
209
210 assert(lsa);
211 al = (struct as_external_lsa *)lsa->data;
212
213 if (lsa->data->type == OSPF_AS_NSSA_LSA)
214 if (IS_DEBUG_OSPF_NSSA)
215 zlog_debug("ospf_ase_calc(): Processing Type-7");
216
217 /* Stay away from any Local Translated Type-7 LSAs */
218 if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) {
219 if (IS_DEBUG_OSPF_NSSA)
220 zlog_debug("ospf_ase_calc(): Rejecting Local Xlt'd");
221 return 0;
718e3744 222 }
718e3744 223
96065dc3 224 if (IS_DEBUG_OSPF(lsa, LSA)) {
d62a17ae 225 zlog_debug(
96b663a3
MS
226 "Route[External]: Calculate AS-external-LSA to %pI4/%d adv_router %pI4",
227 &al->header.id, ip_masklen(al->mask),
228 &al->header.adv_router);
96065dc3
CS
229 }
230
d62a17ae 231 /* (1) If the cost specified by the LSA is LSInfinity, or if the
232 LSA's LS age is equal to MaxAge, then examine the next LSA. */
233 if ((metric = GET_METRIC(al->e[0].metric)) >= OSPF_LS_INFINITY) {
234 if (IS_DEBUG_OSPF(lsa, LSA))
235 zlog_debug(
236 "Route[External]: Metric is OSPF_LS_INFINITY");
237 return 0;
238 }
239 if (IS_LSA_MAXAGE(lsa)) {
240 if (IS_DEBUG_OSPF(lsa, LSA))
241 zlog_debug(
242 "Route[External]: AS-external-LSA is MAXAGE");
243 return 0;
718e3744 244 }
245
d62a17ae 246 /* (2) If the LSA was originated by the calculating router itself,
247 examine the next LSA. */
248 if (IS_LSA_SELF(lsa)) {
249 if (IS_DEBUG_OSPF(lsa, LSA))
250 zlog_debug(
251 "Route[External]: AS-external-LSA is self originated");
252 return 0;
253 }
718e3744 254
d62a17ae 255 /* (3) Call the destination described by the LSA N. N's address is
256 obtained by masking the LSA's Link State ID with the
257 network/subnet mask contained in the body of the LSA. Look
258 up the routing table entries (potentially one per attached
259 area) for the AS boundary router (ASBR) that originated the
260 LSA. If no entries exist for router ASBR (i.e., ASBR is
261 unreachable), do nothing with this LSA and consider the next
262 in the list. */
263
264 asbr.family = AF_INET;
265 asbr.prefix = al->header.adv_router;
266 asbr.prefixlen = IPV4_MAX_BITLEN;
267 apply_mask_ipv4(&asbr);
268
269 asbr_route = ospf_find_asbr_route(ospf, ospf->new_rtrs, &asbr);
270 if (asbr_route == NULL) {
271 if (IS_DEBUG_OSPF(lsa, LSA))
272 zlog_debug(
273 "Route[External]: Can't find originating ASBR route");
274 return 0;
275 }
276 if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) {
277 if (IS_DEBUG_OSPF(lsa, LSA))
278 zlog_debug(
279 "Route[External]: Originating router is not an ASBR");
280 return 0;
281 }
718e3744 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
d62a17ae 554static int ospf_ase_calculate_timer(struct thread *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
563 ospf = THREAD_ARG(t);
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)
579 zlog_debug(
96b663a3
MS
580 "ospf_ase_calculate_timer(): looking at area %pI4",
581 &area->area_id);
d62a17ae 582
583 if (area->external_routing == OSPF_AREA_NSSA)
996c9314 584 LSDB_LOOP (NSSA_LSDB(area), rn, lsa)
044506e7
DS
585 ospf_ase_calculate_route(ospf,
586 lsa);
d62a17ae 587 }
588 /* kevinm: And add the NSSA routes in ospf_top */
996c9314 589 LSDB_LOOP (NSSA_LSDB(ospf), rn, lsa)
044506e7 590 ospf_ase_calculate_route(ospf, lsa);
d62a17ae 591
592 /* Compare old and new external routing table and install the
593 difference info zebra/kernel */
b5a8894d 594 ospf_ase_compare_tables(ospf, ospf->new_external_route,
d62a17ae 595 ospf->old_external_route);
596
597 /* Delete old external routing table */
598 ospf_route_table_free(ospf->old_external_route);
599 ospf->old_external_route = ospf->new_external_route;
600 ospf->new_external_route = route_table_init();
601
602 monotime(&stop_time);
603
05ba78e4 604 if (IS_DEBUG_OSPF_EVENT)
996c9314 605 zlog_info(
63efca0e 606 "SPF Processing Time(usecs): External Routes: %lld",
996c9314
LB
607 (stop_time.tv_sec - start_time.tv_sec)
608 * 1000000LL
609 + (stop_time.tv_usec
610 - start_time.tv_usec));
d62a17ae 611 }
10514170
RW
612
613 /*
614 * Uninstall remnant routes that were installed before the restart, but
615 * that are no longer valid.
616 */
617 if (ospf->gr_info.finishing_restart) {
618 ospf_zebra_gr_disable(ospf);
619 ospf->gr_info.finishing_restart = false;
620 }
621
d62a17ae 622 return 0;
718e3744 623}
624
d62a17ae 625void ospf_ase_calculate_schedule(struct ospf *ospf)
718e3744 626{
d62a17ae 627 if (ospf == NULL)
628 return;
718e3744 629
d62a17ae 630 ospf->ase_calc = 1;
718e3744 631}
632
d62a17ae 633void ospf_ase_calculate_timer_add(struct ospf *ospf)
718e3744 634{
d62a17ae 635 if (ospf == NULL)
636 return;
718e3744 637
d62a17ae 638 thread_add_timer(master, ospf_ase_calculate_timer, ospf,
639 OSPF_ASE_CALC_INTERVAL, &ospf->t_ase_calc);
718e3744 640}
641
d62a17ae 642void ospf_ase_register_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
718e3744 643{
d62a17ae 644 struct route_node *rn;
645 struct prefix_ipv4 p;
646 struct list *lst;
647 struct as_external_lsa *al;
648
649 al = (struct as_external_lsa *)lsa->data;
650 p.family = AF_INET;
651 p.prefix = lsa->data->id;
652 p.prefixlen = ip_masklen(al->mask);
653 apply_mask_ipv4(&p);
654
655 rn = route_node_get(top->external_lsas, (struct prefix *)&p);
656 if ((lst = rn->info) == NULL)
657 rn->info = lst = list_new();
658 else
659 route_unlock_node(rn);
660
661 /* We assume that if LSA is deleted from DB
662 is is also deleted from this RT */
663 listnode_add(lst, ospf_lsa_lock(lsa)); /* external_lsas lst */
718e3744 664}
665
d62a17ae 666void ospf_ase_unregister_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
718e3744 667{
d62a17ae 668 struct route_node *rn;
669 struct prefix_ipv4 p;
670 struct list *lst;
671 struct as_external_lsa *al;
672
673 al = (struct as_external_lsa *)lsa->data;
674 p.family = AF_INET;
675 p.prefix = lsa->data->id;
676 p.prefixlen = ip_masklen(al->mask);
677 apply_mask_ipv4(&p);
678
679 rn = route_node_lookup(top->external_lsas, (struct prefix *)&p);
680
681 if (rn) {
682 lst = rn->info;
87627de6
MR
683 struct listnode *node = listnode_lookup(lst, lsa);
684 /* Unlock lsa only if node is present in the list */
685 if (node) {
686 listnode_delete(lst, lsa);
687 ospf_lsa_unlock(&lsa); /* external_lsas list */
688 }
f91ce319 689
d62a17ae 690 route_unlock_node(rn);
691 }
718e3744 692}
693
d62a17ae 694void ospf_ase_external_lsas_finish(struct route_table *rt)
718e3744 695{
d62a17ae 696 struct route_node *rn;
697 struct ospf_lsa *lsa;
698 struct list *lst;
699 struct listnode *node, *nnode;
700
701 for (rn = route_top(rt); rn; rn = route_next(rn))
702 if ((lst = rn->info) != NULL) {
703 for (ALL_LIST_ELEMENTS(lst, node, nnode, lsa))
704 ospf_lsa_unlock(&lsa); /* external_lsas lst */
6a154c88 705 list_delete(&lst);
d62a17ae 706 }
707
708 route_table_finish(rt);
718e3744 709}
710
d62a17ae 711void ospf_ase_incremental_update(struct ospf *ospf, struct ospf_lsa *lsa)
718e3744 712{
d62a17ae 713 struct list *lsas;
714 struct listnode *node;
715 struct route_node *rn, *rn2;
716 struct prefix_ipv4 p;
717 struct route_table *tmp_old;
718 struct as_external_lsa *al;
719
720 al = (struct as_external_lsa *)lsa->data;
721 p.family = AF_INET;
722 p.prefix = lsa->data->id;
723 p.prefixlen = ip_masklen(al->mask);
724 apply_mask_ipv4(&p);
725
726 /* if new_table is NULL, there was no spf calculation, thus
727 incremental update is unneeded */
728 if (!ospf->new_table)
729 return;
730
731 /* If there is already an intra-area or inter-area route
732 to the destination, no recalculation is necessary
733 (internal routes take precedence). */
734
735 rn = route_node_lookup(ospf->new_table, (struct prefix *)&p);
736 if (rn) {
737 route_unlock_node(rn);
738 if (rn->info)
739 return;
740 }
718e3744 741
d62a17ae 742 rn = route_node_lookup(ospf->external_lsas, (struct prefix *)&p);
743 assert(rn);
744 assert(rn->info);
745 lsas = rn->info;
746 route_unlock_node(rn);
747
748 for (ALL_LIST_ELEMENTS_RO(lsas, node, lsa))
749 ospf_ase_calculate_route(ospf, lsa);
750
751 /* prepare temporary old routing table for compare */
752 tmp_old = route_table_init();
753 rn = route_node_lookup(ospf->old_external_route, (struct prefix *)&p);
754 if (rn && rn->info) {
755 rn2 = route_node_get(tmp_old, (struct prefix *)&p);
756 rn2->info = rn->info;
757 route_unlock_node(rn);
758 }
718e3744 759
d62a17ae 760 /* install changes to zebra */
b5a8894d 761 ospf_ase_compare_tables(ospf, ospf->new_external_route, tmp_old);
d62a17ae 762
763 /* update ospf->old_external_route table */
764 if (rn && rn->info)
765 ospf_route_free((struct ospf_route *)rn->info);
766
767 rn2 = route_node_lookup(ospf->new_external_route, (struct prefix *)&p);
768 /* if new route exists, install it to ospf->old_external_route */
769 if (rn2 && rn2->info) {
770 if (!rn)
771 rn = route_node_get(ospf->old_external_route,
772 (struct prefix *)&p);
773 rn->info = rn2->info;
774 } else {
775 /* remove route node from ospf->old_external_route */
776 if (rn) {
777 rn->info = NULL;
778 route_unlock_node(rn);
779 }
718e3744 780 }
718e3744 781
d62a17ae 782 if (rn2) {
783 /* rn2->info is stored in route node of ospf->old_external_route
784 */
785 rn2->info = NULL;
786 route_unlock_node(rn2);
787 route_unlock_node(rn2);
788 }
718e3744 789
d62a17ae 790 route_table_finish(tmp_old);
718e3744 791}