1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2003 Yasuhiro Ohara
18 #include "lib/northbound_cli.h"
20 #include "ospf6_proto.h"
21 #include "ospf6_lsa.h"
22 #include "ospf6_lsdb.h"
23 #include "ospf6_route.h"
24 #include "ospf6_zebra.h"
25 #include "ospf6_message.h"
26 #include "ospf6_spf.h"
28 #include "ospf6_top.h"
30 #include "ospf6_area.h"
31 #include "ospf6_interface.h"
32 #include "ospf6_neighbor.h"
33 #include "ospf6_asbr.h"
34 #include "ospf6_abr.h"
35 #include "ospf6_intra.h"
36 #include "ospf6_flood.h"
37 #include "ospf6_nssa.h"
39 #include "ospf6_spf.h"
40 #include "ospf6_nssa.h"
44 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_EXTERNAL_INFO
, "OSPF6 ext. info");
45 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_DIST_ARGS
, "OSPF6 Distribute arguments");
46 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_REDISTRIBUTE
, "OSPF6 Redistribute arguments");
47 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_EXTERNAL_RT_AGGR
, "OSPF6 ASBR Summarisation");
49 static void ospf6_asbr_redistribute_set(struct ospf6
*ospf6
, int type
);
50 static void ospf6_asbr_redistribute_unset(struct ospf6
*ospf6
,
51 struct ospf6_redist
*red
, int type
);
53 #include "ospf6d/ospf6_asbr_clippy.c"
55 unsigned char conf_debug_ospf6_asbr
= 0;
57 #define ZROUTE_NAME(x) zebra_route_string(x)
59 /* Originate Type-5 and Type-7 LSA */
60 static struct ospf6_lsa
*ospf6_originate_type5_type7_lsas(
61 struct ospf6_route
*route
,
64 struct ospf6_lsa
*lsa
;
65 struct listnode
*lnode
;
66 struct ospf6_area
*oa
= NULL
;
68 lsa
= ospf6_as_external_lsa_originate(route
, ospf6
);
70 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, lnode
, oa
)) {
72 ospf6_nssa_lsa_originate(route
, oa
, true);
78 /* AS External LSA origination */
79 struct ospf6_lsa
*ospf6_as_external_lsa_originate(struct ospf6_route
*route
,
82 char buffer
[OSPF6_MAX_LSASIZE
];
83 struct ospf6_lsa_header
*lsa_header
;
84 struct ospf6_lsa
*lsa
;
85 struct ospf6_external_info
*info
= route
->route_option
;
87 struct ospf6_as_external_lsa
*as_external_lsa
;
90 if (ospf6
->gr_info
.restart_in_progress
) {
91 if (IS_DEBUG_OSPF6_GR
)
93 "Graceful Restart in progress, don't originate LSA");
97 if (IS_OSPF6_DEBUG_ASBR
|| IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL
))
98 zlog_debug("Originate AS-External-LSA for %pFX",
102 memset(buffer
, 0, sizeof(buffer
));
103 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
104 as_external_lsa
= (struct ospf6_as_external_lsa
105 *)((caddr_t
)lsa_header
106 + sizeof(struct ospf6_lsa_header
));
107 p
= (caddr_t
)((caddr_t
)as_external_lsa
108 + sizeof(struct ospf6_as_external_lsa
));
110 /* Fill AS-External-LSA */
112 if (route
->path
.metric_type
== 2)
113 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
115 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
117 /* forwarding address */
118 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
119 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
121 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
123 /* external route tag */
125 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
127 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
130 OSPF6_ASBR_METRIC_SET(as_external_lsa
, route
->path
.cost
);
133 as_external_lsa
->prefix
.prefix_length
= route
->prefix
.prefixlen
;
136 as_external_lsa
->prefix
.prefix_options
= route
->prefix_options
;
138 /* don't use refer LS-type */
139 as_external_lsa
->prefix
.prefix_refer_lstype
= htons(0);
142 memcpy(p
, &route
->prefix
.u
.prefix6
,
143 OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
));
144 ospf6_prefix_apply_mask(&as_external_lsa
->prefix
);
145 p
+= OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
);
147 /* Forwarding address */
148 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
149 memcpy(p
, &info
->forwarding
, sizeof(struct in6_addr
));
150 p
+= sizeof(struct in6_addr
);
153 /* External Route Tag */
154 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
155 route_tag_t network_order
= htonl(info
->tag
);
157 memcpy(p
, &network_order
, sizeof(network_order
));
158 p
+= sizeof(network_order
);
161 /* Fill LSA Header */
163 lsa_header
->type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
164 lsa_header
->id
= route
->path
.origin
.id
;
165 lsa_header
->adv_router
= ospf6
->router_id
;
167 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
168 lsa_header
->adv_router
, ospf6
->lsdb
);
169 lsa_header
->length
= htons((caddr_t
)p
- (caddr_t
)lsa_header
);
172 ospf6_lsa_checksum(lsa_header
);
175 lsa
= ospf6_lsa_create(lsa_header
);
178 ospf6_lsa_originate_process(lsa
, ospf6
);
183 void ospf6_orig_as_external_lsa(struct event
*thread
)
185 struct ospf6_interface
*oi
;
186 struct ospf6_lsa
*lsa
;
187 uint32_t type
, adv_router
;
189 oi
= (struct ospf6_interface
*)EVENT_ARG(thread
);
191 if (oi
->state
== OSPF6_INTERFACE_DOWN
)
193 if (IS_AREA_NSSA(oi
->area
) || IS_AREA_STUB(oi
->area
))
196 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
197 adv_router
= oi
->area
->ospf6
->router_id
;
198 for (ALL_LSDB_TYPED_ADVRTR(oi
->area
->ospf6
->lsdb
, type
, adv_router
,
200 if (IS_OSPF6_DEBUG_ASBR
)
202 "%s: Send update of AS-External LSA %s seq 0x%x",
204 ntohl(lsa
->header
->seqnum
));
206 ospf6_flood_interface(NULL
, lsa
, oi
);
210 static route_tag_t
ospf6_as_external_lsa_get_tag(struct ospf6_lsa
*lsa
)
212 struct ospf6_as_external_lsa
*external
;
213 ptrdiff_t tag_offset
;
214 route_tag_t network_order
;
219 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
222 if (!CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
225 tag_offset
= sizeof(*external
)
226 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
227 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
228 tag_offset
+= sizeof(struct in6_addr
);
230 memcpy(&network_order
, (caddr_t
)external
+ tag_offset
,
231 sizeof(network_order
));
232 return ntohl(network_order
);
235 void ospf6_asbr_update_route_ecmp_path(struct ospf6_route
*old
,
236 struct ospf6_route
*route
,
239 struct ospf6_route
*old_route
, *next_route
;
240 struct ospf6_path
*ecmp_path
, *o_path
= NULL
;
241 struct listnode
*anode
, *anext
;
242 struct listnode
*nnode
, *rnode
, *rnext
;
243 struct ospf6_nexthop
*nh
, *rnh
;
244 bool route_found
= false;
246 /* check for old entry match with new route origin,
249 for (old_route
= old
; old_route
; old_route
= next_route
) {
250 bool route_updated
= false;
252 next_route
= old_route
->next
;
254 /* The route linked-list is grouped in batches of prefix.
255 * If the new prefix is not the same as the one of interest
256 * then we have walked over the end of the batch and so we
257 * should break rather than continuing unnecessarily.
259 if (!ospf6_route_is_same(old_route
, route
))
261 if (old_route
->path
.type
!= route
->path
.type
)
264 /* Current and New route has same origin,
267 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
, anext
,
269 /* Check old route path and route has same
272 if (o_path
->area_id
!= route
->path
.area_id
273 || !ospf6_ls_origin_same(o_path
, &route
->path
))
276 /* Cost is not same then delete current path */
277 if ((o_path
->cost
== route
->path
.cost
)
278 && (o_path
->u
.cost_e2
== route
->path
.u
.cost_e2
))
281 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
283 "%s: route %pFX cost old %u new %u is not same, replace route",
284 __func__
, &old_route
->prefix
, o_path
->cost
,
288 /* Remove selected current rout path's nh from
291 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
292 for (ALL_LIST_ELEMENTS(old_route
->nh_list
,
293 rnode
, rnext
, rnh
)) {
294 if (!ospf6_nexthop_is_same(rnh
, nh
))
296 listnode_delete(old_route
->nh_list
,
298 ospf6_nexthop_delete(rnh
);
302 listnode_delete(old_route
->paths
, o_path
);
303 ospf6_path_free(o_path
);
304 route_updated
= true;
306 /* Current route's path (adv_router info) is similar
307 * to route being added.
308 * Replace current route's path with paths list head.
309 * Update FIB with effective NHs.
311 if (listcount(old_route
->paths
)) {
312 for (ALL_LIST_ELEMENTS(old_route
->paths
,
313 anode
, anext
, o_path
)) {
314 ospf6_merge_nexthops(
318 /* Update RIB/FIB with effective
321 if (ospf6
->route_table
->hook_add
)
322 (*ospf6
->route_table
->hook_add
)(
325 if (old_route
->path
.origin
.id
326 == route
->path
.origin
.id
327 && old_route
->path
.origin
.adv_router
328 == route
->path
.origin
330 struct ospf6_path
*h_path
;
332 h_path
= (struct ospf6_path
*)
333 listgetdata(listhead(
335 old_route
->path
.origin
.type
=
337 old_route
->path
.origin
.id
=
339 old_route
->path
.origin
.adv_router
=
340 h_path
->origin
.adv_router
;
343 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
345 "%s: route %pFX old cost %u new cost %u, delete old entry.",
346 __func__
, &old_route
->prefix
,
347 old_route
->path
.cost
,
350 if (old
== old_route
)
352 ospf6_route_remove(old_route
,
361 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
363 /* The route linked-list is grouped in batches of prefix.
364 * If the new prefix is not the same as the one of interest
365 * then we have walked over the end of the batch and so we
366 * should break rather than continuing unnecessarily.
368 if (!ospf6_route_is_same(old_route
, route
))
370 if (old_route
->path
.type
!= route
->path
.type
)
373 /* Old Route and New Route have Equal Cost, Merge NHs */
374 if ((old_route
->path
.cost
== route
->path
.cost
)
375 && (old_route
->path
.u
.cost_e2
== route
->path
.u
.cost_e2
)) {
377 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
379 "%s: old route %pFX path cost %u e2 %u",
380 __func__
, &old_route
->prefix
,
381 old_route
->path
.cost
,
382 old_route
->path
.u
.cost_e2
);
385 /* check if this path exists already in
386 * route->paths list, if so, replace nh_list
389 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
391 if (o_path
->area_id
== route
->path
.area_id
392 && ospf6_ls_origin_same(o_path
, &route
->path
))
395 /* If path is not found in old_route paths's list,
396 * add a new path to route paths list and merge
397 * nexthops in route->path->nh_list.
398 * Otherwise replace existing path's nh_list.
400 if (o_path
== NULL
) {
401 ecmp_path
= ospf6_path_dup(&route
->path
);
403 /* Add a nh_list to new ecmp path */
404 ospf6_copy_nexthops(ecmp_path
->nh_list
,
407 /* Add the new path to route's path list */
408 listnode_add_sort(old_route
->paths
, ecmp_path
);
410 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
412 "%s: route %pFX another path added with nh %u, effective paths %u nh %u",
413 __func__
, &route
->prefix
,
414 listcount(ecmp_path
->nh_list
),
415 old_route
->paths
? listcount(
418 listcount(old_route
->nh_list
));
421 list_delete_all_node(o_path
->nh_list
);
422 ospf6_copy_nexthops(o_path
->nh_list
,
426 /* Reset nexthop lists, rebuild from brouter table
427 * for each adv. router.
429 list_delete_all_node(old_route
->nh_list
);
431 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
433 struct ospf6_route
*asbr_entry
;
435 asbr_entry
= ospf6_route_lookup(
437 ospf6
->brouter_table
);
438 if (asbr_entry
== NULL
) {
439 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
441 "%s: ls_prfix %pFX asbr_entry not found.",
446 ospf6_route_merge_nexthops(old_route
,
450 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
452 "%s: route %pFX with effective paths %u nh %u",
453 __func__
, &route
->prefix
,
455 ? listcount(old_route
->paths
)
458 ? listcount(old_route
->nh_list
)
462 if (ospf6
->route_table
->hook_add
)
463 (*ospf6
->route_table
->hook_add
)(old_route
);
465 /* Delete the new route its info added to existing
468 ospf6_route_delete(route
);
475 /* Add new route to existing node in ospf6 route table. */
476 ospf6_route_add(route
, ospf6
->route_table
);
480 /* Check if the forwarding address is local address */
481 static int ospf6_ase_forward_address_check(struct ospf6
*ospf6
,
482 struct in6_addr
*fwd_addr
)
484 struct listnode
*anode
, *node
, *cnode
;
485 struct ospf6_interface
*oi
;
486 struct ospf6_area
*oa
;
487 struct interface
*ifp
;
490 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, oa
)) {
491 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, node
, oi
)) {
492 if (!if_is_operative(oi
->interface
)
493 || oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
497 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
498 if (IPV6_ADDR_SAME(&c
->address
->u
.prefix6
,
508 void ospf6_asbr_lsa_add(struct ospf6_lsa
*lsa
)
510 struct ospf6_as_external_lsa
*external
;
511 struct prefix asbr_id
;
512 struct ospf6_route
*asbr_entry
, *route
, *old
= NULL
;
513 struct ospf6_path
*path
;
516 struct ospf6_area
*oa
= NULL
;
517 struct prefix fwd_addr
;
520 type
= ntohs(lsa
->header
->type
);
521 oa
= lsa
->lsdb
->data
;
523 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
526 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
527 zlog_debug("Calculate AS-External route for %s", lsa
->name
);
529 ospf6
= ospf6_get_by_lsdb(lsa
);
531 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
532 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
533 zlog_debug("Ignore self-originated AS-External-LSA");
537 if (OSPF6_ASBR_METRIC(external
) == OSPF_LS_INFINITY
) {
538 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
539 zlog_debug("Ignore LSA with LSInfinity Metric");
543 if (CHECK_FLAG(external
->prefix
.prefix_options
,
544 OSPF6_PREFIX_OPTION_NU
)) {
545 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
546 zlog_debug("Ignore LSA with NU bit set Metric");
550 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &asbr_id
);
551 asbr_entry
= ospf6_route_lookup(&asbr_id
, ospf6
->brouter_table
);
552 if (asbr_entry
== NULL
) {
553 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
554 zlog_debug("ASBR entry not found: %pFX", &asbr_id
);
557 /* The router advertising external LSA can be ASBR or ABR */
558 if (!CHECK_FLAG(asbr_entry
->path
.router_bits
,
559 OSPF6_ROUTER_BIT_E
)) {
560 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
562 "External bit reset ASBR route entry : %pFX",
568 * RFC 3101 - Section 2.5:
569 * "For a Type-7 LSA the matching routing table entry must
570 * specify an intra-area path through the LSA's originating
573 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_TYPE_7
574 && (asbr_entry
->path
.area_id
!= oa
->area_id
575 || asbr_entry
->path
.type
!= OSPF6_PATH_TYPE_INTRA
)) {
576 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
578 "Intra-area route to NSSA ASBR not found: %pFX",
585 * RFC 3101 - Section 2.5:
586 * "If the destination is a Type-7 default route (destination ID =
587 * DefaultDestination) and one of the following is true, then do
588 * nothing with this LSA and consider the next in the list:
590 * o The calculating router is a border router and the LSA has
591 * its P-bit clear. Appendix E describes a technique
592 * whereby an NSSA border router installs a Type-7 default
593 * LSA without propagating it.
595 * o The calculating router is a border router and is
596 * suppressing the import of summary routes as Type-3
599 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_TYPE_7
600 && external
->prefix
.prefix_length
== 0
601 && CHECK_FLAG(ospf6
->flag
, OSPF6_FLAG_ABR
)
602 && (CHECK_FLAG(external
->prefix
.prefix_options
,
603 OSPF6_PREFIX_OPTION_P
)
604 || oa
->no_summary
)) {
605 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
606 zlog_debug("Skipping Type-7 default route");
610 /* Check the forwarding address */
611 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
612 offset
= sizeof(*external
)
613 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
614 memset(&fwd_addr
, 0, sizeof(fwd_addr
));
615 fwd_addr
.family
= AF_INET6
;
616 fwd_addr
.prefixlen
= IPV6_MAX_BITLEN
;
617 memcpy(&fwd_addr
.u
.prefix6
, (caddr_t
)external
+ offset
,
618 sizeof(struct in6_addr
));
620 if (!IN6_IS_ADDR_UNSPECIFIED(&fwd_addr
.u
.prefix6
)) {
621 if (!ospf6_ase_forward_address_check(
622 ospf6
, &fwd_addr
.u
.prefix6
)) {
623 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
625 "Fwd address %pFX is local address",
630 /* Find the forwarding entry */
631 asbr_entry
= ospf6_route_lookup_bestmatch(
632 &fwd_addr
, ospf6
->route_table
);
633 if (asbr_entry
== NULL
) {
634 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
636 "Fwd address not found: %pFX",
643 route
= ospf6_route_create(ospf6
);
644 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
645 route
->prefix
.family
= AF_INET6
;
646 route
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
647 ospf6_prefix_in6_addr(&route
->prefix
.u
.prefix6
, external
,
649 route
->prefix_options
= external
->prefix
.prefix_options
;
651 route
->path
.area_id
= asbr_entry
->path
.area_id
;
652 route
->path
.origin
.type
= lsa
->header
->type
;
653 route
->path
.origin
.id
= lsa
->header
->id
;
654 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
655 memcpy(&route
->path
.ls_prefix
, &asbr_id
, sizeof(struct prefix
));
657 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
658 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
659 route
->path
.metric_type
= 2;
660 route
->path
.cost
= asbr_entry
->path
.cost
;
661 route
->path
.u
.cost_e2
= OSPF6_ASBR_METRIC(external
);
663 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
664 route
->path
.metric_type
= 1;
666 asbr_entry
->path
.cost
+ OSPF6_ASBR_METRIC(external
);
667 route
->path
.u
.cost_e2
= 0;
670 route
->path
.tag
= ospf6_as_external_lsa_get_tag(lsa
);
672 ospf6_route_copy_nexthops(route
, asbr_entry
);
674 path
= ospf6_path_dup(&route
->path
);
675 ospf6_copy_nexthops(path
->nh_list
, asbr_entry
->nh_list
);
676 listnode_add_sort(route
->paths
, path
);
679 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
681 "%s: %s %u route add %pFX cost %u(%u) nh %u", __func__
,
682 (type
== OSPF6_LSTYPE_AS_EXTERNAL
) ? "AS-External"
684 (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
) ? 1 : 2,
685 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
686 listcount(route
->nh_list
));
688 if (type
== OSPF6_LSTYPE_AS_EXTERNAL
)
689 old
= ospf6_route_lookup(&route
->prefix
, ospf6
->route_table
);
690 else if (type
== OSPF6_LSTYPE_TYPE_7
)
691 old
= ospf6_route_lookup(&route
->prefix
, oa
->route_table
);
693 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
694 zlog_debug("%s: Adding new route", __func__
);
695 /* Add the new route to ospf6 instance route table. */
696 if (type
== OSPF6_LSTYPE_AS_EXTERNAL
)
697 ospf6_route_add(route
, ospf6
->route_table
);
698 /* Add the route to the area route table */
699 else if (type
== OSPF6_LSTYPE_TYPE_7
) {
700 ospf6_route_add(route
, oa
->route_table
);
704 * ECMP: Keep new equal preference path in current
705 * route's path list, update zebra with new effective
706 * list along with addition of ECMP path.
708 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
709 zlog_debug("%s : old route %pFX cost %u(%u) nh %u",
710 __func__
, &route
->prefix
, route
->path
.cost
,
711 route
->path
.u
.cost_e2
,
712 listcount(route
->nh_list
));
713 ospf6_asbr_update_route_ecmp_path(old
, route
, ospf6
);
717 void ospf6_asbr_lsa_remove(struct ospf6_lsa
*lsa
,
718 struct ospf6_route
*asbr_entry
)
720 struct ospf6_as_external_lsa
*external
;
721 struct prefix prefix
;
722 struct ospf6_route
*route
, *nroute
, *route_to_del
;
723 struct ospf6_area
*oa
= NULL
;
728 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
731 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
) || (IS_OSPF6_DEBUG_NSSA
))
734 ospf6
= ospf6_get_by_lsdb(lsa
);
735 type
= ntohs(lsa
->header
->type
);
737 if (type
== OSPF6_LSTYPE_TYPE_7
) {
739 zlog_debug("%s: Withdraw Type 7 route for %s",
740 __func__
, lsa
->name
);
741 oa
= lsa
->lsdb
->data
;
744 zlog_debug("%s: Withdraw AS-External route for %s",
745 __func__
, lsa
->name
);
747 if (ospf6_check_and_set_router_abr(ospf6
))
748 oa
= ospf6
->backbone
;
750 oa
= listnode_head(ospf6
->area_list
);
755 zlog_debug("%s: Invalid area", __func__
);
759 if (lsa
->header
->adv_router
== oa
->ospf6
->router_id
) {
761 zlog_debug("Ignore self-originated AS-External-LSA");
765 route_to_del
= ospf6_route_create(ospf6
);
766 route_to_del
->type
= OSPF6_DEST_TYPE_NETWORK
;
767 route_to_del
->prefix
.family
= AF_INET6
;
768 route_to_del
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
769 ospf6_prefix_in6_addr(&route_to_del
->prefix
.u
.prefix6
, external
,
772 route_to_del
->path
.origin
.type
= lsa
->header
->type
;
773 route_to_del
->path
.origin
.id
= lsa
->header
->id
;
774 route_to_del
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
777 route_to_del
->path
.area_id
= asbr_entry
->path
.area_id
;
778 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
779 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
780 route_to_del
->path
.metric_type
= 2;
781 route_to_del
->path
.cost
= asbr_entry
->path
.cost
;
782 route_to_del
->path
.u
.cost_e2
=
783 OSPF6_ASBR_METRIC(external
);
785 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
786 route_to_del
->path
.metric_type
= 1;
787 route_to_del
->path
.cost
= asbr_entry
->path
.cost
788 + OSPF6_ASBR_METRIC(external
);
789 route_to_del
->path
.u
.cost_e2
= 0;
793 memset(&prefix
, 0, sizeof(struct prefix
));
794 prefix
.family
= AF_INET6
;
795 prefix
.prefixlen
= external
->prefix
.prefix_length
;
796 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, external
, &external
->prefix
);
798 if (type
== OSPF6_LSTYPE_TYPE_7
)
799 route
= ospf6_route_lookup(&prefix
, oa
->route_table
);
801 route
= ospf6_route_lookup(&prefix
, oa
->ospf6
->route_table
);
805 zlog_debug("AS-External route %pFX not found", &prefix
);
806 ospf6_route_delete(route_to_del
);
812 "%s: Current route %pFX cost %u e2 %u, route to del cost %u e2 %u",
813 __func__
, &prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
814 route_to_del
->path
.cost
, route_to_del
->path
.u
.cost_e2
);
816 for (ospf6_route_lock(route
);
817 route
&& ospf6_route_is_prefix(&prefix
, route
); route
= nroute
) {
818 nroute
= ospf6_route_next(route
);
820 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
)
823 /* Route has multiple ECMP paths, remove matching
824 * path. Update current route's effective nh list
825 * after removal of one of the path.
827 if (listcount(route
->paths
) > 1) {
828 struct listnode
*anode
, *anext
;
829 struct listnode
*nnode
, *rnode
, *rnext
;
830 struct ospf6_nexthop
*nh
, *rnh
;
831 struct ospf6_path
*o_path
;
832 bool nh_updated
= false;
834 /* Iterate all paths of route to find maching with LSA
835 * remove from route path list. If route->path is same,
836 * replace from paths list.
838 for (ALL_LIST_ELEMENTS(route
->paths
, anode
, anext
,
840 if ((o_path
->origin
.type
!= lsa
->header
->type
)
841 || (o_path
->origin
.adv_router
842 != lsa
->header
->adv_router
)
843 || (o_path
->origin
.id
!= lsa
->header
->id
))
846 /* Compare LSA cost with current
850 && (o_path
->cost
!= route_to_del
->path
.cost
852 != route_to_del
->path
.u
854 if (IS_OSPF6_DEBUG_EXAMIN(
857 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
868 "%s: route %pFX path found with cost %u nh %u to remove.",
869 __func__
, &prefix
, route
->path
.cost
,
870 listcount(o_path
->nh_list
));
873 /* Remove found path's nh_list from
874 * the route's nh_list.
876 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
,
878 for (ALL_LIST_ELEMENTS(route
->nh_list
,
881 if (!ospf6_nexthop_is_same(rnh
,
884 listnode_delete(route
->nh_list
,
886 ospf6_nexthop_delete(rnh
);
889 /* Delete the path from route's path list */
890 listnode_delete(route
->paths
, o_path
);
891 ospf6_path_free(o_path
);
896 /* Iterate all paths and merge nexthop,
897 * unlesss any of the nexthop similar to
898 * ones deleted as part of path deletion.
901 for (ALL_LIST_ELEMENTS(route
->paths
, anode
,
903 ospf6_merge_nexthops(route
->nh_list
,
909 "%s: AS-External %u route %pFX update paths %u nh %u",
912 == OSPF6_PATH_TYPE_EXTERNAL1
)
915 &route
->prefix
, listcount(route
->paths
),
916 route
->nh_list
? listcount(
921 if (listcount(route
->paths
)) {
922 /* Update RIB/FIB with effective
925 if (oa
->ospf6
->route_table
->hook_add
)
926 (*oa
->ospf6
->route_table
929 /* route's primary path is similar
930 * to LSA, replace route's primary
931 * path with route's paths list head.
933 if ((route
->path
.origin
.id
==
935 (route
->path
.origin
.adv_router
936 == lsa
->header
->adv_router
)) {
937 struct ospf6_path
*h_path
;
939 h_path
= (struct ospf6_path
*)
941 listhead(route
->paths
));
942 route
->path
.origin
.type
=
944 route
->path
.origin
.id
=
946 route
->path
.origin
.adv_router
=
947 h_path
->origin
.adv_router
;
950 if (type
== OSPF6_LSTYPE_TYPE_7
)
952 route
, oa
->route_table
);
956 oa
->ospf6
->route_table
);
962 /* Compare LSA origin and cost with current route info.
963 * if any check fails skip del this route node.
966 && (!ospf6_route_is_same_origin(route
, route_to_del
)
967 || (route
->path
.type
!= route_to_del
->path
.type
)
968 || (route
->path
.cost
!= route_to_del
->path
.cost
)
969 || (route
->path
.u
.cost_e2
970 != route_to_del
->path
.u
.cost_e2
))) {
973 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
974 __func__
, &prefix
, route
->path
.cost
,
975 route_to_del
->path
.cost
);
980 if ((route
->path
.origin
.type
!= lsa
->header
->type
)
981 || (route
->path
.origin
.adv_router
982 != lsa
->header
->adv_router
)
983 || (route
->path
.origin
.id
!= lsa
->header
->id
))
988 "%s: AS-External %u route remove %pFX cost %u(%u) nh %u",
990 route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
993 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
994 listcount(route
->nh_list
));
996 if (type
== OSPF6_LSTYPE_TYPE_7
)
997 ospf6_route_remove(route
, oa
->route_table
);
999 ospf6_route_remove(route
, oa
->ospf6
->route_table
);
1002 ospf6_route_unlock(route
);
1004 ospf6_route_delete(route_to_del
);
1007 void ospf6_asbr_lsentry_add(struct ospf6_route
*asbr_entry
, struct ospf6
*ospf6
)
1009 struct ospf6_lsa
*lsa
;
1013 if (!CHECK_FLAG(asbr_entry
->flag
, OSPF6_ROUTE_BEST
)) {
1015 inet_ntop(AF_INET
, &ADV_ROUTER_IN_PREFIX(&asbr_entry
->prefix
),
1017 zlog_info("ignore non-best path: lsentry %s add", buf
);
1021 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
1022 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
1023 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
)) {
1024 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
1025 ospf6_asbr_lsa_add(lsa
);
1029 void ospf6_asbr_lsentry_remove(struct ospf6_route
*asbr_entry
,
1030 struct ospf6
*ospf6
)
1032 struct ospf6_lsa
*lsa
;
1036 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
1037 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
1038 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
))
1039 ospf6_asbr_lsa_remove(lsa
, asbr_entry
);
1043 /* redistribute function */
1044 static void ospf6_asbr_routemap_set(struct ospf6_redist
*red
,
1045 const char *mapname
)
1047 if (ROUTEMAP_NAME(red
)) {
1048 route_map_counter_decrement(ROUTEMAP(red
));
1049 free(ROUTEMAP_NAME(red
));
1052 ROUTEMAP_NAME(red
) = strdup(mapname
);
1053 ROUTEMAP(red
) = route_map_lookup_by_name(mapname
);
1054 route_map_counter_increment(ROUTEMAP(red
));
1057 static void ospf6_asbr_routemap_unset(struct ospf6_redist
*red
)
1059 if (ROUTEMAP_NAME(red
))
1060 free(ROUTEMAP_NAME(red
));
1062 route_map_counter_decrement(ROUTEMAP(red
));
1064 ROUTEMAP_NAME(red
) = NULL
;
1065 ROUTEMAP(red
) = NULL
;
1068 static void ospf6_asbr_routemap_update_timer(struct event
*thread
)
1070 struct ospf6
*ospf6
= EVENT_ARG(thread
);
1071 struct ospf6_redist
*red
;
1074 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1075 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1080 if (!CHECK_FLAG(red
->flag
, OSPF6_IS_RMAP_CHANGED
))
1083 if (ROUTEMAP_NAME(red
))
1085 route_map_lookup_by_name(ROUTEMAP_NAME(red
));
1087 if (ROUTEMAP(red
)) {
1088 if (IS_OSPF6_DEBUG_ASBR
)
1090 "%s: route-map %s update, reset redist %s",
1091 __func__
, ROUTEMAP_NAME(red
),
1094 ospf6_zebra_no_redistribute(type
, ospf6
->vrf_id
);
1095 ospf6_zebra_redistribute(type
, ospf6
->vrf_id
);
1098 UNSET_FLAG(red
->flag
, OSPF6_IS_RMAP_CHANGED
);
1102 void ospf6_asbr_distribute_list_update(struct ospf6
*ospf6
,
1103 struct ospf6_redist
*red
)
1105 SET_FLAG(red
->flag
, OSPF6_IS_RMAP_CHANGED
);
1107 if (event_is_scheduled(ospf6
->t_distribute_update
))
1110 if (IS_OSPF6_DEBUG_ASBR
)
1111 zlog_debug("%s: trigger redistribute reset thread", __func__
);
1113 event_add_timer_msec(master
, ospf6_asbr_routemap_update_timer
, ospf6
,
1114 OSPF_MIN_LS_INTERVAL
, &ospf6
->t_distribute_update
);
1117 void ospf6_asbr_routemap_update(const char *mapname
)
1120 struct listnode
*node
, *nnode
;
1121 struct ospf6
*ospf6
= NULL
;
1122 struct ospf6_redist
*red
;
1127 for (ALL_LIST_ELEMENTS(om6
->ospf6
, node
, nnode
, ospf6
)) {
1128 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1129 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1130 if (!red
|| (ROUTEMAP_NAME(red
) == NULL
))
1133 route_map_lookup_by_name(ROUTEMAP_NAME(red
));
1136 || strcmp(ROUTEMAP_NAME(red
), mapname
))
1138 if (ROUTEMAP(red
)) {
1139 if (IS_OSPF6_DEBUG_ASBR
)
1141 "%s: route-map %s update, reset redist %s",
1147 route_map_counter_increment(ROUTEMAP(red
));
1148 ospf6_asbr_distribute_list_update(ospf6
, red
);
1151 * if the mapname matches a
1152 * route-map on ospf6 but the
1153 * map doesn't exist, it is
1154 * being deleted. flush and then
1157 if (IS_OSPF6_DEBUG_ASBR
)
1159 "%s: route-map %s deleted, reset redist %s",
1164 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1165 ospf6_asbr_routemap_set(red
, mapname
);
1166 ospf6_asbr_redistribute_set(ospf6
, type
);
1172 static void ospf6_asbr_routemap_event(const char *name
)
1175 struct listnode
*node
, *nnode
;
1176 struct ospf6
*ospf6
;
1177 struct ospf6_redist
*red
;
1181 for (ALL_LIST_ELEMENTS(om6
->ospf6
, node
, nnode
, ospf6
)) {
1182 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1183 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1184 if (red
&& ROUTEMAP_NAME(red
)
1185 && (strcmp(ROUTEMAP_NAME(red
), name
) == 0))
1186 ospf6_asbr_distribute_list_update(ospf6
, red
);
1191 int ospf6_asbr_is_asbr(struct ospf6
*o
)
1193 return (o
->external_table
->count
|| IS_OSPF6_ASBR(o
));
1196 struct ospf6_redist
*ospf6_redist_lookup(struct ospf6
*ospf6
, int type
,
1197 unsigned short instance
)
1199 struct list
*red_list
;
1200 struct listnode
*node
;
1201 struct ospf6_redist
*red
;
1203 red_list
= ospf6
->redist
[type
];
1207 for (ALL_LIST_ELEMENTS_RO(red_list
, node
, red
))
1208 if (red
->instance
== instance
)
1214 static struct ospf6_redist
*ospf6_redist_add(struct ospf6
*ospf6
, int type
,
1217 struct ospf6_redist
*red
;
1219 red
= ospf6_redist_lookup(ospf6
, type
, instance
);
1223 if (!ospf6
->redist
[type
])
1224 ospf6
->redist
[type
] = list_new();
1226 red
= XCALLOC(MTYPE_OSPF6_REDISTRIBUTE
, sizeof(struct ospf6_redist
));
1227 red
->instance
= instance
;
1228 red
->dmetric
.type
= -1;
1229 red
->dmetric
.value
= -1;
1230 ROUTEMAP_NAME(red
) = NULL
;
1231 ROUTEMAP(red
) = NULL
;
1233 listnode_add(ospf6
->redist
[type
], red
);
1234 ospf6
->redistribute
++;
1239 static void ospf6_redist_del(struct ospf6
*ospf6
, struct ospf6_redist
*red
,
1243 listnode_delete(ospf6
->redist
[type
], red
);
1244 if (!ospf6
->redist
[type
]->count
) {
1245 list_delete(&ospf6
->redist
[type
]);
1247 XFREE(MTYPE_OSPF6_REDISTRIBUTE
, red
);
1248 ospf6
->redistribute
--;
1252 /*Set the status of the ospf instance to ASBR based on the status parameter,
1253 * rechedule SPF calculation, originate router LSA*/
1254 void ospf6_asbr_status_update(struct ospf6
*ospf6
, int status
)
1256 struct listnode
*lnode
, *lnnode
;
1257 struct ospf6_area
*oa
;
1259 zlog_info("ASBR[%s:Status:%d]: Update", ospf6
->name
, status
);
1262 if (IS_OSPF6_ASBR(ospf6
)) {
1263 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
1264 ospf6
->name
, status
);
1267 SET_FLAG(ospf6
->flag
, OSPF6_FLAG_ASBR
);
1269 if (!IS_OSPF6_ASBR(ospf6
)) {
1270 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
1271 ospf6
->name
, status
);
1274 UNSET_FLAG(ospf6
->flag
, OSPF6_FLAG_ASBR
);
1277 /* Transition from/to status ASBR, schedule timer. */
1278 ospf6_spf_schedule(ospf6
, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE
);
1280 /* Reoriginate router LSA for all areas */
1281 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1282 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1285 static void ospf6_asbr_redistribute_set(struct ospf6
*ospf6
, int type
)
1287 ospf6_zebra_redistribute(type
, ospf6
->vrf_id
);
1289 ++ospf6
->redist_count
;
1290 ospf6_asbr_status_update(ospf6
, ospf6
->redist_count
);
1293 static void ospf6_asbr_redistribute_unset(struct ospf6
*ospf6
,
1294 struct ospf6_redist
*red
, int type
)
1296 struct ospf6_route
*route
;
1297 struct ospf6_external_info
*info
;
1299 ospf6_zebra_no_redistribute(type
, ospf6
->vrf_id
);
1301 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1302 route
= ospf6_route_next(route
)) {
1303 info
= route
->route_option
;
1304 if (info
->type
!= type
)
1307 ospf6_asbr_redistribute_remove(info
->type
, 0, &route
->prefix
,
1311 ospf6_asbr_routemap_unset(red
);
1312 --ospf6
->redist_count
;
1313 ospf6_asbr_status_update(ospf6
, ospf6
->redist_count
);
1316 /* When an area is unstubified, flood all the external LSAs in the area */
1317 void ospf6_asbr_send_externals_to_area(struct ospf6_area
*oa
)
1319 struct ospf6_lsa
*lsa
, *lsanext
;
1321 for (ALL_LSDB(oa
->ospf6
->lsdb
, lsa
, lsanext
)) {
1322 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
) {
1323 if (IS_OSPF6_DEBUG_ASBR
)
1324 zlog_debug("%s: Flooding AS-External LSA %s",
1325 __func__
, lsa
->name
);
1327 ospf6_flood_area(NULL
, lsa
, oa
);
1332 /* When an area is stubified, remove all the external LSAs in the area */
1333 void ospf6_asbr_remove_externals_from_area(struct ospf6_area
*oa
)
1335 struct ospf6_lsa
*lsa
, *lsanext
;
1336 struct listnode
*node
, *nnode
;
1337 struct ospf6_area
*area
;
1338 struct ospf6
*ospf6
= oa
->ospf6
;
1339 const struct route_node
*iterend
;
1341 /* skip if router is in other non-stub/non-NSSA areas */
1342 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, area
))
1343 if (!IS_AREA_STUB(area
) && !IS_AREA_NSSA(area
))
1346 /* if router is only in a stub area then purge AS-External LSAs */
1347 iterend
= ospf6_lsdb_head(ospf6
->lsdb
, 0, 0, 0, &lsa
);
1348 while (lsa
!= NULL
) {
1349 assert(lsa
->lock
> 1);
1350 lsanext
= ospf6_lsdb_next(iterend
, lsa
);
1351 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
)
1352 ospf6_lsdb_remove(lsa
, ospf6
->lsdb
);
1357 static struct ospf6_external_aggr_rt
*
1358 ospf6_external_aggr_match(struct ospf6
*ospf6
, struct prefix
*p
)
1360 struct route_node
*node
;
1362 node
= route_node_match(ospf6
->rt_aggr_tbl
, p
);
1366 if (IS_OSPF6_DEBUG_AGGR
) {
1367 struct ospf6_external_aggr_rt
*ag
= node
->info
;
1368 zlog_debug("%s: Matching aggregator found.prefix: %pFX Aggregator %pFX",
1374 route_unlock_node(node
);
1379 void ospf6_asbr_redistribute_add(int type
, ifindex_t ifindex
,
1380 struct prefix
*prefix
,
1381 unsigned int nexthop_num
,
1382 const struct in6_addr
*nexthop
,
1383 route_tag_t tag
, struct ospf6
*ospf6
)
1385 route_map_result_t ret
;
1386 struct ospf6_route troute
;
1387 struct ospf6_external_info tinfo
;
1388 struct ospf6_route
*route
, *match
;
1389 struct ospf6_external_info
*info
;
1390 struct ospf6_redist
*red
;
1392 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1397 if ((type
!= DEFAULT_ROUTE
)
1398 && !ospf6_zebra_is_redistribute(type
, ospf6
->vrf_id
))
1401 memset(&troute
, 0, sizeof(troute
));
1402 memset(&tinfo
, 0, sizeof(tinfo
));
1404 if (IS_OSPF6_DEBUG_ASBR
)
1405 zlog_debug("Redistribute %pFX (%s)", prefix
,
1406 type
== DEFAULT_ROUTE
1407 ? "default-information-originate"
1408 : ZROUTE_NAME(type
));
1410 /* if route-map was specified but not found, do not advertise */
1411 if (ROUTEMAP_NAME(red
)) {
1412 if (ROUTEMAP(red
) == NULL
)
1413 ospf6_asbr_routemap_update(NULL
);
1414 if (ROUTEMAP(red
) == NULL
) {
1416 "route-map \"%s\" not found, suppress redistributing",
1417 ROUTEMAP_NAME(red
));
1422 /* apply route-map */
1423 if (ROUTEMAP(red
)) {
1424 troute
.route_option
= &tinfo
;
1425 troute
.ospf6
= ospf6
;
1426 tinfo
.ifindex
= ifindex
;
1429 ret
= route_map_apply(ROUTEMAP(red
), prefix
, &troute
);
1430 if (ret
== RMAP_DENYMATCH
) {
1431 if (IS_OSPF6_DEBUG_ASBR
)
1432 zlog_debug("Denied by route-map \"%s\"",
1433 ROUTEMAP_NAME(red
));
1434 ospf6_asbr_redistribute_remove(type
, ifindex
, prefix
,
1440 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1442 info
= match
->route_option
;
1443 /* copy result of route-map */
1444 if (ROUTEMAP(red
)) {
1445 if (troute
.path
.metric_type
)
1446 match
->path
.metric_type
=
1447 troute
.path
.metric_type
;
1449 match
->path
.metric_type
=
1450 metric_type(ospf6
, type
, 0);
1451 if (troute
.path
.cost
)
1452 match
->path
.cost
= troute
.path
.cost
;
1454 match
->path
.cost
= metric_value(ospf6
, type
, 0);
1456 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1457 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1458 sizeof(struct in6_addr
));
1459 info
->tag
= tinfo
.tag
;
1461 /* If there is no route-map, simply update the tag and
1464 match
->path
.metric_type
= metric_type(ospf6
, type
, 0);
1465 match
->path
.cost
= metric_value(ospf6
, type
, 0);
1471 if (nexthop_num
&& nexthop
) {
1472 ospf6_route_add_nexthop(match
, ifindex
, nexthop
);
1473 if (!IN6_IS_ADDR_UNSPECIFIED(nexthop
)
1474 && !IN6_IS_ADDR_LINKLOCAL(nexthop
))
1475 memcpy(&info
->forwarding
, nexthop
,
1476 sizeof(struct in6_addr
));
1478 ospf6_route_add_nexthop(match
, ifindex
, NULL
);
1480 match
->path
.origin
.id
= htonl(info
->id
);
1481 ospf6_handle_external_lsa_origination(ospf6
, match
, prefix
);
1483 ospf6_asbr_status_update(ospf6
, ospf6
->redistribute
);
1488 /* create new entry */
1489 route
= ospf6_route_create(ospf6
);
1490 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
1491 prefix_copy(&route
->prefix
, prefix
);
1493 info
= (struct ospf6_external_info
*)XCALLOC(
1494 MTYPE_OSPF6_EXTERNAL_INFO
, sizeof(struct ospf6_external_info
));
1495 route
->route_option
= info
;
1497 /* copy result of route-map */
1498 if (ROUTEMAP(red
)) {
1499 if (troute
.path
.metric_type
)
1500 route
->path
.metric_type
= troute
.path
.metric_type
;
1502 route
->path
.metric_type
= metric_type(ospf6
, type
, 0);
1503 if (troute
.path
.cost
)
1504 route
->path
.cost
= troute
.path
.cost
;
1506 route
->path
.cost
= metric_value(ospf6
, type
, 0);
1507 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1508 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1509 sizeof(struct in6_addr
));
1510 info
->tag
= tinfo
.tag
;
1512 /* If there is no route-map, simply update the tag and metric
1515 route
->path
.metric_type
= metric_type(ospf6
, type
, 0);
1516 route
->path
.cost
= metric_value(ospf6
, type
, 0);
1521 if (nexthop_num
&& nexthop
) {
1522 ospf6_route_add_nexthop(route
, ifindex
, nexthop
);
1523 if (!IN6_IS_ADDR_UNSPECIFIED(nexthop
)
1524 && !IN6_IS_ADDR_LINKLOCAL(nexthop
))
1525 memcpy(&info
->forwarding
, nexthop
,
1526 sizeof(struct in6_addr
));
1528 ospf6_route_add_nexthop(route
, ifindex
, NULL
);
1530 route
= ospf6_route_add(route
, ospf6
->external_table
);
1531 ospf6_handle_external_lsa_origination(ospf6
, route
, prefix
);
1533 ospf6_asbr_status_update(ospf6
, ospf6
->redistribute
);
1537 static void ospf6_asbr_external_lsa_remove_by_id(struct ospf6
*ospf6
,
1540 struct ospf6_lsa
*lsa
;
1542 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
1543 htonl(id
), ospf6
->router_id
, ospf6
->lsdb
);
1547 ospf6_external_lsa_purge(ospf6
, lsa
);
1552 ospf6_link_route_to_aggr(struct ospf6_external_aggr_rt
*aggr
,
1553 struct ospf6_route
*rt
)
1555 (void)hash_get(aggr
->match_extnl_hash
, rt
, hash_alloc_intern
);
1556 rt
->aggr_route
= aggr
;
1560 ospf6_asbr_summary_remove_lsa_and_route(struct ospf6
*ospf6
,
1561 struct ospf6_external_aggr_rt
*aggr
)
1564 /* Send a Max age LSA if it is already originated.*/
1565 if (!CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
))
1568 if (IS_OSPF6_DEBUG_AGGR
)
1569 zlog_debug("%s: Flushing Aggregate route (%pFX)",
1573 ospf6_asbr_external_lsa_remove_by_id(ospf6
, aggr
->id
);
1576 if (IS_OSPF6_DEBUG_AGGR
)
1578 "%s: Remove the blackhole route",
1581 ospf6_zebra_route_update_remove(aggr
->route
, ospf6
);
1582 if (aggr
->route
->route_option
)
1583 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
,
1584 aggr
->route
->route_option
);
1585 ospf6_route_delete(aggr
->route
);
1590 /* Unset the Origination flag */
1591 UNSET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
1595 ospf6_unlink_route_from_aggr(struct ospf6
*ospf6
,
1596 struct ospf6_external_aggr_rt
*aggr
,
1597 struct ospf6_route
*rt
)
1599 if (IS_OSPF6_DEBUG_AGGR
)
1600 zlog_debug("%s: Unlinking external route(%pFX) from aggregator(%pFX), external route count:%ld",
1604 OSPF6_EXTERNAL_RT_COUNT(aggr
));
1606 hash_release(aggr
->match_extnl_hash
, rt
);
1607 rt
->aggr_route
= NULL
;
1609 /* Flush the aggregate route if matching
1610 * external route count becomes zero.
1612 if (!OSPF6_EXTERNAL_RT_COUNT(aggr
))
1613 ospf6_asbr_summary_remove_lsa_and_route(ospf6
, aggr
);
1616 void ospf6_asbr_redistribute_remove(int type
, ifindex_t ifindex
,
1617 struct prefix
*prefix
, struct ospf6
*ospf6
)
1619 struct ospf6_route
*match
;
1620 struct ospf6_external_info
*info
= NULL
;
1622 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1623 if (match
== NULL
) {
1624 if (IS_OSPF6_DEBUG_ASBR
)
1625 zlog_debug("No such route %pFX to withdraw", prefix
);
1629 info
= match
->route_option
;
1632 if (info
->type
!= type
) {
1633 if (IS_OSPF6_DEBUG_ASBR
)
1634 zlog_debug("Original protocol mismatch: %pFX", prefix
);
1638 /* This means aggregation on this route was not done, hence remove LSA
1639 * if any originated for this prefix
1641 if (!match
->aggr_route
)
1642 ospf6_asbr_external_lsa_remove_by_id(ospf6
, info
->id
);
1644 ospf6_unlink_route_from_aggr(ospf6
, match
->aggr_route
, match
);
1646 if (IS_OSPF6_DEBUG_ASBR
)
1647 zlog_debug("Removing route from external table %pFX",
1650 ospf6_route_remove(match
, ospf6
->external_table
);
1651 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
, info
);
1653 ospf6_asbr_status_update(ospf6
, ospf6
->redistribute
);
1656 DEFPY (ospf6_redistribute
,
1657 ospf6_redistribute_cmd
,
1658 "redistribute " FRR_REDIST_STR_OSPF6D
"[{metric (0-16777214)|metric-type (1-2)$metric_type|route-map RMAP_NAME$rmap_str}]",
1660 FRR_REDIST_HELP_STR_OSPF6D
1661 "Metric for redistributed routes\n"
1662 "OSPF default metric\n"
1663 "OSPF exterior metric type for redistributed routes\n"
1664 "Set OSPF External Type 1/2 metrics\n"
1665 "Route map reference\n"
1669 struct ospf6_redist
*red
;
1670 int idx_protocol
= 1;
1671 char *proto
= argv
[idx_protocol
]->text
;
1673 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1675 type
= proto_redistnum(AFI_IP6
, proto
);
1677 return CMD_WARNING_CONFIG_FAILED
;
1681 if (!metric_type_str
)
1684 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1686 red
= ospf6_redist_add(ospf6
, type
, 0);
1688 /* Check if nothing has changed. */
1689 if (red
->dmetric
.value
== metric
1690 && red
->dmetric
.type
== metric_type
1691 && ((!ROUTEMAP_NAME(red
) && !rmap_str
)
1692 || (ROUTEMAP_NAME(red
) && rmap_str
1693 && strmatch(ROUTEMAP_NAME(red
), rmap_str
))))
1696 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1699 red
->dmetric
.value
= metric
;
1700 red
->dmetric
.type
= metric_type
;
1702 ospf6_asbr_routemap_set(red
, rmap_str
);
1704 ospf6_asbr_routemap_unset(red
);
1705 ospf6_asbr_redistribute_set(ospf6
, type
);
1710 DEFUN (no_ospf6_redistribute
,
1711 no_ospf6_redistribute_cmd
,
1712 "no redistribute " FRR_REDIST_STR_OSPF6D
"[{metric (0-16777214)|metric-type (1-2)|route-map RMAP_NAME}]",
1715 FRR_REDIST_HELP_STR_OSPF6D
1716 "Metric for redistributed routes\n"
1717 "OSPF default metric\n"
1718 "OSPF exterior metric type for redistributed routes\n"
1719 "Set OSPF External Type 1/2 metrics\n"
1720 "Route map reference\n"
1724 struct ospf6_redist
*red
;
1725 int idx_protocol
= 2;
1726 char *proto
= argv
[idx_protocol
]->text
;
1728 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1730 type
= proto_redistnum(AFI_IP6
, proto
);
1732 return CMD_WARNING_CONFIG_FAILED
;
1734 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1738 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1739 ospf6_redist_del(ospf6
, red
, type
);
1744 int ospf6_redistribute_config_write(struct vty
*vty
, struct ospf6
*ospf6
)
1747 struct ospf6_redist
*red
;
1749 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1750 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1753 if (type
== ZEBRA_ROUTE_OSPF6
)
1756 vty_out(vty
, " redistribute %s", ZROUTE_NAME(type
));
1757 if (red
->dmetric
.value
>= 0)
1758 vty_out(vty
, " metric %d", red
->dmetric
.value
);
1759 if (red
->dmetric
.type
== 1)
1760 vty_out(vty
, " metric-type 1");
1761 if (ROUTEMAP_NAME(red
))
1762 vty_out(vty
, " route-map %s", ROUTEMAP_NAME(red
));
1769 static void ospf6_redistribute_show_config(struct vty
*vty
, struct ospf6
*ospf6
,
1770 json_object
*json_array
,
1771 json_object
*json
, bool use_json
)
1774 int nroute
[ZEBRA_ROUTE_MAX
];
1776 struct ospf6_route
*route
;
1777 struct ospf6_external_info
*info
;
1778 json_object
*json_route
;
1779 struct ospf6_redist
*red
;
1782 memset(nroute
, 0, sizeof(nroute
));
1783 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1784 route
= ospf6_route_next(route
)) {
1785 info
= route
->route_option
;
1786 nroute
[info
->type
]++;
1791 vty_out(vty
, "Redistributing External Routes from:\n");
1793 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1795 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1799 if (type
== ZEBRA_ROUTE_OSPF6
)
1803 json_route
= json_object_new_object();
1804 json_object_string_add(json_route
, "routeType",
1806 json_object_int_add(json_route
, "numberOfRoutes",
1808 json_object_boolean_add(json_route
,
1809 "routeMapNamePresent",
1810 ROUTEMAP_NAME(red
));
1813 if (ROUTEMAP_NAME(red
)) {
1815 json_object_string_add(json_route
,
1817 ROUTEMAP_NAME(red
));
1818 json_object_boolean_add(json_route
,
1823 " %d: %s with route-map \"%s\"%s\n",
1824 nroute
[type
], ZROUTE_NAME(type
),
1827 : " (not found !)"));
1830 vty_out(vty
, " %d: %s\n", nroute
[type
],
1835 json_object_array_add(json_array
, json_route
);
1838 json_object_object_add(json
, "redistributedRoutes", json_array
);
1839 json_object_int_add(json
, "totalRoutes", total
);
1841 vty_out(vty
, "Total %d routes\n", total
);
1844 static void ospf6_redistribute_default_set(struct ospf6
*ospf6
, int originate
)
1846 struct prefix_ipv6 p
= {};
1847 struct in6_addr nexthop
= {};
1848 int cur_originate
= ospf6
->default_originate
;
1850 p
.family
= AF_INET6
;
1853 ospf6
->default_originate
= originate
;
1855 switch (cur_originate
) {
1856 case DEFAULT_ORIGINATE_NONE
:
1858 case DEFAULT_ORIGINATE_ZEBRA
:
1859 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE
,
1860 zclient
, AFI_IP6
, ospf6
->vrf_id
);
1861 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE
, 0,
1862 (struct prefix
*)&p
, ospf6
);
1865 case DEFAULT_ORIGINATE_ALWAYS
:
1866 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE
, 0,
1867 (struct prefix
*)&p
, ospf6
);
1871 switch (originate
) {
1872 case DEFAULT_ORIGINATE_NONE
:
1874 case DEFAULT_ORIGINATE_ZEBRA
:
1875 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD
,
1876 zclient
, AFI_IP6
, ospf6
->vrf_id
);
1879 case DEFAULT_ORIGINATE_ALWAYS
:
1880 ospf6_asbr_redistribute_add(DEFAULT_ROUTE
, 0,
1881 (struct prefix
*)&p
, 0, &nexthop
, 0,
1887 /* Default Route originate. */
1888 DEFPY (ospf6_default_route_originate
,
1889 ospf6_default_route_originate_cmd
,
1890 "default-information originate [{always$always|metric (0-16777214)$mval|metric-type (1-2)$mtype|route-map RMAP_NAME$rtmap}]",
1891 "Control distribution of default route\n"
1892 "Distribute a default route\n"
1893 "Always advertise default route\n"
1894 "OSPFv3 default metric\n"
1896 "OSPFv3 metric type for default routes\n"
1897 "Set OSPFv3 External Type 1/2 metrics\n"
1898 "Route map reference\n"
1899 "Pointer to route-map entries\n")
1901 int default_originate
= DEFAULT_ORIGINATE_ZEBRA
;
1902 struct ospf6_redist
*red
;
1903 bool sameRtmap
= false;
1905 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1907 int cur_originate
= ospf6
->default_originate
;
1909 red
= ospf6_redist_add(ospf6
, DEFAULT_ROUTE
, 0);
1912 default_originate
= DEFAULT_ORIGINATE_ALWAYS
;
1914 if (mval_str
== NULL
)
1917 if (mtype_str
== NULL
)
1920 /* To check if user is providing same route map */
1921 if ((!rtmap
&& !ROUTEMAP_NAME(red
)) ||
1922 (rtmap
&& ROUTEMAP_NAME(red
) &&
1923 (strcmp(rtmap
, ROUTEMAP_NAME(red
)) == 0)))
1926 /* Don't allow if the same lsa is already originated. */
1927 if ((sameRtmap
) && (red
->dmetric
.type
== mtype
)
1928 && (red
->dmetric
.value
== mval
)
1929 && (cur_originate
== default_originate
))
1932 /* Updating Metric details */
1933 red
->dmetric
.type
= mtype
;
1934 red
->dmetric
.value
= mval
;
1936 /* updating route map details */
1938 ospf6_asbr_routemap_set(red
, rtmap
);
1940 ospf6_asbr_routemap_unset(red
);
1942 ospf6_redistribute_default_set(ospf6
, default_originate
);
1946 DEFPY (no_ospf6_default_information_originate
,
1947 no_ospf6_default_information_originate_cmd
,
1948 "no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map RMAP_NAME}]",
1950 "Control distribution of default information\n"
1951 "Distribute a default route\n"
1952 "Always advertise default route\n"
1953 "OSPFv3 default metric\n"
1955 "OSPFv3 metric type for default routes\n"
1956 "Set OSPFv3 External Type 1/2 metrics\n"
1957 "Route map reference\n"
1958 "Pointer to route-map entries\n")
1960 struct ospf6_redist
*red
;
1962 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1964 red
= ospf6_redist_lookup(ospf6
, DEFAULT_ROUTE
, 0);
1968 ospf6_asbr_routemap_unset(red
);
1969 ospf6_redist_del(ospf6
, red
, DEFAULT_ROUTE
);
1971 ospf6_redistribute_default_set(ospf6
, DEFAULT_ORIGINATE_NONE
);
1975 /* Routemap Functions */
1976 static enum route_map_cmd_result_t
1977 ospf6_routemap_rule_match_address_prefixlist(void *rule
,
1978 const struct prefix
*prefix
,
1982 struct prefix_list
*plist
;
1984 plist
= prefix_list_lookup(AFI_IP6
, (char *)rule
);
1986 return RMAP_NOMATCH
;
1988 return (prefix_list_apply(plist
, prefix
) == PREFIX_DENY
? RMAP_NOMATCH
1993 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg
)
1995 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1998 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule
)
2000 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2003 static const struct route_map_rule_cmd
2004 ospf6_routemap_rule_match_address_prefixlist_cmd
= {
2005 "ipv6 address prefix-list",
2006 ospf6_routemap_rule_match_address_prefixlist
,
2007 ospf6_routemap_rule_match_address_prefixlist_compile
,
2008 ospf6_routemap_rule_match_address_prefixlist_free
,
2011 /* `match interface IFNAME' */
2012 /* Match function should return 1 if match is success else return
2014 static enum route_map_cmd_result_t
2015 ospf6_routemap_rule_match_interface(void *rule
, const struct prefix
*prefix
,
2018 struct interface
*ifp
;
2019 struct ospf6_route
*route
;
2020 struct ospf6_external_info
*ei
;
2023 ei
= route
->route_option
;
2024 ifp
= if_lookup_by_name((char *)rule
, route
->ospf6
->vrf_id
);
2026 if (ifp
!= NULL
&& ei
->ifindex
== ifp
->ifindex
)
2029 return RMAP_NOMATCH
;
2032 /* Route map `interface' match statement. `arg' should be
2034 static void *ospf6_routemap_rule_match_interface_compile(const char *arg
)
2036 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2039 /* Free route map's compiled `interface' value. */
2040 static void ospf6_routemap_rule_match_interface_free(void *rule
)
2042 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2045 /* Route map commands for interface matching. */
2046 static const struct route_map_rule_cmd
2047 ospf6_routemap_rule_match_interface_cmd
= {
2049 ospf6_routemap_rule_match_interface
,
2050 ospf6_routemap_rule_match_interface_compile
,
2051 ospf6_routemap_rule_match_interface_free
2054 /* Match function for matching route tags */
2055 static enum route_map_cmd_result_t
2056 ospf6_routemap_rule_match_tag(void *rule
, const struct prefix
*p
, void *object
)
2058 route_tag_t
*tag
= rule
;
2059 struct ospf6_route
*route
= object
;
2060 struct ospf6_external_info
*info
= route
->route_option
;
2062 if (info
->tag
== *tag
)
2065 return RMAP_NOMATCH
;
2068 static const struct route_map_rule_cmd
2069 ospf6_routemap_rule_match_tag_cmd
= {
2071 ospf6_routemap_rule_match_tag
,
2072 route_map_rule_tag_compile
,
2073 route_map_rule_tag_free
,
2076 static enum route_map_cmd_result_t
2077 ospf6_routemap_rule_set_metric_type(void *rule
, const struct prefix
*prefix
,
2080 char *metric_type
= rule
;
2081 struct ospf6_route
*route
= object
;
2083 if (strcmp(metric_type
, "type-2") == 0)
2084 route
->path
.metric_type
= 2;
2086 route
->path
.metric_type
= 1;
2091 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg
)
2093 if (strcmp(arg
, "type-2") && strcmp(arg
, "type-1"))
2095 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2098 static void ospf6_routemap_rule_set_metric_type_free(void *rule
)
2100 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2103 static const struct route_map_rule_cmd
2104 ospf6_routemap_rule_set_metric_type_cmd
= {
2106 ospf6_routemap_rule_set_metric_type
,
2107 ospf6_routemap_rule_set_metric_type_compile
,
2108 ospf6_routemap_rule_set_metric_type_free
,
2111 static enum route_map_cmd_result_t
2112 ospf6_routemap_rule_set_metric(void *rule
, const struct prefix
*prefix
,
2115 char *metric
= rule
;
2116 struct ospf6_route
*route
= object
;
2118 route
->path
.cost
= atoi(metric
);
2122 static void *ospf6_routemap_rule_set_metric_compile(const char *arg
)
2126 metric
= strtoul(arg
, &endp
, 0);
2127 if (metric
> OSPF_LS_INFINITY
|| *endp
!= '\0')
2129 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2132 static void ospf6_routemap_rule_set_metric_free(void *rule
)
2134 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2137 static const struct route_map_rule_cmd
2138 ospf6_routemap_rule_set_metric_cmd
= {
2140 ospf6_routemap_rule_set_metric
,
2141 ospf6_routemap_rule_set_metric_compile
,
2142 ospf6_routemap_rule_set_metric_free
,
2145 static enum route_map_cmd_result_t
2146 ospf6_routemap_rule_set_forwarding(void *rule
, const struct prefix
*prefix
,
2149 char *forwarding
= rule
;
2150 struct ospf6_route
*route
= object
;
2151 struct ospf6_external_info
*info
= route
->route_option
;
2153 if (inet_pton(AF_INET6
, forwarding
, &info
->forwarding
) != 1) {
2154 memset(&info
->forwarding
, 0, sizeof(struct in6_addr
));
2161 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg
)
2164 if (inet_pton(AF_INET6
, arg
, &a
) != 1)
2166 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2169 static void ospf6_routemap_rule_set_forwarding_free(void *rule
)
2171 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2174 static const struct route_map_rule_cmd
2175 ospf6_routemap_rule_set_forwarding_cmd
= {
2176 "forwarding-address",
2177 ospf6_routemap_rule_set_forwarding
,
2178 ospf6_routemap_rule_set_forwarding_compile
,
2179 ospf6_routemap_rule_set_forwarding_free
,
2182 static enum route_map_cmd_result_t
2183 ospf6_routemap_rule_set_tag(void *rule
, const struct prefix
*p
, void *object
)
2185 route_tag_t
*tag
= rule
;
2186 struct ospf6_route
*route
= object
;
2187 struct ospf6_external_info
*info
= route
->route_option
;
2193 static const struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd
= {
2195 ospf6_routemap_rule_set_tag
,
2196 route_map_rule_tag_compile
,
2197 route_map_rule_tag_free
,
2200 /* add "set metric-type" */
2201 DEFUN_YANG (ospf6_routemap_set_metric_type
, ospf6_routemap_set_metric_type_cmd
,
2202 "set metric-type <type-1|type-2>",
2204 "Type of metric for destination routing protocol\n"
2205 "OSPF[6] external type 1 metric\n"
2206 "OSPF[6] external type 2 metric\n")
2208 char *ext
= argv
[2]->text
;
2211 "./set-action[action='frr-ospf-route-map:metric-type']";
2212 char xpath_value
[XPATH_MAXLEN
];
2214 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
2215 snprintf(xpath_value
, sizeof(xpath_value
),
2216 "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath
);
2217 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, ext
);
2218 return nb_cli_apply_changes(vty
, NULL
);
2221 /* delete "set metric-type" */
2222 DEFUN_YANG (ospf6_routemap_no_set_metric_type
, ospf6_routemap_no_set_metric_type_cmd
,
2223 "no set metric-type [<type-1|type-2>]",
2226 "Type of metric for destination routing protocol\n"
2227 "OSPF[6] external type 1 metric\n"
2228 "OSPF[6] external type 2 metric\n")
2231 "./set-action[action='frr-ospf-route-map:metric-type']";
2233 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
2234 return nb_cli_apply_changes(vty
, NULL
);
2237 /* add "set forwarding-address" */
2238 DEFUN_YANG (ospf6_routemap_set_forwarding
, ospf6_routemap_set_forwarding_cmd
,
2239 "set forwarding-address X:X::X:X",
2241 "Forwarding Address\n"
2246 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2247 char xpath_value
[XPATH_MAXLEN
];
2249 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
2250 snprintf(xpath_value
, sizeof(xpath_value
),
2251 "%s/rmap-set-action/frr-ospf6-route-map:ipv6-address", xpath
);
2252 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
,
2253 argv
[idx_ipv6
]->arg
);
2254 return nb_cli_apply_changes(vty
, NULL
);
2257 /* delete "set forwarding-address" */
2258 DEFUN_YANG (ospf6_routemap_no_set_forwarding
, ospf6_routemap_no_set_forwarding_cmd
,
2259 "no set forwarding-address [X:X::X:X]",
2262 "Forwarding Address\n"
2266 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2268 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
2269 return nb_cli_apply_changes(vty
, NULL
);
2272 static void ospf6_routemap_init(void)
2276 route_map_add_hook(ospf6_asbr_routemap_update
);
2277 route_map_delete_hook(ospf6_asbr_routemap_update
);
2278 route_map_event_hook(ospf6_asbr_routemap_event
);
2280 route_map_set_metric_hook(generic_set_add
);
2281 route_map_no_set_metric_hook(generic_set_delete
);
2283 route_map_set_tag_hook(generic_set_add
);
2284 route_map_no_set_tag_hook(generic_set_delete
);
2286 route_map_match_tag_hook(generic_match_add
);
2287 route_map_no_match_tag_hook(generic_match_delete
);
2289 route_map_match_ipv6_address_prefix_list_hook(generic_match_add
);
2290 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete
);
2292 route_map_match_interface_hook(generic_match_add
);
2293 route_map_no_match_interface_hook(generic_match_delete
);
2295 route_map_install_match(
2296 &ospf6_routemap_rule_match_address_prefixlist_cmd
);
2297 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd
);
2298 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd
);
2300 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd
);
2301 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd
);
2302 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd
);
2303 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd
);
2305 /* ASE Metric Type (e.g. Type-1/Type-2) */
2306 install_element(RMAP_NODE
, &ospf6_routemap_set_metric_type_cmd
);
2307 install_element(RMAP_NODE
, &ospf6_routemap_no_set_metric_type_cmd
);
2310 install_element(RMAP_NODE
, &ospf6_routemap_set_forwarding_cmd
);
2311 install_element(RMAP_NODE
, &ospf6_routemap_no_set_forwarding_cmd
);
2315 /* Display functions */
2316 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
2317 char *buf
, int buflen
,
2320 struct ospf6_as_external_lsa
*external
;
2321 struct in6_addr in6
;
2322 int prefix_length
= 0;
2326 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
2330 ospf6_prefix_in6_addr(&in6
, external
,
2332 prefix_length
= external
->prefix
.prefix_length
;
2334 in6
= *((struct in6_addr
2335 *)((caddr_t
)external
2337 ospf6_as_external_lsa
)
2338 + OSPF6_PREFIX_SPACE(
2343 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
2344 if (prefix_length
) {
2345 snprintf(tbuf
, sizeof(tbuf
), "/%d",
2347 strlcat(buf
, tbuf
, buflen
);
2354 static int ospf6_as_external_lsa_show(struct vty
*vty
, struct ospf6_lsa
*lsa
,
2355 json_object
*json_obj
, bool use_json
)
2357 struct ospf6_as_external_lsa
*external
;
2360 assert(lsa
->header
);
2361 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
2365 snprintf(buf
, sizeof(buf
), "%c%c%c",
2366 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
) ? 'E'
2368 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
) ? 'F'
2370 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
) ? 'T'
2374 json_object_string_add(json_obj
, "bits", buf
);
2375 json_object_int_add(json_obj
, "metric",
2376 (unsigned long)OSPF6_ASBR_METRIC(external
));
2377 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
,
2379 json_object_string_add(json_obj
, "prefixOptions", buf
);
2380 json_object_int_add(
2381 json_obj
, "referenceLsType",
2382 ntohs(external
->prefix
.prefix_refer_lstype
));
2383 json_object_string_add(json_obj
, "prefix",
2384 ospf6_as_external_lsa_get_prefix_str(
2385 lsa
, buf
, sizeof(buf
), 0));
2387 /* Forwarding-Address */
2388 json_object_boolean_add(
2389 json_obj
, "forwardingAddressPresent",
2390 CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
));
2391 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
2392 json_object_string_add(
2393 json_obj
, "forwardingAddress",
2394 ospf6_as_external_lsa_get_prefix_str(
2395 lsa
, buf
, sizeof(buf
), 1));
2398 json_object_boolean_add(
2399 json_obj
, "tagPresent",
2400 CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
));
2401 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
2402 json_object_int_add(json_obj
, "tag",
2403 ospf6_as_external_lsa_get_tag(lsa
));
2405 vty_out(vty
, " Bits: %s\n", buf
);
2406 vty_out(vty
, " Metric: %5lu\n",
2407 (unsigned long)OSPF6_ASBR_METRIC(external
));
2409 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
,
2411 vty_out(vty
, " Prefix Options: %s\n", buf
);
2413 vty_out(vty
, " Referenced LSType: %d\n",
2414 ntohs(external
->prefix
.prefix_refer_lstype
));
2416 vty_out(vty
, " Prefix: %s\n",
2417 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
,
2420 /* Forwarding-Address */
2421 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
2422 vty_out(vty
, " Forwarding-Address: %s\n",
2423 ospf6_as_external_lsa_get_prefix_str(
2424 lsa
, buf
, sizeof(buf
), 1));
2428 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
2429 vty_out(vty
, " Tag: %" ROUTE_TAG_PRI
"\n",
2430 ospf6_as_external_lsa_get_tag(lsa
));
2437 static void ospf6_asbr_external_route_show(struct vty
*vty
,
2438 struct ospf6_route
*route
,
2439 json_object
*json_array
,
2442 struct ospf6_external_info
*info
= route
->route_option
;
2443 char prefix
[PREFIX2STR_BUFFER
], id
[16], forwarding
[64];
2445 json_object
*json_route
;
2448 prefix2str(&route
->prefix
, prefix
, sizeof(prefix
));
2449 tmp_id
= ntohl(info
->id
);
2450 inet_ntop(AF_INET
, &tmp_id
, id
, sizeof(id
));
2451 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
2452 inet_ntop(AF_INET6
, &info
->forwarding
, forwarding
,
2453 sizeof(forwarding
));
2455 snprintf(forwarding
, sizeof(forwarding
), ":: (ifindex %d)",
2456 ospf6_route_get_first_nh_index(route
));
2459 json_route
= json_object_new_object();
2460 snprintf(route_type
, sizeof(route_type
), "%c",
2461 zebra_route_char(info
->type
));
2462 json_object_string_add(json_route
, "routeType", route_type
);
2463 json_object_string_add(json_route
, "destination", prefix
);
2464 json_object_string_add(json_route
, "id", id
);
2465 json_object_int_add(json_route
, "metricType",
2466 route
->path
.metric_type
);
2467 json_object_int_add(
2468 json_route
, "routeCost",
2469 (unsigned long)(route
->path
.metric_type
== 2
2470 ? route
->path
.u
.cost_e2
2471 : route
->path
.cost
));
2472 json_object_string_add(json_route
, "forwarding", forwarding
);
2474 json_object_array_add(json_array
, json_route
);
2477 vty_out(vty
, "%c %-32pFX %-15s type-%d %5lu %s\n",
2478 zebra_route_char(info
->type
), &route
->prefix
, id
,
2479 route
->path
.metric_type
,
2480 (unsigned long)(route
->path
.metric_type
== 2
2481 ? route
->path
.u
.cost_e2
2482 : route
->path
.cost
),
2486 DEFUN(show_ipv6_ospf6_redistribute
, show_ipv6_ospf6_redistribute_cmd
,
2487 "show ipv6 ospf6 [vrf <NAME|all>] redistribute [json]",
2488 SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
2490 "redistributing External information\n" JSON_STR
)
2492 struct ospf6_route
*route
;
2493 struct ospf6
*ospf6
= NULL
;
2494 json_object
*json
= NULL
;
2495 bool uj
= use_json(argc
, argv
);
2496 struct listnode
*node
;
2497 const char *vrf_name
= NULL
;
2498 bool all_vrf
= false;
2501 json_object
*json_array_routes
= NULL
;
2502 json_object
*json_array_redistribute
= NULL
;
2504 OSPF6_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
2507 json
= json_object_new_object();
2508 json_array_routes
= json_object_new_array();
2509 json_array_redistribute
= json_object_new_array();
2512 for (ALL_LIST_ELEMENTS_RO(om6
->ospf6
, node
, ospf6
)) {
2514 || ((ospf6
->name
== NULL
&& vrf_name
== NULL
)
2515 || (ospf6
->name
&& vrf_name
2516 && strcmp(ospf6
->name
, vrf_name
) == 0))) {
2517 ospf6_redistribute_show_config(
2518 vty
, ospf6
, json_array_redistribute
, json
, uj
);
2520 for (route
= ospf6_route_head(ospf6
->external_table
);
2521 route
; route
= ospf6_route_next(route
)) {
2522 ospf6_asbr_external_route_show(
2523 vty
, route
, json_array_routes
, uj
);
2527 json_object_object_add(json
, "routes",
2529 vty_json(vty
, json
);
2537 OSPF6_CMD_CHECK_VRF(uj
, all_vrf
, ospf6
);
2542 static struct ospf6_lsa_handler as_external_handler
= {
2543 .lh_type
= OSPF6_LSTYPE_AS_EXTERNAL
,
2544 .lh_name
= "AS-External",
2545 .lh_short_name
= "ASE",
2546 .lh_show
= ospf6_as_external_lsa_show
,
2547 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
2550 static struct ospf6_lsa_handler nssa_external_handler
= {
2551 .lh_type
= OSPF6_LSTYPE_TYPE_7
,
2553 .lh_short_name
= "Type7",
2554 .lh_show
= ospf6_as_external_lsa_show
,
2555 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
2558 void ospf6_asbr_init(void)
2560 ospf6_routemap_init();
2562 ospf6_install_lsa_handler(&as_external_handler
);
2563 ospf6_install_lsa_handler(&nssa_external_handler
);
2565 install_element(VIEW_NODE
, &show_ipv6_ospf6_redistribute_cmd
);
2567 install_element(OSPF6_NODE
, &ospf6_default_route_originate_cmd
);
2568 install_element(OSPF6_NODE
,
2569 &no_ospf6_default_information_originate_cmd
);
2570 install_element(OSPF6_NODE
, &ospf6_redistribute_cmd
);
2571 install_element(OSPF6_NODE
, &no_ospf6_redistribute_cmd
);
2574 void ospf6_asbr_redistribute_disable(struct ospf6
*ospf6
)
2577 struct ospf6_redist
*red
;
2579 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
2580 red
= ospf6_redist_lookup(ospf6
, type
, 0);
2583 if (type
== ZEBRA_ROUTE_OSPF6
)
2585 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
2586 ospf6_redist_del(ospf6
, red
, type
);
2588 red
= ospf6_redist_lookup(ospf6
, DEFAULT_ROUTE
, 0);
2590 ospf6_asbr_routemap_unset(red
);
2591 ospf6_redist_del(ospf6
, red
, type
);
2592 ospf6_redistribute_default_set(ospf6
, DEFAULT_ORIGINATE_NONE
);
2596 void ospf6_asbr_redistribute_reset(struct ospf6
*ospf6
)
2599 struct ospf6_redist
*red
;
2600 char buf
[RMAP_NAME_MAXLEN
];
2602 for (type
= 0; type
<= ZEBRA_ROUTE_MAX
; type
++) {
2604 if (type
== ZEBRA_ROUTE_OSPF6
)
2606 red
= ospf6_redist_lookup(ospf6
, type
, 0);
2610 if (type
== DEFAULT_ROUTE
) {
2611 ospf6_redistribute_default_set(
2612 ospf6
, ospf6
->default_originate
);
2615 if (ROUTEMAP_NAME(red
))
2616 strlcpy(buf
, ROUTEMAP_NAME(red
), sizeof(buf
));
2618 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
2620 ospf6_asbr_routemap_set(red
, buf
);
2621 ospf6_asbr_redistribute_set(ospf6
, type
);
2625 void ospf6_asbr_terminate(void)
2627 /* Cleanup route maps */
2631 DEFUN (debug_ospf6_asbr
,
2632 debug_ospf6_asbr_cmd
,
2636 "Debug OSPFv3 ASBR function\n"
2639 OSPF6_DEBUG_ASBR_ON();
2643 DEFUN (no_debug_ospf6_asbr
,
2644 no_debug_ospf6_asbr_cmd
,
2645 "no debug ospf6 asbr",
2649 "Debug OSPFv3 ASBR function\n"
2652 OSPF6_DEBUG_ASBR_OFF();
2656 int config_write_ospf6_debug_asbr(struct vty
*vty
)
2658 if (IS_OSPF6_DEBUG_ASBR
)
2659 vty_out(vty
, "debug ospf6 asbr\n");
2663 static void ospf6_default_originate_write(struct vty
*vty
, struct ospf6
*o
)
2665 struct ospf6_redist
*red
;
2667 vty_out(vty
, " default-information originate");
2668 if (o
->default_originate
== DEFAULT_ORIGINATE_ALWAYS
)
2669 vty_out(vty
, " always");
2671 red
= ospf6_redist_lookup(o
, DEFAULT_ROUTE
, 0);
2677 if (red
->dmetric
.value
>= 0)
2678 vty_out(vty
, " metric %d", red
->dmetric
.value
);
2680 if (red
->dmetric
.type
>= 0)
2681 vty_out(vty
, " metric-type %d", red
->dmetric
.type
);
2683 if (ROUTEMAP_NAME(red
))
2684 vty_out(vty
, " route-map %s", ROUTEMAP_NAME(red
));
2689 int ospf6_distribute_config_write(struct vty
*vty
, struct ospf6
*o
)
2694 /* Print default originate configuration. */
2695 if (o
->default_originate
!= DEFAULT_ORIGINATE_NONE
)
2696 ospf6_default_originate_write(vty
, o
);
2701 void install_element_ospf6_debug_asbr(void)
2703 install_element(ENABLE_NODE
, &debug_ospf6_asbr_cmd
);
2704 install_element(ENABLE_NODE
, &no_debug_ospf6_asbr_cmd
);
2705 install_element(CONFIG_NODE
, &debug_ospf6_asbr_cmd
);
2706 install_element(CONFIG_NODE
, &no_debug_ospf6_asbr_cmd
);
2709 /* ASBR Summarisation */
2710 void ospf6_fill_aggr_route_details(struct ospf6
*ospf6
,
2711 struct ospf6_external_aggr_rt
*aggr
)
2713 struct ospf6_route
*rt_aggr
= aggr
->route
;
2714 struct ospf6_external_info
*ei_aggr
= rt_aggr
->route_option
;
2716 rt_aggr
->prefix
= aggr
->p
;
2717 ei_aggr
->tag
= aggr
->tag
;
2719 ei_aggr
->id
= aggr
->id
;
2721 /* When metric is not configured, apply the default metric */
2722 rt_aggr
->path
.cost
= ((aggr
->metric
== -1) ?
2723 DEFAULT_DEFAULT_METRIC
2724 : (unsigned int)(aggr
->metric
));
2725 rt_aggr
->path
.metric_type
= aggr
->mtype
;
2727 rt_aggr
->path
.origin
.id
= htonl(aggr
->id
);
2731 ospf6_summary_add_aggr_route_and_blackhole(struct ospf6
*ospf6
,
2732 struct ospf6_external_aggr_rt
*aggr
)
2734 struct ospf6_route
*rt_aggr
;
2735 struct ospf6_route
*old_rt
= NULL
;
2736 struct ospf6_external_info
*info
;
2738 /* Check if a route is already present. */
2740 old_rt
= aggr
->route
;
2742 /* Create summary route and save it. */
2743 rt_aggr
= ospf6_route_create(ospf6
);
2744 rt_aggr
->type
= OSPF6_DEST_TYPE_NETWORK
;
2745 /* Needed to install route while calling zebra api */
2746 SET_FLAG(rt_aggr
->flag
, OSPF6_ROUTE_BEST
);
2748 info
= XCALLOC(MTYPE_OSPF6_EXTERNAL_INFO
, sizeof(*info
));
2749 rt_aggr
->route_option
= info
;
2750 aggr
->route
= rt_aggr
;
2752 /* Prepare the external_info for aggregator
2753 * Fill all the details which will get advertised
2755 ospf6_fill_aggr_route_details(ospf6
, aggr
);
2757 /* Add next-hop to Null interface. */
2758 ospf6_add_route_nexthop_blackhole(rt_aggr
);
2760 /* Free the old route, if any. */
2762 ospf6_zebra_route_update_remove(old_rt
, ospf6
);
2764 if (old_rt
->route_option
)
2765 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
, old_rt
->route_option
);
2767 ospf6_route_delete(old_rt
);
2770 ospf6_zebra_route_update_add(rt_aggr
, ospf6
);
2773 static void ospf6_originate_new_aggr_lsa(struct ospf6
*ospf6
,
2774 struct ospf6_external_aggr_rt
*aggr
)
2776 struct prefix prefix_id
;
2777 struct ospf6_lsa
*lsa
= NULL
;
2779 if (IS_OSPF6_DEBUG_AGGR
)
2780 zlog_debug("%s: Originate new aggregate route(%pFX)", __func__
,
2783 aggr
->id
= ospf6
->external_id
++;
2785 if (IS_OSPF6_DEBUG_AGGR
)
2787 "Advertise AS-External Id:%pI4 prefix %pFX metric %u",
2788 &prefix_id
.u
.prefix4
, &aggr
->p
, aggr
->metric
);
2790 ospf6_summary_add_aggr_route_and_blackhole(ospf6
, aggr
);
2792 /* Originate summary LSA */
2793 lsa
= ospf6_originate_type5_type7_lsas(aggr
->route
, ospf6
);
2795 if (IS_OSPF6_DEBUG_AGGR
)
2796 zlog_debug("%s: Set the origination bit for aggregator",
2798 SET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
2803 ospf6_aggr_handle_advertise_change(struct ospf6
*ospf6
,
2804 struct ospf6_external_aggr_rt
*aggr
)
2806 /* Check if advertise option modified. */
2807 if (CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
2808 if (IS_OSPF6_DEBUG_AGGR
)
2809 zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
2811 ospf6_asbr_summary_remove_lsa_and_route(ospf6
, aggr
);
2816 /* There are no routes present under this aggregation config, hence
2817 * nothing to originate here
2819 if (OSPF6_EXTERNAL_RT_COUNT(aggr
) == 0) {
2820 if (IS_OSPF6_DEBUG_AGGR
)
2821 zlog_debug("%s: No routes present under this aggregation",
2826 if (!CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
)) {
2827 if (IS_OSPF6_DEBUG_AGGR
)
2828 zlog_debug("%s: Now it is advertisable",
2831 ospf6_originate_new_aggr_lsa(ospf6
, aggr
);
2838 ospf6_originate_summary_lsa(struct ospf6
*ospf6
,
2839 struct ospf6_external_aggr_rt
*aggr
,
2840 struct ospf6_route
*rt
)
2842 struct ospf6_lsa
*lsa
= NULL
, *aggr_lsa
= NULL
;
2843 struct ospf6_external_info
*info
= NULL
;
2844 struct ospf6_external_aggr_rt
*old_aggr
;
2845 struct ospf6_as_external_lsa
*external
;
2846 struct ospf6_route
*rt_aggr
= NULL
;
2847 route_tag_t tag
= 0;
2848 unsigned int metric
= 0;
2851 if (IS_OSPF6_DEBUG_AGGR
)
2852 zlog_debug("%s: Prepare to originate Summary route(%pFX)",
2853 __func__
, &aggr
->p
);
2855 /* This case to handle when the overlapping aggregator address
2856 * is available. Best match will be considered.So need to delink
2857 * from old aggregator and link to the new aggr.
2859 if (rt
->aggr_route
) {
2860 if (rt
->aggr_route
!= aggr
) {
2861 old_aggr
= rt
->aggr_route
;
2862 ospf6_unlink_route_from_aggr(ospf6
, old_aggr
, rt
);
2866 /* Add the external route to hash table */
2867 ospf6_link_route_to_aggr(aggr
, rt
);
2869 /* The key for ID field is a running number and not prefix */
2870 info
= rt
->route_option
;
2873 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
2874 htonl(info
->id
), ospf6
->router_id
,
2877 aggr_lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
2878 htonl(aggr
->id
), ospf6
->router_id
, ospf6
->lsdb
);
2880 if (IS_OSPF6_DEBUG_AGGR
)
2881 zlog_debug("%s: Aggr LSA ID: %d flags %x.",
2882 __func__
, aggr
->id
, aggr
->aggrflags
);
2883 /* Don't originate external LSA,
2884 * If it is configured not to advertise.
2886 if (CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
2887 /* If it is already originated as external LSA,
2888 * But, it is configured not to advertise then
2889 * flush the originated external lsa.
2892 if (IS_OSPF6_DEBUG_AGGR
)
2893 zlog_debug("%s: Purge the external LSA %s.",
2894 __func__
, lsa
->name
);
2895 ospf6_external_lsa_purge(ospf6
, lsa
);
2897 rt
->path
.origin
.id
= 0;
2901 if (IS_OSPF6_DEBUG_AGGR
)
2902 zlog_debug("%s: Purge the aggr external LSA %s.",
2903 __func__
, lsa
->name
);
2904 ospf6_asbr_summary_remove_lsa_and_route(ospf6
, aggr
);
2907 UNSET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
2909 if (IS_OSPF6_DEBUG_AGGR
)
2910 zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
2915 /* Summary route already originated,
2918 if (CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
)) {
2921 "%s: Could not refresh/originate %pFX",
2924 /* Remove the assert later */
2929 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END
2931 metric
= (unsigned long)OSPF6_ASBR_METRIC(external
);
2932 tag
= ospf6_as_external_lsa_get_tag(aggr_lsa
);
2933 mtype
= CHECK_FLAG(external
->bits_metric
,
2934 OSPF6_ASBR_BIT_E
) ? 2 : 1;
2936 /* Prepare the external_info for aggregator */
2937 ospf6_fill_aggr_route_details(ospf6
, aggr
);
2938 rt_aggr
= aggr
->route
;
2939 /* If tag/metric/metric-type modified , then re-originate the
2940 * route with modified tag/metric/metric-type details.
2942 if ((tag
!= aggr
->tag
)
2943 || (metric
!= (unsigned int)rt_aggr
->path
.cost
)
2944 || (mtype
!= aggr
->mtype
)) {
2946 if (IS_OSPF6_DEBUG_AGGR
)
2948 "%s: Routetag(old:%d new:%d)/Metric(o:%u,n:%u)/mtype(o:%d n:%d) modified,So refresh the summary route.(%pFX)",
2949 __func__
, tag
, aggr
->tag
,
2955 aggr_lsa
= ospf6_originate_type5_type7_lsas(aggr
->route
,
2958 SET_FLAG(aggr
->aggrflags
,
2959 OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
2965 /* If the external route prefix same as aggregate route
2966 * and if external route is already originated as TYPE-5
2967 * then just update the aggr info and remove the route info
2969 if (lsa
&& prefix_same(&aggr
->p
, &rt
->prefix
)) {
2970 if (IS_OSPF6_DEBUG_AGGR
)
2972 "%s: Route prefix is same as aggr so no need to re-originate LSA(%pFX)",
2973 __PRETTY_FUNCTION__
, &aggr
->p
);
2975 aggr
->id
= info
->id
;
2977 rt
->path
.origin
.id
= 0;
2979 ospf6_summary_add_aggr_route_and_blackhole(ospf6
, aggr
);
2981 SET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
2986 ospf6_originate_new_aggr_lsa(ospf6
, aggr
);
2989 static void ospf6_aggr_handle_external_info(void *data
)
2991 struct ospf6_route
*rt
= (struct ospf6_route
*)data
;
2992 struct ospf6_external_aggr_rt
*aggr
= NULL
;
2993 struct ospf6_lsa
*lsa
= NULL
;
2994 struct ospf6_external_info
*info
;
2995 struct ospf6
*ospf6
= NULL
;
2997 rt
->aggr_route
= NULL
;
2999 rt
->to_be_processed
= true;
3001 if (IS_OSPF6_DEBUG_ASBR
|| IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL
))
3002 zlog_debug("%s: Handle external route for origination/refresh (%pFX)",
3009 aggr
= ospf6_external_aggr_match(ospf6
,
3012 ospf6_originate_summary_lsa(ospf6
, aggr
, rt
);
3016 info
= rt
->route_option
;
3018 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
3019 htonl(info
->id
), ospf6
->router_id
,
3022 if (IS_OSPF6_DEBUG_AGGR
)
3023 zlog_debug("%s: LSA found, refresh it",
3025 EVENT_OFF(lsa
->refresh
);
3026 event_add_event(master
, ospf6_lsa_refresh
, lsa
, 0,
3032 info
->id
= ospf6
->external_id
++;
3033 rt
->path
.origin
.id
= htonl(info
->id
);
3035 (void)ospf6_originate_type5_type7_lsas(rt
, ospf6
);
3038 void ospf6_asbr_summary_config_delete(struct ospf6
*ospf6
,
3039 struct route_node
*rn
)
3041 struct ospf6_external_aggr_rt
*aggr
= rn
->info
;
3043 if (IS_OSPF6_DEBUG_AGGR
)
3044 zlog_debug("%s: Deleting Aggregate route (%pFX)",
3048 ospf6_asbr_summary_remove_lsa_and_route(ospf6
, aggr
);
3051 route_unlock_node(rn
);
3055 ospf6_handle_external_aggr_modify(struct ospf6
*ospf6
,
3056 struct ospf6_external_aggr_rt
*aggr
)
3058 struct ospf6_lsa
*lsa
= NULL
;
3059 struct ospf6_as_external_lsa
*asel
= NULL
;
3060 struct ospf6_route
*rt_aggr
;
3061 unsigned int metric
= 0;
3062 route_tag_t tag
= 0;
3065 lsa
= ospf6_lsdb_lookup(
3066 htons(OSPF6_LSTYPE_AS_EXTERNAL
),
3067 htonl(aggr
->id
), ospf6
->router_id
,
3071 "%s: Could not refresh/originate %pFX",
3075 return OSPF6_FAILURE
;
3078 asel
= (struct ospf6_as_external_lsa
*)
3079 OSPF6_LSA_HEADER_END(lsa
->header
);
3080 metric
= (unsigned long)OSPF6_ASBR_METRIC(asel
);
3081 tag
= ospf6_as_external_lsa_get_tag(lsa
);
3082 mtype
= CHECK_FLAG(asel
->bits_metric
,
3083 OSPF6_ASBR_BIT_E
) ? 2 : 1;
3085 /* Fill all the details for advertisement */
3086 ospf6_fill_aggr_route_details(ospf6
, aggr
);
3087 rt_aggr
= aggr
->route
;
3088 /* If tag/metric/metric-type modified , then
3089 * re-originate the route with modified
3090 * tag/metric/metric-type details.
3092 if ((tag
!= aggr
->tag
)
3094 != (unsigned int)rt_aggr
->path
.cost
)
3097 if (IS_OSPF6_DEBUG_AGGR
)
3099 "%s: Changed tag(old:%d new:%d)/metric(o:%u n:%d)/mtype(o:%d n:%d),So refresh the summary route.(%pFX)",
3103 (unsigned int)rt_aggr
->path
.cost
,
3107 (void)ospf6_originate_type5_type7_lsas(
3112 return OSPF6_SUCCESS
;
3115 static void ospf6_handle_external_aggr_update(struct ospf6
*ospf6
)
3117 struct route_node
*rn
= NULL
;
3120 if (IS_OSPF6_DEBUG_AGGR
)
3121 zlog_debug("%s: Process modified aggregators.", __func__
);
3123 for (rn
= route_top(ospf6
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
3124 struct ospf6_external_aggr_rt
*aggr
;
3131 if (aggr
->action
== OSPF6_ROUTE_AGGR_DEL
) {
3132 aggr
->action
= OSPF6_ROUTE_AGGR_NONE
;
3133 ospf6_asbr_summary_config_delete(ospf6
, rn
);
3135 hash_clean_and_free(&aggr
->match_extnl_hash
,
3136 ospf6_aggr_handle_external_info
);
3138 XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR
, aggr
);
3140 } else if (aggr
->action
== OSPF6_ROUTE_AGGR_MODIFY
) {
3142 aggr
->action
= OSPF6_ROUTE_AGGR_NONE
;
3144 /* Check if tag/metric/metric-type modified */
3145 if (CHECK_FLAG(aggr
->aggrflags
,
3146 OSPF6_EXTERNAL_AGGRT_ORIGINATED
)
3147 && !CHECK_FLAG(aggr
->aggrflags
,
3148 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
3150 ret
= ospf6_handle_external_aggr_modify(ospf6
,
3152 if (ret
== OSPF6_FAILURE
)
3156 /* Advertise option modified ?
3157 * If so, handled it here.
3159 ospf6_aggr_handle_advertise_change(ospf6
, aggr
);
3164 static void ospf6_aggr_unlink_external_info(void *data
)
3166 struct ospf6_route
*rt
= (struct ospf6_route
*)data
;
3168 rt
->aggr_route
= NULL
;
3170 rt
->to_be_processed
= true;
3173 void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt
*aggr
)
3175 hash_clean_and_free(&aggr
->match_extnl_hash
,
3176 ospf6_aggr_unlink_external_info
);
3178 if (IS_OSPF6_DEBUG_AGGR
)
3179 zlog_debug("%s: Release the aggregator Address(%pFX)",
3183 XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR
, aggr
);
3187 ospf6_delete_all_marked_aggregators(struct ospf6
*ospf6
)
3189 struct route_node
*rn
= NULL
;
3190 struct ospf6_external_aggr_rt
*aggr
;
3192 /* Loop through all the aggregators, Delete all aggregators
3193 * which are marked as DELETE. Set action to NONE for remaining
3196 for (rn
= route_top(ospf6
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
3202 if (aggr
->action
!= OSPF6_ROUTE_AGGR_DEL
) {
3203 aggr
->action
= OSPF6_ROUTE_AGGR_NONE
;
3206 ospf6_asbr_summary_config_delete(ospf6
, rn
);
3207 ospf6_external_aggregator_free(aggr
);
3211 static void ospf6_handle_exnl_rt_after_aggr_del(struct ospf6
*ospf6
,
3212 struct ospf6_route
*rt
)
3214 struct ospf6_lsa
*lsa
;
3216 /* Process only marked external routes.
3217 * These routes were part of a deleted
3218 * aggregator.So, originate now.
3220 if (!rt
->to_be_processed
)
3223 rt
->to_be_processed
= false;
3225 lsa
= ospf6_find_external_lsa(ospf6
, &rt
->prefix
);
3228 EVENT_OFF(lsa
->refresh
);
3229 event_add_event(master
, ospf6_lsa_refresh
, lsa
, 0,
3232 if (IS_OSPF6_DEBUG_AGGR
)
3233 zlog_debug("%s: Originate external route(%pFX)",
3237 (void)ospf6_originate_type5_type7_lsas(rt
, ospf6
);
3241 static void ospf6_handle_aggregated_exnl_rt(struct ospf6
*ospf6
,
3242 struct ospf6_external_aggr_rt
*aggr
,
3243 struct ospf6_route
*rt
)
3245 struct ospf6_lsa
*lsa
;
3246 struct ospf6_as_external_lsa
*ext_lsa
;
3247 struct ospf6_external_info
*info
;
3249 /* Handling the case where the external route prefix
3250 * and aggegate prefix is same
3251 * If same don't flush the originated external LSA.
3253 if (prefix_same(&aggr
->p
, &rt
->prefix
)) {
3254 if (IS_OSPF6_DEBUG_AGGR
)
3255 zlog_debug("%s: External Route prefix same as Aggregator(%pFX), so don't flush.",
3262 info
= rt
->route_option
;
3265 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
3266 htonl(info
->id
), ospf6
->router_id
, ospf6
->lsdb
);
3268 ext_lsa
= (struct ospf6_as_external_lsa
3269 *)((char *)(lsa
->header
)
3270 + sizeof(struct ospf6_lsa_header
));
3272 if (rt
->prefix
.prefixlen
!= ext_lsa
->prefix
.prefix_length
)
3275 ospf6_external_lsa_purge(ospf6
, lsa
);
3277 /* Resetting the ID of route */
3278 rt
->path
.origin
.id
= 0;
3284 ospf6_handle_external_aggr_add(struct ospf6
*ospf6
)
3286 struct ospf6_route
*rt
= NULL
;
3287 struct ospf6_external_info
*ei
= NULL
;
3288 struct ospf6_external_aggr_rt
*aggr
;
3290 /* Delete all the aggregators which are marked as
3291 * OSPF6_ROUTE_AGGR_DEL.
3293 ospf6_delete_all_marked_aggregators(ospf6
);
3295 for (rt
= ospf6_route_head(ospf6
->external_table
); rt
;
3296 rt
= ospf6_route_next(rt
)) {
3297 ei
= rt
->route_option
;
3301 if (is_default_prefix(&rt
->prefix
))
3304 aggr
= ospf6_external_aggr_match(ospf6
,
3307 /* If matching aggregator found, Add
3308 * the external route refrenace to the
3309 * aggregator and originate the aggr
3310 * route if it is advertisable.
3311 * flush the external LSA if it is
3312 * already originated for this external
3316 ospf6_originate_summary_lsa(ospf6
, aggr
, rt
);
3318 /* All aggregated external rts
3321 ospf6_handle_aggregated_exnl_rt(
3326 /* External routes which are only out
3327 * of aggregation will be handled here.
3329 ospf6_handle_exnl_rt_after_aggr_del(
3334 static void ospf6_asbr_summary_process(struct event
*thread
)
3336 struct ospf6
*ospf6
= EVENT_ARG(thread
);
3339 operation
= ospf6
->aggr_action
;
3341 if (IS_OSPF6_DEBUG_AGGR
)
3342 zlog_debug("%s: operation:%d",
3346 switch (operation
) {
3347 case OSPF6_ROUTE_AGGR_ADD
:
3348 ospf6_handle_external_aggr_add(ospf6
);
3350 case OSPF6_ROUTE_AGGR_DEL
:
3351 case OSPF6_ROUTE_AGGR_MODIFY
:
3352 ospf6_handle_external_aggr_update(ospf6
);
3360 ospf6_start_asbr_summary_delay_timer(struct ospf6
*ospf6
,
3361 struct ospf6_external_aggr_rt
*aggr
,
3362 ospf6_aggr_action_t operation
)
3364 aggr
->action
= operation
;
3366 if (event_is_scheduled(ospf6
->t_external_aggr
)) {
3367 if (ospf6
->aggr_action
== OSPF6_ROUTE_AGGR_ADD
) {
3369 if (IS_OSPF6_DEBUG_AGGR
)
3370 zlog_debug("%s: Not required to restart timer,set is already added.",
3375 if (operation
== OSPF6_ROUTE_AGGR_ADD
) {
3376 if (IS_OSPF6_DEBUG_AGGR
)
3377 zlog_debug("%s, Restarting Aggregator delay timer.",
3379 EVENT_OFF(ospf6
->t_external_aggr
);
3383 if (IS_OSPF6_DEBUG_AGGR
)
3384 zlog_debug("%s: Start Aggregator delay timer %u(in seconds).",
3385 __func__
, ospf6
->aggr_delay_interval
);
3387 ospf6
->aggr_action
= operation
;
3388 event_add_timer(master
, ospf6_asbr_summary_process
, ospf6
,
3389 ospf6
->aggr_delay_interval
, &ospf6
->t_external_aggr
);
3392 int ospf6_asbr_external_rt_advertise(struct ospf6
*ospf6
,
3395 struct route_node
*rn
;
3396 struct ospf6_external_aggr_rt
*aggr
;
3398 rn
= route_node_lookup(ospf6
->rt_aggr_tbl
, p
);
3400 return OSPF6_INVALID
;
3404 route_unlock_node(rn
);
3406 if (!CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
))
3407 return OSPF6_INVALID
;
3409 UNSET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
);
3411 if (!OSPF6_EXTERNAL_RT_COUNT(aggr
))
3412 return OSPF6_SUCCESS
;
3414 ospf6_start_asbr_summary_delay_timer(ospf6
, aggr
,
3415 OSPF6_ROUTE_AGGR_MODIFY
);
3417 return OSPF6_SUCCESS
;
3420 int ospf6_external_aggr_delay_timer_set(struct ospf6
*ospf6
, uint16_t interval
)
3422 ospf6
->aggr_delay_interval
= interval
;
3424 return OSPF6_SUCCESS
;
3427 static unsigned int ospf6_external_rt_hash_key(const void *data
)
3429 const struct ospf6_route
*rt
= data
;
3430 unsigned int key
= 0;
3432 key
= prefix_hash_key(&rt
->prefix
);
3436 static bool ospf6_external_rt_hash_cmp(const void *d1
, const void *d2
)
3438 const struct ospf6_route
*rt1
= d1
;
3439 const struct ospf6_route
*rt2
= d2
;
3441 return prefix_same(&rt1
->prefix
, &rt2
->prefix
);
3444 static struct ospf6_external_aggr_rt
*
3445 ospf6_external_aggr_new(struct prefix
*p
)
3447 struct ospf6_external_aggr_rt
*aggr
;
3449 aggr
= XCALLOC(MTYPE_OSPF6_EXTERNAL_RT_AGGR
,
3450 sizeof(struct ospf6_external_aggr_rt
));
3452 prefix_copy(&aggr
->p
, p
);
3454 aggr
->mtype
= DEFAULT_METRIC_TYPE
;
3455 aggr
->match_extnl_hash
= hash_create(ospf6_external_rt_hash_key
,
3456 ospf6_external_rt_hash_cmp
,
3457 "Ospf6 external route hash");
3461 static void ospf6_external_aggr_add(struct ospf6
*ospf6
,
3462 struct ospf6_external_aggr_rt
*aggr
)
3464 struct route_node
*rn
;
3466 if (IS_OSPF6_DEBUG_AGGR
)
3467 zlog_debug("%s: Adding Aggregate route to Aggr table (%pFX)",
3471 rn
= route_node_get(ospf6
->rt_aggr_tbl
, &aggr
->p
);
3473 route_unlock_node(rn
);
3478 int ospf6_asbr_external_rt_no_advertise(struct ospf6
*ospf6
,
3481 struct ospf6_external_aggr_rt
*aggr
;
3482 route_tag_t tag
= 0;
3484 aggr
= ospf6_external_aggr_config_lookup(ospf6
, p
);
3486 if (CHECK_FLAG(aggr
->aggrflags
,
3487 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
))
3488 return OSPF6_SUCCESS
;
3490 SET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
);
3495 if (!OSPF6_EXTERNAL_RT_COUNT(aggr
))
3496 return OSPF6_SUCCESS
;
3498 ospf6_start_asbr_summary_delay_timer(ospf6
, aggr
,
3499 OSPF6_ROUTE_AGGR_MODIFY
);
3501 aggr
= ospf6_external_aggr_new(p
);
3504 return OSPF6_FAILURE
;
3506 SET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
);
3507 ospf6_external_aggr_add(ospf6
, aggr
);
3508 ospf6_start_asbr_summary_delay_timer(ospf6
, aggr
,
3509 OSPF6_ROUTE_AGGR_ADD
);
3512 return OSPF6_SUCCESS
;
3515 struct ospf6_external_aggr_rt
*
3516 ospf6_external_aggr_config_lookup(struct ospf6
*ospf6
, struct prefix
*p
)
3518 struct route_node
*rn
;
3520 rn
= route_node_lookup(ospf6
->rt_aggr_tbl
, p
);
3522 route_unlock_node(rn
);
3530 int ospf6_external_aggr_config_set(struct ospf6
*ospf6
, struct prefix
*p
,
3531 route_tag_t tag
, int metric
, int mtype
)
3533 struct ospf6_external_aggr_rt
*aggregator
;
3535 aggregator
= ospf6_external_aggr_config_lookup(ospf6
, p
);
3538 if (CHECK_FLAG(aggregator
->aggrflags
,
3539 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
))
3540 UNSET_FLAG(aggregator
->aggrflags
,
3541 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
);
3542 else if ((aggregator
->tag
== tag
)
3543 && (aggregator
->metric
== metric
)
3544 && (aggregator
->mtype
== mtype
))
3545 return OSPF6_SUCCESS
;
3547 aggregator
->tag
= tag
;
3548 aggregator
->metric
= metric
;
3549 aggregator
->mtype
= mtype
;
3551 ospf6_start_asbr_summary_delay_timer(ospf6
, aggregator
,
3552 OSPF6_ROUTE_AGGR_MODIFY
);
3554 aggregator
= ospf6_external_aggr_new(p
);
3556 return OSPF6_FAILURE
;
3558 aggregator
->tag
= tag
;
3559 aggregator
->metric
= metric
;
3560 aggregator
->mtype
= mtype
;
3562 ospf6_external_aggr_add(ospf6
, aggregator
);
3563 ospf6_start_asbr_summary_delay_timer(ospf6
, aggregator
,
3564 OSPF6_ROUTE_AGGR_ADD
);
3567 return OSPF6_SUCCESS
;
3570 int ospf6_external_aggr_config_unset(struct ospf6
*ospf6
,
3573 struct route_node
*rn
;
3574 struct ospf6_external_aggr_rt
*aggr
;
3576 rn
= route_node_lookup(ospf6
->rt_aggr_tbl
, p
);
3578 return OSPF6_INVALID
;
3582 route_unlock_node(rn
);
3584 if (!OSPF6_EXTERNAL_RT_COUNT(aggr
)) {
3585 ospf6_asbr_summary_config_delete(ospf6
, rn
);
3586 ospf6_external_aggregator_free(aggr
);
3587 return OSPF6_SUCCESS
;
3590 ospf6_start_asbr_summary_delay_timer(ospf6
, aggr
,
3591 OSPF6_ROUTE_AGGR_DEL
);
3593 return OSPF6_SUCCESS
;
3596 void ospf6_handle_external_lsa_origination(struct ospf6
*ospf6
,
3597 struct ospf6_route
*rt
,
3601 struct ospf6_external_aggr_rt
*aggr
;
3602 struct ospf6_external_info
*info
;
3603 struct prefix prefix_id
;
3605 if (!is_default_prefix(p
)) {
3606 aggr
= ospf6_external_aggr_match(ospf6
,
3611 if (IS_OSPF6_DEBUG_AGGR
)
3612 zlog_debug("%s: Send Aggregate LSA (%pFX)",
3616 ospf6_originate_summary_lsa(
3619 /* Handling the case where the
3620 * external route prefix
3621 * and aggegate prefix is same
3622 * If same don't flush the
3626 ospf6_handle_aggregated_exnl_rt(
3632 info
= rt
->route_option
;
3634 /* When the info->id = 0, it means it is being originated for the
3638 info
->id
= ospf6
->external_id
++;
3640 prefix_id
.family
= AF_INET
;
3641 prefix_id
.prefixlen
= 32;
3642 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
3645 rt
->path
.origin
.id
= htonl(info
->id
);
3647 if (IS_OSPF6_DEBUG_ASBR
) {
3648 zlog_debug("Advertise new AS-External Id:%pI4 prefix %pFX metric %u",
3649 &prefix_id
.u
.prefix4
, p
, rt
->path
.metric_type
);
3652 ospf6_originate_type5_type7_lsas(rt
, ospf6
);
3656 void ospf6_unset_all_aggr_flag(struct ospf6
*ospf6
)
3658 struct route_node
*rn
= NULL
;
3659 struct ospf6_external_aggr_rt
*aggr
;
3661 if (IS_OSPF6_DEBUG_AGGR
)
3662 zlog_debug("Unset the origination bit for all aggregator");
3664 /* Resetting the running external ID counter so that the origination
3665 * of external LSAs starts from the beginning 0.0.0.1
3667 ospf6
->external_id
= OSPF6_EXT_INIT_LS_ID
;
3669 for (rn
= route_top(ospf6
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
3675 UNSET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);