summaryrefslogtreecommitdiff
path: root/bgpd/bgp_ecommunity.c
diff options
context:
space:
mode:
authorDonatas Abraitis <donatas@opensourcerouting.org>2023-06-27 13:03:22 +0300
committerGitHub <noreply@github.com>2023-06-27 13:03:22 +0300
commit4199f032e594984e08dddf079e4b4e8755f20c85 (patch)
tree8f53f63df9f911814e1c9e72967b90461125d11b /bgpd/bgp_ecommunity.c
parentf018e3cdcfe3671be8bbcc59a834ef4b64fb16a8 (diff)
parentfc4478721150af6177a5101bdee8359acfa300d8 (diff)
Merge pull request #13722 from fdumontet6WIND/color_extcomm
bgpd,lib,yang: add colored extended communities support
Diffstat (limited to 'bgpd/bgp_ecommunity.c')
-rw-r--r--bgpd/bgp_ecommunity.c120
1 files changed, 105 insertions, 15 deletions
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 29b2250747..e473468dbf 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -355,6 +355,22 @@ bool ecommunity_cmp(const void *arg1, const void *arg2)
ecom1->unit_size) == 0);
}
+static void ecommunity_color_str(char *buf, size_t bufsz, uint8_t *ptr)
+{
+ /*
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x03 | Sub-Type(0x0b) | Flags |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Color Value |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ uint32_t colorid;
+
+ memcpy(&colorid, ptr + 3, 4);
+ colorid = ntohl(colorid);
+ snprintf(buf, bufsz, "Color:%d", colorid);
+}
+
/* Initialize Extended Comminities related hash. */
void ecommunity_init(void)
{
@@ -373,6 +389,7 @@ enum ecommunity_token {
ecommunity_token_rt,
ecommunity_token_nt,
ecommunity_token_soo,
+ ecommunity_token_color,
ecommunity_token_val,
ecommunity_token_rt6,
ecommunity_token_val6,
@@ -510,6 +527,9 @@ static int ecommunity_encode_internal(uint8_t type, uint8_t sub_type,
memcpy(&eval6->val[2], ip6, sizeof(struct in6_addr));
eval6->val[18] = (val >> 8) & 0xff;
eval6->val[19] = val & 0xff;
+ } else if (type == ECOMMUNITY_ENCODE_OPAQUE &&
+ sub_type == ECOMMUNITY_COLOR) {
+ encode_color(val, eval);
} else {
encode_route_target_as4(as, val, eval, trans);
}
@@ -537,16 +557,22 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,
int dot = 0;
int digit = 0;
int separator = 0;
+ int i;
const char *p = str;
char *endptr;
struct in_addr ip;
struct in6_addr ip6;
as_t as = 0;
uint32_t val = 0;
- uint8_t ecomm_type;
+ uint32_t val_color = 0;
+ uint8_t ecomm_type = 0;
+ uint8_t sub_type = 0;
char buf[INET_ADDRSTRLEN + 1];
struct ecommunity_val *eval = (struct ecommunity_val *)eval_ptr;
uint64_t tmp_as = 0;
+ static const char str_color[5] = "color";
+ const char *ptr_color;
+ bool val_color_set = false;
/* Skip white space. */
while (isspace((unsigned char)*p)) {
@@ -558,7 +584,7 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,
if (*p == '\0')
return NULL;
- /* "rt", "nt", and "soo" keyword parse. */
+ /* "rt", "nt", "soo", and "color" keyword parse. */
if (!isdigit((unsigned char)*p)) {
/* "rt" match check. */
if (tolower((unsigned char)*p) == 'r') {
@@ -612,10 +638,33 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,
return p;
}
goto error;
+ } else if (tolower((unsigned char)*p) == 'c') {
+ /* "color" match check.
+ * 'c', 'co', 'col', 'colo' are also accepted
+ */
+ for (i = 0; i < 5; i++) {
+ ptr_color = &str_color[0];
+ if (tolower((unsigned char)*p) == *ptr_color) {
+ p++;
+ ptr_color++;
+ } else if (i > 0) {
+ if (isspace((unsigned char)*p) ||
+ *p == '\0') {
+ *token = ecommunity_token_color;
+ return p;
+ }
+ goto error;
+ }
+ if (isspace((unsigned char)*p) || *p == '\0') {
+ *token = ecommunity_token_color;
+ return p;
+ }
+ goto error;
+ }
+ goto error;
}
goto error;
}
-
/* What a mess, there are several possibilities:
*
* a) A.B.C.D:MN
@@ -716,17 +765,24 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,
} else {
digit = 1;
- /* We're past the IP/ASN part */
+ /* We're past the IP/ASN part,
+ * or we have a color
+ */
if (separator) {
val *= 10;
val += (*p - '0');
+ val_color_set = false;
+ } else {
+ val_color *= 10;
+ val_color += (*p - '0');
+ val_color_set = true;
}
}
p++;
}
/* Low digit part must be there. */
- if (!digit || !separator)
+ if (!digit && (!separator || !val_color_set))
goto error;
/* Encode result into extended community. */
@@ -734,9 +790,15 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,
ecomm_type = ECOMMUNITY_ENCODE_IP;
else if (as > BGP_AS_MAX)
ecomm_type = ECOMMUNITY_ENCODE_AS4;
- else
+ else if (as > 0)
ecomm_type = ECOMMUNITY_ENCODE_AS;
- if (ecommunity_encode(ecomm_type, type, 1, as, ip, val, eval))
+ else if (val_color) {
+ ecomm_type = ECOMMUNITY_ENCODE_OPAQUE;
+ sub_type = ECOMMUNITY_COLOR;
+ val = val_color;
+ }
+
+ if (ecommunity_encode(ecomm_type, sub_type, 1, as, ip, val, eval))
goto error;
*token = ecommunity_token_val;
return p;
@@ -763,6 +825,7 @@ static struct ecommunity *ecommunity_str2com_internal(const char *str, int type,
case ecommunity_token_nt:
case ecommunity_token_rt6:
case ecommunity_token_soo:
+ case ecommunity_token_color:
if (!keyword_included || keyword) {
if (ecom)
ecommunity_free(&ecom);
@@ -771,15 +834,14 @@ static struct ecommunity *ecommunity_str2com_internal(const char *str, int type,
keyword = 1;
if (token == ecommunity_token_rt ||
- token == ecommunity_token_rt6) {
+ token == ecommunity_token_rt6)
type = ECOMMUNITY_ROUTE_TARGET;
- }
- if (token == ecommunity_token_soo) {
+ if (token == ecommunity_token_soo)
type = ECOMMUNITY_SITE_ORIGIN;
- }
- if (token == ecommunity_token_nt) {
+ if (token == ecommunity_token_nt)
type = ECOMMUNITY_NODE_TARGET;
- }
+ if (token == ecommunity_token_color)
+ type = ECOMMUNITY_COLOR;
break;
case ecommunity_token_val:
if (keyword_included) {
@@ -998,10 +1060,12 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,
"rt 100:1 100:2soo 100:3"
extcommunity-list
- "rt 100:1 rt 100:2 soo 100:3show [ip] bgp" and extcommunity-list regular expression matching
+ "rt 100:1 rt 100:2 soo 100:3
+ show [ip] bgp"
+ and extcommunity-list regular expression matching
"RT:100:1 RT:100:2 SoO:100:3"
- For each formath please use below definition for format:
+ For each format please use below definition for format:
ECOMMUNITY_FORMAT_ROUTE_MAP
ECOMMUNITY_FORMAT_COMMUNITY_LIST
@@ -1086,6 +1150,9 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
} else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) {
strlcpy(encbuf, "Default Gateway",
sizeof(encbuf));
+ } else if (*pnt == ECOMMUNITY_COLOR) {
+ ecommunity_color_str(encbuf, sizeof(encbuf),
+ pnt);
} else {
unk_ecom = 1;
}
@@ -1353,6 +1420,29 @@ bool ecommunity_match(const struct ecommunity *ecom1,
return false;
}
+/* return last occurence of color */
+/* it will be the greatest color value */
+extern uint32_t ecommunity_select_color(const struct ecommunity *ecom)
+{
+
+ uint32_t aux_color = 0;
+ uint8_t *p;
+ uint32_t c = 0;
+
+ /* If the value already exists in the structure return 0. */
+
+ for (p = ecom->val; c < ecom->size; p += ecom->unit_size, c++) {
+ if (p == NULL)
+ break;
+
+ if (p[0] == ECOMMUNITY_ENCODE_OPAQUE &&
+ p[1] == ECOMMUNITY_COLOR)
+ ptr_get_be32((const uint8_t *)&p[4], &aux_color);
+ }
+ return aux_color;
+}
+
+
/* return first occurence of type */
extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *ecom,
uint8_t type, uint8_t subtype)