diff options
| author | Naveen Thanikachalam <nthanikachal@vmware.com> | 2019-02-06 06:28:18 -0800 | 
|---|---|---|
| committer | Naveen Thanikachalam <nthanikachal@vmware.com> | 2019-02-28 20:22:41 -0800 | 
| commit | c0d7a6ccb9c51fc81a807da19f9ac8b1e04a9a2e (patch) | |
| tree | b5dbde2b2e8a4ee5900582cf5a77b89e9b65e632 /bgpd/bgp_community.c | |
| parent | e00d800877ef7fc20b1887c2883e855dedcbb442 (diff) | |
bgpd: Code to handle BGP aggregate's communities.
With this commit:
1) The code to manage the communities attribute of the routes that are
   aggregatable under a configured aggregate-address is introduced.
2) The code to compute the aggregate-route's communities attribute is
   introduced.
Signed-off-by: NaveenThanikachalam <nthanikachal@vmware.com>
Diffstat (limited to 'bgpd/bgp_community.c')
| -rw-r--r-- | bgpd/bgp_community.c | 109 | 
1 files changed, 109 insertions, 0 deletions
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index 614e24ca4f..2e28c30950 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -910,3 +910,112 @@ void community_finish(void)  	hash_free(comhash);  	comhash = NULL;  } + +static struct community *bgp_aggr_community_lookup( +						struct bgp_aggregate *aggregate, +						struct community *community) +{ +	return hash_lookup(aggregate->community_hash, community); +} + +static void *bgp_aggr_communty_hash_alloc(void *p) +{ +	struct community *ref = (struct community *)p; +	struct community *community = NULL; + +	community = community_dup(ref); +	return community; +} + +static void bgp_aggr_community_prepare(struct hash_backet *hb, void *arg) +{ +	struct community *commerge = NULL; +	struct community *hb_community = hb->data; +	struct community **aggr_community = arg; + +	if (*aggr_community) { +		commerge = community_merge(*aggr_community, hb_community); +		*aggr_community = community_uniq_sort(commerge); +		community_free(&commerge); +	} else +		*aggr_community = community_dup(hb_community); +} + +void bgp_aggr_community_remove(void *arg) +{ +	struct community *community = arg; + +	community_free(&community); +} + +void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, +				     struct community *community) +{ +	struct community *aggr_community = NULL; + +	if ((aggregate == NULL) || (community == NULL)) +		return; + +	/* Create hash if not already created. +	 */ +	if (aggregate->community_hash == NULL) +		aggregate->community_hash = hash_create( +			(unsigned int (*)(void *))community_hash_make, +			(bool (*)(const void *, const void *))community_cmp, +			"BGP Aggregator community hash"); + +	aggr_community = bgp_aggr_community_lookup(aggregate, community); +	if (aggr_community == NULL) { +		/* Insert community into hash. +		 */ +		aggr_community = hash_get(aggregate->community_hash, community, +					  bgp_aggr_communty_hash_alloc); + +		/* Re-compute aggregate's community. +		 */ +		if (aggregate->community) +			community_free(&aggregate->community); + +		hash_iterate(aggregate->community_hash, +			     bgp_aggr_community_prepare, +			     &aggregate->community); +	} + +	/* Increment refernce counter. +	 */ +	aggr_community->refcnt++; +} + +void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, +					 struct community *community) +{ +	struct community *aggr_community = NULL; +	struct community *ret_comm = NULL; + +	if ((aggregate == NULL) || (community == NULL)) +		return; + +	if (aggregate->community_hash == NULL) +		return; + +	/* Look-up the community in the hash. +	 */ +	aggr_community = bgp_aggr_community_lookup(aggregate, community); +	if (aggr_community) { +		aggr_community->refcnt--; + +		if (aggr_community->refcnt == 0) { +			ret_comm = hash_release(aggregate->community_hash, +						aggr_community); +			community_free(&ret_comm); + +			community_free(&aggregate->community); + +			/* Compute aggregate's community. +			 */ +			hash_iterate(aggregate->community_hash, +				     bgp_aggr_community_prepare, +				     &aggregate->community); +		} +	} +}  | 
