Skip to content

Commit

Permalink
bgpd: allow routes to be imported if the ES/ES-VRF is not present
Browse files Browse the repository at this point in the history
In a sym-IRB setup the remote ES may not be installed if the tenant
VRF is not present locally. To allow that case while retaining the
fast-failover benefits for the case where the tenant VRF is locally
present we use the following approach -
1. If ES is present in the tenant VRF we use the L3NHG for installing
the MAC-IP based tenant route. This allows for efficient failover via
L3NHG updates.
2. If the ES is not present locally in the corresponding tenant VRF we
fall back to a non-NHG multi-path based routing approach. In this
case individual routes are updated when the ES links flap.

PS: #1 can be turned off entirely by disabling use-l3-nhg in BGP.

Ticket: CM-30935

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
  • Loading branch information
AnuradhaKaruppiah committed Mar 26, 2021
1 parent 7052409 commit 36dd457
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 26 deletions.
23 changes: 13 additions & 10 deletions bgpd/bgp_evpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -2852,7 +2852,8 @@ static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,

/* don't import hosts that are locally attached */
static inline bool
bgp_evpn_skip_vrf_import_of_local_es(const struct prefix_evpn *evp,
bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf,
const struct prefix_evpn *evp,
struct bgp_path_info *pi, int install)
{
esi_t *esi;
Expand All @@ -2875,19 +2876,20 @@ bgp_evpn_skip_vrf_import_of_local_es(const struct prefix_evpn *evp,
return true;
}

/* Don't import routes with ES as destination if the nexthop
* has not been advertised via the EAD-ES
/* 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;
else
nh.s_addr = INADDR_ANY;
if (install && !bgp_evpn_es_is_vtep_active(esi, nh)) {
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];

zlog_debug(
"vrf %s of evpn prefix %pFX skipped, nh %pI4 inactive in es %s",
"vrf %s %s of evpn prefix %pFX skipped, nh %pI4 inactive in es %s",
bgp_vrf->name,
install ? "import" : "unimport", evp,
&nh,
esi_to_str(esi, esi_buf,
Expand Down Expand Up @@ -2959,7 +2961,7 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
/* don't import hosts that are locally attached
*/
if (bgp_evpn_skip_vrf_import_of_local_es(
evp, pi, install))
bgp_vrf, evp, pi, install))
continue;

if (is_route_matching_for_vrf(bgp_vrf, pi)) {
Expand Down Expand Up @@ -3168,13 +3170,14 @@ static int install_uninstall_route_in_vrfs(struct bgp *bgp_def, afi_t afi,
|| is_evpn_prefix_ipaddr_v6(evp)))
return 0;

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

for (ALL_LIST_ELEMENTS(vrfs, node, nnode, bgp_vrf)) {
int ret;

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

if (install)
ret = install_evpn_route_entry_in_vrf(bgp_vrf, evp, pi);
else
Expand Down
83 changes: 67 additions & 16 deletions bgpd/bgp_evpn_mh.c
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,15 @@ void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi)
listnode_add(es->macip_path_list, &es_info->es_listnode);
}

/* XXX - When a remote ES is added to a VRF, routes using that as
* a destination need to be migrated to a L2NHG and viceversa
*/
static void
bgp_evpn_es_path_update_on_es_vrf_chg(struct bgp_evpn_es_vrf *es_vrf,
bool active)
{
}

static void
bgp_evpn_es_path_update_on_vtep_chg(struct bgp_evpn_es_vtep *es_vtep,
bool active)
Expand All @@ -1499,6 +1508,9 @@ bgp_evpn_es_path_update_on_vtep_chg(struct bgp_evpn_es_vtep *es_vtep,
struct bgp_path_info *parent_pi;
struct bgp_evpn_es *es = es_vtep->es;

if (!bgp_mh_info->host_routes_use_l3nhg)
return;

if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("update paths linked to es %s on vtep chg",
es->esi_str);
Expand Down Expand Up @@ -1714,7 +1726,7 @@ static void bgp_evpn_mac_update_on_es_oper_chg(struct bgp_evpn_es *es)
continue;

if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("update path %s linked to es %s on vtep chg",
zlog_debug("update path %s linked to es %s on oper chg",
prefix2str(&pi->net->p, prefix_buf,
sizeof(prefix_buf)),
es->esi_str);
Expand Down Expand Up @@ -2546,6 +2558,11 @@ static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_create(struct bgp_evpn_es *es,
bgp_vrf->vrf_id, es_vrf->nhg_id, es_vrf->v6_nhg_id);
bgp_evpn_l3nhg_activate(es_vrf, false /* update */);

/* update paths in the VRF that may already be associated with
* this destination ES
*/
bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, true);

return es_vrf;
}

