Merge pull request #19223 from pguibert6WIND/sid_extend_to_32bits
Some checks failed
github-ci / Ubuntu 22.04 amd64 Build (push) Has been cancelled
github-ci / Ubuntu 22.04 arm64 Build (push) Has been cancelled
github-ci / Ubuntu 24.04 amd64 Build (push) Has been cancelled
github-ci / Ubuntu 24.04 arm64 Build (push) Has been cancelled
github-ci / Ubuntu 22.04 amd64 Test (push) Has been cancelled
github-ci / Ubuntu 22.04 arm64 Test (push) Has been cancelled
github-ci / Ubuntu 24.04 amd64 Test (push) Has been cancelled
github-ci / Ubuntu 24.04 arm64 Test (push) Has been cancelled

SID extension to 32bits
This commit is contained in:
Carmine Scarpitta 2026-01-10 09:50:00 +01:00 committed by GitHub
commit 74b7eb143a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 852 additions and 143 deletions

View file

@ -798,19 +798,19 @@ static void *srv6_l3service_hash_alloc(void *p)
return p;
}
static void srv6_l3service_free(struct bgp_attr_srv6_l3service *l3service)
void bgp_attr_srv6_l3service_free(struct bgp_attr_srv6_l3service *l3service)
{
XFREE(MTYPE_BGP_SRV6_L3SERVICE, l3service);
}
static struct bgp_attr_srv6_l3service *
srv6_l3service_intern(struct bgp_attr_srv6_l3service *l3service)
struct bgp_attr_srv6_l3service *
bgp_attr_srv6_l3service_intern(struct bgp_attr_srv6_l3service *l3service)
{
struct bgp_attr_srv6_l3service *find;
find = hash_get(srv6_l3service_hash, l3service, srv6_l3service_hash_alloc);
if (find != l3service)
srv6_l3service_free(l3service);
bgp_attr_srv6_l3service_free(l3service);
find->refcnt++;
return find;
}
@ -827,7 +827,7 @@ static void srv6_l3service_unintern(struct bgp_attr_srv6_l3service **l3servicep)
if (l3service->refcnt == 0) {
hash_release(srv6_l3service_hash, l3service);
srv6_l3service_free(l3service);
bgp_attr_srv6_l3service_free(l3service);
*l3servicep = NULL;
}
}
@ -950,7 +950,7 @@ static void srv6_init(void)
static void srv6_finish(void)
{
hash_clean_and_free(&srv6_l3service_hash, (void (*)(void *))srv6_l3service_free);
hash_clean_and_free(&srv6_l3service_hash, (void (*)(void *))bgp_attr_srv6_l3service_free);
hash_clean_and_free(&srv6_vpn_hash, (void (*)(void *))srv6_vpn_free);
}
@ -1314,7 +1314,7 @@ struct attr *bgp_attr_intern(struct attr *attr)
if (attr->srv6_l3service) {
if (!attr->srv6_l3service->refcnt)
attr->srv6_l3service = srv6_l3service_intern(attr->srv6_l3service);
attr->srv6_l3service = bgp_attr_srv6_l3service_intern(attr->srv6_l3service);
else
attr->srv6_l3service->refcnt++;
}
@ -1668,7 +1668,7 @@ void bgp_attr_flush(struct attr *attr)
attr->encap_subtlvs = NULL;
}
if (attr->srv6_l3service && !attr->srv6_l3service->refcnt) {
srv6_l3service_free(attr->srv6_l3service);
bgp_attr_srv6_l3service_free(attr->srv6_l3service);
attr->srv6_l3service = NULL;
}
if (attr->srv6_vpn && !attr->srv6_vpn->refcnt) {
@ -3415,7 +3415,7 @@ bgp_attr_srv6_service(struct bgp_attr_parser_args *args)
return err;
}
attr->srv6_l3service = srv6_l3service_intern(attr->srv6_l3service);
attr->srv6_l3service = bgp_attr_srv6_l3service_intern(attr->srv6_l3service);
}
/* Placeholder code for unsupported type */

View file

@ -383,6 +383,9 @@ extern enum bgp_attr_parse_ret
bgp_attr_parse(struct peer *peer, struct attr *attr, bgp_size_t size,
struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw);
extern struct attr *bgp_attr_intern(struct attr *attr);
extern struct bgp_attr_srv6_l3service *
bgp_attr_srv6_l3service_intern(struct bgp_attr_srv6_l3service *vpn);
extern void bgp_attr_srv6_l3service_free(struct bgp_attr_srv6_l3service *vpn);
extern void bgp_attr_unintern_sub(struct attr *attr);
extern void bgp_attr_unintern(struct attr **pattr);
extern void bgp_attr_flush(struct attr *attr);

View file

