summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_lcommunity.c88
-rw-r--r--bgpd/bgp_lcommunity.h10
-rw-r--r--bgpd/bgp_route.c12
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);
}