summaryrefslogtreecommitdiff
path: root/zebra/zebra_vxlan.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_vxlan.c')
-rw-r--r--zebra/zebra_vxlan.c2955
1 files changed, 2323 insertions, 632 deletions
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 66441e1756..ff09b48dcf 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -50,6 +50,7 @@
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_vxlan_private.h"
+#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_router.h"
DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix");
@@ -74,7 +75,6 @@ static const struct message zvtep_flood_str[] = {
{0}
};
-
/* static function declarations */
static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p,
uint16_t cmd);
@@ -95,22 +95,26 @@ static void zvni_print_hash(struct hash_bucket *bucket, void *ctxt[]);
static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
struct ipaddr *ip, uint8_t flags,
- uint32_t seq, int state, uint16_t cmd);
+ uint32_t seq, int state,
+ struct zebra_evpn_es *es,
+ uint16_t cmd);
static unsigned int neigh_hash_keymake(const void *p);
static void *zvni_neigh_alloc(void *p);
static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
- struct ethaddr *mac);
+ struct ethaddr *mac, zebra_mac_t *zmac,
+ uint32_t n_flags);
static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n);
static void zvni_neigh_del_all(zebra_vni_t *zvni, int uninstall, int upd_client,
uint32_t flags);
static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip);
static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
- struct ethaddr *macaddr,
- uint8_t flags, uint32_t seq);
+ struct ethaddr *mac, zebra_mac_t *zmac,
+ uint32_t flags, uint32_t seq);
static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
- struct ethaddr *macaddr,
- uint8_t flags, int state);
-static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n);
+ struct ethaddr *mac,
+ uint32_t flags, int state, bool force);
+static int zvni_rem_neigh_install(zebra_vni_t *zvni,
+ zebra_neigh_t *n, bool was_static);
static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n);
static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n);
static zebra_vni_t *zvni_from_svi(struct interface *ifp,
@@ -142,7 +146,6 @@ static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
/* l3-vni related APIs*/
-static zebra_l3vni_t *zl3vni_lookup(vni_t vni);
static void *zl3vni_alloc(void *p);
static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id);
static int zl3vni_del(zebra_l3vni_t *zl3vni);
@@ -158,21 +161,22 @@ static void zvni_mac_del_all(zebra_vni_t *zvni, int uninstall, int upd_client,
uint32_t flags);
static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *macaddr);
static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr,
- uint8_t flags, uint32_t seq);
-static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr);
+ uint32_t flags, uint32_t seq, struct zebra_evpn_es *es);
+static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr,
+ uint32_t flags, bool force);
static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
struct interface *br_if, vlanid_t vid);
-static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac);
-static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac);
+static int zvni_rem_mac_install(zebra_vni_t *zvni,
+ zebra_mac_t *mac, bool was_static);
+static int zvni_rem_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac);
static void zvni_install_mac_hash(struct hash_bucket *bucket, void *ctxt);
static unsigned int vni_hash_keymake(const void *p);
static void *zvni_alloc(void *p);
-static zebra_vni_t *zvni_lookup(vni_t vni);
static zebra_vni_t *zvni_add(vni_t vni);
static int zvni_del(zebra_vni_t *zvni);
static int zvni_send_add_to_client(zebra_vni_t *zvni);
-static int zvni_send_del_to_client(vni_t vni);
+static int zvni_send_del_to_client(zebra_vni_t *zvni);
static void zvni_build_hash_table(void);
static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep);
static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip);
@@ -225,6 +229,22 @@ static void zebra_vxlan_sg_cleanup(struct hash_bucket *bucket, void *arg);
static void zvni_send_mac_to_client(zebra_vni_t *zvn);
static void zvni_send_neigh_to_client(zebra_vni_t *zvni);
+static void zebra_vxlan_rem_mac_del(zebra_vni_t *zvni,
+ zebra_mac_t *zmac);
+static inline void zebra_vxlan_mac_stop_hold_timer(zebra_mac_t *mac);
+static inline bool zebra_vxlan_mac_is_static(zebra_mac_t *mac);
+static void zebra_vxlan_local_neigh_ref_mac(zebra_neigh_t *n,
+ struct ethaddr *macaddr, zebra_mac_t *mac,
+ bool send_mac_update);
+static void zebra_vxlan_local_neigh_deref_mac(zebra_neigh_t *n,
+ bool send_mac_update);
+static inline bool zebra_vxlan_neigh_is_ready_for_bgp(zebra_neigh_t *n);
+static inline bool zebra_vxlan_neigh_clear_sync_info(zebra_neigh_t *n);
+static void zebra_vxlan_sync_neigh_dp_install(zebra_neigh_t *n,
+ bool set_inactive, bool force_clear_static, const char *caller);
+static inline bool zebra_vxlan_neigh_is_static(zebra_neigh_t *neigh);
+static void zebra_vxlan_neigh_send_add_del_to_client(zebra_neigh_t *n,
+ bool old_bgp_ready, bool new_bgp_ready);
/* Private functions */
static int host_rb_entry_compare(const struct host_rb_entry *hle1,
@@ -731,6 +751,7 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
struct zebra_vrf *zvrf = NULL;
struct timeval detect_start_time = {0, 0};
char timebuf[MONOTIME_STRLEN];
+ char thread_buf[THREAD_TIMER_STRLEN];
zvrf = zebra_vrf_get_evpn();
if (!zvrf)
@@ -743,25 +764,75 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive";
vty = (struct vty *)ctxt;
if (json == NULL) {
+ bool sync_info = false;
+
vty_out(vty, "IP: %s\n",
- ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)));
vty_out(vty, " Type: %s\n", type_str);
vty_out(vty, " State: %s\n", state_str);
vty_out(vty, " MAC: %s\n",
- prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
+ prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
+ vty_out(vty, " Sync-info:");
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE)) {
+ vty_out(vty, " local-inactive");
+ sync_info = true;
+ }
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY)) {
+ vty_out(vty, " peer-proxy");
+ sync_info = true;
+ }
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE)) {
+ vty_out(vty, " peer-active");
+ sync_info = true;
+ }
+ if (n->hold_timer) {
+ vty_out(vty, " (ht: %s)",
+ thread_timer_to_hhmmss(
+ thread_buf,
+ sizeof(thread_buf),
+ n->hold_timer));
+ sync_info = true;
+ }
+ if (!sync_info)
+ vty_out(vty, " -");
+ vty_out(vty, "\n");
} else {
json_object_string_add(json, "ip", buf2);
json_object_string_add(json, "type", type_str);
json_object_string_add(json, "state", state_str);
json_object_string_add(json, "mac", buf1);
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE))
+ json_object_boolean_true_add(json,
+ "localInactive");
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY))
+ json_object_boolean_true_add(json,
+ "peerProxy");
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
+ json_object_boolean_true_add(json,
+ "peerActive");
+ if (n->hold_timer)
+ json_object_string_add(json, "peerActiveHold",
+ thread_timer_to_hhmmss(
+ thread_buf,
+ sizeof(thread_buf),
+ n->hold_timer));
}
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
- if (json == NULL) {
- vty_out(vty, " Remote VTEP: %s\n",
- inet_ntoa(n->r_vtep_ip));
- } else
- json_object_string_add(json, "remoteVtep",
- inet_ntoa(n->r_vtep_ip));
+ if (n->mac->es) {
+ if (json)
+ json_object_string_add(json, "remoteEs",
+ n->mac->es->esi_str);
+ else
+ vty_out(vty, " Remote ES: %s\n",
+ n->mac->es->esi_str);
+ } else {
+ if (json)
+ json_object_string_add(json, "remoteVtep",
+ inet_ntoa(n->r_vtep_ip));
+ else
+ vty_out(vty, " Remote VTEP: %s\n",
+ inet_ntoa(n->r_vtep_ip));
+ }
}
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) {
if (!json) {
@@ -812,6 +883,30 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
}
}
+static void zvni_print_neigh_hdr(struct vty *vty,
+ struct neigh_walk_ctx *wctx)
+{
+ vty_out(vty,
+ "Flags: I=local-inactive, P=peer-active, X=peer-proxy\n");
+ vty_out(vty, "%*s %-6s %-5s %-8s %-17s %-30s %s\n",
+ -wctx->addr_width, "Neighbor", "Type", "Flags",
+ "State", "MAC", "Remote ES/VTEP", "Seq #'s");
+}
+
+static char *zvni_print_neigh_flags(zebra_neigh_t *n, char *flags_buf,
+ uint32_t flags_buf_sz)
+{
+ snprintf(flags_buf, flags_buf_sz, "%s%s%s",
+ (n->flags & ZEBRA_NEIGH_ES_PEER_ACTIVE) ?
+ "P" : "",
+ (n->flags & ZEBRA_NEIGH_ES_PEER_PROXY) ?
+ "X" : "",
+ (n->flags & ZEBRA_NEIGH_LOCAL_INACTIVE) ?
+ "I" : "");
+
+ return flags_buf;
+}
+
/*
* Print neighbor hash entry - called for display of all neighbors.
*/
@@ -824,6 +919,7 @@ static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt)
char buf2[INET6_ADDRSTRLEN];
struct neigh_walk_ctx *wctx = ctxt;
const char *state_str;
+ char flags_buf[6];
vty = wctx->vty;
json_vni = wctx->json;
@@ -840,9 +936,11 @@ static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt)
return;
if (json_vni == NULL) {
- vty_out(vty, "%*s %-6s %-8s %-17s %u/%u\n",
+ vty_out(vty, "%*s %-6s %-5s %-8s %-17s %-30s %u/%u\n",
-wctx->addr_width, buf2, "local",
- state_str, buf1, n->loc_seq, n->rem_seq);
+ zvni_print_neigh_flags(n, flags_buf,
+ sizeof(flags_buf)), state_str,
+ buf1, "", n->loc_seq, n->rem_seq);
} else {
json_object_string_add(json_row, "type", "local");
json_object_string_add(json_row, "state", state_str);
@@ -872,19 +970,25 @@ static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt)
if (json_vni == NULL) {
if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) &&
(wctx->count == 0))
- vty_out(vty, "%*s %-6s %-8s %-17s %-21s %s\n",
- -wctx->addr_width, "Neighbor", "Type",
- "State", "MAC", "Remote VTEP",
- "Seq #'s");
- vty_out(vty, "%*s %-6s %-8s %-17s %-21s %u/%u\n",
- -wctx->addr_width, buf2, "remote", state_str,
- buf1, inet_ntoa(n->r_vtep_ip), n->loc_seq, n->rem_seq);
+ zvni_print_neigh_hdr(vty, wctx);
+ vty_out(vty, "%*s %-6s %-5s %-8s %-17s %-30s %u/%u\n",
+ -wctx->addr_width, buf2, "remote",
+ zvni_print_neigh_flags(n, flags_buf,
+ sizeof(flags_buf)),
+ state_str, buf1,
+ n->mac->es ? n->mac->es->esi_str :
+ inet_ntoa(n->r_vtep_ip),
+ n->loc_seq, n->rem_seq);
} else {
json_object_string_add(json_row, "type", "remote");
json_object_string_add(json_row, "state", state_str);
json_object_string_add(json_row, "mac", buf1);
- json_object_string_add(json_row, "remoteVtep",
- inet_ntoa(n->r_vtep_ip));
+ if (n->mac->es)
+ json_object_string_add(json_row, "remoteEs",
+ n->mac->es->esi_str);
+ else
+ json_object_string_add(json_row, "remoteVtep",
+ inet_ntoa(n->r_vtep_ip));
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW))
json_object_boolean_true_add(json_row,
"defaultGateway");
@@ -987,11 +1091,9 @@ static void zvni_print_neigh_hash_all_vni(struct hash_bucket *bucket,
wctx.json = json_vni;
hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
- if (json == NULL) {
- vty_out(vty, "%*s %-6s %-8s %-17s %-21s %s\n",
- -wctx.addr_width, "IP", "Type",
- "State", "MAC", "Remote VTEP", "Seq #'s");
- }
+ if (json == NULL)
+ zvni_print_neigh_hdr(vty, &wctx);
+
if (print_dup)
hash_iterate(zvni->neigh_table, zvni_print_dad_neigh_hash,
&wctx);
@@ -1164,6 +1266,35 @@ static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty,
}
}
+static void
+zebra_vxlan_mac_get_access_info(zebra_mac_t *mac,
+ struct interface **ifpP, vlanid_t *vid)
+{
+ /* if the mac is associated with an ES we must get the access
+ * info from the ES
+ */
+ if (mac->es) {
+ struct zebra_if *zif;
+
+ /* get the access port from the es */
+ *ifpP = mac->es->zif ? mac->es->zif->ifp : NULL;
+ /* get the vlan from the VNI */
+ if (mac->zvni->vxlan_if) {
+ zif = mac->zvni->vxlan_if->info;
+ *vid = zif->l2info.vxl.access_vlan;
+ } else {
+ *vid = 0;
+ }
+ } else {
+ struct zebra_ns *zns;
+
+ *vid = mac->fwd_info.local.vid;
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ *ifpP = if_lookup_by_index_per_ns(zns,
+ mac->fwd_info.local.ifindex);
+ }
+}
+
/*
* Print a specific MAC entry.
*/
@@ -1177,6 +1308,7 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
struct zebra_vrf *zvrf;
struct timeval detect_start_time = {0, 0};
char timebuf[MONOTIME_STRLEN];
+ char thread_buf[THREAD_TIMER_STRLEN];
zvrf = zebra_vrf_get_evpn();
if (!zvrf)
@@ -1189,21 +1321,21 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
json_object *json_mac = json_object_new_object();
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- struct zebra_ns *zns;
struct interface *ifp;
- ifindex_t ifindex;
+ vlanid_t vid;
- ifindex = mac->fwd_info.local.ifindex;
- zns = zebra_ns_lookup(mac->fwd_info.local.ns_id);
- ifp = if_lookup_by_index_per_ns(zns, ifindex);
- if (!ifp)
- return;
+ zebra_vxlan_mac_get_access_info(mac,
+ &ifp, &vid);
json_object_string_add(json_mac, "type", "local");
- json_object_string_add(json_mac, "intf", ifp->name);
- json_object_int_add(json_mac, "ifindex", ifindex);
- if (mac->fwd_info.local.vid)
+ if (ifp) {
+ json_object_string_add(json_mac,
+ "intf", ifp->name);
+ json_object_int_add(json_mac,
+ "ifindex", ifp->ifindex);
+ }
+ if (vid)
json_object_int_add(json_mac, "vlan",
- mac->fwd_info.local.vid);
+ vid);
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
json_object_string_add(json_mac, "type", "remote");
json_object_string_add(
@@ -1232,6 +1364,25 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
else
json_object_boolean_false_add(json_mac, "isDuplicate");
+ json_object_int_add(json_mac, "syncNeighCount", mac->sync_neigh_cnt);
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE))
+ json_object_boolean_true_add(json_mac,
+ "localInactive");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY))
+ json_object_boolean_true_add(json_mac,
+ "peerProxy");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
+ json_object_boolean_true_add(json_mac,
+ "peerActive");
+ if (mac->hold_timer)
+ json_object_string_add(json_mac, "peerActiveHold",
+ thread_timer_to_hhmmss(
+ thread_buf,
+ sizeof(thread_buf),
+ mac->hold_timer));
+ if (mac->es)
+ json_object_string_add(json_mac, "esi",
+ mac->es->esi_str);
/* print all the associated neigh */
if (!listcount(mac->neigh_list))
json_object_string_add(json_mac, "neighbors", "none");
@@ -1271,22 +1422,28 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
vty_out(vty, "MAC: %s\n", buf1);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- struct zebra_ns *zns;
struct interface *ifp;
- ifindex_t ifindex;
+ vlanid_t vid;
- ifindex = mac->fwd_info.local.ifindex;
- zns = zebra_ns_lookup(mac->fwd_info.local.ns_id);
- ifp = if_lookup_by_index_per_ns(zns, ifindex);
- if (!ifp)
- return;
- vty_out(vty, " Intf: %s(%u)", ifp->name, ifindex);
- if (mac->fwd_info.local.vid)
- vty_out(vty, " VLAN: %u",
- mac->fwd_info.local.vid);
+ zebra_vxlan_mac_get_access_info(mac,
+ &ifp, &vid);
+
+ if (mac->es)
+ vty_out(vty, " ESI: %s\n", mac->es->esi_str);
+
+ if (ifp)
+ vty_out(vty, " Intf: %s(%u)",
+ ifp->name, ifp->ifindex);
+ else
+ vty_out(vty, " Intf: -");
+ vty_out(vty, " VLAN: %u", vid);
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- vty_out(vty, " Remote VTEP: %s",
- inet_ntoa(mac->fwd_info.r_vtep_ip));
+ if (mac->es)
+ vty_out(vty, " Remote ES: %s",
+ mac->es->esi_str);
+ else
+ vty_out(vty, " Remote VTEP: %s",
+ inet_ntoa(mac->fwd_info.r_vtep_ip));
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
vty_out(vty, " Auto Mac ");
}
@@ -1301,8 +1458,22 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
vty_out(vty, " Remote-gateway Mac ");
vty_out(vty, "\n");
- vty_out(vty, " Local Seq: %u Remote Seq: %u", mac->loc_seq,
- mac->rem_seq);
+ vty_out(vty, " Sync-info: neigh#: %u", mac->sync_neigh_cnt);
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE))
+ vty_out(vty, " local-inactive");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY))
+ vty_out(vty, " peer-proxy");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
+ vty_out(vty, " peer-active");
+ if (mac->hold_timer)
+ vty_out(vty, " (ht: %s)",
+ thread_timer_to_hhmmss(
+ thread_buf,
+ sizeof(thread_buf),
+ mac->hold_timer));
+ vty_out(vty, "\n");
+ vty_out(vty, " Local Seq: %u Remote Seq: %u",
+ mac->loc_seq, mac->rem_seq);
vty_out(vty, "\n");
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
@@ -1339,6 +1510,22 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
}
}
+static char *zvni_print_mac_flags(zebra_mac_t *mac, char *flags_buf,
+ uint32_t flags_buf_sz)
+{
+ snprintf(flags_buf, flags_buf_sz, "%s%s%s%s",
+ mac->sync_neigh_cnt ?
+ "N" : "",
+ (mac->flags & ZEBRA_MAC_ES_PEER_ACTIVE) ?
+ "P" : "",
+ (mac->flags & ZEBRA_MAC_ES_PEER_PROXY) ?
+ "X" : "",
+ (mac->flags & ZEBRA_MAC_LOCAL_INACTIVE) ?
+ "I" : "");
+
+ return flags_buf;
+}
+
/*
* Print MAC hash entry - called for display of all MACs.
*/
@@ -1349,6 +1536,7 @@ static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
zebra_mac_t *mac;
char buf1[ETHER_ADDR_STRLEN];
struct mac_walk_ctx *wctx = ctxt;
+ char flags_buf[6];
vty = wctx->vty;
json_mac_hdr = wctx->json;
@@ -1360,26 +1548,24 @@ static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
json_mac = json_object_new_object();
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- struct zebra_ns *zns;
- ifindex_t ifindex;
struct interface *ifp;
vlanid_t vid;
if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
return;
- zns = zebra_ns_lookup(mac->fwd_info.local.ns_id);
- ifindex = mac->fwd_info.local.ifindex;
- ifp = if_lookup_by_index_per_ns(zns, ifindex);
- if (!ifp) // unexpected
- return;
- vid = mac->fwd_info.local.vid;
- if (json_mac_hdr == NULL)
- vty_out(vty, "%-17s %-6s %-21s", buf1, "local",
- ifp->name);
- else {
+ zebra_vxlan_mac_get_access_info(mac,
+ &ifp, &vid);
+ if (json_mac_hdr == NULL) {
+ vty_out(vty, "%-17s %-6s %-5s %-30s", buf1, "local",
+ zvni_print_mac_flags(mac, flags_buf,
+ sizeof(flags_buf)),
+ ifp ? ifp->name : "-");
+ } else {
json_object_string_add(json_mac, "type", "local");
- json_object_string_add(json_mac, "intf", ifp->name);
+ if (ifp)
+ json_object_string_add(json_mac,
+ "intf", ifp->name);
}
if (vid) {
if (json_mac_hdr == NULL)
@@ -1419,14 +1605,19 @@ static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
if (json_mac_hdr == NULL) {
if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) &&
- (wctx->count == 0)) {
+ (wctx->count == 0)) {
vty_out(vty, "\nVNI %u\n\n", wctx->zvni->vni);
- vty_out(vty, "%-17s %-6s %-21s %-5s %s\n",
- "MAC", "Type", "Intf/Remote VTEP",
+ vty_out(vty, "%-17s %-6s %-5s%-30s %-5s %s\n",
+ "MAC", "Type", "Flags",
+ "Intf/Remote ES/VTEP",
"VLAN", "Seq #'s");
}
- vty_out(vty, "%-17s %-6s %-21s %-5s %u/%u\n", buf1,
- "remote", inet_ntoa(mac->fwd_info.r_vtep_ip),
+ vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %u/%u\n", buf1,
+ "remote",
+ zvni_print_mac_flags(mac, flags_buf,
+ sizeof(flags_buf)),
+ mac->es ? mac->es->esi_str :
+ inet_ntoa(mac->fwd_info.r_vtep_ip),
"", mac->loc_seq, mac->rem_seq);
} else {
json_object_string_add(json_mac, "type", "remote");
@@ -1541,8 +1732,11 @@ static void zvni_print_mac_hash_all_vni(struct hash_bucket *bucket, void *ctxt)
if (json == NULL) {
vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n",
zvni->vni, num_macs);
- vty_out(vty, "%-17s %-6s %-21s %-5s %s\n", "MAC",
- "Type", "Intf/Remote VTEP", "VLAN", "Seq #'s");
+ vty_out(vty,
+ "Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy\n");
+ vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %s\n", "MAC",
+ "Type", "Flags", "Intf/Remote ES/VTEP",
+ "VLAN", "Seq #'s");
} else
json_object_int_add(json_vni, "numMacs", num_macs);
}
@@ -2107,13 +2301,16 @@ static void zvni_print_hash_detail(struct hash_bucket *bucket, void *data)
*/
static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
struct ipaddr *ip, uint8_t flags,
- uint32_t seq, int state, uint16_t cmd)
+ uint32_t seq, int state,
+ struct zebra_evpn_es *es,
+ uint16_t cmd)
{
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
int ipa_len;
struct zserv *client = NULL;
struct stream *s = NULL;
+ esi_t *esi = es ? &es->esi : zero_esi;
client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
/* BGP may not be running. */
@@ -2141,6 +2338,7 @@ static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
if (cmd == ZEBRA_MACIP_ADD) {
stream_putc(s, flags); /* sticky mac/gateway mac */
stream_putl(s, seq); /* sequence number */
+ stream_put(s, esi, sizeof(esi_t));
} else {
stream_putl(s, state); /* state - active/inactive */
}
@@ -2151,10 +2349,11 @@ static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Send MACIP %s flags 0x%x MAC %s IP %s seq %u L2-VNI %u to %s",
+ "Send MACIP %s f 0x%x MAC %s IP %s seq %u L2-VNI %u ESI %s to %s",
(cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", flags,
prefix_mac2str(macaddr, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2)), seq, vni,
+ es ? es->esi_str : "-",
zebra_route_string(client->proto));
if (cmd == ZEBRA_MACIP_ADD)
@@ -2223,26 +2422,26 @@ static void *zvni_neigh_alloc(void *p)
* Add neighbor entry.
*/
static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
- struct ethaddr *mac)
+ struct ethaddr *mac, zebra_mac_t *zmac,
+ uint32_t n_flags)
{
zebra_neigh_t tmp_n;
zebra_neigh_t *n = NULL;
- zebra_mac_t *zmac = NULL;
memset(&tmp_n, 0, sizeof(zebra_neigh_t));
memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
n = hash_get(zvni->neigh_table, &tmp_n, zvni_neigh_alloc);
assert(n);
- memcpy(&n->emac, mac, ETH_ALEN);
n->state = ZEBRA_NEIGH_INACTIVE;
n->zvni = zvni;
n->dad_ip_auto_recovery_timer = NULL;
+ n->flags = n_flags;
- /* Associate the neigh to mac */
- zmac = zvni_mac_lookup(zvni, mac);
- if (zmac)
- listnode_add_sort(zmac->neigh_list, n);
+ if (!zmac)
+ zmac = zvni_mac_lookup(zvni, mac);
+ zebra_vxlan_local_neigh_ref_mac(n, mac,
+ zmac, false /* send_mac_update */);
return n;
}
@@ -2253,11 +2452,9 @@ static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n)
{
zebra_neigh_t *tmp_n;
- zebra_mac_t *zmac = NULL;
- zmac = zvni_mac_lookup(zvni, &n->emac);
- if (zmac)
- listnode_delete(zmac->neigh_list, n);
+ if (n->mac)
+ listnode_delete(n->mac->neigh_list, n);
/* Cancel auto recovery */
THREAD_OFF(n->dad_ip_auto_recovery_timer);
@@ -2285,10 +2482,18 @@ static void zvni_neigh_del_hash_entry(struct hash_bucket *bucket, void *arg)
&& IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) {
if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL))
zvni_neigh_send_del_to_client(wctx->zvni->vni, &n->ip,
- &n->emac, 0, n->state);
-
- if (wctx->uninstall)
- zvni_neigh_uninstall(wctx->zvni, n);
+ &n->emac, n->flags, n->state,
+ false /*force*/);
+
+ if (wctx->uninstall) {
+ if (zebra_vxlan_neigh_is_static(n))
+ zebra_vxlan_sync_neigh_dp_install(n,
+ false /* set_inactive */,
+ true /* force_clear_static */,
+ __func__);
+ if ((n->flags & ZEBRA_NEIGH_REMOTE))
+ zvni_neigh_uninstall(wctx->zvni, n);
+ }
zvni_neigh_del(wctx->zvni, n);
}
@@ -2336,8 +2541,7 @@ static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip)
* locally or undergoing any other change (such as sequence number).
*/
static void zvni_process_neigh_on_local_mac_change(zebra_vni_t *zvni,
- zebra_mac_t *zmac,
- bool seq_change)
+ zebra_mac_t *zmac, bool seq_change, bool es_change)
{
zebra_neigh_t *n = NULL;
struct listnode *node = NULL;
@@ -2359,7 +2563,8 @@ static void zvni_process_neigh_on_local_mac_change(zebra_vni_t *zvni,
*/
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- if (IS_ZEBRA_NEIGH_INACTIVE(n) || seq_change) {
+ if (IS_ZEBRA_NEIGH_INACTIVE(n) || seq_change ||
+ es_change) {
ZEBRA_NEIGH_SET_ACTIVE(n);
n->loc_seq = zmac->loc_seq;
if (!(zvrf->dup_addr_detect &&
@@ -2367,7 +2572,7 @@ static void zvni_process_neigh_on_local_mac_change(zebra_vni_t *zvni,
ZEBRA_NEIGH_DUPLICATE)))
zvni_neigh_send_add_to_client(
zvni->vni, &n->ip, &n->emac,
- n->flags, n->loc_seq);
+ n->mac, n->flags, n->loc_seq);
}
}
}
@@ -2401,7 +2606,9 @@ static void zvni_process_neigh_on_local_mac_del(zebra_vni_t *zvni,
ZEBRA_NEIGH_SET_INACTIVE(n);
n->loc_seq = 0;
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, 0, ZEBRA_NEIGH_ACTIVE);
+ &n->emac, n->flags,
+ ZEBRA_NEIGH_ACTIVE,
+ false /*force*/);
}
}
}
@@ -2432,7 +2639,9 @@ static void zvni_process_neigh_on_remote_mac_add(zebra_vni_t *zvni,
ZEBRA_NEIGH_SET_INACTIVE(n);
n->loc_seq = 0;
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, 0, ZEBRA_NEIGH_ACTIVE);
+ &n->emac, n->flags,
+ ZEBRA_NEIGH_ACTIVE,
+ false /* force */);
}
}
}
@@ -2465,11 +2674,27 @@ static void zvni_probe_neigh_on_mac_add(zebra_vni_t *zvni, zebra_mac_t *zmac)
*/
static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
struct ethaddr *macaddr,
- uint8_t neigh_flags,
+ zebra_mac_t *zmac,
+ uint32_t neigh_flags,
uint32_t seq)
{
uint8_t flags = 0;
+ if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_LOCAL_INACTIVE)) {
+ /* host reachability has not been verified locally */
+
+ /* if no ES peer is claiming reachability we can't advertise
+ * the entry
+ */
+ if (!CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
+ return 0;
+
+ /* ES peers are claiming reachability; we will
+ * advertise the entry but with a proxy flag
+ */
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT);
+ }
+
if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
/* Set router flag (R-bit) based on local neigh entry add */
@@ -2479,24 +2704,34 @@ static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
SET_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP);
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
- seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD);
+ seq, ZEBRA_NEIGH_ACTIVE,
+ zmac ? zmac->es : NULL,
+ ZEBRA_MACIP_ADD);
}
/*
* Inform BGP about local neighbor deletion.
*/
static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
- struct ethaddr *macaddr, uint8_t flags,
- int state)
+ struct ethaddr *macaddr, uint32_t flags,
+ int state, bool force)
{
+ if (!force) {
+ if (CHECK_FLAG(flags, ZEBRA_NEIGH_LOCAL_INACTIVE) &&
+ !CHECK_FLAG(flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
+ /* the neigh was not advertised - nothing to delete */
+ return 0;
+ }
+
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
- 0, state, ZEBRA_MACIP_DEL);
+ 0, state, NULL, ZEBRA_MACIP_DEL);
}
/*
* Install remote neighbor into the kernel.
*/
-static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n)
+static int zvni_rem_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n,
+ bool was_static)
{
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
@@ -2521,7 +2756,8 @@ static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n)
flags |= DPLANE_NTF_ROUTER;
ZEBRA_NEIGH_SET_ACTIVE(n);
- dplane_neigh_add(vlan_if, &n->ip, &n->emac, flags);
+ dplane_rem_neigh_add(vlan_if, &n->ip, &n->emac, flags,
+ was_static);
return ret;
}
@@ -2556,7 +2792,7 @@ static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n)
ZEBRA_NEIGH_SET_INACTIVE(n);
n->loc_seq = 0;
- dplane_neigh_delete(vlan_if, &n->ip);
+ dplane_rem_neigh_delete(vlan_if, &n->ip);
return 0;
}
@@ -2579,7 +2815,7 @@ static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n)
if (!vlan_if)
return -1;
- dplane_neigh_update(vlan_if, &n->ip, &n->emac);
+ dplane_rem_neigh_update(vlan_if, &n->ip, &n->emac);
return 0;
}
@@ -2595,7 +2831,7 @@ static void zvni_install_neigh_hash(struct hash_bucket *bucket, void *ctxt)
n = (zebra_neigh_t *)bucket->data;
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
- zvni_neigh_install(wctx->zvni, n);
+ zvni_rem_neigh_install(wctx->zvni, n, false /*was_static*/);
}
/* Get the VRR interface for SVI if any */
@@ -2730,12 +2966,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
zebra_mac_t *mac = NULL;
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan *vxl = NULL;
- struct zebra_vrf *zvrf;
- ns_id_t local_ns_id = NS_DEFAULT;
- zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
- if (zvrf && zvrf->zns)
- local_ns_id = zvrf->zns->ns_id;
zif = zvni->vxlan_if->info;
if (!zif)
return -1;
@@ -2760,12 +2991,11 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
mac->fwd_info.local.ifindex = ifp->ifindex;
- mac->fwd_info.local.ns_id = local_ns_id;
mac->fwd_info.local.vid = vxl->access_vlan;
n = zvni_neigh_lookup(zvni, ip);
if (!n) {
- n = zvni_neigh_add(zvni, ip, macaddr);
+ n = zvni_neigh_add(zvni, ip, macaddr, mac, 0);
if (!n) {
flog_err(
EC_ZEBRA_MAC_ADD_FAILED,
@@ -2799,7 +3029,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
prefix_mac2str(macaddr, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2)), n->flags);
- zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
+ zvni_neigh_send_add_to_client(zvni->vni, ip, &n->emac, n->mac,
n->flags, n->loc_seq);
} else if (advertise_svi_macip_enabled(zvni)) {
@@ -2811,7 +3041,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
prefix_mac2str(macaddr, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2)), n->flags);
- zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
+ zvni_neigh_send_add_to_client(zvni->vni, ip, &n->emac, n->mac,
n->flags, n->loc_seq);
}
@@ -2860,7 +3090,8 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
/* Remove neighbor from BGP. */
zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
- ZEBRA_MACIP_TYPE_GW, ZEBRA_NEIGH_ACTIVE);
+ n->flags, ZEBRA_NEIGH_ACTIVE,
+ false /*force*/);
/* Delete this neighbor entry. */
zvni_neigh_del(zvni, n);
@@ -3008,11 +3239,36 @@ static void zvni_svi_macip_del_for_vni_hash(struct hash_bucket *bucket,
return;
}
+static inline void zvni_local_neigh_update_log(const char *pfx,
+ zebra_neigh_t *n, bool is_router, bool local_inactive,
+ bool old_bgp_ready, bool new_bgp_ready,
+ bool inform_dataplane, bool inform_bgp, const char *sfx)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ if (!IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ return;
+
+ zlog_debug("%s neigh vni %u ip %s mac %s f 0x%x%s%s%s%s%s%s %s",
+ pfx, n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)),
+ n->flags, is_router ? " router" : "",
+ local_inactive ? " local-inactive" : "",
+ old_bgp_ready ? " old_bgp_ready" : "",
+ new_bgp_ready ? " new_bgp_ready" : "",
+ inform_dataplane ? " inform_dp" : "",
+ inform_bgp ? " inform_bgp" : "",
+ sfx);
+}
+
static int zvni_local_neigh_update(zebra_vni_t *zvni,
struct interface *ifp,
struct ipaddr *ip,
struct ethaddr *macaddr,
- bool is_router)
+ bool is_router,
+ bool local_inactive, bool dp_static)
{
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
@@ -3026,6 +3282,11 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
bool neigh_was_remote = false;
bool do_dad = false;
struct in_addr vtep_ip = {.s_addr = 0};
+ bool inform_dataplane = false;
+ bool created = false;
+ bool new_static = false;
+ bool old_bgp_ready = false;
+ bool new_bgp_ready;
/* Check if the MAC exists. */
zmac = zvni_mac_lookup(zvni, macaddr);
@@ -3073,7 +3334,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
n = zvni_neigh_lookup(zvni, ip);
if (!n) {
/* New neighbor - create */
- n = zvni_neigh_add(zvni, ip, macaddr);
+ n = zvni_neigh_add(zvni, ip, macaddr, zmac, 0);
if (!n) {
flog_err(
EC_ZEBRA_MAC_ADD_FAILED,
@@ -3086,17 +3347,28 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
/* Set "local" forwarding info. */
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
n->ifindex = ifp->ifindex;
+ created = true;
} else {
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
bool mac_different;
bool cur_is_router;
+ bool old_local_inactive;
+
+ old_local_inactive = !!CHECK_FLAG(n->flags,
+ ZEBRA_NEIGH_LOCAL_INACTIVE);
+
+ old_bgp_ready =
+ zebra_vxlan_neigh_is_ready_for_bgp(n);
/* Note any changes and see if of interest to BGP. */
- mac_different = (memcmp(n->emac.octet,
- macaddr->octet, ETH_ALEN) != 0) ? 1 : 0;
+ mac_different = !!memcmp(&n->emac,
+ macaddr, ETH_ALEN);
cur_is_router = !!CHECK_FLAG(n->flags,
ZEBRA_NEIGH_ROUTER_FLAG);
- if (!mac_different && is_router == cur_is_router) {
+ new_static = zebra_vxlan_neigh_is_static(n);
+ if (!mac_different && is_router == cur_is_router &&
+ old_local_inactive == local_inactive &&
+ dp_static != new_static) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
" Ignoring entry mac is the same and is_router == cur_is_router");
@@ -3104,7 +3376,9 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
return 0;
}
+ old_zmac = n->mac;
if (!mac_different) {
+ /* XXX - cleanup this code duplication */
bool is_neigh_freezed = false;
/* Only the router flag has changed. */
@@ -3115,6 +3389,15 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
UNSET_FLAG(n->flags,
ZEBRA_NEIGH_ROUTER_FLAG);
+ if (local_inactive)
+ SET_FLAG(n->flags,
+ ZEBRA_NEIGH_LOCAL_INACTIVE);
+ else
+ UNSET_FLAG(n->flags,
+ ZEBRA_NEIGH_LOCAL_INACTIVE);
+ new_bgp_ready =
+ zebra_vxlan_neigh_is_ready_for_bgp(n);
+
/* Neigh is in freeze state and freeze action
* is enabled, do not send update to client.
*/
@@ -3123,13 +3406,20 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
CHECK_FLAG(n->flags,
ZEBRA_NEIGH_DUPLICATE));
- if (IS_ZEBRA_NEIGH_ACTIVE(n) &&
- !is_neigh_freezed)
- return zvni_neigh_send_add_to_client(
- zvni->vni, ip, macaddr,
- n->flags, n->loc_seq);
- else {
- if (IS_ZEBRA_DEBUG_VXLAN)
+ zvni_local_neigh_update_log("local", n,
+ is_router, local_inactive,
+ old_bgp_ready, new_bgp_ready,
+ false, false, "flag-update");
+
+ /* if the neigh can no longer be advertised
+ * remove it from bgp
+ */
+ if (!is_neigh_freezed) {
+ zebra_vxlan_neigh_send_add_del_to_client(
+ n, old_bgp_ready, new_bgp_ready);
+ } else {
+ if (IS_ZEBRA_DEBUG_VXLAN &&
+ IS_ZEBRA_NEIGH_ACTIVE(n))
zlog_debug(
" Neighbor active and frozen");
}
@@ -3142,25 +3432,32 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
* We also need to update the MAC's sequence number
* in different situations.
*/
- if (IS_ZEBRA_NEIGH_ACTIVE(n))
+ if (old_bgp_ready) {
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, 0, n->state);
- old_zmac = zvni_mac_lookup(zvni, &n->emac);
+ &n->emac, n->flags, n->state,
+ false /*force*/);
+ old_bgp_ready = false;
+ }
if (old_zmac) {
old_mac_seq = CHECK_FLAG(old_zmac->flags,
ZEBRA_MAC_REMOTE) ?
old_zmac->rem_seq : old_zmac->loc_seq;
neigh_mac_change = upd_mac_seq = true;
- listnode_delete(old_zmac->neigh_list, n);
- zvni_deref_ip2mac(zvni, old_zmac);
+ zebra_vxlan_local_neigh_deref_mac(n,
+ true /* send_mac_update */);
}
+ /* if mac changes abandon peer flags and tell
+ * dataplane to clear the static flag
+ */
+ if (zebra_vxlan_neigh_clear_sync_info(n))
+ inform_dataplane = true;
/* Update the forwarding info. */
n->ifindex = ifp->ifindex;
- memcpy(&n->emac, macaddr, ETH_ALEN);
/* Link to new MAC */
- listnode_add_sort(zmac->neigh_list, n);
+ zebra_vxlan_local_neigh_ref_mac(n, macaddr, zmac,
+ true /* send_mac_update */);
} else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
/*
* Neighbor has moved from remote to local. Its
@@ -3168,7 +3465,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
*/
if (memcmp(n->emac.octet, macaddr->octet,
ETH_ALEN) != 0) {
- old_zmac = zvni_mac_lookup(zvni, &n->emac);
+ old_zmac = n->mac;
if (old_zmac) {
old_mac_seq = CHECK_FLAG(
old_zmac->flags,
@@ -3176,14 +3473,13 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
old_zmac->rem_seq :
old_zmac->loc_seq;
neigh_mac_change = upd_mac_seq = true;
- listnode_delete(old_zmac->neigh_list,
- n);
- zvni_deref_ip2mac(zvni, old_zmac);
+ zebra_vxlan_local_neigh_deref_mac(n,
+ true /* send_update */);
}
/* Link to new MAC */
- memcpy(&n->emac, macaddr, ETH_ALEN);
- listnode_add_sort(zmac->neigh_list, n);
+ zebra_vxlan_local_neigh_ref_mac(n, macaddr,
+ zmac, true /*send_update*/);
}
/* Based on Mobility event Scenario-B from the
* draft, neigh's previous state was remote treat this
@@ -3212,12 +3508,27 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
MAX(seq1, seq2) : zmac->loc_seq;
}
+ if (local_inactive)
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
+ else
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
+
/* Mark Router flag (R-bit) */
if (is_router)
SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
else
UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+ /* if the dataplane thinks that this is a sync entry but
+ * zebra doesn't we need to re-concile the diff
+ * by re-installing the dataplane entry
+ */
+ if (dp_static) {
+ new_static = zebra_vxlan_neigh_is_static(n);
+ if (!new_static)
+ inform_dataplane = true;
+ }
+
/* Check old and/or new MAC detected as duplicate mark
* the neigh as duplicate
*/
@@ -3240,16 +3551,28 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
zebra_vxlan_dup_addr_detect_for_neigh(zvrf, n, vtep_ip, do_dad,
&neigh_on_hold, true);
+ if (inform_dataplane)
+ zebra_vxlan_sync_neigh_dp_install(n, false /* set_inactive */,
+ false /* force_clear_static */, __func__);
+
/* Before we program this in BGP, we need to check if MAC is locally
* learnt. If not, force neighbor to be inactive and reset its seq.
*/
if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) {
+ zvni_local_neigh_update_log("local",
+ n, is_router, local_inactive,
+ false, false, inform_dataplane, false,
+ "auto-mac");
ZEBRA_NEIGH_SET_INACTIVE(n);
n->loc_seq = 0;
zmac->loc_seq = mac_new_seq;
return 0;
}
+ zvni_local_neigh_update_log("local",
+ n, is_router, local_inactive, false, false, inform_dataplane,
+ true, created ? "created" : "updated");
+
/* If the MAC's sequence number has changed, inform the MAC and all
* neighbors associated with the MAC to BGP, else just inform this
* neighbor.
@@ -3261,9 +3584,10 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
zvni->vni, zmac->loc_seq, mac_new_seq);
zmac->loc_seq = mac_new_seq;
if (zvni_mac_send_add_to_client(zvni->vni, macaddr,
- zmac->flags, zmac->loc_seq))
+ zmac->flags, zmac->loc_seq, zmac->es))
return -1;
- zvni_process_neigh_on_local_mac_change(zvni, zmac, 1);
+ zvni_process_neigh_on_local_mac_change(zvni, zmac, 1,
+ 0 /*es_change*/);
return 0;
}
@@ -3271,9 +3595,10 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
if (!neigh_on_hold) {
ZEBRA_NEIGH_SET_ACTIVE(n);
-
- return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
- n->flags, n->loc_seq);
+ new_bgp_ready =
+ zebra_vxlan_neigh_is_ready_for_bgp(n);
+ zebra_vxlan_neigh_send_add_del_to_client(n,
+ old_bgp_ready, new_bgp_ready);
} else {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(" Neighbor on hold not sending");
@@ -3301,7 +3626,7 @@ static int zvni_remote_neigh_update(zebra_vni_t *zvni,
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
#ifdef GNU_LINUX
if (state & NUD_STALE)
- zvni_neigh_install(zvni, n);
+ zvni_rem_neigh_install(zvni, n, false /*was_static*/);
#endif
} else {
/* We got a "remote" neighbor notification for an entry
@@ -3319,7 +3644,7 @@ static int zvni_remote_neigh_update(zebra_vni_t *zvni,
return -1;
}
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ALL_LOCAL_FLAGS);
SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
ZEBRA_NEIGH_SET_ACTIVE(n);
n->r_vtep_ip = zmac->fwd_info.r_vtep_ip;
@@ -3390,6 +3715,15 @@ static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr)
mac->neigh_list = list_new();
mac->neigh_list->cmp = neigh_list_cmp;
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char buf[ETHER_ADDR_STRLEN];
+
+ zlog_debug("%s: MAC %s flags 0x%x",
+ __func__,
+ prefix_mac2str(&mac->macaddr,
+ buf, sizeof(buf)),
+ mac->flags);
+ }
return mac;
}
@@ -3400,6 +3734,22 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac)
{
zebra_mac_t *tmp_mac;
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char buf[ETHER_ADDR_STRLEN];
+
+ zlog_debug("%s: MAC %s flags 0x%x",
+ __func__,
+ prefix_mac2str(&mac->macaddr,
+ buf, sizeof(buf)),
+ mac->flags);
+ }
+
+ /* force de-ref any ES entry linked to the MAC */
+ zebra_evpn_es_mac_deref_entry(mac);
+
+ /* Cancel proxy hold timer */
+ zebra_vxlan_mac_stop_hold_timer(mac);
+
/* Cancel auto recovery */
THREAD_OFF(mac->dad_mac_auto_recovery_timer);
@@ -3455,10 +3805,18 @@ static void zvni_mac_del_hash_entry(struct hash_bucket *bucket, void *arg)
if (zvni_check_mac_del_from_db(wctx, mac)) {
if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
zvni_mac_send_del_to_client(wctx->zvni->vni,
- &mac->macaddr);
+ &mac->macaddr, mac->flags, false);
+ }
+ if (wctx->uninstall) {
+ if (zebra_vxlan_mac_is_static(mac))
+ zebra_vxlan_sync_mac_dp_install(mac,
+ false /* set_inactive */,
+ true /* force_clear_static */,
+ __func__);
+
+ if (mac->flags & ZEBRA_MAC_REMOTE)
+ zvni_rem_mac_uninstall(wctx->zvni, mac);
}
- if (wctx->uninstall)
- zvni_mac_uninstall(wctx->zvni, mac);
zvni_mac_del(wctx->zvni, mac);
}
@@ -3505,88 +3863,51 @@ static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac)
* Inform BGP about local MAC addition.
*/
static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr,
- uint8_t mac_flags, uint32_t seq)
+ uint32_t mac_flags, uint32_t seq, struct zebra_evpn_es *es)
{
uint8_t flags = 0;
+ if (CHECK_FLAG(mac_flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
+ /* host reachability has not been verified locally */
+
+ /* if no ES peer is claiming reachability we can't advertise the
+ * entry
+ */
+ if (!CHECK_FLAG(mac_flags, ZEBRA_MAC_ES_PEER_ACTIVE))
+ return 0;
+
+ /* ES peers are claiming reachability; we will
+ * advertise the entry but with a proxy flag
+ */
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT);
+ }
+
if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
- seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD);
+ seq, ZEBRA_NEIGH_ACTIVE, es,
+ ZEBRA_MACIP_ADD);
}
/*
* Inform BGP about local MAC deletion.
*/
-static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr)
-{
- return zvni_macip_send_msg_to_client(vni, macaddr, NULL, 0 /* flags */,
- 0 /* seq */, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_DEL);
-}
-
-struct zvni_from_svi_param {
- struct interface *br_if;
- struct interface *svi_if;
- struct zebra_if *zif;
- uint8_t bridge_vlan_aware;
- vlanid_t vid;
-};
-
-static int zvni_map_vlan_ns(struct ns *ns,
- void *_in_param,
- void **_p_zvni)
+static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr,
+ uint32_t flags, bool force)
{
- struct zebra_ns *zns = ns->info;
- struct route_node *rn;
- struct interface *br_if;
- zebra_vni_t **p_zvni = (zebra_vni_t **)_p_zvni;
- zebra_vni_t *zvni;
- struct interface *tmp_if = NULL;
- struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl = NULL;
- struct zvni_from_svi_param *in_param =
- (struct zvni_from_svi_param *)_in_param;
- int found = 0;
-
- if (!in_param)
- return NS_WALK_STOP;
- br_if = in_param->br_if;
- zif = in_param->zif;
- assert(zif);
- assert(br_if);
-
- /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
- /* TODO: Optimize with a hash. */
- for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- tmp_if = (struct interface *)rn->info;
- if (!tmp_if)
- continue;
- zif = tmp_if->info;
- if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
- continue;
- if (!if_is_operative(tmp_if))
- continue;
- vxl = &zif->l2info.vxl;
-
- if (zif->brslave_info.br_if != br_if)
- continue;
-
- if (!in_param->bridge_vlan_aware
- || vxl->access_vlan == in_param->vid) {
- found = 1;
- break;
- }
+ if (!force) {
+ if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE) &&
+ !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE))
+ /* the host was not advertised - nothing to delete */
+ return 0;
}
- if (!found)
- return NS_WALK_CONTINUE;
- zvni = zvni_lookup(vxl->vni);
- if (p_zvni)
- *p_zvni = zvni;
- return NS_WALK_STOP;
+ return zvni_macip_send_msg_to_client(vni, macaddr, NULL, 0 /* flags */,
+ 0 /* seq */, ZEBRA_NEIGH_ACTIVE, NULL,
+ ZEBRA_MACIP_DEL);
}
/*
@@ -3596,51 +3917,25 @@ static int zvni_map_vlan_ns(struct ns *ns,
static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
struct interface *br_if, vlanid_t vid)
{
- struct zebra_if *zif;
- struct zebra_l2info_bridge *br;
- zebra_vni_t **p_zvni;
- zebra_vni_t *zvni = NULL;
- struct zvni_from_svi_param in_param;
-
- /* Determine if bridge is VLAN-aware or not */
- zif = br_if->info;
- assert(zif);
- br = &zif->l2info.br;
- in_param.bridge_vlan_aware = br->vlan_aware;
- in_param.vid = vid;
- in_param.br_if = br_if;
- in_param.zif = zif;
- p_zvni = &zvni;
-
- ns_walk_func(zvni_map_vlan_ns,
- (void *)&in_param,
- (void **)p_zvni);
- return zvni;
-}
-
-static int zvni_from_svi_ns(struct ns *ns,
- void *_in_param,
- void **_p_zvni)
-{
- struct zebra_ns *zns = ns->info;
+ struct zebra_ns *zns;
struct route_node *rn;
- struct interface *br_if;
- zebra_vni_t **p_zvni = (zebra_vni_t **)_p_zvni;
- zebra_vni_t *zvni;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
+ struct zebra_l2info_bridge *br;
struct zebra_l2info_vxlan *vxl = NULL;
- struct zvni_from_svi_param *in_param =
- (struct zvni_from_svi_param *)_in_param;
+ uint8_t bridge_vlan_aware;
+ zebra_vni_t *zvni;
int found = 0;
- if (!in_param)
- return NS_WALK_STOP;
- br_if = in_param->br_if;
- zif = in_param->zif;
+ /* Determine if bridge is VLAN-aware or not */
+ zif = br_if->info;
assert(zif);
+ br = &zif->l2info.br;
+ bridge_vlan_aware = br->vlan_aware;
+ /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
/* TODO: Optimize with a hash. */
+ zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
if (!tmp_if)
@@ -3655,20 +3950,17 @@ static int zvni_from_svi_ns(struct ns *ns,
if (zif->brslave_info.br_if != br_if)
continue;
- if (!in_param->bridge_vlan_aware
- || vxl->access_vlan == !in_param->vid) {
+ if (!bridge_vlan_aware || vxl->access_vlan == vid) {
found = 1;
break;
}
}
if (!found)
- return NS_WALK_CONTINUE;
+ return NULL;
zvni = zvni_lookup(vxl->vni);
- if (p_zvni)
- *p_zvni = zvni;
- return NS_WALK_STOP;
+ return zvni;
}
/*
@@ -3678,11 +3970,16 @@ static int zvni_from_svi_ns(struct ns *ns,
static zebra_vni_t *zvni_from_svi(struct interface *ifp,
struct interface *br_if)
{
- struct zebra_l2info_bridge *br;
- zebra_vni_t *zvni = NULL;
- zebra_vni_t **p_zvni;
+ struct zebra_ns *zns;
+ struct route_node *rn;
+ struct interface *tmp_if = NULL;
struct zebra_if *zif;
- struct zvni_from_svi_param in_param;
+ struct zebra_l2info_bridge *br;
+ struct zebra_l2info_vxlan *vxl = NULL;
+ uint8_t bridge_vlan_aware;
+ vlanid_t vid = 0;
+ zebra_vni_t *zvni;
+ int found = 0;
if (!br_if)
return NULL;
@@ -3695,10 +3992,8 @@ static zebra_vni_t *zvni_from_svi(struct interface *ifp,
zif = br_if->info;
assert(zif);
br = &zif->l2info.br;
- in_param.bridge_vlan_aware = br->vlan_aware;
- in_param.vid = 0;
-
- if (in_param.bridge_vlan_aware) {
+ bridge_vlan_aware = br->vlan_aware;
+ if (bridge_vlan_aware) {
struct zebra_l2info_vlan *vl;
if (!IS_ZEBRA_IF_VLAN(ifp))
@@ -3707,54 +4002,37 @@ static zebra_vni_t *zvni_from_svi(struct interface *ifp,
zif = ifp->info;
assert(zif);
vl = &zif->l2info.vl;
- in_param.vid = vl->vid;
+ vid = vl->vid;
}
- in_param.br_if = br_if;
- in_param.zif = zif;
- p_zvni = &zvni;
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
- ns_walk_func(zvni_from_svi_ns,
- (void *)&in_param,
- (void **)p_zvni);
- return zvni;
-}
-
-static int zvni_map_to_svi_ns(struct ns *ns,
- void *_in_param,
- void **_p_ifp)
-{
- struct zebra_ns *zns = ns->info;
- struct route_node *rn;
- struct zvni_from_svi_param *in_param =
- (struct zvni_from_svi_param *)_in_param;
- struct zebra_l2info_vlan *vl;
- struct interface *tmp_if = NULL;
- struct interface **p_ifp = (struct interface **)_p_ifp;
- struct zebra_if *zif;
-
- if (!in_param)
- return NS_WALK_STOP;
-
/* TODO: Optimize with a hash. */
+ zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
- /* Check oper status of the SVI. */
- if (!tmp_if || !if_is_operative(tmp_if))
+ if (!tmp_if)
continue;
zif = tmp_if->info;
- if (!zif || zif->zif_type != ZEBRA_IF_VLAN
- || zif->link != in_param->br_if)
+ if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
continue;
- vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
+ if (!if_is_operative(tmp_if))
+ continue;
+ vxl = &zif->l2info.vxl;
- if (vl->vid == in_param->vid) {
- if (p_ifp)
- *p_ifp = tmp_if;
- return NS_WALK_STOP;
+ if (zif->brslave_info.br_if != br_if)
+ continue;
+
+ if (!bridge_vlan_aware || vxl->access_vlan == vid) {
+ found = 1;
+ break;
}
}
- return NS_WALK_CONTINUE;
+
+ if (!found)
+ return NULL;
+
+ zvni = zvni_lookup(vxl->vni);
+ return zvni;
}
/* Map to SVI on bridge corresponding to specified VLAN. This can be one
@@ -3766,11 +4044,15 @@ static int zvni_map_to_svi_ns(struct ns *ns,
*/
static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
{
+ struct zebra_ns *zns;
+ struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
struct zebra_l2info_bridge *br;
- struct zvni_from_svi_param in_param;
- struct interface **p_ifp;
+ struct zebra_l2info_vlan *vl;
+ uint8_t bridge_vlan_aware;
+ int found = 0;
+
/* Defensive check, caller expected to invoke only with valid bridge. */
if (!br_if)
return NULL;
@@ -3779,56 +4061,33 @@ static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
zif = br_if->info;
assert(zif);
br = &zif->l2info.br;
- in_param.bridge_vlan_aware = br->vlan_aware;
+ bridge_vlan_aware = br->vlan_aware;
+
/* Check oper status of the SVI. */
- if (!in_param.bridge_vlan_aware)
+ if (!bridge_vlan_aware)
return if_is_operative(br_if) ? br_if : NULL;
- in_param.vid = vid;
- in_param.br_if = br_if;
- in_param.zif = NULL;
- p_ifp = &tmp_if;
- /* Identify corresponding VLAN interface. */
- ns_walk_func(zvni_map_to_svi_ns,
- (void *)&in_param,
- (void **)p_ifp);
- return tmp_if;
-}
-
-static int zvni_map_to_macvlan_ns(struct ns *ns,
- void *_in_param,
- void **_p_ifp)
-{
- struct zebra_ns *zns = ns->info;
- struct zvni_from_svi_param *in_param =
- (struct zvni_from_svi_param *)_in_param;
- struct interface **p_ifp = (struct interface **)_p_ifp;
- struct route_node *rn;
- struct interface *tmp_if = NULL;
- struct zebra_if *zif;
-
- if (!in_param)
- return NS_WALK_STOP;
-
/* Identify corresponding VLAN interface. */
+ /* TODO: Optimize with a hash. */
+ zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
/* Check oper status of the SVI. */
if (!tmp_if || !if_is_operative(tmp_if))
continue;
zif = tmp_if->info;
-
- if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
+ if (!zif || zif->zif_type != ZEBRA_IF_VLAN
+ || zif->link != br_if)
continue;
+ vl = &zif->l2info.vl;
- if (zif->link == in_param->svi_if) {
- if (p_ifp)
- *p_ifp = tmp_if;
- return NS_WALK_STOP;
+ if (vl->vid == vid) {
+ found = 1;
+ break;
}
}
- return NS_WALK_CONTINUE;
+ return found ? tmp_if : NULL;
}
/* Map to MAC-VLAN interface corresponding to specified SVI interface.
@@ -3836,10 +4095,11 @@ static int zvni_map_to_macvlan_ns(struct ns *ns,
static struct interface *zvni_map_to_macvlan(struct interface *br_if,
struct interface *svi_if)
{
+ struct zebra_ns *zns;
+ struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
- struct interface **p_ifp;
- struct zvni_from_svi_param in_param;
+ int found = 0;
/* Defensive check, caller expected to invoke only with valid bridge. */
if (!br_if)
@@ -3854,23 +4114,33 @@ static struct interface *zvni_map_to_macvlan(struct interface *br_if,
zif = br_if->info;
assert(zif);
- in_param.vid = 0;
- in_param.br_if = br_if;
- in_param.zif = NULL;
- in_param.svi_if = svi_if;
- p_ifp = &tmp_if;
-
/* Identify corresponding VLAN interface. */
- ns_walk_func(zvni_map_to_macvlan_ns,
- (void *)&in_param,
- (void **)p_ifp);
- return tmp_if;
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ /* Check oper status of the SVI. */
+ if (!tmp_if || !if_is_operative(tmp_if))
+ continue;
+ zif = tmp_if->info;
+
+ if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
+ continue;
+
+ if (zif->link == svi_if) {
+ found = 1;
+ break;
+ }
+ }
+
+ return found ? tmp_if : NULL;
}
+
/*
* Install remote MAC into the forwarding plane.
*/
-static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac)
+static int zvni_rem_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac,
+ bool was_static)
{
const struct zebra_if *zif, *br_zif;
const struct zebra_l2info_vxlan *vxl;
@@ -3878,6 +4148,8 @@ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac)
enum zebra_dplane_result res;
const struct interface *br_ifp;
vlanid_t vid;
+ uint32_t nhg_id;
+ struct in_addr vtep_ip;
if (!(mac->flags & ZEBRA_MAC_REMOTE))
return 0;
@@ -3895,6 +4167,19 @@ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac)
sticky = !!CHECK_FLAG(mac->flags,
(ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
+ /* If nexthop group for the FDB entry is inactive (not programmed in
+ * the dataplane) the MAC entry cannot be installed
+ */
+ if (mac->es) {
+ if (!(mac->es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
+ return -1;
+ nhg_id = mac->es->nhg_id;
+ vtep_ip.s_addr = 0;
+ } else {
+ nhg_id = 0;
+ vtep_ip = mac->fwd_info.r_vtep_ip;
+ }
+
br_zif = (const struct zebra_if *)(br_ifp->info);
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
@@ -3902,8 +4187,9 @@ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac)
else
vid = 0;
- res = dplane_mac_add(zvni->vxlan_if, br_ifp, vid,
- &mac->macaddr, mac->fwd_info.r_vtep_ip, sticky);
+ res = dplane_rem_mac_add(zvni->vxlan_if, br_ifp, vid,
+ &mac->macaddr, vtep_ip, sticky,
+ nhg_id, was_static);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
else
@@ -3913,7 +4199,7 @@ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac)
/*
* Uninstall remote MAC from the forwarding plane.
*/
-static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac)
+static int zvni_rem_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac)
{
const struct zebra_if *zif, *br_zif;
const struct zebra_l2info_vxlan *vxl;
@@ -3952,7 +4238,7 @@ static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac)
ifp = zvni->vxlan_if;
vtep_ip = mac->fwd_info.r_vtep_ip;
- res = dplane_mac_del(ifp, br_ifp, vid, &mac->macaddr, vtep_ip);
+ res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vtep_ip);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
else
@@ -3970,7 +4256,7 @@ static void zvni_install_mac_hash(struct hash_bucket *bucket, void *ctxt)
mac = (zebra_mac_t *)bucket->data;
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
- zvni_mac_install(wctx->zvni, mac);
+ zvni_rem_mac_install(wctx->zvni, mac, false);
}
/*
@@ -4004,7 +4290,8 @@ static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac)
*/
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) &&
remote_neigh_count(mac) == 0) {
- zvni_mac_uninstall(zvni, mac);
+ zvni_rem_mac_uninstall(zvni, mac);
+ zebra_evpn_es_mac_deref_entry(mac);
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
}
@@ -4019,7 +4306,6 @@ static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac)
static void zvni_read_mac_neigh(zebra_vni_t *zvni, struct interface *ifp)
{
struct zebra_ns *zns;
- struct zebra_vrf *zvrf;
struct zebra_if *zif;
struct interface *vlan_if;
struct zebra_l2info_vxlan *vxl;
@@ -4027,10 +4313,7 @@ static void zvni_read_mac_neigh(zebra_vni_t *zvni, struct interface *ifp)
zif = ifp->info;
vxl = &zif->l2info.vxl;
- zvrf = zebra_vrf_lookup_by_id(zvni->vrf_id);
- if (!zvrf || !zvrf->zns)
- return;
- zns = zvrf->zns;
+ zns = zebra_ns_lookup(NS_DEFAULT);
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
@@ -4075,7 +4358,7 @@ static bool vni_hash_cmp(const void *p1, const void *p2)
return (zvni1->vni == zvni2->vni);
}
-static int vni_list_cmp(void *p1, void *p2)
+int vni_list_cmp(void *p1, void *p2)
{
const zebra_vni_t *zvni1 = p1;
const zebra_vni_t *zvni2 = p2;
@@ -4101,7 +4384,7 @@ static void *zvni_alloc(void *p)
/*
* Look up VNI hash entry.
*/
-static zebra_vni_t *zvni_lookup(vni_t vni)
+zebra_vni_t *zvni_lookup(vni_t vni)
{
struct zebra_vrf *zvrf;
zebra_vni_t tmp_vni;
@@ -4132,6 +4415,8 @@ static zebra_vni_t *zvni_add(vni_t vni)
zvni = hash_get(zvrf->vni_table, &tmp_zvni, zvni_alloc);
assert(zvni);
+ zebra_evpn_vni_es_init(zvni);
+
/* Create hash table for MAC */
zvni->mac_table =
hash_create(mac_hash_keymake, mac_cmp, "Zebra VNI MAC Table");
@@ -4143,6 +4428,30 @@ static zebra_vni_t *zvni_add(vni_t vni)
return zvni;
}
+/* vni<=>vxlan_zif association */
+static void zvni_vxlan_if_set(zebra_vni_t *zvni, struct interface *ifp,
+ bool set)
+{
+ struct zebra_if *zif;
+
+ if (set) {
+ if (zvni->vxlan_if == ifp)
+ return;
+ zvni->vxlan_if = ifp;
+ } else {
+ if (!zvni->vxlan_if)
+ return;
+ zvni->vxlan_if = NULL;
+ }
+
+ if (ifp)
+ zif = ifp->info;
+ else
+ zif = NULL;
+
+ zebra_evpn_vxl_vni_set(zif, zvni, set);
+}
+
/*
* Delete VNI hash entry.
*/
@@ -4154,7 +4463,7 @@ static int zvni_del(zebra_vni_t *zvni)
zvrf = zebra_vrf_get_evpn();
assert(zvrf);
- zvni->vxlan_if = NULL;
+ zvni_vxlan_if_set(zvni, zvni->vxlan_if, false /* set */);
/* Remove references to the BUM mcast grp */
zebra_vxlan_sg_deref(zvni->local_vtep_ip, zvni->mcast_grp);
@@ -4167,6 +4476,8 @@ static int zvni_del(zebra_vni_t *zvni)
hash_free(zvni->mac_table);
zvni->mac_table = NULL;
+ zebra_evpn_vni_es_cleanup(zvni);
+
/* Free the VNI hash entry and allocated memory. */
tmp_zvni = hash_release(zvrf->vni_table, zvni);
XFREE(MTYPE_ZVNI, tmp_zvni);
@@ -4181,6 +4492,7 @@ static int zvni_send_add_to_client(zebra_vni_t *zvni)
{
struct zserv *client;
struct stream *s;
+ int rc;
client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
/* BGP may not be running. */
@@ -4205,13 +4517,22 @@ static int zvni_send_add_to_client(zebra_vni_t *zvni)
zebra_route_string(client->proto));
client->vniadd_cnt++;
- return zserv_send_message(client, s);
+ rc = zserv_send_message(client, s);
+
+ if (!(zvni->flags & ZVNI_READY_FOR_BGP)) {
+ zvni->flags |= ZVNI_READY_FOR_BGP;
+ /* once the VNI is sent the ES-EVIs can also be replayed
+ * to BGP
+ */
+ zebra_evpn_vni_update_all_es(zvni);
+ }
+ return rc;
}
/*
* Inform BGP about local VNI deletion.
*/
-static int zvni_send_del_to_client(vni_t vni)
+static int zvni_send_del_to_client(zebra_vni_t *zvni)
{
struct zserv *client;
struct stream *s;
@@ -4221,38 +4542,41 @@ static int zvni_send_del_to_client(vni_t vni)
if (!client)
return 0;
+ if (zvni->flags & ZVNI_READY_FOR_BGP) {
+ zvni->flags &= ~ZVNI_READY_FOR_BGP;
+ /* the ES-EVIs must be removed from BGP before the VNI is */
+ zebra_evpn_vni_update_all_es(zvni);
+ }
+
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
stream_reset(s);
zclient_create_header(s, ZEBRA_VNI_DEL, zebra_vrf_get_evpn_id());
- stream_putl(s, vni);
+ stream_putl(s, zvni->vni);
/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Send VNI_DEL %u to %s", vni,
+ zlog_debug("Send VNI_DEL %u to %s", zvni->vni,
zebra_route_string(client->proto));
client->vnidel_cnt++;
return zserv_send_message(client, s);
}
-static int zvni_build_hash_table_ns(struct ns *ns,
- void *param_in __attribute__((unused)),
- void **param_out __attribute__((unused)))
+/*
+ * Build the VNI hash table by going over the VxLAN interfaces. This
+ * is called when EVPN (advertise-all-vni) is enabled.
+ */
+static void zvni_build_hash_table(void)
{
- struct zebra_ns *zns = ns->info;
+ struct zebra_ns *zns;
struct route_node *rn;
struct interface *ifp;
- struct zebra_vrf *zvrf;
-
- zvrf = zebra_vrf_get_evpn();
-
- if (!zvrf)
- return NS_WALK_STOP;
/* Walk VxLAN interfaces and create VNI hash. */
+ zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
vni_t vni;
zebra_vni_t *zvni = NULL;
@@ -4269,14 +4593,7 @@ static int zvni_build_hash_table_ns(struct ns *ns,
vxl = &zif->l2info.vxl;
vni = vxl->vni;
- /* link of VXLAN interface should be in zebra_evpn_vrf */
- if (zvrf->zns->ns_id != vxl->link_nsid) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Intf %s(%u) VNI %u, link not in same namespace than BGP EVPN core instance ",
- ifp->name, ifp->ifindex, vni);
- continue;
- }
+
/* L3-VNI and L2-VNI are handled seperately */
zl3vni = zl3vni_lookup(vni);
if (zl3vni) {
@@ -4345,7 +4662,7 @@ static int zvni_build_hash_table_ns(struct ns *ns,
zlog_debug(
"Failed to add VNI hash, IF %s(%u) L2-VNI %u",
ifp->name, ifp->ifindex, vni);
- return NS_WALK_CONTINUE;
+ return;
}
if (zvni->local_vtep_ip.s_addr !=
@@ -4359,8 +4676,12 @@ static int zvni_build_hash_table_ns(struct ns *ns,
vxl->mcast_grp);
zvni->local_vtep_ip = vxl->vtep_ip;
zvni->mcast_grp = vxl->mcast_grp;
+ /* on local vtep-ip check if ES
+ * orig-ip needs to be updated
+ */
+ zebra_evpn_es_set_base_vni(zvni);
}
- zvni->vxlan_if = ifp;
+ zvni_vxlan_if_set(zvni, ifp, true /* set */);
vlan_if = zvni_map_to_svi(vxl->access_vlan,
zif->brslave_info.br_if);
if (vlan_if) {
@@ -4382,19 +4703,6 @@ static int zvni_build_hash_table_ns(struct ns *ns,
}
}
}
- return NS_WALK_CONTINUE;
-}
-
-/*
- * Build the VNI hash table by going over the VxLAN interfaces. This
- * is called when EVPN (advertise-all-vni) is enabled.
- */
-
-static void zvni_build_hash_table(void)
-{
- ns_walk_func(zvni_build_hash_table_ns,
- (void *)NULL,
- (void **)NULL);
}
/*
@@ -4720,8 +5028,9 @@ static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac)
else
vid = 0;
- res = dplane_mac_add(zl3vni->vxlan_if, br_ifp, vid,
- &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0);
+ res = dplane_rem_mac_add(zl3vni->vxlan_if, br_ifp, vid,
+ &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0, 0,
+ false /*was_static*/);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
else
@@ -4770,7 +5079,7 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac)
else
vid = 0;
- res = dplane_mac_del(zl3vni->vxlan_if, br_ifp, vid,
+ res = dplane_rem_mac_del(zl3vni->vxlan_if, br_ifp, vid,
&zrmac->macaddr, zrmac->fwd_info.r_vtep_ip);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
@@ -4949,7 +5258,8 @@ static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n)
if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG)
flags |= DPLANE_NTF_ROUTER;
- dplane_neigh_add(zl3vni->svi_if, &n->ip, &n->emac, flags);
+ dplane_rem_neigh_add(zl3vni->svi_if, &n->ip, &n->emac, flags,
+ false /*was_static*/);
return ret;
}
@@ -4966,7 +5276,7 @@ static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n)
if (!zl3vni->svi_if || !if_is_operative(zl3vni->svi_if))
return 0;
- dplane_neigh_delete(zl3vni->svi_if, &n->ip);
+ dplane_rem_neigh_delete(zl3vni->svi_if, &n->ip);
return 0;
}
@@ -5110,7 +5420,7 @@ static void *zl3vni_alloc(void *p)
/*
* Look up L3 VNI hash entry.
*/
-static zebra_l3vni_t *zl3vni_lookup(vni_t vni)
+zebra_l3vni_t *zl3vni_lookup(vni_t vni)
{
zebra_l3vni_t tmp_l3vni;
zebra_l3vni_t *zl3vni = NULL;
@@ -5179,22 +5489,14 @@ static int zl3vni_del(zebra_l3vni_t *zl3vni)
return 0;
}
-static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
- void *_zl3vni,
- void **_pifp)
+struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
{
- struct zebra_ns *zns = ns->info;
- zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)_zl3vni;
+ struct zebra_ns *zns = NULL;
struct route_node *rn = NULL;
struct interface *ifp = NULL;
- struct zebra_vrf *zvrf;
-
- zvrf = zebra_vrf_get_evpn();
-
- if (!zvrf)
- return NS_WALK_STOP;
/* loop through all vxlan-interface */
+ zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
struct zebra_if *zif = NULL;
@@ -5209,38 +5511,13 @@ static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
continue;
vxl = &zif->l2info.vxl;
- if (vxl->vni != zl3vni->vni)
- continue;
-
- /* link of VXLAN interface should be in zebra_evpn_vrf */
- if (zvrf->zns->ns_id != vxl->link_nsid) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Intf %s(%u) VNI %u, link not in same namespace than BGP EVPN core instance ",
- ifp->name, ifp->ifindex, vxl->vni);
- continue;
+ if (vxl->vni == zl3vni->vni) {
+ zl3vni->local_vtep_ip = vxl->vtep_ip;
+ return ifp;
}
-
-
- zl3vni->local_vtep_ip = vxl->vtep_ip;
- if (_pifp)
- *_pifp = (void *)ifp;
- return NS_WALK_STOP;
}
- return NS_WALK_CONTINUE;
-}
-
-struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
-{
- struct interface **p_ifp;
- struct interface *ifp = NULL;
-
- p_ifp = &ifp;
-
- ns_walk_func(zl3vni_map_to_vxlan_if_ns,
- (void *)zl3vni, (void **)p_ifp);
- return ifp;
+ return NULL;
}
struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni)
@@ -5525,7 +5802,7 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
zlog_debug("Del L2-VNI %u - transition to L3-VNI", vni);
/* Delete VNI from BGP. */
- zvni_send_del_to_client(zvni->vni);
+ zvni_send_del_to_client(zvni);
/* Free up all neighbors and MAC, if any. */
zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
@@ -5633,6 +5910,1167 @@ static int zebra_vxlan_readd_remote_rmac(zebra_l3vni_t *zl3vni,
return 0;
}
+/**************************** SYNC MAC handling *****************************/
+/* if the mac has been added of a mac-route from the peer
+ * or if it is being referenced by a neigh added by the
+ * peer we cannot let it age out i.e. we set the static bit
+ * in the dataplane
+ */
+static inline bool zebra_vxlan_mac_is_static(zebra_mac_t *mac)
+{
+ return ((mac->flags & ZEBRA_MAC_ALL_PEER_FLAGS) ||
+ mac->sync_neigh_cnt);
+}
+
+/* mac needs to be locally active or active on an ES peer */
+static inline bool zebra_vxlan_mac_is_ready_for_bgp(uint32_t flags)
+{
+ return (flags & ZEBRA_MAC_LOCAL) &&
+ (!(flags & ZEBRA_MAC_LOCAL_INACTIVE) ||
+ (flags & ZEBRA_MAC_ES_PEER_ACTIVE));
+}
+
+/* program sync mac flags in the dataplane */
+void zebra_vxlan_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
+ bool force_clear_static, const char *caller)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ struct interface *ifp;
+ bool sticky;
+ bool set_static;
+ zebra_vni_t *zvni = mac->zvni;
+ vlanid_t vid;
+ struct zebra_if *zif;
+ struct interface *br_ifp;
+
+ /* get the access vlan from the vxlan_device */
+ zebra_vxlan_mac_get_access_info(mac,
+ &ifp, &vid);
+
+ if (!ifp) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("%s: dp-install sync-mac vni %u mac %s es %s 0x%x %sskipped, no access-port",
+ caller,
+ zvni->vni,
+ prefix_mac2str(&mac->macaddr, macbuf,
+ sizeof(macbuf)),
+ mac->es ?
+ mac->es->esi_str : "-",
+ mac->flags,
+ set_inactive ? "inactive " : "");
+ return;
+ }
+
+ zif = ifp->info;
+ br_ifp = zif->brslave_info.br_if;
+ if (!br_ifp) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("%s: dp-install sync-mac vni %u mac %s es %s 0x%x %sskipped, no br",
+ caller,
+ zvni->vni,
+ prefix_mac2str(&mac->macaddr, macbuf,
+ sizeof(macbuf)),
+ mac->es ?
+ mac->es->esi_str : "-",
+ mac->flags,
+ set_inactive ? "inactive " : "");
+ return;
+ }
+
+ sticky = !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+ if (force_clear_static)
+ set_static = false;
+ else
+ set_static = zebra_vxlan_mac_is_static(mac);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("dp-install sync-mac vni %u mac %s es %s 0x%x %s%s",
+ zvni->vni,
+ prefix_mac2str(&mac->macaddr, macbuf,
+ sizeof(macbuf)),
+ mac->es ?
+ mac->es->esi_str : "-", mac->flags,
+ set_static ? "static " : "",
+ set_inactive ? "inactive " : "");
+
+ dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky,
+ set_static, set_inactive);
+
+}
+
+static void zebra_vxlan_mac_send_add_del_to_client(zebra_mac_t *mac,
+ bool old_bgp_ready, bool new_bgp_ready)
+{
+ if (new_bgp_ready)
+ zvni_mac_send_add_to_client(mac->zvni->vni,
+ &mac->macaddr, mac->flags,
+ mac->loc_seq, mac->es);
+ else if (old_bgp_ready)
+ zvni_mac_send_del_to_client(mac->zvni->vni,
+ &mac->macaddr, mac->flags,
+ true /* force */);
+}
+
+/* MAC hold timer is used to age out peer-active flag.
+ *
+ * During this wait time we expect the dataplane component or an
+ * external neighmgr daemon to probe existing hosts to independently
+ * establish their presence on the ES.
+ */
+static int zebra_vxlan_mac_hold_exp_cb(struct thread *t)
+{
+ zebra_mac_t *mac;
+ bool old_bgp_ready;
+ bool new_bgp_ready;
+ bool old_static;
+ bool new_static;
+ char macbuf[ETHER_ADDR_STRLEN];
+
+ mac = THREAD_ARG(t);
+ /* the purpose of the hold timer is to age out the peer-active
+ * flag
+ */
+ if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
+ return 0;
+
+ old_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
+ old_static = zebra_vxlan_mac_is_static(mac);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
+ new_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
+ new_static = zebra_vxlan_mac_is_static(mac);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("sync-mac vni %u mac %s es %s 0x%x hold expired",
+ mac->zvni->vni,
+ prefix_mac2str(&mac->macaddr, macbuf,
+ sizeof(macbuf)),
+ mac->es ?
+ mac->es->esi_str : "-",
+ mac->flags);
+
+ /* re-program the local mac in the dataplane if the mac is no
+ * longer static
+ */
+ if (old_static != new_static)
+ zebra_vxlan_sync_mac_dp_install(mac, false /* set_inactive */,
+ false /* force_clear_static */, __func__);
+
+ /* inform bgp if needed */
+ if (old_bgp_ready != new_bgp_ready)
+ zebra_vxlan_mac_send_add_del_to_client(mac,
+ old_bgp_ready, new_bgp_ready);
+
+ return 0;
+}
+
+static inline void zebra_vxlan_mac_start_hold_timer(zebra_mac_t *mac)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+
+ if (mac->hold_timer)
+ return;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("sync-mac vni %u mac %s es %s 0x%x hold started",
+ mac->zvni->vni,
+ prefix_mac2str(&mac->macaddr, macbuf,
+ sizeof(macbuf)),
+ mac->es ?
+ mac->es->esi_str : "-",
+ mac->flags);
+ thread_add_timer(zrouter.master,
+ zebra_vxlan_mac_hold_exp_cb,
+ mac, zmh_info->mac_hold_time,
+ &mac->hold_timer);
+}
+
+static inline void zebra_vxlan_mac_stop_hold_timer(zebra_mac_t *mac)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+
+ if (!mac->hold_timer)
+ return;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("sync-mac vni %u mac %s es %s 0x%x hold stopped",
+ mac->zvni->vni,
+ prefix_mac2str(&mac->macaddr, macbuf,
+ sizeof(macbuf)),
+ mac->es ?
+ mac->es->esi_str : "-",
+ mac->flags);
+ THREAD_OFF(mac->hold_timer);
+}
+
+static inline void zebra_vxlan_mac_clear_sync_info(zebra_mac_t *mac)
+{
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_PEER_FLAGS);
+ zebra_vxlan_mac_stop_hold_timer(mac);
+}
+
+static void zebra_vxlan_sync_mac_del(zebra_mac_t *mac)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ bool old_static;
+ bool new_static;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("sync-mac del vni %u mac %s es %s seq %d f 0x%x",
+ mac->zvni->vni,
+ prefix_mac2str(&mac->macaddr,
+ macbuf, sizeof(macbuf)),
+ mac->es ? mac->es->esi_str : "-",
+ mac->loc_seq,
+ mac->flags);
+ old_static = zebra_vxlan_mac_is_static(mac);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
+ zebra_vxlan_mac_start_hold_timer(mac);
+ new_static = zebra_vxlan_mac_is_static(mac);
+
+ if (old_static != new_static)
+ /* program the local mac in the kernel */
+ zebra_vxlan_sync_mac_dp_install(mac, false /* set_inactive */,
+ false /* force_clear_static */, __func__);
+}
+
+static inline bool zebra_vxlan_mac_is_bgp_seq_ok(zebra_vni_t *zvni,
+ zebra_mac_t *mac, uint32_t seq, uint16_t ipa_len,
+ struct ipaddr *ipaddr)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ uint32_t tmp_seq;
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
+ tmp_seq = mac->loc_seq;
+ else
+ tmp_seq = mac->rem_seq;
+
+ if (seq < tmp_seq) {
+ /* if the mac was never advertised to bgp we must accept
+ * whatever sequence number bgp sends
+ * XXX - check with Vivek
+ */
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) &&
+ !zebra_vxlan_mac_is_ready_for_bgp(mac->flags)) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("sync-macip accept vni %u mac %s%s%s lower seq %u f 0x%x",
+ zvni->vni,
+ prefix_mac2str(&mac->macaddr,
+ macbuf, sizeof(macbuf)),
+ ipa_len ? " IP " : "",
+ ipa_len ?
+ ipaddr2str(ipaddr,
+ ipbuf, sizeof(ipbuf)) : "",
+ tmp_seq, mac->flags);
+ return true;
+ }
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("sync-macip ignore vni %u mac %s%s%s as existing has higher seq %u f 0x%x",
+ zvni->vni,
+ prefix_mac2str(&mac->macaddr,
+ macbuf, sizeof(macbuf)),
+ ipa_len ? " IP " : "",
+ ipa_len ?
+ ipaddr2str(ipaddr,
+ ipbuf, sizeof(ipbuf)) : "",
+ tmp_seq, mac->flags);
+ return false;
+ }
+
+ return true;
+}
+
+/* sync-path that is active on an ES peer */
+static zebra_mac_t *zebra_vxlan_proc_sync_mac_update(zebra_vni_t *zvni,
+ struct ethaddr *macaddr, uint16_t ipa_len,
+ struct ipaddr *ipaddr, uint8_t flags,
+ uint32_t seq, esi_t *esi,
+ struct sync_mac_ip_ctx *ctx)
+{
+ zebra_mac_t *mac;
+ bool inform_bgp = false;
+ bool inform_dataplane = false;
+ bool seq_change = false;
+ bool es_change = false;
+ uint32_t tmp_seq;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ bool old_local = false;
+ bool old_bgp_ready;
+ bool new_bgp_ready;
+
+ mac = zvni_mac_lookup(zvni, macaddr);
+ if (!mac) {
+ /* if it is a new local path we need to inform both
+ * the control protocol and the data-plane
+ */
+ inform_bgp = true;
+ inform_dataplane = true;
+ ctx->mac_created = true;
+ ctx->mac_inactive = true;
+
+ /* create the MAC and associate it with the dest ES */
+ mac = zvni_mac_add(zvni, macaddr);
+ zebra_evpn_es_mac_ref(mac, esi);
+
+ /* local mac activated by an ES peer */
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ /* if mac-only route setup peer flags */
+ if (!ipa_len) {
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
+ SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
+ else
+ SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
+ }
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
+ old_bgp_ready = false;
+ new_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
+ } else {
+ uint32_t old_flags;
+ uint32_t new_flags;
+ bool old_static;
+ bool new_static;
+ bool sticky;
+ bool remote_gw;
+
+ old_flags = mac->flags;
+ sticky = !!CHECK_FLAG(old_flags, ZEBRA_MAC_STICKY);
+ remote_gw = !!CHECK_FLAG(old_flags, ZEBRA_MAC_REMOTE_DEF_GW);
+ if (sticky || remote_gw) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("Ignore sync-macip vni %u mac %s%s%s%s%s",
+ zvni->vni,
+ prefix_mac2str(macaddr,
+ macbuf, sizeof(macbuf)),
+ ipa_len ? " IP " : "",
+ ipa_len ?
+ ipaddr2str(ipaddr, ipbuf,
+ sizeof(ipbuf)) : "",
+ sticky ? " sticky" : "",
+ remote_gw ? " remote_gw" : "");
+ ctx->ignore_macip = true;
+ return NULL;
+ }
+ if (!zebra_vxlan_mac_is_bgp_seq_ok(zvni, mac, seq,
+ ipa_len, ipaddr)) {
+ ctx->ignore_macip = true;
+ return NULL;
+ }
+
+ old_local = !!CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL);
+ old_static = zebra_vxlan_mac_is_static(mac);
+
+ /* re-build the mac flags */
+ new_flags = 0;
+ SET_FLAG(new_flags, ZEBRA_MAC_LOCAL);
+ /* retain old local activity flag */
+ if (old_flags & ZEBRA_MAC_LOCAL) {
+ new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE);
+ } else {
+ new_flags |= ZEBRA_MAC_LOCAL_INACTIVE;
+ ctx->mac_inactive = true;
+ }
+ if (ipa_len) {
+ /* if mac-ip route do NOT update the peer flags
+ * i.e. retain only flags as is
+ */
+ new_flags |= (old_flags & ZEBRA_MAC_ALL_PEER_FLAGS);
+ } else {
+ /* if mac-only route update peer flags */
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
+ SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_PROXY);
+ /* if the mac was peer-active previously we
+ * need to keep the flag and start the
+ * holdtimer on it. the peer-active flag is
+ * cleared on holdtimer expiry.
+ */
+ if (CHECK_FLAG(old_flags,
+ ZEBRA_MAC_ES_PEER_ACTIVE)) {
+ SET_FLAG(new_flags,
+ ZEBRA_MAC_ES_PEER_ACTIVE);
+ zebra_vxlan_mac_start_hold_timer(mac);
+ }
+ } else {
+ SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_ACTIVE);
+ /* stop hold timer if a peer has verified
+ * reachability
+ */
+ zebra_vxlan_mac_stop_hold_timer(mac);
+ }
+ }
+ mac->rem_seq = 0;
+ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+ mac->flags = new_flags;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC &&
+ (old_flags != new_flags))
+ zlog_debug("sync-mac vni %u mac %s old_f 0x%x new_f 0x%x",
+ zvni->vni,
+ prefix_mac2str(macaddr,
+ macbuf, sizeof(macbuf)),
+ old_flags, mac->flags);
+
+ /* update es */
+ es_change = zebra_evpn_es_mac_ref(mac, esi);
+ /* if mac dest change - inform both sides */
+ if (es_change) {
+ inform_bgp = true;
+ inform_dataplane = true;
+ ctx->mac_inactive = true;
+ }
+ /* if peer-flag is being set notify dataplane that the
+ * entry must not be expired because of local inactivity
+ */
+ new_static = zebra_vxlan_mac_is_static(mac);
+ if (old_static != new_static)
+ inform_dataplane = true;
+
+ old_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(old_flags);
+ new_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
+ if (old_bgp_ready != new_bgp_ready)
+ inform_bgp = true;
+ }
+
+
+ /* update sequence number; if that results in a new local sequence
+ * inform bgp
+ */
+ tmp_seq = MAX(mac->loc_seq, seq);
+ if (tmp_seq != mac->loc_seq) {
+ mac->loc_seq = tmp_seq;
+ seq_change = true;
+ inform_bgp = true;
+ }
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("sync-mac %s vni %u mac %s es %s seq %d f 0x%x%s%s",
+ ctx->mac_created ?
+ "created" : "updated",
+ zvni->vni,
+ prefix_mac2str(macaddr,
+ macbuf, sizeof(macbuf)),
+ mac->es ? mac->es->esi_str : "-",
+ mac->loc_seq, mac->flags,
+ inform_bgp ? " inform_bgp" : "",
+ inform_dataplane ? " inform_dp" : "");
+
+ if (inform_bgp)
+ zebra_vxlan_mac_send_add_del_to_client(mac,
+ old_bgp_ready, new_bgp_ready);
+
+ /* neighs using the mac may need to be re-sent to
+ * bgp with updated info
+ */
+ if (seq_change || es_change || !old_local)
+ zvni_process_neigh_on_local_mac_change(zvni, mac,
+ seq_change, es_change);
+
+ if (inform_dataplane) {
+ if (ipa_len)
+ /* if the mac is being created as a part of MAC-IP
+ * route wait for the neigh to be updated or
+ * created before programming the mac
+ */
+ ctx->mac_dp_update_deferred = true;
+ else
+ /* program the local mac in the kernel. when the ES
+ * change we need to force the dataplane to reset
+ * the activity as we are yet to establish activity
+ * locally
+ */
+ zebra_vxlan_sync_mac_dp_install(mac,
+ ctx->mac_inactive,
+ false /* force_clear_static */,
+ __func__);
+ }
+
+ return mac;
+}
+
+/**************************** SYNC neigh handling **************************/
+static inline bool zebra_vxlan_neigh_is_static(zebra_neigh_t *neigh)
+{
+ return !!(neigh->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS);
+}
+
+static inline bool zebra_vxlan_neigh_is_ready_for_bgp(zebra_neigh_t *n)
+{
+ bool mac_ready;
+ bool neigh_ready;
+
+ mac_ready = !!(n->mac->flags & ZEBRA_MAC_LOCAL);
+ neigh_ready = ((n->flags & ZEBRA_NEIGH_LOCAL) &&
+ IS_ZEBRA_NEIGH_ACTIVE(n) &&
+ (!(n->flags & ZEBRA_NEIGH_LOCAL_INACTIVE) ||
+ (n->flags & ZEBRA_NEIGH_ES_PEER_ACTIVE))) ?
+ true : false;
+
+ return mac_ready && neigh_ready;
+}
+
+static void zebra_vxlan_sync_neigh_dp_install(zebra_neigh_t *n,
+ bool set_inactive, bool force_clear_static, const char *caller)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ struct zebra_ns *zns;
+ struct interface *ifp;
+ bool set_static;
+ bool set_router;
+
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ ifp = if_lookup_by_index_per_ns(zns, n->ifindex);
+ if (!ifp) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("%s: dp-install sync-neigh vni %u ip %s mac %s if %d f 0x%x skipped",
+ caller, n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ n->ifindex, n->flags);
+ return;
+ }
+
+ if (force_clear_static)
+ set_static = false;
+ else
+ set_static = zebra_vxlan_neigh_is_static(n);
+
+ set_router = !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+
+ /* XXX - this will change post integration with the new kernel */
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE))
+ set_inactive = true;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("%s: dp-install sync-neigh vni %u ip %s mac %s if %s(%d) f 0x%x%s%s%s",
+ caller, n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ ifp->name, n->ifindex, n->flags,
+ set_router ? " router":"",
+ set_static ? " static":"",
+ set_inactive ? " inactive":"");
+ dplane_local_neigh_add(ifp, &n->ip,
+ &n->emac, set_router, set_static, set_inactive);
+}
+
+static void zebra_vxlan_neigh_send_add_del_to_client(zebra_neigh_t *n,
+ bool old_bgp_ready, bool new_bgp_ready)
+{
+ if (new_bgp_ready)
+ zvni_neigh_send_add_to_client(n->zvni->vni, &n->ip,
+ &n->emac, n->mac, n->flags, n->loc_seq);
+ else if (old_bgp_ready)
+ zvni_neigh_send_del_to_client(n->zvni->vni, &n->ip,
+ &n->emac, n->flags, n->state, true /*force*/);
+}
+
+/* if the static flag associated with the neigh changes we need
+ * to update the sync-neigh references against the MAC
+ * and inform the dataplane about the static flag changes.
+ */
+static void zebra_vxlan_sync_neigh_static_chg(zebra_neigh_t *n,
+ bool old_n_static, bool new_n_static,
+ bool defer_n_dp, bool defer_mac_dp,
+ const char *caller)
+{
+ zebra_mac_t *mac = n->mac;
+ bool old_mac_static;
+ bool new_mac_static;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ if (old_n_static == new_n_static)
+ return;
+
+ /* update the neigh sync references in the dataplane. if
+ * the neigh is in the middle of updates the caller can
+ * request for a defer
+ */
+ if (!defer_n_dp)
+ zebra_vxlan_sync_neigh_dp_install(n, false /* set_inactive */,
+ false /* force_clear_static */, __func__);
+
+ if (!mac)
+ return;
+
+ /* update the mac sync ref cnt */
+ old_mac_static = zebra_vxlan_mac_is_static(mac);
+ if (new_n_static) {
+ ++mac->sync_neigh_cnt;
+ } else if (old_n_static) {
+ if (mac->sync_neigh_cnt)
+ --mac->sync_neigh_cnt;
+ }
+ new_mac_static = zebra_vxlan_mac_is_static(mac);
+
+ /* update the mac sync references in the dataplane */
+ if ((old_mac_static != new_mac_static) && !defer_mac_dp)
+ zebra_vxlan_sync_mac_dp_install(mac,
+ false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh ref-chg vni %u ip %s mac %s f 0x%x %d%s%s%s%s by %s",
+ n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ n->flags, mac->sync_neigh_cnt,
+ old_n_static ? " old_n_static" : "",
+ new_n_static ? " new_n_static" : "",
+ old_mac_static ? " old_mac_static" : "",
+ new_mac_static ? " new_mac_static" : "",
+ caller);
+}
+
+/* Neigh hold timer is used to age out peer-active flag.
+ *
+ * During this wait time we expect the dataplane component or an
+ * external neighmgr daemon to probe existing hosts to independently
+ * establish their presence on the ES.
+ */
+static int zebra_vxlan_neigh_hold_exp_cb(struct thread *t)
+{
+ zebra_neigh_t *n;
+ bool old_bgp_ready;
+ bool new_bgp_ready;
+ bool old_n_static;
+ bool new_n_static;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ n = THREAD_ARG(t);
+ /* the purpose of the hold timer is to age out the peer-active
+ * flag
+ */
+ if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
+ return 0;
+
+ old_bgp_ready = zebra_vxlan_neigh_is_ready_for_bgp(n);
+ old_n_static = zebra_vxlan_neigh_is_static(n);
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
+ new_bgp_ready = zebra_vxlan_neigh_is_ready_for_bgp(n);
+ new_n_static = zebra_vxlan_neigh_is_static(n);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x hold expired",
+ n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ n->flags);
+
+ /* re-program the local neigh in the dataplane if the neigh is no
+ * longer static
+ */
+ if (old_n_static != new_n_static)
+ zebra_vxlan_sync_neigh_static_chg(n, old_n_static,
+ new_n_static, false /*defer_n_dp*/,
+ false /*defer_mac_dp*/, __func__);
+
+ /* inform bgp if needed */
+ if (old_bgp_ready != new_bgp_ready)
+ zebra_vxlan_neigh_send_add_del_to_client(n,
+ old_bgp_ready, new_bgp_ready);
+
+ return 0;
+}
+
+static inline void zebra_vxlan_neigh_start_hold_timer(zebra_neigh_t *n)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ if (n->hold_timer)
+ return;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x hold start",
+ n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ n->flags);
+ thread_add_timer(zrouter.master,
+ zebra_vxlan_neigh_hold_exp_cb,
+ n, zmh_info->neigh_hold_time,
+ &n->hold_timer);
+}
+
+static inline void zebra_vxlan_neigh_stop_hold_timer(zebra_neigh_t *n)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ if (!n->hold_timer)
+ return;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x hold stop",
+ n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ n->flags);
+ THREAD_OFF(n->hold_timer);
+}
+
+static inline bool zebra_vxlan_neigh_clear_sync_info(zebra_neigh_t *n)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ bool old_n_static = false;
+ bool new_n_static = false;
+
+ if (n->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x clear",
+ n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ n->flags);
+
+ old_n_static = zebra_vxlan_neigh_is_static(n);
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ALL_PEER_FLAGS);
+ new_n_static = zebra_vxlan_neigh_is_static(n);
+ if (old_n_static != new_n_static)
+ zebra_vxlan_sync_neigh_static_chg(n, old_n_static,
+ new_n_static, true /*defer_dp)*/,
+ false/*defer_mac_dp*/, __func__);
+ }
+ zebra_vxlan_neigh_stop_hold_timer(n);
+
+ /* if the neigh static flag changed inform that a dp
+ * re-install maybe needed
+ */
+ return old_n_static != new_n_static;
+}
+
+static void zebra_vxlan_local_neigh_deref_mac(zebra_neigh_t *n,
+ bool send_mac_update)
+{
+ zebra_mac_t *mac = n->mac;
+ zebra_vni_t *zvni = n->zvni;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ bool old_static;
+ bool new_static;
+
+ n->mac = NULL;
+ if (!mac)
+ return;
+
+ if ((n->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS) &&
+ mac->sync_neigh_cnt){
+ old_static = zebra_vxlan_mac_is_static(mac);
+ --mac->sync_neigh_cnt;
+ new_static = zebra_vxlan_mac_is_static(mac);
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh deref mac vni %u ip %s mac %s ref %d",
+ n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf,
+ sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ mac->sync_neigh_cnt);
+ if ((old_static != new_static) && send_mac_update)
+ /* program the local mac in the kernel */
+ zebra_vxlan_sync_mac_dp_install(mac,
+ false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
+ }
+
+ listnode_delete(mac->neigh_list, n);
+ zvni_deref_ip2mac(zvni, mac);
+}
+
+static void zebra_vxlan_local_neigh_ref_mac(zebra_neigh_t *n,
+ struct ethaddr *macaddr, zebra_mac_t *mac,
+ bool send_mac_update)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ bool old_static;
+ bool new_static;
+
+ memcpy(&n->emac, macaddr, ETH_ALEN);
+ n->mac = mac;
+
+ /* Link to new MAC */
+ if (!mac)
+ return;
+
+ listnode_add_sort(mac->neigh_list, n);
+ if (n->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS) {
+ old_static = zebra_vxlan_mac_is_static(mac);
+ ++mac->sync_neigh_cnt;
+ new_static = zebra_vxlan_mac_is_static(mac);
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh ref mac vni %u ip %s mac %s ref %d",
+ n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf,
+ sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ mac->sync_neigh_cnt);
+ if ((old_static != new_static) && send_mac_update)
+ /* program the local mac in the kernel */
+ zebra_vxlan_sync_mac_dp_install(mac,
+ false /*set_inactive*/,
+ false /*force_clear_static*/,
+ __func__);
+ }
+}
+
+static inline bool zebra_vxlan_neigh_is_bgp_seq_ok(zebra_vni_t *zvni,
+ zebra_neigh_t *n, struct ethaddr *macaddr, uint32_t seq)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ uint32_t tmp_seq;
+
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
+ tmp_seq = n->loc_seq;
+ else
+ tmp_seq = n->rem_seq;
+
+ if (seq < tmp_seq) {
+ /* if the neigh was never advertised to bgp we must accept
+ * whatever sequence number bgp sends
+ * XXX - check with Vivek
+ */
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) &&
+ !zebra_vxlan_neigh_is_ready_for_bgp(n)) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-macip accept vni %u mac %s IP %s lower seq %u f 0x%x",
+ zvni->vni,
+ prefix_mac2str(macaddr,
+ macbuf, sizeof(macbuf)),
+ ipaddr2str(&n->ip,
+ ipbuf, sizeof(ipbuf)),
+ tmp_seq, n->flags);
+ return true;
+ }
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-macip ignore vni %u mac %s IP %s as existing has higher seq %u f 0x%x",
+ zvni->vni,
+ prefix_mac2str(macaddr,
+ macbuf, sizeof(macbuf)),
+ ipaddr2str(&n->ip,
+ ipbuf, sizeof(ipbuf)),
+ tmp_seq, n->flags);
+ return false;
+ }
+
+ return true;
+}
+
+static void zebra_vxlan_sync_neigh_del(zebra_neigh_t *n)
+{
+ bool old_n_static;
+ bool new_n_static;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh del vni %u ip %s mac %s f 0x%x",
+ n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ n->flags);
+
+ old_n_static = zebra_vxlan_neigh_is_static(n);
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
+ zebra_vxlan_neigh_start_hold_timer(n);
+ new_n_static = zebra_vxlan_neigh_is_static(n);
+
+ if (old_n_static != new_n_static)
+ zebra_vxlan_sync_neigh_static_chg(n, old_n_static,
+ new_n_static, false /*defer-dp*/,
+ false /*defer_mac_dp*/, __func__);
+}
+
+static zebra_neigh_t *zebra_vxlan_proc_sync_neigh_update(zebra_vni_t *zvni,
+ zebra_neigh_t *n, uint16_t ipa_len,
+ struct ipaddr *ipaddr, uint8_t flags, uint32_t seq,
+ esi_t *esi, struct sync_mac_ip_ctx *ctx)
+{
+ struct interface *ifp = NULL;
+ bool is_router;
+ zebra_mac_t *mac = ctx->mac;
+ uint32_t tmp_seq;
+ bool old_router = false;
+ bool old_bgp_ready = false;
+ bool new_bgp_ready;
+ bool inform_dataplane = false;
+ bool inform_bgp = false;
+ bool old_mac_static;
+ bool new_mac_static;
+ bool set_dp_inactive = false;
+ struct zebra_if *zif;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ bool created;
+ ifindex_t ifindex = 0;
+
+ /* locate l3-svi */
+ zif = zvni->vxlan_if->info;
+ if (zif) {
+ struct zebra_l2info_vxlan *vxl;
+
+ vxl = &zif->l2info.vxl;
+ ifp = zvni_map_to_svi(vxl->access_vlan,
+ zif->brslave_info.br_if);
+ if (ifp)
+ ifindex = ifp->ifindex;
+ }
+
+ is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
+ old_mac_static = zebra_vxlan_mac_is_static(mac);
+
+ if (!n) {
+ uint32_t n_flags = 0;
+
+ /* New neighbor - create */
+ SET_FLAG(n_flags, ZEBRA_NEIGH_LOCAL);
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
+ SET_FLAG(n_flags, ZEBRA_NEIGH_ES_PEER_PROXY);
+ else
+ SET_FLAG(n_flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
+ SET_FLAG(n_flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
+
+ n = zvni_neigh_add(zvni, ipaddr, &mac->macaddr, mac,
+ n_flags);
+ n->ifindex = ifindex;
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+
+ created = true;
+ inform_dataplane = true;
+ inform_bgp = true;
+ set_dp_inactive = true;
+ } else {
+ bool mac_change;
+ uint32_t old_flags = n->flags;
+ bool old_n_static;
+ bool new_n_static;
+
+ created = false;
+ old_n_static = zebra_vxlan_neigh_is_static(n);
+ old_bgp_ready = zebra_vxlan_neigh_is_ready_for_bgp(n);
+ old_router = !!CHECK_FLAG(n->flags,
+ ZEBRA_NEIGH_ROUTER_FLAG);
+
+ mac_change = !!memcmp(&n->emac, &mac->macaddr, ETH_ALEN);
+
+ /* deref and clear old info */
+ if (mac_change) {
+ if (old_bgp_ready) {
+ zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
+ &n->emac, n->flags, n->state,
+ false /*force*/);
+ old_bgp_ready = false;
+ }
+ if (n->mac)
+ zebra_vxlan_local_neigh_deref_mac(n,
+ false /*send_mac_update*/);
+ }
+ /* clear old fwd info */
+ n->rem_seq = 0;
+ n->r_vtep_ip.s_addr = 0;
+
+ /* setup new flags */
+ n->flags = 0;
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ /* retain activity flag if the neigh was
+ * previously local
+ */
+ if (old_flags & ZEBRA_NEIGH_LOCAL) {
+ n->flags |= (old_flags & ZEBRA_NEIGH_LOCAL_INACTIVE);
+ } else {
+ inform_dataplane = true;
+ set_dp_inactive = true;
+ n->flags |= ZEBRA_NEIGH_LOCAL_INACTIVE;
+ }
+
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
+ else
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
+
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
+ /* if the neigh was peer-active previously we
+ * need to keep the flag and start the
+ * holdtimer on it. the peer-active flag is
+ * cleared on holdtimer expiry.
+ */
+ if (CHECK_FLAG(old_flags,
+ ZEBRA_NEIGH_ES_PEER_ACTIVE)) {
+ SET_FLAG(n->flags,
+ ZEBRA_NEIGH_ES_PEER_ACTIVE);
+ zebra_vxlan_neigh_start_hold_timer(n);
+ }
+ } else {
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
+ /* stop hold timer if a peer has verified
+ * reachability
+ */
+ zebra_vxlan_neigh_stop_hold_timer(n);
+ }
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH &&
+ (old_flags != n->flags))
+ zlog_debug("sync-neigh vni %u ip %s mac %s old_f 0x%x new_f 0x%x",
+ n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ old_flags, n->flags);
+
+ new_n_static = zebra_vxlan_neigh_is_static(n);
+ if (mac_change) {
+ set_dp_inactive = true;
+ n->flags |= ZEBRA_NEIGH_LOCAL_INACTIVE;
+ inform_dataplane = true;
+ zebra_vxlan_local_neigh_ref_mac(n, &mac->macaddr,
+ mac, false /*send_mac_update*/);
+ } else if (old_n_static != new_n_static) {
+ inform_dataplane = true;
+ /* if static flags have changed without a mac change
+ * we need to create the correct sync-refs against
+ * the existing mac
+ */
+ zebra_vxlan_sync_neigh_static_chg(n,
+ old_n_static, new_n_static,
+ true /*defer_dp*/, true /*defer_mac_dp*/,
+ __func__);
+ }
+
+ /* Update the forwarding info. */
+ if (n->ifindex != ifindex) {
+ n->ifindex = ifindex;
+ inform_dataplane = true;
+ }
+ }
+
+ /* update the neigh seq. we don't bother with the mac seq as
+ * sync_mac_update already took care of that
+ */
+ tmp_seq = MAX(n->loc_seq, seq);
+ if (tmp_seq != n->loc_seq) {
+ n->loc_seq = tmp_seq;
+ inform_bgp = true;
+ }
+
+ /* Mark Router flag (R-bit) */
+ if (is_router)
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+ else
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+
+ if (old_router != is_router)
+ inform_dataplane = true;
+
+ new_bgp_ready = zebra_vxlan_neigh_is_ready_for_bgp(n);
+ if (old_bgp_ready != new_bgp_ready)
+ inform_bgp = true;
+
+ new_mac_static = zebra_vxlan_mac_is_static(mac);
+ if ((old_mac_static != new_mac_static) ||
+ ctx->mac_dp_update_deferred)
+ zebra_vxlan_sync_mac_dp_install(mac,
+ ctx->mac_inactive,
+ false /* force_clear_static */,
+ __func__);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh %s vni %u ip %s mac %s if %s(%d) seq %d f 0x%x%s%s",
+ created ?
+ "created" : "updated",
+ n->zvni->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ ifp ? ifp->name : "", ifindex,
+ n->loc_seq, n->flags,
+ inform_bgp ? " inform_bgp" : "",
+ inform_dataplane ? " inform_dp" : "");
+
+ if (inform_dataplane)
+ zebra_vxlan_sync_neigh_dp_install(n, set_dp_inactive,
+ false /* force_clear_static */, __func__);
+
+ if (inform_bgp)
+ zebra_vxlan_neigh_send_add_del_to_client(n,
+ old_bgp_ready, new_bgp_ready);
+
+ return n;
+}
+
+static void zebra_vxlan_process_sync_macip_add(zebra_vni_t *zvni,
+ struct ethaddr *macaddr,
+ uint16_t ipa_len,
+ struct ipaddr *ipaddr,
+ uint8_t flags,
+ uint32_t seq,
+ esi_t *esi)
+{
+ struct sync_mac_ip_ctx ctx;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ bool sticky;
+ bool remote_gw;
+ zebra_neigh_t *n = NULL;
+
+ sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+ remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+ /* if sticky or remote-gw ignore updates from the peer */
+ if (sticky || remote_gw) {
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_NEIGH ||
+ IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("Ignore sync-macip vni %u mac %s%s%s%s%s",
+ zvni->vni,
+ prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
+ ipa_len ? " IP " : "",
+ ipa_len ?
+ ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "",
+ sticky ? " sticky" : "",
+ remote_gw ? " remote_gw" : "");
+ return;
+ }
+
+ if (ipa_len) {
+ n = zvni_neigh_lookup(zvni, ipaddr);
+ if (n &&
+ !zebra_vxlan_neigh_is_bgp_seq_ok(zvni,
+ n, macaddr, seq))
+ return;
+ }
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.mac = zebra_vxlan_proc_sync_mac_update(zvni, macaddr, ipa_len,
+ ipaddr, flags, seq, esi, &ctx);
+ if (ctx.ignore_macip || !ctx.mac || !ipa_len)
+ return;
+
+ zebra_vxlan_proc_sync_neigh_update(zvni, n, ipa_len,
+ ipaddr, flags, seq, esi, &ctx);
+}
+
+/************************** remote mac-ip handling **************************/
/* Process a remote MACIP add from BGP. */
static void process_remote_macip_add(vni_t vni,
struct ethaddr *macaddr,
@@ -5640,7 +7078,8 @@ static void process_remote_macip_add(vni_t vni,
struct ipaddr *ipaddr,
uint8_t flags,
uint32_t seq,
- struct in_addr vtep_ip)
+ struct in_addr vtep_ip,
+ esi_t *esi)
{
zebra_vni_t *zvni;
zebra_vtep_t *zvtep;
@@ -5658,6 +7097,8 @@ static void process_remote_macip_add(vni_t vni,
bool is_router;
bool do_dad = false;
bool is_dup_detect = false;
+ esi_t *old_esi;
+ bool old_static = false;
/* Locate VNI hash entry - expected to exist. */
zvni = zvni_lookup(vni);
@@ -5678,22 +7119,36 @@ static void process_remote_macip_add(vni_t vni,
return;
}
+ /* Type-2 routes from another PE can be interpreted as remote or
+ * SYNC based on the destination ES -
+ * SYNC - if ES is local
+ * REMOTE - if ES is not local
+ */
+ if (flags & ZEBRA_MACIP_TYPE_SYNC_PATH) {
+ zebra_vxlan_process_sync_macip_add(zvni, macaddr, ipa_len,
+ ipaddr, flags, seq, esi);
+ return;
+ }
+
/* The remote VTEP specified should normally exist, but it is
* possible that when peering comes up, peer may advertise MACIP
* routes before advertising type-3 routes.
*/
- zvtep = zvni_vtep_find(zvni, &vtep_ip);
- if (!zvtep) {
- zvtep = zvni_vtep_add(zvni, &vtep_ip, VXLAN_FLOOD_DISABLED);
+ if (vtep_ip.s_addr) {
+ zvtep = zvni_vtep_find(zvni, &vtep_ip);
if (!zvtep) {
- flog_err(
- EC_ZEBRA_VTEP_ADD_FAILED,
- "Failed to add remote VTEP, VNI %u zvni %p upon remote MACIP ADD",
- vni, zvni);
- return;
- }
+ zvtep = zvni_vtep_add(zvni, &vtep_ip,
+ VXLAN_FLOOD_DISABLED);
+ if (!zvtep) {
+ flog_err(
+ EC_ZEBRA_VTEP_ADD_FAILED,
+ "Failed to add remote VTEP, VNI %u zvni %p upon remote MACIP ADD",
+ vni, zvni);
+ return;
+ }
- zvni_vtep_install(zvni, zvtep);
+ zvni_vtep_install(zvni, zvtep);
+ }
}
sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
@@ -5716,10 +7171,12 @@ static void process_remote_macip_add(vni_t vni,
return;
}
- zvrf = zebra_vrf_get_evpn();
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
if (!zvrf)
return;
+ old_esi = (mac && mac->es) ? &mac->es->esi : zero_esi;
+
/* check if the remote MAC is unknown or has a change.
* If so, that needs to be updated first. Note that client could
* install MAC and MACIP separately or just install the latter.
@@ -5729,6 +7186,7 @@ static void process_remote_macip_add(vni_t vni,
|| sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)
|| remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)
|| !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)
+ || memcmp(old_esi, esi, sizeof(esi_t))
|| seq != mac->rem_seq)
update_mac = 1;
@@ -5744,10 +7202,14 @@ static void process_remote_macip_add(vni_t vni,
return;
}
+ zebra_evpn_es_mac_ref(mac, esi);
+
/* Is this MAC created for a MACIP? */
if (ipa_len)
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
} else {
+ zebra_evpn_es_mac_ref(mac, esi);
+
/* When host moves but changes its (MAC,IP)
* binding, BGP may install a MACIP entry that
* corresponds to "older" location of the host
@@ -5794,11 +7256,25 @@ static void process_remote_macip_add(vni_t vni,
do_dad = true;
/* Remove local MAC from BGP. */
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
- zvni_mac_send_del_to_client(zvni->vni, macaddr);
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ /* force drop the sync flags */
+ old_static = zebra_vxlan_mac_is_static(mac);
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("sync-mac->remote vni %u mac %s es %s seq %d f 0x%x",
+ zvni->vni,
+ prefix_mac2str(macaddr,
+ buf, sizeof(buf)),
+ mac->es ?
+ mac->es->esi_str : "-",
+ mac->loc_seq,
+ mac->flags);
+ zebra_vxlan_mac_clear_sync_info(mac);
+ zvni_mac_send_del_to_client(zvni->vni, macaddr,
+ mac->flags, false /* force */);
+ }
/* Set "auto" and "remote" forwarding info. */
- UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
mac->fwd_info.r_vtep_ip = vtep_ip;
@@ -5821,7 +7297,7 @@ static void process_remote_macip_add(vni_t vni,
if (!is_dup_detect) {
zvni_process_neigh_on_remote_mac_add(zvni, mac);
/* Install the entry. */
- zvni_mac_install(zvni, mac);
+ zvni_rem_mac_install(zvni, mac, old_static);
}
}
@@ -5836,6 +7312,7 @@ static void process_remote_macip_add(vni_t vni,
/* Reset flag */
do_dad = false;
+ old_static = false;
/* Check if the remote neighbor itself is unknown or has a
* change. If so, create or update and then install the entry.
@@ -5851,7 +7328,7 @@ static void process_remote_macip_add(vni_t vni,
if (update_neigh) {
if (!n) {
- n = zvni_neigh_add(zvni, ipaddr, macaddr);
+ n = zvni_neigh_add(zvni, ipaddr, macaddr, mac, 0);
if (!n) {
zlog_warn(
"Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s",
@@ -5893,22 +7370,31 @@ static void process_remote_macip_add(vni_t vni,
tmp_seq);
return;
}
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ old_static = zebra_vxlan_neigh_is_static(n);
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync->remote neigh vni %u ip %s mac %s seq %d f0x%x",
+ n->zvni->vni,
+ ipaddr2str(&n->ip, buf1,
+ sizeof(buf1)),
+ prefix_mac2str(&n->emac, buf,
+ sizeof(buf)),
+ seq, n->flags);
+ zebra_vxlan_neigh_clear_sync_info(n);
+ if (IS_ZEBRA_NEIGH_ACTIVE(n))
+ zvni_mac_send_del_to_client(zvni->vni,
+ macaddr, mac->flags,
+ false /*force*/);
+ }
if (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0) {
- /* MAC change, send a delete for old
- * neigh if learnt locally.
- */
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) &&
- IS_ZEBRA_NEIGH_ACTIVE(n))
- zvni_neigh_send_del_to_client(
- zvni->vni, &n->ip,
- &n->emac, 0, n->state);
-
/* update neigh list for macs */
old_mac = zvni_mac_lookup(zvni, &n->emac);
if (old_mac) {
listnode_delete(old_mac->neigh_list, n);
+ n->mac = NULL;
zvni_deref_ip2mac(zvni, old_mac);
}
+ n->mac = mac;
listnode_add_sort(mac->neigh_list, n);
memcpy(&n->emac, macaddr, ETH_ALEN);
@@ -5934,7 +7420,7 @@ static void process_remote_macip_add(vni_t vni,
}
/* Set "remote" forwarding info. */
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ALL_LOCAL_FLAGS);
n->r_vtep_ip = vtep_ip;
SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
@@ -5964,7 +7450,7 @@ static void process_remote_macip_add(vni_t vni,
false);
/* Install the entry. */
if (!is_dup_detect)
- zvni_neigh_install(zvni, n);
+ zvni_rem_neigh_install(zvni, n, old_static);
}
zvni_probe_neigh_on_mac_add(zvni, mac);
@@ -5973,6 +7459,32 @@ static void process_remote_macip_add(vni_t vni,
n->rem_seq = seq;
}
+static void zebra_vxlan_rem_mac_del(zebra_vni_t *zvni,
+ zebra_mac_t *mac)
+{
+ zvni_process_neigh_on_remote_mac_del(zvni, mac);
+ /* the remote sequence number in the auto mac entry
+ * needs to be reset to 0 as the mac entry may have
+ * been removed on all VTEPs (including
+ * the originating one)
+ */
+ mac->rem_seq = 0;
+
+ /* If all remote neighbors referencing a remote MAC
+ * go away, we need to uninstall the MAC.
+ */
+ if (remote_neigh_count(mac) == 0) {
+ zvni_rem_mac_uninstall(zvni, mac);
+ zebra_evpn_es_mac_deref_entry(mac);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
+ }
+
+ if (list_isempty(mac->neigh_list))
+ zvni_mac_del(zvni, mac);
+ else
+ SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+}
+
/* Process a remote MACIP delete from BGP. */
static void process_remote_macip_del(vni_t vni,
struct ethaddr *macaddr,
@@ -6014,11 +7526,6 @@ static void process_remote_macip_del(vni_t vni,
zns = zebra_ns_lookup(NS_DEFAULT);
vxl = &zif->l2info.vxl;
- /* It is possible remote vtep del request is processed prior to
- * remote macip route delete. remote_vtep_del does not clean up
- * the macip route delete. Explicite withdraw of the macip route
- * is expected to recieve. This handler removes the remote route.
- */
mac = zvni_mac_lookup(zvni, macaddr);
if (ipa_len)
n = zvni_neigh_lookup(zvni, ipaddr);
@@ -6077,11 +7584,14 @@ static void process_remote_macip_del(vni_t vni,
* "old" neighbor (as these are two different MACIP routes).
* Do the delete only if the MAC matches.
*/
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
- && (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0)) {
- zvni_neigh_uninstall(zvni, n);
- zvni_neigh_del(zvni, n);
- zvni_deref_ip2mac(zvni, mac);
+ if (!memcmp(n->emac.octet, macaddr->octet, ETH_ALEN)) {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ zebra_vxlan_sync_neigh_del(n);
+ } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+ zvni_neigh_uninstall(zvni, n);
+ zvni_neigh_del(zvni, n);
+ zvni_deref_ip2mac(zvni, mac);
+ }
}
} else {
/* DAD: when MAC is freeze state as remote learn event,
@@ -6104,27 +7614,11 @@ static void process_remote_macip_del(vni_t vni,
macaddr, vxl->access_vlan);
}
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- zvni_process_neigh_on_remote_mac_del(zvni, mac);
- /*
- * the remote sequence number in the auto mac entry
- * needs to be reset to 0 as the mac entry may have
- * been removed on all VTEPs (including
- * the originating one)
- */
- mac->rem_seq = 0;
-
- /* If all remote neighbors referencing a remote MAC
- * go away, we need to uninstall the MAC.
- */
- if (remote_neigh_count(mac) == 0) {
- zvni_mac_uninstall(zvni, mac);
- UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
- }
- if (list_isempty(mac->neigh_list))
- zvni_mac_del(zvni, mac);
- else
- SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ if (!ipa_len)
+ zebra_vxlan_sync_mac_del(mac);
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_NEIGH_REMOTE)) {
+ zebra_vxlan_rem_mac_del(zvni, mac);
}
}
}
@@ -6560,8 +8054,7 @@ void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
vty_out(vty,
"Number of ARPs (local and remote) known for this VNI: %u\n",
num_neigh);
- vty_out(vty, "%*s %-6s %-8s %-17s %-21s %s\n", -wctx.addr_width,
- "IP", "Type", "State", "MAC", "Remote VTEP", "Seq #'s");
+ zvni_print_neigh_hdr(vty, &wctx);
} else
json_object_int_add(json, "numArpNd", num_neigh);
@@ -6771,9 +8264,9 @@ void zebra_vxlan_print_neigh_vni_dad(struct vty *vty,
vty_out(vty,
"Number of ARPs (local and remote) known for this VNI: %u\n",
num_neigh);
- vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n",
+ vty_out(vty, "%*s %-6s %-8s %-17s %-30s\n",
-wctx.addr_width, "IP", "Type",
- "State", "MAC", "Remote VTEP");
+ "State", "MAC", "Remote ES/VTEP");
} else
json_object_int_add(json, "numArpNd", num_neigh);
@@ -6826,8 +8319,11 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
vty_out(vty,
"Number of MACs (local and remote) known for this VNI: %u\n",
num_macs);
- vty_out(vty, "%-17s %-6s %-21s %-5s %s\n", "MAC", "Type",
- "Intf/Remote VTEP", "VLAN", "Seq #'s");
+ vty_out(vty,
+ "Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy\n");
+ vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %s\n", "MAC",
+ "Type", "Flags", "Intf/Remote ES/VTEP",
+ "VLAN", "Seq #'s");
} else
json_object_int_add(json, "numMacs", num_macs);
@@ -7019,8 +8515,8 @@ void zebra_vxlan_print_macs_vni_dad(struct vty *vty,
vty_out(vty,
"Number of MACs (local and remote) known for this VNI: %u\n",
num_macs);
- vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type",
- "Intf/Remote VTEP", "VLAN");
+ vty_out(vty, "%-17s %-6s %-5s %-30s %-5s\n", "MAC", "Type",
+ "Flags", "Intf/Remote ES/VTEP", "VLAN");
} else
json_object_int_add(json, "numMacs", num_macs);
@@ -7077,7 +8573,8 @@ int zebra_vxlan_clear_dup_detect_vni_mac(struct zebra_vrf *zvrf, vni_t vni,
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
ZEBRA_NEIGH_SET_INACTIVE(nbr);
else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE))
- zvni_neigh_install(zvni, nbr);
+ zvni_rem_neigh_install(zvni, nbr,
+ false /*was_static*/);
}
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
@@ -7103,17 +8600,18 @@ int zebra_vxlan_clear_dup_detect_vni_mac(struct zebra_vrf *zvrf, vni_t vni,
if (zvni_mac_send_add_to_client(zvni->vni,
&mac->macaddr,
mac->flags,
- mac->loc_seq))
+ mac->loc_seq, mac->es))
return 0;
/* Process all neighbors associated with this MAC. */
- zvni_process_neigh_on_local_mac_change(zvni, mac, 0);
+ zvni_process_neigh_on_local_mac_change(zvni, mac, 0,
+ 0 /*es_change*/);
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
zvni_process_neigh_on_remote_mac_add(zvni, mac);
/* Install the entry. */
- zvni_mac_install(zvni, mac);
+ zvni_rem_mac_install(zvni, mac, false /* was_static */);
}
return 0;
@@ -7173,10 +8671,10 @@ int zebra_vxlan_clear_dup_detect_vni_ip(struct zebra_vrf *zvrf, vni_t vni,
if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
zvni_neigh_send_add_to_client(zvni->vni, ip,
- &nbr->emac,
+ &nbr->emac, nbr->mac,
nbr->flags, nbr->loc_seq);
} else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) {
- zvni_neigh_install(zvni, nbr);
+ zvni_rem_neigh_install(zvni, nbr, false /*was_static*/);
}
return 0;
@@ -7223,17 +8721,18 @@ static void zvni_clear_dup_mac_hash(struct hash_bucket *bucket, void *ctxt)
/* Inform to BGP */
if (zvni_mac_send_add_to_client(zvni->vni,
&mac->macaddr,
- mac->flags, mac->loc_seq))
+ mac->flags, mac->loc_seq, mac->es))
return;
/* Process all neighbors associated with this MAC. */
- zvni_process_neigh_on_local_mac_change(zvni, mac, 0);
+ zvni_process_neigh_on_local_mac_change(zvni, mac, 0,
+ 0 /*es_change*/);
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
zvni_process_neigh_on_remote_mac_add(zvni, mac);
/* Install the entry. */
- zvni_mac_install(zvni, mac);
+ zvni_rem_mac_install(zvni, mac, false /* was_static */);
}
}
@@ -7268,10 +8767,10 @@ static void zvni_clear_dup_neigh_hash(struct hash_bucket *bucket, void *ctxt)
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
zvni_neigh_send_add_to_client(zvni->vni, &nbr->ip,
- &nbr->emac,
+ &nbr->emac, nbr->mac,
nbr->flags, nbr->loc_seq);
} else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) {
- zvni_neigh_install(zvni, nbr);
+ zvni_rem_neigh_install(zvni, nbr, false /*was_static*/);
}
}
@@ -7667,6 +9166,8 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
zebra_mac_t *zmac = NULL;
zebra_l3vni_t *zl3vni = NULL;
struct zebra_vrf *zvrf;
+ bool old_bgp_ready;
+ bool new_bgp_ready;
/* check if this is a remote neigh entry corresponding to remote
* next-hop
@@ -7721,7 +9222,36 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
* deleted it, it needs to be re-installed as Quagga is the owner.
*/
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
- zvni_neigh_install(zvni, n);
+ zvni_rem_neigh_install(zvni, n, false /*was_static*/);
+ return 0;
+ }
+
+ /* if this is a sync entry it cannot be dropped re-install it in
+ * the dataplane
+ */
+ old_bgp_ready =
+ zebra_vxlan_neigh_is_ready_for_bgp(n);
+ if (zebra_vxlan_neigh_is_static(n)) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("re-add sync neigh vni %u ip %s mac %s 0x%x",
+ n->zvni->vni,
+ ipaddr2str(&n->ip, buf, sizeof(buf)),
+ prefix_mac2str(&n->emac, buf2,
+ sizeof(buf2)),
+ n->flags);
+
+ if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE))
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
+ /* inform-bgp about change in local-activity if any */
+ new_bgp_ready =
+ zebra_vxlan_neigh_is_ready_for_bgp(n);
+ zebra_vxlan_neigh_send_add_del_to_client(n,
+ old_bgp_ready, new_bgp_ready);
+
+ /* re-install the entry in the kernel */
+ zebra_vxlan_sync_neigh_dp_install(n, false /* set_inactive */,
+ false /* force_clear_static */, __func__);
+
return 0;
}
@@ -7741,7 +9271,9 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
ZEBRA_NEIGH_SET_INACTIVE(n);
/* Remove neighbor from BGP. */
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, 0, n->state);
+ zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
+ &n->emac, n->flags, n->state,
+ false /* force */);
/* Delete this neighbor entry. */
zvni_neigh_del(zvni, n);
@@ -7766,7 +9298,8 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp,
struct ethaddr *macaddr,
uint16_t state,
bool is_ext,
- bool is_router)
+ bool is_router,
+ bool local_inactive, bool dp_static)
{
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
@@ -7787,19 +9320,20 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp,
if (!zvni)
return 0;
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
zlog_debug(
- "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s %s-> L2-VNI %u",
+ "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s%s%s-> L2-VNI %u",
ipaddr2str(ip, buf2, sizeof(buf2)),
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
ifp->ifindex, state, is_ext ? "ext-learned " : "",
is_router ? "router " : "",
+ local_inactive ? "local_inactive " : "",
zvni->vni);
/* Is this about a local neighbor or a remote one? */
if (!is_ext)
return zvni_local_neigh_update(zvni, ifp, ip, macaddr,
- is_router);
+ is_router, local_inactive, dp_static);
return zvni_remote_neigh_update(zvni, ifp, ip, macaddr, state);
}
@@ -7808,7 +9342,7 @@ static int32_t
zebra_vxlan_remote_macip_helper(bool add, struct stream *s, vni_t *vni,
struct ethaddr *macaddr, uint16_t *ipa_len,
struct ipaddr *ip, struct in_addr *vtep_ip,
- uint8_t *flags, uint32_t *seq)
+ uint8_t *flags, uint32_t *seq, esi_t *esi)
{
uint16_t l = 0;
@@ -7846,6 +9380,8 @@ zebra_vxlan_remote_macip_helper(bool add, struct stream *s, vni_t *vni,
STREAM_GETC(s, *flags);
STREAM_GETL(s, *seq);
l += 5;
+ STREAM_GET(esi, s, sizeof(esi_t));
+ l += sizeof(esi_t);
}
return l;
@@ -7877,7 +9413,7 @@ void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS)
while (l < hdr->length) {
int res_length = zebra_vxlan_remote_macip_helper(
false, s, &vni, &macaddr, &ipa_len, &ip, &vtep_ip, NULL,
- NULL);
+ NULL, NULL);
if (res_length == -1)
goto stream_failure;
@@ -7918,6 +9454,8 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS)
uint32_t seq;
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
+ esi_t esi;
+ char esi_buf[ESI_STR_LEN];
memset(&macaddr, 0, sizeof(struct ethaddr));
memset(&ip, 0, sizeof(struct ipaddr));
@@ -7933,25 +9471,32 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS)
while (l < hdr->length) {
int res_length = zebra_vxlan_remote_macip_helper(
true, s, &vni, &macaddr, &ipa_len, &ip, &vtep_ip,
- &flags, &seq);
+ &flags, &seq, &esi);
if (res_length == -1)
goto stream_failure;
l += res_length;
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ if (memcmp(&esi, zero_esi, sizeof(esi_t)))
+ esi_to_str(&esi, esi_buf, sizeof(esi_buf));
+ else
+ strlcpy(esi_buf, "-", ESI_STR_LEN);
zlog_debug(
- "Recv MACIP ADD VNI %u MAC %s%s%s flags 0x%x seq %u VTEP %s from %s",
+ "Recv %sMACIP ADD VNI %u MAC %s%s%s flags 0x%x seq %u VTEP %s ESI %s from %s",
+ (flags & ZEBRA_MACIP_TYPE_SYNC_PATH) ?
+ "sync-" : "",
vni,
prefix_mac2str(&macaddr, buf, sizeof(buf)),
ipa_len ? " IP " : "",
ipa_len ?
ipaddr2str(&ip, buf1, sizeof(buf1)) : "",
- flags, seq, inet_ntoa(vtep_ip),
+ flags, seq, inet_ntoa(vtep_ip), esi_buf,
zebra_route_string(client->proto));
+ }
process_remote_macip_add(vni, &macaddr, ipa_len, &ip,
- flags, seq, vtep_ip);
+ flags, seq, vtep_ip, &esi);
}
stream_failure:
@@ -8050,7 +9595,8 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
ifp->ifindex, vni, mac->flags);
/* Remove MAC from BGP. */
- zvni_mac_send_del_to_client(zvni->vni, macaddr);
+ zvni_mac_send_del_to_client(zvni->vni, macaddr,
+ mac->flags, false /* force */);
/*
* If there are no neigh associated with the mac delete the mac
@@ -8059,7 +9605,7 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
if (!listcount(mac->neigh_list)) {
zvni_mac_del(zvni, mac);
} else {
- UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
}
@@ -8117,7 +9663,7 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
ifp->ifindex, vni);
- zvni_mac_install(zvni, mac);
+ zvni_rem_mac_install(zvni, mac, false /* was_static */);
return 0;
}
@@ -8130,6 +9676,8 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
zebra_vni_t *zvni;
zebra_mac_t *mac;
char buf[ETHER_ADDR_STRLEN];
+ bool old_bgp_ready;
+ bool new_bgp_ready;
/* We are interested in MACs only on ports or (port, VLAN) that
* map to a VNI.
@@ -8159,11 +9707,46 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
ifp->ifindex, vid, zvni->vni, mac->loc_seq,
mac->flags, listcount(mac->neigh_list));
+ old_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
+ if (zebra_vxlan_mac_is_static(mac)) {
+ /* this is a synced entry and can only be removed when the
+ * es-peers stop advertising it.
+ */
+ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("re-add sync-mac vni %u mac %s es %s seq %d f 0x%x",
+ zvni->vni,
+ prefix_mac2str(macaddr,
+ buf, sizeof(buf)),
+ mac->es ? mac->es->esi_str : "-",
+ mac->loc_seq,
+ mac->flags);
+
+ /* inform-bgp about change in local-activity if any */
+ if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
+ new_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
+ zebra_vxlan_mac_send_add_del_to_client(mac,
+ old_bgp_ready, new_bgp_ready);
+ }
+
+ /* re-install the entry in the kernel */
+ zebra_vxlan_sync_mac_dp_install(mac, false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
+
+ return 0;
+ }
+
/* Update all the neigh entries associated with this mac */
zvni_process_neigh_on_local_mac_del(zvni, mac);
/* Remove MAC from BGP. */
- zvni_mac_send_del_to_client(zvni->vni, macaddr);
+ zvni_mac_send_del_to_client(zvni->vni, macaddr,
+ mac->flags, false /* force */);
+
+ zebra_evpn_es_mac_deref_entry(mac);
/*
* If there are no neigh associated with the mac delete the mac
@@ -8172,7 +9755,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
if (!listcount(mac->neigh_list)) {
zvni_mac_del(zvni, mac);
} else {
- UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
}
@@ -8180,13 +9763,36 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
return 0;
}
+/* update local fowarding info. return true if a dest-ES change
+ * is detected
+ */
+static bool zebra_vxlan_local_mac_update_fwd_info(zebra_mac_t *mac,
+ struct interface *ifp, vlanid_t vid)
+{
+ struct zebra_if *zif = ifp->info;
+ bool es_change;
+
+ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+
+ es_change = zebra_evpn_es_mac_ref_entry(mac, zif->es_info.es);
+
+ if (!mac->es) {
+ /* if es is set fwd_info is not-relevant/taped-out */
+ mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.vid = vid;
+ }
+
+ return es_change;
+}
+
/*
* Handle local MAC add (on a port or VLAN corresponding to this VNI).
*/
int zebra_vxlan_local_mac_add_update(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid,
- bool sticky)
+ bool sticky, bool local_inactive,
+ bool dp_static)
{
zebra_vni_t *zvni;
zebra_mac_t *mac;
@@ -8197,11 +9803,13 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
bool upd_neigh = false;
bool is_dup_detect = false;
struct in_addr vtep_ip = {.s_addr = 0};
- ns_id_t local_ns_id = NS_DEFAULT;
-
- zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
- if (zvrf && zvrf->zns)
- local_ns_id = zvrf->zns->ns_id;
+ bool es_change = false;
+ bool new_bgp_ready;
+ /* assume inactive if not present or if not local */
+ bool old_local_inactive = true;
+ bool old_bgp_ready = false;
+ bool inform_dataplane = false;
+ bool new_static = false;
/* We are interested in MACs only on ports or (port, VLAN) that
* map to a VNI.
@@ -8225,22 +9833,24 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
return -1;
}
- zvrf = zebra_vrf_get_evpn();
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
if (!zvrf) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(" No Evpn Global Vrf found");
+ zlog_debug(" No Vrf found for vrf_id: %d",
+ zvni->vxlan_if->vrf_id);
return -1;
}
/* Check if we need to create or update or it is a NO-OP. */
mac = zvni_mac_lookup(zvni, macaddr);
if (!mac) {
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug(
- "ADD %sMAC %s intf %s(%u) VID %u -> VNI %u",
+ "ADD %sMAC %s intf %s(%u) VID %u -> VNI %u%s",
sticky ? "sticky " : "",
prefix_mac2str(macaddr, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, vid, zvni->vni);
+ ifp->name, ifp->ifindex, vid, zvni->vni,
+ local_inactive ? " local-inactive" : "");
mac = zvni_mac_add(zvni, macaddr);
if (!mac) {
@@ -8252,23 +9862,33 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
return -1;
}
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
- mac->fwd_info.local.ifindex = ifp->ifindex;
- mac->fwd_info.local.ns_id = local_ns_id;
- mac->fwd_info.local.vid = vid;
+ es_change = zebra_vxlan_local_mac_update_fwd_info(mac,
+ ifp, vid);
if (sticky)
SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
inform_client = true;
-
} else {
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug(
- "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u curFlags 0x%x",
+ "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags 0x%x",
sticky ? "sticky " : "",
prefix_mac2str(macaddr, buf, sizeof(buf)),
ifp->name, ifp->ifindex, vid, zvni->vni,
+ local_inactive ? "local-inactive " : "",
mac->flags);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ struct interface *old_ifp;
+ vlanid_t old_vid;
+ bool old_static;
+
+ zebra_vxlan_mac_get_access_info(mac,
+ &old_ifp, &old_vid);
+ old_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(
+ mac->flags);
+ old_local_inactive = !!(mac->flags &
+ ZEBRA_MAC_LOCAL_INACTIVE);
+ old_static = zebra_vxlan_mac_is_static(mac);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
mac_sticky = true;
@@ -8277,17 +9897,20 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
* BGP, note it.
*/
if (mac_sticky == sticky
- && mac->fwd_info.local.ifindex == ifp->ifindex
- && mac->fwd_info.local.ns_id == local_ns_id
- && mac->fwd_info.local.vid == vid) {
+ && old_ifp == ifp
+ && old_vid == vid
+ && old_local_inactive == local_inactive
+ && dp_static == old_static) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- " Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, entry exists and has not changed ",
+ " Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u%s, entry exists and has not changed ",
sticky ? "sticky " : "",
prefix_mac2str(macaddr, buf,
sizeof(buf)),
ifp->name, ifp->ifindex, vid,
- zvni->vni);
+ zvni->vni,
+ local_inactive ?
+ " local_inactive" : "");
return 0;
}
if (mac_sticky != sticky) {
@@ -8300,11 +9923,31 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
inform_client = true;
}
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
- mac->fwd_info.local.ifindex = ifp->ifindex;
- mac->fwd_info.local.ns_id = local_ns_id;
- mac->fwd_info.local.vid = vid;
-
+ es_change = zebra_vxlan_local_mac_update_fwd_info(mac,
+ ifp, vid);
+ /* If an es_change is detected we need to advertise
+ * the route with a sequence that is one
+ * greater. This is need to indicate a mac-move
+ * to the ES peers
+ */
+ if (es_change) {
+ mac->loc_seq = mac->loc_seq + 1;
+ /* force drop the peer/sync info as it is
+ * simply no longer relevant
+ */
+ if (CHECK_FLAG(mac->flags,
+ ZEBRA_MAC_ALL_PEER_FLAGS)) {
+ zebra_vxlan_mac_clear_sync_info(mac);
+ new_static =
+ zebra_vxlan_mac_is_static(mac);
+ /* if we clear peer-flags we
+ * also need to notify the dataplane
+ * to drop the static flag
+ */
+ if (old_static != new_static)
+ inform_dataplane = true;
+ }
+ }
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ||
CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
bool do_dad = false;
@@ -8338,10 +9981,8 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
- mac->fwd_info.local.ifindex = ifp->ifindex;
- mac->fwd_info.local.ns_id = local_ns_id;
- mac->fwd_info.local.vid = vid;
+ es_change = zebra_vxlan_local_mac_update_fwd_info(mac,
+ ifp, vid);
if (sticky)
SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
else
@@ -8364,16 +10005,57 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
}
}
- /* Inform BGP if required. */
- if (inform_client) {
- if (zvni_mac_send_add_to_client(zvni->vni, macaddr,
- mac->flags, mac->loc_seq))
- return -1;
+ /* if the dataplane thinks the entry is sync but it is
+ * not sync in zebra we need to re-install to fixup
+ */
+ if (dp_static) {
+ new_static = zebra_vxlan_mac_is_static(mac);
+ if (!new_static)
+ inform_dataplane = true;
+ }
+
+ if (local_inactive)
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
+ else
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
+
+ new_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
+ /* if local-activity has changed we need update bgp
+ * even if bgp already knows about the mac
+ */
+ if ((old_local_inactive != local_inactive) ||
+ (new_bgp_ready != old_bgp_ready)) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("local mac vni %u mac %s es %s seq %d f 0x%x%s",
+ zvni->vni,
+ prefix_mac2str(macaddr,
+ buf, sizeof(buf)),
+ mac->es ? mac->es->esi_str : "",
+ mac->loc_seq,
+ mac->flags,
+ local_inactive ?
+ " local-inactive" : "");
+ inform_client = true;
+ }
+
+ if (es_change) {
+ inform_client = true;
+ upd_neigh = true;
}
+ /* Inform dataplane if required. */
+ if (inform_dataplane)
+ zebra_vxlan_sync_mac_dp_install(mac, false /* set_inactive */,
+ false /* force_clear_static */, __func__);
+
+ /* Inform BGP if required. */
+ if (inform_client)
+ zebra_vxlan_mac_send_add_del_to_client(mac,
+ old_bgp_ready, new_bgp_ready);
+
/* Process all neighbors associated with this MAC, if required. */
if (upd_neigh)
- zvni_process_neigh_on_local_mac_change(zvni, mac, 0);
+ zvni_process_neigh_on_local_mac_change(zvni, mac, 0, es_change);
return 0;
}
@@ -8893,7 +10575,7 @@ int zebra_vxlan_if_down(struct interface *ifp)
assert(zvni->vxlan_if == ifp);
/* Delete this VNI from BGP. */
- zvni_send_del_to_client(zvni->vni);
+ zvni_send_del_to_client(zvni);
/* Free up all neighbors and MACs, if any. */
zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
@@ -9034,9 +10716,8 @@ int zebra_vxlan_if_del(struct interface *ifp)
zl3vni = zl3vni_from_vrf(zvni->vrf_id);
if (zl3vni)
listnode_delete(zl3vni->l2vnis, zvni);
-
/* Delete VNI from BGP. */
- zvni_send_del_to_client(zvni->vni);
+ zvni_send_del_to_client(zvni);
/* Free up all neighbors and MAC, if any. */
zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
@@ -9155,7 +10836,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. */
- zvni_send_del_to_client(zvni->vni);
+ zvni_send_del_to_client(zvni);
zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
zvni_vtep_del_all(zvni, 1);
@@ -9178,9 +10859,12 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp);
zvni->local_vtep_ip = vxl->vtep_ip;
zvni->mcast_grp = vxl->mcast_grp;
+ /* on local vtep-ip check if ES orig-ip
+ * needs to be updated
+ */
+ zebra_evpn_es_set_base_vni(zvni);
}
- zvni->vxlan_if = ifp;
-
+ zvni_vxlan_if_set(zvni, ifp, true /* set */);
/* Take further actions needed.
* Note that if we are here, there is a change of interest.
*/
@@ -9291,8 +10975,12 @@ int zebra_vxlan_if_add(struct interface *ifp)
zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp);
zvni->local_vtep_ip = vxl->vtep_ip;
zvni->mcast_grp = vxl->mcast_grp;
+ /* on local vtep-ip check if ES orig-ip
+ * needs to be updated
+ */
+ zebra_evpn_es_set_base_vni(zvni);
}
- zvni->vxlan_if = ifp;
+ zvni_vxlan_if_set(zvni, ifp, true /* set */);
vlan_if = zvni_map_to_svi(vxl->access_vlan,
zif->brslave_info.br_if);
if (vlan_if) {
@@ -9475,8 +11163,15 @@ int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf)
if (!zl3vni)
return 0;
- zl3vni->vrf_id = VRF_UNKNOWN;
zebra_vxlan_process_l3vni_oper_down(zl3vni);
+
+ /* delete and uninstall all rmacs */
+ hash_iterate(zl3vni->rmac_table, zl3vni_del_rmac_hash_entry, zl3vni);
+ /* delete and uninstall all next-hops */
+ hash_iterate(zl3vni->nh_table, zl3vni_del_nh_hash_entry, zl3vni);
+
+ zl3vni->vrf_id = VRF_UNKNOWN;
+
return 0;
}
@@ -9805,25 +11500,6 @@ stream_failure:
return;
}
-static int macfdb_read_ns(struct ns *ns,
- void *_in_param __attribute__((unused)),
- void **out_param __attribute__((unused)))
-{
- struct zebra_ns *zns = ns->info;
-
- macfdb_read(zns);
- return NS_WALK_CONTINUE;
-}
-
-static int neigh_read_ns(struct ns *ns,
- void *_in_param __attribute__((unused)),
- void **out_param __attribute__((unused)))
-{
- struct zebra_ns *zns = ns->info;
-
- neigh_read(zns);
- return NS_WALK_CONTINUE;
-}
/*
* Handle message from client to learn (or stop learning) about VNIs and MACs.
@@ -9865,6 +11541,9 @@ void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS)
/* Note BUM handling */
zvrf->vxlan_flood_ctrl = flood_ctrl;
+ /* Replay all ESs */
+ zebra_evpn_es_send_all_to_client(true /* add */);
+
/* Build VNI hash table and inform BGP. */
zvni_build_hash_table();
@@ -9873,16 +11552,19 @@ void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS)
NULL);
/* Read the MAC FDB */
- ns_walk_func(macfdb_read_ns, NULL, NULL);
+ macfdb_read(zvrf->zns);
/* Read neighbors */
- ns_walk_func(neigh_read_ns, NULL, NULL);
+ neigh_read(zvrf->zns);
} else {
/* Cleanup VTEPs for all VNIs - uninstall from
* kernel and free entries.
*/
hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
+ /* Delete all ESs in BGP */
+ zebra_evpn_es_send_all_to_client(false /* add */);
+
/* cleanup all l3vnis */
hash_iterate(zrouter.l3vni_table, zl3vni_cleanup_all, NULL);
@@ -9911,10 +11593,15 @@ void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
/* Cleanup VNI info, but don't free the table. */
void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
{
+ struct zebra_vrf *evpn_zvrf = zebra_vrf_get_evpn();
+
if (!zvrf)
return;
hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_cleanup, NULL);
+
+ if (zvrf == evpn_zvrf)
+ zebra_evpn_es_cleanup();
}
/* Close all VNI handling */
@@ -9932,12 +11619,14 @@ void zebra_vxlan_init(void)
zrouter.l3vni_table = hash_create(l3vni_hash_keymake, l3vni_hash_cmp,
"Zebra VRF L3 VNI table");
zrouter.evpn_vrf = NULL;
+ zebra_evpn_mh_init();
}
/* free l3vni table */
void zebra_vxlan_disable(void)
{
hash_free(zrouter.l3vni_table);
+ zebra_evpn_mh_terminate();
}
/* get the l3vni svi ifindex */
@@ -9994,9 +11683,9 @@ static int zebra_vxlan_dad_ip_auto_recovery_exp(struct thread *t)
/* Send to BGP */
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
zvni_neigh_send_add_to_client(zvni->vni, &nbr->ip, &nbr->emac,
- nbr->flags, nbr->loc_seq);
+ nbr->mac, nbr->flags, nbr->loc_seq);
} else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) {
- zvni_neigh_install(zvni, nbr);
+ zvni_rem_neigh_install(zvni, nbr, false /*was_static*/);
}
return 0;
@@ -10039,7 +11728,8 @@ static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t)
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
ZEBRA_NEIGH_SET_INACTIVE(nbr);
else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE))
- zvni_neigh_install(zvni, nbr);
+ zvni_rem_neigh_install(zvni, nbr,
+ false /*was_static*/);
}
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
@@ -10058,17 +11748,18 @@ static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t)
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
/* Inform to BGP */
if (zvni_mac_send_add_to_client(zvni->vni, &mac->macaddr,
- mac->flags, mac->loc_seq))
+ mac->flags, mac->loc_seq, mac->es))
return -1;
/* Process all neighbors associated with this MAC. */
- zvni_process_neigh_on_local_mac_change(zvni, mac, 0);
+ zvni_process_neigh_on_local_mac_change(zvni, mac, 0,
+ 0 /*es_change*/);
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
zvni_process_neigh_on_remote_mac_add(zvni, mac);
/* Install the entry. */
- zvni_mac_install(zvni, mac);
+ zvni_rem_mac_install(zvni, mac, false /* was_static */);
}
return 0;
@@ -10338,7 +12029,7 @@ static void zvni_send_mac_hash_entry_to_client(struct hash_bucket *bucket,
if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
zvni_mac_send_add_to_client(wctx->zvni->vni, &zmac->macaddr,
- zmac->flags, zmac->loc_seq);
+ zmac->flags, zmac->loc_seq, zmac->es);
}
/* Iterator to Notify Local MACs of a L2VNI */
@@ -10374,7 +12065,7 @@ static void zvni_send_neigh_hash_entry_to_client(struct hash_bucket *bucket,
return;
zvni_neigh_send_add_to_client(wctx->zvni->vni, &zn->ip,
- &zn->emac, zn->flags,
+ &zn->emac, zn->mac, zn->flags,
zn->loc_seq);
}
}