summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_ecommunity.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_ecommunity.c')
-rw-r--r--bgpd/bgp_ecommunity.c103
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;
}