@ -371,9 +371,11 @@ void vpn_leak_zebra_vrf_sid_update_per_af(struct bgp *bgp, afi_t afi)
bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length;
ctx.node_len =
bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length;
ctx.function_len =
bgp->vpn_policy[afi]
.tovpn_sid_locator->function_bits_length;
if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_SID_FUNC_WIDE))
ctx.function_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_BGP;
else
ctx.function_len =
bgp->vpn_policy[afi].tovpn_sid_locator->function_bits_length;
ctx.argument_len =
bgp->vpn_policy[afi]
.tovpn_sid_locator->argument_bits_length;
@ -440,7 +442,10 @@ void vpn_leak_zebra_vrf_sid_update_per_vrf(struct bgp *bgp)
if (bgp->tovpn_sid_locator) {
ctx.block_len = bgp->tovpn_sid_locator->block_bits_length;
ctx.node_len = bgp->tovpn_sid_locator->node_bits_length;
ctx.function_len = bgp->tovpn_sid_locator->function_bits_length;
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_FUNC_WIDE))
ctx.function_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_BGP;
else
ctx.function_len = bgp->tovpn_sid_locator->function_bits_length;
ctx.argument_len = bgp->tovpn_sid_locator->argument_bits_length;
if (CHECK_FLAG(bgp->tovpn_sid_locator->flags, SRV6_LOCATOR_USID))
SET_SRV6_FLV_OP(ctx.flv.flv_ops, ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID);
@ -508,9 +513,11 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length;
seg6localctx.node_len =
bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length;
seg6localctx.function_len =
bgp->vpn_policy[afi]
.tovpn_sid_locator->function_bits_length;
if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_SID_FUNC_WIDE))
seg6localctx.function_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_BGP;
else
seg6localctx.function_len =
bgp->vpn_policy[afi].tovpn_sid_locator->function_bits_length;
seg6localctx.argument_len =
bgp->vpn_policy[afi]
.tovpn_sid_locator->argument_bits_length;
@ -526,6 +533,7 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
bgp_zebra_release_srv6_sid(&ctx, bgp->vpn_policy[afi].tovpn_sid_locator->name);
UNSET_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_SID_FUNC_WIDE);
}
/*
@ -559,8 +567,10 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp)
seg6localctx.block_len =
bgp->tovpn_sid_locator->block_bits_length;
seg6localctx.node_len = bgp->tovpn_sid_locator->node_bits_length;
seg6localctx.function_len =
bgp->tovpn_sid_locator->function_bits_length;
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_FUNC_WIDE))
seg6localctx.function_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_BGP;
else
seg6localctx.function_len = bgp->tovpn_sid_locator->function_bits_length;
seg6localctx.argument_len =
bgp->tovpn_sid_locator->argument_bits_length;
}
@ -573,6 +583,7 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp)
ctx.vrf_id = bgp->vrf_id;
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
bgp_zebra_release_srv6_sid(&ctx, bgp->tovpn_sid_locator->name);
UNSET_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_FUNC_WIDE);
}
/*
@ -704,26 +715,37 @@ bool srv6_sid_compose(struct in6_addr *sid_value, struct srv6_locator *locator,
uint8_t offset = 0;
uint8_t func_len = 0, shift_len = 0;
uint32_t sid_func_max = 0;
bool store_in_label = true;
if (!locator || !sid_value)
return false;
if (locator->function_bits_length >
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH) {
if (locator->function_bits_length > BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_BGP) {
if (debug)
zlog_debug("%s: invalid SRv6 Locator (%pFX): Function Length must be less or equal to %d",
__func__, &locator->prefix,
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH);
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_LABEL);
return false;
}
/* Max value that can be encoded in the Function part of the SID */
sid_func_max = (1 << locator->function_bits_length) - 1;
if ((CHECK_FLAG(locator->flags, SRV6_LOCATOR_F3216) ||
CHECK_FLAG(locator->flags, SRV6_LOCATOR_F4816)) &&
sid_func > 0xFFFF) {
/* f3216 and f4816 supports ewlib. increase sid_func_max */
sid_func_max = 0xffffffff;
store_in_label = false;
} else if (locator->function_bits_length == BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_BGP)
/* shifting 32 bits over a 32 bit is not possible. directly encode func_max */
sid_func_max = 0xffffffff;
else
sid_func_max = (1 << locator->function_bits_length) - 1;
if (sid_func > sid_func_max) {
if (debug)
zlog_debug("%s: invalid SRv6 Locator (%pFX): Function Length is too short to support specified function (%u)",
__func__, &locator->prefix, sid_func);
zlog_debug("%s: invalid SRv6 Locator (%pFX): Function Length is too short (%u) to support specified function (%u)",
__func__, &locator->prefix, sid_func_max, sid_func);
return false;
}
@ -735,37 +757,45 @@ bool srv6_sid_compose(struct in6_addr *sid_value, struct srv6_locator *locator,
/* First, we put the locator (LOC) in the most significant bits of sid_value */
*sid_value = locator->prefix.prefix;
/*
* Then, we compute the offset at which we have to place the function (FUNC).
* FUNC will be placed immediately after LOC, i.e. at block_bits_length + node_bits_length
*/
offset = locator->block_bits_length + locator->node_bits_length;
/*
* The FUNC part of the SID is advertised in the label field of SRv6 Service TLV.
* (see SID Transposition Scheme, RFC 9252 section #4).
* Therefore, we need to encode the FUNC in the most significant bits of the
* 20-bit label.
*/
func_len = locator->function_bits_length;
shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH - func_len;
label = sid_func << shift_len;
if (label < MPLS_LABEL_UNRESERVED_MIN) {
if (debug)
zlog_debug("%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
__func__, &locator->prefix, label);
return false;
}
if (sid_exist(bgp_get_default(), sid_value)) {
zlog_warn("%s: skipped to allocate SRv6 SID (%pFX): SID %pI6 already in use",
__func__, &locator->prefix, sid_value);
return false;
}
/* Finally, we put the FUNC in sid_value at the computed offset */
transpose_sid(sid_value, label, offset, func_len);
/*
* Then, we compute the offset at which we have to place the function (FUNC).
* FUNC will be placed immediately after LOC, i.e. at block_bits_length + node_bits_length
*/
offset = locator->block_bits_length + locator->node_bits_length;
if (store_in_label)
func_len = locator->function_bits_length;
else
func_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_BGP;
if (store_in_label && func_len <= BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_LABEL) {
/*
* The FUNC part of the SID is advertised in the label field of SRv6 Service TLV.
* (see SID Transposition Scheme, RFC 9252 section #4).
* Therefore, we need to encode the FUNC in the most significant bits of the
* 20-bit label.
*/
shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_LABEL - func_len;
label = sid_func << shift_len;
if (label < MPLS_LABEL_UNRESERVED_MIN) {
if (debug)
zlog_debug("%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
__func__, &locator->prefix, label);
return false;
}
/* Finally, we put the FUNC in sid_value at the computed offset */
transpose_sid(sid_value, label, offset, func_len,
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_LABEL);
} else {
label = sid_func;
transpose_sid(sid_value, label, offset, func_len,
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_BGP);
}
return true;
}
@ -995,6 +1025,7 @@ void delete_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
bgp_zebra_release_srv6_sid(&ctx, bgp_vrf->vpn_policy[afi].tovpn_sid_locator->name);
UNSET_FLAG(bgp_vrf->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_SID_FUNC_WIDE);
sid_unregister(bgp_vpn, bgp_vrf->vpn_policy[afi].tovpn_sid);
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->vpn_policy[afi].tovpn_sid);
@ -1041,6 +1072,7 @@ void delete_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
ctx.vrf_id = bgp_vrf->vrf_id;
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
bgp_zebra_release_srv6_sid(&ctx, bgp_vrf->tovpn_sid_locator->name);
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_TOVPN_SID_FUNC_WIDE);
sid_unregister(bgp_vpn, bgp_vrf->tovpn_sid);
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
@ -1086,13 +1118,13 @@ void delete_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
* |
* offset from MSB
*/
void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
uint8_t len)
void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset, uint8_t len,
uint8_t len_max)
{
for (uint8_t idx = 0; idx < len; idx++) {
uint8_t tidx = offset + idx;
sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8));
if (label >> (19 - idx) & 0x1)
if (label >> (len_max - 1 - idx) & 0x1)
sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8);
}
}
@ -1716,7 +1748,7 @@ static bool vpn_leak_from_vrf_fill_srv6(struct attr *attr, struct bgp *from_bgp,
mpls_label_t *label)
{
/* Set SID for SRv6 VPN */
if (from_bgp->vpn_policy[afi].tovpn_sid_locator) {
if (from_bgp->vpn_policy[afi].tovpn_sid_locator && from_bgp->vpn_policy[afi].tovpn_sid) {
struct srv6_locator *locator = from_bgp->vpn_policy[afi].tovpn_sid_locator;
encode_label(from_bgp->vpn_policy[afi].tovpn_sid_transpose_label, label);
@ -1734,22 +1766,32 @@ static bool vpn_leak_from_vrf_fill_srv6(struct attr *attr, struct bgp *from_bgp,
from_bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length;
attr->srv6_l3service->loc_node_len =
from_bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length;
attr->srv6_l3service->func_len =
from_bgp->vpn_policy[afi].tovpn_sid_locator->function_bits_length;
if (CHECK_FLAG(from_bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_SID_FUNC_WIDE))
attr->srv6_l3service->func_len =
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_BGP;
else
attr->srv6_l3service->func_len =
from_bgp->vpn_policy[afi].tovpn_sid_locator->function_bits_length;
attr->srv6_l3service->arg_len =
from_bgp->vpn_policy[afi].tovpn_sid_locator->argument_bits_length;
attr->srv6_l3service->transposition_len =
from_bgp->vpn_policy[afi].tovpn_sid_locator->function_bits_length;
attr->srv6_l3service->transposition_offset =
from_bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length +
from_bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length;
;
memcpy(&attr->srv6_l3service->sid,
&from_bgp->vpn_policy[afi].tovpn_sid_locator->prefix.prefix,
sizeof(struct in6_addr));
if (attr->srv6_l3service->func_len >
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_LABEL) {
attr->srv6_l3service->transposition_len = 0;
attr->srv6_l3service->transposition_offset = 0;
IPV6_ADDR_COPY(&attr->srv6_l3service->sid,
from_bgp->vpn_policy[afi].tovpn_sid);
} else {
attr->srv6_l3service->transposition_len =
from_bgp->vpn_policy[afi].tovpn_sid_locator->function_bits_length;
attr->srv6_l3service->transposition_offset =
from_bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length +
from_bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length;
IPV6_ADDR_COPY(&attr->srv6_l3service->sid,
&from_bgp->vpn_policy[afi].tovpn_sid_locator->prefix.prefix);
}
return true;
}
if (from_bgp->tovpn_sid_locator) {
if (from_bgp->tovpn_sid_locator && from_bgp->tovpn_sid) {
struct srv6_locator *locator = from_bgp->tovpn_sid_locator;
encode_label(from_bgp->tovpn_sid_transpose_label, label);
@ -1763,15 +1805,27 @@ static bool vpn_leak_from_vrf_fill_srv6(struct attr *attr, struct bgp *from_bgp,
attr->srv6_l3service->loc_block_len =
from_bgp->tovpn_sid_locator->block_bits_length;
attr->srv6_l3service->loc_node_len = from_bgp->tovpn_sid_locator->node_bits_length;
attr->srv6_l3service->func_len = from_bgp->tovpn_sid_locator->function_bits_length;
if (CHECK_FLAG(from_bgp->vrf_flags, BGP_VRF_TOVPN_SID_FUNC_WIDE))
attr->srv6_l3service->func_len =
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_BGP;
else
attr->srv6_l3service->func_len =
from_bgp->tovpn_sid_locator->function_bits_length;
attr->srv6_l3service->arg_len = from_bgp->tovpn_sid_locator->argument_bits_length;
attr->srv6_l3service->transposition_len =
from_bgp->tovpn_sid_locator->function_bits_length;
attr->srv6_l3service->transposition_offset =
from_bgp->tovpn_sid_locator->block_bits_length +
from_bgp->tovpn_sid_locator->node_bits_length;
memcpy(&attr->srv6_l3service->sid, &from_bgp->tovpn_sid_locator->prefix.prefix,
sizeof(struct in6_addr));
if (attr->srv6_l3service->func_len >
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_LABEL) {
attr->srv6_l3service->transposition_len = 0;
attr->srv6_l3service->transposition_offset = 0;
IPV6_ADDR_COPY(&attr->srv6_l3service->sid, from_bgp->tovpn_sid);
} else {
attr->srv6_l3service->transposition_len =
from_bgp->tovpn_sid_locator->function_bits_length;
attr->srv6_l3service->transposition_offset =
from_bgp->tovpn_sid_locator->block_bits_length +
from_bgp->tovpn_sid_locator->node_bits_length;
IPV6_ADDR_COPY(&attr->srv6_l3service->sid,
&from_bgp->tovpn_sid_locator->prefix.prefix);
}
return true;
}
return false;

View file

@ -29,7 +29,8 @@
#define V4_HEADER_OVERLAY \
" Network Next Hop EthTag Overlay Index RouterMac\n"
#define BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH 20
#define BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_LABEL 20
#define BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_BGP 32
extern void bgp_mplsvpn_init(void);
extern void bgp_mplsvpn_path_nh_label_unlink(struct bgp_path_info *pi);
@ -87,8 +88,8 @@ extern void delete_vrf_tovpn_sid_per_vrf(struct bgp *vpn, struct bgp *vrf);
extern void ensure_vrf_tovpn_sid_per_af(struct bgp *vpn, struct bgp *vrf,
afi_t afi);
extern void ensure_vrf_tovpn_sid_per_vrf(struct bgp *vpn, struct bgp *vrf);
extern void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
uint8_t size);
extern void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset, uint8_t size,
uint8_t size_max);
extern void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, const char *import_name,
afi_t afi, safi_t safi);
void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, const char *import_name,

View file

@ -1111,7 +1111,8 @@ static bool make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p,
transpose_sid(&p->u.prefix6,
decode_label(&pi->extra->labels->label[0]),
pi->attr->srv6_l3service->transposition_offset,
pi->attr->srv6_l3service->transposition_len);
pi->attr->srv6_l3service->transposition_len,
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_LABEL);
} else
IPV6_ADDR_COPY(&(p->u.prefix6), &(pi->attr->srv6_l3service->sid));
} else if (is_bgp_static) {

View file

@ -13007,7 +13007,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
IPV6_ADDR_COPY(&sid_transposed, sid_tmp);
transpose_sid(&sid_transposed, label_sid,
path->attr->srv6_l3service->transposition_offset,
path->attr->srv6_l3service->transposition_len);
path->attr->srv6_l3service->transposition_len,
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_LABEL);
json_object_string_addf(json_path, "remoteTransposedSid", "%pI6",
&sid_transposed);
json_object_string_addf(json_path, "remoteSid", "%pI6",

View file

@ -10546,7 +10546,7 @@ DEFPY (af_label_vpn_export,
DEFPY (af_sid_vpn_export,
af_sid_vpn_export_cmd,
"[no] sid vpn export <(1-1048575)$sid_idx|auto$sid_auto|explicit$sid_explicit X:X::X:X$sid_value>",
"[no] sid vpn export <(1-4294967295)$sid_idx|auto$sid_auto|explicit$sid_explicit X:X::X:X$sid_value>",
NO_STR
"sid value for VRF\n"
"Between current address-family and vpn\n"
@ -10667,7 +10667,7 @@ DEFPY (af_sid_vpn_export,
DEFPY (bgp_sid_vpn_export,
bgp_sid_vpn_export_cmd,
"[no] sid vpn per-vrf export <(1-1048575)$sid_idx|auto$sid_auto|explicit$sid_explicit X:X::X:X$sid_value>",
"[no] sid vpn per-vrf export <(1-4294967295)$sid_idx|auto$sid_auto|explicit$sid_explicit X:X::X:X$sid_value>",
NO_STR
"sid value for VRF\n"
"Between current vrf and vpn\n"
@ -19123,8 +19123,7 @@ static void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
vty_out(vty, "%*ssid vpn export explicit %pI6\n", indent, "",
bgp->vpn_policy[afi].tovpn_sid_explicit);
} else if (tovpn_sid_index != 0) {
vty_out(vty, "%*ssid vpn export %d\n", indent, "",
tovpn_sid_index);
vty_out(vty, "%*ssid vpn export %u\n", indent, "", tovpn_sid_index);
}
if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_RD_SET))
@ -20663,8 +20662,7 @@ int bgp_config_write(struct vty *vty)
vty_out(vty, " sid vpn per-vrf export explicit %pI6\n",
bgp->tovpn_sid_explicit);
} else if (tovpn_sid_index != 0) {
vty_out(vty, " sid vpn per-vrf export %d\n",
tovpn_sid_index);
vty_out(vty, " sid vpn per-vrf export %u\n", tovpn_sid_index);
}
/* IPv4 unicast configuration. */

View file

@ -1490,7 +1490,8 @@ static void bgp_zebra_announce_parse_nexthop(struct bgp_path_info *info, const s
transpose_sid(&api_nh->seg6_segs[0], nh_label,
mpinfo->attr->srv6_l3service->transposition_offset,
mpinfo->attr->srv6_l3service->transposition_len);
mpinfo->attr->srv6_l3service->transposition_len,
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_LABEL);
}
api_nh->seg_num = 1;
@ -3662,7 +3663,7 @@ static int bgp_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS)
char buf[256];
struct in6_addr *tovpn_sid;
struct prefix_ipv6 tmp_prefix;
uint32_t sid_func;
uint32_t sid_func, sid_wide_func = 0;
bool found = false;
char *loc_name;
@ -3684,8 +3685,8 @@ static int bgp_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS)
}
/* Decode the received notification message */
if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr, &sid_func, NULL, &note,
&loc_name)) {
if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr, &sid_func, &sid_wide_func,
&note, &loc_name)) {
zlog_err("%s : error in msg decode", __func__);
return -1;
}
@ -3759,10 +3760,21 @@ static int bgp_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS)
/* Get label */
uint8_t func_len = locator_bgp->function_bits_length;
uint8_t shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH -
func_len;
mpls_label_t label = MPLS_LABEL_IMPLICIT_NULL;
int label = sid_func << shift_len;
if (sid_wide_func && (CHECK_FLAG(locator_bgp->flags, SRV6_LOCATOR_F3216) ||
CHECK_FLAG(locator_bgp->flags, SRV6_LOCATOR_F4816))) {
if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT6)
SET_FLAG(bgp_vrf->vpn_policy[AFI_IP6].flags,
BGP_VPN_POLICY_TOVPN_SID_FUNC_WIDE);
else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT4)
SET_FLAG(bgp_vrf->vpn_policy[AFI_IP].flags,
BGP_VPN_POLICY_TOVPN_SID_FUNC_WIDE);
else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT46)
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_TOVPN_SID_FUNC_WIDE);
} else if (func_len <= BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_LABEL)
label = sid_func
<< (BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH_FOR_LABEL - func_len);
/* Un-export VPN to VRF routes */
if (is_srv6_vpn_enabled(bgp_vrf)) {

View file

@ -294,6 +294,7 @@ struct vpn_policy {
#define BGP_VPN_POLICY_TOVPN_SID_EXPLICIT (1 << 6)
/* Is this value set by the cli? */
#define BGP_VPN_POLICY_TOVPN_RD_CLI_SET (1 << 7)
#define BGP_VPN_POLICY_TOVPN_SID_FUNC_WIDE (1 << 8)
/*
* If we are importing another vrf into us keep a list of
@ -982,6 +983,7 @@ struct bgp {
/* per-VRF toVPN SID */
#define BGP_VRF_TOVPN_SID_AUTO (1 << 7)
#define BGP_VRF_TOVPN_SID_EXPLICIT (1 << 8)
#define BGP_VRF_TOVPN_SID_FUNC_WIDE (1 << 9)
/* unique ID for auto derivation of RD for this vrf */
uint16_t vrf_rd_id;

View file

@ -149,6 +149,8 @@ struct srv6_locator {
uint8_t flags;
#define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */
#define SRV6_LOCATOR_PSP (1 << 1) /* The SRv6 Locator has the PSP flavor */
#define SRV6_LOCATOR_F3216 (1 << 2) /* The SRv6 Locator has F3216 format */
#define SRV6_LOCATOR_F4816 (1 << 3) /* The SRv6 Locator has F4816 format */
/* Pointer to the SID format. */
struct srv6_sid_format *sid_format;

View file

@ -0,0 +1,11 @@
frr version 10.3-dev-my-manual-build
frr defaults traditional
hostname c31
!
ip route 0.0.0.0/0 192.168.3.254
ip route 192.168.0.0/16 192.168.3.254
!
interface eth10
ip address 192.168.3.1/24
exit
!

View file

@ -0,0 +1,11 @@
frr version 10.3-dev-my-manual-build
frr defaults traditional
hostname c32
!
ip route 0.0.0.0/0 192.168.4.254
ip route 192.168.0.0/16 192.168.4.254
!
interface eth10
ip address 192.168.4.1/24
exit
!

View file

@ -0,0 +1,34 @@
{
"2001:db8:3:fff7:fe4b::/128":[
{
"prefix":"2001:db8:3:fff7:fe4b::/128",
"prefixLen":128,
"protocol":"bgp",
"selected":true,
"destSelected":true,
"distance":20,
"metric":0,
"installed":true,
"table":254,
"nexthops":[
{
"flags":3,
"fib":true,
"directlyConnected":true,
"interfaceName":"Vrf10",
"active":true,
"weight":1,
"seg6local":{
"action":"uDT46",
"sidStructure":{
"blockLen":32,
"nodeLen":16,
"funcLen":32,
"argLen":0
}
}
}
]
}
]
}

View file

@ -0,0 +1,18 @@
{
"2001:db8:3:fff7:fe50::":{
"sid":"2001:db8:3:fff7:fe50::",
"behavior":"uDT46",
"context":{
"vrfName":"Vrf10",
"table":10
},
"locator":"MAIN",
"allocationMode":"explicit",
"clients":[
{
"protocol":"bgp",
"instance":0
}
]
}
}

View file

@ -0,0 +1,18 @@
{
"2001:db8:3:fff7:fe4b::":{
"sid":"2001:db8:3:fff7:fe4b::",
"behavior":"uDT46",
"context":{
"vrfName":"Vrf10",
"table":10
},
"locator":"MAIN",
"allocationMode":"explicit",
"clients":[
{
"protocol":"bgp",
"instance":0
}
]
}
}

View file

@ -0,0 +1,34 @@
{
"2001:db8:3:fff7:fe50::":{
"sid":"2001:db8:3:fff7:fe50::",
"behavior":"uDT46",
"context":{
"vrfName":"Vrf10",
"table":10
},
"locator":"MAIN",
"allocationMode":"explicit",
"clients":[
{
"protocol":"bgp",
"instance":0
}
]
},
"2001:db8:3:fff7:fe52::":{
"sid":"2001:db8:3:fff7:fe52::",
"behavior":"uDT46",
"context":{
"vrfName":"Vrf20",
"table":20
},
"locator":"MAIN",
"allocationMode":"explicit",
"clients":[
{
"protocol":"bgp",
"instance":0
}
]
}
}

View file

@ -0,0 +1,62 @@
{
"65003:10":{
"prefix":"192.168.3.0/24",
"advertisedTo":{
"2001:db8:13::1":{
"hostname":"r1"
}
},
"pathCount":1,
"paths":[
{
"aspath":{
"string":"Local",
"segments":[
],
"length":0
},
"nhVrfName":"Vrf10",
"announceNexthopSelf":true,
"origin":"incomplete",
"metric":0,
"weight":32768,
"valid":true,
"sourced":true,
"local":true,
"bestpath":{
"overall":true,
"selectionReason":"First path received"
},
"extendedCommunity":{
"string":"RT:0:10"
},
"originatorId":"192.0.2.3",
"remoteLabel":3,
"remoteTransposedSid":"2001:db8:3:fff7:fe4b::",
"remoteSid":"2001:db8:3:fff7:fe4b::",
"remoteSidStructure":{
"locatorBlockLen": 32,
"locatorNodeLen":16,
"functionLen":32,
"argumentLen":0,
"transpositionLen":0,
"transpositionOffset":0
},
"nexthops":[
{
"ip":"0.0.0.0",
"hostname":"r3",
"afi":"ipv4",
"metric":0,
"accessible":true,
"used":true
}
],
"peer":{
"peerId":"0.0.0.0",
"routerId":"192.0.2.3"
}
}
]
}
}

View file

@ -7,6 +7,7 @@ log commands
password zebra
!
ipv6 route 2001:db8:2:2::/64 2001:db8:12::2
ipv6 route 2001:db8:3::/64 2001:db8:13::2
!
interface eth2
ip address 192.168.1.254/24
@ -18,7 +19,9 @@ exit
!
interface eth10
ipv6 address 2001:db8:12::1/64
mpls bgp forwarding
exit
interface eth20
ipv6 address 2001:db8:13::1/64
exit
!
interface lo
@ -36,6 +39,10 @@ router bgp 65001
neighbor 2001:db8:12::2 timers 3 10
neighbor 2001:db8:12::2 timers connect 1
neighbor 2001:db8:12::2 capability extended-nexthop
neighbor 2001:db8:13::3 remote-as 65003
neighbor 2001:db8:13::3 timers 3 10
neighbor 2001:db8:13::3 timers connect 1
neighbor 2001:db8:13::3 capability extended-nexthop
!
segment-routing srv6
locator MAIN
@ -43,6 +50,7 @@ router bgp 65001
!
address-family ipv4 vpn
neighbor 2001:db8:12::2 activate
neighbor 2001:db8:13::3 activate
exit-address-family
exit
!
@ -86,4 +94,4 @@ segment-routing
exit
exit
!
end
end

View file

@ -0,0 +1,80 @@
frr version 10.4-dev-my-manual-build
frr defaults traditional
hostname r2
log file zebra.log
log commands
!
password zebra
!
ipv6 route 2001:db8:1:1::/64 2001:db8:13::1
!
interface eth1
ip address 192.168.3.254/24
exit
!
interface eth2
ip address 192.168.4.254/24
exit
!
interface eth10
ipv6 address 2001:db8:13::3/64
exit
!
interface lo
ipv6 address 2001:db8:3::/128
exit
!
router bgp 65003
bgp router-id 192.0.2.3
no bgp ebgp-requires-policy
no bgp default ipv4-unicast
neighbor 2001:db8:13::1 remote-as 65001
neighbor 2001:db8:13::1 timers 3 10
neighbor 2001:db8:13::1 timers connect 1
neighbor 2001:db8:13::1 capability extended-nexthop
!
segment-routing srv6
locator MAIN
exit
!
address-family ipv4 vpn
neighbor 2001:db8:13::1 activate
exit-address-family
exit
!
router bgp 65003 vrf Vrf10
bgp router-id 192.0.2.3
!
address-family ipv4 unicast
redistribute connected
rd vpn export 65003:10
rt vpn both 0:10
export vpn
import vpn
exit-address-family
exit
!
router bgp 65003 vrf Vrf20
bgp router-id 192.0.2.3
!
address-family ipv4 unicast
redistribute connected
rd vpn export 65002:30
rt vpn both 0:20
export vpn
import vpn
exit-address-family
exit
!
segment-routing
srv6
locators
locator MAIN
prefix 2001:db8:3::/48
format usid-f3216
exit
exit
exit
exit
!
end

View file

@ -0,0 +1,12 @@
ip link add sr0 type dummy
ip link set sr0 up
sysctl -w net.vrf.strict_mode=1
ip link add Vrf10 type vrf table 10
ip link set Vrf10 up
ip link add Vrf20 type vrf table 20
ip link set Vrf20 up
ip link set eth1 master Vrf10
ip link set eth2 master Vrf20

View file

@ -43,17 +43,23 @@ def open_json_file(filename):
def build_topo(tgen):
tgen.add_router("r1")
tgen.add_router("r2")
tgen.add_router("r3")
tgen.add_router("c11")
tgen.add_router("c12")
tgen.add_router("c21")
tgen.add_router("c22")
tgen.add_router("c31")
tgen.add_router("c32")
tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "eth10", "eth10")
tgen.add_link(tgen.gears["r1"], tgen.gears["c11"], "eth2", "eth10")
tgen.add_link(tgen.gears["r1"], tgen.gears["c12"], "eth3", "eth10")
tgen.add_link(tgen.gears["r2"], tgen.gears["c21"], "eth1", "eth10")
tgen.add_link(tgen.gears["r2"], tgen.gears["c22"], "eth2", "eth10")
tgen.add_link(tgen.gears["r1"], tgen.gears["r3"], "eth20", "eth10")
tgen.add_link(tgen.gears["r3"], tgen.gears["c31"], "eth1", "eth10")
tgen.add_link(tgen.gears["r3"], tgen.gears["c32"], "eth2", "eth10")
def setup_module(mod):
@ -91,15 +97,17 @@ def check_explicit_srv6_sid_allocated(router, expected_file, exact=False):
assert result is None, "Failed"
def _check_sent_bgp_vpn_srv6_sid(router, expected_route_file):
def _check_sent_bgp_vpn_srv6_sid(router, expected_route_file, prefix):
logger.info("checking bgp vpn route with SRv6 SIDs in sending end")
output = json.loads(router.vtysh_cmd("show bgp ipv4 vpn 192.168.1.0/24 json"))
output = json.loads(router.vtysh_cmd(f"show bgp ipv4 vpn {prefix} json"))
expected = open_json_file("{}/{}".format(CWD, expected_route_file))
return topotest.json_cmp(output, expected)
def check_sent_bgp_vpn_srv6_sid(router, expected_file):
func = functools.partial(_check_sent_bgp_vpn_srv6_sid, router, expected_file)
def check_sent_bgp_vpn_srv6_sid(router, expected_file, prefix="192.168.1.0/24"):
func = functools.partial(
_check_sent_bgp_vpn_srv6_sid, router, expected_file, prefix
)
_, result = topotest.run_and_expect(func, None, count=15, wait=1)
assert result is None, "Failed"
@ -138,22 +146,28 @@ def check_rcvd_bgp_vrf_srv6_sid(router, vrf_name, expected_file):
assert result is None, "Failed"
def _check_rcvd_zebra_vrf_srv6_sid(router, vrf_name, expected_route_file):
def _check_rcvd_zebra_vrf_srv6_sid(
router, vrf_name, expected_route_file, prefix, family
):
logger.info(
"checking zebra vrf {} ipv4 route with SRv6 SIDs in receiving end".format(
vrf_name
"checking zebra vrf {} {} route with SRv6 SIDs in receiving end".format(
vrf_name, family
)
)
output = json.loads(
router.vtysh_cmd("show ip route vrf {} 192.168.1.0/24 json".format(vrf_name))
router.vtysh_cmd(
"show {} route vrf {} {} json".format(family, vrf_name, prefix)
)
)
expected = open_json_file("{}/{}".format(CWD, expected_route_file))
return topotest.json_cmp(output, expected)
def check_rcvd_zebra_vrf_srv6_sid(router, vrf_name, expected_file):
def check_rcvd_zebra_vrf_srv6_sid(
router, vrf_name, expected_file, prefix="192.168.1.0/24", family="ip"
):
func = functools.partial(
_check_rcvd_zebra_vrf_srv6_sid, router, vrf_name, expected_file
_check_rcvd_zebra_vrf_srv6_sid, router, vrf_name, expected_file, prefix, family
)
_, result = topotest.run_and_expect(func, None, count=15, wait=1)
assert result is None, "Failed"
@ -397,6 +411,112 @@ def test_explicit_srv6_sid_per_af_disabled():
)
# Configure 'sid vpn per-vrf export 4294442571'
# this value stands for FFF7FE4B
# Demonstrate that when using the index value, the allocation
# is possible on f3216 locator format
def test_explicit_srv6_sid_explicit_wide_index_1():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
router = tgen.gears["r3"]
router.vtysh_cmd(
"""
configure terminal
router bgp 65003 vrf Vrf10
sid vpn per-vrf export 4294442571
"""
)
# FOR DEVELOPER:
# If you want to stop some specific line and start interactive shell,
# please use tgen.mininet_cli() to start it.
logger.info(
"--13--Test for bgp explicit srv6 sid with wide func allocated in zebra"
)
check_explicit_srv6_sid_allocated(
router, "expected_explicit_srv6_sid_wide_allocated_1.json"
)
check_rcvd_zebra_vrf_srv6_sid(
router,
"default",
"expected_allocated_srv6_sid_seg6local_wide_1.json",
"2001:db8:3:fff7:fe4b::/128",
"ipv6",
)
check_sent_bgp_vpn_srv6_sid(
router, "expected_sent_bgp_vpn_srv6_sid_wide_1.json", "192.168.3.0/24"
)
# Configure 'sid vpn per-vrf export explicit X:X::X:X'
# using wide func specifics
# By command 'show segment-routing srv6 sid json'
def test_explicit_srv6_sid_explicit_wide():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
router = tgen.gears["r3"]
router.vtysh_cmd(
"""
configure terminal
router bgp 65003 vrf Vrf10
no sid vpn per-vrf export 4294442571
sid vpn per-vrf export explicit 2001:db8:3:fff7:fe50::
"""
)
# FOR DEVELOPER:
# If you want to stop some specific line and start interactive shell,
# please use tgen.mininet_cli() to start it.
logger.info(
"--14--Test for bgp explicit srv6 sid with wide func allocated in zebra"
)
check_explicit_srv6_sid_allocated(
router, "expected_explicit_srv6_sid_wide_allocated.json"
)
# Configure 'sid vpn per-vrf export 4294442578'
# this value stands for FFF7FE52
# Demonstrate that when using a func-bits of 32 bits, then
# By command 'show segment-routing srv6 sid json' dumps 2 SIDs
def test_explicit_srv6_sid_explicit_wide_index():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
router = tgen.gears["r3"]
router.vtysh_cmd(
"""
configure terminal
segment-routing
srv6
locators
locator MAIN
no format usid-f3216
behavior usid
prefix 2001:db8:3:2::/48 block-len 32 node-len 16 func-bits 32
end
configure terminal
router bgp 65003 vrf Vrf20
sid vpn per-vrf export 4294442578
"""
)
# FOR DEVELOPER:
# If you want to stop some specific line and start interactive shell,
# please use tgen.mininet_cli() to start it.
logger.info(
"--15--Test for bgp explicit srv6 sid with 32 bit function space allocated in zebra"
)
check_explicit_srv6_sid_allocated(
router, "expected_explicit_srv6_sid_wide_allocated_2.json"
)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View file

@ -0,0 +1,22 @@
log file zebra.log
!
hostname dst2
!
! debug zebra kernel
! debug zebra packet
! debug zebra mpls
!
interface lo
ip address 9.9.9.5/32
ipv6 address fc00:0:9::5/128
!
interface eth-rt5
ip address 10.0.11.2/24
ipv6 address 2001:db9:10::2/64
!
ip forwarding
!
ipv6 route 2001:db8:1::/64 2001:db9:10::1
!
line vty
!

View file

@ -27,9 +27,14 @@ router bgp 1
neighbor fc00:0:6::1 timers 3 10
neighbor fc00:0:6::1 timers connect 1
neighbor fc00:0:6::1 ttl-security hops 20
neighbor fc00:0:5::1 remote-as 5
neighbor fc00:0:5::1 timers 3 10
neighbor fc00:0:5::1 timers connect 1
neighbor fc00:0:5::1 ttl-security hops 20
!
address-family ipv6 vpn
neighbor fc00:0:6::1 activate
neighbor fc00:0:5::1 activate
exit-address-family
!
segment-routing srv6

View file

@ -82,5 +82,52 @@
}
]
}
],
"2001:db9:10::/64": [
{
"prefix": "2001:db9:10::/64",
"protocol": "bgp",
"vrfName": "vrf10",
"selected": true,
"destSelected": true,
"distance": 20,
"metric": 0,
"installed": true,
"table": 10,
"internalStatus": 16,
"internalFlags": 9,
"internalNextHopNum": 2,
"internalNextHopActiveNum": 2,
"nexthops": [
{
"flags": 5,
"ip": "fc00:0:5::1",
"afi": "ipv6",
"vrf": "default",
"active": true,
"recursive": true,
"labels": [3],
"weight": 1,
"seg6": {
"segs": "fc05:0:5:cece:2345::"
},
"srv6EncapBehavior": "H.Encaps"
},
{
"flags": 3,
"fib": true,
"afi": "ipv6",
"interfaceName": "eth-sw1",
"vrf": "default",
"active": true,
"labels": [3],
"weight": 1,
"seg6": {
"segs": "fc05:0:5:cece:2345::"
},
"srv6EncapBehavior": "H.Encaps"
}
]
}
]
}

