Skip to content

Commit

Permalink
bgpd: re-eval use-l3nhg when a remote ES is [de]activated in a VRF
Browse files Browse the repository at this point in the history
There are two changes in this commit -

1. Maintain a list of global MAC-IP routes per-ES. This list is maintained
for quick processing on the following events -
a. When the first VTEP/PE becomes active in the ES-VRF, the L3 NHG is
activated and the route can be sent to zebra.
b. When there are no active PEs in the ES-VRF the L3 NHG is
de-activated and -
- If the ES is present in the VRF -
The route is not installed in zebra as there are no active PEs for
the ES-VRF
- If the ES is not present in the VRF -
The route is installed with a flat multi-path list i.e. without L3NHG.
This is to handle the case where there are no locally attached L2VNIs
on the ES (for that tenant VRF).

2. Reinstall VRF route when an ES is installed or uninstalled in a
tenant VRF (the global MAC-IP list in #1 is used for this purpose also).
If an ES is present in the VRF we use L3NHG to enable fast-failover of
routed traffic.

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
  • Loading branch information
AnuradhaKaruppiah committed Aug 28, 2020
1 parent e3aa457 commit 1842507
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 171 deletions.
9 changes: 9 additions & 0 deletions bgpd/bgp_attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,15 @@ struct attr {
*/
#define ATTR_ES_PEER_ROUTER (1 << 4)

/* These two flags are only set on L3 routes installed in a
* VRF as a result of EVPN MAC-IP route
* XXX - while splitting up per-family attrs these need to be
* classified as non-EVPN
*/
#define ATTR_ES_L3_NHG_USE (1 << 5)
#define ATTR_ES_L3_NHG_ACTIVE (1 << 6)
#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE)

/* route tag */
route_tag_t tag;

Expand Down
136 changes: 66 additions & 70 deletions bgpd/bgp_evpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1596,8 +1596,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
}
}

/* MAC-IP routes in the VNI route table are linked to the
* destination ES
/* local MAC-IP routes in the VNI table are linked to
* the destination ES
*/
if (route_change && vpn_rt &&
(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE))
Expand Down Expand Up @@ -2377,6 +2377,8 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
safi_t safi = 0;
char buf[PREFIX_STRLEN];
bool new_pi = false;
bool use_l3nhg = false;
bool is_l3nhg_active = false;

memset(pp, 0, sizeof(struct prefix));
ip_prefix_from_evpn_prefix(evp, pp);
Expand Down Expand Up @@ -2414,6 +2416,13 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
else
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);

bgp_evpn_es_vrf_use_nhg(bgp_vrf, &parent_pi->attr->esi, &use_l3nhg,
&is_l3nhg_active, NULL);
if (use_l3nhg)
attr.es_flags |= ATTR_ES_L3_NHG_USE;
if (is_l3nhg_active)
attr.es_flags |= ATTR_ES_L3_NHG_ACTIVE;

/* Check if route entry is already present. */
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next)
if (pi->extra
Expand Down Expand Up @@ -2535,11 +2544,6 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
pi->uptime = bgp_clock();
}

/* MAC-IP routes in the VNI table are linked to the destination ES */
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
bgp_evpn_path_es_link(pi, vpn->vni,
bgp_evpn_attr_get_esi(pi->attr));

/* Perform route selection and update zebra, if required. */
ret = evpn_route_select_install(bgp, vpn, rn);

Expand Down Expand Up @@ -2867,7 +2871,6 @@ bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf,
struct bgp_path_info *pi, int install)
{
esi_t *esi;
struct in_addr nh;

if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
esi = bgp_evpn_attr_get_esi(pi->attr);
Expand All @@ -2887,33 +2890,54 @@ bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf,
}
return true;
}
}
return false;
}

