Skip to content

Commit

Permalink
zebra, bgp: Support type-5 routes with asymmetric routing
Browse files Browse the repository at this point in the history
Asymmetric routing is an ideal choice when all VLANs are cfged on all leafs.
It simplifies the routing configuration and
eliminates potential need for advertising subnet routes.
However, we need to reach the Internet or global destinations
or to do subnet-based routing between PODs or DCs.
This requires EVPN type-5 routes but those routes require L3 VNI configuration.

This task is to support EVPN type-5 routes for prefix-based routing in
conjunction with asymmetric routing within the POD/DC.
It is done by providing an option to use the L3 VNI only for prefix routes,
so that type-2 routes (host routes) will only use the L2 VNI.

Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
  • Loading branch information
Mitesh Kanjariya authored and mkanjari committed Feb 9, 2018
1 parent b2a7089 commit 235a907
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 41 deletions.
66 changes: 53 additions & 13 deletions bgpd/bgp_evpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -666,10 +666,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom))
attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);

/* Add the export RTs for L3VNI - currently only supported for IPV4 host
* routes
/*
* only attach l3-vni export rts for ipv4 address family and if we are
* advertising both the labels in type-2 routes
*/
if (afi == AFI_IP) {
if (afi == AFI_IP && CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn);
if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode,
Expand All @@ -690,7 +691,12 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
ecommunity_merge(attr->ecommunity, &ecom_sticky);
}

if (afi == AFI_IP && !is_zero_mac(&attr->rmac)) {
/*
* only attach l3-vni rmac for ipv4 address family and if we are
* advertising both the labels in type-2 routes
*/
if (afi == AFI_IP && !is_zero_mac(&attr->rmac) &&
CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
memset(&ecom_rmac, 0, sizeof(ecom_rmac));
encode_rmac_extcomm(&eval_rmac, &attr->rmac);
ecom_rmac.size = 1;
Expand Down Expand Up @@ -1189,8 +1195,13 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,

/* The VNI goes into the 'label' field of the route */
vni2label(vpn->vni, &label[0]);
/* Type-2 routes may carry a second VNI - the L3-VNI */
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {

/* Type-2 routes may carry a second VNI - the L3-VNI.
* Only attach second label if we are advertising two labels for
* type-2 routes.
*/
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
vni_t l3vni;

l3vni = bgpevpn_get_l3vni(vpn);
Expand All @@ -1209,6 +1220,24 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
&& !CHECK_FLAG(tmp_ri->flags, BGP_INFO_REMOVED))
route_change = 0;
else {
/*
* The attributes have changed, type-2 routes needs to
* be advertised with right labels.
*/
vni2label(vpn->vni, &label[0]);
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
vni_t l3vni;

l3vni = bgpevpn_get_l3vni(vpn);
if (l3vni) {
vni2label(l3vni, &label[1]);
num_labels++;
}
}
memcpy(&tmp_ri->extra->label, label, sizeof(label));
tmp_ri->extra->num_labels = num_labels;

/* The attribute has changed. */
/* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(attr);
Expand Down Expand Up @@ -4214,7 +4243,8 @@ static void link_l2vni_hash_to_l3vni(struct hash_backet *backet,
int bgp_evpn_local_l3vni_add(vni_t l3vni,
vrf_id_t vrf_id,
struct ethaddr *rmac,
struct in_addr originator_ip)
struct in_addr originator_ip,
int filter)
{
struct bgp *bgp_vrf = NULL; /* bgp VRF instance */
struct bgp *bgp_def = NULL; /* default bgp instance */
Expand Down Expand Up @@ -4266,6 +4296,10 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni,
/* set the originator ip */
bgp_vrf->originator_ip = originator_ip;

/* set the right filter - are we using l3vni only for prefix routes? */
if (filter)
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY);

/* auto derive RD/RT */
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
evpn_auto_rt_import_add_for_vrf(bgp_vrf);
Expand All @@ -4279,9 +4313,12 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni,
link_l2vni_hash_to_l3vni,
bgp_vrf);

/* updates all corresponding local mac-ip routes */
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
update_routes_for_vni(bgp_def, vpn);
/* Only update all corresponding type-2 routes if we are advertising two
* labels along with type-2 routes
*/
if (!filter)
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
update_routes_for_vni(bgp_def, vpn);

/* advertise type-5 routes if needed */
update_advertise_vrf_routes(bgp_vrf);
Expand Down Expand Up @@ -4340,9 +4377,12 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni,
}

/* update all corresponding local mac-ip routes */
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
update_routes_for_vni(bgp_def, vpn);

if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY)) {
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn)) {
UNSET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);
update_routes_for_vni(bgp_def, vpn);
}
}

