diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 8f9afd313..2b114ad12 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -85,7 +85,7 @@ writing, *isisd* does not support multiple ISIS processes. .. clicmd:: set-overload-bit on-startup (0-86400) - Set overload bit on startup for the specified duration, in seconds. + Set overload bit on startup for the specified duration, in seconds. Reference: :rfc:`3277` .. clicmd:: purge-originator diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index fbf559713..2dc6f15c7 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -448,7 +448,10 @@ void set_overload_on_start_timer(struct thread *thread) assert(area); area->t_overload_on_startup_timer = NULL; - isis_area_overload_bit_set(area, false); + + /* 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) diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 14a66d256..214209e64 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -350,6 +350,8 @@ int isis_instance_overload_enabled_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; diff --git a/isisd/isisd.c b/isisd/isisd.c index 3ba00e6bf..d59a41184 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -3190,9 +3190,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); diff --git a/isisd/isisd.h b/isisd/isisd.h index f1f92b365..81877f745 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -181,6 +181,7 @@ 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 */ diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index bfcca5fd5..519ebba0c 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -368,6 +368,7 @@ def test_isis_database_json(): def test_isis_overload_on_startup(): "Check that overload on startup behaves as expected" + tgen = get_topogen() net = get_topogen().net overload_time = 120 @@ -464,6 +465,124 @@ def check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected): assert assertmsg is True, assertmsg +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_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(): "Run the memory leak test and report results." tgen = get_topogen()