]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: Add `neighbor PEER link-bw-encoding-ieee`
authorDonatas Abraitis <donatas.abraitis@gmail.com>
Sun, 29 Aug 2021 18:54:13 +0000 (21:54 +0300)
committerDonatas Abraitis <donatas.abraitis@gmail.com>
Mon, 30 Aug 2021 11:21:49 +0000 (14:21 +0300)
This is to avoid breaking changes between existing deployments of
extended community for bandwidth encoding. By default FRR uses uint32
to encode bandwidth, which is not as the draft requires (IEEE floating-point).

This switch enables the required encoding per-peer.

Signed-off-by: Donatas Abraitis <donatas.abraitis@gmail.com>
bgpd/bgp_attr.c
bgpd/bgp_ecommunity.c
bgpd/bgp_ecommunity.h
bgpd/bgp_mpath.c
bgpd/bgp_route.c
bgpd/bgp_routemap.c
bgpd/bgp_vty.c
bgpd/bgpd.c
bgpd/bgpd.h
tests/bgpd/test_ecommunity.c

index fb97fea72d72fedc5a9be25e72d424a70209687e..f1c953f21d22fc911c7de772139d1c1471e0bdaa 100644 (file)
@@ -2311,8 +2311,10 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
-       attr->ecommunity =
-               ecommunity_parse(stream_pnt(peer->curr), length);
+       attr->ecommunity = ecommunity_parse(
+               stream_pnt(peer->curr), length,
+               CHECK_FLAG(peer->flags,
+                          PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
        /* XXX: fix ecommunity_parse to use stream API */
        stream_forward_getp(peer->curr, length);
 
@@ -2380,7 +2382,10 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
-       ipv6_ecomm = ecommunity_parse_ipv6(stream_pnt(peer->curr), length);
+       ipv6_ecomm = ecommunity_parse_ipv6(
+               stream_pnt(peer->curr), length,
+               CHECK_FLAG(peer->flags,
+                          PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
        bgp_attr_set_ipv6_ecommunity(attr, ipv6_ecomm);
 
        /* XXX: fix ecommunity_parse to use stream API */
index 6d3abbd20dee7d4481b9ada7960f1c0d913df92b..1e95d401aace2739ebc73898256a8b5ba7a36357 100644 (file)
@@ -201,6 +201,7 @@ ecommunity_uniq_sort_internal(struct ecommunity *ecom,
 
        new = ecommunity_new();
        new->unit_size = ecom_size;
+       new->disable_ieee_floating = ecom->disable_ieee_floating;
 
        for (i = 0; i < ecom->size; i++) {
                eval = (void *)(ecom->val + (i * ecom_size));
@@ -220,8 +221,9 @@ struct ecommunity *ecommunity_uniq_sort(struct ecommunity *ecom)
 
 /* Parse Extended Communites Attribute in BGP packet.  */
 static struct ecommunity *ecommunity_parse_internal(uint8_t *pnt,
-                                       unsigned short length,
-                                       unsigned short size_ecom)
+                                                   unsigned short length,
+                                                   unsigned short size_ecom,
+                                                   bool disable_ieee_floating)
 {
        struct ecommunity tmp;
        struct ecommunity *new;
@@ -234,6 +236,7 @@ static struct ecommunity *ecommunity_parse_internal(uint8_t *pnt,
           Attribute.  */
        tmp.size = length / size_ecom;
        tmp.val = pnt;
+       tmp.disable_ieee_floating = disable_ieee_floating;
 
        /* Create a new Extended Communities Attribute by uniq and sort each
           Extended Communities value  */
@@ -242,17 +245,18 @@ static struct ecommunity *ecommunity_parse_internal(uint8_t *pnt,
        return ecommunity_intern(new);
 }
 
-struct ecommunity *ecommunity_parse(uint8_t *pnt,
-                                   unsigned short length)
+struct ecommunity *ecommunity_parse(uint8_t *pnt, unsigned short length,
+                                   bool disable_ieee_floating)
 {
-       return ecommunity_parse_internal(pnt, length, ECOMMUNITY_SIZE);
+       return ecommunity_parse_internal(pnt, length, ECOMMUNITY_SIZE,
+                                        disable_ieee_floating);
 }
 
-struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt,
-                                        unsigned short length)
+struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, unsigned short length,
+                                        bool disable_ieee_floating)
 {
-       return ecommunity_parse_internal(pnt, length,
-                                        IPV6_ECOMMUNITY_SIZE);
+       return ecommunity_parse_internal(pnt, length, IPV6_ECOMMUNITY_SIZE,
+                                        disable_ieee_floating);
 }
 
 /* Duplicate the Extended Communities Attribute structure.  */
@@ -847,7 +851,8 @@ static uint32_t ieee_float_uint32_to_uint32(uint32_t u)
        return (uint32_t)f.r;
 }
 
-static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt)
+static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,
+                            bool disable_ieee_floating)
 {
        int len = 0;
        as_t as;
@@ -862,7 +867,8 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt)
        as |= (*pnt++);
        (void)ptr_get_be32(pnt, &bw_tmp);
 
-       bw = ieee_float_uint32_to_uint32(bw_tmp);
+       bw = disable_ieee_floating ? bw_tmp
+                                  : ieee_float_uint32_to_uint32(bw_tmp);
 
        if (bw >= ONE_GBPS_BYTES)
                snprintf(bps_buf, sizeof(bps_buf), "%.3f Gbps",
@@ -954,8 +960,9 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                                } else if (sub_type ==
                                           ECOMMUNITY_LINK_BANDWIDTH &&
                                           type == ECOMMUNITY_ENCODE_AS) {
-                                       ecommunity_lb_str(encbuf,
-                                               sizeof(encbuf), pnt);
+                                       ecommunity_lb_str(
+                                               encbuf, sizeof(encbuf), pnt,
+                                               ecom->disable_ieee_floating);
                                } else
                                        unk_ecom = 1;
                        } else {
@@ -1161,7 +1168,8 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                } else if (type == ECOMMUNITY_ENCODE_AS_NON_TRANS) {
                        sub_type = *pnt++;
                        if (sub_type == ECOMMUNITY_LINK_BANDWIDTH)
-                               ecommunity_lb_str(encbuf, sizeof(encbuf), pnt);
+                               ecommunity_lb_str(encbuf, sizeof(encbuf), pnt,
+                                                 ecom->disable_ieee_floating);
                        else
                                unk_ecom = 1;
                } else {
@@ -1547,7 +1555,10 @@ 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 = ieee_float_uint32_to_uint32(bwval);
+                               *bw = ecom->disable_ieee_floating
+                                             ? bwval
+                                             : ieee_float_uint32_to_uint32(
+                                                       bwval);
                        return eval;
                }
        }
