summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr_evpn.c1
-rw-r--r--bgpd/bgp_attr_evpn.h14
-rw-r--r--bgpd/bgp_debug.c26
-rw-r--r--bgpd/bgp_debug.h13
-rw-r--r--bgpd/bgp_evpn.c637
-rw-r--r--bgpd/bgp_evpn.h38
-rw-r--r--bgpd/bgp_evpn_private.h19
-rw-r--r--bgpd/bgp_evpn_vty.c336
-rw-r--r--bgpd/bgp_evpn_vty.h4
-rw-r--r--bgpd/bgp_mac.c4
-rw-r--r--bgpd/bgp_memory.c1
-rw-r--r--bgpd/bgp_memory.h2
-rw-r--r--bgpd/bgp_nb_config.c64
-rw-r--r--bgpd/bgp_nexthop.c14
-rw-r--r--bgpd/bgp_nexthop.h27
-rw-r--r--bgpd/bgp_nht.c58
-rw-r--r--bgpd/bgp_nht.h1
-rw-r--r--bgpd/bgp_route.c98
-rw-r--r--bgpd/bgp_routemap.c213
-rw-r--r--bgpd/bgp_routemap_nb.c14
-rw-r--r--bgpd/bgp_routemap_nb.h8
-rw-r--r--bgpd/bgp_routemap_nb_config.c104
-rw-r--r--bgpd/bgp_updgrp_packet.c3
-rw-r--r--bgpd/bgp_zebra.c54
-rw-r--r--bgpd/bgpd.h35
-rw-r--r--doc/user/bgp.rst109
-rw-r--r--lib/routemap.h4
-rw-r--r--lib/routemap_cli.c10
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_base.json192
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt2.json8
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt5.json192
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_base.json27
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt2.json27
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt5.json6
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_base.json27
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt2.json27
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt5.json6
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgpd.conf30
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra.conf14
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_base.json56
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt2.json56
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt5.json29
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_base.json55
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt2.json55
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt5.json29
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_base.json192
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt2.json68
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt5.json192
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_base.json27
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt2.json27
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt5.json6
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_base.json28
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt2.json28
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt5.json6
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgpd.conf14
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra.conf14
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_base.json56
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt2.json29
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt5.json29
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_base.json56
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt2.json29
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt5.json29
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/__init__.py0
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/host1/bgpd.conf18
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/host1/zebra.conf4
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/host2/bgpd.conf1
-rw-r--r--tests/topotests/bgp-evpn-overlay-index-gateway/host2/zebra.conf4
-rwxr-xr-xtests/topotests/bgp-evpn-overlay-index-gateway/test_bgp_evpn_overlay_index_gateway.py385
-rw-r--r--tools/etc/frr/support_bundle_commands.conf22
-rw-r--r--yang/frr-bgp-route-map.yang32
-rw-r--r--zebra/zebra_evpn.c26
-rw-r--r--zebra/zebra_evpn.h3
-rw-r--r--zebra/zebra_fpm_netlink.c33
-rw-r--r--zebra/zebra_vxlan.c33
-rw-r--r--zebra/zebra_vxlan_private.h1
75 files changed, 3950 insertions, 189 deletions
diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c
index 1df646c34..0e341a8c6 100644
--- a/bgpd/bgp_attr_evpn.c
+++ b/bgpd/bgp_attr_evpn.c
@@ -315,3 +315,4 @@ extern bool is_zero_gw_ip(const union gw_addr *gw_ip, const afi_t afi)
return false;
}
+
diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h
index 6fdf73fd1..102509fdd 100644
--- a/bgpd/bgp_attr_evpn.h
+++ b/bgpd/bgp_attr_evpn.h
@@ -30,7 +30,21 @@ union gw_addr {
struct in6_addr ipv6;
};
+enum overlay_index_type {
+ OVERLAY_INDEX_TYPE_NONE,
+ OVERLAY_INDEX_GATEWAY_IP,
+ OVERLAY_INDEX_ESI,
+ OVERLAY_INDEX_MAC,
+};
+
+/*
+ * Structure to store ovrelay index for EVPN type-5 route
+ * This structure stores ESI and Gateway IP overlay index.
+ * MAC overlay index is stored in the RMAC attribute.
+ */
struct bgp_route_evpn {
+ enum overlay_index_type type;
+ esi_t eth_s_id;
union gw_addr gw_ip;
};
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 8f286e66d..856afb05f 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -2680,10 +2680,14 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
union prefixconstptr pu,
mpls_label_t *label, uint32_t num_labels,
int addpath_valid, uint32_t addpath_id,
+ struct bgp_route_evpn *overlay_index,
char *str, int size)
{
char rd_buf[RD_ADDRSTRLEN];
char tag_buf[30];
+ char overlay_index_buf[INET6_ADDRSTRLEN + 14];
+ const struct prefix_evpn *evp;
+
/* ' with addpath ID ' 17
* max strlen of uint32 + 10
* +/- (just in case) + 1
@@ -2701,6 +2705,23 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
snprintf(pathid_buf, sizeof(pathid_buf), " with addpath ID %u",
addpath_id);
+ overlay_index_buf[0] = '\0';
+ if (overlay_index && overlay_index->type == OVERLAY_INDEX_GATEWAY_IP) {
+ char obuf[INET6_ADDRSTRLEN];
+
+ obuf[0] = '\0';
+ evp = pu.evp;
+ if (is_evpn_prefix_ipaddr_v4(evp))
+ inet_ntop(AF_INET, &overlay_index->gw_ip, obuf,
+ sizeof(obuf));
+ else if (is_evpn_prefix_ipaddr_v6(evp))
+ inet_ntop(AF_INET6, &overlay_index->gw_ip, obuf,
+ sizeof(obuf));
+
+ snprintf(overlay_index_buf, sizeof(overlay_index_buf),
+ " gateway IP %s", obuf);
+ }
+
tag_buf[0] = '\0';
if (bgp_labeled_safi(safi) && num_labels) {
@@ -2720,9 +2741,10 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
}
if (prd)
- snprintfrr(str, size, "RD %s %pFX%s%s %s %s",
+ snprintfrr(str, size, "RD %s %pFX%s%s%s %s %s",
prefix_rd2str(prd, rd_buf, sizeof(rd_buf)), pu.p,
- tag_buf, pathid_buf, afi2str(afi), safi2str(safi));
+ overlay_index_buf, tag_buf, pathid_buf, afi2str(afi),
+ safi2str(safi));
else if (safi == SAFI_FLOWSPEC) {
char return_string[BGP_FLOWSPEC_NLRI_STRING_MAX];
const struct prefix_fs *fs = pu.fs;
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index fa8da1c34..d847fb84e 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -37,7 +37,8 @@
#define DUMP_DETAIL 32
/* RD + Prefix + Path-Id */
-#define BGP_PRD_PATH_STRLEN (PREFIX_STRLEN + RD_ADDRSTRLEN + 20)
+#define BGP_PRD_PATH_STRLEN \
+ (PREFIX_STRLEN + RD_ADDRSTRLEN + INET6_ADDRSTRLEN + 34)
extern int dump_open;
extern int dump_update;
@@ -179,11 +180,11 @@ extern bool bgp_debug_update(struct peer *peer, const struct prefix *p,
extern bool bgp_debug_bestpath(struct bgp_dest *dest);
extern bool bgp_debug_zebra(const struct prefix *p);
-extern const char *
-bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, const struct prefix_rd *prd,
- union prefixconstptr pu, mpls_label_t *label,
- uint32_t num_labels, int addpath_valid,
- uint32_t addpath_id, char *str, int size);
+extern const char *bgp_debug_rdpfxpath2str(
+ afi_t afi, safi_t safi, const struct prefix_rd *prd,
+ union prefixconstptr pu, mpls_label_t *label, uint32_t num_labels,
+ int addpath_valid, uint32_t addpath_id,
+ struct bgp_route_evpn *overlay_index, char *str, int size);
const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data,
size_t datalen);
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index d8e57419e..e08e5b979 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -53,6 +53,7 @@
#include "bgpd/bgp_addpath.h"
#include "bgpd/bgp_mac.h"
#include "bgpd/bgp_vty.h"
+#include "bgpd/bgp_nht.h"
/*
* Definitions and external declarations.
@@ -65,6 +66,28 @@ DEFINE_QOBJ_TYPE(bgp_evpn_es);
* Static function declarations
*/
static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn);
+static void bgp_evpn_remote_ip_hash_init(struct bgpevpn *evpn);
+static void bgp_evpn_remote_ip_hash_destroy(struct bgpevpn *evpn);
+static void bgp_evpn_remote_ip_hash_add(struct bgpevpn *vpn,
+ struct bgp_path_info *pi);
+static void bgp_evpn_remote_ip_hash_del(struct bgpevpn *vpn,
+ struct bgp_path_info *pi);
+static void bgp_evpn_remote_ip_hash_iterate(struct bgpevpn *vpn,
+ void (*func)(struct hash_bucket *,
+ void *),
+ void *arg);
+static void bgp_evpn_link_to_vni_svi_hash(struct bgp *bgp, struct bgpevpn *vpn);
+static void bgp_evpn_unlink_from_vni_svi_hash(struct bgp *bgp,
+ struct bgpevpn *vpn);
+static unsigned int vni_svi_hash_key_make(const void *p);
+static bool vni_svi_hash_cmp(const void *p1, const void *p2);
+static void bgp_evpn_remote_ip_process_nexthops(struct bgpevpn *vpn,
+ struct ipaddr *addr,
+ bool resolve);
+static void bgp_evpn_remote_ip_hash_link_nexthop(struct hash_bucket *bucket,
+ void *args);
+static void bgp_evpn_remote_ip_hash_unlink_nexthop(struct hash_bucket *bucket,
+ void *args);
static struct in_addr zero_vtep_ip;
/*
@@ -1261,7 +1284,8 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn,
/* update evpn type-5 route entry */
static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
- struct attr *src_attr)
+ struct attr *src_attr, afi_t src_afi,
+ safi_t src_safi)
{
afi_t afi = AFI_L2VPN;
safi_t safi = SAFI_EVPN;
@@ -1315,6 +1339,26 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
+ if (src_afi == AFI_IP6 &&
+ CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP)) {
+ if (src_attr &&
+ !IN6_IS_ADDR_UNSPECIFIED(&src_attr->mp_nexthop_global)) {
+ attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
+ memcpy(&attr.evpn_overlay.gw_ip.ipv6,
+ &src_attr->mp_nexthop_global,
+ sizeof(struct in6_addr));
+ }
+ } else if (src_afi == AFI_IP &&
+ CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)) {
+ if (src_attr && src_attr->nexthop.s_addr != 0) {
+ attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
+ memcpy(&attr.evpn_overlay.gw_ip.ipv4,
+ &src_attr->nexthop, sizeof(struct in_addr));
+ }
+ }
+
/* Setup RT and encap extended community */
build_evpn_type5_route_extcomm(bgp_vrf, &attr);
@@ -2198,6 +2242,7 @@ static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
dest = bgp_route_next(dest)) {
for (pi = bgp_dest_get_bgp_path_info(dest);
(pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
+ bgp_evpn_remote_ip_hash_del(vpn, pi);
bgp_path_info_delete(dest, pi);
bgp_path_info_reap(dest, pi);
}
@@ -2381,6 +2426,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
bool new_pi = false;
bool use_l3nhg = false;
bool is_l3nhg_active = false;
+ char buf1[INET6_ADDRSTRLEN];
memset(pp, 0, sizeof(struct prefix));
ip_prefix_from_evpn_prefix(evp, pp);
@@ -2411,10 +2457,36 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
* make sure to set the flag for next hop attribute.
*/
attr = *parent_pi->attr;
- if (afi == AFI_IP6)
- evpn_convert_nexthop_to_ipv6(&attr);
- else
- attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+ if (attr.evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP) {
+ if (afi == AFI_IP6)
+ evpn_convert_nexthop_to_ipv6(&attr);
+ else
+ attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+ } else {
+
+ /*
+ * If gateway IP overlay index is specified in the NLRI of
+ * EVPN RT-5, this gateway IP should be used as the nexthop
+ * for the prefix in the VRF
+ */
+ if (bgp_debug_zebra(NULL)) {
+ zlog_debug(
+ "Install gateway IP %s as nexthop for prefix %pFX in vrf %s",
+ inet_ntop(pp->family, &attr.evpn_overlay.gw_ip,
+ buf1, sizeof(buf1)), pp,
+ vrf_id_to_name(bgp_vrf->vrf_id));
+ }
+
+ if (afi == AFI_IP6) {
+ memcpy(&attr.mp_nexthop_global,
+ &attr.evpn_overlay.gw_ip.ipv6,
+ sizeof(struct in6_addr));
+ attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
+ } else {
+ attr.nexthop = attr.evpn_overlay.gw_ip.ipv4;
+ attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+ }
+ }
bgp_evpn_es_vrf_use_nhg(bgp_vrf, &parent_pi->attr->esi, &use_l3nhg,
&is_l3nhg_active, NULL);
@@ -2460,8 +2532,27 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
pi->attr = attr_new;
pi->uptime = bgp_clock();
}
- /* as it is an importation, change nexthop */
- bgp_path_info_set_flag(dest, pi, BGP_PATH_ANNC_NH_SELF);
+
+ /* Gateway IP nexthop should be resolved */
+ if (attr.evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
+ if (bgp_find_or_add_nexthop(bgp_vrf, bgp_vrf, afi, safi, pi,
+ NULL, 0))
+ bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID);
+ else {
+ if (BGP_DEBUG(nht, NHT)) {
+ inet_ntop(pp->family,
+ &attr.evpn_overlay.gw_ip,
+ buf1, sizeof(buf1));
+ zlog_debug("%s: gateway IP NH unresolved",
+ buf1);
+ }
+ bgp_path_info_unset_flag(dest, pi, BGP_PATH_VALID);
+ }
+ } else {
+
+ /* as it is an importation, change nexthop */
+ bgp_path_info_set_flag(dest, pi, BGP_PATH_ANNC_NH_SELF);
+ }
/* Link path to evpn nexthop */
bgp_evpn_path_nh_add(bgp_vrf, pi);
@@ -2565,6 +2656,9 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
pi->uptime = bgp_clock();
}
+ /* Add this route to remote IP hashtable */
+ bgp_evpn_remote_ip_hash_add(vpn, pi);
+
/* Perform route selection and update zebra, if required. */
ret = evpn_route_select_install(bgp, vpn, dest);
@@ -2693,6 +2787,8 @@ static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
if (!pi)
return 0;
+ bgp_evpn_remote_ip_hash_del(vpn, pi);
+
/* Mark entry for deletion */
bgp_path_info_delete(dest, pi);
@@ -3951,7 +4047,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
mpls_label_t label; /* holds the VNI as in the packet */
int ret;
afi_t gw_afi;
- bool is_valid_update = false;
+ bool is_valid_update = true;
/* Type-5 route should be 34 or 58 bytes:
* RD (8), ESI (10), Eth Tag (4), IP len (1), IP (4 or 16),
@@ -3980,9 +4076,9 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
/* Additional information outside of prefix - ESI and GW IP */
memset(&evpn, 0, sizeof(evpn));
- /* Fetch ESI */
+ /* Fetch ESI overlay index */
if (attr)
- memcpy(&attr->esi, pfx, sizeof(esi_t));
+ memcpy(&evpn.eth_s_id, pfx, sizeof(esi_t));
pfx += ESI_BYTES;
/* Fetch Ethernet Tag. */
@@ -4031,25 +4127,53 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
* field
*/
+ /*
+ * An update containing a non-zero gateway IP and a non-zero ESI
+ * at the same time is should be treated as withdraw
+ */
+ if (bgp_evpn_is_esi_valid(&evpn.eth_s_id)
+ && !is_zero_gw_ip(&evpn.gw_ip, gw_afi)) {
+ flog_err(EC_BGP_EVPN_ROUTE_INVALID,
+ "%s - Rx EVPN Type-5 ESI and gateway-IP both non-zero.",
+ peer->host);
+ is_valid_update = false;
+ } else if (bgp_evpn_is_esi_valid(&evpn.eth_s_id))
+ evpn.type = OVERLAY_INDEX_ESI;
+ else if (!is_zero_gw_ip(&evpn.gw_ip, gw_afi))
+ evpn.type = OVERLAY_INDEX_GATEWAY_IP;
if (attr) {
- is_valid_update = true;
- if (is_zero_mac(&attr->rmac) &&
- is_zero_gw_ip(&evpn.gw_ip, gw_afi))
+ if (is_zero_mac(&attr->rmac)
+ && !bgp_evpn_is_esi_valid(&evpn.eth_s_id)
+ && is_zero_gw_ip(&evpn.gw_ip, gw_afi) && label == 0) {
+ flog_err(EC_BGP_EVPN_ROUTE_INVALID,
+ "%s - Rx EVPN Type-5 ESI, gateway-IP, RMAC and label all zero",
+ peer->host);
is_valid_update = false;
+ }
if (is_mcast_mac(&attr->rmac) || is_bcast_mac(&attr->rmac))
is_valid_update = false;
}
/* Process the route. */
- if (is_valid_update)
+ if (attr && is_valid_update)
ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
&prd, &label, 1, 0, &evpn);
- else
+ else {
+ if (!is_valid_update) {
+ char attr_str[BUFSIZ] = {0};
+
+ bgp_dump_attr(attr, attr_str, BUFSIZ);
+ zlog_warn(
+ "Invalid update from peer %s vrf %u prefix %pFX attr %s - treat as withdraw",
+ peer->hostname, peer->bgp->vrf_id, &p,
+ attr_str);
+ }
ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
&prd, &label, 1, &evpn);
+ }
return ret;
}
@@ -4078,7 +4202,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
/* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */
stream_putc(s, 8 + 10 + 4 + 1 + len + 3);
stream_put(s, prd->val, 8);
- if (attr)
+ if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_ESI)
stream_put(s, &attr->esi, sizeof(esi_t));
else
stream_put(s, 0, sizeof(esi_t));
@@ -4088,7 +4212,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
stream_put_ipv4(s, p_evpn_p->prefix_addr.ip.ipaddr_v4.s_addr);
else
stream_put(s, &p_evpn_p->prefix_addr.ip.ipaddr_v6, 16);
- if (attr) {
+ if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
const struct bgp_route_evpn *evpn_overlay =
bgp_attr_get_evpn_overlay(attr);
@@ -4301,7 +4425,7 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, const struct prefix *p,
struct prefix_evpn evp;
build_type5_prefix_from_ip_prefix(&evp, p);
- ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr);
+ ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr, afi, safi);
if (ret)
flog_err(EC_BGP_EVPN_ROUTE_CREATE,
"%u: Failed to create type-5 route for prefix %pFX",
@@ -5134,7 +5258,8 @@ struct bgpevpn *bgp_evpn_lookup_vni(struct bgp *bgp, vni_t vni)
struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip,
vrf_id_t tenant_vrf_id,
- struct in_addr mcast_grp)
+ struct in_addr mcast_grp,
+ ifindex_t svi_ifindex)
{
struct bgpevpn *vpn;
@@ -5148,6 +5273,7 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
vpn->originator_ip = originator_ip;
vpn->tenant_vrf_id = tenant_vrf_id;
vpn->mcast_grp = mcast_grp;
+ vpn->svi_ifindex = svi_ifindex;
/* Initialize route-target import and export lists */
vpn->import_rtl = list_new();
@@ -5168,6 +5294,9 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
return NULL;
}
+ bgp_evpn_remote_ip_hash_init(vpn);
+ bgp_evpn_link_to_vni_svi_hash(bgp, vpn);
+
/* add to l2vni list on corresponding vrf */
bgpevpn_link_to_l3vni(vpn);
@@ -5185,6 +5314,7 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
*/
void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
{
+ bgp_evpn_remote_ip_hash_destroy(vpn);
bgp_evpn_vni_es_cleanup(vpn);
bgpevpn_unlink_from_l3vni(vpn);
bgp_table_unlock(vpn->route_table);
@@ -5192,6 +5322,7 @@ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
list_delete(&vpn->import_rtl);
list_delete(&vpn->export_rtl);
bf_release_index(bm->rd_idspace, vpn->rd_id);
+ hash_release(bgp->vni_svi_hash, vpn);
hash_release(bgp->vnihash, vpn);
QOBJ_UNREG(vpn);
XFREE(MTYPE_BGP_EVPN, vpn);
@@ -5603,6 +5734,9 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni)
*/
delete_routes_for_vni(bgp, vpn);
+ bgp_evpn_unlink_from_vni_svi_hash(bgp, vpn);
+
+ vpn->svi_ifindex = 0;
/*
* tunnel is no longer active, del tunnel ip address from tip_hash
*/
@@ -5623,8 +5757,8 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni)
int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip,
vrf_id_t tenant_vrf_id,
- struct in_addr mcast_grp)
-
+ struct in_addr mcast_grp,
+ ifindex_t svi_ifindex)
{
struct bgpevpn *vpn;
struct prefix_evpn p;
@@ -5636,18 +5770,65 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
if (is_vni_live(vpn)
&& IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)
&& IPV4_ADDR_SAME(&vpn->mcast_grp, &mcast_grp)
- && vpn->tenant_vrf_id == tenant_vrf_id)
+ && vpn->tenant_vrf_id == tenant_vrf_id
+ && vpn->svi_ifindex == svi_ifindex)
/* Probably some other param has changed that we don't
* care about. */
return 0;
bgp_evpn_mcast_grp_change(bgp, vpn, mcast_grp);
+ if (vpn->svi_ifindex != svi_ifindex) {
+
+ /*
+ * Unresolve all the gateway IP nexthops for this VNI
+ * for old SVI
+ */
+ bgp_evpn_remote_ip_hash_iterate(
+ vpn,
+ (void (*)(struct hash_bucket *, void *))
+ bgp_evpn_remote_ip_hash_unlink_nexthop,
+ vpn);
+ bgp_evpn_unlink_from_vni_svi_hash(bgp, vpn);
+ vpn->svi_ifindex = svi_ifindex;
+ bgp_evpn_link_to_vni_svi_hash(bgp, vpn);
+
+ /*
+ * Resolve all the gateway IP nexthops for this VNI
+ * for new SVI
+ */
+ bgp_evpn_remote_ip_hash_iterate(
+ vpn,
+ (void (*)(struct hash_bucket *, void *))
+ bgp_evpn_remote_ip_hash_link_nexthop,
+ vpn);
+ }
+
/* Update tenant_vrf_id if it has changed. */
if (vpn->tenant_vrf_id != tenant_vrf_id) {
+
+ /*
+ * Unresolve all the gateway IP nexthops for this VNI
+ * in old tenant vrf
+ */
+ bgp_evpn_remote_ip_hash_iterate(
+ vpn,
+ (void (*)(struct hash_bucket *, void *))
+ bgp_evpn_remote_ip_hash_unlink_nexthop,
+ vpn);
bgpevpn_unlink_from_l3vni(vpn);
vpn->tenant_vrf_id = tenant_vrf_id;
bgpevpn_link_to_l3vni(vpn);
+
+ /*
+ * Resolve all the gateway IP nexthops for this VNI
+ * in new tenant vrf
+ */
+ bgp_evpn_remote_ip_hash_iterate(
+ vpn,
+ (void (*)(struct hash_bucket *, void *))
+ bgp_evpn_remote_ip_hash_link_nexthop,
+ vpn);
}
/* If tunnel endpoint IP has changed, update (and delete prior
@@ -5666,7 +5847,7 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
/* Create or update as appropriate. */
if (!vpn) {
vpn = bgp_evpn_new(bgp, vni, originator_ip, tenant_vrf_id,
- mcast_grp);
+ mcast_grp, svi_ifindex);
if (!vpn) {
flog_err(
EC_BGP_VNI,
@@ -5768,6 +5949,8 @@ void bgp_evpn_cleanup(struct bgp *bgp)
hash_free(bgp->vrf_import_rt_hash);
bgp->vrf_import_rt_hash = NULL;
+ hash_free(bgp->vni_svi_hash);
+ bgp->vni_svi_hash = NULL;
hash_free(bgp->vnihash);
bgp->vnihash = NULL;
@@ -5786,6 +5969,9 @@ void bgp_evpn_init(struct bgp *bgp)
{
bgp->vnihash =
hash_create(vni_hash_key_make, vni_hash_cmp, "BGP VNI Hash");
+ bgp->vni_svi_hash =
+ hash_create(vni_svi_hash_key_make, vni_svi_hash_cmp,
+ "BGP VNI hash based on SVI ifindex");
bgp->import_rt_hash =
hash_create(import_rt_hash_key_make, import_rt_hash_cmp,
"BGP Import RT Hash");
@@ -5878,3 +6064,408 @@ bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx)
return false;
}
+
+static void *bgp_evpn_remote_ip_hash_alloc(void *p)
+{
+ const struct evpn_remote_ip *key = (const struct evpn_remote_ip *)p;
+ struct evpn_remote_ip *ip;
+
+ ip = XMALLOC(MTYPE_EVPN_REMOTE_IP, sizeof(struct evpn_remote_ip));
+ *ip = *key;
+ ip->macip_path_list = list_new();
+
+ return ip;
+}
+
+static unsigned int bgp_evpn_remote_ip_hash_key_make(const void *p)
+{
+ const struct evpn_remote_ip *ip = p;
+ const struct ipaddr *addr = &ip->addr;
+
+ if (IS_IPADDR_V4(addr))
+ return jhash_1word(addr->ipaddr_v4.s_addr, 0);
+
+ return jhash2(addr->ipaddr_v6.s6_addr32,
+ array_size(addr->ipaddr_v6.s6_addr32), 0);
+}
+
+static bool bgp_evpn_remote_ip_hash_cmp(const void *p1, const void *p2)
+{
+ const struct evpn_remote_ip *ip1 = p1;
+ const struct evpn_remote_ip *ip2 = p2;
+
+ return (memcmp(&ip1->addr, &ip2->addr, sizeof(struct ipaddr)) == 0);
+}
+
+static void bgp_evpn_remote_ip_hash_init(struct bgpevpn *vpn)
+{
+ if (!evpn_resolve_overlay_index())
+ return;
+
+ vpn->remote_ip_hash = hash_create(bgp_evpn_remote_ip_hash_key_make,
+ bgp_evpn_remote_ip_hash_cmp,
+ "BGP EVPN remote IP hash");
+}
+
+static void bgp_evpn_remote_ip_hash_free(struct hash_bucket *bucket, void *args)
+{
+ struct evpn_remote_ip *ip = (struct evpn_remote_ip *)bucket->data;
+ struct bgpevpn *vpn = (struct bgpevpn *)args;
+
+ bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, false);
+
+ list_delete(&ip->macip_path_list);
+
+ hash_release(vpn->remote_ip_hash, ip);
+ XFREE(MTYPE_EVPN_REMOTE_IP, ip);
+}
+
+static void bgp_evpn_remote_ip_hash_destroy(struct bgpevpn *vpn)
+{
+ if (!evpn_resolve_overlay_index() || vpn->remote_ip_hash == NULL)
+ return;
+
+ hash_iterate(vpn->remote_ip_hash,
+ (void (*)(struct hash_bucket *, void *))bgp_evpn_remote_ip_hash_free,
+ vpn);
+
+ hash_free(vpn->remote_ip_hash);
+ vpn->remote_ip_hash = NULL;
+}
+
+/* Add a remote MAC/IP route to hash table */
+static void bgp_evpn_remote_ip_hash_add(struct bgpevpn *vpn,
+ struct bgp_path_info *pi)
+{
+ struct evpn_remote_ip tmp;
+ struct evpn_remote_ip *ip;
+ struct prefix_evpn *evp;
+
+ if (!evpn_resolve_overlay_index())
+ return;
+
+ if (pi->type != ZEBRA_ROUTE_BGP || pi->sub_type != BGP_ROUTE_IMPORTED
+ || !CHECK_FLAG(pi->flags, BGP_PATH_VALID))
+ return;
+
+ evp = (struct prefix_evpn *)&pi->net->p;
+
+ if (evp->family != AF_EVPN
+ || evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE
+ || is_evpn_prefix_ipaddr_none(evp))
+ return;
+
+ tmp.addr = evp->prefix.macip_addr.ip;
+ ip = hash_lookup(vpn->remote_ip_hash, &tmp);
+ if (ip) {
+ if (listnode_lookup(ip->macip_path_list, pi) != NULL)
+ return;
+ (void)listnode_add(ip->macip_path_list, pi);
+ return;
+ }
+
+ ip = hash_get(vpn->remote_ip_hash, &tmp, bgp_evpn_remote_ip_hash_alloc);
+ if (!ip)
+ return;
+
+ (void)listnode_add(ip->macip_path_list, pi);
+
+ bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, true);
+}
+
+/* Delete a remote MAC/IP route from hash table */
+static void bgp_evpn_remote_ip_hash_del(struct bgpevpn *vpn,
+ struct bgp_path_info *pi)
+{
+ struct evpn_remote_ip tmp;
+ struct evpn_remote_ip *ip;
+ struct prefix_evpn *evp;
+
+ if (!evpn_resolve_overlay_index())
+ return;
+
+ evp = (struct prefix_evpn *)&pi->net->p;
+
+ if (evp->family != AF_EVPN
+ || evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE
+ || is_evpn_prefix_ipaddr_none(evp))
+ return;
+
+ tmp.addr = evp->prefix.macip_addr.ip;
+ ip = hash_lookup(vpn->remote_ip_hash, &tmp);
+ if (ip == NULL)
+ return;
+
+ listnode_delete(ip->macip_path_list, pi);
+
+ if (ip->macip_path_list->count == 0) {
+ bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, false);
+ hash_release(vpn->remote_ip_hash, ip);
+ XFREE(MTYPE_EVPN_REMOTE_IP, ip);
+ }
+}
+
+static void bgp_evpn_remote_ip_hash_iterate(struct bgpevpn *vpn,
+ void (*func)(struct hash_bucket *,
+ void *),
+ void *arg)
+{
+ if (!evpn_resolve_overlay_index())
+ return;
+
+ hash_iterate(vpn->remote_ip_hash, func, arg);
+}
+
+static void show_remote_ip_entry(struct hash_bucket *bucket, void *args)
+{
+ char buf[INET6_ADDRSTRLEN];
+ char buf2[EVPN_ROUTE_STRLEN];
+ struct prefix_evpn *evp;
+
+ struct listnode *node = NULL;
+ struct bgp_path_info *pi = NULL;
+ struct vty *vty = (struct vty *)args;
+ struct evpn_remote_ip *ip = (struct evpn_remote_ip *)bucket->data;
+
+ vty_out(vty, " Remote IP: %s\n",
+ ipaddr2str(&ip->addr, buf, sizeof(buf)));
+ vty_out(vty, " Linked MAC/IP routes:\n");
+ for (ALL_LIST_ELEMENTS_RO(ip->macip_path_list, node, pi)) {
+ evp = (struct prefix_evpn *)&pi->net->p;
+ prefix2str(evp, buf2, sizeof(buf2));
+ vty_out(vty, " %s\n", buf2);
+ }
+}
+
+void bgp_evpn_show_remote_ip_hash(struct hash_bucket *bucket, void *args)
+{
+ struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
+ struct vty *vty = (struct vty *)args;
+
+ vty_out(vty, "VNI: %u\n", vpn->vni);
+ bgp_evpn_remote_ip_hash_iterate(
+ vpn,
+ (void (*)(struct hash_bucket *, void *))show_remote_ip_entry,
+ vty);
+ vty_out(vty, "\n");
+}
+
+static void bgp_evpn_remote_ip_hash_link_nexthop(struct hash_bucket *bucket,
+ void *args)
+{
+ struct evpn_remote_ip *ip = (struct evpn_remote_ip *)bucket->data;
+ struct bgpevpn *vpn = (struct bgpevpn *)args;
+
+ bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, true);
+}
+
+static void bgp_evpn_remote_ip_hash_unlink_nexthop(struct hash_bucket *bucket,
+ void *args)
+{
+ struct evpn_remote_ip *ip = (struct evpn_remote_ip *)bucket->data;
+ struct bgpevpn *vpn = (struct bgpevpn *)args;
+
+ bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, false);
+}
+
+static unsigned int vni_svi_hash_key_make(const void *p)
+{
+ const struct bgpevpn *vpn = p;
+
+ return jhash_1word(vpn->svi_ifindex, 0);
+}
+
+static bool vni_svi_hash_cmp(const void *p1, const void *p2)
+{
+ const struct bgpevpn *vpn1 = p1;
+ const struct bgpevpn *vpn2 = p2;
+
+ return (vpn1->svi_ifindex == vpn2->svi_ifindex);
+}
+
+static struct bgpevpn *bgp_evpn_vni_svi_hash_lookup(struct bgp *bgp,
+ ifindex_t svi)
+{
+ struct bgpevpn *vpn;
+ struct bgpevpn tmp;
+
+ memset(&tmp, 0, sizeof(struct bgpevpn));
+ tmp.svi_ifindex = svi;
+ vpn = hash_lookup(bgp->vni_svi_hash, &tmp);
+ return vpn;
+}
+
+static void bgp_evpn_link_to_vni_svi_hash(struct bgp *bgp, struct bgpevpn *vpn)
+{
+ if (vpn->svi_ifindex == 0)
+ return;
+
+ hash_get(bgp->vni_svi_hash, vpn, hash_alloc_intern);
+}
+
+static void bgp_evpn_unlink_from_vni_svi_hash(struct bgp *bgp,
+ struct bgpevpn *vpn)
+{
+ if (vpn->svi_ifindex == 0)
+ return;
+
+ hash_release(bgp->vni_svi_hash, vpn);
+}
+
+void bgp_evpn_show_vni_svi_hash(struct hash_bucket *bucket, void *args)
+{
+ struct bgpevpn *evpn = (struct bgpevpn *)bucket->data;
+ struct vty *vty = (struct vty *)args;
+
+ vty_out(vty, "SVI: %u VNI: %u\n", evpn->svi_ifindex, evpn->vni);
+}
+
+/*
+ * This function is called for a bgp_nexthop_cache entry when the nexthop is
+ * gateway IP overlay index.
+ * This function returns true if there is a remote MAC/IP route for the gateway
+ * IP in the EVI of the nexthop SVI.
+ */
+bool bgp_evpn_is_gateway_ip_resolved(struct bgp_nexthop_cache *bnc)
+{
+ struct bgp *bgp_evpn = NULL;
+ struct bgpevpn *vpn = NULL;
+ struct evpn_remote_ip tmp;
+ struct prefix *p;
+
+ if (!evpn_resolve_overlay_index())
+ return false;
+
+ if (!bnc->nexthop || bnc->nexthop->ifindex == 0)
+ return false;
+
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn)
+ return false;
+
+ /*
+ * Gateway IP is resolved by nht over SVI interface.
+ * Use this SVI to find corresponding EVI(L2 context)
+ */
+ vpn = bgp_evpn_vni_svi_hash_lookup(bgp_evpn, bnc->nexthop->ifindex);
+ if (!vpn)
+ return false;
+
+ if (vpn->bgp_vrf != bnc->bgp)
+ return false;
+
+ /*
+ * Check if the gateway IP is present in the EVI remote_ip_hash table
+ * which stores all the remote IP addresses received via MAC/IP routes
+ * in this EVI
+ */
+ memset(&tmp, 0, sizeof(struct evpn_remote_ip));
+
+ p = &bnc->prefix;
+ if (p->family == AF_INET) {
+ tmp.addr.ipa_type = IPADDR_V4;
+ memcpy(&(tmp.addr.ipaddr_v4), &(p->u.prefix4),
+ sizeof(struct in_addr));
+ } else if (p->family == AF_INET6) {
+ tmp.addr.ipa_type = IPADDR_V6;
+ memcpy(&(tmp.addr.ipaddr_v6), &(p->u.prefix6),
+ sizeof(struct in6_addr));
+ } else
+ return false;
+
+ if (hash_lookup(vpn->remote_ip_hash, &tmp) == NULL)
+ return false;
+
+ return true;
+}
+
+/* Resolve/Unresolve nexthops when a MAC/IP route is added/deleted */
+static void bgp_evpn_remote_ip_process_nexthops(struct bgpevpn *vpn,
+ struct ipaddr *addr,
+ bool resolve)
+{
+ afi_t afi;
+ struct prefix p;
+ struct bgp_nexthop_cache *bnc;
+ struct bgp_nexthop_cache_head *tree = NULL;
+
+ if (!vpn->bgp_vrf || vpn->svi_ifindex == 0)
+ return;
+
+ memset(&p, 0, sizeof(struct prefix));
+
+ if (addr->ipa_type == IPADDR_V4) {
+ afi = AFI_IP;
+ p.family = AF_INET;
+ memcpy(&(p.u.prefix4), &(addr->ipaddr_v4),
+ sizeof(struct in_addr));
+ p.prefixlen = IPV4_MAX_BITLEN;
+ } else if (addr->ipa_type == IPADDR_V6) {
+ afi = AFI_IP6;
+ p.family = AF_INET6;
+ memcpy(&(p.u.prefix6), &(addr->ipaddr_v6),
+ sizeof(struct in6_addr));
+ p.prefixlen = IPV6_MAX_BITLEN;
+ } else
+ return;
+
+ tree = &vpn->bgp_vrf->nexthop_cache_table[afi];
+ bnc = bnc_find(tree, &p, 0);
+
+ if (!bnc || !bnc->is_evpn_gwip_nexthop)
+ return;
+
+ if (!bnc->nexthop || bnc->nexthop->ifindex != vpn->svi_ifindex)
+ return;
+
+ if (BGP_DEBUG(nht, NHT)) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&bnc->prefix, buf, sizeof(buf));
+ zlog_debug("%s(%u): vni %u mac/ip %s for NH %s",
+ vpn->bgp_vrf->name_pretty, vpn->tenant_vrf_id,
+ vpn->vni, (resolve ? "add" : "delete"), buf);
+ }
+
+ /*
+ * MAC/IP route or SVI or tenant vrf being added to EVI.
+ * Set nexthop as valid only if it is already L3 reachable
+ */
+ if (resolve && bnc->flags & BGP_NEXTHOP_EVPN_INCOMPLETE) {
+ bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
+ bnc->flags |= BGP_NEXTHOP_VALID;
+ bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
+ evaluate_paths(bnc);
+ }
+
+ /* MAC/IP route or SVI or tenant vrf being deleted from EVI */
+ if (!resolve && bnc->flags & BGP_NEXTHOP_VALID) {
+ bnc->flags &= ~BGP_NEXTHOP_VALID;
+ bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE;
+ bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
+ evaluate_paths(bnc);
+ }
+}
+
+void bgp_evpn_handle_resolve_overlay_index_set(struct hash_bucket *bucket,
+ void *arg)
+{
+ struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
+ struct bgp_dest *dest;
+ struct bgp_path_info *pi;
+
+ bgp_evpn_remote_ip_hash_init(vpn);
+
+ for (dest = bgp_table_top(vpn->route_table); dest;
+ dest = bgp_route_next(dest))
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
+ bgp_evpn_remote_ip_hash_add(vpn, pi);
+}
+
+void bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket,
+ void *arg)
+{
+ struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
+
+ bgp_evpn_remote_ip_hash_destroy(vpn);
+}
diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h
index 83a6dd84c..eec746e3b 100644
--- a/bgpd/bgp_evpn.h
+++ b/bgpd/bgp_evpn.h
@@ -63,14 +63,18 @@ static inline int advertise_type5_routes(struct bgp *bgp_vrf,
if (!bgp_vrf->l3vni)
return 0;
- if (afi == AFI_IP &&
- CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST))
+ if ((afi == AFI_IP)
+ && ((CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST))
+ || (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP))))
return 1;
- if (afi == AFI_IP6 &&
- CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
+ if ((afi == AFI_IP6)
+ && ((CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST))
+ || (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP))))
return 1;
return 0;
@@ -152,6 +156,14 @@ static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
return true;
}
+static inline bool evpn_resolve_overlay_index(void)
+{
+ struct bgp *bgp = NULL;
+
+ bgp = bgp_get_evpn();
+ return bgp ? bgp->resolve_overlay_index : false;
+}
+
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
const struct prefix *p,
struct attr *src_attr, afi_t afi,
@@ -198,7 +210,8 @@ extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip,
vrf_id_t tenant_vrf_id,
- struct in_addr mcast_grp);
+ struct in_addr mcast_grp,
+ ifindex_t svi_ifindex);
extern void bgp_evpn_flood_control_change(struct bgp *bgp);
extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp);
extern void bgp_evpn_cleanup(struct bgp *bgp);
@@ -206,4 +219,15 @@ extern void bgp_evpn_init(struct bgp *bgp);
extern int bgp_evpn_get_type5_prefixlen(const struct prefix *pfx);
extern bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx);
extern void update_advertise_vrf_routes(struct bgp *bgp_vrf);
+extern void bgp_evpn_show_remote_ip_hash(struct hash_bucket *bucket,
+ void *args);
+extern void bgp_evpn_show_vni_svi_hash(struct hash_bucket *bucket, void *args);
+extern bool bgp_evpn_is_gateway_ip_resolved(struct bgp_nexthop_cache *bnc);
+extern void
+bgp_evpn_handle_resolve_overlay_index_set(struct hash_bucket *bucket,
+ void *arg);
+extern void
+bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket,
+ void *arg);
+
#endif /* _QUAGGA_BGP_EVPN_H */
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index debed9f68..c46f34bf7 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -62,6 +62,7 @@ RB_PROTOTYPE(bgp_es_evi_rb_head, bgp_evpn_es_evi, rb_node,
struct bgpevpn {
vni_t vni;
vrf_id_t tenant_vrf_id;
+ ifindex_t svi_ifindex;
uint32_t flags;
#define VNI_FLAG_CFGD 0x1 /* VNI is user configured */
#define VNI_FLAG_LIVE 0x2 /* VNI is "live" */
@@ -102,6 +103,15 @@ struct bgpevpn {
struct list *import_rtl;
struct list *export_rtl;
+ /*
+ * EVPN route that uses gateway IP overlay index as its nexthop
+ * needs to do a recursive lookup.
+ * A remote MAC/IP entry should be present for the gateway IP.
+ * Maintain a hash of the addresses received via remote MAC/IP routes
+ * for efficient gateway IP recursive lookup in this EVI
+ */
+ struct hash *remote_ip_hash;
+
/* Route table for EVPN routes for
* this VNI. */
struct bgp_table *route_table;
@@ -178,6 +188,12 @@ struct bgp_evpn_info {
bool is_anycast_mac;
};
+/* This structure defines an entry in remote_ip_hash */
+struct evpn_remote_ip {
+ struct ipaddr addr;
+ struct list *macip_path_list;
+};
+
static inline int is_vrf_rd_configured(struct bgp *bgp_vrf)
{
return (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD));
@@ -612,7 +628,8 @@ extern struct bgpevpn *bgp_evpn_lookup_vni(struct bgp *bgp, vni_t vni);
extern struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip,
vrf_id_t tenant_vrf_id,
- struct in_addr mcast_grp);
+ struct in_addr mcast_grp,
+ ifindex_t svi_ifindex);
extern void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn);
extern bool bgp_evpn_lookup_l3vni_l2vni_table(vni_t vni);
extern int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn);
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 2a7c2ec85..bc66fb9c1 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -59,6 +59,17 @@ struct vni_walk_ctx {
int detail;
};
+int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc, int *oly_idx,
+ enum overlay_index_type *oly)
+{
+ *oly = OVERLAY_INDEX_TYPE_NONE;
+ if (argv_find(argv, argc, "gateway-ip", oly_idx)) {
+ if (oly)
+ *oly = OVERLAY_INDEX_GATEWAY_IP;
+ }
+ return 1;
+}
+
static void display_vrf_import_rt(struct vty *vty, struct vrf_irt_node *irt,
json_object *json)
{
@@ -520,6 +531,9 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
else
json_object_string_add(json, "advertiseSviMacIp",
"Disabled");
+ json_object_string_add(
+ json, "sviInterface",
+ ifindex2ifname(vpn->svi_ifindex, vpn->tenant_vrf_id));
} else {
vty_out(vty, "VNI: %d", vpn->vni);
if (is_vni_live(vpn))
@@ -553,6 +567,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
else
vty_out(vty, " Advertise-svi-macip : %s\n",
"Disabled");
+ vty_out(vty, " SVI interface : %s\n",
+ ifindex2ifname(vpn->svi_ifindex, vpn->tenant_vrf_id));
}
if (!json)
@@ -2279,7 +2295,7 @@ static struct bgpevpn *evpn_create_update_vni(struct bgp *bgp, vni_t vni)
/* tenant vrf will be updated when we get local_vni_add from
* zebra
*/
- vpn = bgp_evpn_new(bgp, vni, bgp->router_id, 0, mcast_grp);
+ vpn = bgp_evpn_new(bgp, vni, bgp->router_id, 0, mcast_grp, 0);
if (!vpn) {
flog_err(
EC_BGP_VNI,
@@ -3286,6 +3302,28 @@ static void evpn_unset_advertise_all_vni(struct bgp *bgp)
bgp_evpn_cleanup_on_disable(bgp);
}
+/* Set resolve overlay index flag */
+static void bgp_evpn_set_unset_resolve_overlay_index(struct bgp *bgp, bool set)
+{
+ if (set == bgp->resolve_overlay_index)
+ return;
+
+ if (set) {
+ bgp->resolve_overlay_index = true;
+ hash_iterate(bgp->vnihash,
+ (void (*)(struct hash_bucket *, void *))
+ bgp_evpn_handle_resolve_overlay_index_set,
+ NULL);
+ } else {
+ hash_iterate(
+ bgp->vnihash,
+ (void (*)(struct hash_bucket *, void *))
+ bgp_evpn_handle_resolve_overlay_index_unset,
+ NULL);
+ bgp->resolve_overlay_index = false;
+ }
+}
+
/*
* EVPN - use RFC8365 to auto-derive RT
*/
@@ -3784,10 +3822,11 @@ DEFUN_HIDDEN (no_bgp_evpn_advertise_vni_subnet,
DEFUN (bgp_evpn_advertise_type5,
bgp_evpn_advertise_type5_cmd,
- "advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR " [route-map WORD]",
+ "advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR " [gateway-ip] [route-map WORD]",
"Advertise prefix routes\n"
BGP_AFI_HELP_STR
BGP_SAFI_HELP_STR
+ "advertise gateway IP overlay index\n"
"route-map for filtering specific routes\n"
"Name of the route map\n")
{
@@ -3799,9 +3838,14 @@ DEFUN (bgp_evpn_advertise_type5,
safi_t safi = 0;
int ret = 0;
int rmap_changed = 0;
+ enum overlay_index_type oly = OVERLAY_INDEX_TYPE_NONE;
+ int idx_oly = 0;
+ bool adv_flag_changed = false;
argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
+ argv_find_and_parse_oly_idx(argv, argc, &idx_oly, &oly);
+
ret = argv_find(argv, argc, "route-map", &idx_rmap);
if (ret) {
if (!bgp_vrf->adv_cmd_rmap[afi][safi].name)
@@ -3826,39 +3870,149 @@ DEFUN (bgp_evpn_advertise_type5,
return CMD_WARNING;
}
+ if ((oly != OVERLAY_INDEX_TYPE_NONE)
+ && (oly != OVERLAY_INDEX_GATEWAY_IP)) {
+ vty_out(vty, "%%Unknown overlay-index type specified");
+ return CMD_WARNING;
+ }
+
if (afi == AFI_IP) {
+ if ((!CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST))
+ && (!CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP))) {
+
+ /*
+ * this is the case for first time ever configuration
+ * adv ipv4 unicast is enabled for the first time.
+ * So no need to reset any flag
+ */
+ if (oly == OVERLAY_INDEX_TYPE_NONE)
+ SET_FLAG(
+ bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST);
+ else if (oly == OVERLAY_INDEX_GATEWAY_IP)
+ SET_FLAG(
+ bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP);
+ } else if ((oly == OVERLAY_INDEX_TYPE_NONE)
+ && (!CHECK_FLAG(
+ bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST))) {
+
+ /*
+ * This is modify case from gateway-ip
+ * to no overlay index
+ */
+ adv_flag_changed = true;
+ UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP);
+ SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST);
+ } else if ((oly == OVERLAY_INDEX_GATEWAY_IP)
+ && (!CHECK_FLAG(
+ bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP))) {
+
+ /*
+ * This is modify case from no overlay index
+ * to gateway-ip
+ */
+ adv_flag_changed = true;
+ UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST);
+ SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP);
+ } else {
- /* if we are already advertising ipv4 prefix as type-5
- * nothing to do
- */
- if (!rmap_changed &&
- CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST))
- return CMD_WARNING;
- SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST);
+ /*
+ * Command is issued with the same option
+ * (no overlay index or gateway-ip) which was
+ * already configured. So nothing to do.
+ * However, route-map may have been modified.
+ * check if route-map has been modified.
+ * If not, return an error
+ */
+ if (!rmap_changed)
+ return CMD_WARNING;
+ }
} else {
+ if ((!CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST))
+ && (!CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP))) {
+
+ /*
+ * this is the case for first time ever configuration
+ * adv ipv6 unicast is enabled for the first time.
+ * So no need to reset any flag
+ */
+ if (oly == OVERLAY_INDEX_TYPE_NONE)
+ SET_FLAG(
+ bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST);
+ else if (oly == OVERLAY_INDEX_GATEWAY_IP)
+ SET_FLAG(
+ bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP);
+ } else if ((oly == OVERLAY_INDEX_TYPE_NONE)
+ && (!CHECK_FLAG(
+ bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST))) {
+
+ /*
+ * This is modify case from gateway-ip
+ * to no overlay index
+ */
+ adv_flag_changed = true;
+ UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP);
+ SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST);
+ } else if ((oly == OVERLAY_INDEX_GATEWAY_IP)
+ && (!CHECK_FLAG(
+ bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP))) {
+
+ /*
+ * This is modify case from no overlay index
+ * to gateway-ip
+ */
+ adv_flag_changed = true;
+ UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST);
+ SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP);
+ } else {
- /* if we are already advertising ipv6 prefix as type-5
- * nothing to do
- */
- if (!rmap_changed &&
- CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
- return CMD_WARNING;
- SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST);
+ /*
+ * Command is issued with the same option
+ * (no overlay index or gateway-ip) which was
+ * already configured. So nothing to do.
+ * However, route-map may have been modified.
+ * check if route-map has been modified.
+ * If not, return an error
+ */
+ if (!rmap_changed)
+ return CMD_WARNING;
+ }
}
- if (rmap_changed) {
+ if ((rmap_changed) || (adv_flag_changed)) {
+
+ /* If either of these are changed, then FRR needs to
+ * withdraw already advertised type5 routes.
+ */
bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
- if (bgp_vrf->adv_cmd_rmap[afi][safi].name) {
- XFREE(MTYPE_ROUTE_MAP_NAME,
- bgp_vrf->adv_cmd_rmap[afi][safi].name);
- route_map_counter_decrement(
+ if (rmap_changed) {
+ if (bgp_vrf->adv_cmd_rmap[afi][safi].name) {
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ bgp_vrf->adv_cmd_rmap[afi][safi].name);
+ route_map_counter_decrement(
bgp_vrf->adv_cmd_rmap[afi][safi].map);
- bgp_vrf->adv_cmd_rmap[afi][safi].name = NULL;
- bgp_vrf->adv_cmd_rmap[afi][safi].map = NULL;
+ bgp_vrf->adv_cmd_rmap[afi][safi].name = NULL;
+ bgp_vrf->adv_cmd_rmap[afi][safi].map = NULL;
+ }
}
}
@@ -3912,22 +4066,30 @@ DEFUN (no_bgp_evpn_advertise_type5,
/* if we are not advertising ipv4 prefix as type-5
* nothing to do
*/
- if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) {
+ if ((CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST)) ||
+ (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP))) {
bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST);
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST);
+ UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP);
}
} else {
/* if we are not advertising ipv6 prefix as type-5
* nothing to do
*/
- if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) {
+ if ((CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST)) ||
+ (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP))){
bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST);
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST);
+ UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP);
}
}
@@ -3977,6 +4139,23 @@ DEFPY (bgp_evpn_ead_evi_tx_disable,
return CMD_SUCCESS;
}
+DEFPY (bgp_evpn_enable_resolve_overlay_index,
+ bgp_evpn_enable_resolve_overlay_index_cmd,
+ "[no$no] enable-resolve-overlay-index",
+ NO_STR
+ "Enable Recursive Resolution of type-5 route overlay index\n")
+{
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+
+ if (bgp != bgp_get_evpn()) {
+ vty_out(vty, "This command is only supported under EVPN VRF\n");
+ return CMD_WARNING;
+ }
+
+ bgp_evpn_set_unset_resolve_overlay_index(bgp, no ? false : true);
+ return CMD_SUCCESS;
+}
+
DEFPY (bgp_evpn_advertise_pip_ip_mac,
bgp_evpn_advertise_pip_ip_mac_cmd,
"[no$no] advertise-pip [ip <A.B.C.D> [mac <X:X:X:X:X:X|X:X:X:X:X:X/M>]]",
@@ -4220,6 +4399,61 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
return CMD_SUCCESS;
}
+DEFUN_HIDDEN(show_bgp_l2vpn_evpn_vni_remote_ip_hash,
+ show_bgp_l2vpn_evpn_vni_remote_ip_hash_cmd,
+ "show bgp l2vpn evpn vni remote-ip-hash",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Show VNI\n"
+ "Remote IP hash\n")
+{
+ struct bgp *bgp_evpn;
+ int idx = 0;
+
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn)
+ return CMD_WARNING;
+
+ if (!argv_find(argv, argc, "evpn", &idx))
+ return CMD_WARNING;
+
+ hash_iterate(bgp_evpn->vnihash,
+ (void (*)(struct hash_bucket *,
+ void *))bgp_evpn_show_remote_ip_hash,
+ vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN(show_bgp_l2vpn_evpn_vni_svi_hash,
+ show_bgp_l2vpn_evpn_vni_svi_hash_cmd,
+ "show bgp l2vpn evpn vni-svi-hash",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Show vni-svi-hash\n")
+{
+ struct bgp *bgp_evpn;
+ int idx = 0;
+
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn)
+ return CMD_WARNING;
+
+ if (!argv_find(argv, argc, "evpn", &idx))
+ return CMD_WARNING;
+
+ hash_iterate(bgp_evpn->vni_svi_hash,
+ (void (*)(struct hash_bucket *,
+ void *))bgp_evpn_show_vni_svi_hash,
+ vty);
+
+ return CMD_SUCCESS;
+}
+
DEFPY(show_bgp_l2vpn_evpn_es_evi,
show_bgp_l2vpn_evpn_es_evi_cmd,
"show bgp l2vpn evpn es-evi [vni (1-16777215)$vni] [json$uj] [detail$detail]",
@@ -6061,6 +6295,9 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
if (bgp->evpn_info->advertise_svi_macip)
vty_out(vty, " advertise-svi-ip\n");
+ if (bgp->resolve_overlay_index)
+ vty_out(vty, " enable-resolve-overlay-index\n");
+
if (bgp_mh_info->host_routes_use_l3nhg !=
BGP_EVPN_MH_USE_ES_L3NHG_DEF) {
if (bgp_mh_info->host_routes_use_l3nhg)
@@ -6107,21 +6344,40 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
vty_out(vty, " flooding disable\n");
if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) {
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST)) {
if (bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name)
vty_out(vty, " advertise ipv4 unicast route-map %s\n",
bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name);
else
- vty_out(vty, " advertise ipv4 unicast\n");
+ vty_out(vty,
+ " advertise ipv4 unicast\n");
+ } else if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)) {
+ if (bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name)
+ vty_out(vty,
+ " advertise ipv4 unicast gateway-ip route-map %s\n",
+ bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name);
+ else
+ vty_out(vty, " advertise ipv4 unicast gateway-ip\n");
}
if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) {
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST)) {
if (bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name)
- vty_out(vty, " advertise ipv6 unicast route-map %s\n",
+ vty_out(vty,
+ " advertise ipv6 unicast route-map %s\n",
+ bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name);
+ else
+ vty_out(vty,
+ " advertise ipv6 unicast\n");
+ } else if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP)) {
+ if (bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name)
+ vty_out(vty,
+ " advertise ipv6 unicast gateway-ip route-map %s\n",
bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name);
else
- vty_out(vty, " advertise ipv6 unicast\n");
+ vty_out(vty, " advertise ipv6 unicast gateway-ip\n");
}
if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
@@ -6230,6 +6486,8 @@ void bgp_ethernetvpn_init(void)
install_element(BGP_EVPN_NODE, &bgp_evpn_use_es_l3nhg_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_ead_evi_rx_disable_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_ead_evi_tx_disable_cmd);
+ install_element(BGP_EVPN_NODE,
+ &bgp_evpn_enable_resolve_overlay_index_cmd);
/* test commands */
install_element(BGP_EVPN_NODE, &test_es_add_cmd);
@@ -6241,6 +6499,8 @@ void bgp_ethernetvpn_init(void)
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_vrf_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_nh_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_remote_ip_hash_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_svi_hash_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_summary_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_cmd);
diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h
index 33f6e4f1b..137365ddb 100644
--- a/bgpd/bgp_evpn_vty.h
+++ b/bgpd/bgp_evpn_vty.h
@@ -28,6 +28,10 @@ extern void bgp_ethernetvpn_init(void);
#define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n"
#define EVPN_HELP_STR "Ethernet Virtual Private Network\n"
+extern int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc,
+ int *oly_idx,
+ enum overlay_index_type *oly);
+
/* Parse type from "type <ead|1|...>", return -1 on failure */
extern int bgp_evpn_cli_parse_type(int *type, struct cmd_token **argv,
int argc);
diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c
index 3d7bc08ac..02b7e6486 100644
--- a/bgpd/bgp_mac.c
+++ b/bgpd/bgp_mac.c
@@ -200,8 +200,8 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
AFI_L2VPN, SAFI_EVPN, &prd,
p, label_pnt, num_labels,
pi->addpath_rx_id ? 1 : 0,
- pi->addpath_rx_id, pfx_buf,
- sizeof(pfx_buf));
+ pi->addpath_rx_id, NULL,
+ pfx_buf, sizeof(pfx_buf));
zlog_debug(
"%s skip update of %s marked as removed",
peer->host, pfx_buf);
diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c
index eb85936f0..196e56a93 100644
--- a/bgpd/bgp_memory.c
+++ b/bgpd/bgp_memory.c
@@ -144,3 +144,4 @@ DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie");
DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service");
DEFINE_MTYPE(BGPD, BGP_SRV6_SID, "BGP srv6 segment-id");
DEFINE_MTYPE(BGPD, BGP_SRV6_FUNCTION, "BGP srv6 function");
+DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry");
diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h
index c5ba37149..0021fa9c3 100644
--- a/bgpd/bgp_memory.h
+++ b/bgpd/bgp_memory.h
@@ -142,4 +142,6 @@ DECLARE_MTYPE(BGP_SRV6_VPN);
DECLARE_MTYPE(BGP_SRV6_SID);
DECLARE_MTYPE(BGP_SRV6_FUNCTION);
+DECLARE_MTYPE(EVPN_REMOTE_IP);
+
#endif /* _QUAGGA_BGP_MEMORY_H */
diff --git a/bgpd/bgp_nb_config.c b/bgpd/bgp_nb_config.c
index 5189d7ba8..ab22aee1c 100644
--- a/bgpd/bgp_nb_config.c
+++ b/bgpd/bgp_nb_config.c
@@ -182,24 +182,52 @@ int bgp_router_destroy(struct nb_cb_destroy_args *args)
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) {
if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
continue;
- if (CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST],
- BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) ||
- CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST],
- BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) ||
- CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST],
- BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) ||
- CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST],
- BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) ||
- CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST],
- BGP_CONFIG_VRF_TO_VRF_EXPORT) ||
- CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST],
- BGP_CONFIG_VRF_TO_VRF_EXPORT) ||
- (bgp == bgp_get_evpn() &&
- (CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST) ||
- CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
- BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))) ||
- (tmp_bgp->vnihash && hashcount(tmp_bgp->vnihash))) {
+ if (CHECK_FLAG(tmp_bgp->af_flags[AFI_IP]
+ [SAFI_UNICAST],
+ BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)
+ || CHECK_FLAG(
+ tmp_bgp->af_flags[AFI_IP6]
+ [SAFI_UNICAST],
+ BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)
+ || CHECK_FLAG(
+ tmp_bgp->af_flags[AFI_IP]
+ [SAFI_UNICAST],
+ BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)
+ || CHECK_FLAG(
+ tmp_bgp->af_flags[AFI_IP6]
+ [SAFI_UNICAST],
+ BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)
+ || CHECK_FLAG(
+ tmp_bgp->af_flags[AFI_IP]
+ [SAFI_UNICAST],
+ BGP_CONFIG_VRF_TO_VRF_EXPORT)
+ || CHECK_FLAG(
+ tmp_bgp->af_flags[AFI_IP6]
+ [SAFI_UNICAST],
+ BGP_CONFIG_VRF_TO_VRF_EXPORT)
+ || (bgp == bgp_get_evpn()
+ && (CHECK_FLAG(
+ tmp_bgp->af_flags
+ [AFI_L2VPN]
+ [SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST)
+ || CHECK_FLAG(
+ tmp_bgp->af_flags
+ [AFI_L2VPN]
+ [SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)
+ || CHECK_FLAG(
+ tmp_bgp->af_flags
+ [AFI_L2VPN]
+ [SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST)
+ || CHECK_FLAG(
+ tmp_bgp->af_flags
+ [AFI_L2VPN]
+ [SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP)))
+ || (tmp_bgp->vnihash
+ && hashcount(tmp_bgp->vnihash))) {
snprintf(
args->errmsg, args->errmsg_len,
"Cannot delete default BGP instance. Dependent VRF instances exist\n");
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index c417dda39..e7bad42f9 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -835,6 +835,18 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
bnc->metric, bnc->path_count);
if (peer)
vty_out(vty, ", peer %s", peer->host);
+ if (bnc->is_evpn_gwip_nexthop)
+ vty_out(vty, " EVPN Gateway IP");
+ vty_out(vty, "\n");
+ bgp_show_nexthops_detail(vty, bgp, bnc);
+ } else if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) {
+ vty_out(vty,
+ " %s overlay index unresolved [IGP metric %d], #paths %d",
+ inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix,
+ buf, sizeof(buf)),
+ bnc->metric, bnc->path_count);
+ if (bnc->is_evpn_gwip_nexthop)
+ vty_out(vty, " EVPN Gateway IP");
vty_out(vty, "\n");
bgp_show_nexthops_detail(vty, bgp, bnc);
} else {
@@ -844,6 +856,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
bnc->path_count);
if (peer)
vty_out(vty, ", peer %s", peer->host);
+ if (bnc->is_evpn_gwip_nexthop)
+ vty_out(vty, " EVPN Gateway IP");
vty_out(vty, "\n");
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
vty_out(vty, " Must be Connected\n");
diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h
index fe0a9646a..16c2b6c65 100644
--- a/bgpd/bgp_nexthop.h
+++ b/bgpd/bgp_nexthop.h
@@ -56,6 +56,10 @@ struct bgp_nexthop_cache {
time_t last_update;
uint16_t flags;
+/*
+ * If the nexthop is EVPN gateway IP NH, VALID flag is set only if the nexthop
+ * is RIB reachable as well as MAC/IP is present
+ */
#define BGP_NEXTHOP_VALID (1 << 0)
#define BGP_NEXTHOP_REGISTERED (1 << 1)
#define BGP_NEXTHOP_CONNECTED (1 << 2)
@@ -64,11 +68,29 @@ struct bgp_nexthop_cache {
#define BGP_STATIC_ROUTE_EXACT_MATCH (1 << 5)
#define BGP_NEXTHOP_LABELED_VALID (1 << 6)
+/*
+ * This flag is added for EVPN gateway IP nexthops.
+ * If the nexthop is RIB reachable, but a MAC/IP is not yet
+ * resolved, this flag is set.
+ * Following table explains the combination of L3 and L2 reachability w.r.t.
+ * VALID and INCOMPLETE flags
+ *
+ * | MACIP resolved | MACIP unresolved
+ *----------------|----------------|------------------
+ * L3 reachable | VALID = 1 | VALID = 0
+ * | INCOMPLETE = 0 | INCOMPLETE = 1
+ * ---------------|----------------|--------------------
+ * L3 unreachable | VALID = 0 | VALID = 0
+ * | INCOMPLETE = 0 | INCOMPLETE = 0
+ */
+#define BGP_NEXTHOP_EVPN_INCOMPLETE (1 << 7)
+
uint16_t change_flags;
#define BGP_NEXTHOP_CHANGED (1 << 0)
#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1)
#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2)
+#define BGP_NEXTHOP_MACIP_CHANGED (1 << 3)
/* Back pointer to the cache tree this entry belongs to. */
struct bgp_nexthop_cache_head *tree;
@@ -79,6 +101,11 @@ struct bgp_nexthop_cache {
LIST_HEAD(path_list, bgp_path_info) paths;
unsigned int path_count;
struct bgp *bgp;
+
+ /* This flag is set to TRUE for a bnc that is gateway IP overlay index
+ * nexthop.
+ */
+ bool is_evpn_gwip_nexthop;
};
extern int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a,
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 4b4a3716e..742ef217d 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -53,7 +53,6 @@ static void register_zebra_rnh(struct bgp_nexthop_cache *bnc,
int is_bgp_static_route);
static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc,
int is_bgp_static_route);
-static void evaluate_paths(struct bgp_nexthop_cache *bnc);
static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p);
static int bgp_nht_ifp_initial(struct thread *thread);
@@ -244,6 +243,9 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
}
}
+ if (pi && is_route_parent_evpn(pi))
+ bnc->is_evpn_gwip_nexthop = true;
+
if (is_bgp_static_route) {
SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
@@ -331,7 +333,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
return 1;
else if (safi == SAFI_UNICAST && pi
&& pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra
- && pi->extra->num_labels) {
+ && pi->extra->num_labels && !bnc->is_evpn_gwip_nexthop) {
return bgp_isvalid_labeled_nexthop(bnc);
} else
return (bgp_isvalid_nexthop(bnc));
@@ -387,6 +389,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
struct nexthop *nhlist_head = NULL;
struct nexthop *nhlist_tail = NULL;
int i;
+ bool evpn_resolved = false;
bnc->last_update = bgp_clock();
bnc->change_flags = 0;
@@ -417,7 +420,8 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
if (!bnc->nexthop_num)
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
- bnc->flags |= BGP_NEXTHOP_VALID;
+ if (!bnc->is_evpn_gwip_nexthop)
+ bnc->flags |= BGP_NEXTHOP_VALID;
bnc->metric = nhr->metric;
bnc->nexthop_num = nhr->nexthop_num;
@@ -488,7 +492,40 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
}
bnc_nexthop_free(bnc);
bnc->nexthop = nhlist_head;
+
+ /*
+ * Gateway IP nexthop is L3 reachable. Mark it as
+ * BGP_NEXTHOP_VALID only if it is recursively resolved with a
+ * remote EVPN RT-2.
+ * Else, mark it as BGP_NEXTHOP_EVPN_INCOMPLETE.
+ * When its mapping with EVPN RT-2 is established, unset
+ * BGP_NEXTHOP_EVPN_INCOMPLETE and set BGP_NEXTHOP_VALID.
+ */
+ if (bnc->is_evpn_gwip_nexthop) {
+ evpn_resolved = bgp_evpn_is_gateway_ip_resolved(bnc);
+
+ if (BGP_DEBUG(nht, NHT)) {
+ char buf2[PREFIX2STR_BUFFER];
+
+ prefix2str(&bnc->prefix, buf2, sizeof(buf2));
+ zlog_debug(
+ "EVPN gateway IP %s recursive MAC/IP lookup %s",
+ buf2,
+ (evpn_resolved ? "successful"
+ : "failed"));
+ }
+
+ if (evpn_resolved) {
+ bnc->flags |= BGP_NEXTHOP_VALID;
+ bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
+ bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
+ } else {
+ bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE;
+ bnc->flags &= ~BGP_NEXTHOP_VALID;
+ }
+ }
} else {
+ bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
bnc->flags &= ~BGP_NEXTHOP_VALID;
bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID;
bnc->nexthop_num = nhr->nexthop_num;
@@ -694,6 +731,7 @@ void bgp_cleanup_nexthops(struct bgp *bgp)
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE);
}
}
}
@@ -888,7 +926,7 @@ static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc,
* RETURNS:
* void.
*/
-static void evaluate_paths(struct bgp_nexthop_cache *bnc)
+void evaluate_paths(struct bgp_nexthop_cache *bnc)
{
struct bgp_dest *dest;
struct bgp_path_info *path;
@@ -942,16 +980,18 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
* In case of unicast routes that were imported from vpn
* and that have labels, they are valid only if there are
* nexthops with labels
+ *
+ * If the nexthop is EVPN gateway-IP,
+ * do not check for a valid label.
*/
bool bnc_is_valid_nexthop = false;
bool path_valid = false;
- if (safi == SAFI_UNICAST &&
- path->sub_type == BGP_ROUTE_IMPORTED &&
- path->extra &&
- path->extra->num_labels) {
-
+ if (safi == SAFI_UNICAST && path->sub_type == BGP_ROUTE_IMPORTED
+ && path->extra && path->extra->num_labels
+ && (path->attr->evpn_overlay.type
+ != OVERLAY_INDEX_GATEWAY_IP)) {
bnc_is_valid_nexthop =
bgp_isvalid_labeled_nexthop(bnc) ? true : false;
} else {
diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h
index 9268b225c..e006aa446 100644
--- a/bgpd/bgp_nht.h
+++ b/bgpd/bgp_nht.h
@@ -90,6 +90,7 @@ extern void bgp_nht_register_nexthops(struct bgp *bgp);
*/
extern void bgp_nht_reg_enhe_cap_intfs(struct peer *peer);
extern void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer);
+extern void evaluate_paths(struct bgp_nexthop_cache *bnc);
/* APIs for setting up and allocating L3 nexthop group ids */
extern uint32_t bgp_l3nhg_id_alloc(void);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index cf651185a..4637cef3e 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -3451,23 +3451,6 @@ struct bgp_path_info *info_make(int type, int sub_type, unsigned short instance,
return new;
}
-static void overlay_index_update(struct attr *attr,
- union gw_addr *gw_ip)
-{
- if (!attr)
- return;
- if (gw_ip == NULL) {
- struct bgp_route_evpn eo;
-
- memset(&eo, 0, sizeof(eo));
- bgp_attr_set_evpn_overlay(attr, &eo);
- } else {
- struct bgp_route_evpn eo = {.gw_ip = *gw_ip};
-
- bgp_attr_set_evpn_overlay(attr, &eo);
- }
-}
-
static bool overlay_index_equal(afi_t afi, struct bgp_path_info *path,
union gw_addr *gw_ip)
{
@@ -3650,6 +3633,11 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (has_valid_label)
assert(label != NULL);
+ /* Update overlay index of the attribute */
+ if (afi == AFI_L2VPN && evpn)
+ memcpy(&attr->evpn_overlay, evpn,
+ sizeof(struct bgp_route_evpn));
+
/* When peer's soft reconfiguration enabled. Record input packet in
Adj-RIBs-In. */
if (!soft_reconfig
@@ -3825,12 +3813,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
goto filtered;
}
- /* Update Overlay Index */
- if (afi == AFI_L2VPN) {
- overlay_index_update(&new_attr,
- evpn == NULL ? NULL : &evpn->gw_ip);
- }
-
/* The flag BGP_NODE_FIB_INSTALL_PENDING is for the following
* condition :
* Suppress fib is enabled
@@ -3865,10 +3847,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
&& (!has_valid_label
|| memcmp(&(bgp_path_info_extra_get(pi))->label, label,
num_labels * sizeof(mpls_label_t))
- == 0)
- && (overlay_index_equal(
- afi, pi,
- evpn == NULL ? NULL : &evpn->gw_ip))) {
+ == 0)) {
if (get_active_bdc_from_pi(pi, afi, safi)
&& peer->sort == BGP_PEER_EBGP
&& CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
@@ -3876,7 +3855,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bgp_debug_rdpfxpath2str(
afi, safi, prd, p, label,
num_labels, addpath_id ? 1 : 0,
- addpath_id, pfx_buf,
+ addpath_id, evpn, pfx_buf,
sizeof(pfx_buf));
zlog_debug("%s rcvd %s", peer->host,
pfx_buf);
@@ -3902,7 +3881,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bgp_debug_rdpfxpath2str(
afi, safi, prd, p, label,
num_labels, addpath_id ? 1 : 0,
- addpath_id, pfx_buf,
+ addpath_id, evpn, pfx_buf,
sizeof(pfx_buf));
zlog_debug(
"%s rcvd %s...duplicate ignored",
@@ -3929,8 +3908,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (bgp_debug_update(peer, p, NULL, 1)) {
bgp_debug_rdpfxpath2str(
afi, safi, prd, p, label, num_labels,
- addpath_id ? 1 : 0, addpath_id, pfx_buf,
- sizeof(pfx_buf));
+ addpath_id ? 1 : 0, addpath_id, evpn,
+ pfx_buf, sizeof(pfx_buf));
zlog_debug(
"%s rcvd %s, flapped quicker than processing",
peer->host, pfx_buf);
@@ -3943,7 +3922,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (bgp_debug_update(peer, p, NULL, 1)) {
bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
num_labels, addpath_id ? 1 : 0,
- addpath_id, pfx_buf,
+ addpath_id, evpn, pfx_buf,
sizeof(pfx_buf));
zlog_debug("%s rcvd %s", peer->host, pfx_buf);
}
@@ -4216,8 +4195,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
- addpath_id ? 1 : 0, addpath_id, pfx_buf,
- sizeof(pfx_buf));
+ addpath_id ? 1 : 0, addpath_id, evpn,
+ pfx_buf, sizeof(pfx_buf));
zlog_debug("%s rcvd %s", peer->host, pfx_buf);
}
@@ -4248,11 +4227,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
}
- /* Update Overlay Index */
- if (afi == AFI_L2VPN) {
- overlay_index_update(new->attr,
- evpn == NULL ? NULL : &evpn->gw_ip);
- }
/* Nexthop reachability check. */
if (((afi == AFI_IP || afi == AFI_IP6)
&& (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST))
@@ -4362,8 +4336,8 @@ filtered:
}
bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
- addpath_id ? 1 : 0, addpath_id, pfx_buf,
- sizeof(pfx_buf));
+ addpath_id ? 1 : 0, addpath_id, evpn,
+ pfx_buf, sizeof(pfx_buf));
zlog_debug("%s rcvd UPDATE about %s -- DENIED due to: %s",
peer->host, pfx_buf, reason);
}
@@ -4447,8 +4421,8 @@ int bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (bgp_debug_update(peer, p, NULL, 1)) {
bgp_debug_rdpfxpath2str(
afi, safi, prd, p, label, num_labels,
- addpath_id ? 1 : 0, addpath_id, pfx_buf,
- sizeof(pfx_buf));
+ addpath_id ? 1 : 0, addpath_id, NULL,
+ pfx_buf, sizeof(pfx_buf));
zlog_debug(
"%s withdrawing route %s not in adj-in",
peer->host, pfx_buf);
@@ -4467,8 +4441,8 @@ int bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
/* Logging. */
if (bgp_debug_update(peer, p, NULL, 1)) {
bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
- addpath_id ? 1 : 0, addpath_id, pfx_buf,
- sizeof(pfx_buf));
+ addpath_id ? 1 : 0, addpath_id, NULL,
+ pfx_buf, sizeof(pfx_buf));
zlog_debug("%s rcvd UPDATE about %s -- withdrawn", peer->host,
pfx_buf);
}
@@ -4488,8 +4462,8 @@ int bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
} else if (bgp_debug_update(peer, p, NULL, 1)) {
bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
- addpath_id ? 1 : 0, addpath_id, pfx_buf,
- sizeof(pfx_buf));
+ addpath_id ? 1 : 0, addpath_id, NULL,
+ pfx_buf, sizeof(pfx_buf));
zlog_debug("%s Can't find the route %s", peer->host, pfx_buf);
}
@@ -9867,6 +9841,11 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_nexthop_global = json_object_new_object();
}
+ if (safi == SAFI_EVPN) {
+ if (!json_paths)
+ vty_out(vty, " Route %pRN", bn);
+ }
+
if (path->extra) {
char tag_buf[30];
@@ -9878,12 +9857,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
}
if (safi == SAFI_EVPN) {
if (!json_paths) {
- vty_out(vty, " Route %pFX",
- (struct prefix_evpn *)
- bgp_dest_get_prefix(bn));
if (tag_buf[0] != '\0')
vty_out(vty, " VNI %s", tag_buf);
- vty_out(vty, "\n");
} else {
if (tag_buf[0])
json_object_string_add(json_path, "VNI",
@@ -9930,6 +9905,27 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
}
}
+ if (safi == SAFI_EVPN
+ && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
+ char gwip_buf[INET6_ADDRSTRLEN];
+
+ if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)&bn->p))
+ inet_ntop(AF_INET, &attr->evpn_overlay.gw_ip.ipv4,
+ gwip_buf, sizeof(gwip_buf));
+ else
+ inet_ntop(AF_INET6, &attr->evpn_overlay.gw_ip.ipv6,
+ gwip_buf, sizeof(gwip_buf));
+
+ if (json_paths)
+ json_object_string_add(json_path, "gatewayIP",
+ gwip_buf);
+ else
+ vty_out(vty, " Gateway IP %s", gwip_buf);
+ }
+
+ if (safi == SAFI_EVPN)
+ vty_out(vty, "\n");
+
/* Line1 display AS-path, Aggregator */
if (attr->aspath) {
if (json_paths) {
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 806a771cf..9a7b7b3cf 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -1084,6 +1084,71 @@ static const struct route_map_rule_cmd route_match_evpn_rd_cmd = {
route_match_rd_free
};
+static enum route_map_cmd_result_t
+route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)
+{
+ struct ipaddr *gw_ip = rule;
+ struct bgp_path_info *path;
+ struct prefix_evpn *evp;
+
+ if (prefix->family != AF_EVPN)
+ return RMAP_OKAY;
+
+ evp = (struct prefix_evpn *)prefix;
+ if (evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE)
+ return RMAP_OKAY;
+
+ if ((is_evpn_prefix_ipaddr_v4(evp) && IPADDRSZ(gw_ip) != 4)
+ || (is_evpn_prefix_ipaddr_v6(evp) && IPADDRSZ(gw_ip) != 16))
+ return RMAP_OKAY;
+
+ path = object;
+
+ /* Set gateway-ip value. */
+ path->attr->evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
+ memcpy(&path->attr->evpn_overlay.gw_ip, &gw_ip->ip.addr,
+ IPADDRSZ(gw_ip));
+
+ return RMAP_OKAY;
+}
+
+/*
+ * Route map `evpn gateway-ip' compile function.
+ * Given string is converted to struct ipaddr structure
+ */
+static void *route_set_evpn_gateway_ip_compile(const char *arg)
+{
+ struct ipaddr *gw_ip = NULL;
+ int ret;
+
+ gw_ip = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct ipaddr));
+
+ ret = str2ipaddr(arg, gw_ip);
+ if (ret < 0) {
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, gw_ip);
+ return NULL;
+ }
+ return gw_ip;
+}
+
+/* Free route map's compiled `evpn gateway_ip' value. */
+static void route_set_evpn_gateway_ip_free(void *rule)
+{
+ struct ipaddr *gw_ip = rule;
+
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, gw_ip);
+}
+
+/* Route map commands for set evpn gateway-ip ipv4. */
+struct route_map_rule_cmd route_set_evpn_gateway_ip_ipv4_cmd = {
+ "evpn gateway-ip ipv4", route_set_evpn_gateway_ip,
+ route_set_evpn_gateway_ip_compile, route_set_evpn_gateway_ip_free};
+
+/* Route map commands for set evpn gateway-ip ipv6. */
+struct route_map_rule_cmd route_set_evpn_gateway_ip_ipv6_cmd = {
+ "evpn gateway-ip ipv6", route_set_evpn_gateway_ip,
+ route_set_evpn_gateway_ip_compile, route_set_evpn_gateway_ip_free};
+
/* Route map commands for VRF route leak with source vrf matching */
static enum route_map_cmd_result_t
route_match_vrl_source_vrf(void *rule, const struct prefix *prefix,
@@ -4067,6 +4132,148 @@ DEFUN_YANG (no_match_evpn_rd,
return nb_cli_apply_changes(vty, NULL);
}
+DEFUN_YANG (set_evpn_gw_ip_ipv4,
+ set_evpn_gw_ip_ipv4_cmd,
+ "set evpn gateway-ip ipv4 A.B.C.D",
+ SET_STR
+ EVPN_HELP_STR
+ "Set gateway IP for prefix advertisement route\n"
+ "IPv4 address\n"
+ "Gateway IP address in IPv4 format\n")
+{
+ int ret;
+ union sockunion su;
+ const char *xpath =
+ "./set-action[action='frr-bgp-route-map:set-evpn-gateway-ip-ipv4']";
+ char xpath_value[XPATH_MAXLEN];
+
+ ret = str2sockunion(argv[4]->arg, &su);
+ if (ret < 0) {
+ vty_out(vty, "%% Malformed gateway IP\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (su.sin.sin_addr.s_addr == 0
+ || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) {
+ vty_out(vty,
+ "%% Gateway IP cannot be 0.0.0.0, multicast or reserved\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv4",
+ xpath);
+
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[4]->arg);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_YANG (no_set_evpn_gw_ip_ipv4,
+ no_set_evpn_gw_ip_ipv4_cmd,
+ "no set evpn gateway-ip ipv4 A.B.C.D",
+ NO_STR
+ SET_STR
+ EVPN_HELP_STR
+ "Set gateway IP for prefix advertisement route\n"
+ "IPv4 address\n"
+ "Gateway IP address in IPv4 format\n")
+{
+ int ret;
+ union sockunion su;
+ const char *xpath =
+ "./set-action[action='frr-bgp-route-map:set-evpn-gateway-ip-ipv4']";
+
+ ret = str2sockunion(argv[5]->arg, &su);
+ if (ret < 0) {
+ vty_out(vty, "%% Malformed gateway IP\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (su.sin.sin_addr.s_addr == 0
+ || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) {
+ vty_out(vty,
+ "%% Gateway IP cannot be 0.0.0.0, multicast or reserved\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_YANG (set_evpn_gw_ip_ipv6,
+ set_evpn_gw_ip_ipv6_cmd,
+ "set evpn gateway-ip ipv6 X:X::X:X",
+ SET_STR
+ EVPN_HELP_STR
+ "Set gateway IP for prefix advertisement route\n"
+ "IPv6 address\n"
+ "Gateway IP address in IPv6 format\n")
+{
+ int ret;
+ union sockunion su;
+ const char *xpath =
+ "./set-action[action='frr-bgp-route-map:set-evpn-gateway-ip-ipv6']";
+ char xpath_value[XPATH_MAXLEN];
+
+ ret = str2sockunion(argv[4]->arg, &su);
+ if (ret < 0) {
+ vty_out(vty, "%% Malformed gateway IP\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr)
+ || IN6_IS_ADDR_MULTICAST(&su.sin6.sin6_addr)) {
+ vty_out(vty,
+ "%% Gateway IP cannot be a linklocal or multicast address\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv6",
+ xpath);
+
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[4]->arg);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_YANG (no_set_evpn_gw_ip_ipv6,
+ no_set_evpn_gw_ip_ipv6_cmd,
+ "no set evpn gateway-ip ipv6 X:X::X:X",
+ NO_STR
+ SET_STR
+ EVPN_HELP_STR
+ "Set gateway IP for prefix advertisement route\n"
+ "IPv4 address\n"
+ "Gateway IP address in IPv4 format\n")
+{
+ int ret;
+ union sockunion su;
+ const char *xpath =
+ "./set-action[action='frr-bgp-route-map:set-evpn-gateway-ip-ipv6']";
+
+ ret = str2sockunion(argv[5]->arg, &su);
+ if (ret < 0) {
+ vty_out(vty, "%% Malformed gateway IP\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr)
+ || IN6_IS_ADDR_MULTICAST(&su.sin6.sin6_addr)) {
+ vty_out(vty,
+ "%% Gateway IP cannot be a linklocal or multicast address\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
DEFPY_YANG(match_vrl_source_vrf,
match_vrl_source_vrf_cmd,
"match source-vrf NAME$vrf_name",
@@ -6124,6 +6331,8 @@ void bgp_route_map_init(void)
route_map_install_match(&route_match_evpn_default_route_cmd);
route_map_install_match(&route_match_vrl_source_vrf_cmd);
+ route_map_install_set(&route_set_evpn_gateway_ip_ipv4_cmd);
+ route_map_install_set(&route_set_evpn_gateway_ip_ipv6_cmd);
route_map_install_set(&route_set_table_id_cmd);
route_map_install_set(&route_set_srte_color_cmd);
route_map_install_set(&route_set_ip_nexthop_cmd);
@@ -6167,6 +6376,10 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &no_match_evpn_rd_cmd);
install_element(RMAP_NODE, &match_evpn_default_route_cmd);
install_element(RMAP_NODE, &no_match_evpn_default_route_cmd);
+ install_element(RMAP_NODE, &set_evpn_gw_ip_ipv4_cmd);
+ install_element(RMAP_NODE, &no_set_evpn_gw_ip_ipv4_cmd);
+ install_element(RMAP_NODE, &set_evpn_gw_ip_ipv6_cmd);
+ install_element(RMAP_NODE, &no_set_evpn_gw_ip_ipv6_cmd);
install_element(RMAP_NODE, &match_vrl_source_vrf_cmd);
install_element(RMAP_NODE, &no_match_vrl_source_vrf_cmd);
diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c
index b165c5d0e..1254591b8 100644
--- a/bgpd/bgp_routemap_nb.c
+++ b/bgpd/bgp_routemap_nb.c
@@ -372,6 +372,20 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
}
},
{
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv4",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_modify,
+ .destroy = lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv6",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_modify,
+ .destroy = lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_destroy,
+ }
+ },
+ {
.xpath = NULL,
},
}
diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h
index a15f52151..f0e492eb6 100644
--- a/bgpd/bgp_routemap_nb.h
+++ b/bgpd/bgp_routemap_nb.h
@@ -130,6 +130,14 @@ int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_mod
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy(struct nb_cb_destroy_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_modify(
+ struct nb_cb_modify_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_destroy(
+ struct nb_cb_destroy_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_modify(
+ struct nb_cb_modify_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_destroy(
+ struct nb_cb_destroy_args *args);
#ifdef __cplusplus
}
diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c
index ff08c16a8..e541d117b 100644
--- a/bgpd/bgp_routemap_nb_config.c
+++ b/bgpd/bgp_routemap_nb_config.c
@@ -2637,3 +2637,107 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_spec
{
return lib_route_map_entry_set_destroy(args);
}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv4
+ */
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct routemap_hook_context *rhc;
+ const char *type;
+ int rv;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ /* Add configuration. */
+ rhc = nb_running_get_entry(args->dnode, NULL, true);
+ type = yang_dnode_get_string(args->dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = generic_set_delete;
+ rhc->rhc_rule = "evpn gateway-ip ipv4";
+ rhc->rhc_event = RMAP_EVENT_SET_DELETED;
+
+ rv = generic_set_add(rhc->rhc_rmi, "evpn gateway-ip ipv4", type,
+ args->errmsg, args->errmsg_len);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+ }
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ return lib_route_map_entry_set_destroy(args);
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv6
+ */
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct routemap_hook_context *rhc;
+ const char *type;
+ int rv;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ /* Add configuration. */
+ rhc = nb_running_get_entry(args->dnode, NULL, true);
+ type = yang_dnode_get_string(args->dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = generic_set_delete;
+ rhc->rhc_rule = "evpn gateway-ip ipv6";
+ rhc->rhc_event = RMAP_EVENT_SET_DELETED;
+
+ rv = generic_set_add(rhc->rhc_rmi, "evpn gateway-ip ipv6", type,
+ args->errmsg, args->errmsg_len);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+ }
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ return lib_route_map_entry_set_destroy(args);
+ }
+
+ return NB_OK;
+}
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 6418decd1..038ef4f79 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -862,6 +862,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p,
label_pnt, num_labels,
addpath_encode, addpath_tx_id,
+ &adv->baa->attr->evpn_overlay,
pfx_buf, sizeof(pfx_buf));
zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
subgrp->update_group->id, subgrp->id,
@@ -1031,7 +1032,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p, NULL, 0,
addpath_encode, addpath_tx_id,
- pfx_buf, sizeof(pfx_buf));
+ NULL, pfx_buf, sizeof(pfx_buf));
zlog_debug("u%" PRIu64 ":s%" PRIu64" send UPDATE %s -- unreachable",
subgrp->update_group->id, subgrp->id,
pfx_buf);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index c2c114d2c..73ce2d9ae 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1058,9 +1058,19 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
* connected routes leaked into a VRF.
*/
if (is_evpn) {
- api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
- SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
- api_nh->ifindex = nh_bgp->l3vni_svi_ifindex;
+
+ /*
+ * If the nexthop is EVPN overlay index gateway IP,
+ * treat the nexthop as NEXTHOP_TYPE_IPV4
+ * Else, mark the nexthop as onlink.
+ */
+ if (attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP)
+ api_nh->type = NEXTHOP_TYPE_IPV4;
+ else {
+ api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
+ api_nh->ifindex = nh_bgp->l3vni_svi_ifindex;
+ }
} else if (nh_othervrf &&
api_nh->gate.ipv4.s_addr == INADDR_ANY) {
api_nh->type = NEXTHOP_TYPE_IFINDEX;
@@ -1085,9 +1095,19 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
api_nh->vrf_id = nh_bgp->vrf_id;
if (is_evpn) {
- api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
- SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
- api_nh->ifindex = nh_bgp->l3vni_svi_ifindex;
+
+ /*
+ * If the nexthop is EVPN overlay index gateway IP,
+ * treat the nexthop as NEXTHOP_TYPE_IPV4
+ * Else, mark the nexthop as onlink.
+ */
+ if (attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP)
+ api_nh->type = NEXTHOP_TYPE_IPV6;
+ else {
+ api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
+ api_nh->ifindex = nh_bgp->l3vni_svi_ifindex;
+ }
} else if (nh_othervrf) {
if (IN6_IS_ADDR_UNSPECIFIED(nexthop)) {
api_nh->type = NEXTHOP_TYPE_IFINDEX;
@@ -1392,8 +1412,13 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
api_nh->label_num = 1;
api_nh->labels[0] = label;
}
- memcpy(&api_nh->rmac, &(mpinfo->attr->rmac),
- sizeof(struct ethaddr));
+
+ if (is_evpn
+ && mpinfo->attr->evpn_overlay.type
+ != OVERLAY_INDEX_GATEWAY_IP)
+ memcpy(&api_nh->rmac, &(mpinfo->attr->rmac),
+ sizeof(struct ethaddr));
+
api_nh->weight = nh_weight;
if (mpinfo->extra
@@ -2805,6 +2830,7 @@ static int bgp_zebra_process_local_vni(ZAPI_CALLBACK_ARGS)
struct in_addr vtep_ip = {INADDR_ANY};
vrf_id_t tenant_vrf_id = VRF_DEFAULT;
struct in_addr mcast_grp = {INADDR_ANY};
+ ifindex_t svi_ifindex = 0;
s = zclient->ibuf;
vni = stream_getl(s);
@@ -2812,6 +2838,7 @@ static int bgp_zebra_process_local_vni(ZAPI_CALLBACK_ARGS)
vtep_ip.s_addr = stream_get_ipv4(s);
stream_get(&tenant_vrf_id, s, sizeof(vrf_id_t));
mcast_grp.s_addr = stream_get_ipv4(s);
+ stream_get(&svi_ifindex, s, sizeof(ifindex_t));
}
bgp = bgp_lookup_by_vrf_id(vrf_id);
@@ -2819,16 +2846,17 @@ static int bgp_zebra_process_local_vni(ZAPI_CALLBACK_ARGS)
return 0;
if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("Rx VNI %s VRF %s VNI %u tenant-vrf %s",
- (cmd == ZEBRA_VNI_ADD) ? "add" : "del",
- vrf_id_to_name(vrf_id), vni,
- vrf_id_to_name(tenant_vrf_id));
+ zlog_debug(
+ "Rx VNI %s VRF %s VNI %u tenant-vrf %s SVI ifindex %u",
+ (cmd == ZEBRA_VNI_ADD) ? "add" : "del",
+ vrf_id_to_name(vrf_id), vni,
+ vrf_id_to_name(tenant_vrf_id), svi_ifindex);
if (cmd == ZEBRA_VNI_ADD)
return bgp_evpn_local_vni_add(
bgp, vni,
vtep_ip.s_addr != INADDR_ANY ? vtep_ip : bgp->router_id,
- tenant_vrf_id, mcast_grp);
+ tenant_vrf_id, mcast_grp, svi_ifindex);
else
return bgp_evpn_local_vni_del(bgp, vni);
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index b18cd4ca7..776f4b0a2 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -510,16 +510,18 @@ struct bgp {
uint16_t af_flags[AFI_MAX][SAFI_MAX];
#define BGP_CONFIG_DAMPENING (1 << 0)
/* l2vpn evpn flags - 1 << 0 is used for DAMPENNG */
-#define BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST (1 << 1)
-#define BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST (1 << 2)
-#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4 (1 << 3)
-#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6 (1 << 4)
+#define BGP_L2VPN_EVPN_ADV_IPV4_UNICAST (1 << 1)
+#define BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP (1 << 2)
+#define BGP_L2VPN_EVPN_ADV_IPV6_UNICAST (1 << 3)
+#define BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP (1 << 4)
+#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4 (1 << 5)
+#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6 (1 << 6)
/* import/export between address families */
-#define BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT (1 << 5)
-#define BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT (1 << 6)
+#define BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT (1 << 7)
+#define BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT (1 << 8)
/* vrf-route leaking flags */
-#define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 7)
-#define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 8)
+#define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 9)
+#define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 10)
/* BGP per AF peer count */
uint32_t af_peer_count[AFI_MAX][SAFI_MAX];
@@ -638,6 +640,14 @@ struct bgp {
/* EVI hash table */
struct hash *vnihash;
+ /*
+ * VNI hash table based on SVI ifindex as its key.
+ * We use SVI ifindex as key to lookup a VNI table for gateway IP
+ * overlay index recursive lookup.
+ * For this purpose, a hashtable is added which optimizes this lookup.
+ */
+ struct hash *vni_svi_hash;
+
/* EVPN enable - advertise gateway macip routes */
int advertise_gw_macip;
@@ -683,6 +693,15 @@ struct bgp {
/* Hash table of EVPN nexthops maintained per-tenant-VRF */
struct hash *evpn_nh_table;
+ /*
+ * Flag resolve_overlay_index is used for recursive resolution
+ * procedures for EVPN type-5 route's gateway IP overlay index.
+ * When this flag is set, we build remote-ip-hash for
+ * all L2VNIs and resolve overlay index nexthops using this hash.
+ * Overlay index nexthops remain unresolved if this flag is not set.
+ */
+ bool resolve_overlay_index;
+
/* vrf flags */
uint32_t vrf_flags;
#define BGP_VRF_AUTO (1 << 0)
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 4e78900e8..7f23f7a63 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -2696,6 +2696,115 @@ remote VTEP.
Note that you should not enable both the advertise-svi-ip and the advertise-default-gw
at the same time.
+.. _bgp-evpn-overlay-index-gateway-ip:
+
+EVPN Overlay Index Gateway IP
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Draft https://tools.ietf.org/html/draft-ietf-bess-evpn-prefix-advertisement-11
+explains the use of overlay indexes for recursive route resolution for EVPN
+type-5 route.
+
+We support gateway IP overlay index.
+A gateway IP, advertised with EVPN prefix route, is used to find an EVPN MAC/IP
+route with its IP field same as the gateway IP. This MAC/IP entry provides the
+nexthop VTEP and the tunnel information required for the VxLAN encapsulation.
+
+Functionality:
+
+::
+
+ . +--------+ BGP +--------+ BGP +--------+ +--------+
+ SN1 | | IPv4 | | EVPN | | | |
+ ======+ Host1 +------+ PE1 +------+ PE2 +------+ Host2 +
+ | | | | | | | |
+ +--------+ +--------+ +--------+ +--------+
+
+Consider above topology where prefix SN1 is connected behind host1. Host1
+advertises SN1 to PE1 over BGP IPv4 session. PE1 advertises SN1 to PE2 using
+EVPN type-5 route with host1 IP as the gateway IP. PE1 also advertises
+Host1 MAC/IP as type-2 route which is used to resolve host1 gateway IP.
+
+PE2 receives this type-5 route and imports it into the vrf based on route
+targets. BGP prefix imported into the vrf uses gateway IP as its BGP nexthop.
+This route is installed into zebra if following conditions are satisfied:
+1. Gateway IP nexthop is L3 reachable.
+2. PE2 has received EVPN type-2 route with IP field set to gateway IP.
+
+Topology requirements:
+1. This feature is supported for asymmetric routing model only. While
+ sending packets to SN1, ingress PE (PE2) performs routing and
+ egress PE (PE1) performs only bridging.
+2. This feature supports only tratitional(non vlan-aware) bridge model. Bridge
+ interface associated with L2VNI is an L3 interface. i.e., this interface is
+ configured with an address in the L2VNI subnet. Note that the gateway IP
+ should also have an address in the same subnet.
+3. As this feature works in asymmetric routing model, all L2VNIs and corresponding
+ VxLAN and bridge interfaces should be present at all the PEs.
+4. L3VNI configuration is required to generate and import EVPN type-5 routes.
+ L3VNI VxLAN and bridge interfaces also should be present.
+
+A PE can use one of the following two mechanisms to advertise an EVPN type-5
+route with gateway IP.
+
+1. CLI to add gateway IP while generating EVPN type-5 route from a BGP IPv4/IPv6
+prefix:
+
+.. index:: advertise <ipv4|ipv6> unicast [gateway-ip]
+.. clicmd:: [no] advertise <ipv4|ipv6> unicast [gateway-ip]
+
+When this CLI is configured for a BGP vrf under L2VPN EVPN address family, EVPN
+type-5 routes are generated for BGP prefixes in the vrf. Nexthop of the BGP
+prefix becomes the gateway IP of the corresponding type-5 route.
+
+If the above command is configured without the "gateway-ip" keyword, type-5
+routes are generated without overlay index.
+
+2. Add gateway IP to EVPN type-5 route using a route-map:
+
+.. index:: set evpn gateway-ip <ipv4|ipv6> <addr>
+.. clicmd:: [no] set evpn gateway-ip <ipv4|ipv6> <addr>
+
+When route-map with above set clause is applied as outbound policy in BGP, it
+will set the gateway-ip in EVPN type-5 NLRI.
+
+Example configuration:
+
+.. code-block:: frr
+
+ router bgp 100
+ neighbor 192.168.0.1 remote-as 101
+ !
+ address-family ipv4 l2vpn evpn
+ neighbor 192.168.0.1 route-map RMAP out
+ exit-address-family
+ !
+ route-map RMAP permit 10
+ set evpn gateway-ip 10.0.0.1
+ set evpn gateway-ip 10::1
+
+A PE that receives a type-5 route with gateway IP overlay index should have
+"enable-resolve-overlay-index" configuration enabled to recursively resolve the
+overlay index nexthop and install the prefix into zebra.
+
+.. index:: enable-resolve-overlay-index
+.. clicmd:: [no] enable-resolve-overlay-index
+
+Example configuration:
+
+.. code-block:: frr
+
+ router bgp 65001
+ bgp router-id 192.168.100.1
+ no bgp ebgp-requires-policy
+ neighbor 10.0.1.2 remote-as 65002
+ !
+ address-family l2vpn evpn
+ neighbor 10.0.1.2 activate
+ advertise-all-vni
+ enable-resolve-overlay-index
+ exit-address-family
+ !
+
EVPN Multihoming
^^^^^^^^^^^^^^^^
diff --git a/lib/routemap.h b/lib/routemap.h
index 5b6b64eae..4d76ae153 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -366,6 +366,10 @@ DECLARE_QOBJ_TYPE(route_map);
(strmatch(A, "frr-bgp-route-map:ipv4-vpn-address"))
#define IS_SET_BGP_IPV4_NH(A) \
(strmatch(A, "frr-bgp-route-map:set-ipv4-nexthop"))
+#define IS_SET_BGP_EVPN_GATEWAY_IP_IPV4(A) \
+ (strmatch(A, "frr-bgp-route-map:set-evpn-gateway-ip-ipv4"))
+#define IS_SET_BGP_EVPN_GATEWAY_IP_IPV6(A) \
+ (strmatch(A, "frr-bgp-route-map:set-evpn-gateway-ip-ipv6"))
/* Prototypes. */
extern void route_map_init(void);
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index e11b9eea7..bf982cfa2 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -1248,6 +1248,16 @@ void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
yang_dnode_get_string(
dnode,
"./rmap-set-action/frr-bgp-route-map:ipv4-nexthop"));
+ } else if (IS_SET_BGP_EVPN_GATEWAY_IP_IPV4(action)) {
+ vty_out(vty, " set evpn gateway-ip ipv4 %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv4"));
+ } else if (IS_SET_BGP_EVPN_GATEWAY_IP_IPV6(action)) {
+ vty_out(vty, " set evpn gateway-ip ipv6 %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv6"));
}
}
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_base.json
new file mode 100644
index 000000000..2eeebad4b
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_base.json
@@ -0,0 +1,192 @@
+{
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:61",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:101:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:61",
+ "ipLen":32,
+ "ip":"50.0.1.11",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:101:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:61",
+ "ipLen":128,
+ "ip":"50:0:1::11",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:101:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:62",
+ "weight":0,
+ "peerId":"10.0.1.2",
+ "path":"102",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"RT:102:100 ET:8"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[3]:[0]:[32]:[10.100.0.1]":{
+ "prefix":"[3]:[0]:[32]:[10.100.0.1]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":3,
+ "ethTag":0,
+ "ipLen":32,
+ "ip":"10.100.0.1",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:101:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[3]:[0]:[32]:[10.100.0.2]":{
+ "prefix":"[3]:[0]:[32]:[10.100.0.2]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":3,
+ "ethTag":0,
+ "ipLen":32,
+ "ip":"10.100.0.2",
+ "weight":0,
+ "peerId":"10.0.1.2",
+ "path":"102",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"RT:102:100 ET:8"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt2.json
new file mode 100644
index 000000000..419bcc3dd
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt2.json
@@ -0,0 +1,8 @@
+{
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]": null,
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]": null,
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]": null,
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]": null,
+ "[3]:[0]:[32]:[10.100.0.1]": null,
+ "[3]:[0]:[32]:[10.100.0.2]": null
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt5.json
new file mode 100644
index 000000000..2eeebad4b
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt5.json
@@ -0,0 +1,192 @@
+{
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:61",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:101:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:61",
+ "ipLen":32,
+ "ip":"50.0.1.11",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:101:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:61",
+ "ipLen":128,
+ "ip":"50:0:1::11",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:101:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:62",
+ "weight":0,
+ "peerId":"10.0.1.2",
+ "path":"102",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"RT:102:100 ET:8"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[3]:[0]:[32]:[10.100.0.1]":{
+ "prefix":"[3]:[0]:[32]:[10.100.0.1]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":3,
+ "ethTag":0,
+ "ipLen":32,
+ "ip":"10.100.0.1",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:101:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[3]:[0]:[32]:[10.100.0.2]":{
+ "prefix":"[3]:[0]:[32]:[10.100.0.2]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":3,
+ "ethTag":0,
+ "ipLen":32,
+ "ip":"10.100.0.2",
+ "weight":0,
+ "peerId":"10.0.1.2",
+ "path":"102",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"RT:102:100 ET:8"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_base.json
new file mode 100644
index 000000000..833f98657
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_base.json
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.1",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100.0.0.21/32": [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "prefix":"100.0.0.21",
+ "prefixLen":32,
+ "network":"100.0.0.21\/32",
+ "metric":0,
+ "weight":0,
+ "peerId":"50.0.1.11",
+ "path":"111",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"50.0.1.11",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+] } } \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt2.json
new file mode 100644
index 000000000..833f98657
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt2.json
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.1",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100.0.0.21/32": [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "prefix":"100.0.0.21",
+ "prefixLen":32,
+ "network":"100.0.0.21\/32",
+ "metric":0,
+ "weight":0,
+ "peerId":"50.0.1.11",
+ "path":"111",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"50.0.1.11",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+] } } \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt5.json
new file mode 100644
index 000000000..4a292bddb
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt5.json
@@ -0,0 +1,6 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.1",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100.0.0.21/32": null } }
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_base.json
new file mode 100644
index 000000000..3dc3fcf9c
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_base.json
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.1",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100::21/128": [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "prefix":"100::21",
+ "prefixLen":128,
+ "network":"100::21\/128",
+ "metric":0,
+ "weight":0,
+ "peerId":"50:0:1::11",
+ "path":"111",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"50:0:1::11",
+ "afi":"ipv6",
+ "scope":"global"
+ }
+ ]
+ }
+] } }
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt2.json
new file mode 100644
index 000000000..3dc3fcf9c
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt2.json
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.1",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100::21/128": [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "prefix":"100::21",
+ "prefixLen":128,
+ "network":"100::21\/128",
+ "metric":0,
+ "weight":0,
+ "peerId":"50:0:1::11",
+ "path":"111",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"50:0:1::11",
+ "afi":"ipv6",
+ "scope":"global"
+ }
+ ]
+ }
+] } }
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt5.json
new file mode 100644
index 000000000..6c11d894e
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt5.json
@@ -0,0 +1,6 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.1",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100::21/128": null } } \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgpd.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgpd.conf
new file mode 100644
index 000000000..63aa99a83
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgpd.conf
@@ -0,0 +1,30 @@
+router bgp 101
+ bgp router-id 10.100.0.1
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.1.2 remote-as 102
+ !
+ address-family l2vpn evpn
+ neighbor 10.0.1.2 activate
+ advertise-all-vni
+ exit-address-family
+!
+router bgp 101 vrf vrf-blue
+ bgp router-id 10.100.0.1
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 50.0.1.11 remote-as 111
+ neighbor 50:0:1::11 remote-as 111
+ !
+ address-family ipv4 unicast
+ no neighbor 50:0:1::11 activate
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ neighbor 50:0:1::11 activate
+ exit-address-family
+ !
+ address-family l2vpn evpn
+ advertise ipv4 unicast gateway-ip
+ advertise ipv6 unicast gateway-ip
+ exit-address-family \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra.conf
new file mode 100644
index 000000000..99a2e89ef
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra.conf
@@ -0,0 +1,14 @@
+!
+log file zebra.log
+!
+ip route 10.100.0.2/32 10.0.1.2
+!
+vrf vrf-blue
+ vni 1000 prefix-routes-only
+ exit-vrf
+!
+interface lo
+ ip address 10.100.0.1/32
+interface PE1-eth0
+ ip address 10.0.1.1/24
+!
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_base.json
new file mode 100644
index 000000000..2dcf35d91
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_base.json
@@ -0,0 +1,56 @@
+{
+ "50.0.1.0\/24":[
+ {
+ "prefix":"50.0.1.0\/24",
+ "protocol":"connected",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"br100",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "100.0.0.21\/32":[
+ {
+ "prefix":"100.0.0.21\/32",
+ "protocol":"bgp",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":20,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "ip":"50.0.1.11",
+ "afi":"ipv4",
+ "interfaceName":"br100",
+ "active":true,
+ "weight":1
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt2.json
new file mode 100644
index 000000000..2dcf35d91
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt2.json
@@ -0,0 +1,56 @@
+{
+ "50.0.1.0\/24":[
+ {
+ "prefix":"50.0.1.0\/24",
+ "protocol":"connected",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"br100",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "100.0.0.21\/32":[
+ {
+ "prefix":"100.0.0.21\/32",
+ "protocol":"bgp",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":20,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "ip":"50.0.1.11",
+ "afi":"ipv4",
+ "interfaceName":"br100",
+ "active":true,
+ "weight":1
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt5.json
new file mode 100644
index 000000000..9c3091dc5
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt5.json
@@ -0,0 +1,29 @@
+{
+ "50.0.1.0\/24":[
+ {
+ "prefix":"50.0.1.0\/24",
+ "protocol":"connected",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"br100",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "100.0.0.21\/32": null
+}
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_base.json
new file mode 100644
index 000000000..229c92765
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_base.json
@@ -0,0 +1,55 @@
+{
+ "50:0:1::\/48":[
+ {
+ "prefix":"50:0:1::\/48",
+ "protocol":"connected",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"br100",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "100::21\/128":[
+ {
+ "prefix":"100::21\/128",
+ "protocol":"bgp",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":20,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"br100",
+ "active":true,
+ "weight":1
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt2.json
new file mode 100644
index 000000000..229c92765
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt2.json
@@ -0,0 +1,55 @@
+{
+ "50:0:1::\/48":[
+ {
+ "prefix":"50:0:1::\/48",
+ "protocol":"connected",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"br100",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "100::21\/128":[
+ {
+ "prefix":"100::21\/128",
+ "protocol":"bgp",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":20,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"br100",
+ "active":true,
+ "weight":1
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt5.json
new file mode 100644
index 000000000..94f82e6d4
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt5.json
@@ -0,0 +1,29 @@
+{
+ "50:0:1::\/48":[
+ {
+ "prefix":"50:0:1::\/48",
+ "protocol":"connected",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"br100",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "100::21\/128": null
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_base.json
new file mode 100644
index 000000000..7b8d38e49
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_base.json
@@ -0,0 +1,192 @@
+{
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:61",
+ "weight":0,
+ "peerId":"10.0.1.1",
+ "path":"101",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"RT:101:100 ET:8"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:61",
+ "ipLen":32,
+ "ip":"50.0.1.11",
+ "weight":0,
+ "peerId":"10.0.1.1",
+ "path":"101",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"RT:101:100 ET:8"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:61",
+ "ipLen":128,
+ "ip":"50:0:1::11",
+ "weight":0,
+ "peerId":"10.0.1.1",
+ "path":"101",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"RT:101:100 ET:8"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:62",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:102:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[3]:[0]:[32]:[10.100.0.1]":{
+ "prefix":"[3]:[0]:[32]:[10.100.0.1]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":3,
+ "ethTag":0,
+ "ipLen":32,
+ "ip":"10.100.0.1",
+ "weight":0,
+ "peerId":"10.0.1.1",
+ "path":"101",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"RT:101:100 ET:8"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[3]:[0]:[32]:[10.100.0.2]":{
+ "prefix":"[3]:[0]:[32]:[10.100.0.2]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":3,
+ "ethTag":0,
+ "ipLen":32,
+ "ip":"10.100.0.2",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:102:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt2.json
new file mode 100644
index 000000000..6273b3e72
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt2.json
@@ -0,0 +1,68 @@
+{
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]": null,
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]": null,
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]": null,
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:62",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:102:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[3]:[0]:[32]:[10.100.0.1]": null,
+ "[3]:[0]:[32]:[10.100.0.2]":{
+ "prefix":"[3]:[0]:[32]:[10.100.0.2]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":3,
+ "ethTag":0,
+ "ipLen":32,
+ "ip":"10.100.0.2",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:102:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt5.json
new file mode 100644
index 000000000..7b8d38e49
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt5.json
@@ -0,0 +1,192 @@
+{
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:61",
+ "weight":0,
+ "peerId":"10.0.1.1",
+ "path":"101",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"RT:101:100 ET:8"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:61",
+ "ipLen":32,
+ "ip":"50.0.1.11",
+ "weight":0,
+ "peerId":"10.0.1.1",
+ "path":"101",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"RT:101:100 ET:8"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:61",
+ "ipLen":128,
+ "ip":"50:0:1::11",
+ "weight":0,
+ "peerId":"10.0.1.1",
+ "path":"101",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"RT:101:100 ET:8"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]":{
+ "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":2,
+ "ethTag":0,
+ "macLen":48,
+ "mac":"1a:2b:3c:4d:5e:62",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:102:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[3]:[0]:[32]:[10.100.0.1]":{
+ "prefix":"[3]:[0]:[32]:[10.100.0.1]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":3,
+ "ethTag":0,
+ "ipLen":32,
+ "ip":"10.100.0.1",
+ "weight":0,
+ "peerId":"10.0.1.1",
+ "path":"101",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"RT:101:100 ET:8"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "[3]:[0]:[32]:[10.100.0.2]":{
+ "prefix":"[3]:[0]:[32]:[10.100.0.2]",
+ "prefixLen":320,
+ "paths":[
+ [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "routeType":3,
+ "ethTag":0,
+ "ipLen":32,
+ "ip":"10.100.0.2",
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "extendedCommunity":{
+ "string":"ET:8 RT:102:100"
+ },
+ "nexthops":[
+ {
+ "ip":"10.100.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_base.json
new file mode 100644
index 000000000..c03d70195
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_base.json
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.2",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100.0.0.21/32": [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "prefix":"100.0.0.21",
+ "prefixLen":32,
+ "network":"100.0.0.21\/32",
+ "metric":0,
+ "weight":0,
+ "peerId":"10.0.1.1",
+ "path":"101 111",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"50.0.1.11",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+] } } \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt2.json
new file mode 100644
index 000000000..7f1b8d2ef
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt2.json
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.2",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100.0.0.21/32": [
+ {
+ "valid":null,
+ "bestpath":null,
+ "pathFrom":"external",
+ "prefix":"100.0.0.21",
+ "prefixLen":32,
+ "network":"100.0.0.21\/32",
+ "metric":0,
+ "weight":0,
+ "peerId":"10.0.1.1",
+ "path":"101 111",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"50.0.1.11",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+] } }
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt5.json
new file mode 100644
index 000000000..52e431163
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt5.json
@@ -0,0 +1,6 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.2",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100.0.0.21/32": null } } \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_base.json
new file mode 100644
index 000000000..1d90c9c79
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_base.json
@@ -0,0 +1,28 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.2",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100::21/128": [
+ {
+ "valid":true,
+ "bestpath":true,
+ "pathFrom":"external",
+ "prefix":"100::21",
+ "prefixLen":128,
+ "network":"100::21\/128",
+ "metric":0,
+ "weight":0,
+ "peerId":"10.0.1.1",
+ "path":"101 111",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"50:0:1::11",
+ "afi":"ipv6",
+ "scope":"global",
+ "used":true
+ }
+ ]
+ }
+] } } \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt2.json
new file mode 100644
index 000000000..a0e63c6e2
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt2.json
@@ -0,0 +1,28 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.2",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100::21/128": [
+ {
+ "valid":null,
+ "bestpath":null,
+ "pathFrom":"external",
+ "prefix":"100::21",
+ "prefixLen":128,
+ "network":"100::21\/128",
+ "metric":0,
+ "weight":0,
+ "peerId":"10.0.1.1",
+ "path":"101 111",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"50:0:1::11",
+ "afi":"ipv6",
+ "scope":"global",
+ "used":true
+ }
+ ]
+ }
+] } }
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt5.json
new file mode 100644
index 000000000..789fe69b2
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt5.json
@@ -0,0 +1,6 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.2",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100::21/128": null } } \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgpd.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgpd.conf
new file mode 100644
index 000000000..59fee15df
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgpd.conf
@@ -0,0 +1,14 @@
+router bgp 102
+ bgp router-id 10.100.0.2
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.1.1 remote-as 101
+ !
+ address-family l2vpn evpn
+ neighbor 10.0.1.1 activate
+ advertise-all-vni
+ enable-resolve-overlay-index
+ exit-address-family
+!
+router bgp 101 vrf vrf-blue
+ bgp router-id 10.100.0.2
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra.conf
new file mode 100644
index 000000000..b78cdcc51
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra.conf
@@ -0,0 +1,14 @@
+!
+log file zebra.log
+!
+ip route 10.100.0.1/32 10.0.1.1
+!
+vrf vrf-blue
+ vni 1000 prefix-routes-only
+ exit-vrf
+!
+interface lo
+ ip address 10.100.0.2/32
+interface PE2-eth0
+ ip address 10.0.1.2/24
+!
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_base.json
new file mode 100644
index 000000000..b3a3640be
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_base.json
@@ -0,0 +1,56 @@
+{
+ "50.0.1.0\/24":[
+ {
+ "prefix":"50.0.1.0\/24",
+ "protocol":"connected",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"br100",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "100.0.0.21\/32":[
+ {
+ "prefix":"100.0.0.21\/32",
+ "protocol":"bgp",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":20,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":40,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "ip":"50.0.1.11",
+ "afi":"ipv4",
+ "interfaceName":"br100",
+ "active":true,
+ "weight":1
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt2.json
new file mode 100644
index 000000000..996fe52f4
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt2.json
@@ -0,0 +1,29 @@
+{
+ "50.0.1.0\/24":[
+ {
+ "prefix":"50.0.1.0\/24",
+ "protocol":"connected",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"br100",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "100.0.0.21\/32": null
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt5.json
new file mode 100644
index 000000000..996fe52f4
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt5.json
@@ -0,0 +1,29 @@
+{
+ "50.0.1.0\/24":[
+ {
+ "prefix":"50.0.1.0\/24",
+ "protocol":"connected",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"br100",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "100.0.0.21\/32": null
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_base.json
new file mode 100644
index 000000000..d5be22a2b
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_base.json
@@ -0,0 +1,56 @@
+{
+ "50:0:1::\/48":[
+ {
+ "prefix":"50:0:1::\/48",
+ "protocol":"connected",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"br100",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "100::21\/128":[
+ {
+ "prefix":"100::21\/128",
+ "protocol":"bgp",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":20,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":40,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "ip":"50:0:1::11",
+ "afi":"ipv6",
+ "interfaceName":"br100",
+ "active":true,
+ "weight":1
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt2.json
new file mode 100644
index 000000000..94f82e6d4
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt2.json
@@ -0,0 +1,29 @@
+{
+ "50:0:1::\/48":[
+ {
+ "prefix":"50:0:1::\/48",
+ "protocol":"connected",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"br100",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "100::21\/128": null
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt5.json
new file mode 100644
index 000000000..94f82e6d4
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt5.json
@@ -0,0 +1,29 @@
+{
+ "50:0:1::\/48":[
+ {
+ "prefix":"50:0:1::\/48",
+ "protocol":"connected",
+ "vrfName":"vrf-blue",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":10,
+ "internalStatus":16,
+ "internalFlags":8,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":3,
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"br100",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "100::21\/128": null
+} \ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/__init__.py b/tests/topotests/bgp-evpn-overlay-index-gateway/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/__init__.py
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/host1/bgpd.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/host1/bgpd.conf
new file mode 100644
index 000000000..7608ec95c
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/host1/bgpd.conf
@@ -0,0 +1,18 @@
+router bgp 111
+ bgp router-id 10.100.0.11
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 50.0.1.1 remote-as 101
+ neighbor 50:0:1::1 remote-as 101
+ !
+ address-family ipv4 unicast
+ network 100.0.0.21/32
+ no neighbor 50:0:1::1 activate
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ network 100::21/128
+ neighbor 50:0:1::1 activate
+ exit-address-family
+
+
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/host1/zebra.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/host1/zebra.conf
new file mode 100644
index 000000000..c8c832e9d
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/host1/zebra.conf
@@ -0,0 +1,4 @@
+!
+int host1-eth0
+ ip address 50.0.1.11/24
+ ipv6 address 50:0:1::11/48
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/host2/bgpd.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/host2/bgpd.conf
new file mode 100644
index 000000000..cdf4cb4fe
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/host2/bgpd.conf
@@ -0,0 +1 @@
+!
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/host2/zebra.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/host2/zebra.conf
new file mode 100644
index 000000000..9135545c5
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/host2/zebra.conf
@@ -0,0 +1,4 @@
+!
+int host1-eth0
+ ip address 50.0.1.21/24
+ ipv6 address 50:0:1::21/48
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/test_bgp_evpn_overlay_index_gateway.py b/tests/topotests/bgp-evpn-overlay-index-gateway/test_bgp_evpn_overlay_index_gateway.py
new file mode 100755
index 000000000..fbce2809e
--- /dev/null
+++ b/tests/topotests/bgp-evpn-overlay-index-gateway/test_bgp_evpn_overlay_index_gateway.py
@@ -0,0 +1,385 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF")
+# in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bgp_evpn_overlay_index_gateway.py: Test EVPN gateway IP overlay index functionality
+Following functionality is covered:
+
+ +--------+ BGP +--------+ BGP +--------+ +--------+
+ SN1 | | IPv4/v6 | | EVPN | | | |
+ ======+ Host1 +---------+ PE1 +------+ PE2 +------+ Host2 +
+ | | | | | | | |
+ +--------+ +--------+ +--------+ +--------+
+
+ Host1 is connected to PE1 and host2 is connected to PE2
+ Host1 and PE1 have IPv4/v6 BGP sessions.
+ PE1 and PE2 gave EVPN session.
+ Host1 advertises IPv4/v6 prefixes to PE1.
+ PE1 advertises these prefixes to PE2 as EVPN type-5 routes.
+ Gateway IP for these EVPN type-5 routes is host1 IP.
+ Host1 MAC/IP is advertised by PE1 as EVPN type-2 route
+
+Following testcases are covered:
+TC_1:
+Check BGP and zebra states for above topology at PE1 and PE2.
+
+TC_2:
+Stop advertising prefixes from host1. It should withdraw type-5 routes. Check states at PE1 and PE2
+Advertise the prefixes again. Check states.
+
+TC_3:
+Shut down VxLAN interface at PE1. This should withdraw type-2 routes. Check states at PE1 and PE2.
+Enable VxLAN interface again. Check states.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+import time
+import platform
+
+#Current Working Directory
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from lib.common_config import (
+ step,
+ write_test_header,
+ write_test_footer,
+ generate_support_bundle,
+)
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+#Global variables
+PES = ['PE1', 'PE2']
+HOSTS = ['host1', 'host2']
+PE_SUFFIX = {'PE1': '1', 'PE2': '2'}
+HOST_SUFFIX = {'host1': '1', 'host2': '2'}
+TRIGGERS = ["base", "no_rt5", "no_rt2"]
+
+
+class TemplateTopo(Topo):
+ """Test topology builder"""
+
+ def build(self, *_args, **_opts):
+ """Build function"""
+ tgen = get_topogen(self)
+
+ # This function only purpose is to define allocation and relationship
+ # between routers and add links.
+
+ # Create routers
+ for pe in PES:
+ tgen.add_router(pe)
+ for host in HOSTS:
+ tgen.add_router(host)
+
+ krel = platform.release()
+ logger.info('Kernel version ' + krel)
+
+ #Add links
+ tgen.add_link(tgen.gears['PE1'], tgen.gears['PE2'], 'PE1-eth0', 'PE2-eth0')
+ tgen.add_link(tgen.gears['PE1'], tgen.gears['host1'], 'PE1-eth1', 'host1-eth0')
+ tgen.add_link(tgen.gears['PE2'], tgen.gears['host2'], 'PE2-eth1', 'host2-eth0')
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ kernelv = platform.release()
+ if topotest.version_cmp(kernelv, "4.15") < 0:
+ logger.info("For EVPN, kernel version should be minimum 4.15. Kernel present {}".format(kernelv))
+ return
+
+ if topotest.version_cmp(kernelv, '4.15') == 0:
+ l3mdev_accept = 1
+ logger.info('setting net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept))
+ else:
+ l3mdev_accept = 0
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ tgen.start_topology()
+
+ # Configure MAC address for hosts as these MACs are advertised with EVPN type-2 routes
+ for (name, host) in tgen.gears.items():
+ if name not in HOSTS:
+ continue
+
+ host_mac = "1a:2b:3c:4d:5e:6{}".format(HOST_SUFFIX[name])
+ host.run("ip link set dev {}-eth0 down").format(name)
+ host.run("ip link set dev {0}-eth0 address {1}".format(name, host_mac))
+ host.run("ip link set dev {}-eth0 up").format(name)
+
+ # Configure PE VxLAN and Bridge interfaces
+ for (name, pe) in tgen.gears.items():
+ if name not in PES:
+ continue
+ vtep_ip = "10.100.0.{}".format(PE_SUFFIX[name])
+ bridge_ip = "50.0.1.{}/24".format(PE_SUFFIX[name])
+ bridge_ipv6 = "50:0:1::{}/48".format(PE_SUFFIX[name])
+
+ pe.run("ip link add vrf-blue type vrf table 10")
+ pe.run("ip link set dev vrf-blue up")
+ pe.run("ip link add vxlan100 type vxlan id 100 dstport 4789 local {}".format(vtep_ip))
+ pe.run("ip link add name br100 type bridge stp_state 0")
+ pe.run("ip link set dev vxlan100 master br100")
+ pe.run("ip link set dev {}-eth1 master br100".format(name))
+ pe.run("ip addr add {} dev br100".format(bridge_ip))
+ pe.run("ip link set up dev br100")
+ pe.run("ip link set up dev vxlan100")
+ pe.run("ip link set up dev {}-eth1".format(name))
+ pe.run("ip link set dev br100 master vrf-blue")
+ pe.run("ip -6 addr add {} dev br100".format(bridge_ipv6))
+
+ pe.run("ip link add vxlan1000 type vxlan id 1000 dstport 4789 local {}".format(vtep_ip))
+ pe.run("ip link add name br1000 type bridge stp_state 0")
+ pe.run("ip link set dev vxlan1000 master br100")
+ pe.run("ip link set up dev br1000")
+ pe.run("ip link set up dev vxlan1000")
+ pe.run("ip link set dev br1000 master vrf-blue")
+
+ pe.run("sysctl -w net.ipv4.ip_forward=1")
+ pe.run("sysctl -w net.ipv6.conf.all.forwarding=1")
+ pe.run("sysctl -w net.ipv4.udp_l3mdev_accept={}".format(l3mdev_accept))
+ pe.run("sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept))
+
+ # For all registred routers, load the zebra configuration file
+ for (name, router) in tgen.routers().items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(name))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(name))
+ )
+
+ # After loading the configurations, this function loads configured daemons.
+ tgen.start_router()
+
+ logger.info("Running setup_module() done")
+ topotest.sleep(200)
+
+
+def teardown_module(mod):
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+def evpn_gateway_ip_show_op_check(trigger=" "):
+ """
+ This function checks CLI O/P for commands mentioned in show_commands for a given trigger
+ :param trigger: Should be a trigger present in TRIGGERS
+ :return: Returns a tuple (result: None for success, retmsg: Log message to be printed on failure)
+ """
+ tgen = get_topogen()
+
+ if trigger not in TRIGGERS:
+ return "Unexpected trigger", "Unexpected trigger {}".format(trigger)
+
+ show_commands = {'bgp_vni_routes': 'show bgp l2vpn evpn route vni 100 json',
+ 'bgp_vrf_ipv4' : 'show bgp vrf vrf-blue ipv4 json',
+ 'bgp_vrf_ipv6' : 'show bgp vrf vrf-blue ipv6 json',
+ 'zebra_vrf_ipv4': 'show ip route vrf vrf-blue json',
+ 'zebra_vrf_ipv6': 'show ipv6 route vrf vrf-blue json'}
+
+ for (name, pe) in tgen.gears.items():
+ if name not in PES:
+ continue
+
+ for (cmd_key, command) in show_commands.items():
+ expected_op_file = "{0}/{1}/{2}_{3}.json".format(CWD, name, cmd_key, trigger)
+ expected_op = json.loads(open(expected_op_file).read())
+
+ test_func = partial(topotest.router_json_cmp, pe, command, expected_op)
+ ret, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = '"{0}" JSON output mismatch for {1}'.format(name, command)
+ if result is not None:
+ return result, assertmsg
+
+ return None, "Pass"
+
+
+def test_evpn_gateway_ip_basic_topo(request):
+ """
+ Tets EVPN overlay index gateway IP functionality. VErify show O/Ps on PE1 and PE2
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ kernelv = platform.release()
+ if topotest.version_cmp(kernelv, "4.15") < 0:
+ logger.info("For EVPN, kernel version should be minimum 4.15")
+ write_test_footer(tc_name)
+ return
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Check O/Ps for EVPN gateway IP overlay Index functionality at PE1 and PE2")
+
+ result, assertmsg = evpn_gateway_ip_show_op_check("base")
+
+ if result is not None:
+ generate_support_bundle()
+ assert result is None, assertmsg
+
+ write_test_footer(tc_name)
+
+
+def test_evpn_gateway_ip_flap_rt5(request):
+ """
+ Withdraw EVPN type-5 routes and check O/Ps at PE1 and PE2
+ """
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ kernelv = platform.release()
+ if topotest.version_cmp(kernelv, "4.15") < 0:
+ logger.info("For EVPN, kernel version should be minimum 4.15")
+ write_test_footer(tc_name)
+ return
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ h1 = tgen.gears['host1']
+
+ step("Withdraw type-5 routes")
+
+ h1.run('vtysh -c "config t" \
+ -c "router bgp 111" \
+ -c "address-family ipv4" \
+ -c "no network 100.0.0.21/32"')
+ h1.run('vtysh -c "config t" \
+ -c "router bgp 111" \
+ -c "address-family ipv6" \
+ -c "no network 100::21/128"')
+
+ result, assertmsg = evpn_gateway_ip_show_op_check("no_rt5")
+ if result is not None:
+ generate_support_bundle()
+ assert result is None, assertmsg
+
+ step("Advertise type-5 routes again")
+
+ h1.run('vtysh -c "config t" \
+ -c "router bgp 111" \
+ -c "address-family ipv4" \
+ -c "network 100.0.0.21/32"')
+ h1.run('vtysh -c "config t" \
+ -c "router bgp 111" \
+ -c "address-family ipv6" \
+ -c "network 100::21/128"')
+
+ result, assertmsg = evpn_gateway_ip_show_op_check("base")
+ if result is not None:
+ generate_support_bundle()
+
+ assert result is None, assertmsg
+
+ write_test_footer(tc_name)
+
+
+def test_evpn_gateway_ip_flap_rt2(request):
+ """
+ Withdraw EVPN type-2 routes and check O/Ps at PE1 and PE2
+ """
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ kernelv = platform.release()
+ if topotest.version_cmp(kernelv, "4.15") < 0:
+ logger.info("For EVPN, kernel version should be minimum 4.15")
+ write_test_footer(tc_name)
+ return
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+
+ step("Shut down VxLAN interface at PE1 which results in withdraw of type-2 routes")
+
+ pe1 = tgen.gears['PE1']
+
+ pe1.run('ip link set dev vxlan100 down')
+
+ result, assertmsg = evpn_gateway_ip_show_op_check("no_rt2")
+ if result is not None:
+ generate_support_bundle()
+ assert result is None, assertmsg
+
+ step("Bring up VxLAN interface at PE1 and advertise type-2 routes again")
+
+ pe1.run('ip link set dev vxlan100 up')
+
+ result, assertmsg = evpn_gateway_ip_show_op_check("base")
+ if result is not None:
+ generate_support_bundle()
+ assert result is None, assertmsg
+
+ write_test_footer(tc_name)
+
+
+def test_memory_leak():
+ """Run the memory leak test and report results"""
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf
index 0d6432048..732470f82 100644
--- a/tools/etc/frr/support_bundle_commands.conf
+++ b/tools/etc/frr/support_bundle_commands.conf
@@ -31,7 +31,29 @@ show bgp ipv6 statistics
show bgp martian next-hop
show bgp nexthop
+show bgp vrf all summary
+show bgp vrf all ipv4
+show bgp vrf all ipv6
+show bgp vrf all neighbors
+
show bgp evpn route
+show bgp l2vpn evpn route vni all
+show bgp l2vpn evpn vni
+show bgp l2vpn evpn import-rt
+show bgp l2vpn evpn vrf-import-rt
+show bgp l2vpn evpn all overlay
+show bgp l2vpn evpn summary
+show bgp l2vpn evpn route detail
+show bgp l2vpn evpn vni remote-ip-hash
+show bgp l2vpn evpn vni-svi-hash
+
+show evpn
+show evpn arp-cache vni all detail
+show evpn mac vni all detail
+show evpn next-hops vni all
+show evpn rmac vni all
+show evpn vni detail
+
CMD_LIST_END
# Zebra Support Bundle Command List
diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang
index ca60c8f7b..1c990b5ed 100644
--- a/yang/frr-bgp-route-map.yang
+++ b/yang/frr-bgp-route-map.yang
@@ -300,6 +300,18 @@ module frr-bgp-route-map {
"Set BGP large community list (for deletion)";
}
+ identity set-evpn-gateway-ip-ipv4 {
+ base frr-route-map:rmap-set-type;
+ description
+ "Set EVPN gateway IP overlay index IPv4";
+ }
+
+ identity set-evpn-gateway-ip-ipv6 {
+ base frr-route-map:rmap-set-type;
+ description
+ "Set EVPN gateway IP overlay index IPv6";
+ }
+
grouping extcommunity-non-transitive-types {
leaf two-octet-as-specific {
type boolean;
@@ -816,5 +828,25 @@ module frr-bgp-route-map {
type bgp-filter:bgp-list-name;
}
}
+ case evpn-gateway-ip-ipv4 {
+ when
+ "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action,
+ 'frr-bgp-route-map:set-evpn-gateway-ip-ipv4')";
+ description
+ "Set EVPN gateway IP overlay index IPv4";
+ leaf evpn-gateway-ip-ipv4 {
+ type inet:ipv4-address;
+ }
+ }
+ case evpn-gateway-ip-ipv6 {
+ when
+ "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action,
+ 'frr-bgp-route-map:set-evpn-gateway-ip-ipv6')";
+ description
+ "Set EVPN gateway IP overlay index IPv6";
+ leaf evpn-gateway-ip-ipv6 {
+ type inet:ipv6-address;
+ }
+ }
}
}
diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c
index 30f4a4476..816f46bac 100644
--- a/zebra/zebra_evpn.c
+++ b/zebra/zebra_evpn.c
@@ -134,6 +134,10 @@ void zebra_evpn_print(zebra_evpn_t *zevpn, void **ctxt)
if (json == NULL) {
vty_out(vty, " VxLAN interface: %s\n", zevpn->vxlan_if->name);
vty_out(vty, " VxLAN ifIndex: %u\n", zevpn->vxlan_if->ifindex);
+ vty_out(vty, " SVI interface: %s\n",
+ (zevpn->svi_if ? zevpn->svi_if->name : ""));
+ vty_out(vty, " SVI ifIndex: %u\n",
+ (zevpn->svi_if ? zevpn->svi_if->ifindex : 0));
vty_out(vty, " Local VTEP IP: %pI4\n",
&zevpn->local_vtep_ip);
vty_out(vty, " Mcast group: %pI4\n",
@@ -142,6 +146,12 @@ void zebra_evpn_print(zebra_evpn_t *zevpn, void **ctxt)
json_object_string_add(json, "vxlanInterface",
zevpn->vxlan_if->name);
json_object_int_add(json, "ifindex", zevpn->vxlan_if->ifindex);
+ if (zevpn->svi_if) {
+ json_object_string_add(json, "sviInterface",
+ zevpn->svi_if->name);
+ json_object_int_add(json, "sviIfindex",
+ zevpn->svi_if->ifindex);
+ }
json_object_string_add(json, "vtepIp",
inet_ntop(AF_INET, &zevpn->local_vtep_ip,
buf, sizeof(buf)));
@@ -1048,6 +1058,8 @@ int zebra_evpn_del(zebra_evpn_t *zevpn)
zvrf = zebra_vrf_get_evpn();
assert(zvrf);
+ zevpn->svi_if = NULL;
+
/* Free the neighbor hash table. */
hash_free(zevpn->neigh_table);
zevpn->neigh_table = NULL;
@@ -1075,6 +1087,7 @@ int zebra_evpn_send_add_to_client(zebra_evpn_t *zevpn)
{
struct zserv *client;
struct stream *s;
+ ifindex_t svi_index;
int rc;
client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
@@ -1082,6 +1095,8 @@ int zebra_evpn_send_add_to_client(zebra_evpn_t *zevpn)
if (!client)
return 0;
+ svi_index = zevpn->svi_if ? zevpn->svi_if->ifindex : 0;
+
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
zclient_create_header(s, ZEBRA_VNI_ADD, zebra_vrf_get_evpn_id());
@@ -1089,15 +1104,18 @@ int zebra_evpn_send_add_to_client(zebra_evpn_t *zevpn)
stream_put_in_addr(s, &zevpn->local_vtep_ip);
stream_put(s, &zevpn->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */
stream_put_in_addr(s, &zevpn->mcast_grp);
+ stream_put(s, &svi_index, sizeof(ifindex_t));
/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Send EVPN_ADD %u %pI4 tenant vrf %s to %s", zevpn->vni,
- &zevpn->local_vtep_ip,
- vrf_id_to_name(zevpn->vrf_id),
- zebra_route_string(client->proto));
+ zlog_debug(
+ "Send EVPN_ADD %u %pI4 tenant vrf %s(%u) SVI index %u to %s",
+ zevpn->vni, &zevpn->local_vtep_ip,
+ vrf_id_to_name(zevpn->vrf_id), zevpn->vrf_id,
+ (zevpn->svi_if ? zevpn->svi_if->ifindex : 0),
+ zebra_route_string(client->proto));
client->vniadd_cnt++;
rc = zserv_send_message(client, s);
diff --git a/zebra/zebra_evpn.h b/zebra/zebra_evpn.h
index 27392ec85..ee9e1406e 100644
--- a/zebra/zebra_evpn.h
+++ b/zebra/zebra_evpn.h
@@ -98,6 +98,9 @@ struct zebra_evpn_t_ {
/* Corresponding VxLAN interface. */
struct interface *vxlan_if;
+ /* Corresponding SVI interface. */
+ struct interface *svi_if;
+
/* List of remote VTEPs */
zebra_vtep_t *vteps;
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index cebd57636..efbd078a5 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -42,6 +42,7 @@
#include "zebra/zebra_fpm_private.h"
#include "zebra/zebra_vxlan_private.h"
+#include "zebra/interface.h"
/*
* af_addr_size
@@ -164,7 +165,10 @@ static int netlink_route_info_add_nh(struct netlink_route_info *ri,
{
struct netlink_nh_info nhi;
union g_addr *src;
- zebra_l3vni_t *zl3vni = NULL;
+ struct zebra_vrf *zvrf = NULL;
+ struct interface *ifp = NULL, *link_if = NULL;
+ struct zebra_if *zif = NULL;
+ vni_t vni = 0;
memset(&nhi, 0, sizeof(nhi));
src = NULL;
@@ -199,12 +203,29 @@ static int netlink_route_info_add_nh(struct netlink_route_info *ri,
if (re && CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
nhi.encap_info.encap_type = FPM_NH_ENCAP_VXLAN;
- zl3vni = zl3vni_from_vrf(nexthop->vrf_id);
- if (zl3vni && is_l3vni_oper_up(zl3vni)) {
-
- /* Add VNI to VxLAN encap info */
- nhi.encap_info.vxlan_encap.vni = zl3vni->vni;
+ /* Extract VNI id for the nexthop SVI interface */
+ zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
+ if (zvrf) {
+ ifp = if_lookup_by_index_per_ns(zvrf->zns,
+ nexthop->ifindex);
+ if (ifp) {
+ zif = (struct zebra_if *)ifp->info;
+ if (zif) {
+ if (IS_ZEBRA_IF_BRIDGE(ifp))
+ link_if = ifp;
+ else if (IS_ZEBRA_IF_VLAN(ifp))
+ link_if =
+ if_lookup_by_index_per_ns(
+ zvrf->zns,
+ zif->link_ifindex);
+ if (link_if)
+ vni = vni_id_from_svi(ifp,
+ link_if);
+ }
+ }
}
+
+ nhi.encap_info.vxlan_encap.vni = vni;
}
/*
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 09eb78917..2f3ea7475 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -1012,6 +1012,7 @@ static int zevpn_build_hash_table_zns(struct ns *ns,
vxl->access_vlan,
zif->brslave_info.br_if);
if (vlan_if) {
+ zevpn->svi_if = vlan_if;
zevpn->vrf_id = vlan_if->vrf_id;
zl3vni = zl3vni_from_vrf(
vlan_if->vrf_id);
@@ -1841,6 +1842,27 @@ static zebra_l3vni_t *zl3vni_from_svi(struct interface *ifp,
return zl3vni;
}
+vni_t vni_id_from_svi(struct interface *ifp, struct interface *br_if)
+{
+ vni_t vni = 0;
+ zebra_evpn_t *zevpn = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
+
+ /* Check if an L3VNI belongs to this SVI interface.
+ * If not, check if an L2VNI belongs to this SVI interface.
+ */
+ zl3vni = zl3vni_from_svi(ifp, br_if);
+ if (zl3vni)
+ vni = zl3vni->vni;
+ else {
+ zevpn = zebra_evpn_from_svi(ifp, br_if);
+ if (zevpn)
+ vni = zevpn->vni;
+ }
+
+ return vni;
+}
+
static inline void zl3vni_get_vrr_rmac(zebra_l3vni_t *zl3vni,
struct ethaddr *rmac)
{
@@ -4527,6 +4549,7 @@ int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if)
zevpn = zebra_evpn_from_svi(ifp, link_if);
if (zevpn) {
+ zevpn->svi_if = NULL;
zevpn->vrf_id = VRF_DEFAULT;
/* update the tenant vrf in BGP */
@@ -4582,6 +4605,7 @@ int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
vrf_id_to_name(ifp->vrf_id));
/* update the vrf information for l2-vni and inform bgp */
+ zevpn->svi_if = ifp;
zevpn->vrf_id = ifp->vrf_id;
if (if_is_operative(zevpn->vxlan_if))
@@ -4792,6 +4816,7 @@ int zebra_vxlan_if_up(struct interface *ifp)
vlan_if = zvni_map_to_svi(vxl->access_vlan,
zif->brslave_info.br_if);
if (vlan_if) {
+ zevpn->svi_if = vlan_if;
zevpn->vrf_id = vlan_if->vrf_id;
zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
if (zl3vni)
@@ -4894,6 +4919,7 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
struct zebra_l2info_vxlan *vxl = NULL;
zebra_evpn_t *zevpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
+ struct interface *vlan_if = NULL;
/* Check if EVPN is enabled. */
if (!is_evpn_enabled())
@@ -4983,6 +5009,7 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
&& (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
/* Delete from client, remove all remote VTEPs */
/* Also, free up all MACs and neighbors. */
+ zevpn->svi_if = NULL;
zebra_evpn_send_del_to_client(zevpn);
zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH);
zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
@@ -5012,6 +5039,11 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
zebra_evpn_es_set_base_evpn(zevpn);
}
zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
+ vlan_if = zvni_map_to_svi(vxl->access_vlan,
+ zif->brslave_info.br_if);
+ if (vlan_if)
+ zevpn->svi_if = vlan_if;
+
/* Take further actions needed.
* Note that if we are here, there is a change of interest.
*/
@@ -5131,6 +5163,7 @@ int zebra_vxlan_if_add(struct interface *ifp)
vlan_if = zvni_map_to_svi(vxl->access_vlan,
zif->brslave_info.br_if);
if (vlan_if) {
+ zevpn->svi_if = vlan_if;
zevpn->vrf_id = vlan_if->vrf_id;
zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
if (zl3vni)
diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h
index 0556c4adc..84ac76b3b 100644
--- a/zebra/zebra_vxlan_private.h
+++ b/zebra/zebra_vxlan_private.h
@@ -224,6 +224,7 @@ extern struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni);
extern struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni);
extern struct interface *zl3vni_map_to_mac_vlan_if(zebra_l3vni_t *zl3vni);
extern zebra_l3vni_t *zl3vni_lookup(vni_t vni);
+extern vni_t vni_id_from_svi(struct interface *ifp, struct interface *br_if);
DECLARE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
bool delete, const char *reason), (rmac, zl3vni, delete, reason));