mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 08:36:43 +00:00
Merge pull request #6695 from adharkar/frr-master-gateway_ip
EVPN route type-5 gateway IP overlay Index
This commit is contained in:
commit
fa855f8fa3
@ -315,3 +315,4 @@ extern bool is_zero_gw_ip(const union gw_addr *gw_ip, const afi_t afi)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
637
bgpd/bgp_evpn.c
637
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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 (afi == AFI_IP) {
|
||||
|
||||
/* 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);
|
||||
} 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);
|
||||
if ((oly != OVERLAY_INDEX_TYPE_NONE)
|
||||
&& (oly != OVERLAY_INDEX_GATEWAY_IP)) {
|
||||
vty_out(vty, "%%Unknown overlay-index type specified");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (rmap_changed) {
|
||||
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 {
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
/*
|
||||
* 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) || (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");
|
||||
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 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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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 */
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -371,6 +371,20 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
|
||||
.destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.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,
|
||||
},
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
35
bgpd/bgpd.h
35
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)
|
||||
|
109
doc/user/bgp.rst
109
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
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
] } }
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
] } }
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"vrfName": "vrf-blue",
|
||||
"routerId": "10.100.0.1",
|
||||
"defaultLocPrf": 100,
|
||||
"localAS": 101,
|
||||
"routes": { "100.0.0.21/32": null } }
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
] } }
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
] } }
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"vrfName": "vrf-blue",
|
||||
"routerId": "10.100.0.1",
|
||||
"defaultLocPrf": 100,
|
||||
"localAS": 101,
|
||||
"routes": { "100::21/128": null } }
|
30
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgpd.conf
Normal file
30
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgpd.conf
Normal file
@ -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
|
@ -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
|
||||
!
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
] } }
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
] } }
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"vrfName": "vrf-blue",
|
||||
"routerId": "10.100.0.2",
|
||||
"defaultLocPrf": 100,
|
||||
"localAS": 101,
|
||||
"routes": { "100.0.0.21/32": null } }
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
] } }
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
] } }
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"vrfName": "vrf-blue",
|
||||
"routerId": "10.100.0.2",
|
||||
"defaultLocPrf": 100,
|
||||
"localAS": 101,
|
||||
"routes": { "100::21/128": null } }
|
14
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgpd.conf
Normal file
14
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgpd.conf
Normal file
@ -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
|
@ -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
|
||||
!
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -0,0 +1,4 @@
|
||||
!
|
||||
int host1-eth0
|
||||
ip address 50.0.1.11/24
|
||||
ipv6 address 50:0:1::11/48
|
@ -0,0 +1 @@
|
||||
!
|
@ -0,0 +1,4 @@
|
||||
!
|
||||
int host1-eth0
|
||||
ip address 50.0.1.21/24
|
||||
ipv6 address 50:0:1::21/48
|
@ -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))
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user