summaryrefslogtreecommitdiff
path: root/bgpd/bgp_evpn.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_evpn.c')
-rw-r--r--bgpd/bgp_evpn.c964
1 files changed, 786 insertions, 178 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 159cb33fee..e142ff6a34 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -41,6 +41,7 @@
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_trace.h"
#include "bgpd/bgp_mpath.h"
+#include "bgpd/bgp_packet.h"
/*
* Definitions and external declarations.
@@ -48,6 +49,7 @@
DEFINE_QOBJ_TYPE(bgpevpn);
DEFINE_QOBJ_TYPE(bgp_evpn_es);
+DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information");
DEFINE_MTYPE_STATIC(BGPD, VRF_ROUTE_TARGET, "L3 Route Target");
/*
@@ -309,6 +311,49 @@ static int is_vni_present_in_irt_vnis(struct list *vnis, struct bgpevpn *vpn)
return 0;
}
+/* Flag if the route is injectable into EVPN.
+ * This would be following category:
+ * Non-imported route,
+ * Non-EVPN imported route,
+ */
+bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi)
+{
+ struct bgp_path_info *parent_pi;
+ struct bgp_table *table;
+ struct bgp_dest *dest;
+
+ if (pi->sub_type != BGP_ROUTE_IMPORTED || !pi->extra ||
+ !pi->extra->vrfleak || !pi->extra->vrfleak->parent)
+ return true;
+
+ parent_pi = (struct bgp_path_info *)pi->extra->vrfleak->parent;
+ dest = parent_pi->net;
+ if (!dest)
+ return true;
+ table = bgp_dest_table(dest);
+ if (table &&
+ table->afi == AFI_L2VPN &&
+ table->safi == SAFI_EVPN)
+ return false;
+
+ return true;
+}
+
+/* Flag if the route is injectable into EVPN.
+ * This would be following category:
+ * Non-imported route,
+ * Non-EVPN imported route,
+ * Non Aggregate suppressed route.
+ */
+bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
+{
+ /* do not import aggr suppressed routes */
+ if (bgp_path_suppressed(pi))
+ return false;
+
+ return is_route_injectable_into_evpn_non_supp(pi);
+}
+
/*
* Compare Route Targets.
*/
@@ -577,7 +622,7 @@ static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl,
if (bgp->advertise_autort_rfc8365)
vni |= EVPN_AUTORT_VXLAN;
- encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
+ encode_route_target_as((bgp->as & 0xFFFF), vni, &eval, true);
ecomadd = ecommunity_new();
ecommunity_add_val(ecomadd, &eval, false, false);
@@ -847,11 +892,10 @@ struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn,
/*
* Add (update) or delete MACIP from zebra.
*/
-static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
- const struct prefix_evpn *p,
- const struct ethaddr *mac,
- struct in_addr remote_vtep_ip, int add,
- uint8_t flags, uint32_t seq, esi_t *esi)
+static enum zclient_send_status bgp_zebra_send_remote_macip(
+ struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p,
+ const struct ethaddr *mac, struct in_addr remote_vtep_ip, int add,
+ uint8_t flags, uint32_t seq, esi_t *esi)
{
struct stream *s;
uint16_t ipa_len;
@@ -859,8 +903,12 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
bool esi_valid;
/* Check socket. */
- if (!zclient || zclient->sock < 0)
- return 0;
+ if (!zclient || zclient->sock < 0) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: No zclient or zclient->sock exists",
+ __func__);
+ return ZCLIENT_SEND_SUCCESS;
+ }
/* Don't try to register if Zebra doesn't know of this instance. */
if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
@@ -868,7 +916,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
zlog_debug(
"%s: No zebra instance to talk to, not installing remote macip",
__func__);
- return 0;
+ return ZCLIENT_SEND_SUCCESS;
}
if (!esi)
@@ -879,7 +927,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
zclient_create_header(
s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL,
bgp->vrf_id);
- stream_putl(s, vpn->vni);
+ stream_putl(s, vpn ? vpn->vni : 0);
if (mac) /* Mac Addr */
stream_put(s, &mac->octet, ETH_ALEN);
@@ -925,7 +973,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
snprintf(esi_buf, sizeof(esi_buf), "-");
zlog_debug(
"Tx %s MACIP, VNI %u MAC %pEA IP %pIA flags 0x%x seq %u remote VTEP %pI4 esi %s",
- add ? "ADD" : "DEL", vpn->vni,
+ add ? "ADD" : "DEL", (vpn ? vpn->vni : 0),
(mac ? mac : &p->prefix.macip_addr.mac),
&p->prefix.macip_addr.ip, flags, seq, &remote_vtep_ip,
esi_buf);
@@ -940,15 +988,20 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
/*
* Add (update) or delete remote VTEP from zebra.
*/
-static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
- const struct prefix_evpn *p,
- int flood_control, int add)
+static enum zclient_send_status
+bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
+ const struct prefix_evpn *p, int flood_control,
+ int add)
{
struct stream *s;
/* Check socket. */
- if (!zclient || zclient->sock < 0)
- return 0;
+ if (!zclient || zclient->sock < 0) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: No zclient or zclient->sock exists",
+ __func__);
+ return ZCLIENT_SEND_SUCCESS;
+ }
/* Don't try to register if Zebra doesn't know of this instance. */
if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
@@ -956,7 +1009,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
zlog_debug(
"%s: No zebra instance to talk to, not installing remote vtep",
__func__);
- return 0;
+ return ZCLIENT_SEND_SUCCESS;
}
s = zclient->obuf;
@@ -965,15 +1018,15 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
zclient_create_header(
s, add ? ZEBRA_REMOTE_VTEP_ADD : ZEBRA_REMOTE_VTEP_DEL,
bgp->vrf_id);
- stream_putl(s, vpn->vni);
+ stream_putl(s, vpn ? vpn->vni : 0);
if (is_evpn_prefix_ipaddr_v4(p))
stream_put_in_addr(s, &p->prefix.imet_addr.ip.ipaddr_v4);
else if (is_evpn_prefix_ipaddr_v6(p)) {
flog_err(
EC_BGP_VTEP_INVALID,
"Bad remote IP when trying to %s remote VTEP for VNI %u",
- add ? "ADD" : "DEL", vpn->vni);
- return -1;
+ add ? "ADD" : "DEL", (vpn ? vpn->vni : 0));
+ return ZCLIENT_SEND_FAILURE;
}
stream_putl(s, flood_control);
@@ -981,7 +1034,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
if (bgp_debug_zebra(NULL))
zlog_debug("Tx %s Remote VTEP, VNI %u remote VTEP %pI4",
- add ? "ADD" : "DEL", vpn->vni,
+ add ? "ADD" : "DEL", (vpn ? vpn->vni : 0),
&p->prefix.imet_addr.ip.ipaddr_v4);
frrtrace(3, frr_bgp, evpn_bum_vtep_zsend, add, vpn, p);
@@ -1050,7 +1103,8 @@ static void build_evpn_type5_route_extcomm(struct bgp *bgp_vrf,
* type-2 routes.
*/
static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
- int add_l3_ecomm)
+ int add_l3_ecomm,
+ struct ecommunity *macvrf_soo)
{
struct ecommunity ecom_encap;
struct ecommunity ecom_sticky;
@@ -1147,6 +1201,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
attr, ecommunity_merge(bgp_attr_get_ecommunity(attr),
&ecom_na));
}
+
+ /* Add MAC-VRF SoO, if configured */
+ if (macvrf_soo)
+ bgp_attr_set_ecommunity(
+ attr, ecommunity_merge(attr->ecommunity, macvrf_soo));
}
/*
@@ -1206,14 +1265,14 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr)
}
/* Install EVPN route into zebra. */
-static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
- const struct prefix_evpn *p,
- struct bgp_path_info *pi)
+enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *pi)
{
- int ret;
uint8_t flags;
int flood_control = VXLAN_FLOOD_DISABLED;
uint32_t seq;
+ enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
flags = 0;
@@ -1291,6 +1350,7 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
flood_control = VXLAN_FLOOD_DISABLED;
break;
}
+
ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, flood_control, 1);
}
@@ -1298,11 +1358,13 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
}
/* Uninstall EVPN route from zebra. */
-static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn,
- const struct prefix_evpn *p,
- struct bgp_path_info *pi, bool is_sync)
+enum zclient_send_status evpn_zebra_uninstall(struct bgp *bgp,
+ struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *pi,
+ bool is_sync)
{
- int ret;
+ enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
ret = bgp_zebra_send_remote_macip(
@@ -1317,7 +1379,7 @@ static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn,
ret = bgp_evpn_remote_es_evi_del(bgp, vpn, p);
else
ret = bgp_zebra_send_remote_vtep(bgp, vpn, p,
- VXLAN_FLOOD_DISABLED, 0);
+ VXLAN_FLOOD_DISABLED, 0);
return ret;
}
@@ -1408,12 +1470,18 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
&& !CHECK_FLAG(dest->flags, BGP_NODE_USER_CLEAR)
&& !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED)
&& !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
- if (bgp_zebra_has_route_changed(old_select))
- ret = evpn_zebra_install(
- bgp, vpn,
- (const struct prefix_evpn *)bgp_dest_get_prefix(
- dest),
- old_select);
+ if (bgp_zebra_has_route_changed(old_select)) {
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
+ evpn_zebra_install(bgp, vpn,
+ (const struct prefix_evpn *)
+ bgp_dest_get_prefix(
+ dest),
+ old_select);
+ else
+ bgp_zebra_route_install(dest, old_select, bgp,
+ true, vpn, false);
+ }
+
UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG);
UNSET_FLAG(old_select->flags, BGP_PATH_LINK_BW_CHG);
bgp_zebra_clear_route_change_flags(dest);
@@ -1445,10 +1513,14 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
if (new_select && new_select->type == ZEBRA_ROUTE_BGP
&& (new_select->sub_type == BGP_ROUTE_IMPORTED ||
bgp_evpn_attr_is_sync(new_select->attr))) {
- ret = evpn_zebra_install(
- bgp, vpn,
- (struct prefix_evpn *)bgp_dest_get_prefix(dest),
- new_select);
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
+ evpn_zebra_install(bgp, vpn,
+ (const struct prefix_evpn *)
+ bgp_dest_get_prefix(dest),
+ new_select);
+ else
+ bgp_zebra_route_install(dest, new_select, bgp, true,
+ vpn, false);
/* If an old best existed and it was a "local" route, the only
* reason
@@ -1465,13 +1537,19 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
evpn_delete_old_local_route(bgp, vpn, dest,
old_select, new_select);
} else {
- if (old_select && old_select->type == ZEBRA_ROUTE_BGP
- && old_select->sub_type == BGP_ROUTE_IMPORTED)
- ret = evpn_zebra_uninstall(
- bgp, vpn,
- (const struct prefix_evpn *)bgp_dest_get_prefix(
- dest),
- old_select, false);
+ if (old_select && old_select->type == ZEBRA_ROUTE_BGP &&
+ old_select->sub_type == BGP_ROUTE_IMPORTED) {
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) ||
+ CHECK_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN))
+ evpn_zebra_uninstall(bgp, vpn,
+ (const struct prefix_evpn *)
+ bgp_dest_get_prefix(
+ dest),
+ old_select, false);
+ else
+ bgp_zebra_route_install(dest, old_select, bgp,
+ false, vpn, false);
+ }
}
/* Clear any route change flags. */
@@ -1624,6 +1702,9 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
vrf_id_to_name(bgp_vrf->vrf_id), evp, &attr.rmac,
&attr.nexthop);
+ frrtrace(4, frr_bgp, evpn_advertise_type5, bgp_vrf->vrf_id, evp,
+ &attr.rmac, attr.nexthop);
+
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
if (src_afi == AFI_IP6 &&
@@ -1685,7 +1766,7 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi,
int paths_eq;
struct ethaddr *tmp_mac;
bool mac_cmp = false;
- struct prefix_evpn *evp = (struct prefix_evpn *)&dest->p;
+ struct prefix_evpn *evp = (struct prefix_evpn *)&dest->rn->p;
/* mac comparison is not needed for MAC-only routes */
@@ -1708,8 +1789,8 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi,
continue;
}
- if (bgp_evpn_path_info_cmp(bgp, tmp_pi,
- second_best_path, &paths_eq))
+ if (bgp_evpn_path_info_cmp(bgp, tmp_pi, second_best_path,
+ &paths_eq, false))
second_best_path = tmp_pi;
}
@@ -1910,7 +1991,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
/* Mark route as self type-2 route */
if (flags && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP))
- tmp_pi->extra->af_flags = BGP_EVPN_MACIP_TYPE_SVI_IP;
+ tmp_pi->extra->evpn->af_flags =
+ BGP_EVPN_MACIP_TYPE_SVI_IP;
bgp_path_info_add(dest, tmp_pi);
} else {
tmp_pi = local_pi;
@@ -2001,9 +2083,19 @@ static void evpn_zebra_reinstall_best_route(struct bgp *bgp,
if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP
&& (curr_select->sub_type == BGP_ROUTE_IMPORTED ||
bgp_evpn_attr_is_sync(curr_select->attr)))
- evpn_zebra_install(bgp, vpn,
- (const struct prefix_evpn *)bgp_dest_get_prefix(dest),
- curr_select);
+ if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP &&
+ (curr_select->sub_type == BGP_ROUTE_IMPORTED ||
+ bgp_evpn_attr_is_sync(curr_select->attr))) {
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
+ evpn_zebra_install(bgp, vpn,
+ (const struct prefix_evpn *)
+ bgp_dest_get_prefix(
+ dest),
+ curr_select);
+ else
+ bgp_zebra_route_install(dest, curr_select, bgp,
+ true, vpn, false);
+ }
}
/*
@@ -2020,10 +2112,10 @@ static void evpn_zebra_reinstall_best_route(struct bgp *bgp,
* additional handling to prevent bgp from injecting and holding on to a
* non-best local path.
*/
-static void evpn_cleanup_local_non_best_route(struct bgp *bgp,
- struct bgpevpn *vpn,
- struct bgp_dest *dest,
- struct bgp_path_info *local_pi)
+static struct bgp_dest *
+evpn_cleanup_local_non_best_route(struct bgp *bgp, struct bgpevpn *vpn,
+ struct bgp_dest *dest,
+ struct bgp_path_info *local_pi)
{
/* local path was not picked as the winner; kick it out */
if (bgp_debug_zebra(NULL))
@@ -2031,10 +2123,11 @@ static void evpn_cleanup_local_non_best_route(struct bgp *bgp,
dest);
evpn_delete_old_local_route(bgp, vpn, dest, local_pi, NULL);
- bgp_path_info_reap(dest, local_pi);
/* tell zebra to re-add the best remote path */
evpn_zebra_reinstall_best_route(bgp, vpn, dest);
+
+ return bgp_path_info_reap(dest, local_pi);
}
static inline bool bgp_evpn_route_add_l3_ecomm_ok(struct bgpevpn *vpn,
@@ -2068,6 +2161,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
int route_change;
bool old_is_sync = false;
bool mac_only = false;
+ struct ecommunity *macvrf_soo = NULL;
memset(&attr, 0, sizeof(attr));
@@ -2125,8 +2219,11 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok(
vpn, p, (attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL);
+ if (bgp->evpn_info)
+ macvrf_soo = bgp->evpn_info->soo;
+
/* Set up extended community. */
- build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm);
+ build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm, macvrf_soo);
/* First, create (or fetch) route node within the VNI.
* NOTE: There is no RD here.
@@ -2167,7 +2264,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
} else {
if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) {
route_change = 0;
- evpn_cleanup_local_non_best_route(bgp, vpn, dest, pi);
+ dest = evpn_cleanup_local_non_best_route(bgp, vpn, dest,
+ pi);
} else {
bool new_is_sync;
@@ -2178,13 +2276,22 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
* has been removed.
*/
new_is_sync = bgp_evpn_attr_is_sync(pi->attr);
- if (!new_is_sync && old_is_sync)
- evpn_zebra_uninstall(bgp, vpn, p, pi, true);
+ if (!new_is_sync && old_is_sync) {
+ if (CHECK_FLAG(bgp->flags,
+ BGP_FLAG_DELETE_IN_PROGRESS))
+ evpn_zebra_uninstall(bgp, vpn, p, pi,
+ true);
+ else
+ bgp_zebra_route_install(dest, pi, bgp,
+ false, vpn,
+ true);
+ }
}
}
bgp_path_info_unlock(pi);
- bgp_dest_unlock_node(dest);
+ if (dest)
+ bgp_dest_unlock_node(dest);
/* If this is a new route or some attribute has changed, export the
* route to the global table. The route will be advertised to peers
@@ -2258,6 +2365,8 @@ static int delete_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp)
if (!dest)
return 0;
+ frrtrace(2, frr_bgp, evpn_withdraw_type5, bgp_vrf->vrf_id, evp);
+
delete_evpn_route_entry(bgp_evpn, afi, safi, dest, &pi);
if (pi)
bgp_process(bgp_evpn, dest, afi, safi);
@@ -2308,9 +2417,13 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
*/
delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
if (pi) {
- bgp_path_info_reap(dest, pi);
+ dest = bgp_path_info_reap(dest, pi);
+ assert(dest);
evpn_route_select_install(bgp, vpn, dest);
}
+
+ /* dest should still exist due to locking make coverity happy */
+ assert(dest);
bgp_dest_unlock_node(dest);
return 0;
@@ -2333,6 +2446,7 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
struct prefix_evpn evp;
int route_change;
bool old_is_sync = false;
+ struct ecommunity *macvrf_soo = NULL;
if (CHECK_FLAG(local_pi->flags, BGP_PATH_REMOVED))
return;
@@ -2341,15 +2455,15 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
* VNI table MAC-IP prefixes don't have MAC so make sure it's set from
* path info here.
*/
- if (is_evpn_prefix_ipaddr_none((struct prefix_evpn *)&dest->p)) {
+ if (is_evpn_prefix_ipaddr_none((struct prefix_evpn *)&dest->rn->p)) {
/* VNI MAC -> Global */
evpn_type2_prefix_global_copy(
- &evp, (struct prefix_evpn *)&dest->p, NULL /* mac */,
+ &evp, (struct prefix_evpn *)&dest->rn->p, NULL /* mac */,
evpn_type2_path_info_get_ip(local_pi));
} else {
/* VNI IP -> Global */
evpn_type2_prefix_global_copy(
- &evp, (struct prefix_evpn *)&dest->p,
+ &evp, (struct prefix_evpn *)&dest->rn->p,
evpn_type2_path_info_get_mac(local_pi), NULL /* ip */);
}
@@ -2371,7 +2485,8 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
attr.router_flag = 1;
}
memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t));
- bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr, local_pi->extra->af_flags);
+ bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr,
+ local_pi->extra->evpn->af_flags);
vni2label(vpn->vni, &(attr.label));
/* Add L3 VNI RTs and RMAC for non IPv6 link-local if
* using L3 VNI for type-2 routes also.
@@ -2380,8 +2495,11 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
vpn, &evp,
(attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL);
+ if (bgp->evpn_info)
+ macvrf_soo = bgp->evpn_info->soo;
+
/* Set up extended community. */
- build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm);
+ build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm, macvrf_soo);
seq = mac_mobility_seqnum(local_pi->attr);
if (bgp_debug_zebra(NULL)) {
@@ -2433,8 +2551,17 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
* has been removed.
*/
new_is_sync = bgp_evpn_attr_is_sync(pi->attr);
- if (!new_is_sync && old_is_sync)
- evpn_zebra_uninstall(bgp, vpn, &evp, pi, true);
+ if (!new_is_sync && old_is_sync) {
+ if (CHECK_FLAG(bgp->flags,
+ BGP_FLAG_DELETE_IN_PROGRESS))
+ (void)evpn_zebra_uninstall(bgp, vpn,
+ &evp, pi,
+ true);
+ else
+ bgp_zebra_route_install(dest, pi, bgp,
+ false, vpn,
+ true);
+ }
}
}
@@ -2547,7 +2674,8 @@ static void delete_global_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
}
}
-static void delete_vni_type2_route(struct bgp *bgp, struct bgp_dest *dest)
+static struct bgp_dest *delete_vni_type2_route(struct bgp *bgp,
+ struct bgp_dest *dest)
{
struct bgp_path_info *pi;
afi_t afi = AFI_L2VPN;
@@ -2557,13 +2685,15 @@ static void delete_vni_type2_route(struct bgp *bgp, struct bgp_dest *dest)
(const struct prefix_evpn *)bgp_dest_get_prefix(dest);
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
- return;
+ return dest;
delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
/* Route entry in local table gets deleted immediately. */
if (pi)
- bgp_path_info_reap(dest, pi);
+ dest = bgp_path_info_reap(dest, pi);
+
+ return dest;
}
static void delete_vni_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
@@ -2574,12 +2704,16 @@ static void delete_vni_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
* routes.
*/
for (dest = bgp_table_top(vpn->mac_table); dest;
- dest = bgp_route_next(dest))
- delete_vni_type2_route(bgp, dest);
+ dest = bgp_route_next(dest)) {
+ dest = delete_vni_type2_route(bgp, dest);
+ assert(dest);
+ }
for (dest = bgp_table_top(vpn->ip_table); dest;
- dest = bgp_route_next(dest))
- delete_vni_type2_route(bgp, dest);
+ dest = bgp_route_next(dest)) {
+ dest = delete_vni_type2_route(bgp, dest);
+ assert(dest);
+ }
}
/*
@@ -2611,7 +2745,9 @@ static void delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
(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);
+ dest = bgp_path_info_reap(dest, pi);
+
+ assert(dest);
}
}
@@ -2620,7 +2756,9 @@ static void delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
for (pi = bgp_dest_get_bgp_path_info(dest);
(pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
bgp_path_info_delete(dest, pi);
- bgp_path_info_reap(dest, pi);
+ dest = bgp_path_info_reap(dest, pi);
+
+ assert(dest);
}
}
}
@@ -2673,6 +2811,21 @@ int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
return 0;
}
+/* Update Type-2/3 Routes for L2VNI.
+ * Called by hash_iterate()
+ */
+static void update_routes_for_vni_hash(struct hash_bucket *bucket,
+ struct bgp *bgp)
+{
+ struct bgpevpn *vpn;
+
+ if (!bucket)
+ return;
+
+ vpn = (struct bgpevpn *)bucket->data;
+ update_routes_for_vni(bgp, vpn);
+}
+
/*
* Delete (and withdraw) local routes for specified VNI from the global
* table and per-VNI table. After this, remove all other routes from
@@ -2690,7 +2843,22 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
delete_all_type2_routes(bgp, vpn);
build_evpn_type3_prefix(&p, vpn->originator_ip);
+
+ /*
+ * To handle the following scenario:
+ * - Say, the new zebra announce fifo list has few vni Evpn prefixes yet
+ * to be sent to zebra.
+ * - At this point if we have triggers like "no advertise-all-vni" or
+ * "networking restart", where a vni is going down.
+ *
+ * Perform the below
+ * 1) send withdraw routes to zebra immediately in case it is installed.
+ * 2) before we blow up the vni table, we need to walk the list and
+ * pop all the dest whose za_vpn points to this vni.
+ */
+ SET_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN);
ret = delete_evpn_route(bgp, vpn, &p);
+ UNSET_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN);
if (ret)
return ret;
@@ -2720,43 +2888,60 @@ static int bgp_evpn_mcast_grp_change(struct bgp *bgp, struct bgpevpn *vpn,
}
/*
- * There is a tunnel endpoint IP address change for this VNI, delete
- * prior type-3 route (if needed) and update.
+ * If there is a tunnel endpoint IP address (VTEP-IP) change for this VNI.
+ - Deletes tip_hash entry for old VTEP-IP
+ - Adds tip_hash entry/refcount for new VTEP-IP
+ - Deletes prior type-3 route for L2VNI (if needed)
+ - Updates originator_ip
* Note: Route re-advertisement happens elsewhere after other processing
* other changes.
*/
-static void handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn,
+static void handle_tunnel_ip_change(struct bgp *bgp_vrf, struct bgp *bgp_evpn,
+ struct bgpevpn *vpn,
struct in_addr originator_ip)
{
struct prefix_evpn p;
+ struct in_addr old_vtep_ip;
- if (IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip))
+ if (bgp_vrf) /* L3VNI */
+ old_vtep_ip = bgp_vrf->originator_ip;
+ else /* L2VNI */
+ old_vtep_ip = vpn->originator_ip;
+
+ /* TIP didn't change, nothing to do */
+ if (IPV4_ADDR_SAME(&old_vtep_ip, &originator_ip))
return;
- /* If VNI is not live, we only need to update the originator ip */
- if (!is_vni_live(vpn)) {
+ /* If L2VNI is not live, we only need to update the originator_ip.
+ * L3VNIs are updated immediately, so we can't bail out early.
+ */
+ if (!bgp_vrf && !is_vni_live(vpn)) {
vpn->originator_ip = originator_ip;
return;
}
/* Update the tunnel-ip hash */
- bgp_tip_del(bgp, &vpn->originator_ip);
- if (bgp_tip_add(bgp, &originator_ip))
+ bgp_tip_del(bgp_evpn, &old_vtep_ip);
+ if (bgp_tip_add(bgp_evpn, &originator_ip))
/* The originator_ip was not already present in the
* bgp martian next-hop table as a tunnel-ip, so we
* need to go back and filter routes matching the new
* martian next-hop.
*/
- bgp_filter_evpn_routes_upon_martian_nh_change(bgp);
+ bgp_filter_evpn_routes_upon_martian_change(bgp_evpn,
+ BGP_MARTIAN_TUN_IP);
- /* Need to withdraw type-3 route as the originator IP is part
- * of the key.
- */
- build_evpn_type3_prefix(&p, vpn->originator_ip);
- delete_evpn_route(bgp, vpn, &p);
+ if (!bgp_vrf) {
+ /* Need to withdraw type-3 route as the originator IP is part
+ * of the key.
+ */
+ build_evpn_type3_prefix(&p, vpn->originator_ip);
+ delete_evpn_route(bgp_evpn, vpn, &p);
+
+ vpn->originator_ip = originator_ip;
+ } else
+ bgp_vrf->originator_ip = originator_ip;
- /* Update the tunnel IP and re-advertise all routes for this VNI. */
- vpn->originator_ip = originator_ip;
return;
}
@@ -2775,7 +2960,11 @@ bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi,
attr_new, dest);
SET_FLAG(pi->flags, BGP_PATH_VALID);
bgp_path_info_extra_get(pi);
- pi->extra->parent = bgp_path_info_lock(parent_pi);
+ if (!pi->extra->vrfleak)
+ pi->extra->vrfleak =
+ XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VRFLEAK,
+ sizeof(struct bgp_path_info_extra_vrfleak));
+ pi->extra->vrfleak->parent = bgp_path_info_lock(parent_pi);
bgp_dest_lock_node((struct bgp_dest *)parent_pi->net);
if (parent_pi->extra) {
memcpy(&pi->extra->label, &parent_pi->extra->label,
@@ -2881,8 +3070,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
/* Check if route entry is already present. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
- if (pi->extra
- && (struct bgp_path_info *)pi->extra->parent == parent_pi)
+ if (pi->extra && pi->extra->vrfleak &&
+ (struct bgp_path_info *)pi->extra->vrfleak->parent ==
+ parent_pi)
break;
if (!pi) {
@@ -2950,13 +3140,24 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
/* Process for route leaking. */
vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi);
- bgp_dest_unlock_node(dest);
+ if (bgp_debug_zebra(NULL)) {
+ struct ipaddr nhip = {};
- if (bgp_debug_zebra(NULL))
- zlog_debug("... %s pi dest %p (l %d) pi %p (l %d, f 0x%x)",
- new_pi ? "new" : "update", dest,
+ if (pi->net->rn->p.family == AF_INET6) {
+ SET_IPADDR_V6(&nhip);
+ IPV6_ADDR_COPY(&nhip.ipaddr_v6, &pi->attr->mp_nexthop_global);
+ } else {
+ SET_IPADDR_V4(&nhip);
+ IPV4_ADDR_COPY(&nhip.ipaddr_v4, &pi->attr->nexthop);
+ }
+ zlog_debug("... %s pi %s dest %p (l %d) pi %p (l %d, f 0x%x) nh %pIA",
+ new_pi ? "new" : "update",
+ bgp_vrf->name_pretty, dest,
bgp_dest_get_lock_count(dest), pi, pi->lock,
- pi->flags);
+ pi->flags, &nhip);
+ }
+
+ bgp_dest_unlock_node(dest);
return ret;
}
@@ -2977,8 +3178,9 @@ static int install_evpn_route_entry_in_vni_common(
/* Check if route entry is already present. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
- if (pi->extra
- && (struct bgp_path_info *)pi->extra->parent == parent_pi)
+ if (pi->extra && pi->extra->vrfleak &&
+ (struct bgp_path_info *)pi->extra->vrfleak->parent ==
+ parent_pi)
break;
if (!pi) {
@@ -3029,7 +3231,7 @@ static int install_evpn_route_entry_in_vni_common(
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("VNI %d path %pFX chg to %s es",
- vpn->vni, &pi->net->p,
+ vpn->vni, &pi->net->rn->p,
new_local_es ? "local"
: "non-local");
bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED);
@@ -3073,8 +3275,9 @@ static int uninstall_evpn_route_entry_in_vni_common(
/* Find matching route entry. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
- if (pi->extra &&
- (struct bgp_path_info *)pi->extra->parent == parent_pi)
+ if (pi->extra && pi->extra->vrfleak &&
+ (struct bgp_path_info *)pi->extra->vrfleak->parent ==
+ parent_pi)
break;
if (!pi)
@@ -3251,8 +3454,9 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
/* Find matching route entry. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
- if (pi->extra
- && (struct bgp_path_info *)pi->extra->parent == parent_pi)
+ if (pi->extra && pi->extra->vrfleak &&
+ (struct bgp_path_info *)pi->extra->vrfleak->parent ==
+ parent_pi)
break;
if (!pi) {
@@ -3260,10 +3464,22 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
return 0;
}
- if (bgp_debug_zebra(NULL))
- zlog_debug("... delete dest %p (l %d) pi %p (l %d, f 0x%x)",
- dest, bgp_dest_get_lock_count(dest), pi, pi->lock,
- pi->flags);
+ if (bgp_debug_zebra(NULL)) {
+ struct ipaddr nhip = {};
+
+ if (pi->net->rn->p.family == AF_INET6) {
+ SET_IPADDR_V6(&nhip);
+ IPV6_ADDR_COPY(&nhip.ipaddr_v6, &pi->attr->mp_nexthop_global);
+ } else {
+ SET_IPADDR_V4(&nhip);
+ IPV4_ADDR_COPY(&nhip.ipaddr_v4, &pi->attr->nexthop);
+ }
+
+ zlog_debug("... delete pi %s dest %p (l %d) pi %p (l %d, f 0x%x) nh %pIA",
+ bgp_vrf->name_pretty, dest,
+ bgp_dest_get_lock_count(dest), pi, pi->lock,
+ pi->flags, &nhip);
+ }
/* Process for route leaking. */
vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi);
@@ -3271,6 +3487,9 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
bgp_aggregate_decrement(bgp_vrf, bgp_dest_get_prefix(dest), pi, afi,
safi);
+ /* Force deletion */
+ SET_FLAG(dest->flags, BGP_NODE_PROCESS_CLEAR);
+
/* Mark entry for deletion */
bgp_path_info_delete(dest, pi);
@@ -3366,7 +3585,7 @@ static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
/*
* Given a route entry and a VRF, see if this route entry should be
- * imported into the VRF i.e., RTs match.
+ * imported into the VRF i.e., RTs match + Site-of-Origin check passes.
*/
static int is_route_matching_for_vrf(struct bgp *bgp_vrf,
struct bgp_path_info *pi)
@@ -3498,6 +3717,41 @@ static int is_route_matching_for_vni(struct bgp *bgp, struct bgpevpn *vpn,
return 0;
}
+static bool bgp_evpn_route_matches_macvrf_soo(struct bgp_path_info *pi,
+ const struct prefix_evpn *evp)
+{
+ struct bgp *bgp_evpn = bgp_get_evpn();
+ struct ecommunity *macvrf_soo;
+ bool ret = false;
+
+ if (!bgp_evpn || !bgp_evpn->evpn_info)
+ return false;
+
+ /* We only stamp the mac-vrf soo on routes from our local L2VNI.
+ * No need to filter additional EVPN routes that originated outside
+ * the MAC-VRF/L2VNI.
+ */
+ if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE &&
+ evp->prefix.route_type != BGP_EVPN_IMET_ROUTE)
+ return false;
+
+ macvrf_soo = bgp_evpn->evpn_info->soo;
+ ret = route_matches_soo(pi, macvrf_soo);
+
+ if (ret && bgp_debug_zebra(NULL)) {
+ char *ecom_str;
+
+ ecom_str = ecommunity_ecom2str(macvrf_soo,
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+ zlog_debug(
+ "import of evpn prefix %pFX skipped, local mac-vrf soo %s",
+ evp, ecom_str);
+ ecommunity_strfree(&ecom_str);
+ }
+
+ return ret;
+}
+
/* This API will scan evpn routes for checking attribute's rmac
* macthes with bgp instance router mac. It avoid installing
* route into bgp vrf table and remote rmac in bridge table.
@@ -3583,8 +3837,9 @@ int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf,
return 0;
/* don't import hosts that are locally attached */
- if (install && bgp_evpn_skip_vrf_import_of_local_es(
- bgp_vrf, evp, pi, install))
+ if (install && (bgp_evpn_skip_vrf_import_of_local_es(
+ bgp_vrf, evp, pi, install) ||
+ bgp_evpn_route_matches_macvrf_soo(pi, evp)))
return 0;
if (install)
@@ -3654,8 +3909,11 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
pi = pi->next) {
ret = bgp_evpn_route_entry_install_if_vrf_match(
bgp_vrf, pi, install);
- if (ret)
+ if (ret) {
+ bgp_dest_unlock_node(rd_dest);
+ bgp_dest_unlock_node(dest);
return ret;
+ }
}
}
}
@@ -3713,30 +3971,35 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp,
&& pi->sub_type == BGP_ROUTE_NORMAL))
continue;
- if (is_route_matching_for_vni(bgp, vpn, pi)) {
- if (install)
- ret = install_evpn_route_entry(
- bgp, vpn, evp, pi);
- else
- ret = uninstall_evpn_route_entry(
- bgp, vpn, evp, pi);
-
- if (ret) {
- flog_err(
- EC_BGP_EVPN_FAIL,
- "%u: Failed to %s EVPN %s route in VNI %u",
- bgp->vrf_id,
- install ? "install"
- : "uninstall",
- rtype == BGP_EVPN_MAC_IP_ROUTE
- ? "MACIP"
- : "IMET",
- vpn->vni);
-
- bgp_dest_unlock_node(rd_dest);
- bgp_dest_unlock_node(dest);
- return ret;
- }
+ if (!is_route_matching_for_vni(bgp, vpn, pi))
+ continue;
+
+ if (install) {
+ if (bgp_evpn_route_matches_macvrf_soo(
+ pi, evp))
+ continue;
+
+ ret = install_evpn_route_entry(bgp, vpn,
+ evp, pi);
+ } else
+ ret = uninstall_evpn_route_entry(
+ bgp, vpn, evp, pi);
+
+ if (ret) {
+ flog_err(
+ EC_BGP_EVPN_FAIL,
+ "%u: Failed to %s EVPN %s route in VNI %u",
+ bgp->vrf_id,
+ install ? "install"
+ : "uninstall",
+ rtype == BGP_EVPN_MAC_IP_ROUTE
+ ? "MACIP"
+ : "IMET",
+ vpn->vni);
+
+ bgp_dest_unlock_node(rd_dest);
+ bgp_dest_unlock_node(dest);
+ return ret;
}
}
}
@@ -3942,6 +4205,12 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
if (!ecom || !ecom->size)
return -1;
+ /* Filter routes carrying a Site-of-Origin that matches our
+ * local MAC-VRF SoO.
+ */
+ if (import && bgp_evpn_route_matches_macvrf_soo(pi, evp))
+ return 0;
+
/* An EVPN route belongs to a VNI or a VRF or an ESI based on the RTs
* attached to the route */
for (i = 0; i < ecom->size; i++) {
@@ -4057,7 +4326,7 @@ void bgp_evpn_import_type2_route(struct bgp_path_info *pi, int import)
return;
install_uninstall_evpn_route(bgp_evpn, AFI_L2VPN, SAFI_EVPN,
- &pi->net->p, pi, import);
+ &pi->net->rn->p, pi, import);
}
/*
@@ -5163,7 +5432,7 @@ void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni, struct list *rtl,
if (bgp->advertise_autort_rfc8365)
vni |= EVPN_AUTORT_VXLAN;
- encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
+ encode_route_target_as((bgp->as & 0xFFFF), vni, &eval, true);
ecom_auto = ecommunity_new();
ecommunity_add_val(ecom_auto, &eval, false, false);
@@ -5489,6 +5758,46 @@ void bgp_evpn_handle_rd_change(struct bgp *bgp, struct bgpevpn *vpn,
update_advertise_vni_routes(bgp, vpn);
}
+/* "mac-vrf soo" vty handler
+ * Handle change to the global MAC-VRF Site-of-Origin:
+ * - Unimport routes with new SoO from VNI/VRF
+ * - Import routes with old SoO into VNI/VRF
+ * - Update SoO on local VNI routes + re-advertise
+ */
+void bgp_evpn_handle_global_macvrf_soo_change(struct bgp *bgp,
+ struct ecommunity *new_soo)
+{
+ struct ecommunity *old_soo;
+
+ old_soo = bgp->evpn_info->soo;
+
+ /* cleanup and bail out if old_soo == new_soo */
+ if (ecommunity_match(old_soo, new_soo)) {
+ ecommunity_free(&new_soo);
+ return;
+ }
+
+ /* set new_soo */
+ bgp->evpn_info->soo = new_soo;
+
+ /* Unimport routes matching the new_soo */
+ bgp_filter_evpn_routes_upon_martian_change(bgp, BGP_MARTIAN_SOO);
+
+ /* Reimport routes with old_soo and !new_soo.
+ */
+ bgp_reimport_evpn_routes_upon_martian_change(
+ bgp, BGP_MARTIAN_SOO, (void *)old_soo, (void *)new_soo);
+
+ /* Update locally originated routes for all L2VNIs */
+ hash_iterate(bgp->vnihash,
+ (void (*)(struct hash_bucket *,
+ void *))update_routes_for_vni_hash,
+ bgp);
+
+ /* clear old_soo */
+ ecommunity_free(&old_soo);
+}
+
/*
* Install routes for this VNI. Invoked upon change to Import RT.
*/
@@ -5922,7 +6231,7 @@ void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn)
snprintfrr(buf, sizeof(buf), "%pI4:%hu", &bgp->router_id, vpn->rd_id);
(void)str2prefix_rd(buf, &vpn->prd);
if (vpn->prd_pretty)
- XFREE(MTYPE_BGP, vpn->prd_pretty);
+ XFREE(MTYPE_BGP_NAME, vpn->prd_pretty);
UNSET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD);
}
@@ -6016,6 +6325,17 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
*/
void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
{
+ struct bgp_dest *dest = NULL;
+
+ while (zebra_announce_count(&bm->zebra_announce_head)) {
+ dest = zebra_announce_pop(&bm->zebra_announce_head);
+ if (dest->za_vpn == vpn) {
+ bgp_path_info_unlock(dest->za_bgp_pi);
+ bgp_dest_unlock_node(dest);
+ } else
+ zebra_announce_add_tail(&bm->zebra_announce_head, dest);
+ }
+
bgp_evpn_remote_ip_hash_destroy(vpn);
bgp_evpn_vni_es_cleanup(vpn);
bgpevpn_unlink_from_l3vni(vpn);
@@ -6028,7 +6348,7 @@ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
hash_release(bgp->vni_svi_hash, vpn);
hash_release(bgp->vnihash, vpn);
if (vpn->prd_pretty)
- XFREE(MTYPE_BGP, vpn->prd_pretty);
+ XFREE(MTYPE_BGP_NAME, vpn->prd_pretty);
QOBJ_UNREG(vpn);
XFREE(MTYPE_BGP_EVPN, vpn);
}
@@ -6056,8 +6376,12 @@ int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi,
return install_uninstall_evpn_route(bgp, afi, safi, p, pi, 0);
}
-/* filter routes which have martian next hops */
-int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp)
+/* Refresh previously-discarded EVPN routes carrying "self" MAC-VRF SoO.
+ * Walk global EVPN rib + import remote routes with old_soo && !new_soo.
+ */
+void bgp_reimport_evpn_routes_upon_macvrf_soo_change(struct bgp *bgp,
+ struct ecommunity *old_soo,
+ struct ecommunity *new_soo)
{
afi_t afi;
safi_t safi;
@@ -6068,12 +6392,9 @@ int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp)
afi = AFI_L2VPN;
safi = SAFI_EVPN;
- /* Walk entire global routing table and evaluate routes which could be
- * imported into this VPN. Note that we cannot just look at the routes
- * for the VNI's RD -
- * remote routes applicable for this VNI could have any RD.
+ /* EVPN routes are a 2-level table: outer=prefix_rd, inner=prefix_evpn.
+ * A remote route could have any RD, so we need to walk them all.
*/
- /* EVPN routes are a 2-level table. */
for (rd_dest = bgp_table_top(bgp->rib[afi][safi]); rd_dest;
rd_dest = bgp_route_next(rd_dest)) {
table = bgp_dest_get_bgp_table_info(rd_dest);
@@ -6082,21 +6403,132 @@ int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp)
for (dest = bgp_table_top(table); dest;
dest = bgp_route_next(dest)) {
+ const struct prefix *p;
+ struct prefix_evpn *evp;
+
+ p = bgp_dest_get_prefix(dest);
+ evp = (struct prefix_evpn *)p;
+
+ /* On export we only add MAC-VRF SoO to RT-2/3, so we
+ * can skip evaluation of other RTs.
+ */
+ if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE &&
+ evp->prefix.route_type != BGP_EVPN_IMET_ROUTE)
+ continue;
for (pi = bgp_dest_get_bgp_path_info(dest); pi;
pi = pi->next) {
+ bool old_soo_fnd = false;
+ bool new_soo_fnd = false;
- /* Consider "valid" remote routes applicable for
- * this VNI. */
+ /* Only consider routes learned from peers */
+ if (!(pi->type == ZEBRA_ROUTE_BGP &&
+ pi->sub_type == BGP_ROUTE_NORMAL))
+ continue;
+
+ if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID))
+ continue;
+
+ old_soo_fnd = route_matches_soo(pi, old_soo);
+ new_soo_fnd = route_matches_soo(pi, new_soo);
+
+ if (old_soo_fnd && !new_soo_fnd) {
+ if (bgp_debug_update(pi->peer, p, NULL,
+ 1)) {
+ char attr_str[BUFSIZ] = {0};
+
+ bgp_dump_attr(pi->attr,
+ attr_str, BUFSIZ);
+
+ zlog_debug(
+ "mac-vrf soo changed: evaluating reimport of prefix %pBD with attr %s",
+ dest, attr_str);
+ }
+
+ bgp_evpn_import_route(bgp, afi, safi, p,
+ pi);
+ }
+ }
+ }
+ }
+}
+
+/* Filter learned (!local) EVPN routes carrying "self" attributes.
+ * Walk the Global EVPN loc-rib unimporting martian routes from the appropriate
+ * L2VNIs (MAC-VRFs) / L3VNIs (IP-VRFs), and deleting them from the Global
+ * loc-rib when applicable (based on martian_type).
+ * This function is the handler for new martian entries, which is triggered by
+ * events occurring on the local system,
+ * e.g.
+ * - New VTEP-IP
+ * + bgp_zebra_process_local_vni
+ * + bgp_zebra_process_local_l3vni
+ * - New MAC-VRF Site-of-Origin
+ * + bgp_evpn_handle_global_macvrf_soo_change
+ * This will likely be extended in the future to cover these events too:
+ * - New Interface IP
+ * + bgp_interface_address_add
+ * - New Interface MAC
+ * + bgp_ifp_up
+ * + bgp_ifp_create
+ * - New RMAC
+ * + bgp_zebra_process_local_l3vni
+ */
+void bgp_filter_evpn_routes_upon_martian_change(
+ struct bgp *bgp, enum bgp_martian_type martian_type)
+{
+ afi_t afi;
+ safi_t safi;
+ struct bgp_dest *rd_dest, *dest;
+ struct bgp_table *table;
+ struct bgp_path_info *pi;
+ struct ecommunity *macvrf_soo;
+
+ afi = AFI_L2VPN;
+ safi = SAFI_EVPN;
+ macvrf_soo = bgp->evpn_info->soo;
+
+ /* EVPN routes are a 2-level table: outer=prefix_rd, inner=prefix_evpn.
+ * A remote route could have any RD, so we need to walk them all.
+ */
+ for (rd_dest = bgp_table_top(bgp->rib[afi][safi]); rd_dest;
+ rd_dest = bgp_route_next(rd_dest)) {
+ table = bgp_dest_get_bgp_table_info(rd_dest);
+ if (!table)
+ continue;
+
+ for (dest = bgp_table_top(table); dest;
+ dest = bgp_route_next(dest)) {
+
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi;
+ pi = pi->next) {
+ bool affected = false;
+ const struct prefix *p;
+
+ /* Only consider routes learned from peers */
if (!(pi->type == ZEBRA_ROUTE_BGP
&& pi->sub_type == BGP_ROUTE_NORMAL))
continue;
- if (bgp_nexthop_self(bgp, afi, pi->type,
- pi->sub_type, pi->attr,
- dest)) {
- const struct prefix *p =
- bgp_dest_get_prefix(dest);
+ p = bgp_dest_get_prefix(dest);
+
+ switch (martian_type) {
+ case BGP_MARTIAN_TUN_IP:
+ affected = bgp_nexthop_self(
+ bgp, afi, pi->type,
+ pi->sub_type, pi->attr, dest);
+ break;
+ case BGP_MARTIAN_SOO:
+ affected = route_matches_soo(
+ pi, macvrf_soo);
+ break;
+ case BGP_MARTIAN_IF_IP:
+ case BGP_MARTIAN_IF_MAC:
+ case BGP_MARTIAN_RMAC:
+ break;
+ }
+
+ if (affected) {
if (bgp_debug_update(pi->peer, p, NULL,
1)) {
char attr_str[BUFSIZ] = {0};
@@ -6106,21 +6538,116 @@ int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp)
sizeof(attr_str));
zlog_debug(
- "%u: prefix %pBD with attr %s - DENIED due to martian or self nexthop",
+ "%u: prefix %pBD with attr %s - DISCARDED due to Martian/%s",
bgp->vrf_id, dest,
- attr_str);
+ attr_str,
+ bgp_martian_type2str(
+ martian_type));
}
+
+
bgp_evpn_unimport_route(bgp, afi, safi,
p, pi);
- bgp_rib_remove(dest, pi, pi->peer, afi,
- safi);
+ /* For now, retain existing handling of
+ * tip_hash updates: (Self SoO routes
+ * are unimported from L2VNI/VRF but
+ * retained in global loc-rib, but Self
+ * IP/MAC routes are also deleted from
+ * global loc-rib).
+ * TODO: use consistent handling for all
+ * martian types
+ */
+ if (martian_type == BGP_MARTIAN_TUN_IP)
+ bgp_rib_remove(dest, pi,
+ pi->peer, afi,
+ safi);
}
}
}
}
+}
- return 0;
+/* Refresh previously-discarded EVPN routes carrying "self" attributes.
+ * This function is the handler for deleted martian entries, which is triggered
+ * by events occurring on the local system,
+ * e.g.
+ * - Del MAC-VRF Site-of-Origin
+ * + bgp_evpn_handle_global_macvrf_soo_change
+ * This will likely be extended in the future to cover these events too:
+ * - Del VTEP-IP
+ * + bgp_zebra_process_local_vni
+ * + bgp_zebra_process_local_l3vni
+ * - Del Interface IP
+ * + bgp_interface_address_delete
+ * - Del Interface MAC
+ * + bgp_ifp_down
+ * + bgp_ifp_destroy
+ * - Del RMAC
+ * + bgp_zebra_process_local_l3vni
+ */
+void bgp_reimport_evpn_routes_upon_martian_change(
+ struct bgp *bgp, enum bgp_martian_type martian_type, void *old_martian,
+ void *new_martian)
+{
+ struct listnode *node;
+ struct peer *peer;
+ safi_t safi;
+ afi_t afi;
+ struct ecommunity *old_soo, *new_soo;
+
+ afi = AFI_L2VPN;
+ safi = SAFI_EVPN;
+
+ /* Self-SoO routes are held in the global EVPN loc-rib, so we can
+ * reimport routes w/o triggering soft-reconfig/route-refresh.
+ */
+ if (martian_type == BGP_MARTIAN_SOO) {
+ old_soo = (struct ecommunity *)old_martian;
+ new_soo = (struct ecommunity *)new_martian;
+
+ /* If !old_soo, then we can skip the reimport because we
+ * wouldn't have filtered anything via the self-SoO import check
+ */
+ if (old_martian)
+ bgp_reimport_evpn_routes_upon_macvrf_soo_change(
+ bgp, old_soo, new_soo);
+
+ return;
+ }
+
+ /* Self-TIP/IP/MAC/RMAC routes are deleted from the global EVPN
+ * loc-rib, so we need to re-learn the routes via soft-reconfig/
+ * route-refresh.
+ */
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
+
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ continue;
+
+ if (peer->connection->status != Established)
+ continue;
+
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG)) {
+ if (bgp_debug_update(peer, NULL, NULL, 1))
+ zlog_debug(
+ "Processing EVPN Martian/%s change on peer %s (inbound, soft-reconfig)",
+ bgp_martian_type2str(martian_type),
+ peer->host);
+
+ bgp_soft_reconfig_in(peer, afi, safi);
+ } else {
+ if (bgp_debug_update(peer, NULL, NULL, 1))
+ zlog_debug(
+ "Processing EVPN Martian/%s change on peer %s",
+ bgp_martian_type2str(martian_type),
+ peer->host);
+ bgp_route_refresh_send(peer, afi, safi, 0,
+ REFRESH_IMMEDIATE, 0,
+ BGP_ROUTE_REFRESH_NORMAL);
+ }
+ }
}
/*
@@ -6269,10 +6796,14 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id,
/* associate the vrf with l3vni and related parameters */
bgp_vrf->l3vni = l3vni;
- bgp_vrf->originator_ip = originator_ip;
bgp_vrf->l3vni_svi_ifindex = svi_ifindex;
bgp_vrf->evpn_info->is_anycast_mac = is_anycast_mac;
+ /* Update tip_hash of the EVPN underlay BGP instance (bgp_evpn)
+ * if the VTEP-IP (originator_ip) has changed
+ */
+ handle_tunnel_ip_change(bgp_vrf, bgp_evpn, vpn, originator_ip);
+
/* copy anycast MAC from VRR MAC */
memcpy(&bgp_vrf->rmac, vrr_rmac, ETH_ALEN);
/* copy sys RMAC from SVI MAC */
@@ -6397,6 +6928,11 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id)
/* delete/withdraw all type-5 routes */
delete_withdraw_vrf_routes(bgp_vrf);
+ /* Tunnel is no longer active.
+ * Delete VTEP-IP from EVPN underlay's tip_hash.
+ */
+ bgp_tip_del(bgp_evpn, &bgp_vrf->originator_ip);
+
/* remove the l3vni from vrf instance */
bgp_vrf->l3vni = 0;
@@ -6461,8 +6997,8 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni)
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
+ /* Tunnel is no longer active.
+ * Delete VTEP-IP from EVPN underlay's tip_hash.
*/
bgp_tip_del(bgp, &vpn->originator_ip);
@@ -6486,6 +7022,7 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
{
struct bgpevpn *vpn;
struct prefix_evpn p;
+ struct bgp *bgp_evpn = bgp_get_evpn();
/* Lookup VNI. If present and no change, exit. */
vpn = bgp_evpn_lookup_vni(bgp, vni);
@@ -6558,7 +7095,7 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
/* If tunnel endpoint IP has changed, update (and delete prior
* type-3 route, if needed.)
*/
- handle_tunnel_ip_change(bgp, vpn, originator_ip);
+ handle_tunnel_ip_change(NULL, bgp, vpn, originator_ip);
/* Update all routes with new endpoint IP and/or export RT
* for VRFs
@@ -6578,14 +7115,17 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
/* Mark as "live" */
SET_FLAG(vpn->flags, VNI_FLAG_LIVE);
- /* tunnel is now active, add tunnel-ip to db */
+ /* Tunnel is newly active.
+ * Add TIP to tip_hash of the EVPN underlay instance (bgp_get_evpn()).
+ */
if (bgp_tip_add(bgp, &originator_ip))
/* The originator_ip was not already present in the
* bgp martian next-hop table as a tunnel-ip, so we
* need to go back and filter routes matching the new
* martian next-hop.
*/
- bgp_filter_evpn_routes_upon_martian_nh_change(bgp);
+ bgp_filter_evpn_routes_upon_martian_change(bgp_evpn,
+ BGP_MARTIAN_TUN_IP);
/*
* Create EVPN type-3 route and schedule for processing.
@@ -6679,8 +7219,13 @@ void bgp_evpn_cleanup(struct bgp *bgp)
list_delete(&bgp->vrf_export_rtl);
list_delete(&bgp->l2vnis);
+ if (bgp->evpn_info) {
+ ecommunity_free(&bgp->evpn_info->soo);
+ XFREE(MTYPE_BGP_EVPN_INFO, bgp->evpn_info);
+ }
+
if (bgp->vrf_prd_pretty)
- XFREE(MTYPE_BGP, bgp->vrf_prd_pretty);
+ XFREE(MTYPE_BGP_NAME, bgp->vrf_prd_pretty);
}
/*
@@ -6712,6 +7257,8 @@ void bgp_evpn_init(struct bgp *bgp)
bgp->vrf_export_rtl->del = evpn_vrf_rt_del;
bgp->l2vnis = list_new();
bgp->l2vnis->cmp = vni_list_cmp;
+ bgp->evpn_info =
+ XCALLOC(MTYPE_BGP_EVPN_INFO, sizeof(struct bgp_evpn_info));
/* By default Duplicate Address Dection is enabled.
* Max-moves (N) 5, detection time (M) 180
* default action is warning-only
@@ -6875,7 +7422,7 @@ static void bgp_evpn_remote_ip_hash_add(struct bgpevpn *vpn,
|| !CHECK_FLAG(pi->flags, BGP_PATH_VALID))
return;
- evp = (struct prefix_evpn *)&pi->net->p;
+ evp = (struct prefix_evpn *)&pi->net->rn->p;
if (evp->family != AF_EVPN
|| evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE
@@ -6908,7 +7455,7 @@ static void bgp_evpn_remote_ip_hash_del(struct bgpevpn *vpn,
if (!evpn_resolve_overlay_index())
return;
- evp = (struct prefix_evpn *)&pi->net->p;
+ evp = (struct prefix_evpn *)&pi->net->rn->p;
if (evp->family != AF_EVPN
|| evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE
@@ -6953,7 +7500,7 @@ static void show_remote_ip_entry(struct hash_bucket *bucket, void *args)
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))
- vty_out(vty, " %pFX\n", &pi->net->p);
+ vty_out(vty, " %pFX\n", &pi->net->rn->p);
}
void bgp_evpn_show_remote_ip_hash(struct hash_bucket *bucket, void *args)
@@ -7248,3 +7795,64 @@ bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf,
return false;
}
+
+/* Upon aggregate set trigger unimport suppressed routes
+ * from EVPN
+ */
+void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi, safi_t safi)
+{
+ struct bgp_dest *agg_dest, *dest, *top;
+ const struct prefix *aggr_p;
+ struct bgp_aggregate *bgp_aggregate;
+ struct bgp_table *table;
+ struct bgp_path_info *pi;
+
+ if (!bgp_get_evpn() && !advertise_type5_routes(bgp, afi))
+ return;
+
+ /* Aggregate-address table walk. */
+ table = bgp->rib[afi][safi];
+ for (agg_dest = bgp_table_top(bgp->aggregate[afi][safi]); agg_dest;
+ agg_dest = bgp_route_next(agg_dest)) {
+ bgp_aggregate = bgp_dest_get_bgp_aggregate_info(agg_dest);
+
+ if (bgp_aggregate == NULL)
+ continue;
+
+ aggr_p = bgp_dest_get_prefix(agg_dest);
+
+ /* Look all nodes below the aggregate prefix in
+ * global AFI/SAFI table (IPv4/IPv6).
+ * Trigger withdrawal (this will be Type-5 routes only)
+ * from EVPN Global table.
+ */
+ top = bgp_node_get(table, aggr_p);
+ for (dest = bgp_node_get(table, aggr_p); dest;
+ dest = bgp_route_next_until(dest, top)) {
+ const struct prefix *dest_p = bgp_dest_get_prefix(dest);
+
+ if (dest_p->prefixlen <= aggr_p->prefixlen)
+ continue;
+
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi;
+ pi = pi->next) {
+ if (pi->sub_type == BGP_ROUTE_AGGREGATE)
+ continue;
+
+ /* Only Suppressed route remove from EVPN */
+ if (!bgp_path_suppressed(pi))
+ continue;
+
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s aggregated %pFX remove suppressed route %pFX",
+ __func__, aggr_p, dest_p);
+
+ if (!is_route_injectable_into_evpn_non_supp(pi))
+ continue;
+
+ bgp_evpn_withdraw_type5_route(bgp, dest_p, afi,
+ safi);
+ }
+ }
+ }
+}