]>
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
,
159 static struct ospf_route
*
160 ospf_ase_calculate_new_route(struct ospf_lsa
*lsa
,
161 struct ospf_route
*asbr_route
, uint32_t metric
)
163 struct as_external_lsa
*al
;
164 struct ospf_route
*new;
166 al
= (struct as_external_lsa
*)lsa
->data
;
168 new = ospf_route_new();
170 /* Set redistributed type -- does make sense? */
171 /* new->type = type; */
172 new->id
= al
->header
.id
;
173 new->mask
= al
->mask
;
175 if (!IS_EXTERNAL_METRIC(al
->e
[0].tos
)) {
176 if (IS_DEBUG_OSPF(lsa
, LSA
))
177 zlog_debug("Route[External]: type-1 created.");
178 new->path_type
= OSPF_PATH_TYPE1_EXTERNAL
;
179 new->cost
= asbr_route
->cost
+ metric
; /* X + Y */
181 if (IS_DEBUG_OSPF(lsa
, LSA
))
182 zlog_debug("Route[External]: type-2 created.");
183 new->path_type
= OSPF_PATH_TYPE2_EXTERNAL
;
184 new->cost
= asbr_route
->cost
; /* X */
185 new->u
.ext
.type2_cost
= metric
; /* Y */
188 new->type
= OSPF_DESTINATION_NETWORK
;
189 new->u
.ext
.origin
= lsa
;
190 new->u
.ext
.tag
= ntohl(al
->e
[0].route_tag
);
191 new->u
.ext
.asbr
= asbr_route
;
193 assert(new != asbr_route
);
198 #define OSPF_ASE_CALC_INTERVAL 1
200 int ospf_ase_calculate_route(struct ospf
*ospf
, struct ospf_lsa
*lsa
)
203 struct as_external_lsa
*al
;
204 struct ospf_route
*asbr_route
;
205 struct prefix_ipv4 asbr
, p
;
206 struct route_node
*rn
;
207 struct ospf_route
*new, * or ;
211 al
= (struct as_external_lsa
*)lsa
->data
;
213 if (lsa
->data
->type
== OSPF_AS_NSSA_LSA
)
214 if (IS_DEBUG_OSPF_NSSA
)
215 zlog_debug("%s: Processing Type-7", __func__
);
217 /* Stay away from any Local Translated Type-7 LSAs */
218 if (CHECK_FLAG(lsa
->flags
, OSPF_LSA_LOCAL_XLT
)) {
219 if (IS_DEBUG_OSPF_NSSA
)
220 zlog_debug("%s: Rejecting Local Xlt'd", __func__
);
224 if (IS_DEBUG_OSPF(lsa
, LSA
)) {
226 "Route[External]: Calculate AS-external-LSA to %pI4/%d adv_router %pI4",
227 &al
->header
.id
, ip_masklen(al
->mask
),
228 &al
->header
.adv_router
);
231 /* (1) If the cost specified by the LSA is LSInfinity, or if the
232 LSA's LS age is equal to MaxAge, then examine the next LSA. */
233 if ((metric
= GET_METRIC(al
->e
[0].metric
)) >= OSPF_LS_INFINITY
) {
234 if (IS_DEBUG_OSPF(lsa
, LSA
))
236 "Route[External]: Metric is OSPF_LS_INFINITY");
239 if (IS_LSA_MAXAGE(lsa
)) {
240 if (IS_DEBUG_OSPF(lsa
, LSA
))
242 "Route[External]: AS-external-LSA is MAXAGE");
246 /* (2) If the LSA was originated by the calculating router itself,
247 examine the next LSA. */
248 if (IS_LSA_SELF(lsa
)) {
249 if (IS_DEBUG_OSPF(lsa
, LSA
))
251 "Route[External]: AS-external-LSA is self originated");
255 /* (3) Call the destination described by the LSA N. N's address is
256 obtained by masking the LSA's Link State ID with the
257 network/subnet mask contained in the body of the LSA. Look
258 up the routing table entries (potentially one per attached
259 area) for the AS boundary router (ASBR) that originated the
260 LSA. If no entries exist for router ASBR (i.e., ASBR is
261 unreachable), do nothing with this LSA and consider the next
264 asbr
.family
= AF_INET
;
265 asbr
.prefix
= al
->header
.adv_router
;
266 asbr
.prefixlen
= IPV4_MAX_BITLEN
;
267 apply_mask_ipv4(&asbr
);
269 asbr_route
= ospf_find_asbr_route(ospf
, ospf
->new_rtrs
, &asbr
);
270 if (asbr_route
== NULL
) {
271 if (IS_DEBUG_OSPF(lsa
, LSA
))
273 "Route[External]: Can't find originating ASBR route");
276 if (!(asbr_route
->u
.std
.flags
& ROUTER_LSA_EXTERNAL
)) {
277 if (IS_DEBUG_OSPF(lsa
, LSA
))
279 "Route[External]: Originating router is not an ASBR");
283 /* Type-5 shouldn't be calculated if it is originated from NSSA ASBR.
284 * As per RFC 3101, expectation is to receive type-7 lsas from
285 * NSSA ASBR. Ignore calculation, if the current LSA is type-5 and
286 * originated ASBR's area is NSSA.
288 if ((lsa
->data
->type
== OSPF_AS_EXTERNAL_LSA
)
289 && (asbr_route
->u
.std
.external_routing
!= OSPF_AREA_DEFAULT
)) {
290 if (IS_DEBUG_OSPF(lsa
, LSA
))
292 "Route[External]: Ignore, If type-5 LSA from NSSA area.");
296 /* Else, this LSA describes an AS external path to destination
297 N. Examine the forwarding address specified in the AS-
298 external-LSA. This indicates the IP address to which
299 packets for the destination should be forwarded. */
301 if (al
->e
[0].fwd_addr
.s_addr
== INADDR_ANY
) {
302 /* If the forwarding address is set to 0.0.0.0, packets should
303 be sent to the ASBR itself. Among the multiple routing table
304 entries for the ASBR, select the preferred entry as follows.
305 If RFC1583Compatibility is set to "disabled", prune the set
306 of routing table entries for the ASBR as described in
307 Section 16.4.1. In any case, among the remaining routing
308 table entries, select the routing table entry with the least
309 cost; when there are multiple least cost routing table
310 entries the entry whose associated area has the largest OSPF
311 Area ID (when considered as an unsigned 32-bit integer) is
314 /* asbr_route already contains the requested route */
316 /* If the forwarding address is non-zero, look up the
317 forwarding address in the routing table.[24] The matching
318 routing table entry must specify an intra-area or inter-area
319 path; if no such path exists, do nothing with the LSA and
320 consider the next in the list. */
321 if (!ospf_ase_forward_address_check(ospf
, al
->e
[0].fwd_addr
)) {
322 if (IS_DEBUG_OSPF(lsa
, LSA
))
324 "Route[External]: Forwarding address is our router address");
328 asbr
.family
= AF_INET
;
329 asbr
.prefix
= al
->e
[0].fwd_addr
;
330 asbr
.prefixlen
= IPV4_MAX_BITLEN
;
332 rn
= route_node_match(ospf
->new_table
, (struct prefix
*)&asbr
);
334 if (rn
== NULL
|| (asbr_route
= rn
->info
) == NULL
) {
335 if (IS_DEBUG_OSPF(lsa
, LSA
))
337 "Route[External]: Can't find route to forwarding address");
339 route_unlock_node(rn
);
343 route_unlock_node(rn
);
346 /* (4) Let X be the cost specified by the preferred routing table
347 entry for the ASBR/forwarding address, and Y the cost
348 specified in the LSA. X is in terms of the link state
349 metric, and Y is a type 1 or 2 external metric. */
352 /* (5) Look up the routing table entry for the destination N. If
353 no entry exists for N, install the AS external path to N,
354 with next hop equal to the list of next hops to the
355 forwarding address, and advertising router equal to ASBR.
356 If the external metric type is 1, then the path-type is set
357 to type 1 external and the cost is equal to X+Y. If the
358 external metric type is 2, the path-type is set to type 2
359 external, the link state component of the route's cost is X,
360 and the type 2 cost is Y. */
361 new = ospf_ase_calculate_new_route(lsa
, asbr_route
, metric
);
363 /* (6) Compare the AS external path described by the LSA with the
364 existing paths in N's routing table entry, as follows. If
365 the new path is preferred, it replaces the present paths in
366 N's routing table entry. If the new path is of equal
367 preference, it is added to N's routing table entry's list of
372 p
.prefix
= al
->header
.id
;
373 p
.prefixlen
= ip_masklen(al
->mask
);
375 /* if there is a Intra/Inter area route to the N
376 do not install external route */
377 if ((rn
= route_node_lookup(ospf
->new_table
, (struct prefix
*)&p
))) {
378 route_unlock_node(rn
);
379 if (rn
->info
== NULL
)
380 zlog_info("Route[External]: rn->info NULL");
382 ospf_route_free(new);
385 /* Find a route to the same dest */
386 /* If there is no route, create new one. */
387 if ((rn
= route_node_lookup(ospf
->new_external_route
,
388 (struct prefix
*)&p
)))
389 route_unlock_node(rn
);
391 if (!rn
|| (or = rn
->info
) == NULL
) {
392 if (IS_DEBUG_OSPF(lsa
, LSA
))
393 zlog_debug("Route[External]: Adding a new route %pFX with paths %u",
394 &p
, listcount(asbr_route
->paths
));
396 ospf_route_add(ospf
->new_external_route
, &p
, new, asbr_route
);
398 if (al
->e
[0].fwd_addr
.s_addr
!= INADDR_ANY
)
399 ospf_ase_complete_direct_routes(new, al
->e
[0].fwd_addr
);
402 /* (a) Intra-area and inter-area paths are always preferred
403 over AS external paths.
405 (b) Type 1 external paths are always preferred over type 2
406 external paths. When all paths are type 2 external
407 paths, the paths with the smallest advertised type 2
408 metric are always preferred. */
409 ret
= ospf_route_cmp(ospf
, new, or);
411 /* (c) If the new AS external path is still
413 from the current paths in the N's routing table
415 and RFC1583Compatibility is set to "disabled", select
416 the preferred paths based on the intra-AS paths to
418 ASBR/forwarding addresses, as specified in Section
421 (d) If the new AS external path is still
423 from the current paths in the N's routing table
425 select the preferred path based on a least cost
426 comparison. Type 1 external paths are compared by
427 looking at the sum of the distance to the forwarding
428 address and the advertised type 1 metric (X+Y). Type
430 external paths advertising equal type 2 metrics are
431 compared by looking at the distance to the forwarding
434 /* New route is better */
436 if (IS_DEBUG_OSPF(lsa
, LSA
))
438 "Route[External]: New route is better");
439 ospf_route_subst(rn
, new, asbr_route
);
440 if (al
->e
[0].fwd_addr
.s_addr
!= INADDR_ANY
)
441 ospf_ase_complete_direct_routes(
442 new, al
->e
[0].fwd_addr
);
446 /* Old route is better */
448 if (IS_DEBUG_OSPF(lsa
, LSA
))
450 "Route[External]: Old route is better");
453 /* Routes are equal */
455 if (IS_DEBUG_OSPF(lsa
, LSA
))
456 zlog_debug("Route[External]: Routes are equal");
457 ospf_route_copy_nexthops(or, asbr_route
->paths
);
458 if (al
->e
[0].fwd_addr
.s_addr
!= INADDR_ANY
)
459 ospf_ase_complete_direct_routes(
460 or, al
->e
[0].fwd_addr
);
463 /* Make sure setting newly calculated ASBR route.*/
464 or->u
.ext
.asbr
= asbr_route
;
466 ospf_route_free(new);
472 static int ospf_ase_route_match_same(struct route_table
*rt
,
473 struct prefix
*prefix
,
474 struct ospf_route
*newor
)
476 struct route_node
*rn
;
477 struct ospf_route
*or;
478 struct ospf_path
*op
;
479 struct ospf_path
*newop
;
486 rn
= route_node_lookup(rt
, prefix
);
490 route_unlock_node(rn
);
496 if (or->path_type
!= newor
->path_type
)
499 switch (or->path_type
) {
500 case OSPF_PATH_TYPE1_EXTERNAL
:
501 if (or->cost
!= newor
->cost
)
504 case OSPF_PATH_TYPE2_EXTERNAL
:
505 if ((or->cost
!= newor
->cost
)
506 || (or->u
.ext
.type2_cost
!= newor
->u
.ext
.type2_cost
))
516 if (or->paths
->count
!= newor
->paths
->count
)
519 /* Check each path. */
520 for (n1
= listhead(or->paths
), n2
= listhead(newor
->paths
); n1
&& n2
;
521 n1
= listnextnode_unchecked(n1
), n2
= listnextnode_unchecked(n2
)) {
522 op
= listgetdata(n1
);
523 newop
= listgetdata(n2
);
525 if (!IPV4_ADDR_SAME(&op
->nexthop
, &newop
->nexthop
))
527 if (op
->ifindex
!= newop
->ifindex
)
531 if (or->u
.ext
.tag
!= newor
->u
.ext
.tag
)
537 static int ospf_ase_compare_tables(struct ospf
*ospf
,
538 struct route_table
*new_external_route
,
539 struct route_table
*old_external_route
)
541 struct route_node
*rn
, *new_rn
;
542 struct ospf_route
* or ;
544 /* Remove deleted routes */
545 for (rn
= route_top(old_external_route
); rn
; rn
= route_next(rn
))
546 if ((or = rn
->info
)) {
547 if (!(new_rn
= route_node_lookup(new_external_route
,
550 ospf
, (struct prefix_ipv4
*)&rn
->p
, or);
552 route_unlock_node(new_rn
);
556 /* Install new routes */
557 for (rn
= route_top(new_external_route
); rn
; rn
= route_next(rn
))
558 if ((or = rn
->info
) != NULL
)
559 if (!ospf_ase_route_match_same(old_external_route
,
562 ospf
, (struct prefix_ipv4
*)&rn
->p
, or);
567 static void ospf_ase_calculate_timer(struct thread
*t
)
570 struct ospf_lsa
*lsa
;
571 struct route_node
*rn
;
572 struct listnode
*node
;
573 struct ospf_area
*area
;
574 struct timeval start_time
, stop_time
;
576 ospf
= THREAD_ARG(t
);
577 ospf
->t_ase_calc
= NULL
;
579 if (ospf
->ase_calc
) {
582 monotime(&start_time
);
584 /* Calculate external route for each AS-external-LSA */
585 LSDB_LOOP (EXTERNAL_LSDB(ospf
), rn
, lsa
)
586 ospf_ase_calculate_route(ospf
, lsa
);
588 /* This version simple adds to the table all NSSA areas */
590 for (ALL_LIST_ELEMENTS_RO(ospf
->areas
, node
, area
)) {
591 if (IS_DEBUG_OSPF_NSSA
)
592 zlog_debug("%s: looking at area %pI4",
593 __func__
, &area
->area_id
);
595 if (area
->external_routing
== OSPF_AREA_NSSA
)
596 LSDB_LOOP (NSSA_LSDB(area
), rn
, lsa
)
597 ospf_ase_calculate_route(ospf
,
600 /* kevinm: And add the NSSA routes in ospf_top */
601 LSDB_LOOP (NSSA_LSDB(ospf
), rn
, lsa
)
602 ospf_ase_calculate_route(ospf
, lsa
);
604 /* Compare old and new external routing table and install the
605 difference info zebra/kernel */
606 ospf_ase_compare_tables(ospf
, ospf
->new_external_route
,
607 ospf
->old_external_route
);
609 /* Delete old external routing table */
610 ospf_route_table_free(ospf
->old_external_route
);
611 ospf
->old_external_route
= ospf
->new_external_route
;
612 ospf
->new_external_route
= route_table_init();
614 monotime(&stop_time
);
616 if (IS_DEBUG_OSPF_EVENT
)
618 "SPF Processing Time(usecs): External Routes: %lld",
619 (stop_time
.tv_sec
- start_time
.tv_sec
)
622 - start_time
.tv_usec
));
626 * Uninstall remnant routes that were installed before the restart, but
627 * that are no longer valid.
629 if (ospf
->gr_info
.finishing_restart
) {
630 ospf_zebra_gr_disable(ospf
);
631 ospf
->gr_info
.finishing_restart
= false;
635 void ospf_ase_calculate_schedule(struct ospf
*ospf
)
643 void ospf_ase_calculate_timer_add(struct ospf
*ospf
)
648 thread_add_timer(master
, ospf_ase_calculate_timer
, ospf
,
649 OSPF_ASE_CALC_INTERVAL
, &ospf
->t_ase_calc
);
652 void ospf_ase_register_external_lsa(struct ospf_lsa
*lsa
, struct ospf
*top
)
654 struct route_node
*rn
;
655 struct prefix_ipv4 p
;
657 struct as_external_lsa
*al
;
659 al
= (struct as_external_lsa
*)lsa
->data
;
661 p
.prefix
= lsa
->data
->id
;
662 p
.prefixlen
= ip_masklen(al
->mask
);
665 rn
= route_node_get(top
->external_lsas
, (struct prefix
*)&p
);
666 if ((lst
= rn
->info
) == NULL
)
667 rn
->info
= lst
= list_new();
669 route_unlock_node(rn
);
671 /* We assume that if LSA is deleted from DB
672 is is also deleted from this RT */
673 listnode_add(lst
, ospf_lsa_lock(lsa
)); /* external_lsas lst */
676 void ospf_ase_unregister_external_lsa(struct ospf_lsa
*lsa
, struct ospf
*top
)
678 struct route_node
*rn
;
679 struct prefix_ipv4 p
;
681 struct as_external_lsa
*al
;
683 al
= (struct as_external_lsa
*)lsa
->data
;
685 p
.prefix
= lsa
->data
->id
;
686 p
.prefixlen
= ip_masklen(al
->mask
);
689 rn
= route_node_lookup(top
->external_lsas
, (struct prefix
*)&p
);
693 struct listnode
*node
= listnode_lookup(lst
, lsa
);
694 /* Unlock lsa only if node is present in the list */
696 listnode_delete(lst
, lsa
);
697 ospf_lsa_unlock(&lsa
); /* external_lsas list */
700 route_unlock_node(rn
);
704 void ospf_ase_external_lsas_finish(struct route_table
*rt
)
706 struct route_node
*rn
;
707 struct ospf_lsa
*lsa
;
709 struct listnode
*node
, *nnode
;
711 for (rn
= route_top(rt
); rn
; rn
= route_next(rn
))
712 if ((lst
= rn
->info
) != NULL
) {
713 for (ALL_LIST_ELEMENTS(lst
, node
, nnode
, lsa
))
714 ospf_lsa_unlock(&lsa
); /* external_lsas lst */
718 route_table_finish(rt
);
721 void ospf_ase_incremental_update(struct ospf
*ospf
, struct ospf_lsa
*lsa
)
724 struct listnode
*node
;
725 struct route_node
*rn
, *rn2
;
726 struct prefix_ipv4 p
;
727 struct route_table
*tmp_old
;
728 struct as_external_lsa
*al
;
730 al
= (struct as_external_lsa
*)lsa
->data
;
732 p
.prefix
= lsa
->data
->id
;
733 p
.prefixlen
= ip_masklen(al
->mask
);
736 /* if new_table is NULL, there was no spf calculation, thus
737 incremental update is unneeded */
738 if (!ospf
->new_table
)
741 /* If there is already an intra-area or inter-area route
742 to the destination, no recalculation is necessary
743 (internal routes take precedence). */
745 rn
= route_node_lookup(ospf
->new_table
, (struct prefix
*)&p
);
747 route_unlock_node(rn
);
752 rn
= route_node_lookup(ospf
->external_lsas
, (struct prefix
*)&p
);
756 route_unlock_node(rn
);
758 for (ALL_LIST_ELEMENTS_RO(lsas
, node
, lsa
))
759 ospf_ase_calculate_route(ospf
, lsa
);
761 /* prepare temporary old routing table for compare */
762 tmp_old
= route_table_init();
763 rn
= route_node_lookup(ospf
->old_external_route
, (struct prefix
*)&p
);
764 if (rn
&& rn
->info
) {
765 rn2
= route_node_get(tmp_old
, (struct prefix
*)&p
);
766 rn2
->info
= rn
->info
;
767 route_unlock_node(rn
);
770 /* install changes to zebra */
771 ospf_ase_compare_tables(ospf
, ospf
->new_external_route
, tmp_old
);
773 /* update ospf->old_external_route table */
775 ospf_route_free((struct ospf_route
*)rn
->info
);
777 rn2
= route_node_lookup(ospf
->new_external_route
, (struct prefix
*)&p
);
778 /* if new route exists, install it to ospf->old_external_route */
779 if (rn2
&& rn2
->info
) {
781 rn
= route_node_get(ospf
->old_external_route
,
782 (struct prefix
*)&p
);
783 rn
->info
= rn2
->info
;
785 /* remove route node from ospf->old_external_route */
788 route_unlock_node(rn
);
793 /* rn2->info is stored in route node of ospf->old_external_route
796 route_unlock_node(rn2
);
797 route_unlock_node(rn2
);
800 route_table_finish(tmp_old
);