mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-25 06:10:23 +00:00
bgpd: cli for SRv6 SID alloc to redirect to vrf (step4)
This commit add cil to configure BGP SRv6-VPN sid allocation. Almost mechanism are based on BGP MPLS-VPN. User can allocate and export sid with using following config. Then bgpd try to allocate new SID to redirect vpn to vrf using SRv6 localsid End.DT4/DT6. Currently linux kernel will regect End.DT4 route install due to no-implementation. (at-least today's FRR's ci kernel.) So now we only supports BGP SRv6-VPNv6. router bgp 1 segment-routing srv6 locator loc1 ! address-family ipv6 vpn exit-address-family ! router bgp 1 vrf vrf10 address-family ipv6 unicast sid vpn export 1 !!(option1)!! sid vpn export auto !!(option2)!! exit-address-family ! Signed-off-by: Hiroki Shirokura <slank.dev@gmail.com>
This commit is contained in:
parent
a0281b2eab
commit
b72c9e1475
@ -317,6 +317,8 @@ static int bgp_vrf_enable(struct vrf *vrf)
|
|||||||
bgp_instance_up(bgp);
|
bgp_instance_up(bgp);
|
||||||
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
|
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
|
||||||
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
|
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
|
||||||
|
vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP);
|
||||||
|
vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6);
|
||||||
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP,
|
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP,
|
||||||
bgp_get_default(), bgp);
|
bgp_get_default(), bgp);
|
||||||
vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, AFI_IP,
|
vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, AFI_IP,
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include "bgpd/bgp_nexthop.h"
|
#include "bgpd/bgp_nexthop.h"
|
||||||
#include "bgpd/bgp_nht.h"
|
#include "bgpd/bgp_nht.h"
|
||||||
#include "bgpd/bgp_evpn.h"
|
#include "bgpd/bgp_evpn.h"
|
||||||
|
#include "bgpd/bgp_memory.h"
|
||||||
|
|
||||||
#ifdef ENABLE_BGP_VNC
|
#ifdef ENABLE_BGP_VNC
|
||||||
#include "bgpd/rfapi/rfapi_backend.h"
|
#include "bgpd/rfapi/rfapi_backend.h"
|
||||||
@ -356,6 +357,85 @@ void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi)
|
|||||||
bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent = label;
|
bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent = label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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'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);
|
||||||
|
enum seg6local_action_t act;
|
||||||
|
struct seg6local_context ctx = {{0}};
|
||||||
|
struct in6_addr *tovpn_sid = NULL;
|
||||||
|
struct in6_addr *tovpn_sid_ls = NULL;
|
||||||
|
struct vrf *vrf;
|
||||||
|
char buf[256] = {0};
|
||||||
|
|
||||||
|
if (bgp->vrf_id == VRF_UNKNOWN) {
|
||||||
|
if (debug)
|
||||||
|
zlog_debug("%s: vrf %s: afi %s: vrf_id not set, "
|
||||||
|
"can't set zebra vrf label",
|
||||||
|
__func__, bgp->name_pretty, afi2str(afi));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tovpn_sid = bgp->vpn_policy[afi].tovpn_sid;
|
||||||
|
if (!tovpn_sid) {
|
||||||
|
if (debug)
|
||||||
|
zlog_debug("%s: vrf %s: afi %s: sid not set", __func__,
|
||||||
|
bgp->name_pretty, afi2str(afi));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
inet_ntop(AF_INET6, tovpn_sid, buf, sizeof(buf));
|
||||||
|
zlog_debug("%s: vrf %s: afi %s: setting sid %s for vrf id %d",
|
||||||
|
__func__, bgp->name_pretty, afi2str(afi), buf,
|
||||||
|
bgp->vrf_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
vrf = vrf_lookup_by_id(bgp->vrf_id);
|
||||||
|
if (!vrf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ctx.table = vrf->data.l.table_id;
|
||||||
|
act = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
|
||||||
|
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
|
||||||
|
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->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
|
||||||
|
|
||||||
|
if (bgp->vrf_id == VRF_UNKNOWN) {
|
||||||
|
if (debug)
|
||||||
|
zlog_debug("%s: vrf %s: afi %s: vrf_id not set, "
|
||||||
|
"can't set zebra vrf label",
|
||||||
|
__func__, bgp->name_pretty, afi2str(afi));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
zlog_debug("%s: deleting sid for vrf %s afi (id=%d)", __func__,
|
||||||
|
bgp->name_pretty, bgp->vrf_id);
|
||||||
|
|
||||||
|
zclient_send_localsid(zclient,
|
||||||
|
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent,
|
||||||
|
bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, NULL);
|
||||||
|
XFREE(MTYPE_BGP_SRV6_SID,
|
||||||
|
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent);
|
||||||
|
}
|
||||||
|
|
||||||
int vpn_leak_label_callback(
|
int vpn_leak_label_callback(
|
||||||
mpls_label_t label,
|
mpls_label_t label,
|
||||||
void *labelid,
|
void *labelid,
|
||||||
@ -417,6 +497,123 @@ int vpn_leak_label_callback(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static 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,
|
||||||
|
sizeof(struct bgp_srv6_function));
|
||||||
|
func->sid = *sid;
|
||||||
|
snprintf(func->locator_name, sizeof(func->locator_name),
|
||||||
|
"%s", locator_name);
|
||||||
|
listnode_add(bgp->srv6_functions, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
|
||||||
|
{
|
||||||
|
struct listnode *node;
|
||||||
|
struct bgp_srv6_function *func;
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func))
|
||||||
|
if (sid_same(&func->sid, sid))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if index != 0: try to allocate as index-mode
|
||||||
|
* else: try to allocate as auto-mode */
|
||||||
|
static bool alloc_new_sid(struct bgp *bgp, uint32_t index,
|
||||||
|
struct in6_addr *sid)
|
||||||
|
{
|
||||||
|
struct listnode *node;
|
||||||
|
struct prefix_ipv6 *chunk;
|
||||||
|
struct in6_addr sid_buf;
|
||||||
|
bool alloced = false;
|
||||||
|
|
||||||
|
if (!bgp || !sid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
|
||||||
|
sid_buf = chunk->prefix;
|
||||||
|
if (index != 0) {
|
||||||
|
sid_buf.s6_addr[15] = index;
|
||||||
|
if (sid_exist(bgp, &sid_buf))
|
||||||
|
return false;
|
||||||
|
alloced = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
for (size_t i=1; i<255; i++) {
|
||||||
|
sid_buf.s6_addr16[7] = i;
|
||||||
|
if (sid_exist(bgp, &sid_buf))
|
||||||
|
continue;
|
||||||
|
alloced = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!alloced)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sid_register(bgp, &sid_buf, bgp->srv6_locator_name);
|
||||||
|
*sid = sid_buf;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
|
||||||
|
{
|
||||||
|
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
|
||||||
|
bool alloced = false;
|
||||||
|
char buf[256];
|
||||||
|
struct in6_addr *sid;
|
||||||
|
uint32_t tovpn_sid_index = 0;
|
||||||
|
bool tovpn_sid_auto = false;
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
zlog_debug("%s: try to allocate new SID for vrf %s: afi %s",
|
||||||
|
__func__, bgp_vrf->name_pretty, afi2str(afi));
|
||||||
|
|
||||||
|
/* skip when tovpn sid is already allocated on vrf instance */
|
||||||
|
if (bgp_vrf->vpn_policy[afi].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 || !bgp_vrf)
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* 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_index) {
|
||||||
|
zlog_err("%s: index-mode and auto-mode both selected. ignored.",
|
||||||
|
__func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
|
||||||
|
alloced = alloc_new_sid(bgp_vpn, tovpn_sid_index, sid);
|
||||||
|
if (!alloced) {
|
||||||
|
zlog_debug("%s: not allocated new sid for vrf %s: afi %s",
|
||||||
|
__func__, bgp_vrf->name_pretty, afi2str(afi));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
inet_ntop(AF_INET6, sid, buf, sizeof(buf));
|
||||||
|
zlog_debug("%s: new sid %s allocated for vrf %s: afi %s",
|
||||||
|
__func__, buf, bgp_vrf->name_pretty,
|
||||||
|
afi2str(afi));
|
||||||
|
}
|
||||||
|
bgp_vrf->vpn_policy[afi].tovpn_sid = sid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static bool ecom_intersect(struct ecommunity *e1, struct ecommunity *e2)
|
static bool ecom_intersect(struct ecommunity *e1, struct ecommunity *e2)
|
||||||
{
|
{
|
||||||
uint32_t i, j;
|
uint32_t i, j;
|
||||||
|
@ -77,7 +77,10 @@ extern void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn,
|
|||||||
|
|
||||||
extern void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi);
|
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_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_withdraw(struct bgp *bgp, afi_t afi);
|
||||||
extern int vpn_leak_label_callback(mpls_label_t label, void *lblid, bool alloc);
|
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 vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
|
extern void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
|
||||||
afi_t afi, safi_t safi);
|
afi_t afi, safi_t safi);
|
||||||
void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
|
void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
|
||||||
@ -237,6 +240,15 @@ static inline void vpn_leak_postchange(vpn_policy_direction_t direction,
|
|||||||
vpn_leak_zebra_vrf_label_update(bgp_vrf, afi);
|
vpn_leak_zebra_vrf_label_update(bgp_vrf, afi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!bgp_vrf->vpn_policy[afi].tovpn_sid)
|
||||||
|
ensure_vrf_tovpn_sid(bgp_vpn, 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);
|
||||||
|
}
|
||||||
|
|
||||||
vpn_leak_from_vrf_update_all(bgp_vpn, bgp_vrf, afi);
|
vpn_leak_from_vrf_update_all(bgp_vpn, bgp_vrf, afi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9232,6 +9232,77 @@ DEFPY (af_label_vpn_export,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY (af_sid_vpn_export,
|
||||||
|
af_sid_vpn_export_cmd,
|
||||||
|
"[no] sid vpn export <(1-255)$sid_idx|auto$sid_auto>",
|
||||||
|
NO_STR
|
||||||
|
"sid value for VRF\n"
|
||||||
|
"Between current address-family and vpn\n"
|
||||||
|
"For routes leaked from current address-family to vpn\n"
|
||||||
|
"Sid allocation index\n"
|
||||||
|
"Automatically assign a label\n")
|
||||||
|
{
|
||||||
|
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||||
|
afi_t afi;
|
||||||
|
int debug = 0;
|
||||||
|
int idx = 0;
|
||||||
|
bool yes = true;
|
||||||
|
|
||||||
|
if (argv_find(argv, argc, "no", &idx))
|
||||||
|
yes = false;
|
||||||
|
debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
|
||||||
|
BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
|
||||||
|
|
||||||
|
afi = vpn_policy_getafi(vty, bgp, false);
|
||||||
|
if (afi == AFI_MAX)
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
|
||||||
|
if (!yes) {
|
||||||
|
/* implement me */
|
||||||
|
vty_out(vty, "It's not implemented");
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip when it's already configured */
|
||||||
|
if ((sid_idx != 0 && bgp->vpn_policy[afi].tovpn_sid_index != 0)
|
||||||
|
|| (sid_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags,
|
||||||
|
BGP_VPN_POLICY_TOVPN_SID_AUTO)))
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
|
||||||
|
/* mode change between sid_idx and sid_auto isn't supported.
|
||||||
|
* user must negate sid vpn export when they want to change
|
||||||
|
* the mode */
|
||||||
|
if ((sid_auto && bgp->vpn_policy[afi].tovpn_sid_index != 0)
|
||||||
|
|| (sid_idx != 0 && CHECK_FLAG(bgp->vpn_policy[afi].flags,
|
||||||
|
BGP_VPN_POLICY_TOVPN_SID_AUTO))) {
|
||||||
|
vty_out(vty, "it's already configured as %s.\n",
|
||||||
|
sid_auto ? "auto-mode" : "idx-mode");
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pre-change */
|
||||||
|
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
|
||||||
|
bgp_get_default(), bgp);
|
||||||
|
|
||||||
|
if (sid_auto) {
|
||||||
|
/* SID allocation auto-mode */
|
||||||
|
if (debug)
|
||||||
|
zlog_debug("%s: auto sid alloc.", __func__);
|
||||||
|
SET_FLAG(bgp->vpn_policy[afi].flags,
|
||||||
|
BGP_VPN_POLICY_TOVPN_SID_AUTO);
|
||||||
|
} else {
|
||||||
|
/* SID allocation index-mode */
|
||||||
|
if (debug)
|
||||||
|
zlog_debug("%s: idx %ld sid alloc.", __func__, sid_idx);
|
||||||
|
bgp->vpn_policy[afi].tovpn_sid_index = sid_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* post-change */
|
||||||
|
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
|
||||||
|
bgp_get_default(), bgp);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
ALIAS (af_label_vpn_export,
|
ALIAS (af_label_vpn_export,
|
||||||
af_no_label_vpn_export_cmd,
|
af_no_label_vpn_export_cmd,
|
||||||
"no label vpn export",
|
"no label vpn export",
|
||||||
@ -19493,6 +19564,8 @@ void bgp_vty_init(void)
|
|||||||
/* srv6 commands */
|
/* srv6 commands */
|
||||||
install_element(BGP_NODE, &bgp_segment_routing_srv6_cmd);
|
install_element(BGP_NODE, &bgp_segment_routing_srv6_cmd);
|
||||||
install_element(BGP_SRV6_NODE, &bgp_srv6_locator_cmd);
|
install_element(BGP_SRV6_NODE, &bgp_srv6_locator_cmd);
|
||||||
|
install_element(BGP_IPV4_NODE, &af_sid_vpn_export_cmd);
|
||||||
|
install_element(BGP_IPV6_NODE, &af_sid_vpn_export_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user