forked from Mirror/frr
Merge pull request #3892 from vivek-cumulus/evpn_vrf_route_leak
Leaking of EVPN-based IPv4 and IPv6 routes between VRFs
This commit is contained in:
commit
f05d888049
|
@ -2502,6 +2502,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
|||
/* Perform route selection and update zebra, if required. */
|
||||
bgp_process(bgp_vrf, rn, afi, safi);
|
||||
|
||||
/* Process for route leaking. */
|
||||
vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2667,6 +2670,9 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
|||
if (!pi)
|
||||
return 0;
|
||||
|
||||
/* Process for route leaking. */
|
||||
vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi);
|
||||
|
||||
bgp_aggregate_decrement(bgp_vrf, &rn->p, pi, afi, safi);
|
||||
|
||||
/* Mark entry for deletion */
|
||||
|
@ -4222,11 +4228,13 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi)
|
|||
|
||||
table = bgp_vrf->rib[afi][safi];
|
||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
||||
/* Only care about "selected" routes - non-imported. */
|
||||
/* Only care about "selected" routes. Also ensure that
|
||||
* these are routes that are injectable into EVPN.
|
||||
*/
|
||||
/* TODO: Support for AddPath for EVPN. */
|
||||
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
|
||||
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
|
||||
&& (!pi->extra || !pi->extra->parent)) {
|
||||
&& is_route_injectable_into_evpn(pi)) {
|
||||
bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p,
|
||||
afi, safi);
|
||||
break;
|
||||
|
@ -4293,12 +4301,13 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
|
|||
table = bgp_vrf->rib[afi][safi];
|
||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
||||
/* Need to identify the "selected" route entry to use its
|
||||
* attribute. Also, we only consider "non-imported" routes.
|
||||
* attribute. Also, ensure that the route is injectable
|
||||
* into EVPN.
|
||||
* TODO: Support for AddPath for EVPN.
|
||||
*/
|
||||
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
|
||||
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
|
||||
&& (!pi->extra || !pi->extra->parent)) {
|
||||
&& is_route_injectable_into_evpn(pi)) {
|
||||
|
||||
/* apply the route-map */
|
||||
if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
|
||||
|
|
|
@ -88,8 +88,13 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
|
|||
!ri->extra->parent)
|
||||
return 0;
|
||||
|
||||
/* See if the parent is of family L2VPN/EVPN */
|
||||
parent_ri = (struct bgp_path_info *)ri->extra->parent;
|
||||
/* Determine parent recursively */
|
||||
for (parent_ri = ri->extra->parent;
|
||||
parent_ri->extra && parent_ri->extra->parent;
|
||||
parent_ri = parent_ri->extra->parent)
|
||||
;
|
||||
|
||||
/* See if of family L2VPN/EVPN */
|
||||
rn = parent_ri->net;
|
||||
if (!rn)
|
||||
return 0;
|
||||
|
@ -101,6 +106,38 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Flag if the route path's family is EVPN. */
|
||||
static inline bool is_pi_family_evpn(struct bgp_path_info *pi)
|
||||
{
|
||||
return is_pi_family_matching(pi, AFI_L2VPN, SAFI_EVPN);
|
||||
}
|
||||
|
||||
/* Flag if the route is injectable into EVPN. This would be either a
|
||||
* non-imported route or a non-EVPN imported route.
|
||||
*/
|
||||
static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
|
||||
{
|
||||
struct bgp_path_info *parent_pi;
|
||||
struct bgp_table *table;
|
||||
struct bgp_node *rn;
|
||||
|
||||
if (pi->sub_type != BGP_ROUTE_IMPORTED ||
|
||||
!pi->extra ||
|
||||
!pi->extra->parent)
|
||||
return true;
|
||||
|
||||
parent_pi = (struct bgp_path_info *)pi->extra->parent;
|
||||
rn = parent_pi->net;
|
||||
if (!rn)
|
||||
return true;
|
||||
table = bgp_node_table(rn);
|
||||
if (table &&
|
||||
table->afi == AFI_L2VPN &&
|
||||
table->safi == SAFI_EVPN)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
|
||||
struct prefix *p,
|
||||
struct attr *src_attr, afi_t afi,
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "bgpd/bgp_zebra.h"
|
||||
#include "bgpd/bgp_nexthop.h"
|
||||
#include "bgpd/bgp_nht.h"
|
||||
#include "bgpd/bgp_evpn.h"
|
||||
|
||||
#if ENABLE_BGP_VNC
|
||||
#include "bgpd/rfapi/rfapi_backend.h"
|
||||
|
@ -552,8 +553,12 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
|
|||
if (bpi->extra && bpi->extra->bgp_orig)
|
||||
bgp_nexthop = bpi->extra->bgp_orig;
|
||||
|
||||
/* No nexthop tracking for redistributed routes */
|
||||
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
|
||||
/*
|
||||
* No nexthop tracking for redistributed routes or for
|
||||
* EVPN-imported routes that get leaked.
|
||||
*/
|
||||
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
|
||||
is_pi_family_evpn(bpi_ultimate))
|
||||
nh_valid = 1;
|
||||
else
|
||||
/*
|
||||
|
@ -614,8 +619,11 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
|
|||
* No nexthop tracking for redistributed routes because
|
||||
* their originating protocols will do the tracking and
|
||||
* withdraw those routes if the nexthops become unreachable
|
||||
* This also holds good for EVPN-imported routes that get
|
||||
* leaked.
|
||||
*/
|
||||
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
|
||||
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
|
||||
is_pi_family_evpn(bpi_ultimate))
|
||||
nh_valid = 1;
|
||||
else
|
||||
/*
|
||||
|
@ -683,11 +691,10 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
|
|||
return;
|
||||
}
|
||||
|
||||
/* loop check - should not be an imported route. */
|
||||
if (path_vrf->extra && path_vrf->extra->bgp_orig)
|
||||
/* Is this route exportable into the VPN table? */
|
||||
if (!is_route_injectable_into_vpn(path_vrf))
|
||||
return;
|
||||
|
||||
|
||||
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
|
||||
if (debug)
|
||||
zlog_debug("%s: %s skipping: %s", __func__,
|
||||
|
@ -894,15 +901,6 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
|
|||
path_vrf->type, path_vrf->sub_type);
|
||||
}
|
||||
|
||||
if (path_vrf->sub_type != BGP_ROUTE_NORMAL
|
||||
&& path_vrf->sub_type != BGP_ROUTE_STATIC
|
||||
&& path_vrf->sub_type != BGP_ROUTE_REDISTRIBUTE) {
|
||||
|
||||
if (debug)
|
||||
zlog_debug("%s: wrong sub_type %d", __func__,
|
||||
path_vrf->sub_type);
|
||||
return;
|
||||
}
|
||||
if (!bgp_vpn)
|
||||
return;
|
||||
|
||||
|
@ -912,6 +910,10 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
|
|||
return;
|
||||
}
|
||||
|
||||
/* Is this route exportable into the VPN table? */
|
||||
if (!is_route_injectable_into_vpn(path_vrf))
|
||||
return;
|
||||
|
||||
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
|
||||
if (debug)
|
||||
zlog_debug("%s: skipping: %s", __func__, debugmsg);
|
||||
|
@ -1352,7 +1354,10 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */
|
|||
|
||||
for (bpi = bgp_node_get_bgp_path_info(bn); bpi;
|
||||
bpi = bpi->next) {
|
||||
if (bpi->extra && bpi->extra->bgp_orig != bgp_vrf) {
|
||||
if (bpi->extra
|
||||
&& bpi->extra->bgp_orig != bgp_vrf
|
||||
&& bpi->extra->parent
|
||||
&& is_pi_family_vpn(bpi->extra->parent)) {
|
||||
|
||||
/* delete route */
|
||||
bgp_aggregate_decrement(bgp_vrf, &bn->p, bpi,
|
||||
|
|
|
@ -226,6 +226,39 @@ static inline void vpn_leak_postchange(vpn_policy_direction_t direction,
|
|||
}
|
||||
}
|
||||
|
||||
/* Flag if the route is injectable into VPN. This would be either a
|
||||
* non-imported route or a non-VPN imported route.
|
||||
*/
|
||||
static inline bool is_route_injectable_into_vpn(struct bgp_path_info *pi)
|
||||
{
|
||||
struct bgp_path_info *parent_pi;
|
||||
struct bgp_table *table;
|
||||
struct bgp_node *rn;
|
||||
|
||||
if (pi->sub_type != BGP_ROUTE_IMPORTED ||
|
||||
!pi->extra ||
|
||||
!pi->extra->parent)
|
||||
return true;
|
||||
|
||||
parent_pi = (struct bgp_path_info *)pi->extra->parent;
|
||||
rn = parent_pi->net;
|
||||
if (!rn)
|
||||
return true;
|
||||
table = bgp_node_table(rn);
|
||||
if (table &&
|
||||
(table->afi == AFI_IP || table->afi == AFI_IP6) &&
|
||||
table->safi == SAFI_MPLS_VPN)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Flag if the route path's family is VPN. */
|
||||
static inline bool is_pi_family_vpn(struct bgp_path_info *pi)
|
||||
{
|
||||
return (is_pi_family_matching(pi, AFI_IP, SAFI_MPLS_VPN) ||
|
||||
is_pi_family_matching(pi, AFI_IP6, SAFI_MPLS_VPN));
|
||||
}
|
||||
|
||||
extern void vpn_policy_routemap_event(const char *rmap_name);
|
||||
|
||||
extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey);
|
||||
|
|
|
@ -2476,8 +2476,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
|||
|
||||
/* advertise/withdraw type-5 routes */
|
||||
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
|
||||
if (advertise_type5_routes(bgp, afi) && new_select &&
|
||||
(!new_select->extra || !new_select->extra->parent)) {
|
||||
if (advertise_type5_routes(bgp, afi) &&
|
||||
new_select &&
|
||||
is_route_injectable_into_evpn(new_select)) {
|
||||
|
||||
/* apply the route-map */
|
||||
if (bgp->adv_cmd_rmap[afi][safi].map) {
|
||||
|
@ -2500,8 +2501,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
|||
afi, safi);
|
||||
|
||||
}
|
||||
} else if (advertise_type5_routes(bgp, afi) && old_select &&
|
||||
(!old_select->extra || !old_select->extra->parent))
|
||||
} else if (advertise_type5_routes(bgp, afi) &&
|
||||
old_select &&
|
||||
is_route_injectable_into_evpn(old_select))
|
||||
bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
|
||||
}
|
||||
|
||||
|
|
|
@ -409,6 +409,24 @@ static inline int bgp_fibupd_safi(safi_t safi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Flag if the route path's family matches params. */
|
||||
static inline bool is_pi_family_matching(struct bgp_path_info *pi,
|
||||
afi_t afi, safi_t safi)
|
||||
{
|
||||
struct bgp_table *table;
|
||||
struct bgp_node *rn;
|
||||
|
||||
rn = pi->net;
|
||||
if (!rn)
|
||||
return false;
|
||||
table = bgp_node_table(rn);
|
||||
if (table &&
|
||||
table->afi == afi &&
|
||||
table->safi == safi)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Prototypes. */
|
||||
extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi,
|
||||
struct peer *peer, afi_t afi, safi_t safi);
|
||||
|
|
|
@ -1456,8 +1456,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
|
|||
&(api_nh->gate.ipv4),
|
||||
sizeof(struct in_addr));
|
||||
zebra_vxlan_evpn_vrf_route_add(
|
||||
vrf_id, &api_nh->rmac, &vtep_ip,
|
||||
&api.prefix);
|
||||
api_nh->vrf_id, &api_nh->rmac,
|
||||
&vtep_ip, &api.prefix);
|
||||
}
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
|
@ -1479,8 +1479,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
|
|||
memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6),
|
||||
sizeof(struct in6_addr));
|
||||
zebra_vxlan_evpn_vrf_route_add(
|
||||
vrf_id, &api_nh->rmac, &vtep_ip,
|
||||
&api.prefix);
|
||||
api_nh->vrf_id, &api_nh->rmac,
|
||||
&vtep_ip, &api.prefix);
|
||||
}
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
|
|
Loading…
Reference in a new issue