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)
+{
+ 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,
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. */
if (!digit || !separator)
goto error;
- /* Encode result into routing distinguisher. */
+ /* Encode result into extended community. */
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;
- }
+ ecomm_type = ECOMMUNITY_ENCODE_IP;
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;
- }
+ ecomm_type = ECOMMUNITY_ENCODE_AS4;
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;
- }
+ ecomm_type = ECOMMUNITY_ENCODE_AS;
+ if (ecommunity_encode (ecomm_type, 0, 1, as, ip, val, eval))
+ goto error;
*token = ecommunity_token_val;
return p;
return ecom;
}
+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;
+}
+
/* Convert extended community attribute to string.
Due to historical reason of industry standard implementation, there
{
int i;
u_int8_t *pnt;
- int encode = 0;
int type = 0;
+ int sub_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);
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)
{
pnt = ecom->val + (i * 8);
/* High-order octet of type. */
- encode = *pnt++;
+ type = *pnt++;
- switch (encode)
+ if (type == ECOMMUNITY_ENCODE_AS ||
+ type == ECOMMUNITY_ENCODE_IP ||
+ type == ECOMMUNITY_ENCODE_AS4)
{
- case ECOMMUNITY_ENCODE_AS:
- case ECOMMUNITY_ENCODE_IP:
- case ECOMMUNITY_ENCODE_AS4:
- break;
-
- case ECOMMUNITY_ENCODE_OPAQUE:
- if(filter == ECOMMUNITY_ROUTE_TARGET)
- {
- continue;
- }
+ /* 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);
- 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;
}
+ else
+ unk_ecom = 1;
+ }
+ else if (type == ECOMMUNITY_ENCODE_EVPN)
+ {
+ if (filter == ECOMMUNITY_ROUTE_TARGET)
+ continue;
if (*pnt == ECOMMUNITY_SITE_ORIGIN)
{
char macaddr[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;
+ else
+ unk_ecom = 1;
}
+ else
+ unk_ecom = 1;
- /* 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;
- }
+ if (unk_ecom)
+ len = sprintf (str_buf + str_pnt, "?");
- /* 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;
- }
+ str_pnt += len;
+ first = 0;
}
+
return str_buf;
}
#define ecom_length(X) ((X)->size * ECOMMUNITY_SIZE)
+/*
+ * Encode BGP Route Target AS:nn.
+ */
+static inline void
+encode_route_target_as (as_t as, u_int32_t val,
+ struct ecommunity_val *eval)
+{
+ eval->val[0] = ECOMMUNITY_ENCODE_AS;
+ eval->val[1] = ECOMMUNITY_ROUTE_TARGET;
+ 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;
+}
+
+/*
+ * Encode BGP Route Target IP:nn.
+ */
+static inline void
+encode_route_target_ip (struct in_addr ip, u_int16_t val,
+ struct ecommunity_val *eval)
+{
+ eval->val[0] = ECOMMUNITY_ENCODE_IP;
+ eval->val[1] = ECOMMUNITY_ROUTE_TARGET;
+ memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
+ eval->val[6] = (val >> 8) & 0xff;
+ eval->val[7] = val & 0xff;
+}
+
+/*
+ * Encode BGP Route Target AS4:nn.
+ */
+static inline void
+encode_route_target_as4 (as_t as, u_int16_t val,
+ struct ecommunity_val *eval)
+{
+ eval->val[0] = ECOMMUNITY_ENCODE_AS4;
+ eval->val[1] = ECOMMUNITY_ROUTE_TARGET;
+ 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;
+}
+
extern void ecommunity_init (void);
extern void ecommunity_finish (void);
extern void ecommunity_free (struct ecommunity **);