diff options
Diffstat (limited to 'bgpd/bgp_ecommunity.c')
| -rw-r--r-- | bgpd/bgp_ecommunity.c | 1329 |
1 files changed, 634 insertions, 695 deletions
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index c80966ec6d..8b17de440d 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -36,29 +36,26 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 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,438 +64,402 @@ 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; - - return (ecom1->size == ecom2->size - && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0); + if (ecom1 == NULL || ecom2 == NULL) + return 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); + ecomhash = hash_create(ecommunity_hash_make, ecommunity_cmp); } -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, }; /* 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; - 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; + 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; + + /* 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++; } - else - { - digit = 1; - - /* We're past the IP/ASN part */ - if (separator) - { - val *= 10; - val += (*p - '0'); - } + + /* Low digit part must be there. */ + if (!digit || !separator) + goto error; + + /* Encode result into routing distinguisher. */ + if (dot) { + if (val > UINT16_MAX) + goto error; + + eval->val[0] = ECOMMUNITY_ENCODE_IP; + eval->val[1] = 0; + memcpy(&eval->val[2], &ip, sizeof(struct in_addr)); + eval->val[6] = (val >> 8) & 0xff; + eval->val[7] = val & 0xff; + } else if (as > BGP_AS_MAX) { + if (val > UINT16_MAX) + goto error; + + eval->val[0] = ECOMMUNITY_ENCODE_AS4; + eval->val[1] = 0; + 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; + } else { + eval->val[0] = ECOMMUNITY_ENCODE_AS; + eval->val[1] = 0; + + 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; } - p++; - } - - /* Low digit part must be there. */ - if (!digit || !separator) - goto error; - - /* Encode result into routing distinguisher. */ - if (dot) - { - if (val > UINT16_MAX) - goto error; - - eval->val[0] = ECOMMUNITY_ENCODE_IP; - eval->val[1] = 0; - memcpy (&eval->val[2], &ip, sizeof (struct in_addr)); - eval->val[6] = (val >> 8) & 0xff; - eval->val[7] = val & 0xff; - } - else if (as > BGP_AS_MAX) - { - if (val > UINT16_MAX) - goto error; - - eval->val[0] = ECOMMUNITY_ENCODE_AS4; - eval->val[1] = 0; - 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; - } - else - { - eval->val[0] = ECOMMUNITY_ENCODE_AS; - eval->val[1] = 0; - - 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; - } - *token = ecommunity_token_val; - return p; - - error: - *token = ecommunity_token_unknown; - return p; + *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 @@ -508,12 +469,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. @@ -521,80 +482,73 @@ 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; } -/* 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: @@ -602,284 +556,269 @@ ecommunity_str2com (const char *str, int type, int keyword_included) 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 encode = 0; - int type = 0; + int i; + u_int8_t *pnt; + int encode = 0; + int type = 0; #define ECOMMUNITY_STR_DEFAULT_LEN 27 - int str_size; - int str_pnt; - char *str_buf; - const char *prefix; - int len = 0; - int first = 1; - - /* 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; - - 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++) - { - /* 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; + const char *prefix; + int len = 0; + int first = 1; + + /* 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; + + if (ecom->size == 0) { + str_buf = XMALLOC(MTYPE_ECOMMUNITY_STR, 1); + str_buf[0] = '\0'; + return str_buf; } - /* Space between each value. */ - if (! first) - str_buf[str_pnt++] = ' '; - - pnt = ecom->val + (i * 8); - - /* High-order octet of type. */ - encode = *pnt++; - - switch (encode) - { - case ECOMMUNITY_ENCODE_AS: - case ECOMMUNITY_ENCODE_IP: - case ECOMMUNITY_ENCODE_AS4: - break; - - case 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); - str_pnt += len; - first = 0; - continue; - } - len = sprintf (str_buf + str_pnt, "?"); - str_pnt += len; - first = 0; - continue; - case 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]); - str_pnt += len; - first = 0; - continue; - } - len = sprintf (str_buf + str_pnt, "?"); - str_pnt += len; - first = 0; - continue; - default: - len = sprintf (str_buf + str_pnt, "?"); - str_pnt += len; - first = 0; - continue; - } - - /* Low-order octet of type. */ - type = *pnt++; - if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN) - { - len = sprintf (str_buf + str_pnt, "?"); - str_pnt += len; - first = 0; - continue; - } + /* 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++) { + /* 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); + } - switch (format) - { - case ECOMMUNITY_FORMAT_COMMUNITY_LIST: - prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo "); - break; - case ECOMMUNITY_FORMAT_DISPLAY: - prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:"); - break; - case ECOMMUNITY_FORMAT_ROUTE_MAP: - prefix = ""; - break; - default: - prefix = ""; - break; - } + /* Space between each value. */ + if (!first) + str_buf[str_pnt++] = ' '; + + pnt = ecom->val + (i * 8); + + /* High-order octet of type. */ + encode = *pnt++; + + switch (encode) { + case ECOMMUNITY_ENCODE_AS: + case ECOMMUNITY_ENCODE_IP: + case ECOMMUNITY_ENCODE_AS4: + break; + + case 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); + str_pnt += len; + first = 0; + continue; + } + len = sprintf(str_buf + str_pnt, "?"); + str_pnt += len; + first = 0; + continue; + case 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]); + str_pnt += len; + first = 0; + continue; + } + len = sprintf(str_buf + str_pnt, "?"); + str_pnt += len; + first = 0; + continue; + default: + len = sprintf(str_buf + str_pnt, "?"); + str_pnt += len; + first = 0; + continue; + } - /* Put string into buffer. */ - if (encode == 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( str_buf + str_pnt, "%s%u:%u", prefix, - eas.as, eas.val ); - str_pnt += len; - first = 0; - } - if (encode == 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 (str_buf + str_pnt, "%s%u:%u", prefix, - eas.as, eas.val); - str_pnt += len; - first = 0; - } - else if (encode == ECOMMUNITY_ENCODE_IP) - { - memcpy (&eip.ip, pnt, 4); - pnt += 4; - eip.val = (*pnt++ << 8); - eip.val |= (*pnt++); - - len = sprintf (str_buf + str_pnt, "%s%s:%u", prefix, - inet_ntoa (eip.ip), eip.val); - str_pnt += len; - first = 0; + /* Low-order octet of type. */ + type = *pnt++; + if (type != ECOMMUNITY_ROUTE_TARGET + && type != ECOMMUNITY_SITE_ORIGIN) { + len = sprintf(str_buf + str_pnt, "?"); + str_pnt += len; + first = 0; + continue; + } + + switch (format) { + case ECOMMUNITY_FORMAT_COMMUNITY_LIST: + prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " + : "soo "); + break; + case ECOMMUNITY_FORMAT_DISPLAY: + prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" + : "SoO:"); + break; + case ECOMMUNITY_FORMAT_ROUTE_MAP: + prefix = ""; + break; + default: + prefix = ""; + break; + } + + /* Put string into buffer. */ + if (encode == 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(str_buf + str_pnt, "%s%u:%u", prefix, + eas.as, eas.val); + str_pnt += len; + first = 0; + } + if (encode == 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(str_buf + str_pnt, "%s%u:%u", prefix, + eas.as, eas.val); + str_pnt += len; + first = 0; + } else if (encode == ECOMMUNITY_ENCODE_IP) { + memcpy(&eip.ip, pnt, 4); + pnt += 4; + eip.val = (*pnt++ << 8); + eip.val |= (*pnt++); + + len = sprintf(str_buf + str_pnt, "%s%s:%u", prefix, + inet_ntoa(eip.ip), eip.val); + 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; } |
