memcpy(&routermac_ecom.val[2], routermac->octet, ETH_ALEN);
if (!attr->ecommunity)
attr->ecommunity = ecommunity_new();
- ecommunity_add_val(attr->ecommunity, &routermac_ecom);
+ ecommunity_add_val(attr->ecommunity, &routermac_ecom, false, false);
ecommunity_str(attr->ecommunity);
}
Attribute structure. When the value is already exists in the
structure, we don't add the value. Newly added value is sorted by
numerical order. When the value is added to the structure return 1
- else return 0. */
-bool ecommunity_add_val(struct ecommunity *ecom, struct ecommunity_val *eval)
+ else return 0.
+ The additional parameters 'unique' and 'overwrite' ensure a particular
+ extended community (based on type and sub-type) is present only
+ once and whether the new value should replace what is existing or
+ not.
+*/
+bool ecommunity_add_val(struct ecommunity *ecom, struct ecommunity_val *eval,
+ bool unique, bool overwrite)
{
- int c;
+ int c, ins_idx;
/* When this is fist value, just add it. */
if (ecom->val == NULL) {
}
/* If the value already exists in the structure return 0. */
+ /* check also if the extended community itself exists. */
c = 0;
+ ins_idx = -1;
for (uint8_t *p = ecom->val; c < ecom->size;
p += ECOMMUNITY_SIZE, c++) {
+ if (unique) {
+ if (p[0] == eval->val[0] &&
+ p[1] == eval->val[1]) {
+ if (overwrite) {
+ memcpy(p, eval->val, ECOMMUNITY_SIZE);
+ return 1;
+ }
+ return 0;
+ }
+ }
int ret = memcmp(p, eval->val, ECOMMUNITY_SIZE);
if (ret == 0)
- return false;
- else if (ret > 0)
- break;
+ return 0;
+ if (ret > 0) {
+ if (!unique)
+ break;
+ if (ins_idx == -1)
+ ins_idx = c;
+ }
}
+ if (ins_idx == -1)
+ ins_idx = c;
+
/* Add the value to the structure with numerical sorting. */
ecom->size++;
ecom->val = XREALLOC(MTYPE_ECOMMUNITY_VAL, ecom->val,
ecom->size * ECOMMUNITY_SIZE);
- memmove(ecom->val + ((c + 1) * ECOMMUNITY_SIZE),
- ecom->val + (c * ECOMMUNITY_SIZE),
- (ecom->size - 1 - c) * ECOMMUNITY_SIZE);
- memcpy(ecom->val + (c * ECOMMUNITY_SIZE), eval->val, ECOMMUNITY_SIZE);
+ memmove(ecom->val + ((ins_idx + 1) * ECOMMUNITY_SIZE),
+ ecom->val + (ins_idx * ECOMMUNITY_SIZE),
+ (ecom->size - 1 - ins_idx) * ECOMMUNITY_SIZE);
+ memcpy(ecom->val + (ins_idx * ECOMMUNITY_SIZE),
+ eval->val, ECOMMUNITY_SIZE);
return true;
}
for (i = 0; i < ecom->size; i++) {
eval = (struct ecommunity_val *)(ecom->val
+ (i * ECOMMUNITY_SIZE));
- ecommunity_add_val(new, eval);
+ ecommunity_add_val(new, eval, false, false);
}
return new;
}
if (ecom == NULL)
ecom = ecommunity_new();
eval.val[1] = type;
- ecommunity_add_val(ecom, &eval);
+ ecommunity_add_val(ecom, &eval, false, false);
break;
case ecommunity_token_unknown:
default:
/* remove ext. community matching type and subtype
* return 1 on success ( removed ), 0 otherwise (not present)
*/
-extern bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
- uint8_t subtype)
+bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
+ uint8_t subtype)
{
uint8_t *p, *q, *new;
int c, found = 0;
extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *,
uint8_t, uint8_t);
extern bool ecommunity_add_val(struct ecommunity *ecom,
- struct ecommunity_val *eval);
+ struct ecommunity_val *eval,
+ bool unique, bool overwrite);
/* for vpn */
extern struct ecommunity *ecommunity_new(void);
-extern bool ecommunity_add_val(struct ecommunity *, struct ecommunity_val *);
extern bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
uint8_t subtype);
extern struct ecommunity *ecommunity_new(void);
encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
ecomadd = ecommunity_new();
- ecommunity_add_val(ecomadd, &eval);
+ ecommunity_add_val(ecomadd, &eval, false, false);
for (ALL_LIST_ELEMENTS_RO(rtl, node, ecom))
if (ecommunity_cmp(ecomadd, ecom))
ecom_found = true;
encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
ecom_auto = ecommunity_new();
- ecommunity_add_val(ecom_auto, &eval);
+ ecommunity_add_val(ecom_auto, &eval, false, false);
node_to_del = NULL;
for (ALL_LIST_ELEMENTS(rtl, node, nnode, ecom)) {
ecom_copy.val[0] &=
~ECOMMUNITY_ENCODE_TRANS_EXP;
ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
- ecommunity_add_val(eckey, &ecom_copy);
+ ecommunity_add_val(eckey, &ecom_copy,
+ false, false);
api_action->action = ACTION_REDIRECT;
api_action->u.redirect_vrf =
beec.val[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP;
beec.val[6] = ((TunnelType) >> 8) & 0xff;
beec.val[7] = (TunnelType)&0xff;
- ecommunity_add_val(attr.ecommunity, &beec);
+ ecommunity_add_val(attr.ecommunity, &beec, false, false);
}
/*
ecom_value.val[7] =
(l2o->logical_net_id >> 0) & 0xff;
rtlist = ecommunity_new();
- ecommunity_add_val(rtlist, &ecom_value);
+ ecommunity_add_val(rtlist, &ecom_value,
+ false, false);
}
if (l2o->tag_id) {
as_t as = bgp->as;
ecom_value.val[7] = val & 0xff;
if (rtlist == NULL)
rtlist = ecommunity_new();
- ecommunity_add_val(rtlist, &ecom_value);
+ ecommunity_add_val(rtlist, &ecom_value,
+ false, false);
}
}
eval.val[7] = (lni >> 0) & 0xff;
enew = ecommunity_new();
- ecommunity_add_val(enew, &eval);
+ ecommunity_add_val(enew, &eval, false, false);
it->rt_import_list = enew;
for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
&bpi->attr->mp_nexthop_global_in.s_addr, 4);
roec.val[6] = 0;
roec.val[7] = 0;
- ecommunity_add_val(new, &roec);
+ ecommunity_add_val(new, &roec, false, false);
break;
case AF_INET6:
/* No support for IPv6 addresses in extended communities
new = ecommunity_new();
assert(new);
- ecommunity_add_val(new, &roec);
+ ecommunity_add_val(new, &roec, false, false);
if (!new->size) {
ecommunity_free(&new);
localadmin = htons(hc->resolve_nve_roo_local_admin);
memcpy(vnc_gateway_magic.val + 6, (char *)&localadmin, 2);
- ecommunity_add_val(*ecom, &vnc_gateway_magic);
+ ecommunity_add_val(*ecom, &vnc_gateway_magic, false, false);
}
return 0;