@@ -1556,9 +1567,9 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
 }
 
 
-struct ecommunity *ecommunity_replace_linkbw(as_t as,
-                                            struct ecommunity *ecom,
-                                            uint64_t cum_bw)
+struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom,
+                                            uint64_t cum_bw,
+                                            bool disable_ieee_floating)
 {
        struct ecommunity *new;
        struct ecommunity_val lb_eval;
@@ -1588,8 +1599,8 @@ struct ecommunity *ecommunity_replace_linkbw(as_t as,
         */
        if (cum_bw > 0xFFFFFFFF)
                cum_bw = 0xFFFFFFFF;
-       encode_lb_extcomm(as > BGP_AS_MAX ? BGP_AS_TRANS : as, cum_bw,
-                         false, &lb_eval);
+       encode_lb_extcomm(as > BGP_AS_MAX ? BGP_AS_TRANS : as, cum_bw, false,
+                         &lb_eval, disable_ieee_floating);
        new = ecommunity_dup(ecom);
        ecommunity_add_val(new, &lb_eval, true, true);
 
index 731a0c664ed1171ddc37ffd0efea46093808f5a0..f22855c329076f3b40afdee136d366434640d983 100644 (file)
@@ -124,6 +124,9 @@ struct ecommunity {
 
        /* Human readable format string.  */
        char *str;
+
+       /* Disable IEEE floating-point encoding for extended community */
+       bool disable_ieee_floating;
 };
 
 struct ecommunity_as {
@@ -214,9 +217,11 @@ static uint32_t uint32_to_ieee_float_uint32(uint32_t u)
  *  bandwidth (bw) is in bytes-per-sec
  */
 static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans,
-                                    struct ecommunity_val *eval)
+                                    struct ecommunity_val *eval,
+                                    bool disable_ieee_floating)
 {
-       uint32_t bandwidth = uint32_to_ieee_float_uint32(bw);
+       uint32_t bandwidth =
+               disable_ieee_floating ? bw : uint32_to_ieee_float_uint32(bw);
 
        memset(eval, 0, sizeof(*eval));
        eval->val[0] = ECOMMUNITY_ENCODE_AS;
@@ -234,9 +239,11 @@ static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans,
 extern void ecommunity_init(void);
 extern void ecommunity_finish(void);
 extern void ecommunity_free(struct ecommunity **);
-extern struct ecommunity *ecommunity_parse(uint8_t *, unsigned short);
+extern struct ecommunity *ecommunity_parse(uint8_t *, unsigned short,
+                                          bool disable_ieee_floating);
 extern struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt,
-                                               unsigned short length);
+                                               unsigned short length,
+                                               bool disable_ieee_floating);
 extern struct ecommunity *ecommunity_dup(struct ecommunity *);
 extern struct ecommunity *ecommunity_merge(struct ecommunity *,
                                           struct ecommunity *);