Expand All @@ -2559,6 +2576,11 @@ static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf *es_vrf)
zlog_debug("es %s vrf %u nhg %u delete", es->esi_str,
bgp_vrf->vrf_id, es_vrf->nhg_id);

/* update paths in the VRF that may already be associated with
* this destination ES
*/
bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, false);

/* Remove the NHG resources */
bgp_evpn_l3nhg_deactivate(es_vrf);
if (es_vrf->nhg_id)
Expand Down Expand Up @@ -2656,24 +2678,54 @@ void bgp_evpn_es_evi_vrf_ref(struct bgpevpn *vpn)
bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf);
}

static bool bgp_evpn_es_vrf_use_nhg(struct bgp *bgp_vrf, esi_t *esi,
struct bgp_evpn_es **es_p,
struct bgp_evpn_es_vrf **es_vrf_p)
{
struct bgp_evpn_es *es;
struct bgp_evpn_es_vrf *es_vrf;

if (!bgp_mh_info->host_routes_use_l3nhg)
return false;

es = bgp_evpn_es_find(esi);
if (!es)
return false;
if (es_p)
*es_p = es;

es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf);
if (!es_vrf)
return false;
if (es_vrf_p)
*es_vrf_p = es_vrf;

return true;
}

bool bgp_evpn_es_vrf_import_ok(struct bgp *bgp_vrf, esi_t *esi,
struct in_addr nh)
{
if (!bgp_evpn_es_vrf_use_nhg(bgp_vrf, esi, NULL, NULL))
return true;

return bgp_evpn_es_is_vtep_active(esi, nh);
}

/* returns false if legacy-exploded mp needs to be used for route install */
bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
uint32_t *nhg_p)
{
esi_t *esi;
struct bgp_evpn_es *es;
struct bgp_evpn_es_vrf *es_vrf;
struct bgp_evpn_es *es = NULL;
struct bgp_evpn_es_vrf *es_vrf = NULL;
struct bgp_path_info *parent_pi;
struct bgp_node *rn;
struct prefix_evpn *evp;
struct bgp_path_info *mpinfo;

*nhg_p = 0;

/* L3NHG support is disabled, use legacy-exploded multipath */
if (!bgp_mh_info->host_routes_use_l3nhg)
return false;

parent_pi = get_route_parent_evpn(pi);
if (!parent_pi)
return false;
Expand All @@ -2691,15 +2743,14 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
if (!memcmp(esi, zero_esi, sizeof(*esi)))
return false;

/* if the ES-VRF is not setup or if the NHG has not been installed
* we cannot install the route yet, return a 0-NHG to indicate
* that
/* L3NHG support is disabled, use legacy-exploded multipath */
if (!bgp_evpn_es_vrf_use_nhg(bgp_vrf, esi, &es, &es_vrf))
return false;

/* if the NHG has not been installed we cannot install the route yet,
* return a 0-NHG to indicate that
*/
es = bgp_evpn_es_find(esi);
if (!es)
return true;
es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf);
if (!es_vrf || !(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
if (!(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
return true;

/* this needs to be set the v6NHG if v6route */
Expand All @@ -2710,7 +2761,7 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,

for (mpinfo = bgp_path_info_mpath_next(pi); mpinfo;
mpinfo = bgp_path_info_mpath_next(mpinfo)) {
/* if any of the paths of have a different ESI we can't use
/* if any of the paths have a different ESI we can't use
* the NHG associated with the ES. fallback to legacy-exploded
* multipath
*/
Expand Down
2 changes: 2 additions & 0 deletions bgpd/bgp_evpn_mh.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,5 +389,7 @@ extern void bgp_evpn_es_vrf_show(struct vty *vty, bool uj,
extern void bgp_evpn_es_vrf_show_esi(struct vty *vty, esi_t *esi, bool uj);
extern void bgp_evpn_switch_ead_evi_rx(void);
extern bool bgp_evpn_es_add_l3_ecomm_ok(esi_t *esi);
extern bool bgp_evpn_es_vrf_import_ok(struct bgp *bgp_vrf, esi_t *esi,
struct in_addr nh);

#endif /* _FRR_BGP_EVPN_MH_H */

0 comments on commit 36dd457

Please sign in to comment.