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,
|
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. */
|
/* Get next Extended Communities token from the string. */
|
||||||
static const char *
|
static const char *
|
||||||
ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
|
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;
|
struct in_addr ip;
|
||||||
as_t as = 0;
|
as_t as = 0;
|
||||||
u_int32_t val = 0;
|
u_int32_t val = 0;
|
||||||
|
u_char ecomm_type;
|
||||||
char buf[INET_ADDRSTRLEN + 1];
|
char buf[INET_ADDRSTRLEN + 1];
|
||||||
|
|
||||||
/* Skip white space. */
|
/* Skip white space. */
|
||||||
@ -452,44 +508,15 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
|
|||||||
if (!digit || !separator)
|
if (!digit || !separator)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Encode result into routing distinguisher. */
|
/* Encode result into extended community. */
|
||||||
if (dot)
|
if (dot)
|
||||||
{
|
ecomm_type = ECOMMUNITY_ENCODE_IP;
|
||||||
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)
|
else if (as > BGP_AS_MAX)
|
||||||
{
|
ecomm_type = ECOMMUNITY_ENCODE_AS4;
|
||||||
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
|
else
|
||||||
{
|
ecomm_type = ECOMMUNITY_ENCODE_AS;
|
||||||
eval->val[0] = ECOMMUNITY_ENCODE_AS;
|
if (ecommunity_encode (ecomm_type, 0, 1, as, ip, val, eval))
|
||||||
eval->val[1] = 0;
|
goto error;
|
||||||
|
|
||||||
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;
|
*token = ecommunity_token_val;
|
||||||
return p;
|
return p;
|
||||||
|
|
||||||
@ -581,6 +608,81 @@ ecommunity_str2com (const char *str, int type, int keyword_included)
|
|||||||
return ecom;
|
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.
|
/* Convert extended community attribute to string.
|
||||||
|
|
||||||
Due to historical reason of industry standard implementation, there
|
Due to historical reason of industry standard implementation, there
|
||||||
@ -610,29 +712,15 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
u_int8_t *pnt;
|
u_int8_t *pnt;
|
||||||
int encode = 0;
|
|
||||||
int type = 0;
|
int type = 0;
|
||||||
|
int sub_type = 0;
|
||||||
#define ECOMMUNITY_STR_DEFAULT_LEN 27
|
#define ECOMMUNITY_STR_DEFAULT_LEN 27
|
||||||
int str_size;
|
int str_size;
|
||||||
int str_pnt;
|
int str_pnt;
|
||||||
char *str_buf;
|
char *str_buf;
|
||||||
const char *prefix;
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int first = 1;
|
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)
|
if (ecom->size == 0)
|
||||||
{
|
{
|
||||||
str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1);
|
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++)
|
for (i = 0; i < ecom->size; i++)
|
||||||
{
|
{
|
||||||
|
int unk_ecom = 0;
|
||||||
|
|
||||||
/* Make it sure size is enough. */
|
/* Make it sure size is enough. */
|
||||||
while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
|
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);
|
pnt = ecom->val + (i * 8);
|
||||||
|
|
||||||
/* High-order octet of type. */
|
/* 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:
|
/* Low-order octet of type. */
|
||||||
case ECOMMUNITY_ENCODE_IP:
|
sub_type = *pnt++;
|
||||||
case ECOMMUNITY_ENCODE_AS4:
|
if (sub_type != ECOMMUNITY_ROUTE_TARGET &&
|
||||||
break;
|
sub_type != ECOMMUNITY_SITE_ORIGIN)
|
||||||
|
unk_ecom = 1;
|
||||||
case ECOMMUNITY_ENCODE_OPAQUE:
|
else
|
||||||
if(filter == ECOMMUNITY_ROUTE_TARGET)
|
len = ecommunity_rt_soo_str (str_buf + str_pnt, pnt, type,
|
||||||
{
|
sub_type, format);
|
||||||
continue;
|
}
|
||||||
}
|
else if (type == ECOMMUNITY_ENCODE_OPAQUE)
|
||||||
|
{
|
||||||
|
if (filter == ECOMMUNITY_ROUTE_TARGET)
|
||||||
|
continue;
|
||||||
if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP)
|
if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP)
|
||||||
{
|
{
|
||||||
uint16_t tunneltype;
|
uint16_t tunneltype;
|
||||||
memcpy (&tunneltype, pnt + 5, 2);
|
memcpy (&tunneltype, pnt + 5, 2);
|
||||||
tunneltype = ntohs(tunneltype);
|
tunneltype = ntohs(tunneltype);
|
||||||
len = sprintf (str_buf + str_pnt, "ET:%d", 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)
|
if (*pnt == ECOMMUNITY_SITE_ORIGIN)
|
||||||
{
|
{
|
||||||
char macaddr[6];
|
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",
|
len = sprintf(str_buf + str_pnt, "EVPN:%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
macaddr[0], macaddr[1], macaddr[2],
|
macaddr[0], macaddr[1], macaddr[2],
|
||||||
macaddr[3], macaddr[4], macaddr[5]);
|
macaddr[3], macaddr[4], macaddr[5]);
|
||||||
str_pnt += len;
|
|
||||||
first = 0;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
len = sprintf (str_buf + str_pnt, "?");
|
else
|
||||||
str_pnt += len;
|
unk_ecom = 1;
|
||||||
first = 0;
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
len = sprintf (str_buf + str_pnt, "?");
|
|
||||||
str_pnt += len;
|
|
||||||
first = 0;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
unk_ecom = 1;
|
||||||
|
|
||||||
/* Low-order octet of type. */
|
if (unk_ecom)
|
||||||
type = *pnt++;
|
len = sprintf (str_buf + str_pnt, "?");
|
||||||
if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
|
|
||||||
{
|
|
||||||
len = sprintf (str_buf + str_pnt, "?");
|
|
||||||
str_pnt += len;
|
|
||||||
first = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (format)
|
str_pnt += len;
|
||||||
{
|
first = 0;
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +76,54 @@ struct ecommunity_val
|
|||||||
|
|
||||||
#define ecom_length(X) ((X)->size * ECOMMUNITY_SIZE)
|
#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_init (void);
|
||||||
extern void ecommunity_finish (void);
|
extern void ecommunity_finish (void);
|
||||||
extern void ecommunity_free (struct ecommunity **);
|
extern void ecommunity_free (struct ecommunity **);
|
||||||
|
Loading…
Reference in New Issue
Block a user