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