From 8bcaad3dedcacab1cc7fdf9914d538427d497db8 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 24 Aug 2021 10:58:20 +0300 Subject: [PATCH] bgpd: Use IEEE-754 Floating Point for storing extcommunity bandwidth https://datatracker.ietf.org/doc/html/draft-ietf-idr-link-bandwidth-07 says: The bandwidth of the link is expressed as 4 octets in IEEE floating point format, units being bytes (not bits!) per second. It is carried in the Local Administrator subfield of the Value Field. Before: ``` Extended Community (16), length: 8, Flags [OT]: unknown extd community typecode (0x0004), Flags [none] 0x0000: 0004 fdeb 0001 e848 0x0000: 0004 fdeb 0001 e848 Updated routes: 172.16.16.1/32 ``` 0001 e848 - means 125000 (1Mbps), which is encoded incorrect. After: ``` Extended Community (16), length: 8, Flags [OT]: unknown extd community typecode (0x0004), Flags [none] 0x0000: 0004 fdeb 47f4 2400 0x0000: 0004 fdeb 47f4 2400 Updated routes: 172.16.16.1/32 ``` 47f4 2400 - means the same, but in floating point format. Signed-off-by: Donatas Abraitis --- bgpd/bgp_ecommunity.c | 20 +++++++++++++++++--- bgpd/bgp_ecommunity.h | 21 +++++++++++++++++---- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index bd3383b753..6d3abbd20d 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -836,11 +836,22 @@ static int ecommunity_rt_soo_str(char *buf, size_t bufsz, const uint8_t *pnt, ECOMMUNITY_SIZE); } +/* Helper function to convert IEEE-754 Floating Point to uint32 */ +static uint32_t ieee_float_uint32_to_uint32(uint32_t u) +{ + union { + float r; + uint32_t d; + } f = {.d = u}; + + return (uint32_t)f.r; +} + static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt) { int len = 0; as_t as; - uint32_t bw; + uint32_t bw_tmp, bw; char bps_buf[20] = {0}; #define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8) @@ -849,7 +860,10 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt) as = (*pnt++ << 8); as |= (*pnt++); - (void)ptr_get_be32(pnt, &bw); + (void)ptr_get_be32(pnt, &bw_tmp); + + bw = ieee_float_uint32_to_uint32(bw_tmp); + if (bw >= ONE_GBPS_BYTES) snprintf(bps_buf, sizeof(bps_buf), "%.3f Gbps", (float)(bw / ONE_GBPS_BYTES)); @@ -1533,7 +1547,7 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw) pnt = ptr_get_be32(pnt, &bwval); (void)pnt; /* consume value */ if (bw) - *bw = bwval; + *bw = ieee_float_uint32_to_uint32(bwval); return eval; } } diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 03b23fcd37..731a0c664e 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -198,6 +198,17 @@ static inline void encode_route_target_as4(as_t as, uint16_t val, eval->val[7] = val & 0xff; } +/* Helper function to convert uint32 to IEEE-754 Floating Point */ +static uint32_t uint32_to_ieee_float_uint32(uint32_t u) +{ + union { + float r; + uint32_t d; + } f = {.r = (float)u}; + + return f.d; +} + /* * Encode BGP Link Bandwidth extended community * bandwidth (bw) is in bytes-per-sec @@ -205,6 +216,8 @@ static inline void encode_route_target_as4(as_t as, uint16_t val, static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans, struct ecommunity_val *eval) { + uint32_t bandwidth = uint32_to_ieee_float_uint32(bw); + memset(eval, 0, sizeof(*eval)); eval->val[0] = ECOMMUNITY_ENCODE_AS; if (non_trans) @@ -212,10 +225,10 @@ static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans, eval->val[1] = ECOMMUNITY_LINK_BANDWIDTH; eval->val[2] = (as >> 8) & 0xff; eval->val[3] = as & 0xff; - eval->val[4] = (bw >> 24) & 0xff; - eval->val[5] = (bw >> 16) & 0xff; - eval->val[6] = (bw >> 8) & 0xff; - eval->val[7] = bw & 0xff; + eval->val[4] = (bandwidth >> 24) & 0xff; + eval->val[5] = (bandwidth >> 16) & 0xff; + eval->val[6] = (bandwidth >> 8) & 0xff; + eval->val[7] = bandwidth & 0xff; } extern void ecommunity_init(void); -- 2.39.5