bgpd: new vpn-policy CLI

PR #1739 added code to leak routes between (default VRF) VPN safi and unicast RIBs in any VRF. That set of changes included temporary CLI including vpn-policy blocks to specify RD/RT/label/&c. After considerable discussion, we arrived at a consensus CLI shown below.

The code of this PR implements the vpn-specific parts of this syntax:

router bgp <as> [vrf <FOO>]
    address-family <afi> unicast
        rd (vpn|evpn) export (AS:NN | IP:nn)
        label (vpn|evpn) export (0..1048575)
        rt (vpn|evpn) (import|export|both) RTLIST...
        nexthop vpn (import|export) (A.B.C.D | X:X::X:X)
        route-map (vpn|evpn|vrf NAME) (import|export) MAP

        [no] import|export [vpn|evpn|evpn8]
        [no] import|export vrf NAME

User documentation of the vpn-specific parts of the above syntax is in PR #1937

Signed-off-by: G. Paul Ziemba <paulz@labn.net>
This commit is contained in:
G. Paul Ziemba 2018-03-16 11:11:37 -07:00
parent 46fe6fd557
commit b9c7bc5ab0
13 changed files with 417 additions and 673 deletions

View File

@ -28,8 +28,8 @@
#include "queue.h"
#include "filter.h"
#include "mpls.h"
#include "lib/json.h"
#include "lib/zclient.h"
#include "json.h"
#include "zclient.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_debug.h"
@ -824,7 +824,6 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
struct prefix *p = &info_vpn->net->p;
afi_t afi = family2afi(p->family);
struct bgp_redist *red;
struct attr static_attr = {0};
struct attr *new_attr = NULL;
struct bgp_node *bn;
@ -836,7 +835,7 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
if (!vpn_leak_from_vpn_active(bgp_vrf, afi, &debugmsg, &red)) {
if (!vpn_leak_from_vpn_active(bgp_vrf, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg);
return;
@ -893,28 +892,7 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
/*
* route map handling
* For now, we apply two route maps: the "redist" route map and the
* vpn-policy route map. Once we finalize CLI syntax, one of these
* route maps will probably go away.
*/
if (red->rmap.map) {
struct bgp_info info;
route_map_result_t ret;
memset(&info, 0, sizeof(info));
info.peer = bgp_vrf->peer_self;
info.attr = &static_attr;
ret = route_map_apply(red->rmap.map, p, RMAP_BGP, &info);
if (RMAP_DENYMATCH == ret) {
bgp_attr_flush(&static_attr); /* free any added parts */
if (debug)
zlog_debug(
"%s: vrf %s redist route map \"%s\" says DENY, skipping",
__func__, bgp_vrf->name,
red->rmap.name);
return;
}
}
if (bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN]) {
struct bgp_info info;
route_map_result_t ret;
@ -994,7 +972,6 @@ void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */
safi_t safi = SAFI_UNICAST;
struct bgp *bgp;
struct listnode *mnode, *mnnode;
struct bgp_redist *red;
struct bgp_node *bn;
struct bgp_info *bi;
const char *debugmsg;
@ -1007,7 +984,7 @@ void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */
/* Loop over VRFs */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
if (!vpn_leak_from_vpn_active(bgp, afi, &debugmsg, &red)) {
if (!vpn_leak_from_vpn_active(bgp, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__,
debugmsg);
@ -1164,36 +1141,27 @@ static void vpn_policy_routemap_update(struct bgp *bgp, const char *rmap_name)
__func__);
}
/*
* vpn -> vrf leaking currently can have two route-maps:
* 1. the vpn-policy tovpn route-map
* 2. the (per-afi) redistribute vpn route-map
*/
char *mapname_vpn_policy =
bgp->vpn_policy[afi]
.rmap_name[BGP_VPN_POLICY_DIR_FROMVPN];
struct bgp_redist *red = NULL;
char *mapname = bgp->vpn_policy[afi]
.rmap_name[BGP_VPN_POLICY_DIR_FROMVPN];
if (vpn_leak_from_vpn_active(bgp, afi, NULL, &red)
&& ((mapname_vpn_policy
&& !strcmp(rmap_name, mapname_vpn_policy))
|| (red && red->rmap.name
&& !strcmp(red->rmap.name, rmap_name)))) {
if (vpn_leak_from_vpn_active(bgp, afi, NULL) &&
mapname &&
!strcmp(rmap_name, mapname)) {
if (debug)
zlog_debug(
"%s: rmap \"%s\" matches vrf-policy fromvpn"
" for as %d afi %s",
if (debug) {
zlog_debug("%s: rmap \"%s\" matches vrf-policy fromvpn for as %d afi %s",
__func__, rmap_name, bgp->as,
afi2str(afi));
}
vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
bgp_get_default(), bgp);
if (!rmap)
if (!rmap) {
bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_FROMVPN] =
NULL;
}
vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
bgp_get_default(), bgp);

View File

@ -107,11 +107,8 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
}
static inline int vpn_leak_from_vpn_active(struct bgp *bgp_vrf, afi_t afi,
const char **pmsg,
struct bgp_redist **pred)
const char **pmsg)
{
struct bgp_redist *red;
if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF
&& bgp_vrf->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
@ -120,14 +117,11 @@ static inline int vpn_leak_from_vpn_active(struct bgp *bgp_vrf, afi_t afi,
return 0;
}
/* Hijack zebra redist bits for this route type */
red = bgp_redist_lookup(bgp_vrf, afi, ZEBRA_ROUTE_BGP_VPN, 0);
if (red) {
if (pred)
*pred = red;
} else {
/* Is vrf configured to import from vpn? */
if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)) {
if (pmsg)
*pmsg = "redist not set";
*pmsg = "import not set";
return 0;
}
if (!bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN]) {

File diff suppressed because it is too large Load Diff

View File

@ -71,5 +71,6 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty,
safi_t *safi, struct bgp **bgp);
extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
safi_t safi, u_char use_json);
extern void bgp_vpn_policy_config_write(struct vty *vty, struct bgp *bgp);
extern void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
afi_t afi);
#endif /* _QUAGGA_BGP_VTY_H */

