From 85292ef926205b36d6550f90e8231184efc941ff Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 10 Apr 2024 13:43:15 +0300 Subject: [PATCH 01/16] doc: Add `neighbor ... extended-link-bandwidth` command Signed-off-by: Donatas Abraitis --- doc/user/bgp.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 68ae796bc9..e7c8264517 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1565,6 +1565,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 From e0b64f241454c60abeb91ee72773d279c8699095 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Mon, 8 Apr 2024 09:22:02 +0300 Subject: [PATCH 02/16] bgpd: Convert 32-bit to 64-bit link bandwidth variable (link_bw) This is needed to implement and use larger bandwidths rather than limiting only to theoretical 34Gbps max bandwidth. Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.h | 2 +- bgpd/bgp_ecommunity.c | 12 ++++++------ bgpd/bgp_ecommunity.h | 9 +++++---- bgpd/bgp_mpath.c | 2 +- bgpd/bgp_routemap.c | 12 ++++++------ 5 files changed, 19 insertions(+), 18 deletions(-) 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_ecommunity.c b/bgpd/bgp_ecommunity.c index e1b462ae56..2e45577324 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1805,7 +1805,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; @@ -1832,10 +1832,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 = 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; } } @@ -1852,7 +1852,7 @@ struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom, 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. diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 794c5a3975..3b558ea049 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -224,12 +224,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; @@ -385,7 +386,7 @@ 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); + uint64_t *bw); extern struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom, uint64_t cum_bw, diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 296e64003d..37a68ecb14 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; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 15828b6594..8b0872bbed 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 @@ -3207,7 +3207,7 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object) 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 +3221,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,7 +3237,7 @@ 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; } @@ -3275,7 +3275,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; From d9219ee847a179850c25d9d0f08511becc2d3102 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Mon, 8 Apr 2024 09:26:29 +0300 Subject: [PATCH 03/16] bgpd: Drop non ieee encoding parsing for ipv6 extended communities Link-bandwidth is encoded into extended community, not ipv6 extended community. Thus it's not needed here at all. Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.c | 5 +---- bgpd/bgp_ecommunity.c | 5 ++--- bgpd/bgp_ecommunity.h | 3 +-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index e2321ad296..0ccdb338e0 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2650,10 +2650,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 */ diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 2e45577324..3d0193f7b8 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. */ diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 3b558ea049..d319846887 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -326,8 +326,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 *); From c4986af74e83c3bb1c7116469be71d5f32645dfc Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 10 Apr 2024 10:12:02 +0300 Subject: [PATCH 04/16] bgpd: Adopt ecommunity_linkbw_present for IPv6 extended communities Signed-off-by: Donatas Abraitis --- bgpd/bgp_ecommunity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 3d0193f7b8..6cded922c2 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1820,7 +1820,7 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_t *bw) 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++; From 540f81c3465fa9fa37a07096026f9b319c6f48ca Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 10 Apr 2024 11:31:43 +0300 Subject: [PATCH 05/16] bgpd: Print IPv6 extended community for `show bgp attribute-info` Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 0ccdb338e0..dc13616b1d 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) From c8a2532ab39ce4829b7225824e28568d1f930da0 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Mon, 8 Apr 2024 09:07:01 +0300 Subject: [PATCH 06/16] bgpd: Add `neighbor ... extended-link-bandwidth` command Signed-off-by: Donatas Abraitis --- bgpd/bgp_vty.c | 26 ++++++++++++++++++++++++++ bgpd/bgpd.c | 1 + bgpd/bgpd.h | 1 + 3 files changed, 28 insertions(+) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 05d3c097b7..0388fae107 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 $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, @@ -18441,6 +18461,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", @@ -20953,6 +20976,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/bgpd.c b/bgpd/bgpd.c index 5fd4ebe8cc..db1ed4943d 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..642453d90d 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -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 From b29fdafa3f67cc196091f5af6af022a098bc4b65 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 10 Apr 2024 13:35:09 +0300 Subject: [PATCH 07/16] bgpd: Print IPv6 extended communities for `show bgp ` Signed-off-by: Donatas Abraitis --- bgpd/bgp_route.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 848e8ffd8d..7c9b641503 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10453,6 +10453,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; @@ -11161,6 +11162,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) { From 09e2a362a32e646d9ab0206d79a7e5ff9980eaeb Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 10 Apr 2024 10:16:01 +0300 Subject: [PATCH 08/16] bgpd: Implement draft-li-idr-link-bandwidth-ext-01 Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.c | 146 ++++++++++++++++++---------------- bgpd/bgp_ecommunity.c | 82 ++++++++++++++++--- bgpd/bgp_ecommunity.h | 43 +++++++++- bgpd/bgp_route.c | 29 ++++--- bgpd/bgp_routemap.c | 61 +++++++++----- bgpd/bgp_routemap_nb_config.c | 6 +- bgpd/bgpd.h | 2 +- lib/routemap_cli.c | 4 +- yang/frr-bgp-route-map.yang | 4 +- 9 files changed, 256 insertions(+), 121 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index dc13616b1d..b57a142d8d 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -4352,6 +4352,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 || + 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, @@ -4654,82 +4717,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; + if (CHECK_FLAG(attr->flag, + ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { + struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr); - for (i = 0; i < ecomm->size; i++) { - pnt = ecomm->val + (i * 8); - tbit = *pnt; + bgp_packet_ecommunity_attribute(s, peer, ecomm, + transparent, + BGP_ATTR_EXT_COMMUNITIES); + } - if (CHECK_FLAG(tbit, - ECOMMUNITY_FLAG_NON_TRANSITIVE)) - continue; + if (CHECK_FLAG(attr->flag, + ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES))) { + struct ecommunity *ecomm = + bgp_attr_get_ipv6_ecommunity(attr); - ecom_tr_size++; - } - - 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_ecommunity.c b/bgpd/bgp_ecommunity.c index 6cded922c2..ac3bc09e9f 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1025,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); @@ -1052,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 + snprintf(bps_buf, sizeof(bps_buf), "%" PRIu64 " bps", bw * 8); + + len = snprintf(buf, bufsz, "LB:%u:%" PRIu64 " (%s)", as, bw, bps_buf); + return len; +} + bool ecommunity_has_route_target(struct ecommunity *ecom) { uint32_t i; @@ -1152,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( @@ -1369,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) @@ -1818,7 +1854,6 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_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 * ecom->unit_size)); type = *pnt++; @@ -1827,6 +1862,8 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_t *bw) 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 */ @@ -1836,6 +1873,18 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_t *bw) : 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; } } @@ -1845,10 +1894,10 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_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; uint64_t cur_bw; @@ -1875,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 d319846887..74616f01a5 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,11 @@ /* RFC 8956 */ #define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0d +/* https://datatracker.ietf.org/doc/html/draft-li-idr-link-bandwidth-ext-01 + * Sub-type is not allocated by IANA, but let's get the first available. + */ +#define ECOMMUNITY_EXTENDED_LINK_BANDWIDTH 0x0016 + /* 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 @@ -245,6 +254,33 @@ static inline void encode_lb_extcomm(as_t as, uint64_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) { @@ -386,10 +422,9 @@ extern void bgp_remove_ecomm_from_aggregate_hash( extern void bgp_aggr_ecommunity_remove(void *arg); extern const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_t *bw); -extern struct ecommunity *ecommunity_replace_linkbw(as_t as, - struct ecommunity *ecom, - uint64_t cum_bw, - bool disable_ieee_floating); +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_route.c b/bgpd/bgp_route.c index 7c9b641503..c9289f97e5 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2771,17 +2771,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; } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 8b0872bbed..1515b64b77 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3206,7 +3206,6 @@ 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; uint64_t bw_bytes = 0; uint16_t mpath_count = 0; struct ecommunity *new_ecom; @@ -3242,26 +3241,48 @@ 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, - 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; - /* new_ecom will be intern()'d or attr_flush()'d in call stack */ - bgp_attr_set_ecommunity(path->attr, new_ecom); + 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); + } + + bgp_attr_set_ecommunity(path->attr, new_ecom); + } /* Mark that route-map has set link bandwidth; used in attribute * setting decisions. @@ -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/bgpd.h b/bgpd/bgpd.h index 642453d90d..06ef1d3537 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. */ 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/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"; } From e53bd693263792f45554b8b20a9264d6c518ad86 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 10 Apr 2024 13:34:47 +0300 Subject: [PATCH 09/16] bgpd: Allow sending extended communities between OAD peers Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index b57a142d8d..7cd8e557b9 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -4357,7 +4357,7 @@ static void bgp_packet_ecommunity_attribute(struct stream *s, struct peer *peer, bool transparent, int attribute) { if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || - transparent) { + 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 | From a988a0a88a09ad5b88eac299bb10b7b8aa64db6a Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 10 Apr 2024 16:13:57 +0300 Subject: [PATCH 10/16] *: Use uint64_t for weight down the path to Zebra Signed-off-by: Donatas Abraitis --- bgpd/bgp_zebra.c | 9 +++++---- lib/zclient.c | 4 ++-- lib/zclient.h | 2 +- zebra/zapi_msg.c | 7 +++---- 4 files changed, 11 insertions(+), 11 deletions(-) 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/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/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)); } } From d92a284523c1773130d1e27c7a4182e5b1438ba7 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 10 Apr 2024 16:33:14 +0300 Subject: [PATCH 11/16] bgpd: Extract link bandwidth from IPv6 extended community if received Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 7cd8e557b9..913634bf59 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2661,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: From 0703ae35cc248e25359be702b1c4412bab4d0375 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 11 Apr 2024 11:52:02 +0300 Subject: [PATCH 12/16] bgpd: Include IPv6 extended community into multipath considerations Signed-off-by: Donatas Abraitis --- bgpd/bgp_mpath.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 37a68ecb14..e12d84b84c 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -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; From 055cc0488bc5b33548cb3eeea2a82685ab1f1a5b Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 11 Apr 2024 11:55:06 +0300 Subject: [PATCH 13/16] tests: Check if extended link bandwidth is considered into also Signed-off-by: Donatas Abraitis --- tests/topotests/bgp_link_bw_ip/r2/bgp-route-3.json | 2 +- tests/topotests/bgp_link_bw_ip/r5/bgpd.conf | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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 From 4d3e679b04f94ba69103c919abcd4c8156123c1f Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 11 Apr 2024 13:15:21 +0300 Subject: [PATCH 14/16] bgpd: Use snprintfrr() to print PRIu64 for ipv6_ecommunity_lb_str() Signed-off-by: Donatas Abraitis --- bgpd/bgp_ecommunity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index ac3bc09e9f..be8f56637e 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1069,9 +1069,9 @@ static int ipv6_ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt) snprintf(bps_buf, sizeof(bps_buf), "%.3f Kbps", (float)(bw / ONE_KBPS_BYTES)); else - snprintf(bps_buf, sizeof(bps_buf), "%" PRIu64 " bps", bw * 8); + snprintfrr(bps_buf, sizeof(bps_buf), "%" PRIu64 " bps", bw * 8); - len = snprintf(buf, bufsz, "LB:%u:%" PRIu64 " (%s)", as, bw, bps_buf); + len = snprintfrr(buf, bufsz, "LB:%u:%" PRIu64 " (%s)", as, bw, bps_buf); return len; } From 593a80651041618a48d04c0c38f1acb23b613400 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sat, 13 Apr 2024 22:05:20 +0300 Subject: [PATCH 15/16] tests: Check if extended link bandwidth can be more than 25gbps Signed-off-by: Donatas Abraitis --- .../bgp_extended_link_bandwidth/__init__.py | 0 .../bgp_extended_link_bandwidth/r1/frr.conf | 32 +++++++ .../bgp_extended_link_bandwidth/r2/frr.conf | 10 ++ .../test_bgp_extended_link_bandwidth.py | 95 +++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 tests/topotests/bgp_extended_link_bandwidth/__init__.py create mode 100644 tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf create mode 100644 tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf create mode 100644 tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py 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 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 +# + +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)) From 634d1375faa62c6593cc9292d32804666333a1f6 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 23 Apr 2024 08:52:31 +0300 Subject: [PATCH 16/16] bgpd: Update IPv6 extended community sub-type for extended link bandwidth Already assigned by IANA, just the draft is not yet updated. https://www.iana.org/assignments/bgp-extended-communities/bgp-extended-communities.xhtml#trans-ipv6 Signed-off-by: Donatas Abraitis --- bgpd/bgp_ecommunity.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 74616f01a5..929e4e60be 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -60,9 +60,10 @@ #define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0d /* https://datatracker.ietf.org/doc/html/draft-li-idr-link-bandwidth-ext-01 - * Sub-type is not allocated by IANA, but let's get the first available. + * Sub-type is allocated by IANA, just the draft is not yet updated with the + * new value. */ -#define ECOMMUNITY_EXTENDED_LINK_BANDWIDTH 0x0016 +#define ECOMMUNITY_EXTENDED_LINK_BANDWIDTH 0x0006 /* Low-order octet of the Extended Communities type field for EVPN types */ #define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY 0x00