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