bgpd: import/unimport vrf routes upon l3vni change

Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
This commit is contained in:
Mitesh Kanjariya 2017-10-13 04:10:03 -07:00
parent 2dbad57fc6
commit 5ba238b74a

View File

@ -635,7 +635,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr)
/* Add the export RTs for L3VNI */
vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn);
if (vrf_export_rtl) {
if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode, ecom))
attr->ecommunity = ecommunity_merge(attr->ecommunity,
ecom);
@ -1584,6 +1584,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
}
/* Perform route selection and update zebra, if required. */
//TODO_MITESH: callbgp process instead
ret = evpn_vrf_route_select_install(bgp_vrf, rn, pp, afi, safi);
return ret;
@ -1749,6 +1750,73 @@ static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
return ret;
}
/*
* Given a route entry and a VRF, see if this route entry should be
* imported into the VRF i.e., RTs match.
*/
static int is_route_matching_for_vrf(struct bgp *bgp_vrf,
struct bgp_info *ri)
{
struct attr *attr = ri->attr;
struct ecommunity *ecom;
int i;
assert(attr);
/* Route should have valid RT to be even considered. */
if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
return 0;
ecom = attr->ecommunity;
if (!ecom || !ecom->size)
return 0;
/* For each extended community RT, see if it matches this VNI. If any RT
* matches, we're done.
*/
for (i = 0; i < ecom->size; i++) {
u_char *pnt;
u_char type, sub_type;
struct ecommunity_val *eval;
struct ecommunity_val eval_tmp;
struct vrf_irt_node *irt;
/* Only deal with RTs */
pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
eval = (struct ecommunity_val *)(ecom->val
+ (i * ECOMMUNITY_SIZE));
type = *pnt++;
sub_type = *pnt++;
if (sub_type != ECOMMUNITY_ROUTE_TARGET)
continue;
/* See if this RT matches specified VNIs import RTs */
irt = lookup_vrf_import_rt(eval);
if (irt && irt->vrfs)
if (is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
return 1;
/* Also check for non-exact match. In this, we mask out the AS
* and
* only check on the local-admin sub-field. This is to
* facilitate using
* VNI as the RT for EBGP peering too.
*/
irt = NULL;
if (type == ECOMMUNITY_ENCODE_AS
|| type == ECOMMUNITY_ENCODE_AS4
|| type == ECOMMUNITY_ENCODE_IP) {
memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
mask_ecom_global_admin(&eval_tmp, eval);
irt = lookup_vrf_import_rt(&eval_tmp);
}
if (irt && irt->vrfs)
if (is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
return 1;
}
return 0;
}
/*
* Given a route entry and a VNI, see if this route entry should be
* imported into the VNI i.e., RTs match.
@ -1816,6 +1884,80 @@ static int is_route_matching_for_vni(struct bgp *bgp, struct bgpevpn *vpn,
return 0;
}
/*
* Install or uninstall mac-ip routes are appropriate for this
* particular VRF.
*/
static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf,
int install)
{
afi_t afi;
safi_t safi;
struct bgp_node *rd_rn, *rn;
struct bgp_table *table;
struct bgp_info *ri;
int ret;
char buf[PREFIX_STRLEN];
struct bgp *bgp_def = NULL;
afi = AFI_L2VPN;
safi = SAFI_EVPN;
bgp_def = bgp_get_default();
if (!bgp_def)
return -1;
/* Walk entire global routing table and evaluate routes which could be
* imported into this VRF. Note that we need to loop through all global
* routes to determine which route matches the import rt on vrf
*/
for (rd_rn = bgp_table_top(bgp_def->rib[afi][safi]); rd_rn;
rd_rn = bgp_route_next(rd_rn)) {
table = (struct bgp_table *)(rd_rn->info);
if (!table)
continue;
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
continue;
for (ri = rn->info; ri; ri = ri->next) {
/* Consider "valid" remote routes applicable for
* this VRF. */
if (!(CHECK_FLAG(ri->flags, BGP_INFO_VALID)
&& ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_NORMAL))
continue;
if (is_route_matching_for_vrf(bgp_vrf, ri)) {
if (install)
ret =
install_evpn_route_entry_in_vrf(
bgp_vrf, evp, ri);
else
ret =
uninstall_evpn_route_entry_in_vrf(
bgp_vrf, evp, ri);
if (ret) {
zlog_err(
"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;
}
}
}
}
}
return 0;
}
/*
* Install or uninstall routes of specified type that are appropriate for this
* particular VNI.
@ -1890,6 +2032,14 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp,
return 0;
}
/* Install any existing remote routes applicable for this VRF into VRF RIB. This
* is invoked upon l3vni-add or l3vni import rt change */
static int install_routes_for_vrf(struct bgp *bgp_vrf)
{
install_uninstall_routes_for_vrf(bgp_vrf, 1);
return 0;
}
/*
* Install any existing remote routes applicable for this VNI into its
* routing table. This is invoked when a VNI becomes "live" or its Import
@ -1911,6 +2061,13 @@ static int install_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
1);
}
/* uninstall routes from l3vni vrf. */
static int uninstall_routes_for_vrf(struct bgp *bgp_vrf)
{
install_uninstall_routes_for_vrf(bgp_vrf, 0);
return 0;
}
/*
* Uninstall any existing remote routes for this VNI. One scenario in which
* this is invoked is upon an import RT change.
@ -2673,7 +2830,8 @@ void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni,
void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomadd)
{
//TODO_MITESH: uninstall routes from VRF
/* uninstall routes from vrf */
uninstall_routes_for_vrf(bgp_vrf);
/* Cleanup the RT to VRF mapping */
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
@ -2688,7 +2846,8 @@ void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
/* map VRF to its RTs */
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
//TODO_MITESH: install routes matching the new VRF
/* install routes matching the new VRF */
install_routes_for_vrf(bgp_vrf);
}
void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
@ -2697,7 +2856,8 @@ void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
struct ecommunity *ecom = NULL;
//TODO_MITESH: uninstall routes from VRF
/* uninstall routes from vrf */
uninstall_routes_for_vrf(bgp_vrf);
/* Cleanup the RT to VRF mapping */
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
@ -2723,7 +2883,8 @@ void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
/* map VRFs to its RTs */
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
//TODO_MITESH: install routes matching this new RT
/* install routes matching this new RT */
install_routes_for_vrf(bgp_vrf);
}
void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
@ -3571,7 +3732,9 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni,
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
update_routes_for_vni(bgp_def, vpn);
//TODO_MITESH: import all the remote routes to VRF
/* install all remote routes belonging to this l3vni into correspondng
* vrf */
install_routes_for_vrf(bgp_vrf);
return 0;
}
@ -3598,6 +3761,9 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni,
return -1;
}
/* unimport remote routes from VRF */
uninstall_routes_for_vrf(bgp_vrf);
/* remove the l3vni from vrf instance */
bgp_vrf->l3vni = 0;
@ -3607,19 +3773,16 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni,
/* delete RD/RT */
if (bgp_vrf->vrf_import_rtl && !list_isempty(bgp_vrf->vrf_import_rtl)) {
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
list_delete(bgp_vrf->vrf_import_rtl);
bgp_vrf->vrf_import_rtl = NULL;
list_delete_all_node(bgp_vrf->vrf_import_rtl);
}
if (bgp_vrf->vrf_export_rtl && !list_isempty(bgp_vrf->vrf_export_rtl)) {
list_delete(bgp_vrf->vrf_export_rtl);
bgp_vrf->vrf_export_rtl = NULL;
list_delete_all_node(bgp_vrf->vrf_export_rtl);
}
/* update all corresponding local mac-ip routes */
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
update_routes_for_vni(bgp_def, vpn);
/* TODO_MITESH: unimport remote routes from VRF */
/* Delete the instance if it was autocreated */
if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))