2 * Area Border Router function.
3 * Copyright (C) 2004 Yasuhiro Ohara
5 * This file is part of GNU Zebra.
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include "ospf6_proto.h"
35 #include "ospf6_route.h"
36 #include "ospf6_lsa.h"
37 #include "ospf6_route.h"
38 #include "ospf6_lsdb.h"
39 #include "ospf6_message.h"
40 #include "ospf6_zebra.h"
42 #include "ospf6_top.h"
43 #include "ospf6_area.h"
44 #include "ospf6_interface.h"
45 #include "ospf6_neighbor.h"
47 #include "ospf6_flood.h"
48 #include "ospf6_intra.h"
49 #include "ospf6_abr.h"
52 unsigned char conf_debug_ospf6_abr
;
54 int ospf6_is_router_abr(struct ospf6
*o
)
56 struct listnode
*node
;
57 struct ospf6_area
*oa
;
60 for (ALL_LIST_ELEMENTS_RO(o
->area_list
, node
, oa
))
61 if (IS_AREA_ENABLED(oa
))
69 static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route
*route
,
70 struct ospf6_area
*area
)
72 struct ospf6_interface
*oi
;
74 oi
= ospf6_interface_lookup_by_ifindex(
75 ospf6_route_get_first_nh_index(route
));
76 if (oi
&& oi
->area
&& oi
->area
== area
)
82 static void ospf6_abr_delete_route(struct ospf6_route
*range
,
83 struct ospf6_route
*summary
,
84 struct ospf6_route_table
*summary_table
,
85 struct ospf6_lsa
*old
)
88 ospf6_route_remove(summary
, summary_table
);
91 if (old
&& !OSPF6_LSA_IS_MAXAGE(old
))
95 void ospf6_abr_enable_area(struct ospf6_area
*area
)
97 struct ospf6_area
*oa
;
98 struct listnode
*node
, *nnode
;
100 for (ALL_LIST_ELEMENTS(area
->ospf6
->area_list
, node
, nnode
, oa
))
101 /* update B bit for each area */
102 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
105 void ospf6_abr_disable_area(struct ospf6_area
*area
)
107 struct ospf6_area
*oa
;
108 struct ospf6_route
*ro
, *nro
;
109 struct ospf6_lsa
*old
;
110 struct listnode
*node
, *nnode
;
112 /* Withdraw all summary prefixes previously originated */
113 for (ro
= ospf6_route_head(area
->summary_prefix
); ro
; ro
= nro
) {
114 nro
= ospf6_route_next(ro
);
115 old
= ospf6_lsdb_lookup(ro
->path
.origin
.type
,
117 area
->ospf6
->router_id
, area
->lsdb
);
119 ospf6_lsa_purge(old
);
120 ospf6_route_remove(ro
, area
->summary_prefix
);
123 /* Withdraw all summary router-routes previously originated */
124 for (ro
= ospf6_route_head(area
->summary_router
); ro
; ro
= nro
) {
125 nro
= ospf6_route_next(ro
);
126 old
= ospf6_lsdb_lookup(ro
->path
.origin
.type
,
128 area
->ospf6
->router_id
, area
->lsdb
);
130 ospf6_lsa_purge(old
);
131 ospf6_route_remove(ro
, area
->summary_router
);
134 /* Schedule Router-LSA for each area (ABR status may change) */
135 for (ALL_LIST_ELEMENTS(area
->ospf6
->area_list
, node
, nnode
, oa
))
136 /* update B bit for each area */
137 OSPF6_ROUTER_LSA_SCHEDULE(oa
);
140 /* RFC 2328 12.4.3. Summary-LSAs */
141 /* Returns 1 if a summary LSA has been generated for the area */
142 /* This is used by the area/range logic to add/remove blackhole routes */
143 int ospf6_abr_originate_summary_to_area(struct ospf6_route
*route
,
144 struct ospf6_area
*area
)
146 struct ospf6_lsa
*lsa
, *old
= NULL
;
147 struct ospf6_route
*summary
, *range
= NULL
;
148 struct ospf6_area
*route_area
;
149 char buffer
[OSPF6_MAX_LSASIZE
];
150 struct ospf6_lsa_header
*lsa_header
;
152 struct ospf6_inter_prefix_lsa
*prefix_lsa
;
153 struct ospf6_inter_router_lsa
*router_lsa
;
154 struct ospf6_route_table
*summary_table
= NULL
;
156 char buf
[PREFIX2STR_BUFFER
];
159 /* Only destination type network, range or ASBR are considered */
160 if (route
->type
!= OSPF6_DEST_TYPE_NETWORK
161 && route
->type
!= OSPF6_DEST_TYPE_RANGE
162 && ((route
->type
!= OSPF6_DEST_TYPE_ROUTER
)
163 || !CHECK_FLAG(route
->path
.router_bits
, OSPF6_ROUTER_BIT_E
))) {
166 "Route type is none of network, range nor ASBR, ignore");
170 /* AS External routes are never considered */
171 if (route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL1
172 || route
->path
.type
== OSPF6_PATH_TYPE_EXTERNAL2
) {
174 zlog_debug("Path type is external, skip");
178 /* do not generate if the path's area is the same as target area */
179 if (route
->path
.area_id
== area
->area_id
) {
181 zlog_debug("The route is in the area itself, ignore");
185 /* do not generate if the nexthops belongs to the target area */
186 if (ospf6_abr_nexthops_belong_to_area(route
, area
)) {
189 "The route's nexthop is in the same area, ignore");
193 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
194 if (ADV_ROUTER_IN_PREFIX(&route
->prefix
)
195 == area
->ospf6
->router_id
) {
197 &(ADV_ROUTER_IN_PREFIX(&route
->prefix
)), buf
,
200 "%s: Skipping ASBR announcement for ABR (%s)",
206 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
207 if (IS_OSPF6_DEBUG_ABR
208 || IS_OSPF6_DEBUG_ORIGINATE(INTER_ROUTER
)) {
211 &(ADV_ROUTER_IN_PREFIX(&route
->prefix
)), buf
,
213 zlog_debug("Originating summary in area %s for ASBR %s",
216 summary_table
= area
->summary_router
;
218 if (IS_OSPF6_DEBUG_ABR
219 || IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX
)) {
221 prefix2str(&route
->prefix
, buf
, sizeof(buf
));
222 zlog_debug("Originating summary in area %s for %s",
225 summary_table
= area
->summary_prefix
;
228 summary
= ospf6_route_lookup(&route
->prefix
, summary_table
);
230 old
= ospf6_lsdb_lookup(summary
->path
.origin
.type
,
231 summary
->path
.origin
.id
,
232 area
->ospf6
->router_id
, area
->lsdb
);
234 /* if this route has just removed, remove corresponding LSA */
235 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)) {
238 "The route has just removed, purge previous LSA");
240 if (route
->type
== OSPF6_DEST_TYPE_RANGE
) {
241 /* Whether the route have active longer prefix */
242 if (!CHECK_FLAG(route
->flag
,
243 OSPF6_ROUTE_ACTIVE_SUMMARY
)) {
246 "The range is not active. withdraw");
248 ospf6_abr_delete_route(route
, summary
,
252 ospf6_lsa_purge(old
);
257 if ((route
->type
== OSPF6_DEST_TYPE_ROUTER
) && IS_AREA_STUB(area
)) {
260 "Area has been stubbed, purge Inter-Router LSA");
262 ospf6_abr_delete_route(route
, summary
, summary_table
, old
);
267 && (route
->path
.subtype
!= OSPF6_PATH_SUBTYPE_DEFAULT_RT
)) {
269 zlog_debug("Area has been stubbed, purge prefix LSA");
271 ospf6_abr_delete_route(route
, summary
, summary_table
, old
);
275 /* do not generate if the route cost is greater or equal to LSInfinity
277 if (route
->path
.cost
>= OSPF_LS_INFINITY
) {
278 /* When we're clearing the range route because all active
280 * under the range are gone, we set the range's cost to
281 * OSPF_AREA_RANGE_COST_UNSPEC, which is > OSPF_LS_INFINITY. We
282 * don't want to trigger the code here for that. This code is
284 * handling routes that have gone to infinity. The range removal
288 if ((route
->type
!= OSPF6_DEST_TYPE_RANGE
)
289 && (route
->path
.cost
!= OSPF_AREA_RANGE_COST_UNSPEC
)) {
292 "The cost exceeds LSInfinity, withdraw");
294 ospf6_lsa_purge(old
);
299 /* if this is a route to ASBR */
300 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
301 /* Only the prefered best path is considered */
302 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_BEST
)) {
305 "This is the secondary path to the ASBR, ignore");
306 ospf6_abr_delete_route(route
, summary
, summary_table
,
311 /* Do not generate if the area is stub */
315 /* if this is an intra-area route, this may be suppressed by aggregation
317 if (route
->type
== OSPF6_DEST_TYPE_NETWORK
318 && route
->path
.type
== OSPF6_PATH_TYPE_INTRA
) {
319 /* search for configured address range for the route's area */
321 ospf6_area_lookup(route
->path
.area_id
, area
->ospf6
);
323 range
= ospf6_route_lookup_bestmatch(&route
->prefix
,
324 route_area
->range_table
);
326 /* ranges are ignored when originate backbone routes to transit
328 Otherwise, if ranges are configured, the route is suppressed.
330 if (range
&& !CHECK_FLAG(range
->flag
, OSPF6_ROUTE_REMOVE
)
331 && (route
->path
.area_id
!= OSPF_AREA_BACKBONE
332 || !IS_AREA_TRANSIT(area
))) {
334 prefix2str(&range
->prefix
, buf
, sizeof(buf
));
335 zlog_debug("Suppressed by range %s of area %s",
336 buf
, route_area
->name
);
338 ospf6_abr_delete_route(route
, summary
, summary_table
,
344 /* If this is a configured address range */
345 if (route
->type
== OSPF6_DEST_TYPE_RANGE
) {
346 /* If DoNotAdvertise is set */
347 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_DO_NOT_ADVERTISE
)) {
350 "This is the range with DoNotAdvertise set. ignore");
351 ospf6_abr_delete_route(route
, summary
, summary_table
,
356 /* If there are no active prefixes in this range, remove */
357 if (!CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)) {
359 zlog_debug("The range is not active. withdraw");
360 ospf6_abr_delete_route(route
, summary
, summary_table
,
366 /* Check export list */
367 if (EXPORT_NAME(area
)) {
368 if (EXPORT_LIST(area
) == NULL
)
370 access_list_lookup(AFI_IP6
, EXPORT_NAME(area
));
372 if (EXPORT_LIST(area
))
373 if (access_list_apply(EXPORT_LIST(area
), &route
->prefix
)
377 &(ADV_ROUTER_IN_PREFIX(
381 "prefix %s was denied by export list",
388 /* Check filter-list */
389 if (PREFIX_LIST_OUT(area
))
390 if (prefix_list_apply(PREFIX_LIST_OUT(area
), &route
->prefix
)
395 &(ADV_ROUTER_IN_PREFIX(&route
->prefix
)),
398 "prefix %s was denied by filter-list out",
404 /* the route is going to be originated. store it in area's summary_table
406 if (summary
== NULL
) {
407 summary
= ospf6_route_copy(route
);
408 summary
->path
.origin
.adv_router
= area
->ospf6
->router_id
;
410 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
411 summary
->path
.origin
.type
=
412 htons(OSPF6_LSTYPE_INTER_ROUTER
);
413 summary
->path
.origin
.id
=
414 ADV_ROUTER_IN_PREFIX(&route
->prefix
);
416 summary
->path
.origin
.type
=
417 htons(OSPF6_LSTYPE_INTER_PREFIX
);
418 summary
->path
.origin
.id
= ospf6_new_ls_id(
419 summary
->path
.origin
.type
,
420 summary
->path
.origin
.adv_router
, area
->lsdb
);
422 summary
= ospf6_route_add(summary
, summary_table
);
424 summary
->type
= route
->type
;
425 monotime(&summary
->changed
);
428 summary
->path
.router_bits
= route
->path
.router_bits
;
429 summary
->path
.options
[0] = route
->path
.options
[0];
430 summary
->path
.options
[1] = route
->path
.options
[1];
431 summary
->path
.options
[2] = route
->path
.options
[2];
432 summary
->path
.prefix_options
= route
->path
.prefix_options
;
433 summary
->path
.area_id
= area
->area_id
;
434 summary
->path
.type
= OSPF6_PATH_TYPE_INTER
;
435 summary
->path
.subtype
= route
->path
.subtype
;
436 summary
->path
.cost
= route
->path
.cost
;
437 /* summary->nexthop[0] = route->nexthop[0]; */
440 memset(buffer
, 0, sizeof(buffer
));
441 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
443 if (route
->type
== OSPF6_DEST_TYPE_ROUTER
) {
444 router_lsa
= (struct ospf6_inter_router_lsa
445 *)((caddr_t
)lsa_header
446 + sizeof(struct ospf6_lsa_header
));
447 p
= (caddr_t
)router_lsa
+ sizeof(struct ospf6_inter_router_lsa
);
449 /* Fill Inter-Area-Router-LSA */
450 router_lsa
->options
[0] = route
->path
.options
[0];
451 router_lsa
->options
[1] = route
->path
.options
[1];
452 router_lsa
->options
[2] = route
->path
.options
[2];
453 OSPF6_ABR_SUMMARY_METRIC_SET(router_lsa
, route
->path
.cost
);
454 router_lsa
->router_id
= ADV_ROUTER_IN_PREFIX(&route
->prefix
);
455 type
= htons(OSPF6_LSTYPE_INTER_ROUTER
);
457 prefix_lsa
= (struct ospf6_inter_prefix_lsa
458 *)((caddr_t
)lsa_header
459 + sizeof(struct ospf6_lsa_header
));
460 p
= (caddr_t
)prefix_lsa
+ sizeof(struct ospf6_inter_prefix_lsa
);
462 /* Fill Inter-Area-Prefix-LSA */
463 OSPF6_ABR_SUMMARY_METRIC_SET(prefix_lsa
, route
->path
.cost
);
464 prefix_lsa
->prefix
.prefix_length
= route
->prefix
.prefixlen
;
465 prefix_lsa
->prefix
.prefix_options
= route
->path
.prefix_options
;
468 memcpy(p
, &route
->prefix
.u
.prefix6
,
469 OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
));
470 ospf6_prefix_apply_mask(&prefix_lsa
->prefix
);
471 p
+= OSPF6_PREFIX_SPACE(route
->prefix
.prefixlen
);
472 type
= htons(OSPF6_LSTYPE_INTER_PREFIX
);
475 /* Fill LSA Header */
477 lsa_header
->type
= type
;
478 lsa_header
->id
= summary
->path
.origin
.id
;
479 lsa_header
->adv_router
= area
->ospf6
->router_id
;
481 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
482 lsa_header
->adv_router
, area
->lsdb
);
483 lsa_header
->length
= htons((caddr_t
)p
- (caddr_t
)lsa_header
);
486 ospf6_lsa_checksum(lsa_header
);
489 lsa
= ospf6_lsa_create(lsa_header
);
492 ospf6_lsa_originate_area(lsa
, area
);
497 void ospf6_abr_range_reset_cost(struct ospf6
*ospf6
)
499 struct listnode
*node
, *nnode
;
500 struct ospf6_area
*oa
;
501 struct ospf6_route
*range
;
503 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
))
504 for (range
= ospf6_route_head(oa
->range_table
); range
;
505 range
= ospf6_route_next(range
))
506 OSPF6_ABR_RANGE_CLEAR_COST(range
);
509 static inline uint32_t ospf6_abr_range_compute_cost(struct ospf6_route
*range
,
512 struct ospf6_route
*ro
;
515 for (ro
= ospf6_route_match_head(&range
->prefix
, o
->route_table
); ro
;
516 ro
= ospf6_route_match_next(&range
->prefix
, ro
)) {
517 if (ro
->path
.area_id
== range
->path
.area_id
518 && (ro
->path
.type
== OSPF6_PATH_TYPE_INTRA
)
519 && !CHECK_FLAG(ro
->flag
, OSPF6_ROUTE_REMOVE
))
520 cost
= MAX(cost
, ro
->path
.cost
);
527 ospf6_abr_range_summary_needs_update(struct ospf6_route
*range
, uint32_t cost
)
529 int redo_summary
= 0;
531 if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_REMOVE
)) {
532 UNSET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
534 } else if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_DO_NOT_ADVERTISE
)) {
535 if (range
->path
.cost
!= 0) {
536 range
->path
.cost
= 0;
540 if ((OSPF6_PATH_COST_IS_CONFIGURED(range
->path
)
541 && range
->path
.cost
!= range
->path
.u
.cost_config
)) {
542 range
->path
.cost
= range
->path
.u
.cost_config
;
543 SET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
545 } else if (!OSPF6_PATH_COST_IS_CONFIGURED(range
->path
)
546 && range
->path
.cost
!= cost
) {
547 range
->path
.cost
= cost
;
548 SET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
551 } else if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)) {
552 /* Cost is zero, meaning no active range */
553 UNSET_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
);
554 range
->path
.cost
= OSPF_AREA_RANGE_COST_UNSPEC
;
558 return (redo_summary
);
561 static void ospf6_abr_range_update(struct ospf6_route
*range
)
564 struct listnode
*node
, *nnode
;
565 struct ospf6_area
*oa
;
566 int summary_orig
= 0;
568 assert(range
->type
== OSPF6_DEST_TYPE_RANGE
);
570 /* update range's cost and active flag */
571 cost
= ospf6_abr_range_compute_cost(range
, ospf6
);
573 /* Non-zero cost is a proxy for active longer prefixes in this range.
574 * If there are active routes covered by this range AND either the
576 * cost has changed or the summarized cost has changed then redo
578 * Alternately, if there are no longer active prefixes and there are
579 * summary announcements, withdraw those announcements.
581 * The don't advertise code relies on the path.cost being set to UNSPEC
583 * work the first time. Subsequent times the path.cost is not 0 anyway
585 * were active ranges.
588 if (ospf6_abr_range_summary_needs_update(range
, cost
)) {
589 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
))
591 ospf6_abr_originate_summary_to_area(range
, oa
);
593 if (CHECK_FLAG(range
->flag
, OSPF6_ROUTE_ACTIVE_SUMMARY
)
595 if (!CHECK_FLAG(range
->flag
,
596 OSPF6_ROUTE_BLACKHOLE_ADDED
)) {
597 if (IS_OSPF6_DEBUG_ABR
)
598 zlog_debug("Add discard route");
600 ospf6_zebra_add_discard(range
);
603 /* Summary removed or no summary generated as no
605 if (CHECK_FLAG(range
->flag
,
606 OSPF6_ROUTE_BLACKHOLE_ADDED
)) {
607 if (IS_OSPF6_DEBUG_ABR
)
608 zlog_debug("Delete discard route");
610 ospf6_zebra_delete_discard(range
);
616 void ospf6_abr_originate_summary(struct ospf6_route
*route
)
618 struct listnode
*node
, *nnode
;
619 struct ospf6_area
*oa
;
620 struct ospf6_route
*range
= NULL
;
622 if (route
->type
== OSPF6_DEST_TYPE_NETWORK
) {
623 oa
= ospf6_area_lookup(route
->path
.area_id
, ospf6
);
624 range
= ospf6_route_lookup_bestmatch(&route
->prefix
,
627 ospf6_abr_range_update(range
);
631 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
))
632 ospf6_abr_originate_summary_to_area(route
, oa
);
635 void ospf6_abr_defaults_to_stub(struct ospf6
*o
)
637 struct listnode
*node
, *nnode
;
638 struct ospf6_area
*oa
;
639 struct ospf6_route
*def
, *route
;
644 def
= ospf6_route_create();
645 def
->type
= OSPF6_DEST_TYPE_NETWORK
;
646 def
->prefix
.family
= AF_INET6
;
647 def
->prefix
.prefixlen
= 0;
648 memset(&def
->prefix
.u
.prefix6
, 0, sizeof(struct in6_addr
));
649 def
->type
= OSPF6_DEST_TYPE_NETWORK
;
650 def
->path
.type
= OSPF6_PATH_TYPE_INTER
;
651 def
->path
.subtype
= OSPF6_PATH_SUBTYPE_DEFAULT_RT
;
652 def
->path
.area_id
= o
->backbone
->area_id
;
654 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, oa
)) {
655 if (!IS_AREA_STUB(oa
)) {
656 /* withdraw defaults when an area switches from stub to
658 route
= ospf6_route_lookup(&def
->prefix
,
661 && (route
->path
.subtype
== def
->path
.subtype
)) {
662 if (IS_OSPF6_DEBUG_ABR
)
664 "Withdrawing default route from non-stubby area %s",
666 SET_FLAG(def
->flag
, OSPF6_ROUTE_REMOVE
);
667 ospf6_abr_originate_summary_to_area(def
, oa
);
670 /* announce defaults to stubby areas */
671 if (IS_OSPF6_DEBUG_ABR
)
673 "Announcing default route into stubby area %s",
675 UNSET_FLAG(def
->flag
, OSPF6_ROUTE_REMOVE
);
676 ospf6_abr_originate_summary_to_area(def
, oa
);
679 ospf6_route_delete(def
);
682 /* RFC 2328 16.2. Calculating the inter-area routes */
683 void ospf6_abr_examin_summary(struct ospf6_lsa
*lsa
, struct ospf6_area
*oa
)
685 struct prefix prefix
, abr_prefix
;
686 struct ospf6_route_table
*table
= NULL
;
687 struct ospf6_route
*range
, *route
, *old
= NULL
, *old_route
;
688 struct ospf6_route
*abr_entry
;
690 char options
[3] = {0, 0, 0};
691 uint8_t prefix_options
= 0;
693 uint8_t router_bits
= 0;
694 char buf
[PREFIX2STR_BUFFER
];
696 struct ospf6_inter_prefix_lsa
*prefix_lsa
= NULL
;
697 struct ospf6_inter_router_lsa
*router_lsa
= NULL
;
698 bool old_entry_updated
= false;
700 memset(&prefix
, 0, sizeof(prefix
));
702 if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_PREFIX
)) {
703 if (IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX
)) {
705 zlog_debug("%s: Examin %s in area %s",
706 __PRETTY_FUNCTION__
, lsa
->name
, oa
->name
);
710 (struct ospf6_inter_prefix_lsa
*)OSPF6_LSA_HEADER_END(
712 prefix
.family
= AF_INET6
;
713 prefix
.prefixlen
= prefix_lsa
->prefix
.prefix_length
;
714 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, &prefix_lsa
->prefix
);
716 prefix2str(&prefix
, buf
, sizeof(buf
));
717 table
= oa
->ospf6
->route_table
;
718 type
= OSPF6_DEST_TYPE_NETWORK
;
719 prefix_options
= prefix_lsa
->prefix
.prefix_options
;
720 cost
= OSPF6_ABR_SUMMARY_METRIC(prefix_lsa
);
721 } else if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_ROUTER
)) {
722 if (IS_OSPF6_DEBUG_EXAMIN(INTER_ROUTER
)) {
724 zlog_debug("%s: Examin %s in area %s",
725 __PRETTY_FUNCTION__
, lsa
->name
, oa
->name
);
729 (struct ospf6_inter_router_lsa
*)OSPF6_LSA_HEADER_END(
731 ospf6_linkstate_prefix(router_lsa
->router_id
, htonl(0),
734 inet_ntop(AF_INET
, &router_lsa
->router_id
, buf
,
737 table
= oa
->ospf6
->brouter_table
;
738 type
= OSPF6_DEST_TYPE_ROUTER
;
739 options
[0] = router_lsa
->options
[0];
740 options
[1] = router_lsa
->options
[1];
741 options
[2] = router_lsa
->options
[2];
742 cost
= OSPF6_ABR_SUMMARY_METRIC(router_lsa
);
743 SET_FLAG(router_bits
, OSPF6_ROUTER_BIT_E
);
747 /* Find existing route */
748 route
= ospf6_route_lookup(&prefix
, table
);
750 ospf6_route_lock(route
);
751 while (route
&& ospf6_route_is_prefix(&prefix
, route
)) {
752 if (route
->path
.area_id
== oa
->area_id
753 && route
->path
.origin
.type
== lsa
->header
->type
754 && route
->path
.origin
.id
== lsa
->header
->id
755 && route
->path
.origin
.adv_router
== lsa
->header
->adv_router
756 && !CHECK_FLAG(route
->flag
, OSPF6_ROUTE_WAS_REMOVED
))
758 route
= ospf6_route_next(route
);
761 ospf6_route_unlock(route
);
763 /* (1) if cost == LSInfinity or if the LSA is MaxAge */
764 if (cost
== OSPF_LS_INFINITY
) {
766 zlog_debug("cost is LS_INFINITY, ignore");
768 ospf6_route_remove(old
, table
);
771 if (OSPF6_LSA_IS_MAXAGE(lsa
)) {
773 zlog_debug("%s: LSA %s is MaxAge, ignore",
774 __PRETTY_FUNCTION__
, lsa
->name
);
776 ospf6_route_remove(old
, table
);
780 /* (2) if the LSA is self-originated, ignore */
781 if (lsa
->header
->adv_router
== oa
->ospf6
->router_id
) {
783 zlog_debug("LSA is self-originated, ignore");
785 ospf6_route_remove(old
, table
);
789 /* (3) if the prefix is equal to an active configured address range */
790 /* or if the NU bit is set in the prefix */
791 if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_PREFIX
)) {
792 /* must have been set in previous block */
795 range
= ospf6_route_lookup(&prefix
, oa
->range_table
);
799 "Prefix is equal to address range, ignore");
801 ospf6_route_remove(old
, table
);
805 if (CHECK_FLAG(prefix_lsa
->prefix
.prefix_options
,
806 OSPF6_PREFIX_OPTION_NU
)
807 || CHECK_FLAG(prefix_lsa
->prefix
.prefix_options
,
808 OSPF6_PREFIX_OPTION_LA
)) {
810 zlog_debug("Prefix has NU/LA bit set, ignore");
812 ospf6_route_remove(old
, table
);
817 if (lsa
->header
->type
== htons(OSPF6_LSTYPE_INTER_ROUTER
)) {
818 /* To pass test suites */
819 if (!OSPF6_OPT_ISSET(router_lsa
->options
, OSPF6_OPT_R
)
820 || !OSPF6_OPT_ISSET(router_lsa
->options
, OSPF6_OPT_V6
)) {
822 zlog_debug("Prefix has NU/LA bit set, ignore");
824 ospf6_route_remove(old
, table
);
828 /* Avoid infinite recursion if someone has maliciously announced
830 Inter-Router LSA for an ABR
832 if (lsa
->header
->adv_router
== router_lsa
->router_id
) {
835 "Ignorning Inter-Router LSA for an ABR (%s)",
838 ospf6_route_remove(old
, table
);
844 /* (4) if the routing table entry for the ABR does not exist */
845 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0), &abr_prefix
);
846 abr_entry
= ospf6_route_lookup(&abr_prefix
, oa
->ospf6
->brouter_table
);
847 if (abr_entry
== NULL
|| abr_entry
->path
.area_id
!= oa
->area_id
848 || CHECK_FLAG(abr_entry
->flag
, OSPF6_ROUTE_REMOVE
)
849 || !CHECK_FLAG(abr_entry
->path
.router_bits
, OSPF6_ROUTER_BIT_B
)) {
851 zlog_debug("%s: ABR router entry does not exist, ignore",
852 __PRETTY_FUNCTION__
);
854 if (old
->type
== OSPF6_DEST_TYPE_ROUTER
&&
855 oa
->intra_brouter_calc
) {
858 "%s: intra_brouter_calc is on, skip brouter remove: %s (%p)",
859 __PRETTY_FUNCTION__
, buf
,
863 zlog_debug("%s: remove old entry: %s %p ",
864 __PRETTY_FUNCTION__
, buf
,
866 ospf6_route_remove(old
, table
);
872 /* Check import list */
873 if (IMPORT_NAME(oa
)) {
874 if (IMPORT_LIST(oa
) == NULL
)
876 access_list_lookup(AFI_IP6
, IMPORT_NAME(oa
));
879 if (access_list_apply(IMPORT_LIST(oa
), &prefix
)
883 "Prefix was denied by import-list");
885 ospf6_route_remove(old
, table
);
890 /* Check input prefix-list */
891 if (PREFIX_LIST_IN(oa
))
892 if (prefix_list_apply(PREFIX_LIST_IN(oa
), &prefix
)
895 zlog_debug("Prefix was denied by prefix-list");
897 ospf6_route_remove(old
, table
);
901 /* (5),(6): the path preference is handled by the sorting
902 in the routing table. Always install the path by substituting
903 old route (if any). */
905 route
= ospf6_route_copy(old
);
907 route
= ospf6_route_create();
910 route
->prefix
= prefix
;
911 route
->path
.origin
.type
= lsa
->header
->type
;
912 route
->path
.origin
.id
= lsa
->header
->id
;
913 route
->path
.origin
.adv_router
= lsa
->header
->adv_router
;
914 route
->path
.router_bits
= router_bits
;
915 route
->path
.options
[0] = options
[0];
916 route
->path
.options
[1] = options
[1];
917 route
->path
.options
[2] = options
[2];
918 route
->path
.prefix_options
= prefix_options
;
919 route
->path
.area_id
= oa
->area_id
;
920 route
->path
.type
= OSPF6_PATH_TYPE_INTER
;
921 route
->path
.cost
= abr_entry
->path
.cost
+ cost
;
923 /* Inter abr_entry is same as brouter.
924 * Avoid duplicate nexthops to brouter and its
925 * learnt route. i.e. use merge nexthops.
927 ospf6_route_merge_nexthops(route
, abr_entry
);
929 /* (7) If the routes are identical, copy the next hops over to existing
930 route. ospf6's route table implementation will otherwise string both
931 routes, but keep the older one as the best route since the routes
934 old
= ospf6_route_lookup(&prefix
, table
);
936 for (old_route
= old
; old_route
; old_route
= old_route
->next
) {
937 if (!ospf6_route_is_same(old_route
, route
) ||
938 (old_route
->type
!= route
->type
) ||
939 (old_route
->path
.type
!= route
->path
.type
))
942 if ((ospf6_route_cmp(route
, old_route
) != 0)) {
944 prefix2str(&prefix
, buf
, sizeof(buf
));
945 zlog_debug("%s: old %p %s cost %u new route cost %u are not same",
947 (void *)old_route
, buf
,
948 old_route
->path
.cost
,
954 old_entry_updated
= true;
955 ospf6_route_merge_nexthops(old
, route
);
957 zlog_debug("%s: Update route: %s old cost %u new cost %u nh %u",
959 buf
, old
->path
.cost
, route
->path
.cost
,
960 listcount(route
->nh_list
));
964 (*table
->hook_add
)(old
);
966 /* Delete new route */
967 ospf6_route_delete(route
);
971 if (old_entry_updated
== false) {
973 zlog_debug("%s: Install route: %s cost %u nh %u",
974 __PRETTY_FUNCTION__
, buf
, route
->path
.cost
,
975 listcount(route
->nh_list
));
976 /* ospf6_ia_add_nw_route (table, &prefix, route); */
977 ospf6_route_add(route
, table
);
981 void ospf6_abr_examin_brouter(uint32_t router_id
)
983 struct ospf6_lsa
*lsa
;
984 struct ospf6_area
*oa
;
987 if (ospf6_is_router_abr(ospf6
))
988 oa
= ospf6
->backbone
;
990 oa
= listgetdata(listhead(ospf6
->area_list
));
993 * It is possible to designate a non backbone
994 * area first. If that is the case safely
995 * fall out of this function.
1000 type
= htons(OSPF6_LSTYPE_INTER_ROUTER
);
1001 for (ALL_LSDB_TYPED_ADVRTR(oa
->lsdb
, type
, router_id
, lsa
))
1002 ospf6_abr_examin_summary(lsa
, oa
);
1004 type
= htons(OSPF6_LSTYPE_INTER_PREFIX
);
1005 for (ALL_LSDB_TYPED_ADVRTR(oa
->lsdb
, type
, router_id
, lsa
))
1006 ospf6_abr_examin_summary(lsa
, oa
);
1009 void ospf6_abr_reimport(struct ospf6_area
*oa
)
1011 struct ospf6_lsa
*lsa
;
1014 type
= htons(OSPF6_LSTYPE_INTER_ROUTER
);
1015 for (ALL_LSDB_TYPED(oa
->lsdb
, type
, lsa
))
1016 ospf6_abr_examin_summary(lsa
, oa
);
1018 type
= htons(OSPF6_LSTYPE_INTER_PREFIX
);
1019 for (ALL_LSDB_TYPED(oa
->lsdb
, type
, lsa
))
1020 ospf6_abr_examin_summary(lsa
, oa
);
1023 void ospf6_abr_prefix_resummarize(struct ospf6
*o
)
1025 struct ospf6_route
*route
;
1027 if (IS_OSPF6_DEBUG_ABR
)
1028 zlog_debug("Re-examining Inter-Prefix Summaries");
1030 for (route
= ospf6_route_head(o
->route_table
); route
;
1031 route
= ospf6_route_next(route
))
1032 ospf6_abr_originate_summary(route
);
1034 if (IS_OSPF6_DEBUG_ABR
)
1035 zlog_debug("Finished re-examining Inter-Prefix Summaries");
1039 /* Display functions */
1040 static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1041 char *buf
, int buflen
,
1044 struct ospf6_inter_prefix_lsa
*prefix_lsa
;
1045 struct in6_addr in6
;
1049 (struct ospf6_inter_prefix_lsa
*)OSPF6_LSA_HEADER_END(
1052 ospf6_prefix_in6_addr(&in6
, &prefix_lsa
->prefix
);
1054 inet_ntop(AF_INET6
, &in6
, buf
, buflen
);
1055 sprintf(&buf
[strlen(buf
)], "/%d",
1056 prefix_lsa
->prefix
.prefix_length
);
1063 static int ospf6_inter_area_prefix_lsa_show(struct vty
*vty
,
1064 struct ospf6_lsa
*lsa
)
1066 struct ospf6_inter_prefix_lsa
*prefix_lsa
;
1067 char buf
[INET6_ADDRSTRLEN
];
1069 prefix_lsa
= (struct ospf6_inter_prefix_lsa
*)OSPF6_LSA_HEADER_END(
1072 vty_out(vty
, " Metric: %lu\n",
1073 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa
));
1075 ospf6_prefix_options_printbuf(prefix_lsa
->prefix
.prefix_options
, buf
,
1077 vty_out(vty
, " Prefix Options: %s\n", buf
);
1079 vty_out(vty
, " Prefix: %s\n",
1080 ospf6_inter_area_prefix_lsa_get_prefix_str(lsa
, buf
,
1086 static char *ospf6_inter_area_router_lsa_get_prefix_str(struct ospf6_lsa
*lsa
,
1087 char *buf
, int buflen
,
1090 struct ospf6_inter_router_lsa
*router_lsa
;
1094 (struct ospf6_inter_router_lsa
*)OSPF6_LSA_HEADER_END(
1099 inet_ntop(AF_INET
, &router_lsa
->router_id
, buf
, buflen
);
1105 static int ospf6_inter_area_router_lsa_show(struct vty
*vty
,
1106 struct ospf6_lsa
*lsa
)
1108 struct ospf6_inter_router_lsa
*router_lsa
;
1111 router_lsa
= (struct ospf6_inter_router_lsa
*)OSPF6_LSA_HEADER_END(
1114 ospf6_options_printbuf(router_lsa
->options
, buf
, sizeof(buf
));
1115 vty_out(vty
, " Options: %s\n", buf
);
1116 vty_out(vty
, " Metric: %lu\n",
1117 (unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa
));
1119 inet_ntop(AF_INET
, &router_lsa
->router_id
, buf
, sizeof(buf
));
1120 vty_out(vty
, " Destination Router ID: %s\n", buf
);
1125 /* Debug commands */
1126 DEFUN (debug_ospf6_abr
,
1127 debug_ospf6_abr_cmd
,
1131 "Debug OSPFv3 ABR function\n"
1134 OSPF6_DEBUG_ABR_ON();
1138 DEFUN (no_debug_ospf6_abr
,
1139 no_debug_ospf6_abr_cmd
,
1140 "no debug ospf6 abr",
1144 "Debug OSPFv3 ABR function\n"
1147 OSPF6_DEBUG_ABR_OFF();
1151 int config_write_ospf6_debug_abr(struct vty
*vty
)
1153 if (IS_OSPF6_DEBUG_ABR
)
1154 vty_out(vty
, "debug ospf6 abr\n");
1158 void install_element_ospf6_debug_abr(void)
1160 install_element(ENABLE_NODE
, &debug_ospf6_abr_cmd
);
1161 install_element(ENABLE_NODE
, &no_debug_ospf6_abr_cmd
);
1162 install_element(CONFIG_NODE
, &debug_ospf6_abr_cmd
);
1163 install_element(CONFIG_NODE
, &no_debug_ospf6_abr_cmd
);
1166 struct ospf6_lsa_handler inter_prefix_handler
= {
1167 .lh_type
= OSPF6_LSTYPE_INTER_PREFIX
,
1168 .lh_name
= "Inter-Prefix",
1169 .lh_short_name
= "IAP",
1170 .lh_show
= ospf6_inter_area_prefix_lsa_show
,
1171 .lh_get_prefix_str
= ospf6_inter_area_prefix_lsa_get_prefix_str
,
1174 struct ospf6_lsa_handler inter_router_handler
= {
1175 .lh_type
= OSPF6_LSTYPE_INTER_ROUTER
,
1176 .lh_name
= "Inter-Router",
1177 .lh_short_name
= "IAR",
1178 .lh_show
= ospf6_inter_area_router_lsa_show
,
1179 .lh_get_prefix_str
= ospf6_inter_area_router_lsa_get_prefix_str
,
1182 void ospf6_abr_init(void)
1184 ospf6_install_lsa_handler(&inter_prefix_handler
);
1185 ospf6_install_lsa_handler(&inter_router_handler
);