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.c475
1 files changed, 440 insertions, 35 deletions
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 7a383ef8c2..b08adc5541 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -38,6 +38,7 @@
#include "zebra/rib.h"
#include "zebra/rt.h"
#include "zebra/rt_netlink.h"
+#include "zebra/if_netlink.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_l2.h"
#include "zebra/zebra_memory.h"
@@ -65,6 +66,9 @@ 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);
+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_clear_protodown_es(struct zebra_evpn_es *es);
esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
@@ -1020,8 +1024,8 @@ static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
nh_ids[i].id);
strlcat(nh_str, nh_buf, sizeof(nh_str));
}
- zlog_debug("es %s nhg 0x%x add %s",
- es->esi_str, es->nhg_id, nh_str);
+ zlog_debug("es %s nhg %u add %s", es->esi_str,
+ es->nhg_id, nh_str);
}
es->flags |= ZEBRA_EVPNES_NHG_ACTIVE;
@@ -1036,8 +1040,8 @@ static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
} 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);
+ zlog_debug("es %s nhg %u 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))
@@ -1061,9 +1065,8 @@ static void zebra_evpn_nh_add(struct zebra_evpn_es_vtep *es_vtep)
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
- zlog_debug("es %s vtep %pI4 nh 0x%x add",
- es_vtep->es->esi_str,
- &es_vtep->vtep_ip, es_vtep->nh_id);
+ zlog_debug("es %s vtep %pI4 nh %u add", es_vtep->es->esi_str,
+ &es_vtep->vtep_ip, es_vtep->nh_id);
/* install the NH */
kernel_upd_mac_nh(es_vtep->nh_id, es_vtep->vtep_ip);
/* add the NH to the parent NHG */
@@ -1078,9 +1081,8 @@ static void zebra_evpn_nh_del(struct zebra_evpn_es_vtep *es_vtep)
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
- zlog_debug("es %s vtep %pI4 nh 0x%x del",
- es_vtep->es->esi_str,
- &es_vtep->vtep_ip, es_vtep->nh_id);
+ zlog_debug("es %s vtep %pI4 nh %u del", es_vtep->es->esi_str,
+ &es_vtep->vtep_ip, es_vtep->nh_id);
nh_id = es_vtep->nh_id;
es_vtep->nh_id = 0;
@@ -1423,7 +1425,7 @@ static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi)
es->nhg_id = zebra_evpn_nhid_alloc(true);
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("es %s nhg 0x%x new", es->esi_str, es->nhg_id);
+ zlog_debug("es %s nhg %u new", es->esi_str, es->nhg_id);
return es;
}
@@ -1663,8 +1665,8 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("local es %s add; nhg 0x%x if %s",
- es->esi_str, es->nhg_id, zif->ifp->name);
+ zlog_debug("local es %s add; nhg %u if %s", es->esi_str,
+ es->nhg_id, zif->ifp->name);
es->flags |= ZEBRA_EVPNES_LOCAL;
listnode_init(&es->local_es_listnode, es);
@@ -1713,6 +1715,9 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
*/
zebra_evpn_es_local_mac_update(es,
false /* force_clear_static */);
+
+ /* inherit EVPN protodown flags on the access port */
+ zebra_evpn_mh_update_protodown_es(es);
}
static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
@@ -1729,6 +1734,9 @@ static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
/* remove the DF filter */
dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
+ /* clear EVPN protodown flags on the access port */
+ zebra_evpn_mh_clear_protodown_es(es);
+
/* if there any local macs referring to the ES as dest we
* need to clear the static reference on them
*/
@@ -1768,9 +1776,8 @@ static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp)
if (IS_ZEBRA_DEBUG_EVPN_MH_ES) {
zif = es->zif;
- zlog_debug("local es %s del; nhg 0x%x if %s",
- es->esi_str, es->nhg_id,
- zif ? zif->ifp->name : "-");
+ zlog_debug("local es %s del; nhg %u if %s", es->esi_str,
+ es->nhg_id, zif ? zif->ifp->name : "-");
}
/* remove all ES-EVIs associated with the ES */
@@ -1794,15 +1801,15 @@ static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es **esp)
if (!(es->flags & ZEBRA_EVPNES_REMOTE)) {
es->flags |= ZEBRA_EVPNES_REMOTE;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("remote es %s add; nhg 0x%x",
- es->esi_str, es->nhg_id);
+ zlog_debug("remote es %s add; nhg %u",
+ es->esi_str, es->nhg_id);
}
} else {
if (es->flags & ZEBRA_EVPNES_REMOTE) {
es->flags &= ~ZEBRA_EVPNES_REMOTE;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("remote es %s del; nhg 0x%x",
- es->esi_str, es->nhg_id);
+ zlog_debug("remote es %s del; nhg %u",
+ es->esi_str, es->nhg_id);
zebra_evpn_es_free(esp);
}
}
@@ -2144,12 +2151,34 @@ bool zebra_evpn_is_if_es_capable(struct zebra_if *zif)
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;
+
+ mh_buf[0] = '\0';
+ snprintf(mh_buf + strlen(mh_buf), sizeof(mh_buf) - strlen(mh_buf),
+ " EVPN-MH:");
+ if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac)) {
+ vty_print = true;
+ snprintf(
+ mh_buf + strlen(mh_buf),
+ 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)));
+ }
+
+ 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");
+ else
+ snprintf(mh_buf + strlen(mh_buf),
+ sizeof(mh_buf) - strlen(mh_buf),
+ " uplink-down");
+ }
- if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac))
- vty_out(vty, " EVPN MH: ES id %u ES sysmac %s\n",
- zif->es_info.lid,
- prefix_mac2str(&zif->es_info.sysmac,
- buf, sizeof(buf)));
+ if (vty_print)
+ vty_out(vty, "%s\n", mh_buf);
}
void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up)
@@ -2366,7 +2395,7 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
vty_out(vty, " DF: status: %s preference: %u\n",
(es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df" : "df",
es->df_pref);
- vty_out(vty, " Nexthop group: 0x%x\n", es->nhg_id);
+ 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)) {
vty_out(vty, " %pI4",
@@ -2377,7 +2406,7 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
alg_buf,
sizeof(alg_buf)),
es_vtep->df_pref);
- vty_out(vty, " nh: 0x%x\n", es_vtep->nh_id);
+ vty_out(vty, " nh: %u\n", es_vtep->nh_id);
}
vty_out(vty, "\n");
@@ -2478,6 +2507,9 @@ int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp)
if (zif->es_info.df_pref)
vty_out(vty, " evpn mh es-df-pref %u\n", zif->es_info.df_pref);
+ if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK)
+ vty_out(vty, " evpn mh uplink\n");
+
return 0;
}
@@ -2600,6 +2632,70 @@ DEFPY(zebra_evpn_es_id,
return CMD_SUCCESS;
}
+/* CLI for tagging an interface as an uplink */
+DEFPY(zebra_evpn_mh_uplink, zebra_evpn_mh_uplink_cmd, "[no] evpn mh uplink",
+ NO_STR "EVPN\n" EVPN_MH_VTY_STR "uplink to the VxLAN core\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct zebra_if *zif;
+
+ zif = ifp->info;
+ zebra_evpn_mh_uplink_cfg_update(zif, no ? false : true);
+
+ return CMD_SUCCESS;
+}
+
+void zebra_evpn_mh_json(json_object *json)
+{
+ json_object *json_array;
+ char thread_buf[THREAD_TIMER_STRLEN];
+
+ json_object_int_add(json, "macHoldtime", zmh_info->mac_hold_time);
+ json_object_int_add(json, "neighHoldtime", zmh_info->neigh_hold_time);
+ json_object_int_add(json, "startupDelay", zmh_info->startup_delay_time);
+ json_object_string_add(
+ json, "startupDelayTimer",
+ thread_timer_to_hhmmss(thread_buf, sizeof(thread_buf),
+ zmh_info->startup_delay_timer));
+ json_object_int_add(json, "uplinkConfigCount",
+ zmh_info->uplink_cfg_cnt);
+ json_object_int_add(json, "uplinkActiveCount",
+ zmh_info->uplink_oper_up_cnt);
+
+ if (zmh_info->protodown_rc) {
+ json_array = json_object_new_array();
+ if (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY)
+ json_object_array_add(
+ json_array,
+ json_object_new_string("startupDelay"));
+ if (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN)
+ json_object_array_add(
+ json_array,
+ json_object_new_string("uplinkDown"));
+ json_object_object_add(json, "protodownReasons", json_array);
+ }
+}
+
+void zebra_evpn_mh_print(struct vty *vty)
+{
+ char pd_buf[ZEBRA_PROTODOWN_RC_STR_LEN];
+ char thread_buf[THREAD_TIMER_STRLEN];
+
+ vty_out(vty, "EVPN MH:\n");
+ vty_out(vty, " mac-holdtime: %ds, neigh-holdtime: %ds\n",
+ zmh_info->mac_hold_time, zmh_info->neigh_hold_time);
+ vty_out(vty, " startup-delay: %ds, start-delay-timer: %s\n",
+ zmh_info->startup_delay_time,
+ thread_timer_to_hhmmss(thread_buf, sizeof(thread_buf),
+ zmh_info->startup_delay_timer));
+ 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",
+ zebra_protodown_rc_str(zmh_info->protodown_rc, pd_buf,
+ sizeof(pd_buf)));
+}
+
/*****************************************************************************/
/* A base L2-VNI is maintained to derive parameters such as ES originator-IP.
* XXX: once single vxlan device model becomes available this will not be
@@ -2705,23 +2801,316 @@ static void zebra_evpn_es_get_one_base_evpn(void)
hash_walk(zvrf->evpn_table, zebra_evpn_es_get_one_base_evpn_cb, NULL);
}
+/*****************************************************************************
+ * local ethernet segments can be error-disabled if the switch is not
+ * ready to start transmitting traffic via the VxLAN overlay
+ */
+bool zebra_evpn_is_es_bond(struct interface *ifp)
+{
+ struct zebra_if *zif = ifp->info;
+
+ return !!(struct zebra_if *)zif->es_info.es;
+}
+
+bool zebra_evpn_is_es_bond_member(struct interface *ifp)
+{
+ struct zebra_if *zif = ifp->info;
+
+ return IS_ZEBRA_IF_BOND_SLAVE(zif->ifp) && zif->bondslave_info.bond_if
+ && ((struct zebra_if *)zif->bondslave_info.bond_if->info)
+ ->es_info.es;
+}
+
+void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if *zif, bool clear,
+ const char *caller)
+{
+ bool old_protodown;
+ bool new_protodown;
+ enum protodown_reasons old_protodown_rc = 0;
+ enum protodown_reasons protodown_rc = 0;
+
+ if (!clear) {
+ struct zebra_if *bond_zif;
+
+ bond_zif = zif->bondslave_info.bond_if->info;
+ 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)
+ zlog_debug(
+ "%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
+ caller, zif->ifp->name, old_protodown_rc,
+ zif->protodown_rc);
+
+ if (old_protodown == new_protodown)
+ return;
+
+ if (new_protodown)
+ zif->flags |= ZIF_FLAG_PROTODOWN;
+ else
+ zif->flags &= ~ZIF_FLAG_PROTODOWN;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("%s protodown %s", zif->ifp->name,
+ new_protodown ? "on" : "off");
+
+ zebra_if_set_protodown(zif->ifp, new_protodown);
+}
+
+/* The bond members inherit the protodown reason code from the bond */
+static void zebra_evpn_mh_update_protodown_bond(struct zebra_if *bond_zif)
+{
+ struct zebra_if *zif;
+ struct listnode *node;
+
+ if (!bond_zif->bond_info.mbr_zifs)
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO(bond_zif->bond_info.mbr_zifs, node, zif)) {
+ zebra_evpn_mh_update_protodown_bond_mbr(zif, false /*clear*/,
+ __func__);
+ }
+}
+
+/* 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)
+{
+ 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))
+ return;
+
+ old_protodown_rc = zif->protodown_rc;
+ zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
+ zif->protodown_rc |=
+ (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug(
+ "es %s ifp %s protodown_rc changed; old 0x%x new 0x%x",
+ es->esi_str, zif->ifp->name, old_protodown_rc,
+ zif->protodown_rc);
+
+ /* update dataplane with the new protodown setting */
+ zebra_evpn_mh_update_protodown_bond(zif);
+}
+
+static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es)
+{
+ struct zebra_if *zif;
+ enum protodown_reasons old_protodown_rc;
+
+ zif = es->zif;
+ if (!(zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
+ return;
+
+ old_protodown_rc = zif->protodown_rc;
+ zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug(
+ "clear: es %s ifp %s protodown_rc cleared; old 0x%x new 0x%x",
+ es->esi_str, zif->ifp->name, old_protodown_rc,
+ zif->protodown_rc);
+
+ /* update dataplane with the new protodown setting */
+ zebra_evpn_mh_update_protodown_bond(zif);
+}
+
+static void zebra_evpn_mh_update_protodown_es_all(void)
+{
+ struct listnode *node;
+ struct zebra_evpn_es *es;
+
+ for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es))
+ zebra_evpn_mh_update_protodown_es(es);
+}
+
+static void zebra_evpn_mh_update_protodown(enum protodown_reasons protodown_rc,
+ bool set)
+{
+ enum protodown_reasons old_protodown_rc = zmh_info->protodown_rc;
+
+ if (set) {
+ if ((protodown_rc & zmh_info->protodown_rc) == protodown_rc)
+ return;
+
+ zmh_info->protodown_rc |= protodown_rc;
+ } else {
+ if (!(protodown_rc & zmh_info->protodown_rc))
+ return;
+ zmh_info->protodown_rc &= ~protodown_rc;
+ }
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("mh protodown_rc changed; old 0x%x new 0x%x",
+ old_protodown_rc, zmh_info->protodown_rc);
+ zebra_evpn_mh_update_protodown_es_all();
+}
+
+static inline bool zebra_evpn_mh_is_all_uplinks_down(void)
+{
+ return zmh_info->uplink_cfg_cnt && !zmh_info->uplink_oper_up_cnt;
+}
+
+static void zebra_evpn_mh_uplink_oper_flags_update(struct zebra_if *zif,
+ bool set)
+{
+ if (set) {
+ if (if_is_operative(zif->ifp)) {
+ if (!(zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)) {
+ zif->flags |= ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
+ ++zmh_info->uplink_oper_up_cnt;
+ }
+ } else {
+ if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP) {
+ zif->flags &= ~ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
+ if (zmh_info->uplink_oper_up_cnt)
+ --zmh_info->uplink_oper_up_cnt;
+ }
+ }
+ } else {
+ if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP) {
+ zif->flags &= ~ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
+ if (zmh_info->uplink_oper_up_cnt)
+ --zmh_info->uplink_oper_up_cnt;
+ }
+ }
+}
+
+static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set)
+{
+ bool old_protodown = zebra_evpn_mh_is_all_uplinks_down();
+ bool new_protodown;
+
+ if (set) {
+ if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK)
+ return;
+
+ zif->flags |= ZIF_FLAG_EVPN_MH_UPLINK;
+ ++zmh_info->uplink_cfg_cnt;
+ } else {
+ if (!(zif->flags & ZIF_FLAG_EVPN_MH_UPLINK))
+ return;
+
+ zif->flags &= ~ZIF_FLAG_EVPN_MH_UPLINK;
+ if (zmh_info->uplink_cfg_cnt)
+ --zmh_info->uplink_cfg_cnt;
+ }
+
+ zebra_evpn_mh_uplink_oper_flags_update(zif, set);
+ new_protodown = zebra_evpn_mh_is_all_uplinks_down();
+ if (old_protodown == new_protodown)
+ return;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug(
+ "mh-uplink-cfg-chg on if %s/%d %s uplinks cfg %u up %u",
+ zif->ifp->name, zif->ifp->ifindex, set ? "set" : "down",
+ zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
+
+ zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN,
+ new_protodown);
+}
+
+void zebra_evpn_mh_uplink_oper_update(struct zebra_if *zif)
+{
+ bool old_protodown = zebra_evpn_mh_is_all_uplinks_down();
+ bool new_protodown;
+
+ zebra_evpn_mh_uplink_oper_flags_update(zif, true /*set*/);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug(
+ "mh-uplink-oper-chg on if %s/%d %s; uplinks cfg %u up %u",
+ zif->ifp->name, zif->ifp->ifindex,
+ if_is_operative(zif->ifp) ? "up" : "down",
+ zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
+
+ new_protodown = zebra_evpn_mh_is_all_uplinks_down();
+ if (old_protodown == new_protodown)
+ return;
+
+ zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN,
+ new_protodown);
+}
+
+static int zebra_evpn_mh_startup_delay_exp_cb(struct thread *t)
+{
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("startup-delay expired");
+
+ zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY,
+ false /* set */);
+
+ return 0;
+}
+
+static void zebra_evpn_mh_startup_delay_timer_start(bool init)
+{
+ /* 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;
+ }
+
+ 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);
+ thread_add_timer(zrouter.master,
+ zebra_evpn_mh_startup_delay_exp_cb, NULL,
+ zmh_info->startup_delay_time,
+ &zmh_info->startup_delay_timer);
+ zebra_evpn_mh_update_protodown(
+ ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY, true /* set */);
+ } else {
+ zebra_evpn_mh_update_protodown(
+ ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY, false /* set */);
+ }
+}
+
/*****************************************************************************/
void zebra_evpn_mh_config_write(struct vty *vty)
{
- if (zmh_info->mac_hold_time != EVPN_MH_MAC_HOLD_TIME_DEF)
- vty_out(vty, "evpn mh mac-holdtime %ld\n",
+ if (zmh_info->mac_hold_time != ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF)
+ vty_out(vty, "evpn mh mac-holdtime %d\n",
zmh_info->mac_hold_time);
- if (zmh_info->neigh_hold_time != EVPN_MH_NEIGH_HOLD_TIME_DEF)
- vty_out(vty, "evpn mh neigh-holdtime %ld\n",
+ if (zmh_info->neigh_hold_time != ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF)
+ vty_out(vty, "evpn mh neigh-holdtime %d\n",
zmh_info->neigh_hold_time);
+
+ if (zmh_info->startup_delay_time != ZEBRA_EVPN_MH_STARTUP_DELAY_DEF)
+ vty_out(vty, "evpn mh startup-delay %d\n",
+ zmh_info->startup_delay_time);
}
int zebra_evpn_mh_neigh_holdtime_update(struct vty *vty,
uint32_t duration, bool set_default)
{
if (set_default)
- duration = EVPN_MH_NEIGH_HOLD_TIME_DEF;
+ duration = ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF;
zmh_info->neigh_hold_time = duration;
@@ -2732,26 +3121,39 @@ int zebra_evpn_mh_mac_holdtime_update(struct vty *vty,
uint32_t duration, bool set_default)
{
if (set_default)
- duration = EVPN_MH_MAC_HOLD_TIME_DEF;
+ duration = ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF;
zmh_info->mac_hold_time = duration;
return 0;
}
+int zebra_evpn_mh_startup_delay_update(struct vty *vty, uint32_t duration,
+ bool set_default)
+{
+ if (set_default)
+ duration = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
+
+ zmh_info->startup_delay_time = duration;
+ zebra_evpn_mh_startup_delay_timer_start(false /* init */);
+
+ return 0;
+}
+
void zebra_evpn_interface_init(void)
{
install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd);
install_element(INTERFACE_NODE, &zebra_evpn_es_sys_mac_cmd);
install_element(INTERFACE_NODE, &zebra_evpn_es_pref_cmd);
+ install_element(INTERFACE_NODE, &zebra_evpn_mh_uplink_cmd);
}
void zebra_evpn_mh_init(void)
{
zrouter.mh_info = XCALLOC(MTYPE_ZMH_INFO, sizeof(*zrouter.mh_info));
- zmh_info->mac_hold_time = EVPN_MH_MAC_HOLD_TIME_DEF;
- zmh_info->neigh_hold_time = EVPN_MH_NEIGH_HOLD_TIME_DEF;
+ zmh_info->mac_hold_time = ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF;
+ zmh_info->neigh_hold_time = ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF;
/* setup ES tables */
RB_INIT(zebra_es_rb_head, &zmh_info->es_rb_tree);
zmh_info->local_es_list = list_new();
@@ -2763,6 +3165,9 @@ void zebra_evpn_mh_init(void)
/* setup broadcast domain tables */
zmh_info->evpn_vlan_table = hash_create(zebra_evpn_acc_vl_hash_keymake,
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*/);
}
void zebra_evpn_mh_terminate(void)