mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 00:56:19 +00:00
bgpd: Refine extended community handling
Define helper functions to form different kinds of route targets. Also, refine functions that encode extended communities as well as generate a string from an extended community. Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com> Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
parent
cec2e17d27
commit
c590076867
@ -304,6 +304,61 @@ enum ecommunity_token
|
||||
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,
|
||||
@ -318,6 +373,7 @@ 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. */
|
||||
@ -452,44 +508,15 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
|
||||
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;
|
||||
|
||||
@ -581,6 +608,81 @@ ecommunity_str2com (const char *str, int type, int keyword_included)
|
||||
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
|
||||
@ -610,29 +712,15 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
|
||||
{
|
||||
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);
|
||||
@ -648,6 +736,8 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
|
||||
|
||||
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)
|
||||
{
|
||||
@ -662,39 +752,39 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
|
||||
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];
|
||||
@ -703,91 +793,20 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
|
||||
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;
|
||||
}
|
||||
if (unk_ecom)
|
||||
len = sprintf (str_buf + str_pnt, "?");
|
||||
|
||||
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;
|
||||
}
|
||||
str_pnt += len;
|
||||
first = 0;
|
||||
}
|
||||
|
||||
return str_buf;
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,54 @@ struct ecommunity_val
|
||||
|
||||
#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 **);
|
||||
|
Loading…
Reference in New Issue
Block a user