2 * Area Border Router function.
3 * Copyright (C) 2004 Yasuhiro Ohara
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 "ospf6_proto.h"
35 #include "ospf6_route.h"
36 #include "ospf6_lsa.h"
37 #include "ospf6_route.h"
38 #include "ospf6_lsdb.h"
39 #include "ospf6_message.h"
40 #include "ospf6_zebra.h"
42 #include "ospf6_top.h"
43 #include "ospf6_area.h"
44 #include "ospf6_interface.h"
45 #include "ospf6_neighbor.h"
47 #include "ospf6_flood.h"
48 #include "ospf6_intra.h"
49 #include "ospf6_asbr.h"
50 #include "ospf6_abr.h"
52 #include "ospf6_nssa.h"
54 unsigned char conf_debug_ospf6_abr
;
56 bool ospf6_check_and_set_router_abr(struct ospf6
*o
)
58 struct listnode
*node
;
59 struct ospf6_area
*oa
;
61 bool is_backbone
= false;
63 for (ALL_LIST_ELEMENTS_RO(o
->area_list
, node
, oa
)) {
64 if (IS_OSPF6_DEBUG_ABR
)
65 zlog_debug("%s, area_id %pI4", __func__
, &oa
->area_id
);
66 if (IS_AREA_ENABLED(oa
))
69 if (o
->backbone
== oa
)
73 if ((area_count
> 1) && (is_backbone
)) {
74 if (IS_OSPF6_DEBUG_ABR
)
75 zlog_debug("%s : set flag OSPF6_FLAG_ABR", __func__
);
76 SET_FLAG(o
->flag
, OSPF6_FLAG_ABR
);
79 if (IS_OSPF6_DEBUG_ABR
)
80 zlog_debug("%s : reset flag OSPF6_FLAG_ABR", __func__
);
81 UNSET_FLAG(o
->flag
, OSPF6_FLAG_ABR
);
86 static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route
*route
,
87 struct ospf6_area
*area
)
89 struct ospf6_interface
*oi
;
91 oi
= ospf6_interface_lookup_by_ifindex(
92 ospf6_route_get_first_nh_index(route
), area
->ospf6
->vrf_id
);
93 if (oi
&& oi
->area
&& oi
->area
== area
)
99 static void ospf6_abr_delete_route(struct ospf6_route
*range
,
100 struct ospf6_route
*summary
,
101 struct ospf6_route_table
*summary_table
,
102 struct ospf6_lsa
*old
)
105 ospf6_route_remove(summary
, summary_table
);
108 if (old
&& !OSPF6_LSA_IS_MAXAGE(old
))
109 ospf6_lsa_purge(old
);
112 void ospf6_abr_enable_area(struct ospf6_area
*area
)
114 struct ospf6_area
*oa
;
115 struct listnode
*node
, *nnode
;
117 for (ALL_LIST_ELEMENTS(area
->ospf6
->area_list
, node
, nnode
, oa
))
118 /* update B bit for each area */
119 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
122 void ospf6_abr_disable_area(struct ospf6_area
*area
)
124 struct ospf6_area
*oa
;
125 struct ospf6_route
*ro
, *nro
;
126 struct ospf6_lsa
*old
;
127 struct listnode
*node
, *nnode
;
129 /* Withdraw all summary prefixes previously originated */
130 for (ro
= ospf6_route_head(area
->summary_prefix
); ro
; ro
= nro
) {
131 nro
= ospf6_route_next(ro
);
132 old
= ospf6_lsdb_lookup(ro
->path
.origin
.type
,
134 area
->ospf6
->router_id
, area
->lsdb
);
136 ospf6_lsa_purge(old
);
137 ospf6_route_remove(ro
, area
->summary_prefix
);
140 /* Withdraw all summary router-routes previously originated */
141 for (ro
= ospf6_route_head(area
->summary_router
); ro
; ro
= nro
) {
142 nro
= ospf6_route_next(ro
);
143 old
= ospf6_lsdb_lookup(ro
->path
.origin
.type
,
145 area
->ospf6
->router_id
, area
->lsdb
);
147 ospf6_lsa_purge(old
);
148 ospf6_route_remove(ro
, area
->summary_router
);
151 /* Schedule Router-LSA for each area (ABR status may change) */
152 for (ALL_LIST_ELEMENTS(area
->ospf6
->area_list
, node
, nnode
, oa
))
153 /* update B bit for each area */
154 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
157 /* RFC 2328 12.4.3. Summary-LSAs */
158 /* Returns 1 if a summary LSA has been generated for the area */
159 /* This is used by the area/range logic to add/remove blackhole routes */
160 int ospf6_abr_originate_summary_to_area(struct ospf6_route
*route
,
161 struct ospf6_area
*area
)
163 struct ospf6_lsa
*lsa
, *old
= NULL
;
164 struct ospf6_route
*summary
, *range
= NULL
;
165 struct ospf6_area
*route_area
;
166 char buffer
[OSPF6_MAX_LSASIZE
];
167 struct ospf6_lsa_header
*lsa_header
;
169 struct ospf6_inter_prefix_lsa
*prefix_lsa
;
170 struct ospf6_inter_router_lsa
*router_lsa
;
171 struct ospf6_route_table
*summary_table
= NULL
;
175 if (IS_OSPF6_DEBUG_ABR
)
176 zlog_debug("%s : start area %s, route %pFX", __func__
,
177 area
->name
, &route
->prefix
);
179 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
)
180 summary_table
= area
->summary_router
;
182 summary_table
= area
->summary_prefix
;
184 summary
= ospf6_route_lookup(&route
->prefix
, summary_table
);
186 old
= ospf6_lsdb_lookup(summary
->path
.origin
.type
,
187 summary
->path
.origin
.id
,
188 area
->ospf6
->router_id
, area
->lsdb
);
189 /* Reset the OSPF6_LSA_UNAPPROVED flag */
191 UNSET_FLAG(old
->flag
, OSPF6_LSA_UNAPPROVED
);
194 /* Only destination type network, range or ASBR are considered */
195 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
196 && route
->type
!= OSPF6_DEST_TYPE_RANGE
197 && ((route
->type
!= OSPF6_DEST_TYPE_ROUTER
)
198 || !CHECK_FLAG(route
->path
.router_bits
, OSPF6_ROUTER_BIT_E
))) {
199 if (IS_OSPF6_DEBUG_ABR
)
201 "%s: Route type %d flag 0x%x is none of network, range nor ASBR, ignore",
202 __func__
, route
->type
, route
->path
.router_bits
);
206 /* AS External routes are never considered */
207 if (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
208 || route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL2
) {
209 if (IS_OSPF6_DEBUG_ABR
)
210 zlog_debug("%s : Path type is external, skip",
215 /* do not generate if the path's area is the same as target area */
216 if (route
->path
.area_id
== area
->area_id
) {
217 if (IS_OSPF6_DEBUG_ABR
)
219 "%s: The route is in the area itself, ignore",
224 /* do not generate if the nexthops belongs to the target area */
225 if (ospf6_abr_nexthops_belong_to_area(route
, area
)) {
226 if (IS_OSPF6_DEBUG_ABR
)
228 "%s: The route's nexthop is in the same area, ignore",
233 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
234 if (ADV_ROUTER_IN_PREFIX(&route
->prefix
)
235 == area
->ospf6
->router_id
) {
236 if (IS_OSPF6_DEBUG_ABR
)
238 "%s: Skipping ASBR announcement for ABR (%pI4)",
240 &ADV_ROUTER_IN_PREFIX(&route
->prefix
));
245 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
246 if (IS_OSPF6_DEBUG_ABR
247 || IS_OSPF6_DEBUG_ORIGINATE(INTER_ROUTER
)) {
249 if (IS_OSPF6_DEBUG_ABR
)
251 "Originating summary in area %s for ASBR %pI4",
253 &ADV_ROUTER_IN_PREFIX(&route
->prefix
));
256 if (IS_OSPF6_DEBUG_ABR
257 || IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX
))
260 if (route
->type
== OSPF6_DEST_TYPE_NETWORK
&&
261 route
->path
.origin
.type
==
262 htons(OSPF6_LSTYPE_INTER_PREFIX
)) {
263 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_BEST
)) {
266 "%s: route %pFX with cost %u is not best, ignore.",
267 __func__
, &route
->prefix
,
273 if (route
->path
.origin
.type
==
274 htons(OSPF6_LSTYPE_INTRA_PREFIX
)) {
275 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_BEST
)) {
278 "%s: intra-prefix route %pFX with cost %u is not best, ignore.",
279 __func__
, &route
->prefix
,
287 "Originating summary in area %s for %pFX cost %u",
288 area
->name
, &route
->prefix
, route
->path
.cost
);
291 /* if this route has just removed, remove corresponding LSA */
292 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)) {
295 "The route has just removed, purge previous LSA");
297 if (route
->type
== OSPF6_DEST_TYPE_RANGE
) {
298 /* Whether the route have active longer prefix */
299 if (!CHECK_FLAG(route
->flag
,
300 OSPF6_ROUTE_ACTIVE_SUMMARY
)) {
303 "The range is not active. withdraw");
305 ospf6_abr_delete_route(route
, summary
,
309 ospf6_route_remove(summary
, summary_table
);
310 ospf6_lsa_purge(old
);
315 if ((route
->type
== OSPF6_DEST_TYPE_ROUTER
) && IS_AREA_STUB(area
)) {
318 "Area has been stubbed, purge Inter-Router LSA");
320 ospf6_abr_delete_route(route
, summary
, summary_table
, old
);
325 && (route
->path
.subtype
!= OSPF6_PATH_SUBTYPE_DEFAULT_RT
)) {
327 zlog_debug("Area has been stubbed, purge prefix LSA");
329 ospf6_abr_delete_route(route
, summary
, summary_table
, old
);
333 /* do not generate if the route cost is greater or equal to LSInfinity
335 if (route
->path
.cost
>= OSPF_LS_INFINITY
) {
336 /* When we're clearing the range route because all active
338 * under the range are gone, we set the range's cost to
339 * OSPF_AREA_RANGE_COST_UNSPEC, which is > OSPF_LS_INFINITY. We
340 * don't want to trigger the code here for that. This code is
342 * handling routes that have gone to infinity. The range removal
346 if ((route
->type
!= OSPF6_DEST_TYPE_RANGE
)
347 && (route
->path
.cost
!= OSPF_AREA_RANGE_COST_UNSPEC
)) {
350 "The cost exceeds LSInfinity, withdraw");
352 ospf6_lsa_purge(old
);
357 /* if this is a route to ASBR */
358 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
359 /* Only the preferred best path is considered */
360 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_BEST
)) {
363 "This is the secondary path to the ASBR, ignore");
364 ospf6_abr_delete_route(route
, summary
, summary_table
,
369 /* Do not generate if the area is stub */
373 /* if this is an intra-area route, this may be suppressed by aggregation
375 if (route
->type
== OSPF6_DEST_TYPE_NETWORK
376 && route
->path
.type
== OSPF6_PATH_TYPE_INTRA
) {
377 /* search for configured address range for the route's area */
379 ospf6_area_lookup(route
->path
.area_id
, area
->ospf6
);
381 range
= ospf6_route_lookup_bestmatch(&route
->prefix
,
382 route_area
->range_table
);
384 /* ranges are ignored when originate backbone routes to transit
386 Otherwise, if ranges are configured, the route is suppressed.
388 if (range
&& !CHECK_FLAG(range
->flag
, OSPF6_ROUTE_REMOVE
)
389 && (route
->path
.area_id
!= OSPF_AREA_BACKBONE
390 || !IS_AREA_TRANSIT(area
))) {
393 "Suppressed by range %pFX of area %s",
394 &range
->prefix
, route_area
->name
);
395 ospf6_abr_delete_route(route
, summary
, summary_table
,
401 /* If this is a configured address range */
402 if (route
->type
== OSPF6_DEST_TYPE_RANGE
) {
403 /* If DoNotAdvertise is set */
404 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_DO_NOT_ADVERTISE
)) {
407 "This is the range with DoNotAdvertise set. ignore");
408 ospf6_abr_delete_route(route
, summary
, summary_table
,
413 /* If there are no active prefixes in this range, remove */
414 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)) {
416 zlog_debug("The range is not active. withdraw");
417 ospf6_abr_delete_route(route
, summary
, summary_table
,
423 /* Check export list */
424 if (EXPORT_NAME(area
)) {
425 if (EXPORT_LIST(area
) == NULL
)
427 access_list_lookup(AFI_IP6
, EXPORT_NAME(area
));
429 if (EXPORT_LIST(area
))
430 if (access_list_apply(EXPORT_LIST(area
), &route
->prefix
)
434 "prefix %pFX was denied by export list",
436 ospf6_abr_delete_route(route
, summary
,
442 /* Check filter-list */
443 if (PREFIX_LIST_OUT(area
))
444 if (prefix_list_apply(PREFIX_LIST_OUT(area
), &route
->prefix
)
448 "prefix %pFX was denied by filter-list out",
450 ospf6_abr_delete_route(route
, summary
, summary_table
,
456 /* the route is going to be originated. store it in area's summary_table
458 if (summary
== NULL
) {
459 summary
= ospf6_route_copy(route
);
460 summary
->path
.origin
.adv_router
= area
->ospf6
->router_id
;
462 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
463 summary
->path
.origin
.type
=
464 htons(OSPF6_LSTYPE_INTER_ROUTER
);
465 summary
->path
.origin
.id
=
466 ADV_ROUTER_IN_PREFIX(&route
->prefix
);
468 summary
->path
.origin
.type
=
469 htons(OSPF6_LSTYPE_INTER_PREFIX
);
470 summary
->path
.origin
.id
= ospf6_new_ls_id(
471 summary
->path
.origin
.type
,
472 summary
->path
.origin
.adv_router
, area
->lsdb
);
474 summary
= ospf6_route_add(summary
, summary_table
);
476 summary
->type
= route
->type
;
477 monotime(&summary
->changed
);
480 summary
->path
.router_bits
= route
->path
.router_bits
;
481 summary
->path
.options
[0] = route
->path
.options
[0];
482 summary
->path
.options
[1] = route
->path
.options
[1];
483 summary
->path
.options
[2] = route
->path
.options
[2];
484 summary
->path
.prefix_options
= route
->path
.prefix_options
;
485 summary
->path
.area_id
= area
->area_id
;
486 summary
->path
.type
= OSPF6_PATH_TYPE_INTER
;
487 summary
->path
.subtype
= route
->path
.subtype
;
488 summary
->path
.cost
= route
->path
.cost
;
489 /* summary->nexthop[0] = route->nexthop[0]; */
492 memset(buffer
, 0, sizeof(buffer
));
493 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
495 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
496 router_lsa
= (struct ospf6_inter_router_lsa
497 *)((caddr_t
)lsa_header
498 + sizeof(struct ospf6_lsa_header
));
499 p
= (caddr_t
)router_lsa
+ sizeof(struct ospf6_inter_router_lsa
);
501 /* Fill Inter-Area-Router-LSA */
502 router_lsa
->options
[0] = route
->path
.options
[0];
503 router_lsa
->options
[1] = route
->path
.options
[1];
504 router_lsa
->options
[2] = route
->path
.options
[2];
505 OSPF6_ABR_SUMMARY_METRIC_SET(router_lsa
, route
->path
.cost
);
506 router_lsa
->router_id
= ADV_ROUTER_IN_PREFIX(&route
->prefix
);
507 type
= htons(OSPF6_LSTYPE_INTER_ROUTER
);
509 prefix_lsa
= (struct ospf6_inter_prefix_lsa
510 *)((caddr_t
)lsa_header
511 + sizeof(struct ospf6_lsa_header
));
512 p
= (caddr_t
)prefix_lsa
+ sizeof(struct ospf6_inter_prefix_lsa
);
514 /* Fill Inter-Area-Prefix-LSA */
515 OSPF6_ABR_SUMMARY_METRIC_SET(prefix_lsa
, route
->path
.cost
);
516 prefix_lsa
->prefix
.prefix_length
= route
->prefix
.prefixlen
;
517 prefix_lsa
->prefix
.prefix_options
= route
->path
.prefix_options
;
520 memcpy(p
, &route
->prefix
.u
.prefix6
,
521 OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
));
522 ospf6_prefix_apply_mask(&prefix_lsa
->prefix
);
523 p
+= OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
);
524 type
= htons(OSPF6_LSTYPE_INTER_PREFIX
);
527 /* Fill LSA Header */
529 lsa_header
->type
= type
;
530 lsa_header
->id
= summary
->path
.origin
.id
;
531 lsa_header
->adv_router
= area
->ospf6
->router_id
;
533 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
534 lsa_header
->adv_router
, area
->lsdb
);
535 lsa_header
->length
= htons((caddr_t
)p
- (caddr_t
)lsa_header
);
538 ospf6_lsa_checksum(lsa_header
);
541 lsa
= ospf6_lsa_create(lsa_header
);
543 /* Reset the unapproved flag */
544 UNSET_FLAG(lsa
->flag
, OSPF6_LSA_UNAPPROVED
);
547 ospf6_lsa_originate_area(lsa
, area
);
549 if (IS_OSPF6_DEBUG_ABR
)
550 zlog_debug("%s : finish area %s", __func__
, area
->name
);
555 void ospf6_abr_range_reset_cost(struct ospf6
*ospf6
)
557 struct listnode
*node
, *nnode
;
558 struct ospf6_area
*oa
;
559 struct ospf6_route
*range
;
561 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
))
562 for (range
= ospf6_route_head(oa
->range_table
); range
;
563 range
= ospf6_route_next(range
))
564 OSPF6_ABR_RANGE_CLEAR_COST(range
);
567 static inline uint32_t ospf6_abr_range_compute_cost(struct ospf6_route
*range
,
570 struct ospf6_route
*ro
;
573 for (ro
= ospf6_route_match_head(&range
->prefix
, o
->route_table
); ro
;
574 ro
= ospf6_route_match_next(&range
->prefix
, ro
)) {
575 if (ro
->path
.area_id
== range
->path
.area_id
576 && (ro
->path
.type
== OSPF6_PATH_TYPE_INTRA
)
577 && !CHECK_FLAG(ro
->flag
, OSPF6_ROUTE_REMOVE
))
578 cost
= MAX(cost
, ro
->path
.cost
);
585 ospf6_abr_range_summary_needs_update(struct ospf6_route
*range
, uint32_t cost
)
587 int redo_summary
= 0;
589 if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_REMOVE
)) {
590 UNSET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
592 } else if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_DO_NOT_ADVERTISE
)) {
593 if (range
->path
.cost
!= 0) {
594 range
->path
.cost
= 0;
598 if ((OSPF6_PATH_COST_IS_CONFIGURED(range
->path
)
599 && range
->path
.cost
!= range
->path
.u
.cost_config
)) {
600 range
->path
.cost
= range
->path
.u
.cost_config
;
601 SET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
603 } else if (!OSPF6_PATH_COST_IS_CONFIGURED(range
->path
)
604 && range
->path
.cost
!= cost
) {
605 range
->path
.cost
= cost
;
606 SET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
609 } else if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)) {
610 /* Cost is zero, meaning no active range */
611 UNSET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
612 range
->path
.cost
= OSPF_AREA_RANGE_COST_UNSPEC
;
616 return (redo_summary
);
619 void ospf6_abr_range_update(struct ospf6_route
*range
, struct ospf6
*ospf6
)
622 struct listnode
*node
, *nnode
;
623 struct ospf6_area
*oa
;
624 int summary_orig
= 0;
626 assert(range
->type
== OSPF6_DEST_TYPE_RANGE
);
628 /* update range's cost and active flag */
629 cost
= ospf6_abr_range_compute_cost(range
, ospf6
);
631 if (IS_OSPF6_DEBUG_ABR
)
632 zlog_debug("%s: range %pFX, cost %d", __func__
, &range
->prefix
,
635 /* Non-zero cost is a proxy for active longer prefixes in this range.
636 * If there are active routes covered by this range AND either the
638 * cost has changed or the summarized cost has changed then redo
640 * Alternately, if there are no longer active prefixes and there are
641 * summary announcements, withdraw those announcements.
643 * The don't advertise code relies on the path.cost being set to UNSPEC
645 * work the first time. Subsequent times the path.cost is not 0 anyway
647 * were active ranges.
650 if (ospf6_abr_range_summary_needs_update(range
, cost
)) {
651 if (IS_OSPF6_DEBUG_ABR
)
652 zlog_debug("%s: range %pFX update", __func__
,
654 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
))
656 ospf6_abr_originate_summary_to_area(range
, oa
);
658 if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)
660 if (!CHECK_FLAG(range
->flag
,
661 OSPF6_ROUTE_BLACKHOLE_ADDED
)) {
662 if (IS_OSPF6_DEBUG_ABR
)
663 zlog_debug("Add discard route");
665 ospf6_zebra_add_discard(range
, ospf6
);
668 /* Summary removed or no summary generated as no
670 if (CHECK_FLAG(range
->flag
,
671 OSPF6_ROUTE_BLACKHOLE_ADDED
)) {
672 if (IS_OSPF6_DEBUG_ABR
)
673 zlog_debug("Delete discard route");
675 ospf6_zebra_delete_discard(range
, ospf6
);
681 void ospf6_abr_originate_summary(struct ospf6_route
*route
, struct ospf6
*ospf6
)
683 struct listnode
*node
, *nnode
;
684 struct ospf6_area
*oa
;
685 struct ospf6_route
*range
= NULL
;
687 if (IS_OSPF6_DEBUG_ABR
)
688 zlog_debug("%s: route %pFX", __func__
, &route
->prefix
);
690 if (route
->type
== OSPF6_DEST_TYPE_NETWORK
) {
691 oa
= ospf6_area_lookup(route
->path
.area_id
, ospf6
);
693 zlog_err("OSPFv6 area lookup failed");
697 range
= ospf6_route_lookup_bestmatch(&route
->prefix
,
700 ospf6_abr_range_update(range
, ospf6
);
704 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
))
705 ospf6_abr_originate_summary_to_area(route
, oa
);
708 void ospf6_abr_defaults_to_stub(struct ospf6
*o
)
710 struct listnode
*node
, *nnode
;
711 struct ospf6_area
*oa
;
712 struct ospf6_route
*def
, *route
;
713 struct ospf6_redist
*red
;
714 int type
= DEFAULT_ROUTE
;
715 struct prefix_ipv6 p
= {};
720 red
= ospf6_redist_lookup(o
, type
, 0);
727 route
= ospf6_route_lookup((struct prefix
*)&p
, o
->external_table
);
731 def
= ospf6_route_create();
732 def
->type
= OSPF6_DEST_TYPE_NETWORK
;
733 def
->prefix
.family
= AF_INET6
;
734 def
->prefix
.prefixlen
= 0;
735 memset(&def
->prefix
.u
.prefix6
, 0, sizeof(struct in6_addr
));
736 def
->type
= OSPF6_DEST_TYPE_NETWORK
;
737 def
->path
.type
= OSPF6_PATH_TYPE_INTER
;
738 def
->path
.subtype
= OSPF6_PATH_SUBTYPE_DEFAULT_RT
;
739 def
->path
.area_id
= o
->backbone
->area_id
;
740 def
->path
.metric_type
= metric_type(o
, type
, 0);
741 def
->path
.cost
= metric_value(o
, type
, 0);
743 for (ALL_LIST_ELEMENTS(o
->area_list
, node
, nnode
, oa
)) {
744 if (!IS_AREA_STUB(oa
)) {
745 /* withdraw defaults when an area switches from stub to
747 route
= ospf6_route_lookup(&def
->prefix
,
750 && (route
->path
.subtype
== def
->path
.subtype
)) {
751 if (IS_OSPF6_DEBUG_ABR
)
753 "Withdrawing default route from non-stubby area %s",
755 SET_FLAG(def
->flag
, OSPF6_ROUTE_REMOVE
);
756 ospf6_abr_originate_summary_to_area(def
, oa
);
759 /* announce defaults to stubby areas */
760 if (IS_OSPF6_DEBUG_ABR
)
762 "Announcing default route into stubby area %s",
764 UNSET_FLAG(def
->flag
, OSPF6_ROUTE_REMOVE
);
765 ospf6_abr_originate_summary_to_area(def
, oa
);
768 ospf6_route_delete(def
);
771 void ospf6_abr_old_path_update(struct ospf6_route
*old_route
,
772 struct ospf6_route
*route
,
773 struct ospf6_route_table
*table
)
775 struct ospf6_path
*o_path
= NULL
;
776 struct listnode
*anode
, *anext
;
777 struct listnode
*nnode
, *rnode
, *rnext
;
778 struct ospf6_nexthop
*nh
, *rnh
;
780 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
, anext
, o_path
)) {
781 if (o_path
->area_id
!= route
->path
.area_id
||
782 (memcmp(&(o_path
)->origin
, &(route
)->path
.origin
,
783 sizeof(struct ospf6_ls_origin
)) != 0))
786 if ((o_path
->cost
== route
->path
.cost
) &&
787 (o_path
->u
.cost_e2
== route
->path
.u
.cost_e2
))
790 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
791 for (ALL_LIST_ELEMENTS(old_route
->nh_list
, rnode
,
793 if (!ospf6_nexthop_is_same(rnh
, nh
))
795 listnode_delete(old_route
->nh_list
, rnh
);
796 ospf6_nexthop_delete(rnh
);
801 listnode_delete(old_route
->paths
, o_path
);
802 ospf6_path_free(o_path
);
804 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
,
806 ospf6_merge_nexthops(old_route
->nh_list
,
810 if (IS_OSPF6_DEBUG_ABR
|| IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX
))
811 zlog_debug("%s: paths %u nh %u", __func__
,
813 ? listcount(old_route
->paths
)
816 ? listcount(old_route
->nh_list
)
820 (*table
->hook_add
)(old_route
);
822 if (old_route
->path
.origin
.id
== route
->path
.origin
.id
&&
823 old_route
->path
.origin
.adv_router
==
824 route
->path
.origin
.adv_router
) {
825 struct ospf6_path
*h_path
;
827 h_path
= (struct ospf6_path
*)
828 listgetdata(listhead(old_route
->paths
));
829 old_route
->path
.origin
.type
= h_path
->origin
.type
;
830 old_route
->path
.origin
.id
= h_path
->origin
.id
;
831 old_route
->path
.origin
.adv_router
=
832 h_path
->origin
.adv_router
;
837 void ospf6_abr_old_route_remove(struct ospf6_lsa
*lsa
, struct ospf6_route
*old
,
838 struct ospf6_route_table
*table
)
840 if (IS_OSPF6_DEBUG_ABR
)
841 zlog_debug("%s: route %pFX, paths %d", __func__
, &old
->prefix
,
842 listcount(old
->paths
));
844 if (listcount(old
->paths
) > 1) {
845 struct listnode
*anode
, *anext
, *nnode
, *rnode
, *rnext
;
846 struct ospf6_path
*o_path
;
847 struct ospf6_nexthop
*nh
, *rnh
;
848 bool nh_updated
= false;
850 for (ALL_LIST_ELEMENTS(old
->paths
, anode
, anext
, o_path
)) {
851 if (o_path
->origin
.adv_router
!= lsa
->header
->adv_router
852 || o_path
->origin
.id
!= lsa
->header
->id
)
854 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
855 for (ALL_LIST_ELEMENTS(old
->nh_list
,
856 rnode
, rnext
, rnh
)) {
857 if (!ospf6_nexthop_is_same(rnh
, nh
))
859 if (IS_OSPF6_DEBUG_ABR
)
860 zlog_debug("deleted nexthop");
861 listnode_delete(old
->nh_list
, rnh
);
862 ospf6_nexthop_delete(rnh
);
865 listnode_delete(old
->paths
, o_path
);
866 ospf6_path_free(o_path
);
871 if (listcount(old
->paths
)) {
872 if (IS_OSPF6_DEBUG_ABR
873 || IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX
))
874 zlog_debug("%s: old %pFX updated nh %u",
875 __func__
, &old
->prefix
,
876 old
->nh_list
? listcount(
881 (*table
->hook_add
)(old
);
883 if ((old
->path
.origin
.id
== lsa
->header
->id
) &&
884 (old
->path
.origin
.adv_router
885 == lsa
->header
->adv_router
)) {
886 struct ospf6_path
*h_path
;
888 h_path
= (struct ospf6_path
*)
890 listhead(old
->paths
));
891 old
->path
.origin
.type
=
893 old
->path
.origin
.id
= h_path
->origin
.id
;
894 old
->path
.origin
.adv_router
=
895 h_path
->origin
.adv_router
;
898 ospf6_route_remove(old
, table
);
901 ospf6_route_remove(old
, table
);
904 /* RFC 2328 16.2. Calculating the inter-area routes */
905 void ospf6_abr_examin_summary(struct ospf6_lsa
*lsa
, struct ospf6_area
*oa
)
907 struct prefix prefix
, abr_prefix
;
908 struct ospf6_route_table
*table
= NULL
;
909 struct ospf6_route
*range
, *route
, *old
= NULL
, *old_route
;
910 struct ospf6_route
*abr_entry
;
912 char options
[3] = {0, 0, 0};
913 uint8_t prefix_options
= 0;
915 uint8_t router_bits
= 0;
916 char buf
[PREFIX2STR_BUFFER
];
918 struct ospf6_inter_prefix_lsa
*prefix_lsa
= NULL
;
919 struct ospf6_inter_router_lsa
*router_lsa
= NULL
;
920 bool old_entry_updated
= false;
921 struct ospf6_path
*path
, *o_path
, *ecmp_path
;
922 struct listnode
*anode
;
923 bool add_route
= false;
925 memset(&prefix
, 0, sizeof(prefix
));
927 if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_PREFIX
)) {
928 if (IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX
)) {
930 zlog_debug("%s: LSA %s age %d in area %s", __func__
,
931 lsa
->name
, ospf6_lsa_age_current(lsa
),
936 (struct ospf6_inter_prefix_lsa
*)OSPF6_LSA_HEADER_END(
938 prefix
.family
= AF_INET6
;
939 prefix
.prefixlen
= prefix_lsa
->prefix
.prefix_length
;
940 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, prefix_lsa
,
941 &prefix_lsa
->prefix
);
943 prefix2str(&prefix
, buf
, sizeof(buf
));
944 table
= oa
->ospf6
->route_table
;
945 type
= OSPF6_DEST_TYPE_NETWORK
;
946 prefix_options
= prefix_lsa
->prefix
.prefix_options
;
947 cost
= OSPF6_ABR_SUMMARY_METRIC(prefix_lsa
);
948 } else if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_ROUTER
)) {
949 if (IS_OSPF6_DEBUG_EXAMIN(INTER_ROUTER
)) {
951 zlog_debug("%s: LSA %s age %d in area %s", __func__
,
952 lsa
->name
, ospf6_lsa_age_current(lsa
),
957 (struct ospf6_inter_router_lsa
*)OSPF6_LSA_HEADER_END(
959 ospf6_linkstate_prefix(router_lsa
->router_id
, htonl(0),
962 inet_ntop(AF_INET
, &router_lsa
->router_id
, buf
,
965 table
= oa
->ospf6
->brouter_table
;
966 type
= OSPF6_DEST_TYPE_ROUTER
;
967 options
[0] = router_lsa
->options
[0];
968 options
[1] = router_lsa
->options
[1];
969 options
[2] = router_lsa
->options
[2];
970 cost
= OSPF6_ABR_SUMMARY_METRIC(router_lsa
);
971 SET_FLAG(router_bits
, OSPF6_ROUTER_BIT_E
);
975 /* Find existing route */
976 route
= ospf6_route_lookup(&prefix
, table
);
978 ospf6_route_lock(route
);
980 zlog_debug("%s: route %pFX, paths %d", __func__
,
981 &prefix
, listcount(route
->paths
));
983 while (route
&& ospf6_route_is_prefix(&prefix
, route
)) {
984 if (route
->path
.area_id
== oa
->area_id
985 && route
->path
.origin
.type
== lsa
->header
->type
986 && !CHECK_FLAG(route
->flag
, OSPF6_ROUTE_WAS_REMOVED
)) {
987 /* LSA adv. router could be part of route's
988 * paths list. Find the existing path and set
991 if (listcount(route
->paths
) > 1) {
992 for (ALL_LIST_ELEMENTS_RO(route
->paths
, anode
,
994 if (o_path
->origin
.id
== lsa
->header
->id
995 && o_path
->origin
.adv_router
==
996 lsa
->header
->adv_router
) {
1001 "%s: old entry found in paths, adv_router %pI4",
1003 &o_path
->origin
.adv_router
);
1008 } else if (route
->path
.origin
.id
== lsa
->header
->id
&&
1009 route
->path
.origin
.adv_router
==
1010 lsa
->header
->adv_router
)
1013 route
= ospf6_route_next(route
);
1016 ospf6_route_unlock(route
);
1018 /* (1) if cost == LSInfinity or if the LSA is MaxAge */
1019 if (cost
== OSPF_LS_INFINITY
) {
1021 zlog_debug("cost is LS_INFINITY, ignore");
1023 ospf6_abr_old_route_remove(lsa
, old
, table
);
1026 if (OSPF6_LSA_IS_MAXAGE(lsa
)) {
1028 zlog_debug("%s: LSA %s is MaxAge, ignore", __func__
,
1031 ospf6_abr_old_route_remove(lsa
, old
, table
);
1036 /* (2) if the LSA is self-originated, ignore */
1037 if (lsa
->header
->adv_router
== oa
->ospf6
->router_id
) {
1039 zlog_debug("LSA %s is self-originated, ignore",
1042 ospf6_route_remove(old
, table
);
1046 /* (3) if the prefix is equal to an active configured address range */
1047 /* or if the NU bit is set in the prefix */
1048 if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_PREFIX
)) {
1049 /* must have been set in previous block */
1052 range
= ospf6_route_lookup(&prefix
, oa
->range_table
);
1056 "Prefix is equal to address range, ignore");
1058 ospf6_route_remove(old
, table
);
1062 if (CHECK_FLAG(prefix_lsa
->prefix
.prefix_options
,
1063 OSPF6_PREFIX_OPTION_NU
)
1064 || CHECK_FLAG(prefix_lsa
->prefix
.prefix_options
,
1065 OSPF6_PREFIX_OPTION_LA
)) {
1067 zlog_debug("Prefix has NU/LA bit set, ignore");
1069 ospf6_route_remove(old
, table
);
1074 if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_ROUTER
)) {
1075 /* To pass test suites */
1077 if (!OSPF6_OPT_ISSET(router_lsa
->options
, OSPF6_OPT_R
)
1078 || !OSPF6_OPT_ISSET(router_lsa
->options
, OSPF6_OPT_V6
)) {
1080 zlog_debug("Prefix has NU/LA bit set, ignore");
1082 ospf6_route_remove(old
, table
);
1086 /* Avoid infinite recursion if someone has maliciously announced
1088 Inter-Router LSA for an ABR
1090 if (lsa
->header
->adv_router
== router_lsa
->router_id
) {
1093 "Ignorning Inter-Router LSA for an ABR (%s)",
1096 ospf6_route_remove(old
, table
);
1102 /* (4) if the routing table entry for the ABR does not exist */
1103 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &abr_prefix
);
1104 abr_entry
= ospf6_route_lookup(&abr_prefix
, oa
->ospf6
->brouter_table
);
1105 if (abr_entry
== NULL
|| abr_entry
->path
.area_id
!= oa
->area_id
1106 || CHECK_FLAG(abr_entry
->flag
, OSPF6_ROUTE_REMOVE
)
1107 || !CHECK_FLAG(abr_entry
->path
.router_bits
, OSPF6_ROUTER_BIT_B
)) {
1110 "%s: ABR router entry %pFX does not exist, ignore",
1111 __func__
, &abr_prefix
);
1113 if (old
->type
== OSPF6_DEST_TYPE_ROUTER
&&
1114 oa
->intra_brouter_calc
) {
1117 "%s: intra_brouter_calc is on, skip brouter remove: %s (%p)",
1118 __func__
, buf
, (void *)old
);
1122 "%s: remove old entry: %s %p ",
1123 __func__
, buf
, (void *)old
);
1124 ospf6_abr_old_route_remove(lsa
, old
, table
);
1130 /* Check import list */
1131 if (IMPORT_NAME(oa
)) {
1132 if (IMPORT_LIST(oa
) == NULL
)
1134 access_list_lookup(AFI_IP6
, IMPORT_NAME(oa
));
1136 if (IMPORT_LIST(oa
))
1137 if (access_list_apply(IMPORT_LIST(oa
), &prefix
)
1141 "Prefix %pFX was denied by import-list",
1144 ospf6_route_remove(old
, table
);
1149 /* Check input prefix-list */
1150 if (PREFIX_LIST_IN(oa
)) {
1151 if (prefix_list_apply(PREFIX_LIST_IN(oa
), &prefix
)
1155 "Prefix %pFX was denied by prefix-list in",
1158 ospf6_route_remove(old
, table
);
1163 /* (5),(6): the path preference is handled by the sorting
1164 in the routing table. Always install the path by substituting
1165 old route (if any). */
1166 route
= ospf6_route_create();
1169 route
->prefix
= prefix
;
1170 route
->path
.origin
.type
= lsa
->header
->type
;
1171 route
->path
.origin
.id
= lsa
->header
->id
;
1172 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
1173 route
->path
.router_bits
= router_bits
;
1174 route
->path
.options
[0] = options
[0];
1175 route
->path
.options
[1] = options
[1];
1176 route
->path
.options
[2] = options
[2];
1177 route
->path
.prefix_options
= prefix_options
;
1178 route
->path
.area_id
= oa
->area_id
;
1179 route
->path
.type
= OSPF6_PATH_TYPE_INTER
;
1180 route
->path
.cost
= abr_entry
->path
.cost
+ cost
;
1182 /* copy brouter rechable nexthops into the route. */
1183 ospf6_route_copy_nexthops(route
, abr_entry
);
1185 /* (7) If the routes are identical, copy the next hops over to existing
1186 route. ospf6's route table implementation will otherwise string both
1187 routes, but keep the older one as the best route since the routes
1190 old
= ospf6_route_lookup(&prefix
, table
);
1193 zlog_debug("%s: found old route %pFX, paths %d",
1194 __func__
, &prefix
, listcount(old
->paths
));
1196 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
1197 if (!ospf6_route_is_same(old_route
, route
) ||
1198 (old_route
->type
!= route
->type
) ||
1199 (old_route
->path
.type
!= route
->path
.type
))
1202 if ((ospf6_route_cmp(route
, old_route
) != 0)) {
1205 "%s: old %p %pFX cost %u new route cost %u are not same",
1206 __func__
, (void *)old_route
, &prefix
,
1207 old_route
->path
.cost
, route
->path
.cost
);
1209 /* Check new route's adv. router is same in one of
1210 * the paths with differed cost, if so remove the
1211 * old path as later new route will be added.
1213 if (listcount(old_route
->paths
) > 1)
1214 ospf6_abr_old_path_update(old_route
, route
,
1219 ospf6_route_merge_nexthops(old_route
, route
);
1220 old_entry_updated
= true;
1222 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
1224 if (o_path
->area_id
== route
->path
.area_id
&&
1225 (memcmp(&(o_path
)->origin
, &(route
)->path
.origin
,
1226 sizeof(struct ospf6_ls_origin
)) == 0))
1230 /* New adv. router for a existing path add to paths list */
1231 if (o_path
== NULL
) {
1232 ecmp_path
= ospf6_path_dup(&route
->path
);
1234 /* Add a nh_list to new ecmp path */
1235 ospf6_copy_nexthops(ecmp_path
->nh_list
, route
->nh_list
);
1237 /* Add the new path to route's path list */
1238 listnode_add_sort(old_route
->paths
, ecmp_path
);
1242 "%s: route %pFX cost %u another path %pI4 added with nh %u, effective paths %u nh %u",
1243 __func__
, &route
->prefix
,
1244 old_route
->path
.cost
,
1245 &ecmp_path
->origin
.adv_router
,
1246 listcount(ecmp_path
->nh_list
),
1248 ? listcount(old_route
->paths
)
1250 listcount(old_route
->nh_list
));
1253 struct ospf6_route
*tmp_route
= ospf6_route_create();
1255 ospf6_copy_nexthops(tmp_route
->nh_list
,
1258 if (ospf6_route_cmp_nexthops(tmp_route
, route
) != 0) {
1259 /* adv. router exists in the list, update nhs */
1260 list_delete_all_node(o_path
->nh_list
);
1261 ospf6_copy_nexthops(o_path
->nh_list
,
1263 ospf6_route_delete(tmp_route
);
1265 /* adv. router has no change in nhs */
1266 old_entry_updated
= false;
1267 ospf6_route_delete(tmp_route
);
1274 "%s: Update route: %s %p old cost %u new cost %u nh %u",
1275 __func__
, buf
, (void *)old_route
,
1276 old_route
->path
.cost
, route
->path
.cost
,
1277 listcount(old_route
->nh_list
));
1279 /* For Inter-Prefix route: Update RIB/FIB,
1280 * For Inter-Router trigger summary update
1282 if (table
->hook_add
)
1283 (*table
->hook_add
)(old_route
);
1288 /* If the old entry is not updated and old entry not found or old entry
1289 * does not match with the new entry then add the new route
1291 if (old_entry_updated
== false) {
1292 if ((old
== NULL
) || (old
->type
!= route
->type
)
1293 || (old
->path
.type
!= route
->path
.type
)
1294 || (old
->path
.cost
!= route
->path
.cost
))
1301 "%s: Install new route: %s cost %u nh %u adv_router %pI4",
1302 __func__
, buf
, route
->path
.cost
,
1303 listcount(route
->nh_list
),
1304 &route
->path
.origin
.adv_router
);
1307 path
= ospf6_path_dup(&route
->path
);
1308 ospf6_copy_nexthops(path
->nh_list
, abr_entry
->nh_list
);
1309 listnode_add_sort(route
->paths
, path
);
1310 /* ospf6_ia_add_nw_route (table, &prefix, route); */
1311 ospf6_route_add(route
, table
);
1313 /* if we did not add the route remove it */
1314 ospf6_route_delete(route
);
1317 void ospf6_abr_examin_brouter(uint32_t router_id
, struct ospf6_route
*route
,
1318 struct ospf6
*ospf6
)
1320 struct ospf6_lsa
*lsa
;
1321 struct ospf6_area
*oa
;
1324 oa
= ospf6_area_lookup(route
->path
.area_id
, ospf6
);
1326 * It is possible to designate a non backbone
1327 * area first. If that is the case safely
1328 * fall out of this function.
1333 type
= htons(OSPF6_LSTYPE_INTER_ROUTER
);
1334 for (ALL_LSDB_TYPED_ADVRTR(oa
->lsdb
, type
, router_id
, lsa
))
1335 ospf6_abr_examin_summary(lsa
, oa
);
1337 type
= htons(OSPF6_LSTYPE_INTER_PREFIX
);
1338 for (ALL_LSDB_TYPED_ADVRTR(oa
->lsdb
, type
, router_id
, lsa
))
1339 ospf6_abr_examin_summary(lsa
, oa
);
1342 void ospf6_abr_reimport(struct ospf6_area
*oa
)
1344 struct ospf6_lsa
*lsa
;
1347 type
= htons(OSPF6_LSTYPE_INTER_ROUTER
);
1348 for (ALL_LSDB_TYPED(oa
->lsdb
, type
, lsa
))
1349 ospf6_abr_examin_summary(lsa
, oa
);
1351 type
= htons(OSPF6_LSTYPE_INTER_PREFIX
);
1352 for (ALL_LSDB_TYPED(oa
->lsdb
, type
, lsa
))
1353 ospf6_abr_examin_summary(lsa
, oa
);
1356 /* export filter removed so determine if we should reoriginate summary LSAs */
1357 void ospf6_abr_reexport(struct ospf6_area
*oa
)
1359 struct ospf6_route
*route
;
1361 /* if not a ABR return success */
1362 if (!ospf6_check_and_set_router_abr(oa
->ospf6
))
1365 /* Redo summaries if required */
1366 for (route
= ospf6_route_head(oa
->ospf6
->route_table
); route
;
1367 route
= ospf6_route_next(route
))
1368 ospf6_abr_originate_summary_to_area(route
, oa
);
1371 void ospf6_abr_prefix_resummarize(struct ospf6
*o
)
1373 struct ospf6_route
*route
;
1375 if (IS_OSPF6_DEBUG_ABR
)
1376 zlog_debug("Re-examining Inter-Prefix Summaries");
1378 for (route
= ospf6_route_head(o
->route_table
); route
;
1379 route
= ospf6_route_next(route
))
1380 ospf6_abr_originate_summary(route
, o
);
1382 if (IS_OSPF6_DEBUG_ABR
)
1383 zlog_debug("Finished re-examining Inter-Prefix Summaries");
1387 /* Display functions */
1388 static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1389 char *buf
, int buflen
,
1392 struct ospf6_inter_prefix_lsa
*prefix_lsa
;
1393 struct in6_addr in6
;
1398 (struct ospf6_inter_prefix_lsa
*)OSPF6_LSA_HEADER_END(
1401 ospf6_prefix_in6_addr(&in6
, prefix_lsa
, &prefix_lsa
->prefix
);
1403 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
1404 snprintf(tbuf
, sizeof(tbuf
), "/%d",
1405 prefix_lsa
->prefix
.prefix_length
);
1406 strlcat(buf
, tbuf
, buflen
);
1413 static int ospf6_inter_area_prefix_lsa_show(struct vty
*vty
,
1414 struct ospf6_lsa
*lsa
,
1415 json_object
*json_obj
,
1418 struct ospf6_inter_prefix_lsa
*prefix_lsa
;
1419 char buf
[INET6_ADDRSTRLEN
];
1421 prefix_lsa
= (struct ospf6_inter_prefix_lsa
*)OSPF6_LSA_HEADER_END(
1425 json_object_int_add(
1427 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa
));
1428 ospf6_prefix_options_printbuf(prefix_lsa
->prefix
.prefix_options
,
1430 json_object_string_add(json_obj
, "prefixOptions", buf
);
1431 json_object_string_add(
1433 ospf6_inter_area_prefix_lsa_get_prefix_str(
1434 lsa
, buf
, sizeof(buf
), 0));
1436 vty_out(vty
, " Metric: %lu\n",
1437 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa
));
1439 ospf6_prefix_options_printbuf(prefix_lsa
->prefix
.prefix_options
,
1441 vty_out(vty
, " Prefix Options: %s\n", buf
);
1443 vty_out(vty
, " Prefix: %s\n",
1444 ospf6_inter_area_prefix_lsa_get_prefix_str(
1445 lsa
, buf
, sizeof(buf
), 0));
1451 static char *ospf6_inter_area_router_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1452 char *buf
, int buflen
,
1455 struct ospf6_inter_router_lsa
*router_lsa
;
1459 (struct ospf6_inter_router_lsa
*)OSPF6_LSA_HEADER_END(
1464 inet_ntop(AF_INET
, &router_lsa
->router_id
, buf
, buflen
);
1470 static int ospf6_inter_area_router_lsa_show(struct vty
*vty
,
1471 struct ospf6_lsa
*lsa
,
1472 json_object
*json_obj
,
1475 struct ospf6_inter_router_lsa
*router_lsa
;
1478 router_lsa
= (struct ospf6_inter_router_lsa
*)OSPF6_LSA_HEADER_END(
1481 ospf6_options_printbuf(router_lsa
->options
, buf
, sizeof(buf
));
1483 json_object_string_add(json_obj
, "options", buf
);
1484 json_object_int_add(
1486 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa
));
1488 vty_out(vty
, " Options: %s\n", buf
);
1489 vty_out(vty
, " Metric: %lu\n",
1490 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa
));
1493 inet_ntop(AF_INET
, &router_lsa
->router_id
, buf
, sizeof(buf
));
1495 json_object_string_add(json_obj
, "destinationRouterId", buf
);
1497 vty_out(vty
, " Destination Router ID: %s\n", buf
);
1502 /* Debug commands */
1503 DEFUN (debug_ospf6_abr
,
1504 debug_ospf6_abr_cmd
,
1508 "Debug OSPFv3 ABR function\n"
1511 OSPF6_DEBUG_ABR_ON();
1515 DEFUN (no_debug_ospf6_abr
,
1516 no_debug_ospf6_abr_cmd
,
1517 "no debug ospf6 abr",
1521 "Debug OSPFv3 ABR function\n"
1524 OSPF6_DEBUG_ABR_OFF();
1528 int config_write_ospf6_debug_abr(struct vty
*vty
)
1530 if (IS_OSPF6_DEBUG_ABR
)
1531 vty_out(vty
, "debug ospf6 abr\n");
1535 void install_element_ospf6_debug_abr(void)
1537 install_element(ENABLE_NODE
, &debug_ospf6_abr_cmd
);
1538 install_element(ENABLE_NODE
, &no_debug_ospf6_abr_cmd
);
1539 install_element(CONFIG_NODE
, &debug_ospf6_abr_cmd
);
1540 install_element(CONFIG_NODE
, &no_debug_ospf6_abr_cmd
);
1543 static struct ospf6_lsa_handler inter_prefix_handler
= {
1544 .lh_type
= OSPF6_LSTYPE_INTER_PREFIX
,
1545 .lh_name
= "Inter-Prefix",
1546 .lh_short_name
= "IAP",
1547 .lh_show
= ospf6_inter_area_prefix_lsa_show
,
1548 .lh_get_prefix_str
= ospf6_inter_area_prefix_lsa_get_prefix_str
,
1551 static struct ospf6_lsa_handler inter_router_handler
= {
1552 .lh_type
= OSPF6_LSTYPE_INTER_ROUTER
,
1553 .lh_name
= "Inter-Router",
1554 .lh_short_name
= "IAR",
1555 .lh_show
= ospf6_inter_area_router_lsa_show
,
1556 .lh_get_prefix_str
= ospf6_inter_area_router_lsa_get_prefix_str
,
1559 void ospf6_abr_init(void)
1561 ospf6_install_lsa_handler(&inter_prefix_handler
);
1562 ospf6_install_lsa_handler(&inter_router_handler
);