Skip to content

Commit

Permalink
bgpd: Implement vrf - vrf route leaking cli
Browse files Browse the repository at this point in the history
add the `import vrf XXXX` command

router bgp 4 vrf DONNA
  <config>
!

router bgp 4 vrf EVA
  <config>
  address-family ipv4 uni
    import vrf DONNA
  !
!

This command will allow for vrf EVA to specify that it would like
to receive the routes from vrf DONNA into it's table.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
  • Loading branch information
donaldsharp committed Apr 25, 2018
1 parent 97722e5 commit 12a844a
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 34 deletions.
104 changes: 72 additions & 32 deletions bgpd/bgp_mplsvpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -640,8 +640,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
char *s = ecommunity_ecom2str(info_vrf->attr->ecommunity,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);

zlog_debug("%s: info_vrf->type=%d, EC{%s}", __func__,
info_vrf->type, s);
zlog_debug("%s: %s info_vrf->type=%d, EC{%s}", __func__,
bgp_vrf->name, info_vrf->type, s);
XFREE(MTYPE_ECOMMUNITY_STR, s);
}

Expand All @@ -661,7 +661,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */

if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg);
zlog_debug("%s: %s skipping: %s", __func__,
bgp_vrf->name, debugmsg);
return;
}

Expand Down Expand Up @@ -737,9 +738,9 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
/* if policy nexthop not set, use 0 */
if (CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) {

struct prefix *nexthop =
&bgp_vrf->vpn_policy[afi].tovpn_nexthop;

switch (nexthop->family) {
case AF_INET:
/* prevent mp_nexthop_global_in <- self in bgp_route.c
Expand All @@ -759,12 +760,31 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
assert(0);
}
} else {
if (afi == AFI_IP) {
/* For ipv4, copy to multiprotocol nexthop field */
static_attr.mp_nexthop_global_in = static_attr.nexthop;
static_attr.mp_nexthop_len = 4;
/* XXX Leave static_attr.nexthop intact for NHT */
static_attr.flag &= ~ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
if (afi == AFI_IP) {
/* For ipv4, copy to multiprotocol nexthop field */
static_attr.mp_nexthop_global_in = static_attr.nexthop;
static_attr.mp_nexthop_len = 4;
/* XXX Leave static_attr.nexthop intact for NHT */
static_attr.flag &= ~ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
}
} else {
switch (afi) {
case AFI_IP:
static_attr.mp_nexthop_global_in.s_addr =
static_attr.nexthop.s_addr;
static_attr.mp_nexthop_len = 4;
static_attr.flag |=
ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
break;
case AFI_IP6:
break;
case AFI_L2VPN:
case AFI_MAX:
assert(!"Unexpected AFI to process");
break;
}
}
nexthop_self_flag = 1;
}
Expand Down Expand Up @@ -1036,22 +1056,36 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
nexthop_orig.family = nhfamily;

switch (nhfamily) {

case AF_INET:
/* save */
nexthop_orig.u.prefix4 = info_vpn->attr->mp_nexthop_global_in;
nexthop_orig.prefixlen = 32;

if (CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
static_attr.nexthop.s_addr =
nexthop_orig.u.prefix4.s_addr;

static_attr.mp_nexthop_global_in =
info_vpn->attr->mp_nexthop_global_in;
static_attr.mp_nexthop_len =
info_vpn->attr->mp_nexthop_len;
}
static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
break;

case AF_INET6:
/* save */
nexthop_orig.u.prefix6 = info_vpn->attr->mp_nexthop_global;
nexthop_orig.prefixlen = 128;

if (CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
static_attr.mp_nexthop_global = nexthop_orig.u.prefix6;
static_attr.mp_nexthop_len = 16;
}
break;
}


