Skip to content

Commit

Permalink
bgpd: Request SRv6 SIDs to SID Manager
Browse files Browse the repository at this point in the history
Currently, the SRv6 Manager assigns a chunk from the locator to BGP,
and BGP is responsible for autonomously allocating SIDs from that
chunk.

Previous commits have extended the SRv6 SID Manager to support APIs for
allocating/releasing SRv6 SIDs to daemons upon request.

This commit modifies BGP to delegate the allocation of SIDs to the SID
Manager. Specifically, BGP uses the GET_SRV6_SID API to obtain an SID
from the SID Manager. Once received, BGP installs the SID in the RIB
and announces it to peers.

Signed-off-by: Carmine Scarpitta <[email protected]>
  • Loading branch information
cscarpitta committed Apr 3, 2024
1 parent d5441a9 commit c2e10c0
Showing 1 changed file with 149 additions and 4 deletions.
153 changes: 149 additions & 4 deletions bgpd/bgp_mplsvpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,88 @@ static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
return label;
}

/**
* Return the SRv6 SID value obtained composing the LOCATOR and FUNCTION.
*
* @param sid_value SRv6 SID value returned
* @param locator Parent locator of the SRv6 SID
* @param sid_func Function part of the SID
* @return True if success, False otherwise
*/
static bool srv6_sid_compose(struct in6_addr *sid_value,
struct srv6_locator *locator, uint32_t sid_func)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
int label = 0;
uint8_t offset = 0;
uint8_t func_len = 0, shift_len = 0;
uint32_t sid_func_max = 0;

if (!locator || !sid_value)
return false;

if (locator->function_bits_length >
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH) {
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);
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 (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);
return false;
}

/**
* Let's build the SID value.
* sid_value = LOC:FUNC::
*/

/* 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);

return true;
}

void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
afi_t afi)
{
Expand All @@ -744,6 +826,8 @@ void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
struct in6_addr *tovpn_sid;
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
bool tovpn_sid_auto = false;
struct srv6_sid_ctx ctx = {};
uint32_t sid_func;

if (debug)
zlog_debug("%s: try to allocate new SID for vrf %s: afi %s",
Expand All @@ -760,6 +844,13 @@ void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
if (!bgp_vpn || !bgp_vpn->srv6_locator)
return;

if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
if (debug)
zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf SRv6 SID",
__func__, bgp_vrf->name_pretty);
return;
}

tovpn_sid_index = bgp_vrf->vpn_policy[afi].tovpn_sid_index;
tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_SID_AUTO);
Expand All @@ -780,8 +871,29 @@ void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,

tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));

tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index,
tovpn_sid_locator, tovpn_sid);
if (!tovpn_sid_auto) {
if (!srv6_sid_compose(tovpn_sid, tovpn_sid_locator,
tovpn_sid_index)) {
zlog_err("%s: failed to compose sid for vrf %s: afi %s",
__func__, bgp_vrf->name_pretty, afi2str(afi));
return;
}
}

ctx.vrf_id = bgp_vrf->vrf_id;
ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
if (!bgp_zebra_request_srv6_sid(&ctx, tovpn_sid,
bgp_vpn->srv6_locator_name, &sid_func)) {
zlog_err("%s: failed to request sid for vrf %s: afi %s",
__func__, bgp_vrf->name_pretty, afi2str(afi));
return;
}

uint8_t func_len = bgp_vpn->srv6_locator->function_bits_length;
uint8_t shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH - func_len;

tovpn_sid_transpose_label = sid_func << shift_len;

if (tovpn_sid_transpose_label == 0) {
if (debug)
Expand All @@ -802,6 +914,8 @@ void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
bgp_vrf->vpn_policy[afi].tovpn_sid_locator = tovpn_sid_locator;
bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label =
tovpn_sid_transpose_label;

sid_register(bgp_vpn, tovpn_sid, bgp_vpn->srv6_locator_name);
}

void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
Expand All @@ -811,6 +925,8 @@ void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
struct in6_addr *tovpn_sid;
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
bool tovpn_sid_auto = false;
struct srv6_sid_ctx ctx = {};
uint32_t sid_func;

if (debug)
zlog_debug("%s: try to allocate new SID for vrf %s", __func__,
Expand All @@ -827,6 +943,13 @@ void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
if (!bgp_vpn || !bgp_vpn->srv6_locator)
return;

if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
if (debug)
zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf SRv6 SID",
__func__, bgp_vrf->name_pretty);
return;
}

tovpn_sid_index = bgp_vrf->tovpn_sid_index;
tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_TOVPN_SID_AUTO);

Expand All @@ -846,8 +969,28 @@ void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)

tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));

tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index,
tovpn_sid_locator, tovpn_sid);
if (!tovpn_sid_auto) {
if (!srv6_sid_compose(tovpn_sid, bgp_vpn->srv6_locator,
bgp_vrf->tovpn_sid_index)) {
zlog_err("%s: failed to compose new sid for vrf %s",
__func__, bgp_vrf->name_pretty);
return;
}
}

ctx.vrf_id = bgp_vrf->vrf_id;
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
if (!bgp_zebra_request_srv6_sid(&ctx, tovpn_sid,
bgp_vpn->srv6_locator_name, &sid_func)) {
zlog_err("%s: failed to request new sid for vrf %s", __func__,
bgp_vrf->name_pretty);
return;
}

uint8_t func_len = bgp_vpn->srv6_locator->function_bits_length;
uint8_t shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH - func_len;

tovpn_sid_transpose_label = sid_func << shift_len;

if (tovpn_sid_transpose_label == 0) {
if (debug)
Expand All @@ -865,6 +1008,8 @@ void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
bgp_vrf->tovpn_sid = tovpn_sid;
bgp_vrf->tovpn_sid_locator = tovpn_sid_locator;
bgp_vrf->tovpn_sid_transpose_label = tovpn_sid_transpose_label;

sid_register(bgp_vpn, tovpn_sid, bgp_vpn->srv6_locator_name);
}

void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
Expand Down

0 comments on commit c2e10c0

Please sign in to comment.