]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: Use IEEE-754 Floating Point for storing extcommunity bandwidth
authorDonatas Abraitis <donatas.abraitis@gmail.com>
Tue, 24 Aug 2021 07:58:20 +0000 (10:58 +0300)
committerDonatas Abraitis <donatas.abraitis@gmail.com>
Sun, 29 Aug 2021 18:10:27 +0000 (21:10 +0300)
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 <donatas.abraitis@gmail.com>
bgpd/bgp_ecommunity.c
bgpd/bgp_ecommunity.h

index bd3383b753e7623eb5153dedbd6802b2b59774fa..6d3abbd20dee7d4481b9ada7960f1c0d913df92b 100644 (file)
@@ -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;
                }
        }
index 03b23fcd37405e6d10d02474cc5b14fbe54aab20..731a0c664ed1171ddc37ffd0efea46093808f5a0 100644 (file)
@@ -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);