summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_advertise.c3
-rw-r--r--bgpd/bgp_attr.c162
-rw-r--r--bgpd/bgp_attr.h2
-rw-r--r--bgpd/bgp_bmp.c38
-rw-r--r--bgpd/bgp_bmp.h2
-rw-r--r--bgpd/bgp_ecommunity.c101
-rw-r--r--bgpd/bgp_ecommunity.h56
-rw-r--r--bgpd/bgp_mpath.c24
-rw-r--r--bgpd/bgp_packet.c10
-rw-r--r--bgpd/bgp_route.c51
-rw-r--r--bgpd/bgp_routemap.c73
-rw-r--r--bgpd/bgp_routemap_nb_config.c6
-rw-r--r--bgpd/bgp_vty.c26
-rw-r--r--bgpd/bgp_zebra.c9
-rw-r--r--bgpd/bgpd.c1
-rw-r--r--bgpd/bgpd.h5
-rw-r--r--doc/user/bgp.rst18
-rw-r--r--doc/user/bmp.rst7
-rw-r--r--lib/libfrr.c2
-rw-r--r--lib/routemap_cli.c4
-rw-r--r--lib/subdir.am1
-rw-r--r--lib/zclient.c4
-rw-r--r--lib/zclient.h2
-rw-r--r--mgmtd/subdir.am1
-rw-r--r--tests/topotests/bgp_extended_link_bandwidth/__init__.py0
-rw-r--r--tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf32
-rw-r--r--tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf10
-rw-r--r--tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py95
-rw-r--r--tests/topotests/bgp_link_bw_ip/r2/bgp-route-3.json2
-rw-r--r--tests/topotests/bgp_link_bw_ip/r5/bgpd.conf1
-rw-r--r--tests/topotests/lib/snmptest.py13
-rw-r--r--yang/frr-bgp-route-map.yang4
-rw-r--r--zebra/zapi_msg.c7
33 files changed, 591 insertions, 181 deletions
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index a81f288c7a..d519749f6b 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -182,12 +182,15 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr,
adj->uptime = monotime(NULL);
adj->addpath_rx_id = addpath_id;
BGP_ADJ_IN_ADD(dest, adj);
+ peer->stat_pfx_adj_rib_in++;
bgp_dest_lock_node(dest);
}
void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai)
{
bgp_attr_unintern(&bai->attr);
+ if (bai->peer)
+ bai->peer->stat_pfx_adj_rib_in--;
BGP_ADJ_IN_DEL(*dest, bai);
*dest = bgp_dest_unlock_node(*dest);
peer_unlock(bai->peer); /* adj_in peer reference */
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index e2321ad296..913634bf59 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -915,12 +915,13 @@ static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty)
"\n",
attr->flag, attr->distance, attr->med, attr->local_pref,
attr->origin, attr->weight, attr->label, sid, attr->aigp_metric);
- vty_out(vty,
- "\taspath: %s Community: %s Extended Community: %s Large Community: %s\n",
+ vty_out(vty, "\taspath: %s Community: %s Large Community: %s\n",
aspath_print(attr->aspath),
community_str(attr->community, false, false),
- ecommunity_str(attr->ecommunity),
lcommunity_str(attr->lcommunity, false, false));
+ vty_out(vty, "\tExtended Community: %s Extended IPv6 Community: %s\n",
+ ecommunity_str(attr->ecommunity),
+ ecommunity_str(attr->ipv6_ecommunity));
}
void attr_show_all(struct vty *vty)
@@ -2650,10 +2651,7 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto ipv6_ext_community_ignore;
- ipv6_ecomm = ecommunity_parse_ipv6(
- stream_pnt(peer->curr), length,
- CHECK_FLAG(peer->flags,
- PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
+ ipv6_ecomm = ecommunity_parse_ipv6(stream_pnt(peer->curr), length);
bgp_attr_set_ipv6_ecommunity(attr, ipv6_ecomm);
/* XXX: fix ecommunity_parse to use stream API */
@@ -2663,6 +2661,10 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
args->total);
+ /* Extract link bandwidth, if any. */
+ (void)ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity(attr),
+ &attr->link_bw);
+
return BGP_ATTR_PARSE_PROCEED;
ipv6_ext_community_ignore:
@@ -4354,6 +4356,69 @@ static bool bgp_append_local_as(struct peer *peer, afi_t afi, safi_t safi)
return false;
}
+static void bgp_packet_ecommunity_attribute(struct stream *s, struct peer *peer,
+ struct ecommunity *ecomm,
+ bool transparent, int attribute)
+{
+ if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED ||
+ peer->sub_sort == BGP_PEER_EBGP_OAD || transparent) {
+ if (ecomm->size * ecomm->unit_size > 255) {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
+ BGP_ATTR_FLAG_TRANS |
+ BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, attribute);
+ stream_putw(s, ecomm->size * ecomm->unit_size);
+ } else {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
+ BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, attribute);
+ stream_putc(s, ecomm->size * ecomm->unit_size);
+ }
+ stream_put(s, ecomm->val, ecomm->size * ecomm->unit_size);
+ } else {
+ uint8_t *pnt;
+ int tbit;
+ int ecom_tr_size = 0;
+ uint32_t i;
+
+ for (i = 0; i < ecomm->size; i++) {
+ pnt = ecomm->val + (i * ecomm->unit_size);
+ tbit = *pnt;
+
+ if (CHECK_FLAG(tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
+ continue;
+
+ ecom_tr_size++;
+ }
+
+ if (ecom_tr_size) {
+ if (ecom_tr_size * ecomm->unit_size > 255) {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
+ BGP_ATTR_FLAG_TRANS |
+ BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, attribute);
+ stream_putw(s, ecom_tr_size * ecomm->unit_size);
+ } else {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
+ BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, attribute);
+ stream_putc(s, ecom_tr_size * ecomm->unit_size);
+ }
+
+ for (i = 0; i < ecomm->size; i++) {
+ pnt = ecomm->val + (i * ecomm->unit_size);
+ tbit = *pnt;
+
+ if (CHECK_FLAG(tbit,
+ ECOMMUNITY_FLAG_NON_TRANSITIVE))
+ continue;
+
+ stream_put(s, pnt, ecomm->unit_size);
+ }
+ }
+ }
+}
+
/* Make attribute packet. */
bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
struct stream *s, struct attr *attr,
@@ -4656,82 +4721,31 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
}
}
- /* Extended Communities attribute. */
- if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
- && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) {
- struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
+ /* Extended IPv6/Communities attributes. */
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) {
bool transparent = CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_RSERVER_CLIENT) &&
from &&
CHECK_FLAG(from->af_flags[afi][safi],
PEER_FLAG_RSERVER_CLIENT);
- if (peer->sort == BGP_PEER_IBGP ||
- peer->sort == BGP_PEER_CONFED || transparent) {
- if (ecomm->size * 8 > 255) {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS
- | BGP_ATTR_FLAG_EXTLEN);
- stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
- stream_putw(s, ecomm->size * 8);
- } else {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
- stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
- stream_putc(s, ecomm->size * 8);
- }
- stream_put(s, ecomm->val, ecomm->size * 8);
- } else {
- uint8_t *pnt;
- int tbit;
- int ecom_tr_size = 0;
- uint32_t i;
-
- for (i = 0; i < ecomm->size; i++) {
- pnt = ecomm->val + (i * 8);
- tbit = *pnt;
+ if (CHECK_FLAG(attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) {
+ struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
- if (CHECK_FLAG(tbit,
- ECOMMUNITY_FLAG_NON_TRANSITIVE))
- continue;
+ bgp_packet_ecommunity_attribute(s, peer, ecomm,
+ transparent,
+ BGP_ATTR_EXT_COMMUNITIES);
+ }
- ecom_tr_size++;
- }
+ if (CHECK_FLAG(attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES))) {
+ struct ecommunity *ecomm =
+ bgp_attr_get_ipv6_ecommunity(attr);
- if (ecom_tr_size) {
- if (ecom_tr_size * 8 > 255) {
- stream_putc(
- s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS
- | BGP_ATTR_FLAG_EXTLEN);
- stream_putc(s,
- BGP_ATTR_EXT_COMMUNITIES);
- stream_putw(s, ecom_tr_size * 8);
- } else {
- stream_putc(
- s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
- stream_putc(s,
- BGP_ATTR_EXT_COMMUNITIES);
- stream_putc(s, ecom_tr_size * 8);
- }
-
- for (i = 0; i < ecomm->size; i++) {
- pnt = ecomm->val + (i * 8);
- tbit = *pnt;
-
- if (CHECK_FLAG(
- tbit,
- ECOMMUNITY_FLAG_NON_TRANSITIVE))
- continue;
-
- stream_put(s, pnt, 8);
- }
- }
+ bgp_packet_ecommunity_attribute(s, peer, ecomm,
+ transparent,
+ BGP_ATTR_IPV6_EXT_COMMUNITIES);
}
}
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 164aa5ae79..3f8e2784f1 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -301,7 +301,7 @@ struct attr {
uint32_t rmap_table_id;
/* Link bandwidth value, if any. */
- uint32_t link_bw;
+ uint64_t link_bw;
/* EVPN ES */
esi_t esi;
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index 5fcb8c5645..14066ae29d 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -1592,6 +1592,15 @@ static void bmp_stat_put_u32(struct stream *s, size_t *cnt, uint16_t type,
(*cnt)++;
}
+static void bmp_stat_put_u64(struct stream *s, size_t *cnt, uint16_t type,
+ uint64_t value)
+{
+ stream_putw(s, type);
+ stream_putw(s, 8);
+ stream_putq(s, value);
+ (*cnt)++;
+}
+
static void bmp_stats(struct event *thread)
{
struct bmp_targets *bt = EVENT_ARG(thread);
@@ -1633,8 +1642,13 @@ static void bmp_stats(struct event *thread)
peer->stat_pfx_dup_withdraw);
bmp_stat_put_u32(s, &count, BMP_STATS_UPD_7606_WITHDRAW,
peer->stat_upd_7606);
- bmp_stat_put_u32(s, &count, BMP_STATS_FRR_NH_INVALID,
- peer->stat_pfx_nh_invalid);
+ if (bt->stats_send_experimental)
+ bmp_stat_put_u32(s, &count, BMP_STATS_FRR_NH_INVALID,
+ peer->stat_pfx_nh_invalid);
+ bmp_stat_put_u64(s, &count, BMP_STATS_SIZE_ADJ_RIB_IN,
+ peer->stat_pfx_adj_rib_in);
+ bmp_stat_put_u64(s, &count, BMP_STATS_SIZE_LOC_RIB,
+ peer->stat_pfx_loc_rib);
stream_putl_at(s, count_pos, count);
@@ -1889,6 +1903,7 @@ static struct bmp_targets *bmp_targets_get(struct bgp *bgp, const char *name)
bt->name = XSTRDUP(MTYPE_BMP_TARGETSNAME, name);
bt->bgp = bgp;
bt->bmpbgp = bmp_bgp_get(bgp);
+ bt->stats_send_experimental = true;
bmp_session_init(&bt->sessions);
bmp_qhash_init(&bt->updhash);
bmp_qlist_init(&bt->updlist);
@@ -2469,6 +2484,21 @@ DEFPY(bmp_stats_cfg,
return CMD_SUCCESS;
}
+DEFPY(bmp_stats_send_experimental,
+ bmp_stats_send_experimental_cmd,
+ "[no] bmp stats send-experimental",
+ NO_STR
+ BMP_STR
+ "Send BMP statistics messages\n"
+ "Send experimental BMP stats [65531-65534]\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
+
+ bt->stats_send_experimental = !!no;
+
+ return CMD_SUCCESS;
+}
+
#define BMP_POLICY_IS_LOCRIB(str) ((str)[0] == 'l') /* __l__oc-rib */
#define BMP_POLICY_IS_PRE(str) ((str)[1] == 'r') /* p__r__e-policy */
@@ -2761,6 +2791,9 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty)
if (bt->acl_name)
vty_out(vty, " ip access-list %s\n", bt->acl_name);
+ if (!bt->stats_send_experimental)
+ vty_out(vty, " no bmp stats send-experimental\n");
+
if (bt->stat_msec)
vty_out(vty, " bmp stats interval %d\n",
bt->stat_msec);
@@ -2816,6 +2849,7 @@ static int bgp_bmp_init(struct event_loop *tm)
install_element(BMP_NODE, &no_bmp_listener_cmd);
install_element(BMP_NODE, &bmp_connect_cmd);
install_element(BMP_NODE, &bmp_acl_cmd);
+ install_element(BMP_NODE, &bmp_stats_send_experimental_cmd);
install_element(BMP_NODE, &bmp_stats_cmd);
install_element(BMP_NODE, &bmp_monitor_cmd);
install_element(BMP_NODE, &bmp_mirror_cmd);
diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h
index dadd99eb6d..33247c4025 100644
--- a/bgpd/bgp_bmp.h
+++ b/bgpd/bgp_bmp.h
@@ -240,6 +240,8 @@ struct bmp_targets {
uint64_t cnt_accept, cnt_aclrefused;
+ bool stats_send_experimental;
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(bmp_targets);
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index e1b462ae56..be8f56637e 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -237,11 +237,10 @@ struct ecommunity *ecommunity_parse(uint8_t *pnt, unsigned short length,
disable_ieee_floating);
}
-struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, unsigned short length,
- bool disable_ieee_floating)
+struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, unsigned short length)
{
return ecommunity_parse_internal(pnt, length, IPV6_ECOMMUNITY_SIZE,
- disable_ieee_floating);
+ false);
}
/* Duplicate the Extended Communities Attribute structure. */
@@ -1026,10 +1025,6 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,
uint32_t bw_tmp, bw;
char bps_buf[20] = {0};
-#define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8)
-#define ONE_MBPS_BYTES (1000 * 1000 / 8)
-#define ONE_KBPS_BYTES (1000 / 8)
-
as = (*pnt++ << 8);
as |= (*pnt++);
(void)ptr_get_be32(pnt, &bw_tmp);
@@ -1053,6 +1048,33 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,
return len;
}
+static int ipv6_ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt)
+{
+ int len = 0;
+ as_t as;
+ uint64_t bw;
+ char bps_buf[20] = { 0 };
+
+ pnt += 2; /* Reserved */
+ pnt = ptr_get_be64(pnt, &bw);
+ (void)ptr_get_be32(pnt, &as);
+
+ if (bw >= ONE_GBPS_BYTES)
+ snprintf(bps_buf, sizeof(bps_buf), "%.3f Gbps",
+ (float)(bw / ONE_GBPS_BYTES));
+ else if (bw >= ONE_MBPS_BYTES)
+ snprintf(bps_buf, sizeof(bps_buf), "%.3f Mbps",
+ (float)(bw / ONE_MBPS_BYTES));
+ else if (bw >= ONE_KBPS_BYTES)
+ snprintf(bps_buf, sizeof(bps_buf), "%.3f Kbps",
+ (float)(bw / ONE_KBPS_BYTES));
+ else
+ snprintfrr(bps_buf, sizeof(bps_buf), "%" PRIu64 " bps", bw * 8);
+
+ len = snprintfrr(buf, bufsz, "LB:%u:%" PRIu64 " (%s)", as, bw, bps_buf);
+ return len;
+}
+
bool ecommunity_has_route_target(struct ecommunity *ecom)
{
uint32_t i;
@@ -1153,6 +1175,12 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
ecommunity_lb_str(
encbuf, sizeof(encbuf), pnt,
ecom->disable_ieee_floating);
+ } else if (sub_type ==
+ ECOMMUNITY_EXTENDED_LINK_BANDWIDTH &&
+ type == ECOMMUNITY_ENCODE_AS4) {
+ ipv6_ecommunity_lb_str(encbuf,
+ sizeof(encbuf),
+ pnt);
} else if (sub_type == ECOMMUNITY_NODE_TARGET &&
type == ECOMMUNITY_ENCODE_IP) {
ecommunity_node_target_str(
@@ -1370,6 +1398,13 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
ecom->disable_ieee_floating);
else
unk_ecom = 1;
+ } else if (type == ECOMMUNITY_ENCODE_AS_NON_TRANS) {
+ sub_type = *pnt++;
+ if (sub_type == ECOMMUNITY_EXTENDED_LINK_BANDWIDTH)
+ ipv6_ecommunity_lb_str(encbuf, sizeof(encbuf),
+ pnt);
+ else
+ unk_ecom = 1;
} else if (type == ECOMMUNITY_ENCODE_IP_NON_TRANS) {
sub_type = *pnt++;
if (sub_type == ECOMMUNITY_NODE_TARGET)
@@ -1805,7 +1840,7 @@ ecommunity_add_origin_validation_state(enum rpki_states rpki_state,
* return the BGP link bandwidth extended community, if present;
* the actual bandwidth is returned via param
*/
-const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
+const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_t *bw)
{
const uint8_t *eval;
uint32_t i;
@@ -1819,23 +1854,36 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
for (i = 0; i < ecom->size; i++) {
const uint8_t *pnt;
uint8_t type, sub_type;
- uint32_t bwval;
- eval = pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
+ eval = pnt = (ecom->val + (i * ecom->unit_size));
type = *pnt++;
sub_type = *pnt++;
if ((type == ECOMMUNITY_ENCODE_AS ||
type == ECOMMUNITY_ENCODE_AS_NON_TRANS) &&
sub_type == ECOMMUNITY_LINK_BANDWIDTH) {
+ uint32_t bwval;
+
pnt += 2; /* bandwidth is encoded as AS:val */
pnt = ptr_get_be32(pnt, &bwval);
(void)pnt; /* consume value */
if (bw)
- *bw = ecom->disable_ieee_floating
- ? bwval
- : ieee_float_uint32_to_uint32(
- bwval);
+ *bw = (uint64_t)(ecom->disable_ieee_floating
+ ? bwval
+ : ieee_float_uint32_to_uint32(
+ bwval));
+ return eval;
+ } else if (type == ECOMMUNITY_ENCODE_AS4 &&
+ sub_type == ECOMMUNITY_EXTENDED_LINK_BANDWIDTH) {
+ uint64_t bwval;
+
+ pnt += 2; /* Reserved */
+ pnt = ptr_get_be64(pnt, &bwval);
+ (void)pnt;
+
+ if (bw)
+ *bw = bwval;
+
return eval;
}
}
@@ -1846,13 +1894,13 @@ 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,
- bool disable_ieee_floating)
+ bool disable_ieee_floating,
+ bool extended)
{
struct ecommunity *new;
- struct ecommunity_val lb_eval;
const uint8_t *eval;
uint8_t type;
- uint32_t cur_bw;
+ uint64_t cur_bw;
/* Nothing to replace if link-bandwidth doesn't exist or
* is non-transitive - just return existing extcommunity.
@@ -1876,10 +1924,21 @@ struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom,
*/
if (cum_bw > 0xFFFFFFFF)
cum_bw = 0xFFFFFFFF;
- 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);
+
+ if (extended) {
+ struct ecommunity_val_ipv6 lb_eval;
+
+ encode_lb_extended_extcomm(as, cum_bw, false, &lb_eval);
+ new = ecommunity_dup(ecom);
+ ecommunity_add_val_ipv6(new, &lb_eval, true, true);
+ } else {
+ struct ecommunity_val 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);
+ }
return new;
}
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 794c5a3975..929e4e60be 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -10,6 +10,10 @@
#include "bgpd/bgp_rpki.h"
#include "bgpd/bgpd.h"
+#define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8)
+#define ONE_MBPS_BYTES (1000 * 1000 / 8)
+#define ONE_KBPS_BYTES (1000 / 8)
+
/* Refer to rfc7153 for the IANA registry definitions. These are
* updated by other standards like rfc7674.
*/
@@ -55,6 +59,12 @@
/* RFC 8956 */
#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0d
+/* https://datatracker.ietf.org/doc/html/draft-li-idr-link-bandwidth-ext-01
+ * Sub-type is allocated by IANA, just the draft is not yet updated with the
+ * new value.
+ */
+#define ECOMMUNITY_EXTENDED_LINK_BANDWIDTH 0x0006
+
/* Low-order octet of the Extended Communities type field for EVPN types */
#define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY 0x00
#define ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL 0x01
@@ -224,12 +234,13 @@ static uint32_t uint32_to_ieee_float_uint32(uint32_t u)
* Encode BGP Link Bandwidth extended community
* bandwidth (bw) is in bytes-per-sec
*/
-static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans,
+static inline void encode_lb_extcomm(as_t as, uint64_t bw, bool non_trans,
struct ecommunity_val *eval,
bool disable_ieee_floating)
{
- uint32_t bandwidth =
- disable_ieee_floating ? bw : uint32_to_ieee_float_uint32(bw);
+ uint64_t bandwidth = disable_ieee_floating
+ ? bw
+ : uint32_to_ieee_float_uint32(bw);
memset(eval, 0, sizeof(*eval));
eval->val[0] = ECOMMUNITY_ENCODE_AS;
@@ -244,6 +255,33 @@ static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans,
eval->val[7] = bandwidth & 0xff;
}
+/*
+ * Encode BGP Link Bandwidth inside IPv6 Extended Community,
+ * bandwidth is in bytes per second.
+ */
+static inline void encode_lb_extended_extcomm(as_t as, uint64_t bandwidth,
+ bool non_trans,
+ struct ecommunity_val_ipv6 *eval)
+{
+ memset(eval, 0, sizeof(*eval));
+ eval->val[0] = ECOMMUNITY_ENCODE_AS4;
+ if (non_trans)
+ eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
+ eval->val[1] = ECOMMUNITY_EXTENDED_LINK_BANDWIDTH;
+ eval->val[4] = (bandwidth >> 56) & 0xff;
+ eval->val[5] = (bandwidth >> 48) & 0xff;
+ eval->val[6] = (bandwidth >> 40) & 0xff;
+ eval->val[7] = (bandwidth >> 32) & 0xff;
+ eval->val[8] = (bandwidth >> 24) & 0xff;
+ eval->val[9] = (bandwidth >> 16) & 0xff;
+ eval->val[10] = (bandwidth >> 8) & 0xff;
+ eval->val[11] = bandwidth & 0xff;
+ eval->val[12] = (as >> 24) & 0xff;
+ eval->val[13] = (as >> 16) & 0xff;
+ eval->val[14] = (as >> 8) & 0xff;
+ eval->val[15] = as & 0xff;
+}
+
static inline void encode_origin_validation_state(enum rpki_states state,
struct ecommunity_val *eval)
{
@@ -325,8 +363,7 @@ extern void ecommunity_free(struct ecommunity **);
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,
- bool disable_ieee_floating);
+ unsigned short length);
extern struct ecommunity *ecommunity_dup(struct ecommunity *);
extern struct ecommunity *ecommunity_merge(struct ecommunity *,
struct ecommunity *);
@@ -385,11 +422,10 @@ extern void bgp_remove_ecomm_from_aggregate_hash(
struct ecommunity *ecommunity);
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,
- bool disable_ieee_floating);
+ uint64_t *bw);
+extern struct ecommunity *
+ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom, uint64_t cum_bw,
+ bool disable_ieee_floating, bool extended);
extern bool soo_in_ecom(struct ecommunity *ecom, struct ecommunity *soo);
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 296e64003d..e12d84b84c 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -521,7 +521,7 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_maxpaths_cfg *mpath_cfg)
{
uint16_t maxpaths, mpath_count, old_mpath_count;
- uint32_t bwval;
+ uint64_t bwval;
uint64_t cum_bw, old_cum_bw;
struct listnode *mp_node, *mp_next_node;
struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
@@ -613,8 +613,11 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
cur_mpath);
prev_mpath = cur_mpath;
mpath_count++;
- if (ecommunity_linkbw_present(
- bgp_attr_get_ecommunity(
+ if (ecommunity_linkbw_present(bgp_attr_get_ecommunity(
+ cur_mpath->attr),
+ &bwval) ||
+ ecommunity_linkbw_present(
+ bgp_attr_get_ipv6_ecommunity(
cur_mpath->attr),
&bwval))
cum_bw += bwval;
@@ -700,8 +703,11 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
prev_mpath = new_mpath;
mpath_changed = 1;
mpath_count++;
- if (ecommunity_linkbw_present(
- bgp_attr_get_ecommunity(
+ if (ecommunity_linkbw_present(bgp_attr_get_ecommunity(
+ new_mpath->attr),
+ &bwval) ||
+ ecommunity_linkbw_present(
+ bgp_attr_get_ipv6_ecommunity(
new_mpath->attr),
&bwval))
cum_bw += bwval;
@@ -724,8 +730,12 @@ void bgp_path_info_mpath_update(struct bgp *bgp, 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(
- bgp_attr_get_ecommunity(new_best->attr), &bwval))
+ (!ecommunity_linkbw_present(bgp_attr_get_ecommunity(
+ new_best->attr),
+ &bwval) &&
+ !ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity(
+ new_best->attr),
+ &bwval)))
all_paths_lb = false;
else
cum_bw += bwval;
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 78554893ff..9c194eac1c 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -3734,7 +3734,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
zlog_err("%pBP: Capability length error", peer);
bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
BGP_NOTIFY_SUBCODE_UNSPECIFIC);
- pnt += length;
+ /*
+ * If we did not return then
+ * pnt += length;
+ */
return BGP_Stop;
}
action = *pnt;
@@ -3759,7 +3762,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
zlog_err("%pBP: Capability length error", peer);
bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
BGP_NOTIFY_SUBCODE_UNSPECIFIC);
- pnt += length;
+ /*
+ * If we did not return then
+ * pnt += length;
+ */
return BGP_Stop;
}
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 3feb2717d1..5f6ef5ae07 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -487,6 +487,8 @@ void bgp_path_info_add_with_caller(const char *name, struct bgp_dest *dest,
bgp_dest_lock_node(dest);
peer_lock(pi->peer); /* bgp_path_info peer reference */
bgp_dest_set_defer_flag(dest, false);
+ if (pi->peer)
+ pi->peer->stat_pfx_loc_rib++;
hook_call(bgp_snmp_update_stats, dest, pi, true);
}
@@ -507,6 +509,8 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest,
pi->next = NULL;
pi->prev = NULL;
+ if (pi->peer)
+ pi->peer->stat_pfx_loc_rib--;
hook_call(bgp_snmp_update_stats, dest, pi, false);
bgp_path_info_unlock(pi);
@@ -521,6 +525,8 @@ static struct bgp_dest *bgp_path_info_reap_unsorted(struct bgp_dest *dest,
pi->next = NULL;
pi->prev = NULL;
+ if (pi->peer)
+ pi->peer->stat_pfx_loc_rib--;
hook_call(bgp_snmp_update_stats, dest, pi, false);
bgp_path_info_unlock(pi);
@@ -2771,17 +2777,26 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
* the most sense. However, don't modify if the link-bandwidth has
* been explicitly set by user policy.
*/
- if (nh_reset &&
- bgp_path_info_mpath_chkwtd(bgp, pi) &&
+ if (nh_reset && bgp_path_info_mpath_chkwtd(bgp, pi) &&
(cum_bw = bgp_path_info_mpath_cumbw(pi)) != 0 &&
- !CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET))
- bgp_attr_set_ecommunity(
- attr,
- ecommunity_replace_linkbw(
- bgp->as, bgp_attr_get_ecommunity(attr), cum_bw,
- CHECK_FLAG(
- peer->flags,
- PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE)));
+ !CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET)) {
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_LINK_BANDWIDTH))
+ bgp_attr_set_ipv6_ecommunity(
+ attr,
+ ecommunity_replace_linkbw(bgp->as,
+ bgp_attr_get_ipv6_ecommunity(
+ attr),
+ cum_bw, false, true));
+ else
+ bgp_attr_set_ecommunity(
+ attr,
+ ecommunity_replace_linkbw(
+ bgp->as, bgp_attr_get_ecommunity(attr),
+ cum_bw,
+ CHECK_FLAG(peer->flags,
+ PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE),
+ false));
+ }
return true;
}
@@ -10457,6 +10472,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_object *json_cluster_list = NULL;
json_object *json_cluster_list_list = NULL;
json_object *json_ext_community = NULL;
+ json_object *json_ext_ipv6_community = NULL;
json_object *json_last_update = NULL;
json_object *json_pmsi = NULL;
json_object *json_nexthop_global = NULL;
@@ -11165,6 +11181,21 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
}
}
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES)) {
+ if (json_paths) {
+ json_ext_ipv6_community = json_object_new_object();
+ json_object_string_add(json_ext_ipv6_community, "string",
+ bgp_attr_get_ipv6_ecommunity(attr)
+ ->str);
+ json_object_object_add(json_path,
+ "extendedIpv6Community",
+ json_ext_ipv6_community);
+ } else {
+ vty_out(vty, " Extended IPv6 Community: %s\n",
+ bgp_attr_get_ipv6_ecommunity(attr)->str);
+ }
+ }
+
/* Line 6 display Large community */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
if (json_paths) {
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 15828b6594..1515b64b77 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -3196,7 +3196,7 @@ struct rmap_ecomm_lb_set {
#define RMAP_ECOMM_LB_SET_CUMUL 2
#define RMAP_ECOMM_LB_SET_NUM_MPATH 3
bool non_trans;
- uint32_t bw;
+ uint64_t bw;
};
static enum route_map_cmd_result_t
@@ -3206,8 +3206,7 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object)
struct bgp_path_info *path;
struct peer *peer;
struct ecommunity ecom_lb = {0};
- struct ecommunity_val lb_eval;
- uint32_t bw_bytes = 0;
+ uint64_t bw_bytes = 0;
uint16_t mpath_count = 0;
struct ecommunity *new_ecom;
struct ecommunity *old_ecom;
@@ -3221,13 +3220,13 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object)
/* Build link bandwidth extended community */
as = (peer->bgp->as > BGP_AS_MAX) ? BGP_AS_TRANS : peer->bgp->as;
if (rels->lb_type == RMAP_ECOMM_LB_SET_VALUE) {
- bw_bytes = ((uint64_t)rels->bw * 1000 * 1000) / 8;
+ bw_bytes = (rels->bw * 1000 * 1000) / 8;
} else if (rels->lb_type == RMAP_ECOMM_LB_SET_CUMUL) {
/* process this only for the best path. */
if (!CHECK_FLAG(path->flags, BGP_PATH_SELECTED))
return RMAP_OKAY;
- bw_bytes = (uint32_t)bgp_path_info_mpath_cumbw(path);
+ bw_bytes = bgp_path_info_mpath_cumbw(path);
if (!bw_bytes)
return RMAP_OKAY;
@@ -3237,31 +3236,53 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object)
if (!CHECK_FLAG(path->flags, BGP_PATH_SELECTED))
return RMAP_OKAY;
- bw_bytes = ((uint64_t)peer->bgp->lb_ref_bw * 1000 * 1000) / 8;
+ bw_bytes = (peer->bgp->lb_ref_bw * 1000 * 1000) / 8;
mpath_count = bgp_path_info_mpath_count(path) + 1;
bw_bytes *= mpath_count;
}
- encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval,
- CHECK_FLAG(peer->flags,
- PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_LINK_BANDWIDTH)) {
+ struct ecommunity_val_ipv6 lb_eval;
- /* add to route or merge with existing */
- old_ecom = bgp_attr_get_ecommunity(path->attr);
- if (old_ecom) {
- new_ecom = ecommunity_dup(old_ecom);
- ecommunity_add_val(new_ecom, &lb_eval, true, true);
- if (!old_ecom->refcnt)
- ecommunity_free(&old_ecom);
+ encode_lb_extended_extcomm(as, bw_bytes, rels->non_trans,
+ &lb_eval);
+
+ old_ecom = bgp_attr_get_ipv6_ecommunity(path->attr);
+ if (old_ecom) {
+ new_ecom = ecommunity_dup(old_ecom);
+ ecommunity_add_val_ipv6(new_ecom, &lb_eval, true, true);
+ if (!old_ecom->refcnt)
+ ecommunity_free(&old_ecom);
+ } else {
+ ecom_lb.size = 1;
+ ecom_lb.unit_size = IPV6_ECOMMUNITY_SIZE;
+ ecom_lb.val = (uint8_t *)lb_eval.val;
+ new_ecom = ecommunity_dup(&ecom_lb);
+ }
+
+ bgp_attr_set_ipv6_ecommunity(path->attr, new_ecom);
} else {
- ecom_lb.size = 1;
- ecom_lb.unit_size = ECOMMUNITY_SIZE;
- ecom_lb.val = (uint8_t *)lb_eval.val;
- new_ecom = ecommunity_dup(&ecom_lb);
- }
+ struct ecommunity_val lb_eval;
+
+ encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval,
+ CHECK_FLAG(peer->flags,
+ PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
+
+ old_ecom = bgp_attr_get_ecommunity(path->attr);
+ if (old_ecom) {
+ new_ecom = ecommunity_dup(old_ecom);
+ ecommunity_add_val(new_ecom, &lb_eval, true, true);
+ if (!old_ecom->refcnt)
+ ecommunity_free(&old_ecom);
+ } else {
+ ecom_lb.size = 1;
+ ecom_lb.unit_size = ECOMMUNITY_SIZE;
+ ecom_lb.val = (uint8_t *)lb_eval.val;
+ new_ecom = ecommunity_dup(&ecom_lb);
+ }
- /* new_ecom will be intern()'d or attr_flush()'d in call stack */
- bgp_attr_set_ecommunity(path->attr, new_ecom);
+ bgp_attr_set_ecommunity(path->attr, new_ecom);
+ }
/* Mark that route-map has set link bandwidth; used in attribute
* setting decisions.
@@ -3275,7 +3296,7 @@ static void *route_set_ecommunity_lb_compile(const char *arg)
{
struct rmap_ecomm_lb_set *rels;
uint8_t lb_type;
- uint32_t bw = 0;
+ uint64_t bw = 0;
char bw_str[40] = {0};
char *p, *str;
bool non_trans = false;
@@ -6875,7 +6896,7 @@ DEFUN_YANG(no_set_ecommunity_none, no_set_ecommunity_none_cmd,
DEFUN_YANG (set_ecommunity_lb,
set_ecommunity_lb_cmd,
- "set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]",
+ "set extcommunity bandwidth <(1-4294967295)|cumulative|num-multipaths> [non-transitive]",
SET_STR
"BGP extended community attribute\n"
"Link bandwidth extended community\n"
@@ -6929,7 +6950,7 @@ DEFUN_YANG (set_ecommunity_lb,
DEFUN_YANG (no_set_ecommunity_lb,
no_set_ecommunity_lb_cmd,
- "no set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]",
+ "no set extcommunity bandwidth <(1-4294967295)|cumulative|num-multipaths> [non-transitive]",
NO_STR
SET_STR
"BGP extended community attribute\n"
diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c
index c1d6ee12e1..15c32eaa28 100644
--- a/bgpd/bgp_routemap_nb_config.c
+++ b/bgpd/bgp_routemap_nb_config.c
@@ -2937,7 +2937,7 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(
struct routemap_hook_context *rhc;
enum ecommunity_lb_type lb_type;
char str[VTY_BUFSIZ];
- uint16_t bandwidth;
+ uint32_t bandwidth;
int ret;
/* Add configuration. */
@@ -2951,8 +2951,8 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(
switch (lb_type) {
case EXPLICIT_BANDWIDTH:
- bandwidth = yang_dnode_get_uint16(args->dnode, "bandwidth");
- snprintf(str, sizeof(str), "%d", bandwidth);
+ bandwidth = yang_dnode_get_uint32(args->dnode, "bandwidth");
+ snprintf(str, sizeof(str), "%u", bandwidth);
break;
case CUMULATIVE_BANDWIDTH:
snprintf(str, sizeof(str), "%s", "cumulative");
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index f8d8e8ad3a..b4e938b822 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -7115,6 +7115,26 @@ DEFUN (no_neighbor_disable_connected_check,
PEER_FLAG_DISABLE_CONNECTED_CHECK);
}
+DEFPY(neighbor_extended_link_bw,
+ neighbor_extended_link_bw_cmd,
+ "[no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor extended-link-bandwidth",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Send Extended (64-bit) version of encoding for Link-Bandwidth\n")
+{
+ int ret;
+
+ if (no)
+ ret = peer_flag_unset_vty(vty, neighbor,
+ PEER_FLAG_EXTENDED_LINK_BANDWIDTH);
+ else
+ ret = peer_flag_set_vty(vty, neighbor,
+ PEER_FLAG_EXTENDED_LINK_BANDWIDTH);
+
+ return ret;
+}
+
/* disable-link-bw-encoding-ieee */
DEFUN(neighbor_disable_link_bw_encoding_ieee,
neighbor_disable_link_bw_encoding_ieee_cmd,
@@ -18439,6 +18459,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty, " neighbor %s disable-link-bw-encoding-ieee\n",
addr);
+ if (peergroup_flag_check(peer, PEER_FLAG_EXTENDED_LINK_BANDWIDTH))
+ vty_out(vty, " neighbor %s extended-link-bandwidth\n", addr);
+
/* extended-optional-parameters */
if (peergroup_flag_check(peer, PEER_FLAG_EXTENDED_OPT_PARAMS))
vty_out(vty, " neighbor %s extended-optional-parameters\n",
@@ -20951,6 +20974,9 @@ void bgp_vty_init(void)
install_element(BGP_NODE,
&no_neighbor_disable_link_bw_encoding_ieee_cmd);
+
+ install_element(BGP_NODE, &neighbor_extended_link_bw_cmd);
+
/* "neighbor extended-optional-parameters" commands. */
install_element(BGP_NODE, &neighbor_extended_optional_parameters_cmd);
install_element(BGP_NODE,
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 9a81965773..ec79f944eb 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1211,7 +1211,7 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
}
static bool bgp_zebra_use_nhop_weighted(struct bgp *bgp, struct attr *attr,
- uint32_t *nh_weight)
+ uint64_t *nh_weight)
{
/* zero link-bandwidth and link-bandwidth not present are treated
* as the same situation.
@@ -1273,7 +1273,7 @@ static void bgp_zebra_announce_parse_nexthop(
for (; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) {
labels = NULL;
num_labels = 0;
- uint32_t nh_weight;
+ uint64_t nh_weight;
bool is_evpn;
bool is_parent_evpn;
@@ -1518,8 +1518,9 @@ static void bgp_debug_zebra_nh(struct zapi_route *api)
snprintf(eth_buf, sizeof(eth_buf), " RMAC %s",
prefix_mac2str(&api_nh->rmac, buf1,
sizeof(buf1)));
- zlog_debug(" nhop [%d]: %s if %u VRF %u wt %u %s %s %s", i + 1,
- nh_buf, api_nh->ifindex, api_nh->vrf_id,
+ zlog_debug(" nhop [%d]: %s if %u VRF %u wt %" PRIu64
+ " %s %s %s",
+ i + 1, nh_buf, api_nh->ifindex, api_nh->vrf_id,
api_nh->weight, label_buf, segs_buf, eth_buf);
}
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 95d949343c..a7564da8b3 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -4623,6 +4623,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
{PEER_FLAG_CAPABILITY_SOFT_VERSION, 0, peer_change_none},
{PEER_FLAG_CAPABILITY_FQDN, 0, peer_change_none},
{PEER_FLAG_AS_LOOP_DETECTION, 0, peer_change_none},
+ {PEER_FLAG_EXTENDED_LINK_BANDWIDTH, 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 e882a181b5..38940dc390 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -478,7 +478,7 @@ struct bgp {
* factor (e.g., number of multipaths for the prefix)
* Value is in Mbps
*/
- uint32_t lb_ref_bw;
+ uint64_t lb_ref_bw;
#define BGP_LINK_BW_REF_BW 1
/* BGP flags. */
@@ -1480,6 +1480,7 @@ struct peer {
#define PEER_FLAG_CAPABILITY_SOFT_VERSION (1ULL << 36)
#define PEER_FLAG_CAPABILITY_FQDN (1ULL << 37) /* fqdn capability */
#define PEER_FLAG_AS_LOOP_DETECTION (1ULL << 38) /* as path loop detection */
+#define PEER_FLAG_EXTENDED_LINK_BANDWIDTH (1ULL << 39)
/*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
@@ -1667,6 +1668,8 @@ struct peer {
uint32_t stat_pfx_nh_invalid;
uint32_t stat_pfx_dup_withdraw;
uint32_t stat_upd_7606; /* RFC7606: treat-as-withdraw */
+ uint64_t stat_pfx_loc_rib; /* RFC7854 : Number of routes in Loc-RIB */
+ uint64_t stat_pfx_adj_rib_in; /* RFC7854 : Number of routes in Adj-RIBs-In */
/* BGP state count */
uint32_t established; /* Established */
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 68ae796bc9..1de6773922 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1334,7 +1334,14 @@ OSPFv3 into ``address-family ipv4 unicast`` as OSPFv3 supports IPv6.
.. clicmd:: redistribute <babel|connected|eigrp|isis|kernel|openfabric|ospf|ospf6|rip|ripng|sharp|static> [metric (0-4294967295)] [route-map WORD]
-Redistribute routes from other protocols into BGP.
+ Redistribute routes from other protocols into BGP.
+
+ Note - When redistributing a static route, or any better Admin Distance route,
+ into BGP for which the same path is learned dynamically from another BGP
+ speaker, if the redistribute path is more preferred from a BGP Best Path
+ standpoint than the dynamically learned path, then BGP will not export
+ the best path to Zebra(RIB) for installation into the routing table,
+ unless BGP receives the path before the static route is created.
.. clicmd:: redistribute <table|table-direct> (1-65535)] [metric (0-4294967295)] [route-map WORD]
@@ -1565,6 +1572,15 @@ Configuring Peers
value is carried encoded as uint32. To enable backward compatibility we
need to disable IEEE floating-point encoding option per-peer.
+.. clicmd:: neighbor PEER extended-link-bandwidth
+
+ By default bandwidth in extended communities is carried encoded as IEEE
+ floating-point format, and is limited to maximum of 25 Gbps.
+
+ Enabling this parameter, you can use the bandwidth of to 4294967295 Mbps.
+
+ This is disabled by default.
+
.. clicmd:: neighbor PEER enforce-first-as
Discard updates received from the specified (eBGP) peer if the AS_PATH
diff --git a/doc/user/bmp.rst b/doc/user/bmp.rst
index 0f46832059..14d0849b34 100644
--- a/doc/user/bmp.rst
+++ b/doc/user/bmp.rst
@@ -23,6 +23,8 @@ The `BMP` implementation in FRR has the following properties:
- 3: count of **prefixes** with loop in cluster id
- 4: count of **prefixes** with loop in AS-path
- 5: count of **prefixes** with loop in originator
+ - 7: count of **routes** in adj-rib-in
+ - 8: count of **routes** in Loc-RIB
- 11: count of updates subjected to :rfc:`7607` "treat as withdrawal"
handling due to errors
- 65531: *experimental* count of prefixes rejected due to invalid next-hop
@@ -146,6 +148,11 @@ associated with a particular ``bmp targets``:
Send BMP Statistics (counter) messages at the specified interval (in
milliseconds.)
+.. clicmd:: bmp stats send-experimental
+
+ Send BMP Statistics (counter) messages whose code is defined as
+ experimental (in the [65531-65534] range).
+
.. clicmd:: bmp monitor AFI SAFI <pre-policy|post-policy|loc-rib>
Perform Route Monitoring for the specified AFI and SAFI. Only IPv4 and
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 03025328b7..876efe23a8 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -59,7 +59,7 @@ char config_default[512];
char frr_zclientpath[512];
static char pidfile_default[1024];
#ifdef HAVE_SQLITE3
-static char dbfile_default[512];
+static char dbfile_default[1024];
#endif
static char vtypath_default[512];
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index 88b341cac0..a12a07c14f 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -1252,14 +1252,14 @@ void route_map_action_show(struct vty *vty, const struct lyd_node *dnode,
} else if (IS_SET_EXTCOMMUNITY_LB(action)) {
enum ecommunity_lb_type lb_type;
char str[VTY_BUFSIZ];
- uint16_t bandwidth;
+ uint32_t bandwidth;
lb_type = yang_dnode_get_enum(
dnode,
"./rmap-set-action/frr-bgp-route-map:extcommunity-lb/lb-type");
switch (lb_type) {
case EXPLICIT_BANDWIDTH:
- bandwidth = yang_dnode_get_uint16(
+ bandwidth = yang_dnode_get_uint32(
dnode,
"./rmap-set-action/frr-bgp-route-map:extcommunity-lb/bandwidth");
snprintf(str, sizeof(str), "%d", bandwidth);
diff --git a/lib/subdir.am b/lib/subdir.am
index 5ec6adf4c0..221c0b1e1d 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -153,6 +153,7 @@ nodist_lib_libfrr_la_SOURCES = \
yang/frr-nexthop.yang.c \
yang/ietf/frr-deviations-ietf-key-chain.yang.c \
yang/ietf/ietf-routing-types.yang.c \
+ yang/ietf/ietf-netconf-acm.yang.c \
yang/ietf/ietf-key-chain.yang.c \
yang/ietf/ietf-interfaces.yang.c \
yang/ietf/ietf-bgp-types.yang.c \
diff --git a/lib/zclient.c b/lib/zclient.c
index 4cbd04c116..8a6eb95134 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1040,7 +1040,7 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
}
if (api_nh->weight)
- stream_putl(s, api_nh->weight);
+ stream_putq(s, api_nh->weight);
/* Router MAC for EVPN routes. */
if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_EVPN))
@@ -1412,7 +1412,7 @@ int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
}
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT))
- STREAM_GETL(s, api_nh->weight);
+ STREAM_GETQ(s, api_nh->weight);
/* Router MAC for EVPN routes. */
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN))
diff --git a/lib/zclient.h b/lib/zclient.h
index 1bf91064e2..3759f94542 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -441,7 +441,7 @@ struct zapi_nexthop {
struct ethaddr rmac;
- uint32_t weight;
+ uint64_t weight;
/* Backup nexthops, for IP-FRR, TI-LFA, etc */
uint8_t backup_num;
diff --git a/mgmtd/subdir.am b/mgmtd/subdir.am
index 1624c6e4f9..5182c4a47d 100644
--- a/mgmtd/subdir.am
+++ b/mgmtd/subdir.am
@@ -61,7 +61,6 @@ mgmtd_mgmtd_SOURCES = \
nodist_mgmtd_mgmtd_SOURCES = \
yang/frr-zebra.yang.c \
yang/frr-zebra-route-map.yang.c \
- yang/ietf/ietf-netconf-acm.yang.c \
yang/ietf/ietf-netconf.yang.c \
yang/ietf/ietf-netconf-with-defaults.yang.c \
# nothing
diff --git a/tests/topotests/bgp_extended_link_bandwidth/__init__.py b/tests/topotests/bgp_extended_link_bandwidth/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_extended_link_bandwidth/__init__.py
diff --git a/tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf b/tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf
new file mode 100644
index 0000000000..d0c0813e84
--- /dev/null
+++ b/tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf
@@ -0,0 +1,32 @@
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
+router bgp 65000
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.1.2 remote-as internal
+ neighbor 192.168.1.2 timers 1 3
+ neighbor 192.168.1.2 timers connect 1
+ neighbor 192.168.1.2 extended-link-bandwidth
+ address-family ipv4 unicast
+ network 10.10.10.40/32
+ network 10.10.10.100/32
+ network 10.10.10.200/32
+ neighbor 192.168.1.2 route-map r2 out
+ exit-address-family
+!
+ip prefix-list p40 seq 5 permit 10.10.10.40/32
+ip prefix-list p100 seq 5 permit 10.10.10.100/32
+ip prefix-list p200 seq 5 permit 10.10.10.200/32
+!
+route-map r2 permit 10
+ match ip address prefix-list p40
+ set extcommunity bandwidth 40000
+route-map r2 permit 20
+ match ip address prefix-list p100
+ set extcommunity bandwidth 100000
+route-map r2 permit 30
+ match ip address prefix-list p200
+ set extcommunity bandwidth 200000
+exit
diff --git a/tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf b/tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf
new file mode 100644
index 0000000000..5cad150aef
--- /dev/null
+++ b/tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf
@@ -0,0 +1,10 @@
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
+router bgp 65000
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as internal
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+!
diff --git a/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py b/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py
new file mode 100644
index 0000000000..e7058f5392
--- /dev/null
+++ b/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+# Copyright (c) 2024 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+import os
+import re
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for _, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_dynamic_capability_role():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r2 = tgen.gears["r2"]
+
+ def _bgp_converge():
+ output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast json detail"))
+ expected = {
+ "routes": {
+ "10.10.10.40/32": {
+ "paths": [
+ {
+ "extendedIpv6Community": {
+ "string": "LB:65000:5000000000 (40.000 Gbps)",
+ }
+ }
+ ]
+ },
+ "10.10.10.100/32": {
+ "paths": [
+ {
+ "extendedIpv6Community": {
+ "string": "LB:65000:12500000000 (100.000 Gbps)",
+ }
+ }
+ ]
+ },
+ "10.10.10.200/32": {
+ "paths": [
+ {
+ "extendedIpv6Community": {
+ "string": "LB:65000:25000000000 (200.000 Gbps)",
+ }
+ }
+ ]
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_converge,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see link bandwidths as expected"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_link_bw_ip/r2/bgp-route-3.json b/tests/topotests/bgp_link_bw_ip/r2/bgp-route-3.json
index dfc4171bad..6289a2eea3 100644
--- a/tests/topotests/bgp_link_bw_ip/r2/bgp-route-3.json
+++ b/tests/topotests/bgp_link_bw_ip/r2/bgp-route-3.json
@@ -4,7 +4,7 @@
{
"valid":true,
"multipath":true,
- "extendedCommunity":{
+ "extendedIpv6Community":{
"string":"LB:65302:125000 (1.000 Mbps)"
},
"nexthops":[
diff --git a/tests/topotests/bgp_link_bw_ip/r5/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r5/bgpd.conf
index 4014bfbc8b..e4ed92db1d 100644
--- a/tests/topotests/bgp_link_bw_ip/r5/bgpd.conf
+++ b/tests/topotests/bgp_link_bw_ip/r5/bgpd.conf
@@ -13,6 +13,7 @@ router bgp 65302
bgp bestpath as-path multipath-relax
no bgp ebgp-requires-policy
neighbor 11.1.2.5 remote-as external
+ neighbor 11.1.2.5 extended-link-bandwidth
neighbor 11.1.2.5 timers 3 10
neighbor 11.1.5.2 remote-as external
neighbor 11.1.5.2 timers 3 10
diff --git a/tests/topotests/lib/snmptest.py b/tests/topotests/lib/snmptest.py
index 814813f7f4..8e2e76d154 100644
--- a/tests/topotests/lib/snmptest.py
+++ b/tests/topotests/lib/snmptest.py
@@ -85,15 +85,18 @@ class SnmpTester(object):
return out_dict, out_list
def get(self, oid):
- cmd = "snmpget {0} {1}".format(self._snmp_config(), oid)
-
+ cmd = "snmpget {0} {1} 2>&1 | grep -v SNMPv2-PDU".format(
+ self._snmp_config(), oid
+ )
result = self.router.cmd(cmd)
if "not found" in result:
return None
return self._get_snmp_value(result)
def get_next(self, oid):
- cmd = "snmpgetnext {0} {1}".format(self._snmp_config(), oid)
+ cmd = "snmpgetnext {0} {1} 2>&1 | grep -v SNMPv2-PDU".format(
+ self._snmp_config(), oid
+ )
result = self.router.cmd(cmd)
print("get_next: {}".format(result))
@@ -102,7 +105,9 @@ class SnmpTester(object):
return self._get_snmp_value(result)
def walk(self, oid):
- cmd = "snmpwalk {0} {1}".format(self._snmp_config(), oid)
+ cmd = "snmpwalk {0} {1} 2>&1 | grep -v SNMPv2-PDU".format(
+ self._snmp_config(), oid
+ )
result = self.router.cmd(cmd)
return self._parse_multiline(result)
diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang
index c679f3b911..b0858e153c 100644
--- a/yang/frr-bgp-route-map.yang
+++ b/yang/frr-bgp-route-map.yang
@@ -881,9 +881,7 @@ identity set-extcommunity-color {
leaf bandwidth {
when "../lb-type = 'explicit-bandwidth'";
mandatory true;
- type uint16 {
- range "1..25600";
- }
+ type uint32;
description
"Bandwidth value in Mbps";
}
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 76cabd1bf0..d585ef996b 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1724,7 +1724,7 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p,
* Let's convert the weights to a scaled value
* between 1 and zrouter.nexthop_weight_scale_value
* This is a simple application of a ratio:
- * scaled_weight/zrouter.nexthop_weight_scale_value =
+ * scaled_weight/zrouter.nexthop_weight_scale_value =
* weight/max_weight
* This translates to:
* scaled_weight = weight * zrouter.nexthop_weight_scale_value
@@ -1738,9 +1738,8 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p,
for (i = 0; i < nexthop_num; i++) {
znh = &nhops[i];
- tmp = (uint64_t)znh->weight *
- zrouter.nexthop_weight_scale_value;
- znh->weight = MAX(1, ((uint32_t)(tmp / max_weight)));
+ tmp = znh->weight * zrouter.nexthop_weight_scale_value;
+ znh->weight = MAX(1, (tmp / max_weight));
}
}