]>
git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_ase.c
2 * OSPF AS external route calculation.
3 * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada
5 * This file is part of GNU Zebra.
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
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.
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
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"
48 struct ospf_route
*ospf_find_asbr_route(struct ospf
*ospf
,
49 struct route_table
*rtrs
,
50 struct prefix_ipv4
*asbr
)
52 struct route_node
*rn
;
53 struct ospf_route
* or, *best
= NULL
;
54 struct listnode
*node
;
61 rn
= route_node_lookup(rtrs
, (struct prefix
*)asbr
);
65 route_unlock_node(rn
);
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
)
75 or->path_type
== OSPF_PATH_INTRA_AREA
)
76 listnode_add(chosen
, or);
78 /* If none is found -- look through all. */
79 if (listcount(chosen
) == 0) {
84 /* Now find the route with least cost. */
85 for (ALL_LIST_ELEMENTS_RO(chosen
, node
, or))
86 if (or->cost
< OSPF_LS_INFINITY
) {
89 else if (best
->cost
> or->cost
)
91 else if (best
->cost
==
100 if (chosen
!= rn
->info
)
101 list_delete(&chosen
);
106 struct ospf_route
*ospf_find_asbr_route_through_area(struct route_table
*rtrs
,
107 struct prefix_ipv4
*asbr
,
108 struct ospf_area
*area
)
110 struct route_node
*rn
;
116 rn
= route_node_lookup(rtrs
, (struct prefix
*)asbr
);
119 struct listnode
*node
;
120 struct ospf_route
* or ;
122 route_unlock_node(rn
);
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
))
132 static void ospf_ase_complete_direct_routes(struct ospf_route
*ro
,
133 struct in_addr nexthop
)
135 struct listnode
*node
;
136 struct ospf_path
*op
;
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
;
143 static int ospf_ase_forward_address_check(struct ospf
*ospf
,
144 struct in_addr fwd_addr
)
146 struct listnode
*ifn
;
147 struct ospf_interface
*oi
;
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
,
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
)
167 struct prefix_ipv4 asbr
;
168 struct ospf_route
*asbr_route
;
169 struct route_node
*rn
;
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
);
177 asbr_route
= ospf_find_asbr_route (ospf
, rt_router
, &asbr
);
179 if (asbr_route
== NULL
)
181 if (IS_DEBUG_OSPF (lsa
, LSA
))
182 zlog_debug ("ospf_ase_calculate(): Route to ASBR %s not found",
183 inet_ntoa (asbr
.prefix
));
187 if (!(asbr_route
->u
.std
.flags
& ROUTER_LSA_EXTERNAL
))
189 if (IS_DEBUG_OSPF (lsa
, LSA
))
190 zlog_debug ("ospf_ase_calculate(): Originating router is not an ASBR");
194 if (al
->e
[0].fwd_addr
.s_addr
!= 0)
196 if (IS_DEBUG_OSPF (lsa
, LSA
))
197 zlog_debug ("ospf_ase_calculate(): "
198 "Forwarding address is not 0.0.0.0.");
200 if (! ospf_ase_forward_address_check (ospf
, al
->e
[0].fwd_addr
))
202 if (IS_DEBUG_OSPF (lsa
, LSA
))
203 zlog_debug ("ospf_ase_calculate(): "
204 "Forwarding address is one of our addresses, Ignore.");
208 if (IS_DEBUG_OSPF (lsa
, LSA
))
209 zlog_debug ("ospf_ase_calculate(): "
210 "Looking up in the Network Routing Table.");
212 /* Looking up the path to the fwd_addr from Network route. */
213 asbr
.family
= AF_INET
;
214 asbr
.prefix
= al
->e
[0].fwd_addr
;
215 asbr
.prefixlen
= IPV4_MAX_BITLEN
;
217 rn
= route_node_match (rt_network
, (struct prefix
*) &asbr
);
221 if (IS_DEBUG_OSPF (lsa
, LSA
))
222 zlog_debug ("ospf_ase_calculate(): "
223 "Couldn't find a route to the forwarding address.");
227 route_unlock_node (rn
);
229 if ((asbr_route
= rn
->info
) == NULL
)
231 if (IS_DEBUG_OSPF (lsa
, LSA
))
232 zlog_debug ("ospf_ase_calculate(): "
233 "Somehow OSPF route to ASBR is lost");
242 static struct ospf_route
*
243 ospf_ase_calculate_new_route(struct ospf_lsa
*lsa
,
244 struct ospf_route
*asbr_route
, uint32_t metric
)
246 struct as_external_lsa
*al
;
247 struct ospf_route
*new;
249 al
= (struct as_external_lsa
*)lsa
->data
;
251 new = ospf_route_new();
253 /* Set redistributed type -- does make sense? */
254 /* new->type = type; */
255 new->id
= al
->header
.id
;
256 new->mask
= al
->mask
;
258 if (!IS_EXTERNAL_METRIC(al
->e
[0].tos
)) {
259 if (IS_DEBUG_OSPF(lsa
, LSA
))
260 zlog_debug("Route[External]: type-1 created.");
261 new->path_type
= OSPF_PATH_TYPE1_EXTERNAL
;
262 new->cost
= asbr_route
->cost
+ metric
; /* X + Y */
264 if (IS_DEBUG_OSPF(lsa
, LSA
))
265 zlog_debug("Route[External]: type-2 created.");
266 new->path_type
= OSPF_PATH_TYPE2_EXTERNAL
;
267 new->cost
= asbr_route
->cost
; /* X */
268 new->u
.ext
.type2_cost
= metric
; /* Y */
271 new->type
= OSPF_DESTINATION_NETWORK
;
272 new->u
.ext
.origin
= lsa
;
273 new->u
.ext
.tag
= ntohl(al
->e
[0].route_tag
);
274 new->u
.ext
.asbr
= asbr_route
;
276 assert(new != asbr_route
);
281 #define OSPF_ASE_CALC_INTERVAL 1
283 int ospf_ase_calculate_route(struct ospf
*ospf
, struct ospf_lsa
*lsa
)
286 struct as_external_lsa
*al
;
287 struct ospf_route
*asbr_route
;
288 struct prefix_ipv4 asbr
, p
;
289 struct route_node
*rn
;
290 struct ospf_route
*new, * or ;
291 char buf1
[INET_ADDRSTRLEN
];
295 al
= (struct as_external_lsa
*)lsa
->data
;
297 if (lsa
->data
->type
== OSPF_AS_NSSA_LSA
)
298 if (IS_DEBUG_OSPF_NSSA
)
299 zlog_debug("ospf_ase_calc(): Processing Type-7");
301 /* Stay away from any Local Translated Type-7 LSAs */
302 if (CHECK_FLAG(lsa
->flags
, OSPF_LSA_LOCAL_XLT
)) {
303 if (IS_DEBUG_OSPF_NSSA
)
304 zlog_debug("ospf_ase_calc(): Rejecting Local Xlt'd");
308 if (IS_DEBUG_OSPF(lsa
, LSA
)) {
309 snprintf(buf1
, INET_ADDRSTRLEN
, "%s",
310 inet_ntoa(al
->header
.adv_router
));
312 "Route[External]: Calculate AS-external-LSA to %s/%d adv_router %s",
313 inet_ntoa(al
->header
.id
), ip_masklen(al
->mask
), buf1
);
316 /* (1) If the cost specified by the LSA is LSInfinity, or if the
317 LSA's LS age is equal to MaxAge, then examine the next LSA. */
318 if ((metric
= GET_METRIC(al
->e
[0].metric
)) >= OSPF_LS_INFINITY
) {
319 if (IS_DEBUG_OSPF(lsa
, LSA
))
321 "Route[External]: Metric is OSPF_LS_INFINITY");
324 if (IS_LSA_MAXAGE(lsa
)) {
325 if (IS_DEBUG_OSPF(lsa
, LSA
))
327 "Route[External]: AS-external-LSA is MAXAGE");
331 /* (2) If the LSA was originated by the calculating router itself,
332 examine the next LSA. */
333 if (IS_LSA_SELF(lsa
)) {
334 if (IS_DEBUG_OSPF(lsa
, LSA
))
336 "Route[External]: AS-external-LSA is self originated");
340 /* (3) Call the destination described by the LSA N. N's address is
341 obtained by masking the LSA's Link State ID with the
342 network/subnet mask contained in the body of the LSA. Look
343 up the routing table entries (potentially one per attached
344 area) for the AS boundary router (ASBR) that originated the
345 LSA. If no entries exist for router ASBR (i.e., ASBR is
346 unreachable), do nothing with this LSA and consider the next
349 asbr
.family
= AF_INET
;
350 asbr
.prefix
= al
->header
.adv_router
;
351 asbr
.prefixlen
= IPV4_MAX_BITLEN
;
352 apply_mask_ipv4(&asbr
);
354 asbr_route
= ospf_find_asbr_route(ospf
, ospf
->new_rtrs
, &asbr
);
355 if (asbr_route
== NULL
) {
356 if (IS_DEBUG_OSPF(lsa
, LSA
))
358 "Route[External]: Can't find originating ASBR route");
361 if (!(asbr_route
->u
.std
.flags
& ROUTER_LSA_EXTERNAL
)) {
362 if (IS_DEBUG_OSPF(lsa
, LSA
))
364 "Route[External]: Originating router is not an ASBR");
368 /* Else, this LSA describes an AS external path to destination
369 N. Examine the forwarding address specified in the AS-
370 external-LSA. This indicates the IP address to which
371 packets for the destination should be forwarded. */
373 if (al
->e
[0].fwd_addr
.s_addr
== INADDR_ANY
) {
374 /* If the forwarding address is set to 0.0.0.0, packets should
375 be sent to the ASBR itself. Among the multiple routing table
376 entries for the ASBR, select the preferred entry as follows.
377 If RFC1583Compatibility is set to "disabled", prune the set
378 of routing table entries for the ASBR as described in
379 Section 16.4.1. In any case, among the remaining routing
380 table entries, select the routing table entry with the least
381 cost; when there are multiple least cost routing table
382 entries the entry whose associated area has the largest OSPF
383 Area ID (when considered as an unsigned 32-bit integer) is
386 /* asbr_route already contains the requested route */
388 /* If the forwarding address is non-zero, look up the
389 forwarding address in the routing table.[24] The matching
390 routing table entry must specify an intra-area or inter-area
391 path; if no such path exists, do nothing with the LSA and
392 consider the next in the list. */
393 if (!ospf_ase_forward_address_check(ospf
, al
->e
[0].fwd_addr
)) {
394 if (IS_DEBUG_OSPF(lsa
, LSA
))
396 "Route[External]: Forwarding address is our router "
401 asbr
.family
= AF_INET
;
402 asbr
.prefix
= al
->e
[0].fwd_addr
;
403 asbr
.prefixlen
= IPV4_MAX_BITLEN
;
405 rn
= route_node_match(ospf
->new_table
, (struct prefix
*)&asbr
);
407 if (rn
== NULL
|| (asbr_route
= rn
->info
) == NULL
) {
408 if (IS_DEBUG_OSPF(lsa
, LSA
))
410 "Route[External]: Can't find route to forwarding "
413 route_unlock_node(rn
);
417 route_unlock_node(rn
);
420 /* (4) Let X be the cost specified by the preferred routing table
421 entry for the ASBR/forwarding address, and Y the cost
422 specified in the LSA. X is in terms of the link state
423 metric, and Y is a type 1 or 2 external metric. */
426 /* (5) Look up the routing table entry for the destination N. If
427 no entry exists for N, install the AS external path to N,
428 with next hop equal to the list of next hops to the
429 forwarding address, and advertising router equal to ASBR.
430 If the external metric type is 1, then the path-type is set
431 to type 1 external and the cost is equal to X+Y. If the
432 external metric type is 2, the path-type is set to type 2
433 external, the link state component of the route's cost is X,
434 and the type 2 cost is Y. */
435 new = ospf_ase_calculate_new_route(lsa
, asbr_route
, metric
);
437 /* (6) Compare the AS external path described by the LSA with the
438 existing paths in N's routing table entry, as follows. If
439 the new path is preferred, it replaces the present paths in
440 N's routing table entry. If the new path is of equal
441 preference, it is added to N's routing table entry's list of
446 p
.prefix
= al
->header
.id
;
447 p
.prefixlen
= ip_masklen(al
->mask
);
449 /* if there is a Intra/Inter area route to the N
450 do not install external route */
451 if ((rn
= route_node_lookup(ospf
->new_table
, (struct prefix
*)&p
))) {
452 route_unlock_node(rn
);
453 if (rn
->info
== NULL
)
454 zlog_info("Route[External]: rn->info NULL");
456 ospf_route_free(new);
459 /* Find a route to the same dest */
460 /* If there is no route, create new one. */
461 if ((rn
= route_node_lookup(ospf
->new_external_route
,
462 (struct prefix
*)&p
)))
463 route_unlock_node(rn
);
465 if (!rn
|| (or = rn
->info
) == NULL
) {
466 if (IS_DEBUG_OSPF(lsa
, LSA
))
467 zlog_debug("Route[External]: Adding a new route %s/%d with paths %u",
468 inet_ntoa(p
.prefix
), p
.prefixlen
,
469 listcount(asbr_route
->paths
));
471 ospf_route_add(ospf
->new_external_route
, &p
, new, asbr_route
);
473 if (al
->e
[0].fwd_addr
.s_addr
!= INADDR_ANY
)
474 ospf_ase_complete_direct_routes(new, al
->e
[0].fwd_addr
);
477 /* (a) Intra-area and inter-area paths are always preferred
478 over AS external paths.
480 (b) Type 1 external paths are always preferred over type 2
481 external paths. When all paths are type 2 external
482 paths, the paths with the smallest advertised type 2
483 metric are always preferred. */
484 ret
= ospf_route_cmp(ospf
, new, or);
486 /* (c) If the new AS external path is still
488 from the current paths in the N's routing table
490 and RFC1583Compatibility is set to "disabled", select
491 the preferred paths based on the intra-AS paths to
493 ASBR/forwarding addresses, as specified in Section
496 (d) If the new AS external path is still
498 from the current paths in the N's routing table
500 select the preferred path based on a least cost
501 comparison. Type 1 external paths are compared by
502 looking at the sum of the distance to the forwarding
503 address and the advertised type 1 metric (X+Y). Type
505 external paths advertising equal type 2 metrics are
506 compared by looking at the distance to the forwarding
509 /* New route is better */
511 if (IS_DEBUG_OSPF(lsa
, LSA
))
513 "Route[External]: New route is better");
514 ospf_route_subst(rn
, new, asbr_route
);
515 if (al
->e
[0].fwd_addr
.s_addr
!= INADDR_ANY
)
516 ospf_ase_complete_direct_routes(
517 new, al
->e
[0].fwd_addr
);
521 /* Old route is better */
523 if (IS_DEBUG_OSPF(lsa
, LSA
))
525 "Route[External]: Old route is better");
528 /* Routes are equal */
530 if (IS_DEBUG_OSPF(lsa
, LSA
))
531 zlog_debug("Route[External]: Routes are equal");
532 ospf_route_copy_nexthops(or, asbr_route
->paths
);
533 if (al
->e
[0].fwd_addr
.s_addr
!= INADDR_ANY
)
534 ospf_ase_complete_direct_routes(
535 or, al
->e
[0].fwd_addr
);
538 /* Make sure setting newly calculated ASBR route.*/
539 or->u
.ext
.asbr
= asbr_route
;
541 ospf_route_free(new);
547 static int ospf_ase_route_match_same(struct route_table
*rt
,
548 struct prefix
*prefix
,
549 struct ospf_route
*newor
)
551 struct route_node
*rn
;
552 struct ospf_route
*or;
553 struct ospf_path
*op
;
554 struct ospf_path
*newop
;
561 rn
= route_node_lookup(rt
, prefix
);
565 route_unlock_node(rn
);
571 if (or->path_type
!= newor
->path_type
)
574 switch (or->path_type
) {
575 case OSPF_PATH_TYPE1_EXTERNAL
:
576 if (or->cost
!= newor
->cost
)
579 case OSPF_PATH_TYPE2_EXTERNAL
:
580 if ((or->cost
!= newor
->cost
)
581 || (or->u
.ext
.type2_cost
!= newor
->u
.ext
.type2_cost
))
591 if (or->paths
->count
!= newor
->paths
->count
)
594 /* Check each path. */
595 for (n1
= listhead(or->paths
), n2
= listhead(newor
->paths
); n1
&& n2
;
596 n1
= listnextnode_unchecked(n1
), n2
= listnextnode_unchecked(n2
)) {
597 op
= listgetdata(n1
);
598 newop
= listgetdata(n2
);
600 if (!IPV4_ADDR_SAME(&op
->nexthop
, &newop
->nexthop
))
602 if (op
->ifindex
!= newop
->ifindex
)
606 if (or->u
.ext
.tag
!= newor
->u
.ext
.tag
)
612 static int ospf_ase_compare_tables(struct ospf
*ospf
,
613 struct route_table
*new_external_route
,
614 struct route_table
*old_external_route
)
616 struct route_node
*rn
, *new_rn
;
617 struct ospf_route
* or ;
619 /* Remove deleted routes */
620 for (rn
= route_top(old_external_route
); rn
; rn
= route_next(rn
))
621 if ((or = rn
->info
)) {
622 if (!(new_rn
= route_node_lookup(new_external_route
,
625 ospf
, (struct prefix_ipv4
*)&rn
->p
, or);
627 route_unlock_node(new_rn
);
631 /* Install new routes */
632 for (rn
= route_top(new_external_route
); rn
; rn
= route_next(rn
))
633 if ((or = rn
->info
) != NULL
)
634 if (!ospf_ase_route_match_same(old_external_route
,
637 ospf
, (struct prefix_ipv4
*)&rn
->p
, or);
642 static int ospf_ase_calculate_timer(struct thread
*t
)
645 struct ospf_lsa
*lsa
;
646 struct route_node
*rn
;
647 struct listnode
*node
;
648 struct ospf_area
*area
;
649 struct timeval start_time
, stop_time
;
651 ospf
= THREAD_ARG(t
);
652 ospf
->t_ase_calc
= NULL
;
654 if (ospf
->ase_calc
) {
657 monotime(&start_time
);
659 /* Calculate external route for each AS-external-LSA */
660 LSDB_LOOP (EXTERNAL_LSDB(ospf
), rn
, lsa
)
661 ospf_ase_calculate_route(ospf
, lsa
);
663 /* This version simple adds to the table all NSSA areas */
665 for (ALL_LIST_ELEMENTS_RO(ospf
->areas
, node
, area
)) {
666 if (IS_DEBUG_OSPF_NSSA
)
668 "ospf_ase_calculate_timer(): looking at area %s",
669 inet_ntoa(area
->area_id
));
671 if (area
->external_routing
== OSPF_AREA_NSSA
)
672 LSDB_LOOP (NSSA_LSDB(area
), rn
, lsa
)
673 ospf_ase_calculate_route(ospf
,
676 /* kevinm: And add the NSSA routes in ospf_top */
677 LSDB_LOOP (NSSA_LSDB(ospf
), rn
, lsa
)
678 ospf_ase_calculate_route(ospf
, lsa
);
680 /* Compare old and new external routing table and install the
681 difference info zebra/kernel */
682 ospf_ase_compare_tables(ospf
, ospf
->new_external_route
,
683 ospf
->old_external_route
);
685 /* Delete old external routing table */
686 ospf_route_table_free(ospf
->old_external_route
);
687 ospf
->old_external_route
= ospf
->new_external_route
;
688 ospf
->new_external_route
= route_table_init();
690 monotime(&stop_time
);
692 if (IS_DEBUG_OSPF_EVENT
)
694 "SPF Processing Time(usecs): External Routes: %lld\n",
695 (stop_time
.tv_sec
- start_time
.tv_sec
)
698 - start_time
.tv_usec
));
703 void ospf_ase_calculate_schedule(struct ospf
*ospf
)
711 void ospf_ase_calculate_timer_add(struct ospf
*ospf
)
716 thread_add_timer(master
, ospf_ase_calculate_timer
, ospf
,
717 OSPF_ASE_CALC_INTERVAL
, &ospf
->t_ase_calc
);
720 void ospf_ase_register_external_lsa(struct ospf_lsa
*lsa
, struct ospf
*top
)
722 struct route_node
*rn
;
723 struct prefix_ipv4 p
;
725 struct as_external_lsa
*al
;
727 al
= (struct as_external_lsa
*)lsa
->data
;
729 p
.prefix
= lsa
->data
->id
;
730 p
.prefixlen
= ip_masklen(al
->mask
);
733 rn
= route_node_get(top
->external_lsas
, (struct prefix
*)&p
);
734 if ((lst
= rn
->info
) == NULL
)
735 rn
->info
= lst
= list_new();
737 route_unlock_node(rn
);
739 /* We assume that if LSA is deleted from DB
740 is is also deleted from this RT */
741 listnode_add(lst
, ospf_lsa_lock(lsa
)); /* external_lsas lst */
744 void ospf_ase_unregister_external_lsa(struct ospf_lsa
*lsa
, struct ospf
*top
)
746 struct route_node
*rn
;
747 struct prefix_ipv4 p
;
749 struct as_external_lsa
*al
;
751 al
= (struct as_external_lsa
*)lsa
->data
;
753 p
.prefix
= lsa
->data
->id
;
754 p
.prefixlen
= ip_masklen(al
->mask
);
757 rn
= route_node_lookup(top
->external_lsas
, (struct prefix
*)&p
);
761 listnode_delete(lst
, lsa
);
762 ospf_lsa_unlock(&lsa
); /* external_lsas list */
763 route_unlock_node(rn
);
767 void ospf_ase_external_lsas_finish(struct route_table
*rt
)
769 struct route_node
*rn
;
770 struct ospf_lsa
*lsa
;
772 struct listnode
*node
, *nnode
;
774 for (rn
= route_top(rt
); rn
; rn
= route_next(rn
))
775 if ((lst
= rn
->info
) != NULL
) {
776 for (ALL_LIST_ELEMENTS(lst
, node
, nnode
, lsa
))
777 ospf_lsa_unlock(&lsa
); /* external_lsas lst */
781 route_table_finish(rt
);
784 void ospf_ase_incremental_update(struct ospf
*ospf
, struct ospf_lsa
*lsa
)
787 struct listnode
*node
;
788 struct route_node
*rn
, *rn2
;
789 struct prefix_ipv4 p
;
790 struct route_table
*tmp_old
;
791 struct as_external_lsa
*al
;
793 al
= (struct as_external_lsa
*)lsa
->data
;
795 p
.prefix
= lsa
->data
->id
;
796 p
.prefixlen
= ip_masklen(al
->mask
);
799 /* if new_table is NULL, there was no spf calculation, thus
800 incremental update is unneeded */
801 if (!ospf
->new_table
)
804 /* If there is already an intra-area or inter-area route
805 to the destination, no recalculation is necessary
806 (internal routes take precedence). */
808 rn
= route_node_lookup(ospf
->new_table
, (struct prefix
*)&p
);
810 route_unlock_node(rn
);
815 rn
= route_node_lookup(ospf
->external_lsas
, (struct prefix
*)&p
);
819 route_unlock_node(rn
);
821 for (ALL_LIST_ELEMENTS_RO(lsas
, node
, lsa
))
822 ospf_ase_calculate_route(ospf
, lsa
);
824 /* prepare temporary old routing table for compare */
825 tmp_old
= route_table_init();
826 rn
= route_node_lookup(ospf
->old_external_route
, (struct prefix
*)&p
);
827 if (rn
&& rn
->info
) {
828 rn2
= route_node_get(tmp_old
, (struct prefix
*)&p
);
829 rn2
->info
= rn
->info
;
830 route_unlock_node(rn
);
833 /* install changes to zebra */
834 ospf_ase_compare_tables(ospf
, ospf
->new_external_route
, tmp_old
);
836 /* update ospf->old_external_route table */
838 ospf_route_free((struct ospf_route
*)rn
->info
);
840 rn2
= route_node_lookup(ospf
->new_external_route
, (struct prefix
*)&p
);
841 /* if new route exists, install it to ospf->old_external_route */
842 if (rn2
&& rn2
->info
) {
844 rn
= route_node_get(ospf
->old_external_route
,
845 (struct prefix
*)&p
);
846 rn
->info
= rn2
->info
;
848 /* remove route node from ospf->old_external_route */
851 route_unlock_node(rn
);
856 /* rn2->info is stored in route node of ospf->old_external_route
859 route_unlock_node(rn2
);
860 route_unlock_node(rn2
);
863 route_table_finish(tmp_old
);