From 003bc2754743d0fd5d85d6dcbfd6279843672dd4 Mon Sep 17 00:00:00 2001 From: vivek Date: Tue, 17 Mar 2020 20:27:23 -0700 Subject: [PATCH] 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 Reviewed-by: Donald Sharp Reviewed-by: Don Slice --- bgpd/bgp_ecommunity.c | 48 ++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 2711cf7a69..5e890d98cb 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -892,36 +892,46 @@ extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *ecom, extern int ecommunity_strip(struct ecommunity *ecom, uint8_t type, uint8_t subtype) { - uint8_t *p; + uint8_t *p, *q, *new; int c, found = 0; /* When this is fist value, just add it. */ if (ecom == NULL || ecom->val == NULL) { 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; for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) { - if (p[0] == type && p[1] == subtype) { - found = 1; - break; - } + if (p[0] == type && p[1] == subtype) + found++; } + /* If no matching ext community exists, return. */ if (found == 0) return 0; - /* Strip The selected value */ - ecom->size--; - /* size is reduced. no memmove to do */ - p = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE); - if (c != 0) - memcpy(p, ecom->val, c * ECOMMUNITY_SIZE); - if ((ecom->size - c) != 0) - memcpy(p + (c)*ECOMMUNITY_SIZE, - ecom->val + (c + 1) * ECOMMUNITY_SIZE, - (ecom->size - c) * ECOMMUNITY_SIZE); - /* shift last ecommunities */ - XFREE(MTYPE_ECOMMUNITY, ecom->val); - ecom->val = p; + + /* Handle the case where everything needs to be stripped. */ + if (found == ecom->size) { + XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val); + ecom->size = 0; + return 1; + } + + /* Strip matching ext community(ies). */ + new = XMALLOC(MTYPE_ECOMMUNITY_VAL, + (ecom->size - found) * ECOMMUNITY_SIZE); + q = new; + 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; } -- 2.39.5