2 * Copyright (C) 2003 Yasuhiro Ohara
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include "ospf6_proto.h"
35 #include "ospf6_lsa.h"
36 #include "ospf6_lsdb.h"
37 #include "ospf6_route.h"
38 #include "ospf6_zebra.h"
39 #include "ospf6_message.h"
41 #include "ospf6_top.h"
42 #include "ospf6_area.h"
43 #include "ospf6_interface.h"
44 #include "ospf6_neighbor.h"
45 #include "ospf6_asbr.h"
46 #include "ospf6_abr.h"
47 #include "ospf6_intra.h"
48 #include "ospf6_flood.h"
52 static void ospf6_asbr_redistribute_set(int type
, vrf_id_t vrf_id
);
53 static void ospf6_asbr_redistribute_unset(struct ospf6
*ospf6
,
54 struct ospf6_redist
*red
, int type
);
56 unsigned char conf_debug_ospf6_asbr
= 0;
58 #define ZROUTE_NAME(x) zebra_route_string(x)
60 /* AS External LSA origination */
61 static void ospf6_as_external_lsa_originate(struct ospf6_route
*route
,
64 char buffer
[OSPF6_MAX_LSASIZE
];
65 struct ospf6_lsa_header
*lsa_header
;
66 struct ospf6_lsa
*lsa
;
67 struct ospf6_external_info
*info
= route
->route_option
;
69 struct ospf6_as_external_lsa
*as_external_lsa
;
72 if (IS_OSPF6_DEBUG_ASBR
|| IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL
))
73 zlog_debug("Originate AS-External-LSA for %pFX",
77 memset(buffer
, 0, sizeof(buffer
));
78 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
79 as_external_lsa
= (struct ospf6_as_external_lsa
80 *)((caddr_t
)lsa_header
81 + sizeof(struct ospf6_lsa_header
));
82 p
= (caddr_t
)((caddr_t
)as_external_lsa
83 + sizeof(struct ospf6_as_external_lsa
));
85 /* Fill AS-External-LSA */
87 if (route
->path
.metric_type
== 2)
88 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
90 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
92 /* forwarding address */
93 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
94 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
96 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
98 /* external route tag */
100 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
102 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
105 OSPF6_ASBR_METRIC_SET(as_external_lsa
, route
->path
.cost
);
108 as_external_lsa
->prefix
.prefix_length
= route
->prefix
.prefixlen
;
111 as_external_lsa
->prefix
.prefix_options
= route
->path
.prefix_options
;
113 /* don't use refer LS-type */
114 as_external_lsa
->prefix
.prefix_refer_lstype
= htons(0);
117 memcpy(p
, &route
->prefix
.u
.prefix6
,
118 OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
));
119 ospf6_prefix_apply_mask(&as_external_lsa
->prefix
);
120 p
+= OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
);
122 /* Forwarding address */
123 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
124 memcpy(p
, &info
->forwarding
, sizeof(struct in6_addr
));
125 p
+= sizeof(struct in6_addr
);
128 /* External Route Tag */
129 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
130 route_tag_t network_order
= htonl(info
->tag
);
132 memcpy(p
, &network_order
, sizeof(network_order
));
133 p
+= sizeof(network_order
);
136 /* Fill LSA Header */
138 lsa_header
->type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
139 lsa_header
->id
= route
->path
.origin
.id
;
140 lsa_header
->adv_router
= ospf6
->router_id
;
142 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
143 lsa_header
->adv_router
, ospf6
->lsdb
);
144 lsa_header
->length
= htons((caddr_t
)p
- (caddr_t
)lsa_header
);
147 ospf6_lsa_checksum(lsa_header
);
150 lsa
= ospf6_lsa_create(lsa_header
);
153 ospf6_lsa_originate_process(lsa
, ospf6
);
156 int ospf6_orig_as_external_lsa(struct thread
*thread
)
158 struct ospf6_interface
*oi
;
159 struct ospf6_lsa
*lsa
;
160 uint32_t type
, adv_router
;
162 oi
= (struct ospf6_interface
*)THREAD_ARG(thread
);
163 oi
->thread_as_extern_lsa
= NULL
;
165 if (oi
->state
== OSPF6_INTERFACE_DOWN
)
168 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
169 adv_router
= oi
->area
->ospf6
->router_id
;
170 for (ALL_LSDB_TYPED_ADVRTR(oi
->area
->ospf6
->lsdb
, type
, adv_router
,
172 if (IS_OSPF6_DEBUG_ASBR
)
174 "%s: Send update of AS-External LSA %s seq 0x%x",
176 ntohl(lsa
->header
->seqnum
));
178 ospf6_flood_interface(NULL
, lsa
, oi
);
184 static route_tag_t
ospf6_as_external_lsa_get_tag(struct ospf6_lsa
*lsa
)
186 struct ospf6_as_external_lsa
*external
;
187 ptrdiff_t tag_offset
;
188 route_tag_t network_order
;
193 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
196 if (!CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
199 tag_offset
= sizeof(*external
)
200 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
201 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
202 tag_offset
+= sizeof(struct in6_addr
);
204 memcpy(&network_order
, (caddr_t
)external
+ tag_offset
,
205 sizeof(network_order
));
206 return ntohl(network_order
);
209 void ospf6_asbr_update_route_ecmp_path(struct ospf6_route
*old
,
210 struct ospf6_route
*route
,
213 struct ospf6_route
*old_route
, *next_route
;
214 struct ospf6_path
*ecmp_path
, *o_path
= NULL
;
215 struct listnode
*anode
, *anext
;
216 struct listnode
*nnode
, *rnode
, *rnext
;
217 struct ospf6_nexthop
*nh
, *rnh
;
218 bool route_found
= false;
220 /* check for old entry match with new route origin,
223 for (old_route
= old
; old_route
; old_route
= next_route
) {
224 bool route_updated
= false;
226 next_route
= old_route
->next
;
228 if (!ospf6_route_is_same(old_route
, route
)
229 || (old_route
->path
.type
!= route
->path
.type
))
232 /* Current and New route has same origin,
235 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
, anext
,
237 /* Check old route path and route has same
240 if (o_path
->area_id
!= route
->path
.area_id
241 || (memcmp(&(o_path
)->origin
, &(route
)->path
.origin
,
242 sizeof(struct ospf6_ls_origin
))
246 /* Cost is not same then delete current path */
247 if ((o_path
->cost
== route
->path
.cost
)
248 && (o_path
->u
.cost_e2
== route
->path
.u
.cost_e2
))
251 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
253 "%s: route %pFX cost old %u new %u is not same, replace route",
254 __func__
, &old_route
->prefix
, o_path
->cost
,
258 /* Remove selected current rout path's nh from
261 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
262 for (ALL_LIST_ELEMENTS(old_route
->nh_list
,
263 rnode
, rnext
, rnh
)) {
264 if (!ospf6_nexthop_is_same(rnh
, nh
))
266 listnode_delete(old_route
->nh_list
,
268 ospf6_nexthop_delete(rnh
);
272 listnode_delete(old_route
->paths
, o_path
);
273 ospf6_path_free(o_path
);
274 route_updated
= true;
276 /* Current route's path (adv_router info) is similar
277 * to route being added.
278 * Replace current route's path with paths list head.
279 * Update FIB with effective NHs.
281 if (listcount(old_route
->paths
)) {
282 for (ALL_LIST_ELEMENTS(old_route
->paths
,
283 anode
, anext
, o_path
)) {
284 ospf6_merge_nexthops(
288 /* Update RIB/FIB with effective
291 if (ospf6
->route_table
->hook_add
)
292 (*ospf6
->route_table
->hook_add
)(
295 if (old_route
->path
.origin
.id
296 == route
->path
.origin
.id
297 && old_route
->path
.origin
.adv_router
298 == route
->path
.origin
300 struct ospf6_path
*h_path
;
302 h_path
= (struct ospf6_path
*)
303 listgetdata(listhead(
305 old_route
->path
.origin
.type
=
307 old_route
->path
.origin
.id
=
309 old_route
->path
.origin
.adv_router
=
310 h_path
->origin
.adv_router
;
313 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
315 "%s: route %pFX old cost %u new cost %u, delete old entry.",
316 __func__
, &old_route
->prefix
,
317 old_route
->path
.cost
,
320 if (old
== old_route
)
322 ospf6_route_remove(old_route
,
331 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
333 /* Current and New Route prefix or route type
334 * is not same skip this current node.
336 if (!ospf6_route_is_same(old_route
, route
)
337 || (old_route
->path
.type
!= route
->path
.type
))
340 /* Old Route and New Route have Equal Cost, Merge NHs */
341 if ((old_route
->path
.cost
== route
->path
.cost
)
342 && (old_route
->path
.u
.cost_e2
== route
->path
.u
.cost_e2
)) {
344 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
346 "%s: old route %pFX path cost %u e2 %u",
347 __func__
, &old_route
->prefix
,
348 old_route
->path
.cost
,
349 old_route
->path
.u
.cost_e2
);
352 /* check if this path exists already in
353 * route->paths list, if so, replace nh_list
356 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
358 if (o_path
->area_id
== route
->path
.area_id
359 && (memcmp(&(o_path
)->origin
,
360 &(route
)->path
.origin
,
361 sizeof(struct ospf6_ls_origin
))
365 /* If path is not found in old_route paths's list,
366 * add a new path to route paths list and merge
367 * nexthops in route->path->nh_list.
368 * Otherwise replace existing path's nh_list.
370 if (o_path
== NULL
) {
371 ecmp_path
= ospf6_path_dup(&route
->path
);
373 /* Add a nh_list to new ecmp path */
374 ospf6_copy_nexthops(ecmp_path
->nh_list
,
377 /* Add the new path to route's path list */
378 listnode_add_sort(old_route
->paths
, ecmp_path
);
380 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
382 "%s: route %pFX another path added with nh %u, effective paths %u nh %u",
383 __func__
, &route
->prefix
,
384 listcount(ecmp_path
->nh_list
),
385 old_route
->paths
? listcount(
388 listcount(old_route
->nh_list
));
391 list_delete_all_node(o_path
->nh_list
);
392 ospf6_copy_nexthops(o_path
->nh_list
,
396 /* Reset nexthop lists, rebuild from brouter table
397 * for each adv. router.
399 list_delete_all_node(old_route
->nh_list
);
401 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
403 struct ospf6_route
*asbr_entry
;
405 asbr_entry
= ospf6_route_lookup(
407 ospf6
->brouter_table
);
408 if (asbr_entry
== NULL
) {
409 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
411 "%s: ls_prfix %pFX asbr_entry not found.",
416 ospf6_route_merge_nexthops(old_route
,
420 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
422 "%s: route %pFX with effective paths %u nh %u",
423 __func__
, &route
->prefix
,
425 ? listcount(old_route
->paths
)
428 ? listcount(old_route
->nh_list
)
432 if (ospf6
->route_table
->hook_add
)
433 (*ospf6
->route_table
->hook_add
)(old_route
);
435 /* Delete the new route its info added to existing
438 ospf6_route_delete(route
);
445 /* Add new route to existing node in ospf6 route table. */
446 ospf6_route_add(route
, ospf6
->route_table
);
450 void ospf6_asbr_lsa_add(struct ospf6_lsa
*lsa
)
452 struct ospf6_as_external_lsa
*external
;
453 struct prefix asbr_id
;
454 struct ospf6_route
*asbr_entry
, *route
, *old
;
455 struct ospf6_path
*path
;
458 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
461 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
462 zlog_debug("Calculate AS-External route for %s", lsa
->name
);
464 ospf6
= ospf6_get_by_lsdb(lsa
);
466 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
467 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
468 zlog_debug("Ignore self-originated AS-External-LSA");
472 if (OSPF6_ASBR_METRIC(external
) == OSPF_LS_INFINITY
) {
473 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
474 zlog_debug("Ignore LSA with LSInfinity Metric");
478 if (CHECK_FLAG(external
->prefix
.prefix_options
,
479 OSPF6_PREFIX_OPTION_NU
)) {
480 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
481 zlog_debug("Ignore LSA with NU bit set Metric");
485 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &asbr_id
);
486 asbr_entry
= ospf6_route_lookup(&asbr_id
, ospf6
->brouter_table
);
487 if (asbr_entry
== NULL
488 || !CHECK_FLAG(asbr_entry
->path
.router_bits
, OSPF6_ROUTER_BIT_E
)) {
489 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
490 zlog_debug("ASBR entry not found: %pFX", &asbr_id
);
494 route
= ospf6_route_create();
495 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
496 route
->prefix
.family
= AF_INET6
;
497 route
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
498 ospf6_prefix_in6_addr(&route
->prefix
.u
.prefix6
, external
,
501 route
->path
.area_id
= asbr_entry
->path
.area_id
;
502 route
->path
.origin
.type
= lsa
->header
->type
;
503 route
->path
.origin
.id
= lsa
->header
->id
;
504 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
505 route
->path
.prefix_options
= external
->prefix
.prefix_options
;
506 memcpy(&route
->path
.ls_prefix
, &asbr_id
, sizeof(struct prefix
));
508 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
509 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
510 route
->path
.metric_type
= 2;
511 route
->path
.cost
= asbr_entry
->path
.cost
;
512 route
->path
.u
.cost_e2
= OSPF6_ASBR_METRIC(external
);
514 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
515 route
->path
.metric_type
= 1;
517 asbr_entry
->path
.cost
+ OSPF6_ASBR_METRIC(external
);
518 route
->path
.u
.cost_e2
= 0;
521 route
->path
.tag
= ospf6_as_external_lsa_get_tag(lsa
);
523 ospf6_route_copy_nexthops(route
, asbr_entry
);
525 path
= ospf6_path_dup(&route
->path
);
526 ospf6_copy_nexthops(path
->nh_list
, asbr_entry
->nh_list
);
527 listnode_add_sort(route
->paths
, path
);
530 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
532 "%s: AS-External %u route add %pFX cost %u(%u) nh %u",
534 (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
) ? 1 : 2,
535 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
536 listcount(route
->nh_list
));
538 old
= ospf6_route_lookup(&route
->prefix
, ospf6
->route_table
);
540 /* Add the new route to ospf6 instance route table. */
541 ospf6_route_add(route
, ospf6
->route_table
);
544 * ECMP: Keep new equal preference path in current
545 * route's path list, update zebra with new effective
546 * list along with addition of ECMP path.
548 ospf6_asbr_update_route_ecmp_path(old
, route
, ospf6
);
552 void ospf6_asbr_lsa_remove(struct ospf6_lsa
*lsa
,
553 struct ospf6_route
*asbr_entry
)
555 struct ospf6_as_external_lsa
*external
;
556 struct prefix prefix
;
557 struct ospf6_route
*route
, *nroute
, *route_to_del
;
558 struct ospf6_area
*oa
= NULL
;
561 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
564 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
565 zlog_debug("Withdraw AS-External route for %s", lsa
->name
);
567 ospf6
= ospf6_get_by_lsdb(lsa
);
568 if (ospf6_is_router_abr(ospf6
))
569 oa
= ospf6
->backbone
;
571 oa
= listgetdata(listhead(ospf6
->area_list
));
576 if (lsa
->header
->adv_router
== oa
->ospf6
->router_id
) {
577 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
578 zlog_debug("Ignore self-originated AS-External-LSA");
582 route_to_del
= ospf6_route_create();
583 route_to_del
->type
= OSPF6_DEST_TYPE_NETWORK
;
584 route_to_del
->prefix
.family
= AF_INET6
;
585 route_to_del
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
586 ospf6_prefix_in6_addr(&route_to_del
->prefix
.u
.prefix6
, external
,
589 route_to_del
->path
.origin
.type
= lsa
->header
->type
;
590 route_to_del
->path
.origin
.id
= lsa
->header
->id
;
591 route_to_del
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
594 route_to_del
->path
.area_id
= asbr_entry
->path
.area_id
;
595 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
596 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
597 route_to_del
->path
.metric_type
= 2;
598 route_to_del
->path
.cost
= asbr_entry
->path
.cost
;
599 route_to_del
->path
.u
.cost_e2
=
600 OSPF6_ASBR_METRIC(external
);
602 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
603 route_to_del
->path
.metric_type
= 1;
604 route_to_del
->path
.cost
= asbr_entry
->path
.cost
605 + OSPF6_ASBR_METRIC(external
);
606 route_to_del
->path
.u
.cost_e2
= 0;
610 memset(&prefix
, 0, sizeof(struct prefix
));
611 prefix
.family
= AF_INET6
;
612 prefix
.prefixlen
= external
->prefix
.prefix_length
;
613 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, external
, &external
->prefix
);
615 route
= ospf6_route_lookup(&prefix
, oa
->ospf6
->route_table
);
617 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
618 zlog_debug("AS-External route %pFX not found", &prefix
);
621 ospf6_route_delete(route_to_del
);
625 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
627 "%s: Current route %pFX cost %u e2 %u, route to del cost %u e2 %u",
628 __func__
, &prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
629 route_to_del
->path
.cost
, route_to_del
->path
.u
.cost_e2
);
632 for (ospf6_route_lock(route
);
633 route
&& ospf6_route_is_prefix(&prefix
, route
); route
= nroute
) {
634 nroute
= ospf6_route_next(route
);
636 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
)
639 /* Route has multiple ECMP paths, remove matching
640 * path. Update current route's effective nh list
641 * after removal of one of the path.
643 if (listcount(route
->paths
) > 1) {
644 struct listnode
*anode
, *anext
;
645 struct listnode
*nnode
, *rnode
, *rnext
;
646 struct ospf6_nexthop
*nh
, *rnh
;
647 struct ospf6_path
*o_path
;
648 bool nh_updated
= false;
650 /* Iterate all paths of route to find maching with LSA
651 * remove from route path list. If route->path is same,
652 * replace from paths list.
654 for (ALL_LIST_ELEMENTS(route
->paths
, anode
, anext
,
656 if ((o_path
->origin
.type
!= lsa
->header
->type
)
657 || (o_path
->origin
.adv_router
658 != lsa
->header
->adv_router
)
659 || (o_path
->origin
.id
!= lsa
->header
->id
))
662 /* Compare LSA cost with current
666 && (o_path
->cost
!= route_to_del
->path
.cost
668 != route_to_del
->path
.u
670 if (IS_OSPF6_DEBUG_EXAMIN(
673 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
682 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
684 "%s: route %pFX path found with cost %u nh %u to remove.",
685 __func__
, &prefix
, route
->path
.cost
,
686 listcount(o_path
->nh_list
));
689 /* Remove found path's nh_list from
690 * the route's nh_list.
692 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
,
694 for (ALL_LIST_ELEMENTS(route
->nh_list
,
697 if (!ospf6_nexthop_is_same(rnh
,
700 listnode_delete(route
->nh_list
,
702 ospf6_nexthop_delete(rnh
);
705 /* Delete the path from route's path list */
706 listnode_delete(route
->paths
, o_path
);
707 ospf6_path_free(o_path
);
712 /* Iterate all paths and merge nexthop,
713 * unlesss any of the nexthop similar to
714 * ones deleted as part of path deletion.
717 for (ALL_LIST_ELEMENTS(route
->paths
, anode
,
719 ospf6_merge_nexthops(route
->nh_list
,
723 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
725 "%s: AS-External %u route %pFX update paths %u nh %u",
728 == OSPF6_PATH_TYPE_EXTERNAL1
)
731 &route
->prefix
, listcount(route
->paths
),
732 route
->nh_list
? listcount(
737 if (listcount(route
->paths
)) {
738 /* Update RIB/FIB with effective
741 if (oa
->ospf6
->route_table
->hook_add
)
742 (*oa
->ospf6
->route_table
745 /* route's primary path is similar
746 * to LSA, replace route's primary
747 * path with route's paths list head.
749 if ((route
->path
.origin
.id
==
751 (route
->path
.origin
.adv_router
752 == lsa
->header
->adv_router
)) {
753 struct ospf6_path
*h_path
;
755 h_path
= (struct ospf6_path
*)
757 listhead(route
->paths
));
758 route
->path
.origin
.type
=
760 route
->path
.origin
.id
=
762 route
->path
.origin
.adv_router
=
763 h_path
->origin
.adv_router
;
767 route
, oa
->ospf6
->route_table
);
773 /* Compare LSA origin and cost with current route info.
774 * if any check fails skip del this route node.
777 && (!ospf6_route_is_same_origin(route
, route_to_del
)
778 || (route
->path
.type
!= route_to_del
->path
.type
)
779 || (route
->path
.cost
!= route_to_del
->path
.cost
)
780 || (route
->path
.u
.cost_e2
781 != route_to_del
->path
.u
.cost_e2
))) {
782 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
784 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
785 __func__
, &prefix
, route
->path
.cost
,
786 route_to_del
->path
.cost
);
791 if ((route
->path
.origin
.type
!= lsa
->header
->type
)
792 || (route
->path
.origin
.adv_router
793 != lsa
->header
->adv_router
)
794 || (route
->path
.origin
.id
!= lsa
->header
->id
))
797 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
799 "%s: AS-External %u route remove %pFX cost %u(%u) nh %u",
801 route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
804 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
805 listcount(route
->nh_list
));
807 ospf6_route_remove(route
, oa
->ospf6
->route_table
);
810 ospf6_route_unlock(route
);
812 ospf6_route_delete(route_to_del
);
815 void ospf6_asbr_lsentry_add(struct ospf6_route
*asbr_entry
, struct ospf6
*ospf6
)
817 struct ospf6_lsa
*lsa
;
821 if (!CHECK_FLAG(asbr_entry
->flag
, OSPF6_ROUTE_BEST
)) {
823 inet_ntop(AF_INET
, &ADV_ROUTER_IN_PREFIX(&asbr_entry
->prefix
),
825 zlog_info("ignore non-best path: lsentry %s add", buf
);
829 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
830 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
831 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
)) {
832 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
833 ospf6_asbr_lsa_add(lsa
);
837 void ospf6_asbr_lsentry_remove(struct ospf6_route
*asbr_entry
,
840 struct ospf6_lsa
*lsa
;
844 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
845 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
846 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
))
847 ospf6_asbr_lsa_remove(lsa
, asbr_entry
);
851 /* redistribute function */
852 static void ospf6_asbr_routemap_set(struct ospf6_redist
*red
,
855 if (ROUTEMAP_NAME(red
)) {
856 route_map_counter_decrement(ROUTEMAP(red
));
857 free(ROUTEMAP_NAME(red
));
860 ROUTEMAP_NAME(red
) = strdup(mapname
);
861 ROUTEMAP(red
) = route_map_lookup_by_name(mapname
);
862 route_map_counter_increment(ROUTEMAP(red
));
865 static void ospf6_asbr_routemap_unset(struct ospf6_redist
*red
)
867 if (ROUTEMAP_NAME(red
))
868 free(ROUTEMAP_NAME(red
));
870 route_map_counter_decrement(ROUTEMAP(red
));
872 ROUTEMAP_NAME(red
) = NULL
;
873 ROUTEMAP(red
) = NULL
;
876 static int ospf6_asbr_routemap_update_timer(struct thread
*thread
)
881 struct ospf6_redist
*red
;
883 arg
= THREAD_ARG(thread
);
884 ospf6
= (struct ospf6
*)arg
[0];
885 arg_type
= (int)(intptr_t)arg
[1];
887 ospf6
->t_distribute_update
= NULL
;
889 red
= ospf6_redist_lookup(ospf6
, arg_type
, 0);
891 if (red
&& ROUTEMAP_NAME(red
))
892 ROUTEMAP(red
) = route_map_lookup_by_name(ROUTEMAP_NAME(red
));
893 if (red
&& ROUTEMAP(red
)) {
894 if (IS_OSPF6_DEBUG_ASBR
)
895 zlog_debug("%s: route-map %s update, reset redist %s",
896 __func__
, ROUTEMAP_NAME(red
),
897 ZROUTE_NAME(arg_type
));
899 ospf6_zebra_no_redistribute(arg_type
, ospf6
->vrf_id
);
900 ospf6_zebra_redistribute(arg_type
, ospf6
->vrf_id
);
903 XFREE(MTYPE_OSPF6_DIST_ARGS
, arg
);
907 void ospf6_asbr_distribute_list_update(int type
, struct ospf6
*ospf6
)
911 if (ospf6
->t_distribute_update
)
914 args
= XCALLOC(MTYPE_OSPF6_DIST_ARGS
, sizeof(void *) * 2);
917 args
[1] = (void *)((ptrdiff_t)type
);
919 if (IS_OSPF6_DEBUG_ASBR
)
920 zlog_debug("%s: trigger redistribute %s reset thread", __func__
,
923 ospf6
->t_distribute_update
= NULL
;
924 thread_add_timer_msec(master
, ospf6_asbr_routemap_update_timer
, args
,
925 OSPF_MIN_LS_INTERVAL
,
926 &ospf6
->t_distribute_update
);
929 static void ospf6_asbr_routemap_update(const char *mapname
)
932 struct listnode
*node
, *nnode
;
933 struct ospf6
*ospf6
= NULL
;
934 struct ospf6_redist
*red
;
939 for (ALL_LIST_ELEMENTS(om6
->ospf6
, node
, nnode
, ospf6
)) {
940 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
941 red
= ospf6_redist_lookup(ospf6
, type
, 0);
942 if (!red
|| (ROUTEMAP_NAME(red
) == NULL
))
945 route_map_lookup_by_name(ROUTEMAP_NAME(red
));
948 || strcmp(ROUTEMAP_NAME(red
), mapname
))
951 if (IS_OSPF6_DEBUG_ASBR
)
953 "%s: route-map %s update, reset redist %s",
959 route_map_counter_increment(ROUTEMAP(red
));
961 ospf6_asbr_distribute_list_update(type
, ospf6
);
964 * if the mapname matches a
965 * route-map on ospf6 but the
966 * map doesn't exist, it is
967 * being deleted. flush and then
970 if (IS_OSPF6_DEBUG_ASBR
)
972 "%s: route-map %s deleted, reset redist %s",
977 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
978 ospf6_asbr_routemap_set(red
, mapname
);
979 ospf6_asbr_redistribute_set(
980 type
, ospf6
->vrf_id
);
986 static void ospf6_asbr_routemap_event(const char *name
)
989 struct listnode
*node
, *nnode
;
991 struct ospf6_redist
*red
;
995 for (ALL_LIST_ELEMENTS(om6
->ospf6
, node
, nnode
, ospf6
)) {
996 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
997 red
= ospf6_redist_lookup(ospf6
, type
, 0);
998 if (red
&& ROUTEMAP_NAME(red
)
999 && (strcmp(ROUTEMAP_NAME(red
), name
) == 0))
1000 ospf6_asbr_distribute_list_update(type
, ospf6
);
1005 int ospf6_asbr_is_asbr(struct ospf6
*o
)
1007 return o
->external_table
->count
;
1010 struct ospf6_redist
*ospf6_redist_lookup(struct ospf6
*ospf6
, int type
,
1011 unsigned short instance
)
1013 struct list
*red_list
;
1014 struct listnode
*node
;
1015 struct ospf6_redist
*red
;
1017 red_list
= ospf6
->redist
[type
];
1021 for (ALL_LIST_ELEMENTS_RO(red_list
, node
, red
))
1022 if (red
->instance
== instance
)
1028 static struct ospf6_redist
*ospf6_redist_add(struct ospf6
*ospf6
, int type
,
1031 struct ospf6_redist
*red
;
1033 red
= ospf6_redist_lookup(ospf6
, type
, instance
);
1037 if (!ospf6
->redist
[type
])
1038 ospf6
->redist
[type
] = list_new();
1040 red
= XCALLOC(MTYPE_OSPF6_REDISTRIBUTE
, sizeof(struct ospf6_redist
));
1041 red
->instance
= instance
;
1042 ROUTEMAP_NAME(red
) = NULL
;
1043 ROUTEMAP(red
) = NULL
;
1045 listnode_add(ospf6
->redist
[type
], red
);
1050 static void ospf6_redist_del(struct ospf6
*ospf6
, struct ospf6_redist
*red
,
1054 listnode_delete(ospf6
->redist
[type
], red
);
1055 if (!ospf6
->redist
[type
]->count
) {
1056 list_delete(&ospf6
->redist
[type
]);
1058 XFREE(MTYPE_OSPF6_REDISTRIBUTE
, red
);
1062 static void ospf6_asbr_redistribute_set(int type
, vrf_id_t vrf_id
)
1064 ospf6_zebra_redistribute(type
, vrf_id
);
1067 static void ospf6_asbr_redistribute_unset(struct ospf6
*ospf6
,
1068 struct ospf6_redist
*red
, int type
)
1070 struct ospf6_route
*route
;
1071 struct ospf6_external_info
*info
;
1073 ospf6_zebra_no_redistribute(type
, ospf6
->vrf_id
);
1075 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1076 route
= ospf6_route_next(route
)) {
1077 info
= route
->route_option
;
1078 if (info
->type
!= type
)
1081 ospf6_asbr_redistribute_remove(info
->type
, 0, &route
->prefix
,
1085 ospf6_asbr_routemap_unset(red
);
1088 /* When an area is unstubified, flood all the external LSAs in the area */
1089 void ospf6_asbr_send_externals_to_area(struct ospf6_area
*oa
)
1091 struct ospf6_lsa
*lsa
, *lsanext
;
1093 for (ALL_LSDB(oa
->ospf6
->lsdb
, lsa
, lsanext
)) {
1094 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
) {
1095 zlog_debug("%s: Flooding AS-External LSA %s",
1096 __func__
, lsa
->name
);
1097 ospf6_flood_area(NULL
, lsa
, oa
);
1102 /* When an area is stubified, remove all the external LSAs in the area */
1103 void ospf6_asbr_remove_externals_from_area(struct ospf6_area
*oa
)
1105 struct ospf6_lsa
*lsa
, *lsanext
;
1106 struct listnode
*node
, *nnode
;
1107 struct ospf6_area
*area
;
1108 struct ospf6
*ospf6
= oa
->ospf6
;
1109 const struct route_node
*iterend
;
1111 /* skip if router is in other non-stub areas */
1112 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, area
))
1113 if (!IS_AREA_STUB(area
))
1116 /* if router is only in a stub area then purge AS-External LSAs */
1117 iterend
= ospf6_lsdb_head(ospf6
->lsdb
, 0, 0, 0, &lsa
);
1118 while (lsa
!= NULL
) {
1119 lsanext
= ospf6_lsdb_next(iterend
, lsa
);
1120 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
)
1121 ospf6_lsdb_remove(lsa
, ospf6
->lsdb
);
1126 void ospf6_asbr_redistribute_add(int type
, ifindex_t ifindex
,
1127 struct prefix
*prefix
,
1128 unsigned int nexthop_num
,
1129 struct in6_addr
*nexthop
, route_tag_t tag
,
1130 struct ospf6
*ospf6
)
1132 route_map_result_t ret
;
1133 struct ospf6_route troute
;
1134 struct ospf6_external_info tinfo
;
1135 struct ospf6_route
*route
, *match
;
1136 struct ospf6_external_info
*info
;
1137 struct prefix prefix_id
;
1138 struct route_node
*node
;
1140 struct listnode
*lnode
, *lnnode
;
1141 struct ospf6_area
*oa
;
1142 struct ospf6_redist
*red
;
1144 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1149 if (!ospf6_zebra_is_redistribute(type
, ospf6
->vrf_id
))
1152 memset(&troute
, 0, sizeof(troute
));
1153 memset(&tinfo
, 0, sizeof(tinfo
));
1155 if (IS_OSPF6_DEBUG_ASBR
)
1156 zlog_debug("Redistribute %pFX (%s)", prefix
, ZROUTE_NAME(type
));
1158 /* if route-map was specified but not found, do not advertise */
1159 if (ROUTEMAP_NAME(red
)) {
1160 if (ROUTEMAP(red
) == NULL
)
1161 ospf6_asbr_routemap_update(NULL
);
1162 if (ROUTEMAP(red
) == NULL
) {
1164 "route-map \"%s\" not found, suppress redistributing",
1165 ROUTEMAP_NAME(red
));
1170 /* apply route-map */
1171 if (ROUTEMAP(red
)) {
1172 troute
.route_option
= &tinfo
;
1173 tinfo
.ifindex
= ifindex
;
1176 ret
= route_map_apply(ROUTEMAP(red
), prefix
, &troute
);
1177 if (ret
== RMAP_DENYMATCH
) {
1178 if (IS_OSPF6_DEBUG_ASBR
)
1179 zlog_debug("Denied by route-map \"%s\"",
1180 ROUTEMAP_NAME(red
));
1181 ospf6_asbr_redistribute_remove(type
, ifindex
, prefix
,
1187 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1189 info
= match
->route_option
;
1190 /* copy result of route-map */
1191 if (ROUTEMAP(red
)) {
1192 if (troute
.path
.metric_type
)
1193 match
->path
.metric_type
=
1194 troute
.path
.metric_type
;
1195 if (troute
.path
.cost
)
1196 match
->path
.cost
= troute
.path
.cost
;
1197 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1198 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1199 sizeof(struct in6_addr
));
1200 info
->tag
= tinfo
.tag
;
1202 /* If there is no route-map, simply update the tag */
1208 if (nexthop_num
&& nexthop
)
1209 ospf6_route_add_nexthop(match
, ifindex
, nexthop
);
1211 ospf6_route_add_nexthop(match
, ifindex
, NULL
);
1213 /* create/update binding in external_id_table */
1214 prefix_id
.family
= AF_INET
;
1215 prefix_id
.prefixlen
= 32;
1216 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1217 node
= route_node_get(ospf6
->external_id_table
, &prefix_id
);
1220 if (IS_OSPF6_DEBUG_ASBR
) {
1221 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
,
1224 "Advertise as AS-External Id:%s prefix %pFX metric %u",
1225 ibuf
, prefix
, match
->path
.metric_type
);
1228 match
->path
.origin
.id
= htonl(info
->id
);
1229 ospf6_as_external_lsa_originate(match
, ospf6
);
1233 /* create new entry */
1234 route
= ospf6_route_create();
1235 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
1236 memcpy(&route
->prefix
, prefix
, sizeof(struct prefix
));
1238 info
= (struct ospf6_external_info
*)XCALLOC(
1239 MTYPE_OSPF6_EXTERNAL_INFO
, sizeof(struct ospf6_external_info
));
1240 route
->route_option
= info
;
1241 info
->id
= ospf6
->external_id
++;
1243 /* copy result of route-map */
1244 if (ROUTEMAP(red
)) {
1245 if (troute
.path
.metric_type
)
1246 route
->path
.metric_type
= troute
.path
.metric_type
;
1247 if (troute
.path
.cost
)
1248 route
->path
.cost
= troute
.path
.cost
;
1249 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1250 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1251 sizeof(struct in6_addr
));
1252 info
->tag
= tinfo
.tag
;
1254 /* If there is no route-map, simply set the tag */
1259 if (nexthop_num
&& nexthop
)
1260 ospf6_route_add_nexthop(route
, ifindex
, nexthop
);
1262 ospf6_route_add_nexthop(route
, ifindex
, NULL
);
1264 /* create/update binding in external_id_table */
1265 prefix_id
.family
= AF_INET
;
1266 prefix_id
.prefixlen
= 32;
1267 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1268 node
= route_node_get(ospf6
->external_id_table
, &prefix_id
);
1271 route
= ospf6_route_add(route
, ospf6
->external_table
);
1272 route
->route_option
= info
;
1274 if (IS_OSPF6_DEBUG_ASBR
) {
1275 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
, sizeof(ibuf
));
1277 "Advertise as AS-External Id:%s prefix %pFX metric %u",
1278 ibuf
, prefix
, route
->path
.metric_type
);
1281 route
->path
.origin
.id
= htonl(info
->id
);
1282 ospf6_as_external_lsa_originate(route
, ospf6
);
1284 /* Router-Bit (ASBR Flag) may have to be updated */
1285 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1286 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1289 void ospf6_asbr_redistribute_remove(int type
, ifindex_t ifindex
,
1290 struct prefix
*prefix
, struct ospf6
*ospf6
)
1292 struct ospf6_route
*match
;
1293 struct ospf6_external_info
*info
= NULL
;
1294 struct route_node
*node
;
1295 struct ospf6_lsa
*lsa
;
1296 struct prefix prefix_id
;
1298 struct listnode
*lnode
, *lnnode
;
1299 struct ospf6_area
*oa
;
1301 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1302 if (match
== NULL
) {
1303 if (IS_OSPF6_DEBUG_ASBR
)
1304 zlog_debug("No such route %pFX to withdraw", prefix
);
1308 info
= match
->route_option
;
1311 if (info
->type
!= type
) {
1312 if (IS_OSPF6_DEBUG_ASBR
)
1313 zlog_debug("Original protocol mismatch: %pFX", prefix
);
1317 if (IS_OSPF6_DEBUG_ASBR
) {
1318 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
, sizeof(ibuf
));
1319 zlog_debug("Withdraw %pFX (AS-External Id:%s)", prefix
, ibuf
);
1322 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
1323 htonl(info
->id
), ospf6
->router_id
, ospf6
->lsdb
);
1325 ospf6_lsa_purge(lsa
);
1327 /* remove binding in external_id_table */
1328 prefix_id
.family
= AF_INET
;
1329 prefix_id
.prefixlen
= 32;
1330 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1331 node
= route_node_lookup(ospf6
->external_id_table
, &prefix_id
);
1334 route_unlock_node(node
); /* to free the lookup lock */
1335 route_unlock_node(node
); /* to free the original lock */
1337 ospf6_route_remove(match
, ospf6
->external_table
);
1338 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
, info
);
1340 /* Router-Bit (ASBR Flag) may have to be updated */
1341 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1342 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1345 DEFUN (ospf6_redistribute
,
1346 ospf6_redistribute_cmd
,
1347 "redistribute " FRR_REDIST_STR_OSPF6D
,
1349 FRR_REDIST_HELP_STR_OSPF6D
)
1352 struct ospf6_redist
*red
;
1354 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1355 OSPF6_CMD_CHECK_RUNNING(ospf6
);
1356 char *proto
= argv
[argc
- 1]->text
;
1357 type
= proto_redistnum(AFI_IP6
, proto
);
1359 return CMD_WARNING_CONFIG_FAILED
;
1361 red
= ospf6_redist_add(ospf6
, type
, 0);
1365 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1366 ospf6_asbr_redistribute_set(type
, ospf6
->vrf_id
);
1371 DEFUN (ospf6_redistribute_routemap
,
1372 ospf6_redistribute_routemap_cmd
,
1373 "redistribute " FRR_REDIST_STR_OSPF6D
" route-map WORD",
1375 FRR_REDIST_HELP_STR_OSPF6D
1376 "Route map reference\n"
1379 int idx_protocol
= 1;
1382 struct ospf6_redist
*red
;
1384 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1385 OSPF6_CMD_CHECK_RUNNING(ospf6
);
1387 char *proto
= argv
[idx_protocol
]->text
;
1388 type
= proto_redistnum(AFI_IP6
, proto
);
1390 return CMD_WARNING_CONFIG_FAILED
;
1392 red
= ospf6_redist_add(ospf6
, type
, 0);
1396 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1397 ospf6_asbr_routemap_set(red
, argv
[idx_word
]->arg
);
1398 ospf6_asbr_redistribute_set(type
, ospf6
->vrf_id
);
1403 DEFUN (no_ospf6_redistribute
,
1404 no_ospf6_redistribute_cmd
,
1405 "no redistribute " FRR_REDIST_STR_OSPF6D
" [route-map WORD]",
1408 FRR_REDIST_HELP_STR_OSPF6D
1409 "Route map reference\n"
1412 int idx_protocol
= 2;
1414 struct ospf6_redist
*red
;
1416 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1418 OSPF6_CMD_CHECK_RUNNING(ospf6
);
1420 char *proto
= argv
[idx_protocol
]->text
;
1421 type
= proto_redistnum(AFI_IP6
, proto
);
1423 return CMD_WARNING_CONFIG_FAILED
;
1425 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1429 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1430 ospf6_redist_del(ospf6
, red
, type
);
1435 int ospf6_redistribute_config_write(struct vty
*vty
, struct ospf6
*ospf6
)
1438 struct ospf6_redist
*red
;
1440 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1441 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1444 if (type
== ZEBRA_ROUTE_OSPF6
)
1447 if (ROUTEMAP_NAME(red
))
1448 vty_out(vty
, " redistribute %s route-map %s\n",
1449 ZROUTE_NAME(type
), ROUTEMAP_NAME(red
));
1451 vty_out(vty
, " redistribute %s\n", ZROUTE_NAME(type
));
1457 static void ospf6_redistribute_show_config(struct vty
*vty
, struct ospf6
*ospf6
,
1458 json_object
*json_array
,
1459 json_object
*json
, bool use_json
)
1462 int nroute
[ZEBRA_ROUTE_MAX
];
1464 struct ospf6_route
*route
;
1465 struct ospf6_external_info
*info
;
1466 json_object
*json_route
;
1467 struct ospf6_redist
*red
;
1470 memset(nroute
, 0, sizeof(nroute
));
1471 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1472 route
= ospf6_route_next(route
)) {
1473 info
= route
->route_option
;
1474 nroute
[info
->type
]++;
1479 vty_out(vty
, "Redistributing External Routes from:\n");
1481 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1483 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1487 if (type
== ZEBRA_ROUTE_OSPF6
)
1491 json_route
= json_object_new_object();
1492 json_object_string_add(json_route
, "routeType",
1494 json_object_int_add(json_route
, "numberOfRoutes",
1496 json_object_boolean_add(json_route
,
1497 "routeMapNamePresent",
1498 ROUTEMAP_NAME(red
));
1501 if (ROUTEMAP_NAME(red
)) {
1503 json_object_string_add(json_route
,
1505 ROUTEMAP_NAME(red
));
1506 json_object_boolean_add(json_route
,
1511 " %d: %s with route-map \"%s\"%s\n",
1512 nroute
[type
], ZROUTE_NAME(type
),
1515 : " (not found !)"));
1518 vty_out(vty
, " %d: %s\n", nroute
[type
],
1523 json_object_array_add(json_array
, json_route
);
1526 json_object_object_add(json
, "redistributedRoutes", json_array
);
1527 json_object_int_add(json
, "totalRoutes", total
);
1529 vty_out(vty
, "Total %d routes\n", total
);
1533 /* Routemap Functions */
1534 static enum route_map_cmd_result_t
1535 ospf6_routemap_rule_match_address_prefixlist(void *rule
,
1536 const struct prefix
*prefix
,
1540 struct prefix_list
*plist
;
1542 plist
= prefix_list_lookup(AFI_IP6
, (char *)rule
);
1544 return RMAP_NOMATCH
;
1546 return (prefix_list_apply(plist
, prefix
) == PREFIX_DENY
? RMAP_NOMATCH
1551 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg
)
1553 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1556 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule
)
1558 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1561 static const struct route_map_rule_cmd
1562 ospf6_routemap_rule_match_address_prefixlist_cmd
= {
1563 "ipv6 address prefix-list",
1564 ospf6_routemap_rule_match_address_prefixlist
,
1565 ospf6_routemap_rule_match_address_prefixlist_compile
,
1566 ospf6_routemap_rule_match_address_prefixlist_free
,
1569 /* `match interface IFNAME' */
1570 /* Match function should return 1 if match is success else return
1572 static enum route_map_cmd_result_t
1573 ospf6_routemap_rule_match_interface(void *rule
, const struct prefix
*prefix
,
1576 struct interface
*ifp
;
1577 struct ospf6_external_info
*ei
;
1579 ei
= ((struct ospf6_route
*)object
)->route_option
;
1580 ifp
= if_lookup_by_name_all_vrf((char *)rule
);
1582 if (ifp
!= NULL
&& ei
->ifindex
== ifp
->ifindex
)
1585 return RMAP_NOMATCH
;
1588 /* Route map `interface' match statement. `arg' should be
1590 static void *ospf6_routemap_rule_match_interface_compile(const char *arg
)
1592 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1595 /* Free route map's compiled `interface' value. */
1596 static void ospf6_routemap_rule_match_interface_free(void *rule
)
1598 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1601 /* Route map commands for interface matching. */
1602 static const struct route_map_rule_cmd
1603 ospf6_routemap_rule_match_interface_cmd
= {
1605 ospf6_routemap_rule_match_interface
,
1606 ospf6_routemap_rule_match_interface_compile
,
1607 ospf6_routemap_rule_match_interface_free
1610 /* Match function for matching route tags */
1611 static enum route_map_cmd_result_t
1612 ospf6_routemap_rule_match_tag(void *rule
, const struct prefix
*p
, void *object
)
1614 route_tag_t
*tag
= rule
;
1615 struct ospf6_route
*route
= object
;
1616 struct ospf6_external_info
*info
= route
->route_option
;
1618 if (info
->tag
== *tag
)
1621 return RMAP_NOMATCH
;
1624 static const struct route_map_rule_cmd
1625 ospf6_routemap_rule_match_tag_cmd
= {
1627 ospf6_routemap_rule_match_tag
,
1628 route_map_rule_tag_compile
,
1629 route_map_rule_tag_free
,
1632 static enum route_map_cmd_result_t
1633 ospf6_routemap_rule_set_metric_type(void *rule
, const struct prefix
*prefix
,
1636 char *metric_type
= rule
;
1637 struct ospf6_route
*route
= object
;
1639 if (strcmp(metric_type
, "type-2") == 0)
1640 route
->path
.metric_type
= 2;
1642 route
->path
.metric_type
= 1;
1647 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg
)
1649 if (strcmp(arg
, "type-2") && strcmp(arg
, "type-1"))
1651 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1654 static void ospf6_routemap_rule_set_metric_type_free(void *rule
)
1656 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1659 static const struct route_map_rule_cmd
1660 ospf6_routemap_rule_set_metric_type_cmd
= {
1662 ospf6_routemap_rule_set_metric_type
,
1663 ospf6_routemap_rule_set_metric_type_compile
,
1664 ospf6_routemap_rule_set_metric_type_free
,
1667 static enum route_map_cmd_result_t
1668 ospf6_routemap_rule_set_metric(void *rule
, const struct prefix
*prefix
,
1671 char *metric
= rule
;
1672 struct ospf6_route
*route
= object
;
1674 route
->path
.cost
= atoi(metric
);
1678 static void *ospf6_routemap_rule_set_metric_compile(const char *arg
)
1682 metric
= strtoul(arg
, &endp
, 0);
1683 if (metric
> OSPF_LS_INFINITY
|| *endp
!= '\0')
1685 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1688 static void ospf6_routemap_rule_set_metric_free(void *rule
)
1690 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1693 static const struct route_map_rule_cmd
1694 ospf6_routemap_rule_set_metric_cmd
= {
1696 ospf6_routemap_rule_set_metric
,
1697 ospf6_routemap_rule_set_metric_compile
,
1698 ospf6_routemap_rule_set_metric_free
,
1701 static enum route_map_cmd_result_t
1702 ospf6_routemap_rule_set_forwarding(void *rule
, const struct prefix
*prefix
,
1705 char *forwarding
= rule
;
1706 struct ospf6_route
*route
= object
;
1707 struct ospf6_external_info
*info
= route
->route_option
;
1709 if (inet_pton(AF_INET6
, forwarding
, &info
->forwarding
) != 1) {
1710 memset(&info
->forwarding
, 0, sizeof(struct in6_addr
));
1717 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg
)
1720 if (inet_pton(AF_INET6
, arg
, &a
) != 1)
1722 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1725 static void ospf6_routemap_rule_set_forwarding_free(void *rule
)
1727 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1730 static const struct route_map_rule_cmd
1731 ospf6_routemap_rule_set_forwarding_cmd
= {
1732 "forwarding-address",
1733 ospf6_routemap_rule_set_forwarding
,
1734 ospf6_routemap_rule_set_forwarding_compile
,
1735 ospf6_routemap_rule_set_forwarding_free
,
1738 static enum route_map_cmd_result_t
1739 ospf6_routemap_rule_set_tag(void *rule
, const struct prefix
*p
, void *object
)
1741 route_tag_t
*tag
= rule
;
1742 struct ospf6_route
*route
= object
;
1743 struct ospf6_external_info
*info
= route
->route_option
;
1749 static const struct route_map_rule_cmd
1750 ospf6_routemap_rule_set_tag_cmd
= {
1752 ospf6_routemap_rule_set_tag
,
1753 route_map_rule_tag_compile
,
1754 route_map_rule_tag_free
,
1757 static int route_map_command_status(struct vty
*vty
, enum rmap_compile_rets ret
)
1760 case RMAP_RULE_MISSING
:
1761 vty_out(vty
, "OSPF6 Can't find rule.\n");
1762 return CMD_WARNING_CONFIG_FAILED
;
1763 case RMAP_COMPILE_ERROR
:
1764 vty_out(vty
, "OSPF6 Argument is malformed.\n");
1765 return CMD_WARNING_CONFIG_FAILED
;
1766 case RMAP_COMPILE_SUCCESS
:
1773 /* add "set metric-type" */
1774 DEFUN (ospf6_routemap_set_metric_type
,
1775 ospf6_routemap_set_metric_type_cmd
,
1776 "set metric-type <type-1|type-2>",
1779 "OSPF6 external type 1 metric\n"
1780 "OSPF6 external type 2 metric\n")
1782 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1783 int idx_external
= 2;
1784 enum rmap_compile_rets ret
= route_map_add_set(route_map_index
,
1786 argv
[idx_external
]->arg
);
1788 return route_map_command_status(vty
, ret
);
1791 /* delete "set metric-type" */
1792 DEFUN (ospf6_routemap_no_set_metric_type
,
1793 ospf6_routemap_no_set_metric_type_cmd
,
1794 "no set metric-type [<type-1|type-2>]",
1798 "OSPF6 external type 1 metric\n"
1799 "OSPF6 external type 2 metric\n")
1801 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1802 char *ext
= (argc
== 4) ? argv
[3]->text
: NULL
;
1803 enum rmap_compile_rets ret
= route_map_delete_set(route_map_index
,
1804 "metric-type", ext
);
1806 return route_map_command_status(vty
, ret
);
1809 /* add "set forwarding-address" */
1810 DEFUN (ospf6_routemap_set_forwarding
,
1811 ospf6_routemap_set_forwarding_cmd
,
1812 "set forwarding-address X:X::X:X",
1814 "Forwarding Address\n"
1817 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1819 enum rmap_compile_rets ret
= route_map_add_set(route_map_index
,
1820 "forwarding-address",
1821 argv
[idx_ipv6
]->arg
);
1823 return route_map_command_status(vty
, ret
);
1826 /* delete "set forwarding-address" */
1827 DEFUN (ospf6_routemap_no_set_forwarding
,
1828 ospf6_routemap_no_set_forwarding_cmd
,
1829 "no set forwarding-address X:X::X:X",
1832 "Forwarding Address\n"
1835 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1837 enum rmap_compile_rets ret
= route_map_delete_set(route_map_index
,
1838 "forwarding-address",
1839 argv
[idx_ipv6
]->arg
);
1841 return route_map_command_status(vty
, ret
);
1844 static void ospf6_routemap_init(void)
1848 route_map_add_hook(ospf6_asbr_routemap_update
);
1849 route_map_delete_hook(ospf6_asbr_routemap_update
);
1850 route_map_event_hook(ospf6_asbr_routemap_event
);
1852 route_map_set_metric_hook(generic_set_add
);
1853 route_map_no_set_metric_hook(generic_set_delete
);
1855 route_map_match_tag_hook(generic_match_add
);
1856 route_map_no_match_tag_hook(generic_match_delete
);
1858 route_map_match_ipv6_address_prefix_list_hook(generic_match_add
);
1859 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete
);
1861 route_map_match_interface_hook(generic_match_add
);
1862 route_map_no_match_interface_hook(generic_match_delete
);
1864 route_map_install_match(
1865 &ospf6_routemap_rule_match_address_prefixlist_cmd
);
1866 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd
);
1867 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd
);
1869 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd
);
1870 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd
);
1871 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd
);
1872 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd
);
1874 /* ASE Metric Type (e.g. Type-1/Type-2) */
1875 install_element(RMAP_NODE
, &ospf6_routemap_set_metric_type_cmd
);
1876 install_element(RMAP_NODE
, &ospf6_routemap_no_set_metric_type_cmd
);
1879 install_element(RMAP_NODE
, &ospf6_routemap_set_forwarding_cmd
);
1880 install_element(RMAP_NODE
, &ospf6_routemap_no_set_forwarding_cmd
);
1884 /* Display functions */
1885 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1886 char *buf
, int buflen
,
1889 struct ospf6_as_external_lsa
*external
;
1890 struct in6_addr in6
;
1891 int prefix_length
= 0;
1895 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1899 ospf6_prefix_in6_addr(&in6
, external
,
1901 prefix_length
= external
->prefix
.prefix_length
;
1903 in6
= *((struct in6_addr
1904 *)((caddr_t
)external
1906 ospf6_as_external_lsa
)
1907 + OSPF6_PREFIX_SPACE(
1912 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
1913 if (prefix_length
) {
1914 snprintf(tbuf
, sizeof(tbuf
), "/%d",
1916 strlcat(buf
, tbuf
, buflen
);
1923 static int ospf6_as_external_lsa_show(struct vty
*vty
, struct ospf6_lsa
*lsa
,
1924 json_object
*json_obj
, bool use_json
)
1926 struct ospf6_as_external_lsa
*external
;
1929 assert(lsa
->header
);
1930 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1934 snprintf(buf
, sizeof(buf
), "%c%c%c",
1935 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
) ? 'E'
1937 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
) ? 'F'
1939 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
) ? 'T'
1943 json_object_string_add(json_obj
, "bits", buf
);
1944 json_object_int_add(json_obj
, "metric",
1945 (unsigned long)OSPF6_ASBR_METRIC(external
));
1946 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
,
1948 json_object_string_add(json_obj
, "prefixOptions", buf
);
1949 json_object_int_add(
1950 json_obj
, "referenceLsType",
1951 ntohs(external
->prefix
.prefix_refer_lstype
));
1952 json_object_string_add(json_obj
, "prefix",
1953 ospf6_as_external_lsa_get_prefix_str(
1954 lsa
, buf
, sizeof(buf
), 0));
1956 /* Forwarding-Address */
1957 json_object_boolean_add(
1958 json_obj
, "forwardingAddressPresent",
1959 CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
));
1960 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
1961 json_object_string_add(
1962 json_obj
, "forwardingAddress",
1963 ospf6_as_external_lsa_get_prefix_str(
1964 lsa
, buf
, sizeof(buf
), 1));
1967 json_object_boolean_add(
1968 json_obj
, "tagPresent",
1969 CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
));
1970 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
1971 json_object_int_add(json_obj
, "tag",
1972 ospf6_as_external_lsa_get_tag(lsa
));
1974 vty_out(vty
, " Bits: %s\n", buf
);
1975 vty_out(vty
, " Metric: %5lu\n",
1976 (unsigned long)OSPF6_ASBR_METRIC(external
));
1978 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
,
1980 vty_out(vty
, " Prefix Options: %s\n", buf
);
1982 vty_out(vty
, " Referenced LSType: %d\n",
1983 ntohs(external
->prefix
.prefix_refer_lstype
));
1985 vty_out(vty
, " Prefix: %s\n",
1986 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
,
1989 /* Forwarding-Address */
1990 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
1991 vty_out(vty
, " Forwarding-Address: %s\n",
1992 ospf6_as_external_lsa_get_prefix_str(
1993 lsa
, buf
, sizeof(buf
), 1));
1997 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
1998 vty_out(vty
, " Tag: %" ROUTE_TAG_PRI
"\n",
1999 ospf6_as_external_lsa_get_tag(lsa
));
2006 static void ospf6_asbr_external_route_show(struct vty
*vty
,
2007 struct ospf6_route
*route
,
2008 json_object
*json_array
,
2011 struct ospf6_external_info
*info
= route
->route_option
;
2012 char prefix
[PREFIX2STR_BUFFER
], id
[16], forwarding
[64];
2014 json_object
*json_route
;
2017 prefix2str(&route
->prefix
, prefix
, sizeof(prefix
));
2018 tmp_id
= ntohl(info
->id
);
2019 inet_ntop(AF_INET
, &tmp_id
, id
, sizeof(id
));
2020 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
2021 inet_ntop(AF_INET6
, &info
->forwarding
, forwarding
,
2022 sizeof(forwarding
));
2024 snprintf(forwarding
, sizeof(forwarding
), ":: (ifindex %d)",
2025 ospf6_route_get_first_nh_index(route
));
2028 json_route
= json_object_new_object();
2029 snprintf(route_type
, sizeof(route_type
), "%c",
2030 zebra_route_char(info
->type
));
2031 json_object_string_add(json_route
, "routeType", route_type
);
2032 json_object_string_add(json_route
, "destination", prefix
);
2033 json_object_string_add(json_route
, "id", id
);
2034 json_object_int_add(json_route
, "metricType",
2035 route
->path
.metric_type
);
2036 json_object_int_add(
2037 json_route
, "routeCost",
2038 (unsigned long)(route
->path
.metric_type
== 2
2039 ? route
->path
.u
.cost_e2
2040 : route
->path
.cost
));
2041 json_object_string_add(json_route
, "forwarding", forwarding
);
2043 json_object_array_add(json_array
, json_route
);
2046 vty_out(vty
, "%c %-32pFX %-15s type-%d %5lu %s\n",
2047 zebra_route_char(info
->type
), &route
->prefix
, id
,
2048 route
->path
.metric_type
,
2049 (unsigned long)(route
->path
.metric_type
== 2
2050 ? route
->path
.u
.cost_e2
2051 : route
->path
.cost
),
2055 DEFUN (show_ipv6_ospf6_redistribute
,
2056 show_ipv6_ospf6_redistribute_cmd
,
2057 "show ipv6 ospf6 redistribute [json]",
2061 "redistributing External information\n"
2064 struct ospf6_route
*route
;
2065 struct ospf6
*ospf6
= NULL
;
2066 json_object
*json
= NULL
;
2067 bool uj
= use_json(argc
, argv
);
2068 json_object
*json_array_routes
= NULL
;
2069 json_object
*json_array_redistribute
= NULL
;
2071 ospf6
= ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME
);
2072 OSPF6_CMD_CHECK_RUNNING(ospf6
);
2075 json
= json_object_new_object();
2076 json_array_routes
= json_object_new_array();
2077 json_array_redistribute
= json_object_new_array();
2079 ospf6_redistribute_show_config(vty
, ospf6
, json_array_redistribute
,
2082 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
2083 route
= ospf6_route_next(route
)) {
2084 ospf6_asbr_external_route_show(vty
, route
, json_array_routes
,
2089 json_object_object_add(json
, "routes", json_array_routes
);
2090 vty_out(vty
, "%s\n",
2091 json_object_to_json_string_ext(
2092 json
, JSON_C_TO_STRING_PRETTY
));
2093 json_object_free(json
);
2098 static struct ospf6_lsa_handler as_external_handler
= {
2099 .lh_type
= OSPF6_LSTYPE_AS_EXTERNAL
,
2100 .lh_name
= "AS-External",
2101 .lh_short_name
= "ASE",
2102 .lh_show
= ospf6_as_external_lsa_show
,
2103 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
2106 void ospf6_asbr_init(void)
2108 ospf6_routemap_init();
2110 ospf6_install_lsa_handler(&as_external_handler
);
2112 install_element(VIEW_NODE
, &show_ipv6_ospf6_redistribute_cmd
);
2114 install_element(OSPF6_NODE
, &ospf6_redistribute_cmd
);
2115 install_element(OSPF6_NODE
, &ospf6_redistribute_routemap_cmd
);
2116 install_element(OSPF6_NODE
, &no_ospf6_redistribute_cmd
);
2119 void ospf6_asbr_redistribute_reset(struct ospf6
*ospf6
)
2122 struct ospf6_redist
*red
;
2124 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
2125 red
= ospf6_redist_lookup(ospf6
, type
, 0);
2128 if (type
== ZEBRA_ROUTE_OSPF6
)
2130 if (ospf6_zebra_is_redistribute(type
, ospf6
->vrf_id
)) {
2131 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
2132 ospf6_redist_del(ospf6
, red
, type
);
2137 void ospf6_asbr_terminate(void)
2139 /* Cleanup route maps */
2143 DEFUN (debug_ospf6_asbr
,
2144 debug_ospf6_asbr_cmd
,
2148 "Debug OSPFv3 ASBR function\n"
2151 OSPF6_DEBUG_ASBR_ON();
2155 DEFUN (no_debug_ospf6_asbr
,
2156 no_debug_ospf6_asbr_cmd
,
2157 "no debug ospf6 asbr",
2161 "Debug OSPFv3 ASBR function\n"
2164 OSPF6_DEBUG_ASBR_OFF();
2168 int config_write_ospf6_debug_asbr(struct vty
*vty
)
2170 if (IS_OSPF6_DEBUG_ASBR
)
2171 vty_out(vty
, "debug ospf6 asbr\n");
2175 void install_element_ospf6_debug_asbr(void)
2177 install_element(ENABLE_NODE
, &debug_ospf6_asbr_cmd
);
2178 install_element(ENABLE_NODE
, &no_debug_ospf6_asbr_cmd
);
2179 install_element(CONFIG_NODE
, &debug_ospf6_asbr_cmd
);
2180 install_element(CONFIG_NODE
, &no_debug_ospf6_asbr_cmd
);