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 #ifndef VTYSH_EXTRACT_PL
69 #include "ospf6d/ospf6_asbr_clippy.c"
72 unsigned char conf_debug_ospf6_asbr
= 0;
74 #define ZROUTE_NAME(x) zebra_route_string(x)
76 /* Originate Type-5 and Type-7 LSA */
77 static struct ospf6_lsa
*ospf6_originate_type5_type7_lsas(
78 struct ospf6_route
*route
,
81 struct ospf6_lsa
*lsa
;
82 struct listnode
*lnode
;
83 struct ospf6_area
*oa
= NULL
;
85 lsa
= ospf6_as_external_lsa_originate(route
, ospf6
);
87 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, lnode
, oa
)) {
89 ospf6_nssa_lsa_originate(route
, oa
, true);
95 /* AS External LSA origination */
96 struct ospf6_lsa
*ospf6_as_external_lsa_originate(struct ospf6_route
*route
,
99 char buffer
[OSPF6_MAX_LSASIZE
];
100 struct ospf6_lsa_header
*lsa_header
;
101 struct ospf6_lsa
*lsa
;
102 struct ospf6_external_info
*info
= route
->route_option
;
104 struct ospf6_as_external_lsa
*as_external_lsa
;
107 if (ospf6
->gr_info
.restart_in_progress
) {
108 if (IS_DEBUG_OSPF6_GR
)
110 "Graceful Restart in progress, don't originate LSA");
114 if (IS_OSPF6_DEBUG_ASBR
|| IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL
))
115 zlog_debug("Originate AS-External-LSA for %pFX",
119 memset(buffer
, 0, sizeof(buffer
));
120 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
121 as_external_lsa
= (struct ospf6_as_external_lsa
122 *)((caddr_t
)lsa_header
123 + sizeof(struct ospf6_lsa_header
));
124 p
= (caddr_t
)((caddr_t
)as_external_lsa
125 + sizeof(struct ospf6_as_external_lsa
));
127 /* Fill AS-External-LSA */
129 if (route
->path
.metric_type
== 2)
130 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
132 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
134 /* forwarding address */
135 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
136 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
138 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
140 /* external route tag */
142 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
144 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
147 OSPF6_ASBR_METRIC_SET(as_external_lsa
, route
->path
.cost
);
150 as_external_lsa
->prefix
.prefix_length
= route
->prefix
.prefixlen
;
153 as_external_lsa
->prefix
.prefix_options
= route
->prefix_options
;
155 /* don't use refer LS-type */
156 as_external_lsa
->prefix
.prefix_refer_lstype
= htons(0);
159 memcpy(p
, &route
->prefix
.u
.prefix6
,
160 OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
));
161 ospf6_prefix_apply_mask(&as_external_lsa
->prefix
);
162 p
+= OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
);
164 /* Forwarding address */
165 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
166 memcpy(p
, &info
->forwarding
, sizeof(struct in6_addr
));
167 p
+= sizeof(struct in6_addr
);
170 /* External Route Tag */
171 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
172 route_tag_t network_order
= htonl(info
->tag
);
174 memcpy(p
, &network_order
, sizeof(network_order
));
175 p
+= sizeof(network_order
);
178 /* Fill LSA Header */
180 lsa_header
->type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
181 lsa_header
->id
= route
->path
.origin
.id
;
182 lsa_header
->adv_router
= ospf6
->router_id
;
184 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
185 lsa_header
->adv_router
, ospf6
->lsdb
);
186 lsa_header
->length
= htons((caddr_t
)p
- (caddr_t
)lsa_header
);
189 ospf6_lsa_checksum(lsa_header
);
192 lsa
= ospf6_lsa_create(lsa_header
);
195 ospf6_lsa_originate_process(lsa
, ospf6
);
200 void ospf6_orig_as_external_lsa(struct thread
*thread
)
202 struct ospf6_interface
*oi
;
203 struct ospf6_lsa
*lsa
;
204 uint32_t type
, adv_router
;
206 oi
= (struct ospf6_interface
*)THREAD_ARG(thread
);
208 if (oi
->state
== OSPF6_INTERFACE_DOWN
)
210 if (IS_AREA_NSSA(oi
->area
) || IS_AREA_STUB(oi
->area
))
213 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
214 adv_router
= oi
->area
->ospf6
->router_id
;
215 for (ALL_LSDB_TYPED_ADVRTR(oi
->area
->ospf6
->lsdb
, type
, adv_router
,
217 if (IS_OSPF6_DEBUG_ASBR
)
219 "%s: Send update of AS-External LSA %s seq 0x%x",
221 ntohl(lsa
->header
->seqnum
));
223 ospf6_flood_interface(NULL
, lsa
, oi
);
227 static route_tag_t
ospf6_as_external_lsa_get_tag(struct ospf6_lsa
*lsa
)
229 struct ospf6_as_external_lsa
*external
;
230 ptrdiff_t tag_offset
;
231 route_tag_t network_order
;
236 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
239 if (!CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
242 tag_offset
= sizeof(*external
)
243 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
244 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
245 tag_offset
+= sizeof(struct in6_addr
);
247 memcpy(&network_order
, (caddr_t
)external
+ tag_offset
,
248 sizeof(network_order
));
249 return ntohl(network_order
);
252 void ospf6_asbr_update_route_ecmp_path(struct ospf6_route
*old
,
253 struct ospf6_route
*route
,
256 struct ospf6_route
*old_route
, *next_route
;
257 struct ospf6_path
*ecmp_path
, *o_path
= NULL
;
258 struct listnode
*anode
, *anext
;
259 struct listnode
*nnode
, *rnode
, *rnext
;
260 struct ospf6_nexthop
*nh
, *rnh
;
261 bool route_found
= false;
263 /* check for old entry match with new route origin,
266 for (old_route
= old
; old_route
; old_route
= next_route
) {
267 bool route_updated
= false;
269 next_route
= old_route
->next
;
271 /* The route linked-list is grouped in batches of prefix.
272 * If the new prefix is not the same as the one of interest
273 * then we have walked over the end of the batch and so we
274 * should break rather than continuing unnecessarily.
276 if (!ospf6_route_is_same(old_route
, route
))
278 if (old_route
->path
.type
!= route
->path
.type
)
281 /* Current and New route has same origin,
284 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
, anext
,
286 /* Check old route path and route has same
289 if (o_path
->area_id
!= route
->path
.area_id
290 || !ospf6_ls_origin_same(o_path
, &route
->path
))
293 /* Cost is not same then delete current path */
294 if ((o_path
->cost
== route
->path
.cost
)
295 && (o_path
->u
.cost_e2
== route
->path
.u
.cost_e2
))
298 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
300 "%s: route %pFX cost old %u new %u is not same, replace route",
301 __func__
, &old_route
->prefix
, o_path
->cost
,
305 /* Remove selected current rout path's nh from
308 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
309 for (ALL_LIST_ELEMENTS(old_route
->nh_list
,
310 rnode
, rnext
, rnh
)) {
311 if (!ospf6_nexthop_is_same(rnh
, nh
))
313 listnode_delete(old_route
->nh_list
,
315 ospf6_nexthop_delete(rnh
);
319 listnode_delete(old_route
->paths
, o_path
);
320 ospf6_path_free(o_path
);
321 route_updated
= true;
323 /* Current route's path (adv_router info) is similar
324 * to route being added.
325 * Replace current route's path with paths list head.
326 * Update FIB with effective NHs.
328 if (listcount(old_route
->paths
)) {
329 for (ALL_LIST_ELEMENTS(old_route
->paths
,
330 anode
, anext
, o_path
)) {
331 ospf6_merge_nexthops(
335 /* Update RIB/FIB with effective
338 if (ospf6
->route_table
->hook_add
)
339 (*ospf6
->route_table
->hook_add
)(
342 if (old_route
->path
.origin
.id
343 == route
->path
.origin
.id
344 && old_route
->path
.origin
.adv_router
345 == route
->path
.origin
347 struct ospf6_path
*h_path
;
349 h_path
= (struct ospf6_path
*)
350 listgetdata(listhead(
352 old_route
->path
.origin
.type
=
354 old_route
->path
.origin
.id
=
356 old_route
->path
.origin
.adv_router
=
357 h_path
->origin
.adv_router
;
360 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
362 "%s: route %pFX old cost %u new cost %u, delete old entry.",
363 __func__
, &old_route
->prefix
,
364 old_route
->path
.cost
,
367 if (old
== old_route
)
369 ospf6_route_remove(old_route
,
378 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
380 /* The route linked-list is grouped in batches of prefix.
381 * If the new prefix is not the same as the one of interest
382 * then we have walked over the end of the batch and so we
383 * should break rather than continuing unnecessarily.
385 if (!ospf6_route_is_same(old_route
, route
))
387 if (old_route
->path
.type
!= route
->path
.type
)
390 /* Old Route and New Route have Equal Cost, Merge NHs */
391 if ((old_route
->path
.cost
== route
->path
.cost
)
392 && (old_route
->path
.u
.cost_e2
== route
->path
.u
.cost_e2
)) {
394 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
396 "%s: old route %pFX path cost %u e2 %u",
397 __func__
, &old_route
->prefix
,
398 old_route
->path
.cost
,
399 old_route
->path
.u
.cost_e2
);
402 /* check if this path exists already in
403 * route->paths list, if so, replace nh_list
406 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
408 if (o_path
->area_id
== route
->path
.area_id
409 && ospf6_ls_origin_same(o_path
, &route
->path
))
412 /* If path is not found in old_route paths's list,
413 * add a new path to route paths list and merge
414 * nexthops in route->path->nh_list.
415 * Otherwise replace existing path's nh_list.
417 if (o_path
== NULL
) {
418 ecmp_path
= ospf6_path_dup(&route
->path
);
420 /* Add a nh_list to new ecmp path */
421 ospf6_copy_nexthops(ecmp_path
->nh_list
,
424 /* Add the new path to route's path list */
425 listnode_add_sort(old_route
->paths
, ecmp_path
);
427 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
429 "%s: route %pFX another path added with nh %u, effective paths %u nh %u",
430 __func__
, &route
->prefix
,
431 listcount(ecmp_path
->nh_list
),
432 old_route
->paths
? listcount(
435 listcount(old_route
->nh_list
));
438 list_delete_all_node(o_path
->nh_list
);
439 ospf6_copy_nexthops(o_path
->nh_list
,
443 /* Reset nexthop lists, rebuild from brouter table
444 * for each adv. router.
446 list_delete_all_node(old_route
->nh_list
);
448 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
450 struct ospf6_route
*asbr_entry
;
452 asbr_entry
= ospf6_route_lookup(
454 ospf6
->brouter_table
);
455 if (asbr_entry
== NULL
) {
456 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
458 "%s: ls_prfix %pFX asbr_entry not found.",
463 ospf6_route_merge_nexthops(old_route
,
467 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
469 "%s: route %pFX with effective paths %u nh %u",
470 __func__
, &route
->prefix
,
472 ? listcount(old_route
->paths
)
475 ? listcount(old_route
->nh_list
)
479 if (ospf6
->route_table
->hook_add
)
480 (*ospf6
->route_table
->hook_add
)(old_route
);
482 /* Delete the new route its info added to existing
485 ospf6_route_delete(route
);
492 /* Add new route to existing node in ospf6 route table. */
493 ospf6_route_add(route
, ospf6
->route_table
);
497 /* Check if the forwarding address is local address */
498 static int ospf6_ase_forward_address_check(struct ospf6
*ospf6
,
499 struct in6_addr
*fwd_addr
)
501 struct listnode
*anode
, *node
, *cnode
;
502 struct ospf6_interface
*oi
;
503 struct ospf6_area
*oa
;
504 struct interface
*ifp
;
507 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, oa
)) {
508 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, node
, oi
)) {
509 if (!if_is_operative(oi
->interface
)
510 || oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
514 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
515 if (IPV6_ADDR_SAME(&c
->address
->u
.prefix6
,
525 void ospf6_asbr_lsa_add(struct ospf6_lsa
*lsa
)
527 struct ospf6_as_external_lsa
*external
;
528 struct prefix asbr_id
;
529 struct ospf6_route
*asbr_entry
, *route
, *old
= NULL
;
530 struct ospf6_path
*path
;
533 struct ospf6_area
*oa
= NULL
;
534 struct prefix fwd_addr
;
537 type
= ntohs(lsa
->header
->type
);
538 oa
= lsa
->lsdb
->data
;
540 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
543 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
544 zlog_debug("Calculate AS-External route for %s", lsa
->name
);
546 ospf6
= ospf6_get_by_lsdb(lsa
);
548 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
549 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
550 zlog_debug("Ignore self-originated AS-External-LSA");
554 if (OSPF6_ASBR_METRIC(external
) == OSPF_LS_INFINITY
) {
555 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
556 zlog_debug("Ignore LSA with LSInfinity Metric");
560 if (CHECK_FLAG(external
->prefix
.prefix_options
,
561 OSPF6_PREFIX_OPTION_NU
)) {
562 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
563 zlog_debug("Ignore LSA with NU bit set Metric");
567 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &asbr_id
);
568 asbr_entry
= ospf6_route_lookup(&asbr_id
, ospf6
->brouter_table
);
569 if (asbr_entry
== NULL
) {
570 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
571 zlog_debug("ASBR entry not found: %pFX", &asbr_id
);
574 /* The router advertising external LSA can be ASBR or ABR */
575 if (!CHECK_FLAG(asbr_entry
->path
.router_bits
,
576 OSPF6_ROUTER_BIT_E
)) {
577 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
579 "External bit reset ASBR route entry : %pFX",
585 * RFC 3101 - Section 2.5:
586 * "For a Type-7 LSA the matching routing table entry must
587 * specify an intra-area path through the LSA's originating
590 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_TYPE_7
591 && (asbr_entry
->path
.area_id
!= oa
->area_id
592 || asbr_entry
->path
.type
!= OSPF6_PATH_TYPE_INTRA
)) {
593 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
595 "Intra-area route to NSSA ASBR not found: %pFX",
602 * RFC 3101 - Section 2.5:
603 * "If the destination is a Type-7 default route (destination ID =
604 * DefaultDestination) and one of the following is true, then do
605 * nothing with this LSA and consider the next in the list:
607 * o The calculating router is a border router and the LSA has
608 * its P-bit clear. Appendix E describes a technique
609 * whereby an NSSA border router installs a Type-7 default
610 * LSA without propagating it.
612 * o The calculating router is a border router and is
613 * suppressing the import of summary routes as Type-3
616 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_TYPE_7
617 && external
->prefix
.prefix_length
== 0
618 && CHECK_FLAG(ospf6
->flag
, OSPF6_FLAG_ABR
)
619 && (CHECK_FLAG(external
->prefix
.prefix_options
,
620 OSPF6_PREFIX_OPTION_P
)
621 || oa
->no_summary
)) {
622 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
623 zlog_debug("Skipping Type-7 default route");
627 /* Check the forwarding address */
628 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
629 offset
= sizeof(*external
)
630 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
631 memset(&fwd_addr
, 0, sizeof(fwd_addr
));
632 fwd_addr
.family
= AF_INET6
;
633 fwd_addr
.prefixlen
= IPV6_MAX_BITLEN
;
634 memcpy(&fwd_addr
.u
.prefix6
, (caddr_t
)external
+ offset
,
635 sizeof(struct in6_addr
));
637 if (!IN6_IS_ADDR_UNSPECIFIED(&fwd_addr
.u
.prefix6
)) {
638 if (!ospf6_ase_forward_address_check(
639 ospf6
, &fwd_addr
.u
.prefix6
)) {
640 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
642 "Fwd address %pFX is local address",
647 /* Find the forwarding entry */
648 asbr_entry
= ospf6_route_lookup_bestmatch(
649 &fwd_addr
, ospf6
->route_table
);
650 if (asbr_entry
== NULL
) {
651 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
653 "Fwd address not found: %pFX",
660 route
= ospf6_route_create(ospf6
);
661 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
662 route
->prefix
.family
= AF_INET6
;
663 route
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
664 ospf6_prefix_in6_addr(&route
->prefix
.u
.prefix6
, external
,
666 route
->prefix_options
= external
->prefix
.prefix_options
;
668 route
->path
.area_id
= asbr_entry
->path
.area_id
;
669 route
->path
.origin
.type
= lsa
->header
->type
;
670 route
->path
.origin
.id
= lsa
->header
->id
;
671 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
672 memcpy(&route
->path
.ls_prefix
, &asbr_id
, sizeof(struct prefix
));
674 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
675 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
676 route
->path
.metric_type
= 2;
677 route
->path
.cost
= asbr_entry
->path
.cost
;
678 route
->path
.u
.cost_e2
= OSPF6_ASBR_METRIC(external
);
680 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
681 route
->path
.metric_type
= 1;
683 asbr_entry
->path
.cost
+ OSPF6_ASBR_METRIC(external
);
684 route
->path
.u
.cost_e2
= 0;
687 route
->path
.tag
= ospf6_as_external_lsa_get_tag(lsa
);
689 ospf6_route_copy_nexthops(route
, asbr_entry
);
691 path
= ospf6_path_dup(&route
->path
);
692 ospf6_copy_nexthops(path
->nh_list
, asbr_entry
->nh_list
);
693 listnode_add_sort(route
->paths
, path
);
696 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
698 "%s: %s %u route add %pFX cost %u(%u) nh %u", __func__
,
699 (type
== OSPF6_LSTYPE_AS_EXTERNAL
) ? "AS-External"
701 (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
) ? 1 : 2,
702 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
703 listcount(route
->nh_list
));
705 if (type
== OSPF6_LSTYPE_AS_EXTERNAL
)
706 old
= ospf6_route_lookup(&route
->prefix
, ospf6
->route_table
);
707 else if (type
== OSPF6_LSTYPE_TYPE_7
)
708 old
= ospf6_route_lookup(&route
->prefix
, oa
->route_table
);
710 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
711 zlog_debug("%s: Adding new route", __func__
);
712 /* Add the new route to ospf6 instance route table. */
713 if (type
== OSPF6_LSTYPE_AS_EXTERNAL
)
714 ospf6_route_add(route
, ospf6
->route_table
);
715 /* Add the route to the area route table */
716 else if (type
== OSPF6_LSTYPE_TYPE_7
) {
717 ospf6_route_add(route
, oa
->route_table
);
721 * ECMP: Keep new equal preference path in current
722 * route's path list, update zebra with new effective
723 * list along with addition of ECMP path.
725 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
726 zlog_debug("%s : old route %pFX cost %u(%u) nh %u",
727 __func__
, &route
->prefix
, route
->path
.cost
,
728 route
->path
.u
.cost_e2
,
729 listcount(route
->nh_list
));
730 ospf6_asbr_update_route_ecmp_path(old
, route
, ospf6
);
734 void ospf6_asbr_lsa_remove(struct ospf6_lsa
*lsa
,
735 struct ospf6_route
*asbr_entry
)
737 struct ospf6_as_external_lsa
*external
;
738 struct prefix prefix
;
739 struct ospf6_route
*route
, *nroute
, *route_to_del
;
740 struct ospf6_area
*oa
= NULL
;
745 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
748 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
) || (IS_OSPF6_DEBUG_NSSA
))
751 ospf6
= ospf6_get_by_lsdb(lsa
);
752 type
= ntohs(lsa
->header
->type
);
754 if (type
== OSPF6_LSTYPE_TYPE_7
) {
756 zlog_debug("%s: Withdraw Type 7 route for %s",
757 __func__
, lsa
->name
);
758 oa
= lsa
->lsdb
->data
;
761 zlog_debug("%s: Withdraw AS-External route for %s",
762 __func__
, lsa
->name
);
764 if (ospf6_check_and_set_router_abr(ospf6
))
765 oa
= ospf6
->backbone
;
767 oa
= listnode_head(ospf6
->area_list
);
772 zlog_debug("%s: Invalid area", __func__
);
776 if (lsa
->header
->adv_router
== oa
->ospf6
->router_id
) {
778 zlog_debug("Ignore self-originated AS-External-LSA");
782 route_to_del
= ospf6_route_create(ospf6
);
783 route_to_del
->type
= OSPF6_DEST_TYPE_NETWORK
;
784 route_to_del
->prefix
.family
= AF_INET6
;
785 route_to_del
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
786 ospf6_prefix_in6_addr(&route_to_del
->prefix
.u
.prefix6
, external
,
789 route_to_del
->path
.origin
.type
= lsa
->header
->type
;
790 route_to_del
->path
.origin
.id
= lsa
->header
->id
;
791 route_to_del
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
794 route_to_del
->path
.area_id
= asbr_entry
->path
.area_id
;
795 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
796 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
797 route_to_del
->path
.metric_type
= 2;
798 route_to_del
->path
.cost
= asbr_entry
->path
.cost
;
799 route_to_del
->path
.u
.cost_e2
=
800 OSPF6_ASBR_METRIC(external
);
802 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
803 route_to_del
->path
.metric_type
= 1;
804 route_to_del
->path
.cost
= asbr_entry
->path
.cost
805 + OSPF6_ASBR_METRIC(external
);
806 route_to_del
->path
.u
.cost_e2
= 0;
810 memset(&prefix
, 0, sizeof(struct prefix
));
811 prefix
.family
= AF_INET6
;
812 prefix
.prefixlen
= external
->prefix
.prefix_length
;
813 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, external
, &external
->prefix
);
815 if (type
== OSPF6_LSTYPE_TYPE_7
)
816 route
= ospf6_route_lookup(&prefix
, oa
->route_table
);
818 route
= ospf6_route_lookup(&prefix
, oa
->ospf6
->route_table
);
822 zlog_debug("AS-External route %pFX not found", &prefix
);
823 ospf6_route_delete(route_to_del
);
829 "%s: Current route %pFX cost %u e2 %u, route to del cost %u e2 %u",
830 __func__
, &prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
831 route_to_del
->path
.cost
, route_to_del
->path
.u
.cost_e2
);
833 for (ospf6_route_lock(route
);
834 route
&& ospf6_route_is_prefix(&prefix
, route
); route
= nroute
) {
835 nroute
= ospf6_route_next(route
);
837 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
)
840 /* Route has multiple ECMP paths, remove matching
841 * path. Update current route's effective nh list
842 * after removal of one of the path.
844 if (listcount(route
->paths
) > 1) {
845 struct listnode
*anode
, *anext
;
846 struct listnode
*nnode
, *rnode
, *rnext
;
847 struct ospf6_nexthop
*nh
, *rnh
;
848 struct ospf6_path
*o_path
;
849 bool nh_updated
= false;
851 /* Iterate all paths of route to find maching with LSA
852 * remove from route path list. If route->path is same,
853 * replace from paths list.
855 for (ALL_LIST_ELEMENTS(route
->paths
, anode
, anext
,
857 if ((o_path
->origin
.type
!= lsa
->header
->type
)
858 || (o_path
->origin
.adv_router
859 != lsa
->header
->adv_router
)
860 || (o_path
->origin
.id
!= lsa
->header
->id
))
863 /* Compare LSA cost with current
867 && (o_path
->cost
!= route_to_del
->path
.cost
869 != route_to_del
->path
.u
871 if (IS_OSPF6_DEBUG_EXAMIN(
874 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
885 "%s: route %pFX path found with cost %u nh %u to remove.",
886 __func__
, &prefix
, route
->path
.cost
,
887 listcount(o_path
->nh_list
));
890 /* Remove found path's nh_list from
891 * the route's nh_list.
893 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
,
895 for (ALL_LIST_ELEMENTS(route
->nh_list
,
898 if (!ospf6_nexthop_is_same(rnh
,
901 listnode_delete(route
->nh_list
,
903 ospf6_nexthop_delete(rnh
);
906 /* Delete the path from route's path list */
907 listnode_delete(route
->paths
, o_path
);
908 ospf6_path_free(o_path
);
913 /* Iterate all paths and merge nexthop,
914 * unlesss any of the nexthop similar to
915 * ones deleted as part of path deletion.
918 for (ALL_LIST_ELEMENTS(route
->paths
, anode
,
920 ospf6_merge_nexthops(route
->nh_list
,
926 "%s: AS-External %u route %pFX update paths %u nh %u",
929 == OSPF6_PATH_TYPE_EXTERNAL1
)
932 &route
->prefix
, listcount(route
->paths
),
933 route
->nh_list
? listcount(
938 if (listcount(route
->paths
)) {
939 /* Update RIB/FIB with effective
942 if (oa
->ospf6
->route_table
->hook_add
)
943 (*oa
->ospf6
->route_table
946 /* route's primary path is similar
947 * to LSA, replace route's primary
948 * path with route's paths list head.
950 if ((route
->path
.origin
.id
==
952 (route
->path
.origin
.adv_router
953 == lsa
->header
->adv_router
)) {
954 struct ospf6_path
*h_path
;
956 h_path
= (struct ospf6_path
*)
958 listhead(route
->paths
));
959 route
->path
.origin
.type
=
961 route
->path
.origin
.id
=
963 route
->path
.origin
.adv_router
=
964 h_path
->origin
.adv_router
;
967 if (type
== OSPF6_LSTYPE_TYPE_7
)
969 route
, oa
->route_table
);
973 oa
->ospf6
->route_table
);
979 /* Compare LSA origin and cost with current route info.
980 * if any check fails skip del this route node.
983 && (!ospf6_route_is_same_origin(route
, route_to_del
)
984 || (route
->path
.type
!= route_to_del
->path
.type
)
985 || (route
->path
.cost
!= route_to_del
->path
.cost
)
986 || (route
->path
.u
.cost_e2
987 != route_to_del
->path
.u
.cost_e2
))) {
990 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
991 __func__
, &prefix
, route
->path
.cost
,
992 route_to_del
->path
.cost
);
997 if ((route
->path
.origin
.type
!= lsa
->header
->type
)
998 || (route
->path
.origin
.adv_router
999 != lsa
->header
->adv_router
)
1000 || (route
->path
.origin
.id
!= lsa
->header
->id
))
1005 "%s: AS-External %u route remove %pFX cost %u(%u) nh %u",
1007 route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
1010 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
1011 listcount(route
->nh_list
));
1013 if (type
== OSPF6_LSTYPE_TYPE_7
)
1014 ospf6_route_remove(route
, oa
->route_table
);
1016 ospf6_route_remove(route
, oa
->ospf6
->route_table
);
1019 ospf6_route_unlock(route
);
1021 ospf6_route_delete(route_to_del
);
1024 void ospf6_asbr_lsentry_add(struct ospf6_route
*asbr_entry
, struct ospf6
*ospf6
)
1026 struct ospf6_lsa
*lsa
;
1030 if (!CHECK_FLAG(asbr_entry
->flag
, OSPF6_ROUTE_BEST
)) {
1032 inet_ntop(AF_INET
, &ADV_ROUTER_IN_PREFIX(&asbr_entry
->prefix
),
1034 zlog_info("ignore non-best path: lsentry %s add", buf
);
1038 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
1039 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
1040 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
)) {
1041 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
1042 ospf6_asbr_lsa_add(lsa
);
1046 void ospf6_asbr_lsentry_remove(struct ospf6_route
*asbr_entry
,
1047 struct ospf6
*ospf6
)
1049 struct ospf6_lsa
*lsa
;
1053 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
1054 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
1055 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
))
1056 ospf6_asbr_lsa_remove(lsa
, asbr_entry
);
1060 /* redistribute function */
1061 static void ospf6_asbr_routemap_set(struct ospf6_redist
*red
,
1062 const char *mapname
)
1064 if (ROUTEMAP_NAME(red
)) {
1065 route_map_counter_decrement(ROUTEMAP(red
));
1066 free(ROUTEMAP_NAME(red
));
1069 ROUTEMAP_NAME(red
) = strdup(mapname
);
1070 ROUTEMAP(red
) = route_map_lookup_by_name(mapname
);
1071 route_map_counter_increment(ROUTEMAP(red
));
1074 static void ospf6_asbr_routemap_unset(struct ospf6_redist
*red
)
1076 if (ROUTEMAP_NAME(red
))
1077 free(ROUTEMAP_NAME(red
));
1079 route_map_counter_decrement(ROUTEMAP(red
));
1081 ROUTEMAP_NAME(red
) = NULL
;
1082 ROUTEMAP(red
) = NULL
;
1085 static void ospf6_asbr_routemap_update_timer(struct thread
*thread
)
1087 struct ospf6
*ospf6
= THREAD_ARG(thread
);
1088 struct ospf6_redist
*red
;
1091 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1092 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1097 if (!CHECK_FLAG(red
->flag
, OSPF6_IS_RMAP_CHANGED
))
1100 if (ROUTEMAP_NAME(red
))
1102 route_map_lookup_by_name(ROUTEMAP_NAME(red
));
1104 if (ROUTEMAP(red
)) {
1105 if (IS_OSPF6_DEBUG_ASBR
)
1107 "%s: route-map %s update, reset redist %s",
1108 __func__
, ROUTEMAP_NAME(red
),
1111 ospf6_zebra_no_redistribute(type
, ospf6
->vrf_id
);
1112 ospf6_zebra_redistribute(type
, ospf6
->vrf_id
);
1115 UNSET_FLAG(red
->flag
, OSPF6_IS_RMAP_CHANGED
);
1119 void ospf6_asbr_distribute_list_update(struct ospf6
*ospf6
,
1120 struct ospf6_redist
*red
)
1122 SET_FLAG(red
->flag
, OSPF6_IS_RMAP_CHANGED
);
1124 if (thread_is_scheduled(ospf6
->t_distribute_update
))
1127 if (IS_OSPF6_DEBUG_ASBR
)
1128 zlog_debug("%s: trigger redistribute reset thread", __func__
);
1130 thread_add_timer_msec(master
, ospf6_asbr_routemap_update_timer
, ospf6
,
1131 OSPF_MIN_LS_INTERVAL
,
1132 &ospf6
->t_distribute_update
);
1135 void ospf6_asbr_routemap_update(const char *mapname
)
1138 struct listnode
*node
, *nnode
;
1139 struct ospf6
*ospf6
= NULL
;
1140 struct ospf6_redist
*red
;
1145 for (ALL_LIST_ELEMENTS(om6
->ospf6
, node
, nnode
, ospf6
)) {
1146 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1147 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1148 if (!red
|| (ROUTEMAP_NAME(red
) == NULL
))
1151 route_map_lookup_by_name(ROUTEMAP_NAME(red
));
1154 || strcmp(ROUTEMAP_NAME(red
), mapname
))
1156 if (ROUTEMAP(red
)) {
1157 if (IS_OSPF6_DEBUG_ASBR
)
1159 "%s: route-map %s update, reset redist %s",
1165 route_map_counter_increment(ROUTEMAP(red
));
1166 ospf6_asbr_distribute_list_update(ospf6
, red
);
1169 * if the mapname matches a
1170 * route-map on ospf6 but the
1171 * map doesn't exist, it is
1172 * being deleted. flush and then
1175 if (IS_OSPF6_DEBUG_ASBR
)
1177 "%s: route-map %s deleted, reset redist %s",
1182 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1183 ospf6_asbr_routemap_set(red
, mapname
);
1184 ospf6_asbr_redistribute_set(ospf6
, type
);
1190 static void ospf6_asbr_routemap_event(const char *name
)
1193 struct listnode
*node
, *nnode
;
1194 struct ospf6
*ospf6
;
1195 struct ospf6_redist
*red
;
1199 for (ALL_LIST_ELEMENTS(om6
->ospf6
, node
, nnode
, ospf6
)) {
1200 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1201 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1202 if (red
&& ROUTEMAP_NAME(red
)
1203 && (strcmp(ROUTEMAP_NAME(red
), name
) == 0))
1204 ospf6_asbr_distribute_list_update(ospf6
, red
);
1209 int ospf6_asbr_is_asbr(struct ospf6
*o
)
1211 return (o
->external_table
->count
|| IS_OSPF6_ASBR(o
));
1214 struct ospf6_redist
*ospf6_redist_lookup(struct ospf6
*ospf6
, int type
,
1215 unsigned short instance
)
1217 struct list
*red_list
;
1218 struct listnode
*node
;
1219 struct ospf6_redist
*red
;
1221 red_list
= ospf6
->redist
[type
];
1225 for (ALL_LIST_ELEMENTS_RO(red_list
, node
, red
))
1226 if (red
->instance
== instance
)
1232 static struct ospf6_redist
*ospf6_redist_add(struct ospf6
*ospf6
, int type
,
1235 struct ospf6_redist
*red
;
1237 red
= ospf6_redist_lookup(ospf6
, type
, instance
);
1241 if (!ospf6
->redist
[type
])
1242 ospf6
->redist
[type
] = list_new();
1244 red
= XCALLOC(MTYPE_OSPF6_REDISTRIBUTE
, sizeof(struct ospf6_redist
));
1245 red
->instance
= instance
;
1246 red
->dmetric
.type
= -1;
1247 red
->dmetric
.value
= -1;
1248 ROUTEMAP_NAME(red
) = NULL
;
1249 ROUTEMAP(red
) = NULL
;
1251 listnode_add(ospf6
->redist
[type
], red
);
1252 ospf6
->redistribute
++;
1257 static void ospf6_redist_del(struct ospf6
*ospf6
, struct ospf6_redist
*red
,
1261 listnode_delete(ospf6
->redist
[type
], red
);
1262 if (!ospf6
->redist
[type
]->count
) {
1263 list_delete(&ospf6
->redist
[type
]);
1265 XFREE(MTYPE_OSPF6_REDISTRIBUTE
, red
);
1266 ospf6
->redistribute
--;
1270 /*Set the status of the ospf instance to ASBR based on the status parameter,
1271 * rechedule SPF calculation, originate router LSA*/
1272 void ospf6_asbr_status_update(struct ospf6
*ospf6
, int status
)
1274 struct listnode
*lnode
, *lnnode
;
1275 struct ospf6_area
*oa
;
1277 zlog_info("ASBR[%s:Status:%d]: Update", ospf6
->name
, status
);
1280 if (IS_OSPF6_ASBR(ospf6
)) {
1281 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
1282 ospf6
->name
, status
);
1285 SET_FLAG(ospf6
->flag
, OSPF6_FLAG_ASBR
);
1287 if (!IS_OSPF6_ASBR(ospf6
)) {
1288 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
1289 ospf6
->name
, status
);
1292 UNSET_FLAG(ospf6
->flag
, OSPF6_FLAG_ASBR
);
1295 /* Transition from/to status ASBR, schedule timer. */
1296 ospf6_spf_schedule(ospf6
, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE
);
1298 /* Reoriginate router LSA for all areas */
1299 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1300 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1303 static void ospf6_asbr_redistribute_set(struct ospf6
*ospf6
, int type
)
1305 ospf6_zebra_redistribute(type
, ospf6
->vrf_id
);
1307 ++ospf6
->redist_count
;
1308 ospf6_asbr_status_update(ospf6
, ospf6
->redist_count
);
1311 static void ospf6_asbr_redistribute_unset(struct ospf6
*ospf6
,
1312 struct ospf6_redist
*red
, int type
)
1314 struct ospf6_route
*route
;
1315 struct ospf6_external_info
*info
;
1317 ospf6_zebra_no_redistribute(type
, ospf6
->vrf_id
);
1319 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1320 route
= ospf6_route_next(route
)) {
1321 info
= route
->route_option
;
1322 if (info
->type
!= type
)
1325 ospf6_asbr_redistribute_remove(info
->type
, 0, &route
->prefix
,
1329 ospf6_asbr_routemap_unset(red
);
1330 --ospf6
->redist_count
;
1331 ospf6_asbr_status_update(ospf6
, ospf6
->redist_count
);
1334 /* When an area is unstubified, flood all the external LSAs in the area */
1335 void ospf6_asbr_send_externals_to_area(struct ospf6_area
*oa
)
1337 struct ospf6_lsa
*lsa
, *lsanext
;
1339 for (ALL_LSDB(oa
->ospf6
->lsdb
, lsa
, lsanext
)) {
1340 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
) {
1341 if (IS_OSPF6_DEBUG_ASBR
)
1342 zlog_debug("%s: Flooding AS-External LSA %s",
1343 __func__
, lsa
->name
);
1345 ospf6_flood_area(NULL
, lsa
, oa
);
1350 /* When an area is stubified, remove all the external LSAs in the area */
1351 void ospf6_asbr_remove_externals_from_area(struct ospf6_area
*oa
)
1353 struct ospf6_lsa
*lsa
, *lsanext
;
1354 struct listnode
*node
, *nnode
;
1355 struct ospf6_area
*area
;
1356 struct ospf6
*ospf6
= oa
->ospf6
;
1357 const struct route_node
*iterend
;
1359 /* skip if router is in other non-stub/non-NSSA areas */
1360 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, area
))
1361 if (!IS_AREA_STUB(area
) && !IS_AREA_NSSA(area
))
1364 /* if router is only in a stub area then purge AS-External LSAs */
1365 iterend
= ospf6_lsdb_head(ospf6
->lsdb
, 0, 0, 0, &lsa
);
1366 while (lsa
!= NULL
) {
1367 assert(lsa
->lock
> 1);
1368 lsanext
= ospf6_lsdb_next(iterend
, lsa
);
1369 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
)
1370 ospf6_lsdb_remove(lsa
, ospf6
->lsdb
);
1375 static struct ospf6_external_aggr_rt
*
1376 ospf6_external_aggr_match(struct ospf6
*ospf6
, struct prefix
*p
)
1378 struct route_node
*node
;
1380 node
= route_node_match(ospf6
->rt_aggr_tbl
, p
);
1384 if (IS_OSPF6_DEBUG_AGGR
) {
1385 struct ospf6_external_aggr_rt
*ag
= node
->info
;
1386 zlog_debug("%s: Matching aggregator found.prefix: %pFX Aggregator %pFX",
1392 route_unlock_node(node
);
1397 void ospf6_asbr_redistribute_add(int type
, ifindex_t ifindex
,
1398 struct prefix
*prefix
,
1399 unsigned int nexthop_num
,
1400 struct in6_addr
*nexthop
, route_tag_t tag
,
1401 struct ospf6
*ospf6
)
1403 route_map_result_t ret
;
1404 struct ospf6_route troute
;
1405 struct ospf6_external_info tinfo
;
1406 struct ospf6_route
*route
, *match
;
1407 struct ospf6_external_info
*info
;
1408 struct ospf6_redist
*red
;
1410 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1415 if ((type
!= DEFAULT_ROUTE
)
1416 && !ospf6_zebra_is_redistribute(type
, ospf6
->vrf_id
))
1419 memset(&troute
, 0, sizeof(troute
));
1420 memset(&tinfo
, 0, sizeof(tinfo
));
1422 if (IS_OSPF6_DEBUG_ASBR
)
1423 zlog_debug("Redistribute %pFX (%s)", prefix
,
1424 type
== DEFAULT_ROUTE
1425 ? "default-information-originate"
1426 : ZROUTE_NAME(type
));
1428 /* if route-map was specified but not found, do not advertise */
1429 if (ROUTEMAP_NAME(red
)) {
1430 if (ROUTEMAP(red
) == NULL
)
1431 ospf6_asbr_routemap_update(NULL
);
1432 if (ROUTEMAP(red
) == NULL
) {
1434 "route-map \"%s\" not found, suppress redistributing",
1435 ROUTEMAP_NAME(red
));
1440 /* apply route-map */
1441 if (ROUTEMAP(red
)) {
1442 troute
.route_option
= &tinfo
;
1443 troute
.ospf6
= ospf6
;
1444 tinfo
.ifindex
= ifindex
;
1447 ret
= route_map_apply(ROUTEMAP(red
), prefix
, &troute
);
1448 if (ret
== RMAP_DENYMATCH
) {
1449 if (IS_OSPF6_DEBUG_ASBR
)
1450 zlog_debug("Denied by route-map \"%s\"",
1451 ROUTEMAP_NAME(red
));
1452 ospf6_asbr_redistribute_remove(type
, ifindex
, prefix
,
1458 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1460 info
= match
->route_option
;
1461 /* copy result of route-map */
1462 if (ROUTEMAP(red
)) {
1463 if (troute
.path
.metric_type
)
1464 match
->path
.metric_type
=
1465 troute
.path
.metric_type
;
1467 match
->path
.metric_type
=
1468 metric_type(ospf6
, type
, 0);
1469 if (troute
.path
.cost
)
1470 match
->path
.cost
= troute
.path
.cost
;
1472 match
->path
.cost
= metric_value(ospf6
, type
, 0);
1474 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1475 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1476 sizeof(struct in6_addr
));
1477 info
->tag
= tinfo
.tag
;
1479 /* If there is no route-map, simply update the tag and
1482 match
->path
.metric_type
= metric_type(ospf6
, type
, 0);
1483 match
->path
.cost
= metric_value(ospf6
, type
, 0);
1489 if (nexthop_num
&& nexthop
)
1490 ospf6_route_add_nexthop(match
, ifindex
, nexthop
);
1492 ospf6_route_add_nexthop(match
, ifindex
, NULL
);
1494 match
->path
.origin
.id
= htonl(info
->id
);
1495 ospf6_handle_external_lsa_origination(ospf6
, match
, prefix
);
1497 ospf6_asbr_status_update(ospf6
, ospf6
->redistribute
);
1502 /* create new entry */
1503 route
= ospf6_route_create(ospf6
);
1504 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
1505 prefix_copy(&route
->prefix
, prefix
);
1507 info
= (struct ospf6_external_info
*)XCALLOC(
1508 MTYPE_OSPF6_EXTERNAL_INFO
, sizeof(struct ospf6_external_info
));
1509 route
->route_option
= info
;
1511 /* copy result of route-map */
1512 if (ROUTEMAP(red
)) {
1513 if (troute
.path
.metric_type
)
1514 route
->path
.metric_type
= troute
.path
.metric_type
;
1516 route
->path
.metric_type
= metric_type(ospf6
, type
, 0);
1517 if (troute
.path
.cost
)
1518 route
->path
.cost
= troute
.path
.cost
;
1520 route
->path
.cost
= metric_value(ospf6
, type
, 0);
1521 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1522 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1523 sizeof(struct in6_addr
));
1524 info
->tag
= tinfo
.tag
;
1526 /* If there is no route-map, simply update the tag and metric
1529 route
->path
.metric_type
= metric_type(ospf6
, type
, 0);
1530 route
->path
.cost
= metric_value(ospf6
, type
, 0);
1535 if (nexthop_num
&& nexthop
)
1536 ospf6_route_add_nexthop(route
, ifindex
, nexthop
);
1538 ospf6_route_add_nexthop(route
, ifindex
, NULL
);
1540 route
= ospf6_route_add(route
, ospf6
->external_table
);
1541 ospf6_handle_external_lsa_origination(ospf6
, route
, prefix
);
1543 ospf6_asbr_status_update(ospf6
, ospf6
->redistribute
);
1547 static void ospf6_asbr_external_lsa_remove_by_id(struct ospf6
*ospf6
,
1550 struct ospf6_lsa
*lsa
;
1552 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
1553 htonl(id
), ospf6
->router_id
, ospf6
->lsdb
);
1557 ospf6_external_lsa_purge(ospf6
, lsa
);
1562 ospf6_link_route_to_aggr(struct ospf6_external_aggr_rt
*aggr
,
1563 struct ospf6_route
*rt
)
1565 (void)hash_get(aggr
->match_extnl_hash
, rt
, hash_alloc_intern
);
1566 rt
->aggr_route
= aggr
;
1570 ospf6_asbr_summary_remove_lsa_and_route(struct ospf6
*ospf6
,
1571 struct ospf6_external_aggr_rt
*aggr
)
1574 /* Send a Max age LSA if it is already originated.*/
1575 if (!CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
))
1578 if (IS_OSPF6_DEBUG_AGGR
)
1579 zlog_debug("%s: Flushing Aggregate route (%pFX)",
1583 ospf6_asbr_external_lsa_remove_by_id(ospf6
, aggr
->id
);
1586 if (IS_OSPF6_DEBUG_AGGR
)
1588 "%s: Remove the blackhole route",
1590 ospf6_zebra_route_update_remove(aggr
->route
, ospf6
);
1591 ospf6_route_delete(aggr
->route
);
1596 /* Unset the Origination flag */
1597 UNSET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
1601 ospf6_unlink_route_from_aggr(struct ospf6
*ospf6
,
1602 struct ospf6_external_aggr_rt
*aggr
,
1603 struct ospf6_route
*rt
)
1605 if (IS_OSPF6_DEBUG_AGGR
)
1606 zlog_debug("%s: Unlinking external route(%pFX) from aggregator(%pFX), external route count:%ld",
1610 OSPF6_EXTERNAL_RT_COUNT(aggr
));
1612 hash_release(aggr
->match_extnl_hash
, rt
);
1613 rt
->aggr_route
= NULL
;
1615 /* Flush the aggregate route if matching
1616 * external route count becomes zero.
1618 if (!OSPF6_EXTERNAL_RT_COUNT(aggr
))
1619 ospf6_asbr_summary_remove_lsa_and_route(ospf6
, aggr
);
1622 void ospf6_asbr_redistribute_remove(int type
, ifindex_t ifindex
,
1623 struct prefix
*prefix
, struct ospf6
*ospf6
)
1625 struct ospf6_route
*match
;
1626 struct ospf6_external_info
*info
= NULL
;
1628 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1629 if (match
== NULL
) {
1630 if (IS_OSPF6_DEBUG_ASBR
)
1631 zlog_debug("No such route %pFX to withdraw", prefix
);
1635 info
= match
->route_option
;
1638 if (info
->type
!= type
) {
1639 if (IS_OSPF6_DEBUG_ASBR
)
1640 zlog_debug("Original protocol mismatch: %pFX", prefix
);
1644 /* This means aggregation on this route was not done, hence remove LSA
1645 * if any originated for this prefix
1647 if (!match
->aggr_route
)
1648 ospf6_asbr_external_lsa_remove_by_id(ospf6
, info
->id
);
1650 ospf6_unlink_route_from_aggr(ospf6
, match
->aggr_route
, match
);
1652 if (IS_OSPF6_DEBUG_ASBR
)
1653 zlog_debug("Removing route from external table %pFX",
1656 ospf6_route_remove(match
, ospf6
->external_table
);
1657 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
, info
);
1659 ospf6_asbr_status_update(ospf6
, ospf6
->redistribute
);
1662 DEFPY (ospf6_redistribute
,
1663 ospf6_redistribute_cmd
,
1664 "redistribute " FRR_REDIST_STR_OSPF6D
"[{metric (0-16777214)|metric-type (1-2)$metric_type|route-map RMAP_NAME$rmap_str}]",
1666 FRR_REDIST_HELP_STR_OSPF6D
1667 "Metric for redistributed routes\n"
1668 "OSPF default metric\n"
1669 "OSPF exterior metric type for redistributed routes\n"
1670 "Set OSPF External Type 1/2 metrics\n"
1671 "Route map reference\n"
1675 struct ospf6_redist
*red
;
1676 int idx_protocol
= 1;
1677 char *proto
= argv
[idx_protocol
]->text
;
1679 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1681 type
= proto_redistnum(AFI_IP6
, proto
);
1683 return CMD_WARNING_CONFIG_FAILED
;
1687 if (!metric_type_str
)
1690 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1692 red
= ospf6_redist_add(ospf6
, type
, 0);
1694 /* Check if nothing has changed. */
1695 if (red
->dmetric
.value
== metric
1696 && red
->dmetric
.type
== metric_type
1697 && ((!ROUTEMAP_NAME(red
) && !rmap_str
)
1698 || (ROUTEMAP_NAME(red
) && rmap_str
1699 && strmatch(ROUTEMAP_NAME(red
), rmap_str
))))
1702 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1705 red
->dmetric
.value
= metric
;
1706 red
->dmetric
.type
= metric_type
;
1708 ospf6_asbr_routemap_set(red
, rmap_str
);
1710 ospf6_asbr_routemap_unset(red
);
1711 ospf6_asbr_redistribute_set(ospf6
, type
);
1716 DEFUN (no_ospf6_redistribute
,
1717 no_ospf6_redistribute_cmd
,
1718 "no redistribute " FRR_REDIST_STR_OSPF6D
"[{metric (0-16777214)|metric-type (1-2)|route-map RMAP_NAME}]",
1721 FRR_REDIST_HELP_STR_OSPF6D
1722 "Metric for redistributed routes\n"
1723 "OSPF default metric\n"
1724 "OSPF exterior metric type for redistributed routes\n"
1725 "Set OSPF External Type 1/2 metrics\n"
1726 "Route map reference\n"
1730 struct ospf6_redist
*red
;
1731 int idx_protocol
= 2;
1732 char *proto
= argv
[idx_protocol
]->text
;
1734 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1736 type
= proto_redistnum(AFI_IP6
, proto
);
1738 return CMD_WARNING_CONFIG_FAILED
;
1740 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1744 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
1745 ospf6_redist_del(ospf6
, red
, type
);
1750 int ospf6_redistribute_config_write(struct vty
*vty
, struct ospf6
*ospf6
)
1753 struct ospf6_redist
*red
;
1755 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1756 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1759 if (type
== ZEBRA_ROUTE_OSPF6
)
1762 vty_out(vty
, " redistribute %s", ZROUTE_NAME(type
));
1763 if (red
->dmetric
.value
>= 0)
1764 vty_out(vty
, " metric %d", red
->dmetric
.value
);
1765 if (red
->dmetric
.type
== 1)
1766 vty_out(vty
, " metric-type 1");
1767 if (ROUTEMAP_NAME(red
))
1768 vty_out(vty
, " route-map %s", ROUTEMAP_NAME(red
));
1775 static void ospf6_redistribute_show_config(struct vty
*vty
, struct ospf6
*ospf6
,
1776 json_object
*json_array
,
1777 json_object
*json
, bool use_json
)
1780 int nroute
[ZEBRA_ROUTE_MAX
];
1782 struct ospf6_route
*route
;
1783 struct ospf6_external_info
*info
;
1784 json_object
*json_route
;
1785 struct ospf6_redist
*red
;
1788 memset(nroute
, 0, sizeof(nroute
));
1789 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1790 route
= ospf6_route_next(route
)) {
1791 info
= route
->route_option
;
1792 nroute
[info
->type
]++;
1797 vty_out(vty
, "Redistributing External Routes from:\n");
1799 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1801 red
= ospf6_redist_lookup(ospf6
, type
, 0);
1805 if (type
== ZEBRA_ROUTE_OSPF6
)
1809 json_route
= json_object_new_object();
1810 json_object_string_add(json_route
, "routeType",
1812 json_object_int_add(json_route
, "numberOfRoutes",
1814 json_object_boolean_add(json_route
,
1815 "routeMapNamePresent",
1816 ROUTEMAP_NAME(red
));
1819 if (ROUTEMAP_NAME(red
)) {
1821 json_object_string_add(json_route
,
1823 ROUTEMAP_NAME(red
));
1824 json_object_boolean_add(json_route
,
1829 " %d: %s with route-map \"%s\"%s\n",
1830 nroute
[type
], ZROUTE_NAME(type
),
1833 : " (not found !)"));
1836 vty_out(vty
, " %d: %s\n", nroute
[type
],
1841 json_object_array_add(json_array
, json_route
);
1844 json_object_object_add(json
, "redistributedRoutes", json_array
);
1845 json_object_int_add(json
, "totalRoutes", total
);
1847 vty_out(vty
, "Total %d routes\n", total
);
1850 static void ospf6_redistribute_default_set(struct ospf6
*ospf6
, int originate
)
1852 struct prefix_ipv6 p
= {};
1853 struct in6_addr nexthop
= {};
1854 int cur_originate
= ospf6
->default_originate
;
1856 p
.family
= AF_INET6
;
1859 ospf6
->default_originate
= originate
;
1861 switch (cur_originate
) {
1862 case DEFAULT_ORIGINATE_NONE
:
1864 case DEFAULT_ORIGINATE_ZEBRA
:
1865 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE
,
1866 zclient
, AFI_IP6
, ospf6
->vrf_id
);
1867 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE
, 0,
1868 (struct prefix
*)&p
, ospf6
);
1871 case DEFAULT_ORIGINATE_ALWAYS
:
1872 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE
, 0,
1873 (struct prefix
*)&p
, ospf6
);
1877 switch (originate
) {
1878 case DEFAULT_ORIGINATE_NONE
:
1880 case DEFAULT_ORIGINATE_ZEBRA
:
1881 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD
,
1882 zclient
, AFI_IP6
, ospf6
->vrf_id
);
1885 case DEFAULT_ORIGINATE_ALWAYS
:
1886 ospf6_asbr_redistribute_add(DEFAULT_ROUTE
, 0,
1887 (struct prefix
*)&p
, 0, &nexthop
, 0,
1893 /* Default Route originate. */
1894 DEFPY (ospf6_default_route_originate
,
1895 ospf6_default_route_originate_cmd
,
1896 "default-information originate [{always$always|metric (0-16777214)$mval|metric-type (1-2)$mtype|route-map RMAP_NAME$rtmap}]",
1897 "Control distribution of default route\n"
1898 "Distribute a default route\n"
1899 "Always advertise default route\n"
1900 "OSPFv3 default metric\n"
1902 "OSPFv3 metric type for default routes\n"
1903 "Set OSPFv3 External Type 1/2 metrics\n"
1904 "Route map reference\n"
1905 "Pointer to route-map entries\n")
1907 int default_originate
= DEFAULT_ORIGINATE_ZEBRA
;
1908 struct ospf6_redist
*red
;
1909 bool sameRtmap
= false;
1911 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1913 int cur_originate
= ospf6
->default_originate
;
1915 red
= ospf6_redist_add(ospf6
, DEFAULT_ROUTE
, 0);
1918 default_originate
= DEFAULT_ORIGINATE_ALWAYS
;
1920 if (mval_str
== NULL
)
1923 if (mtype_str
== NULL
)
1926 /* To check if user is providing same route map */
1927 if ((!rtmap
&& !ROUTEMAP_NAME(red
)) ||
1928 (rtmap
&& ROUTEMAP_NAME(red
) &&
1929 (strcmp(rtmap
, ROUTEMAP_NAME(red
)) == 0)))
1932 /* Don't allow if the same lsa is already originated. */
1933 if ((sameRtmap
) && (red
->dmetric
.type
== mtype
)
1934 && (red
->dmetric
.value
== mval
)
1935 && (cur_originate
== default_originate
))
1938 /* Updating Metric details */
1939 red
->dmetric
.type
= mtype
;
1940 red
->dmetric
.value
= mval
;
1942 /* updating route map details */
1944 ospf6_asbr_routemap_set(red
, rtmap
);
1946 ospf6_asbr_routemap_unset(red
);
1948 ospf6_redistribute_default_set(ospf6
, default_originate
);
1952 DEFPY (no_ospf6_default_information_originate
,
1953 no_ospf6_default_information_originate_cmd
,
1954 "no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map RMAP_NAME}]",
1956 "Control distribution of default information\n"
1957 "Distribute a default route\n"
1958 "Always advertise default route\n"
1959 "OSPFv3 default metric\n"
1961 "OSPFv3 metric type for default routes\n"
1962 "Set OSPFv3 External Type 1/2 metrics\n"
1963 "Route map reference\n"
1964 "Pointer to route-map entries\n")
1966 struct ospf6_redist
*red
;
1968 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1970 red
= ospf6_redist_lookup(ospf6
, DEFAULT_ROUTE
, 0);
1974 ospf6_asbr_routemap_unset(red
);
1975 ospf6_redist_del(ospf6
, red
, DEFAULT_ROUTE
);
1977 ospf6_redistribute_default_set(ospf6
, DEFAULT_ORIGINATE_NONE
);
1981 /* Routemap Functions */
1982 static enum route_map_cmd_result_t
1983 ospf6_routemap_rule_match_address_prefixlist(void *rule
,
1984 const struct prefix
*prefix
,
1988 struct prefix_list
*plist
;
1990 plist
= prefix_list_lookup(AFI_IP6
, (char *)rule
);
1992 return RMAP_NOMATCH
;
1994 return (prefix_list_apply(plist
, prefix
) == PREFIX_DENY
? RMAP_NOMATCH
1999 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg
)
2001 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2004 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule
)
2006 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2009 static const struct route_map_rule_cmd
2010 ospf6_routemap_rule_match_address_prefixlist_cmd
= {
2011 "ipv6 address prefix-list",
2012 ospf6_routemap_rule_match_address_prefixlist
,
2013 ospf6_routemap_rule_match_address_prefixlist_compile
,
2014 ospf6_routemap_rule_match_address_prefixlist_free
,
2017 /* `match interface IFNAME' */
2018 /* Match function should return 1 if match is success else return
2020 static enum route_map_cmd_result_t
2021 ospf6_routemap_rule_match_interface(void *rule
, const struct prefix
*prefix
,
2024 struct interface
*ifp
;
2025 struct ospf6_route
*route
;
2026 struct ospf6_external_info
*ei
;
2029 ei
= route
->route_option
;
2030 ifp
= if_lookup_by_name((char *)rule
, route
->ospf6
->vrf_id
);
2032 if (ifp
!= NULL
&& ei
->ifindex
== ifp
->ifindex
)
2035 return RMAP_NOMATCH
;
2038 /* Route map `interface' match statement. `arg' should be
2040 static void *ospf6_routemap_rule_match_interface_compile(const char *arg
)
2042 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2045 /* Free route map's compiled `interface' value. */
2046 static void ospf6_routemap_rule_match_interface_free(void *rule
)
2048 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2051 /* Route map commands for interface matching. */
2052 static const struct route_map_rule_cmd
2053 ospf6_routemap_rule_match_interface_cmd
= {
2055 ospf6_routemap_rule_match_interface
,
2056 ospf6_routemap_rule_match_interface_compile
,
2057 ospf6_routemap_rule_match_interface_free
2060 /* Match function for matching route tags */
2061 static enum route_map_cmd_result_t
2062 ospf6_routemap_rule_match_tag(void *rule
, const struct prefix
*p
, void *object
)
2064 route_tag_t
*tag
= rule
;
2065 struct ospf6_route
*route
= object
;
2066 struct ospf6_external_info
*info
= route
->route_option
;
2068 if (info
->tag
== *tag
)
2071 return RMAP_NOMATCH
;
2074 static const struct route_map_rule_cmd
2075 ospf6_routemap_rule_match_tag_cmd
= {
2077 ospf6_routemap_rule_match_tag
,
2078 route_map_rule_tag_compile
,
2079 route_map_rule_tag_free
,
2082 static enum route_map_cmd_result_t
2083 ospf6_routemap_rule_set_metric_type(void *rule
, const struct prefix
*prefix
,
2086 char *metric_type
= rule
;
2087 struct ospf6_route
*route
= object
;
2089 if (strcmp(metric_type
, "type-2") == 0)
2090 route
->path
.metric_type
= 2;
2092 route
->path
.metric_type
= 1;
2097 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg
)
2099 if (strcmp(arg
, "type-2") && strcmp(arg
, "type-1"))
2101 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2104 static void ospf6_routemap_rule_set_metric_type_free(void *rule
)
2106 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2109 static const struct route_map_rule_cmd
2110 ospf6_routemap_rule_set_metric_type_cmd
= {
2112 ospf6_routemap_rule_set_metric_type
,
2113 ospf6_routemap_rule_set_metric_type_compile
,
2114 ospf6_routemap_rule_set_metric_type_free
,
2117 static enum route_map_cmd_result_t
2118 ospf6_routemap_rule_set_metric(void *rule
, const struct prefix
*prefix
,
2121 char *metric
= rule
;
2122 struct ospf6_route
*route
= object
;
2124 route
->path
.cost
= atoi(metric
);
2128 static void *ospf6_routemap_rule_set_metric_compile(const char *arg
)
2132 metric
= strtoul(arg
, &endp
, 0);
2133 if (metric
> OSPF_LS_INFINITY
|| *endp
!= '\0')
2135 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2138 static void ospf6_routemap_rule_set_metric_free(void *rule
)
2140 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2143 static const struct route_map_rule_cmd
2144 ospf6_routemap_rule_set_metric_cmd
= {
2146 ospf6_routemap_rule_set_metric
,
2147 ospf6_routemap_rule_set_metric_compile
,
2148 ospf6_routemap_rule_set_metric_free
,
2151 static enum route_map_cmd_result_t
2152 ospf6_routemap_rule_set_forwarding(void *rule
, const struct prefix
*prefix
,
2155 char *forwarding
= rule
;
2156 struct ospf6_route
*route
= object
;
2157 struct ospf6_external_info
*info
= route
->route_option
;
2159 if (inet_pton(AF_INET6
, forwarding
, &info
->forwarding
) != 1) {
2160 memset(&info
->forwarding
, 0, sizeof(struct in6_addr
));
2167 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg
)
2170 if (inet_pton(AF_INET6
, arg
, &a
) != 1)
2172 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
2175 static void ospf6_routemap_rule_set_forwarding_free(void *rule
)
2177 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2180 static const struct route_map_rule_cmd
2181 ospf6_routemap_rule_set_forwarding_cmd
= {
2182 "forwarding-address",
2183 ospf6_routemap_rule_set_forwarding
,
2184 ospf6_routemap_rule_set_forwarding_compile
,
2185 ospf6_routemap_rule_set_forwarding_free
,
2188 static enum route_map_cmd_result_t
2189 ospf6_routemap_rule_set_tag(void *rule
, const struct prefix
*p
, void *object
)
2191 route_tag_t
*tag
= rule
;
2192 struct ospf6_route
*route
= object
;
2193 struct ospf6_external_info
*info
= route
->route_option
;
2199 static const struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd
= {
2201 ospf6_routemap_rule_set_tag
,
2202 route_map_rule_tag_compile
,
2203 route_map_rule_tag_free
,
2206 /* add "set metric-type" */
2207 DEFUN_YANG (ospf6_routemap_set_metric_type
, ospf6_routemap_set_metric_type_cmd
,
2208 "set metric-type <type-1|type-2>",
2211 "OSPF6 external type 1 metric\n"
2212 "OSPF6 external type 2 metric\n")
2214 char *ext
= argv
[2]->text
;
2217 "./set-action[action='frr-ospf-route-map:metric-type']";
2218 char xpath_value
[XPATH_MAXLEN
];
2220 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
2221 snprintf(xpath_value
, sizeof(xpath_value
),
2222 "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath
);
2223 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, ext
);
2224 return nb_cli_apply_changes(vty
, NULL
);
2227 /* delete "set metric-type" */
2228 DEFUN_YANG (ospf6_routemap_no_set_metric_type
, ospf6_routemap_no_set_metric_type_cmd
,
2229 "no set metric-type [<type-1|type-2>]",
2233 "OSPF6 external type 1 metric\n"
2234 "OSPF6 external type 2 metric\n")
2237 "./set-action[action='frr-ospf-route-map:metric-type']";
2239 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
2240 return nb_cli_apply_changes(vty
, NULL
);
2243 /* add "set forwarding-address" */
2244 DEFUN_YANG (ospf6_routemap_set_forwarding
, ospf6_routemap_set_forwarding_cmd
,
2245 "set forwarding-address X:X::X:X",
2247 "Forwarding Address\n"
2252 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2253 char xpath_value
[XPATH_MAXLEN
];
2255 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
2256 snprintf(xpath_value
, sizeof(xpath_value
),
2257 "%s/rmap-set-action/frr-ospf6-route-map:ipv6-address", xpath
);
2258 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
,
2259 argv
[idx_ipv6
]->arg
);
2260 return nb_cli_apply_changes(vty
, NULL
);
2263 /* delete "set forwarding-address" */
2264 DEFUN_YANG (ospf6_routemap_no_set_forwarding
, ospf6_routemap_no_set_forwarding_cmd
,
2265 "no set forwarding-address [X:X::X:X]",
2268 "Forwarding Address\n"
2272 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2274 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
2275 return nb_cli_apply_changes(vty
, NULL
);
2278 static void ospf6_routemap_init(void)
2282 route_map_add_hook(ospf6_asbr_routemap_update
);
2283 route_map_delete_hook(ospf6_asbr_routemap_update
);
2284 route_map_event_hook(ospf6_asbr_routemap_event
);
2286 route_map_set_metric_hook(generic_set_add
);
2287 route_map_no_set_metric_hook(generic_set_delete
);
2289 route_map_set_tag_hook(generic_set_add
);
2290 route_map_no_set_tag_hook(generic_set_delete
);
2292 route_map_match_tag_hook(generic_match_add
);
2293 route_map_no_match_tag_hook(generic_match_delete
);
2295 route_map_match_ipv6_address_prefix_list_hook(generic_match_add
);
2296 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete
);
2298 route_map_match_interface_hook(generic_match_add
);
2299 route_map_no_match_interface_hook(generic_match_delete
);
2301 route_map_install_match(
2302 &ospf6_routemap_rule_match_address_prefixlist_cmd
);
2303 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd
);
2304 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd
);
2306 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd
);
2307 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd
);
2308 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd
);
2309 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd
);
2311 /* ASE Metric Type (e.g. Type-1/Type-2) */
2312 install_element(RMAP_NODE
, &ospf6_routemap_set_metric_type_cmd
);
2313 install_element(RMAP_NODE
, &ospf6_routemap_no_set_metric_type_cmd
);
2316 install_element(RMAP_NODE
, &ospf6_routemap_set_forwarding_cmd
);
2317 install_element(RMAP_NODE
, &ospf6_routemap_no_set_forwarding_cmd
);
2321 /* Display functions */
2322 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
2323 char *buf
, int buflen
,
2326 struct ospf6_as_external_lsa
*external
;
2327 struct in6_addr in6
;
2328 int prefix_length
= 0;
2332 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
2336 ospf6_prefix_in6_addr(&in6
, external
,
2338 prefix_length
= external
->prefix
.prefix_length
;
2340 in6
= *((struct in6_addr
2341 *)((caddr_t
)external
2343 ospf6_as_external_lsa
)
2344 + OSPF6_PREFIX_SPACE(
2349 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
2350 if (prefix_length
) {
2351 snprintf(tbuf
, sizeof(tbuf
), "/%d",
2353 strlcat(buf
, tbuf
, buflen
);
2360 static int ospf6_as_external_lsa_show(struct vty
*vty
, struct ospf6_lsa
*lsa
,
2361 json_object
*json_obj
, bool use_json
)
2363 struct ospf6_as_external_lsa
*external
;
2366 assert(lsa
->header
);
2367 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
2371 snprintf(buf
, sizeof(buf
), "%c%c%c",
2372 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
) ? 'E'
2374 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
) ? 'F'
2376 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
) ? 'T'
2380 json_object_string_add(json_obj
, "bits", buf
);
2381 json_object_int_add(json_obj
, "metric",
2382 (unsigned long)OSPF6_ASBR_METRIC(external
));
2383 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
,
2385 json_object_string_add(json_obj
, "prefixOptions", buf
);
2386 json_object_int_add(
2387 json_obj
, "referenceLsType",
2388 ntohs(external
->prefix
.prefix_refer_lstype
));
2389 json_object_string_add(json_obj
, "prefix",
2390 ospf6_as_external_lsa_get_prefix_str(
2391 lsa
, buf
, sizeof(buf
), 0));
2393 /* Forwarding-Address */
2394 json_object_boolean_add(
2395 json_obj
, "forwardingAddressPresent",
2396 CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
));
2397 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
2398 json_object_string_add(
2399 json_obj
, "forwardingAddress",
2400 ospf6_as_external_lsa_get_prefix_str(
2401 lsa
, buf
, sizeof(buf
), 1));
2404 json_object_boolean_add(
2405 json_obj
, "tagPresent",
2406 CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
));
2407 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
2408 json_object_int_add(json_obj
, "tag",
2409 ospf6_as_external_lsa_get_tag(lsa
));
2411 vty_out(vty
, " Bits: %s\n", buf
);
2412 vty_out(vty
, " Metric: %5lu\n",
2413 (unsigned long)OSPF6_ASBR_METRIC(external
));
2415 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
,
2417 vty_out(vty
, " Prefix Options: %s\n", buf
);
2419 vty_out(vty
, " Referenced LSType: %d\n",
2420 ntohs(external
->prefix
.prefix_refer_lstype
));
2422 vty_out(vty
, " Prefix: %s\n",
2423 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
,
2426 /* Forwarding-Address */
2427 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
2428 vty_out(vty
, " Forwarding-Address: %s\n",
2429 ospf6_as_external_lsa_get_prefix_str(
2430 lsa
, buf
, sizeof(buf
), 1));
2434 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
2435 vty_out(vty
, " Tag: %" ROUTE_TAG_PRI
"\n",
2436 ospf6_as_external_lsa_get_tag(lsa
));
2443 static void ospf6_asbr_external_route_show(struct vty
*vty
,
2444 struct ospf6_route
*route
,
2445 json_object
*json_array
,
2448 struct ospf6_external_info
*info
= route
->route_option
;
2449 char prefix
[PREFIX2STR_BUFFER
], id
[16], forwarding
[64];
2451 json_object
*json_route
;
2454 prefix2str(&route
->prefix
, prefix
, sizeof(prefix
));
2455 tmp_id
= ntohl(info
->id
);
2456 inet_ntop(AF_INET
, &tmp_id
, id
, sizeof(id
));
2457 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
2458 inet_ntop(AF_INET6
, &info
->forwarding
, forwarding
,
2459 sizeof(forwarding
));
2461 snprintf(forwarding
, sizeof(forwarding
), ":: (ifindex %d)",
2462 ospf6_route_get_first_nh_index(route
));
2465 json_route
= json_object_new_object();
2466 snprintf(route_type
, sizeof(route_type
), "%c",
2467 zebra_route_char(info
->type
));
2468 json_object_string_add(json_route
, "routeType", route_type
);
2469 json_object_string_add(json_route
, "destination", prefix
);
2470 json_object_string_add(json_route
, "id", id
);
2471 json_object_int_add(json_route
, "metricType",
2472 route
->path
.metric_type
);
2473 json_object_int_add(
2474 json_route
, "routeCost",
2475 (unsigned long)(route
->path
.metric_type
== 2
2476 ? route
->path
.u
.cost_e2
2477 : route
->path
.cost
));
2478 json_object_string_add(json_route
, "forwarding", forwarding
);
2480 json_object_array_add(json_array
, json_route
);
2483 vty_out(vty
, "%c %-32pFX %-15s type-%d %5lu %s\n",
2484 zebra_route_char(info
->type
), &route
->prefix
, id
,
2485 route
->path
.metric_type
,
2486 (unsigned long)(route
->path
.metric_type
== 2
2487 ? route
->path
.u
.cost_e2
2488 : route
->path
.cost
),
2492 DEFUN(show_ipv6_ospf6_redistribute
, show_ipv6_ospf6_redistribute_cmd
,
2493 "show ipv6 ospf6 [vrf <NAME|all>] redistribute [json]",
2494 SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
2496 "redistributing External information\n" JSON_STR
)
2498 struct ospf6_route
*route
;
2499 struct ospf6
*ospf6
= NULL
;
2500 json_object
*json
= NULL
;
2501 bool uj
= use_json(argc
, argv
);
2502 struct listnode
*node
;
2503 const char *vrf_name
= NULL
;
2504 bool all_vrf
= false;
2507 json_object
*json_array_routes
= NULL
;
2508 json_object
*json_array_redistribute
= NULL
;
2510 OSPF6_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
2513 json
= json_object_new_object();
2514 json_array_routes
= json_object_new_array();
2515 json_array_redistribute
= json_object_new_array();
2518 for (ALL_LIST_ELEMENTS_RO(om6
->ospf6
, node
, ospf6
)) {
2520 || ((ospf6
->name
== NULL
&& vrf_name
== NULL
)
2521 || (ospf6
->name
&& vrf_name
2522 && strcmp(ospf6
->name
, vrf_name
) == 0))) {
2523 ospf6_redistribute_show_config(
2524 vty
, ospf6
, json_array_redistribute
, json
, uj
);
2526 for (route
= ospf6_route_head(ospf6
->external_table
);
2527 route
; route
= ospf6_route_next(route
)) {
2528 ospf6_asbr_external_route_show(
2529 vty
, route
, json_array_routes
, uj
);
2533 json_object_object_add(json
, "routes",
2535 vty_json(vty
, json
);
2543 OSPF6_CMD_CHECK_VRF(uj
, all_vrf
, ospf6
);
2548 static struct ospf6_lsa_handler as_external_handler
= {
2549 .lh_type
= OSPF6_LSTYPE_AS_EXTERNAL
,
2550 .lh_name
= "AS-External",
2551 .lh_short_name
= "ASE",
2552 .lh_show
= ospf6_as_external_lsa_show
,
2553 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
2556 static struct ospf6_lsa_handler nssa_external_handler
= {
2557 .lh_type
= OSPF6_LSTYPE_TYPE_7
,
2559 .lh_short_name
= "Type7",
2560 .lh_show
= ospf6_as_external_lsa_show
,
2561 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
2564 void ospf6_asbr_init(void)
2566 ospf6_routemap_init();
2568 ospf6_install_lsa_handler(&as_external_handler
);
2569 ospf6_install_lsa_handler(&nssa_external_handler
);
2571 install_element(VIEW_NODE
, &show_ipv6_ospf6_redistribute_cmd
);
2573 install_element(OSPF6_NODE
, &ospf6_default_route_originate_cmd
);
2574 install_element(OSPF6_NODE
,
2575 &no_ospf6_default_information_originate_cmd
);
2576 install_element(OSPF6_NODE
, &ospf6_redistribute_cmd
);
2577 install_element(OSPF6_NODE
, &no_ospf6_redistribute_cmd
);
2580 void ospf6_asbr_redistribute_disable(struct ospf6
*ospf6
)
2583 struct ospf6_redist
*red
;
2585 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
2586 red
= ospf6_redist_lookup(ospf6
, type
, 0);
2589 if (type
== ZEBRA_ROUTE_OSPF6
)
2591 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
2592 ospf6_redist_del(ospf6
, red
, type
);
2594 red
= ospf6_redist_lookup(ospf6
, DEFAULT_ROUTE
, 0);
2596 ospf6_asbr_routemap_unset(red
);
2597 ospf6_redist_del(ospf6
, red
, type
);
2598 ospf6_redistribute_default_set(ospf6
, DEFAULT_ORIGINATE_NONE
);
2602 void ospf6_asbr_redistribute_reset(struct ospf6
*ospf6
)
2605 struct ospf6_redist
*red
;
2606 char buf
[RMAP_NAME_MAXLEN
];
2608 for (type
= 0; type
<= ZEBRA_ROUTE_MAX
; type
++) {
2610 if (type
== ZEBRA_ROUTE_OSPF6
)
2612 red
= ospf6_redist_lookup(ospf6
, type
, 0);
2616 if (type
== DEFAULT_ROUTE
) {
2617 ospf6_redistribute_default_set(
2618 ospf6
, ospf6
->default_originate
);
2621 if (ROUTEMAP_NAME(red
))
2622 strlcpy(buf
, ROUTEMAP_NAME(red
), sizeof(buf
));
2624 ospf6_asbr_redistribute_unset(ospf6
, red
, type
);
2626 ospf6_asbr_routemap_set(red
, buf
);
2627 ospf6_asbr_redistribute_set(ospf6
, type
);
2631 void ospf6_asbr_terminate(void)
2633 /* Cleanup route maps */
2637 DEFUN (debug_ospf6_asbr
,
2638 debug_ospf6_asbr_cmd
,
2642 "Debug OSPFv3 ASBR function\n"
2645 OSPF6_DEBUG_ASBR_ON();
2649 DEFUN (no_debug_ospf6_asbr
,
2650 no_debug_ospf6_asbr_cmd
,
2651 "no debug ospf6 asbr",
2655 "Debug OSPFv3 ASBR function\n"
2658 OSPF6_DEBUG_ASBR_OFF();
2662 int config_write_ospf6_debug_asbr(struct vty
*vty
)
2664 if (IS_OSPF6_DEBUG_ASBR
)
2665 vty_out(vty
, "debug ospf6 asbr\n");
2669 static void ospf6_default_originate_write(struct vty
*vty
, struct ospf6
*o
)
2671 struct ospf6_redist
*red
;
2673 vty_out(vty
, " default-information originate");
2674 if (o
->default_originate
== DEFAULT_ORIGINATE_ALWAYS
)
2675 vty_out(vty
, " always");
2677 red
= ospf6_redist_lookup(o
, DEFAULT_ROUTE
, 0);
2683 if (red
->dmetric
.value
>= 0)
2684 vty_out(vty
, " metric %d", red
->dmetric
.value
);
2686 if (red
->dmetric
.type
>= 0)
2687 vty_out(vty
, " metric-type %d", red
->dmetric
.type
);
2689 if (ROUTEMAP_NAME(red
))
2690 vty_out(vty
, " route-map %s", ROUTEMAP_NAME(red
));
2695 int ospf6_distribute_config_write(struct vty
*vty
, struct ospf6
*o
)
2700 /* Print default originate configuration. */
2701 if (o
->default_originate
!= DEFAULT_ORIGINATE_NONE
)
2702 ospf6_default_originate_write(vty
, o
);
2707 void install_element_ospf6_debug_asbr(void)
2709 install_element(ENABLE_NODE
, &debug_ospf6_asbr_cmd
);
2710 install_element(ENABLE_NODE
, &no_debug_ospf6_asbr_cmd
);
2711 install_element(CONFIG_NODE
, &debug_ospf6_asbr_cmd
);
2712 install_element(CONFIG_NODE
, &no_debug_ospf6_asbr_cmd
);
2715 /* ASBR Summarisation */
2716 void ospf6_fill_aggr_route_details(struct ospf6
*ospf6
,
2717 struct ospf6_external_aggr_rt
*aggr
)
2719 struct ospf6_route
*rt_aggr
= aggr
->route
;
2720 struct ospf6_external_info
*ei_aggr
= rt_aggr
->route_option
;
2722 rt_aggr
->prefix
= aggr
->p
;
2723 ei_aggr
->tag
= aggr
->tag
;
2725 ei_aggr
->id
= aggr
->id
;
2727 /* When metric is not configured, apply the default metric */
2728 rt_aggr
->path
.cost
= ((aggr
->metric
== -1) ?
2729 DEFAULT_DEFAULT_METRIC
2730 : (unsigned int)(aggr
->metric
));
2731 rt_aggr
->path
.metric_type
= aggr
->mtype
;
2733 rt_aggr
->path
.origin
.id
= htonl(aggr
->id
);
2737 ospf6_summary_add_aggr_route_and_blackhole(struct ospf6
*ospf6
,
2738 struct ospf6_external_aggr_rt
*aggr
)
2740 struct ospf6_route
*rt_aggr
;
2741 struct ospf6_external_info
*info
;
2743 /* Create summary route and save it. */
2744 rt_aggr
= ospf6_route_create(ospf6
);
2745 rt_aggr
->type
= OSPF6_DEST_TYPE_NETWORK
;
2746 /* Needed to install route while calling zebra api */
2747 SET_FLAG(rt_aggr
->flag
, OSPF6_ROUTE_BEST
);
2749 info
= XCALLOC(MTYPE_OSPF6_EXTERNAL_INFO
, sizeof(*info
));
2750 rt_aggr
->route_option
= info
;
2751 aggr
->route
= rt_aggr
;
2753 /* Prepare the external_info for aggregator
2754 * Fill all the details which will get advertised
2756 ospf6_fill_aggr_route_details(ospf6
, aggr
);
2758 /* Add next-hop to Null interface. */
2759 ospf6_add_route_nexthop_blackhole(rt_aggr
);
2761 ospf6_zebra_route_update_add(rt_aggr
, ospf6
);
2764 static void ospf6_originate_new_aggr_lsa(struct ospf6
*ospf6
,
2765 struct ospf6_external_aggr_rt
*aggr
)
2767 struct prefix prefix_id
;
2768 struct ospf6_lsa
*lsa
= NULL
;
2770 if (IS_OSPF6_DEBUG_AGGR
)
2771 zlog_debug("%s: Originate new aggregate route(%pFX)", __func__
,
2774 aggr
->id
= ospf6
->external_id
++;
2776 if (IS_OSPF6_DEBUG_AGGR
)
2778 "Advertise AS-External Id:%pI4 prefix %pFX metric %u",
2779 &prefix_id
.u
.prefix4
, &aggr
->p
, aggr
->metric
);
2781 ospf6_summary_add_aggr_route_and_blackhole(ospf6
, aggr
);
2783 /* Originate summary LSA */
2784 lsa
= ospf6_originate_type5_type7_lsas(aggr
->route
, ospf6
);
2786 if (IS_OSPF6_DEBUG_AGGR
)
2787 zlog_debug("%s: Set the origination bit for aggregator",
2789 SET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
2794 ospf6_aggr_handle_advertise_change(struct ospf6
*ospf6
,
2795 struct ospf6_external_aggr_rt
*aggr
)
2797 /* Check if advertise option modified. */
2798 if (CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
2799 if (IS_OSPF6_DEBUG_AGGR
)
2800 zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
2802 ospf6_asbr_summary_remove_lsa_and_route(ospf6
, aggr
);
2807 /* There are no routes present under this aggregation config, hence
2808 * nothing to originate here
2810 if (OSPF6_EXTERNAL_RT_COUNT(aggr
) == 0) {
2811 if (IS_OSPF6_DEBUG_AGGR
)
2812 zlog_debug("%s: No routes present under this aggregation",
2817 if (!CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
)) {
2818 if (IS_OSPF6_DEBUG_AGGR
)
2819 zlog_debug("%s: Now it is advertisable",
2822 ospf6_originate_new_aggr_lsa(ospf6
, aggr
);
2829 ospf6_originate_summary_lsa(struct ospf6
*ospf6
,
2830 struct ospf6_external_aggr_rt
*aggr
,
2831 struct ospf6_route
*rt
)
2833 struct ospf6_lsa
*lsa
= NULL
, *aggr_lsa
= NULL
;
2834 struct ospf6_external_info
*info
= NULL
;
2835 struct ospf6_external_aggr_rt
*old_aggr
;
2836 struct ospf6_as_external_lsa
*external
;
2837 struct ospf6_route
*rt_aggr
= NULL
;
2838 route_tag_t tag
= 0;
2839 unsigned int metric
= 0;
2842 if (IS_OSPF6_DEBUG_AGGR
)
2843 zlog_debug("%s: Prepare to originate Summary route(%pFX)",
2844 __func__
, &aggr
->p
);
2846 /* This case to handle when the overlapping aggregator address
2847 * is available. Best match will be considered.So need to delink
2848 * from old aggregator and link to the new aggr.
2850 if (rt
->aggr_route
) {
2851 if (rt
->aggr_route
!= aggr
) {
2852 old_aggr
= rt
->aggr_route
;
2853 ospf6_unlink_route_from_aggr(ospf6
, old_aggr
, rt
);
2857 /* Add the external route to hash table */
2858 ospf6_link_route_to_aggr(aggr
, rt
);
2860 /* The key for ID field is a running number and not prefix */
2861 info
= rt
->route_option
;
2864 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
2865 htonl(info
->id
), ospf6
->router_id
,
2868 aggr_lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
2869 htonl(aggr
->id
), ospf6
->router_id
, ospf6
->lsdb
);
2871 if (IS_OSPF6_DEBUG_AGGR
)
2872 zlog_debug("%s: Aggr LSA ID: %d flags %x.",
2873 __func__
, aggr
->id
, aggr
->aggrflags
);
2874 /* Don't originate external LSA,
2875 * If it is configured not to advertise.
2877 if (CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
2878 /* If it is already originated as external LSA,
2879 * But, it is configured not to advertise then
2880 * flush the originated external lsa.
2883 if (IS_OSPF6_DEBUG_AGGR
)
2884 zlog_debug("%s: Purge the external LSA %s.",
2885 __func__
, lsa
->name
);
2886 ospf6_external_lsa_purge(ospf6
, lsa
);
2888 rt
->path
.origin
.id
= 0;
2892 if (IS_OSPF6_DEBUG_AGGR
)
2893 zlog_debug("%s: Purge the aggr external LSA %s.",
2894 __func__
, lsa
->name
);
2895 ospf6_asbr_summary_remove_lsa_and_route(ospf6
, aggr
);
2898 UNSET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
2900 if (IS_OSPF6_DEBUG_AGGR
)
2901 zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
2906 /* Summary route already originated,
2909 if (CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
)) {
2912 "%s: Could not refresh/originate %pFX",
2915 /* Remove the assert later */
2920 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END
2922 metric
= (unsigned long)OSPF6_ASBR_METRIC(external
);
2923 tag
= ospf6_as_external_lsa_get_tag(aggr_lsa
);
2924 mtype
= CHECK_FLAG(external
->bits_metric
,
2925 OSPF6_ASBR_BIT_E
) ? 2 : 1;
2927 /* Prepare the external_info for aggregator */
2928 ospf6_fill_aggr_route_details(ospf6
, aggr
);
2929 rt_aggr
= aggr
->route
;
2930 /* If tag/metric/metric-type modified , then re-originate the
2931 * route with modified tag/metric/metric-type details.
2933 if ((tag
!= aggr
->tag
)
2934 || (metric
!= (unsigned int)rt_aggr
->path
.cost
)
2935 || (mtype
!= aggr
->mtype
)) {
2937 if (IS_OSPF6_DEBUG_AGGR
)
2939 "%s: Routetag(old:%d new:%d)/Metric(o:%u,n:%u)/mtype(o:%d n:%d) modified,So refresh the summary route.(%pFX)",
2940 __func__
, tag
, aggr
->tag
,
2946 aggr_lsa
= ospf6_originate_type5_type7_lsas(aggr
->route
,
2949 SET_FLAG(aggr
->aggrflags
,
2950 OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
2956 /* If the external route prefix same as aggregate route
2957 * and if external route is already originated as TYPE-5
2958 * then just update the aggr info and remove the route info
2960 if (lsa
&& prefix_same(&aggr
->p
, &rt
->prefix
)) {
2961 if (IS_OSPF6_DEBUG_AGGR
)
2963 "%s: Route prefix is same as aggr so no need to re-originate LSA(%pFX)",
2964 __PRETTY_FUNCTION__
, &aggr
->p
);
2966 aggr
->id
= info
->id
;
2968 rt
->path
.origin
.id
= 0;
2970 ospf6_summary_add_aggr_route_and_blackhole(ospf6
, aggr
);
2972 SET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);
2977 ospf6_originate_new_aggr_lsa(ospf6
, aggr
);
2980 static void ospf6_aggr_handle_external_info(void *data
)
2982 struct ospf6_route
*rt
= (struct ospf6_route
*)data
;
2983 struct ospf6_external_aggr_rt
*aggr
= NULL
;
2984 struct ospf6_lsa
*lsa
= NULL
;
2985 struct ospf6_external_info
*info
;
2986 struct ospf6
*ospf6
= NULL
;
2988 rt
->aggr_route
= NULL
;
2990 rt
->to_be_processed
= true;
2992 if (IS_OSPF6_DEBUG_ASBR
|| IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL
))
2993 zlog_debug("%s: Handle external route for origination/refresh (%pFX)",
3000 aggr
= ospf6_external_aggr_match(ospf6
,
3003 ospf6_originate_summary_lsa(ospf6
, aggr
, rt
);
3007 info
= rt
->route_option
;
3009 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
3010 htonl(info
->id
), ospf6
->router_id
,
3013 if (IS_OSPF6_DEBUG_AGGR
)
3014 zlog_debug("%s: LSA found, refresh it",
3016 THREAD_OFF(lsa
->refresh
);
3017 thread_add_event(master
, ospf6_lsa_refresh
, lsa
, 0,
3023 info
->id
= ospf6
->external_id
++;
3024 rt
->path
.origin
.id
= htonl(info
->id
);
3026 (void)ospf6_originate_type5_type7_lsas(rt
, ospf6
);
3030 ospf6_asbr_summary_config_delete(struct ospf6
*ospf6
, struct route_node
*rn
)
3032 struct ospf6_external_aggr_rt
*aggr
= rn
->info
;
3034 if (IS_OSPF6_DEBUG_AGGR
)
3035 zlog_debug("%s: Deleting Aggregate route (%pFX)",
3039 ospf6_asbr_summary_remove_lsa_and_route(ospf6
, aggr
);
3042 route_unlock_node(rn
);
3046 ospf6_handle_external_aggr_modify(struct ospf6
*ospf6
,
3047 struct ospf6_external_aggr_rt
*aggr
)
3049 struct ospf6_lsa
*lsa
= NULL
;
3050 struct ospf6_as_external_lsa
*asel
= NULL
;
3051 struct ospf6_route
*rt_aggr
;
3052 unsigned int metric
= 0;
3053 route_tag_t tag
= 0;
3056 lsa
= ospf6_lsdb_lookup(
3057 htons(OSPF6_LSTYPE_AS_EXTERNAL
),
3058 htonl(aggr
->id
), ospf6
->router_id
,
3062 "%s: Could not refresh/originate %pFX",
3066 return OSPF6_FAILURE
;
3069 asel
= (struct ospf6_as_external_lsa
*)
3070 OSPF6_LSA_HEADER_END(lsa
->header
);
3071 metric
= (unsigned long)OSPF6_ASBR_METRIC(asel
);
3072 tag
= ospf6_as_external_lsa_get_tag(lsa
);
3073 mtype
= CHECK_FLAG(asel
->bits_metric
,
3074 OSPF6_ASBR_BIT_E
) ? 2 : 1;
3076 /* Fill all the details for advertisement */
3077 ospf6_fill_aggr_route_details(ospf6
, aggr
);
3078 rt_aggr
= aggr
->route
;
3079 /* If tag/metric/metric-type modified , then
3080 * re-originate the route with modified
3081 * tag/metric/metric-type details.
3083 if ((tag
!= aggr
->tag
)
3085 != (unsigned int)rt_aggr
->path
.cost
)
3088 if (IS_OSPF6_DEBUG_AGGR
)
3090 "%s: Changed tag(old:%d new:%d)/metric(o:%u n:%d)/mtype(o:%d n:%d),So refresh the summary route.(%pFX)",
3094 (unsigned int)rt_aggr
->path
.cost
,
3098 (void)ospf6_originate_type5_type7_lsas(
3103 return OSPF6_SUCCESS
;
3106 static void ospf6_handle_external_aggr_update(struct ospf6
*ospf6
)
3108 struct route_node
*rn
= NULL
;
3111 if (IS_OSPF6_DEBUG_AGGR
)
3112 zlog_debug("%s: Process modified aggregators.", __func__
);
3114 for (rn
= route_top(ospf6
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
3115 struct ospf6_external_aggr_rt
*aggr
;
3122 if (aggr
->action
== OSPF6_ROUTE_AGGR_DEL
) {
3123 aggr
->action
= OSPF6_ROUTE_AGGR_NONE
;
3124 ospf6_asbr_summary_config_delete(ospf6
, rn
);
3126 if (OSPF6_EXTERNAL_RT_COUNT(aggr
))
3127 hash_clean(aggr
->match_extnl_hash
,
3128 ospf6_aggr_handle_external_info
);
3130 hash_free(aggr
->match_extnl_hash
);
3131 XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR
, aggr
);
3133 } else if (aggr
->action
== OSPF6_ROUTE_AGGR_MODIFY
) {
3135 aggr
->action
= OSPF6_ROUTE_AGGR_NONE
;
3137 /* Check if tag/metric/metric-type modified */
3138 if (CHECK_FLAG(aggr
->aggrflags
,
3139 OSPF6_EXTERNAL_AGGRT_ORIGINATED
)
3140 && !CHECK_FLAG(aggr
->aggrflags
,
3141 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
3143 ret
= ospf6_handle_external_aggr_modify(ospf6
,
3145 if (ret
== OSPF6_FAILURE
)
3149 /* Advertise option modified ?
3150 * If so, handled it here.
3152 ospf6_aggr_handle_advertise_change(ospf6
, aggr
);
3157 static void ospf6_aggr_unlink_external_info(void *data
)
3159 struct ospf6_route
*rt
= (struct ospf6_route
*)data
;
3161 rt
->aggr_route
= NULL
;
3163 rt
->to_be_processed
= true;
3166 void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt
*aggr
)
3168 if (OSPF6_EXTERNAL_RT_COUNT(aggr
))
3169 hash_clean(aggr
->match_extnl_hash
,
3170 ospf6_aggr_unlink_external_info
);
3173 if (aggr
->route
->route_option
)
3174 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
,
3175 aggr
->route
->route_option
);
3177 ospf6_route_delete(aggr
->route
);
3180 if (IS_OSPF6_DEBUG_AGGR
)
3181 zlog_debug("%s: Release the aggregator Address(%pFX)",
3185 hash_free(aggr
->match_extnl_hash
);
3186 aggr
->match_extnl_hash
= NULL
;
3188 XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR
, aggr
);
3192 ospf6_delete_all_marked_aggregators(struct ospf6
*ospf6
)
3194 struct route_node
*rn
= NULL
;
3195 struct ospf6_external_aggr_rt
*aggr
;
3197 /* Loop through all the aggregators, Delete all aggregators
3198 * which are marked as DELETE. Set action to NONE for remaining
3201 for (rn
= route_top(ospf6
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
3207 if (aggr
->action
!= OSPF6_ROUTE_AGGR_DEL
) {
3208 aggr
->action
= OSPF6_ROUTE_AGGR_NONE
;
3211 ospf6_asbr_summary_config_delete(ospf6
, rn
);
3212 ospf6_external_aggregator_free(aggr
);
3216 static void ospf6_handle_exnl_rt_after_aggr_del(struct ospf6
*ospf6
,
3217 struct ospf6_route
*rt
)
3219 struct ospf6_lsa
*lsa
;
3221 /* Process only marked external routes.
3222 * These routes were part of a deleted
3223 * aggregator.So, originate now.
3225 if (!rt
->to_be_processed
)
3228 rt
->to_be_processed
= false;
3230 lsa
= ospf6_find_external_lsa(ospf6
, &rt
->prefix
);
3233 THREAD_OFF(lsa
->refresh
);
3234 thread_add_event(master
, ospf6_lsa_refresh
, lsa
, 0,
3237 if (IS_OSPF6_DEBUG_AGGR
)
3238 zlog_debug("%s: Originate external route(%pFX)",
3242 (void)ospf6_originate_type5_type7_lsas(rt
, ospf6
);
3246 static void ospf6_handle_aggregated_exnl_rt(struct ospf6
*ospf6
,
3247 struct ospf6_external_aggr_rt
*aggr
,
3248 struct ospf6_route
*rt
)
3250 struct ospf6_lsa
*lsa
;
3251 struct ospf6_as_external_lsa
*ext_lsa
;
3252 struct ospf6_external_info
*info
;
3254 /* Handling the case where the external route prefix
3255 * and aggegate prefix is same
3256 * If same don't flush the originated external LSA.
3258 if (prefix_same(&aggr
->p
, &rt
->prefix
)) {
3259 if (IS_OSPF6_DEBUG_AGGR
)
3260 zlog_debug("%s: External Route prefix same as Aggregator(%pFX), so don't flush.",
3267 info
= rt
->route_option
;
3270 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
3271 htonl(info
->id
), ospf6
->router_id
, ospf6
->lsdb
);
3273 ext_lsa
= (struct ospf6_as_external_lsa
3274 *)((char *)(lsa
->header
)
3275 + sizeof(struct ospf6_lsa_header
));
3277 if (rt
->prefix
.prefixlen
!= ext_lsa
->prefix
.prefix_length
)
3280 ospf6_external_lsa_purge(ospf6
, lsa
);
3282 /* Resetting the ID of route */
3283 rt
->path
.origin
.id
= 0;
3289 ospf6_handle_external_aggr_add(struct ospf6
*ospf6
)
3291 struct ospf6_route
*rt
= NULL
;
3292 struct ospf6_external_info
*ei
= NULL
;
3293 struct ospf6_external_aggr_rt
*aggr
;
3295 /* Delete all the aggregators which are marked as
3296 * OSPF6_ROUTE_AGGR_DEL.
3298 ospf6_delete_all_marked_aggregators(ospf6
);
3300 for (rt
= ospf6_route_head(ospf6
->external_table
); rt
;
3301 rt
= ospf6_route_next(rt
)) {
3302 ei
= rt
->route_option
;
3306 if (is_default_prefix(&rt
->prefix
))
3309 aggr
= ospf6_external_aggr_match(ospf6
,
3312 /* If matching aggregator found, Add
3313 * the external route refrenace to the
3314 * aggregator and originate the aggr
3315 * route if it is advertisable.
3316 * flush the external LSA if it is
3317 * already originated for this external
3321 ospf6_originate_summary_lsa(ospf6
, aggr
, rt
);
3323 /* All aggregated external rts
3326 ospf6_handle_aggregated_exnl_rt(
3331 /* External routes which are only out
3332 * of aggregation will be handled here.
3334 ospf6_handle_exnl_rt_after_aggr_del(
3339 static void ospf6_asbr_summary_process(struct thread
*thread
)
3341 struct ospf6
*ospf6
= THREAD_ARG(thread
);
3344 operation
= ospf6
->aggr_action
;
3346 if (IS_OSPF6_DEBUG_AGGR
)
3347 zlog_debug("%s: operation:%d",
3351 switch (operation
) {
3352 case OSPF6_ROUTE_AGGR_ADD
:
3353 ospf6_handle_external_aggr_add(ospf6
);
3355 case OSPF6_ROUTE_AGGR_DEL
:
3356 case OSPF6_ROUTE_AGGR_MODIFY
:
3357 ospf6_handle_external_aggr_update(ospf6
);
3365 ospf6_start_asbr_summary_delay_timer(struct ospf6
*ospf6
,
3366 struct ospf6_external_aggr_rt
*aggr
,
3367 ospf6_aggr_action_t operation
)
3369 aggr
->action
= operation
;
3371 if (thread_is_scheduled(ospf6
->t_external_aggr
)) {
3372 if (ospf6
->aggr_action
== OSPF6_ROUTE_AGGR_ADD
) {
3374 if (IS_OSPF6_DEBUG_AGGR
)
3375 zlog_debug("%s: Not required to restart timer,set is already added.",
3380 if (operation
== OSPF6_ROUTE_AGGR_ADD
) {
3381 if (IS_OSPF6_DEBUG_AGGR
)
3382 zlog_debug("%s, Restarting Aggregator delay timer.",
3384 THREAD_OFF(ospf6
->t_external_aggr
);
3388 if (IS_OSPF6_DEBUG_AGGR
)
3389 zlog_debug("%s: Start Aggregator delay timer %u(in seconds).",
3390 __func__
, ospf6
->aggr_delay_interval
);
3392 ospf6
->aggr_action
= operation
;
3393 thread_add_timer(master
,
3394 ospf6_asbr_summary_process
,
3395 ospf6
, ospf6
->aggr_delay_interval
,
3396 &ospf6
->t_external_aggr
);
3399 int ospf6_asbr_external_rt_advertise(struct ospf6
*ospf6
,
3402 struct route_node
*rn
;
3403 struct ospf6_external_aggr_rt
*aggr
;
3405 rn
= route_node_lookup(ospf6
->rt_aggr_tbl
, p
);
3407 return OSPF6_INVALID
;
3411 route_unlock_node(rn
);
3413 if (!CHECK_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
))
3414 return OSPF6_INVALID
;
3416 UNSET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
);
3418 if (!OSPF6_EXTERNAL_RT_COUNT(aggr
))
3419 return OSPF6_SUCCESS
;
3421 ospf6_start_asbr_summary_delay_timer(ospf6
, aggr
,
3422 OSPF6_ROUTE_AGGR_MODIFY
);
3424 return OSPF6_SUCCESS
;
3427 int ospf6_external_aggr_delay_timer_set(struct ospf6
*ospf6
, uint16_t interval
)
3429 ospf6
->aggr_delay_interval
= interval
;
3431 return OSPF6_SUCCESS
;
3434 static unsigned int ospf6_external_rt_hash_key(const void *data
)
3436 const struct ospf6_route
*rt
= data
;
3437 unsigned int key
= 0;
3439 key
= prefix_hash_key(&rt
->prefix
);
3443 static bool ospf6_external_rt_hash_cmp(const void *d1
, const void *d2
)
3445 const struct ospf6_route
*rt1
= d1
;
3446 const struct ospf6_route
*rt2
= d2
;
3448 return prefix_same(&rt1
->prefix
, &rt2
->prefix
);
3451 static struct ospf6_external_aggr_rt
*
3452 ospf6_external_aggr_new(struct prefix
*p
)
3454 struct ospf6_external_aggr_rt
*aggr
;
3456 aggr
= XCALLOC(MTYPE_OSPF6_EXTERNAL_RT_AGGR
,
3457 sizeof(struct ospf6_external_aggr_rt
));
3459 prefix_copy(&aggr
->p
, p
);
3461 aggr
->mtype
= DEFAULT_METRIC_TYPE
;
3462 aggr
->match_extnl_hash
= hash_create(ospf6_external_rt_hash_key
,
3463 ospf6_external_rt_hash_cmp
,
3464 "Ospf6 external route hash");
3468 static void ospf6_external_aggr_add(struct ospf6
*ospf6
,
3469 struct ospf6_external_aggr_rt
*aggr
)
3471 struct route_node
*rn
;
3473 if (IS_OSPF6_DEBUG_AGGR
)
3474 zlog_debug("%s: Adding Aggregate route to Aggr table (%pFX)",
3478 rn
= route_node_get(ospf6
->rt_aggr_tbl
, &aggr
->p
);
3480 route_unlock_node(rn
);
3485 int ospf6_asbr_external_rt_no_advertise(struct ospf6
*ospf6
,
3488 struct ospf6_external_aggr_rt
*aggr
;
3489 route_tag_t tag
= 0;
3491 aggr
= ospf6_external_aggr_config_lookup(ospf6
, p
);
3493 if (CHECK_FLAG(aggr
->aggrflags
,
3494 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
))
3495 return OSPF6_SUCCESS
;
3497 SET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
);
3502 if (!OSPF6_EXTERNAL_RT_COUNT(aggr
))
3503 return OSPF6_SUCCESS
;
3505 ospf6_start_asbr_summary_delay_timer(ospf6
, aggr
,
3506 OSPF6_ROUTE_AGGR_MODIFY
);
3508 aggr
= ospf6_external_aggr_new(p
);
3511 return OSPF6_FAILURE
;
3513 SET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
);
3514 ospf6_external_aggr_add(ospf6
, aggr
);
3515 ospf6_start_asbr_summary_delay_timer(ospf6
, aggr
,
3516 OSPF6_ROUTE_AGGR_ADD
);
3519 return OSPF6_SUCCESS
;
3522 struct ospf6_external_aggr_rt
*
3523 ospf6_external_aggr_config_lookup(struct ospf6
*ospf6
, struct prefix
*p
)
3525 struct route_node
*rn
;
3527 rn
= route_node_lookup(ospf6
->rt_aggr_tbl
, p
);
3529 route_unlock_node(rn
);
3537 int ospf6_external_aggr_config_set(struct ospf6
*ospf6
, struct prefix
*p
,
3538 route_tag_t tag
, int metric
, int mtype
)
3540 struct ospf6_external_aggr_rt
*aggregator
;
3542 aggregator
= ospf6_external_aggr_config_lookup(ospf6
, p
);
3545 if (CHECK_FLAG(aggregator
->aggrflags
,
3546 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
))
3547 UNSET_FLAG(aggregator
->aggrflags
,
3548 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE
);
3549 else if ((aggregator
->tag
== tag
)
3550 && (aggregator
->metric
== metric
)
3551 && (aggregator
->mtype
== mtype
))
3552 return OSPF6_SUCCESS
;
3554 aggregator
->tag
= tag
;
3555 aggregator
->metric
= metric
;
3556 aggregator
->mtype
= mtype
;
3558 ospf6_start_asbr_summary_delay_timer(ospf6
, aggregator
,
3559 OSPF6_ROUTE_AGGR_MODIFY
);
3561 aggregator
= ospf6_external_aggr_new(p
);
3563 return OSPF6_FAILURE
;
3565 aggregator
->tag
= tag
;
3566 aggregator
->metric
= metric
;
3567 aggregator
->mtype
= mtype
;
3569 ospf6_external_aggr_add(ospf6
, aggregator
);
3570 ospf6_start_asbr_summary_delay_timer(ospf6
, aggregator
,
3571 OSPF6_ROUTE_AGGR_ADD
);
3574 return OSPF6_SUCCESS
;
3577 int ospf6_external_aggr_config_unset(struct ospf6
*ospf6
,
3580 struct route_node
*rn
;
3581 struct ospf6_external_aggr_rt
*aggr
;
3583 rn
= route_node_lookup(ospf6
->rt_aggr_tbl
, p
);
3585 return OSPF6_INVALID
;
3589 route_unlock_node(rn
);
3591 if (!OSPF6_EXTERNAL_RT_COUNT(aggr
)) {
3592 ospf6_asbr_summary_config_delete(ospf6
, rn
);
3593 ospf6_external_aggregator_free(aggr
);
3594 return OSPF6_SUCCESS
;
3597 ospf6_start_asbr_summary_delay_timer(ospf6
, aggr
,
3598 OSPF6_ROUTE_AGGR_DEL
);
3600 return OSPF6_SUCCESS
;
3603 void ospf6_handle_external_lsa_origination(struct ospf6
*ospf6
,
3604 struct ospf6_route
*rt
,
3608 struct ospf6_external_aggr_rt
*aggr
;
3609 struct ospf6_external_info
*info
;
3610 struct prefix prefix_id
;
3612 if (!is_default_prefix(p
)) {
3613 aggr
= ospf6_external_aggr_match(ospf6
,
3618 if (IS_OSPF6_DEBUG_AGGR
)
3619 zlog_debug("%s: Send Aggregate LSA (%pFX)",
3623 ospf6_originate_summary_lsa(
3626 /* Handling the case where the
3627 * external route prefix
3628 * and aggegate prefix is same
3629 * If same don't flush the
3633 ospf6_handle_aggregated_exnl_rt(
3639 info
= rt
->route_option
;
3641 /* When the info->id = 0, it means it is being originated for the
3645 info
->id
= ospf6
->external_id
++;
3647 prefix_id
.family
= AF_INET
;
3648 prefix_id
.prefixlen
= 32;
3649 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
3652 rt
->path
.origin
.id
= htonl(info
->id
);
3654 if (IS_OSPF6_DEBUG_ASBR
) {
3655 zlog_debug("Advertise new AS-External Id:%pI4 prefix %pFX metric %u",
3656 &prefix_id
.u
.prefix4
, p
, rt
->path
.metric_type
);
3659 ospf6_originate_type5_type7_lsas(rt
, ospf6
);
3663 void ospf6_unset_all_aggr_flag(struct ospf6
*ospf6
)
3665 struct route_node
*rn
= NULL
;
3666 struct ospf6_external_aggr_rt
*aggr
;
3668 if (IS_OSPF6_DEBUG_AGGR
)
3669 zlog_debug("Unset the origination bit for all aggregator");
3671 /* Resetting the running external ID counter so that the origination
3672 * of external LSAs starts from the beginning 0.0.0.1
3674 ospf6
->external_id
= OSPF6_EXT_INIT_LS_ID
;
3676 for (rn
= route_top(ospf6
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
3682 UNSET_FLAG(aggr
->aggrflags
, OSPF6_EXTERNAL_AGGRT_ORIGINATED
);