diff --git a/data/templates/frr/isisd.frr.j2 b/data/templates/frr/isisd.frr.j2 index 5570caaa7..eb14aade6 100644 --- a/data/templates/frr/isisd.frr.j2 +++ b/data/templates/frr/isisd.frr.j2 @@ -1,245 +1,248 @@ ! {% if interface is vyos_defined %} {% for iface, iface_config in interface.items() %} interface {{ iface }} ip router isis VyOS ipv6 router isis VyOS {% if iface_config.bfd is vyos_defined %} isis bfd {% if iface_config.bfd.profile is vyos_defined %} isis bfd profile {{ iface_config.bfd.profile }} {% endif %} {% endif %} {% if iface_config.network.point_to_point is vyos_defined %} isis network point-to-point {% endif %} {% if iface_config.circuit_type is vyos_defined %} isis circuit-type {{ iface_config.circuit_type }} {% endif %} {% if iface_config.hello_interval is vyos_defined %} isis hello-interval {{ iface_config.hello_interval }} {% endif %} {% if iface_config.hello_multiplier is vyos_defined %} isis hello-multiplier {{ iface_config.hello_multiplier }} {% endif %} {% if iface_config.hello_padding is vyos_defined %} isis hello padding {% endif %} {% if iface_config.ldp_sync.disable is vyos_defined %} no isis mpls ldp-sync {% elif iface_config.ldp_sync.holddown is vyos_defined %} isis mpls ldp-sync isis mpls ldp-sync holddown {{ iface_config.ldp_sync.holddown }} {% endif %} {% if iface_config.metric is vyos_defined %} isis metric {{ iface_config.metric }} {% endif %} {% if iface_config.passive is vyos_defined %} isis passive {% endif %} {% if iface_config.password.md5 is vyos_defined %} isis password md5 {{ iface_config.password.md5 }} {% elif iface_config.password.plaintext_password is vyos_defined %} isis password clear {{ iface_config.password.plaintext_password }} {% endif %} {% if iface_config.priority is vyos_defined %} isis priority {{ iface_config.priority }} {% endif %} {% if iface_config.psnp_interval is vyos_defined %} isis psnp-interval {{ iface_config.psnp_interval }} {% endif %} {% if iface_config.no_three_way_handshake is vyos_defined %} no isis three-way-handshake {% endif %} exit ! {% endfor %} {% endif %} ! router isis VyOS {{ 'vrf ' + vrf if vrf is vyos_defined }} net {{ net }} {% if advertise_high_metrics is vyos_defined %} advertise-high-metrics {% endif %} {% if advertise_passive_only is vyos_defined %} advertise-passive-only {% endif %} {% if dynamic_hostname is vyos_defined %} hostname dynamic {% endif %} {% if purge_originator is vyos_defined %} purge-originator {% endif %} {% if set_attached_bit is vyos_defined %} set-attached-bit {% endif %} {% if set_overload_bit is vyos_defined %} set-overload-bit {% endif %} +{% if metric_style is vyos_defined %} + metric-style {{ metric_style }} +{% endif %} {% if domain_password.md5 is vyos_defined %} domain-password md5 {{ domain_password.plaintext_password }} {% elif domain_password.plaintext_password is vyos_defined %} domain-password clear {{ domain_password.plaintext_password }} {% endif %} {% if log_adjacency_changes is vyos_defined %} log-adjacency-changes {% endif %} {% if lsp_gen_interval is vyos_defined %} lsp-gen-interval {{ lsp_gen_interval }} {% endif %} {% if lsp_mtu is vyos_defined %} lsp-mtu {{ lsp_mtu }} {% endif %} {% if lsp_refresh_interval is vyos_defined %} lsp-refresh-interval {{ lsp_refresh_interval }} {% endif %} {% if max_lsp_lifetime is vyos_defined %} max-lsp-lifetime {{ max_lsp_lifetime }} {% endif %} {% if ldp_sync.holddown is vyos_defined %} mpls ldp-sync holddown {{ ldp_sync.holddown }} {% elif ldp_sync is vyos_defined %} mpls ldp-sync {% endif %} {% if spf_interval is vyos_defined %} spf-interval {{ spf_interval }} {% endif %} {% if traffic_engineering.enable is vyos_defined %} mpls-te on {% endif %} {% if traffic_engineering.address is vyos_defined %} mpls-te router-address {{ traffic_engineering.address }} {% endif %} {% if traffic_engineering.inter_as is vyos_defined %} {% set level = '' %} {% if traffic_engineering.inter_as.level_1 is vyos_defined %} {% set level = ' level-1' %} {% endif %} {% if traffic_engineering.inter_as.level_1_2 is vyos_defined %} {% set level = ' level-1-2' %} {% endif %} {% if traffic_engineering.inter_as.level_2 is vyos_defined %} {% set level = ' level-2-only' %} {% endif %} mpls-te inter-as{{ level }} {% endif %} {% if segment_routing is vyos_defined %} {% if segment_routing.maximum_label_depth is vyos_defined %} segment-routing node-msd {{ segment_routing.maximum_label_depth }} {% endif %} {% if segment_routing.global_block is vyos_defined %} {% if segment_routing.local_block is vyos_defined %} segment-routing global-block {{ segment_routing.global_block.low_label_value }} {{ segment_routing.global_block.high_label_value }} local-block {{ segment_routing.local_block.low_label_value }} {{ segment_routing.local_block.high_label_value }} {% else %} segment-routing global-block {{ segment_routing.global_block.low_label_value }} {{ segment_routing.global_block.high_label_value }} {% endif %} {% endif %} {% if segment_routing.prefix is vyos_defined %} {% for prefix, prefix_config in segment_routing.prefix.items() %} {% if prefix_config.absolute is vyos_defined %} {% if prefix_config.absolute.value is vyos_defined %} segment-routing prefix {{ prefix }} absolute {{ prefix_config.absolute.value }} {{ 'explicit-null' if prefix_config.absolute.explicit_null is vyos_defined }} {{ 'no-php-flag' if prefix_config.absolute.no_php_flag is vyos_defined }} {% endif %} {% endif %} {% if prefix_config.index is vyos_defined %} {% if prefix_config.index.value is vyos_defined %} segment-routing prefix {{ prefix }} index {{ prefix_config.index.value }} {{ 'explicit-null' if prefix_config.index.explicit_null is vyos_defined }} {{ 'no-php-flag' if prefix_config.index.no_php_flag is vyos_defined }} {% endif %} {% endif %} {% endfor %} {% endif %} segment-routing on {% endif %} {% if spf_delay_ietf.init_delay is vyos_defined %} spf-delay-ietf init-delay {{ spf_delay_ietf.init_delay }} short-delay {{ spf_delay_ietf.short_delay }} long-delay {{ spf_delay_ietf.long_delay }} holddown {{ spf_delay_ietf.holddown }} time-to-learn {{ spf_delay_ietf.time_to_learn }} {% endif %} {% if area_password.md5 is vyos_defined %} area-password md5 {{ area_password.md5 }} {% elif area_password.plaintext_password is vyos_defined %} area-password clear {{ area_password.plaintext_password }} {% endif %} {% if default_information.originate is vyos_defined %} {% for afi, afi_config in default_information.originate.items() %} {% for level, level_config in afi_config.items() %} default-information originate {{ afi }} {{ level | replace('_', '-') }} {{ 'always' if level_config.always is vyos_defined }} {{ 'route-map ' ~ level_config.route_map if level_config.route_map is vyos_defined }} {{ 'metric ' ~ level_config.metric if level_config.metric is vyos_defined }} {% endfor %} {% endfor %} {% endif %} {% if fast_reroute.lfa is vyos_defined %} {% if fast_reroute.lfa.local is vyos_defined %} {% if fast_reroute.lfa.local.load_sharing.disable.level_1 is vyos_defined %} fast-reroute load-sharing disable level-1 {% elif fast_reroute.lfa.local.load_sharing.disable.level_2 is vyos_defined %} fast-reroute load-sharing disable level-2 {% elif fast_reroute.lfa.local.load_sharing.disable is vyos_defined %} fast-reroute load-sharing disable {% endif %} {% if fast_reroute.lfa.local.priority_limit is vyos_defined %} {% for priority, priority_limit_options in fast_reroute.lfa.local.priority_limit.items() %} {% for level in priority_limit_options %} fast-reroute priority-limit {{ priority }} {{ level | replace('_', '-') }} {% endfor %} {% endfor %} {% endif %} {% if fast_reroute.lfa.local.tiebreaker is vyos_defined %} {% for tiebreaker, tiebreaker_options in fast_reroute.lfa.local.tiebreaker.items() %} {% for index, index_options in tiebreaker_options.items() %} {% for index_value, index_value_options in index_options.items() %} {% for level in index_value_options %} fast-reroute lfa tiebreaker {{ tiebreaker | replace('_', '-') }} index {{ index_value }} {{ level | replace('_', '-') }} {% endfor %} {% endfor %} {% endfor %} {% endfor %} {% endif %} {% endif %} {% if fast_reroute.lfa.remote.prefix_list is vyos_defined %} {% for prefix_list, prefix_list_options in fast_reroute.lfa.remote.prefix_list.items() %} {% if prefix_list_options.level_1 is vyos_defined %} fast-reroute remote-lfa prefix-list {{ prefix_list }} level-1 {% endif %} {% if prefix_list_options.level_2 is vyos_defined %} fast-reroute remote-lfa prefix-list {{ prefix_list }} level-2 {% endif %} {% if prefix_list is vyos_defined and prefix_list_options.level_1 is not vyos_defined and prefix_list_options.level_2 is not vyos_defined %} fast-reroute remote-lfa prefix-list {{ prefix_list }} {% endif %} {% endfor %} {% endif %} {% endif %} {% if redistribute.ipv4 is vyos_defined %} {% for protocol, protocol_options in redistribute.ipv4.items() %} {% for level, level_config in protocol_options.items() %} {% if level_config.metric is vyos_defined %} redistribute ipv4 {{ protocol }} {{ level | replace('_', '-') }} metric {{ level_config.metric }} {% elif level_config.route_map is vyos_defined %} redistribute ipv4 {{ protocol }} {{ level | replace('_', '-') }} route-map {{ level_config.route_map }} {% else %} redistribute ipv4 {{ protocol }} {{ level | replace('_', '-') }} {% endif %} {% endfor %} {% endfor %} {% endif %} {% if redistribute.ipv6 is vyos_defined %} {% for protocol, protocol_options in redistribute.ipv6.items() %} {% for level, level_config in protocol_options.items() %} {% if level_config.metric is vyos_defined %} redistribute ipv6 {{ protocol }} {{ level | replace('_', '-') }} metric {{ level_config.metric }} {% elif level_config.route_map is vyos_defined %} redistribute ipv6 {{ protocol }} {{ level | replace('_', '-') }} route-map {{ level_config.route_map }} {% else %} redistribute ipv6 {{ protocol }} {{ level | replace('_', '-') }} {% endif %} {% endfor %} {% endfor %} {% endif %} {% if topology is vyos_defined %} topology {{ topology }} {% endif %} {% if level is vyos_defined('level-2') %} is-type level-2-only {% elif level is vyos_defined %} is-type {{ level }} {% endif %} exit ! diff --git a/smoketest/scripts/cli/test_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py index 0217c941a..47f002c6a 100755 --- a/smoketest/scripts/cli/test_protocols_isis.py +++ b/smoketest/scripts/cli/test_protocols_isis.py @@ -1,414 +1,416 @@ #!/usr/bin/env python3 # # Copyright (C) 2021-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. import unittest from base_vyostest_shim import VyOSUnitTestSHIM from vyos.configsession import ConfigSessionError from vyos.ifconfig import Section from vyos.utils.process import process_named_running PROCESS_NAME = 'isisd' base_path = ['protocols', 'isis'] domain = 'VyOS' net = '49.0001.1921.6800.1002.00' class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase): @classmethod def setUpClass(cls): cls._interfaces = Section.interfaces('ethernet') # call base-classes classmethod super(TestProtocolsISIS, cls).setUpClass() # Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same cls.daemon_pid = process_named_running(PROCESS_NAME) # ensure we can also run this test on a live system - so lets clean # out the current configuration :) cls.cli_delete(cls, base_path) cls.cli_delete(cls, ['vrf']) def tearDown(self): # cleanup any possible VRF mess self.cli_delete(['vrf']) # always destrox the entire isisd configuration to make the processes # life as hard as possible self.cli_delete(base_path) self.cli_commit() # check process health and continuity self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME)) def isis_base_config(self): self.cli_set(base_path + ['net', net]) for interface in self._interfaces: self.cli_set(base_path + ['interface', interface]) def test_isis_01_redistribute(self): prefix_list = 'EXPORT-ISIS' route_map = 'EXPORT-ISIS' rule = '10' + metric_style = 'transition' self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', rule, 'action', 'permit']) self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', rule, 'prefix', '203.0.113.0/24']) self.cli_set(['policy', 'route-map', route_map, 'rule', rule, 'action', 'permit']) self.cli_set(['policy', 'route-map', route_map, 'rule', rule, 'match', 'ip', 'address', 'prefix-list', prefix_list]) self.cli_set(base_path) # verify() - net id and interface are mandatory with self.assertRaises(ConfigSessionError): self.cli_commit() self.isis_base_config() self.cli_set(base_path + ['redistribute', 'ipv4', 'connected']) # verify() - Redistribute level-1 or level-2 should be specified with self.assertRaises(ConfigSessionError): self.cli_commit() self.cli_set(base_path + ['redistribute', 'ipv4', 'connected', 'level-2', 'route-map', route_map]) + self.cli_set(base_path + ['metric-style', metric_style]) self.cli_set(base_path + ['log-adjacency-changes']) # Commit all changes self.cli_commit() # Verify all changes tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') self.assertIn(f' net {net}', tmp) + self.assertIn(f' metric-style {metric_style}', tmp) self.assertIn(f' log-adjacency-changes', tmp) self.assertIn(f' redistribute ipv4 connected level-2 route-map {route_map}', tmp) for interface in self._interfaces: tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd') self.assertIn(f' ip router isis {domain}', tmp) self.assertIn(f' ipv6 router isis {domain}', tmp) self.cli_delete(['policy', 'route-map', route_map]) self.cli_delete(['policy', 'prefix-list', prefix_list]) def test_isis_02_vrfs(self): vrfs = ['red', 'green', 'blue'] # It is safe to assume that when the basic VRF test works, all other # IS-IS related features work, as we entirely inherit the CLI templates # and Jinja2 FRR template. table = '1000' vrf = 'red' vrf_base = ['vrf', 'name', vrf] vrf_iface = 'eth1' self.cli_set(vrf_base + ['table', table]) self.cli_set(vrf_base + ['protocols', 'isis', 'net', net]) self.cli_set(vrf_base + ['protocols', 'isis', 'interface', vrf_iface]) self.cli_set(vrf_base + ['protocols', 'isis', 'advertise-high-metrics']) self.cli_set(vrf_base + ['protocols', 'isis', 'advertise-passive-only']) self.cli_set(['interfaces', 'ethernet', vrf_iface, 'vrf', vrf]) # Also set a default VRF IS-IS config self.cli_set(base_path + ['net', net]) self.cli_set(base_path + ['interface', 'eth0']) self.cli_commit() # Verify FRR isisd configuration tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') self.assertIn(f'router isis {domain}', tmp) self.assertIn(f' net {net}', tmp) tmp = self.getFRRconfig(f'router isis {domain} vrf {vrf}', daemon='isisd') self.assertIn(f'router isis {domain} vrf {vrf}', tmp) self.assertIn(f' net {net}', tmp) self.assertIn(f' advertise-high-metrics', tmp) self.assertIn(f' advertise-passive-only', tmp) self.cli_delete(['vrf', 'name', vrf]) self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf']) def test_isis_04_default_information(self): metric = '50' route_map = 'default-foo-' self.isis_base_config() for afi in ['ipv4', 'ipv6']: for level in ['level-1', 'level-2']: self.cli_set(base_path + ['default-information', 'originate', afi, level, 'always']) self.cli_set(base_path + ['default-information', 'originate', afi, level, 'metric', metric]) self.cli_set(base_path + ['default-information', 'originate', afi, level, 'route-map', route_map + level + afi]) # Commit all changes self.cli_commit() # Verify all changes tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') self.assertIn(f' net {net}', tmp) for afi in ['ipv4', 'ipv6']: for level in ['level-1', 'level-2']: route_map_name = route_map + level + afi self.assertIn(f' default-information originate {afi} {level} always route-map {route_map_name} metric {metric}', tmp) def test_isis_05_password(self): password = 'foo' self.isis_base_config() for interface in self._interfaces: self.cli_set(base_path + ['interface', interface, 'password', 'plaintext-password', f'{password}-{interface}']) self.cli_set(base_path + ['area-password', 'plaintext-password', password]) self.cli_set(base_path + ['area-password', 'md5', password]) self.cli_set(base_path + ['domain-password', 'plaintext-password', password]) self.cli_set(base_path + ['domain-password', 'md5', password]) # verify() - can not use both md5 and plaintext-password for area-password with self.assertRaises(ConfigSessionError): self.cli_commit() self.cli_delete(base_path + ['area-password', 'md5', password]) # verify() - can not use both md5 and plaintext-password for domain-password with self.assertRaises(ConfigSessionError): self.cli_commit() self.cli_delete(base_path + ['domain-password', 'md5', password]) # Commit all changes self.cli_commit() # Verify all changes tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') self.assertIn(f' net {net}', tmp) self.assertIn(f' domain-password clear {password}', tmp) self.assertIn(f' area-password clear {password}', tmp) for interface in self._interfaces: tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd') self.assertIn(f' isis password clear {password}-{interface}', tmp) def test_isis_06_spf_delay_bfd(self): network = 'point-to-point' holddown = '10' init_delay = '50' long_delay = '200' short_delay = '100' time_to_learn = '75' bfd_profile = 'isis-bfd' self.cli_set(base_path + ['net', net]) for interface in self._interfaces: self.cli_set(base_path + ['interface', interface, 'network', network]) self.cli_set(base_path + ['interface', interface, 'bfd', 'profile', bfd_profile]) self.cli_set(base_path + ['spf-delay-ietf', 'holddown', holddown]) # verify() - All types of spf-delay must be configured with self.assertRaises(ConfigSessionError): self.cli_commit() self.cli_set(base_path + ['spf-delay-ietf', 'init-delay', init_delay]) # verify() - All types of spf-delay must be configured with self.assertRaises(ConfigSessionError): self.cli_commit() self.cli_set(base_path + ['spf-delay-ietf', 'long-delay', long_delay]) # verify() - All types of spf-delay must be configured with self.assertRaises(ConfigSessionError): self.cli_commit() self.cli_set(base_path + ['spf-delay-ietf', 'short-delay', short_delay]) # verify() - All types of spf-delay must be configured with self.assertRaises(ConfigSessionError): self.cli_commit() self.cli_set(base_path + ['spf-delay-ietf', 'time-to-learn', time_to_learn]) # Commit all changes self.cli_commit() # Verify all changes tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') self.assertIn(f' net {net}', tmp) self.assertIn(f' spf-delay-ietf init-delay {init_delay} short-delay {short_delay} long-delay {long_delay} holddown {holddown} time-to-learn {time_to_learn}', tmp) for interface in self._interfaces: tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd') self.assertIn(f' ip router isis {domain}', tmp) self.assertIn(f' ipv6 router isis {domain}', tmp) self.assertIn(f' isis network {network}', tmp) self.assertIn(f' isis bfd', tmp) self.assertIn(f' isis bfd profile {bfd_profile}', tmp) def test_isis_07_segment_routing_configuration(self): global_block_low = "300" global_block_high = "399" local_block_low = "400" local_block_high = "499" interface = 'lo' maximum_stack_size = '5' prefix_one = '192.168.0.1/32' prefix_two = '192.168.0.2/32' prefix_three = '192.168.0.3/32' prefix_four = '192.168.0.4/32' prefix_one_value = '1' prefix_two_value = '2' prefix_three_value = '60000' prefix_four_value = '65000' self.cli_set(base_path + ['net', net]) self.cli_set(base_path + ['interface', interface]) self.cli_set(base_path + ['segment-routing', 'maximum-label-depth', maximum_stack_size]) self.cli_set(base_path + ['segment-routing', 'global-block', 'low-label-value', global_block_low]) self.cli_set(base_path + ['segment-routing', 'global-block', 'high-label-value', global_block_high]) self.cli_set(base_path + ['segment-routing', 'local-block', 'low-label-value', local_block_low]) self.cli_set(base_path + ['segment-routing', 'local-block', 'high-label-value', local_block_high]) self.cli_set(base_path + ['segment-routing', 'prefix', prefix_one, 'index', 'value', prefix_one_value]) self.cli_set(base_path + ['segment-routing', 'prefix', prefix_one, 'index', 'explicit-null']) self.cli_set(base_path + ['segment-routing', 'prefix', prefix_two, 'index', 'value', prefix_two_value]) self.cli_set(base_path + ['segment-routing', 'prefix', prefix_two, 'index', 'no-php-flag']) self.cli_set(base_path + ['segment-routing', 'prefix', prefix_three, 'absolute', 'value', prefix_three_value]) self.cli_set(base_path + ['segment-routing', 'prefix', prefix_three, 'absolute', 'explicit-null']) self.cli_set(base_path + ['segment-routing', 'prefix', prefix_four, 'absolute', 'value', prefix_four_value]) self.cli_set(base_path + ['segment-routing', 'prefix', prefix_four, 'absolute', 'no-php-flag']) # Commit all changes self.cli_commit() # Verify all changes tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') self.assertIn(f' net {net}', tmp) self.assertIn(f' segment-routing on', tmp) self.assertIn(f' segment-routing global-block {global_block_low} {global_block_high} local-block {local_block_low} {local_block_high}', tmp) self.assertIn(f' segment-routing node-msd {maximum_stack_size}', tmp) self.assertIn(f' segment-routing prefix {prefix_one} index {prefix_one_value} explicit-null', tmp) self.assertIn(f' segment-routing prefix {prefix_two} index {prefix_two_value} no-php-flag', tmp) self.assertIn(f' segment-routing prefix {prefix_three} absolute {prefix_three_value} explicit-null', tmp) self.assertIn(f' segment-routing prefix {prefix_four} absolute {prefix_four_value} no-php-flag', tmp) def test_isis_08_ldp_sync(self): holddown = "500" interface = 'lo' self.cli_set(base_path + ['net', net]) self.cli_set(base_path + ['interface', interface]) self.cli_set(base_path + ['ldp-sync', 'holddown', holddown]) # Commit main ISIS changes self.cli_commit() # Verify main ISIS changes tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') self.assertIn(f' net {net}', tmp) self.assertIn(f' mpls ldp-sync', tmp) self.assertIn(f' mpls ldp-sync holddown {holddown}', tmp) for interface in self._interfaces: self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'holddown', holddown]) # Commit interface changes for holddown self.cli_commit() for interface in self._interfaces: # Verify interface changes for holddown tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd') self.assertIn(f'interface {interface}', tmp) self.assertIn(f' ip router isis {domain}', tmp) self.assertIn(f' ipv6 router isis {domain}', tmp) self.assertIn(f' isis mpls ldp-sync holddown {holddown}', tmp) for interface in self._interfaces: self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'disable']) # Commit interface changes for disable self.cli_commit() for interface in self._interfaces: # Verify interface changes for disable tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd') self.assertIn(f'interface {interface}', tmp) self.assertIn(f' ip router isis {domain}', tmp) self.assertIn(f' ipv6 router isis {domain}', tmp) self.assertIn(f' no isis mpls ldp-sync', tmp) def test_isis_09_lfa(self): prefix_list = 'lfa-prefix-list-test-1' prefix_list_address = '192.168.255.255/32' interface = 'lo' self.cli_set(base_path + ['net', net]) self.cli_set(base_path + ['interface', interface]) self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', '1', 'action', 'permit']) self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', '1', 'prefix', prefix_list_address]) # Commit main ISIS changes self.cli_commit() # Add remote portion of LFA with prefix list with validation for level in ['level-1', 'level-2']: self.cli_set(base_path + ['fast-reroute', 'lfa', 'remote', 'prefix-list', prefix_list, level]) self.cli_commit() tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') self.assertIn(f' net {net}', tmp) self.assertIn(f' fast-reroute remote-lfa prefix-list {prefix_list} {level}', tmp) self.cli_delete(base_path + ['fast-reroute']) self.cli_commit() # Add local portion of LFA load-sharing portion with validation for level in ['level-1', 'level-2']: self.cli_set(base_path + ['fast-reroute', 'lfa', 'local', 'load-sharing', 'disable', level]) self.cli_commit() tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') self.assertIn(f' net {net}', tmp) self.assertIn(f' fast-reroute load-sharing disable {level}', tmp) self.cli_delete(base_path + ['fast-reroute']) self.cli_commit() # Add local portion of LFA priority-limit portion with validation for priority in ['critical', 'high', 'medium']: for level in ['level-1', 'level-2']: self.cli_set(base_path + ['fast-reroute', 'lfa', 'local', 'priority-limit', priority, level]) self.cli_commit() tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') self.assertIn(f' net {net}', tmp) self.assertIn(f' fast-reroute priority-limit {priority} {level}', tmp) self.cli_delete(base_path + ['fast-reroute']) self.cli_commit() # Add local portion of LFA tiebreaker portion with validation index = '100' for tiebreaker in ['downstream','lowest-backup-metric','node-protecting']: for level in ['level-1', 'level-2']: self.cli_set(base_path + ['fast-reroute', 'lfa', 'local', 'tiebreaker', tiebreaker, 'index', index, level]) self.cli_commit() tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') self.assertIn(f' net {net}', tmp) self.assertIn(f' fast-reroute lfa tiebreaker {tiebreaker} index {index} {level}', tmp) self.cli_delete(base_path + ['fast-reroute']) self.cli_commit() # Clean up and remove prefix list self.cli_delete(['policy', 'prefix-list', prefix_list]) self.cli_commit() def test_isis_10_topology(self): topologies = ['ipv4-multicast', 'ipv4-mgmt', 'ipv6-unicast', 'ipv6-multicast', 'ipv6-mgmt'] interface = 'lo' # Set a basic IS-IS config self.cli_set(base_path + ['net', net]) - self.cli_set(base_path + ['interface', interface]) for topology in topologies: self.cli_set(base_path + ['topology', topology]) self.cli_commit() tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') self.assertIn(f' net {net}', tmp) self.assertIn(f' topology {topology}', tmp) if __name__ == '__main__': unittest.main(verbosity=2) \ No newline at end of file