summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zebra/zebra_dplane.c2
-rw-r--r--zebra/zebra_evpn_mh.c146
-rw-r--r--zebra/zebra_evpn_mh.h5
3 files changed, 133 insertions, 20 deletions
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 56545d0766..d3bcffe960 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -2908,7 +2908,7 @@ dplane_br_port_update(const struct interface *ifp, bool non_df,
if (non_df)
flags |= DPLANE_BR_PORT_NON_DF;
- if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_EVPN_MH_ES) {
uint32_t i;
char vtep_str[ES_VTEP_LIST_STR_SZ];
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index a6612d50f0..3c457bdfa5 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -63,6 +63,8 @@ static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp);
static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
struct ethaddr *sysmac);
+static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
+ const char *caller);
esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
@@ -897,12 +899,23 @@ static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
es->flags |= ZEBRA_EVPNES_NHG_ACTIVE;
kernel_upd_mac_nhg(es->nhg_id, nh_cnt, nh_ids);
+ if (!(es->flags & ZEBRA_EVPNES_NHG_ACTIVE)) {
+ es->flags |= ZEBRA_EVPNES_NHG_ACTIVE;
+ /* add backup NHG to the br-port */
+ if ((es->flags & ZEBRA_EVPNES_LOCAL))
+ zebra_evpn_es_br_port_dplane_update(es,
+ __func__);
+ }
} else {
if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
zlog_debug("es %s nhg 0x%x del",
es->esi_str, es->nhg_id);
es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
+ /* remove backup NHG from the br-port */
+ if ((es->flags & ZEBRA_EVPNES_LOCAL))
+ zebra_evpn_es_br_port_dplane_update(es,
+ __func__);
kernel_del_mac_nhg(es->nhg_id);
}
}
@@ -1017,7 +1030,76 @@ static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_find(
return NULL;
}
-static void zebra_evpn_es_df_change(struct zebra_evpn_es *es, bool new_non_df,
+/* flush all the dataplane br-port info associated with the ES */
+static bool zebra_evpn_es_br_port_dplane_clear(struct zebra_evpn_es *es)
+{
+ struct in_addr sph_filters[ES_VTEP_MAX_CNT];
+
+ if (!(es->flags & ZEBRA_EVPNES_BR_PORT))
+ return false;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("es %s br-port dplane clear", es->esi_str);
+
+ memset(&sph_filters, 0, sizeof(sph_filters));
+ dplane_br_port_update(es->zif->ifp, false /* non_df */, 0, sph_filters,
+ 0 /* backup_nhg_id */);
+ return true;
+}
+
+static inline bool
+zebra_evpn_es_br_port_dplane_update_needed(struct zebra_evpn_es *es)
+{
+ return (es->flags & ZEBRA_EVPNES_NON_DF)
+ || (es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
+ || listcount(es->es_vtep_list);
+}
+
+/* returns TRUE if dplane entry was updated */
+static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
+ const char *caller)
+{
+ uint32_t backup_nhg_id;
+ struct in_addr sph_filters[ES_VTEP_MAX_CNT];
+ struct listnode *node = NULL;
+ struct zebra_evpn_es_vtep *es_vtep;
+ uint32_t sph_filter_cnt = 0;
+
+ if (!(es->flags & ZEBRA_EVPNES_LOCAL))
+ return zebra_evpn_es_br_port_dplane_clear(es);
+
+ /* If the ES is not a bridge port there is nothing
+ * in the dataplane
+ */
+ if (!(es->flags & ZEBRA_EVPNES_BR_PORT))
+ return false;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("es %s br-port dplane update by %s", es->esi_str, caller);
+ backup_nhg_id = (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) ? es->nhg_id : 0;
+
+ memset(&sph_filters, 0, sizeof(sph_filters));
+ if (listcount(es->es_vtep_list) > ES_VTEP_MAX_CNT) {
+ zlog_warn("es %s vtep count %d exceeds filter cnt %d",
+ es->esi_str, listcount(es->es_vtep_list),
+ ES_VTEP_MAX_CNT);
+ } else {
+ for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
+ if (es_vtep->flags & ZEBRA_EVPNES_VTEP_DEL_IN_PROG)
+ continue;
+ sph_filters[sph_filter_cnt] = es_vtep->vtep_ip;
+ ++sph_filter_cnt;
+ }
+ }
+
+ dplane_br_port_update(es->zif->ifp, !!(es->flags & ZEBRA_EVPNES_NON_DF),
+ sph_filter_cnt, sph_filters, backup_nhg_id);
+
+ return true;
+}
+
+/* returns TRUE if dplane entry was updated */
+static bool zebra_evpn_es_df_change(struct zebra_evpn_es *es, bool new_non_df,
const char *caller)
{
bool old_non_df;
@@ -1030,18 +1112,20 @@ static void zebra_evpn_es_df_change(struct zebra_evpn_es *es, bool new_non_df,
new_non_df ? "non-df" : "df");
if (old_non_df == new_non_df)
- return;
+ return false;
- if (new_non_df) {
+ if (new_non_df)
es->flags |= ZEBRA_EVPNES_NON_DF;
- /* XXX - Setup a dataplane DF filter to block BUM traffic */
- } else {
+ else
es->flags &= ~ZEBRA_EVPNES_NON_DF;
- /* XXX - clear the non-DF block filter */
- }
+
+ /* update non-DF block filter in the dataplane */
+ return zebra_evpn_es_br_port_dplane_update(es, __func__);
}
-static void zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
+
+/* returns TRUE if dplane entry was updated */
+static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
const char *caller)
{
struct listnode *node = NULL;
@@ -1052,10 +1136,8 @@ static void zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
* is no need to setup the BUM block filter
*/
if (!(es->flags & ZEBRA_EVPNES_LOCAL)
- || !zmh_info->es_originator_ip.s_addr) {
- zebra_evpn_es_df_change(es, new_non_df, caller);
- return;
- }
+ || !zmh_info->es_originator_ip.s_addr)
+ return zebra_evpn_es_df_change(es, new_non_df, caller);
/* if oper-state is down DF filtering must be on. when the link comes
* up again dataplane should block BUM till FRR has had the chance
@@ -1063,8 +1145,7 @@ static void zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
*/
if (!(es->flags & ZEBRA_EVPNES_OPER_UP)) {
new_non_df = true;
- zebra_evpn_es_df_change(es, new_non_df, caller);
- return;
+ return zebra_evpn_es_df_change(es, new_non_df, caller);
}
for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
@@ -1096,7 +1177,7 @@ static void zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
}
}
- zebra_evpn_es_df_change(es, new_non_df, caller);
+ return zebra_evpn_es_df_change(es, new_non_df, caller);
}
static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
@@ -1105,6 +1186,7 @@ static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
{
struct zebra_evpn_es_vtep *es_vtep;
bool old_esr_rxed;
+ bool dplane_updated = false;
es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
@@ -1129,14 +1211,18 @@ static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
es_vtep->flags &= ~ZEBRA_EVPNES_VTEP_RXED_ESR;
es_vtep->df_alg = df_alg;
es_vtep->df_pref = df_pref;
- zebra_evpn_es_run_df_election(es, __func__);
+ dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
}
+ /* add the vtep to the SPH list */
+ if (!dplane_updated && (es->flags & ZEBRA_EVPNES_LOCAL))
+ zebra_evpn_es_br_port_dplane_update(es, __func__);
}
static void zebra_evpn_es_vtep_del(struct zebra_evpn_es *es,
struct in_addr vtep_ip)
{
struct zebra_evpn_es_vtep *es_vtep;
+ bool dplane_updated = false;
es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
@@ -1144,10 +1230,15 @@ static void zebra_evpn_es_vtep_del(struct zebra_evpn_es *es,
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("es %s vtep %pI4 del",
es->esi_str, &vtep_ip);
+ es_vtep->flags |= ZEBRA_EVPNES_VTEP_DEL_IN_PROG;
if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR) {
es_vtep->flags &= ~ZEBRA_EVPNES_VTEP_RXED_ESR;
- zebra_evpn_es_run_df_election(es, __func__);
+ dplane_updated =
+ zebra_evpn_es_run_df_election(es, __func__);
}
+ /* remove the vtep from the SPH list */
+ if (!dplane_updated && (es->flags & ZEBRA_EVPNES_LOCAL))
+ zebra_evpn_es_br_port_dplane_update(es, __func__);
zebra_evpn_es_vtep_free(es_vtep);
}
}
@@ -1449,7 +1540,14 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
false /* es_evi_re_reval */);
/* See if the local VTEP can function as DF on the ES */
- zebra_evpn_es_run_df_election(es, __func__);
+ if (!zebra_evpn_es_run_df_election(es, __func__)) {
+ /* check if the dplane entry needs to be re-programmed as a
+ * result of some thing other than DF status change
+ */
+ if (zebra_evpn_es_br_port_dplane_update_needed(es))
+ zebra_evpn_es_br_port_dplane_update(es, __func__);
+ }
+
/* Setup ES-EVIs for all VxLAN stretched VLANs associated with
* the zif
@@ -1467,6 +1565,7 @@ static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
{
struct zebra_if *zif;
struct zebra_evpn_es *es = *esp;
+ bool dplane_updated = false;
if (!(es->flags & ZEBRA_EVPNES_LOCAL))
return;
@@ -1474,7 +1573,7 @@ static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP);
/* remove the DF filter */
- zebra_evpn_es_run_df_election(es, __func__);
+ dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
/* if there any local macs referring to the ES as dest we
* need to clear the static reference on them
@@ -1482,6 +1581,10 @@ static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
zebra_evpn_es_local_mac_update(es,
true /* force_clear_static */);
+ /* flush the BUM filters and backup NHG */
+ if (!dplane_updated)
+ zebra_evpn_es_br_port_dplane_clear(es);
+
/* clear the es from the parent interface */
zif = es->zif;
zif->es_info.es = NULL;
@@ -1670,6 +1773,11 @@ static int zebra_evpn_remote_es_add(esi_t *esi, struct in_addr vtep_ip,
}
}
+ if (df_alg != EVPN_MH_DF_ALG_PREF)
+ zlog_warn("remote es %s vtep %s add %s with unsupported df_alg %d",
+ esi_to_str(esi, buf, sizeof(buf)),
+ inet_ntoa(vtep_ip), esr_rxed ? "esr" : "", df_alg);
+
zebra_evpn_es_vtep_add(es, vtep_ip, esr_rxed, df_alg, df_pref);
zebra_evpn_es_remote_info_re_eval(&es);
diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h
index a3ed09209d..da3c31df95 100644
--- a/zebra/zebra_evpn_mh.h
+++ b/zebra/zebra_evpn_mh.h
@@ -55,6 +55,10 @@ struct zebra_evpn_es {
* VTEP is not the DF
*/
#define ZEBRA_EVPNES_NON_DF (1 << 5)
+/* When the ES becomes a bridge port we need to activate the BUM non-DF
+ * filter, SPH filter and backup NHG for fast-failover
+ */
+#define ZEBRA_EVPNES_BR_PORT (1 << 6)
/* memory used for adding the es to zmh_info->es_rb_tree */
RB_ENTRY(zebra_evpn_es) rb_node;
@@ -127,6 +131,7 @@ struct zebra_evpn_es_vtep {
uint32_t flags;
/* Rxed Type-4 route from this VTEP */
#define ZEBRA_EVPNES_VTEP_RXED_ESR (1 << 0)
+#define ZEBRA_EVPNES_VTEP_DEL_IN_PROG (1 << 1)
/* memory used for adding the entry to es->es_vtep_list */
struct listnode es_listnode;