1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * OSPF AS Boundary Router functions.
4 * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
19 #include "ospfd/ospfd.h"
20 #include "ospfd/ospf_interface.h"
21 #include "ospfd/ospf_asbr.h"
22 #include "ospfd/ospf_lsa.h"
23 #include "ospfd/ospf_lsdb.h"
24 #include "ospfd/ospf_neighbor.h"
25 #include "ospfd/ospf_spf.h"
26 #include "ospfd/ospf_flood.h"
27 #include "ospfd/ospf_route.h"
28 #include "ospfd/ospf_zebra.h"
29 #include "ospfd/ospf_dump.h"
30 #include "ospfd/ospf_errors.h"
32 /* Remove external route. */
33 void ospf_external_route_remove(struct ospf
*ospf
, struct prefix_ipv4
*p
)
35 struct route_node
*rn
;
36 struct ospf_route
* or ;
38 rn
= route_node_lookup(ospf
->old_external_route
, (struct prefix
*)p
);
40 if ((or = rn
->info
)) {
41 zlog_info("Route[%pFX]: external path deleted", p
);
43 /* Remove route from zebra. */
44 if (or->type
== OSPF_DESTINATION_NETWORK
)
46 ospf
, (struct prefix_ipv4
*)&rn
->p
, or);
51 route_unlock_node(rn
);
52 route_unlock_node(rn
);
56 zlog_info("Route[%pFX]: no such external path", p
);
59 /* Add an External info for AS-external-LSA. */
60 struct external_info
*ospf_external_info_new(struct ospf
*ospf
, uint8_t type
,
61 unsigned short instance
)
63 struct external_info
*new;
65 new = XCALLOC(MTYPE_OSPF_EXTERNAL_INFO
, sizeof(struct external_info
));
68 new->instance
= instance
;
69 new->to_be_processed
= 0;
71 ospf_reset_route_map_set_values(&new->route_map_set
);
75 static void ospf_external_info_free(struct external_info
*ei
)
77 XFREE(MTYPE_OSPF_EXTERNAL_INFO
, ei
);
80 void ospf_reset_route_map_set_values(struct route_map_set_values
*values
)
83 values
->metric_type
= -1;
86 int ospf_route_map_set_compare(struct route_map_set_values
*values1
,
87 struct route_map_set_values
*values2
)
89 return values1
->metric
== values2
->metric
90 && values1
->metric_type
== values2
->metric_type
;
93 /* Add an External info for AS-external-LSA. */
94 struct external_info
*
95 ospf_external_info_add(struct ospf
*ospf
, uint8_t type
, unsigned short instance
,
96 struct prefix_ipv4 p
, ifindex_t ifindex
,
97 struct in_addr nexthop
, route_tag_t tag
)
99 struct external_info
*new;
100 struct route_node
*rn
;
101 struct ospf_external
*ext
;
103 ext
= ospf_external_lookup(ospf
, type
, instance
);
105 ext
= ospf_external_add(ospf
, type
, instance
);
107 rn
= route_node_get(EXTERNAL_INFO(ext
), (struct prefix
*)&p
);
108 /* If old info exists, -- discard new one or overwrite with new one? */
109 if (rn
&& rn
->info
) {
111 if ((new->ifindex
== ifindex
)
112 && (new->nexthop
.s_addr
== nexthop
.s_addr
)
113 && (new->tag
== tag
)) {
114 route_unlock_node(rn
);
115 return NULL
; /* NULL => no LSA to refresh */
118 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
))
120 "Redistribute[%s][%d][%u]: %pFX discarding old info with NH %pI4.",
121 ospf_redist_string(type
), instance
,
122 ospf
->vrf_id
, &p
, &nexthop
.s_addr
);
123 XFREE(MTYPE_OSPF_EXTERNAL_INFO
, rn
->info
);
126 /* Create new External info instance. */
127 new = ospf_external_info_new(ospf
, type
, instance
);
129 new->ifindex
= ifindex
;
130 new->nexthop
= nexthop
;
133 new->aggr_route
= NULL
;
135 /* we don't unlock rn from the get() because we're attaching the info */
139 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
)) {
141 "Redistribute[%s][%u]: %pFX external info created, with NH %pI4",
142 ospf_redist_string(type
), ospf
->vrf_id
, &p
,
148 void ospf_external_info_delete(struct ospf
*ospf
, uint8_t type
,
149 unsigned short instance
, struct prefix_ipv4 p
)
151 struct route_node
*rn
;
152 struct ospf_external
*ext
;
154 ext
= ospf_external_lookup(ospf
, type
, instance
);
158 rn
= route_node_lookup(EXTERNAL_INFO(ext
), (struct prefix
*)&p
);
160 ospf_external_info_free(rn
->info
);
162 route_unlock_node(rn
);
163 route_unlock_node(rn
);
167 struct external_info
*ospf_external_info_lookup(struct ospf
*ospf
, uint8_t type
,
168 unsigned short instance
,
169 struct prefix_ipv4
*p
)
171 struct route_node
*rn
;
172 struct ospf_external
*ext
;
174 ext
= ospf_external_lookup(ospf
, type
, instance
);
178 rn
= route_node_lookup(EXTERNAL_INFO(ext
), (struct prefix
*)p
);
180 route_unlock_node(rn
);
188 struct ospf_lsa
*ospf_external_info_find_lsa(struct ospf
*ospf
,
189 struct prefix_ipv4
*p
)
191 struct ospf_lsa
*lsa
;
192 struct as_external_lsa
*al
;
193 struct in_addr mask
, id
;
195 /* First search the lsdb with address specific LSID
196 * where all the host bits are set, if there a matched
198 * Ex: For route 10.0.0.0/16, LSID is 10.0.255.255
199 * If no lsa with above LSID, use received address as
200 * LSID and check if any LSA in LSDB.
201 * If LSA found, check if the mask is same b/w the matched
202 * LSA and received prefix, if same then it is the LSA for
204 * Ex: For route 10.0.0.0/16, LSID is 10.0.0.0
207 masklen2ip(p
->prefixlen
, &mask
);
208 id
.s_addr
= p
->prefix
.s_addr
| (~mask
.s_addr
);
209 lsa
= ospf_lsdb_lookup_by_id(ospf
->lsdb
, OSPF_AS_EXTERNAL_LSA
, id
,
212 if (p
->prefixlen
== IPV4_MAX_BITLEN
) {
213 al
= (struct as_external_lsa
*)lsa
->data
;
215 if (mask
.s_addr
!= al
->mask
.s_addr
)
221 lsa
= ospf_lsdb_lookup_by_id(ospf
->lsdb
, OSPF_AS_EXTERNAL_LSA
,
222 p
->prefix
, ospf
->router_id
);
225 al
= (struct as_external_lsa
*)lsa
->data
;
226 if (mask
.s_addr
== al
->mask
.s_addr
)
234 /* Update ASBR status. */
235 void ospf_asbr_status_update(struct ospf
*ospf
, uint8_t status
)
237 zlog_info("ASBR[%s:Status:%d]: Update",
238 ospf_get_name(ospf
), status
);
243 if (IS_OSPF_ASBR(ospf
)) {
244 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
245 ospf_get_name(ospf
), status
);
248 SET_FLAG(ospf
->flags
, OSPF_FLAG_ASBR
);
250 /* Already non ASBR. */
251 if (!IS_OSPF_ASBR(ospf
)) {
252 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
253 ospf_get_name(ospf
), status
);
256 UNSET_FLAG(ospf
->flags
, OSPF_FLAG_ASBR
);
259 /* Transition from/to status ASBR, schedule timer. */
260 ospf_spf_calculate_schedule(ospf
, SPF_FLAG_ASBR_STATUS_CHANGE
);
261 ospf_router_lsa_update(ospf
);
264 /* If there's redistribution configured, we need to refresh external
265 * LSAs in order to install Type-7 and flood to all NSSA Areas
267 static void ospf_asbr_nssa_redist_update_timer(struct event
*thread
)
269 struct ospf
*ospf
= EVENT_ARG(thread
);
272 ospf
->t_asbr_nssa_redist_update
= NULL
;
274 if (IS_DEBUG_OSPF_EVENT
)
275 zlog_debug("Running ASBR NSSA redistribution update on timer");
277 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
278 struct list
*red_list
;
279 struct listnode
*node
;
280 struct ospf_redist
*red
;
282 red_list
= ospf
->redist
[type
];
286 for (ALL_LIST_ELEMENTS_RO(red_list
, node
, red
))
287 ospf_external_lsa_refresh_type(ospf
, type
,
292 ospf_external_lsa_refresh_default(ospf
);
295 void ospf_schedule_asbr_nssa_redist_update(struct ospf
*ospf
)
297 if (IS_DEBUG_OSPF_EVENT
)
298 zlog_debug("Scheduling ASBR NSSA redistribution update");
300 event_add_timer(master
, ospf_asbr_nssa_redist_update_timer
, ospf
,
301 OSPF_ASBR_NSSA_REDIST_UPDATE_DELAY
,
302 &ospf
->t_asbr_nssa_redist_update
);
305 void ospf_redistribute_withdraw(struct ospf
*ospf
, uint8_t type
,
306 unsigned short instance
)
308 struct route_node
*rn
;
309 struct external_info
*ei
;
310 struct ospf_external
*ext
;
312 ext
= ospf_external_lookup(ospf
, type
, instance
);
316 /* Delete external info for specified type. */
317 if (!EXTERNAL_INFO(ext
))
320 for (rn
= route_top(EXTERNAL_INFO(ext
)); rn
; rn
= route_next(rn
)) {
326 struct ospf_external_aggr_rt
*aggr
;
328 if (is_default_prefix4(&ei
->p
)
329 && ospf
->default_originate
!= DEFAULT_ORIGINATE_NONE
)
332 aggr
= ei
->aggr_route
;
335 ospf_unlink_ei_from_aggr(ospf
, aggr
, ei
);
336 else if (ospf_external_info_find_lsa(ospf
, &ei
->p
))
337 ospf_external_lsa_flush(ospf
, type
, &ei
->p
,
338 ei
->ifindex
/*, ei->nexthop */);
340 ospf_external_info_free(ei
);
341 route_unlock_node(rn
);
347 /* External Route Aggregator Handlers */
348 bool is_valid_summary_addr(struct prefix_ipv4
*p
)
350 /* Default prefix validation*/
351 if (p
->prefix
.s_addr
== INADDR_ANY
)
354 /*Host route shouldn't be configured as summary addres*/
355 if (p
->prefixlen
== IPV4_MAX_BITLEN
)
360 void ospf_asbr_external_aggregator_init(struct ospf
*instance
)
362 instance
->rt_aggr_tbl
= route_table_init();
364 instance
->t_external_aggr
= NULL
;
366 instance
->aggr_action
= 0;
368 instance
->aggr_delay_interval
= OSPF_EXTL_AGGR_DEFAULT_DELAY
;
371 static unsigned int ospf_external_rt_hash_key(const void *data
)
373 const struct external_info
*ei
= data
;
374 unsigned int key
= 0;
376 key
= prefix_hash_key(&ei
->p
);
380 static bool ospf_external_rt_hash_cmp(const void *d1
, const void *d2
)
382 const struct external_info
*ei1
= d1
;
383 const struct external_info
*ei2
= d2
;
385 return prefix_same((struct prefix
*)&ei1
->p
, (struct prefix
*)&ei2
->p
);
388 static struct ospf_external_aggr_rt
*
389 ospf_external_aggregator_new(struct prefix_ipv4
*p
)
391 struct ospf_external_aggr_rt
*aggr
;
393 aggr
= (struct ospf_external_aggr_rt
*)XCALLOC(
394 MTYPE_OSPF_EXTERNAL_RT_AGGR
,
395 sizeof(struct ospf_external_aggr_rt
));
400 aggr
->p
.family
= p
->family
;
401 aggr
->p
.prefix
= p
->prefix
;
402 aggr
->p
.prefixlen
= p
->prefixlen
;
403 aggr
->match_extnl_hash
= hash_create(ospf_external_rt_hash_key
,
404 ospf_external_rt_hash_cmp
,
405 "Ospf external route hash");
409 static void ospf_aggr_handle_external_info(void *data
)
411 struct external_info
*ei
= (struct external_info
*)data
;
412 struct ospf_external_aggr_rt
*aggr
= NULL
;
413 struct ospf
*ospf
= ei
->ospf
;
414 struct ospf_lsa
*lsa
= NULL
;
416 ei
->aggr_route
= NULL
;
418 ei
->to_be_processed
= true;
420 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
421 zlog_debug("%s: Handle extrenal route(%pI4/%d)", __func__
,
422 &ei
->p
.prefix
, ei
->p
.prefixlen
);
426 if (!ospf_redistribute_check(ospf
, ei
, NULL
))
429 aggr
= ospf_external_aggr_match(ospf
, &ei
->p
);
431 (void)ospf_originate_summary_lsa(ospf
, aggr
, ei
);
435 lsa
= ospf_external_info_find_lsa(ospf
, &ei
->p
);
437 ospf_external_lsa_refresh(ospf
, lsa
, ei
, LSA_REFRESH_FORCE
, 1);
439 (void)ospf_external_lsa_originate(ospf
, ei
);
442 static void ospf_aggr_unlink_external_info(void *data
)
444 struct external_info
*ei
= (struct external_info
*)data
;
446 ei
->aggr_route
= NULL
;
448 ei
->to_be_processed
= true;
451 void ospf_external_aggregator_free(struct ospf_external_aggr_rt
*aggr
)
453 hash_clean_and_free(&aggr
->match_extnl_hash
,
454 (void *)ospf_aggr_unlink_external_info
);
456 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
457 zlog_debug("%s: Release the aggregator Address(%pI4/%d)",
458 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
460 XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR
, aggr
);
463 static void ospf_external_aggr_add(struct ospf
*ospf
,
464 struct ospf_external_aggr_rt
*aggr
)
466 struct route_node
*rn
;
468 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
469 zlog_debug("%s: Adding Aggregate route to Aggr table (%pI4/%d)",
470 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
471 rn
= route_node_get(ospf
->rt_aggr_tbl
, (struct prefix
*)&aggr
->p
);
473 route_unlock_node(rn
);
478 static void ospf_external_aggr_delete(struct ospf
*ospf
, struct route_node
*rn
)
480 struct ospf_external_aggr_rt
*aggr
= rn
->info
;
482 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
483 zlog_debug("%s: Deleting Aggregate route (%pI4/%d)", __func__
,
484 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
486 /* Sent a Max age LSA if it is already originated. */
487 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
488 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
489 zlog_debug("%s: Flushing Aggregate route (%pI4/%d)",
490 __func__
, &aggr
->p
.prefix
,
492 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
496 route_unlock_node(rn
);
499 struct ospf_external_aggr_rt
*
500 ospf_extrenal_aggregator_lookup(struct ospf
*ospf
, struct prefix_ipv4
*p
)
502 struct route_node
*rn
;
503 struct ospf_external_aggr_rt
*summary_rt
= NULL
;
505 rn
= route_node_lookup(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
507 summary_rt
= rn
->info
;
508 route_unlock_node(rn
);
514 struct ospf_external_aggr_rt
*ospf_external_aggr_match(struct ospf
*ospf
,
515 struct prefix_ipv4
*p
)
517 struct route_node
*node
;
518 struct ospf_external_aggr_rt
*summary_rt
= NULL
;
520 node
= route_node_match(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
523 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
525 struct ospf_external_aggr_rt
*ag
= node
->info
;
528 "%s: Matching aggregator found.prefix:%pI4/%d Aggregator %pI4/%d",
529 __func__
, &p
->prefix
, p
->prefixlen
,
530 &ag
->p
.prefix
, ag
->p
.prefixlen
);
533 summary_rt
= node
->info
;
534 route_unlock_node(node
);
540 void ospf_unlink_ei_from_aggr(struct ospf
*ospf
,
541 struct ospf_external_aggr_rt
*aggr
,
542 struct external_info
*ei
)
544 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
546 "%s: Unlinking extrenal route(%pI4/%d) from aggregator(%pI4/%d), external route count:%ld",
547 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
,
548 &aggr
->p
.prefix
, aggr
->p
.prefixlen
,
549 OSPF_EXTERNAL_RT_COUNT(aggr
));
550 hash_release(aggr
->match_extnl_hash
, ei
);
551 ei
->aggr_route
= NULL
;
553 /* Flush the aggreagte route if matching
554 * external route count becomes zero.
556 if (!OSPF_EXTERNAL_RT_COUNT(aggr
)
557 && CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
559 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
560 zlog_debug("%s: Flushing the aggreagte route (%pI4/%d)",
561 __func__
, &aggr
->p
.prefix
,
564 /* Flush the aggregate LSA */
565 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
567 /* Unset the Origination flag */
568 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
572 static void ospf_link_ei_to_aggr(struct ospf_external_aggr_rt
*aggr
,
573 struct external_info
*ei
)
575 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
577 "%s: Linking extrenal route(%pI4/%d) to aggregator(%pI4/%d)",
578 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
,
579 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
580 (void)hash_get(aggr
->match_extnl_hash
, ei
, hash_alloc_intern
);
581 ei
->aggr_route
= aggr
;
584 struct ospf_lsa
*ospf_originate_summary_lsa(struct ospf
*ospf
,
585 struct ospf_external_aggr_rt
*aggr
,
586 struct external_info
*ei
)
588 struct ospf_lsa
*lsa
;
589 struct external_info ei_aggr
;
590 struct as_external_lsa
*asel
;
591 struct ospf_external_aggr_rt
*old_aggr
;
594 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
595 zlog_debug("%s: Prepare to originate Summary route(%pI4/%d)",
596 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
598 /* This case to handle when the overlapping aggregator address
599 * is availbe.Best match will be considered.So need to delink
600 * from old aggregator and link to the new aggr.
602 if (ei
->aggr_route
) {
603 if (ei
->aggr_route
!= aggr
) {
604 old_aggr
= ei
->aggr_route
;
605 ospf_unlink_ei_from_aggr(ospf
, old_aggr
, ei
);
609 /* Add the external route to hash table */
610 ospf_link_ei_to_aggr(aggr
, ei
);
612 lsa
= ospf_external_info_find_lsa(ospf
, &aggr
->p
);
613 /* Don't originate external LSA,
614 * If it is configured not to advertise.
616 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
617 /* If it is already originated as external LSA,
618 * But, it is configured not to advertise then
619 * flush the originated external lsa.
622 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
623 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
625 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
627 "%s: Don't originate the summary address,It is configured to not-advertise.",
632 /* Prepare the extrenal_info for aggregator */
633 memset(&ei_aggr
, 0, sizeof(ei_aggr
));
635 ei_aggr
.tag
= aggr
->tag
;
637 ei_aggr
.instance
= ospf
->instance
;
638 ei_aggr
.route_map_set
.metric
= -1;
639 ei_aggr
.route_map_set
.metric_type
= -1;
641 /* Summary route already originated,
644 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
646 flog_warn(EC_OSPF_LSA_MISSING
,
647 "%s: Could not refresh/originate %pI4/%d",
648 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
652 asel
= (struct as_external_lsa
*)lsa
->data
;
653 tag
= (unsigned long)ntohl(asel
->e
[0].route_tag
);
655 /* If tag modified , then re-originate the route
656 * with modified tag details.
658 if (tag
!= ei_aggr
.tag
) {
659 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
661 "%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
662 __func__
, tag
, ei_aggr
.tag
,
663 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
665 ospf_external_lsa_refresh(ospf
, lsa
, &ei_aggr
,
666 LSA_REFRESH_FORCE
, 1);
671 if (lsa
&& IS_LSA_MAXAGE(lsa
)) {
672 /* This is special case.
673 * If a summary route need to be originated but where
674 * summary route already exist in lsdb with maxage, then
675 * it need to be refreshed.
677 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
679 "%s: LSA is in MAX-AGE so refreshing LSA(%pI4/%d)",
680 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
682 ospf_external_lsa_refresh(ospf
, lsa
, &ei_aggr
,
683 LSA_REFRESH_FORCE
, 1);
684 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
688 /* If the external route prefix same as aggregate route
689 * and if external route is already originated as TYPE-5
690 * then it need to be refreshed and originate bit should
693 if (lsa
&& prefix_same((struct prefix
*)&ei_aggr
.p
,
694 (struct prefix
*)&ei
->p
)) {
695 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
697 "%s: External route prefix is same as aggr so refreshing LSA(%pI4/%d)",
698 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
699 ospf_external_lsa_refresh(ospf
, lsa
, &ei_aggr
,
700 LSA_REFRESH_FORCE
, 1);
701 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
705 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
706 zlog_debug("%s: Originate Summary route(%pI4/%d)", __func__
,
707 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
709 /* Originate summary LSA */
710 lsa
= ospf_external_lsa_originate(ospf
, &ei_aggr
);
712 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
713 zlog_debug("%s: Set the origination bit for aggregator",
715 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
720 void ospf_unset_all_aggr_flag(struct ospf
*ospf
)
722 struct route_node
*rn
= NULL
;
724 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
725 zlog_debug("Unset the origination bit for all aggregator");
727 for (rn
= route_top(ospf
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
731 struct ospf_external_aggr_rt
*aggr
= rn
->info
;
733 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
737 static void ospf_delete_all_marked_aggregators(struct ospf
*ospf
)
739 struct route_node
*rn
= NULL
;
741 /* Loop through all the aggregators, Delete all aggregators
742 * which are marked as DELETE. Set action to NONE for remaining
745 for (rn
= route_top(ospf
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
749 struct ospf_external_aggr_rt
*aggr
= rn
->info
;
751 if (aggr
->action
!= OSPF_ROUTE_AGGR_DEL
) {
752 aggr
->action
= OSPF_ROUTE_AGGR_NONE
;
755 ospf_external_aggr_delete(ospf
, rn
);
756 ospf_external_aggregator_free(aggr
);
760 static void ospf_handle_aggregated_exnl_rt(struct ospf
*ospf
,
761 struct ospf_external_aggr_rt
*aggr
,
762 struct external_info
*ei
)
764 struct ospf_lsa
*lsa
;
765 struct as_external_lsa
*al
;
768 /* Handling the case where the external route prefix
769 * and aggregate prefix is same
770 * If same don't flush the originated external LSA.
772 if (prefix_same((struct prefix
*)&aggr
->p
, (struct prefix
*)&ei
->p
)) {
773 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
775 "%s: External Route prefix same as Aggregator(%pI4/%d), so don't flush.",
776 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
);
780 lsa
= ospf_external_info_find_lsa(ospf
, &ei
->p
);
782 al
= (struct as_external_lsa
*)lsa
->data
;
783 masklen2ip(ei
->p
.prefixlen
, &mask
);
785 if (mask
.s_addr
!= al
->mask
.s_addr
)
788 ospf_external_lsa_flush(ospf
, ei
->type
, &ei
->p
, 0);
792 static void ospf_handle_exnl_rt_after_aggr_del(struct ospf
*ospf
,
793 struct external_info
*ei
)
795 struct ospf_lsa
*lsa
;
797 /* Process only marked external routes.
798 * These routes were part of a deleted
799 * aggregator.So, originate now.
801 if (!ei
->to_be_processed
)
804 ei
->to_be_processed
= false;
806 lsa
= ospf_external_info_find_lsa(ospf
, &ei
->p
);
809 ospf_external_lsa_refresh(ospf
, lsa
, ei
, LSA_REFRESH_FORCE
, 0);
811 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
812 zlog_debug("%s: Originate external route(%pI4/%d)",
813 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
);
815 ospf_external_lsa_originate(ospf
, ei
);
819 static void ospf_handle_external_aggr_add(struct ospf
*ospf
)
821 struct external_info
*ei
;
822 struct route_node
*rn
= NULL
;
823 struct route_table
*rt
= NULL
;
826 /* Delete all the aggregators which are marked as
827 * OSPF_ROUTE_AGGR_DEL.
829 ospf_delete_all_marked_aggregators(ospf
);
831 for (type
= 0; type
<= ZEBRA_ROUTE_MAX
; type
++) {
832 struct list
*ext_list
;
833 struct listnode
*node
;
834 struct ospf_external
*ext
;
835 struct ospf_external_aggr_rt
*aggr
;
837 ext_list
= ospf
->external
[type
];
841 for (ALL_LIST_ELEMENTS_RO(ext_list
, node
, ext
)) {
842 rt
= ext
->external_info
;
846 for (rn
= route_top(rt
); rn
; rn
= route_next(rn
)) {
851 if (is_default_prefix4(&ei
->p
))
854 /* Check the AS-external-LSA
855 * should be originated.
857 if (!ospf_redistribute_check(ospf
, ei
, NULL
))
860 aggr
= ospf_external_aggr_match(ospf
, &ei
->p
);
862 /* If matching aggregator found, Add
863 * the external route reference to the
864 * aggregator and originate the aggr
865 * route if it is advertisable.
866 * flush the external LSA if it is
867 * already originated for this external
871 ospf_originate_summary_lsa(ospf
, aggr
,
874 /* All aggregated external rts
877 ospf_handle_aggregated_exnl_rt(
882 /* External routes which are only out
883 * of aggregation will be handled here.
885 ospf_handle_exnl_rt_after_aggr_del(ospf
, ei
);
892 ospf_aggr_handle_advertise_change(struct ospf
*ospf
,
893 struct ospf_external_aggr_rt
*aggr
,
894 struct external_info
*ei_aggr
)
896 struct ospf_lsa
*lsa
;
898 /* Check if advertise option modified. */
899 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
901 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
903 "%s: Don't originate the summary address,It is configured to not-advertise.",
906 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
908 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
910 "%s: No-advertise,So Flush the Aggregate route(%pI4/%d)",
911 __func__
, &aggr
->p
.prefix
,
914 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
916 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
921 if (!CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
922 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
923 zlog_debug("%s: Now it is advatisable", __func__
);
925 lsa
= ospf_external_info_find_lsa(ospf
, &ei_aggr
->p
);
926 if (lsa
&& IS_LSA_MAXAGE(lsa
)) {
927 /* This is special case.
928 * If a summary route need to be originated but where
929 * summary route already exist in lsdb with maxage, then
930 * it need to be refreshed.
932 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
934 "%s: It is already with Maxage, So refresh it (%pI4/%d)",
935 __func__
, &aggr
->p
.prefix
,
938 ospf_external_lsa_refresh(ospf
, lsa
, ei_aggr
,
939 LSA_REFRESH_FORCE
, 1);
941 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
945 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
947 "%s: Originate Aggregate LSA (%pI4/%d)",
948 __func__
, &aggr
->p
.prefix
,
951 /* Originate summary LSA */
952 lsa
= ospf_external_lsa_originate(ospf
, ei_aggr
);
954 SET_FLAG(aggr
->flags
,
955 OSPF_EXTERNAL_AGGRT_ORIGINATED
);
960 static void ospf_handle_external_aggr_update(struct ospf
*ospf
)
962 struct route_node
*rn
= NULL
;
964 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
965 zlog_debug("%s: Process modified aggregators.", __func__
);
967 for (rn
= route_top(ospf
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
968 struct ospf_external_aggr_rt
*aggr
;
969 struct ospf_lsa
*lsa
= NULL
;
970 struct as_external_lsa
*asel
= NULL
;
971 struct external_info ei_aggr
;
979 if (aggr
->action
== OSPF_ROUTE_AGGR_DEL
) {
980 aggr
->action
= OSPF_ROUTE_AGGR_NONE
;
981 ospf_external_aggr_delete(ospf
, rn
);
984 &aggr
->match_extnl_hash
,
985 (void *)ospf_aggr_handle_external_info
);
987 } else if (aggr
->action
== OSPF_ROUTE_AGGR_MODIFY
) {
989 aggr
->action
= OSPF_ROUTE_AGGR_NONE
;
991 /* Prepare the extrenal_info for aggregator */
992 memset(&ei_aggr
, 0, sizeof(ei_aggr
));
994 ei_aggr
.tag
= aggr
->tag
;
996 ei_aggr
.instance
= ospf
->instance
;
997 ei_aggr
.route_map_set
.metric
= -1;
998 ei_aggr
.route_map_set
.metric_type
= -1;
1000 /* Check if tag modified */
1001 if (CHECK_FLAG(aggr
->flags
,
1002 OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
1003 lsa
= ospf_external_info_find_lsa(ospf
,
1006 flog_warn(EC_OSPF_LSA_MISSING
,
1007 "%s: Could not refresh/originate %pI4/%d",
1008 __func__
, &aggr
->p
.prefix
,
1013 asel
= (struct as_external_lsa
*)lsa
->data
;
1014 tag
= (unsigned long)ntohl(
1015 asel
->e
[0].route_tag
);
1017 /* If tag modified , then re-originate the
1018 * route with modified tag details.
1020 if (tag
!= ei_aggr
.tag
) {
1021 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1023 "%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
1029 ospf_external_lsa_refresh(
1030 ospf
, lsa
, &ei_aggr
,
1031 LSA_REFRESH_FORCE
, 1);
1035 /* Advertise option modified ?
1036 * If so, handled it here.
1038 ospf_aggr_handle_advertise_change(ospf
, aggr
, &ei_aggr
);
1043 static void ospf_asbr_external_aggr_process(struct event
*thread
)
1045 struct ospf
*ospf
= EVENT_ARG(thread
);
1048 ospf
->t_external_aggr
= NULL
;
1049 operation
= ospf
->aggr_action
;
1051 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1052 zlog_debug("%s: operation:%d", __func__
, operation
);
1054 switch (operation
) {
1055 case OSPF_ROUTE_AGGR_ADD
:
1056 ospf_handle_external_aggr_add(ospf
);
1058 case OSPF_ROUTE_AGGR_DEL
:
1059 case OSPF_ROUTE_AGGR_MODIFY
:
1060 ospf_handle_external_aggr_update(ospf
);
1066 static void ospf_external_aggr_timer(struct ospf
*ospf
,
1067 struct ospf_external_aggr_rt
*aggr
,
1068 enum ospf_aggr_action_t operation
)
1070 aggr
->action
= operation
;
1072 if (ospf
->t_external_aggr
) {
1073 if (ospf
->aggr_action
== OSPF_ROUTE_AGGR_ADD
) {
1075 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1077 "%s: Not required to retsart timer,set is already added.",
1082 if (operation
== OSPF_ROUTE_AGGR_ADD
) {
1083 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1085 "%s, Restarting Aggregator delay timer.",
1087 EVENT_OFF(ospf
->t_external_aggr
);
1091 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1092 zlog_debug("%s: Start Aggregator delay timer %u(in seconds).",
1093 __func__
, ospf
->aggr_delay_interval
);
1095 ospf
->aggr_action
= operation
;
1096 event_add_timer(master
, ospf_asbr_external_aggr_process
, ospf
,
1097 ospf
->aggr_delay_interval
, &ospf
->t_external_aggr
);
1100 int ospf_asbr_external_aggregator_set(struct ospf
*ospf
, struct prefix_ipv4
*p
,
1103 struct ospf_external_aggr_rt
*aggregator
;
1105 aggregator
= ospf_extrenal_aggregator_lookup(ospf
, p
);
1108 if (CHECK_FLAG(aggregator
->flags
,
1109 OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
))
1110 UNSET_FLAG(aggregator
->flags
,
1111 OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1112 else if (aggregator
->tag
== tag
)
1113 return OSPF_SUCCESS
;
1115 aggregator
->tag
= tag
;
1117 ospf_external_aggr_timer(ospf
, aggregator
,
1118 OSPF_ROUTE_AGGR_MODIFY
);
1120 aggregator
= ospf_external_aggregator_new(p
);
1122 return OSPF_FAILURE
;
1124 aggregator
->tag
= tag
;
1126 ospf_external_aggr_add(ospf
, aggregator
);
1127 ospf_external_aggr_timer(ospf
, aggregator
, OSPF_ROUTE_AGGR_ADD
);
1130 return OSPF_SUCCESS
;
1133 int ospf_asbr_external_aggregator_unset(struct ospf
*ospf
,
1134 struct prefix_ipv4
*p
, route_tag_t tag
)
1136 struct route_node
*rn
;
1137 struct ospf_external_aggr_rt
*aggr
;
1139 rn
= route_node_lookup(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
1141 return OSPF_INVALID
;
1142 route_unlock_node(rn
);
1146 if (tag
&& (tag
!= aggr
->tag
))
1147 return OSPF_INVALID
;
1149 if (!OSPF_EXTERNAL_RT_COUNT(aggr
)) {
1150 ospf_external_aggr_delete(ospf
, rn
);
1151 ospf_external_aggregator_free(aggr
);
1152 return OSPF_SUCCESS
;
1155 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_DEL
);
1157 return OSPF_SUCCESS
;
1160 int ospf_asbr_external_rt_no_advertise(struct ospf
*ospf
, struct prefix_ipv4
*p
)
1162 struct ospf_external_aggr_rt
*aggr
;
1163 route_tag_t tag
= 0;
1165 aggr
= ospf_extrenal_aggregator_lookup(ospf
, p
);
1167 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
))
1168 return OSPF_SUCCESS
;
1170 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1174 if (!OSPF_EXTERNAL_RT_COUNT(aggr
))
1175 return OSPF_SUCCESS
;
1177 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_MODIFY
);
1179 aggr
= ospf_external_aggregator_new(p
);
1182 return OSPF_FAILURE
;
1184 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1185 ospf_external_aggr_add(ospf
, aggr
);
1186 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_ADD
);
1189 return OSPF_SUCCESS
;
1192 int ospf_asbr_external_rt_advertise(struct ospf
*ospf
, struct prefix_ipv4
*p
)
1194 struct route_node
*rn
;
1195 struct ospf_external_aggr_rt
*aggr
;
1197 rn
= route_node_lookup(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
1199 return OSPF_INVALID
;
1200 route_unlock_node(rn
);
1204 if (!CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
))
1205 return OSPF_INVALID
;
1207 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1209 if (!OSPF_EXTERNAL_RT_COUNT(aggr
))
1210 return OSPF_SUCCESS
;
1212 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_MODIFY
);
1213 return OSPF_SUCCESS
;
1216 int ospf_external_aggregator_timer_set(struct ospf
*ospf
, uint16_t interval
)
1218 ospf
->aggr_delay_interval
= interval
;
1219 return OSPF_SUCCESS
;