summaryrefslogtreecommitdiff
path: root/zebra/zebra_evpn_mh.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_evpn_mh.c')
-rw-r--r--zebra/zebra_evpn_mh.c312
1 files changed, 225 insertions, 87 deletions
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 53412a434e..7e712bf1ee 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -63,13 +63,14 @@ static void zebra_evpn_es_get_one_base_evpn(void);
static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
zebra_evpn_t *zevpn, bool add);
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 int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi);
static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
const char *caller);
static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set);
-static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es);
+static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
+ bool resync_dplane);
static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es);
+static void zebra_evpn_mh_startup_delay_timer_start(const char *rc);
esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
@@ -416,15 +417,12 @@ void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail)
vty_out(vty, "Type: L local, R remote\n");
vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
}
+ zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json_array, detail);
} else {
if (!uj)
vty_out(vty, "VNI %d doesn't exist\n", vni);
-
- return;
}
- zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json_array, detail);
-
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
@@ -935,7 +933,7 @@ void zebra_evpn_if_init(struct zebra_if *zif)
/* if an es_id and sysmac are already present against the interface
* activate it
*/
- zebra_evpn_local_es_update(zif, zif->es_info.lid, &zif->es_info.sysmac);
+ zebra_evpn_local_es_update(zif, &zif->es_info.esi);
}
/* handle deletion of an access port by removing it from all associated
@@ -1469,16 +1467,16 @@ static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
/* 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)
+ const char *caller, const char *reason)
{
bool old_non_df;
old_non_df = !!(es->flags & ZEBRA_EVPNES_NON_DF);
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("df-change(%s) es %s old %s new %s", caller,
- es->esi_str, old_non_df ? "non-df" : "df",
- new_non_df ? "non-df" : "df");
+ zlog_debug("df-change es %s %s to %s; %s: %s", es->esi_str,
+ old_non_df ? "non-df" : "df",
+ new_non_df ? "non-df" : "df", caller, reason);
if (old_non_df == new_non_df)
return false;
@@ -1506,7 +1504,8 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
*/
if (!(es->flags & ZEBRA_EVPNES_LOCAL)
|| !zmh_info->es_originator_ip.s_addr)
- return zebra_evpn_es_df_change(es, new_non_df, caller);
+ return zebra_evpn_es_df_change(es, new_non_df, caller,
+ "not-ready");
/* 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
@@ -1514,7 +1513,18 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
*/
if (!(es->flags & ZEBRA_EVPNES_OPER_UP)) {
new_non_df = true;
- return zebra_evpn_es_df_change(es, new_non_df, caller);
+ return zebra_evpn_es_df_change(es, new_non_df, caller,
+ "oper-down");
+ }
+
+ /* ES was just created; we need to wait for the peers to rx the
+ * our Type-4 routes and for the switch to import the peers' Type-4
+ * routes
+ */
+ if (es->df_delay_timer) {
+ new_non_df = true;
+ return zebra_evpn_es_df_change(es, new_non_df, caller,
+ "df-delay");
}
for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
@@ -1546,7 +1556,7 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
}
}
- return zebra_evpn_es_df_change(es, new_non_df, caller);
+ return zebra_evpn_es_df_change(es, new_non_df, caller, "elected");
}
static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
@@ -1636,6 +1646,9 @@ static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi)
{
struct zebra_evpn_es *es;
+ if (!memcmp(esi, zero_esi, sizeof(esi_t)))
+ return NULL;
+
es = XCALLOC(MTYPE_ZES, sizeof(struct zebra_evpn_es));
/* fill in ESI */
@@ -1851,6 +1864,8 @@ static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
uint16_t vid;
struct zebra_evpn_access_bd *acc_bd;
+ if (!bf_is_inited(zif->vlan_bitmap))
+ return;
bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
acc_bd = zebra_evpn_acc_vl_find(vid);
@@ -1928,6 +1943,37 @@ static void zebra_evpn_mh_dup_addr_detect_off(void)
}
}
+/* On config of first local-ES turn off advertisement of STALE/DELAY/PROBE
+ * neighbors
+ */
+static void zebra_evpn_mh_advertise_reach_neigh_only(void)
+{
+ if (zmh_info->flags & ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY)
+ return;
+
+ zmh_info->flags |= ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY;
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("evpn-mh: only REACHABLE neigh advertised");
+
+ /* XXX - if STALE/DELAY/PROBE neighs were previously advertised we
+ * need to withdraw them
+ */
+}
+
+static int zebra_evpn_es_df_delay_exp_cb(struct thread *t)
+{
+ struct zebra_evpn_es *es;
+
+ es = THREAD_ARG(t);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("es %s df-delay expired", es->esi_str);
+
+ zebra_evpn_es_run_df_election(es, __func__);
+
+ return 0;
+}
+
static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
struct zebra_if *zif)
{
@@ -1939,6 +1985,7 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
es->nhg_id, zif->ifp->name);
zebra_evpn_mh_dup_addr_detect_off();
+ zebra_evpn_mh_advertise_reach_neigh_only();
es->flags |= ZEBRA_EVPNES_LOCAL;
listnode_init(&es->local_es_listnode, es);
@@ -1967,6 +2014,12 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
zebra_evpn_es_re_eval_send_to_client(es,
false /* es_evi_re_reval */);
+ /* Start the DF delay timer on the local ES */
+ if (!es->df_delay_timer)
+ thread_add_timer(zrouter.master, zebra_evpn_es_df_delay_exp_cb,
+ es, ZEBRA_EVPN_MH_DF_DELAY_TIME,
+ &es->df_delay_timer);
+
/* See if the local VTEP can function as DF on the ES */
if (!zebra_evpn_es_run_df_election(es, __func__)) {
/* check if the dplane entry needs to be re-programmed as a
@@ -1989,7 +2042,7 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
false /* force_clear_static */);
/* inherit EVPN protodown flags on the access port */
- zebra_evpn_mh_update_protodown_es(es);
+ zebra_evpn_mh_update_protodown_es(es, true /*resync_dplane*/);
}
static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
@@ -2003,6 +2056,8 @@ static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP);
+ THREAD_OFF(es->df_delay_timer);
+
/* remove the DF filter */
dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
@@ -2090,17 +2145,50 @@ static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es **esp)
/* A new local es is created when a local-es-id and sysmac is configured
* against an interface.
*/
-static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
- struct ethaddr *sysmac)
+static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi)
{
struct zebra_evpn_es *old_es = zif->es_info.es;
struct zebra_evpn_es *es;
+
+ memcpy(&zif->es_info.esi, esi, sizeof(*esi));
+ if (old_es && !memcmp(&old_es->esi, esi, sizeof(*esi)))
+ /* dup - nothing to be done */
+ return 0;
+
+ /* release the old_es against the zif */
+ if (old_es)
+ zebra_evpn_local_es_del(&old_es);
+
+ es = zebra_evpn_es_find(esi);
+ if (es) {
+ /* if it exists against another interface flag an error */
+ if (es->zif && es->zif != zif) {
+ memset(&zif->es_info.esi, 0, sizeof(*esi));
+ return -1;
+ }
+ } else {
+ /* create new es */
+ es = zebra_evpn_es_new(esi);
+ }
+
+ if (es)
+ zebra_evpn_es_local_info_set(es, zif);
+
+ return 0;
+}
+
+static int zebra_evpn_type3_esi_update(struct zebra_if *zif, uint32_t lid,
+ struct ethaddr *sysmac)
+{
+ struct zebra_evpn_es *old_es = zif->es_info.es;
esi_t esi;
int offset = 0;
int field_bytes = 0;
/* Complete config of the ES-ID bootstraps the ES */
if (!lid || is_zero_mac(sysmac)) {
+ /* clear old esi */
+ memset(&zif->es_info.esi, 0, sizeof(zif->es_info.esi));
/* if in ES is attached to zif delete it */
if (old_es)
zebra_evpn_local_es_del(&old_es);
@@ -2122,27 +2210,7 @@ static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
esi.val[offset++] = (uint8_t)(lid >> 8);
esi.val[offset++] = (uint8_t)lid;
- if (old_es && !memcmp(&old_es->esi, &esi, sizeof(esi_t)))
- /* dup - nothing to be done */
- return 0;
-
- /* release the old_es against the zif */
- if (old_es)
- zebra_evpn_local_es_del(&old_es);
-
- es = zebra_evpn_es_find(&esi);
- if (es) {
- /* if it exists against another interface flag an error */
- if (es->zif && es->zif != zif)
- return -1;
- } else {
- /* create new es */
- es = zebra_evpn_es_new(&esi);
- }
-
- zebra_evpn_es_local_info_set(es, zif);
-
- return 0;
+ return zebra_evpn_local_es_update(zif, &esi);
}
static int zebra_evpn_remote_es_del(esi_t *esi, struct in_addr vtep_ip)
@@ -2349,7 +2417,7 @@ static int zebra_evpn_es_sys_mac_update(struct zebra_if *zif,
{
int rv;
- rv = zebra_evpn_local_es_update(zif, zif->es_info.lid, sysmac);
+ rv = zebra_evpn_type3_esi_update(zif, zif->es_info.lid, sysmac);
if (!rv)
memcpy(&zif->es_info.sysmac, sysmac, sizeof(struct ethaddr));
@@ -2361,13 +2429,29 @@ static int zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid)
{
int rv;
- rv = zebra_evpn_local_es_update(zif, lid, &zif->es_info.sysmac);
+ rv = zebra_evpn_type3_esi_update(zif, lid, &zif->es_info.sysmac);
if (!rv)
zif->es_info.lid = lid;
return rv;
}
+/* type-0 esi has changed */
+static int zebra_evpn_es_type0_esi_update(struct zebra_if *zif, esi_t *esi)
+{
+ int rv;
+
+ rv = zebra_evpn_local_es_update(zif, esi);
+
+ /* clear the old es_lid, es_sysmac - type-0 is being set so old
+ * type-3 params need to be flushed
+ */
+ memset(&zif->es_info.sysmac, 0, sizeof(struct ethaddr));
+ zif->es_info.lid = 0;
+
+ return rv;
+}
+
void zebra_evpn_es_cleanup(void)
{
struct zebra_evpn_es *es;
@@ -2425,10 +2509,10 @@ void zebra_evpn_if_es_print(struct vty *vty, struct zebra_if *zif)
char buf[ETHER_ADDR_STRLEN];
char mh_buf[80];
bool vty_print = false;
+ char esi_buf[ESI_STR_LEN];
mh_buf[0] = '\0';
- snprintf(mh_buf + strlen(mh_buf), sizeof(mh_buf) - strlen(mh_buf),
- " EVPN-MH:");
+ strlcat(mh_buf, " EVPN-MH:", sizeof(mh_buf));
if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac)) {
vty_print = true;
snprintf(
@@ -2436,17 +2520,21 @@ void zebra_evpn_if_es_print(struct vty *vty, struct zebra_if *zif)
sizeof(mh_buf) - strlen(mh_buf),
" ES id %u ES sysmac %s", zif->es_info.lid,
prefix_mac2str(&zif->es_info.sysmac, buf, sizeof(buf)));
+ } else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi))) {
+ vty_print = true;
+ snprintf(mh_buf + strnlen(mh_buf, sizeof(mh_buf)),
+ sizeof(mh_buf) - strnlen(mh_buf, sizeof(mh_buf)),
+ " ES id %s",
+ esi_to_str(&zif->es_info.esi, esi_buf,
+ sizeof(esi_buf)));
}
if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK) {
vty_print = true;
if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)
- snprintf(mh_buf + strlen(mh_buf),
- sizeof(mh_buf) - strlen(mh_buf), " uplink-up");
+ strlcat(mh_buf, " uplink (up)", sizeof(mh_buf));
else
- snprintf(mh_buf + strlen(mh_buf),
- sizeof(mh_buf) - strlen(mh_buf),
- " uplink-down");
+ strlcat(mh_buf, " uplink (down)", sizeof(mh_buf));
}
if (vty_print)
@@ -2659,6 +2747,7 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
char alg_buf[EVPN_DF_ALG_STR_LEN];
struct zebra_evpn_es_vtep *es_vtep;
struct listnode *node;
+ char thread_buf[THREAD_TIMER_STRLEN];
if (json) {
json_object *json_vteps;
@@ -2695,6 +2784,12 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
listcount(es->es_evi_list));
json_object_int_add(json, "macCount", listcount(es->mac_list));
json_object_int_add(json, "dfPreference", es->df_pref);
+ if (es->df_delay_timer)
+ json_object_string_add(
+ json, "dfDelayTimer",
+ thread_timer_to_hhmmss(thread_buf,
+ sizeof(thread_buf),
+ es->df_delay_timer));
json_object_int_add(json, "nexthopGroup", es->nhg_id);
if (listcount(es->es_vtep_list)) {
json_vteps = json_object_new_array();
@@ -2729,9 +2824,16 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
"yes" : "no");
vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
vty_out(vty, " MAC Count: %d\n", listcount(es->mac_list));
- vty_out(vty, " DF: status: %s preference: %u\n",
- (es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df" : "df",
- es->df_pref);
+ if (es->flags & ZEBRA_EVPNES_LOCAL)
+ vty_out(vty, " DF status: %s \n",
+ (es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df"
+ : "df");
+ if (es->df_delay_timer)
+ vty_out(vty, " DF delay: %s\n",
+ thread_timer_to_hhmmss(thread_buf,
+ sizeof(thread_buf),
+ es->df_delay_timer));
+ vty_out(vty, " DF preference: %u\n", es->df_pref);
vty_out(vty, " Nexthop group: %u\n", es->nhg_id);
vty_out(vty, " VTEPs:\n");
for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
@@ -2833,14 +2935,25 @@ int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp)
{
struct zebra_if *zif = ifp->info;
char buf[ETHER_ADDR_STRLEN];
+ bool type_3_esi = false;
+ char esi_buf[ESI_STR_LEN];
- if (zif->es_info.lid)
+ if (zif->es_info.lid) {
vty_out(vty, " evpn mh es-id %u\n", zif->es_info.lid);
+ type_3_esi = true;
+ }
- if (!is_zero_mac(&zif->es_info.sysmac))
+ if (!is_zero_mac(&zif->es_info.sysmac)) {
vty_out(vty, " evpn mh es-sys-mac %s\n",
prefix_mac2str(&zif->es_info.sysmac,
buf, sizeof(buf)));
+ type_3_esi = true;
+ }
+
+ if (!type_3_esi
+ && memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi)))
+ vty_out(vty, " evpn mh es-id %s\n",
+ esi_to_str(&zif->es_info.esi, esi_buf, sizeof(esi_buf)));
if (zif->es_info.df_pref)
vty_out(vty, " evpn mh es-df-pref %u\n", zif->es_info.df_pref);
@@ -2929,22 +3042,28 @@ DEFPY(zebra_evpn_es_sys_mac,
/* CLI for setting up local-ID part of ESI on an access port */
DEFPY(zebra_evpn_es_id,
zebra_evpn_es_id_cmd,
- "[no$no] evpn mh es-id [(1-16777215)$es_lid]",
+ "[no$no] evpn mh es-id [(1-16777215)$es_lid | NAME$esi_str]",
NO_STR
"EVPN\n"
EVPN_MH_VTY_STR
- "Ethernet segment local identifier\n"
- "ID\n"
+ "Ethernet segment identifier\n"
+ "local discriminator\n"
+ "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n"
)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct zebra_if *zif;
- int ret;
+ int ret = 0;
+ esi_t esi;
zif = ifp->info;
if (no) {
- ret = zebra_evpn_es_lid_update(zif, 0);
+ if (zif->es_info.lid)
+ ret = zebra_evpn_es_lid_update(zif, 0);
+ else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi)))
+ ret = zebra_evpn_es_type0_esi_update(zif, zero_esi);
+
if (ret == -1) {
vty_out(vty, "%%Failed to clear ES local id\n");
return CMD_WARNING;
@@ -2956,14 +3075,23 @@ DEFPY(zebra_evpn_es_id,
return CMD_WARNING;
}
- if (!es_lid) {
- vty_out(vty, "%%Specify local ES ID\n");
- return CMD_WARNING;
+ if (esi_str) {
+ if (!str_to_esi(esi_str, &esi)) {
+ vty_out(vty, "%% Malformed ESI\n");
+ return CMD_WARNING;
+ }
+ ret = zebra_evpn_es_type0_esi_update(zif, &esi);
+ } else {
+ if (!es_lid) {
+ vty_out(vty, "%%Specify local ES ID\n");
+ return CMD_WARNING;
+ }
+ ret = zebra_evpn_es_lid_update(zif, es_lid);
}
- ret = zebra_evpn_es_lid_update(zif, es_lid);
+
if (ret == -1) {
vty_out(vty,
- "%%ESI already exists on a different interface\n");
+ "%%ESI already exists on a different interface\n");
return CMD_WARNING;
}
}
@@ -3029,7 +3157,7 @@ void zebra_evpn_mh_print(struct vty *vty)
vty_out(vty, " uplink-cfg-cnt: %u, uplink-active-cnt: %u\n",
zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
if (zmh_info->protodown_rc)
- vty_out(vty, " protodown: %s\n",
+ vty_out(vty, " protodown reasons: %s\n",
zebra_protodown_rc_str(zmh_info->protodown_rc, pd_buf,
sizeof(pd_buf)));
}
@@ -3174,16 +3302,14 @@ void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if *zif, bool clear,
protodown_rc = bond_zif->protodown_rc;
}
- if (zif->protodown_rc == protodown_rc)
- return;
-
old_protodown = !!(zif->flags & ZIF_FLAG_PROTODOWN);
old_protodown_rc = zif->protodown_rc;
zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
zif->protodown_rc |= (protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
new_protodown = !!zif->protodown_rc;
- if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES
+ && (zif->protodown_rc != old_protodown_rc))
zlog_debug(
"%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
caller, zif->ifp->name, old_protodown_rc,
@@ -3220,14 +3346,20 @@ static void zebra_evpn_mh_update_protodown_bond(struct zebra_if *bond_zif)
}
/* The global EVPN MH protodown rc is applied to all local ESs */
-static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es)
+static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
+ bool resync_dplane)
{
struct zebra_if *zif;
enum protodown_reasons old_protodown_rc;
zif = es->zif;
- if ((zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL)
- == (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
+ /* if the reason code is the same bail unless it is a new
+ * ES bond in that case we would need to ensure that the
+ * dplane is really in sync with zebra
+ */
+ if (!resync_dplane
+ && (zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL)
+ == (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
return;
old_protodown_rc = zif->protodown_rc;
@@ -3235,7 +3367,8 @@ static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es)
zif->protodown_rc |=
(zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
- if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES
+ && (old_protodown_rc != zif->protodown_rc))
zlog_debug(
"es %s ifp %s protodown_rc changed; old 0x%x new 0x%x",
es->esi_str, zif->ifp->name, old_protodown_rc,
@@ -3273,7 +3406,7 @@ static void zebra_evpn_mh_update_protodown_es_all(void)
struct zebra_evpn_es *es;
for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es))
- zebra_evpn_mh_update_protodown_es(es);
+ zebra_evpn_mh_update_protodown_es(es, false /*resync_dplane*/);
}
static void zebra_evpn_mh_update_protodown(enum protodown_reasons protodown_rc,
@@ -3381,6 +3514,13 @@ void zebra_evpn_mh_uplink_oper_update(struct zebra_if *zif)
if (old_protodown == new_protodown)
return;
+ /* if protodown_rc XXX_UPLINK_DOWN is about to be cleared
+ * fire up the start-up delay timer to allow the EVPN network
+ * to converge (Type-2 routes need to be advertised and processed)
+ */
+ if (!new_protodown && (zmh_info->uplink_oper_up_cnt == 1))
+ zebra_evpn_mh_startup_delay_timer_start("uplink-up");
+
zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN,
new_protodown);
}
@@ -3396,26 +3536,19 @@ static int zebra_evpn_mh_startup_delay_exp_cb(struct thread *t)
return 0;
}
-static void zebra_evpn_mh_startup_delay_timer_start(bool init)
+static void zebra_evpn_mh_startup_delay_timer_start(const char *rc)
{
- /* 1. This timer can be started during init.
- * 2. It can also be restarted if it is alreay running and the
- * admin wants to increase or decrease its value
- */
- if (!init && !zmh_info->startup_delay_timer)
- return;
-
if (zmh_info->startup_delay_timer) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("startup-delay timer cancelled");
- thread_cancel(&zmh_info->startup_delay_timer);
- zmh_info->startup_delay_timer = NULL;
+ THREAD_OFF(zmh_info->startup_delay_timer);
}
if (zmh_info->startup_delay_time) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("startup-delay timer started for %d sec",
- zmh_info->startup_delay_time);
+ zlog_debug(
+ "startup-delay timer started for %d sec on %s",
+ zmh_info->startup_delay_time, rc);
thread_add_timer(zrouter.master,
zebra_evpn_mh_startup_delay_exp_cb, NULL,
zmh_info->startup_delay_time,
@@ -3476,7 +3609,12 @@ int zebra_evpn_mh_startup_delay_update(struct vty *vty, uint32_t duration,
duration = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
zmh_info->startup_delay_time = duration;
- zebra_evpn_mh_startup_delay_timer_start(false /* init */);
+
+ /* if startup_delay_timer is running allow it to be adjusted
+ * up or down
+ */
+ if (zmh_info->startup_delay_timer)
+ zebra_evpn_mh_startup_delay_timer_start("config");
return 0;
}
@@ -3526,7 +3664,7 @@ void zebra_evpn_mh_init(void)
zebra_evpn_acc_vl_cmp, "access VLAN hash table");
zmh_info->startup_delay_time = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
- zebra_evpn_mh_startup_delay_timer_start(true /*init*/);
+ zebra_evpn_mh_startup_delay_timer_start("init");
}
void zebra_evpn_mh_terminate(void)