View File

@ -1451,27 +1451,7 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type, u_short instance)
}
#endif
/* vpn -> vrf (happens within bgp but we hijack redist bits */
if ((bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
|| bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
&& type == ZEBRA_ROUTE_BGP_VPN) {
/* leak update all */
vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
bgp_get_default(), bgp);
}
vrf_bitmap_set(zclient->redist[afi][type], bgp->vrf_id);
/* vpn -> vrf (happens within bgp but we hijack redist bits */
if ((bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
|| bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
&& type == ZEBRA_ROUTE_BGP_VPN) {
/* leak update all */
vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
bgp_get_default(), bgp);
}
}
/*
@ -1625,15 +1605,6 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type,
vnc_export_bgp_disable(bgp, afi);
}
#endif
/* vpn -> vrf (happend within bgp but we hijack redist bits */
if ((bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
|| bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
&& type == ZEBRA_ROUTE_BGP_VPN) {
/* leak withdraw all */
vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
bgp_get_default(), bgp);
}
red = bgp_redist_lookup(bgp, afi, type, instance);
if (!red)

View File

@ -7132,10 +7132,18 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
if (safi == SAFI_EVPN)
bgp_config_write_evpn_info(vty, bgp, afi, safi);
if (CHECK_FLAG(bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
if (safi == SAFI_UNICAST) {
bgp_vpn_policy_config_write_afi(vty, bgp, afi);
if (CHECK_FLAG(bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
vty_out(vty, " export vpn\n");
vty_out(vty, " export vpn\n");
}
if (CHECK_FLAG(bgp->af_flags[afi][safi],
BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)) {
vty_out(vty, " import vpn\n");
}
}
vty_endframe(vty, " exit-address-family\n");
@ -7404,8 +7412,6 @@ int bgp_config_write(struct vty *vty)
if (bgp_option_check(BGP_OPT_CONFIG_CISCO))
vty_out(vty, " no auto-summary\n");
bgp_vpn_policy_config_write(vty, bgp);
/* IPv4 unicast configuration. */
bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);

View File

@ -318,6 +318,7 @@ struct bgp {
u_int16_t af_flags[AFI_MAX][SAFI_MAX];
#define BGP_CONFIG_DAMPENING (1 << 0)
#define BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT (1 << 1)
#define BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT (1 << 2)
/* l2vpn evpn flags - 1 << 0 is used for DAMPENNG */
#define BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST (1 << 1)
@ -471,7 +472,7 @@ struct bgp {
uint32_t tovpn_label; /* may be MPLS_LABEL_NONE */
uint32_t tovpn_zebra_vrf_label_last_sent;
struct prefix_rd tovpn_rd;
struct prefix tovpn_nexthop; /* unset => set to router id */
struct prefix tovpn_nexthop; /* unset => set to 0 */
uint32_t flags;
#define BGP_VPN_POLICY_TOVPN_RD_SET 0x00000004
#define BGP_VPN_POLICY_TOVPN_NEXTHOP_SET 0x00000008

View File

@ -87,8 +87,6 @@ const char *node_names[] = {
"bgp vnc l2", // BGP_VNC_L2_GROUP_NODE,
"rfp defaults", // RFP_DEFAULTS_NODE,
"bgp evpn", // BGP_EVPN_NODE,
"bgp vpn policy ipv4", // BGP_VPNPOLICY_IPV4_NODE
"bgp vpn policy ipv6", // BGP_VPNPOLICY_IPV6_NODE
"ospf", // OSPF_NODE,
"ospf6", // OSPF6_NODE,
"ldp", // LDP_NODE,
@ -951,8 +949,6 @@ enum node_type node_parent(enum node_type node)
case BGP_VPNV4_NODE:
case BGP_VPNV6_NODE:
case BGP_VRF_POLICY_NODE:
case BGP_VPNPOLICY_IPV4_NODE:
case BGP_VPNPOLICY_IPV6_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@ -1323,8 +1319,6 @@ void cmd_exit(struct vty *vty)
case BGP_VPNV4_NODE:
case BGP_VPNV6_NODE:
case BGP_VRF_POLICY_NODE:
case BGP_VPNPOLICY_IPV4_NODE:
case BGP_VPNPOLICY_IPV6_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@ -1395,8 +1389,6 @@ DEFUN (config_end,
case BABEL_NODE:
case BGP_NODE:
case BGP_VRF_POLICY_NODE:
case BGP_VPNPOLICY_IPV4_NODE:
case BGP_VPNPOLICY_IPV6_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:

View File

@ -110,8 +110,6 @@ enum node_type {
BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */
RFP_DEFAULTS_NODE, /* RFP defaults node */
BGP_EVPN_NODE, /* BGP EVPN node. */
BGP_VPNPOLICY_IPV4_NODE, /* BGP VPN IPv6 policy */
BGP_VPNPOLICY_IPV6_NODE, /* BGP VPN IPv6 policy */
OSPF_NODE, /* OSPF protocol mode */
OSPF6_NODE, /* OSPF protocol for IPv6 mode */
LDP_NODE, /* LDP protocol mode */

View File

@ -1055,8 +1055,6 @@ int proto_redistnum(int afi, const char *s)
return ZEBRA_ROUTE_BABEL;
else if (strmatch(s, "sharp"))
return ZEBRA_ROUTE_SHARP;
else if (strmatch(s, "vpn"))
return ZEBRA_ROUTE_BGP_VPN;
}
if (afi == AFI_IP6) {
if (strmatch(s, "kernel"))
@ -1085,8 +1083,6 @@ int proto_redistnum(int afi, const char *s)
return ZEBRA_ROUTE_BABEL;
else if (strmatch(s, "sharp"))
return ZEBRA_ROUTE_SHARP;
else if (strmatch(s, "vpn"))
return ZEBRA_ROUTE_BGP_VPN;
}
return -1;
}

View File

@ -76,7 +76,6 @@ ZEBRA_ROUTE_VNC_DIRECT_RH, vnc-rn, NULL, 'V', 0, 0, "VNC-RN"
ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL, 'b', 0, 0, "BGP-Direct"
# bgp unicast -> vnc
ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, "BGP2VNC"
ZEBRA_ROUTE_BGP_VPN, vpn, NULL, 'c', 1, 1, "VPN", bgpd
ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
ZEBRA_ROUTE_SHARP, sharp, sharpd, 'D', 1, 1, "SHARP"
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, "-"
@ -102,6 +101,5 @@ ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)"
ZEBRA_ROUTE_TABLE, "Non-main Kernel Routing Table"
ZEBRA_ROUTE_LDP, "Label Distribution Protocol (LDP)"
ZEBRA_ROUTE_VNC_DIRECT, "VNC direct (not via zebra) routes"
ZEBRA_ROUTE_BGP_VPN, "BGP VPN routes"
ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
ZEBRA_ROUTE_SHARP, "Super Happy Advanced Routing Protocol (sharpd)"

View File

@ -360,9 +360,7 @@ static int vtysh_execute_func(const char *line, int pager)
} else if ((saved_node == KEYCHAIN_KEY_NODE
|| saved_node == LDP_PSEUDOWIRE_NODE
|| saved_node == LDP_IPV4_IFACE_NODE
|| saved_node == LDP_IPV6_IFACE_NODE
|| saved_node == BGP_VPNPOLICY_IPV4_NODE
|| saved_node == BGP_VPNPOLICY_IPV6_NODE)
|| saved_node == LDP_IPV6_IFACE_NODE)
&& (tried == 1)) {
vtysh_execute("exit");
} else if (tried) {
@ -634,9 +632,7 @@ int vtysh_mark_file(const char *filename)
} else if ((prev_node == BGP_EVPN_VNI_NODE)
&& (tried == 1)) {
fprintf(outputfile, "exit-vni\n");
} else if ((prev_node == KEYCHAIN_KEY_NODE
|| prev_node == BGP_VPNPOLICY_IPV4_NODE
|| prev_node == BGP_VPNPOLICY_IPV6_NODE)
} else if ((prev_node == KEYCHAIN_KEY_NODE)
&& (tried == 1)) {
fprintf(outputfile, "exit\n");
} else if (tried) {
@ -1017,12 +1013,6 @@ static struct cmd_node bgp_evpn_node = {BGP_EVPN_NODE,
static struct cmd_node bgp_evpn_vni_node = {BGP_EVPN_VNI_NODE,
"%s(config-router-af-vni)# "};
static struct cmd_node bgp_vpn_policy_ipv4_node = {
BGP_VPNPOLICY_IPV4_NODE, "%s(config-router-vpn-policy-ipv4)# ", 1};
static struct cmd_node bgp_vpn_policy_ipv6_node = {
BGP_VPNPOLICY_IPV6_NODE, "%s(config-router-vpn-policy-ipv6)# ", 1};
static struct cmd_node bgp_ipv6l_node = {BGP_IPV6L_NODE,
"%s(config-router-af)# "};
@ -1274,20 +1264,6 @@ DEFUNSH(VTYSH_BGPD, bgp_evpn_vni, bgp_evpn_vni_cmd, "vni (1-16777215)",
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_BGPD, vpn_policy_afi, vpn_policy_afi_cmd, "vpn-policy <ipv4|ipv6>",
"Configure a VPN policy\n"
BGP_AFI_HELP_STR)
{
int idx = 1;
if (argv_find(argv, argc, "ipv4", &idx))
vty->node = BGP_VPNPOLICY_IPV4_NODE;
else
vty->node = BGP_VPNPOLICY_IPV6_NODE;
return CMD_SUCCESS;
}
#if defined(ENABLE_BGP_VNC)
DEFUNSH(VTYSH_BGPD, vnc_defaults, vnc_defaults_cmd, "vnc defaults",
"VNC/RFP related configuration\n"
@ -1562,8 +1538,6 @@ static int vtysh_exit(struct vty *vty)
case BGP_IPV6M_NODE:
case BGP_IPV6L_NODE:
case BGP_VRF_POLICY_NODE:
case BGP_VPNPOLICY_IPV4_NODE:
case BGP_VPNPOLICY_IPV6_NODE:
case BGP_EVPN_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
@ -3112,8 +3086,6 @@ void vtysh_init_vty(void)
install_node(&bgp_vrf_policy_node, NULL);
install_node(&bgp_evpn_node, NULL);
install_node(&bgp_evpn_vni_node, NULL);
install_node(&bgp_vpn_policy_ipv4_node, NULL);
install_node(&bgp_vpn_policy_ipv6_node, NULL);
install_node(&bgp_vnc_defaults_node, NULL);
install_node(&bgp_vnc_nve_group_node, NULL);
install_node(&bgp_vnc_l2_group_node, NULL);
@ -3206,10 +3178,6 @@ void vtysh_init_vty(void)
install_element(BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd);
install_element(BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd);
install_element(BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd);
install_element(BGP_VPNPOLICY_IPV4_NODE, &vtysh_exit_bgpd_cmd);
install_element(BGP_VPNPOLICY_IPV4_NODE, &vtysh_quit_bgpd_cmd);
install_element(BGP_VPNPOLICY_IPV6_NODE, &vtysh_exit_bgpd_cmd);
install_element(BGP_VPNPOLICY_IPV6_NODE, &vtysh_quit_bgpd_cmd);
#if defined(ENABLE_BGP_VNC)
install_element(BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
install_element(BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
@ -3262,8 +3230,6 @@ void vtysh_init_vty(void)
install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
install_element(BGP_VPNPOLICY_IPV4_NODE, &vtysh_end_all_cmd);
install_element(BGP_VPNPOLICY_IPV6_NODE, &vtysh_end_all_cmd);
install_element(ISIS_NODE, &vtysh_end_all_cmd);
install_element(KEYCHAIN_NODE, &vtysh_end_all_cmd);
install_element(KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd);
@ -3313,7 +3279,6 @@ void vtysh_init_vty(void)
install_element(CONFIG_NODE, &router_bgp_cmd);
install_element(BGP_NODE, &address_family_vpnv4_cmd);
install_element(BGP_NODE, &address_family_vpnv6_cmd);
install_element(BGP_NODE, &vpn_policy_afi_cmd);
#if defined(ENABLE_BGP_VNC)
install_element(BGP_NODE, &vnc_vrf_policy_cmd);
install_element(BGP_NODE, &vnc_defaults_cmd);

View File

@ -1865,7 +1865,6 @@ static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = {
[ZEBRA_ROUTE_VNC_DIRECT_RH] = 3,
[ZEBRA_ROUTE_BGP_DIRECT] = 3,
[ZEBRA_ROUTE_BGP_DIRECT_EXT] = 3,
[ZEBRA_ROUTE_BGP_VPN] = 3,
[ZEBRA_ROUTE_BABEL] = 2,
[ZEBRA_ROUTE_ALL] = 4, // Shouldn't happen but for safety
};