1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Area Border Router function.
4 * Copyright (C) 2004 Yasuhiro Ohara
19 #include "ospf6_proto.h"
20 #include "ospf6_route.h"
21 #include "ospf6_lsa.h"
22 #include "ospf6_route.h"
23 #include "ospf6_lsdb.h"
24 #include "ospf6_message.h"
25 #include "ospf6_zebra.h"
27 #include "ospf6_top.h"
28 #include "ospf6_area.h"
29 #include "ospf6_interface.h"
30 #include "ospf6_neighbor.h"
32 #include "ospf6_flood.h"
33 #include "ospf6_intra.h"
34 #include "ospf6_asbr.h"
35 #include "ospf6_abr.h"
37 #include "ospf6_nssa.h"
39 unsigned char conf_debug_ospf6_abr
;
41 int ospf6_ls_origin_same(struct ospf6_path
*o_path
, struct ospf6_path
*r_path
)
43 if (((o_path
->origin
.type
== r_path
->origin
.type
)
44 && (o_path
->origin
.id
== r_path
->origin
.id
)
45 && (o_path
->origin
.adv_router
== r_path
->origin
.adv_router
)))
51 bool ospf6_check_and_set_router_abr(struct ospf6
*o
)
53 struct listnode
*node
;
54 struct ospf6_area
*oa
;
56 bool is_backbone
= false;
58 for (ALL_LIST_ELEMENTS_RO(o
->area_list
, node
, oa
)) {
59 if (IS_OSPF6_DEBUG_ABR
)
60 zlog_debug("%s, area_id %pI4", __func__
, &oa
->area_id
);
61 if (IS_AREA_ENABLED(oa
))
64 if (o
->backbone
== oa
)
68 if ((area_count
> 1) && (is_backbone
)) {
69 if (IS_OSPF6_DEBUG_ABR
)
70 zlog_debug("%s : set flag OSPF6_FLAG_ABR", __func__
);
71 SET_FLAG(o
->flag
, OSPF6_FLAG_ABR
);
74 if (IS_OSPF6_DEBUG_ABR
)
75 zlog_debug("%s : reset flag OSPF6_FLAG_ABR", __func__
);
76 UNSET_FLAG(o
->flag
, OSPF6_FLAG_ABR
);
81 static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route
*route
,
82 struct ospf6_area
*area
)
84 struct ospf6_interface
*oi
;
86 oi
= ospf6_interface_lookup_by_ifindex(
87 ospf6_route_get_first_nh_index(route
), area
->ospf6
->vrf_id
);
88 if (oi
&& oi
->area
&& oi
->area
== area
)
94 static void ospf6_abr_delete_route(struct ospf6_route
*summary
,
95 struct ospf6_route_table
*summary_table
,
96 struct ospf6_lsa
*old
)
99 ospf6_route_remove(summary
, summary_table
);
102 if (old
&& !OSPF6_LSA_IS_MAXAGE(old
))
103 ospf6_lsa_purge(old
);
106 void ospf6_abr_enable_area(struct ospf6_area
*area
)
108 struct ospf6_area
*oa
;
109 struct listnode
*node
, *nnode
;
111 for (ALL_LIST_ELEMENTS(area
->ospf6
->area_list
, node
, nnode
, oa
))
112 /* update B bit for each area */
113 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
116 void ospf6_abr_disable_area(struct ospf6_area
*area
)
118 struct ospf6_area
*oa
;
119 struct ospf6_route
*ro
, *nro
;
120 struct ospf6_lsa
*old
;
121 struct listnode
*node
, *nnode
;
123 /* Withdraw all summary prefixes previously originated */
124 for (ro
= ospf6_route_head(area
->summary_prefix
); ro
; ro
= nro
) {
125 nro
= ospf6_route_next(ro
);
126 old
= ospf6_lsdb_lookup(ro
->path
.origin
.type
,
128 area
->ospf6
->router_id
, area
->lsdb
);
130 ospf6_lsa_purge(old
);
131 ospf6_route_remove(ro
, area
->summary_prefix
);
134 /* Withdraw all summary router-routes previously originated */
135 for (ro
= ospf6_route_head(area
->summary_router
); ro
; ro
= nro
) {
136 nro
= ospf6_route_next(ro
);
137 old
= ospf6_lsdb_lookup(ro
->path
.origin
.type
,
139 area
->ospf6
->router_id
, area
->lsdb
);
141 ospf6_lsa_purge(old
);
142 ospf6_route_remove(ro
, area
->summary_router
);
145 /* Schedule Router-LSA for each area (ABR status may change) */
146 for (ALL_LIST_ELEMENTS(area
->ospf6
->area_list
, node
, nnode
, oa
))
147 /* update B bit for each area */
148 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
151 /* RFC 2328 12.4.3. Summary-LSAs */
152 /* Returns 1 if a summary LSA has been generated for the area */
153 /* This is used by the area/range logic to add/remove blackhole routes */
154 int ospf6_abr_originate_summary_to_area(struct ospf6_route
*route
,
155 struct ospf6_area
*area
)
157 struct ospf6_lsa
*lsa
, *old
= NULL
;
158 struct ospf6_route
*summary
, *range
= NULL
;
159 struct ospf6_area
*route_area
;
160 char buffer
[OSPF6_MAX_LSASIZE
];
161 struct ospf6_lsa_header
*lsa_header
;
163 struct ospf6_inter_prefix_lsa
*prefix_lsa
;
164 struct ospf6_inter_router_lsa
*router_lsa
;
165 struct ospf6_route_table
*summary_table
= NULL
;
169 if (IS_OSPF6_DEBUG_ABR
) {
172 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
)
174 &ADV_ROUTER_IN_PREFIX(&route
->prefix
), buf
,
177 prefix2str(&route
->prefix
, buf
, sizeof(buf
));
179 zlog_debug("%s : start area %s, route %s", __func__
, area
->name
,
183 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
)
184 summary_table
= area
->summary_router
;
186 summary_table
= area
->summary_prefix
;
188 summary
= ospf6_route_lookup(&route
->prefix
, summary_table
);
190 old
= ospf6_lsdb_lookup(summary
->path
.origin
.type
,
191 summary
->path
.origin
.id
,
192 area
->ospf6
->router_id
, area
->lsdb
);
193 /* Reset the OSPF6_LSA_UNAPPROVED flag */
195 UNSET_FLAG(old
->flag
, OSPF6_LSA_UNAPPROVED
);
198 /* Only destination type network, range or ASBR are considered */
199 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
200 && route
->type
!= OSPF6_DEST_TYPE_RANGE
201 && ((route
->type
!= OSPF6_DEST_TYPE_ROUTER
)
202 || !CHECK_FLAG(route
->path
.router_bits
, OSPF6_ROUTER_BIT_E
))) {
203 if (IS_OSPF6_DEBUG_ABR
)
205 "%s: Route type %d flag 0x%x is none of network, range nor ASBR, ignore",
206 __func__
, route
->type
, route
->path
.router_bits
);
210 /* AS External routes are never considered */
211 if (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
212 || route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL2
) {
213 if (IS_OSPF6_DEBUG_ABR
)
214 zlog_debug("%s : Path type is external, skip",
219 /* do not generate if the path's area is the same as target area */
220 if (route
->path
.area_id
== area
->area_id
) {
221 if (IS_OSPF6_DEBUG_ABR
)
223 "%s: The route is in the area itself, ignore",
228 if (route
->type
== OSPF6_DEST_TYPE_NETWORK
) {
232 ospf6_area_lookup(route
->path
.area_id
, area
->ospf6
);
235 /* Check export-list */
236 if (EXPORT_LIST(route_area
)
237 && access_list_apply(EXPORT_LIST(route_area
),
240 if (IS_OSPF6_DEBUG_ABR
)
242 "%s: prefix %pFX was denied by export-list",
243 __func__
, &route
->prefix
);
247 /* Check output prefix-list */
248 if (PREFIX_LIST_OUT(route_area
)
249 && prefix_list_apply(PREFIX_LIST_OUT(route_area
),
252 if (IS_OSPF6_DEBUG_ABR
)
254 "%s: prefix %pFX was denied by prefix-list out",
255 __func__
, &route
->prefix
);
259 /* Check import-list */
260 if (IMPORT_LIST(area
)
261 && access_list_apply(IMPORT_LIST(area
), &route
->prefix
)
263 if (IS_OSPF6_DEBUG_ABR
)
265 "%s: prefix %pFX was denied by import-list",
266 __func__
, &route
->prefix
);
270 /* Check input prefix-list */
271 if (PREFIX_LIST_IN(area
)
272 && prefix_list_apply(PREFIX_LIST_IN(area
), &route
->prefix
)
274 if (IS_OSPF6_DEBUG_ABR
)
276 "%s: prefix %pFX was denied by prefix-list in",
277 __func__
, &route
->prefix
);
283 ospf6_route_remove(summary
, summary_table
);
285 ospf6_lsa_purge(old
);
291 /* do not generate if the nexthops belongs to the target area */
292 if (ospf6_abr_nexthops_belong_to_area(route
, area
)) {
293 if (IS_OSPF6_DEBUG_ABR
)
295 "%s: The route's nexthop is in the same area, ignore",
300 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
301 if (ADV_ROUTER_IN_PREFIX(&route
->prefix
)
302 == area
->ospf6
->router_id
) {
303 if (IS_OSPF6_DEBUG_ABR
)
305 "%s: Skipping ASBR announcement for ABR (%pI4)",
307 &ADV_ROUTER_IN_PREFIX(&route
->prefix
));
312 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
313 if (IS_OSPF6_DEBUG_ABR
314 || IS_OSPF6_DEBUG_ORIGINATE(INTER_ROUTER
)) {
316 if (IS_OSPF6_DEBUG_ABR
)
318 "Originating summary in area %s for ASBR %pI4",
320 &ADV_ROUTER_IN_PREFIX(&route
->prefix
));
323 if (IS_OSPF6_DEBUG_ABR
324 || IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX
))
327 if (route
->type
== OSPF6_DEST_TYPE_NETWORK
&&
328 route
->path
.origin
.type
==
329 htons(OSPF6_LSTYPE_INTER_PREFIX
)) {
330 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_BEST
)) {
333 "%s: route %pFX with cost %u is not best, ignore.",
334 __func__
, &route
->prefix
,
340 if (route
->path
.origin
.type
==
341 htons(OSPF6_LSTYPE_INTRA_PREFIX
)) {
342 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_BEST
)) {
345 "%s: intra-prefix route %pFX with cost %u is not best, ignore.",
346 __func__
, &route
->prefix
,
354 "Originating summary in area %s for %pFX cost %u",
355 area
->name
, &route
->prefix
, route
->path
.cost
);
358 /* if this route has just removed, remove corresponding LSA */
359 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)) {
362 "The route has just removed, purge previous LSA");
364 if (route
->type
== OSPF6_DEST_TYPE_RANGE
) {
365 /* Whether the route have active longer prefix */
366 if (!CHECK_FLAG(route
->flag
,
367 OSPF6_ROUTE_ACTIVE_SUMMARY
)) {
370 "The range is not active. withdraw");
372 ospf6_abr_delete_route(summary
, summary_table
,
376 ospf6_route_remove(summary
, summary_table
);
377 ospf6_lsa_purge(old
);
382 if ((route
->type
== OSPF6_DEST_TYPE_ROUTER
)
383 && (IS_AREA_STUB(area
) || IS_AREA_NSSA(area
))) {
386 "Area has been stubbed, purge Inter-Router LSA");
388 ospf6_abr_delete_route(summary
, summary_table
, old
);
393 && (route
->path
.subtype
!= OSPF6_PATH_SUBTYPE_DEFAULT_RT
)) {
395 zlog_debug("Area has been stubbed, purge prefix LSA");
397 ospf6_abr_delete_route(summary
, summary_table
, old
);
401 /* do not generate if the route cost is greater or equal to LSInfinity
403 if (route
->path
.cost
>= OSPF_LS_INFINITY
) {
404 /* When we're clearing the range route because all active
406 * under the range are gone, we set the range's cost to
407 * OSPF_AREA_RANGE_COST_UNSPEC, which is > OSPF_LS_INFINITY. We
408 * don't want to trigger the code here for that. This code is
410 * handling routes that have gone to infinity. The range removal
414 if ((route
->type
!= OSPF6_DEST_TYPE_RANGE
)
415 && (route
->path
.cost
!= OSPF_AREA_RANGE_COST_UNSPEC
)) {
418 "The cost exceeds LSInfinity, withdraw");
420 ospf6_lsa_purge(old
);
425 /* if this is a route to ASBR */
426 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
427 /* Only the preferred best path is considered */
428 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_BEST
)) {
431 "This is the secondary path to the ASBR, ignore");
432 ospf6_abr_delete_route(summary
, summary_table
, old
);
436 /* Do not generate if area is NSSA */
438 ospf6_area_lookup(route
->path
.area_id
, area
->ospf6
);
441 if (IS_AREA_NSSA(route_area
)) {
444 "%s: The route comes from NSSA area, skip",
446 ospf6_abr_delete_route(summary
, summary_table
, old
);
450 /* Do not generate if the area is stub */
454 /* if this is an intra-area route, this may be suppressed by aggregation
456 if (route
->type
== OSPF6_DEST_TYPE_NETWORK
457 && route
->path
.type
== OSPF6_PATH_TYPE_INTRA
) {
458 /* search for configured address range for the route's area */
460 ospf6_area_lookup(route
->path
.area_id
, area
->ospf6
);
462 range
= ospf6_route_lookup_bestmatch(&route
->prefix
,
463 route_area
->range_table
);
465 /* ranges are ignored when originate backbone routes to transit
467 Otherwise, if ranges are configured, the route is suppressed.
469 if (range
&& !CHECK_FLAG(range
->flag
, OSPF6_ROUTE_REMOVE
)
470 && (route
->path
.area_id
!= OSPF_AREA_BACKBONE
471 || !IS_AREA_TRANSIT(area
))) {
474 "Suppressed by range %pFX of area %s",
475 &range
->prefix
, route_area
->name
);
476 /* The existing summary route could be a range, don't
477 * remove it in this case
479 if (summary
&& summary
->type
!= OSPF6_DEST_TYPE_RANGE
)
480 ospf6_abr_delete_route(summary
, summary_table
,
486 /* If this is a configured address range */
487 if (route
->type
== OSPF6_DEST_TYPE_RANGE
) {
488 /* If DoNotAdvertise is set */
489 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_DO_NOT_ADVERTISE
)) {
492 "This is the range with DoNotAdvertise set. ignore");
493 ospf6_abr_delete_route(summary
, summary_table
, old
);
497 /* If there are no active prefixes in this range, remove */
498 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)) {
500 zlog_debug("The range is not active. withdraw");
501 ospf6_abr_delete_route(summary
, summary_table
, old
);
506 /* the route is going to be originated. store it in area's summary_table
508 if (summary
== NULL
) {
509 summary
= ospf6_route_copy(route
);
510 summary
->path
.origin
.adv_router
= area
->ospf6
->router_id
;
512 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
513 summary
->path
.origin
.type
=
514 htons(OSPF6_LSTYPE_INTER_ROUTER
);
515 summary
->path
.origin
.id
=
516 ADV_ROUTER_IN_PREFIX(&route
->prefix
);
518 summary
->path
.origin
.type
=
519 htons(OSPF6_LSTYPE_INTER_PREFIX
);
520 summary
->path
.origin
.id
= ospf6_new_ls_id(
521 summary
->path
.origin
.type
,
522 summary
->path
.origin
.adv_router
, area
->lsdb
);
524 summary
= ospf6_route_add(summary
, summary_table
);
526 summary
->type
= route
->type
;
527 monotime(&summary
->changed
);
530 summary
->prefix_options
= route
->prefix_options
;
531 summary
->path
.router_bits
= route
->path
.router_bits
;
532 summary
->path
.options
[0] = route
->path
.options
[0];
533 summary
->path
.options
[1] = route
->path
.options
[1];
534 summary
->path
.options
[2] = route
->path
.options
[2];
535 summary
->path
.area_id
= area
->area_id
;
536 summary
->path
.type
= OSPF6_PATH_TYPE_INTER
;
537 summary
->path
.subtype
= route
->path
.subtype
;
538 summary
->path
.cost
= route
->path
.cost
;
539 /* summary->nexthop[0] = route->nexthop[0]; */
542 memset(buffer
, 0, sizeof(buffer
));
543 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
545 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
546 router_lsa
= (struct ospf6_inter_router_lsa
547 *)((caddr_t
)lsa_header
548 + sizeof(struct ospf6_lsa_header
));
549 p
= (caddr_t
)router_lsa
+ sizeof(struct ospf6_inter_router_lsa
);
551 /* Fill Inter-Area-Router-LSA */
552 router_lsa
->options
[0] = route
->path
.options
[0];
553 router_lsa
->options
[1] = route
->path
.options
[1];
554 router_lsa
->options
[2] = route
->path
.options
[2];
555 OSPF6_ABR_SUMMARY_METRIC_SET(router_lsa
, route
->path
.cost
);
556 router_lsa
->router_id
= ADV_ROUTER_IN_PREFIX(&route
->prefix
);
557 type
= htons(OSPF6_LSTYPE_INTER_ROUTER
);
559 prefix_lsa
= (struct ospf6_inter_prefix_lsa
560 *)((caddr_t
)lsa_header
561 + sizeof(struct ospf6_lsa_header
));
562 p
= (caddr_t
)prefix_lsa
+ sizeof(struct ospf6_inter_prefix_lsa
);
564 /* Fill Inter-Area-Prefix-LSA */
565 OSPF6_ABR_SUMMARY_METRIC_SET(prefix_lsa
, route
->path
.cost
);
566 prefix_lsa
->prefix
.prefix_length
= route
->prefix
.prefixlen
;
567 prefix_lsa
->prefix
.prefix_options
= route
->prefix_options
;
570 memcpy(p
, &route
->prefix
.u
.prefix6
,
571 OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
));
572 ospf6_prefix_apply_mask(&prefix_lsa
->prefix
);
573 p
+= OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
);
574 type
= htons(OSPF6_LSTYPE_INTER_PREFIX
);
577 /* Fill LSA Header */
579 lsa_header
->type
= type
;
580 lsa_header
->id
= summary
->path
.origin
.id
;
581 lsa_header
->adv_router
= area
->ospf6
->router_id
;
583 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
584 lsa_header
->adv_router
, area
->lsdb
);
585 lsa_header
->length
= htons((caddr_t
)p
- (caddr_t
)lsa_header
);
588 ospf6_lsa_checksum(lsa_header
);
591 lsa
= ospf6_lsa_create(lsa_header
);
593 /* Reset the unapproved flag */
594 UNSET_FLAG(lsa
->flag
, OSPF6_LSA_UNAPPROVED
);
597 ospf6_lsa_originate_area(lsa
, area
);
599 if (IS_OSPF6_DEBUG_ABR
)
600 zlog_debug("%s : finish area %s", __func__
, area
->name
);
605 void ospf6_abr_range_reset_cost(struct ospf6
*ospf6
)
607 struct listnode
*node
, *nnode
;
608 struct ospf6_area
*oa
;
609 struct ospf6_route
*range
;
611 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
)) {
612 for (range
= ospf6_route_head(oa
->range_table
); range
;
613 range
= ospf6_route_next(range
))
614 OSPF6_ABR_RANGE_CLEAR_COST(range
);
615 for (range
= ospf6_route_head(oa
->nssa_range_table
); range
;
616 range
= ospf6_route_next(range
))
617 OSPF6_ABR_RANGE_CLEAR_COST(range
);
621 static inline uint32_t ospf6_abr_range_compute_cost(struct ospf6_route
*range
,
624 struct ospf6_route
*ro
;
627 for (ro
= ospf6_route_match_head(&range
->prefix
, o
->route_table
); ro
;
628 ro
= ospf6_route_match_next(&range
->prefix
, ro
)) {
629 if (CHECK_FLAG(ro
->flag
, OSPF6_ROUTE_REMOVE
))
631 if (ro
->path
.area_id
!= range
->path
.area_id
)
633 if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_NSSA_RANGE
)
634 && ro
->path
.type
!= OSPF6_PATH_TYPE_EXTERNAL1
635 && ro
->path
.type
!= OSPF6_PATH_TYPE_EXTERNAL2
)
637 if (!CHECK_FLAG(range
->flag
, OSPF6_ROUTE_NSSA_RANGE
)
638 && ro
->path
.type
!= OSPF6_PATH_TYPE_INTRA
)
641 cost
= MAX(cost
, ro
->path
.cost
);
648 ospf6_abr_range_summary_needs_update(struct ospf6_route
*range
, uint32_t cost
)
650 int redo_summary
= 0;
652 if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_REMOVE
)) {
653 UNSET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
655 } else if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_DO_NOT_ADVERTISE
)) {
656 if (range
->path
.cost
!= 0) {
657 range
->path
.cost
= 0;
661 if ((OSPF6_PATH_COST_IS_CONFIGURED(range
->path
)
662 && range
->path
.cost
!= range
->path
.u
.cost_config
)) {
663 range
->path
.cost
= range
->path
.u
.cost_config
;
664 SET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
666 } else if (!OSPF6_PATH_COST_IS_CONFIGURED(range
->path
)
667 && range
->path
.cost
!= cost
) {
668 range
->path
.cost
= cost
;
669 SET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
672 } else if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)) {
673 /* Cost is zero, meaning no active range */
674 UNSET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
675 range
->path
.cost
= OSPF_AREA_RANGE_COST_UNSPEC
;
679 return (redo_summary
);
682 void ospf6_abr_range_update(struct ospf6_route
*range
, struct ospf6
*ospf6
)
685 struct listnode
*node
, *nnode
;
686 struct ospf6_area
*oa
;
687 int summary_orig
= 0;
689 assert(range
->type
== OSPF6_DEST_TYPE_RANGE
);
690 oa
= ospf6_area_lookup(range
->path
.area_id
, ospf6
);
693 /* update range's cost and active flag */
694 cost
= ospf6_abr_range_compute_cost(range
, ospf6
);
696 if (IS_OSPF6_DEBUG_ABR
)
697 zlog_debug("%s: range %pFX, cost %d", __func__
, &range
->prefix
,
700 /* Non-zero cost is a proxy for active longer prefixes in this range.
701 * If there are active routes covered by this range AND either the
703 * cost has changed or the summarized cost has changed then redo
705 * Alternately, if there are no longer active prefixes and there are
706 * summary announcements, withdraw those announcements.
708 * The don't advertise code relies on the path.cost being set to UNSPEC
710 * work the first time. Subsequent times the path.cost is not 0 anyway
712 * were active ranges.
714 if (!ospf6_abr_range_summary_needs_update(range
, cost
))
717 if (IS_OSPF6_DEBUG_ABR
)
718 zlog_debug("%s: range %pFX update", __func__
, &range
->prefix
);
720 if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_NSSA_RANGE
)) {
721 if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)
722 && !CHECK_FLAG(range
->flag
, OSPF6_ROUTE_DO_NOT_ADVERTISE
)) {
723 ospf6_nssa_lsa_originate(range
, oa
, true);
726 struct ospf6_lsa
*lsa
;
728 lsa
= ospf6_lsdb_lookup(range
->path
.origin
.type
,
729 range
->path
.origin
.id
,
730 ospf6
->router_id
, oa
->lsdb
);
732 ospf6_lsa_premature_aging(lsa
);
735 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
)) {
737 ospf6_abr_originate_summary_to_area(range
, oa
);
741 if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)
743 if (!CHECK_FLAG(range
->flag
, OSPF6_ROUTE_BLACKHOLE_ADDED
)) {
744 if (IS_OSPF6_DEBUG_ABR
)
745 zlog_debug("Add discard route");
747 ospf6_zebra_add_discard(range
, ospf6
);
750 /* Summary removed or no summary generated as no
752 if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_BLACKHOLE_ADDED
)) {
753 if (IS_OSPF6_DEBUG_ABR
)
754 zlog_debug("Delete discard route");
756 ospf6_zebra_delete_discard(range
, ospf6
);
761 void ospf6_abr_originate_summary(struct ospf6_route
*route
, struct ospf6
*ospf6
)
763 struct listnode
*node
, *nnode
;
764 struct ospf6_area
*oa
;
765 struct ospf6_route
*range
= NULL
;
767 if (IS_OSPF6_DEBUG_ABR
) {
770 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
)
772 &ADV_ROUTER_IN_PREFIX(&route
->prefix
), buf
,
775 prefix2str(&route
->prefix
, buf
, sizeof(buf
));
777 zlog_debug("%s: route %s", __func__
, buf
);
780 if (route
->type
== OSPF6_DEST_TYPE_NETWORK
) {
781 oa
= ospf6_area_lookup(route
->path
.area_id
, ospf6
);
783 zlog_err("OSPFv6 area lookup failed");
787 range
= ospf6_route_lookup_bestmatch(&route
->prefix
,
790 ospf6_abr_range_update(range
, ospf6
);
794 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
))
795 ospf6_abr_originate_summary_to_area(route
, oa
);
798 void ospf6_abr_defaults_to_stub(struct ospf6
*o
)
800 struct listnode
*node
, *nnode
;
801 struct ospf6_area
*oa
;
802 struct ospf6_route
*def
, *route
;
803 int type
= DEFAULT_ROUTE
;
808 def
= ospf6_route_create(o
);
809 def
->type
= OSPF6_DEST_TYPE_NETWORK
;
810 def
->prefix
.family
= AF_INET6
;
811 def
->prefix
.prefixlen
= 0;
812 memset(&def
->prefix
.u
.prefix6
, 0, sizeof(struct in6_addr
));
813 def
->type
= OSPF6_DEST_TYPE_NETWORK
;
814 def
->path
.type
= OSPF6_PATH_TYPE_INTER
;
815 def
->path
.subtype
= OSPF6_PATH_SUBTYPE_DEFAULT_RT
;
816 def
->path
.area_id
= o
->backbone
->area_id
;
817 def
->path
.metric_type
= metric_type(o
, type
, 0);
818 def
->path
.cost
= metric_value(o
, type
, 0);
820 for (ALL_LIST_ELEMENTS(o
->area_list
, node
, nnode
, oa
)) {
821 if (IS_AREA_STUB(oa
) || (IS_AREA_NSSA(oa
) && oa
->no_summary
)) {
822 /* announce defaults to stubby areas */
823 if (IS_OSPF6_DEBUG_ABR
)
825 "Announcing default route into stubby area %s",
827 UNSET_FLAG(def
->flag
, OSPF6_ROUTE_REMOVE
);
828 ospf6_abr_originate_summary_to_area(def
, oa
);
830 /* withdraw defaults when an area switches from stub to
832 route
= ospf6_route_lookup(&def
->prefix
,
835 && (route
->path
.subtype
== def
->path
.subtype
)) {
836 if (IS_OSPF6_DEBUG_ABR
)
838 "Withdrawing default route from non-stubby area %s",
840 SET_FLAG(def
->flag
, OSPF6_ROUTE_REMOVE
);
841 ospf6_abr_originate_summary_to_area(def
, oa
);
845 ospf6_route_delete(def
);
848 void ospf6_abr_old_path_update(struct ospf6_route
*old_route
,
849 struct ospf6_route
*route
,
850 struct ospf6_route_table
*table
)
852 struct ospf6_path
*o_path
= NULL
;
853 struct listnode
*anode
, *anext
;
854 struct listnode
*nnode
, *rnode
, *rnext
;
855 struct ospf6_nexthop
*nh
, *rnh
;
857 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
, anext
, o_path
)) {
858 if (o_path
->area_id
!= route
->path
.area_id
859 || !ospf6_ls_origin_same(o_path
, &route
->path
))
862 if ((o_path
->cost
== route
->path
.cost
) &&
863 (o_path
->u
.cost_e2
== route
->path
.u
.cost_e2
))
866 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
867 for (ALL_LIST_ELEMENTS(old_route
->nh_list
, rnode
,
869 if (!ospf6_nexthop_is_same(rnh
, nh
))
871 listnode_delete(old_route
->nh_list
, rnh
);
872 ospf6_nexthop_delete(rnh
);
877 listnode_delete(old_route
->paths
, o_path
);
878 ospf6_path_free(o_path
);
880 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
,
882 ospf6_merge_nexthops(old_route
->nh_list
,
886 if (IS_OSPF6_DEBUG_ABR
|| IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX
))
887 zlog_debug("%s: paths %u nh %u", __func__
,
889 ? listcount(old_route
->paths
)
892 ? listcount(old_route
->nh_list
)
896 (*table
->hook_add
)(old_route
);
898 if (old_route
->path
.origin
.id
== route
->path
.origin
.id
&&
899 old_route
->path
.origin
.adv_router
==
900 route
->path
.origin
.adv_router
) {
901 struct ospf6_path
*h_path
;
903 h_path
= (struct ospf6_path
*)
904 listgetdata(listhead(old_route
->paths
));
905 old_route
->path
.origin
.type
= h_path
->origin
.type
;
906 old_route
->path
.origin
.id
= h_path
->origin
.id
;
907 old_route
->path
.origin
.adv_router
=
908 h_path
->origin
.adv_router
;
913 void ospf6_abr_old_route_remove(struct ospf6_lsa
*lsa
, struct ospf6_route
*old
,
914 struct ospf6_route_table
*table
)
916 if (IS_OSPF6_DEBUG_ABR
)
917 zlog_debug("%s: route %pFX, paths %d", __func__
, &old
->prefix
,
918 listcount(old
->paths
));
920 if (listcount(old
->paths
) > 1) {
921 struct listnode
*anode
, *anext
, *nnode
, *rnode
, *rnext
;
922 struct ospf6_path
*o_path
;
923 struct ospf6_nexthop
*nh
, *rnh
;
924 bool nh_updated
= false;
926 for (ALL_LIST_ELEMENTS(old
->paths
, anode
, anext
, o_path
)) {
927 if (o_path
->origin
.adv_router
!= lsa
->header
->adv_router
928 || o_path
->origin
.id
!= lsa
->header
->id
)
930 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
931 for (ALL_LIST_ELEMENTS(old
->nh_list
,
932 rnode
, rnext
, rnh
)) {
933 if (!ospf6_nexthop_is_same(rnh
, nh
))
935 if (IS_OSPF6_DEBUG_ABR
)
936 zlog_debug("deleted nexthop");
937 listnode_delete(old
->nh_list
, rnh
);
938 ospf6_nexthop_delete(rnh
);
941 listnode_delete(old
->paths
, o_path
);
942 ospf6_path_free(o_path
);
947 if (listcount(old
->paths
)) {
948 if (IS_OSPF6_DEBUG_ABR
949 || IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX
))
950 zlog_debug("%s: old %pFX updated nh %u",
951 __func__
, &old
->prefix
,
952 old
->nh_list
? listcount(
957 (*table
->hook_add
)(old
);
959 if ((old
->path
.origin
.id
== lsa
->header
->id
) &&
960 (old
->path
.origin
.adv_router
961 == lsa
->header
->adv_router
)) {
962 struct ospf6_path
*h_path
;
964 h_path
= (struct ospf6_path
*)
966 listhead(old
->paths
));
967 old
->path
.origin
.type
=
969 old
->path
.origin
.id
= h_path
->origin
.id
;
970 old
->path
.origin
.adv_router
=
971 h_path
->origin
.adv_router
;
974 ospf6_route_remove(old
, table
);
977 ospf6_route_remove(old
, table
);
980 /* RFC 2328 16.2. Calculating the inter-area routes */
981 void ospf6_abr_examin_summary(struct ospf6_lsa
*lsa
, struct ospf6_area
*oa
)
983 struct prefix prefix
, abr_prefix
;
984 struct ospf6_route_table
*table
= NULL
;
985 struct ospf6_route
*range
, *route
, *old
= NULL
, *old_route
;
986 struct ospf6_route
*abr_entry
;
988 char options
[3] = {0, 0, 0};
989 uint8_t prefix_options
= 0;
991 uint8_t router_bits
= 0;
992 char buf
[PREFIX2STR_BUFFER
];
994 struct ospf6_inter_prefix_lsa
*prefix_lsa
= NULL
;
995 struct ospf6_inter_router_lsa
*router_lsa
= NULL
;
996 bool old_entry_updated
= false;
997 struct ospf6_path
*path
, *o_path
, *ecmp_path
;
998 struct listnode
*anode
;
999 bool add_route
= false;
1001 memset(&prefix
, 0, sizeof(prefix
));
1003 if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_PREFIX
)) {
1004 if (IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX
)) {
1006 zlog_debug("%s: LSA %s age %d in area %s", __func__
,
1007 lsa
->name
, ospf6_lsa_age_current(lsa
),
1012 (struct ospf6_inter_prefix_lsa
*)OSPF6_LSA_HEADER_END(
1014 prefix
.family
= AF_INET6
;
1015 prefix
.prefixlen
= prefix_lsa
->prefix
.prefix_length
;
1016 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, prefix_lsa
,
1017 &prefix_lsa
->prefix
);
1019 prefix2str(&prefix
, buf
, sizeof(buf
));
1020 table
= oa
->ospf6
->route_table
;
1021 type
= OSPF6_DEST_TYPE_NETWORK
;
1022 prefix_options
= prefix_lsa
->prefix
.prefix_options
;
1023 cost
= OSPF6_ABR_SUMMARY_METRIC(prefix_lsa
);
1024 } else if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_ROUTER
)) {
1025 if (IS_OSPF6_DEBUG_EXAMIN(INTER_ROUTER
)) {
1027 zlog_debug("%s: LSA %s age %d in area %s", __func__
,
1028 lsa
->name
, ospf6_lsa_age_current(lsa
),
1033 (struct ospf6_inter_router_lsa
*)OSPF6_LSA_HEADER_END(
1035 ospf6_linkstate_prefix(router_lsa
->router_id
, htonl(0),
1038 inet_ntop(AF_INET
, &router_lsa
->router_id
, buf
,
1041 table
= oa
->ospf6
->brouter_table
;
1042 type
= OSPF6_DEST_TYPE_ROUTER
;
1043 options
[0] = router_lsa
->options
[0];
1044 options
[1] = router_lsa
->options
[1];
1045 options
[2] = router_lsa
->options
[2];
1046 cost
= OSPF6_ABR_SUMMARY_METRIC(router_lsa
);
1047 SET_FLAG(router_bits
, OSPF6_ROUTER_BIT_E
);
1051 /* Find existing route */
1052 route
= ospf6_route_lookup(&prefix
, table
);
1054 ospf6_route_lock(route
);
1056 zlog_debug("%s: route %pFX, paths %d", __func__
,
1057 &prefix
, listcount(route
->paths
));
1059 while (route
&& ospf6_route_is_prefix(&prefix
, route
)) {
1060 if (route
->path
.area_id
== oa
->area_id
1061 && route
->path
.origin
.type
== lsa
->header
->type
1062 && !CHECK_FLAG(route
->flag
, OSPF6_ROUTE_WAS_REMOVED
)) {
1063 /* LSA adv. router could be part of route's
1064 * paths list. Find the existing path and set
1067 if (listcount(route
->paths
) > 1) {
1068 for (ALL_LIST_ELEMENTS_RO(route
->paths
, anode
,
1070 if (o_path
->origin
.id
== lsa
->header
->id
1071 && o_path
->origin
.adv_router
==
1072 lsa
->header
->adv_router
) {
1077 "%s: old entry found in paths, adv_router %pI4",
1079 &o_path
->origin
.adv_router
);
1084 } else if (route
->path
.origin
.id
== lsa
->header
->id
&&
1085 route
->path
.origin
.adv_router
==
1086 lsa
->header
->adv_router
)
1089 route
= ospf6_route_next(route
);
1092 ospf6_route_unlock(route
);
1094 /* (1) if cost == LSInfinity or if the LSA is MaxAge */
1095 if (cost
== OSPF_LS_INFINITY
) {
1097 zlog_debug("cost is LS_INFINITY, ignore");
1099 ospf6_abr_old_route_remove(lsa
, old
, table
);
1102 if (OSPF6_LSA_IS_MAXAGE(lsa
)) {
1104 zlog_debug("%s: LSA %s is MaxAge, ignore", __func__
,
1107 ospf6_abr_old_route_remove(lsa
, old
, table
);
1112 /* (2) if the LSA is self-originated, ignore */
1113 if (lsa
->header
->adv_router
== oa
->ospf6
->router_id
) {
1115 zlog_debug("LSA %s is self-originated, ignore",
1118 ospf6_route_remove(old
, table
);
1122 /* (3) if the prefix is equal to an active configured address range */
1123 /* or if the NU bit is set in the prefix */
1124 if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_PREFIX
)) {
1125 /* must have been set in previous block */
1128 range
= ospf6_route_lookup(&prefix
, oa
->range_table
);
1132 "Prefix is equal to address range, ignore");
1134 ospf6_route_remove(old
, table
);
1138 if (CHECK_FLAG(prefix_lsa
->prefix
.prefix_options
,
1139 OSPF6_PREFIX_OPTION_NU
)
1140 || CHECK_FLAG(prefix_lsa
->prefix
.prefix_options
,
1141 OSPF6_PREFIX_OPTION_LA
)) {
1143 zlog_debug("Prefix has NU/LA bit set, ignore");
1145 ospf6_route_remove(old
, table
);
1150 if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_ROUTER
)) {
1151 /* To pass test suites */
1153 if (!OSPF6_OPT_ISSET(router_lsa
->options
, OSPF6_OPT_R
)
1154 || !OSPF6_OPT_ISSET(router_lsa
->options
, OSPF6_OPT_V6
)) {
1156 zlog_debug("Prefix has NU/LA bit set, ignore");
1158 ospf6_route_remove(old
, table
);
1162 /* Avoid infinite recursion if someone has maliciously announced
1164 Inter-Router LSA for an ABR
1166 if (lsa
->header
->adv_router
== router_lsa
->router_id
) {
1169 "Ignoring Inter-Router LSA for an ABR (%s)",
1172 ospf6_route_remove(old
, table
);
1178 /* (4) if the routing table entry for the ABR does not exist */
1179 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &abr_prefix
);
1180 abr_entry
= ospf6_route_lookup(&abr_prefix
, oa
->ospf6
->brouter_table
);
1181 if (abr_entry
== NULL
|| abr_entry
->path
.area_id
!= oa
->area_id
1182 || CHECK_FLAG(abr_entry
->flag
, OSPF6_ROUTE_REMOVE
)
1183 || !CHECK_FLAG(abr_entry
->path
.router_bits
, OSPF6_ROUTER_BIT_B
)) {
1186 "%s: ABR router entry %pFX does not exist, ignore",
1187 __func__
, &abr_prefix
);
1189 if (old
->type
== OSPF6_DEST_TYPE_ROUTER
&&
1190 oa
->intra_brouter_calc
) {
1193 "%s: intra_brouter_calc is on, skip brouter remove: %s (%p)",
1194 __func__
, buf
, (void *)old
);
1198 "%s: remove old entry: %s %p ",
1199 __func__
, buf
, (void *)old
);
1200 ospf6_abr_old_route_remove(lsa
, old
, table
);
1206 /* (5),(6): the path preference is handled by the sorting
1207 in the routing table. Always install the path by substituting
1208 old route (if any). */
1209 route
= ospf6_route_create(oa
->ospf6
);
1212 route
->prefix
= prefix
;
1213 route
->prefix_options
= prefix_options
;
1214 route
->path
.origin
.type
= lsa
->header
->type
;
1215 route
->path
.origin
.id
= lsa
->header
->id
;
1216 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
1217 route
->path
.router_bits
= router_bits
;
1218 route
->path
.options
[0] = options
[0];
1219 route
->path
.options
[1] = options
[1];
1220 route
->path
.options
[2] = options
[2];
1221 route
->path
.area_id
= oa
->area_id
;
1222 route
->path
.type
= OSPF6_PATH_TYPE_INTER
;
1223 route
->path
.cost
= abr_entry
->path
.cost
+ cost
;
1225 /* copy brouter rechable nexthops into the route. */
1226 ospf6_route_copy_nexthops(route
, abr_entry
);
1228 /* (7) If the routes are identical, copy the next hops over to existing
1229 route. ospf6's route table implementation will otherwise string both
1230 routes, but keep the older one as the best route since the routes
1233 old
= ospf6_route_lookup(&prefix
, table
);
1236 zlog_debug("%s: found old route %pFX, paths %d",
1237 __func__
, &prefix
, listcount(old
->paths
));
1239 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
1241 /* The route linked-list is grouped in batches of prefix.
1242 * If the new prefix is not the same as the one of interest
1243 * then we have walked over the end of the batch and so we
1244 * should break rather than continuing unnecessarily.
1246 if (!ospf6_route_is_same(old_route
, route
))
1248 if ((old_route
->type
!= route
->type
)
1249 || (old_route
->path
.type
!= route
->path
.type
))
1252 if ((ospf6_route_cmp(route
, old_route
) != 0)) {
1255 "%s: old %p %pFX cost %u new route cost %u are not same",
1256 __func__
, (void *)old_route
, &prefix
,
1257 old_route
->path
.cost
, route
->path
.cost
);
1259 /* Check new route's adv. router is same in one of
1260 * the paths with differed cost, if so remove the
1261 * old path as later new route will be added.
1263 if (listcount(old_route
->paths
) > 1)
1264 ospf6_abr_old_path_update(old_route
, route
,
1269 list_delete_all_node(old_route
->nh_list
);
1270 ospf6_route_copy_nexthops(old_route
, route
);
1271 old_entry_updated
= true;
1273 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
1275 if (o_path
->area_id
== route
->path
.area_id
1276 && ospf6_ls_origin_same(o_path
, &route
->path
))
1280 /* New adv. router for a existing path add to paths list */
1281 if (o_path
== NULL
) {
1282 ecmp_path
= ospf6_path_dup(&route
->path
);
1284 /* Add a nh_list to new ecmp path */
1285 ospf6_copy_nexthops(ecmp_path
->nh_list
, route
->nh_list
);
1287 /* Add the new path to route's path list */
1288 listnode_add_sort(old_route
->paths
, ecmp_path
);
1292 "%s: route %pFX cost %u another path %pI4 added with nh %u, effective paths %u nh %u",
1293 __func__
, &route
->prefix
,
1294 old_route
->path
.cost
,
1295 &ecmp_path
->origin
.adv_router
,
1296 listcount(ecmp_path
->nh_list
),
1298 ? listcount(old_route
->paths
)
1300 listcount(old_route
->nh_list
));
1303 struct ospf6_route
*tmp_route
;
1305 tmp_route
= ospf6_route_create(oa
->ospf6
);
1307 ospf6_copy_nexthops(tmp_route
->nh_list
,
1310 if (!ospf6_route_cmp_nexthops(tmp_route
, route
)) {
1311 /* adv. router exists in the list, update nhs */
1312 list_delete_all_node(o_path
->nh_list
);
1313 ospf6_copy_nexthops(o_path
->nh_list
,
1315 ospf6_route_delete(tmp_route
);
1317 /* adv. router has no change in nhs */
1318 old_entry_updated
= false;
1319 ospf6_route_delete(tmp_route
);
1326 "%s: Update route: %s %p old cost %u new cost %u nh %u",
1327 __func__
, buf
, (void *)old_route
,
1328 old_route
->path
.cost
, route
->path
.cost
,
1329 listcount(old_route
->nh_list
));
1331 /* For Inter-Prefix route: Update RIB/FIB,
1332 * For Inter-Router trigger summary update
1334 if (table
->hook_add
)
1335 (*table
->hook_add
)(old_route
);
1340 /* If the old entry is not updated and old entry not found or old entry
1341 * does not match with the new entry then add the new route
1343 if (old_entry_updated
== false) {
1344 if ((old
== NULL
) || (old
->type
!= route
->type
)
1345 || (old
->path
.type
!= route
->path
.type
)
1346 || (old
->path
.cost
!= route
->path
.cost
))
1353 "%s: Install new route: %s cost %u nh %u adv_router %pI4",
1354 __func__
, buf
, route
->path
.cost
,
1355 listcount(route
->nh_list
),
1356 &route
->path
.origin
.adv_router
);
1359 path
= ospf6_path_dup(&route
->path
);
1360 ospf6_copy_nexthops(path
->nh_list
, abr_entry
->nh_list
);
1361 listnode_add_sort(route
->paths
, path
);
1362 /* ospf6_ia_add_nw_route (table, &prefix, route); */
1363 ospf6_route_add(route
, table
);
1365 /* if we did not add the route remove it */
1366 ospf6_route_delete(route
);
1369 void ospf6_abr_examin_brouter(uint32_t router_id
, struct ospf6_route
*route
,
1370 struct ospf6
*ospf6
)
1372 struct ospf6_lsa
*lsa
;
1373 struct ospf6_area
*oa
;
1376 oa
= ospf6_area_lookup(route
->path
.area_id
, ospf6
);
1378 * It is possible to designate a non backbone
1379 * area first. If that is the case safely
1380 * fall out of this function.
1385 type
= htons(OSPF6_LSTYPE_INTER_ROUTER
);
1386 for (ALL_LSDB_TYPED_ADVRTR(oa
->lsdb
, type
, router_id
, lsa
))
1387 ospf6_abr_examin_summary(lsa
, oa
);
1389 type
= htons(OSPF6_LSTYPE_INTER_PREFIX
);
1390 for (ALL_LSDB_TYPED_ADVRTR(oa
->lsdb
, type
, router_id
, lsa
))
1391 ospf6_abr_examin_summary(lsa
, oa
);
1394 void ospf6_abr_prefix_resummarize(struct ospf6
*o
)
1396 struct ospf6_route
*route
;
1398 if (IS_OSPF6_DEBUG_ABR
)
1399 zlog_debug("Re-examining Inter-Prefix Summaries");
1401 for (route
= ospf6_route_head(o
->route_table
); route
;
1402 route
= ospf6_route_next(route
))
1403 ospf6_abr_originate_summary(route
, o
);
1405 if (IS_OSPF6_DEBUG_ABR
)
1406 zlog_debug("Finished re-examining Inter-Prefix Summaries");
1410 /* Display functions */
1411 static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1412 char *buf
, int buflen
,
1415 struct ospf6_inter_prefix_lsa
*prefix_lsa
;
1416 struct in6_addr in6
;
1421 (struct ospf6_inter_prefix_lsa
*)OSPF6_LSA_HEADER_END(
1424 ospf6_prefix_in6_addr(&in6
, prefix_lsa
, &prefix_lsa
->prefix
);
1426 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
1427 snprintf(tbuf
, sizeof(tbuf
), "/%d",
1428 prefix_lsa
->prefix
.prefix_length
);
1429 strlcat(buf
, tbuf
, buflen
);
1436 static int ospf6_inter_area_prefix_lsa_show(struct vty
*vty
,
1437 struct ospf6_lsa
*lsa
,
1438 json_object
*json_obj
,
1441 struct ospf6_inter_prefix_lsa
*prefix_lsa
;
1442 char buf
[INET6_ADDRSTRLEN
];
1444 prefix_lsa
= (struct ospf6_inter_prefix_lsa
*)OSPF6_LSA_HEADER_END(
1448 json_object_int_add(
1450 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa
));
1451 ospf6_prefix_options_printbuf(prefix_lsa
->prefix
.prefix_options
,
1453 json_object_string_add(json_obj
, "prefixOptions", buf
);
1454 json_object_string_add(
1456 ospf6_inter_area_prefix_lsa_get_prefix_str(
1457 lsa
, buf
, sizeof(buf
), 0));
1459 vty_out(vty
, " Metric: %lu\n",
1460 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa
));
1462 ospf6_prefix_options_printbuf(prefix_lsa
->prefix
.prefix_options
,
1464 vty_out(vty
, " Prefix Options: %s\n", buf
);
1466 vty_out(vty
, " Prefix: %s\n",
1467 ospf6_inter_area_prefix_lsa_get_prefix_str(
1468 lsa
, buf
, sizeof(buf
), 0));
1474 static char *ospf6_inter_area_router_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1475 char *buf
, int buflen
,
1478 struct ospf6_inter_router_lsa
*router_lsa
;
1482 (struct ospf6_inter_router_lsa
*)OSPF6_LSA_HEADER_END(
1487 inet_ntop(AF_INET
, &router_lsa
->router_id
, buf
, buflen
);
1493 static int ospf6_inter_area_router_lsa_show(struct vty
*vty
,
1494 struct ospf6_lsa
*lsa
,
1495 json_object
*json_obj
,
1498 struct ospf6_inter_router_lsa
*router_lsa
;
1501 router_lsa
= (struct ospf6_inter_router_lsa
*)OSPF6_LSA_HEADER_END(
1504 ospf6_options_printbuf(router_lsa
->options
, buf
, sizeof(buf
));
1506 json_object_string_add(json_obj
, "options", buf
);
1507 json_object_int_add(
1509 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa
));
1511 vty_out(vty
, " Options: %s\n", buf
);
1512 vty_out(vty
, " Metric: %lu\n",
1513 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa
));
1516 inet_ntop(AF_INET
, &router_lsa
->router_id
, buf
, sizeof(buf
));
1518 json_object_string_add(json_obj
, "destinationRouterId", buf
);
1520 vty_out(vty
, " Destination Router ID: %s\n", buf
);
1525 /* Debug commands */
1526 DEFUN (debug_ospf6_abr
,
1527 debug_ospf6_abr_cmd
,
1531 "Debug OSPFv3 ABR function\n"
1534 OSPF6_DEBUG_ABR_ON();
1538 DEFUN (no_debug_ospf6_abr
,
1539 no_debug_ospf6_abr_cmd
,
1540 "no debug ospf6 abr",
1544 "Debug OSPFv3 ABR function\n"
1547 OSPF6_DEBUG_ABR_OFF();
1551 int config_write_ospf6_debug_abr(struct vty
*vty
)
1553 if (IS_OSPF6_DEBUG_ABR
)
1554 vty_out(vty
, "debug ospf6 abr\n");
1558 void install_element_ospf6_debug_abr(void)
1560 install_element(ENABLE_NODE
, &debug_ospf6_abr_cmd
);
1561 install_element(ENABLE_NODE
, &no_debug_ospf6_abr_cmd
);
1562 install_element(CONFIG_NODE
, &debug_ospf6_abr_cmd
);
1563 install_element(CONFIG_NODE
, &no_debug_ospf6_abr_cmd
);
1566 static struct ospf6_lsa_handler inter_prefix_handler
= {
1567 .lh_type
= OSPF6_LSTYPE_INTER_PREFIX
,
1568 .lh_name
= "Inter-Prefix",
1569 .lh_short_name
= "IAP",
1570 .lh_show
= ospf6_inter_area_prefix_lsa_show
,
1571 .lh_get_prefix_str
= ospf6_inter_area_prefix_lsa_get_prefix_str
,
1574 static struct ospf6_lsa_handler inter_router_handler
= {
1575 .lh_type
= OSPF6_LSTYPE_INTER_ROUTER
,
1576 .lh_name
= "Inter-Router",
1577 .lh_short_name
= "IAR",
1578 .lh_show
= ospf6_inter_area_router_lsa_show
,
1579 .lh_get_prefix_str
= ospf6_inter_area_router_lsa_get_prefix_str
,
1582 void ospf6_abr_init(void)
1584 ospf6_install_lsa_handler(&inter_prefix_handler
);
1585 ospf6_install_lsa_handler(&inter_router_handler
);