@@ -294,7 +301,9 @@ extern void bgp_aggr_ecommunity_remove(void *arg);
 extern const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom,
                                                uint32_t *bw);
 extern struct ecommunity *ecommunity_replace_linkbw(as_t as,
-                               struct ecommunity *ecom, uint64_t cum_bw);
+                                                   struct ecommunity *ecom,
+                                                   uint64_t cum_bw,
+                                                   bool disable_ieee_floating);
 
 static inline void ecommunity_strip_rts(struct ecommunity *ecom)
 {
index 8127428bc71dc8597f1e980cad539a7993e38024..1d727d267a9b4b7bc7cba563879ab7b9fd568fe8 100644 (file)
@@ -610,7 +610,8 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest,
                                prev_mpath = cur_mpath;
                                mpath_count++;
                                if (ecommunity_linkbw_present(
-                                       cur_mpath->attr->ecommunity, &bwval))
+                                           cur_mpath->attr->ecommunity,
+                                           &bwval))
                                        cum_bw += bwval;
                                else
                                        all_paths_lb = false;
@@ -699,7 +700,8 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest,
                                mpath_changed = 1;
                                mpath_count++;
                                if (ecommunity_linkbw_present(
-                                       new_mpath->attr->ecommunity, &bwval))
+                                           new_mpath->attr->ecommunity,
+                                           &bwval))
                                        cum_bw += bwval;
                                else
                                        all_paths_lb = false;
@@ -721,9 +723,9 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest,
 
        if (new_best) {
                bgp_path_info_mpath_count_set(new_best, mpath_count - 1);
-               if (mpath_count <= 1 ||
-                   !ecommunity_linkbw_present(
-                       new_best->attr->ecommunity, &bwval))
+               if (mpath_count <= 1
+                   || !ecommunity_linkbw_present(new_best->attr->ecommunity,
+                                                 &bwval))
                        all_paths_lb = false;
                else
                        cum_bw += bwval;
index f97a791dae07c3146202ac37cda40311db0c94c5..b164d710a516104f71dfb241ec558a6cadd54e18 100644 (file)
@@ -2276,7 +2276,9 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
            (cum_bw = bgp_path_info_mpath_cumbw(pi)) != 0 &&
            !CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET))
                attr->ecommunity = ecommunity_replace_linkbw(
-                                       bgp->as, attr->ecommunity, cum_bw);
+                       bgp->as, attr->ecommunity, cum_bw,
+                       CHECK_FLAG(peer->flags,
+                                  PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
 
        return true;
 }
index 5e566f360ae9eef57ec9cc5e2d2a705bc3957632..7be22e6929c41bdc2fafc430a41f40bf8d9a97eb 100644 (file)
@@ -2658,7 +2658,9 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object)
                bw_bytes *= mpath_count;
        }
 
-       encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval);
+       encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval,
+                         CHECK_FLAG(peer->flags,
+                                    PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
 
        /* add to route or merge with existing */
        old_ecom = path->attr->ecommunity;
index 715a768fd851ab71fefb050736747ea747b05008..ccef02a3f7706ce3ccd8ff796cb491a10d08c23f 100644 (file)
@@ -6138,6 +6138,29 @@ DEFUN (no_neighbor_disable_connected_check,
                                   PEER_FLAG_DISABLE_CONNECTED_CHECK);
 }
 