/* Delete the instance if it was autocreated */
if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
Expand Down
3 changes: 2 additions & 1 deletion bgpd/bgp_evpn.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
u_char flags);
extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id,
struct ethaddr *rmac,
struct in_addr originator_ip);
struct in_addr originator_ip,
int filter);
extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id);
extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
Expand Down
21 changes: 17 additions & 4 deletions bgpd/bgp_evpn_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ struct bgpevpn {
#define VNI_FLAG_RD_CFGD 0x4 /* RD is user configured. */
#define VNI_FLAG_IMPRT_CFGD 0x8 /* Import RT is user configured */
#define VNI_FLAG_EXPRT_CFGD 0x10 /* Export RT is user configured */
#define VNI_FLAG_USE_TWO_LABELS 0x20 /* Attach both L2-VNI and L3-VNI if
needed for this VPN */

/* Flag to indicate if we are advertising the g/w mac ip for this VNI*/
u_int8_t advertise_gw_macip;
Expand Down Expand Up @@ -179,19 +181,30 @@ static inline void bgpevpn_unlink_from_l3vni(struct bgpevpn *vpn)
struct bgp *bgp_vrf = NULL;

bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
if (!bgp_vrf || !bgp_vrf->l2vnis)
if (!bgp_vrf)
return;
listnode_delete(bgp_vrf->l2vnis, vpn);

UNSET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);

if (bgp_vrf->l2vnis)
listnode_delete(bgp_vrf->l2vnis, vpn);
}

static inline void bgpevpn_link_to_l3vni(struct bgpevpn *vpn)
{
struct bgp *bgp_vrf = NULL;

bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
if (!bgp_vrf || !bgp_vrf->l2vnis)
if (!bgp_vrf)
return;
listnode_add_sort(bgp_vrf->l2vnis, vpn);

/* check if we are advertising two labels for this vpn */
if (!CHECK_FLAG(bgp_vrf->vrf_flags,
BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY))
SET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);

if (bgp_vrf->l2vnis)
listnode_add_sort(bgp_vrf->l2vnis, vpn);
}

static inline int is_vni_configured(struct bgpevpn *vpn)
Expand Down
15 changes: 15 additions & 0 deletions bgpd/bgp_evpn_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,10 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
inet_ntoa(vpn->originator_ip));
json_object_string_add(json, "advertiseGatewayMacip",
vpn->advertise_gw_macip ? "Yes" : "No");
json_object_int_add(json, "numAdvLabels",
CHECK_FLAG(vpn->flags,
VNI_FLAG_USE_TWO_LABELS) ?
BGP_MAX_LABELS : BGP_MAX_LABELS - 1);
} else {
vty_out(vty, "VNI: %d", vpn->vni);
if (is_vni_live(vpn))
Expand All @@ -451,6 +455,9 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
inet_ntoa(vpn->originator_ip));
vty_out(vty, " Advertise-gw-macip : %s\n",
vpn->advertise_gw_macip ? "Yes" : "No");
vty_out(vty, " Number of advertised labels %d\n",
CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS) ?
BGP_MAX_LABELS : BGP_MAX_LABELS - 1);
}

if (!json)
Expand Down Expand Up @@ -3897,6 +3904,10 @@ DEFUN (show_bgp_vrf_l3vni_info,
vty_out(vty, " L3-VNI: %u\n", bgp->l3vni);
vty_out(vty, " Rmac: %s\n",
prefix_mac2str(&bgp->rmac, buf, sizeof(buf)));
vty_out(vty, " VNI Filter: %s\n",
CHECK_FLAG(bgp->vrf_flags,
BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY) ?
"prefix-routes-only" : "none");
vty_out(vty, " L2-VNI List:\n");
vty_out(vty, " ");
for (ALL_LIST_ELEMENTS_RO(bgp->l2vnis, node, vpn))
Expand All @@ -3922,6 +3933,10 @@ DEFUN (show_bgp_vrf_l3vni_info,
json_object_string_add(json, "rmac",
prefix_mac2str(&bgp->rmac, buf,
sizeof(buf)));
json_object_string_add(json, "vniFilter",
CHECK_FLAG(bgp->vrf_flags,
BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY)
? "prefix-routes-only" : "none");
/* list of l2vnis */
for (ALL_LIST_ELEMENTS_RO(bgp->l2vnis, node, vpn))
json_object_array_add(json_vnis,
Expand Down
10 changes: 7 additions & 3 deletions bgpd/bgp_zebra.c
Original file line number Diff line number Diff line change
Expand Up @@ -1731,6 +1731,7 @@ static void bgp_zebra_connected(struct zclient *zclient)
static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
int filter = 0;
char buf[ETHER_ADDR_STRLEN];
vni_t l3vni = 0;
struct ethaddr rmac;
Expand All @@ -1744,17 +1745,20 @@ static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient,
if (cmd == ZEBRA_L3VNI_ADD) {
stream_get(&rmac, s, sizeof(struct ethaddr));
originator_ip.s_addr = stream_get_ipv4(s);
stream_get(&filter, s, sizeof(int));
}

if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx L3-VNI %s VRF %s VNI %u RMAC %s",
zlog_debug("Rx L3-VNI %s VRF %s VNI %u RMAC %s filter %s",
(cmd == ZEBRA_L3VNI_ADD) ? "add" : "del",
vrf_id_to_name(vrf_id),
l3vni,
prefix_mac2str(&rmac, buf, sizeof(buf)));
prefix_mac2str(&rmac, buf, sizeof(buf)),
filter ? "prefix-routes-only" : "none");

if (cmd == ZEBRA_L3VNI_ADD)
bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip);
bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip,
filter);
else
bgp_evpn_local_l3vni_del(l3vni, vrf_id);

