/* Allocate a new ecommunities. */
struct ecommunity *ecommunity_new(void)
{
- return (struct ecommunity *)XCALLOC(MTYPE_ECOMMUNITY,
- sizeof(struct ecommunity));
+ return XCALLOC(MTYPE_ECOMMUNITY, sizeof(struct ecommunity));
}
void ecommunity_strfree(char **s)
/* Allocate ecommunities. */
void ecommunity_free(struct ecommunity **ecom)
{
- if ((*ecom)->val)
- XFREE(MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
- if ((*ecom)->str)
- XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str);
+ XFREE(MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
+ XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str);
XFREE(MTYPE_ECOMMUNITY, *ecom);
}
}
/* Utinity function to make hash key. */
-unsigned int ecommunity_hash_make(void *arg)
+unsigned int ecommunity_hash_make(const void *arg)
{
const struct ecommunity *ecom = arg;
int size = ecom->size * ECOMMUNITY_SIZE;
/* Low-order octet of type. */
sub_type = *pnt++;
if (sub_type != ECOMMUNITY_ROUTE_TARGET
- && sub_type != ECOMMUNITY_SITE_ORIGIN)
- unk_ecom = 1;
- else
+ && sub_type != ECOMMUNITY_SITE_ORIGIN) {
+ if (sub_type ==
+ ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4 &&
+ type == ECOMMUNITY_ENCODE_IP) {
+ struct in_addr *ipv4 =
+ (struct in_addr *)pnt;
+ char ipv4str[INET_ADDRSTRLEN];
+
+ inet_ntop(AF_INET, ipv4,
+ ipv4str,
+ INET_ADDRSTRLEN);
+ len = sprintf(str_buf + str_pnt,
+ "NH:%s:%d",
+ ipv4str, pnt[5]);
+ } else
+ unk_ecom = 1;
+ } else
len = ecommunity_rt_soo_str(str_buf + str_pnt,
pnt, type, sub_type,
format);
return -1;
return 0;
}
+
+static struct ecommunity *bgp_aggr_ecommunity_lookup(
+ struct bgp_aggregate *aggregate,
+ struct ecommunity *ecommunity)
+{
+ return hash_lookup(aggregate->ecommunity_hash, ecommunity);
+}
+
+static void *bgp_aggr_ecommunty_hash_alloc(void *p)
+{
+ struct ecommunity *ref = (struct ecommunity *)p;
+ struct ecommunity *ecommunity = NULL;
+
+ ecommunity = ecommunity_dup(ref);
+ return ecommunity;
+}
+
+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
+ *aggr_ecommunity = ecommunity_dup(hb_ecommunity);
+}
+
+void bgp_aggr_ecommunity_remove(void *arg)
+{
+ struct ecommunity *ecommunity = arg;
+
+ ecommunity_free(&ecommunity);
+}
+
+void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate,
+ struct ecommunity *ecommunity)
+{
+ struct ecommunity *aggr_ecommunity = NULL;
+
+ if ((aggregate == NULL) || (ecommunity == NULL))
+ return;
+
+ /* Create hash if not already created.
+ */
+ if (aggregate->ecommunity_hash == NULL)
+ aggregate->ecommunity_hash = hash_create(
+ ecommunity_hash_make, ecommunity_cmp,
+ "BGP Aggregator ecommunity hash");
+
+ aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity);
+ if (aggr_ecommunity == NULL) {
+ /* Insert ecommunity into hash.
+ */
+ 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);
+
+ hash_iterate(aggregate->ecommunity_hash,
+ bgp_aggr_ecommunity_prepare,
+ &aggregate->ecommunity);
+ }
+
+ /* Increment refernce counter.
+ */
+ aggr_ecommunity->refcnt++;
+}
+
+void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate,
+ struct ecommunity *ecommunity)
+{
+ struct ecommunity *aggr_ecommunity = NULL;
+ struct ecommunity *ret_ecomm = NULL;
+
+ if ((aggregate == NULL) || (ecommunity == NULL))
+ return;
+
+ if (aggregate->ecommunity_hash == NULL)
+ return;
+
+ /* 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);
+
+ ecommunity_free(&aggregate->ecommunity);
+
+ /* Compute aggregate's ecommunity.
+ */
+ hash_iterate(aggregate->ecommunity_hash,
+ bgp_aggr_ecommunity_prepare,
+ &aggregate->ecommunity);
+ }
+ }
+}