mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 12:37:10 +00:00
ospfd: ospf summarisation core handlers
Description: Apis for creating/deleting aggregate routes. Origination of summary route on behalf of matched external routes. Signed-off-by: Rajesh Girada <rgirada@vmware.com>
This commit is contained in:
parent
ad7222b76c
commit
63f0e9415c
@ -42,7 +42,7 @@
|
||||
#include "ospfd/ospf_route.h"
|
||||
#include "ospfd/ospf_zebra.h"
|
||||
#include "ospfd/ospf_dump.h"
|
||||
|
||||
#include "ospfd/ospf_errors.h"
|
||||
|
||||
/* Remove external route. */
|
||||
void ospf_external_route_remove(struct ospf *ospf, struct prefix_ipv4 *p)
|
||||
@ -80,6 +80,7 @@ struct external_info *ospf_external_info_new(uint8_t type,
|
||||
new = XCALLOC(MTYPE_OSPF_EXTERNAL_INFO, sizeof(struct external_info));
|
||||
new->type = type;
|
||||
new->instance = instance;
|
||||
new->to_be_processed = 0;
|
||||
|
||||
ospf_reset_route_map_set_values(&new->route_map_set);
|
||||
return new;
|
||||
@ -147,6 +148,7 @@ ospf_external_info_add(struct ospf *ospf, uint8_t type, unsigned short instance,
|
||||
new->nexthop = nexthop;
|
||||
new->tag = tag;
|
||||
new->orig_tag = tag;
|
||||
new->aggr_route = NULL;
|
||||
|
||||
/* we don't unlock rn from the get() because we're attaching the info */
|
||||
if (rn)
|
||||
@ -378,6 +380,41 @@ ospf_external_aggregator_new(struct prefix_ipv4 *p)
|
||||
return aggr;
|
||||
}
|
||||
|
||||
static void ospf_aggr_handle_external_info(void *data)
|
||||
{
|
||||
struct external_info *ei = (struct external_info *)data;
|
||||
struct ospf_external_aggr_rt *aggr = NULL;
|
||||
struct ospf *ospf = NULL;
|
||||
struct ospf_lsa *lsa = NULL;
|
||||
|
||||
ei->aggr_route = NULL;
|
||||
|
||||
ei->to_be_processed = true;
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Handle extrenal route(%pI4/%d)", __func__,
|
||||
&ei->p.prefix, ei->p.prefixlen);
|
||||
|
||||
ospf = ospf_lookup_instance(ei->instance);
|
||||
|
||||
assert(ospf);
|
||||
|
||||
if (!ospf_redistribute_check(ospf, ei, NULL))
|
||||
return;
|
||||
|
||||
aggr = ospf_external_aggr_match(ospf, &ei->p);
|
||||
if (aggr) {
|
||||
lsa = ospf_originate_summary_lsa(ospf, aggr, ei);
|
||||
return;
|
||||
}
|
||||
|
||||
lsa = ospf_external_info_find_lsa(ospf, &ei->p);
|
||||
if (lsa)
|
||||
ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE, 1);
|
||||
else
|
||||
lsa = ospf_external_lsa_originate(ospf, ei);
|
||||
}
|
||||
|
||||
static void ospf_aggr_unlink_external_info(void *data)
|
||||
{
|
||||
struct external_info *ei = (struct external_info *)data;
|
||||
@ -394,11 +431,656 @@ void ospf_external_aggregator_free(struct ospf_external_aggr_rt *aggr)
|
||||
(void *)ospf_aggr_unlink_external_info);
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Release the aggregator Address(%s/%d)",
|
||||
__func__, inet_ntoa(aggr->p.prefix),
|
||||
aggr->p.prefixlen);
|
||||
zlog_debug("%s: Release the aggregator Address(%pI4/%d)",
|
||||
__func__, &aggr->p.prefix, aggr->p.prefixlen);
|
||||
hash_free(aggr->match_extnl_hash);
|
||||
aggr->match_extnl_hash = NULL;
|
||||
|
||||
XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR, aggr);
|
||||
}
|
||||
|
||||
static void ospf_external_aggr_add(struct ospf *ospf,
|
||||
struct ospf_external_aggr_rt *aggr)
|
||||
{
|
||||
struct route_node *rn;
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Adding Aggregate route to Aggr table (%pI4/%d)",
|
||||
__func__, &aggr->p.prefix, aggr->p.prefixlen);
|
||||
rn = route_node_get(ospf->rt_aggr_tbl, (struct prefix *)&aggr->p);
|
||||
if (rn->info)
|
||||
route_unlock_node(rn);
|
||||
else
|
||||
rn->info = aggr;
|
||||
}
|
||||
|
||||
static void ospf_external_aggr_delete(struct ospf *ospf, struct route_node *rn)
|
||||
{
|
||||
struct ospf_external_aggr_rt *aggr = rn->info;
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Deleting Aggregate route (%pI4/%d)", __func__,
|
||||
&aggr->p.prefix, aggr->p.prefixlen);
|
||||
|
||||
/* Sent a Max age LSA if it is already originated. */
|
||||
if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Flushing Aggregate route (%pI4/%d)",
|
||||
__func__, &aggr->p.prefix,
|
||||
aggr->p.prefixlen);
|
||||
ospf_external_lsa_flush(ospf, 0, &aggr->p, 0);
|
||||
}
|
||||
|
||||
rn->info = NULL;
|
||||
route_unlock_node(rn);
|
||||
route_unlock_node(rn);
|
||||
}
|
||||
|
||||
struct ospf_external_aggr_rt *
|
||||
ospf_extrenal_aggregator_lookup(struct ospf *ospf, struct prefix_ipv4 *p)
|
||||
{
|
||||
struct route_node *rn;
|
||||
struct ospf_external_aggr_rt *summary_rt = NULL;
|
||||
|
||||
rn = route_node_lookup(ospf->rt_aggr_tbl, (struct prefix *)p);
|
||||
if (rn) {
|
||||
summary_rt = rn->info;
|
||||
route_unlock_node(rn);
|
||||
return summary_rt;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ospf_external_aggr_rt *ospf_external_aggr_match(struct ospf *ospf,
|
||||
struct prefix_ipv4 *p)
|
||||
{
|
||||
struct route_node *node;
|
||||
struct ospf_external_aggr_rt *summary_rt = NULL;
|
||||
|
||||
node = route_node_match(ospf->rt_aggr_tbl, (struct prefix *)p);
|
||||
if (node) {
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
if (node->info) {
|
||||
struct ospf_external_aggr_rt *ag = node->info;
|
||||
|
||||
zlog_debug(
|
||||
"%s: Matching aggregator found.prefix:%pI4/%d Aggregator %pI4/%d\n",
|
||||
__func__, &p->prefix, p->prefixlen,
|
||||
&ag->p.prefix, ag->p.prefixlen);
|
||||
}
|
||||
|
||||
summary_rt = node->info;
|
||||
route_unlock_node(node);
|
||||
return summary_rt;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ospf_unlink_ei_from_aggr(struct ospf *ospf,
|
||||
struct ospf_external_aggr_rt *aggr,
|
||||
struct external_info *ei)
|
||||
{
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: Unlinking extrenal route(%pI4/%d) from aggregator(%pI4/%d), external route count:%ld",
|
||||
__func__, &ei->p.prefix, ei->p.prefixlen,
|
||||
&aggr->p.prefix, aggr->p.prefixlen,
|
||||
OSPF_EXTERNAL_RT_COUNT(aggr));
|
||||
hash_release(aggr->match_extnl_hash, ei);
|
||||
ei->aggr_route = NULL;
|
||||
|
||||
/* Flush the aggreagte route if matching
|
||||
* external route count becomes zero.
|
||||
*/
|
||||
if (!OSPF_EXTERNAL_RT_COUNT(aggr)
|
||||
&& CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Flushing the aggreagte route (%pI4/%d)",
|
||||
__func__, &aggr->p.prefix,
|
||||
aggr->p.prefixlen);
|
||||
|
||||
/* Flush the aggregate LSA */
|
||||
ospf_external_lsa_flush(ospf, 0, &aggr->p, 0);
|
||||
|
||||
/* Unset the Origination flag */
|
||||
UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ospf_link_ei_to_aggr(struct ospf_external_aggr_rt *aggr,
|
||||
struct external_info *ei)
|
||||
{
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: Linking extrenal route(%pI4/%d) to aggregator(%pI4/%d)",
|
||||
__func__, &ei->p.prefix, ei->p.prefixlen,
|
||||
&aggr->p.prefix, aggr->p.prefixlen);
|
||||
hash_get(aggr->match_extnl_hash, ei, hash_alloc_intern);
|
||||
ei->aggr_route = aggr;
|
||||
}
|
||||
|
||||
struct ospf_lsa *ospf_originate_summary_lsa(struct ospf *ospf,
|
||||
struct ospf_external_aggr_rt *aggr,
|
||||
struct external_info *ei)
|
||||
{
|
||||
struct ospf_lsa *lsa;
|
||||
struct external_info ei_aggr;
|
||||
struct as_external_lsa *asel;
|
||||
struct ospf_external_aggr_rt *old_aggr;
|
||||
route_tag_t tag = 0;
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Prepare to originate Summary route(%pI4/%d)",
|
||||
__func__, &aggr->p.prefix, aggr->p.prefixlen);
|
||||
|
||||
/* This case to handle when the overlapping aggregator address
|
||||
* is availbe.Best match will be considered.So need to delink
|
||||
* from old aggregator and link to the new aggr.
|
||||
*/
|
||||
if (ei->aggr_route) {
|
||||
if (ei->aggr_route != aggr) {
|
||||
old_aggr = ei->aggr_route;
|
||||
ospf_unlink_ei_from_aggr(ospf, old_aggr, ei);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the external route to hash table */
|
||||
ospf_link_ei_to_aggr(aggr, ei);
|
||||
|
||||
lsa = ospf_external_info_find_lsa(ospf, &aggr->p);
|
||||
/* Dont originate external LSA,
|
||||
* If it is configured not to advertise.
|
||||
*/
|
||||
if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE)) {
|
||||
/* If it is already originated as external LSA,
|
||||
* But, it is configured not to advertise then
|
||||
* flush the originated external lsa.
|
||||
*/
|
||||
if (lsa)
|
||||
ospf_external_lsa_flush(ospf, 0, &aggr->p, 0);
|
||||
UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: Don't originate the summary address,It is configured to not-advertise.",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Prepare the extrenal_info for aggregator */
|
||||
memset(&ei_aggr, 0, sizeof(struct external_info));
|
||||
ei_aggr.p = aggr->p;
|
||||
ei_aggr.tag = aggr->tag;
|
||||
ei_aggr.type = 0;
|
||||
ei_aggr.instance = ospf->instance;
|
||||
ei_aggr.route_map_set.metric = -1;
|
||||
ei_aggr.route_map_set.metric_type = -1;
|
||||
|
||||
/* Summary route already originated,
|
||||
* So, Do nothing.
|
||||
*/
|
||||
if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
|
||||
if (!lsa) {
|
||||
flog_warn(EC_OSPF_LSA_MISSING,
|
||||
"%s: Could not refresh/originate %pI4/%d",
|
||||
__func__, &aggr->p.prefix, aggr->p.prefixlen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
asel = (struct as_external_lsa *)lsa->data;
|
||||
tag = (unsigned long)ntohl(asel->e[0].route_tag);
|
||||
|
||||
/* If tag modified , then re-originate the route
|
||||
* with modified tag details.
|
||||
*/
|
||||
if (tag != ei_aggr.tag) {
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
|
||||
__func__, tag, ei_aggr.tag,
|
||||
&aggr->p.prefix, aggr->p.prefixlen);
|
||||
|
||||
ospf_external_lsa_refresh(ospf, lsa, &ei_aggr,
|
||||
LSA_REFRESH_FORCE, 1);
|
||||
}
|
||||
return lsa;
|
||||
}
|
||||
|
||||
if (lsa && IS_LSA_MAXAGE(lsa)) {
|
||||
/* This is special case.
|
||||
* If a summary route need to be originated but where
|
||||
* summary route already exist in lsdb with maxage, then
|
||||
* it need to be refreshed.
|
||||
*/
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: LSA is in MAX-AGE so refreshing LSA(%pI4/%d)",
|
||||
__PRETTY_FUNCTION__, &aggr->p.prefix,
|
||||
aggr->p.prefixlen);
|
||||
|
||||
ospf_external_lsa_refresh(ospf, lsa, &ei_aggr,
|
||||
LSA_REFRESH_FORCE, 1);
|
||||
SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
|
||||
return lsa;
|
||||
}
|
||||
|
||||
/* If the external route prefix same as aggregate route
|
||||
* and if external route is already originated as TYPE-5
|
||||
* then it need to be refreshed and originate bit should
|
||||
* be set.
|
||||
*/
|
||||
if (lsa && prefix_same((struct prefix *)&ei_aggr.p,
|
||||
(struct prefix *)&ei->p)) {
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: External route prefix is same as aggr so refreshing LSA(%pI4/%d)",
|
||||
__PRETTY_FUNCTION__, &aggr->p.prefix,
|
||||
aggr->p.prefixlen);
|
||||
ospf_external_lsa_refresh(ospf, lsa, &ei_aggr,
|
||||
LSA_REFRESH_FORCE, 1);
|
||||
SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
|
||||
return lsa;
|
||||
}
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Originate Summary route(%pI4/%d)", __func__,
|
||||
&aggr->p.prefix, aggr->p.prefixlen);
|
||||
|
||||
/* Originate summary LSA */
|
||||
lsa = ospf_external_lsa_originate(ospf, &ei_aggr);
|
||||
if (lsa) {
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Set the origination bit for aggregator",
|
||||
__func__);
|
||||
SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
|
||||
}
|
||||
|
||||
return lsa;
|
||||
}
|
||||
void ospf_unset_all_aggr_flag(struct ospf *ospf)
|
||||
{
|
||||
struct route_node *rn = NULL;
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("Unset the origination bit for all aggregator");
|
||||
|
||||
for (rn = route_top(ospf->rt_aggr_tbl); rn; rn = route_next(rn)) {
|
||||
if (!rn->info)
|
||||
continue;
|
||||
|
||||
struct ospf_external_aggr_rt *aggr = rn->info;
|
||||
|
||||
UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ospf_delete_all_marked_aggregators(struct ospf *ospf)
|
||||
{
|
||||
struct route_node *rn = NULL;
|
||||
|
||||
/* Loop through all the aggregators, Delete all aggregators
|
||||
* which are marked as DELETE. Set action to NONE for remaining
|
||||
* aggregators
|
||||
*/
|
||||
for (rn = route_top(ospf->rt_aggr_tbl); rn; rn = route_next(rn)) {
|
||||
if (!rn->info)
|
||||
continue;
|
||||
|
||||
struct ospf_external_aggr_rt *aggr = rn->info;
|
||||
|
||||
if (aggr->action != OSPF_ROUTE_AGGR_DEL) {
|
||||
aggr->action = OSPF_ROUTE_AGGR_NONE;
|
||||
continue;
|
||||
}
|
||||
ospf_external_aggr_delete(ospf, rn);
|
||||
ospf_external_aggregator_free(aggr);
|
||||
}
|
||||
}
|
||||
|
||||
static void ospf_handle_aggregated_exnl_rt(struct ospf *ospf,
|
||||
struct ospf_external_aggr_rt *aggr,
|
||||
struct external_info *ei)
|
||||
{
|
||||
struct ospf_lsa *lsa;
|
||||
struct as_external_lsa *al;
|
||||
struct in_addr mask;
|
||||
|
||||
/* Handling the case where the external route prefix
|
||||
* and aggregate prefix is same
|
||||
* If same dont flush the originated external LSA.
|
||||
*/
|
||||
if (prefix_same((struct prefix *)&aggr->p, (struct prefix *)&ei->p)) {
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: External Route prefix same as Aggregator(%pI4/%d), so dont flush.",
|
||||
__func__, &ei->p.prefix, ei->p.prefixlen);
|
||||
return;
|
||||
}
|
||||
|
||||
lsa = ospf_external_info_find_lsa(ospf, &ei->p);
|
||||
if (lsa) {
|
||||
al = (struct as_external_lsa *)lsa->data;
|
||||
masklen2ip(ei->p.prefixlen, &mask);
|
||||
|
||||
if (mask.s_addr != al->mask.s_addr)
|
||||
return;
|
||||
|
||||
ospf_external_lsa_flush(ospf, ei->type, &ei->p, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void ospf_handle_exnl_rt_after_aggr_del(struct ospf *ospf,
|
||||
struct external_info *ei)
|
||||
{
|
||||
struct ospf_lsa *lsa;
|
||||
|
||||
/* Process only marked external routes.
|
||||
* These routes were part of a deleted
|
||||
* aggregator.So, originate now.
|
||||
*/
|
||||
if (!ei->to_be_processed)
|
||||
return;
|
||||
|
||||
ei->to_be_processed = false;
|
||||
|
||||
lsa = ospf_external_info_find_lsa(ospf, &ei->p);
|
||||
|
||||
if (lsa)
|
||||
ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE, 0);
|
||||
else {
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Originate external route(%pI4/%d)",
|
||||
__func__, &ei->p.prefix, ei->p.prefixlen);
|
||||
|
||||
ospf_external_lsa_originate(ospf, ei);
|
||||
}
|
||||
}
|
||||
|
||||
static void ospf_handle_external_aggr_add(struct ospf *ospf)
|
||||
{
|
||||
struct external_info *ei;
|
||||
struct route_node *rn = NULL;
|
||||
struct route_table *rt = NULL;
|
||||
int type = 0;
|
||||
|
||||
/* Delete all the aggregators which are marked as
|
||||
* OSPF_ROUTE_AGGR_DEL.
|
||||
*/
|
||||
ospf_delete_all_marked_aggregators(ospf);
|
||||
|
||||
for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
|
||||
struct list *ext_list;
|
||||
struct listnode *node;
|
||||
struct ospf_external *ext;
|
||||
struct ospf_external_aggr_rt *aggr;
|
||||
|
||||
ext_list = ospf->external[type];
|
||||
if (!ext_list)
|
||||
continue;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) {
|
||||
rt = ext->external_info;
|
||||
if (!rt)
|
||||
continue;
|
||||
|
||||
for (rn = route_top(rt); rn; rn = route_next(rn)) {
|
||||
if (!rn->info)
|
||||
continue;
|
||||
|
||||
ei = rn->info;
|
||||
if (is_prefix_default(&ei->p))
|
||||
continue;
|
||||
|
||||
/* Check the AS-external-LSA
|
||||
* should be originated.
|
||||
*/
|
||||
if (!ospf_redistribute_check(ospf, ei, NULL))
|
||||
continue;
|
||||
|
||||
aggr = ospf_external_aggr_match(ospf, &ei->p);
|
||||
|
||||
/* If matching aggregator found, Add
|
||||
* the external route reference to the
|
||||
* aggregator and originate the aggr
|
||||
* route if it is advertisable.
|
||||
* flush the external LSA if it is
|
||||
* already originated for this external
|
||||
* prefix.
|
||||
*/
|
||||
if (aggr) {
|
||||
ospf_originate_summary_lsa(ospf, aggr,
|
||||
ei);
|
||||
|
||||
/* All aggregated external rts
|
||||
* are handled here.
|
||||
*/
|
||||
ospf_handle_aggregated_exnl_rt(
|
||||
ospf, aggr, ei);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* External routes which are only out
|
||||
* of aggregation will be handled here.
|
||||
*/
|
||||
ospf_handle_exnl_rt_after_aggr_del(ospf, ei);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ospf_aggr_handle_advertise_change(struct ospf *ospf,
|
||||
struct ospf_external_aggr_rt *aggr,
|
||||
struct external_info *ei_aggr)
|
||||
{
|
||||
struct ospf_lsa *lsa;
|
||||
|
||||
/* Check if advertise option modified. */
|
||||
if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE)) {
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: Don't originate the summary address,It is configured to not-advertise.",
|
||||
__func__);
|
||||
|
||||
if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: No-advertise,So Flush the Aggregate route(%pI4/%d)",
|
||||
__func__, &aggr->p.prefix,
|
||||
aggr->p.prefixlen);
|
||||
|
||||
ospf_external_lsa_flush(ospf, 0, &aggr->p, 0);
|
||||
|
||||
UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Now it is advatisable", __func__);
|
||||
|
||||
lsa = ospf_external_info_find_lsa(ospf, &ei_aggr->p);
|
||||
if (lsa && IS_LSA_MAXAGE(lsa)) {
|
||||
/* This is special case.
|
||||
* If a summary route need to be originated but where
|
||||
* summary route already exist in lsdb with maxage, then
|
||||
* it need to be refreshed.
|
||||
*/
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: It is already with Maxage, So refresh it (%pI4/%d)",
|
||||
__func__, &aggr->p.prefix,
|
||||
aggr->p.prefixlen);
|
||||
|
||||
ospf_external_lsa_refresh(ospf, lsa, ei_aggr,
|
||||
LSA_REFRESH_FORCE, 1);
|
||||
|
||||
SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
|
||||
|
||||
} else {
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: Originate Aggregate LSA (%pI4/%d)",
|
||||
__func__, &aggr->p.prefix,
|
||||
aggr->p.prefixlen);
|
||||
|
||||
/* Originate summary LSA */
|
||||
lsa = ospf_external_lsa_originate(ospf, ei_aggr);
|
||||
if (lsa)
|
||||
SET_FLAG(aggr->flags,
|
||||
OSPF_EXTERNAL_AGGRT_ORIGINATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ospf_handle_external_aggr_update(struct ospf *ospf)
|
||||
{
|
||||
struct route_node *rn = NULL;
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Process modified aggregators.\n", __func__);
|
||||
|
||||
for (rn = route_top(ospf->rt_aggr_tbl); rn; rn = route_next(rn)) {
|
||||
struct ospf_external_aggr_rt *aggr;
|
||||
struct ospf_lsa *lsa = NULL;
|
||||
struct as_external_lsa *asel = NULL;
|
||||
struct external_info ei_aggr;
|
||||
route_tag_t tag = 0;
|
||||
|
||||
if (!rn->info)
|
||||
continue;
|
||||
|
||||
aggr = rn->info;
|
||||
|
||||
if (aggr->action == OSPF_ROUTE_AGGR_DEL) {
|
||||
aggr->action = OSPF_ROUTE_AGGR_NONE;
|
||||
ospf_external_aggr_delete(ospf, rn);
|
||||
|
||||
if (OSPF_EXTERNAL_RT_COUNT(aggr))
|
||||
hash_clean(
|
||||
aggr->match_extnl_hash,
|
||||
(void *)ospf_aggr_handle_external_info);
|
||||
|
||||
hash_free(aggr->match_extnl_hash);
|
||||
XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR, aggr);
|
||||
|
||||
} else if (aggr->action == OSPF_ROUTE_AGGR_MODIFY) {
|
||||
|
||||
aggr->action = OSPF_ROUTE_AGGR_NONE;
|
||||
|
||||
/* Prepare the extrenal_info for aggregator */
|
||||
memset(&ei_aggr, 0, sizeof(struct external_info));
|
||||
ei_aggr.p = aggr->p;
|
||||
ei_aggr.tag = aggr->tag;
|
||||
ei_aggr.type = 0;
|
||||
ei_aggr.instance = ospf->instance;
|
||||
ei_aggr.route_map_set.metric = -1;
|
||||
ei_aggr.route_map_set.metric_type = -1;
|
||||
|
||||
/* Check if tag modified */
|
||||
if (CHECK_FLAG(aggr->flags,
|
||||
OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
|
||||
lsa = ospf_external_info_find_lsa(ospf,
|
||||
&ei_aggr.p);
|
||||
if (!lsa) {
|
||||
flog_warn(EC_OSPF_LSA_MISSING,
|
||||
"%s: Could not refresh/originate %pI4/%d",
|
||||
__func__, &aggr->p.prefix,
|
||||
aggr->p.prefixlen);
|
||||
continue;
|
||||
}
|
||||
|
||||
asel = (struct as_external_lsa *)lsa->data;
|
||||
tag = (unsigned long)ntohl(
|
||||
asel->e[0].route_tag);
|
||||
|
||||
/* If tag modified , then re-originate the
|
||||
* route with modified tag details.
|
||||
*/
|
||||
if (tag != ei_aggr.tag) {
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
|
||||
__func__, tag,
|
||||
ei_aggr.tag,
|
||||
&aggr->p.prefix,
|
||||
aggr->p.prefixlen);
|
||||
|
||||
ospf_external_lsa_refresh(
|
||||
ospf, lsa, &ei_aggr,
|
||||
LSA_REFRESH_FORCE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Advertise option modified ?
|
||||
* If so, handled it here.
|
||||
*/
|
||||
ospf_aggr_handle_advertise_change(ospf, aggr, &ei_aggr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ospf_asbr_external_aggr_process(struct thread *thread)
|
||||
{
|
||||
struct ospf *ospf = THREAD_ARG(thread);
|
||||
int operation = 0;
|
||||
|
||||
ospf->t_external_aggr = NULL;
|
||||
operation = ospf->aggr_action;
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: operation:%d\n", __func__, operation);
|
||||
|
||||
switch (operation) {
|
||||
case OSPF_ROUTE_AGGR_ADD:
|
||||
ospf_handle_external_aggr_add(ospf);
|
||||
break;
|
||||
case OSPF_ROUTE_AGGR_DEL:
|
||||
case OSPF_ROUTE_AGGR_MODIFY:
|
||||
ospf_handle_external_aggr_update(ospf);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return OSPF_SUCCESS;
|
||||
}
|
||||
static void ospf_external_aggr_timer(struct ospf *ospf,
|
||||
struct ospf_external_aggr_rt *aggr,
|
||||
enum ospf_aggr_action_t operation)
|
||||
{
|
||||
aggr->action = operation;
|
||||
|
||||
if (ospf->t_external_aggr) {
|
||||
if (ospf->aggr_action == OSPF_ROUTE_AGGR_ADD) {
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s: Not required to retsart timer,set is already added.",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (operation == OSPF_ROUTE_AGGR_ADD) {
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug(
|
||||
"%s, Restarting Aggregator delay timer.",
|
||||
__func__);
|
||||
THREAD_OFF(ospf->t_external_aggr);
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
|
||||
zlog_debug("%s: Start Aggregator delay timer %d(in seconds).",
|
||||
__func__, ospf->aggr_delay_interval);
|
||||
|
||||
ospf->aggr_action = operation;
|
||||
thread_add_timer(master, ospf_asbr_external_aggr_process, ospf,
|
||||
ospf->aggr_delay_interval, &ospf->t_external_aggr);
|
||||
}
|
||||
|
@ -134,4 +134,23 @@ extern struct ospf_lsa *ospf_external_info_find_lsa(struct ospf *,
|
||||
extern void ospf_asbr_external_aggregator_init(struct ospf *instance);
|
||||
|
||||
extern void ospf_external_aggregator_free(struct ospf_external_aggr_rt *aggr);
|
||||
extern struct ospf_external_aggr_rt *
|
||||
ospf_external_aggr_match(struct ospf *ospf, struct prefix_ipv4 *p);
|
||||
|
||||
extern void ospf_unlink_ei_from_aggr(struct ospf *ospf,
|
||||
struct ospf_external_aggr_rt *aggr,
|
||||
struct external_info *ei);
|
||||
|
||||
extern struct ospf_lsa *
|
||||
ospf_originate_summary_lsa(struct ospf *ospf,
|
||||
struct ospf_external_aggr_rt *aggr,
|
||||
struct external_info *ei);
|
||||
extern int ospf_external_aggregator_timer_set(struct ospf *ospf,
|
||||
unsigned int interval);
|
||||
extern void ospf_external_aggrigator_free(struct ospf_external_aggr_rt *aggr);
|
||||
|
||||
extern struct ospf_external_aggr_rt *
|
||||
ospf_extrenal_aggregator_lookup(struct ospf *ospf, struct prefix_ipv4 *p);
|
||||
|
||||
void ospf_unset_all_aggr_flag(struct ospf *ospf);
|
||||
#endif /* _ZEBRA_OSPF_ASBR_H */
|
||||
|
@ -225,7 +225,7 @@ static void ospf_process_self_originated_lsa(struct ospf *ospf,
|
||||
ei = ospf_external_info_check(ospf, new);
|
||||
if (ei)
|
||||
ospf_external_lsa_refresh(ospf, new, ei,
|
||||
LSA_REFRESH_FORCE);
|
||||
LSA_REFRESH_FORCE, false);
|
||||
else
|
||||
ospf_lsa_flush_as(ospf, new);
|
||||
break;
|
||||
|
@ -2191,8 +2191,9 @@ void ospf_external_lsa_refresh_default(struct ospf *ospf)
|
||||
if (ei && lsa) {
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p",
|
||||
(void *)lsa);
|
||||
ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE);
|
||||
(void *)lsa);
|
||||
ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE,
|
||||
false);
|
||||
} else if (ei && !lsa) {
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug(
|
||||
@ -2230,7 +2231,8 @@ void ospf_external_lsa_refresh_type(struct ospf *ospf, uint8_t type,
|
||||
ospf, &ei->p);
|
||||
if (lsa)
|
||||
ospf_external_lsa_refresh(
|
||||
ospf, lsa, ei, force);
|
||||
ospf, lsa, ei, force,
|
||||
false);
|
||||
else
|
||||
ospf_external_lsa_originate(
|
||||
ospf, ei);
|
||||
@ -2243,21 +2245,25 @@ void ospf_external_lsa_refresh_type(struct ospf *ospf, uint8_t type,
|
||||
/* Refresh AS-external-LSA. */
|
||||
struct ospf_lsa *ospf_external_lsa_refresh(struct ospf *ospf,
|
||||
struct ospf_lsa *lsa,
|
||||
struct external_info *ei, int force)
|
||||
struct external_info *ei, int force,
|
||||
bool is_aggr)
|
||||
{
|
||||
struct ospf_lsa *new;
|
||||
int changed;
|
||||
int changed = 0;
|
||||
|
||||
/* Check the AS-external-LSA should be originated. */
|
||||
if (!ospf_redistribute_check(ospf, ei, &changed)) {
|
||||
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
|
||||
zlog_debug(
|
||||
"LSA[Type%d:%pI4]: Could not be refreshed, redist check fail",
|
||||
lsa->data->type, &lsa->data->id);
|
||||
ospf_external_lsa_flush(ospf, ei->type, &ei->p,
|
||||
ei->ifindex /*, ei->nexthop */);
|
||||
return NULL;
|
||||
}
|
||||
if (!is_aggr)
|
||||
if (!ospf_redistribute_check(ospf, ei, &changed)) {
|
||||
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
|
||||
zlog_debug(
|
||||
"LSA[Type%d:%s] Could not be refreshed, redist check fail",
|
||||
lsa->data->type,
|
||||
inet_ntoa(lsa->data->id));
|
||||
|
||||
ospf_external_lsa_flush(ospf, ei->type, &ei->p,
|
||||
ei->ifindex /*, ei->nexthop */);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!changed && !force) {
|
||||
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
|
||||
@ -3474,8 +3480,8 @@ struct ospf_lsa *ospf_lsa_refresh(struct ospf *ospf, struct ospf_lsa *lsa)
|
||||
break;
|
||||
ei = ospf_external_info_check(ospf, lsa);
|
||||
if (ei)
|
||||
new = ospf_external_lsa_refresh(ospf, lsa, ei,
|
||||
LSA_REFRESH_FORCE);
|
||||
new = ospf_external_lsa_refresh(
|
||||
ospf, lsa, ei, LSA_REFRESH_FORCE, false);
|
||||
else
|
||||
ospf_lsa_flush_as(ospf, lsa);
|
||||
break;
|
||||
|
@ -313,7 +313,8 @@ extern void ospf_external_lsa_refresh_type(struct ospf *, uint8_t,
|
||||
unsigned short, int);
|
||||
extern struct ospf_lsa *ospf_external_lsa_refresh(struct ospf *,
|
||||
struct ospf_lsa *,
|
||||
struct external_info *, int);
|
||||
struct external_info *, int,
|
||||
bool aggr);
|
||||
extern struct in_addr ospf_lsa_unique_id(struct ospf *, struct ospf_lsdb *,
|
||||
uint8_t, struct prefix_ipv4 *);
|
||||
extern void ospf_schedule_lsa_flood_area(struct ospf_area *, struct ospf_lsa *);
|
||||
|
@ -463,7 +463,7 @@ static int ospf_external_lsa_default_routemap_timer(struct thread *thread)
|
||||
if (ret && !lsa)
|
||||
ospf_external_lsa_originate(ospf, default_ei);
|
||||
else if (ret && lsa && IS_LSA_MAXAGE(lsa))
|
||||
ospf_external_lsa_refresh(ospf, lsa, default_ei, true);
|
||||
ospf_external_lsa_refresh(ospf, lsa, default_ei, true, false);
|
||||
else if (!ret && lsa)
|
||||
ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &default_ei->p, 0);
|
||||
|
||||
@ -973,7 +973,8 @@ static bool ospf_external_lsa_default_routemap_apply(struct ospf *ospf,
|
||||
|
||||
if (lsa && IS_LSA_MAXAGE(lsa))
|
||||
/* Refresh lsa.*/
|
||||
ospf_external_lsa_refresh(ospf, lsa, default_ei, true);
|
||||
ospf_external_lsa_refresh(ospf, lsa, default_ei, true,
|
||||
false);
|
||||
else
|
||||
/* If permit and default not advertised then advertise.
|
||||
*/
|
||||
@ -1196,7 +1197,8 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS)
|
||||
&p.prefix);
|
||||
ospf_external_lsa_refresh(
|
||||
ospf, current, ei,
|
||||
LSA_REFRESH_FORCE);
|
||||
LSA_REFRESH_FORCE,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1338,7 +1340,7 @@ static int ospf_distribute_list_update_timer(struct thread *thread)
|
||||
force = LSA_REFRESH_FORCE;
|
||||
|
||||
ospf_external_lsa_refresh(
|
||||
ospf, lsa, ei, force);
|
||||
ospf, lsa, ei, force, false);
|
||||
} else
|
||||
ospf_external_lsa_originate(
|
||||
ospf, ei);
|
||||
|
Loading…
Reference in New Issue
Block a user