From 7c312383ba8224d60ebd8616e4ece33526f13ebf Mon Sep 17 00:00:00 2001 From: Ameya Dharkar Date: Wed, 13 Nov 2019 16:46:56 -0800 Subject: [PATCH] bgpd: Add nexthop of received EVPN RT-5 for nexthop tracking Problem statement: When IPv4/IPv6 prefixes are received in BGP, bgp_update function registers the nexthop of the route with nexthop tracking module. The BGP route is marked as valid only if the nexthop is resolved. Even for EVPN RT-5, route should be marked as valid only if the the nexthop is resolvable. Code changes: 1. Add nexthop of EVPN RT-5 for nexthop tracking. Route will be marked as valid only if the nexthop is resolved. 2. Only the valid EVPN routes are imported to the vrf. 3. When nht update is received in BGP, make sure that the EVPN routes are imported/unimported based on the route becomes valid/invalid. Testcases: 1. At rtr-1, advertise EVPN RT-5 with a nexthop 10.100.0.2. 10.100.0.2 is resolved at rtr-2 in default vrf. At rtr-2, remote EVPN RT-5 should be marked as valid and should be imported into vrfs. 2. Make the nexthop 10.100.0.2 unreachable at rtr-2 Remote EVPN RT-5 should be marked as invalid and should be unimported from the vrfs. As this code change deals with EVPN type-5 routes only, other EVPN routes should be valid. 3. At rtr-2, add a static route to make nexthop 10.100.0.2 reachable. EVPN RT-5 should again become valid and should be imported into the vrfs. Signed-off-by: Ameya Dharkar --- bgpd/bgp_attr.h | 4 ++++ bgpd/bgp_evpn.c | 23 +++++++++++++++++++++++ bgpd/bgp_evpn.h | 1 + bgpd/bgp_nht.c | 11 +++++++++++ bgpd/bgp_route.c | 28 +++++++++++++++++++--------- 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 42002bd378..375a2272e1 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -69,6 +69,10 @@ #define BGP_PREFIX_SID_IPV6_LENGTH 19 #define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH 6 +#define BGP_ATTR_NH_AFI(afi, attr) \ + ((afi != AFI_L2VPN) ? afi : \ + ((attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) ? AFI_IP : AFI_IP6)) + /* PMSI tunnel types (RFC 6514) */ struct bgp_attr_encap_subtlv { diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 07d3f7b31e..36ea9a991a 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -6026,3 +6026,26 @@ int bgp_evpn_get_type5_prefixlen(struct prefix *pfx) return evp->prefix.prefix_addr.ip_prefix_length; } + +/* + * Should we register nexthop for this EVPN prefix for nexthop tracking? + */ +bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx) +{ + struct prefix_evpn *evp = (struct prefix_evpn *)pfx; + + /* + * EVPN RT-5 should not be marked as valid and imported to vrfs if the + * BGP nexthop is not reachable. To check for the nexthop reachability, + * Add nexthop for EVPN RT-5 for nexthop tracking. + * + * Ideally, a BGP route should be marked as valid only if the + * nexthop is reachable. Thus, other EVPN route types also should be + * added here after testing is performed for them. + */ + if (pfx && pfx->family == AF_EVPN && + evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) + return true; + + return false; +} diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 6d1e8cd31b..798c3e59bc 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -191,5 +191,6 @@ extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp); extern void bgp_evpn_cleanup(struct bgp *bgp); extern void bgp_evpn_init(struct bgp *bgp); extern int bgp_evpn_get_type5_prefixlen(struct prefix *pfx); +extern bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx); #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 6be08efb21..0969c8e77e 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -43,6 +43,7 @@ #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_flowspec_util.h" +#include "bgpd/bgp_evpn.h" extern struct zclient *zclient; @@ -773,6 +774,16 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc) || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)) SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED); + if (safi == SAFI_EVPN && + bgp_evpn_is_prefix_nht_supported(&rn->p)) { + if (CHECK_FLAG(path->flags, BGP_PATH_VALID)) + bgp_evpn_import_route(bgp_path, afi, safi, + &rn->p, path); + else + bgp_evpn_unimport_route(bgp_path, afi, safi, + &rn->p, path); + } + bgp_process(bgp_path, rn, afi, safi); } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 261fe77800..a40cd737a8 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3038,6 +3038,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, int connected = 0; int do_loop_check = 1; int has_valid_label = 0; + afi_t nh_afi; #if ENABLE_BGP_VNC int vnc_implicit_withdraw = 0; #endif @@ -3433,8 +3434,10 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, /* Nexthop reachability check - for unicast and * labeled-unicast.. */ - if ((afi == AFI_IP || afi == AFI_IP6) - && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) { + if (((afi == AFI_IP || afi == AFI_IP6) + && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) + || (safi == SAFI_EVPN && + bgp_evpn_is_prefix_nht_supported(p))) { if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) @@ -3449,8 +3452,10 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, if (pi->extra && pi->extra->bgp_orig) bgp_nexthop = pi->extra->bgp_orig; - if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, afi, pi, - NULL, connected) + nh_afi = BGP_ATTR_NH_AFI(afi, pi->attr); + + if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, nh_afi, + pi, NULL, connected) || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)) bgp_path_info_set_flag(rn, pi, BGP_PATH_VALID); else { @@ -3498,7 +3503,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, * updating * the attributes for the route in the VNI(s). */ - if (safi == SAFI_EVPN && !same_attr) + if (safi == SAFI_EVPN && !same_attr && + CHECK_FLAG(pi->flags, BGP_PATH_VALID)) bgp_evpn_import_route(bgp, afi, safi, p, pi); /* Process change. */ @@ -3571,8 +3577,9 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, evpn == NULL ? NULL : &evpn->gw_ip); } /* Nexthop reachability check. */ - if ((afi == AFI_IP || afi == AFI_IP6) - && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) { + if (((afi == AFI_IP || afi == AFI_IP6) + && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) + || (safi == SAFI_EVPN && bgp_evpn_is_prefix_nht_supported(p))) { if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) @@ -3581,7 +3588,10 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, else connected = 0; - if (bgp_find_or_add_nexthop(bgp, bgp, afi, new, NULL, connected) + nh_afi = BGP_ATTR_NH_AFI(afi, new->attr); + + if (bgp_find_or_add_nexthop(bgp, bgp, nh_afi, new, NULL, + connected) || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)) bgp_path_info_set_flag(rn, new, BGP_PATH_VALID); else { @@ -3632,7 +3642,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, return -1; /* If this is an EVPN route, process for import. */ - if (safi == SAFI_EVPN) + if (safi == SAFI_EVPN && CHECK_FLAG(new->flags, BGP_PATH_VALID)) bgp_evpn_import_route(bgp, afi, safi, p, new); hook_call(bgp_process, bgp, afi, safi, rn, peer, false); -- 2.39.5