summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac1
-rw-r--r--doc/user/isisd.rst4
-rw-r--r--isisd/isis_cli.c41
-rw-r--r--isisd/isis_lsp.c31
-rw-r--r--isisd/isis_lsp.h1
-rw-r--r--isisd/isis_nb.c13
-rw-r--r--isisd/isis_nb.h6
-rw-r--r--isisd/isis_nb_config.c24
-rw-r--r--isisd/isisd.c113
-rw-r--r--isisd/isisd.h10
-rw-r--r--tests/topotests/isis_topo1/test_isis_topo1.py313
-rw-r--r--yang/frr-isisd.yang22
12 files changed, 538 insertions, 41 deletions
diff --git a/configure.ac b/configure.ac
index 4e1080045e..4cbdfe0fcc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2631,6 +2631,7 @@ AC_DEFINE_UNQUOTED([ZEBRA_SERV_PATH], ["$frr_statedir%s%s/zserv.api"], [zebra ap
AC_DEFINE_UNQUOTED([BFDD_CONTROL_SOCKET], ["$frr_statedir%s%s/bfdd.sock"], [bfdd control socket])
AC_DEFINE_UNQUOTED([OSPFD_GR_STATE], ["$frr_statedir%s/ospfd-gr.json"], [ospfd GR state information])
AC_DEFINE_UNQUOTED([OSPF6D_GR_STATE], ["$frr_statedir/ospf6d-gr.json"], [ospf6d GR state information])
+AC_DEFINE_UNQUOTED([ISISD_RESTART], ["$frr_statedir%s/isid-restart.json"], [isisd restart information])
AC_DEFINE_UNQUOTED([OSPF6_AUTH_SEQ_NUM_FILE], ["$frr_statedir/ospf6d-at-seq-no.dat"], [ospf6d AT Sequence number information])
AC_DEFINE_UNQUOTED([DAEMON_VTY_DIR], ["$frr_statedir%s%s"], [daemon vty directory])
AC_DEFINE_UNQUOTED([DAEMON_DB_DIR], ["$frr_statedir"], [daemon database directory])
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst
index 9ccb5ba4b5..2b114ad127 100644
--- a/doc/user/isisd.rst
+++ b/doc/user/isisd.rst
@@ -83,6 +83,10 @@ writing, *isisd* does not support multiple ISIS processes.
Set overload bit to avoid any transit traffic.
+.. clicmd:: set-overload-bit on-startup (0-86400)
+
+ Set overload bit on startup for the specified duration, in seconds. Reference: :rfc:`3277`
+
.. clicmd:: purge-originator
Enable or disable :rfc:`6232` purge originator identification.
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index a673cb8c1e..9db867e2c0 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -404,7 +404,7 @@ DEFPY_YANG(set_overload_bit, set_overload_bit_cmd, "[no] set-overload-bit",
"Reset overload bit to accept transit traffic\n"
"Set overload bit to avoid any transit traffic\n")
{
- nb_cli_enqueue_change(vty, "./overload", NB_OP_MODIFY,
+ nb_cli_enqueue_change(vty, "./overload/enabled", NB_OP_MODIFY,
no ? "false" : "true");
return nb_cli_apply_changes(vty, NULL);
@@ -419,6 +419,42 @@ void cli_show_isis_overload(struct vty *vty, const struct lyd_node *dnode,
}
/*
+ * XPath: /frr-isisd:isis/instance/overload/on-startup
+ */
+DEFPY_YANG(set_overload_bit_on_startup, set_overload_bit_on_startup_cmd,
+ "set-overload-bit on-startup (0-86400)$val",
+ "Set overload bit to avoid any transit traffic\n"
+ "Set overload bit on startup\n"
+ "Set overload time in seconds\n")
+{
+ nb_cli_enqueue_change(vty, "./overload/on-startup", NB_OP_MODIFY,
+ val_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG(no_set_overload_bit_on_startup, no_set_overload_bit_on_startup_cmd,
+ "no set-overload-bit on-startup [(0-86400)$val]",
+ NO_STR
+ "Reset overload bit to accept transit traffic\n"
+ "Set overload bit on startup\n"
+ "Set overload time in seconds\n")
+{
+ nb_cli_enqueue_change(vty, "./overload/on-startup", NB_OP_DESTROY,
+ NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_overload_on_startup(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " set-overload-bit on-startup %s\n",
+ yang_dnode_get_string(dnode, NULL));
+}
+
+/*
* XPath: /frr-isisd:isis/instance/attach-send
*/
DEFPY_YANG(attached_bit_send, attached_bit_send_cmd, "[no] attached-bit send",
@@ -3107,6 +3143,9 @@ void isis_cli_init(void)
install_element(ISIS_NODE, &dynamic_hostname_cmd);
install_element(ISIS_NODE, &set_overload_bit_cmd);
+ install_element(ISIS_NODE, &set_overload_bit_on_startup_cmd);
+ install_element(ISIS_NODE, &no_set_overload_bit_on_startup_cmd);
+
install_element(ISIS_NODE, &attached_bit_send_cmd);
install_element(ISIS_NODE, &attached_bit_receive_ignore_cmd);
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 5387f37039..63b4edb1e1 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -68,6 +68,8 @@ static void lsp_l2_refresh_pseudo(struct thread *thread);
static void lsp_destroy(struct isis_lsp *lsp);
+static bool device_startup;
+
int lsp_id_cmp(uint8_t *id1, uint8_t *id2)
{
return memcmp(id1, id2, ISIS_SYS_ID_LEN + 2);
@@ -437,6 +439,21 @@ bool isis_level2_adj_up(struct isis_area *area)
return false;
}
+/*
+ * Unset the overload bit after the timer expires
+ */
+void set_overload_on_start_timer(struct thread *thread)
+{
+ struct isis_area *area = THREAD_ARG(thread);
+ assert(area);
+
+ area->t_overload_on_startup_timer = NULL;
+
+ /* Check if set-overload-bit is not currently configured */
+ if (!area->overload_configured)
+ isis_area_overload_bit_set(area, false);
+}
+
static void isis_reset_attach_bit(struct isis_adjacency *adj)
{
struct isis_area *area = adj->circuit->area;
@@ -1355,6 +1372,7 @@ int lsp_generate(struct isis_area *area, int level)
uint32_t seq_num = 0;
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
uint16_t rem_lifetime, refresh_time;
+ uint32_t overload_time;
if ((area == NULL) || (area->is_type & level) != level)
return ISIS_ERROR;
@@ -1363,6 +1381,18 @@ int lsp_generate(struct isis_area *area, int level)
memcpy(&lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
+ /* Check if device should be overloaded on startup */
+ if (device_startup) {
+ overload_time = isis_restart_read_overload_time(area);
+ if (overload_time > 0) {
+ isis_area_overload_bit_set(area, true);
+ thread_add_timer(master, set_overload_on_start_timer,
+ area, overload_time,
+ &area->t_overload_on_startup_timer);
+ }
+ device_startup = false;
+ }
+
/* only builds the lsp if the area shares the level */
oldlsp = lsp_search(&area->lspdb[level - 1], lspid);
if (oldlsp) {
@@ -2373,6 +2403,7 @@ int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid,
void lsp_init(void)
{
+ device_startup = true;
hook_register(isis_adj_state_change_hook,
lsp_handle_adj_state_change);
}
diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h
index b13b2a35e6..d7762324d9 100644
--- a/isisd/isis_lsp.h
+++ b/isisd/isis_lsp.h
@@ -66,6 +66,7 @@ DECLARE_RBTREE_UNIQ(lspdb, struct isis_lsp, dbe, lspdb_compare);
void lsp_db_init(struct lspdb_head *head);
void lsp_db_fini(struct lspdb_head *head);
void lsp_tick(struct thread *thread);
+void set_overload_on_start_timer(struct thread *thread);
int lsp_generate(struct isis_area *area, int level);
#define lsp_regenerate_schedule(area, level, all_pseudo) \
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index a2ba33d078..4f4e6dc730 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -81,11 +81,18 @@ const struct frr_yang_module_info frr_isisd_info = {
},
},
{
- .xpath = "/frr-isisd:isis/instance/overload",
+ .xpath = "/frr-isisd:isis/instance/overload/enabled",
.cbs = {
.cli_show = cli_show_isis_overload,
- .modify = isis_instance_overload_modify,
- },
+ .modify = isis_instance_overload_enabled_modify,
+ }
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/overload/on-startup",
+ .cbs = {
+ .cli_show = cli_show_isis_overload_on_startup,
+ .modify = isis_instance_overload_on_startup_modify,
+ }
},
{
.xpath = "/frr-isisd:isis/instance/metric-style",
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index 00ca8be3b0..a9f2eaea95 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -37,7 +37,8 @@ int isis_instance_dynamic_hostname_modify(struct nb_cb_modify_args *args);
int isis_instance_attached_send_modify(struct nb_cb_modify_args *args);
int isis_instance_attached_receive_modify(struct nb_cb_modify_args *args);
int isis_instance_attached_modify(struct nb_cb_modify_args *args);
-int isis_instance_overload_modify(struct nb_cb_modify_args *args);
+int isis_instance_overload_enabled_modify(struct nb_cb_modify_args *args);
+int isis_instance_overload_on_startup_modify(struct nb_cb_modify_args *args);
int isis_instance_metric_style_modify(struct nb_cb_modify_args *args);
int isis_instance_purge_originator_modify(struct nb_cb_modify_args *args);
int isis_instance_lsp_mtu_modify(struct nb_cb_modify_args *args);
@@ -442,6 +443,9 @@ void cli_show_isis_attached_receive(struct vty *vty,
bool show_defaults);
void cli_show_isis_overload(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
+void cli_show_isis_overload_on_startup(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults);
void cli_show_isis_metric_style(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
void cli_show_isis_area_pwd(struct vty *vty, const struct lyd_node *dnode,
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index e0decf48f2..1b7663fcfd 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -336,9 +336,9 @@ int isis_instance_attached_modify(struct nb_cb_modify_args *args)
}
/*
- * XPath: /frr-isisd:isis/instance/overload
+ * XPath: /frr-isisd:isis/instance/overload/enabled
*/
-int isis_instance_overload_modify(struct nb_cb_modify_args *args)
+int isis_instance_overload_enabled_modify(struct nb_cb_modify_args *args)
{
struct isis_area *area;
bool overload;
@@ -348,12 +348,32 @@ int isis_instance_overload_modify(struct nb_cb_modify_args *args)
area = nb_running_get_entry(args->dnode, NULL, true);
overload = yang_dnode_get_bool(args->dnode, NULL);
+ area->overload_configured = overload;
+
isis_area_overload_bit_set(area, overload);
return NB_OK;
}
/*
+ * XPath: /frr-isisd:isis/instance/overload/on-startup
+ */
+int isis_instance_overload_on_startup_modify(struct nb_cb_modify_args *args)
+{
+ struct isis_area *area;
+ uint32_t overload_time;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ overload_time = yang_dnode_get_uint32(args->dnode, NULL);
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ isis_area_overload_on_startup_set(area, overload_time);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-isisd:isis/instance/metric-style
*/
int isis_instance_metric_style_modify(struct nb_cb_modify_args *args)
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 0ff31df0f8..efea1e5d5e 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -3198,9 +3198,15 @@ void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit)
if (new_overload_bit != area->overload_bit) {
area->overload_bit = new_overload_bit;
-
- if (new_overload_bit)
+ if (new_overload_bit) {
area->overload_counter++;
+ } else {
+ /* Cancel overload on startup timer if it's running */
+ if (area->t_overload_on_startup_timer) {
+ THREAD_OFF(area->t_overload_on_startup_timer);
+ area->t_overload_on_startup_timer = NULL;
+ }
+ }
#ifndef FABRICD
hook_call(isis_hook_db_overload, area);
@@ -3213,6 +3219,109 @@ void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit)
#endif /* ifndef FABRICD */
}
+void isis_area_overload_on_startup_set(struct isis_area *area,
+ uint32_t startup_time)
+{
+ if (area->overload_on_startup_time != startup_time) {
+ area->overload_on_startup_time = startup_time;
+ isis_restart_write_overload_time(area, startup_time);
+ }
+}
+
+/*
+ * Returns the path of the file (non-volatile memory) that contains restart
+ * information.
+ */
+char *isis_restart_filepath()
+{
+ static char filepath[MAXPATHLEN];
+ snprintf(filepath, sizeof(filepath), ISISD_RESTART, "");
+ return filepath;
+}
+
+/*
+ * Record in non-volatile memory the overload on startup time.
+ */
+void isis_restart_write_overload_time(struct isis_area *isis_area,
+ uint32_t overload_time)
+{
+ char *filepath;
+ const char *area_name;
+ json_object *json;
+ json_object *json_areas;
+ json_object *json_area;
+
+ filepath = isis_restart_filepath();
+ area_name = isis_area->area_tag;
+
+ json = json_object_from_file(filepath);
+ if (json == NULL)
+ json = json_object_new_object();
+
+ json_object_object_get_ex(json, "areas", &json_areas);
+ if (!json_areas) {
+ json_areas = json_object_new_object();
+ json_object_object_add(json, "areas", json_areas);
+ }
+
+ json_object_object_get_ex(json_areas, area_name, &json_area);
+ if (!json_area) {
+ json_area = json_object_new_object();
+ json_object_object_add(json_areas, area_name, json_area);
+ }
+
+ json_object_int_add(json_area, "overload_time",
+ isis_area->overload_on_startup_time);
+ json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
+ json_object_free(json);
+}
+
+/*
+ * Fetch from non-volatile memory the overload on startup time.
+ */
+uint32_t isis_restart_read_overload_time(struct isis_area *isis_area)
+{
+ char *filepath;
+ const char *area_name;
+ json_object *json;
+ json_object *json_areas;
+ json_object *json_area;
+ json_object *json_overload_time;
+ uint32_t overload_time = 0;
+
+ filepath = isis_restart_filepath();
+ area_name = isis_area->area_tag;
+
+ json = json_object_from_file(filepath);
+ if (json == NULL)
+ json = json_object_new_object();
+
+ json_object_object_get_ex(json, "areas", &json_areas);
+ if (!json_areas) {
+ json_areas = json_object_new_object();
+ json_object_object_add(json, "areas", json_areas);
+ }
+
+ json_object_object_get_ex(json_areas, area_name, &json_area);
+ if (!json_area) {
+ json_area = json_object_new_object();
+ json_object_object_add(json_areas, area_name, json_area);
+ }
+
+ json_object_object_get_ex(json_area, "overload_time",
+ &json_overload_time);
+ if (json_overload_time) {
+ overload_time = json_object_get_int(json_overload_time);
+ }
+
+ json_object_object_del(json_areas, area_name);
+
+ json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
+ json_object_free(json);
+
+ return overload_time;
+}
+
void isis_area_attached_bit_send_set(struct isis_area *area, bool attached_bit)
{
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 4951e5809b..a9c1d60439 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -142,6 +142,7 @@ struct isis_area {
struct flags flags;
struct thread *t_tick; /* LSP walker */
struct thread *t_lsp_refresh[ISIS_LEVELS];
+ struct thread *t_overload_on_startup_timer;
struct timeval last_lsp_refresh_event[ISIS_LEVELS];
struct thread *t_rlfa_rib_update;
/* t_lsp_refresh is used in two ways:
@@ -180,7 +181,9 @@ struct isis_area {
char is_type; /* level-1 level-1-2 or level-2-only */
/* are we overloaded? */
char overload_bit;
+ bool overload_configured;
uint32_t overload_counter;
+ uint32_t overload_on_startup_time;
/* L1/L2 router identifier for inter-area traffic */
char attached_bit_send;
char attached_bit_rcv_ignore;
@@ -290,6 +293,8 @@ void isis_area_invalidate_routes(struct isis_area *area, int levels);
void isis_area_verify_routes(struct isis_area *area);
void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit);
+void isis_area_overload_on_startup_set(struct isis_area *area,
+ uint32_t startup_time);
void isis_area_attached_bit_send_set(struct isis_area *area, bool attached_bit);
void isis_area_attached_bit_receive_set(struct isis_area *area,
bool attached_bit);
@@ -315,7 +320,10 @@ void show_isis_database_lspdb_json(struct json_object *json,
void show_isis_database_lspdb_vty(struct vty *vty, struct isis_area *area,
int level, struct lspdb_head *lspdb,
const char *argv, int ui_level);
-
+char *isis_restart_filepath(void);
+void isis_restart_write_overload_time(struct isis_area *isis_area,
+ uint32_t overload_time);
+uint32_t isis_restart_read_overload_time(struct isis_area *isis_area);
/* YANG paths */
#define ISIS_INSTANCE "/frr-isisd:isis/instance"
#define ISIS_SR "/frr-isisd:isis/instance/segment-routing"
diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py
index 014722387f..8b6c3772b8 100644
--- a/tests/topotests/isis_topo1/test_isis_topo1.py
+++ b/tests/topotests/isis_topo1/test_isis_topo1.py
@@ -25,7 +25,7 @@
"""
test_isis_topo1.py: Test ISIS topology.
"""
-
+import datetime
import functools
import json
import os
@@ -38,6 +38,11 @@ sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib import topotest
+from lib.common_config import (
+ retry,
+ stop_router,
+ start_router,
+)
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
@@ -248,10 +253,12 @@ def test_isis_summary_json():
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
json_output = tgen.gears[rname].vtysh_cmd("show isis summary json", isjson=True)
- assertmsg = "Test isis summary json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['vrf'] == "default", assertmsg
- assert json_output['areas'][0]['area'] == "1", assertmsg
- assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg
+ assertmsg = "Test isis summary json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert json_output["vrf"] == "default", assertmsg
+ assert json_output["areas"][0]["area"] == "1", assertmsg
+ assert json_output["areas"][0]["levels"][0]["id"] != "3", assertmsg
def test_isis_interface_json():
@@ -265,15 +272,29 @@ def test_isis_interface_json():
logger.info("Checking 'show isis interface json'")
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis interface json", isjson=True)
- assertmsg = "Test isis interface json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis interface json", isjson=True
+ )
+ assertmsg = "Test isis interface json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert (
+ json_output["areas"][0]["circuits"][0]["interface"]["name"]
+ == rname + "-eth0"
+ ), assertmsg
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis interface detail json", isjson=True)
- assertmsg = "Test isis interface json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis interface detail json", isjson=True
+ )
+ assertmsg = "Test isis interface json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert (
+ json_output["areas"][0]["circuits"][0]["interface"]["name"]
+ == rname + "-eth0"
+ ), assertmsg
def test_isis_neighbor_json():
@@ -284,19 +305,32 @@ def test_isis_neighbor_json():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- #tgen.mininet_cli()
+ # tgen.mininet_cli()
logger.info("Checking 'show isis neighbor json'")
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis neighbor json", isjson=True)
- assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['circuits'][0]['interface'] == rname+"-eth0", assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis neighbor json", isjson=True
+ )
+ assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert (
+ json_output["areas"][0]["circuits"][0]["interface"] == rname + "-eth0"
+ ), assertmsg
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis neighbor detail json", isjson=True)
- assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis neighbor detail json", isjson=True
+ )
+ assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert (
+ json_output["areas"][0]["circuits"][0]["interface"]["name"]
+ == rname + "-eth0"
+ ), assertmsg
def test_isis_database_json():
@@ -307,21 +341,246 @@ def test_isis_database_json():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- #tgen.mininet_cli()
+ # tgen.mininet_cli()
logger.info("Checking 'show isis database json'")
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis database json", isjson=True)
- assertmsg = "Test isis database json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['area']['name'] == "1", assertmsg
- assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis database json", isjson=True
+ )
+ assertmsg = "Test isis database json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert json_output["areas"][0]["area"]["name"] == "1", assertmsg
+ assert json_output["areas"][0]["levels"][0]["id"] != "3", assertmsg
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis database detail json", isjson=True)
- assertmsg = "Test isis database json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['area']['name'] == "1", assertmsg
- assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis database detail json", isjson=True
+ )
+ assertmsg = "Test isis database json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert json_output["areas"][0]["area"]["name"] == "1", assertmsg
+ assert json_output["areas"][0]["levels"][0]["id"] != "3", assertmsg
+
+
+def test_isis_overload_on_startup():
+ "Check that overload on startup behaves as expected"
+
+ tgen = get_topogen()
+ net = get_topogen().net
+ overload_time = 120
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Testing overload on startup behavior")
+
+ # Configure set-overload-bit on-startup on r3
+ r3 = tgen.gears["r3"]
+ r3.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ set-overload-bit on-startup {overload_time}
+ """
+ )
+ # Restart r3
+ logger.info("Stop router")
+ stop_router(tgen, "r3")
+ logger.info("Start router")
+
+ tstamp_before_start_router = datetime.datetime.now()
+ start_router(tgen, "r3")
+ tstamp_after_start_router = datetime.datetime.now()
+ startup_router_time = (
+ tstamp_after_start_router - tstamp_before_start_router
+ ).total_seconds()
+
+ # Check that the overload bit is set in r3's LSP
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/1")
+ check_lsp_overload_bit("r1", "r3.00-00", "0/0/1")
+
+ # Attempt to unset overload bit while timer is still running
+ r3.vtysh_cmd(
+ """
+ configure
+ router isis 1
+ no set-overload-bit on-startup
+ no set-overload-bit
+ """
+ )
+
+ # Check overload bit is still set
+ check_lsp_overload_bit("r1", "r3.00-00", "0/0/1")
+
+ # Check that overload bit is unset after timer completes
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/0")
+ tstamp_after_bit_unset = datetime.datetime.now()
+ check_lsp_overload_bit("r1", "r3.00-00", "0/0/0")
+
+ # Collect time overloaded
+ time_overloaded = (
+ tstamp_after_bit_unset - tstamp_after_start_router
+ ).total_seconds()
+ logger.info(f"Time Overloaded: {time_overloaded}")
+
+ # Use time it took to startup router as lower bound
+ logger.info(
+ f"Assert that overload time falls in range: {overload_time - startup_router_time} < {time_overloaded} <= {overload_time}"
+ )
+ result = overload_time - startup_router_time < time_overloaded <= overload_time
+ assert result
+
+
+def test_isis_overload_on_startup_cancel_timer():
+ "Check that overload on startup timer is cancelled when overload bit is set/unset"
+
+ tgen = get_topogen()
+ net = get_topogen().net
+ overload_time = 90
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info(
+ "Testing overload on startup behavior with set overload bit: cancel timer"
+ )
+
+ # Configure set-overload-bit on-startup on r3
+ r3 = tgen.gears["r3"]
+ r3.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ set-overload-bit on-startup {overload_time}
+ set-overload-bit
+ """
+ )
+ # Restart r3
+ logger.info("Stop router")
+ stop_router(tgen, "r3")
+ logger.info("Start router")
+ start_router(tgen, "r3")
+
+ # Check that the overload bit is set in r3's LSP
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/1")
+
+ # Check that overload timer is running
+ check_overload_timer("r3", True)
+
+ # Unset overload bit while timer is running
+ r3.vtysh_cmd(
+ """
+ configure
+ router isis 1
+ no set-overload-bit
+ """
+ )
+
+ # Check that overload timer is cancelled
+ check_overload_timer("r3", False)
+
+ # Check overload bit is unset
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/0")
+
+
+def test_isis_overload_on_startup_override_timer():
+ "Check that overload bit remains set after overload timer expires if overload bit is configured"
+
+ tgen = get_topogen()
+ net = get_topogen().net
+ overload_time = 60
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info(
+ "Testing overload on startup behavior with set overload bit: override timer"
+ )
+
+ # Configure set-overload-bit on-startup on r3
+ r3 = tgen.gears["r3"]
+ r3.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ set-overload-bit on-startup {overload_time}
+ set-overload-bit
+ """
+ )
+ # Restart r3
+ logger.info("Stop router")
+ stop_router(tgen, "r3")
+ logger.info("Start router")
+ start_router(tgen, "r3")
+
+ # Check that the overload bit is set in r3's LSP
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/1")
+
+ # Check that overload timer is running
+ check_overload_timer("r3", True)
+
+ # Check that overload timer expired
+ check_overload_timer("r3", False)
+
+ # Check overload bit is still set
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/1")
+
+
+@retry(retry_timeout=200)
+def _check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected):
+ "Verfiy overload bit in router's LSP"
+
+ tgen = get_topogen()
+ router = tgen.gears[router]
+ logger.info(f"check_overload_bit {router}")
+ isis_database_output = router.vtysh_cmd(
+ "show isis database {} json".format(overloaded_router_lsp)
+ )
+
+ database_json = json.loads(isis_database_output)
+ att_p_ol = database_json["areas"][0]["levels"][1]["att-p-ol"]
+ if att_p_ol == att_p_ol_expected:
+ return True
+ return "{} peer with expected att_p_ol {} got {} ".format(
+ router.name, att_p_ol_expected, att_p_ol
+ )
+
+
+def check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected):
+ "Verfiy overload bit in router's LSP"
+
+ assertmsg = _check_lsp_overload_bit(
+ router, overloaded_router_lsp, att_p_ol_expected
+ )
+ assert assertmsg is True, assertmsg
+
+
+@retry(retry_timeout=200)
+def _check_overload_timer(router, timer_expected):
+ "Verfiy overload bit in router's LSP"
+
+ tgen = get_topogen()
+ router = tgen.gears[router]
+ thread_output = router.vtysh_cmd("show thread timers")
+
+ timer_running = "set_overload_on_start_timer" in thread_output
+ if timer_running == timer_expected:
+ return True
+ return "Expected timer running status: {}".format(timer_expected)
+
+
+def check_overload_timer(router, timer_expected):
+ "Verfiy overload bit in router's LSP"
+
+ assertmsg = _check_overload_timer(router, timer_expected)
+ assert assertmsg is True, assertmsg
def test_memory_leak():
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index 0812c86fac..380fce3859 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -1066,11 +1066,25 @@ module frr-isisd {
"If true, identify as L1/L2 router for inter-area traffic.";
}
- leaf overload {
- type boolean;
- default "false";
+ container overload {
description
- "If true, avoid any transit traffic.";
+ "Overload bit configuration.";
+ leaf enabled {
+ type boolean;
+ default "false";
+ description
+ "If true, avoid any transit traffic.";
+ }
+
+ leaf on-startup {
+ type uint32 {
+ range "0..86400";
+ }
+ units "seconds";
+ default "0";
+ description
+ "The duration the overload bit should be set on startup.";
+ }
}
leaf metric-style {