/*
* route map handling
*/
Expand Down Expand Up @@ -1101,28 +1135,34 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
* labels for these routes enables the non-labeled nexthops
* from the originating VRF to be considered valid for this route.
*/
if (!CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
/* work back to original route */
for (bi_ultimate = info_vpn;
bi_ultimate->extra && bi_ultimate->extra->parent;
bi_ultimate = bi_ultimate->extra->parent)
;

/* work back to original route */
for (bi_ultimate = info_vpn;
bi_ultimate->extra && bi_ultimate->extra->parent;
bi_ultimate = bi_ultimate->extra->parent)
;

/* if original route was unicast, then it did not arrive over vpn */
if (bi_ultimate->net) {
struct bgp_table *table;
/*
* if original route was unicast,
* then it did not arrive over vpn
*/
if (bi_ultimate->net) {
struct bgp_table *table;

table = bgp_node_table(bi_ultimate->net);
if (table && (table->safi == SAFI_UNICAST))
origin_local = 1;
}
table = bgp_node_table(bi_ultimate->net);
if (table && (table->safi == SAFI_UNICAST))
origin_local = 1;
}

/* copy labels */
if (!origin_local && info_vpn->extra && info_vpn->extra->num_labels) {
num_labels = info_vpn->extra->num_labels;
if (num_labels > BGP_MAX_LABELS)
num_labels = BGP_MAX_LABELS;
pLabels = info_vpn->extra->label;
/* copy labels */
if (!origin_local &&
info_vpn->extra && info_vpn->extra->num_labels) {
num_labels = info_vpn->extra->num_labels;
if (num_labels > BGP_MAX_LABELS)
num_labels = BGP_MAX_LABELS;
pLabels = info_vpn->extra->label;
}
}

if (debug) {
Expand Down
8 changes: 6 additions & 2 deletions bgpd/bgp_mplsvpn.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,

/* Is vrf configured to export to vpn? */
if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)
&& !CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
if (pmsg)
*pmsg = "export not set";
return 0;
Expand Down Expand Up @@ -147,7 +149,9 @@ static inline int vpn_leak_from_vpn_active(struct bgp *bgp_vrf, afi_t afi,

/* Is vrf configured to import from vpn? */
if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)) {
BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)
&& !CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
if (pmsg)
*pmsg = "import not set";
return 0;
Expand Down
119 changes: 119 additions & 0 deletions bgpd/bgp_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -6575,6 +6575,116 @@ ALIAS (af_route_map_vpn_imexport,
"For routes leaked from vpn to current address-family\n"
"For routes leaked from current address-family to vpn\n")

DEFPY (bgp_imexport_vrf,
bgp_imexport_vrf_cmd,
"[no] import vrf NAME$import_name",
NO_STR
"Import routes from another VRF\n"
"VRF to import from\n"
"The name of the VRF\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
struct listnode *node;
struct bgp *vrf_bgp;
bool remove = false;
int32_t idx = 0;
char *vname;
const char *export_name;
safi_t safi;
afi_t afi;

if (argv_find(argv, argc, "no", &idx))
remove = true;

afi = bgp_node_afi(vty);
safi = bgp_node_safi(vty);

vrf_bgp = bgp_lookup_by_name(import_name);
if (!vrf_bgp) {
vty_out(vty, "VRF %s is not configured as a bgp instance\n",
import_name);
return CMD_WARNING;
}

export_name = bgp->name ? bgp->name : VRF_DEFAULT_NAME;

if (remove) {
for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi].import_vrf, node,
vname)) {
if (strcmp(vname, import_name) == 0)
break;
}

if (!vname) {
vty_out(vty,
"Specified VRF %s was not imported, ignoring",
import_name);
return CMD_WARNING;
}

listnode_delete(bgp->vpn_policy[afi].import_vrf, vname);
XFREE(MTYPE_TMP, vname);

if (bgp->vpn_policy[afi].import_vrf->count == 0) {
UNSET_FLAG(bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT);

ecommunity_free(
&bgp->vpn_policy[afi]
.rtlist[BGP_VPN_POLICY_DIR_FROMVPN]);
}

for (ALL_LIST_ELEMENTS_RO(vrf_bgp->vpn_policy[afi].export_vrf,
node, vname)) {
if (strcmp(vname, export_name) == 0)
break;
}

listnode_delete(vrf_bgp->vpn_policy[afi].export_vrf, vname);
XFREE(MTYPE_TMP, vname);

