Merge pull request #15676 from cscarpitta/bgp-srv6-sid-manager

bgpd: Extend BGP to communicate with the SRv6 SID Manager to allocate/release SRv6 SIDs
This commit is contained in:
Russ White 2024-09-05 11:40:48 -04:00 committed by GitHub
commit 5d9ddcce7c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 596 additions and 176 deletions

View File

@ -474,6 +474,7 @@ void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
struct srv6_sid_ctx ctx = {};
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug)
@ -492,6 +493,11 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
XFREE(MTYPE_BGP_SRV6_SID,
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent);
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = NULL;
ctx.vrf_id = bgp->vrf_id;
ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
bgp_zebra_release_srv6_sid(&ctx);
}
/*
@ -501,6 +507,7 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
struct srv6_sid_ctx ctx = {};
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug)
@ -519,6 +526,10 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp)
NULL);
XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent);
bgp->tovpn_zebra_vrf_sid_last_sent = NULL;
ctx.vrf_id = bgp->vrf_id;
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
bgp_zebra_release_srv6_sid(&ctx);
}
/*
@ -595,8 +606,8 @@ int vpn_leak_label_callback(
return 0;
}
static void sid_register(struct bgp *bgp, const struct in6_addr *sid,
const char *locator_name)
void sid_register(struct bgp *bgp, const struct in6_addr *sid,
const char *locator_name)
{
struct bgp_srv6_function *func;
func = XCALLOC(MTYPE_BGP_SRV6_FUNCTION,
@ -635,108 +646,97 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
return false;
}
/*
* This function generates a new SID based on bgp->srv6_locator_chunks and
* index. The locator and generated SID are stored in arguments sid_locator
* and sid, respectively.
/**
* Return the SRv6 SID value obtained by composing the LOCATOR and FUNCTION.
*
* if index != 0: try to allocate as index-mode
* else: try to allocate as auto-mode
* @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 uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
struct srv6_locator_chunk *sid_locator_chunk,
struct in6_addr *sid)
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);
struct listnode *node;
struct srv6_locator_chunk *chunk;
bool alloced = false;
int label = 0;
uint8_t offset = 0;
uint8_t func_len = 0, shift_len = 0;
uint32_t index_max = 0;
uint32_t sid_func_max = 0;
if (!bgp || !sid_locator_chunk || !sid)
if (!locator || !sid_value)
return false;
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
if (chunk->function_bits_length >
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH) {
if (debug)
zlog_debug(
"%s: invalid SRv6 Locator chunk (%pFX): Function Length must be less or equal to %d",
__func__, &chunk->prefix,
BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH);
continue;
}
index_max = (1 << chunk->function_bits_length) - 1;
if (index > index_max) {
if (debug)
zlog_debug(
"%s: skipped SRv6 Locator chunk (%pFX): Function Length is too short to support specified index (%u)",
__func__, &chunk->prefix, index);
continue;
}
*sid = chunk->prefix.prefix;
*sid_locator_chunk = *chunk;
offset = chunk->block_bits_length + chunk->node_bits_length;
func_len = chunk->function_bits_length;
shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH - func_len;
if (index != 0) {
label = index << 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__, &chunk->prefix,
label);
continue;
}
transpose_sid(sid, label, offset, func_len);
if (sid_exist(bgp, sid))
continue;
alloced = true;
break;
}
for (uint32_t i = 1; i < index_max; i++) {
label = i << 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__, &chunk->prefix,
label);
continue;
}
transpose_sid(sid, label, offset, func_len);
if (sid_exist(bgp, sid))
continue;
alloced = true;
break;
}
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;
}
if (!alloced)
return 0;
/* Max value that can be encoded in the Function part of the SID */
sid_func_max = (1 << locator->function_bits_length) - 1;
sid_register(bgp, sid, bgp->srv6_locator_name);
return label;
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)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
struct srv6_locator_chunk *tovpn_sid_locator;
struct in6_addr *tovpn_sid;
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
struct in6_addr tovpn_sid = {};
uint32_t tovpn_sid_index = 0;
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",
@ -748,11 +748,18 @@ void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
/*
* skip when bgp vpn instance ins't allocated
* or srv6 locator chunk isn't allocated
* or srv6 locator isn't allocated
*/
if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks)
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);
@ -768,40 +775,34 @@ void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
return;
}
tovpn_sid_locator = srv6_locator_chunk_alloc();
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_transpose_label == 0) {
if (debug)
zlog_debug(
"%s: not allocated new sid for vrf %s: afi %s",
__func__, bgp_vrf->name_pretty, afi2str(afi));
srv6_locator_chunk_free(&tovpn_sid_locator);
XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
return;
if (!tovpn_sid_auto) {
if (!srv6_sid_compose(&tovpn_sid, bgp_vpn->srv6_locator,
tovpn_sid_index)) {
zlog_err("%s: failed to compose sid for vrf %s: afi %s",
__func__, bgp_vrf->name_pretty, afi2str(afi));
return;
}
}
if (debug)
zlog_debug("%s: new sid %pI6 allocated for vrf %s: afi %s",
__func__, tovpn_sid, bgp_vrf->name_pretty,
afi2str(afi));
bgp_vrf->vpn_policy[afi].tovpn_sid = tovpn_sid;
bgp_vrf->vpn_policy[afi].tovpn_sid_locator = tovpn_sid_locator;
bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label =
tovpn_sid_transpose_label;
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;
}
}
void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
struct srv6_locator_chunk *tovpn_sid_locator;
struct in6_addr *tovpn_sid;
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
struct in6_addr tovpn_sid = {};
uint32_t tovpn_sid_index = 0;
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__,
@ -813,11 +814,18 @@ void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
/*
* skip when bgp vpn instance ins't allocated
* or srv6 locator chunk isn't allocated
* or srv6 locator isn't allocated
*/
if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks)
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);
@ -832,28 +840,23 @@ void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
return;
}
tovpn_sid_locator = srv6_locator_chunk_alloc();
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_transpose_label == 0) {
if (debug)
zlog_debug("%s: not allocated new sid for vrf %s",
__func__, bgp_vrf->name_pretty);
srv6_locator_chunk_free(&tovpn_sid_locator);
XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
return;
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;
}
}
if (debug)
zlog_debug("%s: new sid %pI6 allocated for vrf %s", __func__,
tovpn_sid, bgp_vrf->name_pretty);
bgp_vrf->tovpn_sid = tovpn_sid;
bgp_vrf->tovpn_sid_locator = tovpn_sid_locator;
bgp_vrf->tovpn_sid_transpose_label = tovpn_sid_transpose_label;
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;
}
}
void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
@ -876,6 +879,7 @@ void delete_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
uint32_t tovpn_sid_index = 0;
bool tovpn_sid_auto = false;
struct srv6_sid_ctx ctx = {};
if (debug)
zlog_debug("%s: try to remove SID for vrf %s: afi %s", __func__,
@ -889,9 +893,22 @@ void delete_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
if (tovpn_sid_index != 0 || tovpn_sid_auto)
return;
srv6_locator_chunk_free(&bgp_vrf->vpn_policy[afi].tovpn_sid_locator);
if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
if (debug)
zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf label",
__func__, bgp_vrf->name_pretty);
return;
}
srv6_locator_free(bgp_vrf->vpn_policy[afi].tovpn_sid_locator);
bgp_vrf->vpn_policy[afi].tovpn_sid_locator = NULL;
if (bgp_vrf->vpn_policy[afi].tovpn_sid) {
ctx.vrf_id = bgp_vrf->vrf_id;
ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
bgp_zebra_release_srv6_sid(&ctx);
sid_unregister(bgp_vpn, bgp_vrf->vpn_policy[afi].tovpn_sid);
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->vpn_policy[afi].tovpn_sid);
}
@ -903,6 +920,7 @@ void delete_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
uint32_t tovpn_sid_index = 0;
bool tovpn_sid_auto = false;
struct srv6_sid_ctx ctx = {};
if (debug)
zlog_debug("%s: try to remove SID for vrf %s", __func__,
@ -916,9 +934,21 @@ void delete_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
if (tovpn_sid_index != 0 || tovpn_sid_auto)
return;
srv6_locator_chunk_free(&bgp_vrf->tovpn_sid_locator);
if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
if (debug)
zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf label",
__func__, bgp_vrf->name_pretty);
return;
}
srv6_locator_free(bgp_vrf->tovpn_sid_locator);
bgp_vrf->tovpn_sid_locator = NULL;
if (bgp_vrf->tovpn_sid) {
ctx.vrf_id = bgp_vrf->vrf_id;
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
bgp_zebra_release_srv6_sid(&ctx);
sid_unregister(bgp_vpn, bgp_vrf->tovpn_sid);
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
}
@ -1763,8 +1793,9 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
/* Set SID for SRv6 VPN */
if (from_bgp->vpn_policy[afi].tovpn_sid_locator) {
struct srv6_locator_chunk *locator =
struct srv6_locator *locator =
from_bgp->vpn_policy[afi].tovpn_sid_locator;
encode_label(
from_bgp->vpn_policy[afi].tovpn_sid_transpose_label,
&label);
@ -1805,8 +1836,8 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
.tovpn_sid_locator->prefix.prefix,
sizeof(struct in6_addr));
} else if (from_bgp->tovpn_sid_locator) {
struct srv6_locator_chunk *locator =
from_bgp->tovpn_sid_locator;
struct srv6_locator *locator = from_bgp->tovpn_sid_locator;
encode_label(from_bgp->tovpn_sid_transpose_label, &label);
static_attr.srv6_l3vpn =
XCALLOC(MTYPE_BGP_SRV6_L3VPN,

View File

@ -419,6 +419,8 @@ struct bgp_mplsvpn_nh_label_bind_cache *bgp_mplsvpn_nh_label_bind_find(
struct bgp_mplsvpn_nh_label_bind_cache_head *tree, struct prefix *p,
mpls_label_t orig_label);
void bgp_mplsvpn_nexthop_init(void);
extern void sid_register(struct bgp *bgp, const struct in6_addr *sid,
const char *locator_name);
extern void sid_unregister(struct bgp *bgp, const struct in6_addr *sid);
#endif /* _QUAGGA_BGP_MPLSVPN_H */

View File

@ -302,18 +302,11 @@ static const char *get_afi_safi_json_str(afi_t afi, safi_t safi)
/* unset srv6 locator */
static int bgp_srv6_locator_unset(struct bgp *bgp)
{
int ret;
struct listnode *node, *nnode;
struct srv6_locator_chunk *chunk;
struct bgp_srv6_function *func;
struct bgp *bgp_vrf;
/* release chunk notification via ZAPI */
ret = bgp_zebra_srv6_manager_release_locator_chunk(
bgp->srv6_locator_name);
if (ret < 0)
return -1;
/* refresh chunks */
for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk)) {
listnode_delete(bgp->srv6_locator_chunks, chunk);
@ -352,20 +345,28 @@ static int bgp_srv6_locator_unset(struct bgp *bgp)
continue;
/* refresh vpnv4 tovpn_sid_locator */
srv6_locator_chunk_free(
&bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator);
srv6_locator_free(bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator);
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator = NULL;
/* refresh vpnv6 tovpn_sid_locator */
srv6_locator_chunk_free(
&bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator);
srv6_locator_free(
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator);
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator = NULL;
/* refresh per-vrf tovpn_sid_locator */
srv6_locator_chunk_free(&bgp_vrf->tovpn_sid_locator);
srv6_locator_free(bgp_vrf->tovpn_sid_locator);
bgp_vrf->tovpn_sid_locator = NULL;
}
/* clear locator name */
memset(bgp->srv6_locator_name, 0, sizeof(bgp->srv6_locator_name));
/* clear SRv6 locator */
if (bgp->srv6_locator) {
srv6_locator_free(bgp->srv6_locator);
bgp->srv6_locator = NULL;
}
return 0;
}
@ -10878,7 +10879,7 @@ DEFPY (bgp_srv6_locator,
snprintf(bgp->srv6_locator_name,
sizeof(bgp->srv6_locator_name), "%s", name);
ret = bgp_zebra_srv6_manager_get_locator_chunk(name);
ret = bgp_zebra_srv6_manager_get_locator(name);
if (ret < 0)
return CMD_WARNING_CONFIG_FAILED;
@ -10929,6 +10930,17 @@ DEFPY (show_bgp_srv6,
return CMD_SUCCESS;
vty_out(vty, "locator_name: %s\n", bgp->srv6_locator_name);
if (bgp->srv6_locator) {
vty_out(vty, " prefix: %pFX\n", &bgp->srv6_locator->prefix);
vty_out(vty, " block-length: %d\n",
bgp->srv6_locator->block_bits_length);
vty_out(vty, " node-length: %d\n",
bgp->srv6_locator->node_bits_length);
vty_out(vty, " func-length: %d\n",
bgp->srv6_locator->function_bits_length);
vty_out(vty, " arg-length: %d\n",
bgp->srv6_locator->argument_bits_length);
}
vty_out(vty, "locator_chunks:\n");
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
vty_out(vty, "- %pFX\n", &chunk->prefix);

View File

@ -3379,11 +3379,278 @@ static int bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS)
return 0;
}
/**
* Internal function to process an SRv6 locator
*
* @param locator The locator to be processed
*/
static int bgp_zebra_process_srv6_locator_internal(struct srv6_locator *locator)
{
struct bgp *bgp = bgp_get_default();
if (!bgp || !bgp->srv6_enabled || !locator)
return -1;
/*
* Check if the main BGP instance is configured to use the received
* locator
*/
if (strcmp(bgp->srv6_locator_name, locator->name) != 0) {
zlog_err("%s: SRv6 Locator name unmatch %s:%s", __func__,
bgp->srv6_locator_name, locator->name);
return 0;
}
zlog_info("%s: Received SRv6 locator %s %pFX, loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u",
__func__, locator->name, &locator->prefix,
locator->block_bits_length, locator->node_bits_length,
locator->function_bits_length, locator->argument_bits_length);
/* Store the locator in the main BGP instance */
bgp->srv6_locator = srv6_locator_alloc(locator->name);
srv6_locator_copy(bgp->srv6_locator, locator);
/*
* Process VPN-to-VRF and VRF-to-VPN leaks to advertise new locator
* and SIDs.
*/
vpn_leak_postchange_all();
return 0;
}
static int bgp_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS)
{
struct bgp *bgp = bgp_get_default();
struct srv6_locator *locator;
struct srv6_sid_ctx ctx;
struct in6_addr sid_addr;
enum zapi_srv6_sid_notify note;
struct bgp *bgp_vrf;
struct vrf *vrf;
struct listnode *node, *nnode;
char buf[256];
struct in6_addr *tovpn_sid;
struct prefix_ipv6 tmp_prefix;
uint32_t sid_func;
bool found = false;
if (!bgp || !bgp->srv6_enabled)
return -1;
if (!bgp->srv6_locator) {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: ignoring SRv6 SID notify: locator not set",
__func__);
return -1;
}
/* Decode the received notification message */
if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr,
&sid_func, NULL, &note, NULL)) {
zlog_err("%s : error in msg decode", __func__);
return -1;
}
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: received SRv6 SID notify: ctx %s sid_value %pI6 %s",
__func__, srv6_sid_ctx2str(buf, sizeof(buf), &ctx),
&sid_addr, zapi_srv6_sid_notify2str(note));
/* Get the BGP instance for which the SID has been requested, if any */
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp_vrf)) {
vrf = vrf_lookup_by_id(bgp_vrf->vrf_id);
if (!vrf)
continue;
if (vrf->vrf_id == ctx.vrf_id) {
found = true;
break;
}
}
if (!found) {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: ignoring SRv6 SID notify: No VRF suitable for received SID ctx %s sid_value %pI6",
__func__,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx),
&sid_addr);
return -1;
}
/* Handle notification */
switch (note) {
case ZAPI_SRV6_SID_ALLOCATED:
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("SRv6 SID %pI6 %s : ALLOCATED", &sid_addr,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
/* Verify that the received SID belongs to the configured locator */
tmp_prefix.family = AF_INET6;
tmp_prefix.prefixlen = IPV6_MAX_BITLEN;
tmp_prefix.prefix = sid_addr;
if (!prefix_match((struct prefix *)&bgp->srv6_locator->prefix,
(struct prefix *)&tmp_prefix))
return -1;
/* Get label */
uint8_t func_len = bgp->srv6_locator->function_bits_length;
uint8_t shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH -
func_len;
int label = sid_func << shift_len;
/* Un-export VPN to VRF routes */
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp,
bgp_vrf);
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP6, bgp,
bgp_vrf);
locator = srv6_locator_alloc(bgp->srv6_locator_name);
srv6_locator_copy(locator, bgp->srv6_locator);
/* Store SID, locator, and label */
tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
*tovpn_sid = sid_addr;
if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT6) {
XFREE(MTYPE_BGP_SRV6_SID,
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
srv6_locator_free(
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator);
sid_unregister(bgp,
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid = tovpn_sid;
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator = locator;
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_transpose_label =
label;
} else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT4) {
XFREE(MTYPE_BGP_SRV6_SID,
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
srv6_locator_free(
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator);
sid_unregister(bgp,
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid = tovpn_sid;
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator = locator;
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_transpose_label =
label;
} else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT46) {
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
srv6_locator_free(bgp_vrf->tovpn_sid_locator);
sid_unregister(bgp, bgp_vrf->tovpn_sid);
bgp_vrf->tovpn_sid = tovpn_sid;
bgp_vrf->tovpn_sid_locator = locator;
bgp_vrf->tovpn_sid_transpose_label = label;
} else {
srv6_locator_free(locator);
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Unsupported behavior. Not assigned SRv6 SID: %s %pI6",
srv6_sid_ctx2str(buf, sizeof(buf),
&ctx),
&sid_addr);
return -1;
}
/* Register the new SID */
sid_register(bgp, tovpn_sid, bgp->srv6_locator_name);
/* Export VPN to VRF routes */
vpn_leak_postchange_all();
break;
case ZAPI_SRV6_SID_RELEASED:
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("SRv6 SID %pI6 %s: RELEASED", &sid_addr,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
/* Un-export VPN to VRF routes */
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp,
bgp_vrf);
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP6, bgp,
bgp_vrf);
/* Remove SID, locator, and label */
if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT6) {
XFREE(MTYPE_BGP_SRV6_SID,
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
if (bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator) {
srv6_locator_free(bgp->vpn_policy[AFI_IP6]
.tovpn_sid_locator);
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator =
NULL;
}
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_transpose_label =
0;
/* Unregister the SID */
sid_unregister(bgp,
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
} else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT4) {
XFREE(MTYPE_BGP_SRV6_SID,
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
if (bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator) {
srv6_locator_free(bgp->vpn_policy[AFI_IP]
.tovpn_sid_locator);
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator =
NULL;
}
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_transpose_label =
0;
/* Unregister the SID */
sid_unregister(bgp,
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
} else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT46) {
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
if (bgp_vrf->tovpn_sid_locator) {
srv6_locator_free(bgp_vrf->tovpn_sid_locator);
bgp_vrf->tovpn_sid_locator = NULL;
}
bgp_vrf->tovpn_sid_transpose_label = 0;
/* Unregister the SID */
sid_unregister(bgp, bgp_vrf->tovpn_sid);
} else {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Unsupported behavior. Not assigned SRv6 SID: %s %pI6",
srv6_sid_ctx2str(buf, sizeof(buf),
&ctx),
&sid_addr);
return -1;
}
/* Export VPN to VRF routes*/
vpn_leak_postchange_all();
break;
case ZAPI_SRV6_SID_FAIL_ALLOC:
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("SRv6 SID %pI6 %s: Failed to allocate",
&sid_addr,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
/* Error will be logged by zebra module */
break;
case ZAPI_SRV6_SID_FAIL_RELEASE:
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: SRv6 SID %pI6 %s failure to release",
__func__, &sid_addr,
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
/* Error will be logged by zebra module */
break;
}
return 0;
}
static int bgp_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)
{
struct srv6_locator loc = {};
struct bgp *bgp = bgp_get_default();
const char *loc_name = bgp->srv6_locator_name;
if (!bgp || !bgp->srv6_enabled)
return 0;
@ -3391,10 +3658,7 @@ static int bgp_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
return -1;
if (bgp_zebra_srv6_manager_get_locator_chunk(loc_name) < 0)
return -1;
return 0;
return bgp_zebra_process_srv6_locator_internal(&loc);
}
static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
@ -3402,7 +3666,8 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
struct srv6_locator loc = {};
struct bgp *bgp = bgp_get_default();
struct listnode *node, *nnode;
struct srv6_locator_chunk *chunk, *tovpn_sid_locator;
struct srv6_locator_chunk *chunk;
struct srv6_locator *tovpn_sid_locator;
struct bgp_srv6_function *func;
struct bgp *bgp_vrf;
struct in6_addr *tovpn_sid;
@ -3414,6 +3679,12 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
return -1;
// clear SRv6 locator
if (bgp->srv6_locator) {
srv6_locator_free(bgp->srv6_locator);
bgp->srv6_locator = NULL;
}
// refresh chunks
for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk))
if (prefix_match((struct prefix *)&loc.prefix,
@ -3490,10 +3761,12 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix,
(struct prefix *)&tmp_prefi))
srv6_locator_chunk_free(
&bgp_vrf->vpn_policy[AFI_IP]
.tovpn_sid_locator);
(struct prefix *)&tmp_prefi)) {
srv6_locator_free(bgp_vrf->vpn_policy[AFI_IP]
.tovpn_sid_locator);
bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator =
NULL;
}
}
/* refresh vpnv6 tovpn_sid_locator */
@ -3504,10 +3777,12 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix,
(struct prefix *)&tmp_prefi))
srv6_locator_chunk_free(
&bgp_vrf->vpn_policy[AFI_IP6]
.tovpn_sid_locator);
(struct prefix *)&tmp_prefi)) {
srv6_locator_free(bgp_vrf->vpn_policy[AFI_IP6]
.tovpn_sid_locator);
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator =
NULL;
}
}
/* refresh per-vrf tovpn_sid_locator */
@ -3517,9 +3792,10 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix,
(struct prefix *)&tmp_prefi))
srv6_locator_chunk_free(
&bgp_vrf->tovpn_sid_locator);
(struct prefix *)&tmp_prefi)) {
srv6_locator_free(bgp_vrf->tovpn_sid_locator);
bgp_vrf->tovpn_sid_locator = NULL;
}
}
}
@ -3556,6 +3832,7 @@ static zclient_handler *const bgp_handlers[] = {
[ZEBRA_SRV6_LOCATOR_DELETE] = bgp_zebra_process_srv6_locator_delete,
[ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] =
bgp_zebra_process_srv6_locator_chunk,
[ZEBRA_SRV6_SID_NOTIFY] = bgp_zebra_srv6_sid_notify,
};
static int bgp_if_new_hook(struct interface *ifp)
@ -4093,6 +4370,89 @@ int bgp_zebra_srv6_manager_release_locator_chunk(const char *name)
return srv6_manager_release_locator_chunk(zclient, name);
}
/**
* Ask the SRv6 Manager (zebra) about a specific locator
*
* @param name Locator name
* @return 0 on success, -1 otherwise
*/
int bgp_zebra_srv6_manager_get_locator(const char *name)
{
if (!name)
return -1;
/*
* Send the Get Locator request to the SRv6 Manager and return the
* result
*/
return srv6_manager_get_locator(zclient, name);
}
/**
* Ask the SRv6 Manager (zebra) to allocate a SID.
*
* Optionally, it is possible to provide an IPv6 address (sid_value parameter).
*
* When sid_value is provided, the SRv6 Manager allocates the requested SID
* address, if the request can be satisfied (explicit allocation).
*
* When sid_value is not provided, the SRv6 Manager allocates any available SID
* from the provided locator (dynamic allocation).
*
* @param ctx Context to be associated with the request SID
* @param sid_value IPv6 address to be associated with the requested SID (optional)
* @param locator_name Name of the locator from which the SID must be allocated
* @param sid_func SID Function allocated by the SRv6 Manager.
*/
bool bgp_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx,
struct in6_addr *sid_value,
const char *locator_name, uint32_t *sid_func)
{
int ret;
if (!ctx || !locator_name)
return false;
/*
* Send the Get SRv6 SID request to the SRv6 Manager and check the
* result
*/
ret = srv6_manager_get_sid(zclient, ctx, sid_value, locator_name,
sid_func);
if (ret < 0) {
zlog_warn("%s: error getting SRv6 SID!", __func__);
return false;
}
return true;
}
/**
* Ask the SRv6 Manager (zebra) to release a previously allocated SID.
*
* This function is used to tell the SRv6 Manager that BGP no longer intends
* to use the SID.
*
* @param ctx Context to be associated with the SID to be released
*/
void bgp_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx)
{
int ret;
if (!ctx)
return;
/*
* Send the Release SRv6 SID request to the SRv6 Manager and check the
* result
*/
ret = srv6_manager_release_sid(zclient, ctx);
if (ret < 0) {
zlog_warn("%s: error releasing SRv6 SID!", __func__);
return;
}
}
void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label,
ifindex_t ifindex, vrf_id_t vrf_id,
enum lsp_types_t ltype, struct prefix *p,

