diff options
Diffstat (limited to 'bgpd/bgp_ecommunity.c')
-rw-r--r-- | bgpd/bgp_ecommunity.c | 103 |
1 files changed, 89 insertions, 14 deletions
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 64f4438f..3e62496d 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -27,6 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgpd.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_aspath.h" /* Hash of community attribute. */ struct hash *ecomhash; @@ -283,7 +284,9 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval, u_int32_t val_high = 0; const char *p = str; struct in_addr ip; - char ipstr[INET_ADDRSTRLEN + 1]; + as_t as4; + int wantas4; + char helpstr[INET_ADDRSTRLEN + 1]; /* Skip white space. */ while (isspace ((int) *p)) @@ -297,7 +300,7 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval, return NULL; /* "rt" and "soo" keyword parse. */ - if (! isdigit ((int) *p)) + if (! isdigit ((int) *p) && *p != '+') { /* "rt" match check. */ if (tolower ((int) *p) == 'r') @@ -346,9 +349,23 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval, goto error; } - while (isdigit ((int) *p) || *p == ':' || *p == '.') + as4 = (as_t) 0; wantas4 = 0; + while (isdigit ((int) *p) || *p == ':' || *p == '.' || *p == '+' ) { - if (*p == ':') + if ( *p == '+' ) + { + /* '+' indicates an AS number which should be encoded + * into a ECOMMUNITY_ENCODE_AS4 + * The actual *value* of the as number is independent + * of the line representation of the extended community + */ + /* test: seen a '+' before? that is an error */ + if ( as4 || wantas4 || val_low || val_high ) + goto error; + + wantas4 = 1; + } + else if (*p == ':') { if (separator) goto error; @@ -361,12 +378,30 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval, if ((p - str) > INET_ADDRSTRLEN) goto error; - memset (ipstr, 0, INET_ADDRSTRLEN + 1); - memcpy (ipstr, str, p - str); + memset (helpstr, 0, INET_ADDRSTRLEN + 1); + memcpy (helpstr, str, p - str); - ret = inet_aton (ipstr, &ip); - if (ret == 0) - goto error; + if ( dot == 1 ) + { + /* ONE dot => 4 Byte AS number */ + if ( wantas4 ) + { + /* wantas4: skip the '+' at the start */ + as4 = str2asnum( helpstr+1, NULL); + } + else + { + as4 = str2asnum( helpstr, NULL); + } + if ( !as4 ) + goto error; + } + else + { + ret = inet_aton (helpstr, &ip); + if (ret == 0) + goto error; + } } else val_high = val_low; @@ -394,8 +429,24 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval, if (! digit || ! separator) goto error; + /* move asnumber to as4, even if it is < 65536 */ + if ( !as4 && dot != 1 ) + { + as4 = val_high; + } /* Encode result into routing distinguisher. */ - if (dot) + if (wantas4) + { + eval->val[0] = ECOMMUNITY_ENCODE_AS4; + eval->val[1] = 0; + eval->val[2] = (as4 >>24) & 0xff; + eval->val[3] = (as4 >>16) & 0xff; + eval->val[4] = (as4 >>8) & 0xff; + eval->val[5] = as4 & 0xff; + eval->val[6] = (val_low >> 8) & 0xff; + eval->val[7] = val_low & 0xff; + } + else if (dot && dot != 1) { eval->val[0] = ECOMMUNITY_ENCODE_IP; eval->val[1] = 0; @@ -407,6 +458,14 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval, { eval->val[0] = ECOMMUNITY_ENCODE_AS; eval->val[1] = 0; + if ( as4 > 65535 ) + { + /* ENCODE_AS can only code with < 65536. + * use BGP_AS_TRANS if we have a too big as number + */ + + val_high = BGP_AS_TRANS; + } eval->val[2] = (val_high >>8) & 0xff; eval->val[3] = val_high & 0xff; eval->val[4] = (val_low >>24) & 0xff; @@ -533,7 +592,7 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) u_int8_t *pnt; int encode = 0; int type = 0; -#define ECOMMUNITY_STR_DEFAULT_LEN 26 +#define ECOMMUNITY_STR_DEFAULT_LEN 27 int str_size; int str_pnt; char *str_buf; @@ -576,7 +635,8 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) /* High-order octet of type. */ encode = *pnt++; - if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP) + if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP + && encode != ECOMMUNITY_ENCODE_AS4) { len = sprintf (str_buf + str_pnt, "?"); str_pnt += len; @@ -618,6 +678,21 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) } /* 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+%s:%d", prefix, + as2str(eas.as), eas.val ); + str_pnt += len; + first = 0; + } if (encode == ECOMMUNITY_ENCODE_AS) { eas.as = (*pnt++ << 8); @@ -628,8 +703,8 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) eas.val |= (*pnt++ << 8); eas.val |= (*pnt++); - len = sprintf (str_buf + str_pnt, "%s%d:%d", prefix, - eas.as, eas.val); + len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix, + as2str(eas.as), eas.val); str_pnt += len; first = 0; } |