+/* link-bw-encoding-ieee */
+DEFUN(neighbor_link_bw_encoding_ieee, neighbor_link_bw_encoding_ieee_cmd,
+      "neighbor <A.B.C.D|X:X::X:X|WORD> disable-link-bw-encoding-ieee",
+      NEIGHBOR_STR NEIGHBOR_ADDR_STR2
+      "Enable IEEE floating-point encoding for extended community bandwidth\n")
+{
+       int idx_peer = 1;
+
+       return peer_flag_set_vty(vty, argv[idx_peer]->arg,
+                                PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE);
+}
+
+DEFUN(no_neighbor_link_bw_encoding_ieee, no_neighbor_link_bw_encoding_ieee_cmd,
+      "no neighbor <A.B.C.D|X:X::X:X|WORD> disable-link-bw-encoding-ieee",
+      NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
+      "Enable IEEE floating-point encoding for extended community bandwidth\n")
+{
+       int idx_peer = 2;
+
+       return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
+                                  PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE);
+}
+
 
 /* enforce-first-as */
 DEFUN (neighbor_enforce_first_as,
@@ -16347,6 +16370,11 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
        if (peergroup_flag_check(peer, PEER_FLAG_DISABLE_CONNECTED_CHECK))
                vty_out(vty, " neighbor %s disable-connected-check\n", addr);
 
+       /* link-bw-encoding-ieee */
+       if (peergroup_flag_check(peer, PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE))
+               vty_out(vty, " neighbor %s disable-link-bw-encoding-ieee\n",
+                       addr);
+
        /* enforce-first-as */
        if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS))
                vty_out(vty, " neighbor %s enforce-first-as\n", addr);
@@ -18240,6 +18268,10 @@ void bgp_vty_init(void)
        install_element(BGP_NODE, &neighbor_disable_connected_check_cmd);
        install_element(BGP_NODE, &no_neighbor_disable_connected_check_cmd);
 
+       /* "neighbor link-bw-encoding-ieee" commands.  */
+       install_element(BGP_NODE, &neighbor_link_bw_encoding_ieee_cmd);
+       install_element(BGP_NODE, &no_neighbor_link_bw_encoding_ieee_cmd);
+
        /* "neighbor enforce-first-as" commands. */
        install_element(BGP_NODE, &neighbor_enforce_first_as_cmd);
        install_element(BGP_NODE, &no_neighbor_enforce_first_as_cmd);
index 591fc1214ca2116bec54c16b9064c05e0719dafb..3ed2d4e24f0a15817b91f83fd015c58d09fe51e0 100644 (file)
@@ -4164,6 +4164,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
        {PEER_FLAG_LOCAL_AS_NO_PREPEND, 0, peer_change_none},
        {PEER_FLAG_LOCAL_AS_REPLACE_AS, 0, peer_change_none},
        {PEER_FLAG_UPDATE_SOURCE, 0, peer_change_none},
+       {PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE, 0, peer_change_none},
        {0, 0, 0}};
 
 static const struct peer_flag_action peer_af_flag_action_list[] = {
index d39743a152c0a727957049276661b52211e4a6b6..43914bd9d1c78be55b677ea5aec64122c895a4db 100644 (file)
@@ -1283,6 +1283,10 @@ struct peer {
 #define PEER_FLAG_RTT_SHUTDOWN (1U << 26) /* shutdown rtt */
 #define PEER_FLAG_TIMER_DELAYOPEN (1U << 27) /* delayopen timer */
 #define PEER_FLAG_TCP_MSS (1U << 28)    /* tcp-mss */
+/* Disable IEEE floating-point link bandwidth encoding in
+ * extended communities.
+ */
+#define PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE (1U << 29)
 
        /*
         *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
index dc6d8268b167edcb7aa456bb9db93159e8e9fc14..317bfff8ab55782828714d5f66283f74356c27d3 100644 (file)
@@ -121,7 +121,7 @@ static void parse_test(struct test_segment *t)
 
        printf("%s: %s\n", t->name, t->desc);
 
-       ecom = ecommunity_parse((uint8_t *)t->data, t->len);
+       ecom = ecommunity_parse((uint8_t *)t->data, t->len, 0);
 
        printf("ecom: %s\nvalidating...:\n", ecommunity_str(ecom));