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 unsigned char conf_debug_ospf6_asbr
= 0;
52 #define ZROUTE_NAME(x) zebra_route_string(x)
54 /* AS External LSA origination */
55 static void ospf6_as_external_lsa_originate(struct ospf6_route
*route
)
57 char buffer
[OSPF6_MAX_LSASIZE
];
58 struct ospf6_lsa_header
*lsa_header
;
59 struct ospf6_lsa
*lsa
;
60 struct ospf6_external_info
*info
= route
->route_option
;
62 struct ospf6_as_external_lsa
*as_external_lsa
;
63 char buf
[PREFIX2STR_BUFFER
];
66 if (IS_OSPF6_DEBUG_ASBR
|| IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL
)) {
67 prefix2str(&route
->prefix
, buf
, sizeof(buf
));
68 zlog_debug("Originate AS-External-LSA for %s", buf
);
72 memset(buffer
, 0, sizeof(buffer
));
73 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
74 as_external_lsa
= (struct ospf6_as_external_lsa
75 *)((caddr_t
)lsa_header
76 + sizeof(struct ospf6_lsa_header
));
77 p
= (caddr_t
)((caddr_t
)as_external_lsa
78 + sizeof(struct ospf6_as_external_lsa
));
80 /* Fill AS-External-LSA */
82 if (route
->path
.metric_type
== 2)
83 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
85 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_E
);
87 /* forwarding address */
88 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
89 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
91 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
);
93 /* external route tag */
95 SET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
97 UNSET_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
);
100 OSPF6_ASBR_METRIC_SET(as_external_lsa
, route
->path
.cost
);
103 as_external_lsa
->prefix
.prefix_length
= route
->prefix
.prefixlen
;
106 as_external_lsa
->prefix
.prefix_options
= route
->path
.prefix_options
;
108 /* don't use refer LS-type */
109 as_external_lsa
->prefix
.prefix_refer_lstype
= htons(0);
112 memcpy(p
, &route
->prefix
.u
.prefix6
,
113 OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
));
114 ospf6_prefix_apply_mask(&as_external_lsa
->prefix
);
115 p
+= OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
);
117 /* Forwarding address */
118 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
119 memcpy(p
, &info
->forwarding
, sizeof(struct in6_addr
));
120 p
+= sizeof(struct in6_addr
);
123 /* External Route Tag */
124 if (CHECK_FLAG(as_external_lsa
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
125 route_tag_t network_order
= htonl(info
->tag
);
127 memcpy(p
, &network_order
, sizeof(network_order
));
128 p
+= sizeof(network_order
);
131 /* Fill LSA Header */
133 lsa_header
->type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
134 lsa_header
->id
= route
->path
.origin
.id
;
135 lsa_header
->adv_router
= ospf6
->router_id
;
137 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
138 lsa_header
->adv_router
, ospf6
->lsdb
);
139 lsa_header
->length
= htons((caddr_t
)p
- (caddr_t
)lsa_header
);
142 ospf6_lsa_checksum(lsa_header
);
145 lsa
= ospf6_lsa_create(lsa_header
);
148 ospf6_lsa_originate_process(lsa
, ospf6
);
151 int ospf6_orig_as_external_lsa(struct thread
*thread
)
153 struct ospf6_interface
*oi
;
154 struct ospf6_lsa
*lsa
;
155 uint32_t type
, adv_router
;
157 oi
= (struct ospf6_interface
*)THREAD_ARG(thread
);
158 oi
->thread_as_extern_lsa
= NULL
;
160 if (oi
->state
== OSPF6_INTERFACE_DOWN
)
163 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
164 adv_router
= oi
->area
->ospf6
->router_id
;
165 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, adv_router
, lsa
)) {
166 if (IS_OSPF6_DEBUG_ASBR
)
168 "%s: Send update of AS-External LSA %s seq 0x%x",
169 __PRETTY_FUNCTION__
, lsa
->name
,
170 ntohl(lsa
->header
->seqnum
));
172 ospf6_flood_interface(NULL
, lsa
, oi
);
178 static route_tag_t
ospf6_as_external_lsa_get_tag(struct ospf6_lsa
*lsa
)
180 struct ospf6_as_external_lsa
*external
;
181 ptrdiff_t tag_offset
;
182 route_tag_t network_order
;
187 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
190 if (!CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
193 tag_offset
= sizeof(*external
)
194 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
195 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
196 tag_offset
+= sizeof(struct in6_addr
);
198 memcpy(&network_order
, (caddr_t
)external
+ tag_offset
,
199 sizeof(network_order
));
200 return ntohl(network_order
);
203 void ospf6_asbr_update_route_ecmp_path(struct ospf6_route
*old
,
204 struct ospf6_route
*route
)
206 struct ospf6_route
*old_route
;
207 struct ospf6_path
*ecmp_path
, *o_path
= NULL
;
208 struct listnode
*anode
, *anext
;
209 struct listnode
*nnode
, *rnode
, *rnext
;
210 struct ospf6_nexthop
*nh
, *rnh
;
211 char buf
[PREFIX2STR_BUFFER
];
212 bool route_found
= false;
214 /* check for old entry match with new route origin,
217 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
218 bool route_updated
= false;
220 if (!ospf6_route_is_same(old_route
, route
)
221 || (old_route
->path
.type
!= route
->path
.type
))
224 /* Current and New route has same origin,
227 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
, anext
,
229 /* Check old route path and route has same
232 if (o_path
->area_id
!= route
->path
.area_id
233 || (memcmp(&(o_path
)->origin
, &(route
)->path
.origin
,
234 sizeof(struct ospf6_ls_origin
))
238 /* Cost is not same then delete current path */
239 if ((o_path
->cost
== route
->path
.cost
)
240 && (o_path
->u
.cost_e2
== route
->path
.u
.cost_e2
))
243 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
244 prefix2str(&old_route
->prefix
, buf
,
247 "%s: route %s cost old %u new %u is not same, replace route",
248 __PRETTY_FUNCTION__
, buf
, o_path
->cost
,
252 /* Remove selected current rout path's nh from
255 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
256 for (ALL_LIST_ELEMENTS(old_route
->nh_list
,
257 rnode
, rnext
, rnh
)) {
258 if (!ospf6_nexthop_is_same(rnh
, nh
))
260 listnode_delete(old_route
->nh_list
,
262 ospf6_nexthop_delete(rnh
);
266 listnode_delete(old_route
->paths
, o_path
);
267 ospf6_path_free(o_path
);
268 route_updated
= true;
270 /* Current route's path (adv_router info) is similar
271 * to route being added.
272 * Replace current route's path with paths list head.
273 * Update FIB with effective NHs.
275 if (listcount(old_route
->paths
)) {
276 for (ALL_LIST_ELEMENTS(old_route
->paths
,
277 anode
, anext
, o_path
)) {
278 ospf6_merge_nexthops(
282 /* Update RIB/FIB with effective
285 if (ospf6
->route_table
->hook_add
)
286 (*ospf6
->route_table
->hook_add
)
289 if (old_route
->path
.origin
.id
290 == route
->path
.origin
.id
291 && old_route
->path
.origin
.adv_router
292 == route
->path
.origin
294 struct ospf6_path
*h_path
;
296 h_path
= (struct ospf6_path
*)
297 listgetdata(listhead(
299 old_route
->path
.origin
.type
=
301 old_route
->path
.origin
.id
=
303 old_route
->path
.origin
.adv_router
=
304 h_path
->origin
.adv_router
;
307 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
308 prefix2str(&old_route
->prefix
, buf
,
311 "%s: route %s old cost %u new cost %u, delete old entry.",
312 __PRETTY_FUNCTION__
, buf
,
313 old_route
->path
.cost
,
316 ospf6_route_remove(old_route
,
325 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
327 /* Current and New Route prefix or route type
328 * is not same skip this current node.
330 if (!ospf6_route_is_same(old_route
, route
)
331 || (old_route
->path
.type
!= route
->path
.type
))
334 /* Old Route and New Route have Equal Cost, Merge NHs */
335 if ((old_route
->path
.cost
== route
->path
.cost
)
336 && (old_route
->path
.u
.cost_e2
== route
->path
.u
.cost_e2
)) {
338 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
339 prefix2str(&old_route
->prefix
, buf
,
342 "%s: old route %s path cost %u e2 %u",
343 __PRETTY_FUNCTION__
, buf
,
344 old_route
->path
.cost
,
345 old_route
->path
.u
.cost_e2
);
348 /* check if this path exists already in
349 * route->paths list, if so, replace nh_list
352 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
354 if (o_path
->area_id
== route
->path
.area_id
355 && (memcmp(&(o_path
)->origin
,
356 &(route
)->path
.origin
,
357 sizeof(struct ospf6_ls_origin
))
361 /* If path is not found in old_route paths's list,
362 * add a new path to route paths list and merge
363 * nexthops in route->path->nh_list.
364 * Otherwise replace existing path's nh_list.
366 if (o_path
== NULL
) {
367 ecmp_path
= ospf6_path_dup(&route
->path
);
369 /* Add a nh_list to new ecmp path */
370 ospf6_copy_nexthops(ecmp_path
->nh_list
,
373 /* Add the new path to route's path list */
374 listnode_add_sort(old_route
->paths
, ecmp_path
);
376 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
377 prefix2str(&route
->prefix
, buf
,
380 "%s: route %s another path added with nh %u, effective paths %u nh %u",
381 __PRETTY_FUNCTION__
, buf
,
382 listcount(ecmp_path
->nh_list
),
388 listcount(old_route
->nh_list
));
391 list_delete_all_node(o_path
->nh_list
);
392 ospf6_copy_nexthops(o_path
->nh_list
,
396 /* Reset nexthop lists, rebuild from brouter table
397 * for each adv. router.
399 list_delete_all_node(old_route
->nh_list
);
401 for (ALL_LIST_ELEMENTS_RO(old_route
->paths
, anode
,
403 struct ospf6_route
*asbr_entry
;
405 asbr_entry
= ospf6_route_lookup(
407 ospf6
->brouter_table
);
408 if (asbr_entry
== NULL
) {
409 if (IS_OSPF6_DEBUG_EXAMIN(
411 prefix2str(&old_route
->prefix
,
413 zlog_debug("%s: ls_prfix %s asbr_entry not found.",
419 ospf6_route_merge_nexthops(old_route
,
423 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
424 prefix2str(&route
->prefix
, buf
, sizeof(buf
));
425 zlog_debug("%s: route %s with effective paths %u nh %u",
426 __PRETTY_FUNCTION__
, buf
,
428 listcount(old_route
->paths
) : 0,
430 listcount(old_route
->nh_list
) : 0);
434 if (ospf6
->route_table
->hook_add
)
435 (*ospf6
->route_table
->hook_add
)(old_route
);
437 /* Delete the new route its info added to existing
440 ospf6_route_delete(route
);
447 /* Add new route to existing node in ospf6 route table. */
448 ospf6_route_add(route
, ospf6
->route_table
);
452 void ospf6_asbr_lsa_add(struct ospf6_lsa
*lsa
)
454 struct ospf6_as_external_lsa
*external
;
455 struct prefix asbr_id
;
456 struct ospf6_route
*asbr_entry
, *route
, *old
;
457 struct ospf6_path
*path
;
458 char buf
[PREFIX2STR_BUFFER
];
460 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
463 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
464 zlog_debug("Calculate AS-External route for %s", lsa
->name
);
466 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
467 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
468 zlog_debug("Ignore self-originated AS-External-LSA");
472 if (OSPF6_ASBR_METRIC(external
) == OSPF_LS_INFINITY
) {
473 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
474 zlog_debug("Ignore LSA with LSInfinity Metric");
478 if (CHECK_FLAG(external
->prefix
.prefix_options
,
479 OSPF6_PREFIX_OPTION_NU
)) {
480 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
481 zlog_debug("Ignore LSA with NU bit set Metric");
485 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &asbr_id
);
486 asbr_entry
= ospf6_route_lookup(&asbr_id
, ospf6
->brouter_table
);
487 if (asbr_entry
== NULL
488 || !CHECK_FLAG(asbr_entry
->path
.router_bits
, OSPF6_ROUTER_BIT_E
)) {
489 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
490 prefix2str(&asbr_id
, buf
, sizeof(buf
));
491 zlog_debug("ASBR entry not found: %s", buf
);
496 route
= ospf6_route_create();
497 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
498 route
->prefix
.family
= AF_INET6
;
499 route
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
500 ospf6_prefix_in6_addr(&route
->prefix
.u
.prefix6
, external
,
503 route
->path
.area_id
= asbr_entry
->path
.area_id
;
504 route
->path
.origin
.type
= lsa
->header
->type
;
505 route
->path
.origin
.id
= lsa
->header
->id
;
506 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
507 route
->path
.prefix_options
= external
->prefix
.prefix_options
;
508 memcpy(&route
->path
.ls_prefix
, &asbr_id
, sizeof(struct prefix
));
510 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
511 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
512 route
->path
.metric_type
= 2;
513 route
->path
.cost
= asbr_entry
->path
.cost
;
514 route
->path
.u
.cost_e2
= OSPF6_ASBR_METRIC(external
);
516 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
517 route
->path
.metric_type
= 1;
519 asbr_entry
->path
.cost
+ OSPF6_ASBR_METRIC(external
);
520 route
->path
.u
.cost_e2
= 0;
523 route
->path
.tag
= ospf6_as_external_lsa_get_tag(lsa
);
525 ospf6_route_copy_nexthops(route
, asbr_entry
);
527 path
= ospf6_path_dup(&route
->path
);
528 ospf6_copy_nexthops(path
->nh_list
, asbr_entry
->nh_list
);
529 listnode_add_sort(route
->paths
, path
);
532 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
533 prefix2str(&route
->prefix
, buf
, sizeof(buf
));
534 zlog_debug("%s: AS-External %u route add %s cost %u(%u) nh %u",
536 (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
) ? 1
538 buf
, route
->path
.cost
, route
->path
.u
.cost_e2
,
539 listcount(route
->nh_list
));
542 old
= ospf6_route_lookup(&route
->prefix
, ospf6
->route_table
);
544 /* Add the new route to ospf6 instance route table. */
545 ospf6_route_add(route
, ospf6
->route_table
);
548 * ECMP: Keep new equal preference path in current
549 * route's path list, update zebra with new effective
550 * list along with addition of ECMP path.
552 ospf6_asbr_update_route_ecmp_path(old
, route
);
556 void ospf6_asbr_lsa_remove(struct ospf6_lsa
*lsa
,
557 struct ospf6_route
*asbr_entry
)
559 struct ospf6_as_external_lsa
*external
;
560 struct prefix prefix
;
561 struct ospf6_route
*route
, *nroute
, *route_to_del
;
562 char buf
[PREFIX2STR_BUFFER
];
564 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
567 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
568 zlog_debug("Withdraw AS-External route for %s", lsa
->name
);
570 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
571 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
572 zlog_debug("Ignore self-originated AS-External-LSA");
576 route_to_del
= ospf6_route_create();
577 route_to_del
->type
= OSPF6_DEST_TYPE_NETWORK
;
578 route_to_del
->prefix
.family
= AF_INET6
;
579 route_to_del
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
580 ospf6_prefix_in6_addr(&route_to_del
->prefix
.u
.prefix6
, external
,
583 route_to_del
->path
.origin
.type
= lsa
->header
->type
;
584 route_to_del
->path
.origin
.id
= lsa
->header
->id
;
585 route_to_del
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
588 route_to_del
->path
.area_id
= asbr_entry
->path
.area_id
;
589 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
590 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
591 route_to_del
->path
.metric_type
= 2;
592 route_to_del
->path
.cost
= asbr_entry
->path
.cost
;
593 route_to_del
->path
.u
.cost_e2
=
594 OSPF6_ASBR_METRIC(external
);
596 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
597 route_to_del
->path
.metric_type
= 1;
598 route_to_del
->path
.cost
= asbr_entry
->path
.cost
599 + OSPF6_ASBR_METRIC(external
);
600 route_to_del
->path
.u
.cost_e2
= 0;
604 memset(&prefix
, 0, sizeof(struct prefix
));
605 prefix
.family
= AF_INET6
;
606 prefix
.prefixlen
= external
->prefix
.prefix_length
;
607 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, external
, &external
->prefix
);
609 route
= ospf6_route_lookup(&prefix
, ospf6
->route_table
);
611 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
612 prefix2str(&prefix
, buf
, sizeof(buf
));
613 zlog_debug("AS-External route %s not found", buf
);
616 ospf6_route_delete(route_to_del
);
620 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
621 prefix2str(&prefix
, buf
, sizeof(buf
));
623 "%s: Current route %s cost %u e2 %u, route to del cost %u e2 %u",
624 __PRETTY_FUNCTION__
, buf
, route
->path
.cost
,
625 route
->path
.u
.cost_e2
, route_to_del
->path
.cost
,
626 route_to_del
->path
.u
.cost_e2
);
629 for (ospf6_route_lock(route
);
630 route
&& ospf6_route_is_prefix(&prefix
, route
); route
= nroute
) {
631 nroute
= ospf6_route_next(route
);
633 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
)
636 /* Route has multiple ECMP paths, remove matching
637 * path. Update current route's effective nh list
638 * after removal of one of the path.
640 if (listcount(route
->paths
) > 1) {
641 struct listnode
*anode
, *anext
;
642 struct listnode
*nnode
, *rnode
, *rnext
;
643 struct ospf6_nexthop
*nh
, *rnh
;
644 struct ospf6_path
*o_path
;
645 bool nh_updated
= false;
647 /* Iterate all paths of route to find maching with LSA
648 * remove from route path list. If route->path is same,
649 * replace from paths list.
651 for (ALL_LIST_ELEMENTS(route
->paths
, anode
, anext
,
653 if ((o_path
->origin
.type
!= lsa
->header
->type
)
654 || (o_path
->origin
.adv_router
655 != lsa
->header
->adv_router
)
656 || (o_path
->origin
.id
!= lsa
->header
->id
))
659 /* Compare LSA cost with current
663 && (o_path
->cost
!= route_to_del
->path
.cost
665 != route_to_del
->path
.u
667 if (IS_OSPF6_DEBUG_EXAMIN(
669 prefix2str(&prefix
, buf
,
672 "%s: route %s to delete is not same, cost %u del cost %u. skip",
674 buf
, route
->path
.cost
,
681 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
682 prefix2str(&prefix
, buf
, sizeof(buf
));
684 "%s: route %s path found with cost %u nh %u to remove.",
685 __PRETTY_FUNCTION__
, buf
,
687 listcount(o_path
->nh_list
));
690 /* Remove found path's nh_list from
691 * the route's nh_list.
693 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
,
695 for (ALL_LIST_ELEMENTS(route
->nh_list
,
698 if (!ospf6_nexthop_is_same(rnh
,
701 listnode_delete(route
->nh_list
,
703 ospf6_nexthop_delete(rnh
);
706 /* Delete the path from route's path list */
707 listnode_delete(route
->paths
, o_path
);
708 ospf6_path_free(o_path
);
713 /* Iterate all paths and merge nexthop,
714 * unlesss any of the nexthop similar to
715 * ones deleted as part of path deletion.
718 for (ALL_LIST_ELEMENTS(route
->paths
, anode
,
720 ospf6_merge_nexthops(route
->nh_list
,
724 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
725 prefix2str(&route
->prefix
, buf
,
728 "%s: AS-External %u route %s update paths %u nh %u",
731 == OSPF6_PATH_TYPE_EXTERNAL1
)
734 buf
, listcount(route
->paths
),
736 listcount(route
->nh_list
) : 0);
739 if (listcount(route
->paths
)) {
740 /* Update RIB/FIB with effective
743 if (ospf6
->route_table
->hook_add
)
744 (*ospf6
->route_table
->hook_add
)
747 /* route's primary path is similar
748 * to LSA, replace route's primary
749 * path with route's paths list head.
751 if ((route
->path
.origin
.id
==
753 (route
->path
.origin
.adv_router
754 == lsa
->header
->adv_router
)) {
755 struct ospf6_path
*h_path
;
757 h_path
= (struct ospf6_path
*)
759 listhead(route
->paths
));
760 route
->path
.origin
.type
=
762 route
->path
.origin
.id
=
764 route
->path
.origin
.adv_router
=
765 h_path
->origin
.adv_router
;
768 ospf6_route_remove(route
,
775 /* Compare LSA origin and cost with current route info.
776 * if any check fails skip del this route node.
779 && (!ospf6_route_is_same_origin(route
, route_to_del
)
780 || (route
->path
.type
!= route_to_del
->path
.type
)
781 || (route
->path
.cost
!= route_to_del
->path
.cost
)
782 || (route
->path
.u
.cost_e2
783 != route_to_del
->path
.u
.cost_e2
))) {
784 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
785 prefix2str(&prefix
, buf
, sizeof(buf
));
787 "%s: route %s to delete is not same, cost %u del cost %u. skip",
788 __PRETTY_FUNCTION__
, buf
,
790 route_to_del
->path
.cost
);
795 if ((route
->path
.origin
.type
!= lsa
->header
->type
)
796 || (route
->path
.origin
.adv_router
797 != lsa
->header
->adv_router
)
798 || (route
->path
.origin
.id
!= lsa
->header
->id
))
801 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
802 prefix2str(&route
->prefix
, buf
, sizeof(buf
));
804 "%s: AS-External %u route remove %s cost %u(%u) nh %u",
806 route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
809 buf
, route
->path
.cost
, route
->path
.u
.cost_e2
,
810 listcount(route
->nh_list
));
812 ospf6_route_remove(route
, ospf6
->route_table
);
815 ospf6_route_unlock(route
);
817 ospf6_route_delete(route_to_del
);
820 void ospf6_asbr_lsentry_add(struct ospf6_route
*asbr_entry
)
822 struct ospf6_lsa
*lsa
;
826 if (!CHECK_FLAG(asbr_entry
->flag
, OSPF6_ROUTE_BEST
)) {
828 inet_ntop(AF_INET
, &ADV_ROUTER_IN_PREFIX(&asbr_entry
->prefix
),
830 zlog_info("ignore non-best path: lsentry %s add", buf
);
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 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
838 ospf6_asbr_lsa_add(lsa
);
842 void ospf6_asbr_lsentry_remove(struct ospf6_route
*asbr_entry
)
844 struct ospf6_lsa
*lsa
;
848 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
849 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
850 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
))
851 ospf6_asbr_lsa_remove(lsa
, asbr_entry
);
855 /* redistribute function */
857 static void ospf6_asbr_routemap_set(int type
, const char *mapname
)
859 if (ospf6
->rmap
[type
].name
) {
860 route_map_counter_decrement(ospf6
->rmap
[type
].map
);
861 free(ospf6
->rmap
[type
].name
);
863 ospf6
->rmap
[type
].name
= strdup(mapname
);
864 ospf6
->rmap
[type
].map
= route_map_lookup_by_name(mapname
);
865 route_map_counter_increment(ospf6
->rmap
[type
].map
);
868 static void ospf6_asbr_routemap_unset(int type
)
870 if (ospf6
->rmap
[type
].name
)
871 free(ospf6
->rmap
[type
].name
);
873 route_map_counter_decrement(ospf6
->rmap
[type
].map
);
875 ospf6
->rmap
[type
].name
= NULL
;
876 ospf6
->rmap
[type
].map
= NULL
;
879 static int ospf6_asbr_routemap_update_timer(struct thread
*thread
)
884 arg
= THREAD_ARG(thread
);
885 arg_type
= (int)(intptr_t)arg
[1];
887 ospf6
->t_distribute_update
= NULL
;
889 if (ospf6
->rmap
[arg_type
].name
)
890 ospf6
->rmap
[arg_type
].map
=
891 route_map_lookup_by_name(ospf6
->rmap
[arg_type
].name
);
892 if (ospf6
->rmap
[arg_type
].map
) {
893 if (IS_OSPF6_DEBUG_ASBR
)
894 zlog_debug("%s: route-map %s update, reset redist %s",
896 ospf6
->rmap
[arg_type
].name
,
897 ZROUTE_NAME(arg_type
));
899 ospf6_zebra_no_redistribute(arg_type
);
900 ospf6_zebra_redistribute(arg_type
);
903 XFREE(MTYPE_OSPF6_DIST_ARGS
, arg
);
907 void ospf6_asbr_distribute_list_update(int type
)
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",
921 __PRETTY_FUNCTION__
, ZROUTE_NAME(type
));
923 ospf6
->t_distribute_update
= NULL
;
924 thread_add_timer_msec(master
, ospf6_asbr_routemap_update_timer
,
925 (void **)args
, OSPF_MIN_LS_INTERVAL
,
926 &ospf6
->t_distribute_update
);
929 static void ospf6_asbr_routemap_update(const char *mapname
)
936 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
937 if (ospf6
->rmap
[type
].name
) {
938 ospf6
->rmap
[type
].map
= route_map_lookup_by_name(
939 ospf6
->rmap
[type
].name
);
941 if (mapname
&& ospf6
->rmap
[type
].map
942 && (strcmp(ospf6
->rmap
[type
].name
, mapname
) == 0)) {
943 if (IS_OSPF6_DEBUG_ASBR
)
945 "%s: route-map %s update, reset redist %s",
946 __PRETTY_FUNCTION__
, mapname
,
949 route_map_counter_increment(
950 ospf6
->rmap
[type
].map
);
952 ospf6_asbr_distribute_list_update(type
);
955 ospf6
->rmap
[type
].map
= NULL
;
959 static void ospf6_asbr_routemap_event(const char *name
)
965 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
966 if ((ospf6
->rmap
[type
].name
)
967 && (strcmp(ospf6
->rmap
[type
].name
, name
) == 0)) {
968 ospf6_asbr_distribute_list_update(type
);
973 int ospf6_asbr_is_asbr(struct ospf6
*o
)
975 return o
->external_table
->count
;
978 static void ospf6_asbr_redistribute_set(int type
)
980 ospf6_zebra_redistribute(type
);
983 static void ospf6_asbr_redistribute_unset(int type
)
985 struct ospf6_route
*route
;
986 struct ospf6_external_info
*info
;
988 ospf6_zebra_no_redistribute(type
);
990 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
991 route
= ospf6_route_next(route
)) {
992 info
= route
->route_option
;
993 if (info
->type
!= type
)
996 ospf6_asbr_redistribute_remove(info
->type
, 0, &route
->prefix
);
999 ospf6_asbr_routemap_unset(type
);
1002 /* When an area is unstubified, flood all the external LSAs in the area */
1003 void ospf6_asbr_send_externals_to_area(struct ospf6_area
*oa
)
1005 struct ospf6_lsa
*lsa
;
1007 for (ALL_LSDB(oa
->ospf6
->lsdb
, lsa
)) {
1008 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
) {
1009 zlog_debug("%s: Flooding AS-External LSA %s",
1010 __func__
, lsa
->name
);
1011 ospf6_flood_area(NULL
, lsa
, oa
);
1016 void ospf6_asbr_redistribute_add(int type
, ifindex_t ifindex
,
1017 struct prefix
*prefix
,
1018 unsigned int nexthop_num
,
1019 struct in6_addr
*nexthop
, route_tag_t tag
)
1021 route_map_result_t ret
;
1022 struct ospf6_route troute
;
1023 struct ospf6_external_info tinfo
;
1024 struct ospf6_route
*route
, *match
;
1025 struct ospf6_external_info
*info
;
1026 struct prefix prefix_id
;
1027 struct route_node
*node
;
1028 char pbuf
[PREFIX2STR_BUFFER
], ibuf
[16];
1029 struct listnode
*lnode
, *lnnode
;
1030 struct ospf6_area
*oa
;
1032 if (!ospf6_zebra_is_redistribute(type
))
1035 memset(&troute
, 0, sizeof(troute
));
1036 memset(&tinfo
, 0, sizeof(tinfo
));
1038 if (IS_OSPF6_DEBUG_ASBR
) {
1039 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1040 zlog_debug("Redistribute %s (%s)", pbuf
, ZROUTE_NAME(type
));
1043 /* if route-map was specified but not found, do not advertise */
1044 if (ospf6
->rmap
[type
].name
) {
1045 if (ospf6
->rmap
[type
].map
== NULL
)
1046 ospf6_asbr_routemap_update(NULL
);
1047 if (ospf6
->rmap
[type
].map
== NULL
) {
1049 "route-map \"%s\" not found, suppress redistributing",
1050 ospf6
->rmap
[type
].name
);
1055 /* apply route-map */
1056 if (ospf6
->rmap
[type
].map
) {
1057 troute
.route_option
= &tinfo
;
1058 tinfo
.ifindex
= ifindex
;
1061 ret
= route_map_apply(ospf6
->rmap
[type
].map
, prefix
, RMAP_OSPF6
,
1063 if (ret
== RMAP_DENYMATCH
) {
1064 if (IS_OSPF6_DEBUG_ASBR
)
1065 zlog_debug("Denied by route-map \"%s\"",
1066 ospf6
->rmap
[type
].name
);
1071 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1073 info
= match
->route_option
;
1074 /* copy result of route-map */
1075 if (ospf6
->rmap
[type
].map
) {
1076 if (troute
.path
.metric_type
)
1077 match
->path
.metric_type
=
1078 troute
.path
.metric_type
;
1079 if (troute
.path
.cost
)
1080 match
->path
.cost
= troute
.path
.cost
;
1081 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1082 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1083 sizeof(struct in6_addr
));
1084 info
->tag
= tinfo
.tag
;
1086 /* If there is no route-map, simply update the tag */
1092 if (nexthop_num
&& nexthop
)
1093 ospf6_route_add_nexthop(match
, ifindex
, nexthop
);
1095 ospf6_route_add_nexthop(match
, ifindex
, NULL
);
1097 /* create/update binding in external_id_table */
1098 prefix_id
.family
= AF_INET
;
1099 prefix_id
.prefixlen
= 32;
1100 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1101 node
= route_node_get(ospf6
->external_id_table
, &prefix_id
);
1104 if (IS_OSPF6_DEBUG_ASBR
) {
1105 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
,
1107 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1109 "Advertise as AS-External Id:%s prefix %s metric %u",
1110 ibuf
, pbuf
, match
->path
.metric_type
);
1113 match
->path
.origin
.id
= htonl(info
->id
);
1114 ospf6_as_external_lsa_originate(match
);
1118 /* create new entry */
1119 route
= ospf6_route_create();
1120 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
1121 memcpy(&route
->prefix
, prefix
, sizeof(struct prefix
));
1123 info
= (struct ospf6_external_info
*)XCALLOC(
1124 MTYPE_OSPF6_EXTERNAL_INFO
, sizeof(struct ospf6_external_info
));
1125 route
->route_option
= info
;
1126 info
->id
= ospf6
->external_id
++;
1128 /* copy result of route-map */
1129 if (ospf6
->rmap
[type
].map
) {
1130 if (troute
.path
.metric_type
)
1131 route
->path
.metric_type
= troute
.path
.metric_type
;
1132 if (troute
.path
.cost
)
1133 route
->path
.cost
= troute
.path
.cost
;
1134 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1135 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1136 sizeof(struct in6_addr
));
1137 info
->tag
= tinfo
.tag
;
1139 /* If there is no route-map, simply set the tag */
1144 if (nexthop_num
&& nexthop
)
1145 ospf6_route_add_nexthop(route
, ifindex
, nexthop
);
1147 ospf6_route_add_nexthop(route
, ifindex
, NULL
);
1149 /* create/update binding in external_id_table */
1150 prefix_id
.family
= AF_INET
;
1151 prefix_id
.prefixlen
= 32;
1152 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1153 node
= route_node_get(ospf6
->external_id_table
, &prefix_id
);
1156 route
= ospf6_route_add(route
, ospf6
->external_table
);
1157 route
->route_option
= info
;
1159 if (IS_OSPF6_DEBUG_ASBR
) {
1160 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
, sizeof(ibuf
));
1161 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1162 zlog_debug("Advertise as AS-External Id:%s prefix %s metric %u",
1163 ibuf
, pbuf
, route
->path
.metric_type
);
1166 route
->path
.origin
.id
= htonl(info
->id
);
1167 ospf6_as_external_lsa_originate(route
);
1169 /* Router-Bit (ASBR Flag) may have to be updated */
1170 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1171 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1174 void ospf6_asbr_redistribute_remove(int type
, ifindex_t ifindex
,
1175 struct prefix
*prefix
)
1177 struct ospf6_route
*match
;
1178 struct ospf6_external_info
*info
= NULL
;
1179 struct route_node
*node
;
1180 struct ospf6_lsa
*lsa
;
1181 struct prefix prefix_id
;
1182 char pbuf
[PREFIX2STR_BUFFER
], ibuf
[16];
1183 struct listnode
*lnode
, *lnnode
;
1184 struct ospf6_area
*oa
;
1186 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1187 if (match
== NULL
) {
1188 if (IS_OSPF6_DEBUG_ASBR
) {
1189 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1190 zlog_debug("No such route %s to withdraw", pbuf
);
1195 info
= match
->route_option
;
1198 if (info
->type
!= type
) {
1199 if (IS_OSPF6_DEBUG_ASBR
) {
1200 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1201 zlog_debug("Original protocol mismatch: %s", pbuf
);
1206 if (IS_OSPF6_DEBUG_ASBR
) {
1207 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1208 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
, sizeof(ibuf
));
1209 zlog_debug("Withdraw %s (AS-External Id:%s)", pbuf
, ibuf
);
1212 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
1213 htonl(info
->id
), ospf6
->router_id
, ospf6
->lsdb
);
1215 ospf6_lsa_purge(lsa
);
1217 /* remove binding in external_id_table */
1218 prefix_id
.family
= AF_INET
;
1219 prefix_id
.prefixlen
= 32;
1220 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1221 node
= route_node_lookup(ospf6
->external_id_table
, &prefix_id
);
1224 route_unlock_node(node
); /* to free the lookup lock */
1225 route_unlock_node(node
); /* to free the original lock */
1227 ospf6_route_remove(match
, ospf6
->external_table
);
1228 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
, info
);
1230 /* Router-Bit (ASBR Flag) may have to be updated */
1231 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1232 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1235 DEFUN (ospf6_redistribute
,
1236 ospf6_redistribute_cmd
,
1237 "redistribute " FRR_REDIST_STR_OSPF6D
,
1239 FRR_REDIST_HELP_STR_OSPF6D
)
1243 char *proto
= argv
[argc
- 1]->text
;
1244 type
= proto_redistnum(AFI_IP6
, proto
);
1246 return CMD_WARNING_CONFIG_FAILED
;
1248 ospf6_asbr_redistribute_unset(type
);
1249 ospf6_asbr_redistribute_set(type
);
1253 DEFUN (ospf6_redistribute_routemap
,
1254 ospf6_redistribute_routemap_cmd
,
1255 "redistribute " FRR_REDIST_STR_OSPF6D
" route-map WORD",
1257 FRR_REDIST_HELP_STR_OSPF6D
1258 "Route map reference\n"
1261 int idx_protocol
= 1;
1265 char *proto
= argv
[idx_protocol
]->text
;
1266 type
= proto_redistnum(AFI_IP6
, proto
);
1268 return CMD_WARNING_CONFIG_FAILED
;
1270 ospf6_asbr_redistribute_unset(type
);
1271 ospf6_asbr_routemap_set(type
, argv
[idx_word
]->arg
);
1272 ospf6_asbr_redistribute_set(type
);
1276 DEFUN (no_ospf6_redistribute
,
1277 no_ospf6_redistribute_cmd
,
1278 "no redistribute " FRR_REDIST_STR_OSPF6D
" [route-map WORD]",
1281 FRR_REDIST_HELP_STR_OSPF6D
1282 "Route map reference\n"
1285 int idx_protocol
= 2;
1288 char *proto
= argv
[idx_protocol
]->text
;
1289 type
= proto_redistnum(AFI_IP6
, proto
);
1291 return CMD_WARNING_CONFIG_FAILED
;
1293 ospf6_asbr_redistribute_unset(type
);
1298 int ospf6_redistribute_config_write(struct vty
*vty
)
1302 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1303 if (type
== ZEBRA_ROUTE_OSPF6
)
1305 if (!ospf6_zebra_is_redistribute(type
))
1308 if (ospf6
->rmap
[type
].name
)
1309 vty_out(vty
, " redistribute %s route-map %s\n",
1310 ZROUTE_NAME(type
), ospf6
->rmap
[type
].name
);
1312 vty_out(vty
, " redistribute %s\n", ZROUTE_NAME(type
));
1318 static void ospf6_redistribute_show_config(struct vty
*vty
)
1321 int nroute
[ZEBRA_ROUTE_MAX
];
1323 struct ospf6_route
*route
;
1324 struct ospf6_external_info
*info
;
1327 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++)
1329 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1330 route
= ospf6_route_next(route
)) {
1331 info
= route
->route_option
;
1332 nroute
[info
->type
]++;
1336 vty_out(vty
, "Redistributing External Routes from:\n");
1337 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1338 if (type
== ZEBRA_ROUTE_OSPF6
)
1340 if (!ospf6_zebra_is_redistribute(type
))
1343 if (ospf6
->rmap
[type
].name
)
1344 vty_out(vty
, " %d: %s with route-map \"%s\"%s\n",
1345 nroute
[type
], ZROUTE_NAME(type
),
1346 ospf6
->rmap
[type
].name
,
1347 (ospf6
->rmap
[type
].map
? ""
1348 : " (not found !)"));
1350 vty_out(vty
, " %d: %s\n", nroute
[type
],
1353 vty_out(vty
, "Total %d routes\n", total
);
1357 /* Routemap Functions */
1358 static enum route_map_cmd_result_t
1359 ospf6_routemap_rule_match_address_prefixlist(void *rule
,
1360 const struct prefix
*prefix
,
1361 route_map_object_t type
,
1364 struct prefix_list
*plist
;
1366 if (type
!= RMAP_OSPF6
)
1367 return RMAP_NOMATCH
;
1369 plist
= prefix_list_lookup(AFI_IP6
, (char *)rule
);
1371 return RMAP_NOMATCH
;
1373 return (prefix_list_apply(plist
, prefix
) == PREFIX_DENY
? RMAP_NOMATCH
1378 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg
)
1380 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1383 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule
)
1385 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1388 struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd
= {
1389 "ipv6 address prefix-list",
1390 ospf6_routemap_rule_match_address_prefixlist
,
1391 ospf6_routemap_rule_match_address_prefixlist_compile
,
1392 ospf6_routemap_rule_match_address_prefixlist_free
,
1395 /* `match interface IFNAME' */
1396 /* Match function should return 1 if match is success else return
1398 static enum route_map_cmd_result_t
1399 ospf6_routemap_rule_match_interface(void *rule
, const struct prefix
*prefix
,
1400 route_map_object_t type
, void *object
)
1402 struct interface
*ifp
;
1403 struct ospf6_external_info
*ei
;
1405 if (type
== RMAP_OSPF6
) {
1406 ei
= ((struct ospf6_route
*)object
)->route_option
;
1407 ifp
= if_lookup_by_name((char *)rule
, VRF_DEFAULT
);
1409 if (ifp
!= NULL
&& ei
->ifindex
== ifp
->ifindex
)
1413 return RMAP_NOMATCH
;
1416 /* Route map `interface' match statement. `arg' should be
1418 static void *ospf6_routemap_rule_match_interface_compile(const char *arg
)
1420 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1423 /* Free route map's compiled `interface' value. */
1424 static void ospf6_routemap_rule_match_interface_free(void *rule
)
1426 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1429 /* Route map commands for interface matching. */
1430 struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd
= {
1431 "interface", ospf6_routemap_rule_match_interface
,
1432 ospf6_routemap_rule_match_interface_compile
,
1433 ospf6_routemap_rule_match_interface_free
};
1435 /* Match function for matching route tags */
1436 static enum route_map_cmd_result_t
1437 ospf6_routemap_rule_match_tag(void *rule
, const struct prefix
*p
,
1438 route_map_object_t type
, void *object
)
1440 route_tag_t
*tag
= rule
;
1441 struct ospf6_route
*route
= object
;
1442 struct ospf6_external_info
*info
= route
->route_option
;
1444 if (type
== RMAP_OSPF6
&& info
->tag
== *tag
)
1447 return RMAP_NOMATCH
;
1450 static struct route_map_rule_cmd ospf6_routemap_rule_match_tag_cmd
= {
1451 "tag", ospf6_routemap_rule_match_tag
, route_map_rule_tag_compile
,
1452 route_map_rule_tag_free
,
1455 static enum route_map_cmd_result_t
1456 ospf6_routemap_rule_set_metric_type(void *rule
, const struct prefix
*prefix
,
1457 route_map_object_t type
, void *object
)
1459 char *metric_type
= rule
;
1460 struct ospf6_route
*route
= object
;
1462 if (type
!= RMAP_OSPF6
)
1465 if (strcmp(metric_type
, "type-2") == 0)
1466 route
->path
.metric_type
= 2;
1468 route
->path
.metric_type
= 1;
1473 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg
)
1475 if (strcmp(arg
, "type-2") && strcmp(arg
, "type-1"))
1477 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1480 static void ospf6_routemap_rule_set_metric_type_free(void *rule
)
1482 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1485 struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd
= {
1486 "metric-type", ospf6_routemap_rule_set_metric_type
,
1487 ospf6_routemap_rule_set_metric_type_compile
,
1488 ospf6_routemap_rule_set_metric_type_free
,
1491 static enum route_map_cmd_result_t
1492 ospf6_routemap_rule_set_metric(void *rule
, const struct prefix
*prefix
,
1493 route_map_object_t type
, void *object
)
1495 char *metric
= rule
;
1496 struct ospf6_route
*route
= object
;
1498 if (type
!= RMAP_OSPF6
)
1501 route
->path
.cost
= atoi(metric
);
1505 static void *ospf6_routemap_rule_set_metric_compile(const char *arg
)
1509 metric
= strtoul(arg
, &endp
, 0);
1510 if (metric
> OSPF_LS_INFINITY
|| *endp
!= '\0')
1512 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1515 static void ospf6_routemap_rule_set_metric_free(void *rule
)
1517 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1520 struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd
= {
1521 "metric", ospf6_routemap_rule_set_metric
,
1522 ospf6_routemap_rule_set_metric_compile
,
1523 ospf6_routemap_rule_set_metric_free
,
1526 static enum route_map_cmd_result_t
1527 ospf6_routemap_rule_set_forwarding(void *rule
, const struct prefix
*prefix
,
1528 route_map_object_t type
, void *object
)
1530 char *forwarding
= rule
;
1531 struct ospf6_route
*route
= object
;
1532 struct ospf6_external_info
*info
= route
->route_option
;
1534 if (type
!= RMAP_OSPF6
)
1537 if (inet_pton(AF_INET6
, forwarding
, &info
->forwarding
) != 1) {
1538 memset(&info
->forwarding
, 0, sizeof(struct in6_addr
));
1545 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg
)
1548 if (inet_pton(AF_INET6
, arg
, &a
) != 1)
1550 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1553 static void ospf6_routemap_rule_set_forwarding_free(void *rule
)
1555 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1558 struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd
= {
1559 "forwarding-address", ospf6_routemap_rule_set_forwarding
,
1560 ospf6_routemap_rule_set_forwarding_compile
,
1561 ospf6_routemap_rule_set_forwarding_free
,
1564 static enum route_map_cmd_result_t
1565 ospf6_routemap_rule_set_tag(void *rule
, const struct prefix
*p
,
1566 route_map_object_t type
, void *object
)
1568 route_tag_t
*tag
= rule
;
1569 struct ospf6_route
*route
= object
;
1570 struct ospf6_external_info
*info
= route
->route_option
;
1572 if (type
!= RMAP_OSPF6
)
1579 static struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd
= {
1580 "tag", ospf6_routemap_rule_set_tag
, route_map_rule_tag_compile
,
1581 route_map_rule_tag_free
,
1584 static int route_map_command_status(struct vty
*vty
, enum rmap_compile_rets ret
)
1587 case RMAP_RULE_MISSING
:
1588 vty_out(vty
, "OSPF6 Can't find rule.\n");
1589 return CMD_WARNING_CONFIG_FAILED
;
1591 case RMAP_COMPILE_ERROR
:
1592 vty_out(vty
, "OSPF6 Argument is malformed.\n");
1593 return CMD_WARNING_CONFIG_FAILED
;
1595 case RMAP_COMPILE_SUCCESS
:
1596 case RMAP_DUPLICATE_RULE
:
1603 /* add "set metric-type" */
1604 DEFUN (ospf6_routemap_set_metric_type
,
1605 ospf6_routemap_set_metric_type_cmd
,
1606 "set metric-type <type-1|type-2>",
1609 "OSPF6 external type 1 metric\n"
1610 "OSPF6 external type 2 metric\n")
1612 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1613 int idx_external
= 2;
1614 enum rmap_compile_rets ret
= route_map_add_set(route_map_index
,
1616 argv
[idx_external
]->arg
);
1618 return route_map_command_status(vty
, ret
);
1621 /* delete "set metric-type" */
1622 DEFUN (ospf6_routemap_no_set_metric_type
,
1623 ospf6_routemap_no_set_metric_type_cmd
,
1624 "no set metric-type [<type-1|type-2>]",
1628 "OSPF6 external type 1 metric\n"
1629 "OSPF6 external type 2 metric\n")
1631 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1632 char *ext
= (argc
== 4) ? argv
[3]->text
: NULL
;
1633 enum rmap_compile_rets ret
= route_map_delete_set(route_map_index
,
1634 "metric-type", ext
);
1636 return route_map_command_status(vty
, ret
);
1639 /* add "set forwarding-address" */
1640 DEFUN (ospf6_routemap_set_forwarding
,
1641 ospf6_routemap_set_forwarding_cmd
,
1642 "set forwarding-address X:X::X:X",
1644 "Forwarding Address\n"
1647 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1649 enum rmap_compile_rets ret
= route_map_add_set(route_map_index
,
1650 "forwarding-address",
1651 argv
[idx_ipv6
]->arg
);
1653 return route_map_command_status(vty
, ret
);
1656 /* delete "set forwarding-address" */
1657 DEFUN (ospf6_routemap_no_set_forwarding
,
1658 ospf6_routemap_no_set_forwarding_cmd
,
1659 "no set forwarding-address X:X::X:X",
1662 "Forwarding Address\n"
1665 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1667 enum rmap_compile_rets ret
= route_map_delete_set(route_map_index
,
1668 "forwarding-address",
1669 argv
[idx_ipv6
]->arg
);
1671 return route_map_command_status(vty
, ret
);
1674 static void ospf6_routemap_init(void)
1678 route_map_add_hook(ospf6_asbr_routemap_update
);
1679 route_map_delete_hook(ospf6_asbr_routemap_update
);
1680 route_map_event_hook(ospf6_asbr_routemap_event
);
1682 route_map_set_metric_hook(generic_set_add
);
1683 route_map_no_set_metric_hook(generic_set_delete
);
1685 route_map_match_tag_hook(generic_match_add
);
1686 route_map_no_match_tag_hook(generic_match_delete
);
1688 route_map_match_ipv6_address_prefix_list_hook(generic_match_add
);
1689 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete
);
1691 route_map_match_interface_hook(generic_match_add
);
1692 route_map_no_match_interface_hook(generic_match_delete
);
1694 route_map_install_match(
1695 &ospf6_routemap_rule_match_address_prefixlist_cmd
);
1696 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd
);
1697 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd
);
1699 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd
);
1700 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd
);
1701 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd
);
1702 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd
);
1704 /* ASE Metric Type (e.g. Type-1/Type-2) */
1705 install_element(RMAP_NODE
, &ospf6_routemap_set_metric_type_cmd
);
1706 install_element(RMAP_NODE
, &ospf6_routemap_no_set_metric_type_cmd
);
1709 install_element(RMAP_NODE
, &ospf6_routemap_set_forwarding_cmd
);
1710 install_element(RMAP_NODE
, &ospf6_routemap_no_set_forwarding_cmd
);
1714 /* Display functions */
1715 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1716 char *buf
, int buflen
,
1719 struct ospf6_as_external_lsa
*external
;
1720 struct in6_addr in6
;
1721 int prefix_length
= 0;
1724 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1728 ospf6_prefix_in6_addr(&in6
, external
,
1730 prefix_length
= external
->prefix
.prefix_length
;
1732 in6
= *((struct in6_addr
1733 *)((caddr_t
)external
1735 ospf6_as_external_lsa
)
1736 + OSPF6_PREFIX_SPACE(
1741 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
1743 sprintf(&buf
[strlen(buf
)], "/%d",
1750 static int ospf6_as_external_lsa_show(struct vty
*vty
, struct ospf6_lsa
*lsa
)
1752 struct ospf6_as_external_lsa
*external
;
1755 assert(lsa
->header
);
1756 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1760 snprintf(buf
, sizeof(buf
), "%c%c%c",
1761 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
) ? 'E'
1763 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
) ? 'F'
1765 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
) ? 'T'
1768 vty_out(vty
, " Bits: %s\n", buf
);
1769 vty_out(vty
, " Metric: %5lu\n",
1770 (unsigned long)OSPF6_ASBR_METRIC(external
));
1772 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
, buf
,
1774 vty_out(vty
, " Prefix Options: %s\n", buf
);
1776 vty_out(vty
, " Referenced LSType: %d\n",
1777 ntohs(external
->prefix
.prefix_refer_lstype
));
1779 vty_out(vty
, " Prefix: %s\n",
1780 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
, sizeof(buf
), 0));
1782 /* Forwarding-Address */
1783 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
1784 vty_out(vty
, " Forwarding-Address: %s\n",
1785 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
,
1790 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
1791 vty_out(vty
, " Tag: %" ROUTE_TAG_PRI
"\n",
1792 ospf6_as_external_lsa_get_tag(lsa
));
1798 static void ospf6_asbr_external_route_show(struct vty
*vty
,
1799 struct ospf6_route
*route
)
1801 struct ospf6_external_info
*info
= route
->route_option
;
1802 char prefix
[PREFIX2STR_BUFFER
], id
[16], forwarding
[64];
1805 prefix2str(&route
->prefix
, prefix
, sizeof(prefix
));
1806 tmp_id
= ntohl(info
->id
);
1807 inet_ntop(AF_INET
, &tmp_id
, id
, sizeof(id
));
1808 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
1809 inet_ntop(AF_INET6
, &info
->forwarding
, forwarding
,
1810 sizeof(forwarding
));
1812 snprintf(forwarding
, sizeof(forwarding
), ":: (ifindex %d)",
1813 ospf6_route_get_first_nh_index(route
));
1815 vty_out(vty
, "%c %-32s %-15s type-%d %5lu %s\n",
1816 zebra_route_char(info
->type
), prefix
, id
,
1817 route
->path
.metric_type
,
1818 (unsigned long)(route
->path
.metric_type
== 2
1819 ? route
->path
.u
.cost_e2
1820 : route
->path
.cost
),
1824 DEFUN (show_ipv6_ospf6_redistribute
,
1825 show_ipv6_ospf6_redistribute_cmd
,
1826 "show ipv6 ospf6 redistribute",
1830 "redistributing External information\n"
1833 struct ospf6_route
*route
;
1835 OSPF6_CMD_CHECK_RUNNING();
1837 ospf6_redistribute_show_config(vty
);
1839 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1840 route
= ospf6_route_next(route
))
1841 ospf6_asbr_external_route_show(vty
, route
);
1846 struct ospf6_lsa_handler as_external_handler
= {
1847 .lh_type
= OSPF6_LSTYPE_AS_EXTERNAL
,
1848 .lh_name
= "AS-External",
1849 .lh_short_name
= "ASE",
1850 .lh_show
= ospf6_as_external_lsa_show
,
1851 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
1854 void ospf6_asbr_init(void)
1856 ospf6_routemap_init();
1858 ospf6_install_lsa_handler(&as_external_handler
);
1860 install_element(VIEW_NODE
, &show_ipv6_ospf6_redistribute_cmd
);
1862 install_element(OSPF6_NODE
, &ospf6_redistribute_cmd
);
1863 install_element(OSPF6_NODE
, &ospf6_redistribute_routemap_cmd
);
1864 install_element(OSPF6_NODE
, &no_ospf6_redistribute_cmd
);
1867 void ospf6_asbr_redistribute_reset(void)
1871 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1872 if (type
== ZEBRA_ROUTE_OSPF6
)
1874 if (ospf6_zebra_is_redistribute(type
))
1875 ospf6_asbr_redistribute_unset(type
);
1879 void ospf6_asbr_terminate(void)
1881 /* Cleanup route maps */
1885 DEFUN (debug_ospf6_asbr
,
1886 debug_ospf6_asbr_cmd
,
1890 "Debug OSPFv3 ASBR function\n"
1893 OSPF6_DEBUG_ASBR_ON();
1897 DEFUN (no_debug_ospf6_asbr
,
1898 no_debug_ospf6_asbr_cmd
,
1899 "no debug ospf6 asbr",
1903 "Debug OSPFv3 ASBR function\n"
1906 OSPF6_DEBUG_ASBR_OFF();
1910 int config_write_ospf6_debug_asbr(struct vty
*vty
)
1912 if (IS_OSPF6_DEBUG_ASBR
)
1913 vty_out(vty
, "debug ospf6 asbr\n");
1917 void install_element_ospf6_debug_asbr(void)
1919 install_element(ENABLE_NODE
, &debug_ospf6_asbr_cmd
);
1920 install_element(ENABLE_NODE
, &no_debug_ospf6_asbr_cmd
);
1921 install_element(CONFIG_NODE
, &debug_ospf6_asbr_cmd
);
1922 install_element(CONFIG_NODE
, &no_debug_ospf6_asbr_cmd
);