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(uint8_t type
,
76 unsigned short instance
)
78 struct external_info
*new;
80 new = XCALLOC(MTYPE_OSPF_EXTERNAL_INFO
, sizeof(struct external_info
));
82 new->instance
= instance
;
83 new->to_be_processed
= 0;
85 ospf_reset_route_map_set_values(&new->route_map_set
);
89 static void ospf_external_info_free(struct external_info
*ei
)
91 XFREE(MTYPE_OSPF_EXTERNAL_INFO
, ei
);
94 void ospf_reset_route_map_set_values(struct route_map_set_values
*values
)
97 values
->metric_type
= -1;
100 int ospf_route_map_set_compare(struct route_map_set_values
*values1
,
101 struct route_map_set_values
*values2
)
103 return values1
->metric
== values2
->metric
104 && values1
->metric_type
== values2
->metric_type
;
107 /* Add an External info for AS-external-LSA. */
108 struct external_info
*
109 ospf_external_info_add(struct ospf
*ospf
, uint8_t type
, unsigned short instance
,
110 struct prefix_ipv4 p
, ifindex_t ifindex
,
111 struct in_addr nexthop
, route_tag_t tag
)
113 struct external_info
*new;
114 struct route_node
*rn
;
115 struct ospf_external
*ext
;
117 ext
= ospf_external_lookup(ospf
, type
, instance
);
119 ext
= ospf_external_add(ospf
, type
, instance
);
121 rn
= route_node_get(EXTERNAL_INFO(ext
), (struct prefix
*)&p
);
122 /* If old info exists, -- discard new one or overwrite with new one? */
123 if (rn
&& rn
->info
) {
125 if ((new->ifindex
== ifindex
)
126 && (new->nexthop
.s_addr
== nexthop
.s_addr
)
127 && (new->tag
== tag
)) {
128 route_unlock_node(rn
);
129 return NULL
; /* NULL => no LSA to refresh */
132 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
))
134 "Redistribute[%s][%d][%u]: %pFX discarding old info with NH %pI4.",
135 ospf_redist_string(type
), instance
,
136 ospf
->vrf_id
, &p
, &nexthop
.s_addr
);
137 XFREE(MTYPE_OSPF_EXTERNAL_INFO
, rn
->info
);
140 /* Create new External info instance. */
141 new = ospf_external_info_new(type
, instance
);
143 new->ifindex
= ifindex
;
144 new->nexthop
= nexthop
;
147 new->aggr_route
= NULL
;
149 /* we don't unlock rn from the get() because we're attaching the info */
153 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
)) {
155 "Redistribute[%s][%u]: %pFX external info created, with NH %pI4",
156 ospf_redist_string(type
), ospf
->vrf_id
, &p
,
162 void ospf_external_info_delete(struct ospf
*ospf
, uint8_t type
,
163 unsigned short instance
, struct prefix_ipv4 p
)
165 struct route_node
*rn
;
166 struct ospf_external
*ext
;
168 ext
= ospf_external_lookup(ospf
, type
, instance
);
172 rn
= route_node_lookup(EXTERNAL_INFO(ext
), (struct prefix
*)&p
);
174 ospf_external_info_free(rn
->info
);
176 route_unlock_node(rn
);
177 route_unlock_node(rn
);
181 struct external_info
*ospf_external_info_lookup(struct ospf
*ospf
, uint8_t type
,
182 unsigned short instance
,
183 struct prefix_ipv4
*p
)
185 struct route_node
*rn
;
186 struct ospf_external
*ext
;
188 ext
= ospf_external_lookup(ospf
, type
, instance
);
192 rn
= route_node_lookup(EXTERNAL_INFO(ext
), (struct prefix
*)p
);
194 route_unlock_node(rn
);
202 struct ospf_lsa
*ospf_external_info_find_lsa(struct ospf
*ospf
,
203 struct prefix_ipv4
*p
)
205 struct ospf_lsa
*lsa
;
206 struct as_external_lsa
*al
;
207 struct in_addr mask
, id
;
209 /* Fisrt search the lsdb with address specifc LSID
210 * where all the host bits are set, if there a matched
212 * Ex: For route 10.0.0.0/16, LSID is 10.0.255.255
213 * If no lsa with above LSID, use received address as
214 * LSID and check if any LSA in LSDB.
215 * If LSA found, check if the mask is same b/w the matched
216 * LSA and received prefix, if same then it is the LSA for
218 * Ex: For route 10.0.0.0/16, LSID is 10.0.0.0
221 masklen2ip(p
->prefixlen
, &mask
);
222 id
.s_addr
= p
->prefix
.s_addr
| (~mask
.s_addr
);
223 lsa
= ospf_lsdb_lookup_by_id(ospf
->lsdb
, OSPF_AS_EXTERNAL_LSA
, id
,
228 lsa
= ospf_lsdb_lookup_by_id(ospf
->lsdb
, OSPF_AS_EXTERNAL_LSA
,
229 p
->prefix
, ospf
->router_id
);
232 al
= (struct as_external_lsa
*)lsa
->data
;
233 if (mask
.s_addr
== al
->mask
.s_addr
)
241 /* Update ASBR status. */
242 void ospf_asbr_status_update(struct ospf
*ospf
, uint8_t status
)
244 zlog_info("ASBR[%s:Status:%d]: Update",
245 ospf_get_name(ospf
), status
);
250 if (IS_OSPF_ASBR(ospf
)) {
251 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
252 ospf_get_name(ospf
), status
);
255 SET_FLAG(ospf
->flags
, OSPF_FLAG_ASBR
);
257 /* Already non ASBR. */
258 if (!IS_OSPF_ASBR(ospf
)) {
259 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
260 ospf_get_name(ospf
), status
);
263 UNSET_FLAG(ospf
->flags
, OSPF_FLAG_ASBR
);
266 /* Transition from/to status ASBR, schedule timer. */
267 ospf_spf_calculate_schedule(ospf
, SPF_FLAG_ASBR_STATUS_CHANGE
);
268 ospf_router_lsa_update(ospf
);
271 /* If there's redistribution configured, we need to refresh external
272 * LSAs in order to install Type-7 and flood to all NSSA Areas
274 static int ospf_asbr_nssa_redist_update_timer(struct thread
*thread
)
276 struct ospf
*ospf
= THREAD_ARG(thread
);
279 ospf
->t_asbr_nssa_redist_update
= NULL
;
281 if (IS_DEBUG_OSPF_EVENT
)
282 zlog_debug("Running ASBR NSSA redistribution update on timer");
284 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++) {
285 struct list
*red_list
;
286 struct listnode
*node
;
287 struct ospf_redist
*red
;
289 red_list
= ospf
->redist
[type
];
293 for (ALL_LIST_ELEMENTS_RO(red_list
, node
, red
))
294 ospf_external_lsa_refresh_type(ospf
, type
,
299 ospf_external_lsa_refresh_default(ospf
);
304 void ospf_schedule_asbr_nssa_redist_update(struct ospf
*ospf
)
306 if (IS_DEBUG_OSPF_EVENT
)
307 zlog_debug("Scheduling ASBR NSSA redistribution update");
309 thread_add_timer(master
, ospf_asbr_nssa_redist_update_timer
, ospf
,
310 OSPF_ASBR_NSSA_REDIST_UPDATE_DELAY
,
311 &ospf
->t_asbr_nssa_redist_update
);
314 void ospf_redistribute_withdraw(struct ospf
*ospf
, uint8_t type
,
315 unsigned short instance
)
317 struct route_node
*rn
;
318 struct external_info
*ei
;
319 struct ospf_external
*ext
;
321 ext
= ospf_external_lookup(ospf
, type
, instance
);
325 /* Delete external info for specified type. */
326 if (!EXTERNAL_INFO(ext
))
329 for (rn
= route_top(EXTERNAL_INFO(ext
)); rn
; rn
= route_next(rn
)) {
335 struct ospf_external_aggr_rt
*aggr
;
337 if (is_default_prefix4(&ei
->p
)
338 && ospf
->default_originate
!= DEFAULT_ORIGINATE_NONE
)
341 aggr
= ei
->aggr_route
;
344 ospf_unlink_ei_from_aggr(ospf
, aggr
, ei
);
345 else if (ospf_external_info_find_lsa(ospf
, &ei
->p
))
346 ospf_external_lsa_flush(ospf
, type
, &ei
->p
,
347 ei
->ifindex
/*, ei->nexthop */);
349 ospf_external_info_free(ei
);
350 route_unlock_node(rn
);
356 /* External Route Aggregator Handlers */
357 bool is_valid_summary_addr(struct prefix_ipv4
*p
)
359 /* Default prefix validation*/
360 if (p
->prefix
.s_addr
== INADDR_ANY
)
363 /*Host route shouldn't be configured as summary addres*/
364 if (p
->prefixlen
== IPV4_MAX_BITLEN
)
369 void ospf_asbr_external_aggregator_init(struct ospf
*instance
)
371 instance
->rt_aggr_tbl
= route_table_init();
373 instance
->t_external_aggr
= NULL
;
375 instance
->aggr_action
= 0;
377 instance
->aggr_delay_interval
= OSPF_EXTL_AGGR_DEFAULT_DELAY
;
380 static unsigned int ospf_external_rt_hash_key(const void *data
)
382 const struct external_info
*ei
= data
;
383 unsigned int key
= 0;
385 key
= prefix_hash_key(&ei
->p
);
389 static bool ospf_external_rt_hash_cmp(const void *d1
, const void *d2
)
391 const struct external_info
*ei1
= d1
;
392 const struct external_info
*ei2
= d2
;
394 return prefix_same((struct prefix
*)&ei1
->p
, (struct prefix
*)&ei2
->p
);
397 static struct ospf_external_aggr_rt
*
398 ospf_external_aggregator_new(struct prefix_ipv4
*p
)
400 struct ospf_external_aggr_rt
*aggr
;
402 aggr
= (struct ospf_external_aggr_rt
*)XCALLOC(
403 MTYPE_OSPF_EXTERNAL_RT_AGGR
,
404 sizeof(struct ospf_external_aggr_rt
));
409 aggr
->p
.family
= p
->family
;
410 aggr
->p
.prefix
= p
->prefix
;
411 aggr
->p
.prefixlen
= p
->prefixlen
;
412 aggr
->match_extnl_hash
= hash_create(ospf_external_rt_hash_key
,
413 ospf_external_rt_hash_cmp
,
414 "Ospf external route hash");
418 static void ospf_aggr_handle_external_info(void *data
)
420 struct external_info
*ei
= (struct external_info
*)data
;
421 struct ospf_external_aggr_rt
*aggr
= NULL
;
422 struct ospf
*ospf
= NULL
;
423 struct ospf_lsa
*lsa
= NULL
;
425 ei
->aggr_route
= NULL
;
427 ei
->to_be_processed
= true;
429 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
430 zlog_debug("%s: Handle extrenal route(%pI4/%d)", __func__
,
431 &ei
->p
.prefix
, ei
->p
.prefixlen
);
433 ospf
= ospf_lookup_instance(ei
->instance
);
437 if (!ospf_redistribute_check(ospf
, ei
, NULL
))
440 aggr
= ospf_external_aggr_match(ospf
, &ei
->p
);
442 (void)ospf_originate_summary_lsa(ospf
, aggr
, ei
);
446 lsa
= ospf_external_info_find_lsa(ospf
, &ei
->p
);
448 ospf_external_lsa_refresh(ospf
, lsa
, ei
, LSA_REFRESH_FORCE
, 1);
450 (void)ospf_external_lsa_originate(ospf
, ei
);
453 static void ospf_aggr_unlink_external_info(void *data
)
455 struct external_info
*ei
= (struct external_info
*)data
;
457 ei
->aggr_route
= NULL
;
459 ei
->to_be_processed
= true;
462 void ospf_external_aggregator_free(struct ospf_external_aggr_rt
*aggr
)
464 if (OSPF_EXTERNAL_RT_COUNT(aggr
))
465 hash_clean(aggr
->match_extnl_hash
,
466 (void *)ospf_aggr_unlink_external_info
);
468 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
469 zlog_debug("%s: Release the aggregator Address(%pI4/%d)",
470 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
471 hash_free(aggr
->match_extnl_hash
);
472 aggr
->match_extnl_hash
= NULL
;
474 XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR
, aggr
);
477 static void ospf_external_aggr_add(struct ospf
*ospf
,
478 struct ospf_external_aggr_rt
*aggr
)
480 struct route_node
*rn
;
482 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
483 zlog_debug("%s: Adding Aggregate route to Aggr table (%pI4/%d)",
484 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
485 rn
= route_node_get(ospf
->rt_aggr_tbl
, (struct prefix
*)&aggr
->p
);
487 route_unlock_node(rn
);
492 static void ospf_external_aggr_delete(struct ospf
*ospf
, struct route_node
*rn
)
494 struct ospf_external_aggr_rt
*aggr
= rn
->info
;
496 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
497 zlog_debug("%s: Deleting Aggregate route (%pI4/%d)", __func__
,
498 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
500 /* Sent a Max age LSA if it is already originated. */
501 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
502 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
503 zlog_debug("%s: Flushing Aggregate route (%pI4/%d)",
504 __func__
, &aggr
->p
.prefix
,
506 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
510 route_unlock_node(rn
);
513 struct ospf_external_aggr_rt
*
514 ospf_extrenal_aggregator_lookup(struct ospf
*ospf
, struct prefix_ipv4
*p
)
516 struct route_node
*rn
;
517 struct ospf_external_aggr_rt
*summary_rt
= NULL
;
519 rn
= route_node_lookup(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
521 summary_rt
= rn
->info
;
522 route_unlock_node(rn
);
528 struct ospf_external_aggr_rt
*ospf_external_aggr_match(struct ospf
*ospf
,
529 struct prefix_ipv4
*p
)
531 struct route_node
*node
;
532 struct ospf_external_aggr_rt
*summary_rt
= NULL
;
534 node
= route_node_match(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
537 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
539 struct ospf_external_aggr_rt
*ag
= node
->info
;
542 "%s: Matching aggregator found.prefix:%pI4/%d Aggregator %pI4/%d",
543 __func__
, &p
->prefix
, p
->prefixlen
,
544 &ag
->p
.prefix
, ag
->p
.prefixlen
);
547 summary_rt
= node
->info
;
548 route_unlock_node(node
);
554 void ospf_unlink_ei_from_aggr(struct ospf
*ospf
,
555 struct ospf_external_aggr_rt
*aggr
,
556 struct external_info
*ei
)
558 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
560 "%s: Unlinking extrenal route(%pI4/%d) from aggregator(%pI4/%d), external route count:%ld",
561 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
,
562 &aggr
->p
.prefix
, aggr
->p
.prefixlen
,
563 OSPF_EXTERNAL_RT_COUNT(aggr
));
564 hash_release(aggr
->match_extnl_hash
, ei
);
565 ei
->aggr_route
= NULL
;
567 /* Flush the aggreagte route if matching
568 * external route count becomes zero.
570 if (!OSPF_EXTERNAL_RT_COUNT(aggr
)
571 && CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
573 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
574 zlog_debug("%s: Flushing the aggreagte route (%pI4/%d)",
575 __func__
, &aggr
->p
.prefix
,
578 /* Flush the aggregate LSA */
579 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
581 /* Unset the Origination flag */
582 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
586 static void ospf_link_ei_to_aggr(struct ospf_external_aggr_rt
*aggr
,
587 struct external_info
*ei
)
589 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
591 "%s: Linking extrenal route(%pI4/%d) to aggregator(%pI4/%d)",
592 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
,
593 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
594 hash_get(aggr
->match_extnl_hash
, ei
, hash_alloc_intern
);
595 ei
->aggr_route
= aggr
;
598 struct ospf_lsa
*ospf_originate_summary_lsa(struct ospf
*ospf
,
599 struct ospf_external_aggr_rt
*aggr
,
600 struct external_info
*ei
)
602 struct ospf_lsa
*lsa
;
603 struct external_info ei_aggr
;
604 struct as_external_lsa
*asel
;
605 struct ospf_external_aggr_rt
*old_aggr
;
608 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
609 zlog_debug("%s: Prepare to originate Summary route(%pI4/%d)",
610 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
612 /* This case to handle when the overlapping aggregator address
613 * is availbe.Best match will be considered.So need to delink
614 * from old aggregator and link to the new aggr.
616 if (ei
->aggr_route
) {
617 if (ei
->aggr_route
!= aggr
) {
618 old_aggr
= ei
->aggr_route
;
619 ospf_unlink_ei_from_aggr(ospf
, old_aggr
, ei
);
623 /* Add the external route to hash table */
624 ospf_link_ei_to_aggr(aggr
, ei
);
626 lsa
= ospf_external_info_find_lsa(ospf
, &aggr
->p
);
627 /* Dont originate external LSA,
628 * If it is configured not to advertise.
630 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
631 /* If it is already originated as external LSA,
632 * But, it is configured not to advertise then
633 * flush the originated external lsa.
636 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
637 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
639 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
641 "%s: Don't originate the summary address,It is configured to not-advertise.",
646 /* Prepare the extrenal_info for aggregator */
647 memset(&ei_aggr
, 0, sizeof(struct external_info
));
649 ei_aggr
.tag
= aggr
->tag
;
651 ei_aggr
.instance
= ospf
->instance
;
652 ei_aggr
.route_map_set
.metric
= -1;
653 ei_aggr
.route_map_set
.metric_type
= -1;
655 /* Summary route already originated,
658 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
660 flog_warn(EC_OSPF_LSA_MISSING
,
661 "%s: Could not refresh/originate %pI4/%d",
662 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
666 asel
= (struct as_external_lsa
*)lsa
->data
;
667 tag
= (unsigned long)ntohl(asel
->e
[0].route_tag
);
669 /* If tag modified , then re-originate the route
670 * with modified tag details.
672 if (tag
!= ei_aggr
.tag
) {
673 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
675 "%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
676 __func__
, tag
, ei_aggr
.tag
,
677 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
679 ospf_external_lsa_refresh(ospf
, lsa
, &ei_aggr
,
680 LSA_REFRESH_FORCE
, 1);
685 if (lsa
&& IS_LSA_MAXAGE(lsa
)) {
686 /* This is special case.
687 * If a summary route need to be originated but where
688 * summary route already exist in lsdb with maxage, then
689 * it need to be refreshed.
691 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
693 "%s: LSA is in MAX-AGE so refreshing LSA(%pI4/%d)",
694 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
696 ospf_external_lsa_refresh(ospf
, lsa
, &ei_aggr
,
697 LSA_REFRESH_FORCE
, 1);
698 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
702 /* If the external route prefix same as aggregate route
703 * and if external route is already originated as TYPE-5
704 * then it need to be refreshed and originate bit should
707 if (lsa
&& prefix_same((struct prefix
*)&ei_aggr
.p
,
708 (struct prefix
*)&ei
->p
)) {
709 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
711 "%s: External route prefix is same as aggr so refreshing LSA(%pI4/%d)",
712 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
713 ospf_external_lsa_refresh(ospf
, lsa
, &ei_aggr
,
714 LSA_REFRESH_FORCE
, 1);
715 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
719 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
720 zlog_debug("%s: Originate Summary route(%pI4/%d)", __func__
,
721 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
723 /* Originate summary LSA */
724 lsa
= ospf_external_lsa_originate(ospf
, &ei_aggr
);
726 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
727 zlog_debug("%s: Set the origination bit for aggregator",
729 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
734 void ospf_unset_all_aggr_flag(struct ospf
*ospf
)
736 struct route_node
*rn
= NULL
;
738 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
739 zlog_debug("Unset the origination bit for all aggregator");
741 for (rn
= route_top(ospf
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
745 struct ospf_external_aggr_rt
*aggr
= rn
->info
;
747 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
751 static void ospf_delete_all_marked_aggregators(struct ospf
*ospf
)
753 struct route_node
*rn
= NULL
;
755 /* Loop through all the aggregators, Delete all aggregators
756 * which are marked as DELETE. Set action to NONE for remaining
759 for (rn
= route_top(ospf
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
763 struct ospf_external_aggr_rt
*aggr
= rn
->info
;
765 if (aggr
->action
!= OSPF_ROUTE_AGGR_DEL
) {
766 aggr
->action
= OSPF_ROUTE_AGGR_NONE
;
769 ospf_external_aggr_delete(ospf
, rn
);
770 ospf_external_aggregator_free(aggr
);
774 static void ospf_handle_aggregated_exnl_rt(struct ospf
*ospf
,
775 struct ospf_external_aggr_rt
*aggr
,
776 struct external_info
*ei
)
778 struct ospf_lsa
*lsa
;
779 struct as_external_lsa
*al
;
782 /* Handling the case where the external route prefix
783 * and aggregate prefix is same
784 * If same dont flush the originated external LSA.
786 if (prefix_same((struct prefix
*)&aggr
->p
, (struct prefix
*)&ei
->p
)) {
787 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
789 "%s: External Route prefix same as Aggregator(%pI4/%d), so dont flush.",
790 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
);
794 lsa
= ospf_external_info_find_lsa(ospf
, &ei
->p
);
796 al
= (struct as_external_lsa
*)lsa
->data
;
797 masklen2ip(ei
->p
.prefixlen
, &mask
);
799 if (mask
.s_addr
!= al
->mask
.s_addr
)
802 ospf_external_lsa_flush(ospf
, ei
->type
, &ei
->p
, 0);
806 static void ospf_handle_exnl_rt_after_aggr_del(struct ospf
*ospf
,
807 struct external_info
*ei
)
809 struct ospf_lsa
*lsa
;
811 /* Process only marked external routes.
812 * These routes were part of a deleted
813 * aggregator.So, originate now.
815 if (!ei
->to_be_processed
)
818 ei
->to_be_processed
= false;
820 lsa
= ospf_external_info_find_lsa(ospf
, &ei
->p
);
823 ospf_external_lsa_refresh(ospf
, lsa
, ei
, LSA_REFRESH_FORCE
, 0);
825 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
826 zlog_debug("%s: Originate external route(%pI4/%d)",
827 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
);
829 ospf_external_lsa_originate(ospf
, ei
);
833 static void ospf_handle_external_aggr_add(struct ospf
*ospf
)
835 struct external_info
*ei
;
836 struct route_node
*rn
= NULL
;
837 struct route_table
*rt
= NULL
;
840 /* Delete all the aggregators which are marked as
841 * OSPF_ROUTE_AGGR_DEL.
843 ospf_delete_all_marked_aggregators(ospf
);
845 for (type
= 0; type
<= ZEBRA_ROUTE_MAX
; type
++) {
846 struct list
*ext_list
;
847 struct listnode
*node
;
848 struct ospf_external
*ext
;
849 struct ospf_external_aggr_rt
*aggr
;
851 ext_list
= ospf
->external
[type
];
855 for (ALL_LIST_ELEMENTS_RO(ext_list
, node
, ext
)) {
856 rt
= ext
->external_info
;
860 for (rn
= route_top(rt
); rn
; rn
= route_next(rn
)) {
865 if (is_default_prefix4(&ei
->p
))
868 /* Check the AS-external-LSA
869 * should be originated.
871 if (!ospf_redistribute_check(ospf
, ei
, NULL
))
874 aggr
= ospf_external_aggr_match(ospf
, &ei
->p
);
876 /* If matching aggregator found, Add
877 * the external route reference to the
878 * aggregator and originate the aggr
879 * route if it is advertisable.
880 * flush the external LSA if it is
881 * already originated for this external
885 ospf_originate_summary_lsa(ospf
, aggr
,
888 /* All aggregated external rts
891 ospf_handle_aggregated_exnl_rt(
896 /* External routes which are only out
897 * of aggregation will be handled here.
899 ospf_handle_exnl_rt_after_aggr_del(ospf
, ei
);
906 ospf_aggr_handle_advertise_change(struct ospf
*ospf
,
907 struct ospf_external_aggr_rt
*aggr
,
908 struct external_info
*ei_aggr
)
910 struct ospf_lsa
*lsa
;
912 /* Check if advertise option modified. */
913 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
915 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
917 "%s: Don't originate the summary address,It is configured to not-advertise.",
920 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
922 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
924 "%s: No-advertise,So Flush the Aggregate route(%pI4/%d)",
925 __func__
, &aggr
->p
.prefix
,
928 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
930 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
935 if (!CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
936 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
937 zlog_debug("%s: Now it is advatisable", __func__
);
939 lsa
= ospf_external_info_find_lsa(ospf
, &ei_aggr
->p
);
940 if (lsa
&& IS_LSA_MAXAGE(lsa
)) {
941 /* This is special case.
942 * If a summary route need to be originated but where
943 * summary route already exist in lsdb with maxage, then
944 * it need to be refreshed.
946 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
948 "%s: It is already with Maxage, So refresh it (%pI4/%d)",
949 __func__
, &aggr
->p
.prefix
,
952 ospf_external_lsa_refresh(ospf
, lsa
, ei_aggr
,
953 LSA_REFRESH_FORCE
, 1);
955 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
959 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
961 "%s: Originate Aggregate LSA (%pI4/%d)",
962 __func__
, &aggr
->p
.prefix
,
965 /* Originate summary LSA */
966 lsa
= ospf_external_lsa_originate(ospf
, ei_aggr
);
968 SET_FLAG(aggr
->flags
,
969 OSPF_EXTERNAL_AGGRT_ORIGINATED
);
974 static void ospf_handle_external_aggr_update(struct ospf
*ospf
)
976 struct route_node
*rn
= NULL
;
978 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
979 zlog_debug("%s: Process modified aggregators.", __func__
);
981 for (rn
= route_top(ospf
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
982 struct ospf_external_aggr_rt
*aggr
;
983 struct ospf_lsa
*lsa
= NULL
;
984 struct as_external_lsa
*asel
= NULL
;
985 struct external_info ei_aggr
;
993 if (aggr
->action
== OSPF_ROUTE_AGGR_DEL
) {
994 aggr
->action
= OSPF_ROUTE_AGGR_NONE
;
995 ospf_external_aggr_delete(ospf
, rn
);
997 if (OSPF_EXTERNAL_RT_COUNT(aggr
))
999 aggr
->match_extnl_hash
,
1000 (void *)ospf_aggr_handle_external_info
);
1002 hash_free(aggr
->match_extnl_hash
);
1003 XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR
, aggr
);
1005 } else if (aggr
->action
== OSPF_ROUTE_AGGR_MODIFY
) {
1007 aggr
->action
= OSPF_ROUTE_AGGR_NONE
;
1009 /* Prepare the extrenal_info for aggregator */
1010 memset(&ei_aggr
, 0, sizeof(struct external_info
));
1011 ei_aggr
.p
= aggr
->p
;
1012 ei_aggr
.tag
= aggr
->tag
;
1014 ei_aggr
.instance
= ospf
->instance
;
1015 ei_aggr
.route_map_set
.metric
= -1;
1016 ei_aggr
.route_map_set
.metric_type
= -1;
1018 /* Check if tag modified */
1019 if (CHECK_FLAG(aggr
->flags
,
1020 OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
1021 lsa
= ospf_external_info_find_lsa(ospf
,
1024 flog_warn(EC_OSPF_LSA_MISSING
,
1025 "%s: Could not refresh/originate %pI4/%d",
1026 __func__
, &aggr
->p
.prefix
,
1031 asel
= (struct as_external_lsa
*)lsa
->data
;
1032 tag
= (unsigned long)ntohl(
1033 asel
->e
[0].route_tag
);
1035 /* If tag modified , then re-originate the
1036 * route with modified tag details.
1038 if (tag
!= ei_aggr
.tag
) {
1039 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1041 "%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
1047 ospf_external_lsa_refresh(
1048 ospf
, lsa
, &ei_aggr
,
1049 LSA_REFRESH_FORCE
, 1);
1053 /* Advertise option modified ?
1054 * If so, handled it here.
1056 ospf_aggr_handle_advertise_change(ospf
, aggr
, &ei_aggr
);
1061 static int ospf_asbr_external_aggr_process(struct thread
*thread
)
1063 struct ospf
*ospf
= THREAD_ARG(thread
);
1066 ospf
->t_external_aggr
= NULL
;
1067 operation
= ospf
->aggr_action
;
1069 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1070 zlog_debug("%s: operation:%d", __func__
, operation
);
1072 switch (operation
) {
1073 case OSPF_ROUTE_AGGR_ADD
:
1074 ospf_handle_external_aggr_add(ospf
);
1076 case OSPF_ROUTE_AGGR_DEL
:
1077 case OSPF_ROUTE_AGGR_MODIFY
:
1078 ospf_handle_external_aggr_update(ospf
);
1084 return OSPF_SUCCESS
;
1086 static void ospf_external_aggr_timer(struct ospf
*ospf
,
1087 struct ospf_external_aggr_rt
*aggr
,
1088 enum ospf_aggr_action_t operation
)
1090 aggr
->action
= operation
;
1092 if (ospf
->t_external_aggr
) {
1093 if (ospf
->aggr_action
== OSPF_ROUTE_AGGR_ADD
) {
1095 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1097 "%s: Not required to retsart timer,set is already added.",
1102 if (operation
== OSPF_ROUTE_AGGR_ADD
) {
1103 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1105 "%s, Restarting Aggregator delay timer.",
1107 THREAD_OFF(ospf
->t_external_aggr
);
1111 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1112 zlog_debug("%s: Start Aggregator delay timer %d(in seconds).",
1113 __func__
, ospf
->aggr_delay_interval
);
1115 ospf
->aggr_action
= operation
;
1116 thread_add_timer(master
, ospf_asbr_external_aggr_process
, ospf
,
1117 ospf
->aggr_delay_interval
, &ospf
->t_external_aggr
);
1120 int ospf_asbr_external_aggregator_set(struct ospf
*ospf
, struct prefix_ipv4
*p
,
1123 struct ospf_external_aggr_rt
*aggregator
;
1125 aggregator
= ospf_extrenal_aggregator_lookup(ospf
, p
);
1128 if (CHECK_FLAG(aggregator
->flags
,
1129 OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
))
1130 UNSET_FLAG(aggregator
->flags
,
1131 OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1132 else if (aggregator
->tag
== tag
)
1133 return OSPF_SUCCESS
;
1135 aggregator
->tag
= tag
;
1137 ospf_external_aggr_timer(ospf
, aggregator
,
1138 OSPF_ROUTE_AGGR_MODIFY
);
1140 aggregator
= ospf_external_aggregator_new(p
);
1142 return OSPF_FAILURE
;
1144 aggregator
->tag
= tag
;
1146 ospf_external_aggr_add(ospf
, aggregator
);
1147 ospf_external_aggr_timer(ospf
, aggregator
, OSPF_ROUTE_AGGR_ADD
);
1150 return OSPF_SUCCESS
;
1153 int ospf_asbr_external_aggregator_unset(struct ospf
*ospf
,
1154 struct prefix_ipv4
*p
, route_tag_t tag
)
1156 struct route_node
*rn
;
1157 struct ospf_external_aggr_rt
*aggr
;
1159 rn
= route_node_lookup(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
1161 return OSPF_INVALID
;
1162 route_unlock_node(rn
);
1166 if (tag
&& (tag
!= aggr
->tag
))
1167 return OSPF_INVALID
;
1169 if (!OSPF_EXTERNAL_RT_COUNT(aggr
)) {
1170 ospf_external_aggr_delete(ospf
, rn
);
1171 ospf_external_aggregator_free(aggr
);
1172 return OSPF_SUCCESS
;
1175 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_DEL
);
1177 return OSPF_SUCCESS
;
1180 int ospf_asbr_external_rt_no_advertise(struct ospf
*ospf
, struct prefix_ipv4
*p
)
1182 struct ospf_external_aggr_rt
*aggr
;
1183 route_tag_t tag
= 0;
1185 aggr
= ospf_extrenal_aggregator_lookup(ospf
, p
);
1187 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
))
1188 return OSPF_SUCCESS
;
1190 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1194 if (!OSPF_EXTERNAL_RT_COUNT(aggr
))
1195 return OSPF_SUCCESS
;
1197 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_MODIFY
);
1199 aggr
= ospf_external_aggregator_new(p
);
1202 return OSPF_FAILURE
;
1204 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1205 ospf_external_aggr_add(ospf
, aggr
);
1206 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_ADD
);
1209 return OSPF_SUCCESS
;
1212 int ospf_asbr_external_rt_advertise(struct ospf
*ospf
, struct prefix_ipv4
*p
)
1214 struct route_node
*rn
;
1215 struct ospf_external_aggr_rt
*aggr
;
1217 rn
= route_node_lookup(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
1219 return OSPF_INVALID
;
1220 route_unlock_node(rn
);
1224 if (!CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
))
1225 return OSPF_INVALID
;
1227 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1229 if (!OSPF_EXTERNAL_RT_COUNT(aggr
))
1230 return OSPF_SUCCESS
;
1232 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_MODIFY
);
1233 return OSPF_SUCCESS
;
1236 int ospf_external_aggregator_timer_set(struct ospf
*ospf
, unsigned int interval
)
1238 ospf
->aggr_delay_interval
= interval
;
1239 return OSPF_SUCCESS
;