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
)
167 zlog_debug("%s: Send update of AS-External LSA %s seq 0x%x",
168 __PRETTY_FUNCTION__
, lsa
->name
,
169 ntohl(lsa
->header
->seqnum
));
171 ospf6_flood_interface(NULL
, lsa
, oi
);
177 static route_tag_t
ospf6_as_external_lsa_get_tag(struct ospf6_lsa
*lsa
)
179 struct ospf6_as_external_lsa
*external
;
180 ptrdiff_t tag_offset
;
181 route_tag_t network_order
;
186 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
189 if (!CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
))
192 tag_offset
= sizeof(*external
)
193 + OSPF6_PREFIX_SPACE(external
->prefix
.prefix_length
);
194 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
))
195 tag_offset
+= sizeof(struct in6_addr
);
197 memcpy(&network_order
, (caddr_t
)external
+ tag_offset
,
198 sizeof(network_order
));
199 return ntohl(network_order
);
202 void ospf6_asbr_update_route_ecmp_path(struct ospf6_route
*old
,
203 struct ospf6_route
*route
)
205 struct ospf6_route
*old_route
;
206 struct ospf6_path
*ecmp_path
, *o_path
= NULL
;
207 struct listnode
*anode
, *anext
;
208 struct listnode
*nnode
, *rnode
, *rnext
;
209 struct ospf6_nexthop
*nh
, *rnh
;
210 char buf
[PREFIX2STR_BUFFER
];
211 bool route_found
= false;
213 /* check for old entry match with new route origin,
216 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
217 bool route_updated
= false;
219 if (!ospf6_route_is_same(old_route
, route
) ||
220 (old_route
->path
.type
!= route
->path
.type
))
223 /* Current and New route has same origin,
226 for (ALL_LIST_ELEMENTS(old_route
->paths
, anode
, anext
,
228 /* Check old route path and route has same
231 if (o_path
->area_id
!= route
->path
.area_id
||
232 (memcmp(&(o_path
)->origin
, &(route
)->path
.origin
,
233 sizeof(struct ospf6_ls_origin
)) != 0))
236 /* Cost is not same then delete current path */
237 if ((o_path
->cost
== route
->path
.cost
) &&
238 (o_path
->u
.cost_e2
== route
->path
.u
.cost_e2
))
241 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
242 prefix2str(&old_route
->prefix
, buf
,
244 zlog_debug("%s: route %s cost old %u new %u is not same, replace route",
245 __PRETTY_FUNCTION__
, buf
,
246 o_path
->cost
, route
->path
.cost
);
249 /* Remove selected current rout path's nh from
252 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
, nnode
, nh
)) {
253 for (ALL_LIST_ELEMENTS(old_route
->nh_list
,
254 rnode
, rnext
, rnh
)) {
255 if (!ospf6_nexthop_is_same(rnh
, nh
))
257 listnode_delete(old_route
->nh_list
,
259 ospf6_nexthop_delete(rnh
);
260 route_updated
= true;
264 listnode_delete(old_route
->paths
, o_path
);
265 ospf6_path_free(o_path
);
267 /* Current route's path (adv_router info) is similar
268 * to route being added.
269 * Replace current route's path with paths list head.
270 * Update FIB with effective NHs.
272 if (listcount(old_route
->paths
)) {
273 if (old_route
->path
.origin
.id
==
274 route
->path
.origin
.id
&&
275 old_route
->path
.origin
.adv_router
==
276 route
->path
.origin
.adv_router
) {
277 struct ospf6_path
*h_path
;
279 h_path
= (struct ospf6_path
*)
280 listgetdata(listhead(old_route
->paths
));
281 old_route
->path
.origin
.type
=
283 old_route
->path
.origin
.id
=
285 old_route
->path
.origin
.adv_router
=
286 h_path
->origin
.adv_router
;
290 for (ALL_LIST_ELEMENTS(old_route
->paths
,
291 anode
, anext
, o_path
)) {
292 ospf6_merge_nexthops(
296 /* Update RIB/FIB with effective
299 if (ospf6
->route_table
->hook_add
)
300 (*ospf6
->route_table
->hook_add
)
305 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
306 prefix2str(&old_route
->prefix
, buf
,
308 zlog_debug("%s: route %s old cost %u new cost %u, delete old entry.",
309 __PRETTY_FUNCTION__
, buf
,
310 old_route
->path
.cost
,
313 ospf6_route_remove(old_route
,
323 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
325 /* Current and New Route prefix or route type
326 * is not same skip this current node.
328 if (!ospf6_route_is_same(old_route
, route
) ||
329 (old_route
->path
.type
!= route
->path
.type
))
332 /* Old Route and New Route have Equal Cost, Merge NHs */
333 if ((old_route
->path
.cost
== route
->path
.cost
) &&
334 (old_route
->path
.u
.cost_e2
== route
->path
.u
.cost_e2
)) {
336 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
337 prefix2str(&old_route
->prefix
, buf
,
339 zlog_debug("%s: old route %s path cost %u e2 %u",
340 __PRETTY_FUNCTION__
, buf
,
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
)) == 0))
357 /* If path is not found in old_route paths's list,
358 * add a new path to route paths list and merge
359 * nexthops in route->path->nh_list.
360 * Otherwise replace existing path's nh_list.
362 if (o_path
== NULL
) {
363 ecmp_path
= ospf6_path_dup(&route
->path
);
365 /* Add a nh_list to new ecmp path */
366 ospf6_copy_nexthops(ecmp_path
->nh_list
,
368 /* Merge nexthop to existing route's nh_list */
369 ospf6_route_merge_nexthops(old_route
, route
);
372 if (ospf6
->route_table
->hook_add
)
373 (*ospf6
->route_table
->hook_add
)
376 /* Add the new path to route's path list */
377 listnode_add_sort(old_route
->paths
, ecmp_path
);
379 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
380 prefix2str(&route
->prefix
, buf
,
382 zlog_debug("%s: route %s another path added with nh %u, effective paths %u nh %u",
383 __PRETTY_FUNCTION__
, buf
,
384 listcount(ecmp_path
->nh_list
),
386 listcount(old_route
->paths
)
388 listcount(old_route
->nh_list
));
391 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
,
393 for (ALL_LIST_ELEMENTS(
395 rnode
, rnext
, rnh
)) {
396 if (!ospf6_nexthop_is_same(rnh
,
403 ospf6_nexthop_delete(rnh
);
406 list_delete_all_node(o_path
->nh_list
);
407 ospf6_copy_nexthops(o_path
->nh_list
,
410 /* Merge nexthop to existing route's nh_list */
411 ospf6_route_merge_nexthops(old_route
,
414 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
415 prefix2str(&route
->prefix
,
417 zlog_debug("%s: existing route %s with effective nh count %u",
418 __PRETTY_FUNCTION__
, buf
,
420 listcount(old_route
->nh_list
)
425 if (ospf6
->route_table
->hook_add
)
426 (*ospf6
->route_table
->hook_add
)
430 /* Delete the new route its info added to existing
433 ospf6_route_delete(route
);
440 /* Add new route to existing node in ospf6 route table. */
441 ospf6_route_add(route
, ospf6
->route_table
);
445 void ospf6_asbr_lsa_add(struct ospf6_lsa
*lsa
)
447 struct ospf6_as_external_lsa
*external
;
448 struct prefix asbr_id
;
449 struct ospf6_route
*asbr_entry
, *route
, *old
;
450 struct ospf6_path
*path
;
451 char buf
[PREFIX2STR_BUFFER
];
453 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
456 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
457 zlog_debug("Calculate AS-External route for %s", lsa
->name
);
459 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
460 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
461 zlog_debug("Ignore self-originated AS-External-LSA");
465 if (OSPF6_ASBR_METRIC(external
) == OSPF_LS_INFINITY
) {
466 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
467 zlog_debug("Ignore LSA with LSInfinity Metric");
471 if (CHECK_FLAG(external
->prefix
.prefix_options
,
472 OSPF6_PREFIX_OPTION_NU
)) {
473 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
474 zlog_debug("Ignore LSA with NU bit set Metric");
478 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &asbr_id
);
479 asbr_entry
= ospf6_route_lookup(&asbr_id
, ospf6
->brouter_table
);
480 if (asbr_entry
== NULL
481 || !CHECK_FLAG(asbr_entry
->path
.router_bits
, OSPF6_ROUTER_BIT_E
)) {
482 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
483 prefix2str(&asbr_id
, buf
, sizeof(buf
));
484 zlog_debug("ASBR entry not found: %s", buf
);
489 route
= ospf6_route_create();
490 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
491 route
->prefix
.family
= AF_INET6
;
492 route
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
493 ospf6_prefix_in6_addr(&route
->prefix
.u
.prefix6
, &external
->prefix
);
495 route
->path
.area_id
= asbr_entry
->path
.area_id
;
496 route
->path
.origin
.type
= lsa
->header
->type
;
497 route
->path
.origin
.id
= lsa
->header
->id
;
498 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
500 route
->path
.prefix_options
= external
->prefix
.prefix_options
;
501 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
502 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
503 route
->path
.metric_type
= 2;
504 route
->path
.cost
= asbr_entry
->path
.cost
;
505 route
->path
.u
.cost_e2
= OSPF6_ASBR_METRIC(external
);
507 route
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
508 route
->path
.metric_type
= 1;
510 asbr_entry
->path
.cost
+ OSPF6_ASBR_METRIC(external
);
511 route
->path
.u
.cost_e2
= 0;
514 route
->path
.tag
= ospf6_as_external_lsa_get_tag(lsa
);
516 ospf6_route_copy_nexthops(route
, asbr_entry
);
518 path
= ospf6_path_dup(&route
->path
);
519 ospf6_copy_nexthops(path
->nh_list
, asbr_entry
->nh_list
);
520 listnode_add_sort(route
->paths
, path
);
523 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
524 prefix2str(&route
->prefix
, buf
, sizeof(buf
));
525 zlog_debug("%s: AS-External %u route add %s cost %u(%u) nh %u",
527 (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
)
528 ? 1 : 2, buf
, route
->path
.cost
,
529 route
->path
.u
.cost_e2
,
530 listcount(route
->nh_list
));
533 old
= ospf6_route_lookup(&route
->prefix
, ospf6
->route_table
);
535 /* Add the new route to ospf6 instance route table. */
536 ospf6_route_add(route
, ospf6
->route_table
);
539 * ECMP: Keep new equal preference path in current
540 * route's path list, update zebra with new effective
541 * list along with addition of ECMP path.
543 ospf6_asbr_update_route_ecmp_path(old
, route
);
548 void ospf6_asbr_lsa_remove(struct ospf6_lsa
*lsa
,
549 struct ospf6_route
*asbr_entry
)
551 struct ospf6_as_external_lsa
*external
;
552 struct prefix prefix
;
553 struct ospf6_route
*route
, *nroute
, *route_to_del
;
554 char buf
[PREFIX2STR_BUFFER
];
556 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
559 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
560 zlog_debug("Withdraw AS-External route for %s", lsa
->name
);
562 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
563 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
))
564 zlog_debug("Ignore self-originated AS-External-LSA");
568 route_to_del
= ospf6_route_create();
569 route_to_del
->type
= OSPF6_DEST_TYPE_NETWORK
;
570 route_to_del
->prefix
.family
= AF_INET6
;
571 route_to_del
->prefix
.prefixlen
= external
->prefix
.prefix_length
;
572 ospf6_prefix_in6_addr(&route_to_del
->prefix
.u
.prefix6
,
575 route_to_del
->path
.origin
.type
= lsa
->header
->type
;
576 route_to_del
->path
.origin
.id
= lsa
->header
->id
;
577 route_to_del
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
580 route_to_del
->path
.area_id
= asbr_entry
->path
.area_id
;
581 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
)) {
582 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL2
;
583 route_to_del
->path
.metric_type
= 2;
584 route_to_del
->path
.cost
= asbr_entry
->path
.cost
;
585 route_to_del
->path
.u
.cost_e2
=
586 OSPF6_ASBR_METRIC(external
);
588 route_to_del
->path
.type
= OSPF6_PATH_TYPE_EXTERNAL1
;
589 route_to_del
->path
.metric_type
= 1;
590 route_to_del
->path
.cost
=
591 asbr_entry
->path
.cost
+
592 OSPF6_ASBR_METRIC(external
);
593 route_to_del
->path
.u
.cost_e2
= 0;
597 memset(&prefix
, 0, sizeof(struct prefix
));
598 prefix
.family
= AF_INET6
;
599 prefix
.prefixlen
= external
->prefix
.prefix_length
;
600 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, &external
->prefix
);
602 route
= ospf6_route_lookup(&prefix
, ospf6
->route_table
);
604 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
605 prefix2str(&prefix
, buf
, sizeof(buf
));
606 zlog_debug("AS-External route %s not found", buf
);
611 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
612 prefix2str(&prefix
, buf
, sizeof(buf
));
613 zlog_debug("%s: Current route %s cost %u e2 %u, route to del cost %u e2 %u",
614 __PRETTY_FUNCTION__
, buf
, route
->path
.cost
,
615 route
->path
.u
.cost_e2
,
616 route_to_del
->path
.cost
,
617 route_to_del
->path
.u
.cost_e2
);
620 for (ospf6_route_lock(route
); route
&&
621 ospf6_route_is_prefix(&prefix
, route
); route
= nroute
) {
622 nroute
= ospf6_route_next(route
);
624 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
)
627 /* Route has multiple ECMP paths, remove matching
628 * path. Update current route's effective nh list
629 * after removal of one of the path.
631 if (listcount(route
->paths
) > 1) {
632 struct listnode
*anode
, *anext
;
633 struct listnode
*nnode
, *rnode
, *rnext
;
634 struct ospf6_nexthop
*nh
, *rnh
;
635 struct ospf6_path
*o_path
;
636 bool nh_updated
= false;
638 /* Iterate all paths of route to find maching with LSA
639 * remove from route path list. If route->path is same,
640 * replace from paths list.
642 for (ALL_LIST_ELEMENTS(route
->paths
, anode
, anext
,
644 if ((o_path
->origin
.type
!= lsa
->header
->type
)
645 || (o_path
->origin
.adv_router
!=
646 lsa
->header
->adv_router
) ||
647 (o_path
->origin
.id
!= lsa
->header
->id
))
650 /* Compare LSA cost with current
653 if (!asbr_entry
&& (o_path
->cost
!=
654 route_to_del
->path
.cost
||
656 route_to_del
->path
.u
.cost_e2
)) {
657 if (IS_OSPF6_DEBUG_EXAMIN(
659 prefix2str(&prefix
, buf
,
662 "%s: route %s to delete is not same, cost %u del cost %u. skip",
663 __PRETTY_FUNCTION__
, buf
,
665 route_to_del
->path
.cost
);
670 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
671 prefix2str(&prefix
, buf
, sizeof(buf
));
673 "%s: route %s path found with nh %u to remove.",
674 __PRETTY_FUNCTION__
, buf
,
675 listcount(o_path
->nh_list
));
678 /* Remove found path's nh_list from
679 * the route's nh_list.
681 for (ALL_LIST_ELEMENTS_RO(o_path
->nh_list
,
683 for (ALL_LIST_ELEMENTS(route
->nh_list
,
684 rnode
, rnext
, rnh
)) {
685 if (!ospf6_nexthop_is_same(rnh
,
688 listnode_delete(route
->nh_list
,
690 ospf6_nexthop_delete(rnh
);
693 /* Delete the path from route's path list */
694 listnode_delete(route
->paths
, o_path
);
695 ospf6_path_free(o_path
);
700 /* Iterate all paths and merge nexthop,
701 * unlesss any of the nexthop similar to
702 * ones deleted as part of path deletion.
705 for (ALL_LIST_ELEMENTS(route
->paths
, anode
,
707 ospf6_merge_nexthops(route
->nh_list
,
711 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
712 prefix2str(&route
->prefix
, buf
,
714 zlog_debug("%s: AS-External %u route %s update paths %u nh %u"
715 , __PRETTY_FUNCTION__
,
717 OSPF6_PATH_TYPE_EXTERNAL1
)
719 listcount(route
->paths
),
720 listcount(route
->nh_list
));
723 /* Update RIB/FIB with effective nh_list */
724 if (ospf6
->route_table
->hook_add
)
725 (*ospf6
->route_table
->hook_add
)(route
);
727 /* route's primary path is similar to LSA,
728 * replace route's primary path with
729 * route's paths list head.
731 if (route
->path
.origin
.id
== lsa
->header
->id
&&
732 route
->path
.origin
.adv_router
==
733 lsa
->header
->adv_router
) {
734 struct ospf6_path
*h_path
;
736 h_path
= (struct ospf6_path
*)
737 listgetdata(listhead(route
->paths
));
738 route
->path
.origin
.type
=
740 route
->path
.origin
.id
=
742 route
->path
.origin
.adv_router
=
743 h_path
->origin
.adv_router
;
749 /* Compare LSA origin and cost with current route info.
750 * if any check fails skip del this route node.
752 if (asbr_entry
&& (!ospf6_route_is_same_origin(route
,
754 (route
->path
.type
!= route_to_del
->path
.type
) ||
755 (route
->path
.cost
!= route_to_del
->path
.cost
) ||
756 (route
->path
.u
.cost_e2
!=
757 route_to_del
->path
.u
.cost_e2
))) {
758 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
759 prefix2str(&prefix
, buf
, sizeof(buf
));
760 zlog_debug("%s: route %s to delete is not same, cost %u del cost %u. skip",
761 __PRETTY_FUNCTION__
, buf
,
763 route_to_del
->path
.cost
);
768 if ((route
->path
.origin
.type
!= lsa
->header
->type
) ||
769 (route
->path
.origin
.adv_router
!=
770 lsa
->header
->adv_router
) ||
771 (route
->path
.origin
.id
!= lsa
->header
->id
))
774 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL
)) {
775 prefix2str(&route
->prefix
, buf
, sizeof(buf
));
776 zlog_debug("%s: AS-External %u route remove %s cost %u(%u) nh %u",
778 route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
779 ? 1 : 2, buf
, route
->path
.cost
,
780 route
->path
.u
.cost_e2
,
781 listcount(route
->nh_list
));
783 ospf6_route_remove(route
, ospf6
->route_table
);
786 ospf6_route_unlock(route
);
788 ospf6_route_delete(route_to_del
);
791 void ospf6_asbr_lsentry_add(struct ospf6_route
*asbr_entry
)
793 struct ospf6_lsa
*lsa
;
797 if (!CHECK_FLAG(asbr_entry
->flag
, OSPF6_ROUTE_BEST
)) {
799 inet_ntop(AF_INET
, &ADV_ROUTER_IN_PREFIX(&asbr_entry
->prefix
),
801 zlog_info("ignore non-best path: lsentry %s add", buf
);
805 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
806 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
807 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
)) {
808 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
809 ospf6_asbr_lsa_add(lsa
);
813 void ospf6_asbr_lsentry_remove(struct ospf6_route
*asbr_entry
)
815 struct ospf6_lsa
*lsa
;
819 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
820 router
= ospf6_linkstate_prefix_adv_router(&asbr_entry
->prefix
);
821 for (ALL_LSDB_TYPED_ADVRTR(ospf6
->lsdb
, type
, router
, lsa
))
822 ospf6_asbr_lsa_remove(lsa
, asbr_entry
);
826 /* redistribute function */
828 static void ospf6_asbr_routemap_set(int type
, const char *mapname
)
830 if (ospf6
->rmap
[type
].name
)
831 free(ospf6
->rmap
[type
].name
);
832 ospf6
->rmap
[type
].name
= strdup(mapname
);
833 ospf6
->rmap
[type
].map
= route_map_lookup_by_name(mapname
);
836 static void ospf6_asbr_routemap_unset(int type
)
838 if (ospf6
->rmap
[type
].name
)
839 free(ospf6
->rmap
[type
].name
);
840 ospf6
->rmap
[type
].name
= NULL
;
841 ospf6
->rmap
[type
].map
= NULL
;
844 static int ospf6_asbr_routemap_update_timer(struct thread
*thread
)
849 arg
= THREAD_ARG(thread
);
850 arg_type
= (int)(intptr_t)arg
[1];
852 ospf6
->t_distribute_update
= NULL
;
854 if (ospf6
->rmap
[arg_type
].name
)
855 ospf6
->rmap
[arg_type
].map
= route_map_lookup_by_name(
856 ospf6
->rmap
[arg_type
].name
);
857 if (ospf6
->rmap
[arg_type
].map
) {
858 if (IS_OSPF6_DEBUG_ASBR
)
859 zlog_debug("%s: route-map %s update, reset redist %s",
861 ospf6
->rmap
[arg_type
].name
,
862 ZROUTE_NAME(arg_type
));
864 ospf6_zebra_no_redistribute(arg_type
);
865 ospf6_zebra_redistribute(arg_type
);
868 XFREE(MTYPE_OSPF6_DIST_ARGS
, arg
);
872 void ospf6_asbr_distribute_list_update(int type
)
876 if (ospf6
->t_distribute_update
)
879 args
= XCALLOC(MTYPE_OSPF6_DIST_ARGS
, sizeof(void *)*2);
882 args
[1] = (void *)((ptrdiff_t)type
);
884 if (IS_OSPF6_DEBUG_ASBR
)
885 zlog_debug("%s: trigger redistribute %s reset thread",
886 __PRETTY_FUNCTION__
, ZROUTE_NAME(type
));
888 ospf6
->t_distribute_update
= NULL
;
889 thread_add_timer_msec(master
, ospf6_asbr_routemap_update_timer
,
890 (void **)args
, OSPF_MIN_LS_INTERVAL
,
891 &ospf6
->t_distribute_update
);
894 static void ospf6_asbr_routemap_update(const char *mapname
)
901 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
902 if (ospf6
->rmap
[type
].name
) {
903 ospf6
->rmap
[type
].map
= route_map_lookup_by_name(
904 ospf6
->rmap
[type
].name
);
906 if (mapname
&& ospf6
->rmap
[type
].map
&&
907 (strcmp(ospf6
->rmap
[type
].name
, mapname
) == 0)) {
908 if (IS_OSPF6_DEBUG_ASBR
)
909 zlog_debug("%s: route-map %s update, reset redist %s",
910 __PRETTY_FUNCTION__
, mapname
,
912 ospf6_asbr_distribute_list_update(type
);
915 ospf6
->rmap
[type
].map
= NULL
;
919 static void ospf6_asbr_routemap_event(route_map_event_t event
, const char *name
)
925 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
926 if ((ospf6
->rmap
[type
].name
) &&
927 (strcmp(ospf6
->rmap
[type
].name
, name
) == 0)) {
928 ospf6_asbr_distribute_list_update(type
);
933 int ospf6_asbr_is_asbr(struct ospf6
*o
)
935 return o
->external_table
->count
;
938 static void ospf6_asbr_redistribute_set(int type
)
940 ospf6_zebra_redistribute(type
);
943 static void ospf6_asbr_redistribute_unset(int type
)
945 struct ospf6_route
*route
;
946 struct ospf6_external_info
*info
;
948 ospf6_zebra_no_redistribute(type
);
950 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
951 route
= ospf6_route_next(route
)) {
952 info
= route
->route_option
;
953 if (info
->type
!= type
)
956 ospf6_asbr_redistribute_remove(info
->type
, 0, &route
->prefix
);
959 ospf6_asbr_routemap_unset(type
);
962 /* When an area is unstubified, flood all the external LSAs in the area */
963 void ospf6_asbr_send_externals_to_area(struct ospf6_area
*oa
)
965 struct ospf6_lsa
*lsa
;
967 for (ALL_LSDB(oa
->ospf6
->lsdb
, lsa
)) {
968 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
) {
969 zlog_debug("%s: Flooding AS-External LSA %s\n",
970 __func__
, lsa
->name
);
971 ospf6_flood_area(NULL
, lsa
, oa
);
976 void ospf6_asbr_redistribute_add(int type
, ifindex_t ifindex
,
977 struct prefix
*prefix
, u_int nexthop_num
,
978 struct in6_addr
*nexthop
, route_tag_t tag
)
981 struct ospf6_route troute
;
982 struct ospf6_external_info tinfo
;
983 struct ospf6_route
*route
, *match
;
984 struct ospf6_external_info
*info
;
985 struct prefix prefix_id
;
986 struct route_node
*node
;
987 char pbuf
[PREFIX2STR_BUFFER
], ibuf
[16];
988 struct listnode
*lnode
, *lnnode
;
989 struct ospf6_area
*oa
;
991 if (!ospf6_zebra_is_redistribute(type
))
994 memset(&troute
, 0, sizeof(troute
));
995 memset(&tinfo
, 0, sizeof(tinfo
));
997 if (IS_OSPF6_DEBUG_ASBR
) {
998 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
999 zlog_debug("Redistribute %s (%s)", pbuf
, ZROUTE_NAME(type
));
1002 /* if route-map was specified but not found, do not advertise */
1003 if (ospf6
->rmap
[type
].name
) {
1004 if (ospf6
->rmap
[type
].map
== NULL
)
1005 ospf6_asbr_routemap_update(NULL
);
1006 if (ospf6
->rmap
[type
].map
== NULL
) {
1008 "route-map \"%s\" not found, suppress redistributing",
1009 ospf6
->rmap
[type
].name
);
1014 /* apply route-map */
1015 if (ospf6
->rmap
[type
].map
) {
1016 troute
.route_option
= &tinfo
;
1017 tinfo
.ifindex
= ifindex
;
1020 ret
= route_map_apply(ospf6
->rmap
[type
].map
, prefix
, RMAP_OSPF6
,
1022 if (ret
== RMAP_DENYMATCH
) {
1023 if (IS_OSPF6_DEBUG_ASBR
)
1024 zlog_debug("Denied by route-map \"%s\"",
1025 ospf6
->rmap
[type
].name
);
1030 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1032 info
= match
->route_option
;
1033 /* copy result of route-map */
1034 if (ospf6
->rmap
[type
].map
) {
1035 if (troute
.path
.metric_type
)
1036 match
->path
.metric_type
=
1037 troute
.path
.metric_type
;
1038 if (troute
.path
.cost
)
1039 match
->path
.cost
= troute
.path
.cost
;
1040 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1041 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1042 sizeof(struct in6_addr
));
1043 info
->tag
= tinfo
.tag
;
1045 /* If there is no route-map, simply update the tag */
1051 if (nexthop_num
&& nexthop
)
1052 ospf6_route_add_nexthop(match
, ifindex
, nexthop
);
1054 ospf6_route_add_nexthop(match
, ifindex
, NULL
);
1056 /* create/update binding in external_id_table */
1057 prefix_id
.family
= AF_INET
;
1058 prefix_id
.prefixlen
= 32;
1059 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1060 node
= route_node_get(ospf6
->external_id_table
, &prefix_id
);
1063 if (IS_OSPF6_DEBUG_ASBR
) {
1064 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
,
1066 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1067 zlog_debug("Advertise as AS-External Id:%s prefix %s metric %u",
1068 ibuf
, pbuf
, match
->path
.metric_type
);
1071 match
->path
.origin
.id
= htonl(info
->id
);
1072 ospf6_as_external_lsa_originate(match
);
1076 /* create new entry */
1077 route
= ospf6_route_create();
1078 route
->type
= OSPF6_DEST_TYPE_NETWORK
;
1079 memcpy(&route
->prefix
, prefix
, sizeof(struct prefix
));
1081 info
= (struct ospf6_external_info
*)XCALLOC(
1082 MTYPE_OSPF6_EXTERNAL_INFO
, sizeof(struct ospf6_external_info
));
1083 route
->route_option
= info
;
1084 info
->id
= ospf6
->external_id
++;
1086 /* copy result of route-map */
1087 if (ospf6
->rmap
[type
].map
) {
1088 if (troute
.path
.metric_type
)
1089 route
->path
.metric_type
= troute
.path
.metric_type
;
1090 if (troute
.path
.cost
)
1091 route
->path
.cost
= troute
.path
.cost
;
1092 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo
.forwarding
))
1093 memcpy(&info
->forwarding
, &tinfo
.forwarding
,
1094 sizeof(struct in6_addr
));
1095 info
->tag
= tinfo
.tag
;
1097 /* If there is no route-map, simply set the tag */
1102 if (nexthop_num
&& nexthop
)
1103 ospf6_route_add_nexthop(route
, ifindex
, nexthop
);
1105 ospf6_route_add_nexthop(route
, ifindex
, NULL
);
1107 /* create/update binding in external_id_table */
1108 prefix_id
.family
= AF_INET
;
1109 prefix_id
.prefixlen
= 32;
1110 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1111 node
= route_node_get(ospf6
->external_id_table
, &prefix_id
);
1114 route
= ospf6_route_add(route
, ospf6
->external_table
);
1115 route
->route_option
= info
;
1117 if (IS_OSPF6_DEBUG_ASBR
) {
1118 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
, sizeof(ibuf
));
1119 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1120 zlog_debug("Advertise as AS-External Id:%s prefix %s metric %u",
1121 ibuf
, pbuf
, route
->path
.metric_type
);
1124 route
->path
.origin
.id
= htonl(info
->id
);
1125 ospf6_as_external_lsa_originate(route
);
1127 /* Router-Bit (ASBR Flag) may have to be updated */
1128 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1129 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1132 void ospf6_asbr_redistribute_remove(int type
, ifindex_t ifindex
,
1133 struct prefix
*prefix
)
1135 struct ospf6_route
*match
;
1136 struct ospf6_external_info
*info
= NULL
;
1137 struct route_node
*node
;
1138 struct ospf6_lsa
*lsa
;
1139 struct prefix prefix_id
;
1140 char pbuf
[PREFIX2STR_BUFFER
], ibuf
[16];
1141 struct listnode
*lnode
, *lnnode
;
1142 struct ospf6_area
*oa
;
1144 match
= ospf6_route_lookup(prefix
, ospf6
->external_table
);
1145 if (match
== NULL
) {
1146 if (IS_OSPF6_DEBUG_ASBR
) {
1147 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1148 zlog_debug("No such route %s to withdraw", pbuf
);
1153 info
= match
->route_option
;
1156 if (info
->type
!= type
) {
1157 if (IS_OSPF6_DEBUG_ASBR
) {
1158 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1159 zlog_debug("Original protocol mismatch: %s", pbuf
);
1164 if (IS_OSPF6_DEBUG_ASBR
) {
1165 prefix2str(prefix
, pbuf
, sizeof(pbuf
));
1166 inet_ntop(AF_INET
, &prefix_id
.u
.prefix4
, ibuf
, sizeof(ibuf
));
1167 zlog_debug("Withdraw %s (AS-External Id:%s)", pbuf
, ibuf
);
1170 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL
),
1171 htonl(info
->id
), ospf6
->router_id
, ospf6
->lsdb
);
1173 ospf6_lsa_purge(lsa
);
1175 /* remove binding in external_id_table */
1176 prefix_id
.family
= AF_INET
;
1177 prefix_id
.prefixlen
= 32;
1178 prefix_id
.u
.prefix4
.s_addr
= htonl(info
->id
);
1179 node
= route_node_lookup(ospf6
->external_id_table
, &prefix_id
);
1182 route_unlock_node(node
); /* to free the lookup lock */
1183 route_unlock_node(node
); /* to free the original lock */
1185 ospf6_route_remove(match
, ospf6
->external_table
);
1186 XFREE(MTYPE_OSPF6_EXTERNAL_INFO
, info
);
1188 /* Router-Bit (ASBR Flag) may have to be updated */
1189 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, lnode
, lnnode
, oa
))
1190 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
1193 DEFUN (ospf6_redistribute
,
1194 ospf6_redistribute_cmd
,
1195 "redistribute " FRR_REDIST_STR_OSPF6D
,
1197 FRR_REDIST_HELP_STR_OSPF6D
)
1201 char *proto
= argv
[argc
- 1]->text
;
1202 type
= proto_redistnum(AFI_IP6
, proto
);
1204 return CMD_WARNING_CONFIG_FAILED
;
1206 ospf6_asbr_redistribute_unset(type
);
1207 ospf6_asbr_redistribute_set(type
);
1211 DEFUN (ospf6_redistribute_routemap
,
1212 ospf6_redistribute_routemap_cmd
,
1213 "redistribute " FRR_REDIST_STR_OSPF6D
" route-map WORD",
1215 FRR_REDIST_HELP_STR_OSPF6D
1216 "Route map reference\n"
1219 int idx_protocol
= 1;
1223 char *proto
= argv
[idx_protocol
]->text
;
1224 type
= proto_redistnum(AFI_IP6
, proto
);
1226 return CMD_WARNING_CONFIG_FAILED
;
1228 ospf6_asbr_redistribute_unset(type
);
1229 ospf6_asbr_routemap_set(type
, argv
[idx_word
]->arg
);
1230 ospf6_asbr_redistribute_set(type
);
1234 DEFUN (no_ospf6_redistribute
,
1235 no_ospf6_redistribute_cmd
,
1236 "no redistribute " FRR_REDIST_STR_OSPF6D
" [route-map WORD]",
1239 FRR_REDIST_HELP_STR_OSPF6D
1240 "Route map reference\n"
1243 int idx_protocol
= 2;
1246 char *proto
= argv
[idx_protocol
]->text
;
1247 type
= proto_redistnum(AFI_IP6
, proto
);
1249 return CMD_WARNING_CONFIG_FAILED
;
1251 ospf6_asbr_redistribute_unset(type
);
1256 int ospf6_redistribute_config_write(struct vty
*vty
)
1260 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1261 if (type
== ZEBRA_ROUTE_OSPF6
)
1263 if (!ospf6_zebra_is_redistribute(type
))
1266 if (ospf6
->rmap
[type
].name
)
1267 vty_out(vty
, " redistribute %s route-map %s\n",
1268 ZROUTE_NAME(type
), ospf6
->rmap
[type
].name
);
1270 vty_out(vty
, " redistribute %s\n", ZROUTE_NAME(type
));
1276 static void ospf6_redistribute_show_config(struct vty
*vty
)
1279 int nroute
[ZEBRA_ROUTE_MAX
];
1281 struct ospf6_route
*route
;
1282 struct ospf6_external_info
*info
;
1285 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++)
1287 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1288 route
= ospf6_route_next(route
)) {
1289 info
= route
->route_option
;
1290 nroute
[info
->type
]++;
1294 vty_out(vty
, "Redistributing External Routes from:\n");
1295 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1296 if (type
== ZEBRA_ROUTE_OSPF6
)
1298 if (!ospf6_zebra_is_redistribute(type
))
1301 if (ospf6
->rmap
[type
].name
)
1302 vty_out(vty
, " %d: %s with route-map \"%s\"%s\n",
1303 nroute
[type
], ZROUTE_NAME(type
),
1304 ospf6
->rmap
[type
].name
,
1305 (ospf6
->rmap
[type
].map
? ""
1306 : " (not found !)"));
1308 vty_out(vty
, " %d: %s\n", nroute
[type
],
1311 vty_out(vty
, "Total %d routes\n", total
);
1315 /* Routemap Functions */
1316 static route_map_result_t
1317 ospf6_routemap_rule_match_address_prefixlist(void *rule
, struct prefix
*prefix
,
1318 route_map_object_t type
,
1321 struct prefix_list
*plist
;
1323 if (type
!= RMAP_OSPF6
)
1324 return RMAP_NOMATCH
;
1326 plist
= prefix_list_lookup(AFI_IP6
, (char *)rule
);
1328 return RMAP_NOMATCH
;
1330 return (prefix_list_apply(plist
, prefix
) == PREFIX_DENY
? RMAP_NOMATCH
1335 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg
)
1337 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1340 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule
)
1342 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1345 struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd
= {
1346 "ipv6 address prefix-list",
1347 ospf6_routemap_rule_match_address_prefixlist
,
1348 ospf6_routemap_rule_match_address_prefixlist_compile
,
1349 ospf6_routemap_rule_match_address_prefixlist_free
,
1352 /* `match interface IFNAME' */
1353 /* Match function should return 1 if match is success else return
1355 static route_map_result_t
1356 ospf6_routemap_rule_match_interface(void *rule
, struct prefix
*prefix
,
1357 route_map_object_t type
, void *object
)
1359 struct interface
*ifp
;
1360 struct ospf6_external_info
*ei
;
1362 if (type
== RMAP_OSPF6
) {
1363 ei
= ((struct ospf6_route
*)object
)->route_option
;
1364 ifp
= if_lookup_by_name((char *)rule
, VRF_DEFAULT
);
1366 if (ifp
!= NULL
&& ei
->ifindex
== ifp
->ifindex
)
1370 return RMAP_NOMATCH
;
1373 /* Route map `interface' match statement. `arg' should be
1375 static void *ospf6_routemap_rule_match_interface_compile(const char *arg
)
1377 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1380 /* Free route map's compiled `interface' value. */
1381 static void ospf6_routemap_rule_match_interface_free(void *rule
)
1383 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1386 /* Route map commands for interface matching. */
1387 struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd
= {
1388 "interface", ospf6_routemap_rule_match_interface
,
1389 ospf6_routemap_rule_match_interface_compile
,
1390 ospf6_routemap_rule_match_interface_free
};
1392 /* Match function for matching route tags */
1393 static route_map_result_t
ospf6_routemap_rule_match_tag(void *rule
,
1394 struct prefix
*prefix
,
1395 route_map_object_t type
,
1398 route_tag_t
*tag
= rule
;
1399 struct ospf6_route
*route
= object
;
1400 struct ospf6_external_info
*info
= route
->route_option
;
1402 if (type
== RMAP_OSPF6
&& info
->tag
== *tag
)
1405 return RMAP_NOMATCH
;
1408 static struct route_map_rule_cmd ospf6_routemap_rule_match_tag_cmd
= {
1409 "tag", ospf6_routemap_rule_match_tag
, route_map_rule_tag_compile
,
1410 route_map_rule_tag_free
,
1413 static route_map_result_t
1414 ospf6_routemap_rule_set_metric_type(void *rule
, struct prefix
*prefix
,
1415 route_map_object_t type
, void *object
)
1417 char *metric_type
= rule
;
1418 struct ospf6_route
*route
= object
;
1420 if (type
!= RMAP_OSPF6
)
1423 if (strcmp(metric_type
, "type-2") == 0)
1424 route
->path
.metric_type
= 2;
1426 route
->path
.metric_type
= 1;
1431 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg
)
1433 if (strcmp(arg
, "type-2") && strcmp(arg
, "type-1"))
1435 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1438 static void ospf6_routemap_rule_set_metric_type_free(void *rule
)
1440 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1443 struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd
= {
1444 "metric-type", ospf6_routemap_rule_set_metric_type
,
1445 ospf6_routemap_rule_set_metric_type_compile
,
1446 ospf6_routemap_rule_set_metric_type_free
,
1449 static route_map_result_t
1450 ospf6_routemap_rule_set_metric(void *rule
, struct prefix
*prefix
,
1451 route_map_object_t type
, void *object
)
1453 char *metric
= rule
;
1454 struct ospf6_route
*route
= object
;
1456 if (type
!= RMAP_OSPF6
)
1459 route
->path
.cost
= atoi(metric
);
1463 static void *ospf6_routemap_rule_set_metric_compile(const char *arg
)
1467 metric
= strtoul(arg
, &endp
, 0);
1468 if (metric
> OSPF_LS_INFINITY
|| *endp
!= '\0')
1470 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1473 static void ospf6_routemap_rule_set_metric_free(void *rule
)
1475 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1478 struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd
= {
1479 "metric", ospf6_routemap_rule_set_metric
,
1480 ospf6_routemap_rule_set_metric_compile
,
1481 ospf6_routemap_rule_set_metric_free
,
1484 static route_map_result_t
1485 ospf6_routemap_rule_set_forwarding(void *rule
, struct prefix
*prefix
,
1486 route_map_object_t type
, void *object
)
1488 char *forwarding
= rule
;
1489 struct ospf6_route
*route
= object
;
1490 struct ospf6_external_info
*info
= route
->route_option
;
1492 if (type
!= RMAP_OSPF6
)
1495 if (inet_pton(AF_INET6
, forwarding
, &info
->forwarding
) != 1) {
1496 memset(&info
->forwarding
, 0, sizeof(struct in6_addr
));
1503 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg
)
1506 if (inet_pton(AF_INET6
, arg
, &a
) != 1)
1508 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED
, arg
);
1511 static void ospf6_routemap_rule_set_forwarding_free(void *rule
)
1513 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
1516 struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd
= {
1517 "forwarding-address", ospf6_routemap_rule_set_forwarding
,
1518 ospf6_routemap_rule_set_forwarding_compile
,
1519 ospf6_routemap_rule_set_forwarding_free
,
1522 static route_map_result_t
ospf6_routemap_rule_set_tag(void *rule
,
1523 struct prefix
*prefix
,
1524 route_map_object_t type
,
1527 route_tag_t
*tag
= rule
;
1528 struct ospf6_route
*route
= object
;
1529 struct ospf6_external_info
*info
= route
->route_option
;
1531 if (type
!= RMAP_OSPF6
)
1538 static struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd
= {
1539 "tag", ospf6_routemap_rule_set_tag
, route_map_rule_tag_compile
,
1540 route_map_rule_tag_free
,
1543 static int route_map_command_status(struct vty
*vty
, int ret
)
1546 case RMAP_RULE_MISSING
:
1547 vty_out(vty
, "OSPF6 Can't find rule.\n");
1548 return CMD_WARNING_CONFIG_FAILED
;
1550 case RMAP_COMPILE_ERROR
:
1551 vty_out(vty
, "OSPF6 Argument is malformed.\n");
1552 return CMD_WARNING_CONFIG_FAILED
;
1554 case RMAP_COMPILE_SUCCESS
:
1561 /* add "set metric-type" */
1562 DEFUN (ospf6_routemap_set_metric_type
,
1563 ospf6_routemap_set_metric_type_cmd
,
1564 "set metric-type <type-1|type-2>",
1567 "OSPF6 external type 1 metric\n"
1568 "OSPF6 external type 2 metric\n")
1570 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1571 int idx_external
= 2;
1572 int ret
= route_map_add_set(route_map_index
, "metric-type",
1573 argv
[idx_external
]->arg
);
1574 return route_map_command_status(vty
, ret
);
1577 /* delete "set metric-type" */
1578 DEFUN (ospf6_routemap_no_set_metric_type
,
1579 ospf6_routemap_no_set_metric_type_cmd
,
1580 "no set metric-type [<type-1|type-2>]",
1584 "OSPF6 external type 1 metric\n"
1585 "OSPF6 external type 2 metric\n")
1587 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1588 char *ext
= (argc
== 4) ? argv
[3]->text
: NULL
;
1589 int ret
= route_map_delete_set(route_map_index
, "metric-type", ext
);
1590 return route_map_command_status(vty
, ret
);
1593 /* add "set forwarding-address" */
1594 DEFUN (ospf6_routemap_set_forwarding
,
1595 ospf6_routemap_set_forwarding_cmd
,
1596 "set forwarding-address X:X::X:X",
1598 "Forwarding Address\n"
1601 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1603 int ret
= route_map_add_set(route_map_index
, "forwarding-address",
1604 argv
[idx_ipv6
]->arg
);
1605 return route_map_command_status(vty
, ret
);
1608 /* delete "set forwarding-address" */
1609 DEFUN (ospf6_routemap_no_set_forwarding
,
1610 ospf6_routemap_no_set_forwarding_cmd
,
1611 "no set forwarding-address X:X::X:X",
1614 "Forwarding Address\n"
1617 VTY_DECLVAR_CONTEXT(route_map_index
, route_map_index
);
1619 int ret
= route_map_delete_set(route_map_index
, "forwarding-address",
1620 argv
[idx_ipv6
]->arg
);
1621 return route_map_command_status(vty
, ret
);
1624 static void ospf6_routemap_init(void)
1628 route_map_add_hook(ospf6_asbr_routemap_update
);
1629 route_map_delete_hook(ospf6_asbr_routemap_update
);
1630 route_map_event_hook(ospf6_asbr_routemap_event
);
1632 route_map_set_metric_hook(generic_set_add
);
1633 route_map_no_set_metric_hook(generic_set_delete
);
1635 route_map_match_tag_hook(generic_match_add
);
1636 route_map_no_match_tag_hook(generic_match_delete
);
1638 route_map_match_ipv6_address_prefix_list_hook(generic_match_add
);
1639 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete
);
1641 route_map_match_interface_hook(generic_match_add
);
1642 route_map_no_match_interface_hook(generic_match_delete
);
1644 route_map_install_match(
1645 &ospf6_routemap_rule_match_address_prefixlist_cmd
);
1646 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd
);
1647 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd
);
1649 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd
);
1650 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd
);
1651 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd
);
1652 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd
);
1654 /* ASE Metric Type (e.g. Type-1/Type-2) */
1655 install_element(RMAP_NODE
, &ospf6_routemap_set_metric_type_cmd
);
1656 install_element(RMAP_NODE
, &ospf6_routemap_no_set_metric_type_cmd
);
1659 install_element(RMAP_NODE
, &ospf6_routemap_set_forwarding_cmd
);
1660 install_element(RMAP_NODE
, &ospf6_routemap_no_set_forwarding_cmd
);
1664 /* Display functions */
1665 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1666 char *buf
, int buflen
,
1669 struct ospf6_as_external_lsa
*external
;
1670 struct in6_addr in6
;
1671 int prefix_length
= 0;
1674 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1678 ospf6_prefix_in6_addr(&in6
, &external
->prefix
);
1679 prefix_length
= external
->prefix
.prefix_length
;
1681 in6
= *((struct in6_addr
1682 *)((caddr_t
)external
1684 ospf6_as_external_lsa
)
1685 + OSPF6_PREFIX_SPACE(
1690 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
1692 sprintf(&buf
[strlen(buf
)], "/%d",
1699 static int ospf6_as_external_lsa_show(struct vty
*vty
, struct ospf6_lsa
*lsa
)
1701 struct ospf6_as_external_lsa
*external
;
1704 assert(lsa
->header
);
1705 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1709 snprintf(buf
, sizeof(buf
), "%c%c%c",
1710 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_E
) ? 'E'
1712 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
) ? 'F'
1714 (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
) ? 'T'
1717 vty_out(vty
, " Bits: %s\n", buf
);
1718 vty_out(vty
, " Metric: %5lu\n",
1719 (u_long
)OSPF6_ASBR_METRIC(external
));
1721 ospf6_prefix_options_printbuf(external
->prefix
.prefix_options
, buf
,
1723 vty_out(vty
, " Prefix Options: %s\n", buf
);
1725 vty_out(vty
, " Referenced LSType: %d\n",
1726 ntohs(external
->prefix
.prefix_refer_lstype
));
1728 vty_out(vty
, " Prefix: %s\n",
1729 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
, sizeof(buf
), 0));
1731 /* Forwarding-Address */
1732 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_F
)) {
1733 vty_out(vty
, " Forwarding-Address: %s\n",
1734 ospf6_as_external_lsa_get_prefix_str(lsa
, buf
,
1739 if (CHECK_FLAG(external
->bits_metric
, OSPF6_ASBR_BIT_T
)) {
1740 vty_out(vty
, " Tag: %" ROUTE_TAG_PRI
"\n",
1741 ospf6_as_external_lsa_get_tag(lsa
));
1747 static void ospf6_asbr_external_route_show(struct vty
*vty
,
1748 struct ospf6_route
*route
)
1750 struct ospf6_external_info
*info
= route
->route_option
;
1751 char prefix
[PREFIX2STR_BUFFER
], id
[16], forwarding
[64];
1754 prefix2str(&route
->prefix
, prefix
, sizeof(prefix
));
1755 tmp_id
= ntohl(info
->id
);
1756 inet_ntop(AF_INET
, &tmp_id
, id
, sizeof(id
));
1757 if (!IN6_IS_ADDR_UNSPECIFIED(&info
->forwarding
))
1758 inet_ntop(AF_INET6
, &info
->forwarding
, forwarding
,
1759 sizeof(forwarding
));
1761 snprintf(forwarding
, sizeof(forwarding
), ":: (ifindex %d)",
1762 ospf6_route_get_first_nh_index(route
));
1764 vty_out(vty
, "%c %-32s %-15s type-%d %5lu %s\n",
1765 zebra_route_char(info
->type
), prefix
, id
,
1766 route
->path
.metric_type
,
1767 (u_long
)(route
->path
.metric_type
== 2 ? route
->path
.u
.cost_e2
1768 : route
->path
.cost
),
1772 DEFUN (show_ipv6_ospf6_redistribute
,
1773 show_ipv6_ospf6_redistribute_cmd
,
1774 "show ipv6 ospf6 redistribute",
1778 "redistributing External information\n"
1781 struct ospf6_route
*route
;
1783 OSPF6_CMD_CHECK_RUNNING();
1785 ospf6_redistribute_show_config(vty
);
1787 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
1788 route
= ospf6_route_next(route
))
1789 ospf6_asbr_external_route_show(vty
, route
);
1794 struct ospf6_lsa_handler as_external_handler
= {
1795 .lh_type
= OSPF6_LSTYPE_AS_EXTERNAL
,
1796 .lh_name
= "AS-External",
1797 .lh_short_name
= "ASE",
1798 .lh_show
= ospf6_as_external_lsa_show
,
1799 .lh_get_prefix_str
= ospf6_as_external_lsa_get_prefix_str
,
1803 void ospf6_asbr_init(void)
1805 ospf6_routemap_init();
1807 ospf6_install_lsa_handler(&as_external_handler
);
1809 install_element(VIEW_NODE
, &show_ipv6_ospf6_redistribute_cmd
);
1811 install_element(OSPF6_NODE
, &ospf6_redistribute_cmd
);
1812 install_element(OSPF6_NODE
, &ospf6_redistribute_routemap_cmd
);
1813 install_element(OSPF6_NODE
, &no_ospf6_redistribute_cmd
);
1816 void ospf6_asbr_redistribute_reset(void)
1820 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
1821 if (type
== ZEBRA_ROUTE_OSPF6
)
1823 if (ospf6_zebra_is_redistribute(type
))
1824 ospf6_asbr_redistribute_unset(type
);
1828 void ospf6_asbr_terminate(void)
1830 /* Cleanup route maps */
1831 route_map_add_hook(NULL
);
1832 route_map_delete_hook(NULL
);
1833 route_map_event_hook(NULL
);
1837 DEFUN (debug_ospf6_asbr
,
1838 debug_ospf6_asbr_cmd
,
1842 "Debug OSPFv3 ASBR function\n"
1845 OSPF6_DEBUG_ASBR_ON();
1849 DEFUN (no_debug_ospf6_asbr
,
1850 no_debug_ospf6_asbr_cmd
,
1851 "no debug ospf6 asbr",
1855 "Debug OSPFv3 ASBR function\n"
1858 OSPF6_DEBUG_ASBR_OFF();
1862 int config_write_ospf6_debug_asbr(struct vty
*vty
)
1864 if (IS_OSPF6_DEBUG_ASBR
)
1865 vty_out(vty
, "debug ospf6 asbr\n");
1869 void install_element_ospf6_debug_asbr()
1871 install_element(ENABLE_NODE
, &debug_ospf6_asbr_cmd
);
1872 install_element(ENABLE_NODE
, &no_debug_ospf6_asbr_cmd
);
1873 install_element(CONFIG_NODE
, &debug_ospf6_asbr_cmd
);
1874 install_element(CONFIG_NODE
, &no_debug_ospf6_asbr_cmd
);