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_intra.h"
47 #include "ospf6_flood.h"
50 static void ospf6_asbr_redistribute_set(int type
, vrf_id_t vrf_id
);
51 static void ospf6_asbr_redistribute_unset(int type
, vrf_id_t vrf_id
);
53 unsigned char conf_debug_ospf6_asbr
= 0;
55 #define ZROUTE_NAME(x) zebra_route_string(x)
57 /* AS External LSA origination */
58 static void ospf6_as_external_lsa_originate(struct ospf6_route
*route
)
60 char buffer
[OSPF6_MAX_LSASIZE
];
61 struct ospf6_lsa_header
*lsa_header
;
62 struct ospf6_lsa
*lsa
;
63 struct ospf6_external_info
*info
= route
->route_option
;
65 struct ospf6_as_external_lsa
*as_external_lsa
;
66 char buf
[PREFIX2STR_BUFFER
];
69 if (IS_OSPF6_DEBUG_ASBR
|| IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL
)) {
70 prefix2str(&route
->prefix
, buf
, sizeof(buf
));
71 zlog_debug("Originate AS-External-LSA for %s", buf
);
75 memset(buffer
, 0, sizeof(buffer
));
76 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
77 as_external_lsa
= (struct ospf6_as_external_lsa
78 *)((caddr_t
)lsa_header
79 + sizeof(struct ospf6_lsa_header
));
80 p
= (caddr_t
)((caddr_t
)as_external_lsa
81 + sizeof(struct ospf6_as_external_lsa
));
83 /* Fill AS-External-LSA */
85 if (route
->path
.metric_type
== 2)
86 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
88 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
90 /* forwarding address */
91 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
92 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
94 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
96 /* external route tag */
98 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
100 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
103 OSPF6_ASBR_METRIC_SET(as_external_lsa
, route
->path
.cost
);
106 as_external_lsa
->prefix
.prefix_length
= route
->prefix
.prefixlen
;
109 as_external_lsa
->prefix
.prefix_options
= route
->path
.prefix_options
;
111 /* don't use refer LS-type */
112 as_external_lsa
->prefix
.prefix_refer_lstype
= htons(0);
115 memcpy(p
, &route
->prefix
.u
.prefix6
,
116 OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
));
117 ospf6_prefix_apply_mask(&as_external_lsa
->prefix
);
118 p
+= OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
);
120 /* Forwarding address */
121 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
122 memcpy(p
, &info
->forwarding
, sizeof(struct in6_addr
));
123 p
+= sizeof(struct in6_addr
);
126 /* External Route Tag */
127 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
128 route_tag_t network_order
= htonl(info
->tag
);
130 memcpy(p
, &network_order
, sizeof(network_order
));
131 p
+= sizeof(network_order
);
134 /* Fill LSA Header */
136 lsa_header
->type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
137 lsa_header
->id
= route
->path
.origin
.id
;
138 lsa_header
->adv_router
= ospf6
->router_id
;
140 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
141 lsa_header
->adv_router
, ospf6
->lsdb
);
142 lsa_header
->length
= htons((caddr_t
)p
- (caddr_t
)lsa_header
);
145 ospf6_lsa_checksum(lsa_header
);
148 lsa
= ospf6_lsa_create(lsa_header
);
151 ospf6_lsa_originate_process(lsa
, ospf6
);
154 int ospf6_orig_as_external_lsa(struct thread
*thread
)
156 struct ospf6_interface
*oi
;
157 struct ospf6_lsa
*lsa
;
158 uint32_t type
, adv_router
;
160 oi
= (struct ospf6_interface
*)THREAD_ARG(thread
);
161 oi
->thread_as_extern_lsa
= NULL
;
163 if (oi
->state
== OSPF6_INTERFACE_DOWN
)
166 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
167 adv_router
= oi
->area
->ospf6
->router_id
;
168 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, adv_router
, lsa
)) {
169 if (IS_OSPF6_DEBUG_ASBR
)
171 "%s: Send update of AS-External LSA %s seq 0x%x",
173 ntohl(lsa
->header
->seqnum
));
175 ospf6_flood_interface(NULL
, lsa
, oi
);
181 static route_tag_t
ospf6_as_external_lsa_get_tag(struct ospf6_lsa
*lsa
)
183 struct ospf6_as_external_lsa
*external
;
184 ptrdiff_t tag_offset
;
185 route_tag_t network_order
;
190 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
193 if (!CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
196 tag_offset
= sizeof(*external
)
197 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
198 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
199 tag_offset
+= sizeof(struct in6_addr
);
201 memcpy(&network_order
, (caddr_t
)external
+ tag_offset
,
202 sizeof(network_order
));
203 return ntohl(network_order
);
206 void ospf6_asbr_update_route_ecmp_path(struct ospf6_route
*old
,
207 struct ospf6_route
*route
)
209 struct ospf6_route
*old_route
;
210 struct ospf6_path
*ecmp_path
, *o_path
= NULL
;
211 struct listnode
*anode
, *anext
;
212 struct listnode
*nnode
, *rnode
, *rnext
;
213 struct ospf6_nexthop
*nh
, *rnh
;
214 char buf
[PREFIX2STR_BUFFER
];
215 bool route_found
= false;
217 /* check for old entry match with new route origin,
220 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
221 bool route_updated
= false;
223 if (!ospf6_route_is_same(old_route
, route
)
224 || (old_route
->path
.type
!= route
->path
.type
))
227 /* Current and New route has same origin,
230 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
, anext
,
232 /* Check old route path and route has same
235 if (o_path
->area_id
!= route
->path
.area_id
236 || (memcmp(&(o_path
)->origin
, &(route
)->path
.origin
,
237 sizeof(struct ospf6_ls_origin
))
241 /* Cost is not same then delete current path */
242 if ((o_path
->cost
== route
->path
.cost
)
243 && (o_path
->u
.cost_e2
== route
->path
.u
.cost_e2
))
246 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
248 "%s: route %pFX cost old %u new %u is not same, replace route",
249 __func__
, &old_route
->prefix
, o_path
->cost
,
253 /* Remove selected current rout path's nh from
256 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
257 for (ALL_LIST_ELEMENTS(old_route
->nh_list
,
258 rnode
, rnext
, rnh
)) {
259 if (!ospf6_nexthop_is_same(rnh
, nh
))
261 listnode_delete(old_route
->nh_list
,
263 ospf6_nexthop_delete(rnh
);
267 listnode_delete(old_route
->paths
, o_path
);
268 ospf6_path_free(o_path
);
269 route_updated
= true;
271 /* Current route's path (adv_router info) is similar
272 * to route being added.
273 * Replace current route's path with paths list head.
274 * Update FIB with effective NHs.
276 if (listcount(old_route
->paths
)) {
277 for (ALL_LIST_ELEMENTS(old_route
->paths
,
278 anode
, anext
, o_path
)) {
279 ospf6_merge_nexthops(
283 /* Update RIB/FIB with effective
286 if (ospf6
->route_table
->hook_add
)
287 (*ospf6
->route_table
->hook_add
)
290 if (old_route
->path
.origin
.id
291 == route
->path
.origin
.id
292 && old_route
->path
.origin
.adv_router
293 == route
->path
.origin
295 struct ospf6_path
*h_path
;
297 h_path
= (struct ospf6_path
*)
298 listgetdata(listhead(
300 old_route
->path
.origin
.type
=
302 old_route
->path
.origin
.id
=
304 old_route
->path
.origin
.adv_router
=
305 h_path
->origin
.adv_router
;
308 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
310 "%s: route %pFX old cost %u new cost %u, delete old entry.",
311 __func__
, &old_route
->prefix
,
312 old_route
->path
.cost
,
315 ospf6_route_remove(old_route
,
324 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
326 /* Current and New Route prefix or route type
327 * is not same skip this current node.
329 if (!ospf6_route_is_same(old_route
, route
)
330 || (old_route
->path
.type
!= route
->path
.type
))
333 /* Old Route and New Route have Equal Cost, Merge NHs */
334 if ((old_route
->path
.cost
== route
->path
.cost
)
335 && (old_route
->path
.u
.cost_e2
== route
->path
.u
.cost_e2
)) {
337 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
339 "%s: old route %pFX path cost %u e2 %u",
340 __func__
, &old_route
->prefix
,
341 old_route
->path
.cost
,
342 old_route
->path
.u
.cost_e2
);
345 /* check if this path exists already in
346 * route->paths list, if so, replace nh_list
349 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
351 if (o_path
->area_id
== route
->path
.area_id
352 && (memcmp(&(o_path
)->origin
,
353 &(route
)->path
.origin
,
354 sizeof(struct ospf6_ls_origin
))
358 /* If path is not found in old_route paths's list,
359 * add a new path to route paths list and merge
360 * nexthops in route->path->nh_list.
361 * Otherwise replace existing path's nh_list.
363 if (o_path
== NULL
) {
364 ecmp_path
= ospf6_path_dup(&route
->path
);
366 /* Add a nh_list to new ecmp path */
367 ospf6_copy_nexthops(ecmp_path
->nh_list
,
370 /* Add the new path to route's path list */
371 listnode_add_sort(old_route
->paths
, ecmp_path
);
373 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
374 prefix2str(&route
->prefix
, buf
,
377 "%s: route %s another path added with nh %u, effective paths %u nh %u",
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(
406 prefix2str(&old_route
->prefix
,
409 "%s: ls_prfix %s asbr_entry not found.",
414 ospf6_route_merge_nexthops(old_route
,
418 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
419 prefix2str(&route
->prefix
, buf
, sizeof(buf
));
421 "%s: route %s with effective paths %u nh %u",
424 ? listcount(old_route
->paths
)
427 ? listcount(old_route
->nh_list
)
432 if (ospf6
->route_table
->hook_add
)
433 (*ospf6
->route_table
->hook_add
)(old_route
);
435 /* Delete the new route its info added to existing
438 ospf6_route_delete(route
);
445 /* Add new route to existing node in ospf6 route table. */
446 ospf6_route_add(route
, ospf6
->route_table
);
450 void ospf6_asbr_lsa_add(struct ospf6_lsa
*lsa
)
452 struct ospf6_as_external_lsa
*external
;
453 struct prefix asbr_id
;
454 struct ospf6_route
*asbr_entry
, *route
, *old
;
455 struct ospf6_path
*path
;
456 char buf
[PREFIX2STR_BUFFER
];
458 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
461 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
462 zlog_debug("Calculate AS-External route for %s", lsa
->name
);
464 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
465 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
466 zlog_debug("Ignore self-originated AS-External-LSA");
470 if (OSPF6_ASBR_METRIC(external
) == OSPF_LS_INFINITY
) {
471 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
472 zlog_debug("Ignore LSA with LSInfinity Metric");
476 if (CHECK_FLAG(external
->prefix
.prefix_options
,
477 OSPF6_PREFIX_OPTION_NU
)) {
478 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
479 zlog_debug("Ignore LSA with NU bit set Metric");
483 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &asbr_id
);
484 asbr_entry
= ospf6_route_lookup(&asbr_id
, ospf6
->brouter_table
);
485 if (asbr_entry
== NULL
486 || !CHECK_FLAG(asbr_entry
->path
.router_bits
, OSPF6_ROUTER_BIT_E
)) {
487 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
488 prefix2str(&asbr_id
, buf
, sizeof(buf
));
489 zlog_debug("ASBR entry not found: %s", buf
);
494 route
= ospf6_route_create();
495 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
496 route
->prefix
.family
= AF_INET6
;
497 route
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
498 ospf6_prefix_in6_addr(&route
->prefix
.u
.prefix6
, external
,
501 route
->path
.area_id
= asbr_entry
->path
.area_id
;
502 route
->path
.origin
.type
= lsa
->header
->type
;
503 route
->path
.origin
.id
= lsa
->header
->id
;
504 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
505 route
->path
.prefix_options
= external
->prefix
.prefix_options
;
506 memcpy(&route
->path
.ls_prefix
, &asbr_id
, sizeof(struct prefix
));
508 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
509 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
510 route
->path
.metric_type
= 2;
511 route
->path
.cost
= asbr_entry
->path
.cost
;
512 route
->path
.u
.cost_e2
= OSPF6_ASBR_METRIC(external
);
514 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
515 route
->path
.metric_type
= 1;
517 asbr_entry
->path
.cost
+ OSPF6_ASBR_METRIC(external
);
518 route
->path
.u
.cost_e2
= 0;
521 route
->path
.tag
= ospf6_as_external_lsa_get_tag(lsa
);
523 ospf6_route_copy_nexthops(route
, asbr_entry
);
525 path
= ospf6_path_dup(&route
->path
);
526 ospf6_copy_nexthops(path
->nh_list
, asbr_entry
->nh_list
);
527 listnode_add_sort(route
->paths
, path
);
530 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
531 prefix2str(&route
->prefix
, buf
, sizeof(buf
));
532 zlog_debug("%s: AS-External %u route add %s cost %u(%u) nh %u",
534 (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
) ? 1
536 buf
, route
->path
.cost
, route
->path
.u
.cost_e2
,
537 listcount(route
->nh_list
));
540 old
= ospf6_route_lookup(&route
->prefix
, ospf6
->route_table
);
542 /* Add the new route to ospf6 instance route table. */
543 ospf6_route_add(route
, ospf6
->route_table
);
546 * ECMP: Keep new equal preference path in current
547 * route's path list, update zebra with new effective
548 * list along with addition of ECMP path.
550 ospf6_asbr_update_route_ecmp_path(old
, route
);
554 void ospf6_asbr_lsa_remove(struct ospf6_lsa
*lsa
,
555 struct ospf6_route
*asbr_entry
)
557 struct ospf6_as_external_lsa
*external
;
558 struct prefix prefix
;
559 struct ospf6_route
*route
, *nroute
, *route_to_del
;
561 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
564 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
565 zlog_debug("Withdraw AS-External route for %s", lsa
->name
);
567 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
568 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
569 zlog_debug("Ignore self-originated AS-External-LSA");
573 route_to_del
= ospf6_route_create();
574 route_to_del
->type
= OSPF6_DEST_TYPE_NETWORK
;
575 route_to_del
->prefix
.family
= AF_INET6
;
576 route_to_del
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
577 ospf6_prefix_in6_addr(&route_to_del
->prefix
.u
.prefix6
, external
,
580 route_to_del
->path
.origin
.type
= lsa
->header
->type
;
581 route_to_del
->path
.origin
.id
= lsa
->header
->id
;
582 route_to_del
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
585 route_to_del
->path
.area_id
= asbr_entry
->path
.area_id
;
586 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
587 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
588 route_to_del
->path
.metric_type
= 2;
589 route_to_del
->path
.cost
= asbr_entry
->path
.cost
;
590 route_to_del
->path
.u
.cost_e2
=
591 OSPF6_ASBR_METRIC(external
);
593 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
594 route_to_del
->path
.metric_type
= 1;
595 route_to_del
->path
.cost
= asbr_entry
->path
.cost
596 + OSPF6_ASBR_METRIC(external
);
597 route_to_del
->path
.u
.cost_e2
= 0;
601 memset(&prefix
, 0, sizeof(struct prefix
));
602 prefix
.family
= AF_INET6
;
603 prefix
.prefixlen
= external
->prefix
.prefix_length
;
604 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, external
, &external
->prefix
);
606 route
= ospf6_route_lookup(&prefix
, ospf6
->route_table
);
608 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
609 zlog_debug("AS-External route %pFX not found", &prefix
);
612 ospf6_route_delete(route_to_del
);
616 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
618 "%s: Current route %pFX cost %u e2 %u, route to del cost %u e2 %u",
619 __func__
, &prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
620 route_to_del
->path
.cost
, route_to_del
->path
.u
.cost_e2
);
623 for (ospf6_route_lock(route
);
624 route
&& ospf6_route_is_prefix(&prefix
, route
); route
= nroute
) {
625 nroute
= ospf6_route_next(route
);
627 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
)
630 /* Route has multiple ECMP paths, remove matching
631 * path. Update current route's effective nh list
632 * after removal of one of the path.
634 if (listcount(route
->paths
) > 1) {
635 struct listnode
*anode
, *anext
;
636 struct listnode
*nnode
, *rnode
, *rnext
;
637 struct ospf6_nexthop
*nh
, *rnh
;
638 struct ospf6_path
*o_path
;
639 bool nh_updated
= false;
641 /* Iterate all paths of route to find maching with LSA
642 * remove from route path list. If route->path is same,
643 * replace from paths list.
645 for (ALL_LIST_ELEMENTS(route
->paths
, anode
, anext
,
647 if ((o_path
->origin
.type
!= lsa
->header
->type
)
648 || (o_path
->origin
.adv_router
649 != lsa
->header
->adv_router
)
650 || (o_path
->origin
.id
!= lsa
->header
->id
))
653 /* Compare LSA cost with current
657 && (o_path
->cost
!= route_to_del
->path
.cost
659 != route_to_del
->path
.u
661 if (IS_OSPF6_DEBUG_EXAMIN(
664 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
673 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
675 "%s: route %pFX path found with cost %u nh %u to remove.",
676 __func__
, &prefix
, route
->path
.cost
,
677 listcount(o_path
->nh_list
));
680 /* Remove found path's nh_list from
681 * the route's nh_list.
683 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
,
685 for (ALL_LIST_ELEMENTS(route
->nh_list
,
688 if (!ospf6_nexthop_is_same(rnh
,
691 listnode_delete(route
->nh_list
,
693 ospf6_nexthop_delete(rnh
);
696 /* Delete the path from route's path list */
697 listnode_delete(route
->paths
, o_path
);
698 ospf6_path_free(o_path
);
703 /* Iterate all paths and merge nexthop,
704 * unlesss any of the nexthop similar to
705 * ones deleted as part of path deletion.
708 for (ALL_LIST_ELEMENTS(route
->paths
, anode
,
710 ospf6_merge_nexthops(route
->nh_list
,
714 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
716 "%s: AS-External %u route %pFX update paths %u nh %u",
719 == OSPF6_PATH_TYPE_EXTERNAL1
)
722 &route
->prefix
, listcount(route
->paths
),
723 route
->nh_list
? listcount(
728 if (listcount(route
->paths
)) {
729 /* Update RIB/FIB with effective
732 if (ospf6
->route_table
->hook_add
)
733 (*ospf6
->route_table
->hook_add
)
736 /* route's primary path is similar
737 * to LSA, replace route's primary
738 * path with route's paths list head.
740 if ((route
->path
.origin
.id
==
742 (route
->path
.origin
.adv_router
743 == lsa
->header
->adv_router
)) {
744 struct ospf6_path
*h_path
;
746 h_path
= (struct ospf6_path
*)
748 listhead(route
->paths
));
749 route
->path
.origin
.type
=
751 route
->path
.origin
.id
=
753 route
->path
.origin
.adv_router
=
754 h_path
->origin
.adv_router
;
757 ospf6_route_remove(route
,
764 /* Compare LSA origin and cost with current route info.
765 * if any check fails skip del this route node.
768 && (!ospf6_route_is_same_origin(route
, route_to_del
)
769 || (route
->path
.type
!= route_to_del
->path
.type
)
770 || (route
->path
.cost
!= route_to_del
->path
.cost
)
771 || (route
->path
.u
.cost_e2
772 != route_to_del
->path
.u
.cost_e2
))) {
773 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
775 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
776 __func__
, &prefix
, route
->path
.cost
,
777 route_to_del
->path
.cost
);
782 if ((route
->path
.origin
.type
!= lsa
->header
->type
)
783 || (route
->path
.origin
.adv_router
784 != lsa
->header
->adv_router
)
785 || (route
->path
.origin
.id
!= lsa
->header
->id
))
788 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
790 "%s: AS-External %u route remove %pFX cost %u(%u) nh %u",
792 route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
795 &route
->prefix
, route
->path
.cost
, route
->path
.u
.cost_e2
,
796 listcount(route
->nh_list
));
798 ospf6_route_remove(route
, ospf6
->route_table
);
801 ospf6_route_unlock(route
);
803 ospf6_route_delete(route_to_del
);
806 void ospf6_asbr_lsentry_add(struct ospf6_route
*asbr_entry
)
808 struct ospf6_lsa
*lsa
;
812 if (!CHECK_FLAG(asbr_entry
->flag
, OSPF6_ROUTE_BEST
)) {
814 inet_ntop(AF_INET
, &ADV_ROUTER_IN_PREFIX(&asbr_entry
->prefix
),
816 zlog_info("ignore non-best path: lsentry %s add", buf
);
820 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
821 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
822 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
)) {
823 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
824 ospf6_asbr_lsa_add(lsa
);
828 void ospf6_asbr_lsentry_remove(struct ospf6_route
*asbr_entry
)
830 struct ospf6_lsa
*lsa
;
834 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
835 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
836 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
))
837 ospf6_asbr_lsa_remove(lsa
, asbr_entry
);
841 /* redistribute function */
843 static void ospf6_asbr_routemap_set(int type
, const char *mapname
)
845 if (ospf6
->rmap
[type
].name
) {
846 route_map_counter_decrement(ospf6
->rmap
[type
].map
);
847 free(ospf6
->rmap
[type
].name
);
849 ospf6
->rmap
[type
].name
= strdup(mapname
);
850 ospf6
->rmap
[type
].map
= route_map_lookup_by_name(mapname
);
851 route_map_counter_increment(ospf6
->rmap
[type
].map
);
854 static void ospf6_asbr_routemap_unset(int type
)
856 if (ospf6
->rmap
[type
].name
)
857 free(ospf6
->rmap
[type
].name
);
859 route_map_counter_decrement(ospf6
->rmap
[type
].map
);
861 ospf6
->rmap
[type
].name
= NULL
;
862 ospf6
->rmap
[type
].map
= NULL
;
865 static int ospf6_asbr_routemap_update_timer(struct thread
*thread
)
870 arg
= THREAD_ARG(thread
);
871 arg_type
= (int)(intptr_t)arg
[1];
873 ospf6
->t_distribute_update
= NULL
;
875 if (ospf6
->rmap
[arg_type
].name
)
876 ospf6
->rmap
[arg_type
].map
=
877 route_map_lookup_by_name(ospf6
->rmap
[arg_type
].name
);
878 if (ospf6
->rmap
[arg_type
].map
) {
879 if (IS_OSPF6_DEBUG_ASBR
)
880 zlog_debug("%s: route-map %s update, reset redist %s",
881 __func__
, ospf6
->rmap
[arg_type
].name
,
882 ZROUTE_NAME(arg_type
));
884 ospf6_zebra_no_redistribute(arg_type
, ospf6
->vrf_id
);
885 ospf6_zebra_redistribute(arg_type
, ospf6
->vrf_id
);
888 XFREE(MTYPE_OSPF6_DIST_ARGS
, arg
);
892 void ospf6_asbr_distribute_list_update(int type
)
896 if (ospf6
->t_distribute_update
)
899 args
= XCALLOC(MTYPE_OSPF6_DIST_ARGS
, sizeof(void *) * 2);
902 args
[1] = (void *)((ptrdiff_t)type
);
904 if (IS_OSPF6_DEBUG_ASBR
)
905 zlog_debug("%s: trigger redistribute %s reset thread", __func__
,
908 ospf6
->t_distribute_update
= NULL
;
909 thread_add_timer_msec(master
, ospf6_asbr_routemap_update_timer
, args
,
910 OSPF_MIN_LS_INTERVAL
,
911 &ospf6
->t_distribute_update
);
914 static void ospf6_asbr_routemap_update(const char *mapname
)
921 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
922 if (ospf6
->rmap
[type
].name
) {
923 ospf6
->rmap
[type
].map
= route_map_lookup_by_name(
924 ospf6
->rmap
[type
].name
);
927 && (strcmp(ospf6
->rmap
[type
].name
, mapname
) == 0)) {
928 if (ospf6
->rmap
[type
].map
) {
929 if (IS_OSPF6_DEBUG_ASBR
)
931 "%s: route-map %s update, reset redist %s",
935 route_map_counter_increment(
936 ospf6
->rmap
[type
].map
);
938 ospf6_asbr_distribute_list_update(type
);
941 * if the mapname matches a route-map on
942 * ospf6 but the map doesn't exist, it
943 * is being deleted. flush and then
946 if (IS_OSPF6_DEBUG_ASBR
)
948 "%s: route-map %s deleted, reset redist %s",
951 ospf6_asbr_redistribute_unset(
952 type
, ospf6
->vrf_id
);
953 ospf6_asbr_routemap_set(type
, mapname
);
954 ospf6_asbr_redistribute_set(
955 type
, ospf6
->vrf_id
);
959 ospf6
->rmap
[type
].map
= NULL
;
963 static void ospf6_asbr_routemap_event(const char *name
)
969 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
970 if ((ospf6
->rmap
[type
].name
)
971 && (strcmp(ospf6
->rmap
[type
].name
, name
) == 0)) {
972 ospf6_asbr_distribute_list_update(type
);
977 int ospf6_asbr_is_asbr(struct ospf6
*o
)
979 return o
->external_table
->count
;
982 static void ospf6_asbr_redistribute_set(int type
, vrf_id_t vrf_id
)
984 ospf6_zebra_redistribute(type
, vrf_id
);
987 static void ospf6_asbr_redistribute_unset(int type
, vrf_id_t vrf_id
)
989 struct ospf6_route
*route
;
990 struct ospf6_external_info
*info
;
992 ospf6_zebra_no_redistribute(type
, vrf_id
);
994 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
995 route
= ospf6_route_next(route
)) {
996 info
= route
->route_option
;
997 if (info
->type
!= type
)
1000 ospf6_asbr_redistribute_remove(info
->type
, 0, &route
->prefix
);
1003 ospf6_asbr_routemap_unset(type
);
1006 /* When an area is unstubified, flood all the external LSAs in the area */
1007 void ospf6_asbr_send_externals_to_area(struct ospf6_area
*oa
)
1009 struct ospf6_lsa
*lsa
;
1011 for (ALL_LSDB(oa
->ospf6
->lsdb
, lsa
)) {
1012 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
) {
1013 zlog_debug("%s: Flooding AS-External LSA %s",
1014 __func__
, lsa
->name
);
1015 ospf6_flood_area(NULL
, lsa
, oa
);
1020 void ospf6_asbr_redistribute_add(int type
, ifindex_t ifindex
,
1021 struct prefix
*prefix
,
1022 unsigned int nexthop_num
,
1023 struct in6_addr
*nexthop
, route_tag_t tag
)
1025 route_map_result_t ret
;
1026 struct ospf6_route troute
;
1027 struct ospf6_external_info tinfo
;
1028 struct ospf6_route
*route
, *match
;
1029 struct ospf6_external_info
*info
;
1030 struct prefix prefix_id
;
1031 struct route_node
*node
;
1032 char pbuf
[PREFIX2STR_BUFFER
], ibuf
[16];
1033 struct listnode
*lnode
, *lnnode
;
1034 struct ospf6_area
*oa
;
1036 if (!ospf6_zebra_is_redistribute(type
, ospf6
->vrf_id
))
1039 memset(&troute
, 0, sizeof(troute
));
1040 memset(&tinfo
, 0, sizeof(tinfo
));
1042 if (IS_OSPF6_DEBUG_ASBR
) {
1043 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1044 zlog_debug("Redistribute %s (%s)", pbuf
, ZROUTE_NAME(type
));
1047 /* if route-map was specified but not found, do not advertise */
1048 if (ospf6
->rmap
[type
].name
) {
1049 if (ospf6
->rmap
[type
].map
== NULL
)
1050 ospf6_asbr_routemap_update(NULL
);
1051 if (ospf6
->rmap
[type
].map
== NULL
) {
1053 "route-map \"%s\" not found, suppress redistributing",
1054 ospf6
->rmap
[type
].name
);
1059 /* apply route-map */
1060 if (ospf6
->rmap
[type
].map
) {
1061 troute
.route_option
= &tinfo
;
1062 tinfo
.ifindex
= ifindex
;
1065 ret
= route_map_apply(ospf6
->rmap
[type
].map
, prefix
, RMAP_OSPF6
,
1067 if (ret
== RMAP_DENYMATCH
) {
1068 if (IS_OSPF6_DEBUG_ASBR
)
1069 zlog_debug("Denied by route-map \"%s\"",
1070 ospf6
->rmap
[type
].name
);
1071 ospf6_asbr_redistribute_remove(type
, ifindex
, prefix
);
1076 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1078 info
= match
->route_option
;
1079 /* copy result of route-map */
1080 if (ospf6
->rmap
[type
].map
) {
1081 if (troute
.path
.metric_type
)
1082 match
->path
.metric_type
=
1083 troute
.path
.metric_type
;
1084 if (troute
.path
.cost
)
1085 match
->path
.cost
= troute
.path
.cost
;
1086 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1087 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1088 sizeof(struct in6_addr
));
1089 info
->tag
= tinfo
.tag
;
1091 /* If there is no route-map, simply update the tag */
1097 if (nexthop_num
&& nexthop
)
1098 ospf6_route_add_nexthop(match
, ifindex
, nexthop
);
1100 ospf6_route_add_nexthop(match
, ifindex
, NULL
);
1102 /* create/update binding in external_id_table */
1103 prefix_id
.family
= AF_INET
;
1104 prefix_id
.prefixlen
= 32;
1105 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1106 node
= route_node_get(ospf6
->external_id_table
, &prefix_id
);
1109 if (IS_OSPF6_DEBUG_ASBR
) {
1110 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
,
1112 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1114 "Advertise as AS-External Id:%s prefix %s metric %u",
1115 ibuf
, pbuf
, match
->path
.metric_type
);
1118 match
->path
.origin
.id
= htonl(info
->id
);
1119 ospf6_as_external_lsa_originate(match
);
1123 /* create new entry */
1124 route
= ospf6_route_create();
1125 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
1126 memcpy(&route
->prefix
, prefix
, sizeof(struct prefix
));
1128 info
= (struct ospf6_external_info
*)XCALLOC(
1129 MTYPE_OSPF6_EXTERNAL_INFO
, sizeof(struct ospf6_external_info
));
1130 route
->route_option
= info
;
1131 info
->id
= ospf6
->external_id
++;
1133 /* copy result of route-map */
1134 if (ospf6
->rmap
[type
].map
) {
1135 if (troute
.path
.metric_type
)
1136 route
->path
.metric_type
= troute
.path
.metric_type
;
1137 if (troute
.path
.cost
)
1138 route
->path
.cost
= troute
.path
.cost
;
1139 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1140 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1141 sizeof(struct in6_addr
));
1142 info
->tag
= tinfo
.tag
;
1144 /* If there is no route-map, simply set the tag */
1149 if (nexthop_num
&& nexthop
)
1150 ospf6_route_add_nexthop(route
, ifindex
, nexthop
);
1152 ospf6_route_add_nexthop(route
, ifindex
, NULL
);
1154 /* create/update binding in external_id_table */
1155 prefix_id
.family
= AF_INET
;
1156 prefix_id
.prefixlen
= 32;
1157 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1158 node
= route_node_get(ospf6
->external_id_table
, &prefix_id
);
1161 route
= ospf6_route_add(route
, ospf6
->external_table
);
1162 route
->route_option
= info
;
1164 if (IS_OSPF6_DEBUG_ASBR
) {
1165 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
, sizeof(ibuf
));
1166 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1167 zlog_debug("Advertise as AS-External Id:%s prefix %s metric %u",
1168 ibuf
, pbuf
, route
->path
.metric_type
);
1171 route
->path
.origin
.id
= htonl(info
->id
);
1172 ospf6_as_external_lsa_originate(route
);
1174 /* Router-Bit (ASBR Flag) may have to be updated */
1175 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1176 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1179 void ospf6_asbr_redistribute_remove(int type
, ifindex_t ifindex
,
1180 struct prefix
*prefix
)
1182 struct ospf6_route
*match
;
1183 struct ospf6_external_info
*info
= NULL
;
1184 struct route_node
*node
;
1185 struct ospf6_lsa
*lsa
;
1186 struct prefix prefix_id
;
1187 char pbuf
[PREFIX2STR_BUFFER
], ibuf
[16];
1188 struct listnode
*lnode
, *lnnode
;
1189 struct ospf6_area
*oa
;
1191 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1192 if (match
== NULL
) {
1193 if (IS_OSPF6_DEBUG_ASBR
) {
1194 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1195 zlog_debug("No such route %s to withdraw", pbuf
);
1200 info
= match
->route_option
;
1203 if (info
->type
!= type
) {
1204 if (IS_OSPF6_DEBUG_ASBR
) {
1205 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1206 zlog_debug("Original protocol mismatch: %s", pbuf
);
1211 if (IS_OSPF6_DEBUG_ASBR
) {
1212 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1213 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
, sizeof(ibuf
));
1214 zlog_debug("Withdraw %s (AS-External Id:%s)", pbuf
, ibuf
);
1217 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
1218 htonl(info
->id
), ospf6
->router_id
, ospf6
->lsdb
);
1220 ospf6_lsa_purge(lsa
);
1222 /* remove binding in external_id_table */
1223 prefix_id
.family
= AF_INET
;
1224 prefix_id
.prefixlen
= 32;
1225 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1226 node
= route_node_lookup(ospf6
->external_id_table
, &prefix_id
);
1229 route_unlock_node(node
); /* to free the lookup lock */
1230 route_unlock_node(node
); /* to free the original lock */
1232 ospf6_route_remove(match
, ospf6
->external_table
);
1233 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
, info
);
1235 /* Router-Bit (ASBR Flag) may have to be updated */
1236 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1237 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1240 DEFUN (ospf6_redistribute
,
1241 ospf6_redistribute_cmd
,
1242 "redistribute " FRR_REDIST_STR_OSPF6D
,
1244 FRR_REDIST_HELP_STR_OSPF6D
)
1248 OSPF6_CMD_CHECK_RUNNING();
1250 char *proto
= argv
[argc
- 1]->text
;
1251 type
= proto_redistnum(AFI_IP6
, proto
);
1253 return CMD_WARNING_CONFIG_FAILED
;
1255 ospf6_asbr_redistribute_unset(type
, ospf6
->vrf_id
);
1256 ospf6_asbr_redistribute_set(type
, ospf6
->vrf_id
);
1260 DEFUN (ospf6_redistribute_routemap
,
1261 ospf6_redistribute_routemap_cmd
,
1262 "redistribute " FRR_REDIST_STR_OSPF6D
" route-map WORD",
1264 FRR_REDIST_HELP_STR_OSPF6D
1265 "Route map reference\n"
1268 int idx_protocol
= 1;
1272 OSPF6_CMD_CHECK_RUNNING();
1274 char *proto
= argv
[idx_protocol
]->text
;
1275 type
= proto_redistnum(AFI_IP6
, proto
);
1277 return CMD_WARNING_CONFIG_FAILED
;
1279 ospf6_asbr_redistribute_unset(type
, ospf6
->vrf_id
);
1280 ospf6_asbr_routemap_set(type
, argv
[idx_word
]->arg
);
1281 ospf6_asbr_redistribute_set(type
, ospf6
->vrf_id
);
1285 DEFUN (no_ospf6_redistribute
,
1286 no_ospf6_redistribute_cmd
,
1287 "no redistribute " FRR_REDIST_STR_OSPF6D
" [route-map WORD]",
1290 FRR_REDIST_HELP_STR_OSPF6D
1291 "Route map reference\n"
1294 int idx_protocol
= 2;
1297 OSPF6_CMD_CHECK_RUNNING();
1299 char *proto
= argv
[idx_protocol
]->text
;
1300 type
= proto_redistnum(AFI_IP6
, proto
);
1302 return CMD_WARNING_CONFIG_FAILED
;
1304 ospf6_asbr_redistribute_unset(type
, ospf6
->vrf_id
);
1309 int ospf6_redistribute_config_write(struct vty
*vty
)
1313 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1314 if (type
== ZEBRA_ROUTE_OSPF6
)
1316 if (!ospf6_zebra_is_redistribute(type
, ospf6
->vrf_id
))
1319 if (ospf6
->rmap
[type
].name
)
1320 vty_out(vty
, " redistribute %s route-map %s\n",
1321 ZROUTE_NAME(type
), ospf6
->rmap
[type
].name
);
1323 vty_out(vty
, " redistribute %s\n", ZROUTE_NAME(type
));
1329 static void ospf6_redistribute_show_config(struct vty
*vty
)
1332 int nroute
[ZEBRA_ROUTE_MAX
];
1334 struct ospf6_route
*route
;
1335 struct ospf6_external_info
*info
;
1338 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++)
1340 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1341 route
= ospf6_route_next(route
)) {
1342 info
= route
->route_option
;
1343 nroute
[info
->type
]++;
1347 vty_out(vty
, "Redistributing External Routes from:\n");
1348 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1349 if (type
== ZEBRA_ROUTE_OSPF6
)
1351 if (!ospf6_zebra_is_redistribute(type
, ospf6
->vrf_id
))
1354 if (ospf6
->rmap
[type
].name
)
1355 vty_out(vty
, " %d: %s with route-map \"%s\"%s\n",
1356 nroute
[type
], ZROUTE_NAME(type
),
1357 ospf6
->rmap
[type
].name
,
1358 (ospf6
->rmap
[type
].map
? ""
1359 : " (not found !)"));
1361 vty_out(vty
, " %d: %s\n", nroute
[type
],
1364 vty_out(vty
, "Total %d routes\n", total
);
1368 /* Routemap Functions */
1369 static enum route_map_cmd_result_t
1370 ospf6_routemap_rule_match_address_prefixlist(void *rule
,
1371 const struct prefix
*prefix
,
1372 route_map_object_t type
,
1375 struct prefix_list
*plist
;
1377 if (type
!= RMAP_OSPF6
)
1378 return RMAP_NOMATCH
;
1380 plist
= prefix_list_lookup(AFI_IP6
, (char *)rule
);
1382 return RMAP_NOMATCH
;
1384 return (prefix_list_apply(plist
, prefix
) == PREFIX_DENY
? RMAP_NOMATCH
1389 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg
)
1391 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1394 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule
)
1396 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1399 static const struct route_map_rule_cmd
1400 ospf6_routemap_rule_match_address_prefixlist_cmd
= {
1401 "ipv6 address prefix-list",
1402 ospf6_routemap_rule_match_address_prefixlist
,
1403 ospf6_routemap_rule_match_address_prefixlist_compile
,
1404 ospf6_routemap_rule_match_address_prefixlist_free
,
1407 /* `match interface IFNAME' */
1408 /* Match function should return 1 if match is success else return
1410 static enum route_map_cmd_result_t
1411 ospf6_routemap_rule_match_interface(void *rule
, const struct prefix
*prefix
,
1412 route_map_object_t type
, void *object
)
1414 struct interface
*ifp
;
1415 struct ospf6_external_info
*ei
;
1417 if (type
== RMAP_OSPF6
) {
1418 ei
= ((struct ospf6_route
*)object
)->route_option
;
1419 ifp
= if_lookup_by_name_all_vrf((char *)rule
);
1421 if (ifp
!= NULL
&& ei
->ifindex
== ifp
->ifindex
)
1425 return RMAP_NOMATCH
;
1428 /* Route map `interface' match statement. `arg' should be
1430 static void *ospf6_routemap_rule_match_interface_compile(const char *arg
)
1432 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1435 /* Free route map's compiled `interface' value. */
1436 static void ospf6_routemap_rule_match_interface_free(void *rule
)
1438 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1441 /* Route map commands for interface matching. */
1442 static const struct route_map_rule_cmd
1443 ospf6_routemap_rule_match_interface_cmd
= {
1445 ospf6_routemap_rule_match_interface
,
1446 ospf6_routemap_rule_match_interface_compile
,
1447 ospf6_routemap_rule_match_interface_free
1450 /* Match function for matching route tags */
1451 static enum route_map_cmd_result_t
1452 ospf6_routemap_rule_match_tag(void *rule
, const struct prefix
*p
,
1453 route_map_object_t type
, void *object
)
1455 route_tag_t
*tag
= rule
;
1456 struct ospf6_route
*route
= object
;
1457 struct ospf6_external_info
*info
= route
->route_option
;
1459 if (type
== RMAP_OSPF6
&& info
->tag
== *tag
)
1462 return RMAP_NOMATCH
;
1465 static const struct route_map_rule_cmd
1466 ospf6_routemap_rule_match_tag_cmd
= {
1468 ospf6_routemap_rule_match_tag
,
1469 route_map_rule_tag_compile
,
1470 route_map_rule_tag_free
,
1473 static enum route_map_cmd_result_t
1474 ospf6_routemap_rule_set_metric_type(void *rule
, const struct prefix
*prefix
,
1475 route_map_object_t type
, void *object
)
1477 char *metric_type
= rule
;
1478 struct ospf6_route
*route
= object
;
1480 if (type
!= RMAP_OSPF6
)
1483 if (strcmp(metric_type
, "type-2") == 0)
1484 route
->path
.metric_type
= 2;
1486 route
->path
.metric_type
= 1;
1491 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg
)
1493 if (strcmp(arg
, "type-2") && strcmp(arg
, "type-1"))
1495 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1498 static void ospf6_routemap_rule_set_metric_type_free(void *rule
)
1500 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1503 static const struct route_map_rule_cmd
1504 ospf6_routemap_rule_set_metric_type_cmd
= {
1506 ospf6_routemap_rule_set_metric_type
,
1507 ospf6_routemap_rule_set_metric_type_compile
,
1508 ospf6_routemap_rule_set_metric_type_free
,
1511 static enum route_map_cmd_result_t
1512 ospf6_routemap_rule_set_metric(void *rule
, const struct prefix
*prefix
,
1513 route_map_object_t type
, void *object
)
1515 char *metric
= rule
;
1516 struct ospf6_route
*route
= object
;
1518 if (type
!= RMAP_OSPF6
)
1521 route
->path
.cost
= atoi(metric
);
1525 static void *ospf6_routemap_rule_set_metric_compile(const char *arg
)
1529 metric
= strtoul(arg
, &endp
, 0);
1530 if (metric
> OSPF_LS_INFINITY
|| *endp
!= '\0')
1532 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1535 static void ospf6_routemap_rule_set_metric_free(void *rule
)
1537 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1540 static const struct route_map_rule_cmd
1541 ospf6_routemap_rule_set_metric_cmd
= {
1543 ospf6_routemap_rule_set_metric
,
1544 ospf6_routemap_rule_set_metric_compile
,
1545 ospf6_routemap_rule_set_metric_free
,
1548 static enum route_map_cmd_result_t
1549 ospf6_routemap_rule_set_forwarding(void *rule
, const struct prefix
*prefix
,
1550 route_map_object_t type
, void *object
)
1552 char *forwarding
= rule
;
1553 struct ospf6_route
*route
= object
;
1554 struct ospf6_external_info
*info
= route
->route_option
;
1556 if (type
!= RMAP_OSPF6
)
1559 if (inet_pton(AF_INET6
, forwarding
, &info
->forwarding
) != 1) {
1560 memset(&info
->forwarding
, 0, sizeof(struct in6_addr
));
1567 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg
)
1570 if (inet_pton(AF_INET6
, arg
, &a
) != 1)
1572 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1575 static void ospf6_routemap_rule_set_forwarding_free(void *rule
)
1577 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1580 static const struct route_map_rule_cmd
1581 ospf6_routemap_rule_set_forwarding_cmd
= {
1582 "forwarding-address",
1583 ospf6_routemap_rule_set_forwarding
,
1584 ospf6_routemap_rule_set_forwarding_compile
,
1585 ospf6_routemap_rule_set_forwarding_free
,
1588 static enum route_map_cmd_result_t
1589 ospf6_routemap_rule_set_tag(void *rule
, const struct prefix
*p
,
1590 route_map_object_t type
, void *object
)
1592 route_tag_t
*tag
= rule
;
1593 struct ospf6_route
*route
= object
;
1594 struct ospf6_external_info
*info
= route
->route_option
;
1596 if (type
!= RMAP_OSPF6
)
1603 static const struct route_map_rule_cmd
1604 ospf6_routemap_rule_set_tag_cmd
= {
1606 ospf6_routemap_rule_set_tag
,
1607 route_map_rule_tag_compile
,
1608 route_map_rule_tag_free
,
1611 static int route_map_command_status(struct vty
*vty
, enum rmap_compile_rets ret
)
1614 case RMAP_RULE_MISSING
:
1615 vty_out(vty
, "OSPF6 Can't find rule.\n");
1616 return CMD_WARNING_CONFIG_FAILED
;
1617 case RMAP_COMPILE_ERROR
:
1618 vty_out(vty
, "OSPF6 Argument is malformed.\n");
1619 return CMD_WARNING_CONFIG_FAILED
;
1620 case RMAP_COMPILE_SUCCESS
:
1627 /* add "set metric-type" */
1628 DEFUN (ospf6_routemap_set_metric_type
,
1629 ospf6_routemap_set_metric_type_cmd
,
1630 "set metric-type <type-1|type-2>",
1633 "OSPF6 external type 1 metric\n"
1634 "OSPF6 external type 2 metric\n")
1636 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1637 int idx_external
= 2;
1638 enum rmap_compile_rets ret
= route_map_add_set(route_map_index
,
1640 argv
[idx_external
]->arg
);
1642 return route_map_command_status(vty
, ret
);
1645 /* delete "set metric-type" */
1646 DEFUN (ospf6_routemap_no_set_metric_type
,
1647 ospf6_routemap_no_set_metric_type_cmd
,
1648 "no set metric-type [<type-1|type-2>]",
1652 "OSPF6 external type 1 metric\n"
1653 "OSPF6 external type 2 metric\n")
1655 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1656 char *ext
= (argc
== 4) ? argv
[3]->text
: NULL
;
1657 enum rmap_compile_rets ret
= route_map_delete_set(route_map_index
,
1658 "metric-type", ext
);
1660 return route_map_command_status(vty
, ret
);
1663 /* add "set forwarding-address" */
1664 DEFUN (ospf6_routemap_set_forwarding
,
1665 ospf6_routemap_set_forwarding_cmd
,
1666 "set forwarding-address X:X::X:X",
1668 "Forwarding Address\n"
1671 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1673 enum rmap_compile_rets ret
= route_map_add_set(route_map_index
,
1674 "forwarding-address",
1675 argv
[idx_ipv6
]->arg
);
1677 return route_map_command_status(vty
, ret
);
1680 /* delete "set forwarding-address" */
1681 DEFUN (ospf6_routemap_no_set_forwarding
,
1682 ospf6_routemap_no_set_forwarding_cmd
,
1683 "no set forwarding-address X:X::X:X",
1686 "Forwarding Address\n"
1689 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1691 enum rmap_compile_rets ret
= route_map_delete_set(route_map_index
,
1692 "forwarding-address",
1693 argv
[idx_ipv6
]->arg
);
1695 return route_map_command_status(vty
, ret
);
1698 static void ospf6_routemap_init(void)
1702 route_map_add_hook(ospf6_asbr_routemap_update
);
1703 route_map_delete_hook(ospf6_asbr_routemap_update
);
1704 route_map_event_hook(ospf6_asbr_routemap_event
);
1706 route_map_set_metric_hook(generic_set_add
);
1707 route_map_no_set_metric_hook(generic_set_delete
);
1709 route_map_match_tag_hook(generic_match_add
);
1710 route_map_no_match_tag_hook(generic_match_delete
);
1712 route_map_match_ipv6_address_prefix_list_hook(generic_match_add
);
1713 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete
);
1715 route_map_match_interface_hook(generic_match_add
);
1716 route_map_no_match_interface_hook(generic_match_delete
);
1718 route_map_install_match(
1719 &ospf6_routemap_rule_match_address_prefixlist_cmd
);
1720 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd
);
1721 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd
);
1723 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd
);
1724 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd
);
1725 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd
);
1726 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd
);
1728 /* ASE Metric Type (e.g. Type-1/Type-2) */
1729 install_element(RMAP_NODE
, &ospf6_routemap_set_metric_type_cmd
);
1730 install_element(RMAP_NODE
, &ospf6_routemap_no_set_metric_type_cmd
);
1733 install_element(RMAP_NODE
, &ospf6_routemap_set_forwarding_cmd
);
1734 install_element(RMAP_NODE
, &ospf6_routemap_no_set_forwarding_cmd
);
1738 /* Display functions */
1739 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1740 char *buf
, int buflen
,
1743 struct ospf6_as_external_lsa
*external
;
1744 struct in6_addr in6
;
1745 int prefix_length
= 0;
1748 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1752 ospf6_prefix_in6_addr(&in6
, external
,
1754 prefix_length
= external
->prefix
.prefix_length
;
1756 in6
= *((struct in6_addr
1757 *)((caddr_t
)external
1759 ospf6_as_external_lsa
)
1760 + OSPF6_PREFIX_SPACE(
1765 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
1767 sprintf(&buf
[strlen(buf
)], "/%d",
1774 static int ospf6_as_external_lsa_show(struct vty
*vty
, struct ospf6_lsa
*lsa
)
1776 struct ospf6_as_external_lsa
*external
;
1779 assert(lsa
->header
);
1780 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1784 snprintf(buf
, sizeof(buf
), "%c%c%c",
1785 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
) ? 'E'
1787 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
) ? 'F'
1789 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
) ? 'T'
1792 vty_out(vty
, " Bits: %s\n", buf
);
1793 vty_out(vty
, " Metric: %5lu\n",
1794 (unsigned long)OSPF6_ASBR_METRIC(external
));
1796 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
, buf
,
1798 vty_out(vty
, " Prefix Options: %s\n", buf
);
1800 vty_out(vty
, " Referenced LSType: %d\n",
1801 ntohs(external
->prefix
.prefix_refer_lstype
));
1803 vty_out(vty
, " Prefix: %s\n",
1804 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
, sizeof(buf
), 0));
1806 /* Forwarding-Address */
1807 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
1808 vty_out(vty
, " Forwarding-Address: %s\n",
1809 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
,
1814 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
1815 vty_out(vty
, " Tag: %" ROUTE_TAG_PRI
"\n",
1816 ospf6_as_external_lsa_get_tag(lsa
));
1822 static void ospf6_asbr_external_route_show(struct vty
*vty
,
1823 struct ospf6_route
*route
)
1825 struct ospf6_external_info
*info
= route
->route_option
;
1826 char prefix
[PREFIX2STR_BUFFER
], id
[16], forwarding
[64];
1829 prefix2str(&route
->prefix
, prefix
, sizeof(prefix
));
1830 tmp_id
= ntohl(info
->id
);
1831 inet_ntop(AF_INET
, &tmp_id
, id
, sizeof(id
));
1832 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
1833 inet_ntop(AF_INET6
, &info
->forwarding
, forwarding
,
1834 sizeof(forwarding
));
1836 snprintf(forwarding
, sizeof(forwarding
), ":: (ifindex %d)",
1837 ospf6_route_get_first_nh_index(route
));
1839 vty_out(vty
, "%c %-32s %-15s type-%d %5lu %s\n",
1840 zebra_route_char(info
->type
), prefix
, id
,
1841 route
->path
.metric_type
,
1842 (unsigned long)(route
->path
.metric_type
== 2
1843 ? route
->path
.u
.cost_e2
1844 : route
->path
.cost
),
1848 DEFUN (show_ipv6_ospf6_redistribute
,
1849 show_ipv6_ospf6_redistribute_cmd
,
1850 "show ipv6 ospf6 redistribute",
1854 "redistributing External information\n"
1857 struct ospf6_route
*route
;
1859 OSPF6_CMD_CHECK_RUNNING();
1861 ospf6_redistribute_show_config(vty
);
1863 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1864 route
= ospf6_route_next(route
))
1865 ospf6_asbr_external_route_show(vty
, route
);
1870 static struct ospf6_lsa_handler as_external_handler
= {
1871 .lh_type
= OSPF6_LSTYPE_AS_EXTERNAL
,
1872 .lh_name
= "AS-External",
1873 .lh_short_name
= "ASE",
1874 .lh_show
= ospf6_as_external_lsa_show
,
1875 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
1878 void ospf6_asbr_init(void)
1880 ospf6_routemap_init();
1882 ospf6_install_lsa_handler(&as_external_handler
);
1884 install_element(VIEW_NODE
, &show_ipv6_ospf6_redistribute_cmd
);
1886 install_element(OSPF6_NODE
, &ospf6_redistribute_cmd
);
1887 install_element(OSPF6_NODE
, &ospf6_redistribute_routemap_cmd
);
1888 install_element(OSPF6_NODE
, &no_ospf6_redistribute_cmd
);
1891 void ospf6_asbr_redistribute_reset(vrf_id_t vrf_id
)
1895 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1896 if (type
== ZEBRA_ROUTE_OSPF6
)
1898 if (ospf6_zebra_is_redistribute(type
, vrf_id
))
1899 ospf6_asbr_redistribute_unset(type
, vrf_id
);
1903 void ospf6_asbr_terminate(void)
1905 /* Cleanup route maps */
1909 DEFUN (debug_ospf6_asbr
,
1910 debug_ospf6_asbr_cmd
,
1914 "Debug OSPFv3 ASBR function\n"
1917 OSPF6_DEBUG_ASBR_ON();
1921 DEFUN (no_debug_ospf6_asbr
,
1922 no_debug_ospf6_asbr_cmd
,
1923 "no debug ospf6 asbr",
1927 "Debug OSPFv3 ASBR function\n"
1930 OSPF6_DEBUG_ASBR_OFF();
1934 int config_write_ospf6_debug_asbr(struct vty
*vty
)
1936 if (IS_OSPF6_DEBUG_ASBR
)
1937 vty_out(vty
, "debug ospf6 asbr\n");
1941 void install_element_ospf6_debug_asbr(void)
1943 install_element(ENABLE_NODE
, &debug_ospf6_asbr_cmd
);
1944 install_element(ENABLE_NODE
, &no_debug_ospf6_asbr_cmd
);
1945 install_element(CONFIG_NODE
, &debug_ospf6_asbr_cmd
);
1946 install_element(CONFIG_NODE
, &no_debug_ospf6_asbr_cmd
);