summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss White <russ@riw.us>2023-03-02 16:42:50 -0500
committerGitHub <noreply@github.com>2023-03-02 16:42:50 -0500
commit15424f55f3077ee49171b7bc238794042db3ea8f (patch)
tree5f79204ea8dcd332418a82a5eaf2ea9af28a77c1
parent48cdfc16dd34e1bbfaf23c386605d44a6dcb01fb (diff)
parent102a6e269919d4a3c443d3fd984a3d0e1cf24b06 (diff)
Merge pull request #12650 from isabelladeleon12/advertise_high_metrics
isisd: Add support for advertise-high-metrics
-rw-r--r--doc/user/isisd.rst6
-rw-r--r--isisd/isis_circuit.c4
-rw-r--r--isisd/isis_cli.c25
-rw-r--r--isisd/isis_nb.c7
-rw-r--r--isisd/isis_nb.h4
-rw-r--r--isisd/isis_nb_config.c18
-rw-r--r--isisd/isisd.c55
-rw-r--r--isisd/isisd.h4
-rw-r--r--tests/topotests/isis_advertise_high_metrics/__init__.py0
-rw-r--r--tests/topotests/isis_advertise_high_metrics/r1/isisd.conf19
-rw-r--r--tests/topotests/isis_advertise_high_metrics/r1/zebra.conf5
-rw-r--r--tests/topotests/isis_advertise_high_metrics/r2/isisd.conf18
-rw-r--r--tests/topotests/isis_advertise_high_metrics/r2/zebra.conf5
-rw-r--r--tests/topotests/isis_advertise_high_metrics/r3/isisd.conf20
-rw-r--r--tests/topotests/isis_advertise_high_metrics/r3/zebra.conf5
-rw-r--r--tests/topotests/isis_advertise_high_metrics/r4/isisd.conf19
-rw-r--r--tests/topotests/isis_advertise_high_metrics/r4/zebra.conf5
-rw-r--r--tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py485
-rw-r--r--yang/frr-isisd.yang7
19 files changed, 711 insertions, 0 deletions
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst
index d68fa67259..055841d230 100644
--- a/doc/user/isisd.rst
+++ b/doc/user/isisd.rst
@@ -79,6 +79,12 @@ writing, *isisd* does not support multiple ISIS processes.
- wide
Use new style of TLVs to carry wider metric. FRR uses this as a default value
+.. clicmd:: advertise-high-metrics
+
+ Advertise high metric value on all interfaces to gracefully shift traffic off the router. Reference: :rfc:`3277`
+
+ For narrow metrics, the high metric value is 63; for wide metrics, 16777215; for transition metrics, 62.
+
.. clicmd:: set-overload-bit
Set overload bit to avoid any transit traffic.
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index dd5f921bef..8644da2f08 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -1499,6 +1499,10 @@ ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level,
return ferr_cfg_invalid("metric %d too large for narrow metric",
metric);
+ /* Don't modify metric if advertise high metrics is configured */
+ if (circuit->area && circuit->area->advertise_high_metrics)
+ return ferr_ok();
+
/* inform ldp-sync of metric change
* if ldp-sync is running need to save metric
* and restore new values after ldp-sync completion.
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index 5c7f610881..4a598aa8c9 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -440,6 +440,29 @@ void cli_show_isis_overload_on_startup(struct vty *vty,
}
/*
+ * XPath: /frr-isisd:isis/instance/advertise-high-metrics
+ */
+DEFPY_YANG(advertise_high_metrics, advertise_high_metrics_cmd,
+ "[no] advertise-high-metrics",
+ NO_STR "Advertise high metric value on all interfaces\n")
+{
+ nb_cli_enqueue_change(vty, "./advertise-high-metrics", NB_OP_MODIFY,
+ no ? "false" : "true");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_advertise_high_metrics(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults)
+{
+ if (yang_dnode_get_bool(dnode, NULL))
+ vty_out(vty, " advertise-high-metrics\n");
+ else if (show_defaults)
+ vty_out(vty, " no advertise-high-metrics\n");
+}
+
+/*
* XPath: /frr-isisd:isis/instance/attach-send
*/
DEFPY_YANG(attached_bit_send, attached_bit_send_cmd, "[no] attached-bit send",
@@ -3160,6 +3183,8 @@ void isis_cli_init(void)
install_element(ISIS_NODE, &metric_style_cmd);
install_element(ISIS_NODE, &no_metric_style_cmd);
+ install_element(ISIS_NODE, &advertise_high_metrics_cmd);
+
install_element(ISIS_NODE, &area_passwd_cmd);
install_element(ISIS_NODE, &domain_passwd_cmd);
install_element(ISIS_NODE, &no_area_passwd_cmd);
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index 5caa61a4d1..7dc3a0eb3d 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -82,6 +82,13 @@ const struct frr_yang_module_info frr_isisd_info = {
}
},
{
+ .xpath = "/frr-isisd:isis/instance/advertise-high-metrics",
+ .cbs = {
+ .cli_show = cli_show_advertise_high_metrics,
+ .modify = isis_instance_advertise_high_metrics_modify,
+ }
+ },
+ {
.xpath = "/frr-isisd:isis/instance/metric-style",
.cbs = {
.cli_show = cli_show_isis_metric_style,
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index c90f6dca37..480b2ce041 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -26,6 +26,7 @@ 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_enabled_modify(struct nb_cb_modify_args *args);
int isis_instance_overload_on_startup_modify(struct nb_cb_modify_args *args);
+int isis_instance_advertise_high_metrics_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);
@@ -464,6 +465,9 @@ void cli_show_isis_overload(struct vty *vty, const struct lyd_node *dnode,
void cli_show_isis_overload_on_startup(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults);
+void cli_show_advertise_high_metrics(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 ea021a4ff5..2b3355bc9f 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -361,6 +361,24 @@ int isis_instance_overload_on_startup_modify(struct nb_cb_modify_args *args)
}
/*
+ * XPath: /frr-isisd:isis/instance/advertise-high-metrics
+ */
+int isis_instance_advertise_high_metrics_modify(struct nb_cb_modify_args *args)
+{
+ struct isis_area *area;
+ bool advertise_high_metrics;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ advertise_high_metrics = yang_dnode_get_bool(args->dnode, NULL);
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ isis_area_advertise_high_metrics_set(area, advertise_high_metrics);
+
+ 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 852d7b88e8..586785b05f 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -2503,6 +2503,9 @@ static void common_isis_summary_vty(struct vty *vty, struct isis *isis)
vty_out(vty, " RX counters per PDU type:\n");
pdu_counter_print(vty, " ", area->pdu_rx_counters);
+ vty_out(vty, " Advertise high metrics: %s\n",
+ area->advertise_high_metrics ? "Enabled" : "Disabled");
+
for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
if ((area->is_type & level) == 0)
continue;
@@ -3247,6 +3250,58 @@ void config_end_lsp_generate(struct isis_area *area)
}
}
+void isis_area_advertise_high_metrics_set(struct isis_area *area,
+ bool advertise_high_metrics)
+{
+ struct listnode *node;
+ struct isis_circuit *circuit;
+ int max_metric;
+ char xpath[XPATH_MAXLEN];
+ struct lyd_node *dnode;
+ int configured_metric_l1;
+ int configured_metric_l2;
+
+ if (area->advertise_high_metrics == advertise_high_metrics)
+ return;
+
+ if (advertise_high_metrics) {
+ if (area->oldmetric && area->newmetric)
+ max_metric = ISIS_NARROW_METRIC_INFINITY;
+ else if (area->newmetric)
+ max_metric = MAX_WIDE_LINK_METRIC;
+ else
+ max_metric = MAX_NARROW_LINK_METRIC;
+
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
+ isis_circuit_metric_set(circuit, IS_LEVEL_1,
+ max_metric);
+ isis_circuit_metric_set(circuit, IS_LEVEL_2,
+ max_metric);
+ }
+
+ area->advertise_high_metrics = true;
+ } else {
+ area->advertise_high_metrics = false;
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
+ /* Get configured metric */
+ snprintf(xpath, XPATH_MAXLEN,
+ "/frr-interface:lib/interface[name='%s']",
+ circuit->interface->name);
+ dnode = yang_dnode_get(running_config->dnode, xpath);
+
+ configured_metric_l1 = yang_dnode_get_uint32(
+ dnode, "./frr-isisd:isis/metric/level-1");
+ configured_metric_l2 = yang_dnode_get_uint32(
+ dnode, "./frr-isisd:isis/metric/level-2");
+
+ isis_circuit_metric_set(circuit, IS_LEVEL_1,
+ configured_metric_l1);
+ isis_circuit_metric_set(circuit, IS_LEVEL_2,
+ configured_metric_l2);
+ }
+ }
+}
+
/*
* Returns the path of the file (non-volatile memory) that contains restart
* information.
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 0f1161e574..37a36fd37a 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -175,6 +175,8 @@ struct isis_area {
uint32_t overload_on_startup_time;
/* advertise prefixes of passive interfaces only? */
bool advertise_passive_only;
+ /* Are we advertising high metrics? */
+ bool advertise_high_metrics;
/* L1/L2 router identifier for inter-area traffic */
char attached_bit_send;
char attached_bit_rcv_ignore;
@@ -289,6 +291,8 @@ void isis_area_switchover_routes(struct isis_area *area, int family,
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_advertise_high_metrics_set(struct isis_area *area,
+ bool advertise_high_metrics);
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);
diff --git a/tests/topotests/isis_advertise_high_metrics/__init__.py b/tests/topotests/isis_advertise_high_metrics/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/isis_advertise_high_metrics/__init__.py
diff --git a/tests/topotests/isis_advertise_high_metrics/r1/isisd.conf b/tests/topotests/isis_advertise_high_metrics/r1/isisd.conf
new file mode 100644
index 0000000000..747c64ef4f
--- /dev/null
+++ b/tests/topotests/isis_advertise_high_metrics/r1/isisd.conf
@@ -0,0 +1,19 @@
+hostname r1
+! debug isis adj-packets
+! debug isis events
+! debug isis update-packets
+interface eth-r2
+ ip router isis 1
+ isis circuit-type level-2-only
+ isis network point-to-point
+!
+interface eth-r3
+ ip router isis 1
+ isis circuit-type level-2-only
+ isis metric 20
+ isis network point-to-point
+!
+router isis 1
+ is-type level-2-only
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0000.00
+! \ No newline at end of file
diff --git a/tests/topotests/isis_advertise_high_metrics/r1/zebra.conf b/tests/topotests/isis_advertise_high_metrics/r1/zebra.conf
new file mode 100644
index 0000000000..b14ce0d88d
--- /dev/null
+++ b/tests/topotests/isis_advertise_high_metrics/r1/zebra.conf
@@ -0,0 +1,5 @@
+interface eth-r2
+ ip address 192.168.1.0/31
+
+interface eth-r3
+ ip address 192.168.1.2/31 \ No newline at end of file
diff --git a/tests/topotests/isis_advertise_high_metrics/r2/isisd.conf b/tests/topotests/isis_advertise_high_metrics/r2/isisd.conf
new file mode 100644
index 0000000000..cee62ad57a
--- /dev/null
+++ b/tests/topotests/isis_advertise_high_metrics/r2/isisd.conf
@@ -0,0 +1,18 @@
+hostname r2
+! debug isis adj-packets
+! debug isis events
+! debug isis update-packets
+interface eth-r1
+ ip router isis 1
+ isis circuit-type level-2-only
+ isis network point-to-point
+!
+interface eth-r4
+ ip router isis 1
+ isis circuit-type level-2-only
+ isis network point-to-point
+!
+router isis 1
+ is-type level-2-only
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00
+! \ No newline at end of file
diff --git a/tests/topotests/isis_advertise_high_metrics/r2/zebra.conf b/tests/topotests/isis_advertise_high_metrics/r2/zebra.conf
new file mode 100644
index 0000000000..01de593415
--- /dev/null
+++ b/tests/topotests/isis_advertise_high_metrics/r2/zebra.conf
@@ -0,0 +1,5 @@
+interface eth-r1
+ ip address 192.168.1.1/31
+
+interface eth-r4
+ ip address 192.168.1.7/31 \ No newline at end of file
diff --git a/tests/topotests/isis_advertise_high_metrics/r3/isisd.conf b/tests/topotests/isis_advertise_high_metrics/r3/isisd.conf
new file mode 100644
index 0000000000..6d795f093c
--- /dev/null
+++ b/tests/topotests/isis_advertise_high_metrics/r3/isisd.conf
@@ -0,0 +1,20 @@
+hostname r3
+! debug isis adj-packets
+! debug isis events
+! debug isis update-packets
+interface eth-r1
+ ip router isis 1
+ isis circuit-type level-2-only
+ isis metric 20
+ isis network point-to-point
+!
+interface eth-r4
+ ip router isis 1
+ isis circuit-type level-2-only
+ isis metric 20
+ isis network point-to-point
+!
+router isis 1
+ is-type level-2-only
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00
+! \ No newline at end of file
diff --git a/tests/topotests/isis_advertise_high_metrics/r3/zebra.conf b/tests/topotests/isis_advertise_high_metrics/r3/zebra.conf
new file mode 100644
index 0000000000..668431ca4f
--- /dev/null
+++ b/tests/topotests/isis_advertise_high_metrics/r3/zebra.conf
@@ -0,0 +1,5 @@
+interface eth-r1
+ ip address 192.168.1.3/31
+
+interface eth-r4
+ ip address 192.168.1.4/31 \ No newline at end of file
diff --git a/tests/topotests/isis_advertise_high_metrics/r4/isisd.conf b/tests/topotests/isis_advertise_high_metrics/r4/isisd.conf
new file mode 100644
index 0000000000..b281014b9e
--- /dev/null
+++ b/tests/topotests/isis_advertise_high_metrics/r4/isisd.conf
@@ -0,0 +1,19 @@
+hostname r4
+! debug isis adj-packets
+! debug isis events
+! debug isis update-packets
+interface eth-r2
+ ip router isis 1
+ isis circuit-type level-2-only
+ isis network point-to-point
+!
+interface eth-r3
+ ip router isis 1
+ isis circuit-type level-2-only
+ isis metric 20
+ isis network point-to-point
+!
+router isis 1
+ is-type level-2-only
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0003.00
+! \ No newline at end of file
diff --git a/tests/topotests/isis_advertise_high_metrics/r4/zebra.conf b/tests/topotests/isis_advertise_high_metrics/r4/zebra.conf
new file mode 100644
index 0000000000..6819dbb89e
--- /dev/null
+++ b/tests/topotests/isis_advertise_high_metrics/r4/zebra.conf
@@ -0,0 +1,5 @@
+interface eth-r2
+ ip address 192.168.1.6/31
+
+interface eth-r3
+ ip address 192.168.1.5/31
diff --git a/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py b/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py
new file mode 100644
index 0000000000..5eef879e3f
--- /dev/null
+++ b/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py
@@ -0,0 +1,485 @@
+#!/usr/bin/env python
+
+#
+# test_isis_advertise_high_metrics.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by Volta Networks
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+r"""
+test_isis_advertise_high_metrics.py: Advertise High Metrics FRR ISIS Test
+"""
+
+import os
+import re
+import sys
+import pytest
+import json
+from time import sleep
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+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
+
+# Required to instantiate the topology builder class.
+
+pytestmark = [pytest.mark.isisd]
+
+
+def build_topo(tgen):
+ "Build function"
+
+ # Add ISIS routers:
+ # r2
+ # / \
+ # r1 r4
+ # \ /
+ # r3
+
+ #
+ # Define FRR Routers
+ #
+ for router in ["r1", "r2", "r3", "r4"]:
+ tgen.add_router(router)
+ #
+ # Define connections
+ #
+ switch = tgen.add_switch("s0")
+ switch.add_link(tgen.gears["r1"], nodeif="eth-r2")
+ switch.add_link(tgen.gears["r2"], nodeif="eth-r1")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"], nodeif="eth-r3")
+ switch.add_link(tgen.gears["r3"], nodeif="eth-r1")
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"], nodeif="eth-r4")
+ switch.add_link(tgen.gears["r4"], nodeif="eth-r2")
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r3"], nodeif="eth-r4")
+ switch.add_link(tgen.gears["r4"], nodeif="eth-r3")
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in tgen.routers().items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
+ )
+
+ # After loading the configurations, this function loads configured daemons.
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+@retry(retry_timeout=60)
+def _check_interface_metrics(router, expected_metrics):
+ "Verfiy metrics on router's isis interfaces"
+
+ tgen = get_topogen()
+ router = tgen.gears[router]
+ logger.info(f"check_interface_metrics {router}")
+ isis_interface_output = router.vtysh_cmd(
+ "show isis interface detail json"
+ )
+
+ intf_json = json.loads(isis_interface_output)
+ for i in range(len(expected_metrics)):
+ metric = intf_json["areas"][0]["circuits"][i]["interface"]["levels"][0]["metric"]
+ if (metric != expected_metrics[i]):
+ intf_name = intf_json["areas"][0]["circuits"][i]["interface"]["name"]
+ return "{} with expected metric {} on {} got {}".format(
+ router.name, expected_metrics[i], intf_name, metric
+ )
+ return True
+
+
+def check_interface_metrics(router, expected_metrics):
+ "Verfiy metrics on router's isis interfaces"
+
+ assertmsg = _check_interface_metrics(
+ router, expected_metrics
+ )
+ assert assertmsg is True, assertmsg
+
+
+@retry(retry_timeout=60)
+def _check_lsp_metrics(router, lsp, expected_metrics):
+ "Verfiy metrics on router's lsp"
+ tgen = get_topogen()
+ router = tgen.gears[router]
+ logger.info(f"check_lsp_metrics {router}")
+ isis_lsp_output = router.vtysh_cmd(
+ "show isis database detail {}".format(lsp)
+ )
+
+ metrics_list = [int(i) for i in re.findall(r"Metric: (\d+)", isis_lsp_output)]
+ if len(metrics_list) == 0:
+ return False
+ for metric in metrics_list:
+ if metric not in expected_metrics:
+ return "{} with expected metrics {} got {}".format(
+ router.name, expected_metrics, metrics_list
+ )
+
+ return True
+
+
+def check_lsp_metrics(router, lsp, expected_metrics):
+ "Verfiy metrics on router's lsp"
+
+ assertmsg = _check_lsp_metrics(
+ router, lsp, expected_metrics
+ )
+ assert assertmsg is True, assertmsg
+
+
+@retry(retry_timeout=60)
+def _check_ip_route(router, destination, expected_interface):
+ "Verfiy IS-IS route"
+
+ tgen = get_topogen()
+ router = tgen.gears[router]
+ logger.info(f"check_ip_route {router}")
+ route_output = router.vtysh_cmd(
+ "show ip route {} json".format(destination)
+ )
+ route_json = json.loads(route_output)
+
+ interface = route_json[destination][0]["nexthops"][0]["interfaceName"]
+
+ if (interface != expected_interface):
+ return "{} with expected route to {} got {} expected {}".format(
+ router.name, destination, interface, expected_interface
+ )
+
+ return True
+
+
+def check_ip_route(router, destination, expected_interface):
+ "Verfiy IS-IS route"
+
+ assertmsg = _check_ip_route(
+ router, destination, expected_interface
+ )
+ assert assertmsg is True, assertmsg
+
+
+def test_isis_daemon_up():
+ "Check isis daemon up before starting test"
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for router in ["r1", "r2", "r3", "r4"]:
+ r = tgen.gears[router]
+ daemons = r.vtysh_cmd(
+ "show daemons"
+ )
+ assert "isisd" in daemons
+
+ # Verify initial metric values.
+ check_lsp_metrics("r1", "r1.00-00", [10, 20])
+ check_lsp_metrics("r2", "r2.00-00", [10, 10])
+ check_lsp_metrics("r3", "r3.00-00", [20, 20])
+ check_lsp_metrics("r4", "r4.00-00", [10, 20])
+
+
+def test_isis_advertise_high_metrics():
+ "Check that advertise high metrics behaves as expected"
+
+ tgen = get_topogen()
+ net = get_topogen().net
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Testing advertise high metrics basic behavior")
+
+ # Confirm low metrics values on each isis interface on r1
+ r1 = tgen.gears["r1"]
+ check_interface_metrics("r1", [10, 20])
+
+ # Confirm low metrics values within isis database on r1
+ check_lsp_metrics("r1", "r1.00-00", [10, 20])
+
+ # Configure advertise high metrics
+ r1.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ advertise-high-metrics
+ """
+ )
+
+ # Confirm high wide metrics values on each isis interface on r1
+ check_interface_metrics("r1", [16777215])
+
+ # Confirm high wide metrics values within isis database on r1
+ check_lsp_metrics("r1", "r1.00-00", [16777215])
+
+ # Remove advertise high metrics
+ r1.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ no advertise-high-metrics
+ """
+ )
+
+ # Confirm low metrics values on each isis interface on r1
+ check_interface_metrics("r1", [10, 20])
+
+ # Confirm low metrics values within isis database on r1
+ check_lsp_metrics("r1", "r1.00-00", [10, 20])
+
+
+def test_isis_advertise_high_metrics_narrow():
+ "Check that advertise high metrics behaves as expected with narrow metrics"
+
+ tgen = get_topogen()
+ net = get_topogen().net
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Testing advertise high metrics with narrow metric style")
+
+ r1 = tgen.gears["r1"]
+
+ # Configure narrow metric-style
+ r1.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ metric-style narrow
+ """
+ )
+
+ # Confirm low metrics values on each isis interface on r1
+ check_interface_metrics("r1", [10, 20])
+
+ # Confirm low metrics values within isis database on r1
+ check_lsp_metrics("r1", "r1.00-00", [10, 20])
+
+ # Configure advertise high metrics
+ r1.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ advertise-high-metrics
+ """
+ )
+
+ # Confirm high narrow metrics values on each isis interface on r1
+ check_interface_metrics("r1", [63])
+
+ # Confirm high narrow metrics values within isis database on r1
+ check_lsp_metrics("r1", "r1.00-00", [63])
+
+ # Remove advertise high metrics
+ r1.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ no advertise-high-metrics
+ """
+ )
+
+ # Confirm low metrics values on each isis interface on r1
+ check_interface_metrics("r1", [10, 20])
+
+ # Confirm low metrics values within isis database on r1
+ check_lsp_metrics("r1", "r1.00-00", [10, 20])
+
+ # Remove narrow metric-style
+ r1.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ no metric-style narrow
+ """
+ )
+
+
+def test_isis_advertise_high_metrics_transition():
+ "Check that advertise high metrics behaves as expected with transition metrics"
+ tgen = get_topogen()
+ net = get_topogen().net
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Testing advertise high metrics with transition metric style")
+
+ r1 = tgen.gears["r1"]
+
+ # Configure transition metric-style
+ r1.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ metric-style transition
+ """
+ )
+
+ # Confirm low metrics values on each isis interface on r1
+ check_interface_metrics("r1", [10, 20])
+
+ # Confirm low metrics values within isis database on r1
+ check_lsp_metrics("r1", "r1.00-00", [10, 20])
+
+ # Configure advertise high metrics
+ r1.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ advertise-high-metrics
+ """
+ )
+
+ # Confirm high transition metrics values on each isis interface on r1
+ check_interface_metrics("r1", [62])
+
+ # Confirm high transition metrics values within isis database on r1
+ check_lsp_metrics("r1", "r1.00-00", [62])
+
+ # Remove advertise high metrics
+ r1.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ no advertise-high-metrics
+ """
+ )
+
+ # Confirm low metrics values on each isis interface on r1
+ check_interface_metrics("r1", [10, 20])
+
+ # Confirm low metrics values within isis database on r1
+ check_lsp_metrics("r1", "r1.00-00", [10, 20])
+
+ # Remove narrow metric-style
+ r1.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ no metric-style transition
+ """
+ )
+
+
+def test_isis_advertise_high_metrics_route():
+ """
+ Topology:
+
+ r2
+ / \
+ r1 r4
+ \ /
+ r3
+
+ Devices are configured with preferred route between r1 and r4:
+ r1 -> r2 -> r4
+ Configure "advertise-high-metrics" on r2 and check that preferred route is:
+ r1 -> r3 -> r4.
+ Shut r3 and check that preferred route is:
+ r1 -> r2 -> r4.
+ """
+ tgen = get_topogen()
+ net = get_topogen().net
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Testing advertise high metrics route behavior")
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+
+ # Verify the preferred path from r1 to r4 (192.168.1.6) is currently via 192.168.1.1, eth-r2
+ check_ip_route("r1", "192.168.1.6/31", "eth-r2")
+
+ # Configure advertise high metrics on r2
+ r2.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ advertise-high-metrics
+ """
+ )
+
+ # Verify the preferred path from r1 to r4 (192.168.1.6) is now via 192.168.1.3, eth-r3
+ check_ip_route("r1", "192.168.1.6/31", "eth-r3")
+
+ # Shutdown r3
+ logger.info("Stop router r3")
+ stop_router(tgen, "r3")
+
+ # Verify the preferred path from r1 to r4 (192.168.1.6) is now via 192.168.1.1, eth-r2
+ check_ip_route("r1", "192.168.1.6/31", "eth-r2")
+
+ # Start r3
+ logger.info("Start router r3")
+ start_router(tgen, "r3")
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index ff3ba5d12b..0c2cf232fb 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -1169,6 +1169,13 @@ module frr-isisd {
"Define the style of TLVs metric supported.";
}
+ leaf advertise-high-metrics {
+ type boolean;
+ default "false";
+ description
+ "Advertise high metric value on all interfaces.";
+ }
+
leaf purge-originator {
type boolean;
default "false";