View file

@ -88,5 +88,52 @@
],
"asPath": "6"
}
],
"2001:7::/64": [
{
"prefix": "2001:7::/64",
"protocol": "bgp",
"vrfName": "vrf20",
"selected": true,
"destSelected": true,
"distance": 20,
"metric": 0,
"installed": true,
"table": 20,
"internalStatus": 16,
"internalFlags": 9,
"internalNextHopNum": 2,
"internalNextHopActiveNum": 2,
"nexthops": [
{
"flags": 5,
"ip": "fc00:0:5::1",
"afi": "ipv6",
"vrf": "default",
"active": true,
"recursive": true,
"labels": [3],
"weight": 1,
"seg6": {
"segs": "fc05:0:5:1:4dfc::"
},
"srv6EncapBehavior": "H.Encaps"
},
{
"flags": 3,
"fib": true,
"afi": "ipv6",
"interfaceName": "eth-sw1",
"vrf": "default",
"active": true,
"labels": [3],
"weight": 1,
"seg6": {
"segs": "fc05:0:5:1:4dfc::"
},
"srv6EncapBehavior": "H.Encaps"
}
]
}
]
}

View file

@ -0,0 +1,67 @@
frr defaults traditional
!
bgp send-extra-data zebra
!
hostname rt5
password zebra
!
log stdout notifications
log commands
!
!debug bgp neighbor-events
!debug bgp zebra
!debug bgp vnc verbose
!debug bgp update-groups
!debug bgp updates in
!debug bgp updates out
!debug bgp updates
!debug bgp vpn label
!debug bgp vpn leak-from-vrf
!debug bgp vpn leak-to-vrf
!!debug bgp vpn rmap-event
!
router bgp 5
bgp router-id 5.5.5.5
no bgp ebgp-requires-policy
no bgp default ipv4-unicast
neighbor fc00:0:1::1 remote-as 1
neighbor fc00:0:1::1 timers 3 10
neighbor fc00:0:1::1 timers connect 1
neighbor fc00:0:1::1 ttl-security hops 20
!
address-family ipv6 vpn
neighbor fc00:0:1::1 activate
exit-address-family
!
segment-routing srv6
locator loc2
!
!
router bgp 5 vrf vrf10
bgp router-id 5.5.5.5
no bgp ebgp-requires-policy
no bgp default ipv4-unicast
!
address-family ipv6 unicast
sid vpn export explicit fc05:0:5:cece:2345::
rd vpn export 5:10
rt vpn both 99:99
import vpn
export vpn
redistribute connected
exit-address-family
!
router bgp 5 vrf vrf20
bgp router-id 5.5.5.5
no bgp ebgp-requires-policy
no bgp default ipv4-unicast
!
address-family ipv6 unicast
sid vpn export 85500
rd vpn export 5:10
rt vpn both 88:88
import vpn
export vpn
redistribute connected
exit-address-family
!

