Skip to content

Commit

Permalink
bgpd: add support for per-VRF SRv6 SID
Browse files Browse the repository at this point in the history
In the current implementation of bgpd, SRv6 SIDs can be configured only
under the address-family. This enables bgpd to leak IPv6 routes using
an SRv6 End.DT6 behavior and IPv4 routes using an SRv6 End.DT4
behavior. It is not possible to leak both IPv6 and IPv4 routes using a
single SRv6 SID.

This commit adds a new CLI command
"sid vpn per-vrf export <sid_idx|auto>" that enables bgpd to leak both
IPv6 and IPv4 routes using a single SRv6 SID (End.DT46 behavior).

Signed-off-by: Carmine Scarpitta <carmine.scarpitta@uniroma2.it>
  • Loading branch information
cscarpitta committed Oct 18, 2022
1 parent 696f437 commit 527588a
Show file tree
Hide file tree
Showing 5 changed files with 356 additions and 10 deletions.
211 changes: 208 additions & 3 deletions bgpd/bgp_mplsvpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi)
* leaked to VPN. Zebra should install this srv6-function in the kernel with
* an action of "End.DT4/6's IP FIB to route the PDU."
*/
void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
void vpn_leak_zebra_vrf_sid_update_per_af(struct bgp *bgp, afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
enum seg6local_action_t act;
Expand Down Expand Up @@ -406,11 +406,78 @@ void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls;
}

/*
* This function informs zebra of the srv6-function this vrf sets on routes
* leaked to VPN. Zebra should install this srv6-function in the kernel with
* an action of "End.DT46's IP FIB to route the PDU."
*/
void vpn_leak_zebra_vrf_sid_update_per_vrf(struct bgp *bgp)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
enum seg6local_action_t act;
struct seg6local_context ctx = {};
struct in6_addr *tovpn_sid = NULL;
struct in6_addr *tovpn_sid_ls = NULL;
struct vrf *vrf;

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

tovpn_sid = bgp->tovpn_sid;
if (!tovpn_sid) {
if (debug)
zlog_debug("%s: vrf %s: sid not set", __func__,
bgp->name_pretty);
return;
}

if (debug)
zlog_debug("%s: vrf %s: setting sid %pI6 for vrf id %d",
__func__, bgp->name_pretty, tovpn_sid, bgp->vrf_id);

vrf = vrf_lookup_by_id(bgp->vrf_id);
if (!vrf)
return;

ctx.table = vrf->data.l.table_id;
act = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
zclient_send_localsid(zclient, tovpn_sid, bgp->vrf_id, act, &ctx);

tovpn_sid_ls = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
*tovpn_sid_ls = *tovpn_sid;
bgp->tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls;
}

/*
* This function informs zebra of the srv6-function this vrf sets on routes
* leaked to VPN. Zebra should install this srv6-function in the kernel with
* an action of "End.DT4/6/46's IP FIB to route the PDU."
*/
void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);

if (bgp->vpn_policy[afi].tovpn_sid)
return vpn_leak_zebra_vrf_sid_update_per_af(bgp, afi);

if (bgp->tovpn_sid)
return vpn_leak_zebra_vrf_sid_update_per_vrf(bgp);

if (debug)
zlog_debug("%s: vrf %s: afi %s: sid not set", __func__,
bgp->name_pretty, afi2str(afi));
}

/*
* If zebra tells us vrf has become unconfigured, tell zebra not to
* use this srv6-function to forward to the vrf anymore
*/
void vpn_leak_zebra_vrf_sid_withdraw(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);

Expand All @@ -432,6 +499,45 @@ void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi)
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent);
}

/*
* If zebra tells us vrf has become unconfigured, tell zebra not to
* use this srv6-function to forward to the vrf anymore
*/
void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);

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

if (debug)
zlog_debug("%s: deleting sid for vrf %s (id=%d)", __func__,
bgp->name_pretty, bgp->vrf_id);

zclient_send_localsid(zclient, bgp->tovpn_zebra_vrf_sid_last_sent,
bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC,
NULL);
XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent);
}

/*
* If zebra tells us vrf has become unconfigured, tell zebra not to
* use this srv6-function to forward to the vrf anymore
*/
void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi)
{
if (bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent)
vpn_leak_zebra_vrf_sid_withdraw_per_af(bgp, afi);

if (bgp->tovpn_zebra_vrf_sid_last_sent)
vpn_leak_zebra_vrf_sid_withdraw_per_vrf(bgp);
}

int vpn_leak_label_callback(
mpls_label_t label,
void *labelid,
Expand Down Expand Up @@ -610,7 +716,8 @@ static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
return label;
}

void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
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);
char buf[256];
Expand Down Expand Up @@ -678,6 +785,81 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
tovpn_sid_transpose_label;
}

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;
bool tovpn_sid_auto = false;

if (debug)
zlog_debug("%s: try to allocate new SID for vrf %s", __func__,
bgp_vrf->name_pretty);

/* skip when tovpn sid is already allocated on vrf instance */
if (bgp_vrf->tovpn_sid)
return;

/*
* skip when bgp vpn instance ins't allocated
* or srv6 locator chunk isn't allocated
*/
if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks)
return;

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

/* skip when VPN isn't configured on vrf-instance */
if (tovpn_sid_index == 0 && !tovpn_sid_auto)
return;

