2 * Copyright (C) 2003 Yasuhiro Ohara
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include "ospf6_proto.h"
35 #include "ospf6_lsa.h"
36 #include "ospf6_lsdb.h"
37 #include "ospf6_route.h"
38 #include "ospf6_zebra.h"
39 #include "ospf6_message.h"
41 #include "ospf6_top.h"
42 #include "ospf6_area.h"
43 #include "ospf6_interface.h"
44 #include "ospf6_neighbor.h"
45 #include "ospf6_asbr.h"
46 #include "ospf6_abr.h"
47 #include "ospf6_intra.h"
48 #include "ospf6_flood.h"
52 static void ospf6_asbr_redistribute_set(int type
, vrf_id_t vrf_id
);
53 static void ospf6_asbr_redistribute_unset(int type
, vrf_id_t vrf_id
);
55 unsigned char conf_debug_ospf6_asbr
= 0;
57 #define ZROUTE_NAME(x) zebra_route_string(x)
59 /* AS External LSA origination */
60 static void ospf6_as_external_lsa_originate(struct ospf6_route
*route
,
63 char buffer
[OSPF6_MAX_LSASIZE
];
64 struct ospf6_lsa_header
*lsa_header
;
65 struct ospf6_lsa
*lsa
;
66 struct ospf6_external_info
*info
= route
->route_option
;
68 struct ospf6_as_external_lsa
*as_external_lsa
;
71 if (IS_OSPF6_DEBUG_ASBR
|| IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL
))
72 zlog_debug("Originate AS-External-LSA for %pFX",
76 memset(buffer
, 0, sizeof(buffer
));
77 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
78 as_external_lsa
= (struct ospf6_as_external_lsa
79 *)((caddr_t
)lsa_header
80 + sizeof(struct ospf6_lsa_header
));
81 p
= (caddr_t
)((caddr_t
)as_external_lsa
82 + sizeof(struct ospf6_as_external_lsa
));
84 /* Fill AS-External-LSA */
86 if (route
->path
.metric_type
== 2)
87 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
89 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
91 /* forwarding address */
92 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
93 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
95 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
97 /* external route tag */
99 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
101 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
104 OSPF6_ASBR_METRIC_SET(as_external_lsa
, route
->path
.cost
);
107 as_external_lsa
->prefix
.prefix_length
= route
->prefix
.prefixlen
;
110 as_external_lsa
->prefix
.prefix_options
= route
->path
.prefix_options
;
112 /* don't use refer LS-type */
113 as_external_lsa
->prefix
.prefix_refer_lstype
= htons(0);
116 memcpy(p
, &route
->prefix
.u
.prefix6
,
117 OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
));
118 ospf6_prefix_apply_mask(&as_external_lsa
->prefix
);
119 p
+= OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
);
121 /* Forwarding address */
122 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
123 memcpy(p
, &info
->forwarding
, sizeof(struct in6_addr
));
124 p
+= sizeof(struct in6_addr
);
127 /* External Route Tag */
128 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
129 route_tag_t network_order
= htonl(info
->tag
);
131 memcpy(p
, &network_order
, sizeof(network_order
));
132 p
+= sizeof(network_order
);
135 /* Fill LSA Header */
137 lsa_header
->type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
138 lsa_header
->id
= route
->path
.origin
.id
;
139 lsa_header
->adv_router
= ospf6
->router_id
;
141 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
142 lsa_header
->adv_router
, ospf6
->lsdb
);
143 lsa_header
->length
= htons((caddr_t
)p
- (caddr_t
)lsa_header
);
146 ospf6_lsa_checksum(lsa_header
);
149 lsa
= ospf6_lsa_create(lsa_header
);
152 ospf6_lsa_originate_process(lsa
, ospf6
);
155 int ospf6_orig_as_external_lsa(struct thread
*thread
)
157 struct ospf6_interface
*oi
;
158 struct ospf6_lsa
*lsa
;
159 uint32_t type
, adv_router
;
161 oi
= (struct ospf6_interface
*)THREAD_ARG(thread
);
162 oi
->thread_as_extern_lsa
= NULL
;
164 if (oi
->state
== OSPF6_INTERFACE_DOWN
)
167 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
168 adv_router
= oi
->area
->ospf6
->router_id
;
169 for (ALL_LSDB_TYPED_ADVRTR(oi
->area
->ospf6
->lsdb
, type
, adv_router
,
171 if (IS_OSPF6_DEBUG_ASBR
)
173 "%s: Send update of AS-External LSA %s seq 0x%x",
175 ntohl(lsa
->header
->seqnum
));
177 ospf6_flood_interface(NULL
, lsa
, oi
);
183 static route_tag_t
ospf6_as_external_lsa_get_tag(struct ospf6_lsa
*lsa
)
185 struct ospf6_as_external_lsa
*external
;
186 ptrdiff_t tag_offset
;
187 route_tag_t network_order
;
192 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
195 if (!CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
198 tag_offset
= sizeof(*external
)
199 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
200 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
201 tag_offset
+= sizeof(struct in6_addr
);
203 memcpy(&network_order
, (caddr_t
)external
+ tag_offset
,
204 sizeof(network_order
));
205 return ntohl(network_order
);
208 void ospf6_asbr_update_route_ecmp_path(struct ospf6_route
*old
,
209 struct ospf6_route
*route
,
212 struct ospf6_route
*old_route
;
213 struct ospf6_path
*ecmp_path
, *o_path
= NULL
;
214 struct listnode
*anode
, *anext
;
215 struct listnode
*nnode
, *rnode
, *rnext
;
216 struct ospf6_nexthop
*nh
, *rnh
;
217 bool route_found
= false;
219 /* check for old entry match with new route origin,
222 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
223 bool route_updated
= false;
225 if (!ospf6_route_is_same(old_route
, route
)
226 || (old_route
->path
.type
!= route
->path
.type
))
229 /* Current and New route has same origin,
232 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
, anext
,
234 /* Check old route path and route has same
237 if (o_path
->area_id
!= route
->path
.area_id
238 || (memcmp(&(o_path
)->origin
, &(route
)->path
.origin
,
239 sizeof(struct ospf6_ls_origin
))
243 /* Cost is not same then delete current path */
244 if ((o_path
->cost
== route
->path
.cost
)
245 && (o_path
->u
.cost_e2
== route
->path
.u
.cost_e2
))
248 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
250 "%s: route %pFX cost old %u new %u is not same, replace route",
251 __func__
, &old_route
->prefix
, o_path
->cost
,
255 /* Remove selected current rout path's nh from
258 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
259 for (ALL_LIST_ELEMENTS(old_route
->nh_list
,
260 rnode
, rnext
, rnh
)) {
261 if (!ospf6_nexthop_is_same(rnh
, nh
))
263 listnode_delete(old_route
->nh_list
,
265 ospf6_nexthop_delete(rnh
);
269 listnode_delete(old_route
->paths
, o_path
);
270 ospf6_path_free(o_path
);
271 route_updated
= true;
273 /* Current route's path (adv_router info) is similar
274 * to route being added.
275 * Replace current route's path with paths list head.
276 * Update FIB with effective NHs.
278 if (listcount(old_route
->paths
)) {
279 for (ALL_LIST_ELEMENTS(old_route
->paths
,
280 anode
, anext
, o_path
)) {
281 ospf6_merge_nexthops(
285 /* Update RIB/FIB with effective
288 if (ospf6
->route_table
->hook_add
)
289 (*ospf6
->route_table
->hook_add
)(
292 if (old_route
->path
.origin
.id
293 == route
->path
.origin
.id
294 && old_route
->path
.origin
.adv_router
295 == route
->path
.origin
297 struct ospf6_path
*h_path
;
299 h_path
= (struct ospf6_path
*)
300 listgetdata(listhead(
302 old_route
->path
.origin
.type
=
304 old_route
->path
.origin
.id
=
306 old_route
->path
.origin
.adv_router
=
307 h_path
->origin
.adv_router
;
310 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
312 "%s: route %pFX old cost %u new cost %u, delete old entry.",
313 __func__
, &old_route
->prefix
,
314 old_route
->path
.cost
,
317 ospf6_route_remove(old_route
,
318 ospf6
->route_table
, ospf6
);
326 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
328 /* Current and New Route prefix or route type
329 * is not same skip this current node.
331 if (!ospf6_route_is_same(old_route
, route
)
332 || (old_route
->path
.type
!= route
->path
.type
))
335 /* Old Route and New Route have Equal Cost, Merge NHs */
336 if ((old_route
->path
.cost
== route
->path
.cost
)
337 && (old_route
->path
.u
.cost_e2
== route
->path
.u
.cost_e2
)) {
339 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
341 "%s: old route %pFX path cost %u e2 %u",
342 __func__
, &old_route
->prefix
,
343 old_route
->path
.cost
,
344 old_route
->path
.u
.cost_e2
);
347 /* check if this path exists already in
348 * route->paths list, if so, replace nh_list
351 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
353 if (o_path
->area_id
== route
->path
.area_id
354 && (memcmp(&(o_path
)->origin
,
355 &(route
)->path
.origin
,
356 sizeof(struct ospf6_ls_origin
))
360 /* If path is not found in old_route paths's list,
361 * add a new path to route paths list and merge
362 * nexthops in route->path->nh_list.
363 * Otherwise replace existing path's nh_list.
365 if (o_path
== NULL
) {
366 ecmp_path
= ospf6_path_dup(&route
->path
);
368 /* Add a nh_list to new ecmp path */
369 ospf6_copy_nexthops(ecmp_path
->nh_list
,
372 /* Add the new path to route's path list */
373 listnode_add_sort(old_route
->paths
, ecmp_path
);
375 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
377 "%s: route %pFX another path added with nh %u, effective paths %u nh %u",
378 __func__
, &route
->prefix
,
379 listcount(ecmp_path
->nh_list
),
380 old_route
->paths
? listcount(
383 listcount(old_route
->nh_list
));
386 list_delete_all_node(o_path
->nh_list
);
387 ospf6_copy_nexthops(o_path
->nh_list
,
391 /* Reset nexthop lists, rebuild from brouter table
392 * for each adv. router.
394 list_delete_all_node(old_route
->nh_list
);
396 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
398 struct ospf6_route
*asbr_entry
;
400 asbr_entry
= ospf6_route_lookup(
402 ospf6
->brouter_table
);
403 if (asbr_entry
== NULL
) {
404 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
406 "%s: ls_prfix %pFX asbr_entry not found.",
411 ospf6_route_merge_nexthops(old_route
,
415 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
417 "%s: route %pFX with effective paths %u nh %u",
418 __func__
, &route
->prefix
,
420 ? listcount(old_route
->paths
)
423 ? listcount(old_route
->nh_list
)
427 if (ospf6
->route_table
->hook_add
)
428 (*ospf6
->route_table
->hook_add
)(old_route
,
431 /* Delete the new route its info added to existing
434 ospf6_route_delete(route
);
441 /* Add new route to existing node in ospf6 route table. */
442 ospf6_route_add(route
, ospf6
->route_table
, ospf6
);
446 void ospf6_asbr_lsa_add(struct ospf6_lsa
*lsa
, struct ospf6
*ospf6
)
448 struct ospf6_as_external_lsa
*external
;
449 struct prefix asbr_id
;
450 struct ospf6_route
*asbr_entry
, *route
, *old
;
451 struct ospf6_path
*path
;
453 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
456 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
457 zlog_debug("Calculate AS-External route for %s", lsa
->name
);
459 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
460 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
461 zlog_debug("Ignore self-originated AS-External-LSA");
465 if (OSPF6_ASBR_METRIC(external
) == OSPF_LS_INFINITY
) {
466 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
467 zlog_debug("Ignore LSA with LSInfinity Metric");
471 if (CHECK_FLAG(external
->prefix
.prefix_options
,
472 OSPF6_PREFIX_OPTION_NU
)) {
473 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
474 zlog_debug("Ignore LSA with NU bit set Metric");
478 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &asbr_id
);
479 asbr_entry
= ospf6_route_lookup(&asbr_id
, ospf6
->brouter_table
);
480 if (asbr_entry
== NULL
481 || !CHECK_FLAG(asbr_entry
->path
.router_bits
, OSPF6_ROUTER_BIT_E
)) {
482 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
483 zlog_debug("ASBR entry not found: %pFX", &asbr_id
);
487 route
= ospf6_route_create();
488 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
489 route
->prefix
.family
= AF_INET6
;
490 route
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
491 ospf6_prefix_in6_addr(&route
->prefix
.u
.prefix6
, external
,
494 route
->path
.area_id
= asbr_entry
->path
.area_id
;
495 route
->path
.origin
.type
= lsa
->header
->type
;
496 route
->path
.origin
.id
= lsa
->header
->id
;
497 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
498 route
->path
.prefix_options
= external
->prefix
.prefix_options
;
499 memcpy(&route
->path
.ls_prefix
, &asbr_id
, sizeof(struct prefix
));
501 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
502 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
503 route
->path
.metric_type
= 2;
504 route
->path
.cost
= asbr_entry
->path
.cost
;
505 route
->path
.u
.cost_e2
= OSPF6_ASBR_METRIC(external
);
507 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
508 route
->path
.metric_type
= 1;
510 asbr_entry
->path
.cost
+ OSPF6_ASBR_METRIC(external
);
511 route
->path
.u
.cost_e2
= 0;
514 route
->path
.tag
= ospf6_as_external_lsa_get_tag(lsa
);
516 ospf6_route_copy_nexthops(route
, asbr_entry
);
518 path
= ospf6_path_dup(&route
->path
);
519 ospf6_copy_nexthops(path
->nh_list
, asbr_entry
->nh_list
);
520 listnode_add_sort(route
->paths
, path
);
523 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
525 "%s: AS-External %u route add %pFX cost %u(%u) nh %u",
527 (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
) ? 1 : 2,
528 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
529 listcount(route
->nh_list
));
531 old
= ospf6_route_lookup(&route
->prefix
, ospf6
->route_table
);
533 /* Add the new route to ospf6 instance route table. */
534 ospf6_route_add(route
, ospf6
->route_table
, ospf6
);
537 * ECMP: Keep new equal preference path in current
538 * route's path list, update zebra with new effective
539 * list along with addition of ECMP path.
541 ospf6_asbr_update_route_ecmp_path(old
, route
, ospf6
);
545 void ospf6_asbr_lsa_remove(struct ospf6_lsa
*lsa
,
546 struct ospf6_route
*asbr_entry
)
548 struct ospf6_as_external_lsa
*external
;
549 struct prefix prefix
;
550 struct ospf6_route
*route
, *nroute
, *route_to_del
;
551 struct ospf6_area
*oa
= NULL
;
554 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
557 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
558 zlog_debug("Withdraw AS-External route for %s", lsa
->name
);
560 ospf6
= ospf6_get_by_lsdb(lsa
);
561 if (ospf6_is_router_abr(ospf6
))
562 oa
= ospf6
->backbone
;
564 oa
= listgetdata(listhead(ospf6
->area_list
));
569 if (lsa
->header
->adv_router
== oa
->ospf6
->router_id
) {
570 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
571 zlog_debug("Ignore self-originated AS-External-LSA");
575 route_to_del
= ospf6_route_create();
576 route_to_del
->type
= OSPF6_DEST_TYPE_NETWORK
;
577 route_to_del
->prefix
.family
= AF_INET6
;
578 route_to_del
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
579 ospf6_prefix_in6_addr(&route_to_del
->prefix
.u
.prefix6
, external
,
582 route_to_del
->path
.origin
.type
= lsa
->header
->type
;
583 route_to_del
->path
.origin
.id
= lsa
->header
->id
;
584 route_to_del
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
587 route_to_del
->path
.area_id
= asbr_entry
->path
.area_id
;
588 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
589 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
590 route_to_del
->path
.metric_type
= 2;
591 route_to_del
->path
.cost
= asbr_entry
->path
.cost
;
592 route_to_del
->path
.u
.cost_e2
=
593 OSPF6_ASBR_METRIC(external
);
595 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
596 route_to_del
->path
.metric_type
= 1;
597 route_to_del
->path
.cost
= asbr_entry
->path
.cost
598 + OSPF6_ASBR_METRIC(external
);
599 route_to_del
->path
.u
.cost_e2
= 0;
603 memset(&prefix
, 0, sizeof(struct prefix
));
604 prefix
.family
= AF_INET6
;
605 prefix
.prefixlen
= external
->prefix
.prefix_length
;
606 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, external
, &external
->prefix
);
608 route
= ospf6_route_lookup(&prefix
, oa
->ospf6
->route_table
);
610 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
611 zlog_debug("AS-External route %pFX not found", &prefix
);
614 ospf6_route_delete(route_to_del
);
618 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
620 "%s: Current route %pFX cost %u e2 %u, route to del cost %u e2 %u",
621 __func__
, &prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
622 route_to_del
->path
.cost
, route_to_del
->path
.u
.cost_e2
);
625 for (ospf6_route_lock(route
);
626 route
&& ospf6_route_is_prefix(&prefix
, route
); route
= nroute
) {
627 nroute
= ospf6_route_next(route
);
629 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
)
632 /* Route has multiple ECMP paths, remove matching
633 * path. Update current route's effective nh list
634 * after removal of one of the path.
636 if (listcount(route
->paths
) > 1) {
637 struct listnode
*anode
, *anext
;
638 struct listnode
*nnode
, *rnode
, *rnext
;
639 struct ospf6_nexthop
*nh
, *rnh
;
640 struct ospf6_path
*o_path
;
641 bool nh_updated
= false;
643 /* Iterate all paths of route to find maching with LSA
644 * remove from route path list. If route->path is same,
645 * replace from paths list.
647 for (ALL_LIST_ELEMENTS(route
->paths
, anode
, anext
,
649 if ((o_path
->origin
.type
!= lsa
->header
->type
)
650 || (o_path
->origin
.adv_router
651 != lsa
->header
->adv_router
)
652 || (o_path
->origin
.id
!= lsa
->header
->id
))
655 /* Compare LSA cost with current
659 && (o_path
->cost
!= route_to_del
->path
.cost
661 != route_to_del
->path
.u
663 if (IS_OSPF6_DEBUG_EXAMIN(
666 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
675 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
677 "%s: route %pFX path found with cost %u nh %u to remove.",
678 __func__
, &prefix
, route
->path
.cost
,
679 listcount(o_path
->nh_list
));
682 /* Remove found path's nh_list from
683 * the route's nh_list.
685 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
,
687 for (ALL_LIST_ELEMENTS(route
->nh_list
,
690 if (!ospf6_nexthop_is_same(rnh
,
693 listnode_delete(route
->nh_list
,
695 ospf6_nexthop_delete(rnh
);
698 /* Delete the path from route's path list */
699 listnode_delete(route
->paths
, o_path
);
700 ospf6_path_free(o_path
);
705 /* Iterate all paths and merge nexthop,
706 * unlesss any of the nexthop similar to
707 * ones deleted as part of path deletion.
710 for (ALL_LIST_ELEMENTS(route
->paths
, anode
,
712 ospf6_merge_nexthops(route
->nh_list
,
716 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
718 "%s: AS-External %u route %pFX update paths %u nh %u",
721 == OSPF6_PATH_TYPE_EXTERNAL1
)
724 &route
->prefix
, listcount(route
->paths
),
725 route
->nh_list
? listcount(
730 if (listcount(route
->paths
)) {
731 /* Update RIB/FIB with effective
734 if (oa
->ospf6
->route_table
->hook_add
)
735 (*oa
->ospf6
->route_table
739 /* route's primary path is similar
740 * to LSA, replace route's primary
741 * path with route's paths list head.
743 if ((route
->path
.origin
.id
==
745 (route
->path
.origin
.adv_router
746 == lsa
->header
->adv_router
)) {
747 struct ospf6_path
*h_path
;
749 h_path
= (struct ospf6_path
*)
751 listhead(route
->paths
));
752 route
->path
.origin
.type
=
754 route
->path
.origin
.id
=
756 route
->path
.origin
.adv_router
=
757 h_path
->origin
.adv_router
;
761 route
, oa
->ospf6
->route_table
,
768 /* Compare LSA origin and cost with current route info.
769 * if any check fails skip del this route node.
772 && (!ospf6_route_is_same_origin(route
, route_to_del
)
773 || (route
->path
.type
!= route_to_del
->path
.type
)
774 || (route
->path
.cost
!= route_to_del
->path
.cost
)
775 || (route
->path
.u
.cost_e2
776 != route_to_del
->path
.u
.cost_e2
))) {
777 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
779 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
780 __func__
, &prefix
, route
->path
.cost
,
781 route_to_del
->path
.cost
);
786 if ((route
->path
.origin
.type
!= lsa
->header
->type
)
787 || (route
->path
.origin
.adv_router
788 != lsa
->header
->adv_router
)
789 || (route
->path
.origin
.id
!= lsa
->header
->id
))
792 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
794 "%s: AS-External %u route remove %pFX cost %u(%u) nh %u",
796 route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
799 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
800 listcount(route
->nh_list
));
802 ospf6_route_remove(route
, oa
->ospf6
->route_table
, oa
->ospf6
);
805 ospf6_route_unlock(route
);
807 ospf6_route_delete(route_to_del
);
810 void ospf6_asbr_lsentry_add(struct ospf6_route
*asbr_entry
, struct ospf6
*ospf6
)
812 struct ospf6_lsa
*lsa
;
816 if (!CHECK_FLAG(asbr_entry
->flag
, OSPF6_ROUTE_BEST
)) {
818 inet_ntop(AF_INET
, &ADV_ROUTER_IN_PREFIX(&asbr_entry
->prefix
),
820 zlog_info("ignore non-best path: lsentry %s add", buf
);
824 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
825 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
826 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
)) {
827 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
828 ospf6_asbr_lsa_add(lsa
, ospf6
);
832 void ospf6_asbr_lsentry_remove(struct ospf6_route
*asbr_entry
,
835 struct ospf6_lsa
*lsa
;
839 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
840 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
841 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
))
842 ospf6_asbr_lsa_remove(lsa
, asbr_entry
);
846 /* redistribute function */
848 static void ospf6_asbr_routemap_set(int type
, const char *mapname
,
851 struct ospf6
*ospf6
= NULL
;
853 ospf6
= ospf6_lookup_by_vrf_id(vrf_id
);
858 if (ospf6
->rmap
[type
].name
) {
859 route_map_counter_decrement(ospf6
->rmap
[type
].map
);
860 free(ospf6
->rmap
[type
].name
);
862 ospf6
->rmap
[type
].name
= strdup(mapname
);
863 ospf6
->rmap
[type
].map
= route_map_lookup_by_name(mapname
);
864 route_map_counter_increment(ospf6
->rmap
[type
].map
);
867 static void ospf6_asbr_routemap_unset(int type
, struct ospf6
*ospf6
)
869 if (ospf6
->rmap
[type
].name
)
870 free(ospf6
->rmap
[type
].name
);
872 route_map_counter_decrement(ospf6
->rmap
[type
].map
);
874 ospf6
->rmap
[type
].name
= NULL
;
875 ospf6
->rmap
[type
].map
= NULL
;
878 static int ospf6_asbr_routemap_update_timer(struct thread
*thread
)
884 arg
= THREAD_ARG(thread
);
885 ospf6
= (struct ospf6
*)arg
[0];
886 arg_type
= (int)(intptr_t)arg
[1];
888 ospf6
->t_distribute_update
= NULL
;
890 if (ospf6
->rmap
[arg_type
].name
)
891 ospf6
->rmap
[arg_type
].map
=
892 route_map_lookup_by_name(ospf6
->rmap
[arg_type
].name
);
893 if (ospf6
->rmap
[arg_type
].map
) {
894 if (IS_OSPF6_DEBUG_ASBR
)
895 zlog_debug("%s: route-map %s update, reset redist %s",
896 __func__
, ospf6
->rmap
[arg_type
].name
,
897 ZROUTE_NAME(arg_type
));
899 ospf6_zebra_no_redistribute(arg_type
, ospf6
->vrf_id
);
900 ospf6_zebra_redistribute(arg_type
, ospf6
->vrf_id
);
903 XFREE(MTYPE_OSPF6_DIST_ARGS
, arg
);
907 void ospf6_asbr_distribute_list_update(int type
, struct ospf6
*ospf6
)
911 if (ospf6
->t_distribute_update
)
914 args
= XCALLOC(MTYPE_OSPF6_DIST_ARGS
, sizeof(void *) * 2);
917 args
[1] = (void *)((ptrdiff_t)type
);
919 if (IS_OSPF6_DEBUG_ASBR
)
920 zlog_debug("%s: trigger redistribute %s reset thread", __func__
,
923 ospf6
->t_distribute_update
= NULL
;
924 thread_add_timer_msec(master
, ospf6_asbr_routemap_update_timer
, args
,
925 OSPF_MIN_LS_INTERVAL
,
926 &ospf6
->t_distribute_update
);
929 static void ospf6_asbr_routemap_update(const char *mapname
)
932 struct listnode
*node
, *nnode
;
933 struct ospf6
*ospf6
= NULL
;
938 for (ALL_LIST_ELEMENTS(om6
->ospf6
, node
, nnode
, ospf6
)) {
939 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
940 if (ospf6
->rmap
[type
].name
== NULL
)
942 ospf6
->rmap
[type
].map
= route_map_lookup_by_name(
943 ospf6
->rmap
[type
].name
);
945 if (mapname
== NULL
|| strcmp(ospf6
->rmap
[type
].name
, mapname
))
947 if (ospf6
->rmap
[type
].map
) {
948 if (IS_OSPF6_DEBUG_ASBR
)
950 "%s: route-map %s update, reset redist %s",
956 route_map_counter_increment(
957 ospf6
->rmap
[type
].map
);
959 ospf6_asbr_distribute_list_update(
963 * if the mapname matches a
964 * route-map on ospf6 but the
965 * map doesn't exist, it is
966 * being deleted. flush and then
969 if (IS_OSPF6_DEBUG_ASBR
)
971 "%s: route-map %s deleted, reset redist %s",
976 ospf6_asbr_redistribute_unset(
977 type
, ospf6
->vrf_id
);
978 ospf6_asbr_routemap_set(
981 ospf6_asbr_redistribute_set(
982 type
, ospf6
->vrf_id
);
988 static void ospf6_asbr_routemap_event(const char *name
)
991 struct listnode
*node
, *nnode
;
996 for (ALL_LIST_ELEMENTS(om6
->ospf6
, node
, nnode
, ospf6
)) {
997 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
998 if ((ospf6
->rmap
[type
].name
)
999 && (strcmp(ospf6
->rmap
[type
].name
, name
) == 0))
1000 ospf6_asbr_distribute_list_update(type
, ospf6
);
1005 int ospf6_asbr_is_asbr(struct ospf6
*o
)
1007 return o
->external_table
->count
;
1010 static void ospf6_asbr_redistribute_set(int type
, vrf_id_t vrf_id
)
1012 ospf6_zebra_redistribute(type
, vrf_id
);
1015 static void ospf6_asbr_redistribute_unset(int type
, vrf_id_t vrf_id
)
1017 struct ospf6_route
*route
;
1018 struct ospf6_external_info
*info
;
1019 struct ospf6
*ospf6
= NULL
;
1021 ospf6
= ospf6_lookup_by_vrf_id(vrf_id
);
1026 ospf6_zebra_no_redistribute(type
, vrf_id
);
1028 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1029 route
= ospf6_route_next(route
)) {
1030 info
= route
->route_option
;
1031 if (info
->type
!= type
)
1034 ospf6_asbr_redistribute_remove(info
->type
, 0, &route
->prefix
,
1038 ospf6_asbr_routemap_unset(type
, ospf6
);
1041 /* When an area is unstubified, flood all the external LSAs in the area */
1042 void ospf6_asbr_send_externals_to_area(struct ospf6_area
*oa
)
1044 struct ospf6_lsa
*lsa
, *lsanext
;
1046 for (ALL_LSDB(oa
->ospf6
->lsdb
, lsa
, lsanext
)) {
1047 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
) {
1048 zlog_debug("%s: Flooding AS-External LSA %s",
1049 __func__
, lsa
->name
);
1050 ospf6_flood_area(NULL
, lsa
, oa
);
1055 void ospf6_asbr_redistribute_add(int type
, ifindex_t ifindex
,
1056 struct prefix
*prefix
,
1057 unsigned int nexthop_num
,
1058 struct in6_addr
*nexthop
, route_tag_t tag
,
1059 struct ospf6
*ospf6
)
1061 route_map_result_t ret
;
1062 struct ospf6_route troute
;
1063 struct ospf6_external_info tinfo
;
1064 struct ospf6_route
*route
, *match
;
1065 struct ospf6_external_info
*info
;
1066 struct prefix prefix_id
;
1067 struct route_node
*node
;
1069 struct listnode
*lnode
, *lnnode
;
1070 struct ospf6_area
*oa
;
1072 if (!ospf6_zebra_is_redistribute(type
, ospf6
->vrf_id
))
1075 memset(&troute
, 0, sizeof(troute
));
1076 memset(&tinfo
, 0, sizeof(tinfo
));
1078 if (IS_OSPF6_DEBUG_ASBR
)
1079 zlog_debug("Redistribute %pFX (%s)", prefix
, ZROUTE_NAME(type
));
1081 /* if route-map was specified but not found, do not advertise */
1082 if (ospf6
->rmap
[type
].name
) {
1083 if (ospf6
->rmap
[type
].map
== NULL
)
1084 ospf6_asbr_routemap_update(NULL
);
1085 if (ospf6
->rmap
[type
].map
== NULL
) {
1087 "route-map \"%s\" not found, suppress redistributing",
1088 ospf6
->rmap
[type
].name
);
1093 /* apply route-map */
1094 if (ospf6
->rmap
[type
].map
) {
1095 troute
.route_option
= &tinfo
;
1096 tinfo
.ifindex
= ifindex
;
1099 ret
= route_map_apply(ospf6
->rmap
[type
].map
, prefix
, &troute
);
1100 if (ret
== RMAP_DENYMATCH
) {
1101 if (IS_OSPF6_DEBUG_ASBR
)
1102 zlog_debug("Denied by route-map \"%s\"",
1103 ospf6
->rmap
[type
].name
);
1104 ospf6_asbr_redistribute_remove(type
, ifindex
, prefix
,
1110 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1112 info
= match
->route_option
;
1113 /* copy result of route-map */
1114 if (ospf6
->rmap
[type
].map
) {
1115 if (troute
.path
.metric_type
)
1116 match
->path
.metric_type
=
1117 troute
.path
.metric_type
;
1118 if (troute
.path
.cost
)
1119 match
->path
.cost
= troute
.path
.cost
;
1120 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1121 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1122 sizeof(struct in6_addr
));
1123 info
->tag
= tinfo
.tag
;
1125 /* If there is no route-map, simply update the tag */
1131 if (nexthop_num
&& nexthop
)
1132 ospf6_route_add_nexthop(match
, ifindex
, nexthop
);
1134 ospf6_route_add_nexthop(match
, ifindex
, NULL
);
1136 /* create/update binding in external_id_table */
1137 prefix_id
.family
= AF_INET
;
1138 prefix_id
.prefixlen
= 32;
1139 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1140 node
= route_node_get(ospf6
->external_id_table
, &prefix_id
);
1143 if (IS_OSPF6_DEBUG_ASBR
) {
1144 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
,
1147 "Advertise as AS-External Id:%s prefix %pFX metric %u",
1148 ibuf
, prefix
, match
->path
.metric_type
);
1151 match
->path
.origin
.id
= htonl(info
->id
);
1152 ospf6_as_external_lsa_originate(match
, ospf6
);
1156 /* create new entry */
1157 route
= ospf6_route_create();
1158 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
1159 memcpy(&route
->prefix
, prefix
, sizeof(struct prefix
));
1161 info
= (struct ospf6_external_info
*)XCALLOC(
1162 MTYPE_OSPF6_EXTERNAL_INFO
, sizeof(struct ospf6_external_info
));
1163 route
->route_option
= info
;
1164 info
->id
= ospf6
->external_id
++;
1166 /* copy result of route-map */
1167 if (ospf6
->rmap
[type
].map
) {
1168 if (troute
.path
.metric_type
)
1169 route
->path
.metric_type
= troute
.path
.metric_type
;
1170 if (troute
.path
.cost
)
1171 route
->path
.cost
= troute
.path
.cost
;
1172 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1173 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1174 sizeof(struct in6_addr
));
1175 info
->tag
= tinfo
.tag
;
1177 /* If there is no route-map, simply set the tag */
1182 if (nexthop_num
&& nexthop
)
1183 ospf6_route_add_nexthop(route
, ifindex
, nexthop
);
1185 ospf6_route_add_nexthop(route
, ifindex
, NULL
);
1187 /* create/update binding in external_id_table */
1188 prefix_id
.family
= AF_INET
;
1189 prefix_id
.prefixlen
= 32;
1190 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1191 node
= route_node_get(ospf6
->external_id_table
, &prefix_id
);
1194 route
= ospf6_route_add(route
, ospf6
->external_table
, ospf6
);
1195 route
->route_option
= info
;
1197 if (IS_OSPF6_DEBUG_ASBR
) {
1198 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
, sizeof(ibuf
));
1200 "Advertise as AS-External Id:%s prefix %pFX metric %u",
1201 ibuf
, prefix
, route
->path
.metric_type
);
1204 route
->path
.origin
.id
= htonl(info
->id
);
1205 ospf6_as_external_lsa_originate(route
, ospf6
);
1207 /* Router-Bit (ASBR Flag) may have to be updated */
1208 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1209 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1212 void ospf6_asbr_redistribute_remove(int type
, ifindex_t ifindex
,
1213 struct prefix
*prefix
, struct ospf6
*ospf6
)
1215 struct ospf6_route
*match
;
1216 struct ospf6_external_info
*info
= NULL
;
1217 struct route_node
*node
;
1218 struct ospf6_lsa
*lsa
;
1219 struct prefix prefix_id
;
1221 struct listnode
*lnode
, *lnnode
;
1222 struct ospf6_area
*oa
;
1224 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1225 if (match
== NULL
) {
1226 if (IS_OSPF6_DEBUG_ASBR
)
1227 zlog_debug("No such route %pFX to withdraw", prefix
);
1231 info
= match
->route_option
;
1234 if (info
->type
!= type
) {
1235 if (IS_OSPF6_DEBUG_ASBR
)
1236 zlog_debug("Original protocol mismatch: %pFX", prefix
);
1240 if (IS_OSPF6_DEBUG_ASBR
) {
1241 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
, sizeof(ibuf
));
1242 zlog_debug("Withdraw %pFX (AS-External Id:%s)", prefix
, ibuf
);
1245 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
1246 htonl(info
->id
), ospf6
->router_id
, ospf6
->lsdb
);
1248 ospf6_lsa_purge(lsa
);
1250 /* remove binding in external_id_table */
1251 prefix_id
.family
= AF_INET
;
1252 prefix_id
.prefixlen
= 32;
1253 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1254 node
= route_node_lookup(ospf6
->external_id_table
, &prefix_id
);
1257 route_unlock_node(node
); /* to free the lookup lock */
1258 route_unlock_node(node
); /* to free the original lock */
1260 ospf6_route_remove(match
, ospf6
->external_table
, ospf6
);
1261 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
, info
);
1263 /* Router-Bit (ASBR Flag) may have to be updated */
1264 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1265 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1268 DEFUN (ospf6_redistribute
,
1269 ospf6_redistribute_cmd
,
1270 "redistribute " FRR_REDIST_STR_OSPF6D
,
1272 FRR_REDIST_HELP_STR_OSPF6D
)
1276 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1277 OSPF6_CMD_CHECK_RUNNING(ospf6
);
1278 char *proto
= argv
[argc
- 1]->text
;
1279 type
= proto_redistnum(AFI_IP6
, proto
);
1281 return CMD_WARNING_CONFIG_FAILED
;
1283 ospf6_asbr_redistribute_unset(type
, ospf6
->vrf_id
);
1284 ospf6_asbr_redistribute_set(type
, ospf6
->vrf_id
);
1288 DEFUN (ospf6_redistribute_routemap
,
1289 ospf6_redistribute_routemap_cmd
,
1290 "redistribute " FRR_REDIST_STR_OSPF6D
" route-map WORD",
1292 FRR_REDIST_HELP_STR_OSPF6D
1293 "Route map reference\n"
1296 int idx_protocol
= 1;
1300 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1301 OSPF6_CMD_CHECK_RUNNING(ospf6
);
1303 char *proto
= argv
[idx_protocol
]->text
;
1304 type
= proto_redistnum(AFI_IP6
, proto
);
1306 return CMD_WARNING_CONFIG_FAILED
;
1308 ospf6_asbr_redistribute_unset(type
, ospf6
->vrf_id
);
1309 ospf6_asbr_routemap_set(type
, argv
[idx_word
]->arg
, ospf6
->vrf_id
);
1310 ospf6_asbr_redistribute_set(type
, ospf6
->vrf_id
);
1314 DEFUN (no_ospf6_redistribute
,
1315 no_ospf6_redistribute_cmd
,
1316 "no redistribute " FRR_REDIST_STR_OSPF6D
" [route-map WORD]",
1319 FRR_REDIST_HELP_STR_OSPF6D
1320 "Route map reference\n"
1323 int idx_protocol
= 2;
1326 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1328 OSPF6_CMD_CHECK_RUNNING(ospf6
);
1330 char *proto
= argv
[idx_protocol
]->text
;
1331 type
= proto_redistnum(AFI_IP6
, proto
);
1333 return CMD_WARNING_CONFIG_FAILED
;
1335 ospf6_asbr_redistribute_unset(type
, ospf6
->vrf_id
);
1340 int ospf6_redistribute_config_write(struct vty
*vty
, struct ospf6
*ospf6
)
1344 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1345 if (type
== ZEBRA_ROUTE_OSPF6
)
1347 if (!ospf6_zebra_is_redistribute(type
, ospf6
->vrf_id
))
1350 if (ospf6
->rmap
[type
].name
)
1351 vty_out(vty
, " redistribute %s route-map %s\n",
1352 ZROUTE_NAME(type
), ospf6
->rmap
[type
].name
);
1354 vty_out(vty
, " redistribute %s\n", ZROUTE_NAME(type
));
1360 static void ospf6_redistribute_show_config(struct vty
*vty
, struct ospf6
*ospf6
,
1361 json_object
*json_array
,
1362 json_object
*json
, bool use_json
)
1365 int nroute
[ZEBRA_ROUTE_MAX
];
1367 struct ospf6_route
*route
;
1368 struct ospf6_external_info
*info
;
1369 json_object
*json_route
;
1372 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++)
1374 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1375 route
= ospf6_route_next(route
)) {
1376 info
= route
->route_option
;
1377 nroute
[info
->type
]++;
1382 json_route
= json_object_new_object();
1384 vty_out(vty
, "Redistributing External Routes from:\n");
1386 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1387 if (type
== ZEBRA_ROUTE_OSPF6
)
1389 if (!ospf6_zebra_is_redistribute(type
, ospf6
->vrf_id
))
1393 json_object_string_add(json_route
, "routeType",
1395 json_object_int_add(json_route
, "numberOfRoutes",
1397 json_object_boolean_add(json_route
,
1398 "routeMapNamePresent",
1399 ospf6
->rmap
[type
].name
);
1402 if (ospf6
->rmap
[type
].name
) {
1404 json_object_string_add(json_route
,
1406 ospf6
->rmap
[type
].name
);
1407 json_object_boolean_add(json_route
,
1409 ospf6
->rmap
[type
].map
);
1412 " %d: %s with route-map \"%s\"%s\n",
1413 nroute
[type
], ZROUTE_NAME(type
),
1414 ospf6
->rmap
[type
].name
,
1415 (ospf6
->rmap
[type
].map
1417 : " (not found !)"));
1420 vty_out(vty
, " %d: %s\n", nroute
[type
],
1425 json_object_array_add(json_array
, json_route
);
1428 json_object_object_add(json
, "redistributedRoutes", json_array
);
1429 json_object_int_add(json
, "totalRoutes", total
);
1431 vty_out(vty
, "Total %d routes\n", total
);
1435 /* Routemap Functions */
1436 static enum route_map_cmd_result_t
1437 ospf6_routemap_rule_match_address_prefixlist(void *rule
,
1438 const struct prefix
*prefix
,
1442 struct prefix_list
*plist
;
1444 plist
= prefix_list_lookup(AFI_IP6
, (char *)rule
);
1446 return RMAP_NOMATCH
;
1448 return (prefix_list_apply(plist
, prefix
) == PREFIX_DENY
? RMAP_NOMATCH
1453 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg
)
1455 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1458 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule
)
1460 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1463 static const struct route_map_rule_cmd
1464 ospf6_routemap_rule_match_address_prefixlist_cmd
= {
1465 "ipv6 address prefix-list",
1466 ospf6_routemap_rule_match_address_prefixlist
,
1467 ospf6_routemap_rule_match_address_prefixlist_compile
,
1468 ospf6_routemap_rule_match_address_prefixlist_free
,
1471 /* `match interface IFNAME' */
1472 /* Match function should return 1 if match is success else return
1474 static enum route_map_cmd_result_t
1475 ospf6_routemap_rule_match_interface(void *rule
, const struct prefix
*prefix
,
1478 struct interface
*ifp
;
1479 struct ospf6_external_info
*ei
;
1481 ei
= ((struct ospf6_route
*)object
)->route_option
;
1482 ifp
= if_lookup_by_name_all_vrf((char *)rule
);
1484 if (ifp
!= NULL
&& ei
->ifindex
== ifp
->ifindex
)
1487 return RMAP_NOMATCH
;
1490 /* Route map `interface' match statement. `arg' should be
1492 static void *ospf6_routemap_rule_match_interface_compile(const char *arg
)
1494 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1497 /* Free route map's compiled `interface' value. */
1498 static void ospf6_routemap_rule_match_interface_free(void *rule
)
1500 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1503 /* Route map commands for interface matching. */
1504 static const struct route_map_rule_cmd
1505 ospf6_routemap_rule_match_interface_cmd
= {
1507 ospf6_routemap_rule_match_interface
,
1508 ospf6_routemap_rule_match_interface_compile
,
1509 ospf6_routemap_rule_match_interface_free
1512 /* Match function for matching route tags */
1513 static enum route_map_cmd_result_t
1514 ospf6_routemap_rule_match_tag(void *rule
, const struct prefix
*p
, void *object
)
1516 route_tag_t
*tag
= rule
;
1517 struct ospf6_route
*route
= object
;
1518 struct ospf6_external_info
*info
= route
->route_option
;
1520 if (info
->tag
== *tag
)
1523 return RMAP_NOMATCH
;
1526 static const struct route_map_rule_cmd
1527 ospf6_routemap_rule_match_tag_cmd
= {
1529 ospf6_routemap_rule_match_tag
,
1530 route_map_rule_tag_compile
,
1531 route_map_rule_tag_free
,
1534 static enum route_map_cmd_result_t
1535 ospf6_routemap_rule_set_metric_type(void *rule
, const struct prefix
*prefix
,
1538 char *metric_type
= rule
;
1539 struct ospf6_route
*route
= object
;
1541 if (strcmp(metric_type
, "type-2") == 0)
1542 route
->path
.metric_type
= 2;
1544 route
->path
.metric_type
= 1;
1549 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg
)
1551 if (strcmp(arg
, "type-2") && strcmp(arg
, "type-1"))
1553 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1556 static void ospf6_routemap_rule_set_metric_type_free(void *rule
)
1558 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1561 static const struct route_map_rule_cmd
1562 ospf6_routemap_rule_set_metric_type_cmd
= {
1564 ospf6_routemap_rule_set_metric_type
,
1565 ospf6_routemap_rule_set_metric_type_compile
,
1566 ospf6_routemap_rule_set_metric_type_free
,
1569 static enum route_map_cmd_result_t
1570 ospf6_routemap_rule_set_metric(void *rule
, const struct prefix
*prefix
,
1573 char *metric
= rule
;
1574 struct ospf6_route
*route
= object
;
1576 route
->path
.cost
= atoi(metric
);
1580 static void *ospf6_routemap_rule_set_metric_compile(const char *arg
)
1584 metric
= strtoul(arg
, &endp
, 0);
1585 if (metric
> OSPF_LS_INFINITY
|| *endp
!= '\0')
1587 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1590 static void ospf6_routemap_rule_set_metric_free(void *rule
)
1592 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1595 static const struct route_map_rule_cmd
1596 ospf6_routemap_rule_set_metric_cmd
= {
1598 ospf6_routemap_rule_set_metric
,
1599 ospf6_routemap_rule_set_metric_compile
,
1600 ospf6_routemap_rule_set_metric_free
,
1603 static enum route_map_cmd_result_t
1604 ospf6_routemap_rule_set_forwarding(void *rule
, const struct prefix
*prefix
,
1607 char *forwarding
= rule
;
1608 struct ospf6_route
*route
= object
;
1609 struct ospf6_external_info
*info
= route
->route_option
;
1611 if (inet_pton(AF_INET6
, forwarding
, &info
->forwarding
) != 1) {
1612 memset(&info
->forwarding
, 0, sizeof(struct in6_addr
));
1619 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg
)
1622 if (inet_pton(AF_INET6
, arg
, &a
) != 1)
1624 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1627 static void ospf6_routemap_rule_set_forwarding_free(void *rule
)
1629 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1632 static const struct route_map_rule_cmd
1633 ospf6_routemap_rule_set_forwarding_cmd
= {
1634 "forwarding-address",
1635 ospf6_routemap_rule_set_forwarding
,
1636 ospf6_routemap_rule_set_forwarding_compile
,
1637 ospf6_routemap_rule_set_forwarding_free
,
1640 static enum route_map_cmd_result_t
1641 ospf6_routemap_rule_set_tag(void *rule
, const struct prefix
*p
, void *object
)
1643 route_tag_t
*tag
= rule
;
1644 struct ospf6_route
*route
= object
;
1645 struct ospf6_external_info
*info
= route
->route_option
;
1651 static const struct route_map_rule_cmd
1652 ospf6_routemap_rule_set_tag_cmd
= {
1654 ospf6_routemap_rule_set_tag
,
1655 route_map_rule_tag_compile
,
1656 route_map_rule_tag_free
,
1659 static int route_map_command_status(struct vty
*vty
, enum rmap_compile_rets ret
)
1662 case RMAP_RULE_MISSING
:
1663 vty_out(vty
, "OSPF6 Can't find rule.\n");
1664 return CMD_WARNING_CONFIG_FAILED
;
1665 case RMAP_COMPILE_ERROR
:
1666 vty_out(vty
, "OSPF6 Argument is malformed.\n");
1667 return CMD_WARNING_CONFIG_FAILED
;
1668 case RMAP_COMPILE_SUCCESS
:
1675 /* add "set metric-type" */
1676 DEFUN (ospf6_routemap_set_metric_type
,
1677 ospf6_routemap_set_metric_type_cmd
,
1678 "set metric-type <type-1|type-2>",
1681 "OSPF6 external type 1 metric\n"
1682 "OSPF6 external type 2 metric\n")
1684 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1685 int idx_external
= 2;
1686 enum rmap_compile_rets ret
= route_map_add_set(route_map_index
,
1688 argv
[idx_external
]->arg
);
1690 return route_map_command_status(vty
, ret
);
1693 /* delete "set metric-type" */
1694 DEFUN (ospf6_routemap_no_set_metric_type
,
1695 ospf6_routemap_no_set_metric_type_cmd
,
1696 "no set metric-type [<type-1|type-2>]",
1700 "OSPF6 external type 1 metric\n"
1701 "OSPF6 external type 2 metric\n")
1703 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1704 char *ext
= (argc
== 4) ? argv
[3]->text
: NULL
;
1705 enum rmap_compile_rets ret
= route_map_delete_set(route_map_index
,
1706 "metric-type", ext
);
1708 return route_map_command_status(vty
, ret
);
1711 /* add "set forwarding-address" */
1712 DEFUN (ospf6_routemap_set_forwarding
,
1713 ospf6_routemap_set_forwarding_cmd
,
1714 "set forwarding-address X:X::X:X",
1716 "Forwarding Address\n"
1719 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1721 enum rmap_compile_rets ret
= route_map_add_set(route_map_index
,
1722 "forwarding-address",
1723 argv
[idx_ipv6
]->arg
);
1725 return route_map_command_status(vty
, ret
);
1728 /* delete "set forwarding-address" */
1729 DEFUN (ospf6_routemap_no_set_forwarding
,
1730 ospf6_routemap_no_set_forwarding_cmd
,
1731 "no set forwarding-address X:X::X:X",
1734 "Forwarding Address\n"
1737 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1739 enum rmap_compile_rets ret
= route_map_delete_set(route_map_index
,
1740 "forwarding-address",
1741 argv
[idx_ipv6
]->arg
);
1743 return route_map_command_status(vty
, ret
);
1746 static void ospf6_routemap_init(void)
1750 route_map_add_hook(ospf6_asbr_routemap_update
);
1751 route_map_delete_hook(ospf6_asbr_routemap_update
);
1752 route_map_event_hook(ospf6_asbr_routemap_event
);
1754 route_map_set_metric_hook(generic_set_add
);
1755 route_map_no_set_metric_hook(generic_set_delete
);
1757 route_map_match_tag_hook(generic_match_add
);
1758 route_map_no_match_tag_hook(generic_match_delete
);
1760 route_map_match_ipv6_address_prefix_list_hook(generic_match_add
);
1761 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete
);
1763 route_map_match_interface_hook(generic_match_add
);
1764 route_map_no_match_interface_hook(generic_match_delete
);
1766 route_map_install_match(
1767 &ospf6_routemap_rule_match_address_prefixlist_cmd
);
1768 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd
);
1769 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd
);
1771 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd
);
1772 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd
);
1773 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd
);
1774 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd
);
1776 /* ASE Metric Type (e.g. Type-1/Type-2) */
1777 install_element(RMAP_NODE
, &ospf6_routemap_set_metric_type_cmd
);
1778 install_element(RMAP_NODE
, &ospf6_routemap_no_set_metric_type_cmd
);
1781 install_element(RMAP_NODE
, &ospf6_routemap_set_forwarding_cmd
);
1782 install_element(RMAP_NODE
, &ospf6_routemap_no_set_forwarding_cmd
);
1786 /* Display functions */
1787 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1788 char *buf
, int buflen
,
1791 struct ospf6_as_external_lsa
*external
;
1792 struct in6_addr in6
;
1793 int prefix_length
= 0;
1796 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1800 ospf6_prefix_in6_addr(&in6
, external
,
1802 prefix_length
= external
->prefix
.prefix_length
;
1804 in6
= *((struct in6_addr
1805 *)((caddr_t
)external
1807 ospf6_as_external_lsa
)
1808 + OSPF6_PREFIX_SPACE(
1813 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
1815 sprintf(&buf
[strlen(buf
)], "/%d",
1822 static int ospf6_as_external_lsa_show(struct vty
*vty
, struct ospf6_lsa
*lsa
)
1824 struct ospf6_as_external_lsa
*external
;
1827 assert(lsa
->header
);
1828 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1832 snprintf(buf
, sizeof(buf
), "%c%c%c",
1833 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
) ? 'E'
1835 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
) ? 'F'
1837 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
) ? 'T'
1840 vty_out(vty
, " Bits: %s\n", buf
);
1841 vty_out(vty
, " Metric: %5lu\n",
1842 (unsigned long)OSPF6_ASBR_METRIC(external
));
1844 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
, buf
,
1846 vty_out(vty
, " Prefix Options: %s\n", buf
);
1848 vty_out(vty
, " Referenced LSType: %d\n",
1849 ntohs(external
->prefix
.prefix_refer_lstype
));
1851 vty_out(vty
, " Prefix: %s\n",
1852 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
, sizeof(buf
), 0));
1854 /* Forwarding-Address */
1855 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
1856 vty_out(vty
, " Forwarding-Address: %s\n",
1857 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
,
1862 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
1863 vty_out(vty
, " Tag: %" ROUTE_TAG_PRI
"\n",
1864 ospf6_as_external_lsa_get_tag(lsa
));
1870 static void ospf6_asbr_external_route_show(struct vty
*vty
,
1871 struct ospf6_route
*route
,
1872 json_object
*json_array
,
1875 struct ospf6_external_info
*info
= route
->route_option
;
1876 char prefix
[PREFIX2STR_BUFFER
], id
[16], forwarding
[64];
1878 json_object
*json_route
;
1881 prefix2str(&route
->prefix
, prefix
, sizeof(prefix
));
1882 tmp_id
= ntohl(info
->id
);
1883 inet_ntop(AF_INET
, &tmp_id
, id
, sizeof(id
));
1884 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
1885 inet_ntop(AF_INET6
, &info
->forwarding
, forwarding
,
1886 sizeof(forwarding
));
1888 snprintf(forwarding
, sizeof(forwarding
), ":: (ifindex %d)",
1889 ospf6_route_get_first_nh_index(route
));
1892 json_route
= json_object_new_object();
1893 snprintf(route_type
, sizeof(route_type
), "%c",
1894 zebra_route_char(info
->type
));
1895 json_object_string_add(json_route
, "routeType", route_type
);
1896 json_object_string_add(json_route
, "destination", prefix
);
1897 json_object_string_add(json_route
, "id", id
);
1898 json_object_int_add(json_route
, "metricType",
1899 route
->path
.metric_type
);
1900 json_object_int_add(
1901 json_route
, "routeCost",
1902 (unsigned long)(route
->path
.metric_type
== 2
1903 ? route
->path
.u
.cost_e2
1904 : route
->path
.cost
));
1905 json_object_string_add(json_route
, "forwarding", forwarding
);
1907 json_object_array_add(json_array
, json_route
);
1910 vty_out(vty
, "%c %-32pFX %-15s type-%d %5lu %s\n",
1911 zebra_route_char(info
->type
), &route
->prefix
, id
,
1912 route
->path
.metric_type
,
1913 (unsigned long)(route
->path
.metric_type
== 2
1914 ? route
->path
.u
.cost_e2
1915 : route
->path
.cost
),
1919 DEFUN (show_ipv6_ospf6_redistribute
,
1920 show_ipv6_ospf6_redistribute_cmd
,
1921 "show ipv6 ospf6 redistribute [json]",
1925 "redistributing External information\n"
1928 struct ospf6_route
*route
;
1929 struct ospf6
*ospf6
= NULL
;
1930 json_object
*json
= NULL
;
1931 bool uj
= use_json(argc
, argv
);
1932 json_object
*json_array_routes
= NULL
;
1933 json_object
*json_array_redistribute
= NULL
;
1935 ospf6
= ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME
);
1936 OSPF6_CMD_CHECK_RUNNING(ospf6
);
1939 json
= json_object_new_object();
1940 json_array_routes
= json_object_new_array();
1941 json_array_redistribute
= json_object_new_array();
1943 ospf6_redistribute_show_config(vty
, ospf6
, json_array_redistribute
,
1946 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1947 route
= ospf6_route_next(route
)) {
1948 ospf6_asbr_external_route_show(vty
, route
, json_array_routes
,
1953 json_object_object_add(json
, "routes", json_array_routes
);
1954 vty_out(vty
, "%s\n",
1955 json_object_to_json_string_ext(
1956 json
, JSON_C_TO_STRING_PRETTY
));
1957 json_object_free(json
);
1962 static struct ospf6_lsa_handler as_external_handler
= {
1963 .lh_type
= OSPF6_LSTYPE_AS_EXTERNAL
,
1964 .lh_name
= "AS-External",
1965 .lh_short_name
= "ASE",
1966 .lh_show
= ospf6_as_external_lsa_show
,
1967 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
1970 void ospf6_asbr_init(void)
1972 ospf6_routemap_init();
1974 ospf6_install_lsa_handler(&as_external_handler
);
1976 install_element(VIEW_NODE
, &show_ipv6_ospf6_redistribute_cmd
);
1978 install_element(OSPF6_NODE
, &ospf6_redistribute_cmd
);
1979 install_element(OSPF6_NODE
, &ospf6_redistribute_routemap_cmd
);
1980 install_element(OSPF6_NODE
, &no_ospf6_redistribute_cmd
);
1983 void ospf6_asbr_redistribute_reset(vrf_id_t vrf_id
)
1987 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1988 if (type
== ZEBRA_ROUTE_OSPF6
)
1990 if (ospf6_zebra_is_redistribute(type
, vrf_id
))
1991 ospf6_asbr_redistribute_unset(type
, vrf_id
);
1995 void ospf6_asbr_terminate(void)
1997 /* Cleanup route maps */
2001 DEFUN (debug_ospf6_asbr
,
2002 debug_ospf6_asbr_cmd
,
2006 "Debug OSPFv3 ASBR function\n"
2009 OSPF6_DEBUG_ASBR_ON();
2013 DEFUN (no_debug_ospf6_asbr
,
2014 no_debug_ospf6_asbr_cmd
,
2015 "no debug ospf6 asbr",
2019 "Debug OSPFv3 ASBR function\n"
2022 OSPF6_DEBUG_ASBR_OFF();
2026 int config_write_ospf6_debug_asbr(struct vty
*vty
)
2028 if (IS_OSPF6_DEBUG_ASBR
)
2029 vty_out(vty
, "debug ospf6 asbr\n");
2033 void install_element_ospf6_debug_asbr(void)
2035 install_element(ENABLE_NODE
, &debug_ospf6_asbr_cmd
);
2036 install_element(ENABLE_NODE
, &no_debug_ospf6_asbr_cmd
);
2037 install_element(CONFIG_NODE
, &debug_ospf6_asbr_cmd
);
2038 install_element(CONFIG_NODE
, &no_debug_ospf6_asbr_cmd
);