summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.c11
-rw-r--r--bgpd/bgp_ecommunity.c51
-rw-r--r--bgpd/bgp_ecommunity.h19
-rw-r--r--bgpd/bgp_mpath.c12
-rw-r--r--bgpd/bgp_route.c4
-rw-r--r--bgpd/bgp_routemap.c4
-rw-r--r--bgpd/bgp_vty.c32
-rw-r--r--bgpd/bgpd.c1
-rw-r--r--bgpd/bgpd.h4
-rw-r--r--tests/bgpd/test_ecommunity.c2
10 files changed, 104 insertions, 36 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index fb97fea72d..f1c953f21d 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -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 */
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 6d3abbd20d..1e95d401aa 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -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);
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 731a0c664e..f22855c329 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -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)
{
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 8127428bc7..1d727d267a 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -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;
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index f97a791dae..b164d710a5 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -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;
}
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 5e566f360a..7be22e6929 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -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;
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 715a768fd8..ccef02a3f7 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -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);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 591fc1214c..3ed2d4e24f 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -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[] = {
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index d39743a152..43914bd9d1 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -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
diff --git a/tests/bgpd/test_ecommunity.c b/tests/bgpd/test_ecommunity.c
index dc6d8268b1..317bfff8ab 100644
--- a/tests/bgpd/test_ecommunity.c
+++ b/tests/bgpd/test_ecommunity.c
@@ -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));