View file

@ -8,6 +8,7 @@ hostname rt5
interface lo
ip address 5.5.5.5/32
ipv6 address fc00:0:5::1/128
ipv6 address fc05:0:5::/48
!
interface eth-rt3-1
ip address 10.0.4.5/24
@ -21,12 +22,21 @@ interface eth-rt4
interface eth-rt6
ip address 10.0.8.5/24
!
interface eth-dst2 vrf vrf10
ip address 10.0.11.1/24
ip address 2001:db9:10::1/64
!
interface eth-ce7 vrf vrf20
ipv6 address 2001:7::1/64
!
segment-routing
srv6
locators
locator loc1
prefix fc00:0:5::/48
prefix fc00:0:5::/48 block-len 32 node-len 16 func-bits 16
format usid-f3216
locator loc2
prefix fc05:0:5::/48 block-len 32 node-len 16 func-bits 32
!
!
!

View file

@ -29,12 +29,12 @@ test_srv6_sid_manager.py:
10.0.2.0/24| |10.0.3.0/24 10.0.4.0/24| |10.0.5.0/24
| | | |
eth-rt2-1| |eth-rt2-2 eth-rt3-1| |eth-rt3-2
+---------+ +---------+
| | | |
| RT4 | 10.0.6.0/24 | RT5 |
| 4.4.4.4 +---------------------+ 5.5.5.5 |
| |eth-rt5 eth-rt4| |
+---------+ +---------+
+---------+ +---------+ +---------+
| | | | | |
| RT4 | 10.0.6.0/24 | RT5 |eth-dst2 | DST2 |
| 4.4.4.4 +---------------------+ 5.5.5.5 |-------------+ 9.9.9.5 |
| |eth-rt5 eth-rt4| | eth-rt5| |
+---------+ +---------+ +---------+
eth-rt6| |eth-rt6
| |
10.0.7.0/24| |10.0.8.0/24
@ -99,6 +99,8 @@ def build_topo(tgen):
tgen.add_router("ce4")
tgen.add_router("ce5")
tgen.add_router("ce6")
tgen.add_router("ce7")
tgen.add_router("dst2")
# Define connections
switch = tgen.add_switch("s1")
@ -138,12 +140,17 @@ def build_topo(tgen):
switch.add_link(tgen.gears["rt6"], nodeif="eth-dst")
switch.add_link(tgen.gears["dst"], nodeif="eth-rt6")
switch = tgen.add_switch("s10")
switch.add_link(tgen.gears["rt5"], nodeif="eth-dst2")
switch.add_link(tgen.gears["dst2"], nodeif="eth-rt5")
tgen.add_link(tgen.gears["ce1"], tgen.gears["rt1"], "eth-rt1", "eth-ce1")
tgen.add_link(tgen.gears["ce2"], tgen.gears["rt6"], "eth-rt6", "eth-ce2")
tgen.add_link(tgen.gears["ce3"], tgen.gears["rt1"], "eth-rt1", "eth-ce3")
tgen.add_link(tgen.gears["ce4"], tgen.gears["rt6"], "eth-rt6", "eth-ce4")
tgen.add_link(tgen.gears["ce5"], tgen.gears["rt1"], "eth-rt1", "eth-ce5")
tgen.add_link(tgen.gears["ce6"], tgen.gears["rt6"], "eth-rt6", "eth-ce6")
tgen.add_link(tgen.gears["ce7"], tgen.gears["rt5"], "eth-rt5", "eth-ce7")
tgen.gears["rt1"].run("ip link add vrf10 type vrf table 10")
tgen.gears["rt1"].run("ip link set vrf10 up")
@ -153,6 +160,13 @@ def build_topo(tgen):
tgen.gears["rt1"].run("ip link set eth-ce3 master vrf10")
tgen.gears["rt1"].run("ip link set eth-ce5 master vrf20")
tgen.gears["rt5"].run("ip link add vrf10 type vrf table 10")
tgen.gears["rt5"].run("ip link set vrf10 up")
tgen.gears["rt5"].run("ip link set eth-dst2 master vrf10")
tgen.gears["rt5"].run("ip link add vrf20 type vrf table 20")
tgen.gears["rt5"].run("ip link set vrf20 up")
tgen.gears["rt5"].run("ip link set eth-ce7 master vrf20")
tgen.gears["rt6"].run("ip link add vrf10 type vrf table 10")
tgen.gears["rt6"].run("ip link set vrf10 up")
tgen.gears["rt6"].run("ip link add vrf20 type vrf table 20")
@ -226,15 +240,19 @@ def setup_module(mod):
# For all registered routers, load the zebra and isis configuration files
for rname, router in tgen.routers().items():
router.load_config(TopoRouter.RD_ZEBRA,
os.path.join(CWD, '{}/zebra.conf'.format(rname)))
router.load_config(TopoRouter.RD_ISIS,
os.path.join(CWD, '{}/isisd.conf'.format(rname)))
router.load_config(TopoRouter.RD_BGP,
os.path.join(CWD, '{}/bgpd.conf'.format(rname)))
if (os.path.exists('{}/sharpd.conf'.format(rname))):
router.load_config(TopoRouter.RD_SHARP,
os.path.join(CWD, '{}/sharpd.conf'.format(rname)))
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
)
router.load_config(
TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
)
if os.path.exists("{}/sharpd.conf".format(rname)):
router.load_config(
TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
)
# Start routers
tgen.start_router()
@ -258,7 +276,9 @@ def router_compare_json_output(rname, command, reference):
expected = json.loads(open(filename).read())
# Run test function until we get an result. Wait at most 60 seconds.
test_func = functools.partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
test_func = functools.partial(
topotest.router_json_cmp, tgen.gears[rname], command, expected
)
_, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
assert diff is None, assertmsg
@ -332,9 +352,7 @@ def test_rib_ipv6():
pytest.skip(tgen.errors)
for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
router_compare_json_output(
rname, "show ipv6 route json", "show_ipv6_route.ref"
)
router_compare_json_output(rname, "show ipv6 route json", "show_ipv6_route.ref")
def test_srv6_locator():
@ -347,8 +365,10 @@ def test_srv6_locator():
for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
router_compare_json_output(
rname, "show segment-routing srv6 locator json", "show_srv6_locator_table.ref"
)
rname,
"show segment-routing srv6 locator json",
"show_srv6_locator_table.ref",
)
def test_vpn_rib():
@ -381,7 +401,9 @@ def test_ping():
# Setup encap route on rt1, decap route on rt2
# tgen.gears["rt1"].vtysh_cmd("sharp install seg6-routes fc00:0:9::1 nexthop-seg6 2001:db8:1::2 encap fc00:0:2:6:fe00:: 1")
tgen.gears["rt1"].cmd("ip -6 r a fc00:0:9::1/128 encap seg6 mode encap segs fc00:0:2:6:fe00:: via 2001:db8:1::2")
tgen.gears["rt1"].cmd(
"ip -6 r a fc00:0:9::1/128 encap seg6 mode encap segs fc00:0:2:6:fe00:: via 2001:db8:1::2"
)
# tgen.gears["rt6"].vtysh_cmd("sharp install seg6local-routes fc00:0:f00d:: nexthop-seg6local eth-dst End_DT6 254 1")
tgen.gears["rt6"].cmd("ip -6 r a fc00:0:9::1/128 via 2001:db8:10::2 vrf vrf10")
tgen.gears["dst"].cmd("ip -6 r a 2001:db8:1::1/128 via 2001:db8:10::1")

