diff options
| -rw-r--r-- | bgpd/bgp_lcommunity.c | 88 | ||||
| -rw-r--r-- | bgpd/bgp_lcommunity.h | 10 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 12 |
3 files changed, 84 insertions, 26 deletions
diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index aeb290719a..3243ce96b5 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -555,15 +555,13 @@ static void *bgp_aggr_lcommunty_hash_alloc(void *p) static void bgp_aggr_lcommunity_prepare(struct hash_backet *hb, void *arg) { - struct lcommunity *lcommerge = NULL; struct lcommunity *hb_lcommunity = hb->data; struct lcommunity **aggr_lcommunity = arg; - if (*aggr_lcommunity) { - lcommerge = lcommunity_merge(*aggr_lcommunity, hb_lcommunity); - *aggr_lcommunity = lcommunity_uniq_sort(lcommerge); - lcommunity_free(&lcommerge); - } else + if (*aggr_lcommunity) + *aggr_lcommunity = lcommunity_merge(*aggr_lcommunity, + hb_lcommunity); + else *aggr_lcommunity = lcommunity_dup(hb_lcommunity); } @@ -577,6 +575,15 @@ void bgp_aggr_lcommunity_remove(void *arg) void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate, struct lcommunity *lcommunity) { + + bgp_compute_aggregate_lcommunity_hash(aggregate, lcommunity); + bgp_compute_aggregate_lcommunity_val(aggregate); +} + +void bgp_compute_aggregate_lcommunity_hash(struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + struct lcommunity *aggr_lcommunity = NULL; if ((aggregate == NULL) || (lcommunity == NULL)) @@ -596,20 +603,34 @@ void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate, aggr_lcommunity = hash_get(aggregate->lcommunity_hash, lcommunity, bgp_aggr_lcommunty_hash_alloc); + } - /* Re-compute aggregate's lcommunity. - */ - if (aggregate->lcommunity) - lcommunity_free(&aggregate->lcommunity); + /* Increment reference counter. + */ + aggr_lcommunity->refcnt++; +} + +void bgp_compute_aggregate_lcommunity_val(struct bgp_aggregate *aggregate) +{ + struct lcommunity *lcommerge = NULL; + + if (aggregate == NULL) + return; + /* Re-compute aggregate's lcommunity. + */ + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + if (aggregate->lcommunity_hash && + aggregate->lcommunity_hash->count) { hash_iterate(aggregate->lcommunity_hash, bgp_aggr_lcommunity_prepare, &aggregate->lcommunity); + lcommerge = aggregate->lcommunity; + aggregate->lcommunity = lcommunity_uniq_sort(lcommerge); + if (lcommerge) + lcommunity_free(&lcommerge); } - - /* Increment refernce counter. - */ - aggr_lcommunity->refcnt++; } void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate, @@ -618,10 +639,9 @@ void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate, struct lcommunity *aggr_lcommunity = NULL; struct lcommunity *ret_lcomm = NULL; - if ((aggregate == NULL) || (lcommunity == NULL)) - return; - - if (aggregate->lcommunity_hash == NULL) + if ((!aggregate) + || (!aggregate->lcommunity_hash) + || (!lcommunity)) return; /* Look-up the lcommunity in the hash. @@ -635,13 +655,33 @@ void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate, aggr_lcommunity); lcommunity_free(&ret_lcomm); - lcommunity_free(&aggregate->lcommunity); + bgp_compute_aggregate_lcommunity_val(aggregate); + + } + } +} + +void bgp_remove_lcomm_from_aggregate_hash(struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + struct lcommunity *aggr_lcommunity = NULL; + struct lcommunity *ret_lcomm = NULL; - /* Compute aggregate's lcommunity. - */ - hash_iterate(aggregate->lcommunity_hash, - bgp_aggr_lcommunity_prepare, - &aggregate->lcommunity); + if ((!aggregate) + || (!aggregate->lcommunity_hash) + || (!lcommunity)) + return; + + /* Look-up the lcommunity in the hash. + */ + aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity); + if (aggr_lcommunity) { + aggr_lcommunity->refcnt--; + + if (aggr_lcommunity->refcnt == 0) { + ret_lcomm = hash_release(aggregate->lcommunity_hash, + aggr_lcommunity); + lcommunity_free(&ret_lcomm); } } } diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h index a512395492..7d63f4d26a 100644 --- a/bgpd/bgp_lcommunity.h +++ b/bgpd/bgp_lcommunity.h @@ -75,9 +75,19 @@ extern void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr); extern void bgp_compute_aggregate_lcommunity( struct bgp_aggregate *aggregate, struct lcommunity *lcommunity); + +extern void bgp_compute_aggregate_lcommunity_hash( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity); +extern void bgp_compute_aggregate_lcommunity_val( + struct bgp_aggregate *aggregate); + extern void bgp_remove_lcommunity_from_aggregate( struct bgp_aggregate *aggregate, struct lcommunity *lcommunity); +extern void bgp_remove_lcomm_from_aggregate_hash( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity); extern void bgp_aggr_lcommunity_remove(void *arg); #endif /* _QUAGGA_BGP_LCOMMUNITY_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 05974bb2ba..be13d3bcad 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5947,13 +5947,16 @@ void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, /* Compute aggregate route's large community. */ if (pi->attr->lcommunity) - bgp_compute_aggregate_lcommunity( + bgp_compute_aggregate_lcommunity_hash( aggregate, pi->attr->lcommunity); } if (match) bgp_process(bgp, rn, afi, safi); } + if (aggregate->as_set) + bgp_compute_aggregate_lcommunity_val(aggregate); + bgp_unlock_node(top); @@ -6055,7 +6058,7 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, if (pi->attr->lcommunity) /* Remove lcommunity from aggregate. */ - bgp_remove_lcommunity_from_aggregate( + bgp_remove_lcomm_from_aggregate_hash( aggregate, pi->attr->lcommunity); } @@ -6066,6 +6069,11 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, if (match) bgp_process(bgp, rn, afi, safi); } + if (aggregate->as_set) { + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + } + bgp_unlock_node(top); } |
