]>
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
== INADDR_ANY
)
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 %pI4 not found",
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
!= INADDR_ANY
)
196 if (IS_DEBUG_OSPF (lsa
, LSA
))
197 zlog_debug ("ospf_ase_calculate(): Forwarding address is not 0.0.0.0.");
199 if (! ospf_ase_forward_address_check (ospf
, al
->e
[0].fwd_addr
))
201 if (IS_DEBUG_OSPF (lsa
, LSA
))
202 zlog_debug ("ospf_ase_calculate(): Forwarding address is one of our addresses, Ignore.");
206 if (IS_DEBUG_OSPF (lsa
, LSA
))
207 zlog_debug ("ospf_ase_calculate(): Looking up in the Network Routing Table.");
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
;
214 rn
= route_node_match (rt_network
, (struct prefix
*) &asbr
);
218 if (IS_DEBUG_OSPF (lsa
, LSA
))
219 zlog_debug ("ospf_ase_calculate(): Couldn't find a route to the forwarding address.");
223 route_unlock_node (rn
);
225 if ((asbr_route
= rn
->info
) == NULL
)
227 if (IS_DEBUG_OSPF (lsa
, LSA
))
228 zlog_debug ("ospf_ase_calculate(): Somehow OSPF route to ASBR is lost");
237 static struct ospf_route
*
238 ospf_ase_calculate_new_route(struct ospf_lsa
*lsa
,
239 struct ospf_route
*asbr_route
, uint32_t metric
)
241 struct as_external_lsa
*al
;
242 struct ospf_route
*new;
244 al
= (struct as_external_lsa
*)lsa
->data
;
246 new = ospf_route_new();
248 /* Set redistributed type -- does make sense? */
249 /* new->type = type; */
250 new->id
= al
->header
.id
;
251 new->mask
= al
->mask
;
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 */
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 */
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
;
271 assert(new != asbr_route
);
276 #define OSPF_ASE_CALC_INTERVAL 1
278 int ospf_ase_calculate_route(struct ospf
*ospf
, struct ospf_lsa
*lsa
)
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 ;
289 al
= (struct as_external_lsa
*)lsa
->data
;
291 if (lsa
->data
->type
== OSPF_AS_NSSA_LSA
)
292 if (IS_DEBUG_OSPF_NSSA
)
293 zlog_debug("ospf_ase_calc(): Processing Type-7");
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");
302 if (IS_DEBUG_OSPF(lsa
, LSA
)) {
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
);
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
))
314 "Route[External]: Metric is OSPF_LS_INFINITY");
317 if (IS_LSA_MAXAGE(lsa
)) {
318 if (IS_DEBUG_OSPF(lsa
, LSA
))
320 "Route[External]: AS-external-LSA is MAXAGE");
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
))
329 "Route[External]: AS-external-LSA is self originated");
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
342 asbr
.family
= AF_INET
;
343 asbr
.prefix
= al
->header
.adv_router
;
344 asbr
.prefixlen
= IPV4_MAX_BITLEN
;
345 apply_mask_ipv4(&asbr
);
347 asbr_route
= ospf_find_asbr_route(ospf
, ospf
->new_rtrs
, &asbr
);
348 if (asbr_route
== NULL
) {
349 if (IS_DEBUG_OSPF(lsa
, LSA
))
351 "Route[External]: Can't find originating ASBR route");
354 if (!(asbr_route
->u
.std
.flags
& ROUTER_LSA_EXTERNAL
)) {
355 if (IS_DEBUG_OSPF(lsa
, LSA
))
357 "Route[External]: Originating router is not an ASBR");
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. */
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
379 /* asbr_route already contains the requested route */
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
))
389 "Route[External]: Forwarding address is our router address");
393 asbr
.family
= AF_INET
;
394 asbr
.prefix
= al
->e
[0].fwd_addr
;
395 asbr
.prefixlen
= IPV4_MAX_BITLEN
;
397 rn
= route_node_match(ospf
->new_table
, (struct prefix
*)&asbr
);
399 if (rn
== NULL
|| (asbr_route
= rn
->info
) == NULL
) {
400 if (IS_DEBUG_OSPF(lsa
, LSA
))
402 "Route[External]: Can't find route to forwarding address");
404 route_unlock_node(rn
);
408 route_unlock_node(rn
);
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. */
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
);
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
437 p
.prefix
= al
->header
.id
;
438 p
.prefixlen
= ip_masklen(al
->mask
);
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");
447 ospf_route_free(new);
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
);
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
));
461 ospf_route_add(ospf
->new_external_route
, &p
, new, asbr_route
);
463 if (al
->e
[0].fwd_addr
.s_addr
!= INADDR_ANY
)
464 ospf_ase_complete_direct_routes(new, al
->e
[0].fwd_addr
);
467 /* (a) Intra-area and inter-area paths are always preferred
468 over AS external paths.
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);
476 /* (c) If the new AS external path is still
478 from the current paths in the N's routing table
480 and RFC1583Compatibility is set to "disabled", select
481 the preferred paths based on the intra-AS paths to
483 ASBR/forwarding addresses, as specified in Section
486 (d) If the new AS external path is still
488 from the current paths in the N's routing table
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
495 external paths advertising equal type 2 metrics are
496 compared by looking at the distance to the forwarding
499 /* New route is better */
501 if (IS_DEBUG_OSPF(lsa
, LSA
))
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
);
511 /* Old route is better */
513 if (IS_DEBUG_OSPF(lsa
, LSA
))
515 "Route[External]: Old route is better");
518 /* Routes are equal */
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
);
528 /* Make sure setting newly calculated ASBR route.*/
529 or->u
.ext
.asbr
= asbr_route
;
531 ospf_route_free(new);
537 static int ospf_ase_route_match_same(struct route_table
*rt
,
538 struct prefix
*prefix
,
539 struct ospf_route
*newor
)
541 struct route_node
*rn
;
542 struct ospf_route
*or;
543 struct ospf_path
*op
;
544 struct ospf_path
*newop
;
551 rn
= route_node_lookup(rt
, prefix
);
555 route_unlock_node(rn
);
561 if (or->path_type
!= newor
->path_type
)
564 switch (or->path_type
) {
565 case OSPF_PATH_TYPE1_EXTERNAL
:
566 if (or->cost
!= newor
->cost
)
569 case OSPF_PATH_TYPE2_EXTERNAL
:
570 if ((or->cost
!= newor
->cost
)
571 || (or->u
.ext
.type2_cost
!= newor
->u
.ext
.type2_cost
))
581 if (or->paths
->count
!= newor
->paths
->count
)
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
);
590 if (!IPV4_ADDR_SAME(&op
->nexthop
, &newop
->nexthop
))
592 if (op
->ifindex
!= newop
->ifindex
)
596 if (or->u
.ext
.tag
!= newor
->u
.ext
.tag
)
602 static int ospf_ase_compare_tables(struct ospf
*ospf
,
603 struct route_table
*new_external_route
,
604 struct route_table
*old_external_route
)
606 struct route_node
*rn
, *new_rn
;
607 struct ospf_route
* or ;
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
,
615 ospf
, (struct prefix_ipv4
*)&rn
->p
, or);
617 route_unlock_node(new_rn
);
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
,
627 ospf
, (struct prefix_ipv4
*)&rn
->p
, or);
632 static int ospf_ase_calculate_timer(struct thread
*t
)
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
;
641 ospf
= THREAD_ARG(t
);
642 ospf
->t_ase_calc
= NULL
;
644 if (ospf
->ase_calc
) {
647 monotime(&start_time
);
649 /* Calculate external route for each AS-external-LSA */
650 LSDB_LOOP (EXTERNAL_LSDB(ospf
), rn
, lsa
)
651 ospf_ase_calculate_route(ospf
, lsa
);
653 /* This version simple adds to the table all NSSA areas */
655 for (ALL_LIST_ELEMENTS_RO(ospf
->areas
, node
, area
)) {
656 if (IS_DEBUG_OSPF_NSSA
)
658 "ospf_ase_calculate_timer(): looking at area %pI4",
661 if (area
->external_routing
== OSPF_AREA_NSSA
)
662 LSDB_LOOP (NSSA_LSDB(area
), rn
, lsa
)
663 ospf_ase_calculate_route(ospf
,
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
);
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
);
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();
680 monotime(&stop_time
);
682 if (IS_DEBUG_OSPF_EVENT
)
684 "SPF Processing Time(usecs): External Routes: %lld",
685 (stop_time
.tv_sec
- start_time
.tv_sec
)
688 - start_time
.tv_usec
));
693 void ospf_ase_calculate_schedule(struct ospf
*ospf
)
701 void ospf_ase_calculate_timer_add(struct ospf
*ospf
)
706 thread_add_timer(master
, ospf_ase_calculate_timer
, ospf
,
707 OSPF_ASE_CALC_INTERVAL
, &ospf
->t_ase_calc
);
710 void ospf_ase_register_external_lsa(struct ospf_lsa
*lsa
, struct ospf
*top
)
712 struct route_node
*rn
;
713 struct prefix_ipv4 p
;
715 struct as_external_lsa
*al
;
717 al
= (struct as_external_lsa
*)lsa
->data
;
719 p
.prefix
= lsa
->data
->id
;
720 p
.prefixlen
= ip_masklen(al
->mask
);
723 rn
= route_node_get(top
->external_lsas
, (struct prefix
*)&p
);
724 if ((lst
= rn
->info
) == NULL
)
725 rn
->info
= lst
= list_new();
727 route_unlock_node(rn
);
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 */
734 void ospf_ase_unregister_external_lsa(struct ospf_lsa
*lsa
, struct ospf
*top
)
736 struct route_node
*rn
;
737 struct prefix_ipv4 p
;
739 struct as_external_lsa
*al
;
741 al
= (struct as_external_lsa
*)lsa
->data
;
743 p
.prefix
= lsa
->data
->id
;
744 p
.prefixlen
= ip_masklen(al
->mask
);
747 rn
= route_node_lookup(top
->external_lsas
, (struct prefix
*)&p
);
751 listnode_delete(lst
, lsa
);
752 ospf_lsa_unlock(&lsa
); /* external_lsas list */
753 route_unlock_node(rn
);
757 void ospf_ase_external_lsas_finish(struct route_table
*rt
)
759 struct route_node
*rn
;
760 struct ospf_lsa
*lsa
;
762 struct listnode
*node
, *nnode
;
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 */
771 route_table_finish(rt
);
774 void ospf_ase_incremental_update(struct ospf
*ospf
, struct ospf_lsa
*lsa
)
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
;
783 al
= (struct as_external_lsa
*)lsa
->data
;
785 p
.prefix
= lsa
->data
->id
;
786 p
.prefixlen
= ip_masklen(al
->mask
);
789 /* if new_table is NULL, there was no spf calculation, thus
790 incremental update is unneeded */
791 if (!ospf
->new_table
)
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). */
798 rn
= route_node_lookup(ospf
->new_table
, (struct prefix
*)&p
);
800 route_unlock_node(rn
);
805 rn
= route_node_lookup(ospf
->external_lsas
, (struct prefix
*)&p
);
809 route_unlock_node(rn
);
811 for (ALL_LIST_ELEMENTS_RO(lsas
, node
, lsa
))
812 ospf_ase_calculate_route(ospf
, lsa
);
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
);
823 /* install changes to zebra */
824 ospf_ase_compare_tables(ospf
, ospf
->new_external_route
, tmp_old
);
826 /* update ospf->old_external_route table */
828 ospf_route_free((struct ospf_route
*)rn
->info
);
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
) {
834 rn
= route_node_get(ospf
->old_external_route
,
835 (struct prefix
*)&p
);
836 rn
->info
= rn2
->info
;
838 /* remove route node from ospf->old_external_route */
841 route_unlock_node(rn
);
846 /* rn2->info is stored in route node of ospf->old_external_route
849 route_unlock_node(rn2
);
850 route_unlock_node(rn2
);
853 route_table_finish(tmp_old
);