UNSET_FLAG(vrf_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_EXPORT);
UNSET_FLAG(vrf_bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET);

ecommunity_free(&vrf_bgp->vpn_policy[afi]
.rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi, bgp, vrf_bgp);
} else {
char buf[1000];

for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi].import_vrf, node,
vname)) {
if (strcmp(vname, import_name) == 0)
return CMD_WARNING;
}

vname = XSTRDUP(MTYPE_TMP, import_name);
listnode_add(bgp->vpn_policy[afi].import_vrf, vname);

vname = XSTRDUP(MTYPE_TMP, export_name);
listnode_add(vrf_bgp->vpn_policy[afi].export_vrf, vname);

prefix_rd2str(&vrf_bgp->vrf_prd, buf, sizeof(buf));
vrf_bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN] =
ecommunity_str2com(buf, ECOMMUNITY_ROUTE_TARGET, 0);
bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN] =
ecommunity_str2com(buf, ECOMMUNITY_ROUTE_TARGET, 0);

SET_FLAG(bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT);
SET_FLAG(vrf_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_EXPORT);
SET_FLAG(vrf_bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET);
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi, bgp,
vrf_bgp);
}

return CMD_SUCCESS;
}

/* This command is valid only in a bgp vrf instance or the default instance */
DEFPY (bgp_imexport_vpn,
bgp_imexport_vpn_cmd,
Expand Down Expand Up @@ -11744,6 +11854,12 @@ void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
{
int indent = 2;

if (CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_VRF_TO_VRF_IMPORT)
|| CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_VRF_TO_VRF_EXPORT))
return;

if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {

Expand Down Expand Up @@ -13063,6 +13179,9 @@ void bgp_vty_init(void)
install_element(BGP_IPV4_NODE, &bgp_imexport_vpn_cmd);
install_element(BGP_IPV6_NODE, &bgp_imexport_vpn_cmd);

install_element(BGP_IPV4_NODE, &bgp_imexport_vrf_cmd);
install_element(BGP_IPV6_NODE, &bgp_imexport_vrf_cmd);

/* ttl_security commands */
install_element(BGP_NODE, &neighbor_ttl_security_cmd);
install_element(BGP_NODE, &no_neighbor_ttl_security_cmd);
Expand Down
13 changes: 13 additions & 0 deletions bgpd/bgpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2956,6 +2956,9 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent =
MPLS_LABEL_NONE;

bgp->vpn_policy[afi].import_vrf = list_new();
bgp->vpn_policy[afi].export_vrf = list_new();
}
if (name) {
bgp->name = XSTRDUP(MTYPE_BGP, name);
Expand Down Expand Up @@ -7194,6 +7197,16 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,

vty_out(vty, " import vpn\n");
}
if (CHECK_FLAG(bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
struct listnode *node;
char *name;

for (ALL_LIST_ELEMENTS_RO(
bgp->vpn_policy[afi].import_vrf, node,
name))
vty_out(vty, " import vrf %s\n", name);
}
}

vty_endframe(vty, " exit-address-family\n");
Expand Down
6 changes: 6 additions & 0 deletions bgpd/bgpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ struct vpn_policy {
#define BGP_VPN_POLICY_TOVPN_LABEL_AUTO (1 << 0)
#define BGP_VPN_POLICY_TOVPN_RD_SET (1 << 1)
#define BGP_VPN_POLICY_TOVPN_NEXTHOP_SET (1 << 2)

/* If we are importing a vrf -> vrf keep a list of vrf names */
struct list *import_vrf;
struct list *export_vrf;
};

/*
Expand Down Expand Up @@ -345,6 +349,8 @@ struct bgp {
#define BGP_CONFIG_DAMPENING (1 << 0)
#define BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT (1 << 1)
#define BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT (1 << 2)
#define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 3)
#define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 4)

/* l2vpn evpn flags - 1 << 0 is used for DAMPENNG */
#define BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST (1 << 1)
Expand Down

0 comments on commit 12a844a

Please sign in to comment.