2 * OSPF AS Boundary Router functions.
3 * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
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 "ospfd/ospfd.h"
35 #include "ospfd/ospf_interface.h"
36 #include "ospfd/ospf_asbr.h"
37 #include "ospfd/ospf_lsa.h"
38 #include "ospfd/ospf_lsdb.h"
39 #include "ospfd/ospf_neighbor.h"
40 #include "ospfd/ospf_spf.h"
41 #include "ospfd/ospf_flood.h"
42 #include "ospfd/ospf_route.h"
43 #include "ospfd/ospf_zebra.h"
44 #include "ospfd/ospf_dump.h"
45 #include "ospfd/ospf_errors.h"
47 /* Remove external route. */
48 void ospf_external_route_remove(struct ospf
*ospf
, struct prefix_ipv4
*p
)
50 struct route_node
*rn
;
51 struct ospf_route
* or ;
53 rn
= route_node_lookup(ospf
->old_external_route
, (struct prefix
*)p
);
55 if ((or = rn
->info
)) {
56 zlog_info("Route[%pFX]: external path deleted", p
);
58 /* Remove route from zebra. */
59 if (or->type
== OSPF_DESTINATION_NETWORK
)
61 ospf
, (struct prefix_ipv4
*)&rn
->p
, or);
66 route_unlock_node(rn
);
67 route_unlock_node(rn
);
71 zlog_info("Route[%pFX]: no such external path", p
);
74 /* Add an External info for AS-external-LSA. */
75 struct external_info
*ospf_external_info_new(struct ospf
*ospf
, uint8_t type
,
76 unsigned short instance
)
78 struct external_info
*new;
80 new = XCALLOC(MTYPE_OSPF_EXTERNAL_INFO
, sizeof(struct external_info
));
83 new->instance
= instance
;
84 new->to_be_processed
= 0;
86 ospf_reset_route_map_set_values(&new->route_map_set
);
90 static void ospf_external_info_free(struct external_info
*ei
)
92 XFREE(MTYPE_OSPF_EXTERNAL_INFO
, ei
);
95 void ospf_reset_route_map_set_values(struct route_map_set_values
*values
)
98 values
->metric_type
= -1;
101 int ospf_route_map_set_compare(struct route_map_set_values
*values1
,
102 struct route_map_set_values
*values2
)
104 return values1
->metric
== values2
->metric
105 && values1
->metric_type
== values2
->metric_type
;
108 /* Add an External info for AS-external-LSA. */
109 struct external_info
*
110 ospf_external_info_add(struct ospf
*ospf
, uint8_t type
, unsigned short instance
,
111 struct prefix_ipv4 p
, ifindex_t ifindex
,
112 struct in_addr nexthop
, route_tag_t tag
)
114 struct external_info
*new;
115 struct route_node
*rn
;
116 struct ospf_external
*ext
;
118 ext
= ospf_external_lookup(ospf
, type
, instance
);
120 ext
= ospf_external_add(ospf
, type
, instance
);
122 rn
= route_node_get(EXTERNAL_INFO(ext
), (struct prefix
*)&p
);
123 /* If old info exists, -- discard new one or overwrite with new one? */
124 if (rn
&& rn
->info
) {
126 if ((new->ifindex
== ifindex
)
127 && (new->nexthop
.s_addr
== nexthop
.s_addr
)
128 && (new->tag
== tag
)) {
129 route_unlock_node(rn
);
130 return NULL
; /* NULL => no LSA to refresh */
133 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
))
135 "Redistribute[%s][%d][%u]: %pFX discarding old info with NH %pI4.",
136 ospf_redist_string(type
), instance
,
137 ospf
->vrf_id
, &p
, &nexthop
.s_addr
);
138 XFREE(MTYPE_OSPF_EXTERNAL_INFO
, rn
->info
);
141 /* Create new External info instance. */
142 new = ospf_external_info_new(ospf
, type
, instance
);
144 new->ifindex
= ifindex
;
145 new->nexthop
= nexthop
;
148 new->aggr_route
= NULL
;
150 /* we don't unlock rn from the get() because we're attaching the info */
154 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
)) {
156 "Redistribute[%s][%u]: %pFX external info created, with NH %pI4",
157 ospf_redist_string(type
), ospf
->vrf_id
, &p
,
163 void ospf_external_info_delete(struct ospf
*ospf
, uint8_t type
,
164 unsigned short instance
, struct prefix_ipv4 p
)
166 struct route_node
*rn
;
167 struct ospf_external
*ext
;
169 ext
= ospf_external_lookup(ospf
, type
, instance
);
173 rn
= route_node_lookup(EXTERNAL_INFO(ext
), (struct prefix
*)&p
);
175 ospf_external_info_free(rn
->info
);
177 route_unlock_node(rn
);
178 route_unlock_node(rn
);
182 struct external_info
*ospf_external_info_lookup(struct ospf
*ospf
, uint8_t type
,
183 unsigned short instance
,
184 struct prefix_ipv4
*p
)
186 struct route_node
*rn
;
187 struct ospf_external
*ext
;
189 ext
= ospf_external_lookup(ospf
, type
, instance
);
193 rn
= route_node_lookup(EXTERNAL_INFO(ext
), (struct prefix
*)p
);
195 route_unlock_node(rn
);
203 struct ospf_lsa
*ospf_external_info_find_lsa(struct ospf
*ospf
,
204 struct prefix_ipv4
*p
)
206 struct ospf_lsa
*lsa
;
207 struct as_external_lsa
*al
;
208 struct in_addr mask
, id
;
210 /* First search the lsdb with address specific LSID
211 * where all the host bits are set, if there a matched
213 * Ex: For route 10.0.0.0/16, LSID is 10.0.255.255
214 * If no lsa with above LSID, use received address as
215 * LSID and check if any LSA in LSDB.
216 * If LSA found, check if the mask is same b/w the matched
217 * LSA and received prefix, if same then it is the LSA for
219 * Ex: For route 10.0.0.0/16, LSID is 10.0.0.0
222 masklen2ip(p
->prefixlen
, &mask
);
223 id
.s_addr
= p
->prefix
.s_addr
| (~mask
.s_addr
);
224 lsa
= ospf_lsdb_lookup_by_id(ospf
->lsdb
, OSPF_AS_EXTERNAL_LSA
, id
,
227 if (p
->prefixlen
== IPV4_MAX_BITLEN
) {
228 al
= (struct as_external_lsa
*)lsa
->data
;
230 if (mask
.s_addr
!= al
->mask
.s_addr
)
236 lsa
= ospf_lsdb_lookup_by_id(ospf
->lsdb
, OSPF_AS_EXTERNAL_LSA
,
237 p
->prefix
, ospf
->router_id
);
240 al
= (struct as_external_lsa
*)lsa
->data
;
241 if (mask
.s_addr
== al
->mask
.s_addr
)
249 /* Update ASBR status. */
250 void ospf_asbr_status_update(struct ospf
*ospf
, uint8_t status
)
252 zlog_info("ASBR[%s:Status:%d]: Update",
253 ospf_get_name(ospf
), status
);
258 if (IS_OSPF_ASBR(ospf
)) {
259 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
260 ospf_get_name(ospf
), status
);
263 SET_FLAG(ospf
->flags
, OSPF_FLAG_ASBR
);
265 /* Already non ASBR. */
266 if (!IS_OSPF_ASBR(ospf
)) {
267 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
268 ospf_get_name(ospf
), status
);
271 UNSET_FLAG(ospf
->flags
, OSPF_FLAG_ASBR
);
274 /* Transition from/to status ASBR, schedule timer. */
275 ospf_spf_calculate_schedule(ospf
, SPF_FLAG_ASBR_STATUS_CHANGE
);
276 ospf_router_lsa_update(ospf
);
279 /* If there's redistribution configured, we need to refresh external
280 * LSAs in order to install Type-7 and flood to all NSSA Areas
282 static void ospf_asbr_nssa_redist_update_timer(struct thread
*thread
)
284 struct ospf
*ospf
= THREAD_ARG(thread
);
287 ospf
->t_asbr_nssa_redist_update
= NULL
;
289 if (IS_DEBUG_OSPF_EVENT
)
290 zlog_debug("Running ASBR NSSA redistribution update on timer");
292 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
293 struct list
*red_list
;
294 struct listnode
*node
;
295 struct ospf_redist
*red
;
297 red_list
= ospf
->redist
[type
];
301 for (ALL_LIST_ELEMENTS_RO(red_list
, node
, red
))
302 ospf_external_lsa_refresh_type(ospf
, type
,
307 ospf_external_lsa_refresh_default(ospf
);
310 void ospf_schedule_asbr_nssa_redist_update(struct ospf
*ospf
)
312 if (IS_DEBUG_OSPF_EVENT
)
313 zlog_debug("Scheduling ASBR NSSA redistribution update");
315 thread_add_timer(master
, ospf_asbr_nssa_redist_update_timer
, ospf
,
316 OSPF_ASBR_NSSA_REDIST_UPDATE_DELAY
,
317 &ospf
->t_asbr_nssa_redist_update
);
320 void ospf_redistribute_withdraw(struct ospf
*ospf
, uint8_t type
,
321 unsigned short instance
)
323 struct route_node
*rn
;
324 struct external_info
*ei
;
325 struct ospf_external
*ext
;
327 ext
= ospf_external_lookup(ospf
, type
, instance
);
331 /* Delete external info for specified type. */
332 if (!EXTERNAL_INFO(ext
))
335 for (rn
= route_top(EXTERNAL_INFO(ext
)); rn
; rn
= route_next(rn
)) {
341 struct ospf_external_aggr_rt
*aggr
;
343 if (is_default_prefix4(&ei
->p
)
344 && ospf
->default_originate
!= DEFAULT_ORIGINATE_NONE
)
347 aggr
= ei
->aggr_route
;
350 ospf_unlink_ei_from_aggr(ospf
, aggr
, ei
);
351 else if (ospf_external_info_find_lsa(ospf
, &ei
->p
))
352 ospf_external_lsa_flush(ospf
, type
, &ei
->p
,
353 ei
->ifindex
/*, ei->nexthop */);
355 ospf_external_info_free(ei
);
356 route_unlock_node(rn
);
362 /* External Route Aggregator Handlers */
363 bool is_valid_summary_addr(struct prefix_ipv4
*p
)
365 /* Default prefix validation*/
366 if (p
->prefix
.s_addr
== INADDR_ANY
)
369 /*Host route shouldn't be configured as summary addres*/
370 if (p
->prefixlen
== IPV4_MAX_BITLEN
)
375 void ospf_asbr_external_aggregator_init(struct ospf
*instance
)
377 instance
->rt_aggr_tbl
= route_table_init();
379 instance
->t_external_aggr
= NULL
;
381 instance
->aggr_action
= 0;
383 instance
->aggr_delay_interval
= OSPF_EXTL_AGGR_DEFAULT_DELAY
;
386 static unsigned int ospf_external_rt_hash_key(const void *data
)
388 const struct external_info
*ei
= data
;
389 unsigned int key
= 0;
391 key
= prefix_hash_key(&ei
->p
);
395 static bool ospf_external_rt_hash_cmp(const void *d1
, const void *d2
)
397 const struct external_info
*ei1
= d1
;
398 const struct external_info
*ei2
= d2
;
400 return prefix_same((struct prefix
*)&ei1
->p
, (struct prefix
*)&ei2
->p
);
403 static struct ospf_external_aggr_rt
*
404 ospf_external_aggregator_new(struct prefix_ipv4
*p
)
406 struct ospf_external_aggr_rt
*aggr
;
408 aggr
= (struct ospf_external_aggr_rt
*)XCALLOC(
409 MTYPE_OSPF_EXTERNAL_RT_AGGR
,
410 sizeof(struct ospf_external_aggr_rt
));
415 aggr
->p
.family
= p
->family
;
416 aggr
->p
.prefix
= p
->prefix
;
417 aggr
->p
.prefixlen
= p
->prefixlen
;
418 aggr
->match_extnl_hash
= hash_create(ospf_external_rt_hash_key
,
419 ospf_external_rt_hash_cmp
,
420 "Ospf external route hash");
424 static void ospf_aggr_handle_external_info(void *data
)
426 struct external_info
*ei
= (struct external_info
*)data
;
427 struct ospf_external_aggr_rt
*aggr
= NULL
;
428 struct ospf
*ospf
= ei
->ospf
;
429 struct ospf_lsa
*lsa
= NULL
;
431 ei
->aggr_route
= NULL
;
433 ei
->to_be_processed
= true;
435 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
436 zlog_debug("%s: Handle extrenal route(%pI4/%d)", __func__
,
437 &ei
->p
.prefix
, ei
->p
.prefixlen
);
441 if (!ospf_redistribute_check(ospf
, ei
, NULL
))
444 aggr
= ospf_external_aggr_match(ospf
, &ei
->p
);
446 (void)ospf_originate_summary_lsa(ospf
, aggr
, ei
);
450 lsa
= ospf_external_info_find_lsa(ospf
, &ei
->p
);
452 ospf_external_lsa_refresh(ospf
, lsa
, ei
, LSA_REFRESH_FORCE
, 1);
454 (void)ospf_external_lsa_originate(ospf
, ei
);
457 static void ospf_aggr_unlink_external_info(void *data
)
459 struct external_info
*ei
= (struct external_info
*)data
;
461 ei
->aggr_route
= NULL
;
463 ei
->to_be_processed
= true;
466 void ospf_external_aggregator_free(struct ospf_external_aggr_rt
*aggr
)
468 if (OSPF_EXTERNAL_RT_COUNT(aggr
))
469 hash_clean(aggr
->match_extnl_hash
,
470 (void *)ospf_aggr_unlink_external_info
);
472 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
473 zlog_debug("%s: Release the aggregator Address(%pI4/%d)",
474 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
475 hash_free(aggr
->match_extnl_hash
);
476 aggr
->match_extnl_hash
= NULL
;
478 XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR
, aggr
);
481 static void ospf_external_aggr_add(struct ospf
*ospf
,
482 struct ospf_external_aggr_rt
*aggr
)
484 struct route_node
*rn
;
486 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
487 zlog_debug("%s: Adding Aggregate route to Aggr table (%pI4/%d)",
488 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
489 rn
= route_node_get(ospf
->rt_aggr_tbl
, (struct prefix
*)&aggr
->p
);
491 route_unlock_node(rn
);
496 static void ospf_external_aggr_delete(struct ospf
*ospf
, struct route_node
*rn
)
498 struct ospf_external_aggr_rt
*aggr
= rn
->info
;
500 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
501 zlog_debug("%s: Deleting Aggregate route (%pI4/%d)", __func__
,
502 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
504 /* Sent a Max age LSA if it is already originated. */
505 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
506 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
507 zlog_debug("%s: Flushing Aggregate route (%pI4/%d)",
508 __func__
, &aggr
->p
.prefix
,
510 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
514 route_unlock_node(rn
);
517 struct ospf_external_aggr_rt
*
518 ospf_extrenal_aggregator_lookup(struct ospf
*ospf
, struct prefix_ipv4
*p
)
520 struct route_node
*rn
;
521 struct ospf_external_aggr_rt
*summary_rt
= NULL
;
523 rn
= route_node_lookup(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
525 summary_rt
= rn
->info
;
526 route_unlock_node(rn
);
532 struct ospf_external_aggr_rt
*ospf_external_aggr_match(struct ospf
*ospf
,
533 struct prefix_ipv4
*p
)
535 struct route_node
*node
;
536 struct ospf_external_aggr_rt
*summary_rt
= NULL
;
538 node
= route_node_match(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
541 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
543 struct ospf_external_aggr_rt
*ag
= node
->info
;
546 "%s: Matching aggregator found.prefix:%pI4/%d Aggregator %pI4/%d",
547 __func__
, &p
->prefix
, p
->prefixlen
,
548 &ag
->p
.prefix
, ag
->p
.prefixlen
);
551 summary_rt
= node
->info
;
552 route_unlock_node(node
);
558 void ospf_unlink_ei_from_aggr(struct ospf
*ospf
,
559 struct ospf_external_aggr_rt
*aggr
,
560 struct external_info
*ei
)
562 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
564 "%s: Unlinking extrenal route(%pI4/%d) from aggregator(%pI4/%d), external route count:%ld",
565 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
,
566 &aggr
->p
.prefix
, aggr
->p
.prefixlen
,
567 OSPF_EXTERNAL_RT_COUNT(aggr
));
568 hash_release(aggr
->match_extnl_hash
, ei
);
569 ei
->aggr_route
= NULL
;
571 /* Flush the aggreagte route if matching
572 * external route count becomes zero.
574 if (!OSPF_EXTERNAL_RT_COUNT(aggr
)
575 && CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
577 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
578 zlog_debug("%s: Flushing the aggreagte route (%pI4/%d)",
579 __func__
, &aggr
->p
.prefix
,
582 /* Flush the aggregate LSA */
583 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
585 /* Unset the Origination flag */
586 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
590 static void ospf_link_ei_to_aggr(struct ospf_external_aggr_rt
*aggr
,
591 struct external_info
*ei
)
593 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
595 "%s: Linking extrenal route(%pI4/%d) to aggregator(%pI4/%d)",
596 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
,
597 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
598 (void)hash_get(aggr
->match_extnl_hash
, ei
, hash_alloc_intern
);
599 ei
->aggr_route
= aggr
;
602 struct ospf_lsa
*ospf_originate_summary_lsa(struct ospf
*ospf
,
603 struct ospf_external_aggr_rt
*aggr
,
604 struct external_info
*ei
)
606 struct ospf_lsa
*lsa
;
607 struct external_info ei_aggr
;
608 struct as_external_lsa
*asel
;
609 struct ospf_external_aggr_rt
*old_aggr
;
612 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
613 zlog_debug("%s: Prepare to originate Summary route(%pI4/%d)",
614 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
616 /* This case to handle when the overlapping aggregator address
617 * is availbe.Best match will be considered.So need to delink
618 * from old aggregator and link to the new aggr.
620 if (ei
->aggr_route
) {
621 if (ei
->aggr_route
!= aggr
) {
622 old_aggr
= ei
->aggr_route
;
623 ospf_unlink_ei_from_aggr(ospf
, old_aggr
, ei
);
627 /* Add the external route to hash table */
628 ospf_link_ei_to_aggr(aggr
, ei
);
630 lsa
= ospf_external_info_find_lsa(ospf
, &aggr
->p
);
631 /* Don't originate external LSA,
632 * If it is configured not to advertise.
634 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
635 /* If it is already originated as external LSA,
636 * But, it is configured not to advertise then
637 * flush the originated external lsa.
640 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
641 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
643 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
645 "%s: Don't originate the summary address,It is configured to not-advertise.",
650 /* Prepare the extrenal_info for aggregator */
651 memset(&ei_aggr
, 0, sizeof(ei_aggr
));
653 ei_aggr
.tag
= aggr
->tag
;
655 ei_aggr
.instance
= ospf
->instance
;
656 ei_aggr
.route_map_set
.metric
= -1;
657 ei_aggr
.route_map_set
.metric_type
= -1;
659 /* Summary route already originated,
662 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
664 flog_warn(EC_OSPF_LSA_MISSING
,
665 "%s: Could not refresh/originate %pI4/%d",
666 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
670 asel
= (struct as_external_lsa
*)lsa
->data
;
671 tag
= (unsigned long)ntohl(asel
->e
[0].route_tag
);
673 /* If tag modified , then re-originate the route
674 * with modified tag details.
676 if (tag
!= ei_aggr
.tag
) {
677 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
679 "%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
680 __func__
, tag
, ei_aggr
.tag
,
681 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
683 ospf_external_lsa_refresh(ospf
, lsa
, &ei_aggr
,
684 LSA_REFRESH_FORCE
, 1);
689 if (lsa
&& IS_LSA_MAXAGE(lsa
)) {
690 /* This is special case.
691 * If a summary route need to be originated but where
692 * summary route already exist in lsdb with maxage, then
693 * it need to be refreshed.
695 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
697 "%s: LSA is in MAX-AGE so refreshing LSA(%pI4/%d)",
698 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
700 ospf_external_lsa_refresh(ospf
, lsa
, &ei_aggr
,
701 LSA_REFRESH_FORCE
, 1);
702 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
706 /* If the external route prefix same as aggregate route
707 * and if external route is already originated as TYPE-5
708 * then it need to be refreshed and originate bit should
711 if (lsa
&& prefix_same((struct prefix
*)&ei_aggr
.p
,
712 (struct prefix
*)&ei
->p
)) {
713 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
715 "%s: External route prefix is same as aggr so refreshing LSA(%pI4/%d)",
716 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
717 ospf_external_lsa_refresh(ospf
, lsa
, &ei_aggr
,
718 LSA_REFRESH_FORCE
, 1);
719 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
723 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
724 zlog_debug("%s: Originate Summary route(%pI4/%d)", __func__
,
725 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
727 /* Originate summary LSA */
728 lsa
= ospf_external_lsa_originate(ospf
, &ei_aggr
);
730 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
731 zlog_debug("%s: Set the origination bit for aggregator",
733 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
738 void ospf_unset_all_aggr_flag(struct ospf
*ospf
)
740 struct route_node
*rn
= NULL
;
742 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
743 zlog_debug("Unset the origination bit for all aggregator");
745 for (rn
= route_top(ospf
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
749 struct ospf_external_aggr_rt
*aggr
= rn
->info
;
751 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
755 static void ospf_delete_all_marked_aggregators(struct ospf
*ospf
)
757 struct route_node
*rn
= NULL
;
759 /* Loop through all the aggregators, Delete all aggregators
760 * which are marked as DELETE. Set action to NONE for remaining
763 for (rn
= route_top(ospf
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
767 struct ospf_external_aggr_rt
*aggr
= rn
->info
;
769 if (aggr
->action
!= OSPF_ROUTE_AGGR_DEL
) {
770 aggr
->action
= OSPF_ROUTE_AGGR_NONE
;
773 ospf_external_aggr_delete(ospf
, rn
);
774 ospf_external_aggregator_free(aggr
);
778 static void ospf_handle_aggregated_exnl_rt(struct ospf
*ospf
,
779 struct ospf_external_aggr_rt
*aggr
,
780 struct external_info
*ei
)
782 struct ospf_lsa
*lsa
;
783 struct as_external_lsa
*al
;
786 /* Handling the case where the external route prefix
787 * and aggregate prefix is same
788 * If same don't flush the originated external LSA.
790 if (prefix_same((struct prefix
*)&aggr
->p
, (struct prefix
*)&ei
->p
)) {
791 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
793 "%s: External Route prefix same as Aggregator(%pI4/%d), so don't flush.",
794 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
);
798 lsa
= ospf_external_info_find_lsa(ospf
, &ei
->p
);
800 al
= (struct as_external_lsa
*)lsa
->data
;
801 masklen2ip(ei
->p
.prefixlen
, &mask
);
803 if (mask
.s_addr
!= al
->mask
.s_addr
)
806 ospf_external_lsa_flush(ospf
, ei
->type
, &ei
->p
, 0);
810 static void ospf_handle_exnl_rt_after_aggr_del(struct ospf
*ospf
,
811 struct external_info
*ei
)
813 struct ospf_lsa
*lsa
;
815 /* Process only marked external routes.
816 * These routes were part of a deleted
817 * aggregator.So, originate now.
819 if (!ei
->to_be_processed
)
822 ei
->to_be_processed
= false;
824 lsa
= ospf_external_info_find_lsa(ospf
, &ei
->p
);
827 ospf_external_lsa_refresh(ospf
, lsa
, ei
, LSA_REFRESH_FORCE
, 0);
829 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
830 zlog_debug("%s: Originate external route(%pI4/%d)",
831 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
);
833 ospf_external_lsa_originate(ospf
, ei
);
837 static void ospf_handle_external_aggr_add(struct ospf
*ospf
)
839 struct external_info
*ei
;
840 struct route_node
*rn
= NULL
;
841 struct route_table
*rt
= NULL
;
844 /* Delete all the aggregators which are marked as
845 * OSPF_ROUTE_AGGR_DEL.
847 ospf_delete_all_marked_aggregators(ospf
);
849 for (type
= 0; type
<= ZEBRA_ROUTE_MAX
; type
++) {
850 struct list
*ext_list
;
851 struct listnode
*node
;
852 struct ospf_external
*ext
;
853 struct ospf_external_aggr_rt
*aggr
;
855 ext_list
= ospf
->external
[type
];
859 for (ALL_LIST_ELEMENTS_RO(ext_list
, node
, ext
)) {
860 rt
= ext
->external_info
;
864 for (rn
= route_top(rt
); rn
; rn
= route_next(rn
)) {
869 if (is_default_prefix4(&ei
->p
))
872 /* Check the AS-external-LSA
873 * should be originated.
875 if (!ospf_redistribute_check(ospf
, ei
, NULL
))
878 aggr
= ospf_external_aggr_match(ospf
, &ei
->p
);
880 /* If matching aggregator found, Add
881 * the external route reference to the
882 * aggregator and originate the aggr
883 * route if it is advertisable.
884 * flush the external LSA if it is
885 * already originated for this external
889 ospf_originate_summary_lsa(ospf
, aggr
,
892 /* All aggregated external rts
895 ospf_handle_aggregated_exnl_rt(
900 /* External routes which are only out
901 * of aggregation will be handled here.
903 ospf_handle_exnl_rt_after_aggr_del(ospf
, ei
);
910 ospf_aggr_handle_advertise_change(struct ospf
*ospf
,
911 struct ospf_external_aggr_rt
*aggr
,
912 struct external_info
*ei_aggr
)
914 struct ospf_lsa
*lsa
;
916 /* Check if advertise option modified. */
917 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
919 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
921 "%s: Don't originate the summary address,It is configured to not-advertise.",
924 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
926 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
928 "%s: No-advertise,So Flush the Aggregate route(%pI4/%d)",
929 __func__
, &aggr
->p
.prefix
,
932 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
934 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
939 if (!CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
940 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
941 zlog_debug("%s: Now it is advatisable", __func__
);
943 lsa
= ospf_external_info_find_lsa(ospf
, &ei_aggr
->p
);
944 if (lsa
&& IS_LSA_MAXAGE(lsa
)) {
945 /* This is special case.
946 * If a summary route need to be originated but where
947 * summary route already exist in lsdb with maxage, then
948 * it need to be refreshed.
950 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
952 "%s: It is already with Maxage, So refresh it (%pI4/%d)",
953 __func__
, &aggr
->p
.prefix
,
956 ospf_external_lsa_refresh(ospf
, lsa
, ei_aggr
,
957 LSA_REFRESH_FORCE
, 1);
959 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
963 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
965 "%s: Originate Aggregate LSA (%pI4/%d)",
966 __func__
, &aggr
->p
.prefix
,
969 /* Originate summary LSA */
970 lsa
= ospf_external_lsa_originate(ospf
, ei_aggr
);
972 SET_FLAG(aggr
->flags
,
973 OSPF_EXTERNAL_AGGRT_ORIGINATED
);
978 static void ospf_handle_external_aggr_update(struct ospf
*ospf
)
980 struct route_node
*rn
= NULL
;
982 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
983 zlog_debug("%s: Process modified aggregators.", __func__
);
985 for (rn
= route_top(ospf
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
986 struct ospf_external_aggr_rt
*aggr
;
987 struct ospf_lsa
*lsa
= NULL
;
988 struct as_external_lsa
*asel
= NULL
;
989 struct external_info ei_aggr
;
997 if (aggr
->action
== OSPF_ROUTE_AGGR_DEL
) {
998 aggr
->action
= OSPF_ROUTE_AGGR_NONE
;
999 ospf_external_aggr_delete(ospf
, rn
);
1001 if (OSPF_EXTERNAL_RT_COUNT(aggr
))
1003 aggr
->match_extnl_hash
,
1004 (void *)ospf_aggr_handle_external_info
);
1006 hash_free(aggr
->match_extnl_hash
);
1007 XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR
, aggr
);
1009 } else if (aggr
->action
== OSPF_ROUTE_AGGR_MODIFY
) {
1011 aggr
->action
= OSPF_ROUTE_AGGR_NONE
;
1013 /* Prepare the extrenal_info for aggregator */
1014 memset(&ei_aggr
, 0, sizeof(ei_aggr
));
1015 ei_aggr
.p
= aggr
->p
;
1016 ei_aggr
.tag
= aggr
->tag
;
1018 ei_aggr
.instance
= ospf
->instance
;
1019 ei_aggr
.route_map_set
.metric
= -1;
1020 ei_aggr
.route_map_set
.metric_type
= -1;
1022 /* Check if tag modified */
1023 if (CHECK_FLAG(aggr
->flags
,
1024 OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
1025 lsa
= ospf_external_info_find_lsa(ospf
,
1028 flog_warn(EC_OSPF_LSA_MISSING
,
1029 "%s: Could not refresh/originate %pI4/%d",
1030 __func__
, &aggr
->p
.prefix
,
1035 asel
= (struct as_external_lsa
*)lsa
->data
;
1036 tag
= (unsigned long)ntohl(
1037 asel
->e
[0].route_tag
);
1039 /* If tag modified , then re-originate the
1040 * route with modified tag details.
1042 if (tag
!= ei_aggr
.tag
) {
1043 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1045 "%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
1051 ospf_external_lsa_refresh(
1052 ospf
, lsa
, &ei_aggr
,
1053 LSA_REFRESH_FORCE
, 1);
1057 /* Advertise option modified ?
1058 * If so, handled it here.
1060 ospf_aggr_handle_advertise_change(ospf
, aggr
, &ei_aggr
);
1065 static void ospf_asbr_external_aggr_process(struct thread
*thread
)
1067 struct ospf
*ospf
= THREAD_ARG(thread
);
1070 ospf
->t_external_aggr
= NULL
;
1071 operation
= ospf
->aggr_action
;
1073 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1074 zlog_debug("%s: operation:%d", __func__
, operation
);
1076 switch (operation
) {
1077 case OSPF_ROUTE_AGGR_ADD
:
1078 ospf_handle_external_aggr_add(ospf
);
1080 case OSPF_ROUTE_AGGR_DEL
:
1081 case OSPF_ROUTE_AGGR_MODIFY
:
1082 ospf_handle_external_aggr_update(ospf
);
1088 static void ospf_external_aggr_timer(struct ospf
*ospf
,
1089 struct ospf_external_aggr_rt
*aggr
,
1090 enum ospf_aggr_action_t operation
)
1092 aggr
->action
= operation
;
1094 if (ospf
->t_external_aggr
) {
1095 if (ospf
->aggr_action
== OSPF_ROUTE_AGGR_ADD
) {
1097 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1099 "%s: Not required to retsart timer,set is already added.",
1104 if (operation
== OSPF_ROUTE_AGGR_ADD
) {
1105 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1107 "%s, Restarting Aggregator delay timer.",
1109 THREAD_OFF(ospf
->t_external_aggr
);
1113 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1114 zlog_debug("%s: Start Aggregator delay timer %u(in seconds).",
1115 __func__
, ospf
->aggr_delay_interval
);
1117 ospf
->aggr_action
= operation
;
1118 thread_add_timer(master
, ospf_asbr_external_aggr_process
, ospf
,
1119 ospf
->aggr_delay_interval
, &ospf
->t_external_aggr
);
1122 int ospf_asbr_external_aggregator_set(struct ospf
*ospf
, struct prefix_ipv4
*p
,
1125 struct ospf_external_aggr_rt
*aggregator
;
1127 aggregator
= ospf_extrenal_aggregator_lookup(ospf
, p
);
1130 if (CHECK_FLAG(aggregator
->flags
,
1131 OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
))
1132 UNSET_FLAG(aggregator
->flags
,
1133 OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1134 else if (aggregator
->tag
== tag
)
1135 return OSPF_SUCCESS
;
1137 aggregator
->tag
= tag
;
1139 ospf_external_aggr_timer(ospf
, aggregator
,
1140 OSPF_ROUTE_AGGR_MODIFY
);
1142 aggregator
= ospf_external_aggregator_new(p
);
1144 return OSPF_FAILURE
;
1146 aggregator
->tag
= tag
;
1148 ospf_external_aggr_add(ospf
, aggregator
);
1149 ospf_external_aggr_timer(ospf
, aggregator
, OSPF_ROUTE_AGGR_ADD
);
1152 return OSPF_SUCCESS
;
1155 int ospf_asbr_external_aggregator_unset(struct ospf
*ospf
,
1156 struct prefix_ipv4
*p
, route_tag_t tag
)
1158 struct route_node
*rn
;
1159 struct ospf_external_aggr_rt
*aggr
;
1161 rn
= route_node_lookup(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
1163 return OSPF_INVALID
;
1164 route_unlock_node(rn
);
1168 if (tag
&& (tag
!= aggr
->tag
))
1169 return OSPF_INVALID
;
1171 if (!OSPF_EXTERNAL_RT_COUNT(aggr
)) {
1172 ospf_external_aggr_delete(ospf
, rn
);
1173 ospf_external_aggregator_free(aggr
);
1174 return OSPF_SUCCESS
;
1177 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_DEL
);
1179 return OSPF_SUCCESS
;
1182 int ospf_asbr_external_rt_no_advertise(struct ospf
*ospf
, struct prefix_ipv4
*p
)
1184 struct ospf_external_aggr_rt
*aggr
;
1185 route_tag_t tag
= 0;
1187 aggr
= ospf_extrenal_aggregator_lookup(ospf
, p
);
1189 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
))
1190 return OSPF_SUCCESS
;
1192 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1196 if (!OSPF_EXTERNAL_RT_COUNT(aggr
))
1197 return OSPF_SUCCESS
;
1199 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_MODIFY
);
1201 aggr
= ospf_external_aggregator_new(p
);
1204 return OSPF_FAILURE
;
1206 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1207 ospf_external_aggr_add(ospf
, aggr
);
1208 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_ADD
);
1211 return OSPF_SUCCESS
;
1214 int ospf_asbr_external_rt_advertise(struct ospf
*ospf
, struct prefix_ipv4
*p
)
1216 struct route_node
*rn
;
1217 struct ospf_external_aggr_rt
*aggr
;
1219 rn
= route_node_lookup(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
1221 return OSPF_INVALID
;
1222 route_unlock_node(rn
);
1226 if (!CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
))
1227 return OSPF_INVALID
;
1229 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1231 if (!OSPF_EXTERNAL_RT_COUNT(aggr
))
1232 return OSPF_SUCCESS
;
1234 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_MODIFY
);
1235 return OSPF_SUCCESS
;
1238 int ospf_external_aggregator_timer_set(struct ospf
*ospf
, uint16_t interval
)
1240 ospf
->aggr_delay_interval
= interval
;
1241 return OSPF_SUCCESS
;