summaryrefslogtreecommitdiff
path: root/bgpd/bgp_ecommunity.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_ecommunity.c')
-rw-r--r--bgpd/bgp_ecommunity.c1370
1 files changed, 650 insertions, 720 deletions
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 9349214348..7ac16896a2 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -36,29 +36,26 @@
static struct hash *ecomhash;
/* Allocate a new ecommunities. */
-struct ecommunity *
-ecommunity_new (void)
+struct ecommunity *ecommunity_new(void)
{
- return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY,
- sizeof (struct ecommunity));
+ return (struct ecommunity *)XCALLOC(MTYPE_ECOMMUNITY,
+ sizeof(struct ecommunity));
}
/* Allocate ecommunities. */
-void
-ecommunity_free (struct ecommunity **ecom)
+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, *ecom);
- ecom = NULL;
+ if ((*ecom)->val)
+ XFREE(MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
+ if ((*ecom)->str)
+ XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str);
+ XFREE(MTYPE_ECOMMUNITY, *ecom);
+ ecom = NULL;
}
-static void
-ecommunity_hash_free (struct ecommunity *ecom)
+static void ecommunity_hash_free(struct ecommunity *ecom)
{
- ecommunity_free(&ecom);
+ ecommunity_free(&ecom);
}
@@ -67,465 +64,425 @@ ecommunity_hash_free (struct ecommunity *ecom)
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. */
-int
-ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval)
+int ecommunity_add_val(struct ecommunity *ecom, struct ecommunity_val *eval)
{
- u_int8_t *p;
- int ret;
- int c;
-
- /* When this is fist value, just add it. */
- if (ecom->val == NULL)
- {
- ecom->size++;
- ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom));
- memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE);
- return 1;
- }
-
- /* If the value already exists in the structure return 0. */
- c = 0;
- for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
- {
- ret = memcmp (p, eval->val, ECOMMUNITY_SIZE);
- if (ret == 0)
- return 0;
- if (ret > 0)
- break;
- }
-
- /* Add the value to the structure with numerical sorting. */
- ecom->size++;
- ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom));
-
- 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);
-
- return 1;
+ u_int8_t *p;
+ int ret;
+ int c;
+
+ /* When this is fist value, just add it. */
+ if (ecom->val == NULL) {
+ ecom->size++;
+ ecom->val = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom_length(ecom));
+ memcpy(ecom->val, eval->val, ECOMMUNITY_SIZE);
+ return 1;
+ }
+
+ /* If the value already exists in the structure return 0. */
+ c = 0;
+ for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) {
+ ret = memcmp(p, eval->val, ECOMMUNITY_SIZE);
+ if (ret == 0)
+ return 0;
+ if (ret > 0)
+ break;
+ }
+
+ /* Add the value to the structure with numerical sorting. */
+ ecom->size++;
+ ecom->val =
+ XREALLOC(MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length(ecom));
+
+ 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);
+
+ return 1;
}
/* This function takes pointer to Extended Communites strucutre then
create a new Extended Communities structure by uniq and sort each
Extended Communities value. */
-struct ecommunity *
-ecommunity_uniq_sort (struct ecommunity *ecom)
+struct ecommunity *ecommunity_uniq_sort(struct ecommunity *ecom)
{
- int i;
- struct ecommunity *new;
- struct ecommunity_val *eval;
-
- if (! ecom)
- return NULL;
-
- new = ecommunity_new ();
-
- for (i = 0; i < ecom->size; i++)
- {
- eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE));
- ecommunity_add_val (new, eval);
- }
- return new;
+ int i;
+ struct ecommunity *new;
+ struct ecommunity_val *eval;
+
+ if (!ecom)
+ return NULL;
+
+ new = ecommunity_new();
+
+ for (i = 0; i < ecom->size; i++) {
+ eval = (struct ecommunity_val *)(ecom->val
+ + (i * ECOMMUNITY_SIZE));
+ ecommunity_add_val(new, eval);
+ }
+ return new;
}
/* Parse Extended Communites Attribute in BGP packet. */
-struct ecommunity *
-ecommunity_parse (u_int8_t *pnt, u_short length)
+struct ecommunity *ecommunity_parse(u_int8_t *pnt, u_short length)
{
- struct ecommunity tmp;
- struct ecommunity *new;
+ struct ecommunity tmp;
+ struct ecommunity *new;
- /* Length check. */
- if (length % ECOMMUNITY_SIZE)
- return NULL;
+ /* Length check. */
+ if (length % ECOMMUNITY_SIZE)
+ return NULL;
- /* Prepare tmporary structure for making a new Extended Communities
- Attribute. */
- tmp.size = length / ECOMMUNITY_SIZE;
- tmp.val = pnt;
+ /* Prepare tmporary structure for making a new Extended Communities
+ Attribute. */
+ tmp.size = length / ECOMMUNITY_SIZE;
+ tmp.val = pnt;
- /* Create a new Extended Communities Attribute by uniq and sort each
- Extended Communities value */
- new = ecommunity_uniq_sort (&tmp);
+ /* Create a new Extended Communities Attribute by uniq and sort each
+ Extended Communities value */
+ new = ecommunity_uniq_sort(&tmp);
- return ecommunity_intern (new);
+ return ecommunity_intern(new);
}
/* Duplicate the Extended Communities Attribute structure. */
-struct ecommunity *
-ecommunity_dup (struct ecommunity *ecom)
+struct ecommunity *ecommunity_dup(struct ecommunity *ecom)
{
- struct ecommunity *new;
-
- new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity));
- new->size = ecom->size;
- if (new->size)
- {
- new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
- memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE);
- }
- else
- new->val = NULL;
- return new;
+ struct ecommunity *new;
+
+ new = XCALLOC(MTYPE_ECOMMUNITY, sizeof(struct ecommunity));
+ new->size = ecom->size;
+ if (new->size) {
+ new->val = XMALLOC(MTYPE_ECOMMUNITY_VAL,
+ ecom->size * ECOMMUNITY_SIZE);
+ memcpy(new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE);
+ } else
+ new->val = NULL;
+ return new;
}
/* Retrun string representation of communities attribute. */
-char *
-ecommunity_str (struct ecommunity *ecom)
+char *ecommunity_str(struct ecommunity *ecom)
{
- if (! ecom->str)
- ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
- return ecom->str;
+ if (!ecom->str)
+ ecom->str =
+ ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
+ return ecom->str;
}
/* Merge two Extended Communities Attribute structure. */
-struct ecommunity *
-ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2)
+struct ecommunity *ecommunity_merge(struct ecommunity *ecom1,
+ struct ecommunity *ecom2)
{
- if (ecom1->val)
- ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val,
- (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
- else
- ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL,
- (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
-
- memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE),
- ecom2->val, ecom2->size * ECOMMUNITY_SIZE);
- ecom1->size += ecom2->size;
-
- return ecom1;
+ if (ecom1->val)
+ ecom1->val =
+ XREALLOC(MTYPE_ECOMMUNITY_VAL, ecom1->val,
+ (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
+ else
+ ecom1->val =
+ XMALLOC(MTYPE_ECOMMUNITY_VAL,
+ (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
+
+ memcpy(ecom1->val + (ecom1->size * ECOMMUNITY_SIZE), ecom2->val,
+ ecom2->size * ECOMMUNITY_SIZE);
+ ecom1->size += ecom2->size;
+
+ return ecom1;
}
/* Intern Extended Communities Attribute. */
-struct ecommunity *
-ecommunity_intern (struct ecommunity *ecom)
+struct ecommunity *ecommunity_intern(struct ecommunity *ecom)
{
- struct ecommunity *find;
+ struct ecommunity *find;
- assert (ecom->refcnt == 0);
+ assert(ecom->refcnt == 0);
- find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern);
+ find = (struct ecommunity *)hash_get(ecomhash, ecom, hash_alloc_intern);
- if (find != ecom)
- ecommunity_free (&ecom);
+ if (find != ecom)
+ ecommunity_free(&ecom);
- find->refcnt++;
+ find->refcnt++;
- if (! find->str)
- find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY, 0);
+ if (!find->str)
+ find->str =
+ ecommunity_ecom2str(find, ECOMMUNITY_FORMAT_DISPLAY, 0);
- return find;
+ return find;
}
/* Unintern Extended Communities Attribute. */
-void
-ecommunity_unintern (struct ecommunity **ecom)
+void ecommunity_unintern(struct ecommunity **ecom)
{
- struct ecommunity *ret;
-
- if ((*ecom)->refcnt)
- (*ecom)->refcnt--;
-
- /* Pull off from hash. */
- if ((*ecom)->refcnt == 0)
- {
- /* Extended community must be in the hash. */
- ret = (struct ecommunity *) hash_release (ecomhash, *ecom);
- assert (ret != NULL);
-
- ecommunity_free (ecom);
- }
+ struct ecommunity *ret;
+
+ if ((*ecom)->refcnt)
+ (*ecom)->refcnt--;
+
+ /* Pull off from hash. */
+ if ((*ecom)->refcnt == 0) {
+ /* Extended community must be in the hash. */
+ ret = (struct ecommunity *)hash_release(ecomhash, *ecom);
+ assert(ret != NULL);
+
+ ecommunity_free(ecom);
+ }
}
/* Utinity function to make hash key. */
-unsigned int
-ecommunity_hash_make (void *arg)
+unsigned int ecommunity_hash_make(void *arg)
{
- const struct ecommunity *ecom = arg;
- int size = ecom->size * ECOMMUNITY_SIZE;
- u_int8_t *pnt = ecom->val;
- unsigned int key = 0;
- int c;
-
- for (c = 0; c < size; c += ECOMMUNITY_SIZE)
- {
- key += pnt[c];
- key += pnt[c + 1];
- key += pnt[c + 2];
- key += pnt[c + 3];
- key += pnt[c + 4];
- key += pnt[c + 5];
- key += pnt[c + 6];
- key += pnt[c + 7];
- }
-
- return key;
+ const struct ecommunity *ecom = arg;
+ int size = ecom->size * ECOMMUNITY_SIZE;
+ u_int8_t *pnt = ecom->val;
+ unsigned int key = 0;
+ int c;
+
+ for (c = 0; c < size; c += ECOMMUNITY_SIZE) {
+ key += pnt[c];
+ key += pnt[c + 1];
+ key += pnt[c + 2];
+ key += pnt[c + 3];
+ key += pnt[c + 4];
+ key += pnt[c + 5];
+ key += pnt[c + 6];
+ key += pnt[c + 7];
+ }
+
+ return key;
}
/* Compare two Extended Communities Attribute structure. */
-int
-ecommunity_cmp (const void *arg1, const void *arg2)
+int ecommunity_cmp(const void *arg1, const void *arg2)
{
- const struct ecommunity *ecom1 = arg1;
- const struct ecommunity *ecom2 = arg2;
+ const struct ecommunity *ecom1 = arg1;
+ const struct ecommunity *ecom2 = arg2;
+
+ if (ecom1 == NULL && ecom2 == NULL)
+ return 1;
- if (ecom1 == NULL && ecom2 == NULL)
- return 1;
+ if (ecom1 == NULL || ecom2 == NULL)
+ return 0;
- if (ecom1 == NULL || ecom2 == NULL)
- return 0;
-
- return (ecom1->size == ecom2->size
- && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0);
+ return (ecom1->size == ecom2->size
+ && memcmp(ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE)
+ == 0);
}
/* Initialize Extended Comminities related hash. */
-void
-ecommunity_init (void)
+void ecommunity_init(void)
{
- ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp, NULL);
+ ecomhash = hash_create(ecommunity_hash_make, ecommunity_cmp, NULL);
}
-void
-ecommunity_finish (void)
+void ecommunity_finish(void)
{
- hash_clean (ecomhash, (void (*)(void *))ecommunity_hash_free);
- hash_free (ecomhash);
- ecomhash = NULL;
+ hash_clean(ecomhash, (void (*)(void *))ecommunity_hash_free);
+ hash_free(ecomhash);
+ ecomhash = NULL;
}
/* Extended Communities token enum. */
-enum ecommunity_token
-{
- ecommunity_token_unknown = 0,
- ecommunity_token_rt,
- ecommunity_token_soo,
- ecommunity_token_val,
+enum ecommunity_token {
+ ecommunity_token_unknown = 0,
+ ecommunity_token_rt,
+ ecommunity_token_soo,
+ ecommunity_token_val,
};
/*
* Encode BGP extended community from passed values. Supports types
* defined in RFC 4360 and well-known sub-types.
*/
-static int
-ecommunity_encode (u_char type, u_char sub_type, int trans,
- as_t as, struct in_addr ip, u_int32_t val,
- struct ecommunity_val *eval)
+static int ecommunity_encode(u_char type, u_char sub_type, int trans, as_t as,
+ struct in_addr ip, u_int32_t val,
+ struct ecommunity_val *eval)
{
- assert (eval);
- if (type == ECOMMUNITY_ENCODE_AS)
- {
- if (as > BGP_AS_MAX)
- return -1;
- }
- else if (type == ECOMMUNITY_ENCODE_IP
- || type == ECOMMUNITY_ENCODE_AS4)
- {
- if (val > UINT16_MAX)
- return -1;
- }
-
- /* Fill in the values. */
- eval->val[0] = type;
- if (!trans)
- eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
- eval->val[1] = sub_type;
- if (type == ECOMMUNITY_ENCODE_AS)
- {
- eval->val[2] = (as >> 8) & 0xff;
- eval->val[3] = as & 0xff;
- eval->val[4] = (val >> 24) & 0xff;
- eval->val[5] = (val >> 16) & 0xff;
- eval->val[6] = (val >> 8) & 0xff;
- eval->val[7] = val & 0xff;
- }
- else if (type == ECOMMUNITY_ENCODE_IP)
- {
- memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
- eval->val[6] = (val >> 8) & 0xff;
- eval->val[7] = val & 0xff;
- }
- else
- {
- eval->val[2] = (as >> 24) & 0xff;
- eval->val[3] = (as >> 16) & 0xff;
- eval->val[4] = (as >> 8) & 0xff;
- eval->val[5] = as & 0xff;
- eval->val[6] = (val >> 8) & 0xff;
- eval->val[7] = val & 0xff;
- }
-
- return 0;
+ assert(eval);
+ if (type == ECOMMUNITY_ENCODE_AS) {
+ if (as > BGP_AS_MAX)
+ return -1;
+ } else if (type == ECOMMUNITY_ENCODE_IP
+ || type == ECOMMUNITY_ENCODE_AS4) {
+ if (val > UINT16_MAX)
+ return -1;
+ }
+
+ /* Fill in the values. */
+ eval->val[0] = type;
+ if (!trans)
+ eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
+ eval->val[1] = sub_type;
+ if (type == ECOMMUNITY_ENCODE_AS) {
+ eval->val[2] = (as >> 8) & 0xff;
+ eval->val[3] = as & 0xff;
+ eval->val[4] = (val >> 24) & 0xff;
+ eval->val[5] = (val >> 16) & 0xff;
+ eval->val[6] = (val >> 8) & 0xff;
+ eval->val[7] = val & 0xff;
+ } else if (type == ECOMMUNITY_ENCODE_IP) {
+ memcpy(&eval->val[2], &ip, sizeof(struct in_addr));
+ eval->val[6] = (val >> 8) & 0xff;
+ eval->val[7] = val & 0xff;
+ } else {
+ eval->val[2] = (as >> 24) & 0xff;
+ eval->val[3] = (as >> 16) & 0xff;
+ eval->val[4] = (as >> 8) & 0xff;
+ eval->val[5] = as & 0xff;
+ eval->val[6] = (val >> 8) & 0xff;
+ eval->val[7] = val & 0xff;
+ }
+
+ return 0;
}
/* Get next Extended Communities token from the string. */
-static const char *
-ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
- enum ecommunity_token *token)
+static const char *ecommunity_gettoken(const char *str,
+ struct ecommunity_val *eval,
+ enum ecommunity_token *token)
{
- int ret;
- int dot = 0;
- int digit = 0;
- int separator = 0;
- const char *p = str;
- char *endptr;
- struct in_addr ip;
- as_t as = 0;
- u_int32_t val = 0;
- u_char ecomm_type;
- char buf[INET_ADDRSTRLEN + 1];
-
- /* Skip white space. */
- while (isspace ((int) *p))
- {
- p++;
- str++;
- }
-
- /* Check the end of the line. */
- if (*p == '\0')
- return NULL;
-
- /* "rt" and "soo" keyword parse. */
- if (! isdigit ((int) *p))
- {
- /* "rt" match check. */
- if (tolower ((int) *p) == 'r')
- {
- p++;
- if (tolower ((int) *p) == 't')
- {
- p++;
- *token = ecommunity_token_rt;
- return p;
- }
- if (isspace ((int) *p) || *p == '\0')
- {
- *token = ecommunity_token_rt;
- return p;
- }
- goto error;
+ int ret;
+ int dot = 0;
+ int digit = 0;
+ int separator = 0;
+ const char *p = str;
+ char *endptr;
+ struct in_addr ip;
+ as_t as = 0;
+ u_int32_t val = 0;
+ u_char ecomm_type;
+ char buf[INET_ADDRSTRLEN + 1];
+
+ /* Skip white space. */
+ while (isspace((int)*p)) {
+ p++;
+ str++;
}
- /* "soo" match check. */
- else if (tolower ((int) *p) == 's')
- {
- p++;
- if (tolower ((int) *p) == 'o')
- {
- p++;
- if (tolower ((int) *p) == 'o')
- {
- p++;
- *token = ecommunity_token_soo;
- return p;
+
+ /* Check the end of the line. */
+ if (*p == '\0')
+ return NULL;
+
+ /* "rt" and "soo" keyword parse. */
+ if (!isdigit((int)*p)) {
+ /* "rt" match check. */
+ if (tolower((int)*p) == 'r') {
+ p++;
+ if (tolower((int)*p) == 't') {
+ p++;
+ *token = ecommunity_token_rt;
+ return p;
+ }
+ if (isspace((int)*p) || *p == '\0') {
+ *token = ecommunity_token_rt;
+ return p;
+ }
+ goto error;
}
- if (isspace ((int) *p) || *p == '\0')
- {
- *token = ecommunity_token_soo;
- return p;
+ /* "soo" match check. */
+ else if (tolower((int)*p) == 's') {
+ p++;
+ if (tolower((int)*p) == 'o') {
+ p++;
+ if (tolower((int)*p) == 'o') {
+ p++;
+ *token = ecommunity_token_soo;
+ return p;
+ }
+ if (isspace((int)*p) || *p == '\0') {
+ *token = ecommunity_token_soo;
+ return p;
+ }
+ goto error;
+ }
+ if (isspace((int)*p) || *p == '\0') {
+ *token = ecommunity_token_soo;
+ return p;
+ }
+ goto error;
}
- goto error;
- }
- if (isspace ((int) *p) || *p == '\0')
- {
- *token = ecommunity_token_soo;
- return p;
- }
- goto error;
+ goto error;
}
- goto error;
- }
-
- /* What a mess, there are several possibilities:
- *
- * a) A.B.C.D:MN
- * b) EF:OPQR
- * c) GHJK:MN
- *
- * A.B.C.D: Four Byte IP
- * EF: Two byte ASN
- * GHJK: Four-byte ASN
- * MN: Two byte value
- * OPQR: Four byte value
- *
- */
- while (isdigit ((int) *p) || *p == ':' || *p == '.')
- {
- if (*p == ':')
- {
- if (separator)
- goto error;
-
- separator = 1;
- digit = 0;
-
- if ((p - str) > INET_ADDRSTRLEN)
- goto error;
- memset (buf, 0, INET_ADDRSTRLEN + 1);
- memcpy (buf, str, p - str);
-
- if (dot)
- {
- /* Parsing A.B.C.D in:
- * A.B.C.D:MN
- */
- ret = inet_aton (buf, &ip);
- if (ret == 0)
- goto error;
- }
- else
- {
- /* ASN */
- as = strtoul (buf, &endptr, 10);
- if (*endptr != '\0' || as == BGP_AS4_MAX)
- goto error;
- }
- }
- else if (*p == '.')
- {
- if (separator)
- goto error;
- dot++;
- if (dot > 4)
- goto error;
- }
- else
- {
- digit = 1;
-
- /* We're past the IP/ASN part */
- if (separator)
- {
- val *= 10;
- val += (*p - '0');
- }
+
+ /* What a mess, there are several possibilities:
+ *
+ * a) A.B.C.D:MN
+ * b) EF:OPQR
+ * c) GHJK:MN
+ *
+ * A.B.C.D: Four Byte IP
+ * EF: Two byte ASN
+ * GHJK: Four-byte ASN
+ * MN: Two byte value
+ * OPQR: Four byte value
+ *
+ */
+ while (isdigit((int)*p) || *p == ':' || *p == '.') {
+ if (*p == ':') {
+ if (separator)
+ goto error;
+
+ separator = 1;
+ digit = 0;
+
+ if ((p - str) > INET_ADDRSTRLEN)
+ goto error;
+ memset(buf, 0, INET_ADDRSTRLEN + 1);
+ memcpy(buf, str, p - str);
+
+ if (dot) {
+ /* Parsing A.B.C.D in:
+ * A.B.C.D:MN
+ */
+ ret = inet_aton(buf, &ip);
+ if (ret == 0)
+ goto error;
+ } else {
+ /* ASN */
+ as = strtoul(buf, &endptr, 10);
+ if (*endptr != '\0' || as == BGP_AS4_MAX)
+ goto error;
+ }
+ } else if (*p == '.') {
+ if (separator)
+ goto error;
+ dot++;
+ if (dot > 4)
+ goto error;
+ } else {
+ digit = 1;
+
+ /* We're past the IP/ASN part */
+ if (separator) {
+ val *= 10;
+ val += (*p - '0');
+ }
+ }
+ p++;
}
- p++;
- }
-
- /* Low digit part must be there. */
- if (!digit || !separator)
- goto error;
-
- /* Encode result into extended community. */
- if (dot)
- ecomm_type = ECOMMUNITY_ENCODE_IP;
- else if (as > BGP_AS_MAX)
- ecomm_type = ECOMMUNITY_ENCODE_AS4;
- else
- ecomm_type = ECOMMUNITY_ENCODE_AS;
- if (ecommunity_encode (ecomm_type, 0, 1, as, ip, val, eval))
- goto error;
- *token = ecommunity_token_val;
- return p;
-
- error:
- *token = ecommunity_token_unknown;
- return p;
+
+ /* Low digit part must be there. */
+ if (!digit || !separator)
+ goto error;
+
+ /* Encode result into extended community. */
+ if (dot)
+ ecomm_type = ECOMMUNITY_ENCODE_IP;
+ else if (as > BGP_AS_MAX)
+ ecomm_type = ECOMMUNITY_ENCODE_AS4;
+ else
+ ecomm_type = ECOMMUNITY_ENCODE_AS;
+ if (ecommunity_encode(ecomm_type, 0, 1, as, ip, val, eval))
+ goto error;
+ *token = ecommunity_token_val;
+ return p;
+
+error:
+ *token = ecommunity_token_unknown;
+ return p;
}
-/* Convert string to extended community attribute.
+/* Convert string to extended community attribute.
When type is already known, please specify both str and type. str
should not include keyword such as "rt" and "soo". Type is
@@ -535,12 +492,12 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
For example route-map's "set extcommunity" command case:
"rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
- type = ECOMMUNITY_ROUTE_TARGET
- keyword_included = 0
+ type = ECOMMUNITY_ROUTE_TARGET
+ keyword_included = 0
"soo 100:1" -> str = "100:1"
- type = ECOMMUNITY_SITE_ORIGIN
- keyword_included = 0
+ type = ECOMMUNITY_SITE_ORIGIN
+ keyword_included = 0
When string includes keyword for each extended community value.
Please specify keyword_included as non-zero value.
@@ -548,155 +505,140 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
For example standard extcommunity-list case:
"rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
- type = 0
- keyword_include = 1
+ type = 0
+ keyword_include = 1
*/
-struct ecommunity *
-ecommunity_str2com (const char *str, int type, int keyword_included)
+struct ecommunity *ecommunity_str2com(const char *str, int type,
+ int keyword_included)
{
- struct ecommunity *ecom = NULL;
- enum ecommunity_token token = ecommunity_token_unknown;
- struct ecommunity_val eval;
- int keyword = 0;
-
- while ((str = ecommunity_gettoken (str, &eval, &token)))
- {
- switch (token)
- {
- case ecommunity_token_rt:
- case ecommunity_token_soo:
- if (! keyword_included || keyword)
- {
- if (ecom)
- ecommunity_free (&ecom);
- return NULL;
- }
- keyword = 1;
-
- if (token == ecommunity_token_rt)
- {
- type = ECOMMUNITY_ROUTE_TARGET;
- }
- if (token == ecommunity_token_soo)
- {
- type = ECOMMUNITY_SITE_ORIGIN;
- }
- break;
- case ecommunity_token_val:
- if (keyword_included)
- {
- if (! keyword)
- {
- if (ecom)
- ecommunity_free (&ecom);
- return NULL;
+ struct ecommunity *ecom = NULL;
+ enum ecommunity_token token = ecommunity_token_unknown;
+ struct ecommunity_val eval;
+ int keyword = 0;
+
+ while ((str = ecommunity_gettoken(str, &eval, &token))) {
+ switch (token) {
+ case ecommunity_token_rt:
+ case ecommunity_token_soo:
+ if (!keyword_included || keyword) {
+ if (ecom)
+ ecommunity_free(&ecom);
+ return NULL;
+ }
+ keyword = 1;
+
+ if (token == ecommunity_token_rt) {
+ type = ECOMMUNITY_ROUTE_TARGET;
+ }
+ if (token == ecommunity_token_soo) {
+ type = ECOMMUNITY_SITE_ORIGIN;
+ }
+ break;
+ case ecommunity_token_val:
+ if (keyword_included) {
+ if (!keyword) {
+ if (ecom)
+ ecommunity_free(&ecom);
+ return NULL;
+ }
+ keyword = 0;
+ }
+ if (ecom == NULL)
+ ecom = ecommunity_new();
+ eval.val[1] = type;
+ ecommunity_add_val(ecom, &eval);
+ break;
+ case ecommunity_token_unknown:
+ default:
+ if (ecom)
+ ecommunity_free(&ecom);
+ return NULL;
}
- keyword = 0;
- }
- if (ecom == NULL)
- ecom = ecommunity_new ();
- eval.val[1] = type;
- ecommunity_add_val (ecom, &eval);
- break;
- case ecommunity_token_unknown:
- default:
- if (ecom)
- ecommunity_free (&ecom);
- return NULL;
}
- }
- return ecom;
+ return ecom;
}
-static int
-ecommunity_rt_soo_str (char *buf, u_int8_t *pnt, int type,
- int sub_type, int format)
+static int ecommunity_rt_soo_str(char *buf, u_int8_t *pnt, int type,
+ int sub_type, int format)
{
- int len = 0;
- const char *prefix;
-
- /* For parse Extended Community attribute tupple. */
- struct ecommunity_as
- {
- as_t as;
- u_int32_t val;
- } eas;
-
- struct ecommunity_ip
- {
- struct in_addr ip;
- u_int16_t val;
- } eip;
-
-
- /* Determine prefix for string, if any. */
- switch (format)
- {
- case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
- prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
- break;
- case ECOMMUNITY_FORMAT_DISPLAY:
- prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
- break;
- case ECOMMUNITY_FORMAT_ROUTE_MAP:
- prefix = "";
- break;
- default:
- prefix = "";
- break;
- }
-
- /* Put string into buffer. */
- if (type == ECOMMUNITY_ENCODE_AS4)
- {
- eas.as = (*pnt++ << 24);
- eas.as |= (*pnt++ << 16);
- eas.as |= (*pnt++ << 8);
- eas.as |= (*pnt++);
- eas.val = (*pnt++ << 8);
- eas.val |= (*pnt++);
-
- len = sprintf (buf, "%s%u:%u", prefix, eas.as, eas.val);
- }
- else if (type == ECOMMUNITY_ENCODE_AS)
- {
- eas.as = (*pnt++ << 8);
- eas.as |= (*pnt++);
-
- eas.val = (*pnt++ << 24);
- eas.val |= (*pnt++ << 16);
- eas.val |= (*pnt++ << 8);
- eas.val |= (*pnt++);
-
- len = sprintf (buf, "%s%u:%u", prefix, eas.as, eas.val);
- }
- else if (type == ECOMMUNITY_ENCODE_IP)
- {
- memcpy (&eip.ip, pnt, 4);
- pnt += 4;
- eip.val = (*pnt++ << 8);
- eip.val |= (*pnt++);
-
- len = sprintf (buf, "%s%s:%u", prefix, inet_ntoa (eip.ip), eip.val);
- }
-
- return len;
+ int len = 0;
+ const char *prefix;
+
+ /* For parse Extended Community attribute tupple. */
+ struct ecommunity_as {
+ as_t as;
+ u_int32_t val;
+ } eas;
+
+ struct ecommunity_ip {
+ struct in_addr ip;
+ u_int16_t val;
+ } eip;
+
+
+ /* Determine prefix for string, if any. */
+ switch (format) {
+ case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
+ prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
+ break;
+ case ECOMMUNITY_FORMAT_DISPLAY:
+ prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
+ break;
+ case ECOMMUNITY_FORMAT_ROUTE_MAP:
+ prefix = "";
+ break;
+ default:
+ prefix = "";
+ break;
+ }
+
+ /* Put string into buffer. */
+ if (type == ECOMMUNITY_ENCODE_AS4) {
+ eas.as = (*pnt++ << 24);
+ eas.as |= (*pnt++ << 16);
+ eas.as |= (*pnt++ << 8);
+ eas.as |= (*pnt++);
+ eas.val = (*pnt++ << 8);
+ eas.val |= (*pnt++);
+
+ len = sprintf(buf, "%s%u:%u", prefix, eas.as, eas.val);
+ } else if (type == ECOMMUNITY_ENCODE_AS) {
+ eas.as = (*pnt++ << 8);
+ eas.as |= (*pnt++);
+
+ eas.val = (*pnt++ << 24);
+ eas.val |= (*pnt++ << 16);
+ eas.val |= (*pnt++ << 8);
+ eas.val |= (*pnt++);
+
+ len = sprintf(buf, "%s%u:%u", prefix, eas.as, eas.val);
+ } else if (type == ECOMMUNITY_ENCODE_IP) {
+ memcpy(&eip.ip, pnt, 4);
+ pnt += 4;
+ eip.val = (*pnt++ << 8);
+ eip.val |= (*pnt++);
+
+ len = sprintf(buf, "%s%s:%u", prefix, inet_ntoa(eip.ip),
+ eip.val);
+ }
+
+ return len;
}
-/* Convert extended community attribute to string.
+/* Convert extended community attribute to string.
Due to historical reason of industry standard implementation, there
are three types of format.
route-map set extcommunity format
- "rt 100:1 100:2"
- "soo 100:3"
+ "rt 100:1 100:2"
+ "soo 100:3"
extcommunity-list
- "rt 100:1 rt 100:2 soo 100:3"
+ "rt 100:1 rt 100:2 soo 100:3"
"show [ip] bgp" and extcommunity-list regular expression matching
- "RT:100:1 RT:100:2 SoO:100:3"
+ "RT:100:1 RT:100:2 SoO:100:3"
For each formath please use below definition for format:
@@ -704,213 +646,201 @@ ecommunity_rt_soo_str (char *buf, u_int8_t *pnt, int type,
ECOMMUNITY_FORMAT_COMMUNITY_LIST
ECOMMUNITY_FORMAT_DISPLAY
- Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
+ Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
0 value displays all
*/
-char *
-ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
+char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
{
- int i;
- u_int8_t *pnt;
- int type = 0;
- int sub_type = 0;
+ int i;
+ u_int8_t *pnt;
+ int type = 0;
+ int sub_type = 0;
#define ECOMMUNITY_STR_DEFAULT_LEN 27
- int str_size;
- int str_pnt;
- char *str_buf;
- int len = 0;
- int first = 1;
-
- if (ecom->size == 0)
- {
- str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1);
- str_buf[0] = '\0';
- return str_buf;
- }
-
- /* Prepare buffer. */
- str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
- str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
- str_buf[0] = '\0';
- str_pnt = 0;
-
- for (i = 0; i < ecom->size; i++)
- {
- int unk_ecom = 0;
-
- /* Make it sure size is enough. */
- while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
- {
- str_size *= 2;
- str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
+ int str_size;
+ int str_pnt;
+ char *str_buf;
+ int len = 0;
+ int first = 1;
+
+ if (ecom->size == 0) {
+ str_buf = XMALLOC(MTYPE_ECOMMUNITY_STR, 1);
+ str_buf[0] = '\0';
+ return str_buf;
+ }
+
+ /* Prepare buffer. */
+ str_buf = XMALLOC(MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
+ str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
+ str_buf[0] = '\0';
+ str_pnt = 0;
+
+ for (i = 0; i < ecom->size; i++) {
+ int unk_ecom = 0;
+
+ /* Make it sure size is enough. */
+ while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) {
+ str_size *= 2;
+ str_buf = XREALLOC(MTYPE_ECOMMUNITY_STR, str_buf,
+ str_size);
+ }
+
+ /* Space between each value. */
+ if (!first)
+ str_buf[str_pnt++] = ' ';
+
+ pnt = ecom->val + (i * 8);
+
+ /* High-order octet of type. */
+ type = *pnt++;
+
+ if (type == ECOMMUNITY_ENCODE_AS || type == ECOMMUNITY_ENCODE_IP
+ || type == ECOMMUNITY_ENCODE_AS4) {
+ /* Low-order octet of type. */
+ sub_type = *pnt++;
+ if (sub_type != ECOMMUNITY_ROUTE_TARGET
+ && sub_type != ECOMMUNITY_SITE_ORIGIN)
+ unk_ecom = 1;
+ else
+ len = ecommunity_rt_soo_str(str_buf + str_pnt,
+ pnt, type, sub_type,
+ format);
+ } else if (type == ECOMMUNITY_ENCODE_OPAQUE) {
+ if (filter == ECOMMUNITY_ROUTE_TARGET)
+ continue;
+ if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP) {
+ uint16_t tunneltype;
+ memcpy(&tunneltype, pnt + 5, 2);
+ tunneltype = ntohs(tunneltype);
+ len = sprintf(str_buf + str_pnt, "ET:%d",
+ tunneltype);
+ } else
+ unk_ecom = 1;
+ } else if (type == ECOMMUNITY_ENCODE_EVPN) {
+ if (filter == ECOMMUNITY_ROUTE_TARGET)
+ continue;
+ if (*pnt == ECOMMUNITY_SITE_ORIGIN) {
+ char macaddr[6];
+ pnt++;
+ memcpy(&macaddr, pnt, 6);
+ len = sprintf(
+ str_buf + str_pnt,
+ "EVPN:%02x:%02x:%02x:%02x:%02x:%02x",
+ macaddr[0], macaddr[1], macaddr[2],
+ macaddr[3], macaddr[4], macaddr[5]);
+ } else if (*pnt
+ == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) {
+ u_int32_t seqnum;
+ u_char flags = *++pnt;
+
+ memcpy(&seqnum, pnt + 2, 4);
+ seqnum = ntohl(seqnum);
+ if (flags
+ & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
+ len = sprintf(str_buf + str_pnt,
+ "MM:%u, sticky MAC",
+ seqnum);
+ else
+ len = sprintf(str_buf + str_pnt,
+ "MM:%u", seqnum);
+ } else
+ unk_ecom = 1;
+ } else
+ unk_ecom = 1;
+
+ if (unk_ecom)
+ len = sprintf(str_buf + str_pnt, "?");
+
+ str_pnt += len;
+ first = 0;
}
- /* Space between each value. */
- if (! first)
- str_buf[str_pnt++] = ' ';
-
- pnt = ecom->val + (i * 8);
-
- /* High-order octet of type. */
- type = *pnt++;
-
- if (type == ECOMMUNITY_ENCODE_AS ||
- type == ECOMMUNITY_ENCODE_IP ||
- type == ECOMMUNITY_ENCODE_AS4)
- {
- /* Low-order octet of type. */
- sub_type = *pnt++;
- if (sub_type != ECOMMUNITY_ROUTE_TARGET &&
- sub_type != ECOMMUNITY_SITE_ORIGIN)
- unk_ecom = 1;
- else
- len = ecommunity_rt_soo_str (str_buf + str_pnt, pnt, type,
- sub_type, format);
- }
- else if (type == ECOMMUNITY_ENCODE_OPAQUE)
- {
- if (filter == ECOMMUNITY_ROUTE_TARGET)
- continue;
- if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP)
- {
- uint16_t tunneltype;
- memcpy (&tunneltype, pnt + 5, 2);
- tunneltype = ntohs(tunneltype);
- len = sprintf (str_buf + str_pnt, "ET:%d", tunneltype);
- }
- else
- unk_ecom = 1;
- }
- else if (type == ECOMMUNITY_ENCODE_EVPN)
- {
- if (filter == ECOMMUNITY_ROUTE_TARGET)
- continue;
- if (*pnt == ECOMMUNITY_SITE_ORIGIN)
- {
- char macaddr[6];
- pnt++;
- memcpy(&macaddr, pnt, 6);
- len = sprintf(str_buf + str_pnt, "EVPN:%02x:%02x:%02x:%02x:%02x:%02x",
- macaddr[0], macaddr[1], macaddr[2],
- macaddr[3], macaddr[4], macaddr[5]);
- }
- else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY)
- {
- u_int32_t seqnum;
- u_char flags = *++pnt;
-
- memcpy (&seqnum, pnt + 2, 4);
- seqnum = ntohl(seqnum);
- if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
- len = sprintf (str_buf + str_pnt, "MM:%u, sticky MAC", seqnum);
- else
- len = sprintf (str_buf + str_pnt, "MM:%u", seqnum);
- }
- else
- unk_ecom = 1;
- }
- else
- unk_ecom = 1;
-
- if (unk_ecom)
- len = sprintf (str_buf + str_pnt, "?");
-
- str_pnt += len;
- first = 0;
- }
-
- return str_buf;
+ return str_buf;
}
-int
-ecommunity_match (const struct ecommunity *ecom1,
- const struct ecommunity *ecom2)
+int ecommunity_match(const struct ecommunity *ecom1,
+ const struct ecommunity *ecom2)
{
- int i = 0;
- int j = 0;
-
- if (ecom1 == NULL && ecom2 == NULL)
- return 1;
-
- if (ecom1 == NULL || ecom2 == NULL)
- return 0;
-
- if (ecom1->size < ecom2->size)
- return 0;
-
- /* Every community on com2 needs to be on com1 for this to match */
- while (i < ecom1->size && j < ecom2->size)
- {
- if (memcmp (ecom1->val + i * ECOMMUNITY_SIZE,
- ecom2->val + j * ECOMMUNITY_SIZE,
- ECOMMUNITY_SIZE) == 0)
- j++;
- i++;
- }
-
- if (j == ecom2->size)
- return 1;
- else
- return 0;
+ int i = 0;
+ int j = 0;
+
+ if (ecom1 == NULL && ecom2 == NULL)
+ return 1;
+
+ if (ecom1 == NULL || ecom2 == NULL)
+ return 0;
+
+ if (ecom1->size < ecom2->size)
+ return 0;
+
+ /* Every community on com2 needs to be on com1 for this to match */
+ while (i < ecom1->size && j < ecom2->size) {
+ if (memcmp(ecom1->val + i * ECOMMUNITY_SIZE,
+ ecom2->val + j * ECOMMUNITY_SIZE, ECOMMUNITY_SIZE)
+ == 0)
+ j++;
+ i++;
+ }
+
+ if (j == ecom2->size)
+ return 1;
+ else
+ return 0;
}
/* return first occurence of type */
-extern struct ecommunity_val *ecommunity_lookup (const struct ecommunity *ecom, uint8_t type, uint8_t subtype)
+extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *ecom,
+ uint8_t type, uint8_t subtype)
{
- u_int8_t *p;
- int c;
-
- /* If the value already exists in the structure return 0. */
- c = 0;
- for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
- {
- if(p == NULL)
- {
- continue;
- }
- if(p[0] == type && p[1] == subtype)
- return (struct ecommunity_val *)p;
- }
- return NULL;
+ u_int8_t *p;
+ int c;
+
+ /* If the value already exists in the structure return 0. */
+ c = 0;
+ for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) {
+ if (p == NULL) {
+ continue;
+ }
+ if (p[0] == type && p[1] == subtype)
+ return (struct ecommunity_val *)p;
+ }
+ return NULL;
}
/* remove ext. community matching type and subtype
* return 1 on success ( removed ), 0 otherwise (not present)
*/
-extern int ecommunity_strip (struct ecommunity *ecom, uint8_t type, uint8_t subtype)
+extern int ecommunity_strip(struct ecommunity *ecom, uint8_t type,
+ uint8_t subtype)
{
- u_int8_t *p;
- 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. */
- c = 0;
- for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
- {
- if (p[0] == type && p[1] == subtype)
- {
- found = 1;
- break;
- }
- }
- 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;
- return 1;
+ u_int8_t *p;
+ 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. */
+ c = 0;
+ for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) {
+ if (p[0] == type && p[1] == subtype) {
+ found = 1;
+ break;
+ }
+ }
+ 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;
+ return 1;
}