/* Don't import routes with ES as destination if L3NHG is in
* use and the nexthop has not been advertised via the EAD-ES
*/
if (pi->attr)
nh = pi->attr->nexthop;
/*
* Install or uninstall a mac-ip route in the provided vrf if
* there is a rt match
*/
int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf,
struct bgp_path_info *pi,
int install)
{
int ret = 0;
char buf[PREFIX_STRLEN];
const struct prefix_evpn *evp =
(const struct prefix_evpn *)bgp_node_get_prefix(pi->net);

/* Consider "valid" remote routes applicable for
* this VRF.
*/
if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID)
&& pi->type == ZEBRA_ROUTE_BGP
&& pi->sub_type == BGP_ROUTE_NORMAL))
return 0;

/* don't import hosts that are locally attached */
if (bgp_evpn_skip_vrf_import_of_local_es(bgp_vrf, evp, pi, install))
return 0;

if (is_route_matching_for_vrf(bgp_vrf, pi)) {
if (bgp_evpn_route_rmac_self_check(bgp_vrf, evp, pi))
return 0;

if (install)
ret = install_evpn_route_entry_in_vrf(bgp_vrf, evp, pi);
else
nh.s_addr = 0;
if (install && !bgp_evpn_es_vrf_import_ok(bgp_vrf, esi, nh)) {
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) {
char esi_buf[ESI_STR_LEN];
char prefix_buf[PREFIX_STRLEN];
ret = uninstall_evpn_route_entry_in_vrf(bgp_vrf, evp,
pi);

zlog_debug(
"vrf %s %s of evpn prefix %s skipped, nh %s inactive in es %s",
bgp_vrf->name,
install ? "import" : "unimport",
prefix2str(evp, prefix_buf,
sizeof(prefix_buf)),
inet_ntoa(nh),
esi_to_str(esi, esi_buf,
sizeof(esi_buf)));
}
return true;
}
if (ret)
flog_err(EC_BGP_EVPN_FAIL,
"Failed to %s EVPN %s route in VRF %s",
install ? "install" : "uninstall",
prefix2str(evp, buf, sizeof(buf)),
vrf_id_to_name(bgp_vrf->vrf_id));
}
return false;

return ret;
}

/*
Expand All @@ -2928,7 +2952,6 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
struct bgp_table *table;
struct bgp_path_info *pi;
int ret;
char buf[PREFIX_STRLEN];
struct bgp *bgp_evpn = NULL;

afi = AFI_L2VPN;
Expand Down Expand Up @@ -2963,44 +2986,10 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)

for (pi = bgp_node_get_bgp_path_info(rn); pi;
pi = pi->next) {
/* Consider "valid" remote routes applicable for
* this VRF.
*/
if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID)
&& pi->type == ZEBRA_ROUTE_BGP
&& pi->sub_type == BGP_ROUTE_NORMAL))
continue;

/* don't import hosts that are locally attached */
if (bgp_evpn_skip_vrf_import_of_local_es(
bgp_vrf, evp, pi, install))
continue;

if (is_route_matching_for_vrf(bgp_vrf, pi)) {
if (bgp_evpn_route_rmac_self_check(
bgp_vrf, evp, pi))
continue;

if (install)
ret = install_evpn_route_entry_in_vrf(
bgp_vrf, evp, pi);
else
ret = uninstall_evpn_route_entry_in_vrf(
bgp_vrf, evp, pi);

if (ret) {
flog_err(
EC_BGP_EVPN_FAIL,
"Failed to %s EVPN %s route in VRF %s",
install ? "install"
: "uninstall",
prefix2str(evp, buf,
sizeof(buf)),
vrf_id_to_name(
bgp_vrf->vrf_id));
return ret;
}
}
ret = bgp_evpn_route_entry_install_if_vrf_match(
bgp_vrf, pi, install);
if (ret)
return ret;
}
}
}
Expand Down Expand Up @@ -3303,6 +3292,13 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
if (sub_type != ECOMMUNITY_ROUTE_TARGET)
continue;

/* non-local MAC-IP routes in the global route table are linked
* to the destination ES
*/
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
bgp_evpn_path_es_link(pi, 0,
bgp_evpn_attr_get_esi(pi->attr));

/*
* macip routes (type-2) are imported into VNI and VRF tables.
* IMET route is imported into VNI table.
Expand Down
Loading

0 comments on commit 1842507

Please sign in to comment.