View file

@ -287,7 +287,21 @@ void zebra_srv6_locator_format_set(struct srv6_locator *locator,
/* Change format */
locator->sid_format = format;
if (format) {
if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) {
SET_FLAG(locator->flags, SRV6_LOCATOR_F3216);
UNSET_FLAG(locator->flags, SRV6_LOCATOR_F4816);
} else if (strmatch(format->name, SRV6_SID_FORMAT_USID_F4816_NAME)) {
SET_FLAG(locator->flags, SRV6_LOCATOR_F4816);
UNSET_FLAG(locator->flags, SRV6_LOCATOR_F3216);
} else {
UNSET_FLAG(locator->flags, SRV6_LOCATOR_F3216);
UNSET_FLAG(locator->flags, SRV6_LOCATOR_F4816);
}
} else {
UNSET_FLAG(locator->flags, SRV6_LOCATOR_F3216);
UNSET_FLAG(locator->flags, SRV6_LOCATOR_F4816);
}
/* Allocate the new parent block */
zebra_srv6_sid_locator_block_alloc(locator);
@ -1910,9 +1924,15 @@ static int get_srv6_sid_explicit(struct zebra_srv6_sid **sid, struct srv6_sid_ct
zebra_srv6_sid_entry_add(*sid, locator->name, sid_value, is_localonly);
if (IS_ZEBRA_DEBUG_SRV6)
zlog_debug("%s: allocated explicit SRv6 SID function %u for context %s", __func__,
(*sid)->func, srv6_sid_ctx2str(buf, sizeof(buf), ctx));
if (IS_ZEBRA_DEBUG_SRV6) {
if ((*sid)->wide_func == 0)
zlog_debug("%s: allocated explicit SRv6 SID function %u for context %s",
__func__, (*sid)->func, srv6_sid_ctx2str(buf, sizeof(buf), ctx));
else
zlog_debug("%s: allocated explicit SRv6 SID function %u (wide SID %u) for context %s",
__func__, (*sid)->func, (*sid)->wide_func,
srv6_sid_ctx2str(buf, sizeof(buf), ctx));
}
frrtrace(3, frr_zebra, get_srv6_sid_explicit, srv6_sid_ctx2str(buf, sizeof(buf), ctx),
sid_value, 2);

View file

@ -949,19 +949,6 @@ DEFPY (locator_prefix,
return CMD_WARNING_CONFIG_FAILED;
}
/*
* Currently, the SID transposition algorithm implemented in bgpd
* handles incorrectly the SRv6 locators with function length greater
* than 20 bits. To prevent issues, we currently limit the function
* length to 20 bits.
* This limit will be removed when the bgpd SID transposition is fixed.
*/
if (func_bit_len > 20) {
vty_out(vty,
"%% currently func_bit_len > 20 is not supported\n");
return CMD_WARNING_CONFIG_FAILED;
}
locator->block_bits_length = block_bit_len;
locator->node_bits_length = node_bit_len;
locator->function_bits_length = func_bit_len;