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"
53 unsigned char conf_debug_ospf6_abr
;
55 int ospf6_is_router_abr(struct ospf6
*o
)
57 struct listnode
*node
;
58 struct ospf6_area
*oa
;
61 for (ALL_LIST_ELEMENTS_RO(o
->area_list
, node
, oa
))
62 if (IS_AREA_ENABLED(oa
))
70 static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route
*route
,
71 struct ospf6_area
*area
)
73 struct ospf6_interface
*oi
;
75 oi
= ospf6_interface_lookup_by_ifindex(
76 ospf6_route_get_first_nh_index(route
), area
->ospf6
->vrf_id
);
77 if (oi
&& oi
->area
&& oi
->area
== area
)
83 static void ospf6_abr_delete_route(struct ospf6_route
*range
,
84 struct ospf6_route
*summary
,
85 struct ospf6_route_table
*summary_table
,
86 struct ospf6_lsa
*old
)
89 ospf6_route_remove(summary
, summary_table
);
92 if (old
&& !OSPF6_LSA_IS_MAXAGE(old
))
96 void ospf6_abr_enable_area(struct ospf6_area
*area
)
98 struct ospf6_area
*oa
;
99 struct listnode
*node
, *nnode
;
101 for (ALL_LIST_ELEMENTS(area
->ospf6
->area_list
, node
, nnode
, oa
))
102 /* update B bit for each area */
103 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
106 void ospf6_abr_disable_area(struct ospf6_area
*area
)
108 struct ospf6_area
*oa
;
109 struct ospf6_route
*ro
, *nro
;
110 struct ospf6_lsa
*old
;
111 struct listnode
*node
, *nnode
;
113 /* Withdraw all summary prefixes previously originated */
114 for (ro
= ospf6_route_head(area
->summary_prefix
); ro
; ro
= nro
) {
115 nro
= ospf6_route_next(ro
);
116 old
= ospf6_lsdb_lookup(ro
->path
.origin
.type
,
118 area
->ospf6
->router_id
, area
->lsdb
);
120 ospf6_lsa_purge(old
);
121 ospf6_route_remove(ro
, area
->summary_prefix
);
124 /* Withdraw all summary router-routes previously originated */
125 for (ro
= ospf6_route_head(area
->summary_router
); ro
; ro
= nro
) {
126 nro
= ospf6_route_next(ro
);
127 old
= ospf6_lsdb_lookup(ro
->path
.origin
.type
,
129 area
->ospf6
->router_id
, area
->lsdb
);
131 ospf6_lsa_purge(old
);
132 ospf6_route_remove(ro
, area
->summary_router
);
135 /* Schedule Router-LSA for each area (ABR status may change) */
136 for (ALL_LIST_ELEMENTS(area
->ospf6
->area_list
, node
, nnode
, oa
))
137 /* update B bit for each area */
138 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
141 /* RFC 2328 12.4.3. Summary-LSAs */
142 /* Returns 1 if a summary LSA has been generated for the area */
143 /* This is used by the area/range logic to add/remove blackhole routes */
144 int ospf6_abr_originate_summary_to_area(struct ospf6_route
*route
,
145 struct ospf6_area
*area
)
147 struct ospf6_lsa
*lsa
, *old
= NULL
;
148 struct ospf6_route
*summary
, *range
= NULL
;
149 struct ospf6_area
*route_area
;
150 char buffer
[OSPF6_MAX_LSASIZE
];
151 struct ospf6_lsa_header
*lsa_header
;
153 struct ospf6_inter_prefix_lsa
*prefix_lsa
;
154 struct ospf6_inter_router_lsa
*router_lsa
;
155 struct ospf6_route_table
*summary_table
= NULL
;
159 /* Only destination type network, range or ASBR are considered */
160 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
161 && route
->type
!= OSPF6_DEST_TYPE_RANGE
162 && ((route
->type
!= OSPF6_DEST_TYPE_ROUTER
)
163 || !CHECK_FLAG(route
->path
.router_bits
, OSPF6_ROUTER_BIT_E
))) {
167 /* AS External routes are never considered */
168 if (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
169 || route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL2
) {
173 /* do not generate if the path's area is the same as target area */
174 if (route
->path
.area_id
== area
->area_id
) {
178 /* do not generate if the nexthops belongs to the target area */
179 if (ospf6_abr_nexthops_belong_to_area(route
, area
)) {
183 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
184 if (ADV_ROUTER_IN_PREFIX(&route
->prefix
)
185 == area
->ospf6
->router_id
) {
187 "%s: Skipping ASBR announcement for ABR (%pI4)",
189 &ADV_ROUTER_IN_PREFIX(&route
->prefix
));
194 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
195 if (IS_OSPF6_DEBUG_ABR
196 || IS_OSPF6_DEBUG_ORIGINATE(INTER_ROUTER
)) {
199 "Originating summary in area %s for ASBR %pI4",
201 &ADV_ROUTER_IN_PREFIX(&route
->prefix
));
203 summary_table
= area
->summary_router
;
205 if (IS_OSPF6_DEBUG_ABR
206 || IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX
))
209 if (route
->type
== OSPF6_DEST_TYPE_NETWORK
&&
210 route
->path
.origin
.type
==
211 htons(OSPF6_LSTYPE_INTER_PREFIX
)) {
212 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_BEST
)) {
215 "%s: route %pFX with cost %u is not best, ignore.",
216 __func__
, &route
->prefix
,
222 if (route
->path
.origin
.type
==
223 htons(OSPF6_LSTYPE_INTRA_PREFIX
)) {
224 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_BEST
)) {
227 "%s: intra-prefix route %pFX with cost %u is not best, ignore.",
228 __func__
, &route
->prefix
,
236 "Originating summary in area %s for %pFX cost %u",
237 area
->name
, &route
->prefix
, route
->path
.cost
);
238 summary_table
= area
->summary_prefix
;
241 summary
= ospf6_route_lookup(&route
->prefix
, summary_table
);
243 old
= ospf6_lsdb_lookup(summary
->path
.origin
.type
,
244 summary
->path
.origin
.id
,
245 area
->ospf6
->router_id
, area
->lsdb
);
247 /* if this route has just removed, remove corresponding LSA */
248 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)) {
251 "The route has just removed, purge previous LSA");
253 if (route
->type
== OSPF6_DEST_TYPE_RANGE
) {
254 /* Whether the route have active longer prefix */
255 if (!CHECK_FLAG(route
->flag
,
256 OSPF6_ROUTE_ACTIVE_SUMMARY
)) {
259 "The range is not active. withdraw");
261 ospf6_abr_delete_route(route
, summary
,
265 ospf6_route_remove(summary
, summary_table
);
266 ospf6_lsa_purge(old
);
271 if ((route
->type
== OSPF6_DEST_TYPE_ROUTER
) && IS_AREA_STUB(area
)) {
274 "Area has been stubbed, purge Inter-Router LSA");
276 ospf6_abr_delete_route(route
, summary
, summary_table
, old
);
281 && (route
->path
.subtype
!= OSPF6_PATH_SUBTYPE_DEFAULT_RT
)) {
283 zlog_debug("Area has been stubbed, purge prefix LSA");
285 ospf6_abr_delete_route(route
, summary
, summary_table
, old
);
289 /* do not generate if the route cost is greater or equal to LSInfinity
291 if (route
->path
.cost
>= OSPF_LS_INFINITY
) {
292 /* When we're clearing the range route because all active
294 * under the range are gone, we set the range's cost to
295 * OSPF_AREA_RANGE_COST_UNSPEC, which is > OSPF_LS_INFINITY. We
296 * don't want to trigger the code here for that. This code is
298 * handling routes that have gone to infinity. The range removal
302 if ((route
->type
!= OSPF6_DEST_TYPE_RANGE
)
303 && (route
->path
.cost
!= OSPF_AREA_RANGE_COST_UNSPEC
)) {
306 "The cost exceeds LSInfinity, withdraw");
308 ospf6_lsa_purge(old
);
313 /* if this is a route to ASBR */
314 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
315 /* Only the preferred best path is considered */
316 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_BEST
)) {
319 "This is the secondary path to the ASBR, ignore");
320 ospf6_abr_delete_route(route
, summary
, summary_table
,
325 /* Do not generate if the area is stub */
329 /* if this is an intra-area route, this may be suppressed by aggregation
331 if (route
->type
== OSPF6_DEST_TYPE_NETWORK
332 && route
->path
.type
== OSPF6_PATH_TYPE_INTRA
) {
333 /* search for configured address range for the route's area */
335 ospf6_area_lookup(route
->path
.area_id
, area
->ospf6
);
337 range
= ospf6_route_lookup_bestmatch(&route
->prefix
,
338 route_area
->range_table
);
340 /* ranges are ignored when originate backbone routes to transit
342 Otherwise, if ranges are configured, the route is suppressed.
344 if (range
&& !CHECK_FLAG(range
->flag
, OSPF6_ROUTE_REMOVE
)
345 && (route
->path
.area_id
!= OSPF_AREA_BACKBONE
346 || !IS_AREA_TRANSIT(area
))) {
349 "Suppressed by range %pFX of area %s",
350 &range
->prefix
, route_area
->name
);
351 ospf6_abr_delete_route(route
, summary
, summary_table
,
357 /* If this is a configured address range */
358 if (route
->type
== OSPF6_DEST_TYPE_RANGE
) {
359 /* If DoNotAdvertise is set */
360 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_DO_NOT_ADVERTISE
)) {
363 "This is the range with DoNotAdvertise set. ignore");
364 ospf6_abr_delete_route(route
, summary
, summary_table
,
369 /* If there are no active prefixes in this range, remove */
370 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)) {
372 zlog_debug("The range is not active. withdraw");
373 ospf6_abr_delete_route(route
, summary
, summary_table
,
379 /* Check export list */
380 if (EXPORT_NAME(area
)) {
381 if (EXPORT_LIST(area
) == NULL
)
383 access_list_lookup(AFI_IP6
, EXPORT_NAME(area
));
385 if (EXPORT_LIST(area
))
386 if (access_list_apply(EXPORT_LIST(area
), &route
->prefix
)
390 "prefix %pFX was denied by export list",
396 /* Check filter-list */
397 if (PREFIX_LIST_OUT(area
))
398 if (prefix_list_apply(PREFIX_LIST_OUT(area
), &route
->prefix
)
402 "prefix %pFX was denied by filter-list out",
407 /* the route is going to be originated. store it in area's summary_table
409 if (summary
== NULL
) {
410 summary
= ospf6_route_copy(route
);
411 summary
->path
.origin
.adv_router
= area
->ospf6
->router_id
;
413 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
414 summary
->path
.origin
.type
=
415 htons(OSPF6_LSTYPE_INTER_ROUTER
);
416 summary
->path
.origin
.id
=
417 ADV_ROUTER_IN_PREFIX(&route
->prefix
);
419 summary
->path
.origin
.type
=
420 htons(OSPF6_LSTYPE_INTER_PREFIX
);
421 summary
->path
.origin
.id
= ospf6_new_ls_id(
422 summary
->path
.origin
.type
,
423 summary
->path
.origin
.adv_router
, area
->lsdb
);
425 summary
= ospf6_route_add(summary
, summary_table
);
427 summary
->type
= route
->type
;
428 monotime(&summary
->changed
);
431 summary
->path
.router_bits
= route
->path
.router_bits
;
432 summary
->path
.options
[0] = route
->path
.options
[0];
433 summary
->path
.options
[1] = route
->path
.options
[1];
434 summary
->path
.options
[2] = route
->path
.options
[2];
435 summary
->path
.prefix_options
= route
->path
.prefix_options
;
436 summary
->path
.area_id
= area
->area_id
;
437 summary
->path
.type
= OSPF6_PATH_TYPE_INTER
;
438 summary
->path
.subtype
= route
->path
.subtype
;
439 summary
->path
.cost
= route
->path
.cost
;
440 /* summary->nexthop[0] = route->nexthop[0]; */
443 memset(buffer
, 0, sizeof(buffer
));
444 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
446 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
447 router_lsa
= (struct ospf6_inter_router_lsa
448 *)((caddr_t
)lsa_header
449 + sizeof(struct ospf6_lsa_header
));
450 p
= (caddr_t
)router_lsa
+ sizeof(struct ospf6_inter_router_lsa
);
452 /* Fill Inter-Area-Router-LSA */
453 router_lsa
->options
[0] = route
->path
.options
[0];
454 router_lsa
->options
[1] = route
->path
.options
[1];
455 router_lsa
->options
[2] = route
->path
.options
[2];
456 OSPF6_ABR_SUMMARY_METRIC_SET(router_lsa
, route
->path
.cost
);
457 router_lsa
->router_id
= ADV_ROUTER_IN_PREFIX(&route
->prefix
);
458 type
= htons(OSPF6_LSTYPE_INTER_ROUTER
);
460 prefix_lsa
= (struct ospf6_inter_prefix_lsa
461 *)((caddr_t
)lsa_header
462 + sizeof(struct ospf6_lsa_header
));
463 p
= (caddr_t
)prefix_lsa
+ sizeof(struct ospf6_inter_prefix_lsa
);
465 /* Fill Inter-Area-Prefix-LSA */
466 OSPF6_ABR_SUMMARY_METRIC_SET(prefix_lsa
, route
->path
.cost
);
467 prefix_lsa
->prefix
.prefix_length
= route
->prefix
.prefixlen
;
468 prefix_lsa
->prefix
.prefix_options
= route
->path
.prefix_options
;
471 memcpy(p
, &route
->prefix
.u
.prefix6
,
472 OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
));
473 ospf6_prefix_apply_mask(&prefix_lsa
->prefix
);
474 p
+= OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
);
475 type
= htons(OSPF6_LSTYPE_INTER_PREFIX
);
478 /* Fill LSA Header */
480 lsa_header
->type
= type
;
481 lsa_header
->id
= summary
->path
.origin
.id
;
482 lsa_header
->adv_router
= area
->ospf6
->router_id
;
484 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
485 lsa_header
->adv_router
, area
->lsdb
);
486 lsa_header
->length
= htons((caddr_t
)p
- (caddr_t
)lsa_header
);
489 ospf6_lsa_checksum(lsa_header
);
492 lsa
= ospf6_lsa_create(lsa_header
);
495 ospf6_lsa_originate_area(lsa
, area
);
500 void ospf6_abr_range_reset_cost(struct ospf6
*ospf6
)
502 struct listnode
*node
, *nnode
;
503 struct ospf6_area
*oa
;
504 struct ospf6_route
*range
;
506 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
))
507 for (range
= ospf6_route_head(oa
->range_table
); range
;
508 range
= ospf6_route_next(range
))
509 OSPF6_ABR_RANGE_CLEAR_COST(range
);
512 static inline uint32_t ospf6_abr_range_compute_cost(struct ospf6_route
*range
,
515 struct ospf6_route
*ro
;
518 for (ro
= ospf6_route_match_head(&range
->prefix
, o
->route_table
); ro
;
519 ro
= ospf6_route_match_next(&range
->prefix
, ro
)) {
520 if (ro
->path
.area_id
== range
->path
.area_id
521 && (ro
->path
.type
== OSPF6_PATH_TYPE_INTRA
)
522 && !CHECK_FLAG(ro
->flag
, OSPF6_ROUTE_REMOVE
))
523 cost
= MAX(cost
, ro
->path
.cost
);
530 ospf6_abr_range_summary_needs_update(struct ospf6_route
*range
, uint32_t cost
)
532 int redo_summary
= 0;
534 if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_REMOVE
)) {
535 UNSET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
537 } else if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_DO_NOT_ADVERTISE
)) {
538 if (range
->path
.cost
!= 0) {
539 range
->path
.cost
= 0;
543 if ((OSPF6_PATH_COST_IS_CONFIGURED(range
->path
)
544 && range
->path
.cost
!= range
->path
.u
.cost_config
)) {
545 range
->path
.cost
= range
->path
.u
.cost_config
;
546 SET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
548 } else if (!OSPF6_PATH_COST_IS_CONFIGURED(range
->path
)
549 && range
->path
.cost
!= cost
) {
550 range
->path
.cost
= cost
;
551 SET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
554 } else if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)) {
555 /* Cost is zero, meaning no active range */
556 UNSET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
557 range
->path
.cost
= OSPF_AREA_RANGE_COST_UNSPEC
;
561 return (redo_summary
);
564 static void ospf6_abr_range_update(struct ospf6_route
*range
,
568 struct listnode
*node
, *nnode
;
569 struct ospf6_area
*oa
;
570 int summary_orig
= 0;
572 assert(range
->type
== OSPF6_DEST_TYPE_RANGE
);
574 /* update range's cost and active flag */
575 cost
= ospf6_abr_range_compute_cost(range
, ospf6
);
577 /* Non-zero cost is a proxy for active longer prefixes in this range.
578 * If there are active routes covered by this range AND either the
580 * cost has changed or the summarized cost has changed then redo
582 * Alternately, if there are no longer active prefixes and there are
583 * summary announcements, withdraw those announcements.
585 * The don't advertise code relies on the path.cost being set to UNSPEC
587 * work the first time. Subsequent times the path.cost is not 0 anyway
589 * were active ranges.
592 if (ospf6_abr_range_summary_needs_update(range
, cost
)) {
593 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
))
595 ospf6_abr_originate_summary_to_area(range
, oa
);
597 if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)
599 if (!CHECK_FLAG(range
->flag
,
600 OSPF6_ROUTE_BLACKHOLE_ADDED
)) {
601 if (IS_OSPF6_DEBUG_ABR
)
602 zlog_debug("Add discard route");
604 ospf6_zebra_add_discard(range
, ospf6
);
607 /* Summary removed or no summary generated as no
609 if (CHECK_FLAG(range
->flag
,
610 OSPF6_ROUTE_BLACKHOLE_ADDED
)) {
611 if (IS_OSPF6_DEBUG_ABR
)
612 zlog_debug("Delete discard route");
614 ospf6_zebra_delete_discard(range
, ospf6
);
620 void ospf6_abr_originate_summary(struct ospf6_route
*route
, struct ospf6
*ospf6
)
622 struct listnode
*node
, *nnode
;
623 struct ospf6_area
*oa
;
624 struct ospf6_route
*range
= NULL
;
627 if (route
->type
== OSPF6_DEST_TYPE_NETWORK
) {
628 oa
= ospf6_area_lookup(route
->path
.area_id
, ospf6
);
630 zlog_err("OSPFv6 area lookup failed");
634 range
= ospf6_route_lookup_bestmatch(&route
->prefix
,
637 ospf6_abr_range_update(range
, ospf6
);
641 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
))
642 ospf6_abr_originate_summary_to_area(route
, oa
);
645 void ospf6_abr_defaults_to_stub(struct ospf6
*o
)
647 struct listnode
*node
, *nnode
;
648 struct ospf6_area
*oa
;
649 struct ospf6_route
*def
, *route
;
650 struct ospf6_redist
*red
;
651 int type
= DEFAULT_ROUTE
;
652 struct prefix_ipv6 p
= {};
657 red
= ospf6_redist_lookup(o
, type
, 0);
664 route
= ospf6_route_lookup((struct prefix
*)&p
, o
->external_table
);
668 def
= ospf6_route_create();
669 def
->type
= OSPF6_DEST_TYPE_NETWORK
;
670 def
->prefix
.family
= AF_INET6
;
671 def
->prefix
.prefixlen
= 0;
672 memset(&def
->prefix
.u
.prefix6
, 0, sizeof(struct in6_addr
));
673 def
->type
= OSPF6_DEST_TYPE_NETWORK
;
674 def
->path
.type
= OSPF6_PATH_TYPE_INTER
;
675 def
->path
.subtype
= OSPF6_PATH_SUBTYPE_DEFAULT_RT
;
676 def
->path
.area_id
= o
->backbone
->area_id
;
677 def
->path
.metric_type
= metric_type(o
, type
, 0);
678 def
->path
.cost
= metric_value(o
, type
, 0);
680 for (ALL_LIST_ELEMENTS(o
->area_list
, node
, nnode
, oa
)) {
681 if (!IS_AREA_STUB(oa
)) {
682 /* withdraw defaults when an area switches from stub to
684 route
= ospf6_route_lookup(&def
->prefix
,
687 && (route
->path
.subtype
== def
->path
.subtype
)) {
688 if (IS_OSPF6_DEBUG_ABR
)
690 "Withdrawing default route from non-stubby area %s",
692 SET_FLAG(def
->flag
, OSPF6_ROUTE_REMOVE
);
693 ospf6_abr_originate_summary_to_area(def
, oa
);
696 /* announce defaults to stubby areas */
697 if (IS_OSPF6_DEBUG_ABR
)
699 "Announcing default route into stubby area %s",
701 UNSET_FLAG(def
->flag
, OSPF6_ROUTE_REMOVE
);
702 ospf6_abr_originate_summary_to_area(def
, oa
);
705 ospf6_route_delete(def
);
708 void ospf6_abr_old_path_update(struct ospf6_route
*old_route
,
709 struct ospf6_route
*route
,
710 struct ospf6_route_table
*table
)
712 struct ospf6_path
*o_path
= NULL
;
713 struct listnode
*anode
, *anext
;
714 struct listnode
*nnode
, *rnode
, *rnext
;
715 struct ospf6_nexthop
*nh
, *rnh
;
717 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
, anext
, o_path
)) {
718 if (o_path
->area_id
!= route
->path
.area_id
||
719 (memcmp(&(o_path
)->origin
, &(route
)->path
.origin
,
720 sizeof(struct ospf6_ls_origin
)) != 0))
723 if ((o_path
->cost
== route
->path
.cost
) &&
724 (o_path
->u
.cost_e2
== route
->path
.u
.cost_e2
))
727 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
728 for (ALL_LIST_ELEMENTS(old_route
->nh_list
, rnode
,
730 if (!ospf6_nexthop_is_same(rnh
, nh
))
732 listnode_delete(old_route
->nh_list
, rnh
);
733 ospf6_nexthop_delete(rnh
);
738 listnode_delete(old_route
->paths
, o_path
);
739 ospf6_path_free(o_path
);
741 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
,
743 ospf6_merge_nexthops(old_route
->nh_list
,
747 if (IS_OSPF6_DEBUG_ABR
|| IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX
))
748 zlog_debug("%s: paths %u nh %u", __func__
,
750 ? listcount(old_route
->paths
)
753 ? listcount(old_route
->nh_list
)
757 (*table
->hook_add
)(old_route
);
759 if (old_route
->path
.origin
.id
== route
->path
.origin
.id
&&
760 old_route
->path
.origin
.adv_router
==
761 route
->path
.origin
.adv_router
) {
762 struct ospf6_path
*h_path
;
764 h_path
= (struct ospf6_path
*)
765 listgetdata(listhead(old_route
->paths
));
766 old_route
->path
.origin
.type
= h_path
->origin
.type
;
767 old_route
->path
.origin
.id
= h_path
->origin
.id
;
768 old_route
->path
.origin
.adv_router
=
769 h_path
->origin
.adv_router
;
774 void ospf6_abr_old_route_remove(struct ospf6_lsa
*lsa
, struct ospf6_route
*old
,
775 struct ospf6_route_table
*table
)
777 if (IS_OSPF6_DEBUG_ABR
)
778 zlog_debug("%s: route %pFX, paths %d", __func__
, &old
->prefix
,
779 listcount(old
->paths
));
781 if (listcount(old
->paths
) > 1) {
782 struct listnode
*anode
, *anext
, *nnode
, *rnode
, *rnext
;
783 struct ospf6_path
*o_path
;
784 struct ospf6_nexthop
*nh
, *rnh
;
785 bool nh_updated
= false;
787 for (ALL_LIST_ELEMENTS(old
->paths
, anode
, anext
, o_path
)) {
788 if (o_path
->origin
.adv_router
!= lsa
->header
->adv_router
789 || o_path
->origin
.id
!= lsa
->header
->id
)
791 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
792 for (ALL_LIST_ELEMENTS(old
->nh_list
,
793 rnode
, rnext
, rnh
)) {
794 if (!ospf6_nexthop_is_same(rnh
, nh
))
796 if (IS_OSPF6_DEBUG_ABR
)
797 zlog_debug("deleted nexthop");
798 listnode_delete(old
->nh_list
, rnh
);
799 ospf6_nexthop_delete(rnh
);
802 listnode_delete(old
->paths
, o_path
);
803 ospf6_path_free(o_path
);
808 if (listcount(old
->paths
)) {
809 if (IS_OSPF6_DEBUG_ABR
810 || IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX
))
811 zlog_debug("%s: old %pFX updated nh %u",
812 __func__
, &old
->prefix
,
813 old
->nh_list
? listcount(
818 (*table
->hook_add
)(old
);
820 if ((old
->path
.origin
.id
== lsa
->header
->id
) &&
821 (old
->path
.origin
.adv_router
822 == lsa
->header
->adv_router
)) {
823 struct ospf6_path
*h_path
;
825 h_path
= (struct ospf6_path
*)
827 listhead(old
->paths
));
828 old
->path
.origin
.type
=
830 old
->path
.origin
.id
= h_path
->origin
.id
;
831 old
->path
.origin
.adv_router
=
832 h_path
->origin
.adv_router
;
835 ospf6_route_remove(old
, table
);
838 ospf6_route_remove(old
, table
);
841 /* RFC 2328 16.2. Calculating the inter-area routes */
842 void ospf6_abr_examin_summary(struct ospf6_lsa
*lsa
, struct ospf6_area
*oa
)
844 struct prefix prefix
, abr_prefix
;
845 struct ospf6_route_table
*table
= NULL
;
846 struct ospf6_route
*range
, *route
, *old
= NULL
, *old_route
;
847 struct ospf6_route
*abr_entry
;
849 char options
[3] = {0, 0, 0};
850 uint8_t prefix_options
= 0;
852 uint8_t router_bits
= 0;
853 char buf
[PREFIX2STR_BUFFER
];
855 struct ospf6_inter_prefix_lsa
*prefix_lsa
= NULL
;
856 struct ospf6_inter_router_lsa
*router_lsa
= NULL
;
857 bool old_entry_updated
= false;
858 struct ospf6_path
*path
, *o_path
, *ecmp_path
;
859 struct listnode
*anode
;
860 bool add_route
= false;
862 memset(&prefix
, 0, sizeof(prefix
));
864 if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_PREFIX
)) {
865 if (IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX
)) {
867 zlog_debug("%s: LSA %s age %d in area %s", __func__
,
868 lsa
->name
, ospf6_lsa_age_current(lsa
),
873 (struct ospf6_inter_prefix_lsa
*)OSPF6_LSA_HEADER_END(
875 prefix
.family
= AF_INET6
;
876 prefix
.prefixlen
= prefix_lsa
->prefix
.prefix_length
;
877 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, prefix_lsa
,
878 &prefix_lsa
->prefix
);
880 prefix2str(&prefix
, buf
, sizeof(buf
));
881 table
= oa
->ospf6
->route_table
;
882 type
= OSPF6_DEST_TYPE_NETWORK
;
883 prefix_options
= prefix_lsa
->prefix
.prefix_options
;
884 cost
= OSPF6_ABR_SUMMARY_METRIC(prefix_lsa
);
885 } else if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_ROUTER
)) {
886 if (IS_OSPF6_DEBUG_EXAMIN(INTER_ROUTER
)) {
888 zlog_debug("%s: LSA %s age %d in area %s", __func__
,
889 lsa
->name
, ospf6_lsa_age_current(lsa
),
894 (struct ospf6_inter_router_lsa
*)OSPF6_LSA_HEADER_END(
896 ospf6_linkstate_prefix(router_lsa
->router_id
, htonl(0),
899 inet_ntop(AF_INET
, &router_lsa
->router_id
, buf
,
902 table
= oa
->ospf6
->brouter_table
;
903 type
= OSPF6_DEST_TYPE_ROUTER
;
904 options
[0] = router_lsa
->options
[0];
905 options
[1] = router_lsa
->options
[1];
906 options
[2] = router_lsa
->options
[2];
907 cost
= OSPF6_ABR_SUMMARY_METRIC(router_lsa
);
908 SET_FLAG(router_bits
, OSPF6_ROUTER_BIT_E
);
912 /* Find existing route */
913 route
= ospf6_route_lookup(&prefix
, table
);
915 ospf6_route_lock(route
);
917 zlog_debug("%s: route %pFX, paths %d", __func__
,
918 &prefix
, listcount(route
->paths
));
920 while (route
&& ospf6_route_is_prefix(&prefix
, route
)) {
921 if (route
->path
.area_id
== oa
->area_id
922 && route
->path
.origin
.type
== lsa
->header
->type
923 && !CHECK_FLAG(route
->flag
, OSPF6_ROUTE_WAS_REMOVED
)) {
924 /* LSA adv. router could be part of route's
925 * paths list. Find the existing path and set
928 if (listcount(route
->paths
) > 1) {
929 for (ALL_LIST_ELEMENTS_RO(route
->paths
, anode
,
931 if (o_path
->origin
.id
== lsa
->header
->id
932 && o_path
->origin
.adv_router
==
933 lsa
->header
->adv_router
) {
938 "%s: old entry found in paths, adv_router %pI4",
940 &o_path
->origin
.adv_router
);
945 } else if (route
->path
.origin
.id
== lsa
->header
->id
&&
946 route
->path
.origin
.adv_router
==
947 lsa
->header
->adv_router
)
950 route
= ospf6_route_next(route
);
953 ospf6_route_unlock(route
);
955 /* (1) if cost == LSInfinity or if the LSA is MaxAge */
956 if (cost
== OSPF_LS_INFINITY
) {
958 zlog_debug("cost is LS_INFINITY, ignore");
960 ospf6_abr_old_route_remove(lsa
, old
, table
);
963 if (OSPF6_LSA_IS_MAXAGE(lsa
)) {
965 zlog_debug("%s: LSA %s is MaxAge, ignore", __func__
,
968 ospf6_abr_old_route_remove(lsa
, old
, table
);
973 /* (2) if the LSA is self-originated, ignore */
974 if (lsa
->header
->adv_router
== oa
->ospf6
->router_id
) {
976 zlog_debug("LSA %s is self-originated, ignore",
979 ospf6_route_remove(old
, table
);
983 /* (3) if the prefix is equal to an active configured address range */
984 /* or if the NU bit is set in the prefix */
985 if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_PREFIX
)) {
986 /* must have been set in previous block */
989 range
= ospf6_route_lookup(&prefix
, oa
->range_table
);
993 "Prefix is equal to address range, ignore");
995 ospf6_route_remove(old
, table
);
999 if (CHECK_FLAG(prefix_lsa
->prefix
.prefix_options
,
1000 OSPF6_PREFIX_OPTION_NU
)
1001 || CHECK_FLAG(prefix_lsa
->prefix
.prefix_options
,
1002 OSPF6_PREFIX_OPTION_LA
)) {
1004 zlog_debug("Prefix has NU/LA bit set, ignore");
1006 ospf6_route_remove(old
, table
);
1011 if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_ROUTER
)) {
1012 /* To pass test suites */
1014 if (!OSPF6_OPT_ISSET(router_lsa
->options
, OSPF6_OPT_R
)
1015 || !OSPF6_OPT_ISSET(router_lsa
->options
, OSPF6_OPT_V6
)) {
1017 zlog_debug("Prefix has NU/LA bit set, ignore");
1019 ospf6_route_remove(old
, table
);
1023 /* Avoid infinite recursion if someone has maliciously announced
1025 Inter-Router LSA for an ABR
1027 if (lsa
->header
->adv_router
== router_lsa
->router_id
) {
1030 "Ignorning Inter-Router LSA for an ABR (%s)",
1033 ospf6_route_remove(old
, table
);
1039 /* (4) if the routing table entry for the ABR does not exist */
1040 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &abr_prefix
);
1041 abr_entry
= ospf6_route_lookup(&abr_prefix
, oa
->ospf6
->brouter_table
);
1042 if (abr_entry
== NULL
|| abr_entry
->path
.area_id
!= oa
->area_id
1043 || CHECK_FLAG(abr_entry
->flag
, OSPF6_ROUTE_REMOVE
)
1044 || !CHECK_FLAG(abr_entry
->path
.router_bits
, OSPF6_ROUTER_BIT_B
)) {
1047 "%s: ABR router entry %pFX does not exist, ignore",
1048 __func__
, &abr_prefix
);
1050 if (old
->type
== OSPF6_DEST_TYPE_ROUTER
&&
1051 oa
->intra_brouter_calc
) {
1054 "%s: intra_brouter_calc is on, skip brouter remove: %s (%p)",
1055 __func__
, buf
, (void *)old
);
1059 "%s: remove old entry: %s %p ",
1060 __func__
, buf
, (void *)old
);
1061 ospf6_abr_old_route_remove(lsa
, old
, table
);
1067 /* Check import list */
1068 if (IMPORT_NAME(oa
)) {
1069 if (IMPORT_LIST(oa
) == NULL
)
1071 access_list_lookup(AFI_IP6
, IMPORT_NAME(oa
));
1073 if (IMPORT_LIST(oa
))
1074 if (access_list_apply(IMPORT_LIST(oa
), &prefix
)
1078 "Prefix was denied by import-list");
1080 ospf6_route_remove(old
, table
);
1085 /* Check input prefix-list */
1086 if (PREFIX_LIST_IN(oa
)) {
1087 if (prefix_list_apply(PREFIX_LIST_IN(oa
), &prefix
)
1090 zlog_debug("Prefix was denied by prefix-list");
1092 ospf6_route_remove(old
, table
);
1097 /* (5),(6): the path preference is handled by the sorting
1098 in the routing table. Always install the path by substituting
1099 old route (if any). */
1100 route
= ospf6_route_create();
1103 route
->prefix
= prefix
;
1104 route
->path
.origin
.type
= lsa
->header
->type
;
1105 route
->path
.origin
.id
= lsa
->header
->id
;
1106 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
1107 route
->path
.router_bits
= router_bits
;
1108 route
->path
.options
[0] = options
[0];
1109 route
->path
.options
[1] = options
[1];
1110 route
->path
.options
[2] = options
[2];
1111 route
->path
.prefix_options
= prefix_options
;
1112 route
->path
.area_id
= oa
->area_id
;
1113 route
->path
.type
= OSPF6_PATH_TYPE_INTER
;
1114 route
->path
.cost
= abr_entry
->path
.cost
+ cost
;
1116 /* copy brouter rechable nexthops into the route. */
1117 ospf6_route_copy_nexthops(route
, abr_entry
);
1119 /* (7) If the routes are identical, copy the next hops over to existing
1120 route. ospf6's route table implementation will otherwise string both
1121 routes, but keep the older one as the best route since the routes
1124 old
= ospf6_route_lookup(&prefix
, table
);
1127 zlog_debug("%s: found old route %pFX, paths %d",
1128 __func__
, &prefix
, listcount(old
->paths
));
1130 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
1131 if (!ospf6_route_is_same(old_route
, route
) ||
1132 (old_route
->type
!= route
->type
) ||
1133 (old_route
->path
.type
!= route
->path
.type
))
1136 if ((ospf6_route_cmp(route
, old_route
) != 0)) {
1139 "%s: old %p %pFX cost %u new route cost %u are not same",
1140 __func__
, (void *)old_route
, &prefix
,
1141 old_route
->path
.cost
, route
->path
.cost
);
1143 /* Check new route's adv. router is same in one of
1144 * the paths with differed cost, if so remove the
1145 * old path as later new route will be added.
1147 if (listcount(old_route
->paths
) > 1)
1148 ospf6_abr_old_path_update(old_route
, route
,
1153 ospf6_route_merge_nexthops(old_route
, route
);
1154 old_entry_updated
= true;
1156 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
1158 if (o_path
->area_id
== route
->path
.area_id
&&
1159 (memcmp(&(o_path
)->origin
, &(route
)->path
.origin
,
1160 sizeof(struct ospf6_ls_origin
)) == 0))
1164 /* New adv. router for a existing path add to paths list */
1165 if (o_path
== NULL
) {
1166 ecmp_path
= ospf6_path_dup(&route
->path
);
1168 /* Add a nh_list to new ecmp path */
1169 ospf6_copy_nexthops(ecmp_path
->nh_list
, route
->nh_list
);
1171 /* Add the new path to route's path list */
1172 listnode_add_sort(old_route
->paths
, ecmp_path
);
1176 "%s: route %pFX cost %u another path %pI4 added with nh %u, effective paths %u nh %u",
1177 __func__
, &route
->prefix
,
1178 old_route
->path
.cost
,
1179 &ecmp_path
->origin
.adv_router
,
1180 listcount(ecmp_path
->nh_list
),
1182 ? listcount(old_route
->paths
)
1184 listcount(old_route
->nh_list
));
1187 struct ospf6_route
*tmp_route
= ospf6_route_create();
1189 ospf6_copy_nexthops(tmp_route
->nh_list
,
1192 if (ospf6_route_cmp_nexthops(tmp_route
, route
) != 0) {
1193 /* adv. router exists in the list, update nhs */
1194 list_delete_all_node(o_path
->nh_list
);
1195 ospf6_copy_nexthops(o_path
->nh_list
,
1197 ospf6_route_delete(tmp_route
);
1199 /* adv. router has no change in nhs */
1200 old_entry_updated
= false;
1201 ospf6_route_delete(tmp_route
);
1208 "%s: Update route: %s %p old cost %u new cost %u nh %u",
1209 __func__
, buf
, (void *)old_route
,
1210 old_route
->path
.cost
, route
->path
.cost
,
1211 listcount(old_route
->nh_list
));
1213 /* For Inter-Prefix route: Update RIB/FIB,
1214 * For Inter-Router trigger summary update
1216 if (table
->hook_add
)
1217 (*table
->hook_add
)(old_route
);
1219 /* Delete new route */
1220 ospf6_route_delete(route
);
1224 /* If the old entry is not updated and old entry not found or old entry
1225 * does not match with the new entry then add the new route
1227 if (old_entry_updated
== false) {
1228 if ((old
== NULL
) || (old
->type
!= route
->type
)
1229 || (old
->path
.type
!= route
->path
.type
)
1230 || (old
->path
.cost
!= route
->path
.cost
))
1237 "%s: Install new route: %s cost %u nh %u adv_router %pI4",
1238 __func__
, buf
, route
->path
.cost
,
1239 listcount(route
->nh_list
),
1240 &route
->path
.origin
.adv_router
);
1243 path
= ospf6_path_dup(&route
->path
);
1244 ospf6_copy_nexthops(path
->nh_list
, abr_entry
->nh_list
);
1245 listnode_add_sort(route
->paths
, path
);
1246 /* ospf6_ia_add_nw_route (table, &prefix, route); */
1247 ospf6_route_add(route
, table
);
1251 void ospf6_abr_examin_brouter(uint32_t router_id
, struct ospf6_route
*route
,
1252 struct ospf6
*ospf6
)
1254 struct ospf6_lsa
*lsa
;
1255 struct ospf6_area
*oa
;
1258 oa
= ospf6_area_lookup(route
->path
.area_id
, ospf6
);
1260 * It is possible to designate a non backbone
1261 * area first. If that is the case safely
1262 * fall out of this function.
1267 type
= htons(OSPF6_LSTYPE_INTER_ROUTER
);
1268 for (ALL_LSDB_TYPED_ADVRTR(oa
->lsdb
, type
, router_id
, lsa
))
1269 ospf6_abr_examin_summary(lsa
, oa
);
1271 type
= htons(OSPF6_LSTYPE_INTER_PREFIX
);
1272 for (ALL_LSDB_TYPED_ADVRTR(oa
->lsdb
, type
, router_id
, lsa
))
1273 ospf6_abr_examin_summary(lsa
, oa
);
1276 void ospf6_abr_reimport(struct ospf6_area
*oa
)
1278 struct ospf6_lsa
*lsa
;
1281 type
= htons(OSPF6_LSTYPE_INTER_ROUTER
);
1282 for (ALL_LSDB_TYPED(oa
->lsdb
, type
, lsa
))
1283 ospf6_abr_examin_summary(lsa
, oa
);
1285 type
= htons(OSPF6_LSTYPE_INTER_PREFIX
);
1286 for (ALL_LSDB_TYPED(oa
->lsdb
, type
, lsa
))
1287 ospf6_abr_examin_summary(lsa
, oa
);
1290 void ospf6_abr_prefix_resummarize(struct ospf6
*o
)
1292 struct ospf6_route
*route
;
1294 if (IS_OSPF6_DEBUG_ABR
)
1295 zlog_debug("Re-examining Inter-Prefix Summaries");
1297 for (route
= ospf6_route_head(o
->route_table
); route
;
1298 route
= ospf6_route_next(route
))
1299 ospf6_abr_originate_summary(route
, o
);
1301 if (IS_OSPF6_DEBUG_ABR
)
1302 zlog_debug("Finished re-examining Inter-Prefix Summaries");
1306 /* Display functions */
1307 static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1308 char *buf
, int buflen
,
1311 struct ospf6_inter_prefix_lsa
*prefix_lsa
;
1312 struct in6_addr in6
;
1317 (struct ospf6_inter_prefix_lsa
*)OSPF6_LSA_HEADER_END(
1320 ospf6_prefix_in6_addr(&in6
, prefix_lsa
, &prefix_lsa
->prefix
);
1322 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
1323 snprintf(tbuf
, sizeof(tbuf
), "/%d",
1324 prefix_lsa
->prefix
.prefix_length
);
1325 strlcat(buf
, tbuf
, buflen
);
1332 static int ospf6_inter_area_prefix_lsa_show(struct vty
*vty
,
1333 struct ospf6_lsa
*lsa
,
1334 json_object
*json_obj
,
1337 struct ospf6_inter_prefix_lsa
*prefix_lsa
;
1338 char buf
[INET6_ADDRSTRLEN
];
1340 prefix_lsa
= (struct ospf6_inter_prefix_lsa
*)OSPF6_LSA_HEADER_END(
1344 json_object_int_add(
1346 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa
));
1347 ospf6_prefix_options_printbuf(prefix_lsa
->prefix
.prefix_options
,
1349 json_object_string_add(json_obj
, "prefixOptions", buf
);
1350 json_object_string_add(
1352 ospf6_inter_area_prefix_lsa_get_prefix_str(
1353 lsa
, buf
, sizeof(buf
), 0));
1355 vty_out(vty
, " Metric: %lu\n",
1356 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa
));
1358 ospf6_prefix_options_printbuf(prefix_lsa
->prefix
.prefix_options
,
1360 vty_out(vty
, " Prefix Options: %s\n", buf
);
1362 vty_out(vty
, " Prefix: %s\n",
1363 ospf6_inter_area_prefix_lsa_get_prefix_str(
1364 lsa
, buf
, sizeof(buf
), 0));
1370 static char *ospf6_inter_area_router_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1371 char *buf
, int buflen
,
1374 struct ospf6_inter_router_lsa
*router_lsa
;
1378 (struct ospf6_inter_router_lsa
*)OSPF6_LSA_HEADER_END(
1383 inet_ntop(AF_INET
, &router_lsa
->router_id
, buf
, buflen
);
1389 static int ospf6_inter_area_router_lsa_show(struct vty
*vty
,
1390 struct ospf6_lsa
*lsa
,
1391 json_object
*json_obj
,
1394 struct ospf6_inter_router_lsa
*router_lsa
;
1397 router_lsa
= (struct ospf6_inter_router_lsa
*)OSPF6_LSA_HEADER_END(
1400 ospf6_options_printbuf(router_lsa
->options
, buf
, sizeof(buf
));
1402 json_object_string_add(json_obj
, "options", buf
);
1403 json_object_int_add(
1405 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa
));
1407 vty_out(vty
, " Options: %s\n", buf
);
1408 vty_out(vty
, " Metric: %lu\n",
1409 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa
));
1412 inet_ntop(AF_INET
, &router_lsa
->router_id
, buf
, sizeof(buf
));
1414 json_object_string_add(json_obj
, "destinationRouterId", buf
);
1416 vty_out(vty
, " Destination Router ID: %s\n", buf
);
1421 /* Debug commands */
1422 DEFUN (debug_ospf6_abr
,
1423 debug_ospf6_abr_cmd
,
1427 "Debug OSPFv3 ABR function\n"
1430 OSPF6_DEBUG_ABR_ON();
1434 DEFUN (no_debug_ospf6_abr
,
1435 no_debug_ospf6_abr_cmd
,
1436 "no debug ospf6 abr",
1440 "Debug OSPFv3 ABR function\n"
1443 OSPF6_DEBUG_ABR_OFF();
1447 int config_write_ospf6_debug_abr(struct vty
*vty
)
1449 if (IS_OSPF6_DEBUG_ABR
)
1450 vty_out(vty
, "debug ospf6 abr\n");
1454 void install_element_ospf6_debug_abr(void)
1456 install_element(ENABLE_NODE
, &debug_ospf6_abr_cmd
);
1457 install_element(ENABLE_NODE
, &no_debug_ospf6_abr_cmd
);
1458 install_element(CONFIG_NODE
, &debug_ospf6_abr_cmd
);
1459 install_element(CONFIG_NODE
, &no_debug_ospf6_abr_cmd
);
1462 static struct ospf6_lsa_handler inter_prefix_handler
= {
1463 .lh_type
= OSPF6_LSTYPE_INTER_PREFIX
,
1464 .lh_name
= "Inter-Prefix",
1465 .lh_short_name
= "IAP",
1466 .lh_show
= ospf6_inter_area_prefix_lsa_show
,
1467 .lh_get_prefix_str
= ospf6_inter_area_prefix_lsa_get_prefix_str
,
1470 static struct ospf6_lsa_handler inter_router_handler
= {
1471 .lh_type
= OSPF6_LSTYPE_INTER_ROUTER
,
1472 .lh_name
= "Inter-Router",
1473 .lh_short_name
= "IAR",
1474 .lh_show
= ospf6_inter_area_router_lsa_show
,
1475 .lh_get_prefix_str
= ospf6_inter_area_router_lsa_get_prefix_str
,
1478 void ospf6_abr_init(void)
1480 ospf6_install_lsa_handler(&inter_prefix_handler
);
1481 ospf6_install_lsa_handler(&inter_router_handler
);