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
;
116 char inetbuf
[INET6_BUFSIZ
];
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? */
127 if ((new->ifindex
== ifindex
)
128 && (new->nexthop
.s_addr
== nexthop
.s_addr
)
129 && (new->tag
== tag
)) {
130 route_unlock_node(rn
);
131 return NULL
; /* NULL => no LSA to refresh */
134 inet_ntop(AF_INET
, (void *)&nexthop
.s_addr
, inetbuf
,
136 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
))
138 "Redistribute[%s][%d][%u]: %pFX discarding old info with NH %s.",
139 ospf_redist_string(type
), instance
,
140 ospf
->vrf_id
, &p
, inetbuf
);
141 XFREE(MTYPE_OSPF_EXTERNAL_INFO
, rn
->info
);
144 /* Create new External info instance. */
145 new = ospf_external_info_new(type
, instance
);
147 new->ifindex
= ifindex
;
148 new->nexthop
= nexthop
;
151 new->aggr_route
= NULL
;
153 /* we don't unlock rn from the get() because we're attaching the info */
157 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
)) {
158 inet_ntop(AF_INET
, (void *)&nexthop
.s_addr
, inetbuf
,
161 "Redistribute[%s][%u]: %pFX external info created, with NH %s",
162 ospf_redist_string(type
), ospf
->vrf_id
,
168 void ospf_external_info_delete(struct ospf
*ospf
, uint8_t type
,
169 unsigned short instance
, 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 ospf_external_info_free(rn
->info
);
182 route_unlock_node(rn
);
183 route_unlock_node(rn
);
187 struct external_info
*ospf_external_info_lookup(struct ospf
*ospf
, uint8_t type
,
188 unsigned short instance
,
189 struct prefix_ipv4
*p
)
191 struct route_node
*rn
;
192 struct ospf_external
*ext
;
194 ext
= ospf_external_lookup(ospf
, type
, instance
);
198 rn
= route_node_lookup(EXTERNAL_INFO(ext
), (struct prefix
*)p
);
200 route_unlock_node(rn
);
208 struct ospf_lsa
*ospf_external_info_find_lsa(struct ospf
*ospf
,
209 struct prefix_ipv4
*p
)
211 struct ospf_lsa
*lsa
;
212 struct as_external_lsa
*al
;
213 struct in_addr mask
, id
;
215 /* Fisrt search the lsdb with address specifc LSID
216 * where all the host bits are set, if there a matched
218 * Ex: For route 10.0.0.0/16, LSID is 10.0.255.255
219 * If no lsa with above LSID, use received address as
220 * LSID and check if any LSA in LSDB.
221 * If LSA found, check if the mask is same b/w the matched
222 * LSA and received prefix, if same then it is the LSA for
224 * Ex: For route 10.0.0.0/16, LSID is 10.0.0.0
227 masklen2ip(p
->prefixlen
, &mask
);
228 id
.s_addr
= p
->prefix
.s_addr
| (~mask
.s_addr
);
229 lsa
= ospf_lsdb_lookup_by_id(ospf
->lsdb
, OSPF_AS_EXTERNAL_LSA
, id
,
234 lsa
= ospf_lsdb_lookup_by_id(ospf
->lsdb
, OSPF_AS_EXTERNAL_LSA
,
235 p
->prefix
, ospf
->router_id
);
238 al
= (struct as_external_lsa
*)lsa
->data
;
239 if (mask
.s_addr
== al
->mask
.s_addr
)
247 /* Update ASBR status. */
248 void ospf_asbr_status_update(struct ospf
*ospf
, uint8_t status
)
250 zlog_info("ASBR[%s:Status:%d]: Update",
251 ospf_get_name(ospf
), status
);
256 if (IS_OSPF_ASBR(ospf
)) {
257 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
258 ospf_get_name(ospf
), status
);
261 SET_FLAG(ospf
->flags
, OSPF_FLAG_ASBR
);
263 /* Already non ASBR. */
264 if (!IS_OSPF_ASBR(ospf
)) {
265 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
266 ospf_get_name(ospf
), status
);
269 UNSET_FLAG(ospf
->flags
, OSPF_FLAG_ASBR
);
272 /* Transition from/to status ASBR, schedule timer. */
273 ospf_spf_calculate_schedule(ospf
, SPF_FLAG_ASBR_STATUS_CHANGE
);
274 ospf_router_lsa_update(ospf
);
277 /* If there's redistribution configured, we need to refresh external
278 * LSAs in order to install Type-7 and flood to all NSSA Areas
280 void ospf_asbr_nssa_redist_task(struct ospf
*ospf
)
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
,
296 LSA_REFRESH_IF_CHANGED
);
299 ospf_external_lsa_refresh_default(ospf
);
302 void ospf_redistribute_withdraw(struct ospf
*ospf
, uint8_t type
,
303 unsigned short instance
)
305 struct route_node
*rn
;
306 struct external_info
*ei
;
307 struct ospf_external
*ext
;
309 ext
= ospf_external_lookup(ospf
, type
, instance
);
313 /* Delete external info for specified type. */
314 if (EXTERNAL_INFO(ext
))
315 for (rn
= route_top(EXTERNAL_INFO(ext
)); rn
;
318 if (ospf_external_info_find_lsa(ospf
, &ei
->p
)) {
319 if (is_prefix_default(&ei
->p
)
320 && ospf
->default_originate
321 != DEFAULT_ORIGINATE_NONE
)
323 ospf_external_lsa_flush(
325 ei
->ifindex
/*, ei->nexthop */);
327 ospf_external_info_free(ei
);
328 route_unlock_node(rn
);
333 /* External Route Aggregator Handlers */
334 bool is_valid_summary_addr(struct prefix_ipv4
*p
)
336 /* Default prefix validation*/
337 if (p
->prefix
.s_addr
== INADDR_ANY
)
340 /*Host route shouldn't be configured as summary addres*/
341 if (p
->prefixlen
== IPV4_MAX_PREFIXLEN
)
346 void ospf_asbr_external_aggregator_init(struct ospf
*instance
)
348 instance
->rt_aggr_tbl
= route_table_init();
350 instance
->t_external_aggr
= NULL
;
352 instance
->aggr_action
= 0;
354 instance
->aggr_delay_interval
= OSPF_EXTL_AGGR_DEFAULT_DELAY
;
357 static unsigned int ospf_external_rt_hash_key(const void *data
)
359 const struct external_info
*ei
= data
;
360 unsigned int key
= 0;
362 key
= prefix_hash_key(&ei
->p
);
366 static bool ospf_external_rt_hash_cmp(const void *d1
, const void *d2
)
368 const struct external_info
*ei1
= d1
;
369 const struct external_info
*ei2
= d2
;
371 return prefix_same((struct prefix
*)&ei1
->p
, (struct prefix
*)&ei2
->p
);
374 static struct ospf_external_aggr_rt
*
375 ospf_external_aggregator_new(struct prefix_ipv4
*p
)
377 struct ospf_external_aggr_rt
*aggr
;
379 aggr
= (struct ospf_external_aggr_rt
*)XCALLOC(
380 MTYPE_OSPF_EXTERNAL_RT_AGGR
,
381 sizeof(struct ospf_external_aggr_rt
));
386 aggr
->p
.family
= p
->family
;
387 aggr
->p
.prefix
= p
->prefix
;
388 aggr
->p
.prefixlen
= p
->prefixlen
;
389 aggr
->match_extnl_hash
= hash_create(ospf_external_rt_hash_key
,
390 ospf_external_rt_hash_cmp
,
391 "Ospf external route hash");
395 static void ospf_aggr_handle_external_info(void *data
)
397 struct external_info
*ei
= (struct external_info
*)data
;
398 struct ospf_external_aggr_rt
*aggr
= NULL
;
399 struct ospf
*ospf
= NULL
;
400 struct ospf_lsa
*lsa
= NULL
;
402 ei
->aggr_route
= NULL
;
404 ei
->to_be_processed
= true;
406 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
407 zlog_debug("%s: Handle extrenal route(%pI4/%d)", __func__
,
408 &ei
->p
.prefix
, ei
->p
.prefixlen
);
410 ospf
= ospf_lookup_instance(ei
->instance
);
414 if (!ospf_redistribute_check(ospf
, ei
, NULL
))
417 aggr
= ospf_external_aggr_match(ospf
, &ei
->p
);
419 (void)ospf_originate_summary_lsa(ospf
, aggr
, ei
);
423 lsa
= ospf_external_info_find_lsa(ospf
, &ei
->p
);
425 ospf_external_lsa_refresh(ospf
, lsa
, ei
, LSA_REFRESH_FORCE
, 1);
427 (void)ospf_external_lsa_originate(ospf
, ei
);
430 static void ospf_aggr_unlink_external_info(void *data
)
432 struct external_info
*ei
= (struct external_info
*)data
;
434 ei
->aggr_route
= NULL
;
436 ei
->to_be_processed
= true;
439 void ospf_external_aggregator_free(struct ospf_external_aggr_rt
*aggr
)
441 if (OSPF_EXTERNAL_RT_COUNT(aggr
))
442 hash_clean(aggr
->match_extnl_hash
,
443 (void *)ospf_aggr_unlink_external_info
);
445 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
446 zlog_debug("%s: Release the aggregator Address(%pI4/%d)",
447 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
448 hash_free(aggr
->match_extnl_hash
);
449 aggr
->match_extnl_hash
= NULL
;
451 XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR
, aggr
);
454 static void ospf_external_aggr_add(struct ospf
*ospf
,
455 struct ospf_external_aggr_rt
*aggr
)
457 struct route_node
*rn
;
459 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
460 zlog_debug("%s: Adding Aggregate route to Aggr table (%pI4/%d)",
461 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
462 rn
= route_node_get(ospf
->rt_aggr_tbl
, (struct prefix
*)&aggr
->p
);
464 route_unlock_node(rn
);
469 static void ospf_external_aggr_delete(struct ospf
*ospf
, struct route_node
*rn
)
471 struct ospf_external_aggr_rt
*aggr
= rn
->info
;
473 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
474 zlog_debug("%s: Deleting Aggregate route (%pI4/%d)", __func__
,
475 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
477 /* Sent a Max age LSA if it is already originated. */
478 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
479 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
480 zlog_debug("%s: Flushing Aggregate route (%pI4/%d)",
481 __func__
, &aggr
->p
.prefix
,
483 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
487 route_unlock_node(rn
);
488 route_unlock_node(rn
);
491 struct ospf_external_aggr_rt
*
492 ospf_extrenal_aggregator_lookup(struct ospf
*ospf
, struct prefix_ipv4
*p
)
494 struct route_node
*rn
;
495 struct ospf_external_aggr_rt
*summary_rt
= NULL
;
497 rn
= route_node_lookup(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
499 summary_rt
= rn
->info
;
500 route_unlock_node(rn
);
506 struct ospf_external_aggr_rt
*ospf_external_aggr_match(struct ospf
*ospf
,
507 struct prefix_ipv4
*p
)
509 struct route_node
*node
;
510 struct ospf_external_aggr_rt
*summary_rt
= NULL
;
512 node
= route_node_match(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
515 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
517 struct ospf_external_aggr_rt
*ag
= node
->info
;
520 "%s: Matching aggregator found.prefix:%pI4/%d Aggregator %pI4/%d\n",
521 __func__
, &p
->prefix
, p
->prefixlen
,
522 &ag
->p
.prefix
, ag
->p
.prefixlen
);
525 summary_rt
= node
->info
;
526 route_unlock_node(node
);
532 void ospf_unlink_ei_from_aggr(struct ospf
*ospf
,
533 struct ospf_external_aggr_rt
*aggr
,
534 struct external_info
*ei
)
536 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
538 "%s: Unlinking extrenal route(%pI4/%d) from aggregator(%pI4/%d), external route count:%ld",
539 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
,
540 &aggr
->p
.prefix
, aggr
->p
.prefixlen
,
541 OSPF_EXTERNAL_RT_COUNT(aggr
));
542 hash_release(aggr
->match_extnl_hash
, ei
);
543 ei
->aggr_route
= NULL
;
545 /* Flush the aggreagte route if matching
546 * external route count becomes zero.
548 if (!OSPF_EXTERNAL_RT_COUNT(aggr
)
549 && CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
551 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
552 zlog_debug("%s: Flushing the aggreagte route (%pI4/%d)",
553 __func__
, &aggr
->p
.prefix
,
556 /* Flush the aggregate LSA */
557 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
559 /* Unset the Origination flag */
560 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
564 static void ospf_link_ei_to_aggr(struct ospf_external_aggr_rt
*aggr
,
565 struct external_info
*ei
)
567 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
569 "%s: Linking extrenal route(%pI4/%d) to aggregator(%pI4/%d)",
570 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
,
571 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
572 hash_get(aggr
->match_extnl_hash
, ei
, hash_alloc_intern
);
573 ei
->aggr_route
= aggr
;
576 struct ospf_lsa
*ospf_originate_summary_lsa(struct ospf
*ospf
,
577 struct ospf_external_aggr_rt
*aggr
,
578 struct external_info
*ei
)
580 struct ospf_lsa
*lsa
;
581 struct external_info ei_aggr
;
582 struct as_external_lsa
*asel
;
583 struct ospf_external_aggr_rt
*old_aggr
;
586 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
587 zlog_debug("%s: Prepare to originate Summary route(%pI4/%d)",
588 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
590 /* This case to handle when the overlapping aggregator address
591 * is availbe.Best match will be considered.So need to delink
592 * from old aggregator and link to the new aggr.
594 if (ei
->aggr_route
) {
595 if (ei
->aggr_route
!= aggr
) {
596 old_aggr
= ei
->aggr_route
;
597 ospf_unlink_ei_from_aggr(ospf
, old_aggr
, ei
);
601 /* Add the external route to hash table */
602 ospf_link_ei_to_aggr(aggr
, ei
);
604 lsa
= ospf_external_info_find_lsa(ospf
, &aggr
->p
);
605 /* Dont originate external LSA,
606 * If it is configured not to advertise.
608 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
609 /* If it is already originated as external LSA,
610 * But, it is configured not to advertise then
611 * flush the originated external lsa.
614 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
615 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
617 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
619 "%s: Don't originate the summary address,It is configured to not-advertise.",
624 /* Prepare the extrenal_info for aggregator */
625 memset(&ei_aggr
, 0, sizeof(struct external_info
));
627 ei_aggr
.tag
= aggr
->tag
;
629 ei_aggr
.instance
= ospf
->instance
;
630 ei_aggr
.route_map_set
.metric
= -1;
631 ei_aggr
.route_map_set
.metric_type
= -1;
633 /* Summary route already originated,
636 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
638 flog_warn(EC_OSPF_LSA_MISSING
,
639 "%s: Could not refresh/originate %pI4/%d",
640 __func__
, &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
644 asel
= (struct as_external_lsa
*)lsa
->data
;
645 tag
= (unsigned long)ntohl(asel
->e
[0].route_tag
);
647 /* If tag modified , then re-originate the route
648 * with modified tag details.
650 if (tag
!= ei_aggr
.tag
) {
651 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
653 "%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
654 __func__
, tag
, ei_aggr
.tag
,
655 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
657 ospf_external_lsa_refresh(ospf
, lsa
, &ei_aggr
,
658 LSA_REFRESH_FORCE
, 1);
663 if (lsa
&& IS_LSA_MAXAGE(lsa
)) {
664 /* This is special case.
665 * If a summary route need to be originated but where
666 * summary route already exist in lsdb with maxage, then
667 * it need to be refreshed.
669 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
671 "%s: LSA is in MAX-AGE so refreshing LSA(%pI4/%d)",
672 __PRETTY_FUNCTION__
, &aggr
->p
.prefix
,
675 ospf_external_lsa_refresh(ospf
, lsa
, &ei_aggr
,
676 LSA_REFRESH_FORCE
, 1);
677 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
681 /* If the external route prefix same as aggregate route
682 * and if external route is already originated as TYPE-5
683 * then it need to be refreshed and originate bit should
686 if (lsa
&& prefix_same((struct prefix
*)&ei_aggr
.p
,
687 (struct prefix
*)&ei
->p
)) {
688 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
690 "%s: External route prefix is same as aggr so refreshing LSA(%pI4/%d)",
691 __PRETTY_FUNCTION__
, &aggr
->p
.prefix
,
693 ospf_external_lsa_refresh(ospf
, lsa
, &ei_aggr
,
694 LSA_REFRESH_FORCE
, 1);
695 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
699 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
700 zlog_debug("%s: Originate Summary route(%pI4/%d)", __func__
,
701 &aggr
->p
.prefix
, aggr
->p
.prefixlen
);
703 /* Originate summary LSA */
704 lsa
= ospf_external_lsa_originate(ospf
, &ei_aggr
);
706 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
707 zlog_debug("%s: Set the origination bit for aggregator",
709 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
714 void ospf_unset_all_aggr_flag(struct ospf
*ospf
)
716 struct route_node
*rn
= NULL
;
718 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
719 zlog_debug("Unset the origination bit for all aggregator");
721 for (rn
= route_top(ospf
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
725 struct ospf_external_aggr_rt
*aggr
= rn
->info
;
727 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
731 static void ospf_delete_all_marked_aggregators(struct ospf
*ospf
)
733 struct route_node
*rn
= NULL
;
735 /* Loop through all the aggregators, Delete all aggregators
736 * which are marked as DELETE. Set action to NONE for remaining
739 for (rn
= route_top(ospf
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
743 struct ospf_external_aggr_rt
*aggr
= rn
->info
;
745 if (aggr
->action
!= OSPF_ROUTE_AGGR_DEL
) {
746 aggr
->action
= OSPF_ROUTE_AGGR_NONE
;
749 ospf_external_aggr_delete(ospf
, rn
);
750 ospf_external_aggregator_free(aggr
);
754 static void ospf_handle_aggregated_exnl_rt(struct ospf
*ospf
,
755 struct ospf_external_aggr_rt
*aggr
,
756 struct external_info
*ei
)
758 struct ospf_lsa
*lsa
;
759 struct as_external_lsa
*al
;
762 /* Handling the case where the external route prefix
763 * and aggregate prefix is same
764 * If same dont flush the originated external LSA.
766 if (prefix_same((struct prefix
*)&aggr
->p
, (struct prefix
*)&ei
->p
)) {
767 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
769 "%s: External Route prefix same as Aggregator(%pI4/%d), so dont flush.",
770 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
);
774 lsa
= ospf_external_info_find_lsa(ospf
, &ei
->p
);
776 al
= (struct as_external_lsa
*)lsa
->data
;
777 masklen2ip(ei
->p
.prefixlen
, &mask
);
779 if (mask
.s_addr
!= al
->mask
.s_addr
)
782 ospf_external_lsa_flush(ospf
, ei
->type
, &ei
->p
, 0);
786 static void ospf_handle_exnl_rt_after_aggr_del(struct ospf
*ospf
,
787 struct external_info
*ei
)
789 struct ospf_lsa
*lsa
;
791 /* Process only marked external routes.
792 * These routes were part of a deleted
793 * aggregator.So, originate now.
795 if (!ei
->to_be_processed
)
798 ei
->to_be_processed
= false;
800 lsa
= ospf_external_info_find_lsa(ospf
, &ei
->p
);
803 ospf_external_lsa_refresh(ospf
, lsa
, ei
, LSA_REFRESH_FORCE
, 0);
805 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
806 zlog_debug("%s: Originate external route(%pI4/%d)",
807 __func__
, &ei
->p
.prefix
, ei
->p
.prefixlen
);
809 ospf_external_lsa_originate(ospf
, ei
);
813 static void ospf_handle_external_aggr_add(struct ospf
*ospf
)
815 struct external_info
*ei
;
816 struct route_node
*rn
= NULL
;
817 struct route_table
*rt
= NULL
;
820 /* Delete all the aggregators which are marked as
821 * OSPF_ROUTE_AGGR_DEL.
823 ospf_delete_all_marked_aggregators(ospf
);
825 for (type
= 0; type
<= ZEBRA_ROUTE_MAX
; type
++) {
826 struct list
*ext_list
;
827 struct listnode
*node
;
828 struct ospf_external
*ext
;
829 struct ospf_external_aggr_rt
*aggr
;
831 ext_list
= ospf
->external
[type
];
835 for (ALL_LIST_ELEMENTS_RO(ext_list
, node
, ext
)) {
836 rt
= ext
->external_info
;
840 for (rn
= route_top(rt
); rn
; rn
= route_next(rn
)) {
845 if (is_prefix_default(&ei
->p
))
848 /* Check the AS-external-LSA
849 * should be originated.
851 if (!ospf_redistribute_check(ospf
, ei
, NULL
))
854 aggr
= ospf_external_aggr_match(ospf
, &ei
->p
);
856 /* If matching aggregator found, Add
857 * the external route reference to the
858 * aggregator and originate the aggr
859 * route if it is advertisable.
860 * flush the external LSA if it is
861 * already originated for this external
865 ospf_originate_summary_lsa(ospf
, aggr
,
868 /* All aggregated external rts
871 ospf_handle_aggregated_exnl_rt(
876 /* External routes which are only out
877 * of aggregation will be handled here.
879 ospf_handle_exnl_rt_after_aggr_del(ospf
, ei
);
886 ospf_aggr_handle_advertise_change(struct ospf
*ospf
,
887 struct ospf_external_aggr_rt
*aggr
,
888 struct external_info
*ei_aggr
)
890 struct ospf_lsa
*lsa
;
892 /* Check if advertise option modified. */
893 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
)) {
895 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
897 "%s: Don't originate the summary address,It is configured to not-advertise.",
900 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
902 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
904 "%s: No-advertise,So Flush the Aggregate route(%pI4/%d)",
905 __func__
, &aggr
->p
.prefix
,
908 ospf_external_lsa_flush(ospf
, 0, &aggr
->p
, 0);
910 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
915 if (!CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
916 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
917 zlog_debug("%s: Now it is advatisable", __func__
);
919 lsa
= ospf_external_info_find_lsa(ospf
, &ei_aggr
->p
);
920 if (lsa
&& IS_LSA_MAXAGE(lsa
)) {
921 /* This is special case.
922 * If a summary route need to be originated but where
923 * summary route already exist in lsdb with maxage, then
924 * it need to be refreshed.
926 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
928 "%s: It is already with Maxage, So refresh it (%pI4/%d)",
929 __func__
, &aggr
->p
.prefix
,
932 ospf_external_lsa_refresh(ospf
, lsa
, ei_aggr
,
933 LSA_REFRESH_FORCE
, 1);
935 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_ORIGINATED
);
939 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
941 "%s: Originate Aggregate LSA (%pI4/%d)",
942 __func__
, &aggr
->p
.prefix
,
945 /* Originate summary LSA */
946 lsa
= ospf_external_lsa_originate(ospf
, ei_aggr
);
948 SET_FLAG(aggr
->flags
,
949 OSPF_EXTERNAL_AGGRT_ORIGINATED
);
954 static void ospf_handle_external_aggr_update(struct ospf
*ospf
)
956 struct route_node
*rn
= NULL
;
958 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
959 zlog_debug("%s: Process modified aggregators.\n", __func__
);
961 for (rn
= route_top(ospf
->rt_aggr_tbl
); rn
; rn
= route_next(rn
)) {
962 struct ospf_external_aggr_rt
*aggr
;
963 struct ospf_lsa
*lsa
= NULL
;
964 struct as_external_lsa
*asel
= NULL
;
965 struct external_info ei_aggr
;
973 if (aggr
->action
== OSPF_ROUTE_AGGR_DEL
) {
974 aggr
->action
= OSPF_ROUTE_AGGR_NONE
;
975 ospf_external_aggr_delete(ospf
, rn
);
977 if (OSPF_EXTERNAL_RT_COUNT(aggr
))
979 aggr
->match_extnl_hash
,
980 (void *)ospf_aggr_handle_external_info
);
982 hash_free(aggr
->match_extnl_hash
);
983 XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR
, aggr
);
985 } else if (aggr
->action
== OSPF_ROUTE_AGGR_MODIFY
) {
987 aggr
->action
= OSPF_ROUTE_AGGR_NONE
;
989 /* Prepare the extrenal_info for aggregator */
990 memset(&ei_aggr
, 0, sizeof(struct external_info
));
992 ei_aggr
.tag
= aggr
->tag
;
994 ei_aggr
.instance
= ospf
->instance
;
995 ei_aggr
.route_map_set
.metric
= -1;
996 ei_aggr
.route_map_set
.metric_type
= -1;
998 /* Check if tag modified */
999 if (CHECK_FLAG(aggr
->flags
,
1000 OSPF_EXTERNAL_AGGRT_ORIGINATED
)) {
1001 lsa
= ospf_external_info_find_lsa(ospf
,
1004 flog_warn(EC_OSPF_LSA_MISSING
,
1005 "%s: Could not refresh/originate %pI4/%d",
1006 __func__
, &aggr
->p
.prefix
,
1011 asel
= (struct as_external_lsa
*)lsa
->data
;
1012 tag
= (unsigned long)ntohl(
1013 asel
->e
[0].route_tag
);
1015 /* If tag modified , then re-originate the
1016 * route with modified tag details.
1018 if (tag
!= ei_aggr
.tag
) {
1019 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1021 "%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
1027 ospf_external_lsa_refresh(
1028 ospf
, lsa
, &ei_aggr
,
1029 LSA_REFRESH_FORCE
, 1);
1033 /* Advertise option modified ?
1034 * If so, handled it here.
1036 ospf_aggr_handle_advertise_change(ospf
, aggr
, &ei_aggr
);
1041 static int ospf_asbr_external_aggr_process(struct thread
*thread
)
1043 struct ospf
*ospf
= THREAD_ARG(thread
);
1046 ospf
->t_external_aggr
= NULL
;
1047 operation
= ospf
->aggr_action
;
1049 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1050 zlog_debug("%s: operation:%d\n", __func__
, operation
);
1052 switch (operation
) {
1053 case OSPF_ROUTE_AGGR_ADD
:
1054 ospf_handle_external_aggr_add(ospf
);
1056 case OSPF_ROUTE_AGGR_DEL
:
1057 case OSPF_ROUTE_AGGR_MODIFY
:
1058 ospf_handle_external_aggr_update(ospf
);
1064 return OSPF_SUCCESS
;
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 THREAD_OFF(ospf
->t_external_aggr
);
1091 if (IS_DEBUG_OSPF(lsa
, EXTNL_LSA_AGGR
))
1092 zlog_debug("%s: Start Aggregator delay timer %d(in seconds).",
1093 __func__
, ospf
->aggr_delay_interval
);
1095 ospf
->aggr_action
= operation
;
1096 thread_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
;
1145 if (tag
&& (tag
!= aggr
->tag
))
1146 return OSPF_INVALID
;
1148 if (!OSPF_EXTERNAL_RT_COUNT(aggr
)) {
1149 ospf_external_aggr_delete(ospf
, rn
);
1150 ospf_external_aggregator_free(aggr
);
1151 return OSPF_SUCCESS
;
1154 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_DEL
);
1156 return OSPF_SUCCESS
;
1159 int ospf_asbr_external_rt_no_advertise(struct ospf
*ospf
, struct prefix_ipv4
*p
)
1161 struct ospf_external_aggr_rt
*aggr
;
1162 route_tag_t tag
= 0;
1164 aggr
= ospf_extrenal_aggregator_lookup(ospf
, p
);
1166 if (CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
))
1167 return OSPF_SUCCESS
;
1169 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1173 if (!OSPF_EXTERNAL_RT_COUNT(aggr
))
1174 return OSPF_SUCCESS
;
1176 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_MODIFY
);
1178 aggr
= ospf_external_aggregator_new(p
);
1181 return OSPF_FAILURE
;
1183 SET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1184 ospf_external_aggr_add(ospf
, aggr
);
1185 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_ADD
);
1188 return OSPF_SUCCESS
;
1191 int ospf_asbr_external_rt_advertise(struct ospf
*ospf
, struct prefix_ipv4
*p
)
1193 struct route_node
*rn
;
1194 struct ospf_external_aggr_rt
*aggr
;
1196 rn
= route_node_lookup(ospf
->rt_aggr_tbl
, (struct prefix
*)p
);
1198 return OSPF_INVALID
;
1202 if (!CHECK_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
))
1203 return OSPF_INVALID
;
1205 UNSET_FLAG(aggr
->flags
, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE
);
1207 if (!OSPF_EXTERNAL_RT_COUNT(aggr
))
1208 return OSPF_SUCCESS
;
1210 ospf_external_aggr_timer(ospf
, aggr
, OSPF_ROUTE_AGGR_MODIFY
);
1211 return OSPF_SUCCESS
;
1214 int ospf_external_aggregator_timer_set(struct ospf
*ospf
, unsigned int interval
)
1216 ospf
->aggr_delay_interval
= interval
;
1217 return OSPF_SUCCESS
;