View File

@ -117,6 +117,13 @@ extern int bgp_zebra_update(struct bgp *bgp, afi_t afi, safi_t safi,
extern int bgp_zebra_stale_timer_update(struct bgp *bgp);
extern int bgp_zebra_srv6_manager_get_locator_chunk(const char *name);
extern int bgp_zebra_srv6_manager_release_locator_chunk(const char *name);
extern int bgp_zebra_srv6_manager_get_locator(const char *name);
extern bool bgp_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx,
struct in6_addr *sid_value,
const char *locator_name,
uint32_t *sid_func);
extern void bgp_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx);
extern void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label,
ifindex_t index, vrf_id_t vrfid,
enum lsp_types_t ltype,

View File

@ -1497,9 +1497,11 @@ static void bgp_srv6_init(struct bgp *bgp)
static void bgp_srv6_cleanup(struct bgp *bgp)
{
for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
if (bgp->vpn_policy[afi].tovpn_sid_locator != NULL)
srv6_locator_chunk_free(
&bgp->vpn_policy[afi].tovpn_sid_locator);
if (bgp->vpn_policy[afi].tovpn_sid_locator != NULL) {
srv6_locator_free(
bgp->vpn_policy[afi].tovpn_sid_locator);
bgp->vpn_policy[afi].tovpn_sid_locator = NULL;
}
if (bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent != NULL)
XFREE(MTYPE_BGP_SRV6_SID,
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent);
@ -1510,8 +1512,10 @@ static void bgp_srv6_cleanup(struct bgp *bgp)
}
}
if (bgp->tovpn_sid_locator != NULL)
srv6_locator_chunk_free(&bgp->tovpn_sid_locator);
if (bgp->tovpn_sid_locator != NULL) {
srv6_locator_free(bgp->tovpn_sid_locator);
bgp->tovpn_sid_locator = NULL;
}
if (bgp->tovpn_zebra_vrf_sid_last_sent != NULL)
XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent);
if (bgp->tovpn_sid != NULL) {
@ -1523,6 +1527,9 @@ static void bgp_srv6_cleanup(struct bgp *bgp)
list_delete(&bgp->srv6_locator_chunks);
if (bgp->srv6_functions)
list_delete(&bgp->srv6_functions);
srv6_locator_free(bgp->srv6_locator);
bgp->srv6_locator = NULL;
}
/* Allocate new peer object, implicitely locked. */

View File

@ -270,7 +270,7 @@ struct vpn_policy {
*/
uint32_t tovpn_sid_index; /* unset => set to 0 */
struct in6_addr *tovpn_sid;
struct srv6_locator_chunk *tovpn_sid_locator;
struct srv6_locator *tovpn_sid_locator;
uint32_t tovpn_sid_transpose_label;
struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
};
@ -836,11 +836,12 @@ struct bgp {
/* BGP VPN SRv6 backend */
bool srv6_enabled;
char srv6_locator_name[SRV6_LOCNAME_SIZE];
struct srv6_locator *srv6_locator;
struct list *srv6_locator_chunks;
struct list *srv6_functions;
uint32_t tovpn_sid_index; /* unset => set to 0 */
struct in6_addr *tovpn_sid;
struct srv6_locator_chunk *tovpn_sid_locator;
struct srv6_locator *tovpn_sid_locator;
uint32_t tovpn_sid_transpose_label;
struct in6_addr *tovpn_zebra_vrf_sid_last_sent;