From 4edd83f91b545f7b862b5bdccf45c85769ceafd5 Mon Sep 17 00:00:00 2001 From: vdhingra Date: Mon, 19 Aug 2019 00:50:15 -0700 Subject: [PATCH] bgpd : route agg. with ecomm attribute is consuming lot of cycles. While configuring aggregate route prepare the hash table first, then prepare the aggregated ecomm value and then do the unique sort once for ecommunity. Signed-off-by: vishaldhingra --- bgpd/bgp_ecommunity.c | 86 +++++++++++++++++++++++++++++++------------ bgpd/bgp_ecommunity.h | 9 +++++ bgpd/bgp_route.c | 7 +++- 3 files changed, 76 insertions(+), 26 deletions(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 850b85aa6a..11f5a326df 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1042,15 +1042,13 @@ static void *bgp_aggr_ecommunty_hash_alloc(void *p) static void bgp_aggr_ecommunity_prepare(struct hash_backet *hb, void *arg) { - struct ecommunity *ecommerge = NULL; struct ecommunity *hb_ecommunity = hb->data; struct ecommunity **aggr_ecommunity = arg; - if (*aggr_ecommunity) { - ecommerge = ecommunity_merge(*aggr_ecommunity, hb_ecommunity); - *aggr_ecommunity = ecommunity_uniq_sort(ecommerge); - ecommunity_free(&ecommerge); - } else + if (*aggr_ecommunity) + *aggr_ecommunity = ecommunity_merge(*aggr_ecommunity, + hb_ecommunity); + else *aggr_ecommunity = ecommunity_dup(hb_ecommunity); } @@ -1063,6 +1061,14 @@ void bgp_aggr_ecommunity_remove(void *arg) void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate, struct ecommunity *ecommunity) +{ + bgp_compute_aggregate_ecommunity_hash(aggregate, ecommunity); + bgp_compute_aggregate_ecommunity_val(aggregate); +} + + +void bgp_compute_aggregate_ecommunity_hash(struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) { struct ecommunity *aggr_ecommunity = NULL; @@ -1083,20 +1089,34 @@ void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate, aggr_ecommunity = hash_get(aggregate->ecommunity_hash, ecommunity, bgp_aggr_ecommunty_hash_alloc); + } - /* Re-compute aggregate's ecommunity. - */ - if (aggregate->ecommunity) - ecommunity_free(&aggregate->ecommunity); + /* Increment reference counter. + */ + aggr_ecommunity->refcnt++; +} +void bgp_compute_aggregate_ecommunity_val(struct bgp_aggregate *aggregate) +{ + struct ecommunity *ecommerge = NULL; + + if (aggregate == NULL) + return; + + /* Re-compute aggregate's ecommunity. + */ + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); + if (aggregate->ecommunity_hash + && aggregate->ecommunity_hash->count) { hash_iterate(aggregate->ecommunity_hash, bgp_aggr_ecommunity_prepare, &aggregate->ecommunity); + ecommerge = aggregate->ecommunity; + aggregate->ecommunity = ecommunity_uniq_sort(ecommerge); + if (ecommerge) + ecommunity_free(&ecommerge); } - - /* Increment refernce counter. - */ - aggr_ecommunity->refcnt++; } void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate, @@ -1105,10 +1125,9 @@ void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate, struct ecommunity *aggr_ecommunity = NULL; struct ecommunity *ret_ecomm = NULL; - if ((aggregate == NULL) || (ecommunity == NULL)) - return; - - if (aggregate->ecommunity_hash == NULL) + if ((!aggregate) + || (!aggregate->ecommunity_hash) + || (!ecommunity)) return; /* Look-up the ecommunity in the hash. @@ -1121,14 +1140,33 @@ void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate, ret_ecomm = hash_release(aggregate->ecommunity_hash, aggr_ecommunity); ecommunity_free(&ret_ecomm); + bgp_compute_aggregate_ecommunity_val(aggregate); + } + } +} + +void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ + + struct ecommunity *aggr_ecommunity = NULL; + struct ecommunity *ret_ecomm = NULL; - ecommunity_free(&aggregate->ecommunity); + if ((!aggregate) + || (!aggregate->ecommunity_hash) + || (!ecommunity)) + return; - /* Compute aggregate's ecommunity. - */ - hash_iterate(aggregate->ecommunity_hash, - bgp_aggr_ecommunity_prepare, - &aggregate->ecommunity); + /* Look-up the ecommunity in the hash. + */ + aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity); + if (aggr_ecommunity) { + aggr_ecommunity->refcnt--; + + if (aggr_ecommunity->refcnt == 0) { + ret_ecomm = hash_release(aggregate->ecommunity_hash, + aggr_ecommunity); + ecommunity_free(&ret_ecomm); } } } diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 79be4ee422..249e5bf7de 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -190,9 +190,18 @@ extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, extern void bgp_compute_aggregate_ecommunity( struct bgp_aggregate *aggregate, struct ecommunity *ecommunity); + +extern void bgp_compute_aggregate_ecommunity_hash( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); +extern void bgp_compute_aggregate_ecommunity_val( + struct bgp_aggregate *aggregate); extern void bgp_remove_ecommunity_from_aggregate( struct bgp_aggregate *aggregate, struct ecommunity *ecommunity); +extern void bgp_remove_ecomm_from_aggregate_hash( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); extern void bgp_aggr_ecommunity_remove(void *arg); #endif /* _QUAGGA_BGP_ECOMMUNITY_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4236c6158e..e286beecfb 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5940,7 +5940,7 @@ void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, /* Compute aggregate route's extended community. */ if (pi->attr->ecommunity) - bgp_compute_aggregate_ecommunity( + bgp_compute_aggregate_ecommunity_hash( aggregate, pi->attr->ecommunity); @@ -5956,6 +5956,7 @@ void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, } if (aggregate->as_set) { bgp_compute_aggregate_community_val(aggregate); + bgp_compute_aggregate_ecommunity_val(aggregate); bgp_compute_aggregate_lcommunity_val(aggregate); } @@ -6054,7 +6055,7 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, if (pi->attr->ecommunity) /* Remove ecommunity from aggregate. */ - bgp_remove_ecommunity_from_aggregate( + bgp_remove_ecomm_from_aggregate_hash( aggregate, pi->attr->ecommunity); @@ -6075,6 +6076,8 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, if (aggregate->as_set) { if (aggregate->community) community_free(&aggregate->community); + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); if (aggregate->lcommunity) lcommunity_free(&aggregate->lcommunity); } -- 2.39.5