mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-11 13:12:28 +00:00
bgpd: import/unimport vrf routes upon l3vni change
Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
This commit is contained in:
parent
2dbad57fc6
commit
5ba238b74a
185
bgpd/bgp_evpn.c
185
bgpd/bgp_evpn.c
@ -635,7 +635,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr)
|
|||||||
|
|
||||||
/* Add the export RTs for L3VNI */
|
/* Add the export RTs for L3VNI */
|
||||||
vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn);
|
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))
|
for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode, ecom))
|
||||||
attr->ecommunity = ecommunity_merge(attr->ecommunity,
|
attr->ecommunity = ecommunity_merge(attr->ecommunity,
|
||||||
ecom);
|
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. */
|
/* 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);
|
ret = evpn_vrf_route_select_install(bgp_vrf, rn, pp, afi, safi);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -1749,6 +1750,73 @@ static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
|
|||||||
return ret;
|
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
|
* Given a route entry and a VNI, see if this route entry should be
|
||||||
* imported into the VNI i.e., RTs match.
|
* 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;
|
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
|
* Install or uninstall routes of specified type that are appropriate for this
|
||||||
* particular VNI.
|
* particular VNI.
|
||||||
@ -1890,6 +2032,14 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp,
|
|||||||
return 0;
|
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
|
* Install any existing remote routes applicable for this VNI into its
|
||||||
* routing table. This is invoked when a VNI becomes "live" or its Import
|
* 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);
|
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
|
* Uninstall any existing remote routes for this VNI. One scenario in which
|
||||||
* this is invoked is upon an import RT change.
|
* 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,
|
void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
|
||||||
struct ecommunity *ecomadd)
|
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 */
|
/* Cleanup the RT to VRF mapping */
|
||||||
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
|
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 */
|
/* map VRF to its RTs */
|
||||||
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
|
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,
|
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 listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
|
||||||
struct ecommunity *ecom = 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 */
|
/* Cleanup the RT to VRF mapping */
|
||||||
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
|
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 */
|
/* map VRFs to its RTs */
|
||||||
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
|
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,
|
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))
|
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
|
||||||
update_routes_for_vni(bgp_def, 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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -3598,6 +3761,9 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* unimport remote routes from VRF */
|
||||||
|
uninstall_routes_for_vrf(bgp_vrf);
|
||||||
|
|
||||||
/* remove the l3vni from vrf instance */
|
/* remove the l3vni from vrf instance */
|
||||||
bgp_vrf->l3vni = 0;
|
bgp_vrf->l3vni = 0;
|
||||||
|
|
||||||
@ -3607,19 +3773,16 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni,
|
|||||||
/* delete RD/RT */
|
/* delete RD/RT */
|
||||||
if (bgp_vrf->vrf_import_rtl && !list_isempty(bgp_vrf->vrf_import_rtl)) {
|
if (bgp_vrf->vrf_import_rtl && !list_isempty(bgp_vrf->vrf_import_rtl)) {
|
||||||
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
|
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
|
||||||
list_delete(bgp_vrf->vrf_import_rtl);
|
list_delete_all_node(bgp_vrf->vrf_import_rtl);
|
||||||
bgp_vrf->vrf_import_rtl = NULL;
|
|
||||||
}
|
}
|
||||||
if (bgp_vrf->vrf_export_rtl && !list_isempty(bgp_vrf->vrf_export_rtl)) {
|
if (bgp_vrf->vrf_export_rtl && !list_isempty(bgp_vrf->vrf_export_rtl)) {
|
||||||
list_delete(bgp_vrf->vrf_export_rtl);
|
list_delete_all_node(bgp_vrf->vrf_export_rtl);
|
||||||
bgp_vrf->vrf_export_rtl = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update all corresponding local mac-ip routes */
|
/* update all corresponding local mac-ip routes */
|
||||||
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
|
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
|
||||||
update_routes_for_vni(bgp_def, vpn);
|
update_routes_for_vni(bgp_def, vpn);
|
||||||
|
|
||||||
/* TODO_MITESH: unimport remote routes from VRF */
|
|
||||||
|
|
||||||
/* Delete the instance if it was autocreated */
|
/* Delete the instance if it was autocreated */
|
||||||
if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
|
if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
|
||||||
|
Loading…
Reference in New Issue
Block a user