2 * Copyright (C) 2003 Yasuhiro Ohara
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #include "lib/northbound_cli.h"
35 #include "ospf6_proto.h"
36 #include "ospf6_lsa.h"
37 #include "ospf6_lsdb.h"
38 #include "ospf6_route.h"
39 #include "ospf6_zebra.h"
40 #include "ospf6_message.h"
41 #include "ospf6_spf.h"
43 #include "ospf6_top.h"
45 #include "ospf6_area.h"
46 #include "ospf6_interface.h"
47 #include "ospf6_neighbor.h"
48 #include "ospf6_asbr.h"
49 #include "ospf6_abr.h"
50 #include "ospf6_intra.h"
51 #include "ospf6_flood.h"
52 #include "ospf6_nssa.h"
54 #include "ospf6_spf.h"
55 #include "ospf6_nssa.h"
59 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_EXTERNAL_INFO
, "OSPF6 ext. info");
60 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_DIST_ARGS
, "OSPF6 Distribute arguments");
61 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_REDISTRIBUTE
, "OSPF6 Redistribute arguments");
62 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_EXTERNAL_RT_AGGR
, "OSPF6 ASBR Summarisation");
64 static void ospf6_asbr_redistribute_set(struct ospf6
*ospf6
, int type
);
65 static void ospf6_asbr_redistribute_unset(struct ospf6
*ospf6
,
66 struct ospf6_redist
*red
, int type
);
68 #include "ospf6d/ospf6_asbr_clippy.c"
70 unsigned char conf_debug_ospf6_asbr
= 0;
72 #define ZROUTE_NAME(x) zebra_route_string(x)
74 /* Originate Type-5 and Type-7 LSA */
75 static struct ospf6_lsa
*ospf6_originate_type5_type7_lsas(
76 struct ospf6_route
*route
,
79 struct ospf6_lsa
*lsa
;
80 struct listnode
*lnode
;
81 struct ospf6_area
*oa
= NULL
;
83 lsa
= ospf6_as_external_lsa_originate(route
, ospf6
);
85 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, lnode
, oa
)) {
87 ospf6_nssa_lsa_originate(route
, oa
, true);
93 /* AS External LSA origination */
94 struct ospf6_lsa
*ospf6_as_external_lsa_originate(struct ospf6_route
*route
,
97 char buffer
[OSPF6_MAX_LSASIZE
];
98 struct ospf6_lsa_header
*lsa_header
;
99 struct ospf6_lsa
*lsa
;
100 struct ospf6_external_info
*info
= route
->route_option
;
102 struct ospf6_as_external_lsa
*as_external_lsa
;
105 if (ospf6
->gr_info
.restart_in_progress
) {
106 if (IS_DEBUG_OSPF6_GR
)
108 "Graceful Restart in progress, don't originate LSA");
112 if (IS_OSPF6_DEBUG_ASBR
|| IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL
))
113 zlog_debug("Originate AS-External-LSA for %pFX",
117 memset(buffer
, 0, sizeof(buffer
));
118 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
119 as_external_lsa
= (struct ospf6_as_external_lsa
120 *)((caddr_t
)lsa_header
121 + sizeof(struct ospf6_lsa_header
));
122 p
= (caddr_t
)((caddr_t
)as_external_lsa
123 + sizeof(struct ospf6_as_external_lsa
));
125 /* Fill AS-External-LSA */
127 if (route
->path
.metric_type
== 2)
128 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
130 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
132 /* forwarding address */
133 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
134 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
136 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
138 /* external route tag */
140 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
142 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
145 OSPF6_ASBR_METRIC_SET(as_external_lsa
, route
->path
.cost
);
148 as_external_lsa
->prefix
.prefix_length
= route
->prefix
.prefixlen
;
151 as_external_lsa
->prefix
.prefix_options
= route
->prefix_options
;
153 /* don't use refer LS-type */
154 as_external_lsa
->prefix
.prefix_refer_lstype
= htons(0);
157 memcpy(p
, &route
->prefix
.u
.prefix6
,
158 OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
));
159 ospf6_prefix_apply_mask(&as_external_lsa
->prefix
);
160 p
+= OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
);
162 /* Forwarding address */
163 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
164 memcpy(p
, &info
->forwarding
, sizeof(struct in6_addr
));
165 p
+= sizeof(struct in6_addr
);
168 /* External Route Tag */
169 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
170 route_tag_t network_order
= htonl(info
->tag
);
172 memcpy(p
, &network_order
, sizeof(network_order
));
173 p
+= sizeof(network_order
);
176 /* Fill LSA Header */
178 lsa_header
->type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
179 lsa_header
->id
= route
->path
.origin
.id
;
180 lsa_header
->adv_router
= ospf6
->router_id
;
182 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
183 lsa_header
->adv_router
, ospf6
->lsdb
);
184 lsa_header
->length
= htons((caddr_t
)p
- (caddr_t
)lsa_header
);
187 ospf6_lsa_checksum(lsa_header
);
190 lsa
= ospf6_lsa_create(lsa_header
);
193 ospf6_lsa_originate_process(lsa
, ospf6
);
198 void ospf6_orig_as_external_lsa(struct thread
*thread
)
200 struct ospf6_interface
*oi
;
201 struct ospf6_lsa
*lsa
;
202 uint32_t type
, adv_router
;
204 oi
= (struct ospf6_interface
*)THREAD_ARG(thread
);
206 if (oi
->state
== OSPF6_INTERFACE_DOWN
)
208 if (IS_AREA_NSSA(oi
->area
) || IS_AREA_STUB(oi
->area
))
211 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
212 adv_router
= oi
->area
->ospf6
->router_id
;
213 for (ALL_LSDB_TYPED_ADVRTR(oi
->area
->ospf6
->lsdb
, type
, adv_router
,
215 if (IS_OSPF6_DEBUG_ASBR
)
217 "%s: Send update of AS-External LSA %s seq 0x%x",
219 ntohl(lsa
->header
->seqnum
));
221 ospf6_flood_interface(NULL
, lsa
, oi
);
225 static route_tag_t
ospf6_as_external_lsa_get_tag(struct ospf6_lsa
*lsa
)
227 struct ospf6_as_external_lsa
*external
;
228 ptrdiff_t tag_offset
;
229 route_tag_t network_order
;
234 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
237 if (!CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
240 tag_offset
= sizeof(*external
)
241 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
242 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
243 tag_offset
+= sizeof(struct in6_addr
);
245 memcpy(&network_order
, (caddr_t
)external
+ tag_offset
,
246 sizeof(network_order
));
247 return ntohl(network_order
);
250 void ospf6_asbr_update_route_ecmp_path(struct ospf6_route
*old
,
251 struct ospf6_route
*route
,
254 struct ospf6_route
*old_route
, *next_route
;
255 struct ospf6_path
*ecmp_path
, *o_path
= NULL
;
256 struct listnode
*anode
, *anext
;
257 struct listnode
*nnode
, *rnode
, *rnext
;
258 struct ospf6_nexthop
*nh
, *rnh
;
259 bool route_found
= false;
261 /* check for old entry match with new route origin,
264 for (old_route
= old
; old_route
; old_route
= next_route
) {
265 bool route_updated
= false;
267 next_route
= old_route
->next
;
269 /* The route linked-list is grouped in batches of prefix.
270 * If the new prefix is not the same as the one of interest
271 * then we have walked over the end of the batch and so we
272 * should break rather than continuing unnecessarily.
274 if (!ospf6_route_is_same(old_route
, route
))
276 if (old_route
->path
.type
!= route
->path
.type
)
279 /* Current and New route has same origin,
282 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
, anext
,
284 /* Check old route path and route has same
287 if (o_path
->area_id
!= route
->path
.area_id
288 || !ospf6_ls_origin_same(o_path
, &route
->path
))
291 /* Cost is not same then delete current path */
292 if ((o_path
->cost
== route
->path
.cost
)
293 && (o_path
->u
.cost_e2
== route
->path
.u
.cost_e2
))
296 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
298 "%s: route %pFX cost old %u new %u is not same, replace route",
299 __func__
, &old_route
->prefix
, o_path
->cost
,
303 /* Remove selected current rout path's nh from
306 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
307 for (ALL_LIST_ELEMENTS(old_route
->nh_list
,
308 rnode
, rnext
, rnh
)) {
309 if (!ospf6_nexthop_is_same(rnh
, nh
))
311 listnode_delete(old_route
->nh_list
,
313 ospf6_nexthop_delete(rnh
);
317 listnode_delete(old_route
->paths
, o_path
);
318 ospf6_path_free(o_path
);
319 route_updated
= true;
321 /* Current route's path (adv_router info) is similar
322 * to route being added.
323 * Replace current route's path with paths list head.
324 * Update FIB with effective NHs.
326 if (listcount(old_route
->paths
)) {
327 for (ALL_LIST_ELEMENTS(old_route
->paths
,
328 anode
, anext
, o_path
)) {
329 ospf6_merge_nexthops(
333 /* Update RIB/FIB with effective
336 if (ospf6
->route_table
->hook_add
)
337 (*ospf6
->route_table
->hook_add
)(
340 if (old_route
->path
.origin
.id
341 == route
->path
.origin
.id
342 && old_route
->path
.origin
.adv_router
343 == route
->path
.origin
345 struct ospf6_path
*h_path
;
347 h_path
= (struct ospf6_path
*)
348 listgetdata(listhead(
350 old_route
->path
.origin
.type
=
352 old_route
->path
.origin
.id
=
354 old_route
->path
.origin
.adv_router
=
355 h_path
->origin
.adv_router
;
358 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
360 "%s: route %pFX old cost %u new cost %u, delete old entry.",
361 __func__
, &old_route
->prefix
,
362 old_route
->path
.cost
,
365 if (old
== old_route
)
367 ospf6_route_remove(old_route
,
376 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
378 /* The route linked-list is grouped in batches of prefix.
379 * If the new prefix is not the same as the one of interest
380 * then we have walked over the end of the batch and so we
381 * should break rather than continuing unnecessarily.
383 if (!ospf6_route_is_same(old_route
, route
))
385 if (old_route
->path
.type
!= route
->path
.type
)
388 /* Old Route and New Route have Equal Cost, Merge NHs */
389 if ((old_route
->path
.cost
== route
->path
.cost
)
390 && (old_route
->path
.u
.cost_e2
== route
->path
.u
.cost_e2
)) {
392 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
394 "%s: old route %pFX path cost %u e2 %u",
395 __func__
, &old_route
->prefix
,
396 old_route
->path
.cost
,
397 old_route
->path
.u
.cost_e2
);
400 /* check if this path exists already in
401 * route->paths list, if so, replace nh_list
404 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
406 if (o_path
->area_id
== route
->path
.area_id
407 && ospf6_ls_origin_same(o_path
, &route
->path
))
410 /* If path is not found in old_route paths's list,
411 * add a new path to route paths list and merge
412 * nexthops in route->path->nh_list.
413 * Otherwise replace existing path's nh_list.
415 if (o_path
== NULL
) {
416 ecmp_path
= ospf6_path_dup(&route
->path
);
418 /* Add a nh_list to new ecmp path */
419 ospf6_copy_nexthops(ecmp_path
->nh_list
,
422 /* Add the new path to route's path list */
423 listnode_add_sort(old_route
->paths
, ecmp_path
);
425 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
427 "%s: route %pFX another path added with nh %u, effective paths %u nh %u",
428 __func__
, &route
->prefix
,
429 listcount(ecmp_path
->nh_list
),
430 old_route
->paths
? listcount(
433 listcount(old_route
->nh_list
));
436 list_delete_all_node(o_path
->nh_list
);
437 ospf6_copy_nexthops(o_path
->nh_list
,
441 /* Reset nexthop lists, rebuild from brouter table
442 * for each adv. router.
444 list_delete_all_node(old_route
->nh_list
);
446 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
448 struct ospf6_route
*asbr_entry
;
450 asbr_entry
= ospf6_route_lookup(
452 ospf6
->brouter_table
);
453 if (asbr_entry
== NULL
) {
454 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
456 "%s: ls_prfix %pFX asbr_entry not found.",
461 ospf6_route_merge_nexthops(old_route
,
465 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
467 "%s: route %pFX with effective paths %u nh %u",
468 __func__
, &route
->prefix
,
470 ? listcount(old_route
->paths
)
473 ? listcount(old_route
->nh_list
)
477 if (ospf6
->route_table
->hook_add
)
478 (*ospf6
->route_table
->hook_add
)(old_route
);
480 /* Delete the new route its info added to existing
483 ospf6_route_delete(route
);
490 /* Add new route to existing node in ospf6 route table. */
491 ospf6_route_add(route
, ospf6
->route_table
);
495 /* Check if the forwarding address is local address */
496 static int ospf6_ase_forward_address_check(struct ospf6
*ospf6
,
497 struct in6_addr
*fwd_addr
)
499 struct listnode
*anode
, *node
, *cnode
;
500 struct ospf6_interface
*oi
;
501 struct ospf6_area
*oa
;
502 struct interface
*ifp
;
505 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, oa
)) {
506 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, node
, oi
)) {
507 if (!if_is_operative(oi
->interface
)
508 || oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
512 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
513 if (IPV6_ADDR_SAME(&c
->address
->u
.prefix6
,
523 void ospf6_asbr_lsa_add(struct ospf6_lsa
*lsa
)
525 struct ospf6_as_external_lsa
*external
;
526 struct prefix asbr_id
;
527 struct ospf6_route
*asbr_entry
, *route
, *old
= NULL
;
528 struct ospf6_path
*path
;
531 struct ospf6_area
*oa
= NULL
;
532 struct prefix fwd_addr
;
535 type
= ntohs(lsa
->header
->type
);
536 oa
= lsa
->lsdb
->data
;
538 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
541 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
542 zlog_debug("Calculate AS-External route for %s", lsa
->name
);
544 ospf6
= ospf6_get_by_lsdb(lsa
);
546 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
547 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
548 zlog_debug("Ignore self-originated AS-External-LSA");
552 if (OSPF6_ASBR_METRIC(external
) == OSPF_LS_INFINITY
) {
553 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
554 zlog_debug("Ignore LSA with LSInfinity Metric");
558 if (CHECK_FLAG(external
->prefix
.prefix_options
,
559 OSPF6_PREFIX_OPTION_NU
)) {
560 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
561 zlog_debug("Ignore LSA with NU bit set Metric");
565 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &asbr_id
);
566 asbr_entry
= ospf6_route_lookup(&asbr_id
, ospf6
->brouter_table
);
567 if (asbr_entry
== NULL
) {
568 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
569 zlog_debug("ASBR entry not found: %pFX", &asbr_id
);
572 /* The router advertising external LSA can be ASBR or ABR */
573 if (!CHECK_FLAG(asbr_entry
->path
.router_bits
,
574 OSPF6_ROUTER_BIT_E
)) {
575 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
577 "External bit reset ASBR route entry : %pFX",
583 * RFC 3101 - Section 2.5:
584 * "For a Type-7 LSA the matching routing table entry must
585 * specify an intra-area path through the LSA's originating
588 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_TYPE_7
589 && (asbr_entry
->path
.area_id
!= oa
->area_id
590 || asbr_entry
->path
.type
!= OSPF6_PATH_TYPE_INTRA
)) {
591 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
593 "Intra-area route to NSSA ASBR not found: %pFX",
600 * RFC 3101 - Section 2.5:
601 * "If the destination is a Type-7 default route (destination ID =
602 * DefaultDestination) and one of the following is true, then do
603 * nothing with this LSA and consider the next in the list:
605 * o The calculating router is a border router and the LSA has
606 * its P-bit clear. Appendix E describes a technique
607 * whereby an NSSA border router installs a Type-7 default
608 * LSA without propagating it.
610 * o The calculating router is a border router and is
611 * suppressing the import of summary routes as Type-3
614 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_TYPE_7
615 && external
->prefix
.prefix_length
== 0
616 && CHECK_FLAG(ospf6
->flag
, OSPF6_FLAG_ABR
)
617 && (CHECK_FLAG(external
->prefix
.prefix_options
,
618 OSPF6_PREFIX_OPTION_P
)
619 || oa
->no_summary
)) {
620 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
621 zlog_debug("Skipping Type-7 default route");
625 /* Check the forwarding address */
626 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
627 offset
= sizeof(*external
)
628 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
629 memset(&fwd_addr
, 0, sizeof(fwd_addr
));
630 fwd_addr
.family
= AF_INET6
;
631 fwd_addr
.prefixlen
= IPV6_MAX_BITLEN
;
632 memcpy(&fwd_addr
.u
.prefix6
, (caddr_t
)external
+ offset
,
633 sizeof(struct in6_addr
));
635 if (!IN6_IS_ADDR_UNSPECIFIED(&fwd_addr
.u
.prefix6
)) {
636 if (!ospf6_ase_forward_address_check(
637 ospf6
, &fwd_addr
.u
.prefix6
)) {
638 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
640 "Fwd address %pFX is local address",
645 /* Find the forwarding entry */
646 asbr_entry
= ospf6_route_lookup_bestmatch(
647 &fwd_addr
, ospf6
->route_table
);
648 if (asbr_entry
== NULL
) {
649 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
651 "Fwd address not found: %pFX",
658 route
= ospf6_route_create(ospf6
);
659 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
660 route
->prefix
.family
= AF_INET6
;
661 route
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
662 ospf6_prefix_in6_addr(&route
->prefix
.u
.prefix6
, external
,
664 route
->prefix_options
= external
->prefix
.prefix_options
;
666 route
->path
.area_id
= asbr_entry
->path
.area_id
;
667 route
->path
.origin
.type
= lsa
->header
->type
;
668 route
->path
.origin
.id
= lsa
->header
->id
;
669 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
670 memcpy(&route
->path
.ls_prefix
, &asbr_id
, sizeof(struct prefix
));
672 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
673 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
674 route
->path
.metric_type
= 2;
675 route
->path
.cost
= asbr_entry
->path
.cost
;
676 route
->path
.u
.cost_e2
= OSPF6_ASBR_METRIC(external
);
678 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
679 route
->path
.metric_type
= 1;
681 asbr_entry
->path
.cost
+ OSPF6_ASBR_METRIC(external
);
682 route
->path
.u
.cost_e2
= 0;
685 route
->path
.tag
= ospf6_as_external_lsa_get_tag(lsa
);
687 ospf6_route_copy_nexthops(route
, asbr_entry
);
689 path
= ospf6_path_dup(&route
->path
);
690 ospf6_copy_nexthops(path
->nh_list
, asbr_entry
->nh_list
);
691 listnode_add_sort(route
->paths
, path
);
694 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
696 "%s: %s %u route add %pFX cost %u(%u) nh %u", __func__
,
697 (type
== OSPF6_LSTYPE_AS_EXTERNAL
) ? "AS-External"
699 (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
) ? 1 : 2,
700 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
701 listcount(route
->nh_list
));
703 if (type
== OSPF6_LSTYPE_AS_EXTERNAL
)
704 old
= ospf6_route_lookup(&route
->prefix
, ospf6
->route_table
);
705 else if (type
== OSPF6_LSTYPE_TYPE_7
)
706 old
= ospf6_route_lookup(&route
->prefix
, oa
->route_table
);
708 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
709 zlog_debug("%s: Adding new route", __func__
);
710 /* Add the new route to ospf6 instance route table. */
711 if (type
== OSPF6_LSTYPE_AS_EXTERNAL
)
712 ospf6_route_add(route
, ospf6
->route_table
);
713 /* Add the route to the area route table */
714 else if (type
== OSPF6_LSTYPE_TYPE_7
) {
715 ospf6_route_add(route
, oa
->route_table
);
719 * ECMP: Keep new equal preference path in current
720 * route's path list, update zebra with new effective
721 * list along with addition of ECMP path.
723 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
724 zlog_debug("%s : old route %pFX cost %u(%u) nh %u",
725 __func__
, &route
->prefix
, route
->path
.cost
,
726 route
->path
.u
.cost_e2
,
727 listcount(route
->nh_list
));
728 ospf6_asbr_update_route_ecmp_path(old
, route
, ospf6
);
732 void ospf6_asbr_lsa_remove(struct ospf6_lsa
*lsa
,
733 struct ospf6_route
*asbr_entry
)
735 struct ospf6_as_external_lsa
*external
;
736 struct prefix prefix
;
737 struct ospf6_route
*route
, *nroute
, *route_to_del
;
738 struct ospf6_area
*oa
= NULL
;
743 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
746 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
) || (IS_OSPF6_DEBUG_NSSA
))
749 ospf6
= ospf6_get_by_lsdb(lsa
);
750 type
= ntohs(lsa
->header
->type
);
752 if (type
== OSPF6_LSTYPE_TYPE_7
) {
754 zlog_debug("%s: Withdraw Type 7 route for %s",
755 __func__
, lsa
->name
);
756 oa
= lsa
->lsdb
->data
;
759 zlog_debug("%s: Withdraw AS-External route for %s",
760 __func__
, lsa
->name
);
762 if (ospf6_check_and_set_router_abr(ospf6
))
763 oa
= ospf6
->backbone
;
765 oa
= listnode_head(ospf6
->area_list
);
770 zlog_debug("%s: Invalid area", __func__
);
774 if (lsa
->header
->adv_router
== oa
->ospf6
->router_id
) {
776 zlog_debug("Ignore self-originated AS-External-LSA");
780 route_to_del
= ospf6_route_create(ospf6
);
781 route_to_del
->type
= OSPF6_DEST_TYPE_NETWORK
;
782 route_to_del
->prefix
.family
= AF_INET6
;
783 route_to_del
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
784 ospf6_prefix_in6_addr(&route_to_del
->prefix
.u
.prefix6
, external
,
787 route_to_del
->path
.origin
.type
= lsa
->header
->type
;
788 route_to_del
->path
.origin
.id
= lsa
->header
->id
;
789 route_to_del
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
792 route_to_del
->path
.area_id
= asbr_entry
->path
.area_id
;
793 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
794 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
795 route_to_del
->path
.metric_type
= 2;
796 route_to_del
->path
.cost
= asbr_entry
->path
.cost
;
797 route_to_del
->path
.u
.cost_e2
=
798 OSPF6_ASBR_METRIC(external
);
800 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
801 route_to_del
->path
.metric_type
= 1;
802 route_to_del
->path
.cost
= asbr_entry
->path
.cost
803 + OSPF6_ASBR_METRIC(external
);
804 route_to_del
->path
.u
.cost_e2
= 0;
808 memset(&prefix
, 0, sizeof(struct prefix
));
809 prefix
.family
= AF_INET6
;
810 prefix
.prefixlen
= external
->prefix
.prefix_length
;
811 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, external
, &external
->prefix
);
813 if (type
== OSPF6_LSTYPE_TYPE_7
)
814 route
= ospf6_route_lookup(&prefix
, oa
->route_table
);
816 route
= ospf6_route_lookup(&prefix
, oa
->ospf6
->route_table
);
820 zlog_debug("AS-External route %pFX not found", &prefix
);
821 ospf6_route_delete(route_to_del
);
827 "%s: Current route %pFX cost %u e2 %u, route to del cost %u e2 %u",
828 __func__
, &prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
829 route_to_del
->path
.cost
, route_to_del
->path
.u
.cost_e2
);
831 for (ospf6_route_lock(route
);
832 route
&& ospf6_route_is_prefix(&prefix
, route
); route
= nroute
) {
833 nroute
= ospf6_route_next(route
);
835 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
)
838 /* Route has multiple ECMP paths, remove matching
839 * path. Update current route's effective nh list
840 * after removal of one of the path.
842 if (listcount(route
->paths
) > 1) {
843 struct listnode
*anode
, *anext
;
844 struct listnode
*nnode
, *rnode
, *rnext
;
845 struct ospf6_nexthop
*nh
, *rnh
;
846 struct ospf6_path
*o_path
;
847 bool nh_updated
= false;
849 /* Iterate all paths of route to find maching with LSA
850 * remove from route path list. If route->path is same,
851 * replace from paths list.
853 for (ALL_LIST_ELEMENTS(route
->paths
, anode
, anext
,
855 if ((o_path
->origin
.type
!= lsa
->header
->type
)
856 || (o_path
->origin
.adv_router
857 != lsa
->header
->adv_router
)
858 || (o_path
->origin
.id
!= lsa
->header
->id
))
861 /* Compare LSA cost with current
865 && (o_path
->cost
!= route_to_del
->path
.cost
867 != route_to_del
->path
.u
869 if (IS_OSPF6_DEBUG_EXAMIN(
872 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
883 "%s: route %pFX path found with cost %u nh %u to remove.",
884 __func__
, &prefix
, route
->path
.cost
,
885 listcount(o_path
->nh_list
));
888 /* Remove found path's nh_list from
889 * the route's nh_list.
891 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
,
893 for (ALL_LIST_ELEMENTS(route
->nh_list
,
896 if (!ospf6_nexthop_is_same(rnh
,
899 listnode_delete(route
->nh_list
,
901 ospf6_nexthop_delete(rnh
);
904 /* Delete the path from route's path list */
905 listnode_delete(route
->paths
, o_path
);
906 ospf6_path_free(o_path
);
911 /* Iterate all paths and merge nexthop,
912 * unlesss any of the nexthop similar to
913 * ones deleted as part of path deletion.
916 for (ALL_LIST_ELEMENTS(route
->paths
, anode
,
918 ospf6_merge_nexthops(route
->nh_list
,
924 "%s: AS-External %u route %pFX update paths %u nh %u",
927 == OSPF6_PATH_TYPE_EXTERNAL1
)
930 &route
->prefix
, listcount(route
->paths
),
931 route
->nh_list
? listcount(
936 if (listcount(route
->paths
)) {
937 /* Update RIB/FIB with effective
940 if (oa
->ospf6
->route_table
->hook_add
)
941 (*oa
->ospf6
->route_table
944 /* route's primary path is similar
945 * to LSA, replace route's primary
946 * path with route's paths list head.
948 if ((route
->path
.origin
.id
==
950 (route
->path
.origin
.adv_router
951 == lsa
->header
->adv_router
)) {
952 struct ospf6_path
*h_path
;
954 h_path
= (struct ospf6_path
*)
956 listhead(route
->paths
));
957 route
->path
.origin
.type
=
959 route
->path
.origin
.id
=
961 route
->path
.origin
.adv_router
=
962 h_path
->origin
.adv_router
;
965 if (type
== OSPF6_LSTYPE_TYPE_7
)
967 route
, oa
->route_table
);
971 oa
->ospf6
->route_table
);
977 /* Compare LSA origin and cost with current route info.
978 * if any check fails skip del this route node.
981 && (!ospf6_route_is_same_origin(route
, route_to_del
)
982 || (route
->path
.type
!= route_to_del
->path
.type
)
983 || (route
->path
.cost
!= route_to_del
->path
.cost
)
984 || (route
->path
.u
.cost_e2
985 != route_to_del
->path
.u
.cost_e2
))) {
988 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
989 __func__
, &prefix
, route
->path
.cost
,
990 route_to_del
->path
.cost
);
995 if ((route
->path
.origin
.type
!= lsa
->header
->type
)
996 || (route
->path
.origin
.adv_router
997 != lsa
->header
->adv_router
)
998 || (route
->path
.origin
.id
!= lsa
->header
->id
))
1003 "%s: AS-External %u route remove %pFX cost %u(%u) nh %u",
1005 route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
1008 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
1009 listcount(route
->nh_list
));
1011 if (type
== OSPF6_LSTYPE_TYPE_7
)
1012 ospf6_route_remove(route
, oa
->route_table
);
1014 ospf6_route_remove(route
, oa
->ospf6
->route_table
);
1017 ospf6_route_unlock(route
);
1019 ospf6_route_delete(route_to_del
);
1022 void ospf6_asbr_lsentry_add(struct ospf6_route
*asbr_entry
, struct ospf6
*ospf6
)
1024 struct ospf6_lsa
*lsa
;
1028 if (!CHECK_FLAG(asbr_entry
->flag
, OSPF6_ROUTE_BEST
)) {
1030 inet_ntop(AF_INET
, &ADV_ROUTER_IN_PREFIX(&asbr_entry
->prefix
),
1032 zlog_info("ignore non-best path: lsentry %s add", buf
);
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 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
1040 ospf6_asbr_lsa_add(lsa
);
1044 void ospf6_asbr_lsentry_remove(struct ospf6_route
*asbr_entry
,
1045 struct ospf6
*ospf6
)
1047 struct ospf6_lsa
*lsa
;
1051 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
1052 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
1053 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
))
1054 ospf6_asbr_lsa_remove(lsa
, asbr_entry
);
1058 /* redistribute function */
1059 static void ospf6_asbr_routemap_set(struct ospf6_redist
*red
,
1060 const char *mapname
)
1062 if (ROUTEMAP_NAME(red
)) {
1063 route_map_counter_decrement(ROUTEMAP(red
));
1064 free(ROUTEMAP_NAME(red
));
1067 ROUTEMAP_NAME(red
) = strdup(mapname
);
1068 ROUTEMAP(red
) = route_map_lookup_by_name(mapname
);
1069 route_map_counter_increment(ROUTEMAP(red
));
1072 static void ospf6_asbr_routemap_unset(struct ospf6_redist
*red
)
1074 if (ROUTEMAP_NAME(red
))
1075 free(ROUTEMAP_NAME(red
));
1077 route_map_counter_decrement(ROUTEMAP(red
));
1079 ROUTEMAP_NAME(red
) = NULL
;
1080 ROUTEMAP(red
) = NULL
;
1083 static void ospf6_asbr_routemap_update_timer(struct thread
*thread
)
1085 struct ospf6
*ospf6
= THREAD_ARG(thread
);
1086 struct ospf6_redist
*red
;
1089 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1090 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1095 if (!CHECK_FLAG(red
->flag
, OSPF6_IS_RMAP_CHANGED
))
1098 if (ROUTEMAP_NAME(red
))
1100 route_map_lookup_by_name(ROUTEMAP_NAME(red
));
1102 if (ROUTEMAP(red
)) {
1103 if (IS_OSPF6_DEBUG_ASBR
)
1105 "%s: route-map %s update, reset redist %s",
1106 __func__
, ROUTEMAP_NAME(red
),
1109 ospf6_zebra_no_redistribute(type
, ospf6
->vrf_id
);
1110 ospf6_zebra_redistribute(type
, ospf6
->vrf_id
);
1113 UNSET_FLAG(red
->flag
, OSPF6_IS_RMAP_CHANGED
);
1117 void ospf6_asbr_distribute_list_update(struct ospf6
*ospf6
,
1118 struct ospf6_redist
*red
)
1120 SET_FLAG(red
->flag
, OSPF6_IS_RMAP_CHANGED
);
1122 if (thread_is_scheduled(ospf6
->t_distribute_update
))
1125 if (IS_OSPF6_DEBUG_ASBR
)
1126 zlog_debug("%s: trigger redistribute reset thread", __func__
);
1128 thread_add_timer_msec(master
, ospf6_asbr_routemap_update_timer
, ospf6
,
1129 OSPF_MIN_LS_INTERVAL
,
1130 &ospf6
->t_distribute_update
);
1133 void ospf6_asbr_routemap_update(const char *mapname
)
1136 struct listnode
*node
, *nnode
;
1137 struct ospf6
*ospf6
= NULL
;
1138 struct ospf6_redist
*red
;
1143 for (ALL_LIST_ELEMENTS(om6
->ospf6
, node
, nnode
, ospf6
)) {
1144 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1145 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1146 if (!red
|| (ROUTEMAP_NAME(red
) == NULL
))
1149 route_map_lookup_by_name(ROUTEMAP_NAME(red
));
1152 || strcmp(ROUTEMAP_NAME(red
), mapname
))
1154 if (ROUTEMAP(red
)) {
1155 if (IS_OSPF6_DEBUG_ASBR
)
1157 "%s: route-map %s update, reset redist %s",
1163 route_map_counter_increment(ROUTEMAP(red
));
1164 ospf6_asbr_distribute_list_update(ospf6
, red
);
1167 * if the mapname matches a
1168 * route-map on ospf6 but the
1169 * map doesn't exist, it is
1170 * being deleted. flush and then
1173 if (IS_OSPF6_DEBUG_ASBR
)
1175 "%s: route-map %s deleted, reset redist %s",
1180 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1181 ospf6_asbr_routemap_set(red
, mapname
);
1182 ospf6_asbr_redistribute_set(ospf6
, type
);
1188 static void ospf6_asbr_routemap_event(const char *name
)
1191 struct listnode
*node
, *nnode
;
1192 struct ospf6
*ospf6
;
1193 struct ospf6_redist
*red
;
1197 for (ALL_LIST_ELEMENTS(om6
->ospf6
, node
, nnode
, ospf6
)) {
1198 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1199 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1200 if (red
&& ROUTEMAP_NAME(red
)
1201 && (strcmp(ROUTEMAP_NAME(red
), name
) == 0))
1202 ospf6_asbr_distribute_list_update(ospf6
, red
);
1207 int ospf6_asbr_is_asbr(struct ospf6
*o
)
1209 return (o
->external_table
->count
|| IS_OSPF6_ASBR(o
));
1212 struct ospf6_redist
*ospf6_redist_lookup(struct ospf6
*ospf6
, int type
,
1213 unsigned short instance
)
1215 struct list
*red_list
;
1216 struct listnode
*node
;
1217 struct ospf6_redist
*red
;
1219 red_list
= ospf6
->redist
[type
];
1223 for (ALL_LIST_ELEMENTS_RO(red_list
, node
, red
))
1224 if (red
->instance
== instance
)
1230 static struct ospf6_redist
*ospf6_redist_add(struct ospf6
*ospf6
, int type
,
1233 struct ospf6_redist
*red
;
1235 red
= ospf6_redist_lookup(ospf6
, type
, instance
);
1239 if (!ospf6
->redist
[type
])
1240 ospf6
->redist
[type
] = list_new();
1242 red
= XCALLOC(MTYPE_OSPF6_REDISTRIBUTE
, sizeof(struct ospf6_redist
));
1243 red
->instance
= instance
;
1244 red
->dmetric
.type
= -1;
1245 red
->dmetric
.value
= -1;
1246 ROUTEMAP_NAME(red
) = NULL
;
1247 ROUTEMAP(red
) = NULL
;
1249 listnode_add(ospf6
->redist
[type
], red
);
1250 ospf6
->redistribute
++;
1255 static void ospf6_redist_del(struct ospf6
*ospf6
, struct ospf6_redist
*red
,
1259 listnode_delete(ospf6
->redist
[type
], red
);
1260 if (!ospf6
->redist
[type
]->count
) {
1261 list_delete(&ospf6
->redist
[type
]);
1263 XFREE(MTYPE_OSPF6_REDISTRIBUTE
, red
);
1264 ospf6
->redistribute
--;
1268 /*Set the status of the ospf instance to ASBR based on the status parameter,
1269 * rechedule SPF calculation, originate router LSA*/
1270 void ospf6_asbr_status_update(struct ospf6
*ospf6
, int status
)
1272 struct listnode
*lnode
, *lnnode
;
1273 struct ospf6_area
*oa
;
1275 zlog_info("ASBR[%s:Status:%d]: Update", ospf6
->name
, status
);
1278 if (IS_OSPF6_ASBR(ospf6
)) {
1279 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
1280 ospf6
->name
, status
);
1283 SET_FLAG(ospf6
->flag
, OSPF6_FLAG_ASBR
);
1285 if (!IS_OSPF6_ASBR(ospf6
)) {
1286 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
1287 ospf6
->name
, status
);
1290 UNSET_FLAG(ospf6
->flag
, OSPF6_FLAG_ASBR
);
1293 /* Transition from/to status ASBR, schedule timer. */
1294 ospf6_spf_schedule(ospf6
, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE
);
1296 /* Reoriginate router LSA for all areas */
1297 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1298 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1301 static void ospf6_asbr_redistribute_set(struct ospf6
*ospf6
, int type
)
1303 ospf6_zebra_redistribute(type
, ospf6
->vrf_id
);
1305 ++ospf6
->redist_count
;
1306 ospf6_asbr_status_update(ospf6
, ospf6
->redist_count
);
1309 static void ospf6_asbr_redistribute_unset(struct ospf6
*ospf6
,
1310 struct ospf6_redist
*red
, int type
)
1312 struct ospf6_route
*route
;
1313 struct ospf6_external_info
*info
;
1315 ospf6_zebra_no_redistribute(type
, ospf6
->vrf_id
);
1317 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1318 route
= ospf6_route_next(route
)) {
1319 info
= route
->route_option
;
1320 if (info
->type
!= type
)
1323 ospf6_asbr_redistribute_remove(info
->type
, 0, &route
->prefix
,
1327 ospf6_asbr_routemap_unset(red
);
1328 --ospf6
->redist_count
;
1329 ospf6_asbr_status_update(ospf6
, ospf6
->redist_count
);
1332 /* When an area is unstubified, flood all the external LSAs in the area */
1333 void ospf6_asbr_send_externals_to_area(struct ospf6_area
*oa
)
1335 struct ospf6_lsa
*lsa
, *lsanext
;
1337 for (ALL_LSDB(oa
->ospf6
->lsdb
, lsa
, lsanext
)) {
1338 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
) {
1339 if (IS_OSPF6_DEBUG_ASBR
)
1340 zlog_debug("%s: Flooding AS-External LSA %s",
1341 __func__
, lsa
->name
);
1343 ospf6_flood_area(NULL
, lsa
, oa
);
1348 /* When an area is stubified, remove all the external LSAs in the area */
1349 void ospf6_asbr_remove_externals_from_area(struct ospf6_area
*oa
)
1351 struct ospf6_lsa
*lsa
, *lsanext
;
1352 struct listnode
*node
, *nnode
;
1353 struct ospf6_area
*area
;
1354 struct ospf6
*ospf6
= oa
->ospf6
;
1355 const struct route_node
*iterend
;
1357 /* skip if router is in other non-stub/non-NSSA areas */
1358 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, area
))
1359 if (!IS_AREA_STUB(area
) && !IS_AREA_NSSA(area
))
1362 /* if router is only in a stub area then purge AS-External LSAs */
1363 iterend
= ospf6_lsdb_head(ospf6
->lsdb
, 0, 0, 0, &lsa
);
1364 while (lsa
!= NULL
) {
1365 assert(lsa
->lock
> 1);
1366 lsanext
= ospf6_lsdb_next(iterend
, lsa
);
1367 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
)
1368 ospf6_lsdb_remove(lsa
, ospf6
->lsdb
);
1373 static struct ospf6_external_aggr_rt
*
1374 ospf6_external_aggr_match(struct ospf6
*ospf6
, struct prefix
*p
)
1376 struct route_node
*node
;
1378 node
= route_node_match(ospf6
->rt_aggr_tbl
, p
);
1382 if (IS_OSPF6_DEBUG_AGGR
) {
1383 struct ospf6_external_aggr_rt
*ag
= node
->info
;
1384 zlog_debug("%s: Matching aggregator found.prefix: %pFX Aggregator %pFX",
1390 route_unlock_node(node
);
1395 void ospf6_asbr_redistribute_add(int type
, ifindex_t ifindex
,
1396 struct prefix
*prefix
,
1397 unsigned int nexthop_num
,
1398 struct in6_addr
*nexthop
, route_tag_t tag
,
1399 struct ospf6
*ospf6
)
1401 route_map_result_t ret
;
1402 struct ospf6_route troute
;
1403 struct ospf6_external_info tinfo
;
1404 struct ospf6_route
*route
, *match
;
1405 struct ospf6_external_info
*info
;
1406 struct ospf6_redist
*red
;
1408 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1413 if ((type
!= DEFAULT_ROUTE
)
1414 && !ospf6_zebra_is_redistribute(type
, ospf6
->vrf_id
))
1417 memset(&troute
, 0, sizeof(troute
));
1418 memset(&tinfo
, 0, sizeof(tinfo
));
1420 if (IS_OSPF6_DEBUG_ASBR
)
1421 zlog_debug("Redistribute %pFX (%s)", prefix
,
1422 type
== DEFAULT_ROUTE
1423 ? "default-information-originate"
1424 : ZROUTE_NAME(type
));
1426 /* if route-map was specified but not found, do not advertise */
1427 if (ROUTEMAP_NAME(red
)) {
1428 if (ROUTEMAP(red
) == NULL
)
1429 ospf6_asbr_routemap_update(NULL
);
1430 if (ROUTEMAP(red
) == NULL
) {
1432 "route-map \"%s\" not found, suppress redistributing",
1433 ROUTEMAP_NAME(red
));
1438 /* apply route-map */
1439 if (ROUTEMAP(red
)) {
1440 troute
.route_option
= &tinfo
;
1441 troute
.ospf6
= ospf6
;
1442 tinfo
.ifindex
= ifindex
;
1445 ret
= route_map_apply(ROUTEMAP(red
), prefix
, &troute
);
1446 if (ret
== RMAP_DENYMATCH
) {
1447 if (IS_OSPF6_DEBUG_ASBR
)
1448 zlog_debug("Denied by route-map \"%s\"",
1449 ROUTEMAP_NAME(red
));
1450 ospf6_asbr_redistribute_remove(type
, ifindex
, prefix
,
1456 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1458 info
= match
->route_option
;
1459 /* copy result of route-map */
1460 if (ROUTEMAP(red
)) {
1461 if (troute
.path
.metric_type
)
1462 match
->path
.metric_type
=
1463 troute
.path
.metric_type
;
1465 match
->path
.metric_type
=
1466 metric_type(ospf6
, type
, 0);
1467 if (troute
.path
.cost
)
1468 match
->path
.cost
= troute
.path
.cost
;
1470 match
->path
.cost
= metric_value(ospf6
, type
, 0);
1472 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1473 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1474 sizeof(struct in6_addr
));
1475 info
->tag
= tinfo
.tag
;
1477 /* If there is no route-map, simply update the tag and
1480 match
->path
.metric_type
= metric_type(ospf6
, type
, 0);
1481 match
->path
.cost
= metric_value(ospf6
, type
, 0);
1487 if (nexthop_num
&& nexthop
)
1488 ospf6_route_add_nexthop(match
, ifindex
, nexthop
);
1490 ospf6_route_add_nexthop(match
, ifindex
, NULL
);
1492 match
->path
.origin
.id
= htonl(info
->id
);
1493 ospf6_handle_external_lsa_origination(ospf6
, match
, prefix
);
1495 ospf6_asbr_status_update(ospf6
, ospf6
->redistribute
);
1500 /* create new entry */
1501 route
= ospf6_route_create(ospf6
);
1502 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
1503 prefix_copy(&route
->prefix
, prefix
);
1505 info
= (struct ospf6_external_info
*)XCALLOC(
1506 MTYPE_OSPF6_EXTERNAL_INFO
, sizeof(struct ospf6_external_info
));
1507 route
->route_option
= info
;
1509 /* copy result of route-map */
1510 if (ROUTEMAP(red
)) {
1511 if (troute
.path
.metric_type
)
1512 route
->path
.metric_type
= troute
.path
.metric_type
;
1514 route
->path
.metric_type
= metric_type(ospf6
, type
, 0);
1515 if (troute
.path
.cost
)
1516 route
->path
.cost
= troute
.path
.cost
;
1518 route
->path
.cost
= metric_value(ospf6
, type
, 0);
1519 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1520 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1521 sizeof(struct in6_addr
));
1522 info
->tag
= tinfo
.tag
;
1524 /* If there is no route-map, simply update the tag and metric
1527 route
->path
.metric_type
= metric_type(ospf6
, type
, 0);
1528 route
->path
.cost
= metric_value(ospf6
, type
, 0);
1533 if (nexthop_num
&& nexthop
)
1534 ospf6_route_add_nexthop(route
, ifindex
, nexthop
);
1536 ospf6_route_add_nexthop(route
, ifindex
, NULL
);
1538 route
= ospf6_route_add(route
, ospf6
->external_table
);
1539 ospf6_handle_external_lsa_origination(ospf6
, route
, prefix
);
1541 ospf6_asbr_status_update(ospf6
, ospf6
->redistribute
);
1545 static void ospf6_asbr_external_lsa_remove_by_id(struct ospf6
*ospf6
,
1548 struct ospf6_lsa
*lsa
;
1550 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
1551 htonl(id
), ospf6
->router_id
, ospf6
->lsdb
);
1555 ospf6_external_lsa_purge(ospf6
, lsa
);
1560 ospf6_link_route_to_aggr(struct ospf6_external_aggr_rt
*aggr
,
1561 struct ospf6_route
*rt
)
1563 (void)hash_get(aggr
->match_extnl_hash
, rt
, hash_alloc_intern
);
1564 rt
->aggr_route
= aggr
;
1568 ospf6_asbr_summary_remove_lsa_and_route(struct ospf6
*ospf6
,
1569 struct ospf6_external_aggr_rt
*aggr
)
1572 /* Send a Max age LSA if it is already originated.*/
1573 if (!CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
))
1576 if (IS_OSPF6_DEBUG_AGGR
)
1577 zlog_debug("%s: Flushing Aggregate route (%pFX)",
1581 ospf6_asbr_external_lsa_remove_by_id(ospf6
, aggr
->id
);
1584 if (IS_OSPF6_DEBUG_AGGR
)
1586 "%s: Remove the blackhole route",
1589 ospf6_zebra_route_update_remove(aggr
->route
, ospf6
);
1590 if (aggr
->route
->route_option
)
1591 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
,
1592 aggr
->route
->route_option
);
1593 ospf6_route_delete(aggr
->route
);
1598 /* Unset the Origination flag */
1599 UNSET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
1603 ospf6_unlink_route_from_aggr(struct ospf6
*ospf6
,
1604 struct ospf6_external_aggr_rt
*aggr
,
1605 struct ospf6_route
*rt
)
1607 if (IS_OSPF6_DEBUG_AGGR
)
1608 zlog_debug("%s: Unlinking external route(%pFX) from aggregator(%pFX), external route count:%ld",
1612 OSPF6_EXTERNAL_RT_COUNT(aggr
));
1614 hash_release(aggr
->match_extnl_hash
, rt
);
1615 rt
->aggr_route
= NULL
;
1617 /* Flush the aggregate route if matching
1618 * external route count becomes zero.
1620 if (!OSPF6_EXTERNAL_RT_COUNT(aggr
))
1621 ospf6_asbr_summary_remove_lsa_and_route(ospf6
, aggr
);
1624 void ospf6_asbr_redistribute_remove(int type
, ifindex_t ifindex
,
1625 struct prefix
*prefix
, struct ospf6
*ospf6
)
1627 struct ospf6_route
*match
;
1628 struct ospf6_external_info
*info
= NULL
;
1630 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1631 if (match
== NULL
) {
1632 if (IS_OSPF6_DEBUG_ASBR
)
1633 zlog_debug("No such route %pFX to withdraw", prefix
);
1637 info
= match
->route_option
;
1640 if (info
->type
!= type
) {
1641 if (IS_OSPF6_DEBUG_ASBR
)
1642 zlog_debug("Original protocol mismatch: %pFX", prefix
);
1646 /* This means aggregation on this route was not done, hence remove LSA
1647 * if any originated for this prefix
1649 if (!match
->aggr_route
)
1650 ospf6_asbr_external_lsa_remove_by_id(ospf6
, info
->id
);
1652 ospf6_unlink_route_from_aggr(ospf6
, match
->aggr_route
, match
);
1654 if (IS_OSPF6_DEBUG_ASBR
)
1655 zlog_debug("Removing route from external table %pFX",
1658 ospf6_route_remove(match
, ospf6
->external_table
);
1659 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
, info
);
1661 ospf6_asbr_status_update(ospf6
, ospf6
->redistribute
);
1664 DEFPY (ospf6_redistribute
,
1665 ospf6_redistribute_cmd
,
1666 "redistribute " FRR_REDIST_STR_OSPF6D
"[{metric (0-16777214)|metric-type (1-2)$metric_type|route-map RMAP_NAME$rmap_str}]",
1668 FRR_REDIST_HELP_STR_OSPF6D
1669 "Metric for redistributed routes\n"
1670 "OSPF default metric\n"
1671 "OSPF exterior metric type for redistributed routes\n"
1672 "Set OSPF External Type 1/2 metrics\n"
1673 "Route map reference\n"
1677 struct ospf6_redist
*red
;
1678 int idx_protocol
= 1;
1679 char *proto
= argv
[idx_protocol
]->text
;
1681 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1683 type
= proto_redistnum(AFI_IP6
, proto
);
1685 return CMD_WARNING_CONFIG_FAILED
;
1689 if (!metric_type_str
)
1692 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1694 red
= ospf6_redist_add(ospf6
, type
, 0);
1696 /* Check if nothing has changed. */
1697 if (red
->dmetric
.value
== metric
1698 && red
->dmetric
.type
== metric_type
1699 && ((!ROUTEMAP_NAME(red
) && !rmap_str
)
1700 || (ROUTEMAP_NAME(red
) && rmap_str
1701 && strmatch(ROUTEMAP_NAME(red
), rmap_str
))))
1704 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1707 red
->dmetric
.value
= metric
;
1708 red
->dmetric
.type
= metric_type
;
1710 ospf6_asbr_routemap_set(red
, rmap_str
);
1712 ospf6_asbr_routemap_unset(red
);
1713 ospf6_asbr_redistribute_set(ospf6
, type
);
1718 DEFUN (no_ospf6_redistribute
,
1719 no_ospf6_redistribute_cmd
,
1720 "no redistribute " FRR_REDIST_STR_OSPF6D
"[{metric (0-16777214)|metric-type (1-2)|route-map RMAP_NAME}]",
1723 FRR_REDIST_HELP_STR_OSPF6D
1724 "Metric for redistributed routes\n"
1725 "OSPF default metric\n"
1726 "OSPF exterior metric type for redistributed routes\n"
1727 "Set OSPF External Type 1/2 metrics\n"
1728 "Route map reference\n"
1732 struct ospf6_redist
*red
;
1733 int idx_protocol
= 2;
1734 char *proto
= argv
[idx_protocol
]->text
;
1736 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1738 type
= proto_redistnum(AFI_IP6
, proto
);
1740 return CMD_WARNING_CONFIG_FAILED
;
1742 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1746 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1747 ospf6_redist_del(ospf6
, red
, type
);
1752 int ospf6_redistribute_config_write(struct vty
*vty
, struct ospf6
*ospf6
)
1755 struct ospf6_redist
*red
;
1757 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1758 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1761 if (type
== ZEBRA_ROUTE_OSPF6
)
1764 vty_out(vty
, " redistribute %s", ZROUTE_NAME(type
));
1765 if (red
->dmetric
.value
>= 0)
1766 vty_out(vty
, " metric %d", red
->dmetric
.value
);
1767 if (red
->dmetric
.type
== 1)
1768 vty_out(vty
, " metric-type 1");
1769 if (ROUTEMAP_NAME(red
))
1770 vty_out(vty
, " route-map %s", ROUTEMAP_NAME(red
));
1777 static void ospf6_redistribute_show_config(struct vty
*vty
, struct ospf6
*ospf6
,
1778 json_object
*json_array
,
1779 json_object
*json
, bool use_json
)
1782 int nroute
[ZEBRA_ROUTE_MAX
];
1784 struct ospf6_route
*route
;
1785 struct ospf6_external_info
*info
;
1786 json_object
*json_route
;
1787 struct ospf6_redist
*red
;
1790 memset(nroute
, 0, sizeof(nroute
));
1791 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1792 route
= ospf6_route_next(route
)) {
1793 info
= route
->route_option
;
1794 nroute
[info
->type
]++;
1799 vty_out(vty
, "Redistributing External Routes from:\n");
1801 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1803 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1807 if (type
== ZEBRA_ROUTE_OSPF6
)
1811 json_route
= json_object_new_object();
1812 json_object_string_add(json_route
, "routeType",
1814 json_object_int_add(json_route
, "numberOfRoutes",
1816 json_object_boolean_add(json_route
,
1817 "routeMapNamePresent",
1818 ROUTEMAP_NAME(red
));
1821 if (ROUTEMAP_NAME(red
)) {
1823 json_object_string_add(json_route
,
1825 ROUTEMAP_NAME(red
));
1826 json_object_boolean_add(json_route
,
1831 " %d: %s with route-map \"%s\"%s\n",
1832 nroute
[type
], ZROUTE_NAME(type
),
1835 : " (not found !)"));
1838 vty_out(vty
, " %d: %s\n", nroute
[type
],
1843 json_object_array_add(json_array
, json_route
);
1846 json_object_object_add(json
, "redistributedRoutes", json_array
);
1847 json_object_int_add(json
, "totalRoutes", total
);
1849 vty_out(vty
, "Total %d routes\n", total
);
1852 static void ospf6_redistribute_default_set(struct ospf6
*ospf6
, int originate
)
1854 struct prefix_ipv6 p
= {};
1855 struct in6_addr nexthop
= {};
1856 int cur_originate
= ospf6
->default_originate
;
1858 p
.family
= AF_INET6
;
1861 ospf6
->default_originate
= originate
;
1863 switch (cur_originate
) {
1864 case DEFAULT_ORIGINATE_NONE
:
1866 case DEFAULT_ORIGINATE_ZEBRA
:
1867 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE
,
1868 zclient
, AFI_IP6
, ospf6
->vrf_id
);
1869 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE
, 0,
1870 (struct prefix
*)&p
, ospf6
);
1873 case DEFAULT_ORIGINATE_ALWAYS
:
1874 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE
, 0,
1875 (struct prefix
*)&p
, ospf6
);
1879 switch (originate
) {
1880 case DEFAULT_ORIGINATE_NONE
:
1882 case DEFAULT_ORIGINATE_ZEBRA
:
1883 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD
,
1884 zclient
, AFI_IP6
, ospf6
->vrf_id
);
1887 case DEFAULT_ORIGINATE_ALWAYS
:
1888 ospf6_asbr_redistribute_add(DEFAULT_ROUTE
, 0,
1889 (struct prefix
*)&p
, 0, &nexthop
, 0,
1895 /* Default Route originate. */
1896 DEFPY (ospf6_default_route_originate
,
1897 ospf6_default_route_originate_cmd
,
1898 "default-information originate [{always$always|metric (0-16777214)$mval|metric-type (1-2)$mtype|route-map RMAP_NAME$rtmap}]",
1899 "Control distribution of default route\n"
1900 "Distribute a default route\n"
1901 "Always advertise default route\n"
1902 "OSPFv3 default metric\n"
1904 "OSPFv3 metric type for default routes\n"
1905 "Set OSPFv3 External Type 1/2 metrics\n"
1906 "Route map reference\n"
1907 "Pointer to route-map entries\n")
1909 int default_originate
= DEFAULT_ORIGINATE_ZEBRA
;
1910 struct ospf6_redist
*red
;
1911 bool sameRtmap
= false;
1913 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1915 int cur_originate
= ospf6
->default_originate
;
1917 red
= ospf6_redist_add(ospf6
, DEFAULT_ROUTE
, 0);
1920 default_originate
= DEFAULT_ORIGINATE_ALWAYS
;
1922 if (mval_str
== NULL
)
1925 if (mtype_str
== NULL
)
1928 /* To check if user is providing same route map */
1929 if ((!rtmap
&& !ROUTEMAP_NAME(red
)) ||
1930 (rtmap
&& ROUTEMAP_NAME(red
) &&
1931 (strcmp(rtmap
, ROUTEMAP_NAME(red
)) == 0)))
1934 /* Don't allow if the same lsa is already originated. */
1935 if ((sameRtmap
) && (red
->dmetric
.type
== mtype
)
1936 && (red
->dmetric
.value
== mval
)
1937 && (cur_originate
== default_originate
))
1940 /* Updating Metric details */
1941 red
->dmetric
.type
= mtype
;
1942 red
->dmetric
.value
= mval
;
1944 /* updating route map details */
1946 ospf6_asbr_routemap_set(red
, rtmap
);
1948 ospf6_asbr_routemap_unset(red
);
1950 ospf6_redistribute_default_set(ospf6
, default_originate
);
1954 DEFPY (no_ospf6_default_information_originate
,
1955 no_ospf6_default_information_originate_cmd
,
1956 "no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map RMAP_NAME}]",
1958 "Control distribution of default information\n"
1959 "Distribute a default route\n"
1960 "Always advertise default route\n"
1961 "OSPFv3 default metric\n"
1963 "OSPFv3 metric type for default routes\n"
1964 "Set OSPFv3 External Type 1/2 metrics\n"
1965 "Route map reference\n"
1966 "Pointer to route-map entries\n")
1968 struct ospf6_redist
*red
;
1970 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1972 red
= ospf6_redist_lookup(ospf6
, DEFAULT_ROUTE
, 0);
1976 ospf6_asbr_routemap_unset(red
);
1977 ospf6_redist_del(ospf6
, red
, DEFAULT_ROUTE
);
1979 ospf6_redistribute_default_set(ospf6
, DEFAULT_ORIGINATE_NONE
);
1983 /* Routemap Functions */
1984 static enum route_map_cmd_result_t
1985 ospf6_routemap_rule_match_address_prefixlist(void *rule
,
1986 const struct prefix
*prefix
,
1990 struct prefix_list
*plist
;
1992 plist
= prefix_list_lookup(AFI_IP6
, (char *)rule
);
1994 return RMAP_NOMATCH
;
1996 return (prefix_list_apply(plist
, prefix
) == PREFIX_DENY
? RMAP_NOMATCH
2001 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg
)
2003 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2006 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule
)
2008 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2011 static const struct route_map_rule_cmd
2012 ospf6_routemap_rule_match_address_prefixlist_cmd
= {
2013 "ipv6 address prefix-list",
2014 ospf6_routemap_rule_match_address_prefixlist
,
2015 ospf6_routemap_rule_match_address_prefixlist_compile
,
2016 ospf6_routemap_rule_match_address_prefixlist_free
,
2019 /* `match interface IFNAME' */
2020 /* Match function should return 1 if match is success else return
2022 static enum route_map_cmd_result_t
2023 ospf6_routemap_rule_match_interface(void *rule
, const struct prefix
*prefix
,
2026 struct interface
*ifp
;
2027 struct ospf6_route
*route
;
2028 struct ospf6_external_info
*ei
;
2031 ei
= route
->route_option
;
2032 ifp
= if_lookup_by_name((char *)rule
, route
->ospf6
->vrf_id
);
2034 if (ifp
!= NULL
&& ei
->ifindex
== ifp
->ifindex
)
2037 return RMAP_NOMATCH
;
2040 /* Route map `interface' match statement. `arg' should be
2042 static void *ospf6_routemap_rule_match_interface_compile(const char *arg
)
2044 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2047 /* Free route map's compiled `interface' value. */
2048 static void ospf6_routemap_rule_match_interface_free(void *rule
)
2050 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2053 /* Route map commands for interface matching. */
2054 static const struct route_map_rule_cmd
2055 ospf6_routemap_rule_match_interface_cmd
= {
2057 ospf6_routemap_rule_match_interface
,
2058 ospf6_routemap_rule_match_interface_compile
,
2059 ospf6_routemap_rule_match_interface_free
2062 /* Match function for matching route tags */
2063 static enum route_map_cmd_result_t
2064 ospf6_routemap_rule_match_tag(void *rule
, const struct prefix
*p
, void *object
)
2066 route_tag_t
*tag
= rule
;
2067 struct ospf6_route
*route
= object
;
2068 struct ospf6_external_info
*info
= route
->route_option
;
2070 if (info
->tag
== *tag
)
2073 return RMAP_NOMATCH
;
2076 static const struct route_map_rule_cmd
2077 ospf6_routemap_rule_match_tag_cmd
= {
2079 ospf6_routemap_rule_match_tag
,
2080 route_map_rule_tag_compile
,
2081 route_map_rule_tag_free
,
2084 static enum route_map_cmd_result_t
2085 ospf6_routemap_rule_set_metric_type(void *rule
, const struct prefix
*prefix
,
2088 char *metric_type
= rule
;
2089 struct ospf6_route
*route
= object
;
2091 if (strcmp(metric_type
, "type-2") == 0)
2092 route
->path
.metric_type
= 2;
2094 route
->path
.metric_type
= 1;
2099 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg
)
2101 if (strcmp(arg
, "type-2") && strcmp(arg
, "type-1"))
2103 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2106 static void ospf6_routemap_rule_set_metric_type_free(void *rule
)
2108 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2111 static const struct route_map_rule_cmd
2112 ospf6_routemap_rule_set_metric_type_cmd
= {
2114 ospf6_routemap_rule_set_metric_type
,
2115 ospf6_routemap_rule_set_metric_type_compile
,
2116 ospf6_routemap_rule_set_metric_type_free
,
2119 static enum route_map_cmd_result_t
2120 ospf6_routemap_rule_set_metric(void *rule
, const struct prefix
*prefix
,
2123 char *metric
= rule
;
2124 struct ospf6_route
*route
= object
;
2126 route
->path
.cost
= atoi(metric
);
2130 static void *ospf6_routemap_rule_set_metric_compile(const char *arg
)
2134 metric
= strtoul(arg
, &endp
, 0);
2135 if (metric
> OSPF_LS_INFINITY
|| *endp
!= '\0')
2137 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2140 static void ospf6_routemap_rule_set_metric_free(void *rule
)
2142 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2145 static const struct route_map_rule_cmd
2146 ospf6_routemap_rule_set_metric_cmd
= {
2148 ospf6_routemap_rule_set_metric
,
2149 ospf6_routemap_rule_set_metric_compile
,
2150 ospf6_routemap_rule_set_metric_free
,
2153 static enum route_map_cmd_result_t
2154 ospf6_routemap_rule_set_forwarding(void *rule
, const struct prefix
*prefix
,
2157 char *forwarding
= rule
;
2158 struct ospf6_route
*route
= object
;
2159 struct ospf6_external_info
*info
= route
->route_option
;
2161 if (inet_pton(AF_INET6
, forwarding
, &info
->forwarding
) != 1) {
2162 memset(&info
->forwarding
, 0, sizeof(struct in6_addr
));
2169 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg
)
2172 if (inet_pton(AF_INET6
, arg
, &a
) != 1)
2174 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2177 static void ospf6_routemap_rule_set_forwarding_free(void *rule
)
2179 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2182 static const struct route_map_rule_cmd
2183 ospf6_routemap_rule_set_forwarding_cmd
= {
2184 "forwarding-address",
2185 ospf6_routemap_rule_set_forwarding
,
2186 ospf6_routemap_rule_set_forwarding_compile
,
2187 ospf6_routemap_rule_set_forwarding_free
,
2190 static enum route_map_cmd_result_t
2191 ospf6_routemap_rule_set_tag(void *rule
, const struct prefix
*p
, void *object
)
2193 route_tag_t
*tag
= rule
;
2194 struct ospf6_route
*route
= object
;
2195 struct ospf6_external_info
*info
= route
->route_option
;
2201 static const struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd
= {
2203 ospf6_routemap_rule_set_tag
,
2204 route_map_rule_tag_compile
,
2205 route_map_rule_tag_free
,
2208 /* add "set metric-type" */
2209 DEFUN_YANG (ospf6_routemap_set_metric_type
, ospf6_routemap_set_metric_type_cmd
,
2210 "set metric-type <type-1|type-2>",
2212 "Type of metric for destination routing protocol\n"
2213 "OSPF[6] external type 1 metric\n"
2214 "OSPF[6] external type 2 metric\n")
2216 char *ext
= argv
[2]->text
;
2219 "./set-action[action='frr-ospf-route-map:metric-type']";
2220 char xpath_value
[XPATH_MAXLEN
];
2222 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
2223 snprintf(xpath_value
, sizeof(xpath_value
),
2224 "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath
);
2225 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, ext
);
2226 return nb_cli_apply_changes(vty
, NULL
);
2229 /* delete "set metric-type" */
2230 DEFUN_YANG (ospf6_routemap_no_set_metric_type
, ospf6_routemap_no_set_metric_type_cmd
,
2231 "no set metric-type [<type-1|type-2>]",
2234 "Type of metric for destination routing protocol\n"
2235 "OSPF[6] external type 1 metric\n"
2236 "OSPF[6] external type 2 metric\n")
2239 "./set-action[action='frr-ospf-route-map:metric-type']";
2241 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
2242 return nb_cli_apply_changes(vty
, NULL
);
2245 /* add "set forwarding-address" */
2246 DEFUN_YANG (ospf6_routemap_set_forwarding
, ospf6_routemap_set_forwarding_cmd
,
2247 "set forwarding-address X:X::X:X",
2249 "Forwarding Address\n"
2254 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2255 char xpath_value
[XPATH_MAXLEN
];
2257 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
2258 snprintf(xpath_value
, sizeof(xpath_value
),
2259 "%s/rmap-set-action/frr-ospf6-route-map:ipv6-address", xpath
);
2260 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
,
2261 argv
[idx_ipv6
]->arg
);
2262 return nb_cli_apply_changes(vty
, NULL
);
2265 /* delete "set forwarding-address" */
2266 DEFUN_YANG (ospf6_routemap_no_set_forwarding
, ospf6_routemap_no_set_forwarding_cmd
,
2267 "no set forwarding-address [X:X::X:X]",
2270 "Forwarding Address\n"
2274 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2276 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
2277 return nb_cli_apply_changes(vty
, NULL
);
2280 static void ospf6_routemap_init(void)
2284 route_map_add_hook(ospf6_asbr_routemap_update
);
2285 route_map_delete_hook(ospf6_asbr_routemap_update
);
2286 route_map_event_hook(ospf6_asbr_routemap_event
);
2288 route_map_set_metric_hook(generic_set_add
);
2289 route_map_no_set_metric_hook(generic_set_delete
);
2291 route_map_set_tag_hook(generic_set_add
);
2292 route_map_no_set_tag_hook(generic_set_delete
);
2294 route_map_match_tag_hook(generic_match_add
);
2295 route_map_no_match_tag_hook(generic_match_delete
);
2297 route_map_match_ipv6_address_prefix_list_hook(generic_match_add
);
2298 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete
);
2300 route_map_match_interface_hook(generic_match_add
);
2301 route_map_no_match_interface_hook(generic_match_delete
);
2303 route_map_install_match(
2304 &ospf6_routemap_rule_match_address_prefixlist_cmd
);
2305 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd
);
2306 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd
);
2308 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd
);
2309 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd
);
2310 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd
);
2311 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd
);
2313 /* ASE Metric Type (e.g. Type-1/Type-2) */
2314 install_element(RMAP_NODE
, &ospf6_routemap_set_metric_type_cmd
);
2315 install_element(RMAP_NODE
, &ospf6_routemap_no_set_metric_type_cmd
);
2318 install_element(RMAP_NODE
, &ospf6_routemap_set_forwarding_cmd
);
2319 install_element(RMAP_NODE
, &ospf6_routemap_no_set_forwarding_cmd
);
2323 /* Display functions */
2324 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
2325 char *buf
, int buflen
,
2328 struct ospf6_as_external_lsa
*external
;
2329 struct in6_addr in6
;
2330 int prefix_length
= 0;
2334 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
2338 ospf6_prefix_in6_addr(&in6
, external
,
2340 prefix_length
= external
->prefix
.prefix_length
;
2342 in6
= *((struct in6_addr
2343 *)((caddr_t
)external
2345 ospf6_as_external_lsa
)
2346 + OSPF6_PREFIX_SPACE(
2351 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
2352 if (prefix_length
) {
2353 snprintf(tbuf
, sizeof(tbuf
), "/%d",
2355 strlcat(buf
, tbuf
, buflen
);
2362 static int ospf6_as_external_lsa_show(struct vty
*vty
, struct ospf6_lsa
*lsa
,
2363 json_object
*json_obj
, bool use_json
)
2365 struct ospf6_as_external_lsa
*external
;
2368 assert(lsa
->header
);
2369 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
2373 snprintf(buf
, sizeof(buf
), "%c%c%c",
2374 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
) ? 'E'
2376 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
) ? 'F'
2378 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
) ? 'T'
2382 json_object_string_add(json_obj
, "bits", buf
);
2383 json_object_int_add(json_obj
, "metric",
2384 (unsigned long)OSPF6_ASBR_METRIC(external
));
2385 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
,
2387 json_object_string_add(json_obj
, "prefixOptions", buf
);
2388 json_object_int_add(
2389 json_obj
, "referenceLsType",
2390 ntohs(external
->prefix
.prefix_refer_lstype
));
2391 json_object_string_add(json_obj
, "prefix",
2392 ospf6_as_external_lsa_get_prefix_str(
2393 lsa
, buf
, sizeof(buf
), 0));
2395 /* Forwarding-Address */
2396 json_object_boolean_add(
2397 json_obj
, "forwardingAddressPresent",
2398 CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
));
2399 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
2400 json_object_string_add(
2401 json_obj
, "forwardingAddress",
2402 ospf6_as_external_lsa_get_prefix_str(
2403 lsa
, buf
, sizeof(buf
), 1));
2406 json_object_boolean_add(
2407 json_obj
, "tagPresent",
2408 CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
));
2409 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
2410 json_object_int_add(json_obj
, "tag",
2411 ospf6_as_external_lsa_get_tag(lsa
));
2413 vty_out(vty
, " Bits: %s\n", buf
);
2414 vty_out(vty
, " Metric: %5lu\n",
2415 (unsigned long)OSPF6_ASBR_METRIC(external
));
2417 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
,
2419 vty_out(vty
, " Prefix Options: %s\n", buf
);
2421 vty_out(vty
, " Referenced LSType: %d\n",
2422 ntohs(external
->prefix
.prefix_refer_lstype
));
2424 vty_out(vty
, " Prefix: %s\n",
2425 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
,
2428 /* Forwarding-Address */
2429 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
2430 vty_out(vty
, " Forwarding-Address: %s\n",
2431 ospf6_as_external_lsa_get_prefix_str(
2432 lsa
, buf
, sizeof(buf
), 1));
2436 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
2437 vty_out(vty
, " Tag: %" ROUTE_TAG_PRI
"\n",
2438 ospf6_as_external_lsa_get_tag(lsa
));
2445 static void ospf6_asbr_external_route_show(struct vty
*vty
,
2446 struct ospf6_route
*route
,
2447 json_object
*json_array
,
2450 struct ospf6_external_info
*info
= route
->route_option
;
2451 char prefix
[PREFIX2STR_BUFFER
], id
[16], forwarding
[64];
2453 json_object
*json_route
;
2456 prefix2str(&route
->prefix
, prefix
, sizeof(prefix
));
2457 tmp_id
= ntohl(info
->id
);
2458 inet_ntop(AF_INET
, &tmp_id
, id
, sizeof(id
));
2459 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
2460 inet_ntop(AF_INET6
, &info
->forwarding
, forwarding
,
2461 sizeof(forwarding
));
2463 snprintf(forwarding
, sizeof(forwarding
), ":: (ifindex %d)",
2464 ospf6_route_get_first_nh_index(route
));
2467 json_route
= json_object_new_object();
2468 snprintf(route_type
, sizeof(route_type
), "%c",
2469 zebra_route_char(info
->type
));
2470 json_object_string_add(json_route
, "routeType", route_type
);
2471 json_object_string_add(json_route
, "destination", prefix
);
2472 json_object_string_add(json_route
, "id", id
);
2473 json_object_int_add(json_route
, "metricType",
2474 route
->path
.metric_type
);
2475 json_object_int_add(
2476 json_route
, "routeCost",
2477 (unsigned long)(route
->path
.metric_type
== 2
2478 ? route
->path
.u
.cost_e2
2479 : route
->path
.cost
));
2480 json_object_string_add(json_route
, "forwarding", forwarding
);
2482 json_object_array_add(json_array
, json_route
);
2485 vty_out(vty
, "%c %-32pFX %-15s type-%d %5lu %s\n",
2486 zebra_route_char(info
->type
), &route
->prefix
, id
,
2487 route
->path
.metric_type
,
2488 (unsigned long)(route
->path
.metric_type
== 2
2489 ? route
->path
.u
.cost_e2
2490 : route
->path
.cost
),
2494 DEFUN(show_ipv6_ospf6_redistribute
, show_ipv6_ospf6_redistribute_cmd
,
2495 "show ipv6 ospf6 [vrf <NAME|all>] redistribute [json]",
2496 SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
2498 "redistributing External information\n" JSON_STR
)
2500 struct ospf6_route
*route
;
2501 struct ospf6
*ospf6
= NULL
;
2502 json_object
*json
= NULL
;
2503 bool uj
= use_json(argc
, argv
);
2504 struct listnode
*node
;
2505 const char *vrf_name
= NULL
;
2506 bool all_vrf
= false;
2509 json_object
*json_array_routes
= NULL
;
2510 json_object
*json_array_redistribute
= NULL
;
2512 OSPF6_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
2515 json
= json_object_new_object();
2516 json_array_routes
= json_object_new_array();
2517 json_array_redistribute
= json_object_new_array();
2520 for (ALL_LIST_ELEMENTS_RO(om6
->ospf6
, node
, ospf6
)) {
2522 || ((ospf6
->name
== NULL
&& vrf_name
== NULL
)
2523 || (ospf6
->name
&& vrf_name
2524 && strcmp(ospf6
->name
, vrf_name
) == 0))) {
2525 ospf6_redistribute_show_config(
2526 vty
, ospf6
, json_array_redistribute
, json
, uj
);
2528 for (route
= ospf6_route_head(ospf6
->external_table
);
2529 route
; route
= ospf6_route_next(route
)) {
2530 ospf6_asbr_external_route_show(
2531 vty
, route
, json_array_routes
, uj
);
2535 json_object_object_add(json
, "routes",
2537 vty_json(vty
, json
);
2545 OSPF6_CMD_CHECK_VRF(uj
, all_vrf
, ospf6
);
2550 static struct ospf6_lsa_handler as_external_handler
= {
2551 .lh_type
= OSPF6_LSTYPE_AS_EXTERNAL
,
2552 .lh_name
= "AS-External",
2553 .lh_short_name
= "ASE",
2554 .lh_show
= ospf6_as_external_lsa_show
,
2555 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
2558 static struct ospf6_lsa_handler nssa_external_handler
= {
2559 .lh_type
= OSPF6_LSTYPE_TYPE_7
,
2561 .lh_short_name
= "Type7",
2562 .lh_show
= ospf6_as_external_lsa_show
,
2563 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
2566 void ospf6_asbr_init(void)
2568 ospf6_routemap_init();
2570 ospf6_install_lsa_handler(&as_external_handler
);
2571 ospf6_install_lsa_handler(&nssa_external_handler
);
2573 install_element(VIEW_NODE
, &show_ipv6_ospf6_redistribute_cmd
);
2575 install_element(OSPF6_NODE
, &ospf6_default_route_originate_cmd
);
2576 install_element(OSPF6_NODE
,
2577 &no_ospf6_default_information_originate_cmd
);
2578 install_element(OSPF6_NODE
, &ospf6_redistribute_cmd
);
2579 install_element(OSPF6_NODE
, &no_ospf6_redistribute_cmd
);
2582 void ospf6_asbr_redistribute_disable(struct ospf6
*ospf6
)
2585 struct ospf6_redist
*red
;
2587 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
2588 red
= ospf6_redist_lookup(ospf6
, type
, 0);
2591 if (type
== ZEBRA_ROUTE_OSPF6
)
2593 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
2594 ospf6_redist_del(ospf6
, red
, type
);
2596 red
= ospf6_redist_lookup(ospf6
, DEFAULT_ROUTE
, 0);
2598 ospf6_asbr_routemap_unset(red
);
2599 ospf6_redist_del(ospf6
, red
, type
);
2600 ospf6_redistribute_default_set(ospf6
, DEFAULT_ORIGINATE_NONE
);
2604 void ospf6_asbr_redistribute_reset(struct ospf6
*ospf6
)
2607 struct ospf6_redist
*red
;
2608 char buf
[RMAP_NAME_MAXLEN
];
2610 for (type
= 0; type
<= ZEBRA_ROUTE_MAX
; type
++) {
2612 if (type
== ZEBRA_ROUTE_OSPF6
)
2614 red
= ospf6_redist_lookup(ospf6
, type
, 0);
2618 if (type
== DEFAULT_ROUTE
) {
2619 ospf6_redistribute_default_set(
2620 ospf6
, ospf6
->default_originate
);
2623 if (ROUTEMAP_NAME(red
))
2624 strlcpy(buf
, ROUTEMAP_NAME(red
), sizeof(buf
));
2626 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
2628 ospf6_asbr_routemap_set(red
, buf
);
2629 ospf6_asbr_redistribute_set(ospf6
, type
);
2633 void ospf6_asbr_terminate(void)
2635 /* Cleanup route maps */
2639 DEFUN (debug_ospf6_asbr
,
2640 debug_ospf6_asbr_cmd
,
2644 "Debug OSPFv3 ASBR function\n"
2647 OSPF6_DEBUG_ASBR_ON();
2651 DEFUN (no_debug_ospf6_asbr
,
2652 no_debug_ospf6_asbr_cmd
,
2653 "no debug ospf6 asbr",
2657 "Debug OSPFv3 ASBR function\n"
2660 OSPF6_DEBUG_ASBR_OFF();
2664 int config_write_ospf6_debug_asbr(struct vty
*vty
)
2666 if (IS_OSPF6_DEBUG_ASBR
)
2667 vty_out(vty
, "debug ospf6 asbr\n");
2671 static void ospf6_default_originate_write(struct vty
*vty
, struct ospf6
*o
)
2673 struct ospf6_redist
*red
;
2675 vty_out(vty
, " default-information originate");
2676 if (o
->default_originate
== DEFAULT_ORIGINATE_ALWAYS
)
2677 vty_out(vty
, " always");
2679 red
= ospf6_redist_lookup(o
, DEFAULT_ROUTE
, 0);
2685 if (red
->dmetric
.value
>= 0)
2686 vty_out(vty
, " metric %d", red
->dmetric
.value
);
2688 if (red
->dmetric
.type
>= 0)
2689 vty_out(vty
, " metric-type %d", red
->dmetric
.type
);
2691 if (ROUTEMAP_NAME(red
))
2692 vty_out(vty
, " route-map %s", ROUTEMAP_NAME(red
));
2697 int ospf6_distribute_config_write(struct vty
*vty
, struct ospf6
*o
)
2702 /* Print default originate configuration. */
2703 if (o
->default_originate
!= DEFAULT_ORIGINATE_NONE
)
2704 ospf6_default_originate_write(vty
, o
);
2709 void install_element_ospf6_debug_asbr(void)
2711 install_element(ENABLE_NODE
, &debug_ospf6_asbr_cmd
);
2712 install_element(ENABLE_NODE
, &no_debug_ospf6_asbr_cmd
);
2713 install_element(CONFIG_NODE
, &debug_ospf6_asbr_cmd
);
2714 install_element(CONFIG_NODE
, &no_debug_ospf6_asbr_cmd
);
2717 /* ASBR Summarisation */
2718 void ospf6_fill_aggr_route_details(struct ospf6
*ospf6
,
2719 struct ospf6_external_aggr_rt
*aggr
)
2721 struct ospf6_route
*rt_aggr
= aggr
->route
;
2722 struct ospf6_external_info
*ei_aggr
= rt_aggr
->route_option
;
2724 rt_aggr
->prefix
= aggr
->p
;
2725 ei_aggr
->tag
= aggr
->tag
;
2727 ei_aggr
->id
= aggr
->id
;
2729 /* When metric is not configured, apply the default metric */
2730 rt_aggr
->path
.cost
= ((aggr
->metric
== -1) ?
2731 DEFAULT_DEFAULT_METRIC
2732 : (unsigned int)(aggr
->metric
));
2733 rt_aggr
->path
.metric_type
= aggr
->mtype
;
2735 rt_aggr
->path
.origin
.id
= htonl(aggr
->id
);
2739 ospf6_summary_add_aggr_route_and_blackhole(struct ospf6
*ospf6
,
2740 struct ospf6_external_aggr_rt
*aggr
)
2742 struct ospf6_route
*rt_aggr
;
2743 struct ospf6_route
*old_rt
= NULL
;
2744 struct ospf6_external_info
*info
;
2746 /* Check if a route is already present. */
2748 old_rt
= aggr
->route
;
2750 /* Create summary route and save it. */
2751 rt_aggr
= ospf6_route_create(ospf6
);
2752 rt_aggr
->type
= OSPF6_DEST_TYPE_NETWORK
;
2753 /* Needed to install route while calling zebra api */
2754 SET_FLAG(rt_aggr
->flag
, OSPF6_ROUTE_BEST
);
2756 info
= XCALLOC(MTYPE_OSPF6_EXTERNAL_INFO
, sizeof(*info
));
2757 rt_aggr
->route_option
= info
;
2758 aggr
->route
= rt_aggr
;
2760 /* Prepare the external_info for aggregator
2761 * Fill all the details which will get advertised
2763 ospf6_fill_aggr_route_details(ospf6
, aggr
);
2765 /* Add next-hop to Null interface. */
2766 ospf6_add_route_nexthop_blackhole(rt_aggr
);
2768 /* Free the old route, if any. */
2770 ospf6_zebra_route_update_remove(old_rt
, ospf6
);
2772 if (old_rt
->route_option
)
2773 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
, old_rt
->route_option
);
2775 ospf6_route_delete(old_rt
);
2778 ospf6_zebra_route_update_add(rt_aggr
, ospf6
);
2781 static void ospf6_originate_new_aggr_lsa(struct ospf6
*ospf6
,
2782 struct ospf6_external_aggr_rt
*aggr
)
2784 struct prefix prefix_id
;
2785 struct ospf6_lsa
*lsa
= NULL
;
2787 if (IS_OSPF6_DEBUG_AGGR
)
2788 zlog_debug("%s: Originate new aggregate route(%pFX)", __func__
,
2791 aggr
->id
= ospf6
->external_id
++;
2793 if (IS_OSPF6_DEBUG_AGGR
)
2795 "Advertise AS-External Id:%pI4 prefix %pFX metric %u",
2796 &prefix_id
.u
.prefix4
, &aggr
->p
, aggr
->metric
);
2798 ospf6_summary_add_aggr_route_and_blackhole(ospf6
, aggr
);
2800 /* Originate summary LSA */
2801 lsa
= ospf6_originate_type5_type7_lsas(aggr
->route
, ospf6
);
2803 if (IS_OSPF6_DEBUG_AGGR
)
2804 zlog_debug("%s: Set the origination bit for aggregator",
2806 SET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
2811 ospf6_aggr_handle_advertise_change(struct ospf6
*ospf6
,
2812 struct ospf6_external_aggr_rt
*aggr
)
2814 /* Check if advertise option modified. */
2815 if (CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
2816 if (IS_OSPF6_DEBUG_AGGR
)
2817 zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
2819 ospf6_asbr_summary_remove_lsa_and_route(ospf6
, aggr
);
2824 /* There are no routes present under this aggregation config, hence
2825 * nothing to originate here
2827 if (OSPF6_EXTERNAL_RT_COUNT(aggr
) == 0) {
2828 if (IS_OSPF6_DEBUG_AGGR
)
2829 zlog_debug("%s: No routes present under this aggregation",
2834 if (!CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
)) {
2835 if (IS_OSPF6_DEBUG_AGGR
)
2836 zlog_debug("%s: Now it is advertisable",
2839 ospf6_originate_new_aggr_lsa(ospf6
, aggr
);
2846 ospf6_originate_summary_lsa(struct ospf6
*ospf6
,
2847 struct ospf6_external_aggr_rt
*aggr
,
2848 struct ospf6_route
*rt
)
2850 struct ospf6_lsa
*lsa
= NULL
, *aggr_lsa
= NULL
;
2851 struct ospf6_external_info
*info
= NULL
;
2852 struct ospf6_external_aggr_rt
*old_aggr
;
2853 struct ospf6_as_external_lsa
*external
;
2854 struct ospf6_route
*rt_aggr
= NULL
;
2855 route_tag_t tag
= 0;
2856 unsigned int metric
= 0;
2859 if (IS_OSPF6_DEBUG_AGGR
)
2860 zlog_debug("%s: Prepare to originate Summary route(%pFX)",
2861 __func__
, &aggr
->p
);
2863 /* This case to handle when the overlapping aggregator address
2864 * is available. Best match will be considered.So need to delink
2865 * from old aggregator and link to the new aggr.
2867 if (rt
->aggr_route
) {
2868 if (rt
->aggr_route
!= aggr
) {
2869 old_aggr
= rt
->aggr_route
;
2870 ospf6_unlink_route_from_aggr(ospf6
, old_aggr
, rt
);
2874 /* Add the external route to hash table */
2875 ospf6_link_route_to_aggr(aggr
, rt
);
2877 /* The key for ID field is a running number and not prefix */
2878 info
= rt
->route_option
;
2881 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
2882 htonl(info
->id
), ospf6
->router_id
,
2885 aggr_lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
2886 htonl(aggr
->id
), ospf6
->router_id
, ospf6
->lsdb
);
2888 if (IS_OSPF6_DEBUG_AGGR
)
2889 zlog_debug("%s: Aggr LSA ID: %d flags %x.",
2890 __func__
, aggr
->id
, aggr
->aggrflags
);
2891 /* Don't originate external LSA,
2892 * If it is configured not to advertise.
2894 if (CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
2895 /* If it is already originated as external LSA,
2896 * But, it is configured not to advertise then
2897 * flush the originated external lsa.
2900 if (IS_OSPF6_DEBUG_AGGR
)
2901 zlog_debug("%s: Purge the external LSA %s.",
2902 __func__
, lsa
->name
);
2903 ospf6_external_lsa_purge(ospf6
, lsa
);
2905 rt
->path
.origin
.id
= 0;
2909 if (IS_OSPF6_DEBUG_AGGR
)
2910 zlog_debug("%s: Purge the aggr external LSA %s.",
2911 __func__
, lsa
->name
);
2912 ospf6_asbr_summary_remove_lsa_and_route(ospf6
, aggr
);
2915 UNSET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
2917 if (IS_OSPF6_DEBUG_AGGR
)
2918 zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
2923 /* Summary route already originated,
2926 if (CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
)) {
2929 "%s: Could not refresh/originate %pFX",
2932 /* Remove the assert later */
2937 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END
2939 metric
= (unsigned long)OSPF6_ASBR_METRIC(external
);
2940 tag
= ospf6_as_external_lsa_get_tag(aggr_lsa
);
2941 mtype
= CHECK_FLAG(external
->bits_metric
,
2942 OSPF6_ASBR_BIT_E
) ? 2 : 1;
2944 /* Prepare the external_info for aggregator */
2945 ospf6_fill_aggr_route_details(ospf6
, aggr
);
2946 rt_aggr
= aggr
->route
;
2947 /* If tag/metric/metric-type modified , then re-originate the
2948 * route with modified tag/metric/metric-type details.
2950 if ((tag
!= aggr
->tag
)
2951 || (metric
!= (unsigned int)rt_aggr
->path
.cost
)
2952 || (mtype
!= aggr
->mtype
)) {
2954 if (IS_OSPF6_DEBUG_AGGR
)
2956 "%s: Routetag(old:%d new:%d)/Metric(o:%u,n:%u)/mtype(o:%d n:%d) modified,So refresh the summary route.(%pFX)",
2957 __func__
, tag
, aggr
->tag
,
2963 aggr_lsa
= ospf6_originate_type5_type7_lsas(aggr
->route
,
2966 SET_FLAG(aggr
->aggrflags
,
2967 OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
2973 /* If the external route prefix same as aggregate route
2974 * and if external route is already originated as TYPE-5
2975 * then just update the aggr info and remove the route info
2977 if (lsa
&& prefix_same(&aggr
->p
, &rt
->prefix
)) {
2978 if (IS_OSPF6_DEBUG_AGGR
)
2980 "%s: Route prefix is same as aggr so no need to re-originate LSA(%pFX)",
2981 __PRETTY_FUNCTION__
, &aggr
->p
);
2983 aggr
->id
= info
->id
;
2985 rt
->path
.origin
.id
= 0;
2987 ospf6_summary_add_aggr_route_and_blackhole(ospf6
, aggr
);
2989 SET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
2994 ospf6_originate_new_aggr_lsa(ospf6
, aggr
);
2997 static void ospf6_aggr_handle_external_info(void *data
)
2999 struct ospf6_route
*rt
= (struct ospf6_route
*)data
;
3000 struct ospf6_external_aggr_rt
*aggr
= NULL
;
3001 struct ospf6_lsa
*lsa
= NULL
;
3002 struct ospf6_external_info
*info
;
3003 struct ospf6
*ospf6
= NULL
;
3005 rt
->aggr_route
= NULL
;
3007 rt
->to_be_processed
= true;
3009 if (IS_OSPF6_DEBUG_ASBR
|| IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL
))
3010 zlog_debug("%s: Handle external route for origination/refresh (%pFX)",
3017 aggr
= ospf6_external_aggr_match(ospf6
,
3020 ospf6_originate_summary_lsa(ospf6
, aggr
, rt
);
3024 info
= rt
->route_option
;
3026 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
3027 htonl(info
->id
), ospf6
->router_id
,
3030 if (IS_OSPF6_DEBUG_AGGR
)
3031 zlog_debug("%s: LSA found, refresh it",
3033 THREAD_OFF(lsa
->refresh
);
3034 thread_add_event(master
, ospf6_lsa_refresh
, lsa
, 0,
3040 info
->id
= ospf6
->external_id
++;
3041 rt
->path
.origin
.id
= htonl(info
->id
);
3043 (void)ospf6_originate_type5_type7_lsas(rt
, ospf6
);
3046 void ospf6_asbr_summary_config_delete(struct ospf6
*ospf6
,
3047 struct route_node
*rn
)
3049 struct ospf6_external_aggr_rt
*aggr
= rn
->info
;
3051 if (IS_OSPF6_DEBUG_AGGR
)
3052 zlog_debug("%s: Deleting Aggregate route (%pFX)",
3056 ospf6_asbr_summary_remove_lsa_and_route(ospf6
, aggr
);
3059 route_unlock_node(rn
);
3063 ospf6_handle_external_aggr_modify(struct ospf6
*ospf6
,
3064 struct ospf6_external_aggr_rt
*aggr
)
3066 struct ospf6_lsa
*lsa
= NULL
;
3067 struct ospf6_as_external_lsa
*asel
= NULL
;
3068 struct ospf6_route
*rt_aggr
;
3069 unsigned int metric
= 0;
3070 route_tag_t tag
= 0;
3073 lsa
= ospf6_lsdb_lookup(
3074 htons(OSPF6_LSTYPE_AS_EXTERNAL
),
3075 htonl(aggr
->id
), ospf6
->router_id
,
3079 "%s: Could not refresh/originate %pFX",
3083 return OSPF6_FAILURE
;
3086 asel
= (struct ospf6_as_external_lsa
*)
3087 OSPF6_LSA_HEADER_END(lsa
->header
);
3088 metric
= (unsigned long)OSPF6_ASBR_METRIC(asel
);
3089 tag
= ospf6_as_external_lsa_get_tag(lsa
);
3090 mtype
= CHECK_FLAG(asel
->bits_metric
,
3091 OSPF6_ASBR_BIT_E
) ? 2 : 1;
3093 /* Fill all the details for advertisement */
3094 ospf6_fill_aggr_route_details(ospf6
, aggr
);
3095 rt_aggr
= aggr
->route
;
3096 /* If tag/metric/metric-type modified , then
3097 * re-originate the route with modified
3098 * tag/metric/metric-type details.
3100 if ((tag
!= aggr
->tag
)
3102 != (unsigned int)rt_aggr
->path
.cost
)
3105 if (IS_OSPF6_DEBUG_AGGR
)
3107 "%s: Changed tag(old:%d new:%d)/metric(o:%u n:%d)/mtype(o:%d n:%d),So refresh the summary route.(%pFX)",
3111 (unsigned int)rt_aggr
->path
.cost
,
3115 (void)ospf6_originate_type5_type7_lsas(
3120 return OSPF6_SUCCESS
;
3123 static void ospf6_handle_external_aggr_update(struct ospf6
*ospf6
)
3125 struct route_node
*rn
= NULL
;
3128 if (IS_OSPF6_DEBUG_AGGR
)
3129 zlog_debug("%s: Process modified aggregators.", __func__
);
3131 for (rn
= route_top(ospf6
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
3132 struct ospf6_external_aggr_rt
*aggr
;
3139 if (aggr
->action
== OSPF6_ROUTE_AGGR_DEL
) {
3140 aggr
->action
= OSPF6_ROUTE_AGGR_NONE
;
3141 ospf6_asbr_summary_config_delete(ospf6
, rn
);
3143 if (OSPF6_EXTERNAL_RT_COUNT(aggr
))
3144 hash_clean(aggr
->match_extnl_hash
,
3145 ospf6_aggr_handle_external_info
);
3147 hash_free(aggr
->match_extnl_hash
);
3148 XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR
, aggr
);
3150 } else if (aggr
->action
== OSPF6_ROUTE_AGGR_MODIFY
) {
3152 aggr
->action
= OSPF6_ROUTE_AGGR_NONE
;
3154 /* Check if tag/metric/metric-type modified */
3155 if (CHECK_FLAG(aggr
->aggrflags
,
3156 OSPF6_EXTERNAL_AGGRT_ORIGINATED
)
3157 && !CHECK_FLAG(aggr
->aggrflags
,
3158 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
3160 ret
= ospf6_handle_external_aggr_modify(ospf6
,
3162 if (ret
== OSPF6_FAILURE
)
3166 /* Advertise option modified ?
3167 * If so, handled it here.
3169 ospf6_aggr_handle_advertise_change(ospf6
, aggr
);
3174 static void ospf6_aggr_unlink_external_info(void *data
)
3176 struct ospf6_route
*rt
= (struct ospf6_route
*)data
;
3178 rt
->aggr_route
= NULL
;
3180 rt
->to_be_processed
= true;
3183 void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt
*aggr
)
3185 if (OSPF6_EXTERNAL_RT_COUNT(aggr
))
3186 hash_clean(aggr
->match_extnl_hash
,
3187 ospf6_aggr_unlink_external_info
);
3189 if (IS_OSPF6_DEBUG_AGGR
)
3190 zlog_debug("%s: Release the aggregator Address(%pFX)",
3194 hash_free(aggr
->match_extnl_hash
);
3195 aggr
->match_extnl_hash
= NULL
;
3197 XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR
, aggr
);
3201 ospf6_delete_all_marked_aggregators(struct ospf6
*ospf6
)
3203 struct route_node
*rn
= NULL
;
3204 struct ospf6_external_aggr_rt
*aggr
;
3206 /* Loop through all the aggregators, Delete all aggregators
3207 * which are marked as DELETE. Set action to NONE for remaining
3210 for (rn
= route_top(ospf6
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
3216 if (aggr
->action
!= OSPF6_ROUTE_AGGR_DEL
) {
3217 aggr
->action
= OSPF6_ROUTE_AGGR_NONE
;
3220 ospf6_asbr_summary_config_delete(ospf6
, rn
);
3221 ospf6_external_aggregator_free(aggr
);
3225 static void ospf6_handle_exnl_rt_after_aggr_del(struct ospf6
*ospf6
,
3226 struct ospf6_route
*rt
)
3228 struct ospf6_lsa
*lsa
;
3230 /* Process only marked external routes.
3231 * These routes were part of a deleted
3232 * aggregator.So, originate now.
3234 if (!rt
->to_be_processed
)
3237 rt
->to_be_processed
= false;
3239 lsa
= ospf6_find_external_lsa(ospf6
, &rt
->prefix
);
3242 THREAD_OFF(lsa
->refresh
);
3243 thread_add_event(master
, ospf6_lsa_refresh
, lsa
, 0,
3246 if (IS_OSPF6_DEBUG_AGGR
)
3247 zlog_debug("%s: Originate external route(%pFX)",
3251 (void)ospf6_originate_type5_type7_lsas(rt
, ospf6
);
3255 static void ospf6_handle_aggregated_exnl_rt(struct ospf6
*ospf6
,
3256 struct ospf6_external_aggr_rt
*aggr
,
3257 struct ospf6_route
*rt
)
3259 struct ospf6_lsa
*lsa
;
3260 struct ospf6_as_external_lsa
*ext_lsa
;
3261 struct ospf6_external_info
*info
;
3263 /* Handling the case where the external route prefix
3264 * and aggegate prefix is same
3265 * If same don't flush the originated external LSA.
3267 if (prefix_same(&aggr
->p
, &rt
->prefix
)) {
3268 if (IS_OSPF6_DEBUG_AGGR
)
3269 zlog_debug("%s: External Route prefix same as Aggregator(%pFX), so don't flush.",
3276 info
= rt
->route_option
;
3279 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
3280 htonl(info
->id
), ospf6
->router_id
, ospf6
->lsdb
);
3282 ext_lsa
= (struct ospf6_as_external_lsa
3283 *)((char *)(lsa
->header
)
3284 + sizeof(struct ospf6_lsa_header
));
3286 if (rt
->prefix
.prefixlen
!= ext_lsa
->prefix
.prefix_length
)
3289 ospf6_external_lsa_purge(ospf6
, lsa
);
3291 /* Resetting the ID of route */
3292 rt
->path
.origin
.id
= 0;
3298 ospf6_handle_external_aggr_add(struct ospf6
*ospf6
)
3300 struct ospf6_route
*rt
= NULL
;
3301 struct ospf6_external_info
*ei
= NULL
;
3302 struct ospf6_external_aggr_rt
*aggr
;
3304 /* Delete all the aggregators which are marked as
3305 * OSPF6_ROUTE_AGGR_DEL.
3307 ospf6_delete_all_marked_aggregators(ospf6
);
3309 for (rt
= ospf6_route_head(ospf6
->external_table
); rt
;
3310 rt
= ospf6_route_next(rt
)) {
3311 ei
= rt
->route_option
;
3315 if (is_default_prefix(&rt
->prefix
))
3318 aggr
= ospf6_external_aggr_match(ospf6
,
3321 /* If matching aggregator found, Add
3322 * the external route refrenace to the
3323 * aggregator and originate the aggr
3324 * route if it is advertisable.
3325 * flush the external LSA if it is
3326 * already originated for this external
3330 ospf6_originate_summary_lsa(ospf6
, aggr
, rt
);
3332 /* All aggregated external rts
3335 ospf6_handle_aggregated_exnl_rt(
3340 /* External routes which are only out
3341 * of aggregation will be handled here.
3343 ospf6_handle_exnl_rt_after_aggr_del(
3348 static void ospf6_asbr_summary_process(struct thread
*thread
)
3350 struct ospf6
*ospf6
= THREAD_ARG(thread
);
3353 operation
= ospf6
->aggr_action
;
3355 if (IS_OSPF6_DEBUG_AGGR
)
3356 zlog_debug("%s: operation:%d",
3360 switch (operation
) {
3361 case OSPF6_ROUTE_AGGR_ADD
:
3362 ospf6_handle_external_aggr_add(ospf6
);
3364 case OSPF6_ROUTE_AGGR_DEL
:
3365 case OSPF6_ROUTE_AGGR_MODIFY
:
3366 ospf6_handle_external_aggr_update(ospf6
);
3374 ospf6_start_asbr_summary_delay_timer(struct ospf6
*ospf6
,
3375 struct ospf6_external_aggr_rt
*aggr
,
3376 ospf6_aggr_action_t operation
)
3378 aggr
->action
= operation
;
3380 if (thread_is_scheduled(ospf6
->t_external_aggr
)) {
3381 if (ospf6
->aggr_action
== OSPF6_ROUTE_AGGR_ADD
) {
3383 if (IS_OSPF6_DEBUG_AGGR
)
3384 zlog_debug("%s: Not required to restart timer,set is already added.",
3389 if (operation
== OSPF6_ROUTE_AGGR_ADD
) {
3390 if (IS_OSPF6_DEBUG_AGGR
)
3391 zlog_debug("%s, Restarting Aggregator delay timer.",
3393 THREAD_OFF(ospf6
->t_external_aggr
);
3397 if (IS_OSPF6_DEBUG_AGGR
)
3398 zlog_debug("%s: Start Aggregator delay timer %u(in seconds).",
3399 __func__
, ospf6
->aggr_delay_interval
);
3401 ospf6
->aggr_action
= operation
;
3402 thread_add_timer(master
,
3403 ospf6_asbr_summary_process
,
3404 ospf6
, ospf6
->aggr_delay_interval
,
3405 &ospf6
->t_external_aggr
);
3408 int ospf6_asbr_external_rt_advertise(struct ospf6
*ospf6
,
3411 struct route_node
*rn
;
3412 struct ospf6_external_aggr_rt
*aggr
;
3414 rn
= route_node_lookup(ospf6
->rt_aggr_tbl
, p
);
3416 return OSPF6_INVALID
;
3420 route_unlock_node(rn
);
3422 if (!CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
))
3423 return OSPF6_INVALID
;
3425 UNSET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
);
3427 if (!OSPF6_EXTERNAL_RT_COUNT(aggr
))
3428 return OSPF6_SUCCESS
;
3430 ospf6_start_asbr_summary_delay_timer(ospf6
, aggr
,
3431 OSPF6_ROUTE_AGGR_MODIFY
);
3433 return OSPF6_SUCCESS
;
3436 int ospf6_external_aggr_delay_timer_set(struct ospf6
*ospf6
, uint16_t interval
)
3438 ospf6
->aggr_delay_interval
= interval
;
3440 return OSPF6_SUCCESS
;
3443 static unsigned int ospf6_external_rt_hash_key(const void *data
)
3445 const struct ospf6_route
*rt
= data
;
3446 unsigned int key
= 0;
3448 key
= prefix_hash_key(&rt
->prefix
);
3452 static bool ospf6_external_rt_hash_cmp(const void *d1
, const void *d2
)
3454 const struct ospf6_route
*rt1
= d1
;
3455 const struct ospf6_route
*rt2
= d2
;
3457 return prefix_same(&rt1
->prefix
, &rt2
->prefix
);
3460 static struct ospf6_external_aggr_rt
*
3461 ospf6_external_aggr_new(struct prefix
*p
)
3463 struct ospf6_external_aggr_rt
*aggr
;
3465 aggr
= XCALLOC(MTYPE_OSPF6_EXTERNAL_RT_AGGR
,
3466 sizeof(struct ospf6_external_aggr_rt
));
3468 prefix_copy(&aggr
->p
, p
);
3470 aggr
->mtype
= DEFAULT_METRIC_TYPE
;
3471 aggr
->match_extnl_hash
= hash_create(ospf6_external_rt_hash_key
,
3472 ospf6_external_rt_hash_cmp
,
3473 "Ospf6 external route hash");
3477 static void ospf6_external_aggr_add(struct ospf6
*ospf6
,
3478 struct ospf6_external_aggr_rt
*aggr
)
3480 struct route_node
*rn
;
3482 if (IS_OSPF6_DEBUG_AGGR
)
3483 zlog_debug("%s: Adding Aggregate route to Aggr table (%pFX)",
3487 rn
= route_node_get(ospf6
->rt_aggr_tbl
, &aggr
->p
);
3489 route_unlock_node(rn
);
3494 int ospf6_asbr_external_rt_no_advertise(struct ospf6
*ospf6
,
3497 struct ospf6_external_aggr_rt
*aggr
;
3498 route_tag_t tag
= 0;
3500 aggr
= ospf6_external_aggr_config_lookup(ospf6
, p
);
3502 if (CHECK_FLAG(aggr
->aggrflags
,
3503 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
))
3504 return OSPF6_SUCCESS
;
3506 SET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
);
3511 if (!OSPF6_EXTERNAL_RT_COUNT(aggr
))
3512 return OSPF6_SUCCESS
;
3514 ospf6_start_asbr_summary_delay_timer(ospf6
, aggr
,
3515 OSPF6_ROUTE_AGGR_MODIFY
);
3517 aggr
= ospf6_external_aggr_new(p
);
3520 return OSPF6_FAILURE
;
3522 SET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
);
3523 ospf6_external_aggr_add(ospf6
, aggr
);
3524 ospf6_start_asbr_summary_delay_timer(ospf6
, aggr
,
3525 OSPF6_ROUTE_AGGR_ADD
);
3528 return OSPF6_SUCCESS
;
3531 struct ospf6_external_aggr_rt
*
3532 ospf6_external_aggr_config_lookup(struct ospf6
*ospf6
, struct prefix
*p
)
3534 struct route_node
*rn
;
3536 rn
= route_node_lookup(ospf6
->rt_aggr_tbl
, p
);
3538 route_unlock_node(rn
);
3546 int ospf6_external_aggr_config_set(struct ospf6
*ospf6
, struct prefix
*p
,
3547 route_tag_t tag
, int metric
, int mtype
)
3549 struct ospf6_external_aggr_rt
*aggregator
;
3551 aggregator
= ospf6_external_aggr_config_lookup(ospf6
, p
);
3554 if (CHECK_FLAG(aggregator
->aggrflags
,
3555 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
))
3556 UNSET_FLAG(aggregator
->aggrflags
,
3557 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
);
3558 else if ((aggregator
->tag
== tag
)
3559 && (aggregator
->metric
== metric
)
3560 && (aggregator
->mtype
== mtype
))
3561 return OSPF6_SUCCESS
;
3563 aggregator
->tag
= tag
;
3564 aggregator
->metric
= metric
;
3565 aggregator
->mtype
= mtype
;
3567 ospf6_start_asbr_summary_delay_timer(ospf6
, aggregator
,
3568 OSPF6_ROUTE_AGGR_MODIFY
);
3570 aggregator
= ospf6_external_aggr_new(p
);
3572 return OSPF6_FAILURE
;
3574 aggregator
->tag
= tag
;
3575 aggregator
->metric
= metric
;
3576 aggregator
->mtype
= mtype
;
3578 ospf6_external_aggr_add(ospf6
, aggregator
);
3579 ospf6_start_asbr_summary_delay_timer(ospf6
, aggregator
,
3580 OSPF6_ROUTE_AGGR_ADD
);
3583 return OSPF6_SUCCESS
;
3586 int ospf6_external_aggr_config_unset(struct ospf6
*ospf6
,
3589 struct route_node
*rn
;
3590 struct ospf6_external_aggr_rt
*aggr
;
3592 rn
= route_node_lookup(ospf6
->rt_aggr_tbl
, p
);
3594 return OSPF6_INVALID
;
3598 route_unlock_node(rn
);
3600 if (!OSPF6_EXTERNAL_RT_COUNT(aggr
)) {
3601 ospf6_asbr_summary_config_delete(ospf6
, rn
);
3602 ospf6_external_aggregator_free(aggr
);
3603 return OSPF6_SUCCESS
;
3606 ospf6_start_asbr_summary_delay_timer(ospf6
, aggr
,
3607 OSPF6_ROUTE_AGGR_DEL
);
3609 return OSPF6_SUCCESS
;
3612 void ospf6_handle_external_lsa_origination(struct ospf6
*ospf6
,
3613 struct ospf6_route
*rt
,
3617 struct ospf6_external_aggr_rt
*aggr
;
3618 struct ospf6_external_info
*info
;
3619 struct prefix prefix_id
;
3621 if (!is_default_prefix(p
)) {
3622 aggr
= ospf6_external_aggr_match(ospf6
,
3627 if (IS_OSPF6_DEBUG_AGGR
)
3628 zlog_debug("%s: Send Aggregate LSA (%pFX)",
3632 ospf6_originate_summary_lsa(
3635 /* Handling the case where the
3636 * external route prefix
3637 * and aggegate prefix is same
3638 * If same don't flush the
3642 ospf6_handle_aggregated_exnl_rt(
3648 info
= rt
->route_option
;
3650 /* When the info->id = 0, it means it is being originated for the
3654 info
->id
= ospf6
->external_id
++;
3656 prefix_id
.family
= AF_INET
;
3657 prefix_id
.prefixlen
= 32;
3658 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
3661 rt
->path
.origin
.id
= htonl(info
->id
);
3663 if (IS_OSPF6_DEBUG_ASBR
) {
3664 zlog_debug("Advertise new AS-External Id:%pI4 prefix %pFX metric %u",
3665 &prefix_id
.u
.prefix4
, p
, rt
->path
.metric_type
);
3668 ospf6_originate_type5_type7_lsas(rt
, ospf6
);
3672 void ospf6_unset_all_aggr_flag(struct ospf6
*ospf6
)
3674 struct route_node
*rn
= NULL
;
3675 struct ospf6_external_aggr_rt
*aggr
;
3677 if (IS_OSPF6_DEBUG_AGGR
)
3678 zlog_debug("Unset the origination bit for all aggregator");
3680 /* Resetting the running external ID counter so that the origination
3681 * of external LSAs starts from the beginning 0.0.0.1
3683 ospf6
->external_id
= OSPF6_EXT_INIT_LS_ID
;
3685 for (rn
= route_top(ospf6
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
3691 UNSET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);