diff options
| author | Donald Sharp <sharpd@cumulusnetworks.com> | 2019-03-01 09:54:10 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-03-01 09:54:10 -0500 | 
| commit | 3d47101da770d1f05770c2733ae26cf312483168 (patch) | |
| tree | 35c0fec22ac76c1a686fb19abba20fa053a0d8b6 /bgpd/bgp_aspath.c | |
| parent | 1c628520307cee621fb864496b57ddaff5bc6300 (diff) | |
| parent | fc96884124d73c9b1374d48d783579328f5ec26d (diff) | |
Merge pull request #3743 from NaveenThanikachalam/2990_New
bgpd: Address performance issues in BGP route aggregation.
Diffstat (limited to 'bgpd/bgp_aspath.c')
| -rw-r--r-- | bgpd/bgp_aspath.c | 116 | 
1 files changed, 114 insertions, 2 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 51833394d9..3bd3de031c 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -212,6 +212,9 @@ static struct assegment *assegment_append_asns(struct assegment *seg,  {  	as_t *newas; +	if (!seg) +		return seg; +  	newas = XREALLOC(MTYPE_AS_SEG_DATA, seg->as,  			 ASSEGMENT_DATA_SIZE(seg->length + num, 1)); @@ -1372,7 +1375,8 @@ static struct aspath *aspath_merge(struct aspath *as1, struct aspath *as2)  	while (last && last->next)  		last = last->next; -	last->next = as2->segments; +	if (last) +		last->next = as2->segments;  	as2->segments = new;  	aspath_str_update(as2, false);  	return as2; @@ -1447,7 +1451,8 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)  		 * bypass the merged seg2, and attach any chain after it  		 * to chain descending from as2's head  		 */ -		as2segtail->next = as2seghead->next; +		if (as2segtail) +			as2segtail->next = as2seghead->next;  		/* as2->segments is now referenceless and useless */  		assegment_free(as2seghead); @@ -2096,3 +2101,110 @@ void aspath_print_all_vty(struct vty *vty)  				       void *))aspath_show_all_iterator,  		     vty);  } + +static struct aspath *bgp_aggr_aspath_lookup(struct bgp_aggregate *aggregate, +					     struct aspath *aspath) +{ +	return hash_lookup(aggregate->aspath_hash, aspath); +} + +static void *bgp_aggr_aspath_hash_alloc(void *p) +{ +	struct aspath *ref = (struct aspath *)p; +	struct aspath *aspath = NULL; + +	aspath = aspath_dup(ref); +	return aspath; +} + +static void bgp_aggr_aspath_prepare(struct hash_backet *hb, void *arg) +{ +	struct aspath *asmerge = NULL; +	struct aspath *hb_aspath = hb->data; +	struct aspath **aggr_aspath = arg; + +	if (*aggr_aspath) { +		asmerge = aspath_aggregate(*aggr_aspath, hb_aspath); +		aspath_free(*aggr_aspath); +		*aggr_aspath = asmerge; +	} else +		*aggr_aspath = aspath_dup(hb_aspath); +} + +void bgp_aggr_aspath_remove(void *arg) +{ +	struct aspath *aspath = arg; + +	aspath_free(aspath); +} + +void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, +				  struct aspath *aspath) +{ +	struct aspath *aggr_aspath = NULL; + +	if ((aggregate == NULL) || (aspath == NULL)) +		return; + +	/* Create hash if not already created. +	 */ +	if (aggregate->aspath_hash == NULL) +		aggregate->aspath_hash = hash_create( +					aspath_key_make, aspath_cmp, +					"BGP Aggregator as-path hash"); + +	aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath); +	if (aggr_aspath == NULL) { +		/* Insert as-path into hash. +		 */ +		aggr_aspath = hash_get(aggregate->aspath_hash, aspath, +				       bgp_aggr_aspath_hash_alloc); + +		/* Compute aggregate's as-path. +		 */ +		hash_iterate(aggregate->aspath_hash, +			     bgp_aggr_aspath_prepare, +			     &aggregate->aspath); +	} + +	/* Increment refernce counter. +	 */ +	aggr_aspath->refcnt++; +} + +void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, +				      struct aspath *aspath) +{ +	struct aspath *aggr_aspath = NULL; +	struct aspath *ret_aspath = NULL; + +	if ((aggregate == NULL) || (aspath == NULL)) +		return; + +	if (aggregate->aspath_hash == NULL) +		return; + +	/* Look-up the aspath in the hash. +	 */ +	aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath); +	if (aggr_aspath) { +		aggr_aspath->refcnt--; + +		if (aggr_aspath->refcnt == 0) { +			ret_aspath = hash_release(aggregate->aspath_hash, +						  aggr_aspath); +			aspath_free(ret_aspath); + +			/* Remove aggregate's old as-path. +			 */ +			aspath_free(aggregate->aspath); +			aggregate->aspath = NULL; + +			/* Compute aggregate's as-path. +			 */ +			hash_iterate(aggregate->aspath_hash, +				     bgp_aggr_aspath_prepare, +				     &aggregate->aspath); +		} +	} +}  | 
