mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-08 12:49:18 +00:00
bgpd: Make strip extcommunity handle multiple extcommunities
Extended communities like the BGP Route Target can be present multiple times in a route's path attribute. Ensure that the strip function for a particular extended community (type and subtype) handles this and strips all occurrences. Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com> Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com> Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
This commit is contained in:
parent
1f7170c3bd
commit
003bc27547
@ -892,36 +892,46 @@ extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *ecom,
|
|||||||
extern int ecommunity_strip(struct ecommunity *ecom, uint8_t type,
|
extern int ecommunity_strip(struct ecommunity *ecom, uint8_t type,
|
||||||
uint8_t subtype)
|
uint8_t subtype)
|
||||||
{
|
{
|
||||||
uint8_t *p;
|
uint8_t *p, *q, *new;
|
||||||
int c, found = 0;
|
int c, found = 0;
|
||||||
/* When this is fist value, just add it. */
|
/* When this is fist value, just add it. */
|
||||||
if (ecom == NULL || ecom->val == NULL) {
|
if (ecom == NULL || ecom->val == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the value already exists in the structure return 0. */
|
/* Check if any existing ext community matches. */
|
||||||
|
/* Certain extended communities like the Route Target can be present
|
||||||
|
* multiple times, handle that.
|
||||||
|
*/
|
||||||
c = 0;
|
c = 0;
|
||||||
for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) {
|
for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) {
|
||||||
if (p[0] == type && p[1] == subtype) {
|
if (p[0] == type && p[1] == subtype)
|
||||||
found = 1;
|
found++;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
/* If no matching ext community exists, return. */
|
||||||
if (found == 0)
|
if (found == 0)
|
||||||
return 0;
|
return 0;
|
||||||
/* Strip The selected value */
|
|
||||||
ecom->size--;
|
/* Handle the case where everything needs to be stripped. */
|
||||||
/* size is reduced. no memmove to do */
|
if (found == ecom->size) {
|
||||||
p = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
|
XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
|
||||||
if (c != 0)
|
ecom->size = 0;
|
||||||
memcpy(p, ecom->val, c * ECOMMUNITY_SIZE);
|
return 1;
|
||||||
if ((ecom->size - c) != 0)
|
}
|
||||||
memcpy(p + (c)*ECOMMUNITY_SIZE,
|
|
||||||
ecom->val + (c + 1) * ECOMMUNITY_SIZE,
|
/* Strip matching ext community(ies). */
|
||||||
(ecom->size - c) * ECOMMUNITY_SIZE);
|
new = XMALLOC(MTYPE_ECOMMUNITY_VAL,
|
||||||
/* shift last ecommunities */
|
(ecom->size - found) * ECOMMUNITY_SIZE);
|
||||||
XFREE(MTYPE_ECOMMUNITY, ecom->val);
|
q = new;
|
||||||
ecom->val = p;
|
for (c = 0, p = ecom->val; c < ecom->size; c++, p += ECOMMUNITY_SIZE) {
|
||||||
|
if (!(p[0] == type && p[1] == subtype)) {
|
||||||
|
memcpy(q, p, ECOMMUNITY_SIZE);
|
||||||
|
q += ECOMMUNITY_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
|
||||||
|
ecom->val = new;
|
||||||
|
ecom->size -= found;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user