From: vivek Date: Mon, 15 May 2017 19:31:01 +0000 (-0700) Subject: bgpd: Refine extended community handling X-Git-Tag: reindent-master-before~6^2~26 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=c5900768674b99a11d187e3584dc577bc05765b2;p=mirror%2Ffrr.git 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 Reviewed-by: Donald Sharp --- diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 0555d1bbe3..bb2ef260ee 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -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; - } - - 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; } diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index d6006e81d5..8981ea3465 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -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 **);