/* check invalid case both configured index and auto */
if (tovpn_sid_index != 0 && tovpn_sid_auto) {
zlog_err("%s: index-mode and auto-mode both selected. ignored.",
__func__);
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 (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;
}

void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
{
/* per-af sid */
if (bgp_vrf->vpn_policy[afi].tovpn_sid_index != 0 ||
CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_SID_AUTO))
return ensure_vrf_tovpn_sid_per_af(bgp_vpn, bgp_vrf, afi);

/* per-vrf sid */
if (bgp_vrf->tovpn_sid_index != 0 ||
CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_TOVPN_SID_AUTO))
return ensure_vrf_tovpn_sid_per_vrf(bgp_vpn, bgp_vrf);
}

/*
* This function embeds upper `len` bits of `label` in `sid`,
* starting at offset `offset` as seen from the MSB of `sid`.
Expand Down Expand Up @@ -1337,6 +1519,29 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
&from_bgp->vpn_policy[afi]
.tovpn_sid_locator->prefix.prefix,
sizeof(struct in6_addr));
} else if (from_bgp->tovpn_sid_locator) {
encode_label(from_bgp->tovpn_sid_transpose_label, &label);
static_attr.srv6_l3vpn =
XCALLOC(MTYPE_BGP_SRV6_L3VPN,
sizeof(struct bgp_attr_srv6_l3vpn));
static_attr.srv6_l3vpn->sid_flags = 0x00;
static_attr.srv6_l3vpn->endpoint_behavior = 0xffff;
static_attr.srv6_l3vpn->loc_block_len =
from_bgp->tovpn_sid_locator->block_bits_length;
static_attr.srv6_l3vpn->loc_node_len =
from_bgp->tovpn_sid_locator->node_bits_length;
static_attr.srv6_l3vpn->func_len =
from_bgp->tovpn_sid_locator->function_bits_length;
static_attr.srv6_l3vpn->arg_len =
from_bgp->tovpn_sid_locator->argument_bits_length;
static_attr.srv6_l3vpn->transposition_len =
from_bgp->tovpn_sid_locator->function_bits_length;
static_attr.srv6_l3vpn->transposition_offset =
from_bgp->tovpn_sid_locator->block_bits_length +
from_bgp->tovpn_sid_locator->node_bits_length;
memcpy(&static_attr.srv6_l3vpn->sid,
&from_bgp->tovpn_sid_locator->prefix.prefix,
sizeof(struct in6_addr));
}


Expand Down
30 changes: 23 additions & 7 deletions bgpd/bgp_mplsvpn.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,16 @@ extern void vpn_leak_to_vrf_withdraw(struct bgp *from_bgp,
extern void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi);
extern void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi);
extern void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi);
extern void vpn_leak_zebra_vrf_sid_update_per_af(struct bgp *bgp, afi_t afi);
extern void vpn_leak_zebra_vrf_sid_update_per_vrf(struct bgp *bgp);
extern void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi);
extern void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi);
extern void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp);
extern int vpn_leak_label_callback(mpls_label_t label, void *lblid, bool alloc);
extern void ensure_vrf_tovpn_sid(struct bgp *vpn, struct bgp *vrf, afi_t afi);
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 vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
Expand Down Expand Up @@ -251,17 +258,26 @@ static inline void vpn_leak_postchange(enum vpn_policy_direction direction,
vpn_leak_zebra_vrf_label_update(bgp_vrf, afi);
}

if (!bgp_vrf->vpn_policy[afi].tovpn_sid)
if (!bgp_vrf->vpn_policy[afi].tovpn_sid && !bgp_vrf->tovpn_sid)
ensure_vrf_tovpn_sid(bgp_vpn, bgp_vrf, afi);

if (!bgp_vrf->vpn_policy[afi].tovpn_sid
&& bgp_vrf->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent)
if ((!bgp_vrf->vpn_policy[afi].tovpn_sid &&
bgp_vrf->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent) ||
(!bgp_vrf->tovpn_sid &&
bgp_vrf->tovpn_zebra_vrf_sid_last_sent))
vpn_leak_zebra_vrf_sid_withdraw(bgp_vrf, afi);

if (sid_diff(bgp_vrf->vpn_policy[afi].tovpn_sid,
bgp_vrf->vpn_policy[afi]
.tovpn_zebra_vrf_sid_last_sent)) {
vpn_leak_zebra_vrf_sid_update(bgp_vrf, afi);
if (bgp_vrf->vpn_policy[afi].tovpn_sid) {
if (sid_diff(bgp_vrf->vpn_policy[afi].tovpn_sid,
bgp_vrf->vpn_policy[afi]
.tovpn_zebra_vrf_sid_last_sent)) {
vpn_leak_zebra_vrf_sid_update(bgp_vrf, afi);
}
} else if (bgp_vrf->tovpn_sid) {
if (sid_diff(bgp_vrf->tovpn_sid,
bgp_vrf->tovpn_zebra_vrf_sid_last_sent)) {
vpn_leak_zebra_vrf_sid_update(bgp_vrf, afi);
}
}

vpn_leak_from_vrf_update_all(bgp_vpn, bgp_vrf, afi);
Expand Down
Loading

0 comments on commit 527588a

Please sign in to comment.