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
33 #include "lib/northbound_cli.h"
35 #include "ospf6_proto.h"
36 #include "ospf6_lsa.h"
37 #include "ospf6_lsdb.h"
38 #include "ospf6_route.h"
39 #include "ospf6_zebra.h"
40 #include "ospf6_message.h"
41 #include "ospf6_spf.h"
43 #include "ospf6_top.h"
45 #include "ospf6_area.h"
46 #include "ospf6_interface.h"
47 #include "ospf6_neighbor.h"
48 #include "ospf6_asbr.h"
49 #include "ospf6_abr.h"
50 #include "ospf6_intra.h"
51 #include "ospf6_flood.h"
53 #include "ospf6_spf.h"
54 #include "ospf6_nssa.h"
57 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_EXTERNAL_INFO
, "OSPF6 ext. info");
58 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_DIST_ARGS
, "OSPF6 Distribute arguments");
59 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_REDISTRIBUTE
, "OSPF6 Redistribute arguments");
61 static void ospf6_asbr_redistribute_set(struct ospf6
*ospf6
, int type
);
62 static void ospf6_asbr_redistribute_unset(struct ospf6
*ospf6
,
63 struct ospf6_redist
*red
, int type
);
65 #ifndef VTYSH_EXTRACT_PL
66 #include "ospf6d/ospf6_asbr_clippy.c"
69 unsigned char conf_debug_ospf6_asbr
= 0;
71 #define ZROUTE_NAME(x) zebra_route_string(x)
73 /* AS External LSA origination */
74 void ospf6_as_external_lsa_originate(struct ospf6_route
*route
,
77 char buffer
[OSPF6_MAX_LSASIZE
];
78 struct ospf6_lsa_header
*lsa_header
;
79 struct ospf6_lsa
*lsa
;
80 struct ospf6_external_info
*info
= route
->route_option
;
82 struct ospf6_as_external_lsa
*as_external_lsa
;
85 if (IS_OSPF6_DEBUG_ASBR
|| IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL
))
86 zlog_debug("Originate AS-External-LSA for %pFX",
90 memset(buffer
, 0, sizeof(buffer
));
91 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
92 as_external_lsa
= (struct ospf6_as_external_lsa
93 *)((caddr_t
)lsa_header
94 + sizeof(struct ospf6_lsa_header
));
95 p
= (caddr_t
)((caddr_t
)as_external_lsa
96 + sizeof(struct ospf6_as_external_lsa
));
98 /* Fill AS-External-LSA */
100 if (route
->path
.metric_type
== 2)
101 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
103 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
105 /* forwarding address */
106 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
107 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
109 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
111 /* external route tag */
113 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
115 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
118 OSPF6_ASBR_METRIC_SET(as_external_lsa
, route
->path
.cost
);
121 as_external_lsa
->prefix
.prefix_length
= route
->prefix
.prefixlen
;
124 as_external_lsa
->prefix
.prefix_options
= route
->path
.prefix_options
;
126 /* don't use refer LS-type */
127 as_external_lsa
->prefix
.prefix_refer_lstype
= htons(0);
130 memcpy(p
, &route
->prefix
.u
.prefix6
,
131 OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
));
132 ospf6_prefix_apply_mask(&as_external_lsa
->prefix
);
133 p
+= OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
);
135 /* Forwarding address */
136 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
137 memcpy(p
, &info
->forwarding
, sizeof(struct in6_addr
));
138 p
+= sizeof(struct in6_addr
);
141 /* External Route Tag */
142 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
143 route_tag_t network_order
= htonl(info
->tag
);
145 memcpy(p
, &network_order
, sizeof(network_order
));
146 p
+= sizeof(network_order
);
149 /* Fill LSA Header */
151 lsa_header
->type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
152 lsa_header
->id
= route
->path
.origin
.id
;
153 lsa_header
->adv_router
= ospf6
->router_id
;
155 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
156 lsa_header
->adv_router
, ospf6
->lsdb
);
157 lsa_header
->length
= htons((caddr_t
)p
- (caddr_t
)lsa_header
);
160 ospf6_lsa_checksum(lsa_header
);
163 lsa
= ospf6_lsa_create(lsa_header
);
166 ospf6_lsa_originate_process(lsa
, ospf6
);
169 int ospf6_orig_as_external_lsa(struct thread
*thread
)
171 struct ospf6_interface
*oi
;
172 struct ospf6_lsa
*lsa
;
173 uint32_t type
, adv_router
;
175 oi
= (struct ospf6_interface
*)THREAD_ARG(thread
);
176 oi
->thread_as_extern_lsa
= NULL
;
178 if (oi
->state
== OSPF6_INTERFACE_DOWN
)
180 if (IS_AREA_NSSA(oi
->area
))
183 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
184 adv_router
= oi
->area
->ospf6
->router_id
;
185 for (ALL_LSDB_TYPED_ADVRTR(oi
->area
->ospf6
->lsdb
, type
, adv_router
,
187 if (IS_OSPF6_DEBUG_ASBR
)
189 "%s: Send update of AS-External LSA %s seq 0x%x",
191 ntohl(lsa
->header
->seqnum
));
193 ospf6_flood_interface(NULL
, lsa
, oi
);
199 static route_tag_t
ospf6_as_external_lsa_get_tag(struct ospf6_lsa
*lsa
)
201 struct ospf6_as_external_lsa
*external
;
202 ptrdiff_t tag_offset
;
203 route_tag_t network_order
;
208 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
211 if (!CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
214 tag_offset
= sizeof(*external
)
215 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
216 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
217 tag_offset
+= sizeof(struct in6_addr
);
219 memcpy(&network_order
, (caddr_t
)external
+ tag_offset
,
220 sizeof(network_order
));
221 return ntohl(network_order
);
224 void ospf6_asbr_update_route_ecmp_path(struct ospf6_route
*old
,
225 struct ospf6_route
*route
,
228 struct ospf6_route
*old_route
, *next_route
;
229 struct ospf6_path
*ecmp_path
, *o_path
= NULL
;
230 struct listnode
*anode
, *anext
;
231 struct listnode
*nnode
, *rnode
, *rnext
;
232 struct ospf6_nexthop
*nh
, *rnh
;
233 bool route_found
= false;
235 /* check for old entry match with new route origin,
238 for (old_route
= old
; old_route
; old_route
= next_route
) {
239 bool route_updated
= false;
241 next_route
= old_route
->next
;
243 if (!ospf6_route_is_same(old_route
, route
)
244 || (old_route
->path
.type
!= route
->path
.type
))
247 /* Current and New route has same origin,
250 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
, anext
,
252 /* Check old route path and route has same
255 if (o_path
->area_id
!= route
->path
.area_id
256 || (memcmp(&(o_path
)->origin
, &(route
)->path
.origin
,
257 sizeof(struct ospf6_ls_origin
))
261 /* Cost is not same then delete current path */
262 if ((o_path
->cost
== route
->path
.cost
)
263 && (o_path
->u
.cost_e2
== route
->path
.u
.cost_e2
))
266 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
268 "%s: route %pFX cost old %u new %u is not same, replace route",
269 __func__
, &old_route
->prefix
, o_path
->cost
,
273 /* Remove selected current rout path's nh from
276 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
277 for (ALL_LIST_ELEMENTS(old_route
->nh_list
,
278 rnode
, rnext
, rnh
)) {
279 if (!ospf6_nexthop_is_same(rnh
, nh
))
281 listnode_delete(old_route
->nh_list
,
283 ospf6_nexthop_delete(rnh
);
287 listnode_delete(old_route
->paths
, o_path
);
288 ospf6_path_free(o_path
);
289 route_updated
= true;
291 /* Current route's path (adv_router info) is similar
292 * to route being added.
293 * Replace current route's path with paths list head.
294 * Update FIB with effective NHs.
296 if (listcount(old_route
->paths
)) {
297 for (ALL_LIST_ELEMENTS(old_route
->paths
,
298 anode
, anext
, o_path
)) {
299 ospf6_merge_nexthops(
303 /* Update RIB/FIB with effective
306 if (ospf6
->route_table
->hook_add
)
307 (*ospf6
->route_table
->hook_add
)(
310 if (old_route
->path
.origin
.id
311 == route
->path
.origin
.id
312 && old_route
->path
.origin
.adv_router
313 == route
->path
.origin
315 struct ospf6_path
*h_path
;
317 h_path
= (struct ospf6_path
*)
318 listgetdata(listhead(
320 old_route
->path
.origin
.type
=
322 old_route
->path
.origin
.id
=
324 old_route
->path
.origin
.adv_router
=
325 h_path
->origin
.adv_router
;
328 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
330 "%s: route %pFX old cost %u new cost %u, delete old entry.",
331 __func__
, &old_route
->prefix
,
332 old_route
->path
.cost
,
335 if (old
== old_route
)
337 ospf6_route_remove(old_route
,
346 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
348 /* Current and New Route prefix or route type
349 * is not same skip this current node.
351 if (!ospf6_route_is_same(old_route
, route
)
352 || (old_route
->path
.type
!= route
->path
.type
))
355 /* Old Route and New Route have Equal Cost, Merge NHs */
356 if ((old_route
->path
.cost
== route
->path
.cost
)
357 && (old_route
->path
.u
.cost_e2
== route
->path
.u
.cost_e2
)) {
359 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
361 "%s: old route %pFX path cost %u e2 %u",
362 __func__
, &old_route
->prefix
,
363 old_route
->path
.cost
,
364 old_route
->path
.u
.cost_e2
);
367 /* check if this path exists already in
368 * route->paths list, if so, replace nh_list
371 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
373 if (o_path
->area_id
== route
->path
.area_id
374 && (memcmp(&(o_path
)->origin
,
375 &(route
)->path
.origin
,
376 sizeof(struct ospf6_ls_origin
))
380 /* If path is not found in old_route paths's list,
381 * add a new path to route paths list and merge
382 * nexthops in route->path->nh_list.
383 * Otherwise replace existing path's nh_list.
385 if (o_path
== NULL
) {
386 ecmp_path
= ospf6_path_dup(&route
->path
);
388 /* Add a nh_list to new ecmp path */
389 ospf6_copy_nexthops(ecmp_path
->nh_list
,
392 /* Add the new path to route's path list */
393 listnode_add_sort(old_route
->paths
, ecmp_path
);
395 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
397 "%s: route %pFX another path added with nh %u, effective paths %u nh %u",
398 __func__
, &route
->prefix
,
399 listcount(ecmp_path
->nh_list
),
400 old_route
->paths
? listcount(
403 listcount(old_route
->nh_list
));
406 list_delete_all_node(o_path
->nh_list
);
407 ospf6_copy_nexthops(o_path
->nh_list
,
411 /* Reset nexthop lists, rebuild from brouter table
412 * for each adv. router.
414 list_delete_all_node(old_route
->nh_list
);
416 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
418 struct ospf6_route
*asbr_entry
;
420 asbr_entry
= ospf6_route_lookup(
422 ospf6
->brouter_table
);
423 if (asbr_entry
== NULL
) {
424 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
426 "%s: ls_prfix %pFX asbr_entry not found.",
431 ospf6_route_merge_nexthops(old_route
,
435 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
437 "%s: route %pFX with effective paths %u nh %u",
438 __func__
, &route
->prefix
,
440 ? listcount(old_route
->paths
)
443 ? listcount(old_route
->nh_list
)
447 if (ospf6
->route_table
->hook_add
)
448 (*ospf6
->route_table
->hook_add
)(old_route
);
450 /* Delete the new route its info added to existing
453 ospf6_route_delete(route
);
460 /* Add new route to existing node in ospf6 route table. */
461 ospf6_route_add(route
, ospf6
->route_table
);
465 /* Check if the forwarding address is local address */
466 static int ospf6_ase_forward_address_check(struct ospf6
*ospf6
,
467 struct in6_addr
*fwd_addr
)
469 struct listnode
*anode
, *node
, *cnode
;
470 struct ospf6_interface
*oi
;
471 struct ospf6_area
*oa
;
472 struct interface
*ifp
;
475 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, oa
)) {
476 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, node
, oi
)) {
477 if (!if_is_operative(oi
->interface
)
478 || oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
482 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
483 if (IPV6_ADDR_SAME(&c
->address
->u
.prefix6
,
493 void ospf6_asbr_lsa_add(struct ospf6_lsa
*lsa
)
495 struct ospf6_as_external_lsa
*external
;
496 struct prefix asbr_id
;
497 struct ospf6_route
*asbr_entry
, *route
, *old
= NULL
;
498 struct ospf6_path
*path
;
501 struct ospf6_area
*oa
= NULL
;
502 struct prefix fwd_addr
;
505 type
= ntohs(lsa
->header
->type
);
506 oa
= lsa
->lsdb
->data
;
508 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
511 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
512 zlog_debug("Calculate AS-External route for %s", lsa
->name
);
514 ospf6
= ospf6_get_by_lsdb(lsa
);
516 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
517 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
518 zlog_debug("Ignore self-originated AS-External-LSA");
522 if (OSPF6_ASBR_METRIC(external
) == OSPF_LS_INFINITY
) {
523 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
524 zlog_debug("Ignore LSA with LSInfinity Metric");
528 if (CHECK_FLAG(external
->prefix
.prefix_options
,
529 OSPF6_PREFIX_OPTION_NU
)) {
530 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
531 zlog_debug("Ignore LSA with NU bit set Metric");
535 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &asbr_id
);
536 asbr_entry
= ospf6_route_lookup(&asbr_id
, ospf6
->brouter_table
);
537 if (asbr_entry
== NULL
) {
538 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
539 zlog_debug("ASBR entry not found: %pFX", &asbr_id
);
542 /* The router advertising external LSA can be ASBR or ABR */
543 if (!CHECK_FLAG(asbr_entry
->path
.router_bits
,
544 OSPF6_ROUTER_BIT_E
)) {
545 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
547 "External bit reset ASBR route entry : %pFX",
553 /* Check the forwarding address */
554 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
555 offset
= sizeof(*external
)
556 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
557 memset(&fwd_addr
, 0, sizeof(struct prefix
));
558 fwd_addr
.family
= AF_INET6
;
559 fwd_addr
.prefixlen
= IPV6_MAX_BITLEN
;
560 memcpy(&fwd_addr
.u
.prefix6
, (caddr_t
)external
+ offset
,
561 sizeof(struct in6_addr
));
563 if (!IN6_IS_ADDR_UNSPECIFIED(&fwd_addr
.u
.prefix6
)) {
564 if (!ospf6_ase_forward_address_check(
565 ospf6
, &fwd_addr
.u
.prefix6
)) {
566 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
568 "Fwd address %pFX is local address",
573 /* Find the forwarding entry */
574 asbr_entry
= ospf6_route_lookup_bestmatch(
575 &fwd_addr
, ospf6
->route_table
);
576 if (asbr_entry
== NULL
) {
577 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
579 "Fwd address not found: %pFX",
586 route
= ospf6_route_create();
587 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
588 route
->prefix
.family
= AF_INET6
;
589 route
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
590 ospf6_prefix_in6_addr(&route
->prefix
.u
.prefix6
, external
,
593 route
->path
.area_id
= asbr_entry
->path
.area_id
;
594 route
->path
.origin
.type
= lsa
->header
->type
;
595 route
->path
.origin
.id
= lsa
->header
->id
;
596 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
597 route
->path
.prefix_options
= external
->prefix
.prefix_options
;
598 memcpy(&route
->path
.ls_prefix
, &asbr_id
, sizeof(struct prefix
));
600 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
601 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
602 route
->path
.metric_type
= 2;
603 route
->path
.cost
= asbr_entry
->path
.cost
;
604 route
->path
.u
.cost_e2
= OSPF6_ASBR_METRIC(external
);
606 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
607 route
->path
.metric_type
= 1;
609 asbr_entry
->path
.cost
+ OSPF6_ASBR_METRIC(external
);
610 route
->path
.u
.cost_e2
= 0;
613 route
->path
.tag
= ospf6_as_external_lsa_get_tag(lsa
);
615 ospf6_route_copy_nexthops(route
, asbr_entry
);
617 path
= ospf6_path_dup(&route
->path
);
618 ospf6_copy_nexthops(path
->nh_list
, asbr_entry
->nh_list
);
619 listnode_add_sort(route
->paths
, path
);
622 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
624 "%s: %s %u route add %pFX cost %u(%u) nh %u", __func__
,
625 (type
== OSPF6_LSTYPE_AS_EXTERNAL
) ? "AS-External"
627 (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
) ? 1 : 2,
628 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
629 listcount(route
->nh_list
));
631 if (type
== OSPF6_LSTYPE_AS_EXTERNAL
)
632 old
= ospf6_route_lookup(&route
->prefix
, ospf6
->route_table
);
633 else if (type
== OSPF6_LSTYPE_TYPE_7
)
634 old
= ospf6_route_lookup(&route
->prefix
, oa
->route_table
);
636 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
637 zlog_debug("%s: Adding new route", __func__
);
638 /* Add the new route to ospf6 instance route table. */
639 if (type
== OSPF6_LSTYPE_AS_EXTERNAL
)
640 ospf6_route_add(route
, ospf6
->route_table
);
641 /* Add the route to the area route table */
642 else if (type
== OSPF6_LSTYPE_TYPE_7
) {
643 ospf6_route_add(route
, oa
->route_table
);
647 * ECMP: Keep new equal preference path in current
648 * route's path list, update zebra with new effective
649 * list along with addition of ECMP path.
651 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
652 zlog_debug("%s : old route %pFX cost %u(%u) nh %u",
653 __func__
, &route
->prefix
, route
->path
.cost
,
654 route
->path
.u
.cost_e2
,
655 listcount(route
->nh_list
));
656 ospf6_asbr_update_route_ecmp_path(old
, route
, ospf6
);
660 void ospf6_asbr_lsa_remove(struct ospf6_lsa
*lsa
,
661 struct ospf6_route
*asbr_entry
)
663 struct ospf6_as_external_lsa
*external
;
664 struct prefix prefix
;
665 struct ospf6_route
*route
, *nroute
, *route_to_del
;
666 struct ospf6_area
*oa
= NULL
;
671 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
674 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
) || (IS_OSPF6_DEBUG_NSSA
))
677 ospf6
= ospf6_get_by_lsdb(lsa
);
678 type
= ntohs(lsa
->header
->type
);
680 if (type
== OSPF6_LSTYPE_TYPE_7
) {
682 zlog_debug("%s: Withdraw Type 7 route for %s",
683 __func__
, lsa
->name
);
684 oa
= lsa
->lsdb
->data
;
687 zlog_debug("%s: Withdraw AS-External route for %s",
688 __func__
, lsa
->name
);
690 if (ospf6_check_and_set_router_abr(ospf6
))
691 oa
= ospf6
->backbone
;
693 oa
= listgetdata(listhead(ospf6
->area_list
));
698 zlog_debug("%s: Invalid area", __func__
);
702 if (lsa
->header
->adv_router
== oa
->ospf6
->router_id
) {
704 zlog_debug("Ignore self-originated AS-External-LSA");
708 route_to_del
= ospf6_route_create();
709 route_to_del
->type
= OSPF6_DEST_TYPE_NETWORK
;
710 route_to_del
->prefix
.family
= AF_INET6
;
711 route_to_del
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
712 ospf6_prefix_in6_addr(&route_to_del
->prefix
.u
.prefix6
, external
,
715 route_to_del
->path
.origin
.type
= lsa
->header
->type
;
716 route_to_del
->path
.origin
.id
= lsa
->header
->id
;
717 route_to_del
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
720 route_to_del
->path
.area_id
= asbr_entry
->path
.area_id
;
721 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
722 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
723 route_to_del
->path
.metric_type
= 2;
724 route_to_del
->path
.cost
= asbr_entry
->path
.cost
;
725 route_to_del
->path
.u
.cost_e2
=
726 OSPF6_ASBR_METRIC(external
);
728 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
729 route_to_del
->path
.metric_type
= 1;
730 route_to_del
->path
.cost
= asbr_entry
->path
.cost
731 + OSPF6_ASBR_METRIC(external
);
732 route_to_del
->path
.u
.cost_e2
= 0;
736 memset(&prefix
, 0, sizeof(struct prefix
));
737 prefix
.family
= AF_INET6
;
738 prefix
.prefixlen
= external
->prefix
.prefix_length
;
739 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, external
, &external
->prefix
);
741 if (type
== OSPF6_LSTYPE_TYPE_7
)
742 route
= ospf6_route_lookup(&prefix
, oa
->route_table
);
744 route
= ospf6_route_lookup(&prefix
, oa
->ospf6
->route_table
);
748 zlog_debug("AS-External route %pFX not found", &prefix
);
749 ospf6_route_delete(route_to_del
);
755 "%s: Current route %pFX cost %u e2 %u, route to del cost %u e2 %u",
756 __func__
, &prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
757 route_to_del
->path
.cost
, route_to_del
->path
.u
.cost_e2
);
759 for (ospf6_route_lock(route
);
760 route
&& ospf6_route_is_prefix(&prefix
, route
); route
= nroute
) {
761 nroute
= ospf6_route_next(route
);
763 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
)
766 /* Route has multiple ECMP paths, remove matching
767 * path. Update current route's effective nh list
768 * after removal of one of the path.
770 if (listcount(route
->paths
) > 1) {
771 struct listnode
*anode
, *anext
;
772 struct listnode
*nnode
, *rnode
, *rnext
;
773 struct ospf6_nexthop
*nh
, *rnh
;
774 struct ospf6_path
*o_path
;
775 bool nh_updated
= false;
777 /* Iterate all paths of route to find maching with LSA
778 * remove from route path list. If route->path is same,
779 * replace from paths list.
781 for (ALL_LIST_ELEMENTS(route
->paths
, anode
, anext
,
783 if ((o_path
->origin
.type
!= lsa
->header
->type
)
784 || (o_path
->origin
.adv_router
785 != lsa
->header
->adv_router
)
786 || (o_path
->origin
.id
!= lsa
->header
->id
))
789 /* Compare LSA cost with current
793 && (o_path
->cost
!= route_to_del
->path
.cost
795 != route_to_del
->path
.u
797 if (IS_OSPF6_DEBUG_EXAMIN(
800 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
811 "%s: route %pFX path found with cost %u nh %u to remove.",
812 __func__
, &prefix
, route
->path
.cost
,
813 listcount(o_path
->nh_list
));
816 /* Remove found path's nh_list from
817 * the route's nh_list.
819 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
,
821 for (ALL_LIST_ELEMENTS(route
->nh_list
,
824 if (!ospf6_nexthop_is_same(rnh
,
827 listnode_delete(route
->nh_list
,
829 ospf6_nexthop_delete(rnh
);
832 /* Delete the path from route's path list */
833 listnode_delete(route
->paths
, o_path
);
834 ospf6_path_free(o_path
);
839 /* Iterate all paths and merge nexthop,
840 * unlesss any of the nexthop similar to
841 * ones deleted as part of path deletion.
844 for (ALL_LIST_ELEMENTS(route
->paths
, anode
,
846 ospf6_merge_nexthops(route
->nh_list
,
852 "%s: AS-External %u route %pFX update paths %u nh %u",
855 == OSPF6_PATH_TYPE_EXTERNAL1
)
858 &route
->prefix
, listcount(route
->paths
),
859 route
->nh_list
? listcount(
864 if (listcount(route
->paths
)) {
865 /* Update RIB/FIB with effective
868 if (oa
->ospf6
->route_table
->hook_add
)
869 (*oa
->ospf6
->route_table
872 /* route's primary path is similar
873 * to LSA, replace route's primary
874 * path with route's paths list head.
876 if ((route
->path
.origin
.id
==
878 (route
->path
.origin
.adv_router
879 == lsa
->header
->adv_router
)) {
880 struct ospf6_path
*h_path
;
882 h_path
= (struct ospf6_path
*)
884 listhead(route
->paths
));
885 route
->path
.origin
.type
=
887 route
->path
.origin
.id
=
889 route
->path
.origin
.adv_router
=
890 h_path
->origin
.adv_router
;
893 if (type
== OSPF6_LSTYPE_TYPE_7
)
895 route
, oa
->route_table
);
899 oa
->ospf6
->route_table
);
905 /* Compare LSA origin and cost with current route info.
906 * if any check fails skip del this route node.
909 && (!ospf6_route_is_same_origin(route
, route_to_del
)
910 || (route
->path
.type
!= route_to_del
->path
.type
)
911 || (route
->path
.cost
!= route_to_del
->path
.cost
)
912 || (route
->path
.u
.cost_e2
913 != route_to_del
->path
.u
.cost_e2
))) {
916 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
917 __func__
, &prefix
, route
->path
.cost
,
918 route_to_del
->path
.cost
);
923 if ((route
->path
.origin
.type
!= lsa
->header
->type
)
924 || (route
->path
.origin
.adv_router
925 != lsa
->header
->adv_router
)
926 || (route
->path
.origin
.id
!= lsa
->header
->id
))
931 "%s: AS-External %u route remove %pFX cost %u(%u) nh %u",
933 route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
936 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
937 listcount(route
->nh_list
));
939 if (type
== OSPF6_LSTYPE_TYPE_7
)
940 ospf6_route_remove(route
, oa
->route_table
);
942 ospf6_route_remove(route
, oa
->ospf6
->route_table
);
945 ospf6_route_unlock(route
);
947 ospf6_route_delete(route_to_del
);
950 void ospf6_asbr_lsentry_add(struct ospf6_route
*asbr_entry
, struct ospf6
*ospf6
)
952 struct ospf6_lsa
*lsa
;
956 if (!CHECK_FLAG(asbr_entry
->flag
, OSPF6_ROUTE_BEST
)) {
958 inet_ntop(AF_INET
, &ADV_ROUTER_IN_PREFIX(&asbr_entry
->prefix
),
960 zlog_info("ignore non-best path: lsentry %s add", buf
);
964 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
965 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
966 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
)) {
967 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
968 ospf6_asbr_lsa_add(lsa
);
972 void ospf6_asbr_lsentry_remove(struct ospf6_route
*asbr_entry
,
975 struct ospf6_lsa
*lsa
;
979 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
980 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
981 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
))
982 ospf6_asbr_lsa_remove(lsa
, asbr_entry
);
986 /* redistribute function */
987 static void ospf6_asbr_routemap_set(struct ospf6_redist
*red
,
990 if (ROUTEMAP_NAME(red
)) {
991 route_map_counter_decrement(ROUTEMAP(red
));
992 free(ROUTEMAP_NAME(red
));
995 ROUTEMAP_NAME(red
) = strdup(mapname
);
996 ROUTEMAP(red
) = route_map_lookup_by_name(mapname
);
997 route_map_counter_increment(ROUTEMAP(red
));
1000 static void ospf6_asbr_routemap_unset(struct ospf6_redist
*red
)
1002 if (ROUTEMAP_NAME(red
))
1003 free(ROUTEMAP_NAME(red
));
1005 route_map_counter_decrement(ROUTEMAP(red
));
1007 ROUTEMAP_NAME(red
) = NULL
;
1008 ROUTEMAP(red
) = NULL
;
1011 static int ospf6_asbr_routemap_update_timer(struct thread
*thread
)
1013 struct ospf6
*ospf6
= THREAD_ARG(thread
);
1014 struct ospf6_redist
*red
;
1017 ospf6
->t_distribute_update
= NULL
;
1019 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1020 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1025 if (!CHECK_FLAG(red
->flag
, OSPF6_IS_RMAP_CHANGED
))
1028 if (ROUTEMAP_NAME(red
))
1030 route_map_lookup_by_name(ROUTEMAP_NAME(red
));
1032 if (ROUTEMAP(red
)) {
1033 if (IS_OSPF6_DEBUG_ASBR
)
1035 "%s: route-map %s update, reset redist %s",
1036 __func__
, ROUTEMAP_NAME(red
),
1039 ospf6_zebra_no_redistribute(type
, ospf6
->vrf_id
);
1040 ospf6_zebra_redistribute(type
, ospf6
->vrf_id
);
1043 UNSET_FLAG(red
->flag
, OSPF6_IS_RMAP_CHANGED
);
1049 void ospf6_asbr_distribute_list_update(struct ospf6
*ospf6
,
1050 struct ospf6_redist
*red
)
1052 SET_FLAG(red
->flag
, OSPF6_IS_RMAP_CHANGED
);
1054 if (ospf6
->t_distribute_update
)
1057 if (IS_OSPF6_DEBUG_ASBR
)
1058 zlog_debug("%s: trigger redistribute reset thread", __func__
);
1060 ospf6
->t_distribute_update
= NULL
;
1061 thread_add_timer_msec(master
, ospf6_asbr_routemap_update_timer
, ospf6
,
1062 OSPF_MIN_LS_INTERVAL
,
1063 &ospf6
->t_distribute_update
);
1066 void ospf6_asbr_routemap_update(const char *mapname
)
1069 struct listnode
*node
, *nnode
;
1070 struct ospf6
*ospf6
= NULL
;
1071 struct ospf6_redist
*red
;
1076 for (ALL_LIST_ELEMENTS(om6
->ospf6
, node
, nnode
, ospf6
)) {
1077 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1078 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1079 if (!red
|| (ROUTEMAP_NAME(red
) == NULL
))
1082 route_map_lookup_by_name(ROUTEMAP_NAME(red
));
1085 || strcmp(ROUTEMAP_NAME(red
), mapname
))
1087 if (ROUTEMAP(red
)) {
1088 if (IS_OSPF6_DEBUG_ASBR
)
1090 "%s: route-map %s update, reset redist %s",
1096 route_map_counter_increment(ROUTEMAP(red
));
1097 ospf6_asbr_distribute_list_update(ospf6
, red
);
1100 * if the mapname matches a
1101 * route-map on ospf6 but the
1102 * map doesn't exist, it is
1103 * being deleted. flush and then
1106 if (IS_OSPF6_DEBUG_ASBR
)
1108 "%s: route-map %s deleted, reset redist %s",
1113 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1114 ospf6_asbr_routemap_set(red
, mapname
);
1115 ospf6_asbr_redistribute_set(ospf6
, type
);
1121 static void ospf6_asbr_routemap_event(const char *name
)
1124 struct listnode
*node
, *nnode
;
1125 struct ospf6
*ospf6
;
1126 struct ospf6_redist
*red
;
1130 for (ALL_LIST_ELEMENTS(om6
->ospf6
, node
, nnode
, ospf6
)) {
1131 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1132 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1133 if (red
&& ROUTEMAP_NAME(red
)
1134 && (strcmp(ROUTEMAP_NAME(red
), name
) == 0))
1135 ospf6_asbr_distribute_list_update(ospf6
, red
);
1140 int ospf6_asbr_is_asbr(struct ospf6
*o
)
1142 return (o
->external_table
->count
|| IS_OSPF6_ASBR(o
));
1145 struct ospf6_redist
*ospf6_redist_lookup(struct ospf6
*ospf6
, int type
,
1146 unsigned short instance
)
1148 struct list
*red_list
;
1149 struct listnode
*node
;
1150 struct ospf6_redist
*red
;
1152 red_list
= ospf6
->redist
[type
];
1156 for (ALL_LIST_ELEMENTS_RO(red_list
, node
, red
))
1157 if (red
->instance
== instance
)
1163 static struct ospf6_redist
*ospf6_redist_add(struct ospf6
*ospf6
, int type
,
1166 struct ospf6_redist
*red
;
1168 red
= ospf6_redist_lookup(ospf6
, type
, instance
);
1172 if (!ospf6
->redist
[type
])
1173 ospf6
->redist
[type
] = list_new();
1175 red
= XCALLOC(MTYPE_OSPF6_REDISTRIBUTE
, sizeof(struct ospf6_redist
));
1176 red
->instance
= instance
;
1177 red
->dmetric
.type
= -1;
1178 red
->dmetric
.value
= -1;
1179 ROUTEMAP_NAME(red
) = NULL
;
1180 ROUTEMAP(red
) = NULL
;
1182 listnode_add(ospf6
->redist
[type
], red
);
1183 ospf6
->redistribute
++;
1188 static void ospf6_redist_del(struct ospf6
*ospf6
, struct ospf6_redist
*red
,
1192 listnode_delete(ospf6
->redist
[type
], red
);
1193 if (!ospf6
->redist
[type
]->count
) {
1194 list_delete(&ospf6
->redist
[type
]);
1196 XFREE(MTYPE_OSPF6_REDISTRIBUTE
, red
);
1197 ospf6
->redistribute
--;
1201 /*Set the status of the ospf instance to ASBR based on the status parameter,
1202 * rechedule SPF calculation, originate router LSA*/
1203 void ospf6_asbr_status_update(struct ospf6
*ospf6
, int status
)
1205 struct listnode
*lnode
, *lnnode
;
1206 struct ospf6_area
*oa
;
1208 zlog_info("ASBR[%s:Status:%d]: Update", ospf6
->name
, status
);
1211 if (IS_OSPF6_ASBR(ospf6
)) {
1212 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
1213 ospf6
->name
, status
);
1216 SET_FLAG(ospf6
->flag
, OSPF6_FLAG_ASBR
);
1218 if (!IS_OSPF6_ASBR(ospf6
)) {
1219 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
1220 ospf6
->name
, status
);
1223 UNSET_FLAG(ospf6
->flag
, OSPF6_FLAG_ASBR
);
1226 /* Transition from/to status ASBR, schedule timer. */
1227 ospf6_spf_schedule(ospf6
, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE
);
1229 /* Reoriginate router LSA for all areas */
1230 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1231 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1234 static void ospf6_asbr_redistribute_set(struct ospf6
*ospf6
, int type
)
1236 ospf6_zebra_redistribute(type
, ospf6
->vrf_id
);
1238 ospf6_asbr_status_update(ospf6
, ++ospf6
->redist_count
);
1241 static void ospf6_asbr_redistribute_unset(struct ospf6
*ospf6
,
1242 struct ospf6_redist
*red
, int type
)
1244 struct ospf6_route
*route
;
1245 struct ospf6_external_info
*info
;
1247 ospf6_zebra_no_redistribute(type
, ospf6
->vrf_id
);
1249 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1250 route
= ospf6_route_next(route
)) {
1251 info
= route
->route_option
;
1252 if (info
->type
!= type
)
1255 ospf6_asbr_redistribute_remove(info
->type
, 0, &route
->prefix
,
1259 ospf6_asbr_routemap_unset(red
);
1260 ospf6_asbr_status_update(ospf6
, --ospf6
->redist_count
);
1263 /* When an area is unstubified, flood all the external LSAs in the area */
1264 void ospf6_asbr_send_externals_to_area(struct ospf6_area
*oa
)
1266 struct ospf6_lsa
*lsa
, *lsanext
;
1268 for (ALL_LSDB(oa
->ospf6
->lsdb
, lsa
, lsanext
)) {
1269 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
) {
1270 if (IS_OSPF6_DEBUG_ASBR
)
1271 zlog_debug("%s: Flooding AS-External LSA %s",
1272 __func__
, lsa
->name
);
1274 ospf6_flood_area(NULL
, lsa
, oa
);
1279 /* When an area is stubified, remove all the external LSAs in the area */
1280 void ospf6_asbr_remove_externals_from_area(struct ospf6_area
*oa
)
1282 struct ospf6_lsa
*lsa
, *lsanext
;
1283 struct listnode
*node
, *nnode
;
1284 struct ospf6_area
*area
;
1285 struct ospf6
*ospf6
= oa
->ospf6
;
1286 const struct route_node
*iterend
;
1288 /* skip if router is in other non-stub areas */
1289 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, area
))
1290 if (!IS_AREA_STUB(area
))
1293 /* if router is only in a stub area then purge AS-External LSAs */
1294 iterend
= ospf6_lsdb_head(ospf6
->lsdb
, 0, 0, 0, &lsa
);
1295 while (lsa
!= NULL
) {
1296 assert(lsa
->lock
> 1);
1297 lsanext
= ospf6_lsdb_next(iterend
, lsa
);
1298 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
)
1299 ospf6_lsdb_remove(lsa
, ospf6
->lsdb
);
1304 void ospf6_asbr_redistribute_add(int type
, ifindex_t ifindex
,
1305 struct prefix
*prefix
,
1306 unsigned int nexthop_num
,
1307 struct in6_addr
*nexthop
, route_tag_t tag
,
1308 struct ospf6
*ospf6
)
1310 route_map_result_t ret
;
1311 struct listnode
*lnode
;
1312 struct ospf6_area
*oa
;
1313 struct ospf6_route troute
;
1314 struct ospf6_external_info tinfo
;
1315 struct ospf6_route
*route
, *match
;
1316 struct ospf6_external_info
*info
;
1317 struct prefix prefix_id
;
1318 struct route_node
*node
;
1320 struct ospf6_redist
*red
;
1322 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1327 if ((type
!= DEFAULT_ROUTE
)
1328 && !ospf6_zebra_is_redistribute(type
, ospf6
->vrf_id
))
1331 memset(&troute
, 0, sizeof(troute
));
1332 memset(&tinfo
, 0, sizeof(tinfo
));
1334 if (IS_OSPF6_DEBUG_ASBR
)
1335 zlog_debug("Redistribute %pFX (%s)", prefix
, ZROUTE_NAME(type
));
1337 /* if route-map was specified but not found, do not advertise */
1338 if (ROUTEMAP_NAME(red
)) {
1339 if (ROUTEMAP(red
) == NULL
)
1340 ospf6_asbr_routemap_update(NULL
);
1341 if (ROUTEMAP(red
) == NULL
) {
1343 "route-map \"%s\" not found, suppress redistributing",
1344 ROUTEMAP_NAME(red
));
1349 /* apply route-map */
1350 if (ROUTEMAP(red
)) {
1351 troute
.route_option
= &tinfo
;
1352 tinfo
.ifindex
= ifindex
;
1355 ret
= route_map_apply(ROUTEMAP(red
), prefix
, &troute
);
1356 if (ret
== RMAP_DENYMATCH
) {
1357 if (IS_OSPF6_DEBUG_ASBR
)
1358 zlog_debug("Denied by route-map \"%s\"",
1359 ROUTEMAP_NAME(red
));
1360 ospf6_asbr_redistribute_remove(type
, ifindex
, prefix
,
1366 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1368 info
= match
->route_option
;
1369 /* copy result of route-map */
1370 if (ROUTEMAP(red
)) {
1371 if (troute
.path
.metric_type
)
1372 match
->path
.metric_type
=
1373 troute
.path
.metric_type
;
1375 match
->path
.metric_type
=
1376 metric_type(ospf6
, type
, 0);
1377 if (troute
.path
.cost
)
1378 match
->path
.cost
= troute
.path
.cost
;
1380 match
->path
.cost
= metric_value(ospf6
, type
, 0);
1381 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1382 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1383 sizeof(struct in6_addr
));
1384 info
->tag
= tinfo
.tag
;
1386 /* If there is no route-map, simply update the tag and
1389 match
->path
.metric_type
= metric_type(ospf6
, type
, 0);
1390 match
->path
.cost
= metric_value(ospf6
, type
, 0);
1396 if (nexthop_num
&& nexthop
)
1397 ospf6_route_add_nexthop(match
, ifindex
, nexthop
);
1399 ospf6_route_add_nexthop(match
, ifindex
, NULL
);
1401 /* create/update binding in external_id_table */
1402 prefix_id
.family
= AF_INET
;
1403 prefix_id
.prefixlen
= 32;
1404 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1405 node
= route_node_get(ospf6
->external_id_table
, &prefix_id
);
1408 if (IS_OSPF6_DEBUG_ASBR
) {
1409 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
,
1412 "Advertise as AS-External Id:%s prefix %pFX metric %u",
1413 ibuf
, prefix
, match
->path
.metric_type
);
1416 match
->path
.origin
.id
= htonl(info
->id
);
1417 ospf6_as_external_lsa_originate(match
, ospf6
);
1418 ospf6_asbr_status_update(ospf6
, ospf6
->redistribute
);
1419 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, lnode
, oa
)) {
1420 if (IS_AREA_NSSA(oa
))
1421 ospf6_nssa_lsa_originate(match
, oa
);
1427 /* create new entry */
1428 route
= ospf6_route_create();
1429 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
1430 prefix_copy(&route
->prefix
, prefix
);
1432 info
= (struct ospf6_external_info
*)XCALLOC(
1433 MTYPE_OSPF6_EXTERNAL_INFO
, sizeof(struct ospf6_external_info
));
1434 route
->route_option
= info
;
1435 info
->id
= ospf6
->external_id
++;
1437 /* copy result of route-map */
1438 if (ROUTEMAP(red
)) {
1439 if (troute
.path
.metric_type
)
1440 route
->path
.metric_type
= troute
.path
.metric_type
;
1442 route
->path
.metric_type
= metric_type(ospf6
, type
, 0);
1443 if (troute
.path
.cost
)
1444 route
->path
.cost
= troute
.path
.cost
;
1446 route
->path
.cost
= metric_value(ospf6
, type
, 0);
1447 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1448 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1449 sizeof(struct in6_addr
));
1450 info
->tag
= tinfo
.tag
;
1452 /* If there is no route-map, simply update the tag and metric
1455 route
->path
.metric_type
= metric_type(ospf6
, type
, 0);
1456 route
->path
.cost
= metric_value(ospf6
, type
, 0);
1461 if (nexthop_num
&& nexthop
)
1462 ospf6_route_add_nexthop(route
, ifindex
, nexthop
);
1464 ospf6_route_add_nexthop(route
, ifindex
, NULL
);
1466 /* create/update binding in external_id_table */
1467 prefix_id
.family
= AF_INET
;
1468 prefix_id
.prefixlen
= 32;
1469 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1470 node
= route_node_get(ospf6
->external_id_table
, &prefix_id
);
1473 route
= ospf6_route_add(route
, ospf6
->external_table
);
1474 route
->route_option
= info
;
1476 if (IS_OSPF6_DEBUG_ASBR
) {
1477 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
, sizeof(ibuf
));
1479 "Advertise as AS-External Id:%s prefix %pFX metric %u",
1480 ibuf
, prefix
, route
->path
.metric_type
);
1483 route
->path
.origin
.id
= htonl(info
->id
);
1484 ospf6_as_external_lsa_originate(route
, ospf6
);
1485 ospf6_asbr_status_update(ospf6
, ospf6
->redistribute
);
1486 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, lnode
, oa
)) {
1487 if (IS_AREA_NSSA(oa
))
1488 ospf6_nssa_lsa_originate(route
, oa
);
1492 void ospf6_asbr_redistribute_remove(int type
, ifindex_t ifindex
,
1493 struct prefix
*prefix
, struct ospf6
*ospf6
)
1495 struct ospf6_area
*oa
;
1496 struct ospf6_route
*match
;
1497 struct ospf6_external_info
*info
= NULL
;
1498 struct listnode
*lnode
;
1499 struct route_node
*node
;
1500 struct ospf6_lsa
*lsa
;
1501 struct prefix prefix_id
;
1504 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1505 if (match
== NULL
) {
1506 if (IS_OSPF6_DEBUG_ASBR
)
1507 zlog_debug("No such route %pFX to withdraw", prefix
);
1511 info
= match
->route_option
;
1514 if (info
->type
!= type
) {
1515 if (IS_OSPF6_DEBUG_ASBR
)
1516 zlog_debug("Original protocol mismatch: %pFX", prefix
);
1520 if (IS_OSPF6_DEBUG_ASBR
) {
1521 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
, sizeof(ibuf
));
1522 zlog_debug("Withdraw %pFX (AS-External Id:%s)", prefix
, ibuf
);
1525 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
1526 htonl(info
->id
), ospf6
->router_id
, ospf6
->lsdb
);
1528 if (IS_OSPF6_DEBUG_ASBR
) {
1529 zlog_debug("withdraw type 5 LSA for route %pFX",
1532 ospf6_lsa_purge(lsa
);
1535 /* Delete the NSSA LSA */
1536 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, lnode
, oa
)) {
1537 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7
),
1538 htonl(info
->id
), ospf6
->router_id
,
1541 if (IS_OSPF6_DEBUG_ASBR
) {
1542 zlog_debug("withdraw type 7 LSA for route %pFX",
1545 ospf6_lsa_purge(lsa
);
1549 /* remove binding in external_id_table */
1550 prefix_id
.family
= AF_INET
;
1551 prefix_id
.prefixlen
= 32;
1552 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1553 node
= route_node_lookup(ospf6
->external_id_table
, &prefix_id
);
1556 route_unlock_node(node
); /* to free the lookup lock */
1557 route_unlock_node(node
); /* to free the original lock */
1559 ospf6_route_remove(match
, ospf6
->external_table
);
1560 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
, info
);
1562 ospf6_asbr_status_update(ospf6
, ospf6
->redistribute
);
1565 DEFUN (ospf6_redistribute
,
1566 ospf6_redistribute_cmd
,
1567 "redistribute " FRR_REDIST_STR_OSPF6D
,
1569 FRR_REDIST_HELP_STR_OSPF6D
)
1572 struct ospf6_redist
*red
;
1574 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1576 char *proto
= argv
[argc
- 1]->text
;
1577 type
= proto_redistnum(AFI_IP6
, proto
);
1579 return CMD_WARNING_CONFIG_FAILED
;
1581 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1583 ospf6_redist_add(ospf6
, type
, 0);
1585 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1587 ospf6_asbr_redistribute_set(ospf6
, type
);
1592 DEFUN (ospf6_redistribute_routemap
,
1593 ospf6_redistribute_routemap_cmd
,
1594 "redistribute " FRR_REDIST_STR_OSPF6D
" route-map WORD",
1596 FRR_REDIST_HELP_STR_OSPF6D
1597 "Route map reference\n"
1600 int idx_protocol
= 1;
1603 struct ospf6_redist
*red
;
1605 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1607 char *proto
= argv
[idx_protocol
]->text
;
1608 type
= proto_redistnum(AFI_IP6
, proto
);
1610 return CMD_WARNING_CONFIG_FAILED
;
1612 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1614 red
= ospf6_redist_add(ospf6
, type
, 0);
1616 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1618 ospf6_asbr_routemap_set(red
, argv
[idx_word
]->arg
);
1619 ospf6_asbr_redistribute_set(ospf6
, type
);
1624 DEFUN (no_ospf6_redistribute
,
1625 no_ospf6_redistribute_cmd
,
1626 "no redistribute " FRR_REDIST_STR_OSPF6D
" [route-map WORD]",
1629 FRR_REDIST_HELP_STR_OSPF6D
1630 "Route map reference\n"
1633 int idx_protocol
= 2;
1635 struct ospf6_redist
*red
;
1637 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1639 char *proto
= argv
[idx_protocol
]->text
;
1640 type
= proto_redistnum(AFI_IP6
, proto
);
1642 return CMD_WARNING_CONFIG_FAILED
;
1644 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1648 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1649 ospf6_redist_del(ospf6
, red
, type
);
1654 int ospf6_redistribute_config_write(struct vty
*vty
, struct ospf6
*ospf6
)
1657 struct ospf6_redist
*red
;
1659 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1660 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1663 if (type
== ZEBRA_ROUTE_OSPF6
)
1666 if (ROUTEMAP_NAME(red
))
1667 vty_out(vty
, " redistribute %s route-map %s\n",
1668 ZROUTE_NAME(type
), ROUTEMAP_NAME(red
));
1670 vty_out(vty
, " redistribute %s\n", ZROUTE_NAME(type
));
1676 static void ospf6_redistribute_show_config(struct vty
*vty
, struct ospf6
*ospf6
,
1677 json_object
*json_array
,
1678 json_object
*json
, bool use_json
)
1681 int nroute
[ZEBRA_ROUTE_MAX
];
1683 struct ospf6_route
*route
;
1684 struct ospf6_external_info
*info
;
1685 json_object
*json_route
;
1686 struct ospf6_redist
*red
;
1689 memset(nroute
, 0, sizeof(nroute
));
1690 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1691 route
= ospf6_route_next(route
)) {
1692 info
= route
->route_option
;
1693 nroute
[info
->type
]++;
1698 vty_out(vty
, "Redistributing External Routes from:\n");
1700 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1702 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1706 if (type
== ZEBRA_ROUTE_OSPF6
)
1710 json_route
= json_object_new_object();
1711 json_object_string_add(json_route
, "routeType",
1713 json_object_int_add(json_route
, "numberOfRoutes",
1715 json_object_boolean_add(json_route
,
1716 "routeMapNamePresent",
1717 ROUTEMAP_NAME(red
));
1720 if (ROUTEMAP_NAME(red
)) {
1722 json_object_string_add(json_route
,
1724 ROUTEMAP_NAME(red
));
1725 json_object_boolean_add(json_route
,
1730 " %d: %s with route-map \"%s\"%s\n",
1731 nroute
[type
], ZROUTE_NAME(type
),
1734 : " (not found !)"));
1737 vty_out(vty
, " %d: %s\n", nroute
[type
],
1742 json_object_array_add(json_array
, json_route
);
1745 json_object_object_add(json
, "redistributedRoutes", json_array
);
1746 json_object_int_add(json
, "totalRoutes", total
);
1748 vty_out(vty
, "Total %d routes\n", total
);
1751 static void ospf6_redistribute_default_set(struct ospf6
*ospf6
, int originate
)
1753 struct prefix_ipv6 p
= {};
1754 struct in6_addr nexthop
= {};
1755 int cur_originate
= ospf6
->default_originate
;
1757 p
.family
= AF_INET6
;
1760 ospf6
->default_originate
= originate
;
1762 switch (cur_originate
) {
1763 case DEFAULT_ORIGINATE_NONE
:
1765 case DEFAULT_ORIGINATE_ZEBRA
:
1766 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE
,
1767 zclient
, AFI_IP6
, ospf6
->vrf_id
);
1768 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE
, 0,
1769 (struct prefix
*)&p
, ospf6
);
1772 case DEFAULT_ORIGINATE_ALWAYS
:
1773 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE
, 0,
1774 (struct prefix
*)&p
, ospf6
);
1778 switch (originate
) {
1779 case DEFAULT_ORIGINATE_NONE
:
1781 case DEFAULT_ORIGINATE_ZEBRA
:
1782 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD
,
1783 zclient
, AFI_IP6
, ospf6
->vrf_id
);
1786 case DEFAULT_ORIGINATE_ALWAYS
:
1787 ospf6_asbr_redistribute_add(DEFAULT_ROUTE
, 0,
1788 (struct prefix
*)&p
, 0, &nexthop
, 0,
1794 /* Default Route originate. */
1795 DEFPY (ospf6_default_route_originate
,
1796 ospf6_default_route_originate_cmd
,
1797 "default-information originate [{always$always|metric (0-16777214)$mval|metric-type (1-2)$mtype|route-map WORD$rtmap}]",
1798 "Control distribution of default route\n"
1799 "Distribute a default route\n"
1800 "Always advertise default route\n"
1801 "OSPFv3 default metric\n"
1803 "OSPFv3 metric type for default routes\n"
1804 "Set OSPFv3 External Type 1/2 metrics\n"
1805 "Route map reference\n"
1806 "Pointer to route-map entries\n")
1808 int default_originate
= DEFAULT_ORIGINATE_ZEBRA
;
1809 struct ospf6_redist
*red
;
1810 bool sameRtmap
= false;
1812 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1814 int cur_originate
= ospf6
->default_originate
;
1816 red
= ospf6_redist_add(ospf6
, DEFAULT_ROUTE
, 0);
1819 default_originate
= DEFAULT_ORIGINATE_ALWAYS
;
1821 if (mval_str
== NULL
)
1824 if (mtype_str
== NULL
)
1827 /* To check ,if user is providing same route map */
1828 if ((rtmap
== ROUTEMAP_NAME(red
))
1829 || (rtmap
&& ROUTEMAP_NAME(red
)
1830 && (strcmp(rtmap
, ROUTEMAP_NAME(red
)) == 0)))
1833 /* Don't allow if the same lsa is aleardy originated. */
1834 if ((sameRtmap
) && (red
->dmetric
.type
== mtype
)
1835 && (red
->dmetric
.value
== mval
)
1836 && (cur_originate
== default_originate
))
1839 /* Updating Metric details */
1840 red
->dmetric
.type
= mtype
;
1841 red
->dmetric
.value
= mval
;
1843 /* updating route map details */
1845 ospf6_asbr_routemap_set(red
, rtmap
);
1847 ospf6_asbr_routemap_unset(red
);
1849 ospf6_redistribute_default_set(ospf6
, default_originate
);
1853 DEFPY (no_ospf6_default_information_originate
,
1854 no_ospf6_default_information_originate_cmd
,
1855 "no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
1857 "Control distribution of default information\n"
1858 "Distribute a default route\n"
1859 "Always advertise default route\n"
1860 "OSPFv3 default metric\n"
1862 "OSPFv3 metric type for default routes\n"
1863 "Set OSPFv3 External Type 1/2 metrics\n"
1864 "Route map reference\n"
1865 "Pointer to route-map entries\n")
1867 struct ospf6_redist
*red
;
1869 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1871 red
= ospf6_redist_lookup(ospf6
, DEFAULT_ROUTE
, 0);
1875 ospf6_asbr_routemap_unset(red
);
1876 ospf6_redist_del(ospf6
, red
, DEFAULT_ROUTE
);
1878 ospf6_redistribute_default_set(ospf6
, DEFAULT_ORIGINATE_NONE
);
1882 /* Routemap Functions */
1883 static enum route_map_cmd_result_t
1884 ospf6_routemap_rule_match_address_prefixlist(void *rule
,
1885 const struct prefix
*prefix
,
1889 struct prefix_list
*plist
;
1891 plist
= prefix_list_lookup(AFI_IP6
, (char *)rule
);
1893 return RMAP_NOMATCH
;
1895 return (prefix_list_apply(plist
, prefix
) == PREFIX_DENY
? RMAP_NOMATCH
1900 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg
)
1902 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1905 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule
)
1907 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1910 static const struct route_map_rule_cmd
1911 ospf6_routemap_rule_match_address_prefixlist_cmd
= {
1912 "ipv6 address prefix-list",
1913 ospf6_routemap_rule_match_address_prefixlist
,
1914 ospf6_routemap_rule_match_address_prefixlist_compile
,
1915 ospf6_routemap_rule_match_address_prefixlist_free
,
1918 /* `match interface IFNAME' */
1919 /* Match function should return 1 if match is success else return
1921 static enum route_map_cmd_result_t
1922 ospf6_routemap_rule_match_interface(void *rule
, const struct prefix
*prefix
,
1925 struct interface
*ifp
;
1926 struct ospf6_external_info
*ei
;
1928 ei
= ((struct ospf6_route
*)object
)->route_option
;
1929 ifp
= if_lookup_by_name_all_vrf((char *)rule
);
1931 if (ifp
!= NULL
&& ei
->ifindex
== ifp
->ifindex
)
1934 return RMAP_NOMATCH
;
1937 /* Route map `interface' match statement. `arg' should be
1939 static void *ospf6_routemap_rule_match_interface_compile(const char *arg
)
1941 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1944 /* Free route map's compiled `interface' value. */
1945 static void ospf6_routemap_rule_match_interface_free(void *rule
)
1947 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1950 /* Route map commands for interface matching. */
1951 static const struct route_map_rule_cmd
1952 ospf6_routemap_rule_match_interface_cmd
= {
1954 ospf6_routemap_rule_match_interface
,
1955 ospf6_routemap_rule_match_interface_compile
,
1956 ospf6_routemap_rule_match_interface_free
1959 /* Match function for matching route tags */
1960 static enum route_map_cmd_result_t
1961 ospf6_routemap_rule_match_tag(void *rule
, const struct prefix
*p
, void *object
)
1963 route_tag_t
*tag
= rule
;
1964 struct ospf6_route
*route
= object
;
1965 struct ospf6_external_info
*info
= route
->route_option
;
1967 if (info
->tag
== *tag
)
1970 return RMAP_NOMATCH
;
1973 static const struct route_map_rule_cmd
1974 ospf6_routemap_rule_match_tag_cmd
= {
1976 ospf6_routemap_rule_match_tag
,
1977 route_map_rule_tag_compile
,
1978 route_map_rule_tag_free
,
1981 static enum route_map_cmd_result_t
1982 ospf6_routemap_rule_set_metric_type(void *rule
, const struct prefix
*prefix
,
1985 char *metric_type
= rule
;
1986 struct ospf6_route
*route
= object
;
1988 if (strcmp(metric_type
, "type-2") == 0)
1989 route
->path
.metric_type
= 2;
1991 route
->path
.metric_type
= 1;
1996 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg
)
1998 if (strcmp(arg
, "type-2") && strcmp(arg
, "type-1"))
2000 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2003 static void ospf6_routemap_rule_set_metric_type_free(void *rule
)
2005 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2008 static const struct route_map_rule_cmd
2009 ospf6_routemap_rule_set_metric_type_cmd
= {
2011 ospf6_routemap_rule_set_metric_type
,
2012 ospf6_routemap_rule_set_metric_type_compile
,
2013 ospf6_routemap_rule_set_metric_type_free
,
2016 static enum route_map_cmd_result_t
2017 ospf6_routemap_rule_set_metric(void *rule
, const struct prefix
*prefix
,
2020 char *metric
= rule
;
2021 struct ospf6_route
*route
= object
;
2023 route
->path
.cost
= atoi(metric
);
2027 static void *ospf6_routemap_rule_set_metric_compile(const char *arg
)
2031 metric
= strtoul(arg
, &endp
, 0);
2032 if (metric
> OSPF_LS_INFINITY
|| *endp
!= '\0')
2034 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2037 static void ospf6_routemap_rule_set_metric_free(void *rule
)
2039 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2042 static const struct route_map_rule_cmd
2043 ospf6_routemap_rule_set_metric_cmd
= {
2045 ospf6_routemap_rule_set_metric
,
2046 ospf6_routemap_rule_set_metric_compile
,
2047 ospf6_routemap_rule_set_metric_free
,
2050 static enum route_map_cmd_result_t
2051 ospf6_routemap_rule_set_forwarding(void *rule
, const struct prefix
*prefix
,
2054 char *forwarding
= rule
;
2055 struct ospf6_route
*route
= object
;
2056 struct ospf6_external_info
*info
= route
->route_option
;
2058 if (inet_pton(AF_INET6
, forwarding
, &info
->forwarding
) != 1) {
2059 memset(&info
->forwarding
, 0, sizeof(struct in6_addr
));
2066 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg
)
2069 if (inet_pton(AF_INET6
, arg
, &a
) != 1)
2071 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2074 static void ospf6_routemap_rule_set_forwarding_free(void *rule
)
2076 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2079 static const struct route_map_rule_cmd
2080 ospf6_routemap_rule_set_forwarding_cmd
= {
2081 "forwarding-address",
2082 ospf6_routemap_rule_set_forwarding
,
2083 ospf6_routemap_rule_set_forwarding_compile
,
2084 ospf6_routemap_rule_set_forwarding_free
,
2087 static enum route_map_cmd_result_t
2088 ospf6_routemap_rule_set_tag(void *rule
, const struct prefix
*p
, void *object
)
2090 route_tag_t
*tag
= rule
;
2091 struct ospf6_route
*route
= object
;
2092 struct ospf6_external_info
*info
= route
->route_option
;
2098 static const struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd
= {
2100 ospf6_routemap_rule_set_tag
,
2101 route_map_rule_tag_compile
,
2102 route_map_rule_tag_free
,
2105 /* add "set metric-type" */
2106 DEFUN_YANG (ospf6_routemap_set_metric_type
, ospf6_routemap_set_metric_type_cmd
,
2107 "set metric-type <type-1|type-2>",
2110 "OSPF6 external type 1 metric\n"
2111 "OSPF6 external type 2 metric\n")
2113 char *ext
= argv
[2]->text
;
2116 "./set-action[action='frr-ospf-route-map:metric-type']";
2117 char xpath_value
[XPATH_MAXLEN
];
2119 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
2120 snprintf(xpath_value
, sizeof(xpath_value
),
2121 "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath
);
2122 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, ext
);
2123 return nb_cli_apply_changes(vty
, NULL
);
2126 /* delete "set metric-type" */
2127 DEFUN_YANG (ospf6_routemap_no_set_metric_type
, ospf6_routemap_no_set_metric_type_cmd
,
2128 "no set metric-type [<type-1|type-2>]",
2132 "OSPF6 external type 1 metric\n"
2133 "OSPF6 external type 2 metric\n")
2136 "./set-action[action='frr-ospf-route-map:metric-type']";
2138 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
2139 return nb_cli_apply_changes(vty
, NULL
);
2142 /* add "set forwarding-address" */
2143 DEFUN_YANG (ospf6_routemap_set_forwarding
, ospf6_routemap_set_forwarding_cmd
,
2144 "set forwarding-address X:X::X:X",
2146 "Forwarding Address\n"
2151 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2152 char xpath_value
[XPATH_MAXLEN
];
2154 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
2155 snprintf(xpath_value
, sizeof(xpath_value
),
2156 "%s/rmap-set-action/frr-ospf6-route-map:ipv6-address", xpath
);
2157 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
,
2158 argv
[idx_ipv6
]->arg
);
2159 return nb_cli_apply_changes(vty
, NULL
);
2162 /* delete "set forwarding-address" */
2163 DEFUN_YANG (ospf6_routemap_no_set_forwarding
, ospf6_routemap_no_set_forwarding_cmd
,
2164 "no set forwarding-address [X:X::X:X]",
2167 "Forwarding Address\n"
2171 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2173 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
2174 return nb_cli_apply_changes(vty
, NULL
);
2177 static void ospf6_routemap_init(void)
2181 route_map_add_hook(ospf6_asbr_routemap_update
);
2182 route_map_delete_hook(ospf6_asbr_routemap_update
);
2183 route_map_event_hook(ospf6_asbr_routemap_event
);
2185 route_map_set_metric_hook(generic_set_add
);
2186 route_map_no_set_metric_hook(generic_set_delete
);
2188 route_map_set_tag_hook(generic_set_add
);
2189 route_map_no_set_tag_hook(generic_set_delete
);
2191 route_map_match_tag_hook(generic_match_add
);
2192 route_map_no_match_tag_hook(generic_match_delete
);
2194 route_map_match_ipv6_address_prefix_list_hook(generic_match_add
);
2195 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete
);
2197 route_map_match_interface_hook(generic_match_add
);
2198 route_map_no_match_interface_hook(generic_match_delete
);
2200 route_map_install_match(
2201 &ospf6_routemap_rule_match_address_prefixlist_cmd
);
2202 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd
);
2203 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd
);
2205 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd
);
2206 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd
);
2207 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd
);
2208 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd
);
2210 /* ASE Metric Type (e.g. Type-1/Type-2) */
2211 install_element(RMAP_NODE
, &ospf6_routemap_set_metric_type_cmd
);
2212 install_element(RMAP_NODE
, &ospf6_routemap_no_set_metric_type_cmd
);
2215 install_element(RMAP_NODE
, &ospf6_routemap_set_forwarding_cmd
);
2216 install_element(RMAP_NODE
, &ospf6_routemap_no_set_forwarding_cmd
);
2220 /* Display functions */
2221 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
2222 char *buf
, int buflen
,
2225 struct ospf6_as_external_lsa
*external
;
2226 struct in6_addr in6
;
2227 int prefix_length
= 0;
2231 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
2235 ospf6_prefix_in6_addr(&in6
, external
,
2237 prefix_length
= external
->prefix
.prefix_length
;
2239 in6
= *((struct in6_addr
2240 *)((caddr_t
)external
2242 ospf6_as_external_lsa
)
2243 + OSPF6_PREFIX_SPACE(
2248 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
2249 if (prefix_length
) {
2250 snprintf(tbuf
, sizeof(tbuf
), "/%d",
2252 strlcat(buf
, tbuf
, buflen
);
2259 static int ospf6_as_external_lsa_show(struct vty
*vty
, struct ospf6_lsa
*lsa
,
2260 json_object
*json_obj
, bool use_json
)
2262 struct ospf6_as_external_lsa
*external
;
2265 assert(lsa
->header
);
2266 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
2270 snprintf(buf
, sizeof(buf
), "%c%c%c",
2271 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
) ? 'E'
2273 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
) ? 'F'
2275 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
) ? 'T'
2279 json_object_string_add(json_obj
, "bits", buf
);
2280 json_object_int_add(json_obj
, "metric",
2281 (unsigned long)OSPF6_ASBR_METRIC(external
));
2282 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
,
2284 json_object_string_add(json_obj
, "prefixOptions", buf
);
2285 json_object_int_add(
2286 json_obj
, "referenceLsType",
2287 ntohs(external
->prefix
.prefix_refer_lstype
));
2288 json_object_string_add(json_obj
, "prefix",
2289 ospf6_as_external_lsa_get_prefix_str(
2290 lsa
, buf
, sizeof(buf
), 0));
2292 /* Forwarding-Address */
2293 json_object_boolean_add(
2294 json_obj
, "forwardingAddressPresent",
2295 CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
));
2296 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
2297 json_object_string_add(
2298 json_obj
, "forwardingAddress",
2299 ospf6_as_external_lsa_get_prefix_str(
2300 lsa
, buf
, sizeof(buf
), 1));
2303 json_object_boolean_add(
2304 json_obj
, "tagPresent",
2305 CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
));
2306 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
2307 json_object_int_add(json_obj
, "tag",
2308 ospf6_as_external_lsa_get_tag(lsa
));
2310 vty_out(vty
, " Bits: %s\n", buf
);
2311 vty_out(vty
, " Metric: %5lu\n",
2312 (unsigned long)OSPF6_ASBR_METRIC(external
));
2314 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
,
2316 vty_out(vty
, " Prefix Options: %s\n", buf
);
2318 vty_out(vty
, " Referenced LSType: %d\n",
2319 ntohs(external
->prefix
.prefix_refer_lstype
));
2321 vty_out(vty
, " Prefix: %s\n",
2322 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
,
2325 /* Forwarding-Address */
2326 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
2327 vty_out(vty
, " Forwarding-Address: %s\n",
2328 ospf6_as_external_lsa_get_prefix_str(
2329 lsa
, buf
, sizeof(buf
), 1));
2333 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
2334 vty_out(vty
, " Tag: %" ROUTE_TAG_PRI
"\n",
2335 ospf6_as_external_lsa_get_tag(lsa
));
2342 static void ospf6_asbr_external_route_show(struct vty
*vty
,
2343 struct ospf6_route
*route
,
2344 json_object
*json_array
,
2347 struct ospf6_external_info
*info
= route
->route_option
;
2348 char prefix
[PREFIX2STR_BUFFER
], id
[16], forwarding
[64];
2350 json_object
*json_route
;
2353 prefix2str(&route
->prefix
, prefix
, sizeof(prefix
));
2354 tmp_id
= ntohl(info
->id
);
2355 inet_ntop(AF_INET
, &tmp_id
, id
, sizeof(id
));
2356 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
2357 inet_ntop(AF_INET6
, &info
->forwarding
, forwarding
,
2358 sizeof(forwarding
));
2360 snprintf(forwarding
, sizeof(forwarding
), ":: (ifindex %d)",
2361 ospf6_route_get_first_nh_index(route
));
2364 json_route
= json_object_new_object();
2365 snprintf(route_type
, sizeof(route_type
), "%c",
2366 zebra_route_char(info
->type
));
2367 json_object_string_add(json_route
, "routeType", route_type
);
2368 json_object_string_add(json_route
, "destination", prefix
);
2369 json_object_string_add(json_route
, "id", id
);
2370 json_object_int_add(json_route
, "metricType",
2371 route
->path
.metric_type
);
2372 json_object_int_add(
2373 json_route
, "routeCost",
2374 (unsigned long)(route
->path
.metric_type
== 2
2375 ? route
->path
.u
.cost_e2
2376 : route
->path
.cost
));
2377 json_object_string_add(json_route
, "forwarding", forwarding
);
2379 json_object_array_add(json_array
, json_route
);
2382 vty_out(vty
, "%c %-32pFX %-15s type-%d %5lu %s\n",
2383 zebra_route_char(info
->type
), &route
->prefix
, id
,
2384 route
->path
.metric_type
,
2385 (unsigned long)(route
->path
.metric_type
== 2
2386 ? route
->path
.u
.cost_e2
2387 : route
->path
.cost
),
2391 DEFUN(show_ipv6_ospf6_redistribute
, show_ipv6_ospf6_redistribute_cmd
,
2392 "show ipv6 ospf6 [vrf <NAME|all>] redistribute [json]",
2393 SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
2395 "redistributing External information\n" JSON_STR
)
2397 struct ospf6_route
*route
;
2398 struct ospf6
*ospf6
= NULL
;
2399 json_object
*json
= NULL
;
2400 bool uj
= use_json(argc
, argv
);
2401 struct listnode
*node
;
2402 const char *vrf_name
= NULL
;
2403 bool all_vrf
= false;
2406 json_object
*json_array_routes
= NULL
;
2407 json_object
*json_array_redistribute
= NULL
;
2409 OSPF6_CMD_CHECK_RUNNING();
2410 OSPF6_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
2413 json
= json_object_new_object();
2414 json_array_routes
= json_object_new_array();
2415 json_array_redistribute
= json_object_new_array();
2418 for (ALL_LIST_ELEMENTS_RO(om6
->ospf6
, node
, ospf6
)) {
2420 || ((ospf6
->name
== NULL
&& vrf_name
== NULL
)
2421 || (ospf6
->name
&& vrf_name
2422 && strcmp(ospf6
->name
, vrf_name
) == 0))) {
2423 ospf6_redistribute_show_config(
2424 vty
, ospf6
, json_array_redistribute
, json
, uj
);
2426 for (route
= ospf6_route_head(ospf6
->external_table
);
2427 route
; route
= ospf6_route_next(route
)) {
2428 ospf6_asbr_external_route_show(
2429 vty
, route
, json_array_routes
, uj
);
2433 json_object_object_add(json
, "routes",
2435 vty_out(vty
, "%s\n",
2436 json_object_to_json_string_ext(
2437 json
, JSON_C_TO_STRING_PRETTY
));
2438 json_object_free(json
);
2449 static struct ospf6_lsa_handler as_external_handler
= {
2450 .lh_type
= OSPF6_LSTYPE_AS_EXTERNAL
,
2451 .lh_name
= "AS-External",
2452 .lh_short_name
= "ASE",
2453 .lh_show
= ospf6_as_external_lsa_show
,
2454 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
2457 static struct ospf6_lsa_handler nssa_external_handler
= {
2458 .lh_type
= OSPF6_LSTYPE_TYPE_7
,
2460 .lh_short_name
= "Type7",
2461 .lh_show
= ospf6_as_external_lsa_show
,
2462 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
2465 void ospf6_asbr_init(void)
2467 ospf6_routemap_init();
2469 ospf6_install_lsa_handler(&as_external_handler
);
2470 ospf6_install_lsa_handler(&nssa_external_handler
);
2472 install_element(VIEW_NODE
, &show_ipv6_ospf6_redistribute_cmd
);
2474 install_element(OSPF6_NODE
, &ospf6_default_route_originate_cmd
);
2475 install_element(OSPF6_NODE
,
2476 &no_ospf6_default_information_originate_cmd
);
2477 install_element(OSPF6_NODE
, &ospf6_redistribute_cmd
);
2478 install_element(OSPF6_NODE
, &ospf6_redistribute_routemap_cmd
);
2479 install_element(OSPF6_NODE
, &no_ospf6_redistribute_cmd
);
2482 void ospf6_asbr_redistribute_disable(struct ospf6
*ospf6
)
2485 struct ospf6_redist
*red
;
2487 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
2488 red
= ospf6_redist_lookup(ospf6
, type
, 0);
2491 if (type
== ZEBRA_ROUTE_OSPF6
)
2493 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
2494 ospf6_redist_del(ospf6
, red
, type
);
2496 red
= ospf6_redist_lookup(ospf6
, DEFAULT_ROUTE
, 0);
2498 ospf6_asbr_routemap_unset(red
);
2499 ospf6_redist_del(ospf6
, red
, type
);
2500 ospf6_redistribute_default_set(ospf6
, DEFAULT_ORIGINATE_NONE
);
2504 void ospf6_asbr_redistribute_reset(struct ospf6
*ospf6
)
2507 struct ospf6_redist
*red
;
2508 char buf
[RMAP_NAME_MAXLEN
];
2510 for (type
= 0; type
<= ZEBRA_ROUTE_MAX
; type
++) {
2512 if (type
== ZEBRA_ROUTE_OSPF6
)
2514 red
= ospf6_redist_lookup(ospf6
, type
, 0);
2518 if (type
== DEFAULT_ROUTE
) {
2519 ospf6_redistribute_default_set(
2520 ospf6
, ospf6
->default_originate
);
2523 if (ROUTEMAP_NAME(red
))
2524 strlcpy(buf
, ROUTEMAP_NAME(red
), sizeof(buf
));
2526 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
2528 ospf6_asbr_routemap_set(red
, buf
);
2529 ospf6_asbr_redistribute_set(ospf6
, type
);
2533 void ospf6_asbr_terminate(void)
2535 /* Cleanup route maps */
2539 DEFUN (debug_ospf6_asbr
,
2540 debug_ospf6_asbr_cmd
,
2544 "Debug OSPFv3 ASBR function\n"
2547 OSPF6_DEBUG_ASBR_ON();
2551 DEFUN (no_debug_ospf6_asbr
,
2552 no_debug_ospf6_asbr_cmd
,
2553 "no debug ospf6 asbr",
2557 "Debug OSPFv3 ASBR function\n"
2560 OSPF6_DEBUG_ASBR_OFF();
2564 int config_write_ospf6_debug_asbr(struct vty
*vty
)
2566 if (IS_OSPF6_DEBUG_ASBR
)
2567 vty_out(vty
, "debug ospf6 asbr\n");
2571 int ospf6_distribute_config_write(struct vty
*vty
, struct ospf6
*ospf6
)
2573 struct ospf6_redist
*red
;
2576 /* default-route print. */
2577 if (ospf6
->default_originate
!= DEFAULT_ORIGINATE_NONE
) {
2578 vty_out(vty
, " default-information originate");
2579 if (ospf6
->default_originate
2580 == DEFAULT_ORIGINATE_ALWAYS
)
2581 vty_out(vty
, " always");
2583 red
= ospf6_redist_lookup(ospf6
, DEFAULT_ROUTE
, 0);
2585 if (red
->dmetric
.value
>= 0)
2586 vty_out(vty
, " metric %d",
2587 red
->dmetric
.value
);
2589 if (red
->dmetric
.type
>= 0)
2590 vty_out(vty
, " metric-type %d",
2593 if (ROUTEMAP_NAME(red
))
2594 vty_out(vty
, " route-map %s",
2595 ROUTEMAP_NAME(red
));
2604 void install_element_ospf6_debug_asbr(void)
2606 install_element(ENABLE_NODE
, &debug_ospf6_asbr_cmd
);
2607 install_element(ENABLE_NODE
, &no_debug_ospf6_asbr_cmd
);
2608 install_element(CONFIG_NODE
, &debug_ospf6_asbr_cmd
);
2609 install_element(CONFIG_NODE
, &no_debug_ospf6_asbr_cmd
);