Expand Down
1 change: 1 addition & 0 deletions bgpd/bgpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ struct bgp {
#define BGP_VRF_IMPORT_RT_CFGD (1 << 3)
#define BGP_VRF_EXPORT_RT_CFGD (1 << 4)
#define BGP_VRF_RD_CFGD (1 << 5)
#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 6)

/* unique ID for auto derivation of RD for this vrf */
uint16_t vrf_rd_id;
Expand Down
5 changes: 4 additions & 1 deletion zebra/zebra_vrf.c
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,10 @@ static int vrf_config_write(struct vty *vty)
if (vrf_is_user_cfged(vrf)) {
vty_out(vty, "vrf %s\n", zvrf_name(zvrf));
if (zvrf->l3vni)
vty_out(vty, " vni %u\n", zvrf->l3vni);
vty_out(vty, " vni %u%s\n",
zvrf->l3vni,
is_l3vni_for_prefix_routes_only(zvrf->l3vni) ?
" prefix-routes-only" :"");
vty_out(vty, "!\n");
}

Expand Down
28 changes: 20 additions & 8 deletions zebra/zebra_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -2338,20 +2338,26 @@ DEFUN (show_vrf,

DEFUN (default_vrf_vni_mapping,
default_vrf_vni_mapping_cmd,
"vni " CMD_VNI_RANGE,
"vni " CMD_VNI_RANGE "[prefix-routes-only]",
"VNI corresponding to the DEFAULT VRF\n"
"VNI-ID\n")
"VNI-ID\n"
"Prefix routes only \n")
{
int ret = 0;
char err[ERR_STR_SZ];
struct zebra_vrf *zvrf = NULL;
vni_t vni = strtoul(argv[1]->arg, NULL, 10);
int filter = 0;

zvrf = vrf_info_lookup(VRF_DEFAULT);
if (!zvrf)
return CMD_WARNING;

ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 1);
if (argc == 3)
filter = 1;

ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ,
filter, 1);
if (ret != 0) {
vty_out(vty, "%s\n", err);
return CMD_WARNING;
Expand All @@ -2376,7 +2382,7 @@ DEFUN (no_default_vrf_vni_mapping,
if (!zvrf)
return CMD_WARNING;

ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0);
ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0, 0);
if (ret != 0) {
vty_out(vty, "%s\n", err);
return CMD_WARNING;
Expand All @@ -2387,11 +2393,13 @@ DEFUN (no_default_vrf_vni_mapping,

DEFUN (vrf_vni_mapping,
vrf_vni_mapping_cmd,
"vni " CMD_VNI_RANGE,
"vni " CMD_VNI_RANGE "[prefix-routes-only]",
"VNI corresponding to tenant VRF\n"
"VNI-ID\n")
"VNI-ID\n"
"prefix-routes-only\n")
{
int ret = 0;
int filter = 0;

ZEBRA_DECLVAR_CONTEXT(vrf, zvrf);
vni_t vni = strtoul(argv[1]->arg, NULL, 10);
Expand All @@ -2400,9 +2408,13 @@ DEFUN (vrf_vni_mapping,
assert(vrf);
assert(zvrf);

if (argc == 3)
filter = 1;

/* Mark as having FRR configuration */
vrf_set_user_cfged(vrf);
ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 1);
ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ,
filter, 1);
if (ret != 0) {
vty_out(vty, "%s\n", err);
return CMD_WARNING;
Expand All @@ -2427,7 +2439,7 @@ DEFUN (no_vrf_vni_mapping,
assert(vrf);
assert(zvrf);

ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0);
ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0, 0);
if (ret != 0) {
vty_out(vty, "%s\n", err);
return CMD_WARNING;
Expand Down
Loading

0 comments on commit 235a907

Please sign in to comment.