Page MenuHomeVyOS Platform

No OneTemporary

Size
591 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py
index 20f108b03..45b300857 100644
--- a/smoketest/scripts/cli/base_interfaces_test.py
+++ b/smoketest/scripts/cli/base_interfaces_test.py
@@ -1,1392 +1,1388 @@
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 re
from json import loads
from netifaces import ifaddresses # pylint: disable = no-name-in-module
from socket import AF_INET
from socket import AF_INET6
from systemd import journal
from base_vyostest_shim import VyOSUnitTestSHIM
-from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.defaults import directories
from vyos.ifconfig import Interface
from vyos.ifconfig import Section
from vyos.pki import CERT_BEGIN
from vyos.utils.file import read_file
from vyos.utils.dict import dict_search
from vyos.utils.process import cmd
from vyos.utils.process import process_named_running
from vyos.utils.network import get_interface_config
from vyos.utils.network import get_interface_vrf
from vyos.utils.network import get_vrf_tableid
from vyos.utils.network import interface_exists
from vyos.utils.network import is_intf_addr_assigned
from vyos.utils.network import is_ipv6_link_local
from vyos.utils.network import get_nft_vrf_zone_mapping
from vyos.xml_ref import cli_defined
from vyos.xml_ref import default_value
dhclient_base_dir = directories['isc_dhclient_dir']
dhclient_process_name = 'dhclient'
dhcp6c_base_dir = directories['dhcp6_client_dir']
dhcp6c_process_name = 'dhcp6c'
MSG_TESTCASE_UNSUPPORTED = 'unsupported on interface family'
server_ca_root_cert_data = """
MIIBcTCCARagAwIBAgIUDcAf1oIQV+6WRaW7NPcSnECQ/lUwCgYIKoZIzj0EAwIw
HjEcMBoGA1UEAwwTVnlPUyBzZXJ2ZXIgcm9vdCBDQTAeFw0yMjAyMTcxOTQxMjBa
Fw0zMjAyMTUxOTQxMjBaMB4xHDAaBgNVBAMME1Z5T1Mgc2VydmVyIHJvb3QgQ0Ew
WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ0y24GzKQf4aM2Ir12tI9yITOIzAUj
ZXyJeCmYI6uAnyAMqc4Q4NKyfq3nBi4XP87cs1jlC1P2BZ8MsjL5MdGWozIwMDAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRwC/YaieMEnjhYa7K3Flw/o0SFuzAK
BggqhkjOPQQDAgNJADBGAiEAh3qEj8vScsjAdBy5shXzXDVVOKWCPTdGrPKnu8UW
a2cCIQDlDgkzWmn5ujc5ATKz1fj+Se/aeqwh4QyoWCVTFLIxhQ==
"""
server_ca_intermediate_cert_data = """
MIIBmTCCAT+gAwIBAgIUNzrtHzLmi3QpPK57tUgCnJZhXXQwCgYIKoZIzj0EAwIw
HjEcMBoGA1UEAwwTVnlPUyBzZXJ2ZXIgcm9vdCBDQTAeFw0yMjAyMTcxOTQxMjFa
Fw0zMjAyMTUxOTQxMjFaMCYxJDAiBgNVBAMMG1Z5T1Mgc2VydmVyIGludGVybWVk
aWF0ZSBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEl2nJ1CzoqPV6hWII2m
eGN/uieU6wDMECTk/LgG8CCCSYb488dibUiFN/1UFsmoLIdIhkx/6MUCYh62m8U2
WNujUzBRMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMV3YwH88I5gFsFUibbQ
kMR0ECPsMB8GA1UdIwQYMBaAFHAL9hqJ4wSeOFhrsrcWXD+jRIW7MAoGCCqGSM49
BAMCA0gAMEUCIQC/ahujD9dp5pMMCd3SZddqGC9cXtOwMN0JR3e5CxP13AIgIMQm
jMYrinFoInxmX64HfshYqnUY8608nK9D2BNPOHo=
"""
client_ca_root_cert_data = """
MIIBcDCCARagAwIBAgIUZmoW2xVdwkZSvglnkCq0AHKa6zIwCgYIKoZIzj0EAwIw
HjEcMBoGA1UEAwwTVnlPUyBjbGllbnQgcm9vdCBDQTAeFw0yMjAyMTcxOTQxMjFa
Fw0zMjAyMTUxOTQxMjFaMB4xHDAaBgNVBAMME1Z5T1MgY2xpZW50IHJvb3QgQ0Ew
WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATUpKXzQk2NOVKDN4VULk2yw4mOKPvn
mg947+VY7lbpfOfAUD0QRg95qZWCw899eKnXp/U4TkAVrmEKhUb6OJTFozIwMDAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTXu6xGWUl25X3sBtrhm3BJSICIATAK
BggqhkjOPQQDAgNIADBFAiEAnTzEwuTI9bz2Oae3LZbjP6f/f50KFJtjLZFDbQz7
DpYCIDNRHV8zBUibC+zg5PqMpQBKd/oPfNU76nEv6xkp/ijO
"""
client_ca_intermediate_cert_data = """
MIIBmDCCAT+gAwIBAgIUJEMdotgqA7wU4XXJvEzDulUAGqgwCgYIKoZIzj0EAwIw
HjEcMBoGA1UEAwwTVnlPUyBjbGllbnQgcm9vdCBDQTAeFw0yMjAyMTcxOTQxMjJa
Fw0zMjAyMTUxOTQxMjJaMCYxJDAiBgNVBAMMG1Z5T1MgY2xpZW50IGludGVybWVk
aWF0ZSBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGyIVIi217s9j3O+WQ2b
6R65/Z0ZjQpELxPjBRc0CA0GFCo+pI5EvwI+jNFArvTAJ5+ZdEWUJ1DQhBKDDQdI
avCjUzBRMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOUS8oNJjChB1Rb9Blcl
ETvziHJ9MB8GA1UdIwQYMBaAFNe7rEZZSXblfewG2uGbcElIgIgBMAoGCCqGSM49
BAMCA0cAMEQCIArhaxWgRsAUbEeNHD/ULtstLHxw/P97qPUSROLQld53AiBjgiiz
9pDfISmpekZYz6bIDWRIR0cXUToZEMFNzNMrQg==
"""
client_cert_data = """
MIIBmTCCAUCgAwIBAgIUV5T77XdE/tV82Tk4Vzhp5BIFFm0wCgYIKoZIzj0EAwIw
JjEkMCIGA1UEAwwbVnlPUyBjbGllbnQgaW50ZXJtZWRpYXRlIENBMB4XDTIyMDIx
NzE5NDEyMloXDTMyMDIxNTE5NDEyMlowIjEgMB4GA1UEAwwXVnlPUyBjbGllbnQg
Y2VydGlmaWNhdGUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARuyynqfc/qJj5e
KJ03oOH8X4Z8spDeAPO9WYckMM0ldPj+9kU607szFzPwjaPWzPdgyIWz3hcN8yAh
CIhytmJao1AwTjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTIFKrxZ+PqOhYSUqnl
TGCUmM7wTjAfBgNVHSMEGDAWgBTlEvKDSYwoQdUW/QZXJRE784hyfTAKBggqhkjO
PQQDAgNHADBEAiAvO8/jvz05xqmP3OXD53XhfxDLMIxzN4KPoCkFqvjlhQIgIHq2
/geVx3rAOtSps56q/jiDouN/aw01TdpmGKVAa9U=
"""
client_key_data = """
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgxaxAQsJwjoOCByQE
+qSYKtKtJzbdbOnTsKNSrfgkFH6hRANCAARuyynqfc/qJj5eKJ03oOH8X4Z8spDe
APO9WYckMM0ldPj+9kU607szFzPwjaPWzPdgyIWz3hcN8yAhCIhytmJa
"""
def get_wpa_supplicant_value(interface, key):
tmp = read_file(f'/run/wpa_supplicant/{interface}.conf')
tmp = re.findall(r'\n?{}=(.*)'.format(key), tmp)
return tmp[0]
def get_certificate_count(interface, cert_type):
tmp = read_file(f'/run/wpa_supplicant/{interface}_{cert_type}.pem')
return tmp.count(CERT_BEGIN)
def is_mirrored_to(interface, mirror_if, qdisc):
"""
Ask TC if we are mirroring traffic to a discrete interface.
interface: source interface
mirror_if: destination where we mirror our data to
qdisc: must be ffff or 1 for ingress/egress
"""
if qdisc not in ['ffff', '1']:
raise ValueError()
ret_val = False
tmp = cmd(f'tc -s -p filter ls dev {interface} parent {qdisc}: | grep mirred')
tmp = tmp.lower()
if mirror_if in tmp:
ret_val = True
return ret_val
class BasicInterfaceTest:
class TestCase(VyOSUnitTestSHIM.TestCase):
_test_dhcp = False
_test_eapol = False
_test_ip = False
_test_mtu = False
_test_vlan = False
_test_qinq = False
_test_ipv6 = False
_test_ipv6_pd = False
_test_ipv6_dhcpc6 = False
_test_mirror = False
_test_vrf = False
_base_path = []
_options = {}
_interfaces = []
_qinq_range = ['10', '20', '30']
_vlan_range = ['100', '200', '300', '2000']
_test_addr = ['192.0.2.1/26', '192.0.2.255/31', '192.0.2.64/32',
'2001:db8:1::ffff/64', '2001:db8:101::1/112']
_mirror_interfaces = []
# choose IPv6 minimum MTU value for tests - this must always work
_mtu = '1280'
@classmethod
def setUpClass(cls):
super(BasicInterfaceTest.TestCase, cls).setUpClass()
# XXX the case of test_vif_8021q_mtu_limits, below, shows that
# we should extend cli_defined to support more complex queries
cls._test_vlan = cli_defined(cls._base_path, 'vif')
cls._test_qinq = cli_defined(cls._base_path, 'vif-s')
cls._test_dhcp = cli_defined(cls._base_path, 'dhcp-options')
cls._test_eapol = cli_defined(cls._base_path, 'eapol')
cls._test_ip = cli_defined(cls._base_path, 'ip')
cls._test_ipv6 = cli_defined(cls._base_path, 'ipv6')
cls._test_ipv6_dhcpc6 = cli_defined(cls._base_path, 'dhcpv6-options')
cls._test_ipv6_pd = cli_defined(cls._base_path + ['dhcpv6-options'], 'pd')
cls._test_mtu = cli_defined(cls._base_path, 'mtu')
cls._test_vrf = cli_defined(cls._base_path, 'vrf')
# Setup mirror interfaces for SPAN (Switch Port Analyzer)
for span in cls._mirror_interfaces:
section = Section.section(span)
cls.cli_set(cls, ['interfaces', section, span])
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
-
@classmethod
def tearDownClass(cls):
# Tear down mirror interfaces for SPAN (Switch Port Analyzer)
for span in cls._mirror_interfaces:
section = Section.section(span)
cls.cli_delete(cls, ['interfaces', section, span])
super(BasicInterfaceTest.TestCase, cls).tearDownClass()
def tearDown(self):
self.cli_delete(self._base_path)
self.cli_commit()
# Verify that no previously interface remained on the system
ct_map = get_nft_vrf_zone_mapping()
for intf in self._interfaces:
self.assertFalse(interface_exists(intf))
for map_entry in ct_map:
self.assertNotEqual(intf, map_entry['interface'])
# No daemon started during tests should remain running
for daemon in ['dhcp6c', 'dhclient']:
# if _interface list is populated do a more fine grained search
# by also checking the cmd arguments passed to the daemon
if self._interfaces:
for tmp in self._interfaces:
self.assertFalse(process_named_running(daemon, tmp))
else:
self.assertFalse(process_named_running(daemon))
def test_dhcp_disable_interface(self):
if not self._test_dhcp:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
# When interface is configured as admin down, it must be admin down
# even when dhcpc starts on the given interface
for interface in self._interfaces:
self.cli_set(self._base_path + [interface, 'disable'])
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
# Also enable DHCP (ISC DHCP always places interface in admin up
# state so we check that we do not start DHCP client.
# https://vyos.dev/T2767
self.cli_set(self._base_path + [interface, 'address', 'dhcp'])
self.cli_commit()
# Validate interface state
for interface in self._interfaces:
flags = read_file(f'/sys/class/net/{interface}/flags')
self.assertEqual(int(flags, 16) & 1, 0)
def test_dhcp_client_options(self):
if not self._test_dhcp or not self._test_vrf:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
client_id = 'VyOS-router'
distance = '100'
hostname = 'vyos'
vendor_class_id = 'vyos-vendor'
user_class = 'vyos'
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_set(self._base_path + [interface, 'address', 'dhcp'])
self.cli_set(self._base_path + [interface, 'dhcp-options', 'client-id', client_id])
self.cli_set(self._base_path + [interface, 'dhcp-options', 'default-route-distance', distance])
self.cli_set(self._base_path + [interface, 'dhcp-options', 'host-name', hostname])
self.cli_set(self._base_path + [interface, 'dhcp-options', 'vendor-class-id', vendor_class_id])
self.cli_set(self._base_path + [interface, 'dhcp-options', 'user-class', user_class])
self.cli_commit()
for interface in self._interfaces:
# Check if dhclient process runs
dhclient_pid = process_named_running(dhclient_process_name, cmdline=interface, timeout=10)
self.assertTrue(dhclient_pid)
dhclient_config = read_file(f'{dhclient_base_dir}/dhclient_{interface}.conf')
self.assertIn(f'request subnet-mask, broadcast-address, routers, domain-name-servers', dhclient_config)
self.assertIn(f'require subnet-mask;', dhclient_config)
self.assertIn(f'send host-name "{hostname}";', dhclient_config)
self.assertIn(f'send dhcp-client-identifier "{client_id}";', dhclient_config)
self.assertIn(f'send vendor-class-identifier "{vendor_class_id}";', dhclient_config)
self.assertIn(f'send user-class "{user_class}";', dhclient_config)
# and the commandline has the appropriate options
cmdline = read_file(f'/proc/{dhclient_pid}/cmdline')
self.assertIn(f'-e\x00IF_METRIC={distance}', cmdline)
def test_dhcp_vrf(self):
if not self._test_dhcp or not self._test_vrf:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
cli_default_metric = default_value(self._base_path + [self._interfaces[0],
'dhcp-options', 'default-route-distance'])
vrf_name = 'purple4'
self.cli_set(['vrf', 'name', vrf_name, 'table', '65000'])
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_set(self._base_path + [interface, 'address', 'dhcp'])
self.cli_set(self._base_path + [interface, 'vrf', vrf_name])
self.cli_commit()
# Validate interface state
for interface in self._interfaces:
tmp = get_interface_vrf(interface)
self.assertEqual(tmp, vrf_name)
# Check if dhclient process runs
dhclient_pid = process_named_running(dhclient_process_name, cmdline=interface, timeout=10)
self.assertTrue(dhclient_pid)
# .. inside the appropriate VRF instance
vrf_pids = cmd(f'ip vrf pids {vrf_name}')
self.assertIn(str(dhclient_pid), vrf_pids)
# and the commandline has the appropriate options
cmdline = read_file(f'/proc/{dhclient_pid}/cmdline')
self.assertIn(f'-e\x00IF_METRIC={cli_default_metric}', cmdline)
# T5103: remove interface from VRF instance and move DHCP client
# back to default VRF. This must restart the DHCP client process
for interface in self._interfaces:
self.cli_delete(self._base_path + [interface, 'vrf'])
self.cli_commit()
# Validate interface state
for interface in self._interfaces:
tmp = get_interface_vrf(interface)
self.assertEqual(tmp, 'default')
# Check if dhclient process runs
dhclient_pid = process_named_running(dhclient_process_name, cmdline=interface, timeout=10)
self.assertTrue(dhclient_pid)
# .. inside the appropriate VRF instance
vrf_pids = cmd(f'ip vrf pids {vrf_name}')
self.assertNotIn(str(dhclient_pid), vrf_pids)
# and the commandline has the appropriate options
cmdline = read_file(f'/proc/{dhclient_pid}/cmdline')
self.assertIn(f'-e\x00IF_METRIC={cli_default_metric}', cmdline)
self.cli_delete(['vrf', 'name', vrf_name])
def test_dhcpv6_vrf(self):
if not self._test_ipv6_dhcpc6 or not self._test_vrf:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
vrf_name = 'purple6'
self.cli_set(['vrf', 'name', vrf_name, 'table', '65001'])
# When interface is configured as admin down, it must be admin down
# even when dhcpc starts on the given interface
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_set(self._base_path + [interface, 'address', 'dhcpv6'])
self.cli_set(self._base_path + [interface, 'vrf', vrf_name])
self.cli_commit()
# Validate interface state
for interface in self._interfaces:
tmp = get_interface_vrf(interface)
self.assertEqual(tmp, vrf_name)
# Check if dhclient process runs
tmp = process_named_running(dhcp6c_process_name, cmdline=interface, timeout=10)
self.assertTrue(tmp)
# .. inside the appropriate VRF instance
vrf_pids = cmd(f'ip vrf pids {vrf_name}')
self.assertIn(str(tmp), vrf_pids)
# T7135: remove interface from VRF instance and move DHCP client
# back to default VRF. This must restart the DHCP client process
for interface in self._interfaces:
self.cli_delete(self._base_path + [interface, 'vrf'])
self.cli_commit()
# Validate interface state
for interface in self._interfaces:
tmp = get_interface_vrf(interface)
self.assertEqual(tmp, 'default')
# Check if dhclient process runs
tmp = process_named_running(dhcp6c_process_name, cmdline=interface, timeout=10)
self.assertTrue(tmp)
# .. inside the appropriate VRF instance
vrf_pids = cmd(f'ip vrf pids {vrf_name}')
self.assertNotIn(str(tmp), vrf_pids)
self.cli_delete(['vrf', 'name', vrf_name])
def test_move_interface_between_vrf_instances(self):
if not self._test_vrf:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
vrf1_name = 'smoketest_mgmt1'
vrf1_table = '5424'
vrf2_name = 'smoketest_mgmt2'
vrf2_table = '7412'
self.cli_set(['vrf', 'name', vrf1_name, 'table', vrf1_table])
self.cli_set(['vrf', 'name', vrf2_name, 'table', vrf2_table])
# move interface into first VRF
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_set(self._base_path + [interface, 'vrf', vrf1_name])
self.cli_commit()
# check that interface belongs to proper VRF
for interface in self._interfaces:
tmp = get_interface_vrf(interface)
self.assertEqual(tmp, vrf1_name)
tmp = get_interface_config(vrf1_name)
self.assertEqual(int(vrf1_table), get_vrf_tableid(interface))
# move interface into second VRF
for interface in self._interfaces:
self.cli_set(self._base_path + [interface, 'vrf', vrf2_name])
self.cli_commit()
# check that interface belongs to proper VRF
for interface in self._interfaces:
tmp = get_interface_vrf(interface)
self.assertEqual(tmp, vrf2_name)
tmp = get_interface_config(vrf2_name)
self.assertEqual(int(vrf2_table), get_vrf_tableid(interface))
self.cli_delete(['vrf', 'name', vrf1_name])
self.cli_delete(['vrf', 'name', vrf2_name])
def test_add_to_invalid_vrf(self):
if not self._test_vrf:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
# move interface into first VRF
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_set(self._base_path + [interface, 'vrf', 'invalid'])
# check validate() - can not use a non-existing VRF
with self.assertRaises(ConfigSessionError):
self.cli_commit()
for interface in self._interfaces:
self.cli_delete(self._base_path + [interface, 'vrf', 'invalid'])
self.cli_set(self._base_path + [interface, 'description', 'test_add_to_invalid_vrf'])
def test_span_mirror(self):
if not self._mirror_interfaces:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
# Check the two-way mirror rules of ingress and egress
for mirror in self._mirror_interfaces:
for interface in self._interfaces:
self.cli_set(self._base_path + [interface, 'mirror', 'ingress', mirror])
self.cli_set(self._base_path + [interface, 'mirror', 'egress', mirror])
self.cli_commit()
# Verify config
for mirror in self._mirror_interfaces:
for interface in self._interfaces:
self.assertTrue(is_mirrored_to(interface, mirror, 'ffff'))
self.assertTrue(is_mirrored_to(interface, mirror, '1'))
def test_interface_disable(self):
# Check if description can be added to interface and
# can be read back
for intf in self._interfaces:
self.cli_set(self._base_path + [intf, 'disable'])
for option in self._options.get(intf, []):
self.cli_set(self._base_path + [intf] + option.split())
self.cli_commit()
# Validate interface description
for intf in self._interfaces:
self.assertEqual(Interface(intf).get_admin_state(), 'down')
def test_interface_description(self):
# Check if description can be added to interface and
# can be read back
for intf in self._interfaces:
test_string=f'Description-Test-{intf}'
self.cli_set(self._base_path + [intf, 'description', test_string])
for option in self._options.get(intf, []):
self.cli_set(self._base_path + [intf] + option.split())
self.cli_commit()
# Validate interface description
for intf in self._interfaces:
test_string=f'Description-Test-{intf}'
tmp = read_file(f'/sys/class/net/{intf}/ifalias')
self.assertEqual(tmp, test_string)
self.assertEqual(Interface(intf).get_alias(), test_string)
self.cli_delete(self._base_path + [intf, 'description'])
self.cli_commit()
# Validate remove interface description "empty"
for intf in self._interfaces:
tmp = read_file(f'/sys/class/net/{intf}/ifalias')
self.assertEqual(tmp, str())
self.assertEqual(Interface(intf).get_alias(), str())
# Test maximum interface description lengt (255 characters)
test_string='abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789___'
for intf in self._interfaces:
self.cli_set(self._base_path + [intf, 'description', test_string])
for option in self._options.get(intf, []):
self.cli_set(self._base_path + [intf] + option.split())
self.cli_commit()
# Validate interface description
for intf in self._interfaces:
tmp = read_file(f'/sys/class/net/{intf}/ifalias')
self.assertEqual(tmp, test_string)
self.assertEqual(Interface(intf).get_alias(), test_string)
def test_add_single_ip_address(self):
addr = '192.0.2.0/31'
for intf in self._interfaces:
self.cli_set(self._base_path + [intf, 'address', addr])
for option in self._options.get(intf, []):
self.cli_set(self._base_path + [intf] + option.split())
self.cli_commit()
for intf in self._interfaces:
self.assertTrue(is_intf_addr_assigned(intf, addr))
self.assertEqual(Interface(intf).get_admin_state(), 'up')
def test_add_multiple_ip_addresses(self):
# Add address
for intf in self._interfaces:
for option in self._options.get(intf, []):
self.cli_set(self._base_path + [intf] + option.split())
for addr in self._test_addr:
self.cli_set(self._base_path + [intf, 'address', addr])
self.cli_commit()
# Validate address
for intf in self._interfaces:
for af in AF_INET, AF_INET6:
for addr in ifaddresses(intf)[af]:
# checking link local addresses makes no sense
if is_ipv6_link_local(addr['addr']):
continue
self.assertTrue(is_intf_addr_assigned(intf, addr['addr']))
def test_ipv6_link_local_address(self):
# Common function for IPv6 link-local address assignemnts
if not self._test_ipv6:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
for interface in self._interfaces:
base = self._base_path + [interface]
# just set the interface base without any option - some interfaces
# (VTI) do not require any option to be brought up
self.cli_set(base)
for option in self._options.get(interface, []):
self.cli_set(base + option.split())
# after commit we must have an IPv6 link-local address
self.cli_commit()
for interface in self._interfaces:
self.assertIn(AF_INET6, ifaddresses(interface))
for addr in ifaddresses(interface)[AF_INET6]:
self.assertTrue(is_ipv6_link_local(addr['addr']))
# disable IPv6 link-local address assignment
for interface in self._interfaces:
base = self._base_path + [interface]
self.cli_set(base + ['ipv6', 'address', 'no-default-link-local'])
# after commit we must have no IPv6 link-local address
self.cli_commit()
for interface in self._interfaces:
self.assertNotIn(AF_INET6, ifaddresses(interface))
def test_interface_mtu(self):
if not self._test_mtu:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
for intf in self._interfaces:
base = self._base_path + [intf]
self.cli_set(base + ['mtu', self._mtu])
for option in self._options.get(intf, []):
self.cli_set(base + option.split())
# commit interface changes
self.cli_commit()
# verify changed MTU
for intf in self._interfaces:
tmp = get_interface_config(intf)
self.assertEqual(tmp['mtu'], int(self._mtu))
def test_mtu_1200_no_ipv6_interface(self):
# Testcase if MTU can be changed to 1200 on non IPv6
# enabled interfaces
if not self._test_mtu or not self._test_ipv6:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
old_mtu = self._mtu
self._mtu = '1200'
for intf in self._interfaces:
base = self._base_path + [intf]
for option in self._options.get(intf, []):
self.cli_set(base + option.split())
self.cli_set(base + ['mtu', self._mtu])
# check validate() - can not set low MTU if 'no-default-link-local'
# is not set on CLI
with self.assertRaises(ConfigSessionError):
self.cli_commit()
for intf in self._interfaces:
base = self._base_path + [intf]
self.cli_set(base + ['ipv6', 'address', 'no-default-link-local'])
# commit interface changes
self.cli_commit()
# verify changed MTU
for intf in self._interfaces:
tmp = get_interface_config(intf)
self.assertEqual(tmp['mtu'], int(self._mtu))
self._mtu = old_mtu
def test_vif_8021q_interfaces(self):
# XXX: This testcase is not allowed to run as first testcase, reason
# is the Wireless test will first load the wifi kernel hwsim module
# which creates a wlan0 and wlan1 interface which will fail the
# tearDown() test in the end that no interface is allowed to survive!
if not self._test_vlan:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
for interface in self._interfaces:
base = self._base_path + [interface]
for option in self._options.get(interface, []):
self.cli_set(base + option.split())
for vlan in self._vlan_range:
base = self._base_path + [interface, 'vif', vlan]
for address in self._test_addr:
self.cli_set(base + ['address', address])
self.cli_commit()
for intf in self._interfaces:
for vlan in self._vlan_range:
vif = f'{intf}.{vlan}'
for address in self._test_addr:
self.assertTrue(is_intf_addr_assigned(vif, address))
self.assertEqual(Interface(vif).get_admin_state(), 'up')
# T4064: Delete interface addresses, keep VLAN interface
for interface in self._interfaces:
base = self._base_path + [interface]
for vlan in self._vlan_range:
base = self._base_path + [interface, 'vif', vlan]
self.cli_delete(base + ['address'])
self.cli_commit()
# Verify no IP address is assigned
for interface in self._interfaces:
for vlan in self._vlan_range:
vif = f'{intf}.{vlan}'
for address in self._test_addr:
self.assertFalse(is_intf_addr_assigned(vif, address))
def test_vif_8021q_mtu_limits(self):
# XXX: This testcase is not allowed to run as first testcase, reason
# is the Wireless test will first load the wifi kernel hwsim module
# which creates a wlan0 and wlan1 interface which will fail the
# tearDown() test in the end that no interface is allowed to survive!
if not self._test_vlan or not self._test_mtu:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
mtu_1500 = '1500'
mtu_9000 = '9000'
for interface in self._interfaces:
base = self._base_path + [interface]
self.cli_set(base + ['mtu', mtu_1500])
for option in self._options.get(interface, []):
self.cli_set(base + option.split())
if 'source-interface' in option:
iface = option.split()[-1]
iface_type = Section.section(iface)
self.cli_set(['interfaces', iface_type, iface, 'mtu', mtu_9000])
for vlan in self._vlan_range:
base = self._base_path + [interface, 'vif', vlan]
self.cli_set(base + ['mtu', mtu_9000])
# check validate() - Interface MTU "9000" too high, parent interface MTU is "1500"!
with self.assertRaises(ConfigSessionError):
self.cli_commit()
# Change MTU on base interface to be the same as on the VIF interface
for interface in self._interfaces:
base = self._base_path + [interface]
self.cli_set(base + ['mtu', mtu_9000])
self.cli_commit()
# Verify MTU on base and VIF interfaces
for interface in self._interfaces:
tmp = get_interface_config(interface)
self.assertEqual(tmp['mtu'], int(mtu_9000))
for vlan in self._vlan_range:
tmp = get_interface_config(f'{interface}.{vlan}')
self.assertEqual(tmp['mtu'], int(mtu_9000))
def test_vif_8021q_qos_change(self):
# XXX: This testcase is not allowed to run as first testcase, reason
# is the Wireless test will first load the wifi kernel hwsim module
# which creates a wlan0 and wlan1 interface which will fail the
# tearDown() test in the end that no interface is allowed to survive!
if not self._test_vlan:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
for interface in self._interfaces:
base = self._base_path + [interface]
for option in self._options.get(interface, []):
self.cli_set(base + option.split())
for vlan in self._vlan_range:
base = self._base_path + [interface, 'vif', vlan]
self.cli_set(base + ['ingress-qos', '0:1'])
self.cli_set(base + ['egress-qos', '1:6'])
self.cli_commit()
for intf in self._interfaces:
for vlan in self._vlan_range:
vif = f'{intf}.{vlan}'
tmp = get_interface_config(f'{vif}')
tmp2 = dict_search('linkinfo.info_data.ingress_qos', tmp)
for item in tmp2 if tmp2 else []:
from_key = item['from']
to_key = item['to']
self.assertEqual(from_key, 0)
self.assertEqual(to_key, 1)
tmp2 = dict_search('linkinfo.info_data.egress_qos', tmp)
for item in tmp2 if tmp2 else []:
from_key = item['from']
to_key = item['to']
self.assertEqual(from_key, 1)
self.assertEqual(to_key, 6)
self.assertEqual(Interface(vif).get_admin_state(), 'up')
new_ingress_qos_from = 1
new_ingress_qos_to = 6
new_egress_qos_from = 2
new_egress_qos_to = 7
for interface in self._interfaces:
base = self._base_path + [interface]
for vlan in self._vlan_range:
base = self._base_path + [interface, 'vif', vlan]
self.cli_set(base + ['ingress-qos', f'{new_ingress_qos_from}:{new_ingress_qos_to}'])
self.cli_set(base + ['egress-qos', f'{new_egress_qos_from}:{new_egress_qos_to}'])
self.cli_commit()
for intf in self._interfaces:
for vlan in self._vlan_range:
vif = f'{intf}.{vlan}'
tmp = get_interface_config(f'{vif}')
tmp2 = dict_search('linkinfo.info_data.ingress_qos', tmp)
if tmp2:
from_key = tmp2[0]['from']
to_key = tmp2[0]['to']
self.assertEqual(from_key, new_ingress_qos_from)
self.assertEqual(to_key, new_ingress_qos_to)
tmp2 = dict_search('linkinfo.info_data.egress_qos', tmp)
if tmp2:
from_key = tmp2[0]['from']
to_key = tmp2[0]['to']
self.assertEqual(from_key, new_egress_qos_from)
self.assertEqual(to_key, new_egress_qos_to)
def test_vif_8021q_lower_up_down(self):
# Testcase for https://vyos.dev/T3349
if not self._test_vlan:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
for interface in self._interfaces:
base = self._base_path + [interface]
for option in self._options.get(interface, []):
self.cli_set(base + option.split())
# disable the lower interface
self.cli_set(base + ['disable'])
for vlan in self._vlan_range:
vlan_base = self._base_path + [interface, 'vif', vlan]
# disable the vlan interface
self.cli_set(vlan_base + ['disable'])
self.cli_commit()
# re-enable all lower interfaces
for interface in self._interfaces:
base = self._base_path + [interface]
self.cli_delete(base + ['disable'])
self.cli_commit()
# verify that the lower interfaces are admin up and the vlan
# interfaces are all admin down
for interface in self._interfaces:
self.assertEqual(Interface(interface).get_admin_state(), 'up')
for vlan in self._vlan_range:
ifname = f'{interface}.{vlan}'
self.assertEqual(Interface(ifname).get_admin_state(), 'down')
def test_vif_s_8021ad_vlan_interfaces(self):
# XXX: This testcase is not allowed to run as first testcase, reason
# is the Wireless test will first load the wifi kernel hwsim module
# which creates a wlan0 and wlan1 interface which will fail the
# tearDown() test in the end that no interface is allowed to survive!
if not self._test_qinq:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
for interface in self._interfaces:
base = self._base_path + [interface]
for option in self._options.get(interface, []):
self.cli_set(base + option.split())
for vif_s in self._qinq_range:
for vif_c in self._vlan_range:
base = self._base_path + [interface, 'vif-s', vif_s, 'vif-c', vif_c]
self.cli_set(base + ['mtu', self._mtu])
for address in self._test_addr:
self.cli_set(base + ['address', address])
self.cli_commit()
for interface in self._interfaces:
for vif_s in self._qinq_range:
tmp = get_interface_config(f'{interface}.{vif_s}')
self.assertEqual(dict_search('linkinfo.info_data.protocol', tmp), '802.1ad')
for vif_c in self._vlan_range:
vif = f'{interface}.{vif_s}.{vif_c}'
# For an unknown reason this regularely fails on the QEMU builds,
# thus the test for reading back IP addresses is temporary
# disabled. There is no big deal here, as this uses the same
# methods on 802.1q and here it works and is verified.
# for address in self._test_addr:
# self.assertTrue(is_intf_addr_assigned(vif, address))
tmp = get_interface_config(vif)
self.assertEqual(tmp['mtu'], int(self._mtu))
# T4064: Delete interface addresses, keep VLAN interface
for interface in self._interfaces:
base = self._base_path + [interface]
for vif_s in self._qinq_range:
for vif_c in self._vlan_range:
self.cli_delete(self._base_path + [interface, 'vif-s', vif_s, 'vif-c', vif_c, 'address'])
self.cli_commit()
# Verify no IP address is assigned
for interface in self._interfaces:
base = self._base_path + [interface]
for vif_s in self._qinq_range:
for vif_c in self._vlan_range:
vif = f'{interface}.{vif_s}.{vif_c}'
for address in self._test_addr:
self.assertFalse(is_intf_addr_assigned(vif, address))
# T3972: remove vif-c interfaces from vif-s
for interface in self._interfaces:
base = self._base_path + [interface]
for vif_s in self._qinq_range:
base = self._base_path + [interface, 'vif-s', vif_s, 'vif-c']
self.cli_delete(base)
self.cli_commit()
def test_vif_s_protocol_change(self):
# XXX: This testcase is not allowed to run as first testcase, reason
# is the Wireless test will first load the wifi kernel hwsim module
# which creates a wlan0 and wlan1 interface which will fail the
# tearDown() test in the end that no interface is allowed to survive!
if not self._test_qinq:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
for interface in self._interfaces:
base = self._base_path + [interface]
for option in self._options.get(interface, []):
self.cli_set(base + option.split())
for vif_s in self._qinq_range:
for vif_c in self._vlan_range:
base = self._base_path + [interface, 'vif-s', vif_s, 'vif-c', vif_c]
for address in self._test_addr:
self.cli_set(base + ['address', address])
self.cli_commit()
for interface in self._interfaces:
for vif_s in self._qinq_range:
tmp = get_interface_config(f'{interface}.{vif_s}')
# check for the default value
self.assertEqual(tmp['linkinfo']['info_data']['protocol'], '802.1ad')
# T3532: now change ethertype
new_protocol = '802.1q'
for interface in self._interfaces:
for vif_s in self._qinq_range:
base = self._base_path + [interface, 'vif-s', vif_s]
self.cli_set(base + ['protocol', new_protocol])
self.cli_commit()
# Verify new ethertype configuration
for interface in self._interfaces:
for vif_s in self._qinq_range:
tmp = get_interface_config(f'{interface}.{vif_s}')
self.assertEqual(tmp['linkinfo']['info_data']['protocol'], new_protocol.upper())
def test_interface_ip_options(self):
if not self._test_ip:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
arp_tmo = '300'
mss = '1420'
for interface in self._interfaces:
path = self._base_path + [interface]
for option in self._options.get(interface, []):
self.cli_set(path + option.split())
# Options
if cli_defined(self._base_path + ['ip'], 'adjust-mss'):
self.cli_set(path + ['ip', 'adjust-mss', mss])
if cli_defined(self._base_path + ['ip'], 'arp-cache-timeout'):
self.cli_set(path + ['ip', 'arp-cache-timeout', arp_tmo])
if cli_defined(self._base_path + ['ip'], 'disable-arp-filter'):
self.cli_set(path + ['ip', 'disable-arp-filter'])
if cli_defined(self._base_path + ['ip'], 'disable-forwarding'):
self.cli_set(path + ['ip', 'disable-forwarding'])
if cli_defined(self._base_path + ['ip'], 'enable-directed-broadcast'):
self.cli_set(path + ['ip', 'enable-directed-broadcast'])
if cli_defined(self._base_path + ['ip'], 'enable-arp-accept'):
self.cli_set(path + ['ip', 'enable-arp-accept'])
if cli_defined(self._base_path + ['ip'], 'enable-arp-announce'):
self.cli_set(path + ['ip', 'enable-arp-announce'])
if cli_defined(self._base_path + ['ip'], 'enable-arp-ignore'):
self.cli_set(path + ['ip', 'enable-arp-ignore'])
if cli_defined(self._base_path + ['ip'], 'enable-proxy-arp'):
self.cli_set(path + ['ip', 'enable-proxy-arp'])
if cli_defined(self._base_path + ['ip'], 'proxy-arp-pvlan'):
self.cli_set(path + ['ip', 'proxy-arp-pvlan'])
if cli_defined(self._base_path + ['ip'], 'source-validation'):
self.cli_set(path + ['ip', 'source-validation', 'loose'])
self.cli_commit()
for interface in self._interfaces:
if cli_defined(self._base_path + ['ip'], 'adjust-mss'):
base_options = f'oifname "{interface}"'
out = cmd('sudo nft list chain raw VYOS_TCP_MSS')
for line in out.splitlines():
if line.startswith(base_options):
self.assertIn(f'tcp option maxseg size set {mss}', line)
if cli_defined(self._base_path + ['ip'], 'arp-cache-timeout'):
tmp = read_file(f'/proc/sys/net/ipv4/neigh/{interface}/base_reachable_time_ms')
self.assertEqual(tmp, str((int(arp_tmo) * 1000))) # tmo value is in milli seconds
proc_base = f'/proc/sys/net/ipv4/conf/{interface}'
if cli_defined(self._base_path + ['ip'], 'disable-arp-filter'):
tmp = read_file(f'{proc_base}/arp_filter')
self.assertEqual('0', tmp)
if cli_defined(self._base_path + ['ip'], 'enable-arp-accept'):
tmp = read_file(f'{proc_base}/arp_accept')
self.assertEqual('1', tmp)
if cli_defined(self._base_path + ['ip'], 'enable-arp-announce'):
tmp = read_file(f'{proc_base}/arp_announce')
self.assertEqual('1', tmp)
if cli_defined(self._base_path + ['ip'], 'enable-arp-ignore'):
tmp = read_file(f'{proc_base}/arp_ignore')
self.assertEqual('1', tmp)
if cli_defined(self._base_path + ['ip'], 'disable-forwarding'):
tmp = read_file(f'{proc_base}/forwarding')
self.assertEqual('0', tmp)
if cli_defined(self._base_path + ['ip'], 'enable-directed-broadcast'):
tmp = read_file(f'{proc_base}/bc_forwarding')
self.assertEqual('1', tmp)
if cli_defined(self._base_path + ['ip'], 'enable-proxy-arp'):
tmp = read_file(f'{proc_base}/proxy_arp')
self.assertEqual('1', tmp)
if cli_defined(self._base_path + ['ip'], 'proxy-arp-pvlan'):
tmp = read_file(f'{proc_base}/proxy_arp_pvlan')
self.assertEqual('1', tmp)
if cli_defined(self._base_path + ['ip'], 'source-validation'):
base_options = f'iifname "{interface}"'
out = cmd('sudo nft list chain ip raw vyos_rpfilter')
for line in out.splitlines():
if line.startswith(base_options):
self.assertIn('fib saddr oif 0', line)
self.assertIn('drop', line)
def test_interface_ipv6_options(self):
if not self._test_ipv6:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
mss = '1400'
dad_transmits = '10'
accept_dad = '0'
source_validation = 'strict'
interface_identifier = '::fffe'
for interface in self._interfaces:
path = self._base_path + [interface]
for option in self._options.get(interface, []):
self.cli_set(path + option.split())
# Options
if cli_defined(self._base_path + ['ipv6'], 'adjust-mss'):
self.cli_set(path + ['ipv6', 'adjust-mss', mss])
if cli_defined(self._base_path + ['ipv6'], 'accept-dad'):
self.cli_set(path + ['ipv6', 'accept-dad', accept_dad])
if cli_defined(self._base_path + ['ipv6'], 'dup-addr-detect-transmits'):
self.cli_set(path + ['ipv6', 'dup-addr-detect-transmits', dad_transmits])
if cli_defined(self._base_path + ['ipv6'], 'disable-forwarding'):
self.cli_set(path + ['ipv6', 'disable-forwarding'])
if cli_defined(self._base_path + ['ipv6'], 'source-validation'):
self.cli_set(path + ['ipv6', 'source-validation', source_validation])
if cli_defined(self._base_path + ['ipv6', 'address'], 'interface-identifier'):
self.cli_set(path + ['ipv6', 'address', 'interface-identifier', interface_identifier])
self.cli_commit()
for interface in self._interfaces:
proc_base = f'/proc/sys/net/ipv6/conf/{interface}'
if cli_defined(self._base_path + ['ipv6'], 'adjust-mss'):
base_options = f'oifname "{interface}"'
out = cmd('sudo nft list chain ip6 raw VYOS_TCP_MSS')
for line in out.splitlines():
if line.startswith(base_options):
self.assertIn(f'tcp option maxseg size set {mss}', line)
if cli_defined(self._base_path + ['ipv6'], 'accept-dad'):
tmp = read_file(f'{proc_base}/accept_dad')
self.assertEqual(accept_dad, tmp)
if cli_defined(self._base_path + ['ipv6'], 'dup-addr-detect-transmits'):
tmp = read_file(f'{proc_base}/dad_transmits')
self.assertEqual(dad_transmits, tmp)
if cli_defined(self._base_path + ['ipv6'], 'disable-forwarding'):
tmp = read_file(f'{proc_base}/forwarding')
self.assertEqual('0', tmp)
if cli_defined(self._base_path + ['ipv6'], 'source-validation'):
base_options = f'iifname "{interface}"'
out = cmd('sudo nft list chain ip6 raw vyos_rpfilter')
for line in out.splitlines():
if line.startswith(base_options):
self.assertIn('fib saddr . iif oif 0', line)
self.assertIn('drop', line)
if cli_defined(self._base_path + ['ipv6', 'address'], 'interface-identifier'):
tmp = cmd(f'ip -j token show dev {interface}')
tmp = loads(tmp)[0]
self.assertEqual(tmp['token'], interface_identifier)
self.assertEqual(tmp['ifname'], interface)
def test_dhcpv6_client_options(self):
if not self._test_ipv6_dhcpc6:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
duid_base = 10
for interface in self._interfaces:
duid = f'00:01:00:01:27:71:db:f0:00:50:00:00:00:{duid_base}'
path = self._base_path + [interface]
for option in self._options.get(interface, []):
self.cli_set(path + option.split())
# Enable DHCPv6 client
self.cli_set(path + ['address', 'dhcpv6'])
self.cli_set(path + ['dhcpv6-options', 'no-release'])
self.cli_set(path + ['dhcpv6-options', 'rapid-commit'])
self.cli_set(path + ['dhcpv6-options', 'parameters-only'])
self.cli_set(path + ['dhcpv6-options', 'duid', duid])
duid_base += 1
self.cli_commit()
duid_base = 10
for interface in self._interfaces:
duid = f'00:01:00:01:27:71:db:f0:00:50:00:00:00:{duid_base}'
dhcpc6_config = read_file(f'{dhcp6c_base_dir}/dhcp6c.{interface}.conf')
self.assertIn(f'interface {interface} ' + '{', dhcpc6_config)
self.assertIn(f' request domain-name-servers;', dhcpc6_config)
self.assertIn(f' request domain-name;', dhcpc6_config)
self.assertIn(f' information-only;', dhcpc6_config)
self.assertIn(f' send ia-na 0;', dhcpc6_config)
self.assertIn(f' send rapid-commit;', dhcpc6_config)
self.assertIn(f' send client-id {duid};', dhcpc6_config)
self.assertIn('};', dhcpc6_config)
duid_base += 1
# T7058: verify daemon has no problems understanding the custom DUID option
j = journal.Reader()
j.this_boot()
j.add_match(_SYSTEMD_UNIT=f'dhcp6c@{interface}.service')
for entry in j:
self.assertNotIn('yyerror0', entry.get('MESSAGE', ''))
self.assertNotIn('syntax error', entry.get('MESSAGE', ''))
# Better ask the process about it's commandline in the future
pid = process_named_running(dhcp6c_process_name, cmdline=interface, timeout=10)
self.assertTrue(pid)
# DHCPv6 option "no-release" requires "-n" daemon startup option
dhcp6c_options = read_file(f'/proc/{pid}/cmdline')
self.assertIn('-n', dhcp6c_options)
def test_dhcpv6pd_auto_sla_id(self):
if not self._test_ipv6_pd:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
prefix_len = '56'
sla_len = str(64 - int(prefix_len))
# Create delegatee interfaces first to avoid any confusion by dhcpc6
# this is mainly an "issue" with virtual-ethernet interfaces
delegatees = ['dum2340', 'dum2341', 'dum2342', 'dum2343', 'dum2344']
for delegatee in delegatees:
section = Section.section(delegatee)
self.cli_set(['interfaces', section, delegatee])
self.cli_commit()
for interface in self._interfaces:
path = self._base_path + [interface]
for option in self._options.get(interface, []):
self.cli_set(path + option.split())
address = '1'
# prefix delegation stuff
pd_base = path + ['dhcpv6-options', 'pd', '0']
self.cli_set(pd_base + ['length', prefix_len])
for delegatee in delegatees:
self.cli_set(pd_base + ['interface', delegatee, 'address', address])
# increment interface address
address = str(int(address) + 1)
self.cli_commit()
for interface in self._interfaces:
dhcpc6_config = read_file(f'{dhcp6c_base_dir}/dhcp6c.{interface}.conf')
# verify DHCPv6 prefix delegation
self.assertIn(f'prefix ::/{prefix_len} infinity;', dhcpc6_config)
address = '1'
sla_id = '0'
for delegatee in delegatees:
self.assertIn(f'prefix-interface {delegatee}' + r' {', dhcpc6_config)
self.assertIn(f'ifid {address};', dhcpc6_config)
self.assertIn(f'sla-id {sla_id};', dhcpc6_config)
# increment sla-id
sla_id = str(int(sla_id) + 1)
# increment interface address
address = str(int(address) + 1)
# Check for running process
self.assertTrue(process_named_running(dhcp6c_process_name, cmdline=interface, timeout=10))
for delegatee in delegatees:
# we can already cleanup the test delegatee interface here
# as until commit() is called, nothing happens
section = Section.section(delegatee)
self.cli_delete(['interfaces', section, delegatee])
def test_dhcpv6pd_manual_sla_id(self):
if not self._test_ipv6_pd:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
prefix_len = '56'
sla_len = str(64 - int(prefix_len))
# Create delegatee interfaces first to avoid any confusion by dhcpc6
# this is mainly an "issue" with virtual-ethernet interfaces
delegatees = ['dum3340', 'dum3341', 'dum3342', 'dum3343', 'dum3344']
for delegatee in delegatees:
section = Section.section(delegatee)
self.cli_set(['interfaces', section, delegatee])
self.cli_commit()
for interface in self._interfaces:
path = self._base_path + [interface]
for option in self._options.get(interface, []):
self.cli_set(path + option.split())
# prefix delegation stuff
address = '1'
sla_id = '1'
pd_base = path + ['dhcpv6-options', 'pd', '0']
self.cli_set(pd_base + ['length', prefix_len])
for delegatee in delegatees:
self.cli_set(pd_base + ['interface', delegatee, 'address', address])
self.cli_set(pd_base + ['interface', delegatee, 'sla-id', sla_id])
# increment interface address
address = str(int(address) + 1)
sla_id = str(int(sla_id) + 1)
self.cli_commit()
# Verify dhcpc6 client configuration
for interface in self._interfaces:
address = '1'
sla_id = '1'
dhcpc6_config = read_file(f'{dhcp6c_base_dir}/dhcp6c.{interface}.conf')
# verify DHCPv6 prefix delegation
self.assertIn(f'prefix ::/{prefix_len} infinity;', dhcpc6_config)
for delegatee in delegatees:
self.assertIn(f'prefix-interface {delegatee}' + r' {', dhcpc6_config)
self.assertIn(f'ifid {address};', dhcpc6_config)
self.assertIn(f'sla-id {sla_id};', dhcpc6_config)
# increment sla-id
sla_id = str(int(sla_id) + 1)
# increment interface address
address = str(int(address) + 1)
# Check for running process
self.assertTrue(process_named_running(dhcp6c_process_name, cmdline=interface, timeout=10))
for delegatee in delegatees:
# we can already cleanup the test delegatee interface here
# as until commit() is called, nothing happens
section = Section.section(delegatee)
self.cli_delete(['interfaces', section, delegatee])
def test_eapol(self):
if not self._test_eapol:
self.skipTest(MSG_TESTCASE_UNSUPPORTED)
cfg_dir = '/run/wpa_supplicant'
ca_certs = {
'eapol-server-ca-root': server_ca_root_cert_data,
'eapol-server-ca-intermediate': server_ca_intermediate_cert_data,
'eapol-client-ca-root': client_ca_root_cert_data,
'eapol-client-ca-intermediate': client_ca_intermediate_cert_data,
}
cert_name = 'eapol-client'
for name, data in ca_certs.items():
self.cli_set(['pki', 'ca', name, 'certificate', data.replace('\n','')])
self.cli_set(['pki', 'certificate', cert_name, 'certificate', client_cert_data.replace('\n','')])
self.cli_set(['pki', 'certificate', cert_name, 'private', 'key', client_key_data.replace('\n','')])
for interface in self._interfaces:
path = self._base_path + [interface]
for option in self._options.get(interface, []):
self.cli_set(path + option.split())
# Enable EAPoL
self.cli_set(self._base_path + [interface, 'eapol', 'ca-certificate', 'eapol-server-ca-intermediate'])
self.cli_set(self._base_path + [interface, 'eapol', 'ca-certificate', 'eapol-client-ca-intermediate'])
self.cli_set(self._base_path + [interface, 'eapol', 'certificate', cert_name])
self.cli_commit()
# Test multiple CA chains
self.assertEqual(get_certificate_count(interface, 'ca'), 4)
for interface in self._interfaces:
self.cli_delete(self._base_path + [interface, 'eapol', 'ca-certificate', 'eapol-client-ca-intermediate'])
self.cli_commit()
# Validate interface config
for interface in self._interfaces:
tmp = get_wpa_supplicant_value(interface, 'key_mgmt')
self.assertEqual('IEEE8021X', tmp)
tmp = get_wpa_supplicant_value(interface, 'eap')
self.assertEqual('TLS', tmp)
tmp = get_wpa_supplicant_value(interface, 'eapol_flags')
self.assertEqual('0', tmp)
tmp = get_wpa_supplicant_value(interface, 'ca_cert')
self.assertEqual(f'"{cfg_dir}/{interface}_ca.pem"', tmp)
tmp = get_wpa_supplicant_value(interface, 'client_cert')
self.assertEqual(f'"{cfg_dir}/{interface}_cert.pem"', tmp)
tmp = get_wpa_supplicant_value(interface, 'private_key')
self.assertEqual(f'"{cfg_dir}/{interface}_cert.key"', tmp)
mac = read_file(f'/sys/class/net/{interface}/address')
tmp = get_wpa_supplicant_value(interface, 'identity')
self.assertEqual(f'"{mac}"', tmp)
# Check certificate files have the full chain
self.assertEqual(get_certificate_count(interface, 'ca'), 2)
self.assertEqual(get_certificate_count(interface, 'cert'), 3)
# Check for running process
self.assertTrue(process_named_running('wpa_supplicant', cmdline=f'-i{interface}'))
# Remove EAPoL configuration
for interface in self._interfaces:
self.cli_delete(self._base_path + [interface, 'eapol'])
# Commit and check that process is no longer running
self.cli_commit()
self.assertFalse(process_named_running('wpa_supplicant'))
for name in ca_certs:
self.cli_delete(['pki', 'ca', name])
self.cli_delete(['pki', 'certificate', cert_name])
diff --git a/smoketest/scripts/cli/base_vyostest_shim.py b/smoketest/scripts/cli/base_vyostest_shim.py
index 9f4656dfc..cb1759a5b 100644
--- a/smoketest/scripts/cli/base_vyostest_shim.py
+++ b/smoketest/scripts/cli/base_vyostest_shim.py
@@ -1,245 +1,260 @@
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 importlib.util
import os
-import unittest
import paramiko
import pprint
+import re
+import sys
+import unittest
from time import sleep
from typing import Type
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos import ConfigError
from vyos.defaults import commit_lock
from vyos.utils.process import cmd
from vyos.utils.process import run
save_config = '/tmp/vyos-smoketest-save'
-# The commit process is not finished until all pending files from
-# VYATTA_CHANGES_ONLY_DIR are copied to VYATTA_ACTIVE_CONFIGURATION_DIR. This
-# is done inside libvyatta-cfg1 and the FUSE UnionFS part. On large non-
-# interactive commits FUSE UnionFS might not replicate the real state in time,
-# leading to errors when querying the working and effective configuration.
-# TO BE DELETED AFTER SWITCH TO IN MEMORY CONFIG
-CSTORE_GUARD_TIME = 4
-
# This class acts as shim between individual Smoketests developed for VyOS and
# the Python UnitTest framework. Before every test is loaded, we dump the current
# system configuration and reload it after the test - despite the test results.
#
# Using this approach we can not render a live system useless while running any
# kind of smoketest. In addition it adds debug capabilities like printing the
# command used to execute the test.
+
class VyOSUnitTestSHIM:
class TestCase(unittest.TestCase):
# if enabled in derived class, print out each and every set/del command
# on the CLI. This is usefull to grap all the commands required to
# trigger the certain failure condition.
# Use "self.debug = True" in derived classes setUp() method
debug = False
- # Time to wait after a commit to ensure the CStore is up to date
- # only required for testcases using FRR
- _commit_guard_time = 0
@staticmethod
def debug_on():
return os.path.exists('/tmp/vyos.smoketest.debug')
@classmethod
def setUpClass(cls):
+ # Import frr-reload.py functionality
+ file_path = '/usr/lib/frr/frr-reload.py'
+ module_name = 'frr_reload'
+
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
+ module = importlib.util.module_from_spec(spec)
+ sys.modules[module_name] = module
+ spec.loader.exec_module(module)
+ Vtysh = getattr(module, 'Vtysh')
+ cls._vtysh = Vtysh(bindir='/usr/bin', confdir='/etc/frr')
+
cls._session = ConfigSession(os.getpid())
cls._session.save_config(save_config)
cls.debug = cls.debug_on()
pass
@classmethod
def tearDownClass(cls):
# discard any pending changes which might caused a messed up config
cls._session.discard()
# ... and restore the initial state
cls._session.migrate_and_load_config(save_config)
try:
cls._session.commit()
except (ConfigError, ConfigSessionError):
cls._session.discard()
cls.fail(cls)
def cli_set(self, path, value=None):
if self.debug:
str = f'set {" ".join(path)} {value}' if value else f'set {" ".join(path)}'
print(str)
self._session.set(path, value)
def cli_delete(self, config):
if self.debug:
print('del ' + ' '.join(config))
self._session.delete(config)
def cli_discard(self):
if self.debug:
print('DISCARD')
self._session.discard()
def cli_commit(self):
if self.debug:
print('commit')
# During a commit there is a process opening commit_lock, and run()
# returns 0
while run(f'sudo lsof -nP {commit_lock}') == 0:
sleep(0.250)
# Return the output of commit
# Necessary for testing Warning cases
- out = self._session.commit()
- # Wait for CStore completion for fast non-interactive commits
- sleep(self._commit_guard_time)
-
- return out
+ return self._session.commit()
def cli_save(self, file):
if self.debug:
print('save')
self._session.save_config(file)
def op_mode(self, path : list) -> None:
"""
Execute OP-mode command and return stdout
"""
if self.debug:
print('commit')
path = ' '.join(path)
out = cmd(f'/opt/vyatta/bin/vyatta-op-cmd-wrapper {path}')
if self.debug:
print(f'\n\ncommand "{path}" returned:\n')
pprint.pprint(out)
return out
- def getFRRconfig(self, string=None, end='$', endsection='^!',
- substring=None, endsubsection=None, empty_retry=0):
+ def getFRRconfig(self, start_section:str=None, stop_section='^!',
+ start_subsection:str=None, stop_subsection='^ exit') -> str:
"""
Retrieve current "running configuration" from FRR
- string: search for a specific start string in the configuration
- end: end of the section to search for (line ending)
- endsection: end of the configuration
- substring: search section under the result found by string
- endsubsection: end of the subsection (usually something with "exit")
+ start_section: search for a specific start string in the configuration
+ stop_section: end of the configuration
+ start_subsection: search section under the result found by string
+ stop_subsection: end of the subsection (usually something with "exit")
"""
- command = f'vtysh -c "show run no-header"'
- if string:
- command += f' | sed -n "/^{string}{end}/,/{endsection}/p"'
- if substring and endsubsection:
- command += f' | sed -n "/^{substring}/,/{endsubsection}/p"'
- out = cmd(command)
+ frr_config = self._vtysh.mark_show_run()
+ if not start_section:
+ return frr_config
+
+ extracted = []
+ in_section = False
+ for line in frr_config.splitlines():
+ if not in_section:
+ if re.match(start_section, line):
+ in_section = True
+ extracted.append(line)
+ else:
+ extracted.append(line)
+ if re.match(stop_section, line):
+ break
+ output = '\n'.join(extracted)
+
+ # Use extracted list when searching for optional subsection
+ # used by e.g. BGP address-family check
+ if start_subsection:
+ extracted_subsection = []
+ in_subsection = False
+ for line in extracted:
+ if not in_subsection:
+ if re.match(start_subsection, line):
+ in_subsection = True
+ extracted_subsection.append(line)
+ else:
+ extracted_subsection.append(line)
+ if re.match(stop_subsection, line):
+ break
+ output = '\n'.join(extracted_subsection)
+
if self.debug:
- print(f'\n\ncommand "{command}" returned:\n')
- pprint.pprint(out)
- if empty_retry > 0:
- retry_count = 0
- while not out and retry_count < empty_retry:
- if self.debug and retry_count % 10 == 0:
- print(f"Attempt {retry_count}: FRR config is still empty. Retrying...")
- retry_count += 1
- sleep(1)
- out = cmd(command)
- if not out:
- print(f'FRR configuration still empty after {empty_retry} retires!')
- return out
+ print(output)
+ return output
def getFRRopmode(self, command : str, json : bool=False):
from json import loads
if json: command += f' json'
out = cmd(f'vtysh -c "{command}"')
if json:
out = loads(out)
if self.debug:
print(f'\n\ncommand "{command}" returned:\n')
pprint.pprint(out)
return out
@staticmethod
def ssh_send_cmd(command, username, password, key_filename=None,
hostname='localhost'):
""" SSH command execution helper """
# Try to login via SSH
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(hostname=hostname, username=username,
password=password, key_filename=key_filename)
_, stdout, stderr = ssh_client.exec_command(command)
output = stdout.read().decode().strip()
error = stderr.read().decode().strip()
ssh_client.close()
return output, error
# Verify nftables output
def verify_nftables(self, nftables_search, table, inverse=False, args=''):
nftables_output = cmd(f'sudo nft {args} list table {table}')
for search in nftables_search:
matched = False
for line in nftables_output.split("\n"):
if all(item in line for item in search):
matched = True
break
self.assertTrue(not matched if inverse else matched, msg=search)
def verify_nftables_chain(self, nftables_search, table, chain, inverse=False, args=''):
nftables_output = cmd(f'sudo nft {args} list chain {table} {chain}')
for search in nftables_search:
matched = False
for line in nftables_output.split("\n"):
if all(item in line for item in search):
matched = True
break
self.assertTrue(not matched if inverse else matched, msg=search)
def verify_nftables_chain_exists(self, table, chain, inverse=False):
try:
cmd(f'sudo nft list chain {table} {chain}')
if inverse:
self.fail(f'Chain exists: {table} {chain}')
except OSError:
if not inverse:
self.fail(f'Chain does not exist: {table} {chain}')
# Verify ip rule output
def verify_rules(self, rules_search, inverse=False, addr_family='inet'):
rule_output = cmd(f'ip -family {addr_family} rule show')
for search in rules_search:
matched = False
for line in rule_output.split("\n"):
if all(item in line for item in search):
matched = True
break
self.assertTrue(not matched if inverse else matched, msg=search)
# standard construction; typing suggestion: https://stackoverflow.com/a/70292317
def ignore_warning(warning: Type[Warning]):
import warnings
from functools import wraps
def inner(f):
@wraps(f)
def wrapped(*args, **kwargs):
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=warning)
return f(*args, **kwargs)
return wrapped
return inner
diff --git a/smoketest/scripts/cli/test_interfaces_bonding.py b/smoketest/scripts/cli/test_interfaces_bonding.py
index 03760f54a..21918282d 100755
--- a/smoketest/scripts/cli/test_interfaces_bonding.py
+++ b/smoketest/scripts/cli/test_interfaces_bonding.py
@@ -1,338 +1,338 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 os
import unittest
from base_interfaces_test import BasicInterfaceTest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.ifconfig import Section
from vyos.ifconfig.interface import Interface
from vyos.configsession import ConfigSessionError
from vyos.utils.network import get_interface_config
from vyos.utils.file import read_file
class BondingInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
cls._base_path = ['interfaces', 'bonding']
cls._mirror_interfaces = ['dum21354']
cls._members = []
# we need to filter out VLAN interfaces identified by a dot (.)
# in their name - just in case!
if 'TEST_ETH' in os.environ:
cls._members = os.environ['TEST_ETH'].split()
else:
for tmp in Section.interfaces('ethernet', vlan=False):
cls._members.append(tmp)
cls._options = {'bond0' : []}
for member in cls._members:
cls._options['bond0'].append(f'member interface {member}')
cls._interfaces = list(cls._options)
# call base-classes classmethod
super(BondingInterfaceTest, cls).setUpClass()
def test_add_single_ip_address(self):
super().test_add_single_ip_address()
for interface in self._interfaces:
slaves = read_file(f'/sys/class/net/{interface}/bonding/slaves').split()
self.assertListEqual(slaves, self._members)
def test_vif_8021q_interfaces(self):
super().test_vif_8021q_interfaces()
for interface in self._interfaces:
slaves = read_file(f'/sys/class/net/{interface}/bonding/slaves').split()
self.assertListEqual(slaves, self._members)
def test_bonding_keep_mac(self):
# T7571: A bond interface should always run from the physical interfaces
# MAC address and not a synthetic one.
base_mac = Interface(self._members[0]).get_mac()
# configure member interfaces
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_commit()
# Verify bond interface MAC address matches the address of it's first member
for interface in self._interfaces:
mac = Interface(interface).get_mac()
self.assertEqual(mac, base_mac)
def test_bonding_remove_member(self):
# T2515: when removing a bond member the previously enslaved/member
# interface must be in its former admin-up/down state. Here we ensure
# that it is admin-up as it was admin-up before.
# configure member interfaces
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_commit()
# remove single bond member port
for interface in self._interfaces:
remove_member = self._members[0]
self.cli_delete(self._base_path + [interface, 'member', 'interface', remove_member])
self.cli_commit()
# removed member port must be admin-up
for interface in self._interfaces:
remove_member = self._members[0]
state = Interface(remove_member).get_admin_state()
self.assertEqual('up', state)
def test_bonding_min_links(self):
# configure member interfaces
min_links = len(self._interfaces)
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_set(self._base_path + [interface, 'min-links', str(min_links)])
self.cli_commit()
# verify config
for interface in self._interfaces:
tmp = get_interface_config(interface)
self.assertEqual(min_links, tmp['linkinfo']['info_data']['min_links'])
# check LACP default rate
self.assertEqual('slow', tmp['linkinfo']['info_data']['ad_lacp_rate'])
def test_bonding_lacp_rate(self):
# configure member interfaces
lacp_rate = 'fast'
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_set(self._base_path + [interface, 'lacp-rate', lacp_rate])
self.cli_commit()
# verify config
for interface in self._interfaces:
tmp = get_interface_config(interface)
# check LACP minimum links (default value)
self.assertEqual(0, tmp['linkinfo']['info_data']['min_links'])
self.assertEqual(lacp_rate, tmp['linkinfo']['info_data']['ad_lacp_rate'])
def test_bonding_hash_policy(self):
# Define available bonding hash policies
hash_policies = ['layer2', 'layer2+3', 'encap2+3', 'encap3+4']
for hash_policy in hash_policies:
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_set(self._base_path + [interface, 'hash-policy', hash_policy])
self.cli_commit()
# verify config
for interface in self._interfaces:
defined_policy = read_file(f'/sys/class/net/{interface}/bonding/xmit_hash_policy').split()
self.assertEqual(defined_policy[0], hash_policy)
def test_bonding_mii_monitoring_interval(self):
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_commit()
# verify default
for interface in self._interfaces:
tmp = read_file(f'/sys/class/net/{interface}/bonding/miimon').split()
self.assertIn('100', tmp)
mii_mon = '250'
for interface in self._interfaces:
self.cli_set(self._base_path + [interface, 'mii-mon-interval', mii_mon])
self.cli_commit()
# verify new CLI value
for interface in self._interfaces:
tmp = read_file(f'/sys/class/net/{interface}/bonding/miimon').split()
self.assertIn(mii_mon, tmp)
def test_bonding_multi_use_member(self):
# Define available bonding hash policies
bonds = ['bond10', 'bond20', 'bond30']
for interface in bonds:
for member in self._members:
self.cli_set(self._base_path + [interface, 'member', 'interface', member])
# check validate() - can not use the same member interfaces multiple times
with self.assertRaises(ConfigSessionError):
self.cli_commit()
# only keep the first bond interface configuration
for interface in bonds[1:]:
self.cli_delete(self._base_path + [interface])
self.cli_commit()
bond = bonds[0]
member_ifaces = read_file(f'/sys/class/net/{bond}/bonding/slaves').split()
for member in self._members:
self.assertIn(member, member_ifaces)
def test_bonding_source_interface(self):
# Re-use member interface that is already a source-interface
bond = 'bond99'
pppoe = 'pppoe98756'
member = next(iter(self._members))
self.cli_set(self._base_path + [bond, 'member', 'interface', member])
self.cli_set(['interfaces', 'pppoe', pppoe, 'source-interface', member])
# check validate() - can not add interface to bond, it is the source-interface of ...
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(['interfaces', 'pppoe', pppoe])
self.cli_commit()
# verify config
slaves = read_file(f'/sys/class/net/{bond}/bonding/slaves').split()
self.assertIn(member, slaves)
def test_bonding_source_bridge_interface(self):
# Re-use member interface that is already a source-interface
bond = 'bond1097'
bridge = 'br6327'
member = next(iter(self._members))
self.cli_set(self._base_path + [bond, 'member', 'interface', member])
self.cli_set(['interfaces', 'bridge', bridge, 'member', 'interface', member])
# check validate() - can not add interface to bond, it is a member of bridge ...
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(['interfaces', 'bridge', bridge])
self.cli_commit()
# verify config
slaves = read_file(f'/sys/class/net/{bond}/bonding/slaves').split()
self.assertIn(member, slaves)
def test_bonding_uniq_member_description(self):
ethernet_path = ['interfaces', 'ethernet']
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_commit()
# Add any changes on bonding members
# For example add description on separate ethX interfaces
for interface in self._interfaces:
for member in self._members:
self.cli_set(ethernet_path + [member, 'description', member + '_interface'])
self.cli_commit()
# verify config
for interface in self._interfaces:
slaves = read_file(f'/sys/class/net/{interface}/bonding/slaves').split()
for member in self._members:
self.assertIn(member, slaves)
def test_bonding_system_mac(self):
# configure member interfaces and system-mac
default_system_mac = '00:00:00:00:00:00' # default MAC is all zeroes
system_mac = '00:50:ab:cd:ef:11'
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_set(self._base_path + [interface, 'system-mac', system_mac])
self.cli_commit()
# verify config
for interface in self._interfaces:
tmp = read_file(f'/sys/class/net/{interface}/bonding/ad_actor_system')
self.assertIn(tmp, system_mac)
for interface in self._interfaces:
self.cli_delete(self._base_path + [interface, 'system-mac'])
self.cli_commit()
# verify default value
for interface in self._interfaces:
tmp = read_file(f'/sys/class/net/{interface}/bonding/ad_actor_system')
self.assertIn(tmp, default_system_mac)
def test_bonding_evpn_multihoming(self):
id = '5'
for interface in self._interfaces:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
self.cli_set(self._base_path + [interface, 'evpn', 'es-id', id])
self.cli_set(self._base_path + [interface, 'evpn', 'es-df-pref', id])
self.cli_set(self._base_path + [interface, 'evpn', 'es-sys-mac', f'00:12:34:56:78:0{id}'])
self.cli_set(self._base_path + [interface, 'evpn', 'uplink'])
id = int(id) + 1
self.cli_commit()
id = '5'
for interface in self._interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f' evpn mh es-id {id}', frrconfig)
self.assertIn(f' evpn mh es-df-pref {id}', frrconfig)
self.assertIn(f' evpn mh es-sys-mac 00:12:34:56:78:0{id}', frrconfig)
self.assertIn(f' evpn mh uplink', frrconfig)
id = int(id) + 1
for interface in self._interfaces:
self.cli_delete(self._base_path + [interface, 'evpn', 'es-id'])
self.cli_delete(self._base_path + [interface, 'evpn', 'es-df-pref'])
self.cli_commit()
id = '5'
for interface in self._interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f' evpn mh es-sys-mac 00:12:34:56:78:0{id}', frrconfig)
self.assertIn(f' evpn mh uplink', frrconfig)
id = int(id) + 1
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_interfaces_ethernet.py b/smoketest/scripts/cli/test_interfaces_ethernet.py
index d42ed29dc..cdc3dad9e 100755
--- a/smoketest/scripts/cli/test_interfaces_ethernet.py
+++ b/smoketest/scripts/cli/test_interfaces_ethernet.py
@@ -1,245 +1,245 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 os
import unittest
from glob import glob
from json import loads
from socket import AF_INET
from socket import AF_INET6
from netifaces import ifaddresses # pylint: disable = no-name-in-module
from base_interfaces_test import BasicInterfaceTest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.utils.file import read_file
from vyos.utils.network import is_intf_addr_assigned
from vyos.utils.network import is_ipv6_link_local
from vyos.utils.process import cmd
from vyos.utils.process import popen
class EthernetInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
cls._base_path = ['interfaces', 'ethernet']
cls._mirror_interfaces = ['dum21354']
# We only test on physical interfaces and not VLAN (sub-)interfaces
if 'TEST_ETH' in os.environ:
tmp = os.environ['TEST_ETH'].split()
cls._interfaces = tmp
else:
for tmp in Section.interfaces('ethernet', vlan=False):
cls._interfaces.append(tmp)
cls._macs = {}
for interface in cls._interfaces:
cls._macs[interface] = read_file(f'/sys/class/net/{interface}/address')
# call base-classes classmethod
super(EthernetInterfaceTest, cls).setUpClass()
def tearDown(self):
for interface in self._interfaces:
# when using a dedicated interface to test via TEST_ETH environment
# variable only this one will be cleared in the end - usable to test
# ethernet interfaces via SSH
self.cli_delete(self._base_path + [interface])
self.cli_set(self._base_path + [interface, 'duplex', 'auto'])
self.cli_set(self._base_path + [interface, 'speed', 'auto'])
self.cli_set(self._base_path + [interface, 'hw-id', self._macs[interface]])
self.cli_commit()
# Verify that no address remains on the system as this is an eternal
# interface.
for interface in self._interfaces:
self.assertNotIn(AF_INET, ifaddresses(interface))
# required for IPv6 link-local address
self.assertIn(AF_INET6, ifaddresses(interface))
for addr in ifaddresses(interface)[AF_INET6]:
# checking link local addresses makes no sense
if is_ipv6_link_local(addr['addr']):
continue
self.assertFalse(is_intf_addr_assigned(interface, addr['addr']))
# Ensure no VLAN interfaces are left behind
tmp = [
x
for x in Section.interfaces('ethernet')
if x.startswith(f'{interface}.')
]
self.assertListEqual(tmp, [])
def test_offloading_rps(self):
# enable RPS on all available CPUs, RPS works with a CPU bitmask,
# where each bit represents a CPU (core/thread). The formula below
# expands to rps_cpus = 255 for a 8 core system
rps_cpus = (1 << os.cpu_count()) - 1
# XXX: we should probably reserve one core when the system is under
# high preasure so we can still have a core left for housekeeping.
# This is done by masking out the lowst bit so CPU0 is spared from
# receive packet steering.
rps_cpus &= ~1
for interface in self._interfaces:
self.cli_set(self._base_path + [interface, 'offload', 'rps'])
self.cli_commit()
for interface in self._interfaces:
cpus = read_file(f'/sys/class/net/{interface}/queues/rx-0/rps_cpus')
# remove the nasty ',' separation on larger strings
cpus = cpus.replace(',', '')
cpus = int(cpus, 16)
self.assertEqual(f'{cpus:x}', f'{rps_cpus:x}')
def test_offloading_rfs(self):
global_rfs_flow = 32768
rfs_flow = global_rfs_flow
for interface in self._interfaces:
self.cli_set(self._base_path + [interface, 'offload', 'rfs'])
self.cli_commit()
for interface in self._interfaces:
queues = len(glob(f'/sys/class/net/{interface}/queues/rx-*'))
rfs_flow = int(global_rfs_flow / queues)
for i in range(0, queues):
tmp = read_file(
f'/sys/class/net/{interface}/queues/rx-{i}/rps_flow_cnt'
)
self.assertEqual(int(tmp), rfs_flow)
tmp = read_file('/proc/sys/net/core/rps_sock_flow_entries')
self.assertEqual(int(tmp), global_rfs_flow)
# delete configuration of RFS and check all values returned to default "0"
for interface in self._interfaces:
self.cli_delete(self._base_path + [interface, 'offload', 'rfs'])
self.cli_commit()
for interface in self._interfaces:
queues = len(glob(f'/sys/class/net/{interface}/queues/rx-*'))
rfs_flow = int(global_rfs_flow / queues)
for i in range(0, queues):
tmp = read_file(
f'/sys/class/net/{interface}/queues/rx-{i}/rps_flow_cnt'
)
self.assertEqual(int(tmp), 0)
def test_non_existing_interface(self):
unknonw_interface = self._base_path + ['eth667']
self.cli_set(unknonw_interface)
# check validate() - interface does not exist
with self.assertRaises(ConfigSessionError):
self.cli_commit()
# we need to remove this wrong interface from the configuration
# manually, else tearDown() will have problem in commit()
self.cli_delete(unknonw_interface)
def test_speed_duplex_verify(self):
for interface in self._interfaces:
self.cli_set(self._base_path + [interface, 'speed', '1000'])
# check validate() - if either speed or duplex is not auto, the
# other one must be manually configured, too
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(self._base_path + [interface, 'speed', 'auto'])
self.cli_commit()
def test_ethtool_ring_buffer(self):
for interface in self._interfaces:
# We do not use vyos.ethtool here to not have any chance
# for invalid testcases. Re-gain data by hand
tmp = cmd(f'sudo ethtool --json --show-ring {interface}')
tmp = loads(tmp)
max_rx = str(tmp[0]['rx-max'])
max_tx = str(tmp[0]['tx-max'])
self.cli_set(self._base_path + [interface, 'ring-buffer', 'rx', max_rx])
self.cli_set(self._base_path + [interface, 'ring-buffer', 'tx', max_tx])
self.cli_commit()
for interface in self._interfaces:
tmp = cmd(f'sudo ethtool --json --show-ring {interface}')
tmp = loads(tmp)
max_rx = str(tmp[0]['rx-max'])
max_tx = str(tmp[0]['tx-max'])
rx = str(tmp[0]['rx'])
tx = str(tmp[0]['tx'])
# validate if the above change was carried out properly and the
# ring-buffer size got increased
self.assertEqual(max_rx, rx)
self.assertEqual(max_tx, tx)
def test_ethtool_flow_control(self):
for interface in self._interfaces:
# Disable flow-control
self.cli_set(self._base_path + [interface, 'disable-flow-control'])
# Check current flow-control state on ethernet interface
out, err = popen(f'sudo ethtool --json --show-pause {interface}')
# Flow-control not supported - test if it bails out with a proper
# this is a dynamic path where err = 1 on VMware, but err = 0 on
# a physical box.
if bool(err):
with self.assertRaises(ConfigSessionError):
self.cli_commit()
else:
out = loads(out)
# Flow control is on
self.assertTrue(out[0]['autonegotiate'])
# commit change on CLI to disable-flow-control and re-test
self.cli_commit()
out, err = popen(f'sudo ethtool --json --show-pause {interface}')
out = loads(out)
self.assertFalse(out[0]['autonegotiate'])
def test_ethtool_evpn_uplink_tracking(self):
for interface in self._interfaces:
self.cli_set(self._base_path + [interface, 'evpn', 'uplink'])
self.cli_commit()
for interface in self._interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(' evpn mh uplink', frrconfig)
def test_switchdev(self):
interface = self._interfaces[0]
self.cli_set(self._base_path + [interface, 'switchdev'])
# check validate() - virtual interfaces do not support switchdev
# should print out warning that enabling failed
self.cli_delete(self._base_path + [interface, 'switchdev'])
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_interfaces_pppoe.py b/smoketest/scripts/cli/test_interfaces_pppoe.py
index 227a01032..06585f43b 100755
--- a/smoketest/scripts/cli/test_interfaces_pppoe.py
+++ b/smoketest/scripts/cli/test_interfaces_pppoe.py
@@ -1,409 +1,414 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 psutil import process_iter
from ipaddress import IPv4Address
from ipaddress import IPv6Address
from ipaddress import IPv4Network
from ipaddress import IPv6Network
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.utils.dict import dict_search_recursive
from vyos.utils.network import get_interface_address
from vyos.xml_ref import default_value
config_file: str = '/etc/ppp/peers/{}'
base_path: list = ['interfaces', 'pppoe']
veth_path: list = ['interfaces', 'virtual-ethernet']
pppoe_server_path = ['service', 'pppoe-server']
connect_timeout: int = 20
name_servers: list = ['1.1.1.1', '2.2.2.2']
ipv4_pool: str = '100.64.0.0/18'
ipv6_pool: str = '2001:db8:8000::/48'
ipv6_pool_pd: str = '2001:db8:9000::/48'
+def calculate_ipv6_interface_address(prefix: IPv6Network, sla_id: int, interface_id: int):
+ # Ensure SLA-ID is 8 bits
+ if not (0 <= sla_id <= 0xFF):
+ raise ValueError('SLA-ID must be an 8-bit integer (0-255)')
+
+ # Ensure Interface ID is 64 bits
+ if not (0 <= interface_id <= 0xFFFFFFFFFFFFFFFF):
+ raise ValueError('Interface ID must be a 64-bit integer')
+
+ # Build the /64 subnet from the PD prefix len + SLA-ID
+ subnet_int = int(prefix.network_address) | (sla_id << 64)
+
+ # Calculate full interface address
+ return IPv6Address(subnet_int | interface_id)
+
def get_config_value(interface, key):
with open(config_file.format(interface), 'r') as f:
for line in f:
if line.startswith(key):
return list(line.split())
return []
def wait_for_interface(interface: str, timeout=connect_timeout) -> bool:
""" Wait until PPPoE interface has been connected to the BRAS """
from time import time
from time import sleep
from vyos.utils.network import get_interface_config
start_time = time()
while not get_interface_config(interface):
sleep(0.250)
if time() - start_time >= timeout:
return False
return True
# add a classmethod to setup a temporaray PPPoE server for "proper" validation
class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(PPPoEInterfaceTest, cls).setUpClass()
# 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, veth_path)
cls.cli_delete(cls, pppoe_server_path)
cls._interfaces = ['pppoe10', 'pppoe20', 'pppoe30']
cls._source_interface = 'veth102'
pppoe_server_interface = 'veth101'
cls.cli_set(cls, veth_path + [pppoe_server_interface, 'peer-name', cls._source_interface])
cls.cli_set(cls, veth_path + [cls._source_interface, 'peer-name', pppoe_server_interface])
cls.cli_set(cls, pppoe_server_path + ['authentication', 'mode', 'local'])
cls.cli_set(cls, pppoe_server_path + ['client-ip-pool', 'IPv4-POOL', 'range', ipv4_pool])
cls.cli_set(cls, pppoe_server_path + ['client-ipv6-pool', 'IPv6-POOL', 'prefix', ipv6_pool, 'mask', '64'])
cls.cli_set(cls, pppoe_server_path + ['client-ipv6-pool', 'IPv6-POOL', 'delegate', ipv6_pool_pd, 'delegation-prefix', '56'])
cls.cli_set(cls, pppoe_server_path + ['default-ipv6-pool', 'IPv6-POOL'])
cls.cli_set(cls, pppoe_server_path + ['default-pool', 'IPv4-POOL'])
cls.cli_set(cls, pppoe_server_path + ['gateway-address', '100.64.0.1'])
cls.cli_set(cls, pppoe_server_path + ['interface', pppoe_server_interface])
for ns in name_servers:
cls.cli_set(cls, pppoe_server_path + ['name-server', ns])
cls.cli_set(cls, pppoe_server_path + ['ppp-options', 'disable-ccp'])
cls.cli_set(cls, pppoe_server_path + ['ppp-options', 'ipv6', 'allow'])
cls.cli_set(cls, pppoe_server_path + ['session-control', 'disable'])
cls.u_p_dict = {}
for interface in cls._interfaces:
username = f'VyOS-user-{interface}'
password = f'VyOS-passwd-{interface}'
cls.cli_set(cls, pppoe_server_path + ['authentication', 'local-users',
'username', username, 'password', password])
cls.u_p_dict[interface] = (username, password)
# Start PPPoE server
cls.cli_commit(cls)
@classmethod
def tearDownClass(cls):
cls.cli_delete(cls, base_path)
cls.cli_delete(cls, veth_path)
cls.cli_delete(cls, pppoe_server_path)
# Stop PPPoE server
cls.cli_commit(cls)
super(PPPoEInterfaceTest, cls).tearDownClass()
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
def _verify_interface_address(self, interface):
# Verify that the assigned IPv4/IPv6 addresses from the BRAS (PPPoE
# server) are from the assigned pools
for address in get_interface_address(interface):
if 'family' in address and address['family'] == 'inet':
# The PPPoE assigned IPv4 address must be from our pool
self.assertIn(IPv4Address(address['address']), IPv4Network(ipv4_pool))
elif 'family' in address and address['family'] == 'inet6':
# The PPPoE assigned IPv6 address must be from our pool
ipv6 = IPv6Address(address['address'])
if not ipv6.is_link_local:
self.assertIn(ipv6, IPv6Network(ipv6_pool))
def test_pppoe_client(self):
# Check if PPPoE dialer can be configured and runs
mtu = '1400'
for interface in self._interfaces:
(user, passwd) = self.u_p_dict[interface]
self.cli_set(base_path + [interface, 'authentication', 'username', user])
self.cli_set(base_path + [interface, 'authentication', 'password', passwd])
self.cli_set(base_path + [interface, 'mtu', mtu])
self.cli_set(base_path + [interface, 'no-peer-dns'])
# check validate() - a source-interface is required
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + [interface, 'source-interface', self._source_interface])
# commit changes
self.cli_commit()
# verify configuration file(s)
for interface in self._interfaces:
self.assertTrue(wait_for_interface(interface),
msg=f'Interface {interface} not found after {connect_timeout} seconds!')
(user, passwd) = self.u_p_dict[interface]
tmp = get_config_value(interface, 'mtu')[1]
self.assertEqual(tmp, mtu)
# MRU must default to MTU if not specified on CLI
tmp = get_config_value(interface, 'mru')[1]
self.assertEqual(tmp, mtu)
tmp = get_config_value(interface, 'user')[1].replace('"', '')
self.assertEqual(tmp, user)
tmp = get_config_value(interface, 'password')[1].replace('"', '')
self.assertEqual(tmp, passwd)
tmp = get_config_value(interface, 'ifname')[1]
self.assertEqual(tmp, interface)
# Validate and verify assigned IP addresses
self._verify_interface_address(interface)
# validate that we have learned a default route
tmp = self.getFRRopmode('show ip route 0.0.0.0/0', json=True)
# Test if we have a default route 0.0.0.0/0 pointing to our PPPoE interface
tmp = dict_search_recursive(tmp, 'interfaceName')
self.assertTrue(any(iface == interface for (iface, _) in tmp))
def test_pppoe_client_disabled_interface(self):
# Check if PPPoE Client can be disabled
for interface in self._interfaces:
(user, passwd) = self.u_p_dict[interface]
self.cli_set(base_path + [interface, 'authentication', 'username', user])
self.cli_set(base_path + [interface, 'authentication', 'password', passwd])
self.cli_set(base_path + [interface, 'source-interface', self._source_interface])
self.cli_set(base_path + [interface, 'disable'])
self.cli_commit()
# Validate PPPoE client process - must not run as interfaces are disabled
for interface in self._interfaces:
running = False
for proc in process_iter():
if interface in proc.cmdline():
running = True
break
self.assertFalse(running)
# enable PPPoE interfaces
for interface in self._interfaces:
self.cli_delete(base_path + [interface, 'disable'])
self.cli_commit()
def test_pppoe_authentication(self):
# When username or password is set - so must be the other
for interface in self._interfaces:
(user, passwd) = self.u_p_dict[interface]
self.cli_set(base_path + [interface, 'source-interface', self._source_interface])
self.cli_set(base_path + [interface, 'ipv6', 'address', 'autoconf'])
self.cli_set(base_path + [interface, 'authentication', 'username', user])
# check validate() - if user is set, so must be the password
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + [interface, 'authentication', 'password', passwd])
self.cli_commit()
for interface in self._interfaces:
self.assertTrue(wait_for_interface(interface),
msg=f'Interface {interface} not found after {connect_timeout} seconds!')
# Validate and verify assigned IP addresses
self._verify_interface_address(interface)
def test_pppoe_dhcpv6pd(self):
# Check if PPPoE dialer can be configured with DHCPv6-PD
- address = '1'
- sla_id = '0'
-
- # verify IPv6 DHCPv6-PD assignment on one dialer interface only - to not mix things up
+ address = 1
+ sla_id = 0xff
for interface in self._interfaces:
(user, passwd) = self.u_p_dict[interface]
interface_id = ''.join(c for c in interface if c.isdigit())
self.cli_set(base_path + [interface, 'authentication', 'username', user])
self.cli_set(base_path + [interface, 'authentication', 'password', passwd])
self.cli_set(base_path + [interface, 'no-default-route'])
self.cli_set(base_path + [interface, 'no-peer-dns'])
self.cli_set(base_path + [interface, 'source-interface', self._source_interface])
self.cli_set(base_path + [interface, 'ipv6', 'address', 'autoconf'])
# interface we will delegate to
delegate_if = f'dum{interface_id}'
self.cli_set(['interfaces', 'dummy', delegate_if])
# prefix delegation stuff
dhcpv6_pd_base = base_path + [interface, 'dhcpv6-options', 'pd', '0']
self.cli_set(dhcpv6_pd_base + ['length', '56'])
- self.cli_set(dhcpv6_pd_base + ['interface', delegate_if, 'address', address])
- self.cli_set(dhcpv6_pd_base + ['interface', delegate_if, 'sla-id', sla_id])
-
- address = str(int(address) + 1)
- sla_id = str(int(sla_id) + 2)
+ self.cli_set(dhcpv6_pd_base + ['interface', delegate_if, 'address'], value=str(address))
+ self.cli_set(dhcpv6_pd_base + ['interface', delegate_if, 'sla-id'], value=str(sla_id))
# commit changes
self.cli_commit()
- address = '1'
- sla_id = '0'
for interface in self._interfaces:
self.assertTrue(wait_for_interface(interface),
msg=f'Interface {interface} not found after {connect_timeout} seconds!')
(user, passwd) = self.u_p_dict[interface]
mtu_default = default_value(base_path + [interface, 'mtu'])
tmp = get_config_value(interface, 'mtu')[1]
self.assertEqual(tmp, mtu_default)
tmp = get_config_value(interface, 'user')[1].replace('"', '')
self.assertEqual(tmp, user)
tmp = get_config_value(interface, 'password')[1].replace('"', '')
self.assertEqual(tmp, passwd)
tmp = get_config_value(interface, '+ipv6 ipv6cp-use-ipaddr')
self.assertListEqual(tmp, ['+ipv6', 'ipv6cp-use-ipaddr'])
# Validate and verify assigned IP addresses
self._verify_interface_address(interface)
# interface we delegated to
delegate_if = f'dum{interface_id}'
tmp = get_interface_address(delegate_if)
self.assertIn('addr_info', tmp)
# Verify IPv6 address received from out DHCPv6-PD
for addr_info in tmp['addr_info']:
if 'family' not in addr_info or addr_info['family'] != 'inet6':
continue
+
# Skip link-local interface address
ipv6 = IPv6Address(addr_info['local'])
if ipv6.is_link_local:
continue
# DHCPv6-PD assigned interface addres is of length /64
self.assertEqual(addr_info['prefixlen'], 64)
# Interface IP address must be within the PD pool
self.assertIn(ipv6, IPv6Network(ipv6_pool_pd))
# Get corresponding PD assigned prefix for this site/connection
pd_prefix = IPv6Network(f"{ipv6}/56", strict=False)
# Prefix must be within the PD pool
- self.assertIn(pd_prefix, IPv6Network(ipv6_pool_pd))
- # Calculate the assigned IP address from the prefix delegation
- network_addr = str(pd_prefix.network_address) # 2001:db8:8003::
- generated_sla_addr = network_addr[:-1] + f'{sla_id}::{address}'
- self.assertEqual(generated_sla_addr, ipv6)
-
- address = str(int(address) + 1)
- sla_id = str(int(sla_id) + 2)
+ self.assertTrue(pd_prefix.subnet_of(IPv6Network(ipv6_pool_pd)))
+
+ gen_addr = calculate_ipv6_interface_address(pd_prefix, sla_id, address)
+ self.assertEqual(gen_addr, ipv6)
self.cli_delete(['interfaces', 'dummy', delegate_if])
def test_pppoe_options(self):
# Verify access-concentrator and service-name CLI options
ac_name: str = 'ACN123'
service_name: str = 'VyOS'
self.cli_set(pppoe_server_path + ['access-concentrator', ac_name])
self.cli_set(pppoe_server_path + ['service-name', service_name])
self.cli_commit()
# as this tests uniqueness - we only use one interface in this test
interface = self._interfaces[0]
(user, passwd) = self.u_p_dict[interface]
host_uniq = 'cafe010203'
self.cli_set(base_path + [interface, 'authentication', 'username', user])
self.cli_set(base_path + [interface, 'authentication', 'password', passwd])
self.cli_set(base_path + [interface, 'source-interface', self._source_interface])
self.cli_set(base_path + [interface, 'access-concentrator', ac_name])
self.cli_set(base_path + [interface, 'service-name', service_name])
self.cli_set(base_path + [interface, 'host-uniq', host_uniq])
# commit changes
self.cli_commit()
self.assertTrue(wait_for_interface(interface),
msg=f'Interface {interface} not found after {connect_timeout} seconds!')
tmp = get_config_value(interface, 'pppoe-ac')[1]
self.assertEqual(tmp, f'"{ac_name}"')
tmp = get_config_value(interface, 'pppoe-service')[1]
self.assertEqual(tmp, f'"{service_name}"')
tmp = get_config_value(interface, 'pppoe-host-uniq')[1]
self.assertEqual(tmp, f'"{host_uniq}"')
# Validate and verify assigned IP addresses
self._verify_interface_address(interface)
self.cli_delete(pppoe_server_path + ['access-concentrator'])
self.cli_delete(pppoe_server_path + ['service-name'])
def test_pppoe_mtu_mru(self):
# Check if PPPoE dialer can be configured and runs
for interface in self._interfaces:
(user, passwd) = self.u_p_dict[interface]
mtu = '1400'
mru = '1300'
self.cli_set(base_path + [interface, 'authentication', 'username', user])
self.cli_set(base_path + [interface, 'authentication', 'password', passwd])
self.cli_set(base_path + [interface, 'mtu', mtu])
self.cli_set(base_path + [interface, 'mru', '9000'])
# check validate() - a source-interface is required
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + [interface, 'source-interface', self._source_interface])
# check validate() - MRU needs to be less or equal then MTU
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + [interface, 'mru', mru])
# commit changes
self.cli_commit()
# verify configuration file(s)
for interface in self._interfaces:
self.assertTrue(wait_for_interface(interface),
msg=f'Interface {interface} not found after {connect_timeout} seconds!')
(user, passwd) = self.u_p_dict[interface]
tmp = get_config_value(interface, 'mtu')[1]
self.assertEqual(tmp, mtu)
tmp = get_config_value(interface, 'mru')[1]
self.assertEqual(tmp, mru)
tmp = get_config_value(interface, 'user')[1].replace('"', '')
self.assertEqual(tmp, user)
tmp = get_config_value(interface, 'password')[1].replace('"', '')
self.assertEqual(tmp, passwd)
tmp = get_config_value(interface, 'ifname')[1]
self.assertEqual(tmp, interface)
# Validate and verify assigned IP addresses
self._verify_interface_address(interface)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py
index 69e768a4b..5cb15c242 100755
--- a/smoketest/scripts/cli/test_policy.py
+++ b/smoketest/scripts/cli/test_policy.py
@@ -1,2054 +1,2051 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.utils.process import cmd
base_path = ['policy']
class TestPolicy(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestPolicy, cls).setUpClass()
# 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'])
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
def test_access_list(self):
acls = {
'50' : {
'rule' : {
'5' : {
'action' : 'permit',
'source' : { 'any' : '' },
},
'10' : {
'action' : 'deny',
'source' : { 'host' : '1.2.3.4' },
},
},
},
'150' : {
'rule' : {
'5' : {
'action' : 'permit',
'source' : { 'any' : '' },
'destination' : { 'host' : '2.2.2.2' },
},
'10' : {
'action' : 'deny',
'source' : { 'any' : '' },
'destination' : { 'any' : '' },
},
},
},
'2000' : {
'rule' : {
'5' : {
'action' : 'permit',
'destination' : { 'any' : '' },
'source' : { 'network' : '10.0.0.0', 'inverse-mask' : '0.255.255.255' },
},
'10' : {
'action' : 'permit',
'destination' : { 'any' : '' },
'source' : { 'network' : '172.16.0.0', 'inverse-mask' : '0.15.255.255' },
},
'15' : {
'action' : 'permit',
'destination' : { 'any' : '' },
'source' : { 'network' : '192.168.0.0', 'inverse-mask' : '0.0.255.255' },
},
'20' : {
'action' : 'permit',
'destination' : { 'network' : '172.16.0.0', 'inverse-mask' : '0.15.255.255' },
'source' : { 'network' : '10.0.0.0', 'inverse-mask' : '0.255.255.255' },
},
'25' : {
'action' : 'deny',
'destination' : { 'network' : '192.168.0.0', 'inverse-mask' : '0.0.255.255' },
'source' : { 'network' : '172.16.0.0', 'inverse-mask' : '0.15.255.255' },
},
'30' : {
'action' : 'deny',
'destination' : { 'any' : '' },
'source' : { 'any' : '' },
},
},
},
}
for acl, acl_config in acls.items():
path = base_path + ['access-list', acl]
self.cli_set(path + ['description', f'VyOS-ACL-{acl}'])
if 'rule' not in acl_config:
continue
for rule, rule_config in acl_config['rule'].items():
self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
for direction in ['source', 'destination']:
if direction in rule_config:
if 'any' in rule_config[direction]:
self.cli_set(path + ['rule', rule, direction, 'any'])
if 'host' in rule_config[direction]:
self.cli_set(path + ['rule', rule, direction, 'host', rule_config[direction]['host']])
if 'network' in rule_config[direction]:
self.cli_set(path + ['rule', rule, direction, 'network', rule_config[direction]['network']])
self.cli_set(path + ['rule', rule, direction, 'inverse-mask', rule_config[direction]['inverse-mask']])
self.cli_commit()
- config = self.getFRRconfig('access-list', end='')
+ config = self.getFRRconfig('access-list')
for acl, acl_config in acls.items():
for rule, rule_config in acl_config['rule'].items():
tmp = f'access-list {acl} seq {rule}'
if rule_config['action'] == 'permit':
tmp += ' permit'
else:
tmp += ' deny'
if {'source', 'destination'} <= set(rule_config):
tmp += ' ip'
for direction in ['source', 'destination']:
if direction in rule_config:
if 'any' in rule_config[direction]:
tmp += ' any'
if 'host' in rule_config[direction]:
# XXX: Some weird side rule from the old vyatta days
# possible to clean this up after the vyos-1x migration
if int(acl) in range(100, 200) or int(acl) in range(2000, 2700):
tmp += ' host'
tmp += ' ' + rule_config[direction]['host']
if 'network' in rule_config[direction]:
tmp += ' ' + rule_config[direction]['network'] + ' ' + rule_config[direction]['inverse-mask']
self.assertIn(tmp, config)
def test_access_list6(self):
acls = {
'50' : {
'rule' : {
'5' : {
'action' : 'permit',
'source' : { 'any' : '' },
},
'10' : {
'action' : 'deny',
'source' : { 'network' : '2001:db8:10::/48', 'exact-match' : '' },
},
'15' : {
'action' : 'deny',
'source' : { 'network' : '2001:db8:20::/48' },
},
},
},
'100' : {
'rule' : {
'5' : {
'action' : 'deny',
'source' : { 'network' : '2001:db8:10::/64', 'exact-match' : '' },
},
'10' : {
'action' : 'deny',
'source' : { 'network' : '2001:db8:20::/64', },
},
'15' : {
'action' : 'deny',
'source' : { 'network' : '2001:db8:30::/64', 'exact-match' : '' },
},
'20' : {
'action' : 'deny',
'source' : { 'network' : '2001:db8:40::/64', 'exact-match' : '' },
},
'25' : {
'action' : 'deny',
'source' : { 'any' : '' },
},
},
},
}
for acl, acl_config in acls.items():
path = base_path + ['access-list6', acl]
self.cli_set(path + ['description', f'VyOS-ACL-{acl}'])
if 'rule' not in acl_config:
continue
for rule, rule_config in acl_config['rule'].items():
self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
for direction in ['source', 'destination']:
if direction in rule_config:
if 'any' in rule_config[direction]:
self.cli_set(path + ['rule', rule, direction, 'any'])
if 'network' in rule_config[direction]:
self.cli_set(path + ['rule', rule, direction, 'network', rule_config[direction]['network']])
if 'exact-match' in rule_config[direction]:
self.cli_set(path + ['rule', rule, direction, 'exact-match'])
self.cli_commit()
- config = self.getFRRconfig('ipv6 access-list', end='')
+ config = self.getFRRconfig('ipv6 access-list')
for acl, acl_config in acls.items():
for rule, rule_config in acl_config['rule'].items():
tmp = f'ipv6 access-list {acl} seq {rule}'
if rule_config['action'] == 'permit':
tmp += ' permit'
else:
tmp += ' deny'
if {'source', 'destination'} <= set(rule_config):
tmp += ' ip'
for direction in ['source', 'destination']:
if direction in rule_config:
if 'any' in rule_config[direction]:
tmp += ' any'
if 'network' in rule_config[direction]:
tmp += ' ' + rule_config[direction]['network']
if 'exact-match' in rule_config[direction]:
tmp += ' exact-match'
self.assertIn(tmp, config)
def test_as_path_list(self):
test_data = {
'VyOS' : {
'rule' : {
'5' : {
'action' : 'permit',
'regex' : '^44501 64502$',
},
'10' : {
'action' : 'permit',
'regex' : '44501|44502|44503',
},
'15' : {
'action' : 'permit',
'regex' : '^44501_([0-9]+_)+',
},
},
},
'Customers' : {
'rule' : {
'5' : {
'action' : 'permit',
'regex' : '_10_',
},
'10' : {
'action' : 'permit',
'regex' : '_20_',
},
'15' : {
'action' : 'permit',
'regex' : '_30_',
},
'20' : {
'action' : 'deny',
'regex' : '_40_',
},
},
},
'bogons' : {
'rule' : {
'5' : {
'action' : 'permit',
'regex' : '_0_',
},
'10' : {
'action' : 'permit',
'regex' : '_23456_',
},
'15' : {
'action' : 'permit',
'regex' : '_6449[6-9]_|_65[0-4][0-9][0-9]_|_655[0-4][0-9]_|_6555[0-1]_',
},
'20' : {
'action' : 'permit',
'regex' : '_6555[2-9]_|_655[6-9][0-9]_|_65[6-9][0-9][0-9]_|_6[6-9][0-9][0-9][0-]_|_[7-9][0-9][0-9][0-9][0-9]_|_1[0-2][0-9][0-9][0-9][0-9]_|_130[0-9][0-9][0-9]_|_1310[0-6][0-9]_|_13107[01]_',
},
},
},
}
for as_path, as_path_config in test_data.items():
path = base_path + ['as-path-list', as_path]
self.cli_set(path + ['description', f'VyOS-ASPATH-{as_path}'])
if 'rule' not in as_path_config:
continue
for rule, rule_config in as_path_config['rule'].items():
if 'action' in rule_config:
self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
if 'regex' in rule_config:
self.cli_set(path + ['rule', rule, 'regex', rule_config['regex']])
self.cli_commit()
- config = self.getFRRconfig('bgp as-path access-list', end='')
+ config = self.getFRRconfig('bgp as-path access-list')
for as_path, as_path_config in test_data.items():
if 'rule' not in as_path_config:
continue
for rule, rule_config in as_path_config['rule'].items():
tmp = f'bgp as-path access-list {as_path} seq {rule}'
if rule_config['action'] == 'permit':
tmp += ' permit'
else:
tmp += ' deny'
tmp += ' ' + rule_config['regex']
self.assertIn(tmp, config)
def test_community_list(self):
test_data = {
'100' : {
'rule' : {
'5' : {
'action' : 'permit',
'regex' : '.*',
},
},
},
'200' : {
'rule' : {
'5' : {
'action' : 'deny',
'regex' : '^1:201$',
},
'10' : {
'action' : 'deny',
'regex' : '1:101$',
},
'15' : {
'action' : 'deny',
'regex' : '^1:100$',
},
},
},
}
for comm_list, comm_list_config in test_data.items():
path = base_path + ['community-list', comm_list]
self.cli_set(path + ['description', f'VyOS-COMM-{comm_list}'])
if 'rule' not in comm_list_config:
continue
for rule, rule_config in comm_list_config['rule'].items():
if 'action' in rule_config:
self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
if 'regex' in rule_config:
self.cli_set(path + ['rule', rule, 'regex', rule_config['regex']])
self.cli_commit()
- config = self.getFRRconfig('bgp community-list', end='')
+ config = self.getFRRconfig('bgp community-list')
for comm_list, comm_list_config in test_data.items():
if 'rule' not in comm_list_config:
continue
for rule, rule_config in comm_list_config['rule'].items():
tmp = f'bgp community-list {comm_list} seq {rule}'
if rule_config['action'] == 'permit':
tmp += ' permit'
else:
tmp += ' deny'
tmp += ' ' + rule_config['regex']
self.assertIn(tmp, config)
def test_extended_community_list(self):
test_data = {
'foo' : {
'rule' : {
'5' : {
'action' : 'permit',
'regex' : '.*',
},
},
},
'200' : {
'rule' : {
'5' : {
'action' : 'deny',
'regex' : '^1:201$',
},
'10' : {
'action' : 'deny',
'regex' : '1:101$',
},
'15' : {
'action' : 'deny',
'regex' : '^1:100$',
},
},
},
}
for comm_list, comm_list_config in test_data.items():
path = base_path + ['extcommunity-list', comm_list]
self.cli_set(path + ['description', f'VyOS-EXTCOMM-{comm_list}'])
if 'rule' not in comm_list_config:
continue
for rule, rule_config in comm_list_config['rule'].items():
if 'action' in rule_config:
self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
if 'regex' in rule_config:
self.cli_set(path + ['rule', rule, 'regex', rule_config['regex']])
self.cli_commit()
- config = self.getFRRconfig('bgp extcommunity-list', end='')
+ config = self.getFRRconfig('bgp extcommunity-list')
for comm_list, comm_list_config in test_data.items():
if 'rule' not in comm_list_config:
continue
for rule, rule_config in comm_list_config['rule'].items():
# if the community is not a number but a name, the expanded
# keyword is used
expanded = ''
if not comm_list.isnumeric():
expanded = ' expanded'
tmp = f'bgp extcommunity-list{expanded} {comm_list} seq {rule}'
if rule_config['action'] == 'permit':
tmp += ' permit'
else:
tmp += ' deny'
tmp += ' ' + rule_config['regex']
self.assertIn(tmp, config)
def test_large_community_list(self):
test_data = {
'foo' : {
'rule' : {
'5' : {
'action' : 'permit',
'regex' : '667:123:100',
},
},
},
'bar' : {
'rule' : {
'5' : {
'action' : 'permit',
'regex' : '65000:120:10',
},
'10' : {
'action' : 'permit',
'regex' : '65000:120:20',
},
'15' : {
'action' : 'permit',
'regex' : '65000:120:30',
},
},
},
}
for comm_list, comm_list_config in test_data.items():
path = base_path + ['large-community-list', comm_list]
self.cli_set(path + ['description', f'VyOS-LARGECOMM-{comm_list}'])
if 'rule' not in comm_list_config:
continue
for rule, rule_config in comm_list_config['rule'].items():
if 'action' in rule_config:
self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
if 'regex' in rule_config:
self.cli_set(path + ['rule', rule, 'regex', rule_config['regex']])
self.cli_commit()
- config = self.getFRRconfig('bgp large-community-list', end='')
+ config = self.getFRRconfig('bgp large-community-list')
for comm_list, comm_list_config in test_data.items():
if 'rule' not in comm_list_config:
continue
for rule, rule_config in comm_list_config['rule'].items():
tmp = f'bgp large-community-list expanded {comm_list} seq {rule}'
if rule_config['action'] == 'permit':
tmp += ' permit'
else:
tmp += ' deny'
tmp += ' ' + rule_config['regex']
self.assertIn(tmp, config)
def test_prefix_list(self):
test_data = {
'foo' : {
'rule' : {
'5' : {
'action' : 'permit',
'prefix' : '10.0.0.0/8',
'ge' : '16',
'le' : '24',
},
'10' : {
'action' : 'deny',
'prefix' : '172.16.0.0/12',
'ge' : '16',
},
'15' : {
'action' : 'permit',
'prefix' : '192.168.0.0/16',
},
},
},
'bar' : {
'rule' : {
'5' : {
'action' : 'permit',
'prefix' : '10.0.10.0/24',
'ge' : '25',
'le' : '26',
},
'10' : {
'action' : 'deny',
'prefix' : '10.0.20.0/24',
'le' : '25',
},
'15' : {
'action' : 'permit',
'prefix' : '10.0.25.0/24',
},
},
},
}
for prefix_list, prefix_list_config in test_data.items():
path = base_path + ['prefix-list', prefix_list]
self.cli_set(path + ['description', f'VyOS-PFX-LIST-{prefix_list}'])
if 'rule' not in prefix_list_config:
continue
for rule, rule_config in prefix_list_config['rule'].items():
if 'action' in rule_config:
self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
if 'prefix' in rule_config:
self.cli_set(path + ['rule', rule, 'prefix', rule_config['prefix']])
if 'ge' in rule_config:
self.cli_set(path + ['rule', rule, 'ge', rule_config['ge']])
if 'le' in rule_config:
self.cli_set(path + ['rule', rule, 'le', rule_config['le']])
self.cli_commit()
- config = self.getFRRconfig('ip prefix-list', end='')
+ config = self.getFRRconfig('ip prefix-list')
for prefix_list, prefix_list_config in test_data.items():
if 'rule' not in prefix_list_config:
continue
for rule, rule_config in prefix_list_config['rule'].items():
tmp = f'ip prefix-list {prefix_list} seq {rule}'
if rule_config['action'] == 'permit':
tmp += ' permit'
else:
tmp += ' deny'
tmp += ' ' + rule_config['prefix']
if 'ge' in rule_config:
tmp += ' ge ' + rule_config['ge']
if 'le' in rule_config:
tmp += ' le ' + rule_config['le']
self.assertIn(tmp, config)
def test_prefix_list6(self):
test_data = {
'foo' : {
'rule' : {
'5' : {
'action' : 'permit',
'prefix' : '2001:db8::/32',
'ge' : '40',
'le' : '48',
},
'10' : {
'action' : 'deny',
'prefix' : '2001:db8::/32',
'ge' : '48',
},
'15' : {
'action' : 'permit',
'prefix' : '2001:db8:1000::/64',
},
},
},
'bar' : {
'rule' : {
'5' : {
'action' : 'permit',
'prefix' : '2001:db8:100::/40',
'ge' : '48',
},
'10' : {
'action' : 'permit',
'prefix' : '2001:db8:200::/40',
'ge' : '48',
},
'15' : {
'action' : 'deny',
'prefix' : '2001:db8:300::/40',
'le' : '64',
},
},
},
}
for prefix_list, prefix_list_config in test_data.items():
path = base_path + ['prefix-list6', prefix_list]
self.cli_set(path + ['description', f'VyOS-PFX-LIST-{prefix_list}'])
if 'rule' not in prefix_list_config:
continue
for rule, rule_config in prefix_list_config['rule'].items():
if 'action' in rule_config:
self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
if 'prefix' in rule_config:
self.cli_set(path + ['rule', rule, 'prefix', rule_config['prefix']])
if 'ge' in rule_config:
self.cli_set(path + ['rule', rule, 'ge', rule_config['ge']])
if 'le' in rule_config:
self.cli_set(path + ['rule', rule, 'le', rule_config['le']])
self.cli_commit()
- config = self.getFRRconfig('ipv6 prefix-list', end='')
+ config = self.getFRRconfig('ipv6 prefix-list')
for prefix_list, prefix_list_config in test_data.items():
if 'rule' not in prefix_list_config:
continue
for rule, rule_config in prefix_list_config['rule'].items():
tmp = f'ipv6 prefix-list {prefix_list} seq {rule}'
if rule_config['action'] == 'permit':
tmp += ' permit'
else:
tmp += ' deny'
tmp += ' ' + rule_config['prefix']
if 'ge' in rule_config:
tmp += ' ge ' + rule_config['ge']
if 'le' in rule_config:
tmp += ' le ' + rule_config['le']
self.assertIn(tmp, config)
def test_prefix_list_duplicates(self):
# FRR does not allow to specify the same profix list rule multiple times
#
# vyos(config)# ip prefix-list foo seq 10 permit 192.0.2.0/24
# vyos(config)# ip prefix-list foo seq 20 permit 192.0.2.0/24
# % Configuration failed.
# Error type: validation
# Error description: duplicated prefix list value: 192.0.2.0/24
# There is also a VyOS verify() function to test this
prefix = '100.64.0.0/10'
prefix_list = 'duplicates'
test_range = range(20, 25)
path = base_path + ['prefix-list', prefix_list]
for rule in test_range:
self.cli_set(path + ['rule', str(rule), 'action', 'permit'])
self.cli_set(path + ['rule', str(rule), 'prefix', prefix])
# Duplicate prefixes
with self.assertRaises(ConfigSessionError):
self.cli_commit()
for rule in test_range:
self.cli_set(path + ['rule', str(rule), 'le', str(rule)])
self.cli_commit()
- config = self.getFRRconfig('ip prefix-list', end='')
+ config = self.getFRRconfig('ip prefix-list')
for rule in test_range:
tmp = f'ip prefix-list {prefix_list} seq {rule} permit {prefix} le {rule}'
self.assertIn(tmp, config)
def test_route_map_community_set(self):
test_data = {
"community-configuration": {
"rule": {
"10": {
"action": "permit",
"set": {
"community": {
"replace": [
"65000:10",
"65001:11"
]
},
"extcommunity": {
"bandwidth": "200",
"rt": [
"65000:10",
"192.168.0.1:11"
],
"soo": [
"192.168.0.1:11",
"65000:10"
]
},
"large-community": {
"replace": [
"65000:65000:10",
"65000:65000:11"
]
}
}
},
"20": {
"action": "permit",
"set": {
"community": {
"add": [
"65000:10",
"65001:11"
]
},
"extcommunity": {
"bandwidth": "200",
"bandwidth-non-transitive": {}
},
"large-community": {
"add": [
"65000:65000:10",
"65000:65000:11"
]
}
}
},
"30": {
"action": "permit",
"set": {
"community": {
"none": {}
},
"extcommunity": {
"none": {}
},
"large-community": {
"none": {}
}
}
}
}
}
}
for route_map, route_map_config in test_data.items():
path = base_path + ['route-map', route_map]
self.cli_set(path + ['description', f'VyOS ROUTE-MAP {route_map}'])
if 'rule' not in route_map_config:
continue
for rule, rule_config in route_map_config['rule'].items():
if 'action' in rule_config:
self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
if 'set' in rule_config:
#Add community in configuration
if 'community' in rule_config['set']:
if 'none' in rule_config['set']['community']:
self.cli_set(path + ['rule', rule, 'set', 'community', 'none'])
else:
community_path = path + ['rule', rule, 'set', 'community']
if 'add' in rule_config['set']['community']:
for community_unit in rule_config['set']['community']['add']:
self.cli_set(community_path + ['add', community_unit])
if 'replace' in rule_config['set']['community']:
for community_unit in rule_config['set']['community']['replace']:
self.cli_set(community_path + ['replace', community_unit])
#Add large-community in configuration
if 'large-community' in rule_config['set']:
if 'none' in rule_config['set']['large-community']:
self.cli_set(path + ['rule', rule, 'set', 'large-community', 'none'])
else:
community_path = path + ['rule', rule, 'set', 'large-community']
if 'add' in rule_config['set']['large-community']:
for community_unit in rule_config['set']['large-community']['add']:
self.cli_set(community_path + ['add', community_unit])
if 'replace' in rule_config['set']['large-community']:
for community_unit in rule_config['set']['large-community']['replace']:
self.cli_set(community_path + ['replace', community_unit])
#Add extcommunity in configuration
if 'extcommunity' in rule_config['set']:
if 'none' in rule_config['set']['extcommunity']:
self.cli_set(path + ['rule', rule, 'set', 'extcommunity', 'none'])
else:
if 'bandwidth' in rule_config['set']['extcommunity']:
self.cli_set(path + ['rule', rule, 'set', 'extcommunity', 'bandwidth', rule_config['set']['extcommunity']['bandwidth']])
if 'bandwidth-non-transitive' in rule_config['set']['extcommunity']:
self.cli_set(path + ['rule', rule, 'set','extcommunity', 'bandwidth-non-transitive'])
if 'rt' in rule_config['set']['extcommunity']:
for community_unit in rule_config['set']['extcommunity']['rt']:
self.cli_set(path + ['rule', rule, 'set', 'extcommunity','rt',community_unit])
if 'soo' in rule_config['set']['extcommunity']:
for community_unit in rule_config['set']['extcommunity']['soo']:
self.cli_set(path + ['rule', rule, 'set', 'extcommunity','soo',community_unit])
self.cli_commit()
for route_map, route_map_config in test_data.items():
if 'rule' not in route_map_config:
continue
for rule, rule_config in route_map_config['rule'].items():
name = f'route-map {route_map} {rule_config["action"]} {rule}'
config = self.getFRRconfig(name)
self.assertIn(name, config)
if 'set' in rule_config:
#Check community
if 'community' in rule_config['set']:
if 'none' in rule_config['set']['community']:
tmp = f'set community none'
self.assertIn(tmp, config)
if 'replace' in rule_config['set']['community']:
values = ' '.join(rule_config['set']['community']['replace'])
tmp = f'set community {values}'
self.assertIn(tmp, config)
if 'add' in rule_config['set']['community']:
values = ' '.join(rule_config['set']['community']['add'])
tmp = f'set community {values} additive'
self.assertIn(tmp, config)
#Check large-community
if 'large-community' in rule_config['set']:
if 'none' in rule_config['set']['large-community']:
tmp = f'set large-community none'
self.assertIn(tmp, config)
if 'replace' in rule_config['set']['large-community']:
values = ' '.join(rule_config['set']['large-community']['replace'])
tmp = f'set large-community {values}'
self.assertIn(tmp, config)
if 'add' in rule_config['set']['large-community']:
values = ' '.join(rule_config['set']['large-community']['add'])
tmp = f'set large-community {values} additive'
self.assertIn(tmp, config)
#Check extcommunity
if 'extcommunity' in rule_config['set']:
if 'none' in rule_config['set']['extcommunity']:
tmp = 'set extcommunity none'
self.assertIn(tmp, config)
if 'bandwidth' in rule_config['set']['extcommunity']:
values = rule_config['set']['extcommunity']['bandwidth']
tmp = f'set extcommunity bandwidth {values}'
if 'bandwidth-non-transitive' in rule_config['set']['extcommunity']:
tmp = tmp + ' non-transitive'
self.assertIn(tmp, config)
if 'rt' in rule_config['set']['extcommunity']:
values = ' '.join(rule_config['set']['extcommunity']['rt'])
tmp = f'set extcommunity rt {values}'
self.assertIn(tmp, config)
if 'soo' in rule_config['set']['extcommunity']:
values = ' '.join(rule_config['set']['extcommunity']['soo'])
tmp = f'set extcommunity soo {values}'
self.assertIn(tmp, config)
def test_route_map(self):
access_list = '50'
as_path_list = '100'
test_interface = 'eth0'
community_list = 'BGP-comm-0815'
# ext community name only allows alphanumeric characters and no hyphen :/
# maybe change this if possible in vyos-1x rewrite
extcommunity_list = 'BGPextcomm123'
large_community_list = 'bgp-large-community-123456'
prefix_list = 'foo-pfx-list'
ipv6_nexthop_address = 'fe80::1'
local_pref = '300'
metric = '50'
peer = '2.3.4.5'
peerv6 = '2001:db8::1'
tag = '6542'
goto = '25'
ipv4_nexthop_address= '192.0.2.2'
ipv4_prefix_len= '18'
ipv6_prefix_len= '122'
ipv4_nexthop_type= 'blackhole'
ipv6_nexthop_type= 'blackhole'
test_data = {
'foo-map-bar' : {
'rule' : {
'5' : {
'action' : 'permit',
'continue' : '20',
},
'10' : {
'action' : 'permit',
'call' : 'complicated-configuration',
},
},
},
'a-matching-rule-0815': {
'rule' : {
'5' : {
'action' : 'deny',
'match' : {
'as-path' : as_path_list,
'rpki-invalid': '',
'tag': tag,
},
},
'7' : {
'action' : 'deny',
'match' : {
'rpki-comm-invalid': '',
},
},
'10' : {
'action' : 'permit',
'match' : {
'community' : community_list,
'interface' : test_interface,
'rpki-not-found': '',
},
},
'12' : {
'action' : 'permit',
'match' : {
'rpki-comm-not-found': '',
},
},
'15' : {
'action' : 'permit',
'match' : {
'extcommunity' : extcommunity_list,
'rpki-valid': '',
},
'on-match' : {
'next' : '',
},
},
'17' : {
'action' : 'permit',
'match' : {
'rpki-comm-valid': '',
},
},
'20' : {
'action' : 'permit',
'match' : {
'ip-address-acl': access_list,
'ip-nexthop-acl': access_list,
'ip-route-source-acl': access_list,
'ipv6-address-acl': access_list,
'origin-incomplete' : '',
},
'on-match' : {
'goto' : goto,
},
},
'25' : {
'action' : 'permit',
'match' : {
'ip-address-pfx': prefix_list,
'ip-nexthop-pfx': prefix_list,
'ip-route-source-pfx': prefix_list,
'ipv6-address-pfx': prefix_list,
'origin-igp': '',
},
},
'30' : {
'action' : 'permit',
'match' : {
'ipv6-nexthop-address' : ipv6_nexthop_address,
'ipv6-nexthop-access-list' : access_list,
'ipv6-nexthop-prefix-list' : prefix_list,
'ipv6-nexthop-type' : ipv6_nexthop_type,
'ipv6-address-pfx-len' : ipv6_prefix_len,
'large-community' : large_community_list,
'local-pref' : local_pref,
'metric': metric,
'origin-egp': '',
'peer' : peer,
},
},
'31' : {
'action' : 'permit',
'match' : {
'peer' : peerv6,
},
},
'40' : {
'action' : 'permit',
'match' : {
'ip-nexthop-addr' : ipv4_nexthop_address,
'ip-address-pfx-len' : ipv4_prefix_len,
},
},
'42' : {
'action' : 'deny',
'match' : {
'ip-nexthop-plen' : ipv4_prefix_len,
},
},
'44' : {
'action' : 'permit',
'match' : {
'ip-nexthop-type' : ipv4_nexthop_type,
},
},
},
},
'complicated-configuration' : {
'rule' : {
'10' : {
'action' : 'deny',
'set' : {
'aggregator-as' : '1234567890',
'aggregator-ip' : '10.255.255.0',
'as-path-exclude' : '1234',
'as-path-prepend' : '1234567890 987654321',
'as-path-prepend-last-as' : '5',
'atomic-aggregate' : '',
'distance' : '110',
'ipv6-next-hop-global' : '2001::1',
'ipv6-next-hop-local' : 'fe80::1',
'ip-next-hop' : '192.168.1.1',
'local-preference' : '500',
'metric' : '150',
'metric-type' : 'type-1',
'origin' : 'incomplete',
'l3vpn' : '',
'originator-id' : '172.16.10.1',
'src' : '100.0.0.1',
'tag' : '65530',
'weight' : '2',
},
},
},
},
'bandwidth-configuration' : {
'rule' : {
'10' : {
'action' : 'deny',
'set' : {
'as-path-prepend' : '100 100',
'distance' : '200',
'extcommunity-bw' : 'num-multipaths',
},
},
},
},
'evpn-configuration' : {
'rule' : {
'10' : {
'action' : 'permit',
'match' : {
'evpn-default-route' : '',
'evpn-rd' : '100:300',
'evpn-route-type' : 'prefix',
'evpn-vni' : '1234',
},
},
'20' : {
'action' : 'permit',
'set' : {
'as-path-exclude' : 'all',
'evpn-gateway-ipv4' : '192.0.2.99',
'evpn-gateway-ipv6' : '2001:db8:f00::1',
},
},
},
},
'match-protocol' : {
'rule' : {
'10' : {
'action' : 'permit',
'match' : {
'protocol' : 'static',
},
},
'20' : {
'action' : 'permit',
'match' : {
'protocol' : 'bgp',
},
},
},
},
'relative-metric' : {
'rule' : {
'10' : {
'action' : 'permit',
'match' : {
'ip-nexthop-addr' : ipv4_nexthop_address,
},
'set' : {
'metric' : '+10',
},
},
'20' : {
'action' : 'permit',
'match' : {
'ip-nexthop-addr' : ipv4_nexthop_address,
},
'set' : {
'metric' : '-20',
},
},
'30': {
'action': 'permit',
'match': {
'ip-nexthop-addr': ipv4_nexthop_address,
},
'set': {
'metric': 'rtt',
},
},
'40': {
'action': 'permit',
'match': {
'ip-nexthop-addr': ipv4_nexthop_address,
},
'set': {
'metric': '+rtt',
},
},
'50': {
'action': 'permit',
'match': {
'ip-nexthop-addr': ipv4_nexthop_address,
},
'set': {
'metric': '-rtt',
},
},
},
},
'vrf-match': {
'rule': {
'10': {
'action': 'permit',
'match': {
'source-vrf': 'TEST',
},
},
},
},
}
self.cli_set(['policy', 'access-list', access_list, 'rule', '10', 'action', 'permit'])
self.cli_set(['policy', 'access-list', access_list, 'rule', '10', 'source', 'host', '1.1.1.1'])
self.cli_set(['policy', 'access-list6', access_list, 'rule', '10', 'action', 'permit'])
self.cli_set(['policy', 'access-list6', access_list, 'rule', '10', 'source', 'network', '2001:db8::/32'])
self.cli_set(['policy', 'as-path-list', as_path_list, 'rule', '10', 'action', 'permit'])
self.cli_set(['policy', 'as-path-list', as_path_list, 'rule', '10', 'regex', '64501 64502'])
self.cli_set(['policy', 'community-list', community_list, 'rule', '10', 'action', 'deny'])
self.cli_set(['policy', 'community-list', community_list, 'rule', '10', 'regex', '65432'])
self.cli_set(['policy', 'extcommunity-list', extcommunity_list, 'rule', '10', 'action', 'deny'])
self.cli_set(['policy', 'extcommunity-list', extcommunity_list, 'rule', '10', 'regex', '65000'])
self.cli_set(['policy', 'large-community-list', large_community_list, 'rule', '10', 'action', 'permit'])
self.cli_set(['policy', 'large-community-list', large_community_list, 'rule', '10', 'regex', '100:200:300'])
self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', '10', 'action', 'permit'])
self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', '10', 'prefix', '192.0.2.0/24'])
self.cli_set(['policy', 'prefix-list6', prefix_list, 'rule', '10', 'action', 'permit'])
self.cli_set(['policy', 'prefix-list6', prefix_list, 'rule', '10', 'prefix', '2001:db8::/32'])
for route_map, route_map_config in test_data.items():
path = base_path + ['route-map', route_map]
self.cli_set(path + ['description', f'VyOS ROUTE-MAP {route_map}'])
if 'rule' not in route_map_config:
continue
for rule, rule_config in route_map_config['rule'].items():
if 'action' in rule_config:
self.cli_set(path + ['rule', rule, 'action', rule_config['action']])
if 'call' in rule_config:
self.cli_set(path + ['rule', rule, 'call', rule_config['call']])
if 'continue' in rule_config:
self.cli_set(path + ['rule', rule, 'continue', rule_config['continue']])
if 'match' in rule_config:
if 'as-path' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'as-path', rule_config['match']['as-path']])
if 'community' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'community', 'community-list', rule_config['match']['community']])
self.cli_set(path + ['rule', rule, 'match', 'community', 'exact-match'])
if 'evpn-default-route' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'evpn', 'default-route'])
if 'evpn-rd' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'evpn', 'rd', rule_config['match']['evpn-rd']])
if 'evpn-route-type' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'evpn', 'route-type', rule_config['match']['evpn-route-type']])
if 'evpn-vni' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'evpn', 'vni', rule_config['match']['evpn-vni']])
if 'extcommunity' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'extcommunity', rule_config['match']['extcommunity']])
if 'interface' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'interface', rule_config['match']['interface']])
if 'ip-address-acl' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ip', 'address', 'access-list', rule_config['match']['ip-address-acl']])
if 'ip-address-pfx' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ip', 'address', 'prefix-list', rule_config['match']['ip-address-pfx']])
if 'ip-address-pfx-len' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ip', 'address', 'prefix-len', rule_config['match']['ip-address-pfx-len']])
if 'ip-nexthop-acl' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ip', 'nexthop', 'access-list', rule_config['match']['ip-nexthop-acl']])
if 'ip-nexthop-pfx' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ip', 'nexthop', 'prefix-list', rule_config['match']['ip-nexthop-pfx']])
if 'ip-nexthop-addr' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ip', 'nexthop', 'address', rule_config['match']['ip-nexthop-addr']])
if 'ip-nexthop-plen' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ip', 'nexthop', 'prefix-len', rule_config['match']['ip-nexthop-plen']])
if 'ip-nexthop-type' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ip', 'nexthop', 'type', rule_config['match']['ip-nexthop-type']])
if 'ip-route-source-acl' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ip', 'route-source', 'access-list', rule_config['match']['ip-route-source-acl']])
if 'ip-route-source-pfx' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ip', 'route-source', 'prefix-list', rule_config['match']['ip-route-source-pfx']])
if 'ipv6-address-acl' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'address', 'access-list', rule_config['match']['ipv6-address-acl']])
if 'ipv6-address-pfx' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'address', 'prefix-list', rule_config['match']['ipv6-address-pfx']])
if 'ipv6-address-pfx-len' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'address', 'prefix-len', rule_config['match']['ipv6-address-pfx-len']])
if 'ipv6-nexthop-address' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'nexthop', 'address', rule_config['match']['ipv6-nexthop-address']])
if 'ipv6-nexthop-access-list' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'nexthop', 'access-list', rule_config['match']['ipv6-nexthop-access-list']])
if 'ipv6-nexthop-prefix-list' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'nexthop', 'prefix-list', rule_config['match']['ipv6-nexthop-prefix-list']])
if 'ipv6-nexthop-type' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'nexthop', 'type', rule_config['match']['ipv6-nexthop-type']])
if 'large-community' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'large-community', 'large-community-list', rule_config['match']['large-community']])
if 'local-pref' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'local-preference', rule_config['match']['local-pref']])
if 'metric' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'metric', rule_config['match']['metric']])
if 'origin-igp' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'origin', 'igp'])
if 'origin-egp' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'origin', 'egp'])
if 'origin-incomplete' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'origin', 'incomplete'])
if 'peer' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'peer', rule_config['match']['peer']])
if 'rpki-invalid' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'rpki', 'invalid'])
if 'rpki-not-found' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'rpki', 'notfound'])
if 'rpki-valid' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'rpki', 'valid'])
if 'rpki-comm-invalid' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'rpki-extcommunity', 'invalid'])
if 'rpki-comm-not-found' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'rpki-extcommunity', 'notfound'])
if 'rpki-comm-valid' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'rpki-extcommunity', 'valid'])
if 'protocol' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'protocol', rule_config['match']['protocol']])
if 'source-vrf' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'source-vrf', rule_config['match']['source-vrf']])
if 'tag' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'tag', rule_config['match']['tag']])
if 'on-match' in rule_config:
if 'goto' in rule_config['on-match']:
self.cli_set(path + ['rule', rule, 'on-match', 'goto', rule_config['on-match']['goto']])
if 'next' in rule_config['on-match']:
self.cli_set(path + ['rule', rule, 'on-match', 'next'])
if 'set' in rule_config:
if 'aggregator-as' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'aggregator', 'as', rule_config['set']['aggregator-as']])
if 'aggregator-ip' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'aggregator', 'ip', rule_config['set']['aggregator-ip']])
if 'as-path-exclude' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'as-path', 'exclude', rule_config['set']['as-path-exclude']])
if 'as-path-prepend' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'as-path', 'prepend', rule_config['set']['as-path-prepend']])
if 'atomic-aggregate' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'atomic-aggregate'])
if 'distance' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'distance', rule_config['set']['distance']])
if 'ipv6-next-hop-global' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'ipv6-next-hop', 'global', rule_config['set']['ipv6-next-hop-global']])
if 'ipv6-next-hop-local' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'ipv6-next-hop', 'local', rule_config['set']['ipv6-next-hop-local']])
if 'ip-next-hop' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'ip-next-hop', rule_config['set']['ip-next-hop']])
if 'l3vpn' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'l3vpn-nexthop', 'encapsulation', 'gre'])
if 'local-preference' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'local-preference', rule_config['set']['local-preference']])
if 'metric' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'metric', rule_config['set']['metric']])
if 'metric-type' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'metric-type', rule_config['set']['metric-type']])
if 'origin' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'origin', rule_config['set']['origin']])
if 'originator-id' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'originator-id', rule_config['set']['originator-id']])
if 'src' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'src', rule_config['set']['src']])
if 'tag' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'tag', rule_config['set']['tag']])
if 'weight' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'weight', rule_config['set']['weight']])
if 'evpn-gateway-ipv4' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'evpn', 'gateway', 'ipv4', rule_config['set']['evpn-gateway-ipv4']])
if 'evpn-gateway-ipv6' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'evpn', 'gateway', 'ipv6', rule_config['set']['evpn-gateway-ipv6']])
self.cli_commit()
for route_map, route_map_config in test_data.items():
if 'rule' not in route_map_config:
continue
for rule, rule_config in route_map_config['rule'].items():
name = f'route-map {route_map} {rule_config["action"]} {rule}'
config = self.getFRRconfig(name)
self.assertIn(name, config)
if 'call' in rule_config:
tmp = 'call ' + rule_config['call']
self.assertIn(tmp, config)
if 'continue' in rule_config:
tmp = 'on-match goto ' + rule_config['continue']
self.assertIn(tmp, config)
if 'match' in rule_config:
if 'as-path' in rule_config['match']:
tmp = 'match as-path ' + rule_config['match']['as-path']
self.assertIn(tmp, config)
if 'community' in rule_config['match']:
tmp = f'match community {rule_config["match"]["community"]} exact-match'
self.assertIn(tmp, config)
if 'evpn-default-route' in rule_config['match']:
tmp = f'match evpn default-route'
self.assertIn(tmp, config)
if 'evpn-rd' in rule_config['match']:
tmp = f'match evpn rd {rule_config["match"]["evpn-rd"]}'
self.assertIn(tmp, config)
if 'evpn-route-type' in rule_config['match']:
tmp = f'match evpn route-type {rule_config["match"]["evpn-route-type"]}'
self.assertIn(tmp, config)
if 'evpn-vni' in rule_config['match']:
tmp = f'match evpn vni {rule_config["match"]["evpn-vni"]}'
self.assertIn(tmp, config)
if 'extcommunity' in rule_config['match']:
tmp = f'match extcommunity {rule_config["match"]["extcommunity"]}'
self.assertIn(tmp, config)
if 'interface' in rule_config['match']:
tmp = f'match interface {rule_config["match"]["interface"]}'
self.assertIn(tmp, config)
if 'ip-address-acl' in rule_config['match']:
tmp = f'match ip address {rule_config["match"]["ip-address-acl"]}'
self.assertIn(tmp, config)
if 'ip-address-pfx' in rule_config['match']:
tmp = f'match ip address prefix-list {rule_config["match"]["ip-address-pfx"]}'
self.assertIn(tmp, config)
if 'ip-address-pfx-len' in rule_config['match']:
tmp = f'match ip address prefix-len {rule_config["match"]["ip-address-pfx-len"]}'
self.assertIn(tmp, config)
if 'ip-nexthop-acl' in rule_config['match']:
tmp = f'match ip next-hop {rule_config["match"]["ip-nexthop-acl"]}'
self.assertIn(tmp, config)
if 'ip-nexthop-pfx' in rule_config['match']:
tmp = f'match ip next-hop prefix-list {rule_config["match"]["ip-nexthop-pfx"]}'
self.assertIn(tmp, config)
if 'ip-nexthop-addr' in rule_config['match']:
tmp = f'match ip next-hop address {rule_config["match"]["ip-nexthop-addr"]}'
self.assertIn(tmp, config)
if 'ip-nexthop-plen' in rule_config['match']:
tmp = f'match ip next-hop prefix-len {rule_config["match"]["ip-nexthop-plen"]}'
self.assertIn(tmp, config)
if 'ip-nexthop-type' in rule_config['match']:
tmp = f'match ip next-hop type {rule_config["match"]["ip-nexthop-type"]}'
self.assertIn(tmp, config)
if 'ip-route-source-acl' in rule_config['match']:
tmp = f'match ip route-source {rule_config["match"]["ip-route-source-acl"]}'
self.assertIn(tmp, config)
if 'ip-route-source-pfx' in rule_config['match']:
tmp = f'match ip route-source prefix-list {rule_config["match"]["ip-route-source-pfx"]}'
self.assertIn(tmp, config)
if 'ipv6-address-acl' in rule_config['match']:
tmp = f'match ipv6 address {rule_config["match"]["ipv6-address-acl"]}'
self.assertIn(tmp, config)
if 'ipv6-address-pfx' in rule_config['match']:
tmp = f'match ipv6 address prefix-list {rule_config["match"]["ipv6-address-pfx"]}'
self.assertIn(tmp, config)
if 'ipv6-address-pfx-len' in rule_config['match']:
tmp = f'match ipv6 address prefix-len {rule_config["match"]["ipv6-address-pfx-len"]}'
self.assertIn(tmp, config)
if 'ipv6-nexthop-address' in rule_config['match']:
tmp = f'match ipv6 next-hop address {rule_config["match"]["ipv6-nexthop-address"]}'
self.assertIn(tmp, config)
if 'ipv6-nexthop-access-list' in rule_config['match']:
tmp = f'match ipv6 next-hop {rule_config["match"]["ipv6-nexthop-access-list"]}'
self.assertIn(tmp, config)
if 'ipv6-nexthop-prefix-list' in rule_config['match']:
tmp = f'match ipv6 next-hop prefix-list {rule_config["match"]["ipv6-nexthop-prefix-list"]}'
self.assertIn(tmp, config)
if 'ipv6-nexthop-type' in rule_config['match']:
tmp = f'match ipv6 next-hop type {rule_config["match"]["ipv6-nexthop-type"]}'
self.assertIn(tmp, config)
if 'large-community' in rule_config['match']:
tmp = f'match large-community {rule_config["match"]["large-community"]}'
self.assertIn(tmp, config)
if 'local-pref' in rule_config['match']:
tmp = f'match local-preference {rule_config["match"]["local-pref"]}'
self.assertIn(tmp, config)
if 'metric' in rule_config['match']:
tmp = f'match metric {rule_config["match"]["metric"]}'
self.assertIn(tmp, config)
if 'origin-igp' in rule_config['match']:
tmp = f'match origin igp'
self.assertIn(tmp, config)
if 'origin-egp' in rule_config['match']:
tmp = f'match origin egp'
self.assertIn(tmp, config)
if 'origin-incomplete' in rule_config['match']:
tmp = f'match origin incomplete'
self.assertIn(tmp, config)
if 'peer' in rule_config['match']:
tmp = f'match peer {rule_config["match"]["peer"]}'
self.assertIn(tmp, config)
if 'protocol' in rule_config['match']:
tmp = f'match source-protocol {rule_config["match"]["protocol"]}'
self.assertIn(tmp, config)
if 'rpki-invalid' in rule_config['match']:
tmp = f'match rpki invalid'
self.assertIn(tmp, config)
if 'rpki-not-found' in rule_config['match']:
tmp = f'match rpki notfound'
self.assertIn(tmp, config)
if 'rpki-valid' in rule_config['match']:
tmp = f'match rpki valid'
self.assertIn(tmp, config)
if 'rpki-comm-invalid' in rule_config['match']:
tmp = f'match rpki-extcommunity invalid'
self.assertIn(tmp, config)
if 'rpki-comm-not-found' in rule_config['match']:
tmp = f'match rpki-extcommunity notfound'
self.assertIn(tmp, config)
if 'rpki-comm-valid' in rule_config['match']:
tmp = f'match rpki-extcommunity valid'
self.assertIn(tmp, config)
if 'source-vrf' in rule_config['match']:
tmp = f'match source-vrf {rule_config["match"]["source-vrf"]}'
self.assertIn(tmp, config)
if 'tag' in rule_config['match']:
tmp = f'match tag {rule_config["match"]["tag"]}'
self.assertIn(tmp, config)
if 'on-match' in rule_config:
if 'goto' in rule_config['on-match']:
tmp = f'on-match goto {rule_config["on-match"]["goto"]}'
self.assertIn(tmp, config)
if 'next' in rule_config['on-match']:
tmp = f'on-match next'
self.assertIn(tmp, config)
if 'set' in rule_config:
tmp = ' set '
if 'aggregator-as' in rule_config['set']:
tmp += 'aggregator as ' + rule_config['set']['aggregator-as']
elif 'aggregator-ip' in rule_config['set']:
tmp += ' ' + rule_config['set']['aggregator-ip']
elif 'as-path-exclude' in rule_config['set']:
tmp += 'as-path exclude ' + rule_config['set']['as-path-exclude']
elif 'as-path-prepend' in rule_config['set']:
tmp += 'as-path prepend ' + rule_config['set']['as-path-prepend']
elif 'as-path-prepend-last-as' in rule_config['set']:
tmp += 'as-path prepend last-as' + rule_config['set']['as-path-prepend-last-as']
elif 'atomic-aggregate' in rule_config['set']:
tmp += 'atomic-aggregate'
elif 'distance' in rule_config['set']:
tmp += 'distance ' + rule_config['set']['distance']
elif 'ip-next-hop' in rule_config['set']:
tmp += 'ip next-hop ' + rule_config['set']['ip-next-hop']
elif 'ipv6-next-hop-global' in rule_config['set']:
tmp += 'ipv6 next-hop global ' + rule_config['set']['ipv6-next-hop-global']
elif 'ipv6-next-hop-local' in rule_config['set']:
tmp += 'ipv6 next-hop local ' + rule_config['set']['ipv6-next-hop-local']
elif 'l3vpn' in rule_config['set']:
tmp += 'l3vpn next-hop encapsulation gre'
elif 'local-preference' in rule_config['set']:
tmp += 'local-preference ' + rule_config['set']['local-preference']
elif 'metric' in rule_config['set']:
tmp += 'metric ' + rule_config['set']['metric']
elif 'metric-type' in rule_config['set']:
tmp += 'metric-type ' + rule_config['set']['metric-type']
elif 'origin' in rule_config['set']:
tmp += 'origin ' + rule_config['set']['origin']
elif 'originator-id' in rule_config['set']:
tmp += 'originator-id ' + rule_config['set']['originator-id']
elif 'src' in rule_config['set']:
tmp += 'src ' + rule_config['set']['src']
elif 'tag' in rule_config['set']:
tmp += 'tag ' + rule_config['set']['tag']
elif 'weight' in rule_config['set']:
tmp += 'weight ' + rule_config['set']['weight']
elif 'vpn-gateway-ipv4' in rule_config['set']:
tmp += 'evpn gateway ipv4 ' + rule_config['set']['vpn-gateway-ipv4']
elif 'vpn-gateway-ipv6' in rule_config['set']:
tmp += 'evpn gateway ipv6 ' + rule_config['set']['vpn-gateway-ipv6']
self.assertIn(tmp, config)
# Test set table for some sources
def test_table_id(self):
path = base_path + ['local-route']
sources = ['203.0.113.1', '203.0.113.2']
rule = '50'
table = '23'
for src in sources:
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'source', 'address', src])
self.cli_commit()
original = """
50: from 203.0.113.1 lookup 23
50: from 203.0.113.2 lookup 23
"""
tmp = cmd('ip rule show prio 50')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table for fwmark
def test_fwmark_table_id(self):
path = base_path + ['local-route']
fwmk = '24'
rule = '101'
table = '154'
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'fwmark', fwmk])
self.cli_commit()
original = """
101: from all fwmark 0x18 lookup 154
"""
tmp = cmd('ip rule show prio 101')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table for destination
def test_destination_table_id(self):
path = base_path + ['local-route']
dst = '203.0.113.1'
rule = '102'
table = '154'
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'destination', 'address', dst])
self.cli_commit()
original = """
102: from all to 203.0.113.1 lookup 154
"""
tmp = cmd('ip rule show prio 102')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table for destination and protocol
def test_protocol_destination_table_id(self):
path = base_path + ['local-route']
dst = '203.0.113.12'
rule = '85'
table = '104'
proto = 'tcp'
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'destination', 'address', dst])
self.cli_set(path + ['rule', rule, 'protocol', proto])
self.cli_commit()
original = """
85: from all to 203.0.113.12 ipproto tcp lookup 104
"""
tmp = cmd('ip rule show prio 85')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table for destination, source, protocol, fwmark and port
def test_protocol_port_address_fwmark_table_id(self):
path = base_path + ['local-route']
dst = '203.0.113.5'
src_list = ['203.0.113.1', '203.0.113.2']
rule = '23'
fwmark = '123456'
table = '123'
new_table = '111'
proto = 'udp'
new_proto = 'tcp'
src_port = '5555'
dst_port = '8888'
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'destination', 'address', dst])
self.cli_set(path + ['rule', rule, 'source', 'port', src_port])
self.cli_set(path + ['rule', rule, 'protocol', proto])
self.cli_set(path + ['rule', rule, 'fwmark', fwmark])
self.cli_set(path + ['rule', rule, 'destination', 'port', dst_port])
for src in src_list:
self.cli_set(path + ['rule', rule, 'source', 'address', src])
self.cli_commit()
original = """
23: from 203.0.113.1 to 203.0.113.5 fwmark 0x1e240 ipproto udp sport 5555 dport 8888 lookup 123
23: from 203.0.113.2 to 203.0.113.5 fwmark 0x1e240 ipproto udp sport 5555 dport 8888 lookup 123
"""
tmp = cmd(f'ip rule show prio {rule}')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Change table and protocol, delete fwmark and source port
self.cli_delete(path + ['rule', rule, 'fwmark'])
self.cli_delete(path + ['rule', rule, 'source', 'port'])
self.cli_set(path + ['rule', rule, 'set', 'table', new_table])
self.cli_set(path + ['rule', rule, 'protocol', new_proto])
self.cli_commit()
original = """
23: from 203.0.113.1 to 203.0.113.5 ipproto tcp dport 8888 lookup 111
23: from 203.0.113.2 to 203.0.113.5 ipproto tcp dport 8888 lookup 111
"""
tmp = cmd(f'ip rule show prio {rule}')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table for sources with fwmark
def test_fwmark_sources_table_id(self):
path = base_path + ['local-route']
sources = ['203.0.113.11', '203.0.113.12']
fwmk = '23'
rule = '100'
table = '150'
for src in sources:
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'source', 'address', src])
self.cli_set(path + ['rule', rule, 'fwmark', fwmk])
self.cli_commit()
original = """
100: from 203.0.113.11 fwmark 0x17 lookup 150
100: from 203.0.113.12 fwmark 0x17 lookup 150
"""
tmp = cmd('ip rule show prio 100')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table for sources with iif
def test_iif_sources_table_id(self):
path = base_path + ['local-route']
sources = ['203.0.113.11', '203.0.113.12']
iif = 'lo'
rule = '100'
table = '150'
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'inbound-interface', iif])
for src in sources:
self.cli_set(path + ['rule', rule, 'source', 'address', src])
self.cli_commit()
# Check generated configuration
# Expected values
original = """
100: from 203.0.113.11 iif lo lookup 150
100: from 203.0.113.12 iif lo lookup 150
"""
tmp = cmd('ip rule show prio 100')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table for sources and destinations with fwmark
def test_fwmark_sources_destination_table_id(self):
path = base_path + ['local-route']
sources = ['203.0.113.11', '203.0.113.12']
destinations = ['203.0.113.13', '203.0.113.15']
fwmk = '23'
rule = '103'
table = '150'
for src in sources:
for dst in destinations:
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'source', 'address', src])
self.cli_set(path + ['rule', rule, 'destination', 'address', dst])
self.cli_set(path + ['rule', rule, 'fwmark', fwmk])
self.cli_commit()
original = """
103: from 203.0.113.11 to 203.0.113.13 fwmark 0x17 lookup 150
103: from 203.0.113.11 to 203.0.113.15 fwmark 0x17 lookup 150
103: from 203.0.113.12 to 203.0.113.13 fwmark 0x17 lookup 150
103: from 203.0.113.12 to 203.0.113.15 fwmark 0x17 lookup 150
"""
tmp = cmd('ip rule show prio 103')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table ipv6 for some sources ipv6
def test_ipv6_table_id(self):
path = base_path + ['local-route6']
sources = ['2001:db8:123::/48', '2001:db8:126::/48']
rule = '50'
table = '23'
for src in sources:
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'source', 'address', src])
self.cli_commit()
original = """
50: from 2001:db8:123::/48 lookup 23
50: from 2001:db8:126::/48 lookup 23
"""
tmp = cmd('ip -6 rule show prio 50')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table for fwmark ipv6
def test_fwmark_ipv6_table_id(self):
path = base_path + ['local-route6']
fwmk = '24'
rule = '100'
table = '154'
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'fwmark', fwmk])
self.cli_commit()
original = """
100: from all fwmark 0x18 lookup 154
"""
tmp = cmd('ip -6 rule show prio 100')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table for destination ipv6
def test_destination_ipv6_table_id(self):
path = base_path + ['local-route6']
dst = '2001:db8:1337::/126'
rule = '101'
table = '154'
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'destination', 'address', dst])
self.cli_commit()
original = """
101: from all to 2001:db8:1337::/126 lookup 154
"""
tmp = cmd('ip -6 rule show prio 101')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table for sources with fwmark ipv6
def test_fwmark_sources_ipv6_table_id(self):
path = base_path + ['local-route6']
sources = ['2001:db8:1338::/126', '2001:db8:1339::/126']
fwmk = '23'
rule = '102'
table = '150'
for src in sources:
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'source', 'address', src])
self.cli_set(path + ['rule', rule, 'fwmark', fwmk])
self.cli_commit()
original = """
102: from 2001:db8:1338::/126 fwmark 0x17 lookup 150
102: from 2001:db8:1339::/126 fwmark 0x17 lookup 150
"""
tmp = cmd('ip -6 rule show prio 102')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table for sources with iif ipv6
def test_iif_sources_ipv6_table_id(self):
path = base_path + ['local-route6']
sources = ['2001:db8:1338::/126', '2001:db8:1339::/126']
iif = 'lo'
rule = '102'
table = '150'
for src in sources:
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'source', 'address', src])
self.cli_set(path + ['rule', rule, 'inbound-interface', iif])
self.cli_commit()
# Check generated configuration
# Expected values
original = """
102: from 2001:db8:1338::/126 iif lo lookup 150
102: from 2001:db8:1339::/126 iif lo lookup 150
"""
tmp = cmd('ip -6 rule show prio 102')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test set table for sources and destinations with fwmark ipv6
def test_fwmark_sources_destination_ipv6_table_id(self):
path = base_path + ['local-route6']
sources = ['2001:db8:1338::/126', '2001:db8:1339::/56']
destinations = ['2001:db8:13::/48', '2001:db8:16::/48']
fwmk = '23'
rule = '103'
table = '150'
for src in sources:
for dst in destinations:
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'source', 'address', src])
self.cli_set(path + ['rule', rule, 'destination', 'address', dst])
self.cli_set(path + ['rule', rule, 'fwmark', fwmk])
self.cli_commit()
original = """
103: from 2001:db8:1338::/126 to 2001:db8:13::/48 fwmark 0x17 lookup 150
103: from 2001:db8:1338::/126 to 2001:db8:16::/48 fwmark 0x17 lookup 150
103: from 2001:db8:1339::/56 to 2001:db8:13::/48 fwmark 0x17 lookup 150
103: from 2001:db8:1339::/56 to 2001:db8:16::/48 fwmark 0x17 lookup 150
"""
tmp = cmd('ip -6 rule show prio 103')
self.assertEqual(sort_ip(tmp), sort_ip(original))
# Test delete table for sources and destination with fwmark ipv4/ipv6
def test_delete_ipv4_ipv6_table_id(self):
path = base_path + ['local-route']
path_v6 = base_path + ['local-route6']
sources = ['203.0.113.0/24', '203.0.114.5']
destinations = ['203.0.112.0/24', '203.0.116.5']
sources_v6 = ['2001:db8:1338::/126', '2001:db8:1339::/56']
destinations_v6 = ['2001:db8:13::/48', '2001:db8:16::/48']
fwmk = '23'
rule = '103'
table = '150'
for src in sources:
for dst in destinations:
self.cli_set(path + ['rule', rule, 'set', 'table', table])
self.cli_set(path + ['rule', rule, 'source', 'address', src])
self.cli_set(path + ['rule', rule, 'destination', 'address', dst])
self.cli_set(path + ['rule', rule, 'fwmark', fwmk])
for src in sources_v6:
for dst in destinations_v6:
self.cli_set(path_v6 + ['rule', rule, 'set', 'table', table])
self.cli_set(path_v6 + ['rule', rule, 'source', 'address', src])
self.cli_set(path_v6 + ['rule', rule, 'destination', 'address', dst])
self.cli_set(path_v6 + ['rule', rule, 'fwmark', fwmk])
self.cli_commit()
original = """
103: from 203.0.113.0/24 to 203.0.116.5 fwmark 0x17 lookup 150
103: from 203.0.114.5 to 203.0.112.0/24 fwmark 0x17 lookup 150
103: from 203.0.114.5 to 203.0.116.5 fwmark 0x17 lookup 150
103: from 203.0.113.0/24 to 203.0.112.0/24 fwmark 0x17 lookup 150
"""
original_v6 = """
103: from 2001:db8:1338::/126 to 2001:db8:16::/48 fwmark 0x17 lookup 150
103: from 2001:db8:1339::/56 to 2001:db8:13::/48 fwmark 0x17 lookup 150
103: from 2001:db8:1339::/56 to 2001:db8:16::/48 fwmark 0x17 lookup 150
103: from 2001:db8:1338::/126 to 2001:db8:13::/48 fwmark 0x17 lookup 150
"""
tmp = cmd('ip rule show prio 103')
tmp_v6 = cmd('ip -6 rule show prio 103')
self.assertEqual(sort_ip(tmp), sort_ip(original))
self.assertEqual(sort_ip(tmp_v6), sort_ip(original_v6))
self.cli_delete(path)
self.cli_delete(path_v6)
self.cli_commit()
tmp = cmd('ip rule show prio 103')
tmp_v6 = cmd('ip -6 rule show prio 103')
self.assertEqual(sort_ip(tmp), [])
self.assertEqual(sort_ip(tmp_v6), [])
# Test multiple commits ipv4
def test_multiple_commit_ipv4_table_id(self):
path = base_path + ['local-route']
sources = ['192.0.2.1', '192.0.2.2']
destination = '203.0.113.25'
rule = '105'
table = '151'
self.cli_set(path + ['rule', rule, 'set', 'table', table])
for src in sources:
self.cli_set(path + ['rule', rule, 'source', 'address', src])
self.cli_commit()
original_first = """
105: from 192.0.2.1 lookup 151
105: from 192.0.2.2 lookup 151
"""
tmp = cmd('ip rule show prio 105')
self.assertEqual(sort_ip(tmp), sort_ip(original_first))
# Create second commit with added destination
self.cli_set(path + ['rule', rule, 'destination', 'address', destination])
self.cli_commit()
original_second = """
105: from 192.0.2.1 to 203.0.113.25 lookup 151
105: from 192.0.2.2 to 203.0.113.25 lookup 151
"""
tmp = cmd('ip rule show prio 105')
self.assertEqual(sort_ip(tmp), sort_ip(original_second))
def test_frr_individual_remove_T6283_T6250(self):
path = base_path + ['route-map']
route_maps = ['RMAP-1', 'RMAP_2']
seq = '10'
base_local_preference = 300
base_table = 50
# T6250
local_preference = base_local_preference
table = base_table
for route_map in route_maps:
self.cli_set(path + [route_map, 'rule', seq, 'action', 'permit'])
self.cli_set(path + [route_map, 'rule', seq, 'set', 'table', str(table)])
self.cli_set(path + [route_map, 'rule', seq, 'set', 'local-preference', str(local_preference)])
local_preference += 20
table += 5
self.cli_commit()
local_preference = base_local_preference
table = base_table
for route_map in route_maps:
- config = self.getFRRconfig(f'route-map {route_map} permit {seq}', end='', endsection='^exit')
+ config = self.getFRRconfig(f'route-map {route_map} permit {seq}', stop_section='^exit')
self.assertIn(f' set local-preference {local_preference}', config)
self.assertIn(f' set table {table}', config)
local_preference += 20
table += 5
for route_map in route_maps:
self.cli_delete(path + [route_map, 'rule', '10', 'set', 'table'])
# we explicitly commit multiple times to be as vandal as possible to the system
self.cli_commit()
local_preference = base_local_preference
for route_map in route_maps:
- config = self.getFRRconfig(f'route-map {route_map} permit {seq}', end='', endsection='^exit')
+ config = self.getFRRconfig(f'route-map {route_map} permit {seq}', stop_section='^exit')
self.assertIn(f' set local-preference {local_preference}', config)
local_preference += 20
# T6283
seq = '20'
prepend = '100 100 100'
for route_map in route_maps:
self.cli_set(path + [route_map, 'rule', seq, 'action', 'permit'])
self.cli_set(path + [route_map, 'rule', seq, 'set', 'as-path', 'prepend', prepend])
self.cli_commit()
for route_map in route_maps:
- config = self.getFRRconfig(f'route-map {route_map} permit {seq}', end='', endsection='^exit')
+ config = self.getFRRconfig(f'route-map {route_map} permit {seq}', stop_section='^exit')
self.assertIn(f' set as-path prepend {prepend}', config)
for route_map in route_maps:
self.cli_delete(path + [route_map, 'rule', seq, 'set'])
# we explicitly commit multiple times to be as vandal as possible to the system
self.cli_commit()
for route_map in route_maps:
- config = self.getFRRconfig(f'route-map {route_map} permit {seq}', end='', endsection='^exit')
+ config = self.getFRRconfig(f'route-map {route_map} permit {seq}', stop_section='^exit')
self.assertNotIn(f' set', config)
def sort_ip(output):
o = '\n'.join([' '.join(line.strip().split()) for line in output.strip().splitlines()])
o = o.splitlines()
o.sort()
return o
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_policy_local-route.py b/smoketest/scripts/cli/test_policy_local-route.py
index afb3ee43b..51c400619 100644
--- a/smoketest/scripts/cli/test_policy_local-route.py
+++ b/smoketest/scripts/cli/test_policy_local-route.py
@@ -1,174 +1,171 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
interface = 'eth0'
mark = '100'
table_id = '101'
extra_table_id = '102'
vrf_name = 'LPBRVRF'
vrf_rt_id = '202'
class TestPolicyLocalRoute(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestPolicyLocalRoute, cls).setUpClass()
# Clear out current configuration to allow running this test on a live system
cls.cli_delete(cls, ['policy', 'local-route'])
cls.cli_delete(cls, ['policy', 'local-route6'])
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
cls.cli_set(cls, ['vrf', 'name', vrf_name, 'table', vrf_rt_id])
@classmethod
def tearDownClass(cls):
cls.cli_delete(cls, ['vrf', 'name', vrf_name])
super(TestPolicyLocalRoute, cls).tearDownClass()
def tearDown(self):
self.cli_delete(['policy', 'local-route'])
self.cli_delete(['policy', 'local-route6'])
self.cli_commit()
ip_rule_search = [
[f'lookup {table_id}']
]
self.verify_rules(ip_rule_search, inverse=True)
self.verify_rules(ip_rule_search, inverse=True, addr_family='inet6')
def test_local_pbr_matching_criteria(self):
self.cli_set(['policy', 'local-route', 'rule', '4', 'inbound-interface', interface])
self.cli_set(['policy', 'local-route', 'rule', '4', 'protocol', 'udp'])
self.cli_set(['policy', 'local-route', 'rule', '4', 'fwmark', mark])
self.cli_set(['policy', 'local-route', 'rule', '4', 'destination', 'address', '198.51.100.0/24'])
self.cli_set(['policy', 'local-route', 'rule', '4', 'destination', 'port', '111'])
self.cli_set(['policy', 'local-route', 'rule', '4', 'source', 'address', '198.51.100.1'])
self.cli_set(['policy', 'local-route', 'rule', '4', 'source', 'port', '443'])
self.cli_set(['policy', 'local-route', 'rule', '4', 'set', 'table', table_id])
self.cli_set(['policy', 'local-route6', 'rule', '6', 'inbound-interface', interface])
self.cli_set(['policy', 'local-route6', 'rule', '6', 'protocol', 'tcp'])
self.cli_set(['policy', 'local-route6', 'rule', '6', 'fwmark', mark])
self.cli_set(['policy', 'local-route6', 'rule', '6', 'destination', 'address', '2001:db8::/64'])
self.cli_set(['policy', 'local-route6', 'rule', '6', 'destination', 'port', '123'])
self.cli_set(['policy', 'local-route6', 'rule', '6', 'source', 'address', '2001:db8::1'])
self.cli_set(['policy', 'local-route6', 'rule', '6', 'source', 'port', '80'])
self.cli_set(['policy', 'local-route6', 'rule', '6', 'set', 'table', table_id])
self.cli_commit()
rule_lookup = f'lookup {table_id}'
rule_fwmark = 'fwmark ' + hex(int(mark))
rule_interface = f'iif {interface}'
ip4_rule_search = [
['from 198.51.100.1', 'to 198.51.100.0/24', rule_fwmark, rule_interface, 'ipproto udp', 'sport 443', 'dport 111', rule_lookup]
]
self.verify_rules(ip4_rule_search)
ip6_rule_search = [
['from 2001:db8::1', 'to 2001:db8::/64', rule_fwmark, rule_interface, 'ipproto tcp', 'sport 80', 'dport 123', rule_lookup]
]
self.verify_rules(ip6_rule_search, addr_family='inet6')
def test_local_pbr_rule_removal(self):
self.cli_set(['policy', 'local-route', 'rule', '1', 'destination', 'address', '198.51.100.1'])
self.cli_set(['policy', 'local-route', 'rule', '1', 'set', 'table', table_id])
self.cli_set(['policy', 'local-route', 'rule', '2', 'destination', 'address', '198.51.100.2'])
self.cli_set(['policy', 'local-route', 'rule', '2', 'set', 'table', table_id])
self.cli_set(['policy', 'local-route', 'rule', '3', 'destination', 'address', '198.51.100.3'])
self.cli_set(['policy', 'local-route', 'rule', '3', 'set', 'table', table_id])
self.cli_commit()
rule_lookup = f'lookup {table_id}'
ip_rule_search = [
['to 198.51.100.1', rule_lookup],
['to 198.51.100.2', rule_lookup],
['to 198.51.100.3', rule_lookup],
]
self.verify_rules(ip_rule_search)
self.cli_delete(['policy', 'local-route', 'rule', '2'])
self.cli_commit()
ip_rule_missing = [
['to 198.51.100.2', rule_lookup],
]
self.verify_rules(ip_rule_missing, inverse=True)
def test_local_pbr_rule_changes(self):
self.cli_set(['policy', 'local-route', 'rule', '1', 'destination', 'address', '198.51.100.0/24'])
self.cli_set(['policy', 'local-route', 'rule', '1', 'set', 'table', table_id])
self.cli_commit()
self.cli_set(['policy', 'local-route', 'rule', '1', 'set', 'table', extra_table_id])
self.cli_commit()
ip_rule_search_extra = [
['to 198.51.100.0/24', f'lookup {extra_table_id}']
]
self.verify_rules(ip_rule_search_extra)
ip_rule_search_orig = [
['to 198.51.100.0/24', f'lookup {table_id}']
]
self.verify_rules(ip_rule_search_orig, inverse=True)
self.cli_delete(['policy', 'local-route', 'rule', '1', 'set', 'table'])
self.cli_set(['policy', 'local-route', 'rule', '1', 'set', 'vrf', vrf_name])
self.cli_commit()
ip_rule_search_vrf = [
['to 198.51.100.0/24', f'lookup {vrf_name}']
]
self.verify_rules(ip_rule_search_extra, inverse=True)
self.verify_rules(ip_rule_search_vrf)
def test_local_pbr_target_vrf(self):
self.cli_set(['policy', 'local-route', 'rule', '1', 'destination', 'address', '198.51.100.0/24'])
self.cli_set(['policy', 'local-route', 'rule', '1', 'set', 'vrf', vrf_name])
self.cli_commit()
ip_rule_search = [
['to 198.51.100.0/24', f'lookup {vrf_name}']
]
self.verify_rules(ip_rule_search)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_policy_route.py b/smoketest/scripts/cli/test_policy_route.py
index 6eb403979..8caa7b342 100755
--- a/smoketest/scripts/cli/test_policy_route.py
+++ b/smoketest/scripts/cli/test_policy_route.py
@@ -1,345 +1,342 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
mark = '100'
conn_mark = '555'
conn_mark_set = '111'
table_mark_offset = 0x7fffffff
table_id = '101'
vrf = 'PBRVRF'
vrf_table_id = '102'
interface = 'eth0'
interface_wc = 'ppp*'
interface_ip = '172.16.10.1/24'
class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestPolicyRoute, cls).setUpClass()
# Clear out current configuration to allow running this test on a live system
cls.cli_delete(cls, ['policy', 'route'])
cls.cli_delete(cls, ['policy', 'route6'])
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
cls.cli_set(cls, ['interfaces', 'ethernet', interface, 'address', interface_ip])
cls.cli_set(cls, ['protocols', 'static', 'table', table_id, 'route', '0.0.0.0/0', 'interface', interface])
cls.cli_set(cls, ['vrf', 'name', vrf, 'table', vrf_table_id])
@classmethod
def tearDownClass(cls):
cls.cli_delete(cls, ['interfaces', 'ethernet', interface, 'address', interface_ip])
cls.cli_delete(cls, ['protocols', 'static', 'table', table_id])
cls.cli_delete(cls, ['vrf', 'name', vrf])
super(TestPolicyRoute, cls).tearDownClass()
def tearDown(self):
self.cli_delete(['policy', 'route'])
self.cli_delete(['policy', 'route6'])
self.cli_commit()
# Verify nftables cleanup
nftables_search = [
['set N_smoketest_network'],
['set N_smoketest_network1'],
['chain VYOS_PBR_smoketest']
]
self.verify_nftables(nftables_search, 'ip vyos_mangle', inverse=True)
# Verify ip rule cleanup
ip_rule_search = [
['fwmark ' + hex(table_mark_offset - int(table_id)), 'lookup ' + table_id]
]
self.verify_rules(ip_rule_search, inverse=True)
def test_pbr_group(self):
self.cli_set(['firewall', 'group', 'network-group', 'smoketest_network', 'network', '172.16.99.0/24'])
self.cli_set(['firewall', 'group', 'network-group', 'smoketest_network1', 'network', '172.16.101.0/24'])
self.cli_set(['firewall', 'group', 'network-group', 'smoketest_network1', 'include', 'smoketest_network'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'source', 'group', 'network-group', 'smoketest_network'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'destination', 'group', 'network-group', 'smoketest_network1'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'set', 'mark', mark])
self.cli_set(['policy', 'route', 'smoketest', 'interface', interface])
self.cli_commit()
nftables_search = [
[f'iifname "{interface}"','jump VYOS_PBR_UD_smoketest'],
['ip daddr @N_smoketest_network1', 'ip saddr @N_smoketest_network'],
]
self.verify_nftables(nftables_search, 'ip vyos_mangle')
self.cli_delete(['firewall'])
def test_pbr_mark(self):
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'source', 'address', '172.16.20.10'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'destination', 'address', '172.16.10.10'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'set', 'mark', mark])
self.cli_set(['policy', 'route', 'smoketest', 'interface', interface])
self.cli_commit()
mark_hex = "{0:#010x}".format(int(mark))
nftables_search = [
[f'iifname "{interface}"','jump VYOS_PBR_UD_smoketest'],
['ip daddr 172.16.10.10', 'ip saddr 172.16.20.10', 'meta mark set ' + mark_hex],
]
self.verify_nftables(nftables_search, 'ip vyos_mangle')
def test_pbr_mark_connection(self):
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'source', 'address', '172.16.20.10'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'destination', 'address', '172.16.10.10'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'connection-mark', conn_mark])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'set', 'connection-mark', conn_mark_set])
self.cli_set(['policy', 'route', 'smoketest', 'interface', interface])
self.cli_commit()
mark_hex = "{0:#010x}".format(int(conn_mark))
mark_hex_set = "{0:#010x}".format(int(conn_mark_set))
nftables_search = [
[f'iifname "{interface}"','jump VYOS_PBR_UD_smoketest'],
['ip daddr 172.16.10.10', 'ip saddr 172.16.20.10', 'ct mark ' + mark_hex, 'ct mark set ' + mark_hex_set],
]
self.verify_nftables(nftables_search, 'ip vyos_mangle')
def test_pbr_table(self):
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'protocol', 'tcp'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'destination', 'port', '8888'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'tcp', 'flags', 'syn'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'tcp', 'flags', 'not', 'ack'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'set', 'table', table_id])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'protocol', 'tcp_udp'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'destination', 'port', '8888'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'set', 'table', table_id])
self.cli_set(['policy', 'route', 'smoketest', 'interface', interface])
self.cli_set(['policy', 'route6', 'smoketest6', 'interface', interface])
self.cli_commit()
mark_hex = "{0:#010x}".format(table_mark_offset - int(table_id))
# IPv4
nftables_search = [
[f'iifname "{interface}"', 'jump VYOS_PBR_UD_smoketest'],
['tcp flags syn / syn,ack', 'tcp dport 8888', 'meta mark set ' + mark_hex]
]
self.verify_nftables(nftables_search, 'ip vyos_mangle')
# IPv6
nftables6_search = [
[f'iifname "{interface}"', 'jump VYOS_PBR6_UD_smoketest'],
['meta l4proto { tcp, udp }', 'th dport 8888', 'meta mark set ' + mark_hex]
]
self.verify_nftables(nftables6_search, 'ip6 vyos_mangle')
# IP rule fwmark -> table
ip_rule_search = [
['fwmark ' + hex(table_mark_offset - int(table_id)), 'lookup ' + table_id]
]
self.verify_rules(ip_rule_search)
def test_pbr_vrf(self):
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'protocol', 'tcp'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'destination', 'port', '8888'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'tcp', 'flags', 'syn'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'tcp', 'flags', 'not', 'ack'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'set', 'vrf', vrf])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'protocol', 'tcp_udp'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'destination', 'port', '8888'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'set', 'vrf', vrf])
self.cli_set(['policy', 'route', 'smoketest', 'interface', interface])
self.cli_set(['policy', 'route6', 'smoketest6', 'interface', interface])
self.cli_commit()
mark_hex = "{0:#010x}".format(table_mark_offset - int(vrf_table_id))
# IPv4
nftables_search = [
[f'iifname "{interface}"', 'jump VYOS_PBR_UD_smoketest'],
['tcp flags syn / syn,ack', 'tcp dport 8888', 'meta mark set ' + mark_hex]
]
self.verify_nftables(nftables_search, 'ip vyos_mangle')
# IPv6
nftables6_search = [
[f'iifname "{interface}"', 'jump VYOS_PBR6_UD_smoketest'],
['meta l4proto { tcp, udp }', 'th dport 8888', 'meta mark set ' + mark_hex]
]
self.verify_nftables(nftables6_search, 'ip6 vyos_mangle')
# IP rule fwmark -> table
ip_rule_search = [
['fwmark ' + hex(table_mark_offset - int(vrf_table_id)), 'lookup ' + vrf]
]
self.verify_rules(ip_rule_search)
def test_pbr_matching_criteria(self):
self.cli_set(['policy', 'route', 'smoketest', 'default-log'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'protocol', 'udp'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'action', 'drop'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'mark', '2020'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'protocol', 'tcp'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'tcp', 'flags', 'syn'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'tcp', 'flags', 'not', 'ack'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'mark', '2-3000'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'set', 'table', table_id])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'source', 'address', '198.51.100.0/24'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'protocol', 'tcp'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'destination', 'port', '22'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'state', 'new'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'ttl', 'gt', '2'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'mark', '!456'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'set', 'table', table_id])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'protocol', 'icmp'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'icmp', 'type-name', 'echo-request'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'packet-length', '128'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'packet-length', '1024-2048'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'packet-type', 'other'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'log'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'set', 'table', table_id])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '5', 'dscp', '41'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '5', 'dscp', '57-59'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '5', 'mark', '!456-500'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '5', 'set', 'table', table_id])
self.cli_set(['policy', 'route6', 'smoketest6', 'default-log'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'protocol', 'udp'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'action', 'drop'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '2', 'protocol', 'tcp'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '2', 'tcp', 'flags', 'syn'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '2', 'tcp', 'flags', 'not', 'ack'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '2', 'set', 'table', table_id])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '3', 'source', 'address', '2001:db8::0/64'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '3', 'protocol', 'tcp'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '3', 'destination', 'port', '22'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '3', 'state', 'new'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '3', 'hop-limit', 'gt', '2'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '3', 'set', 'table', table_id])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'protocol', 'icmpv6'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'icmpv6', 'type', 'echo-request'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'packet-length-exclude', '128'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'packet-length-exclude', '1024-2048'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'packet-type', 'multicast'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'log'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'set', 'table', table_id])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '5', 'dscp-exclude', '61'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '5', 'dscp-exclude', '14-19'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '5', 'set', 'table', table_id])
self.cli_set(['policy', 'route', 'smoketest', 'interface', interface])
self.cli_set(['policy', 'route', 'smoketest', 'interface', interface_wc])
self.cli_set(['policy', 'route6', 'smoketest6', 'interface', interface_wc])
self.cli_commit()
mark_hex = "{0:#010x}".format(table_mark_offset - int(table_id))
# IPv4
nftables_search = [
['iifname { "' + interface + '", "' + interface_wc + '" }', 'jump VYOS_PBR_UD_smoketest'],
['meta l4proto udp', 'meta mark 0x000007e4', 'drop'],
['tcp flags syn / syn,ack', 'meta mark 0x00000002-0x00000bb8', 'meta mark set ' + mark_hex],
['ct state new', 'tcp dport 22', 'ip saddr 198.51.100.0/24', 'ip ttl > 2', 'meta mark != 0x000001c8', 'meta mark set ' + mark_hex],
['log prefix "[ipv4-route-smoketest-4-A]"', 'icmp type echo-request', 'ip length { 128, 1024-2048 }', 'meta pkttype other', 'meta mark set ' + mark_hex],
['ip dscp { 0x29, 0x39-0x3b }', 'meta mark != 0x000001c8-0x000001f4', 'meta mark set ' + mark_hex],
['log prefix "[ipv4-smoketest-default]"']
]
self.verify_nftables(nftables_search, 'ip vyos_mangle')
# IPv6
nftables6_search = [
[f'iifname "{interface_wc}"', 'jump VYOS_PBR6_UD_smoketest'],
['meta l4proto udp', 'drop'],
['tcp flags syn / syn,ack', 'meta mark set ' + mark_hex],
['ct state new', 'tcp dport 22', 'ip6 saddr 2001:db8::/64', 'ip6 hoplimit > 2', 'meta mark set ' + mark_hex],
['log prefix "[ipv6-route6-smoketest6-4-A]"', 'icmpv6 type echo-request', 'ip6 length != { 128, 1024-2048 }', 'meta pkttype multicast', 'meta mark set ' + mark_hex],
['ip6 dscp != { 0x0e-0x13, 0x3d }', 'meta mark set ' + mark_hex],
['log prefix "[ipv6-smoketest6-default]"']
]
self.verify_nftables(nftables6_search, 'ip6 vyos_mangle')
def test_geoip(self):
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'action', 'drop'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'source', 'geoip', 'country-code', 'se'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'source', 'geoip', 'country-code', 'gb'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'action', 'accept'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'source', 'geoip', 'country-code', 'de'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'source', 'geoip', 'country-code', 'fr'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'source', 'geoip', 'inverse-match'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'action', 'drop'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'source', 'geoip', 'country-code', 'se'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'source', 'geoip', 'country-code', 'gb'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '2', 'action', 'accept'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '2', 'source', 'geoip', 'country-code', 'de'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '2', 'source', 'geoip', 'country-code', 'fr'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '2', 'source', 'geoip', 'inverse-match'])
self.cli_commit()
nftables_search = [
['ip saddr @GEOIP_CC_route_smoketest_1', 'drop'],
['ip saddr != @GEOIP_CC_route_smoketest_2', 'accept'],
]
# -t prevents 1000+ GeoIP elements being returned
self.verify_nftables(nftables_search, 'ip vyos_mangle', args='-t')
nftables_search = [
['ip6 saddr @GEOIP_CC6_route6_smoketest6_1', 'drop'],
['ip6 saddr != @GEOIP_CC6_route6_smoketest6_2', 'accept'],
]
self.verify_nftables(nftables_search, 'ip6 vyos_mangle', args='-t')
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_babel.py b/smoketest/scripts/cli/test_protocols_babel.py
index 51fce28e4..cca5b5659 100755
--- a/smoketest/scripts/cli/test_protocols_babel.py
+++ b/smoketest/scripts/cli/test_protocols_babel.py
@@ -1,222 +1,219 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.ifconfig import Section
from vyos.frrender import babel_daemon
from vyos.utils.process import process_named_running
from vyos.xml_ref import default_value
base_path = ['protocols', 'babel']
class TestProtocolsBABEL(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
cls._interfaces = Section.interfaces('ethernet', vlan=False)
# call base-classes classmethod
super(TestProtocolsBABEL, cls).setUpClass()
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(babel_daemon)
# 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, ['policy', 'prefix-list'])
cls.cli_delete(cls, ['policy', 'prefix-list6'])
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
# always destroy the entire babel configuration to make the processes
# life as hard as possible
self.cli_delete(base_path)
self.cli_delete(['policy', 'prefix-list'])
self.cli_delete(['policy', 'prefix-list6'])
self.cli_commit()
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(babel_daemon))
def test_01_basic(self):
diversity_factor = '64'
resend_delay = '100'
smoothing_half_life = '400'
self.cli_set(base_path + ['parameters', 'diversity'])
self.cli_set(base_path + ['parameters', 'diversity-factor', diversity_factor])
self.cli_set(base_path + ['parameters', 'resend-delay', resend_delay])
self.cli_set(base_path + ['parameters', 'smoothing-half-life', smoothing_half_life])
self.cli_commit()
- frrconfig = self.getFRRconfig('router babel', endsection='^exit')
+ frrconfig = self.getFRRconfig('router babel', stop_section='^exit')
self.assertIn(f' babel diversity', frrconfig)
self.assertIn(f' babel diversity-factor {diversity_factor}', frrconfig)
self.assertIn(f' babel resend-delay {resend_delay}', frrconfig)
self.assertIn(f' babel smoothing-half-life {smoothing_half_life}', frrconfig)
def test_02_redistribute(self):
ipv4_protos = ['bgp', 'connected', 'isis', 'kernel', 'nhrp', 'ospf', 'rip', 'static']
ipv6_protos = ['bgp', 'connected', 'isis', 'kernel', 'ospfv3', 'ripng', 'static']
self.cli_set(base_path + ['interface', self._interfaces[0], 'enable-timestamps'])
for protocol in ipv4_protos:
self.cli_set(base_path + ['redistribute', 'ipv4', protocol])
for protocol in ipv6_protos:
self.cli_set(base_path + ['redistribute', 'ipv6', protocol])
self.cli_commit()
- frrconfig = self.getFRRconfig('router babel', endsection='^exit', empty_retry=5)
+ frrconfig = self.getFRRconfig('router babel', stop_section='^exit')
for protocol in ipv4_protos:
self.assertIn(f' redistribute ipv4 {protocol}', frrconfig)
for protocol in ipv6_protos:
if protocol == 'ospfv3':
protocol = 'ospf6'
self.assertIn(f' redistribute ipv6 {protocol}', frrconfig)
def test_03_distribute_list(self):
access_list_in4 = '40'
access_list_out4 = '50'
access_list_in4_iface = '44'
access_list_out4_iface = '55'
access_list_in6 = 'AL-foo-in6'
access_list_out6 = 'AL-foo-out6'
prefix_list_in4 = 'PL-foo-in4'
prefix_list_out4 = 'PL-foo-out4'
prefix_list_in6 = 'PL-foo-in6'
prefix_list_out6 = 'PL-foo-out6'
self.cli_set(['policy', 'access-list', access_list_in4])
self.cli_set(['policy', 'access-list', access_list_out4])
self.cli_set(['policy', 'access-list6', access_list_in6])
self.cli_set(['policy', 'access-list6', access_list_out6])
self.cli_set(['policy', 'access-list', f'{access_list_in4_iface}'])
self.cli_set(['policy', 'access-list', f'{access_list_out4_iface}'])
self.cli_set(['policy', 'prefix-list', prefix_list_in4])
self.cli_set(['policy', 'prefix-list', prefix_list_out4])
self.cli_set(['policy', 'prefix-list6', prefix_list_in6])
self.cli_set(['policy', 'prefix-list6', prefix_list_out6])
self.cli_set(base_path + ['distribute-list', 'ipv4', 'access-list', 'in', access_list_in4])
self.cli_set(base_path + ['distribute-list', 'ipv4', 'access-list', 'out', access_list_out4])
self.cli_set(base_path + ['distribute-list', 'ipv6', 'access-list', 'in', access_list_in6])
self.cli_set(base_path + ['distribute-list', 'ipv6', 'access-list', 'out', access_list_out6])
self.cli_set(base_path + ['distribute-list', 'ipv4', 'prefix-list', 'in', prefix_list_in4])
self.cli_set(base_path + ['distribute-list', 'ipv4', 'prefix-list', 'out', prefix_list_out4])
self.cli_set(base_path + ['distribute-list', 'ipv6', 'prefix-list', 'in', prefix_list_in6])
self.cli_set(base_path + ['distribute-list', 'ipv6', 'prefix-list', 'out', prefix_list_out6])
for interface in self._interfaces:
self.cli_set(base_path + ['interface', interface])
self.cli_set(['policy', 'access-list6', f'{access_list_in6}-{interface}'])
self.cli_set(['policy', 'access-list6', f'{access_list_out6}-{interface}'])
self.cli_set(['policy', 'prefix-list', f'{prefix_list_in4}-{interface}'])
self.cli_set(['policy', 'prefix-list', f'{prefix_list_out4}-{interface}'])
self.cli_set(['policy', 'prefix-list6', f'{prefix_list_in6}-{interface}'])
self.cli_set(['policy', 'prefix-list6', f'{prefix_list_out6}-{interface}'])
tmp_path = base_path + ['distribute-list', 'ipv4', 'interface', interface]
self.cli_set(tmp_path + ['access-list', 'in', f'{access_list_in4_iface}'])
self.cli_set(tmp_path + ['access-list', 'out', f'{access_list_out4_iface}'])
self.cli_set(tmp_path + ['prefix-list', 'in', f'{prefix_list_in4}-{interface}'])
self.cli_set(tmp_path + ['prefix-list', 'out', f'{prefix_list_out4}-{interface}'])
tmp_path = base_path + ['distribute-list', 'ipv6', 'interface', interface]
self.cli_set(tmp_path + ['access-list', 'in', f'{access_list_in6}-{interface}'])
self.cli_set(tmp_path + ['access-list', 'out', f'{access_list_out6}-{interface}'])
self.cli_set(tmp_path + ['prefix-list', 'in', f'{prefix_list_in6}-{interface}'])
self.cli_set(tmp_path + ['prefix-list', 'out', f'{prefix_list_out6}-{interface}'])
self.cli_commit()
- frrconfig = self.getFRRconfig('router babel', endsection='^exit')
+ frrconfig = self.getFRRconfig('router babel', stop_section='^exit')
self.assertIn(f' distribute-list {access_list_in4} in', frrconfig)
self.assertIn(f' distribute-list {access_list_out4} out', frrconfig)
self.assertIn(f' ipv6 distribute-list {access_list_in6} in', frrconfig)
self.assertIn(f' ipv6 distribute-list {access_list_out6} out', frrconfig)
self.assertIn(f' distribute-list prefix {prefix_list_in4} in', frrconfig)
self.assertIn(f' distribute-list prefix {prefix_list_out4} out', frrconfig)
self.assertIn(f' ipv6 distribute-list prefix {prefix_list_in6} in', frrconfig)
self.assertIn(f' ipv6 distribute-list prefix {prefix_list_out6} out', frrconfig)
for interface in self._interfaces:
self.assertIn(f' distribute-list {access_list_in4_iface} in {interface}', frrconfig)
self.assertIn(f' distribute-list {access_list_out4_iface} out {interface}', frrconfig)
self.assertIn(f' ipv6 distribute-list {access_list_in6}-{interface} in {interface}', frrconfig)
self.assertIn(f' ipv6 distribute-list {access_list_out6}-{interface} out {interface}', frrconfig)
self.assertIn(f' distribute-list prefix {prefix_list_in4}-{interface} in {interface}', frrconfig)
self.assertIn(f' distribute-list prefix {prefix_list_out4}-{interface} out {interface}', frrconfig)
self.assertIn(f' ipv6 distribute-list prefix {prefix_list_in6}-{interface} in {interface}', frrconfig)
self.assertIn(f' ipv6 distribute-list prefix {prefix_list_out6}-{interface} out {interface}', frrconfig)
def test_04_interfaces(self):
def_update_interval = default_value(base_path + ['interface', 'eth0', 'update-interval'])
channel = '20'
hello_interval = '1000'
max_rtt_penalty = '100'
rtt_decay = '23'
rtt_max = '119'
rtt_min = '11'
rxcost = '40000'
type = 'wired'
for interface in self._interfaces:
self.cli_set(base_path + ['interface', interface])
self.cli_set(base_path + ['interface', interface, 'channel', channel])
self.cli_set(base_path + ['interface', interface, 'enable-timestamps'])
self.cli_set(base_path + ['interface', interface, 'hello-interval', hello_interval])
self.cli_set(base_path + ['interface', interface, 'max-rtt-penalty', max_rtt_penalty])
self.cli_set(base_path + ['interface', interface, 'rtt-decay', rtt_decay])
self.cli_set(base_path + ['interface', interface, 'rtt-max', rtt_max])
self.cli_set(base_path + ['interface', interface, 'rtt-min', rtt_min])
self.cli_set(base_path + ['interface', interface, 'rxcost', rxcost])
self.cli_set(base_path + ['interface', interface, 'split-horizon', 'disable'])
self.cli_set(base_path + ['interface', interface, 'type', type])
self.cli_commit()
- frrconfig = self.getFRRconfig('router babel', endsection='^exit')
+ frrconfig = self.getFRRconfig('router babel', stop_section='^exit')
for interface in self._interfaces:
self.assertIn(f' network {interface}', frrconfig)
- iface_config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ iface_config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f' babel channel {channel}', iface_config)
self.assertIn(f' babel enable-timestamps', iface_config)
self.assertIn(f' babel update-interval {def_update_interval}', iface_config)
self.assertIn(f' babel hello-interval {hello_interval}', iface_config)
self.assertIn(f' babel rtt-decay {rtt_decay}', iface_config)
self.assertIn(f' babel rtt-max {rtt_max}', iface_config)
self.assertIn(f' babel rtt-min {rtt_min}', iface_config)
self.assertIn(f' babel rxcost {rxcost}', iface_config)
self.assertIn(f' babel max-rtt-penalty {max_rtt_penalty}', iface_config)
self.assertIn(f' no babel split-horizon', iface_config)
self.assertIn(f' babel {type}', iface_config)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py
index 6923593f3..46d33edf3 100755
--- a/smoketest/scripts/cli/test_protocols_bfd.py
+++ b/smoketest/scripts/cli/test_protocols_bfd.py
@@ -1,243 +1,240 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.frrender import bfd_daemon
from vyos.utils.process import process_named_running
base_path = ['protocols', 'bfd']
dum_if = 'dum1001'
vrf_name = 'red'
peers = {
'192.0.2.10' : {
'intv_rx' : '500',
'intv_tx' : '600',
'multihop' : '',
'source_addr': '192.0.2.254',
'profile' : 'foo-bar-baz',
'minimum_ttl': '20',
},
'192.0.2.20' : {
'echo_mode' : '',
'intv_echo' : '100',
'intv_mult' : '100',
'intv_rx' : '222',
'intv_tx' : '333',
'passive' : '',
'shutdown' : '',
'profile' : 'foo',
'source_intf': dum_if,
},
'2001:db8::1000:1' : {
'source_addr': '2001:db8::1',
'vrf' : vrf_name,
},
'2001:db8::2000:1' : {
'source_addr': '2001:db8::1',
'multihop' : '',
'profile' : 'baz_foo',
},
}
profiles = {
'foo' : {
'echo_mode' : '',
'intv_echo' : '100',
'intv_mult' : '101',
'intv_rx' : '222',
'intv_tx' : '333',
'shutdown' : '',
'minimum_ttl': '40',
},
'foo-bar-baz' : {
'intv_mult' : '4',
'intv_rx' : '400',
'intv_tx' : '400',
},
'baz_foo' : {
'intv_mult' : '102',
'intv_rx' : '444',
'passive' : '',
},
}
class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestProtocolsBFD, cls).setUpClass()
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(bfd_daemon)
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
-
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(bfd_daemon))
def test_bfd_peer(self):
self.cli_set(['vrf', 'name', vrf_name, 'table', '1000'])
for peer, peer_config in peers.items():
if 'echo_mode' in peer_config:
self.cli_set(base_path + ['peer', peer, 'echo-mode'])
if 'intv_echo' in peer_config:
self.cli_set(base_path + ['peer', peer, 'interval', 'echo-interval', peer_config["intv_echo"]])
if 'intv_mult' in peer_config:
self.cli_set(base_path + ['peer', peer, 'interval', 'multiplier', peer_config["intv_mult"]])
if 'intv_rx' in peer_config:
self.cli_set(base_path + ['peer', peer, 'interval', 'receive', peer_config["intv_rx"]])
if 'intv_tx' in peer_config:
self.cli_set(base_path + ['peer', peer, 'interval', 'transmit', peer_config["intv_tx"]])
if 'minimum_ttl' in peer_config:
self.cli_set(base_path + ['peer', peer, 'minimum-ttl', peer_config["minimum_ttl"]])
if 'multihop' in peer_config:
self.cli_set(base_path + ['peer', peer, 'multihop'])
if 'passive' in peer_config:
self.cli_set(base_path + ['peer', peer, 'passive'])
if 'shutdown' in peer_config:
self.cli_set(base_path + ['peer', peer, 'shutdown'])
if 'source_addr' in peer_config:
self.cli_set(base_path + ['peer', peer, 'source', 'address', peer_config["source_addr"]])
if 'source_intf' in peer_config:
self.cli_set(base_path + ['peer', peer, 'source', 'interface', peer_config["source_intf"]])
if 'vrf' in peer_config:
self.cli_set(base_path + ['peer', peer, 'vrf', peer_config["vrf"]])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig('bfd', endsection='^exit')
+ frrconfig = self.getFRRconfig('bfd', stop_section='^exit')
for peer, peer_config in peers.items():
tmp = f'peer {peer}'
if 'multihop' in peer_config:
tmp += f' multihop'
if 'source_addr' in peer_config:
tmp += f' local-address {peer_config["source_addr"]}'
if 'source_intf' in peer_config:
tmp += f' interface {peer_config["source_intf"]}'
if 'vrf' in peer_config:
tmp += f' vrf {peer_config["vrf"]}'
self.assertIn(tmp, frrconfig)
- peerconfig = self.getFRRconfig('bfd', endsection='^exit', substring=f' peer {peer}',
- endsubsection='^ exit')
+ peerconfig = self.getFRRconfig('bfd', stop_section='^exit',
+ start_subsection=f' peer {peer}',
+ stop_subsection='^ exit')
if 'echo_mode' in peer_config:
self.assertIn(f'echo-mode', peerconfig)
if 'intv_echo' in peer_config:
self.assertIn(f'echo receive-interval {peer_config["intv_echo"]}', peerconfig)
self.assertIn(f'echo transmit-interval {peer_config["intv_echo"]}', peerconfig)
if 'intv_mult' in peer_config:
self.assertIn(f'detect-multiplier {peer_config["intv_mult"]}', peerconfig)
if 'intv_rx' in peer_config:
self.assertIn(f'receive-interval {peer_config["intv_rx"]}', peerconfig)
if 'intv_tx' in peer_config:
self.assertIn(f'transmit-interval {peer_config["intv_tx"]}', peerconfig)
if 'minimum_ttl' in peer_config:
self.assertIn(f'minimum-ttl {peer_config["minimum_ttl"]}', peerconfig)
if 'passive' in peer_config:
self.assertIn(f'passive-mode', peerconfig)
if 'shutdown' in peer_config:
self.assertIn(f'shutdown', peerconfig)
else:
self.assertNotIn(f'shutdown', peerconfig)
self.cli_delete(['vrf', 'name', vrf_name])
def test_bfd_profile(self):
for profile, profile_config in profiles.items():
if 'echo_mode' in profile_config:
self.cli_set(base_path + ['profile', profile, 'echo-mode'])
if 'intv_echo' in profile_config:
self.cli_set(base_path + ['profile', profile, 'interval', 'echo-interval', profile_config["intv_echo"]])
if 'intv_mult' in profile_config:
self.cli_set(base_path + ['profile', profile, 'interval', 'multiplier', profile_config["intv_mult"]])
if 'intv_rx' in profile_config:
self.cli_set(base_path + ['profile', profile, 'interval', 'receive', profile_config["intv_rx"]])
if 'intv_tx' in profile_config:
self.cli_set(base_path + ['profile', profile, 'interval', 'transmit', profile_config["intv_tx"]])
if 'minimum_ttl' in profile_config:
self.cli_set(base_path + ['profile', profile, 'minimum-ttl', profile_config["minimum_ttl"]])
if 'passive' in profile_config:
self.cli_set(base_path + ['profile', profile, 'passive'])
if 'shutdown' in profile_config:
self.cli_set(base_path + ['profile', profile, 'shutdown'])
for peer, peer_config in peers.items():
if 'profile' in peer_config:
self.cli_set(base_path + ['peer', peer, 'profile', peer_config["profile"] + 'wrong'])
if 'source_addr' in peer_config:
self.cli_set(base_path + ['peer', peer, 'source', 'address', peer_config["source_addr"]])
if 'source_intf' in peer_config:
self.cli_set(base_path + ['peer', peer, 'source', 'interface', peer_config["source_intf"]])
# BFD profile does not exist!
with self.assertRaises(ConfigSessionError):
self.cli_commit()
for peer, peer_config in peers.items():
if 'profile' in peer_config:
self.cli_set(base_path + ['peer', peer, 'profile', peer_config["profile"]])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
for profile, profile_config in profiles.items():
- config = self.getFRRconfig('bfd', endsection='^exit',
- substring=f' profile {profile}', endsubsection='^ exit',)
+ config = self.getFRRconfig('bfd', stop_section='^exit',
+ start_subsection=f' profile {profile}', stop_subsection='^ exit',)
if 'echo_mode' in profile_config:
self.assertIn(f' echo-mode', config)
if 'intv_echo' in profile_config:
self.assertIn(f' echo receive-interval {profile_config["intv_echo"]}', config)
self.assertIn(f' echo transmit-interval {profile_config["intv_echo"]}', config)
if 'intv_mult' in profile_config:
self.assertIn(f' detect-multiplier {profile_config["intv_mult"]}', config)
if 'intv_rx' in profile_config:
self.assertIn(f' receive-interval {profile_config["intv_rx"]}', config)
if 'intv_tx' in profile_config:
self.assertIn(f' transmit-interval {profile_config["intv_tx"]}', config)
if 'minimum_ttl' in profile_config:
self.assertIn(f' minimum-ttl {profile_config["minimum_ttl"]}', config)
if 'passive' in profile_config:
self.assertIn(f' passive-mode', config)
if 'shutdown' in profile_config:
self.assertIn(f' shutdown', config)
else:
self.assertNotIn(f'shutdown', config)
for peer, peer_config in peers.items():
- peerconfig = self.getFRRconfig('bfd', endsection='^exit',
- substring=f' peer {peer}', endsubsection='^ exit')
+ peerconfig = self.getFRRconfig('bfd', stop_section='^exit',
+ start_subsection=f' peer {peer}', stop_subsection='^ exit')
if 'profile' in peer_config:
self.assertIn(f' profile {peer_config["profile"]}', peerconfig)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index 3a4cba386..ba63b2296 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -1,1688 +1,1684 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 time import sleep
from base_vyostest_shim import VyOSUnitTestSHIM
-from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.ifconfig import Section
from vyos.configsession import ConfigSessionError
from vyos.template import is_ipv6
from vyos.utils.process import process_named_running
from vyos.utils.process import cmd
from vyos.frrender import bgp_daemon
ASN = '64512'
base_path = ['protocols', 'bgp']
route_map_in = 'foo-map-in'
route_map_out = 'foo-map-out'
prefix_list_in = 'pfx-foo-in'
prefix_list_out = 'pfx-foo-out'
prefix_list_in6 = 'pfx-foo-in6'
prefix_list_out6 = 'pfx-foo-out6'
bfd_profile = 'foo-bar-baz'
import_afi = 'ipv4-unicast'
import_vrf = 'red'
import_rd = ASN + ':100'
import_vrf_base = ['vrf', 'name']
neighbor_config = {
'192.0.2.1' : {
'bfd' : '',
'cap_dynamic' : '',
'cap_ext_next' : '',
'cap_ext_sver' : '',
'remote_as' : '100',
'adv_interv' : '400',
'passive' : '',
'password' : 'VyOS-Secure123',
'shutdown' : '',
'cap_over' : '',
'ttl_security' : '5',
'system_as' : '300',
'route_map_in' : route_map_in,
'route_map_out' : route_map_out,
'no_send_comm_ext' : '',
'addpath_all' : '',
'p_attr_discard' : ['10', '20', '30', '40', '50'],
},
'192.0.2.2' : {
'bfd_profile' : bfd_profile,
'remote_as' : '200',
'shutdown' : '',
'no_cap_nego' : '',
'port' : '667',
'cap_strict' : '',
'advertise_map' : route_map_in,
'non_exist_map' : route_map_out,
'pfx_list_in' : prefix_list_in,
'pfx_list_out' : prefix_list_out,
'no_send_comm_std' : '',
'local_role' : 'rs-client',
'p_attr_taw' : '200',
},
'192.0.2.3' : {
'advertise_map' : route_map_in,
'description' : 'foo bar baz',
'remote_as' : '200',
'passive' : '',
'multi_hop' : '5',
'update_src' : 'lo',
'peer_group' : 'foo',
'graceful_rst' : '',
},
'2001:db8::1' : {
'advertise_map' : route_map_in,
'exist_map' : route_map_out,
'cap_dynamic' : '',
'cap_ext_next' : '',
'cap_ext_sver' : '',
'remote_as' : '123',
'adv_interv' : '400',
'passive' : '',
'password' : 'VyOS-Secure123',
'shutdown' : '',
'cap_over' : '',
'ttl_security' : '5',
'system_as' : '300',
'solo' : '',
'route_map_in' : route_map_in,
'route_map_out' : route_map_out,
'no_send_comm_std' : '',
'addpath_per_as' : '',
'peer_group' : 'foo-bar',
'local_role' : 'customer',
'local_role_strict': '',
},
'2001:db8::2' : {
'remote_as' : '456',
'shutdown' : '',
'no_cap_nego' : '',
'port' : '667',
'cap_strict' : '',
'pfx_list_in' : prefix_list_in6,
'pfx_list_out' : prefix_list_out6,
'no_send_comm_ext' : '',
'peer_group' : 'foo-bar_baz',
'graceful_rst_hlp' : '',
'disable_conn_chk' : '',
},
}
peer_group_config = {
'foo' : {
'advertise_map' : route_map_in,
'exist_map' : route_map_out,
'bfd' : '',
'remote_as' : '100',
'passive' : '',
'password' : 'VyOS-Secure123',
'shutdown' : '',
'solo' : '',
'cap_over' : '',
'ttl_security' : '5',
'disable_conn_chk' : '',
'p_attr_discard' : ['100', '150', '200'],
},
'bar' : {
'remote_as' : '111',
'graceful_rst_no' : '',
'port' : '667',
'p_attr_taw' : '126',
},
'foo-bar' : {
'advertise_map' : route_map_in,
'description' : 'foo peer bar group',
'remote_as' : '200',
'shutdown' : '',
'no_cap_nego' : '',
'system_as' : '300',
'pfx_list_in' : prefix_list_in,
'pfx_list_out' : prefix_list_out,
'no_send_comm_ext' : '',
},
'foo-bar_baz' : {
'advertise_map' : route_map_in,
'non_exist_map' : route_map_out,
'bfd_profile' : bfd_profile,
'cap_dynamic' : '',
'cap_ext_next' : '',
'remote_as' : '200',
'passive' : '',
'multi_hop' : '5',
'update_src' : 'lo',
'route_map_in' : route_map_in,
'route_map_out' : route_map_out,
'local_role' : 'peer',
'local_role_strict': '',
},
}
class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestProtocolsBGP, cls).setUpClass()
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(bgp_daemon)
# 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, ['policy', 'route-map'])
cls.cli_delete(cls, ['policy', 'prefix-list'])
cls.cli_delete(cls, ['policy', 'prefix-list6'])
cls.cli_delete(cls, ['vrf'])
cls.cli_set(cls, ['policy', 'route-map', route_map_in, 'rule', '10', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'route-map', route_map_out, 'rule', '10', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_in, 'rule', '10', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_in, 'rule', '10', 'prefix', '192.0.2.0/25'])
cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_out, 'rule', '10', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_out, 'rule', '10', 'prefix', '192.0.2.128/25'])
cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_in6, 'rule', '10', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_in6, 'rule', '10', 'prefix', '2001:db8:1000::/64'])
cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'action', 'deny'])
cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'prefix', '2001:db8:2000::/64'])
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
-
@classmethod
def tearDownClass(cls):
cls.cli_delete(cls, ['policy', 'route-map'])
cls.cli_delete(cls, ['policy', 'prefix-list'])
cls.cli_delete(cls, ['policy', 'prefix-list6'])
def setUp(self):
self.cli_set(base_path + ['system-as', ASN])
def tearDown(self):
# cleanup any possible VRF mess
self.cli_delete(['vrf'])
# always destrox the entire bgpd configuration to make the processes
# life as hard as possible
self.cli_delete(base_path)
self.cli_commit()
- frrconfig = self.getFRRconfig('router bgp', endsection='^exit')
+ frrconfig = self.getFRRconfig('router bgp', stop_section='^exit')
self.assertNotIn(f'router bgp', frrconfig)
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(bgp_daemon))
def create_bgp_instances_for_import_test(self):
table = '1000'
self.cli_set(import_vrf_base + [import_vrf, 'table', table])
self.cli_set(import_vrf_base + [import_vrf, 'protocols', 'bgp', 'system-as', ASN])
def verify_frr_config(self, peer, peer_config, frrconfig):
# recurring patterns to verify for both a simple neighbor and a peer-group
if 'bfd' in peer_config:
self.assertIn(f' neighbor {peer} bfd', frrconfig)
if 'bfd_profile' in peer_config:
self.assertIn(f' neighbor {peer} bfd profile {peer_config["bfd_profile"]}', frrconfig)
self.assertIn(f' neighbor {peer} bfd check-control-plane-failure', frrconfig)
if 'cap_dynamic' in peer_config:
self.assertIn(f' neighbor {peer} capability dynamic', frrconfig)
if 'cap_ext_next' in peer_config:
self.assertIn(f' neighbor {peer} capability extended-nexthop', frrconfig)
if 'cap_ext_sver' in peer_config:
self.assertIn(f' neighbor {peer} capability software-version', frrconfig)
if 'description' in peer_config:
self.assertIn(f' neighbor {peer} description {peer_config["description"]}', frrconfig)
if 'no_cap_nego' in peer_config:
self.assertIn(f' neighbor {peer} dont-capability-negotiate', frrconfig)
if 'multi_hop' in peer_config:
self.assertIn(f' neighbor {peer} ebgp-multihop {peer_config["multi_hop"]}', frrconfig)
if 'local_as' in peer_config:
self.assertIn(f' neighbor {peer} local-as {peer_config["local_as"]} no-prepend replace-as', frrconfig)
if 'local_role' in peer_config:
tmp = f' neighbor {peer} local-role {peer_config["local_role"]}'
if 'local_role_strict' in peer_config:
tmp += ' strict'
self.assertIn(tmp, frrconfig)
if 'cap_over' in peer_config:
self.assertIn(f' neighbor {peer} override-capability', frrconfig)
if 'passive' in peer_config:
self.assertIn(f' neighbor {peer} passive', frrconfig)
if 'password' in peer_config:
self.assertIn(f' neighbor {peer} password {peer_config["password"]}', frrconfig)
if 'port' in peer_config:
self.assertIn(f' neighbor {peer} port {peer_config["port"]}', frrconfig)
if 'remote_as' in peer_config:
self.assertIn(f' neighbor {peer} remote-as {peer_config["remote_as"]}', frrconfig)
if 'solo' in peer_config:
self.assertIn(f' neighbor {peer} solo', frrconfig)
if 'shutdown' in peer_config:
self.assertIn(f' neighbor {peer} shutdown', frrconfig)
if 'ttl_security' in peer_config:
self.assertIn(f' neighbor {peer} ttl-security hops {peer_config["ttl_security"]}', frrconfig)
if 'update_src' in peer_config:
self.assertIn(f' neighbor {peer} update-source {peer_config["update_src"]}', frrconfig)
if 'route_map_in' in peer_config:
self.assertIn(f' neighbor {peer} route-map {peer_config["route_map_in"]} in', frrconfig)
if 'route_map_out' in peer_config:
self.assertIn(f' neighbor {peer} route-map {peer_config["route_map_out"]} out', frrconfig)
if 'pfx_list_in' in peer_config:
self.assertIn(f' neighbor {peer} prefix-list {peer_config["pfx_list_in"]} in', frrconfig)
if 'pfx_list_out' in peer_config:
self.assertIn(f' neighbor {peer} prefix-list {peer_config["pfx_list_out"]} out', frrconfig)
if 'no_send_comm_std' in peer_config:
self.assertIn(f' no neighbor {peer} send-community', frrconfig)
if 'no_send_comm_ext' in peer_config:
self.assertIn(f' no neighbor {peer} send-community extended', frrconfig)
if 'addpath_all' in peer_config:
self.assertIn(f' neighbor {peer} addpath-tx-all-paths', frrconfig)
if 'p_attr_discard' in peer_config:
tmp = ' '.join(peer_config["p_attr_discard"])
self.assertIn(f' neighbor {peer} path-attribute discard {tmp}', frrconfig)
if 'p_attr_taw' in peer_config:
self.assertIn(f' neighbor {peer} path-attribute treat-as-withdraw {peer_config["p_attr_taw"]}', frrconfig)
if 'addpath_per_as' in peer_config:
self.assertIn(f' neighbor {peer} addpath-tx-bestpath-per-AS', frrconfig)
if 'advertise_map' in peer_config:
base = f' neighbor {peer} advertise-map {peer_config["advertise_map"]}'
if 'exist_map' in peer_config:
base = f'{base} exist-map {peer_config["exist_map"]}'
if 'non_exist_map' in peer_config:
base = f'{base} non-exist-map {peer_config["non_exist_map"]}'
self.assertIn(base, frrconfig)
if 'graceful_rst' in peer_config:
self.assertIn(f' neighbor {peer} graceful-restart', frrconfig)
if 'graceful_rst_no' in peer_config:
self.assertIn(f' neighbor {peer} graceful-restart-disable', frrconfig)
if 'graceful_rst_hlp' in peer_config:
self.assertIn(f' neighbor {peer} graceful-restart-helper', frrconfig)
if 'disable_conn_chk' in peer_config:
self.assertIn(f' neighbor {peer} disable-connected-check', frrconfig)
def test_bgp_01_simple(self):
router_id = '127.0.0.1'
local_pref = '500'
stalepath_time = '60'
max_path_v4 = '2'
max_path_v4ibgp = '4'
max_path_v6 = '8'
max_path_v6ibgp = '16'
cond_adv_timer = '30'
min_hold_time = '2'
tcp_keepalive_idle = '66'
tcp_keepalive_interval = '77'
tcp_keepalive_probes = '22'
self.cli_set(base_path + ['parameters', 'allow-martian-nexthop'])
self.cli_set(base_path + ['parameters', 'disable-ebgp-connected-route-check'])
self.cli_set(base_path + ['parameters', 'no-hard-administrative-reset'])
self.cli_set(base_path + ['parameters', 'log-neighbor-changes'])
self.cli_set(base_path + ['parameters', 'labeled-unicast', 'explicit-null'])
self.cli_set(base_path + ['parameters', 'router-id', router_id])
# System AS number MUST be defined - as this is set in setUp() we remove
# this once for testing of the proper error
self.cli_delete(base_path + ['system-as'])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + ['system-as', ASN])
# Default local preference (higher = more preferred, default value is 100)
self.cli_set(base_path + ['parameters', 'default', 'local-pref', local_pref])
self.cli_set(base_path + ['parameters', 'graceful-restart', 'stalepath-time', stalepath_time])
self.cli_set(base_path + ['parameters', 'graceful-shutdown'])
self.cli_set(base_path + ['parameters', 'ebgp-requires-policy'])
self.cli_set(base_path + ['parameters', 'bestpath', 'as-path', 'multipath-relax'])
self.cli_set(base_path + ['parameters', 'bestpath', 'bandwidth', 'default-weight-for-missing'])
self.cli_set(base_path + ['parameters', 'bestpath', 'compare-routerid'])
self.cli_set(base_path + ['parameters', 'bestpath', 'peer-type', 'multipath-relax'])
self.cli_set(base_path + ['parameters', 'conditional-advertisement', 'timer', cond_adv_timer])
self.cli_set(base_path + ['parameters', 'fast-convergence'])
self.cli_set(base_path + ['parameters', 'minimum-holdtime', min_hold_time])
self.cli_set(base_path + ['parameters', 'no-suppress-duplicates'])
self.cli_set(base_path + ['parameters', 'reject-as-sets'])
self.cli_set(base_path + ['parameters', 'route-reflector-allow-outbound-policy'])
self.cli_set(base_path + ['parameters', 'no-ipv6-auto-ra'])
self.cli_set(base_path + ['parameters', 'shutdown'])
self.cli_set(base_path + ['parameters', 'suppress-fib-pending'])
self.cli_set(base_path + ['parameters', 'tcp-keepalive', 'idle', tcp_keepalive_idle])
self.cli_set(base_path + ['parameters', 'tcp-keepalive', 'interval', tcp_keepalive_interval])
self.cli_set(base_path + ['parameters', 'tcp-keepalive', 'probes', tcp_keepalive_probes])
# AFI maximum path support
self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'maximum-paths', 'ebgp', max_path_v4])
self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'maximum-paths', 'ibgp', max_path_v4ibgp])
self.cli_set(base_path + ['address-family', 'ipv4-labeled-unicast', 'maximum-paths', 'ebgp', max_path_v4])
self.cli_set(base_path + ['address-family', 'ipv4-labeled-unicast', 'maximum-paths', 'ibgp', max_path_v4ibgp])
self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'maximum-paths', 'ebgp', max_path_v6])
self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'maximum-paths', 'ibgp', max_path_v6ibgp])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' bgp router-id {router_id}', frrconfig)
self.assertIn(f' bgp allow-martian-nexthop', frrconfig)
self.assertIn(f' bgp disable-ebgp-connected-route-check', frrconfig)
self.assertIn(f' bgp log-neighbor-changes', frrconfig)
self.assertIn(f' bgp default local-preference {local_pref}', frrconfig)
self.assertIn(f' bgp conditional-advertisement timer {cond_adv_timer}', frrconfig)
self.assertIn(f' bgp fast-convergence', frrconfig)
self.assertIn(f' bgp graceful-restart stalepath-time {stalepath_time}', frrconfig)
self.assertIn(f' bgp graceful-shutdown', frrconfig)
self.assertIn(f' no bgp hard-administrative-reset', frrconfig)
self.assertIn(f' bgp labeled-unicast explicit-null', frrconfig)
self.assertIn(f' bgp bestpath as-path multipath-relax', frrconfig)
self.assertIn(f' bgp bestpath bandwidth default-weight-for-missing', frrconfig)
self.assertIn(f' bgp bestpath compare-routerid', frrconfig)
self.assertIn(f' bgp bestpath peer-type multipath-relax', frrconfig)
self.assertIn(f' bgp minimum-holdtime {min_hold_time}', frrconfig)
self.assertIn(f' bgp reject-as-sets', frrconfig)
self.assertIn(f' bgp route-reflector allow-outbound-policy', frrconfig)
self.assertIn(f' no bgp ipv6-auto-ra', frrconfig)
self.assertIn(f' bgp shutdown', frrconfig)
self.assertIn(f' bgp suppress-fib-pending', frrconfig)
self.assertIn(f' bgp tcp-keepalive {tcp_keepalive_idle} {tcp_keepalive_interval} {tcp_keepalive_probes}', frrconfig)
self.assertNotIn(f'bgp ebgp-requires-policy', frrconfig)
self.assertIn(f' no bgp suppress-duplicates', frrconfig)
- afiv4_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
- substring=' address-family ipv4 unicast',
- endsubsection='^ exit-address-family')
+ afiv4_config = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit',
+ start_subsection=' address-family ipv4 unicast',
+ stop_subsection='^ exit-address-family')
self.assertIn(f' maximum-paths {max_path_v4}', afiv4_config)
self.assertIn(f' maximum-paths ibgp {max_path_v4ibgp}', afiv4_config)
- afiv4_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
- substring=' address-family ipv4 labeled-unicast',
- endsubsection='^ exit-address-family')
+ afiv4_config = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit',
+ start_subsection=' address-family ipv4 labeled-unicast',
+ stop_subsection='^ exit-address-family')
self.assertIn(f' maximum-paths {max_path_v4}', afiv4_config)
self.assertIn(f' maximum-paths ibgp {max_path_v4ibgp}', afiv4_config)
- afiv6_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
- substring=' address-family ipv6 unicast',
- endsubsection='^ exit-address-family')
+ afiv6_config = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit',
+ start_subsection=' address-family ipv6 unicast',
+ stop_subsection='^ exit-address-family')
self.assertIn(f' maximum-paths {max_path_v6}', afiv6_config)
self.assertIn(f' maximum-paths ibgp {max_path_v6ibgp}', afiv6_config)
def test_bgp_02_neighbors(self):
# Test out individual neighbor configuration items, not all of them are
# also available to a peer-group!
self.cli_set(base_path + ['parameters', 'deterministic-med'])
for peer, peer_config in neighbor_config.items():
afi = 'ipv4-unicast'
if is_ipv6(peer):
afi = 'ipv6-unicast'
if 'adv_interv' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'advertisement-interval', peer_config["adv_interv"]])
if 'bfd' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'bfd'])
if 'bfd_profile' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'bfd', 'profile', peer_config["bfd_profile"]])
self.cli_set(base_path + ['neighbor', peer, 'bfd', 'check-control-plane-failure'])
if 'cap_dynamic' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'capability', 'dynamic'])
if 'cap_ext_next' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'capability', 'extended-nexthop'])
if 'cap_ext_sver' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'capability', 'software-version'])
if 'description' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'description', peer_config["description"]])
if 'no_cap_nego' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'disable-capability-negotiation'])
if 'multi_hop' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'ebgp-multihop', peer_config["multi_hop"]])
if 'local_as' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'local-as', peer_config["local_as"], 'no-prepend', 'replace-as'])
if 'local_role' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'local-role', peer_config["local_role"]])
if 'local_role_strict' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'local-role', peer_config["local_role"], 'strict'])
if 'cap_over' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'override-capability'])
if 'passive' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'passive'])
if 'password' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'password', peer_config["password"]])
if 'port' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'port', peer_config["port"]])
if 'remote_as' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'remote-as', peer_config["remote_as"]])
if 'cap_strict' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'strict-capability-match'])
if 'shutdown' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'shutdown'])
if 'solo' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'solo'])
if 'ttl_security' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'ttl-security', 'hops', peer_config["ttl_security"]])
if 'update_src' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'update-source', peer_config["update_src"]])
if 'p_attr_discard' in peer_config:
for attribute in peer_config['p_attr_discard']:
self.cli_set(base_path + ['neighbor', peer, 'path-attribute', 'discard', attribute])
if 'p_attr_taw' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'path-attribute', 'treat-as-withdraw', peer_config["p_attr_taw"]])
if 'route_map_in' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'route-map', 'import', peer_config["route_map_in"]])
if 'route_map_out' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'route-map', 'export', peer_config["route_map_out"]])
if 'pfx_list_in' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'prefix-list', 'import', peer_config["pfx_list_in"]])
if 'pfx_list_out' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'prefix-list', 'export', peer_config["pfx_list_out"]])
if 'no_send_comm_std' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'disable-send-community', 'standard'])
if 'no_send_comm_ext' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'disable-send-community', 'extended'])
if 'addpath_all' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'addpath-tx-all'])
if 'addpath_per_as' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'addpath-tx-per-as'])
if 'graceful_rst' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'graceful-restart', 'enable'])
if 'graceful_rst_no' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'graceful-restart', 'disable'])
if 'graceful_rst_hlp' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'graceful-restart', 'restart-helper'])
if 'disable_conn_chk' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'disable-connected-check'])
# Conditional advertisement
if 'advertise_map' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'conditionally-advertise', 'advertise-map', peer_config["advertise_map"]])
# Either exist-map or non-exist-map needs to be specified
if 'exist_map' not in peer_config and 'non_exist_map' not in peer_config:
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'conditionally-advertise', 'exist-map', route_map_in])
if 'exist_map' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'conditionally-advertise', 'exist-map', peer_config["exist_map"]])
if 'non_exist_map' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'conditionally-advertise', 'non-exist-map', peer_config["non_exist_map"]])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
for peer, peer_config in neighbor_config.items():
if 'adv_interv' in peer_config:
self.assertIn(f' neighbor {peer} advertisement-interval {peer_config["adv_interv"]}', frrconfig)
if 'cap_strict' in peer_config:
self.assertIn(f' neighbor {peer} strict-capability-match', frrconfig)
self.verify_frr_config(peer, peer_config, frrconfig)
def test_bgp_03_peer_groups(self):
# Test out individual peer-group configuration items
for peer_group, config in peer_group_config.items():
if 'bfd' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'bfd'])
if 'bfd_profile' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'bfd', 'profile', config["bfd_profile"]])
self.cli_set(base_path + ['peer-group', peer_group, 'bfd', 'check-control-plane-failure'])
if 'cap_dynamic' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'capability', 'dynamic'])
if 'cap_ext_next' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'capability', 'extended-nexthop'])
if 'cap_ext_sver' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'capability', 'software-version'])
if 'description' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'description', config["description"]])
if 'no_cap_nego' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'disable-capability-negotiation'])
if 'multi_hop' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'ebgp-multihop', config["multi_hop"]])
if 'local_as' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'local-as', config["local_as"], 'no-prepend', 'replace-as'])
if 'local_role' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'local-role', config["local_role"]])
if 'local_role_strict' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'local-role', config["local_role"], 'strict'])
if 'cap_over' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'override-capability'])
if 'passive' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'passive'])
if 'password' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'password', config["password"]])
if 'port' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'port', config["port"]])
if 'remote_as' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'remote-as', config["remote_as"]])
if 'solo' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'solo'])
if 'shutdown' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'shutdown'])
if 'ttl_security' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'ttl-security', 'hops', config["ttl_security"]])
if 'update_src' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'update-source', config["update_src"]])
if 'route_map_in' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'route-map', 'import', config["route_map_in"]])
if 'route_map_out' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'route-map', 'export', config["route_map_out"]])
if 'pfx_list_in' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'prefix-list', 'import', config["pfx_list_in"]])
if 'pfx_list_out' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'prefix-list', 'export', config["pfx_list_out"]])
if 'no_send_comm_std' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'disable-send-community', 'standard'])
if 'no_send_comm_ext' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'disable-send-community', 'extended'])
if 'addpath_all' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'addpath-tx-all'])
if 'addpath_per_as' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'addpath-tx-per-as'])
if 'graceful_rst' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'graceful-restart', 'enable'])
if 'graceful_rst_no' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'graceful-restart', 'disable'])
if 'graceful_rst_hlp' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'graceful-restart', 'restart-helper'])
if 'disable_conn_chk' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'disable-connected-check'])
if 'p_attr_discard' in config:
for attribute in config['p_attr_discard']:
self.cli_set(base_path + ['peer-group', peer_group, 'path-attribute', 'discard', attribute])
if 'p_attr_taw' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'path-attribute', 'treat-as-withdraw', config["p_attr_taw"]])
# Conditional advertisement
if 'advertise_map' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'conditionally-advertise', 'advertise-map', config["advertise_map"]])
# Either exist-map or non-exist-map needs to be specified
if 'exist_map' not in config and 'non_exist_map' not in config:
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'conditionally-advertise', 'exist-map', route_map_in])
if 'exist_map' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'conditionally-advertise', 'exist-map', config["exist_map"]])
if 'non_exist_map' in config:
self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'conditionally-advertise', 'non-exist-map', config["non_exist_map"]])
for peer, peer_config in neighbor_config.items():
if 'peer_group' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'peer-group', peer_config['peer_group']])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
for peer, peer_config in peer_group_config.items():
self.assertIn(f' neighbor {peer_group} peer-group', frrconfig)
self.verify_frr_config(peer, peer_config, frrconfig)
for peer, peer_config in neighbor_config.items():
if 'peer_group' in peer_config:
self.assertIn(f' neighbor {peer} peer-group {peer_config["peer_group"]}', frrconfig)
def test_bgp_04_afi_ipv4(self):
networks = {
'10.0.0.0/8' : {
'as_set' : '',
'summary_only' : '',
'route_map' : route_map_in,
},
'100.64.0.0/10' : {
'as_set' : '',
},
'192.168.0.0/16' : {
'summary_only' : '',
},
}
# We want to redistribute ...
redistributes = {
'babel' : {
'metric' : '100',
'route_map' : 'redistr-ipv4-babel',
},
'connected' : {
'metric' : '200',
'route_map' : 'redistr-ipv4-connected',
},
'isis' : {
'metric' : '300',
'route_map' : 'redistr-ipv4-isis',
},
'kernel' : {
'metric' : '400',
'route_map' : 'redistr-ipv4-kernel',
},
'nhrp': {
'metric': '400',
'route_map': 'redistr-ipv4-nhrp',
},
'ospf' : {
'metric' : '500',
'route_map' : 'redistr-ipv4-ospf',
},
'rip' : {
'metric' : '600',
'route_map' : 'redistr-ipv4-rip',
},
'static' : {
'metric' : '700',
'route_map' : 'redistr-ipv4-static',
},
'table' : {
'10' : {
'metric' : '810',
'route_map' : 'redistr-ipv4-table-10',
},
'20' : {
'metric' : '820',
'route_map' : 'redistr-ipv4-table-20',
},
'30' : {
'metric' : '830',
'route_map' : 'redistr-ipv4-table-30',
},
},
}
for proto, proto_config in redistributes.items():
proto_path = base_path + ['address-family', 'ipv4-unicast', 'redistribute', proto]
if proto == 'table':
for table, table_config in proto_config.items():
self.cli_set(proto_path + [table])
if 'metric' in table_config:
self.cli_set(proto_path + [table, 'metric'], value=table_config.get('metric'))
if 'route_map' in table_config:
self.cli_set(['policy', 'route-map', table_config.get('route_map'), 'rule', '10', 'action'], value='permit')
self.cli_set(proto_path + [table, 'route-map'], value=table_config.get('route_map'))
else:
self.cli_set(proto_path)
if 'metric' in proto_config:
self.cli_set(proto_path + ['metric', proto_config['metric']])
if 'route_map' in proto_config:
self.cli_set(['policy', 'route-map', proto_config['route_map'], 'rule', '10', 'action', 'permit'])
self.cli_set(proto_path + ['route-map', proto_config['route_map']])
for network, network_config in networks.items():
self.cli_set(base_path + ['address-family', 'ipv4-unicast',
'network', network])
if 'as_set' in network_config:
self.cli_set(base_path + ['address-family', 'ipv4-unicast',
'aggregate-address', network, 'as-set'])
if 'summary_only' in network_config:
self.cli_set(base_path + ['address-family', 'ipv4-unicast',
'aggregate-address', network, 'summary-only'])
if 'route_map' in network_config:
self.cli_set(base_path + ['address-family', 'ipv4-unicast',
'aggregate-address', network, 'route-map', network_config['route_map']])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(' address-family ipv4 unicast', frrconfig)
for proto, proto_config in redistributes.items():
if proto == 'table':
for table, table_config in proto_config.items():
tmp = f' redistribute table-direct {table}'
if 'metric' in proto_config:
metric = proto_config['metric']
tmp += f' metric {metric}'
if 'route_map' in proto_config:
route_map = proto_config['route_map']
tmp += f' route-map {route_map}'
self.assertIn(tmp, frrconfig)
else:
tmp = f' redistribute {proto}'
if 'metric' in proto_config:
metric = proto_config['metric']
tmp += f' metric {metric}'
if 'route_map' in proto_config:
route_map = proto_config['route_map']
tmp += f' route-map {route_map}'
self.assertIn(tmp, frrconfig)
for network, network_config in networks.items():
self.assertIn(f' network {network}', frrconfig)
command = f'aggregate-address {network}'
if 'as_set' in network_config:
command = f'{command} as-set'
if 'summary_only' in network_config:
command = f'{command} summary-only'
if 'route_map' in network_config:
command = f'{command} route-map {network_config["route_map"]}'
self.assertIn(command, frrconfig)
for proto, proto_config in redistributes.items():
if 'route_map' in proto_config:
self.cli_delete(['policy', 'route-map', proto_config['route_map']])
def test_bgp_05_afi_ipv6(self):
networks = {
'2001:db8:100::/48' : {
},
'2001:db8:200::/48' : {
},
'2001:db8:300::/48' : {
'summary_only' : '',
},
}
# We want to redistribute ...
redistributes = {
'babel' : {
'metric' : '100',
'route_map' : 'redistr-ipv6-babel',
},
'connected' : {
'metric' : '200',
'route_map' : 'redistr-ipv6-connected',
},
'isis' : {
'metric' : '300',
'route_map' : 'redistr-ipv6-isis',
},
'kernel' : {
'metric' : '400',
'route_map' : 'redistr-ipv6-kernel',
},
'ospfv3' : {
'metric' : '500',
'route_map' : 'redistr-ipv6-ospfv3',
},
'ripng' : {
'metric' : '600',
'route_map' : 'redistr-ipv6-ripng',
},
'static' : {
'metric' : '700',
'route_map' : 'redistr-ipv6-static',
},
'table' : {
'110' : {
'metric' : '811',
'route_map' : 'redistr-ipv6-table-110',
},
'120' : {
'metric' : '821',
'route_map' : 'redistr-ipv6-table-120',
},
'130' : {
'metric' : '831',
'route_map' : 'redistr-ipv6-table-130',
},
},
}
for proto, proto_config in redistributes.items():
proto_path = base_path + ['address-family', 'ipv6-unicast', 'redistribute', proto]
if proto == 'table':
for table, table_config in proto_config.items():
self.cli_set(proto_path + [table])
if 'metric' in table_config:
self.cli_set(proto_path + [table, 'metric'], value=table_config.get('metric'))
if 'route_map' in table_config:
self.cli_set(['policy', 'route-map', table_config.get('route_map'), 'rule', '10', 'action'], value='permit')
self.cli_set(proto_path + [table, 'route-map'], value=table_config.get('route_map'))
else:
self.cli_set(proto_path)
if 'metric' in proto_config:
self.cli_set(proto_path + ['metric', proto_config['metric']])
if 'route_map' in proto_config:
self.cli_set(['policy', 'route-map', proto_config['route_map'], 'rule', '20', 'action', 'permit'])
self.cli_set(proto_path + ['route-map', proto_config['route_map']])
for network, network_config in networks.items():
self.cli_set(base_path + ['address-family', 'ipv6-unicast',
'network', network])
if 'summary_only' in network_config:
self.cli_set(base_path + ['address-family', 'ipv6-unicast',
'aggregate-address', network, 'summary-only'])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(' address-family ipv6 unicast', frrconfig)
# T2100: By default ebgp-requires-policy is disabled to keep VyOS
# 1.3 and 1.2 backwards compatibility
self.assertIn(' no bgp ebgp-requires-policy', frrconfig)
for proto, proto_config in redistributes.items():
if proto == 'table':
for table, table_config in proto_config.items():
tmp = f' redistribute table-direct {table}'
if 'metric' in proto_config:
metric = proto_config['metric']
tmp += f' metric {metric}'
if 'route_map' in proto_config:
route_map = proto_config['route_map']
tmp += f' route-map {route_map}'
self.assertIn(tmp, frrconfig)
else:
# FRR calls this OSPF6
if proto == 'ospfv3':
proto = 'ospf6'
tmp = f' redistribute {proto}'
if 'metric' in proto_config:
metric = proto_config['metric']
tmp += f' metric {metric}'
if 'route_map' in proto_config:
route_map = proto_config['route_map']
tmp += f' route-map {route_map}'
self.assertIn(tmp, frrconfig)
for network, network_config in networks.items():
self.assertIn(f' network {network}', frrconfig)
if 'as_set' in network_config:
self.assertIn(f' aggregate-address {network} summary-only', frrconfig)
for proto, proto_config in redistributes.items():
if 'route_map' in proto_config:
self.cli_delete(['policy', 'route-map', proto_config['route_map']])
def test_bgp_06_listen_range(self):
# Implemented via T1875
limit = '64'
listen_ranges = ['192.0.2.0/25', '192.0.2.128/25']
peer_group = 'listenfoobar'
self.cli_set(base_path + ['listen', 'limit', limit])
for prefix in listen_ranges:
self.cli_set(base_path + ['listen', 'range', prefix])
# check validate() - peer-group must be defined for range/prefix
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + ['listen', 'range', prefix, 'peer-group', peer_group])
# check validate() - peer-group does yet not exist!
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + ['peer-group', peer_group, 'remote-as', ASN])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' neighbor {peer_group} peer-group', frrconfig)
self.assertIn(f' neighbor {peer_group} remote-as {ASN}', frrconfig)
self.assertIn(f' bgp listen limit {limit}', frrconfig)
for prefix in listen_ranges:
self.assertIn(f' bgp listen range {prefix} peer-group {peer_group}', frrconfig)
def test_bgp_07_l2vpn_evpn(self):
vnis = ['10010', '10020', '10030']
soo = '1.2.3.4:10000'
evi_limit = '1000'
route_targets = ['1.1.1.1:100', '1.1.1.1:200', '1.1.1.1:300']
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-all-vni'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-default-gw'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-svi-ip'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'flooding', 'disable'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'default-originate', 'ipv4'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'default-originate', 'ipv6'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'disable-ead-evi-rx'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'disable-ead-evi-tx'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'mac-vrf', 'soo', soo])
for vni in vnis:
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni, 'advertise-default-gw'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni, 'advertise-svi-ip'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'ead-es-frag', 'evi-limit', evi_limit])
for route_target in route_targets:
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'ead-es-route-target', 'export', route_target])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' address-family l2vpn evpn', frrconfig)
self.assertIn(f' advertise-all-vni', frrconfig)
self.assertIn(f' advertise-default-gw', frrconfig)
self.assertIn(f' advertise-svi-ip', frrconfig)
self.assertIn(f' default-originate ipv4', frrconfig)
self.assertIn(f' default-originate ipv6', frrconfig)
self.assertIn(f' disable-ead-evi-rx', frrconfig)
self.assertIn(f' disable-ead-evi-tx', frrconfig)
self.assertIn(f' flooding disable', frrconfig)
self.assertIn(f' mac-vrf soo {soo}', frrconfig)
for vni in vnis:
- vniconfig = self.getFRRconfig(f' vni {vni}', endsection='^ exit-vni')
+ vniconfig = self.getFRRconfig(f' vni {vni}', stop_section='^ exit-vni')
self.assertIn(f'vni {vni}', vniconfig)
self.assertIn(f' advertise-default-gw', vniconfig)
self.assertIn(f' advertise-svi-ip', vniconfig)
self.assertIn(f' ead-es-frag evi-limit {evi_limit}', frrconfig)
for route_target in route_targets:
self.assertIn(f' ead-es-route-target export {route_target}', frrconfig)
def test_bgp_09_distance_and_flowspec(self):
distance_external = '25'
distance_internal = '30'
distance_local = '35'
distance_v4_prefix = '169.254.0.0/32'
distance_v6_prefix = '2001::/128'
distance_prefix_value = '110'
distance_families = ['ipv4-unicast', 'ipv6-unicast','ipv4-multicast', 'ipv6-multicast']
verify_families = ['ipv4 unicast', 'ipv6 unicast','ipv4 multicast', 'ipv6 multicast']
flowspec_families = ['address-family ipv4 flowspec', 'address-family ipv6 flowspec']
flowspec_int = 'lo'
# Per family distance support
for family in distance_families:
self.cli_set(base_path + ['address-family', family, 'distance', 'external', distance_external])
self.cli_set(base_path + ['address-family', family, 'distance', 'internal', distance_internal])
self.cli_set(base_path + ['address-family', family, 'distance', 'local', distance_local])
if 'ipv4' in family:
self.cli_set(base_path + ['address-family', family, 'distance',
'prefix', distance_v4_prefix, 'distance', distance_prefix_value])
if 'ipv6' in family:
self.cli_set(base_path + ['address-family', family, 'distance',
'prefix', distance_v6_prefix, 'distance', distance_prefix_value])
# IPv4 flowspec interface check
self.cli_set(base_path + ['address-family', 'ipv4-flowspec', 'local-install', 'interface', flowspec_int])
# IPv6 flowspec interface check
self.cli_set(base_path + ['address-family', 'ipv6-flowspec', 'local-install', 'interface', flowspec_int])
# Commit changes
self.cli_commit()
# Verify FRR distances configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
for family in verify_families:
self.assertIn(f'address-family {family}', frrconfig)
self.assertIn(f'distance bgp {distance_external} {distance_internal} {distance_local}', frrconfig)
if 'ipv4' in family:
self.assertIn(f'distance {distance_prefix_value} {distance_v4_prefix}', frrconfig)
if 'ipv6' in family:
self.assertIn(f'distance {distance_prefix_value} {distance_v6_prefix}', frrconfig)
# Verify FRR flowspec configuration
for family in flowspec_families:
self.assertIn(f'{family}', frrconfig)
self.assertIn(f'local-install {flowspec_int}', frrconfig)
def test_bgp_10_vrf_simple(self):
router_id = '127.0.0.3'
vrfs = ['red', 'green', 'blue']
# It is safe to assume that when the basic VRF test works, all
# other BGP related features work, as we entirely inherit the CLI
# templates and Jinja2 FRR template.
table = '1000'
# testing only one AFI is sufficient as it's generic code
for vrf in vrfs:
vrf_base = ['vrf', 'name', vrf]
self.cli_set(vrf_base + ['table', table])
self.cli_set(vrf_base + ['protocols', 'bgp', 'system-as', ASN])
self.cli_set(vrf_base + ['protocols', 'bgp', 'parameters', 'router-id', router_id])
table = str(int(table) + 1000)
# import VRF routes do main RIB
self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'import', 'vrf', vrf])
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' address-family ipv6 unicast', frrconfig)
for vrf in vrfs:
self.assertIn(f' import vrf {vrf}', frrconfig)
# Verify FRR bgpd configuration
- frr_vrf_config = self.getFRRconfig(f'router bgp {ASN} vrf {vrf}', endsection='^exit')
+ frr_vrf_config = self.getFRRconfig(f'router bgp {ASN} vrf {vrf}', stop_section='^exit')
self.assertIn(f'router bgp {ASN} vrf {vrf}', frr_vrf_config)
self.assertIn(f' bgp router-id {router_id}', frr_vrf_config)
def test_bgp_11_confederation(self):
router_id = '127.10.10.2'
confed_id = str(int(ASN) + 1)
confed_asns = '10 20 30 40'
self.cli_set(base_path + ['parameters', 'router-id', router_id])
self.cli_set(base_path + ['parameters', 'confederation', 'identifier', confed_id])
for asn in confed_asns.split():
self.cli_set(base_path + ['parameters', 'confederation', 'peers', asn])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' bgp router-id {router_id}', frrconfig)
self.assertIn(f' bgp confederation identifier {confed_id}', frrconfig)
self.assertIn(f' bgp confederation peers {confed_asns}', frrconfig)
def test_bgp_12_v6_link_local(self):
remote_asn = str(int(ASN) + 10)
interface = 'eth0'
self.cli_set(base_path + ['neighbor', interface, 'address-family', 'ipv6-unicast'])
self.cli_set(base_path + ['neighbor', interface, 'interface', 'v6only', 'remote-as', remote_asn])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' neighbor {interface} interface v6only remote-as {remote_asn}', frrconfig)
self.assertIn(f' address-family ipv6 unicast', frrconfig)
self.assertIn(f' neighbor {interface} activate', frrconfig)
self.assertIn(f' exit-address-family', frrconfig)
def test_bgp_13_vpn(self):
remote_asn = str(int(ASN) + 150)
neighbor = '192.0.2.55'
vrf_name = 'red'
label = 'auto'
rd = f'{neighbor}:{ASN}'
rt_export = f'{neighbor}:1002 1.2.3.4:567'
rt_import = f'{neighbor}:1003 500:100'
# testing only one AFI is sufficient as it's generic code
for afi in ['ipv4-unicast', 'ipv6-unicast']:
self.cli_set(base_path + ['address-family', afi, 'export', 'vpn'])
self.cli_set(base_path + ['address-family', afi, 'import', 'vpn'])
self.cli_set(base_path + ['address-family', afi, 'label', 'vpn', 'export', label])
self.cli_set(base_path + ['address-family', afi, 'label', 'vpn', 'allocation-mode', 'per-nexthop'])
self.cli_set(base_path + ['address-family', afi, 'rd', 'vpn', 'export', rd])
self.cli_set(base_path + ['address-family', afi, 'route-map', 'vpn', 'export', route_map_out])
self.cli_set(base_path + ['address-family', afi, 'route-map', 'vpn', 'import', route_map_in])
self.cli_set(base_path + ['address-family', afi, 'route-target', 'vpn', 'export', rt_export])
self.cli_set(base_path + ['address-family', afi, 'route-target', 'vpn', 'import', rt_import])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
for afi in ['ipv4', 'ipv6']:
- afi_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
- substring=f' address-family {afi} unicast',
- endsubsection='^ exit-address-family')
+ afi_config = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit',
+ start_subsection=f' address-family {afi} unicast',
+ stop_subsection='^ exit-address-family')
self.assertIn(f'address-family {afi} unicast', afi_config)
self.assertIn(f' export vpn', afi_config)
self.assertIn(f' import vpn', afi_config)
self.assertIn(f' label vpn export {label}', afi_config)
self.assertIn(f' label vpn export allocation-mode per-nexthop', afi_config)
self.assertIn(f' rd vpn export {rd}', afi_config)
self.assertIn(f' route-map vpn export {route_map_out}', afi_config)
self.assertIn(f' route-map vpn import {route_map_in}', afi_config)
self.assertIn(f' rt vpn export {rt_export}', afi_config)
self.assertIn(f' rt vpn import {rt_import}', afi_config)
self.assertIn(f' exit-address-family', afi_config)
def test_bgp_14_remote_as_peer_group_override(self):
# Peer-group member cannot override remote-as of peer-group
remote_asn = str(int(ASN) + 150)
neighbor = '192.0.2.1'
peer_group = 'bar'
interface = 'eth0'
self.cli_set(base_path + ['neighbor', neighbor, 'remote-as', remote_asn])
self.cli_set(base_path + ['neighbor', neighbor, 'peer-group', peer_group])
self.cli_set(base_path + ['peer-group', peer_group, 'remote-as', remote_asn])
# Peer-group member cannot override remote-as of peer-group
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(base_path + ['neighbor', neighbor, 'remote-as'])
# re-test with interface based peer-group
self.cli_set(base_path + ['neighbor', interface, 'interface', 'peer-group', peer_group])
self.cli_set(base_path + ['neighbor', interface, 'interface', 'remote-as', 'external'])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(base_path + ['neighbor', interface, 'interface', 'remote-as'])
# re-test with interface based v6only peer-group
self.cli_set(base_path + ['neighbor', interface, 'interface', 'v6only', 'peer-group', peer_group])
self.cli_set(base_path + ['neighbor', interface, 'interface', 'v6only', 'remote-as', 'external'])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(base_path + ['neighbor', interface, 'interface', 'v6only', 'remote-as'])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' neighbor {neighbor} peer-group {peer_group}', frrconfig)
self.assertIn(f' neighbor {peer_group} peer-group', frrconfig)
self.assertIn(f' neighbor {peer_group} remote-as {remote_asn}', frrconfig)
def test_bgp_15_local_as_ebgp(self):
# https://vyos.dev/T4560
# local-as allowed only for ebgp peers
neighbor = '192.0.2.99'
remote_asn = '500'
local_asn = '400'
self.cli_set(base_path + ['neighbor', neighbor, 'remote-as', ASN])
self.cli_set(base_path + ['neighbor', neighbor, 'local-as', local_asn])
# check validate() - local-as allowed only for ebgp peers
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + ['neighbor', neighbor, 'remote-as', remote_asn])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' neighbor {neighbor} remote-as {remote_asn}', frrconfig)
self.assertIn(f' neighbor {neighbor} local-as {local_asn}', frrconfig)
def test_bgp_16_import_rd_rt_compatibility(self):
# Verify if import vrf and rd vpn export
# exist in the same address family
self.create_bgp_instances_for_import_test()
self.cli_set(
base_path + ['address-family', import_afi, 'import', 'vrf',
import_vrf])
self.cli_set(
base_path + ['address-family', import_afi, 'rd', 'vpn', 'export',
import_rd])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
def test_bgp_17_import_rd_rt_compatibility(self):
# Verify if vrf that is in import vrf list contains rd vpn export
self.create_bgp_instances_for_import_test()
self.cli_set(
base_path + ['address-family', import_afi, 'import', 'vrf',
import_vrf])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
- frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
+ frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f'address-family ipv4 unicast', frrconfig)
self.assertIn(f' import vrf {import_vrf}', frrconfig)
self.assertIn(f'router bgp {ASN} vrf {import_vrf}', frrconfig_vrf)
self.cli_set(
import_vrf_base + [import_vrf] + base_path + ['address-family',
import_afi, 'rd',
'vpn', 'export',
import_rd])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
def test_bgp_18_deleting_import_vrf(self):
# Verify deleting vrf that is in import vrf list
self.create_bgp_instances_for_import_test()
self.cli_set(
base_path + ['address-family', import_afi, 'import', 'vrf',
import_vrf])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
- frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
+ frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f'address-family ipv4 unicast', frrconfig)
self.assertIn(f' import vrf {import_vrf}', frrconfig)
self.assertIn(f'router bgp {ASN} vrf {import_vrf}', frrconfig_vrf)
self.cli_delete(import_vrf_base + [import_vrf])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
def test_bgp_19_deleting_default_vrf(self):
# Verify deleting existent vrf default if other vrfs were created
self.create_bgp_instances_for_import_test()
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
- frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
+ frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f'router bgp {ASN} vrf {import_vrf}', frrconfig_vrf)
self.cli_delete(base_path)
with self.assertRaises(ConfigSessionError):
self.cli_commit()
def test_bgp_20_import_rd_rt_compatibility(self):
# Verify if vrf that has rd vpn export is in import vrf of other vrfs
self.create_bgp_instances_for_import_test()
self.cli_set(
import_vrf_base + [import_vrf] + base_path + ['address-family',
import_afi, 'rd',
'vpn', 'export',
import_rd])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
- frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
+ frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f'router bgp {ASN} vrf {import_vrf}', frrconfig_vrf)
self.assertIn(f'address-family ipv4 unicast', frrconfig_vrf)
self.assertIn(f' rd vpn export {import_rd}', frrconfig_vrf)
self.cli_set(
base_path + ['address-family', import_afi, 'import', 'vrf',
import_vrf])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
def test_bgp_21_import_unspecified_vrf(self):
# Verify if vrf that is in import is unspecified
self.create_bgp_instances_for_import_test()
self.cli_set(
base_path + ['address-family', import_afi, 'import', 'vrf',
'test'])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
def test_bgp_22_interface_mpls_forwarding(self):
interfaces = Section.interfaces('ethernet', vlan=False)
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'mpls', 'forwarding'])
self.cli_commit()
for interface in interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', frrconfig)
self.assertIn(f' mpls bgp forwarding', frrconfig)
def test_bgp_23_vrf_interface_mpls_forwarding(self):
self.create_bgp_instances_for_import_test()
interfaces = Section.interfaces('ethernet', vlan=False)
for interface in interfaces:
self.cli_set(['interfaces', 'ethernet', interface, 'vrf', import_vrf])
self.cli_set(import_vrf_base + [import_vrf] + base_path + ['interface', interface, 'mpls', 'forwarding'])
self.cli_commit()
for interface in interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', frrconfig)
self.assertIn(f' mpls bgp forwarding', frrconfig)
self.cli_delete(['interfaces', 'ethernet', interface, 'vrf'])
def test_bgp_24_srv6_sid(self):
locator_name = 'VyOS_foo'
sid = 'auto'
nexthop_ipv4 = '192.0.0.1'
nexthop_ipv6 = '2001:db8:100:200::2'
self.cli_set(base_path + ['srv6', 'locator', locator_name])
self.cli_set(base_path + ['sid', 'vpn', 'per-vrf', 'export', sid])
self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'sid', 'vpn', 'export', sid])
# verify() - SID per VRF and SID per address-family are mutually exclusive!
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(base_path + ['address-family', 'ipv4-unicast', 'sid'])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' segment-routing srv6', frrconfig)
self.assertIn(f' locator {locator_name}', frrconfig)
self.assertIn(f' sid vpn per-vrf export {sid}', frrconfig)
# Now test AFI SID
self.cli_delete(base_path + ['sid'])
self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'sid', 'vpn', 'export', sid])
self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'nexthop', 'vpn', 'export', nexthop_ipv4])
self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'sid', 'vpn', 'export', sid])
self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'nexthop', 'vpn', 'export', nexthop_ipv6])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' segment-routing srv6', frrconfig)
self.assertIn(f' locator {locator_name}', frrconfig)
- afiv4_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
- substring=' address-family ipv4 unicast',
- endsubsection='^ exit-address-family')
+ afiv4_config = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit',
+ start_subsection=' address-family ipv4 unicast',
+ stop_subsection='^ exit-address-family')
self.assertIn(f' sid vpn export {sid}', afiv4_config)
self.assertIn(f' nexthop vpn export {nexthop_ipv4}', afiv4_config)
- afiv6_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
- substring=' address-family ipv6 unicast',
- endsubsection='^ exit-address-family')
+ afiv6_config = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit',
+ start_subsection=' address-family ipv6 unicast',
+ stop_subsection='^ exit-address-family')
self.assertIn(f' sid vpn export {sid}', afiv6_config)
self.assertIn(f' nexthop vpn export {nexthop_ipv6}', afiv6_config)
def test_bgp_25_ipv4_labeled_unicast_peer_group(self):
pg_ipv4 = 'foo4'
ipv4_max_prefix = '20'
ipv4_prefix = '192.0.2.0/24'
self.cli_set(base_path + ['listen', 'range', ipv4_prefix, 'peer-group', pg_ipv4])
self.cli_set(base_path + ['parameters', 'labeled-unicast', 'ipv4-explicit-null'])
self.cli_set(base_path + ['peer-group', pg_ipv4, 'address-family', 'ipv4-labeled-unicast', 'maximum-prefix', ipv4_max_prefix])
self.cli_set(base_path + ['peer-group', pg_ipv4, 'remote-as', 'external'])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' neighbor {pg_ipv4} peer-group', frrconfig)
self.assertIn(f' neighbor {pg_ipv4} remote-as external', frrconfig)
self.assertIn(f' bgp listen range {ipv4_prefix} peer-group {pg_ipv4}', frrconfig)
self.assertIn(f' bgp labeled-unicast ipv4-explicit-null', frrconfig)
- afiv4_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
- substring=' address-family ipv4 labeled-unicast',
- endsubsection='^ exit-address-family')
+ afiv4_config = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit',
+ start_subsection=' address-family ipv4 labeled-unicast',
+ stop_subsection='^ exit-address-family')
self.assertIn(f' neighbor {pg_ipv4} activate', afiv4_config)
self.assertIn(f' neighbor {pg_ipv4} maximum-prefix {ipv4_max_prefix}', afiv4_config)
def test_bgp_26_ipv6_labeled_unicast_peer_group(self):
pg_ipv6 = 'foo6'
ipv6_max_prefix = '200'
ipv6_prefix = '2001:db8:1000::/64'
self.cli_set(base_path + ['listen', 'range', ipv6_prefix, 'peer-group', pg_ipv6])
self.cli_set(base_path + ['parameters', 'labeled-unicast', 'ipv6-explicit-null'])
self.cli_set(base_path + ['peer-group', pg_ipv6, 'address-family', 'ipv6-labeled-unicast', 'maximum-prefix', ipv6_max_prefix])
self.cli_set(base_path + ['peer-group', pg_ipv6, 'remote-as', 'external'])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' neighbor {pg_ipv6} peer-group', frrconfig)
self.assertIn(f' neighbor {pg_ipv6} remote-as external', frrconfig)
self.assertIn(f' bgp listen range {ipv6_prefix} peer-group {pg_ipv6}', frrconfig)
self.assertIn(f' bgp labeled-unicast ipv6-explicit-null', frrconfig)
- afiv6_config = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit',
- substring=' address-family ipv6 labeled-unicast',
- endsubsection='^ exit-address-family')
+ afiv6_config = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit',
+ start_subsection=' address-family ipv6 labeled-unicast',
+ stop_subsection='^ exit-address-family')
self.assertIn(f' neighbor {pg_ipv6} activate', afiv6_config)
self.assertIn(f' neighbor {pg_ipv6} maximum-prefix {ipv6_max_prefix}', afiv6_config)
def test_bgp_27_route_reflector_client(self):
int_neighbors = ['192.0.2.2', '192.0.2.3', '192.0.2.4', '192.0.2.5']
int_interfaces = ['dum0', 'dum1', 'dum2', 'dum3']
int_pg_names = ['SMOKETESTINT0', 'SMOKETESTINT1', 'SMOKETESTINT2']
remote_as_types = ['external', 'internal']
for int_interface in int_interfaces:
self.cli_set(['interfaces', 'dummy', int_interface])
self.cli_commit()
def _set_neighbor_0(neighbor, remote_as_type):
# set route-reflector-client in neighbor and set remote-as in peer_group
interface_cmd = ['interface'] if neighbor.startswith('dum') else []
self.cli_set(base_path + ['peer-group', int_pg_names[0], 'remote-as', remote_as_type])
self.cli_set(base_path + ['neighbor', neighbor, 'address-family', 'ipv4-unicast', 'route-reflector-client'])
self.cli_set(base_path + ['neighbor', neighbor] + interface_cmd + ['peer-group', int_pg_names[0]])
def _set_neighbor_1(neighbor, remote_as_type):
# set route-reflector-client in peer_group and set remote-as in neighbor
interface_cmd = ['interface'] if neighbor.startswith('dum') else []
self.cli_set(base_path + ['peer-group', int_pg_names[1], 'address-family', 'ipv4-unicast', 'route-reflector-client'])
self.cli_set(base_path + ['neighbor', neighbor] + interface_cmd + ['remote-as', remote_as_type])
self.cli_set(base_path + ['neighbor', neighbor] + interface_cmd + ['peer-group', int_pg_names[1]])
def _set_neighbor_2(neighbor, remote_as_type):
# set route-reflector-client and remote-as in peer_group
interface_cmd = ['interface'] if neighbor.startswith('dum') else []
self.cli_set(base_path + ['peer-group', int_pg_names[2], 'remote-as', remote_as_type])
self.cli_set(base_path + ['peer-group', int_pg_names[2], 'address-family', 'ipv4-unicast', 'route-reflector-client'])
self.cli_set(base_path + ['neighbor', neighbor] + interface_cmd + ['peer-group', int_pg_names[2]])
def _set_neighbor_3(neighbor, remote_as_type):
# set route-reflector-client and remote-as in neighbor
interface_cmd = ['interface'] if neighbor.startswith('dum') else []
self.cli_set(base_path + ['neighbor', neighbor, 'address-family', 'ipv4-unicast', 'route-reflector-client'])
self.cli_set(base_path + ['neighbor', neighbor] + interface_cmd + ['remote-as', remote_as_type])
-
+
set_neighbor_funcs = [_set_neighbor_0, _set_neighbor_1, _set_neighbor_2, _set_neighbor_3]
for remote_as_type in remote_as_types:
for func_count, set_neighbor_func in enumerate(set_neighbor_funcs):
for neighbors in [int_neighbors, int_interfaces]:
set_neighbor_func(neighbors[func_count], remote_as_type)
if remote_as_type == 'external':
with self.assertRaises(ConfigSessionError) as e:
self.cli_commit()
self.cli_discard()
else:
self.cli_commit()
-
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit', substring=' address-family ipv4 unicast', endsubsection='^ exit-address-family')
+
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit', start_subsection=' address-family ipv4 unicast', stop_subsection='^ exit-address-family')
neighbor_has_rr_client = [
int_neighbors[0], int_neighbors[3],
int_interfaces[0], int_interfaces[3],
int_pg_names[1], int_pg_names[2],
]
[self.assertIn(f'neighbor {neighbor} route-reflector-client', frrconfig) for neighbor in neighbor_has_rr_client]
# tearDown dummy interfaces
self.cli_delete(['interfaces', 'dummy'])
self.cli_commit()
def test_bgp_28_peer_group_member_all_internal_or_external(self):
def _common_config_check(conf, include_ras=True):
if include_ras:
self.assertIn(f'neighbor {int_neighbors[0]} remote-as {ASN}', conf)
self.assertIn(f'neighbor {int_neighbors[1]} remote-as {ASN}', conf)
self.assertIn(f'neighbor {ext_neighbors[0]} remote-as {int(ASN) + 1}',conf)
self.assertIn(f'neighbor {int_neighbors[0]} peer-group {int_pg_name}', conf)
self.assertIn(f'neighbor {int_neighbors[1]} peer-group {int_pg_name}', conf)
self.assertIn(f'neighbor {ext_neighbors[0]} peer-group {ext_pg_name}', conf)
int_neighbors = ['192.0.2.2', '192.0.2.3']
ext_neighbors = ['192.122.2.2', '192.122.2.3']
int_pg_name, ext_pg_name = 'SMOKETESTINT', 'SMOKETESTEXT'
self.cli_set(base_path + ['neighbor', int_neighbors[0], 'peer-group', int_pg_name])
self.cli_set(base_path + ['neighbor', int_neighbors[0], 'remote-as', ASN])
self.cli_set(base_path + ['peer-group', int_pg_name, 'address-family', 'ipv4-unicast'])
self.cli_set(base_path + ['neighbor', ext_neighbors[0], 'peer-group', ext_pg_name])
self.cli_set(base_path + ['neighbor', ext_neighbors[0], 'remote-as', f'{int(ASN) + 1}'])
self.cli_set(base_path + ['peer-group', ext_pg_name, 'address-family', 'ipv4-unicast'])
self.cli_commit()
# test add external remote-as to internal group
self.cli_set(base_path + ['neighbor', int_neighbors[1], 'peer-group', int_pg_name])
self.cli_set(base_path + ['neighbor', int_neighbors[1], 'remote-as', f'{int(ASN) + 1}'])
with self.assertRaises(ConfigSessionError) as e:
self.cli_commit()
# self.assertIn('\nPeer-group members must be all internal or all external\n', str(e.exception))
# test add internal remote-as to internal group
self.cli_set(base_path + ['neighbor', int_neighbors[1], 'remote-as', ASN])
self.cli_commit()
- conf = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ conf = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
_common_config_check(conf)
# test add internal remote-as to external group
self.cli_set(base_path + ['neighbor', ext_neighbors[1], 'peer-group', ext_pg_name])
self.cli_set(base_path + ['neighbor', ext_neighbors[1], 'remote-as', ASN])
with self.assertRaises(ConfigSessionError) as e:
self.cli_commit()
# self.assertIn('\nPeer-group members must be all internal or all external\n', str(e.exception))
# test add external remote-as to external group
self.cli_set(base_path + ['neighbor', ext_neighbors[1], 'remote-as', f'{int(ASN) + 2}'])
self.cli_commit()
- conf = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ conf = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
_common_config_check(conf)
self.assertIn(f'neighbor {ext_neighbors[1]} remote-as {int(ASN) + 2}', conf)
self.assertIn(f'neighbor {ext_neighbors[1]} peer-group {ext_pg_name}', conf)
# test named remote-as
self.cli_set(base_path + ['neighbor', int_neighbors[0], 'remote-as', 'internal'])
self.cli_set(base_path + ['neighbor', int_neighbors[1], 'remote-as', 'internal'])
self.cli_set(base_path + ['neighbor', ext_neighbors[0], 'remote-as', 'external'])
self.cli_set(base_path + ['neighbor', ext_neighbors[1], 'remote-as', 'external'])
self.cli_commit()
- conf = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ conf = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
_common_config_check(conf, include_ras=False)
self.assertIn(f'neighbor {int_neighbors[0]} remote-as internal', conf)
self.assertIn(f'neighbor {int_neighbors[1]} remote-as internal', conf)
self.assertIn(f'neighbor {ext_neighbors[0]} remote-as external', conf)
self.assertIn(f'neighbor {ext_neighbors[1]} remote-as external', conf)
self.assertIn(f'neighbor {ext_neighbors[1]} peer-group {ext_pg_name}', conf)
def test_bgp_29_peer_group_remote_as_equal_local_as(self):
self.cli_set(base_path + ['system-as', ASN])
self.cli_set(base_path + ['peer-group', 'OVERLAY', 'local-as', f'{int(ASN) + 1}'])
self.cli_set(base_path + ['peer-group', 'OVERLAY', 'remote-as', f'{int(ASN) + 1}'])
self.cli_set(base_path + ['peer-group', 'OVERLAY', 'address-family', 'l2vpn-evpn'])
self.cli_set(base_path + ['peer-group', 'UNDERLAY', 'address-family', 'ipv4-unicast'])
self.cli_set(base_path + ['neighbor', '10.177.70.62', 'peer-group', 'UNDERLAY'])
self.cli_set(base_path + ['neighbor', '10.177.70.62', 'remote-as', 'external'])
self.cli_set(base_path + ['neighbor', '10.177.75.1', 'peer-group', 'OVERLAY'])
self.cli_set(base_path + ['neighbor', '10.177.75.2', 'peer-group', 'OVERLAY'])
self.cli_commit()
- conf = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ conf = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'neighbor OVERLAY remote-as {int(ASN) + 1}', conf)
self.assertIn(f'neighbor OVERLAY local-as {int(ASN) + 1}', conf)
def test_bgp_30_import_vrf_routemap(self):
router_id = '127.0.0.3'
table = '1000'
vrf = 'red'
vrf_base = ['vrf', 'name', vrf]
self.cli_set(vrf_base + ['table', table])
self.cli_set(vrf_base + ['protocols', 'bgp', 'system-as', ASN])
self.cli_set(
vrf_base + ['protocols', 'bgp', 'parameters', 'router-id',
router_id])
self.cli_set(
base_path + ['address-family', 'ipv4-unicast', 'import',
'vrf', vrf])
self.cli_set(
base_path + ['address-family', 'ipv4-unicast', 'route-map',
'vrf', 'import', route_map_in])
self.cli_commit()
# Verify FRR bgpd configuration
frrconfig = self.getFRRconfig(f'router bgp {ASN}',
- endsection='^exit')
+ stop_section='^exit')
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' address-family ipv4 unicast', frrconfig)
self.assertIn(f' import vrf {vrf}', frrconfig)
self.assertIn(f' import vrf route-map {route_map_in}', frrconfig)
# Verify FRR bgpd configuration
frr_vrf_config = self.getFRRconfig(
- f'router bgp {ASN} vrf {vrf}', endsection='^exit')
+ f'router bgp {ASN} vrf {vrf}', stop_section='^exit')
self.assertIn(f'router bgp {ASN} vrf {vrf}', frr_vrf_config)
self.assertIn(f' bgp router-id {router_id}', frr_vrf_config)
def test_bgp_99_bmp(self):
target_name = 'instance-bmp'
target_address = '127.0.0.1'
target_port = '5000'
min_retry = '1024'
max_retry = '2048'
monitor_ipv4 = 'pre-policy'
monitor_ipv6 = 'pre-policy'
mirror_buffer = '32000000'
bmp_path = base_path + ['bmp']
target_path = bmp_path + ['target', target_name]
# by default the 'bmp' module not loaded for the bgpd expect Error
self.cli_set(bmp_path)
if not process_named_running('bgpd', 'bmp'):
with self.assertRaises(ConfigSessionError):
self.cli_commit()
# add required 'bmp' module to bgpd and restart bgpd
self.cli_delete(bmp_path)
self.cli_set(['system', 'frr', 'bmp'])
self.cli_commit()
# restart bgpd to apply "-M bmp" and update PID
cmd(f'sudo kill -9 {self.daemon_pid}')
# let the bgpd process recover
sleep(10)
# update daemon PID - this was a planned daemon restart
self.daemon_pid = process_named_running(bgp_daemon)
# set bmp config but not set address
self.cli_set(target_path + ['port', target_port])
# address is not set, expect Error
with self.assertRaises(ConfigSessionError):
self.cli_commit()
# config other bmp options
self.cli_set(target_path + ['address', target_address])
self.cli_set(bmp_path + ['mirror-buffer-limit', mirror_buffer])
self.cli_set(target_path + ['port', target_port])
self.cli_set(target_path + ['min-retry', min_retry])
self.cli_set(target_path + ['max-retry', max_retry])
self.cli_set(target_path + ['mirror'])
self.cli_set(target_path + ['monitor', 'ipv4-unicast', monitor_ipv4])
self.cli_set(target_path + ['monitor', 'ipv6-unicast', monitor_ipv6])
self.cli_commit()
# Verify bgpd bmp configuration
- frrconfig = self.getFRRconfig(f'router bgp {ASN}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router bgp {ASN}', stop_section='^exit')
self.assertIn(f'bmp mirror buffer-limit {mirror_buffer}', frrconfig)
self.assertIn(f'bmp targets {target_name}', frrconfig)
self.assertIn(f'bmp mirror', frrconfig)
self.assertIn(f'bmp monitor ipv4 unicast {monitor_ipv4}', frrconfig)
self.assertIn(f'bmp monitor ipv6 unicast {monitor_ipv6}', frrconfig)
self.assertIn(f'bmp connect {target_address} port {target_port} min-retry {min_retry} max-retry {max_retry}', frrconfig)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py
index b755b8b0f..f6ca91370 100755
--- a/smoketest/scripts/cli/test_protocols_isis.py
+++ b/smoketest/scripts/cli/test_protocols_isis.py
@@ -1,481 +1,478 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.utils.process import process_named_running
from vyos.frrender import isis_daemon
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(isis_daemon)
# 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'])
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
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(isis_daemon))
def test_isis_01_redistribute(self):
prefix_list = 'EXPORT-ISIS'
route_map = 'EXPORT-ISIS'
rule = '10'
metric_style = 'transition'
redistribute = ['babel', 'bgp', 'connected', 'kernel', 'nhrp', 'ospf', 'rip', 'static']
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.cli_set(base_path + ['net', net])
for interface in self._interfaces:
self.cli_set(base_path + ['interface', interface])
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()
for proto in redistribute:
self.cli_set(base_path + ['redistribute', 'ipv4', proto, '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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' metric-style {metric_style}', tmp)
self.assertIn(f' log-adjacency-changes', tmp)
for proto in redistribute:
self.assertIn(f' redistribute ipv4 {proto} level-2 route-map {route_map}', tmp)
for interface in self._interfaces:
- tmp = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ tmp = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='^exit')
self.assertIn(f'router isis {domain}', tmp)
self.assertIn(f' net {net}', tmp)
- tmp = self.getFRRconfig(f'router isis {domain} vrf {vrf}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain} vrf {vrf}', stop_section='^exit')
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.cli_set(base_path + ['net', net])
for interface in self._interfaces:
self.cli_set(base_path + ['interface', interface])
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='^exit')
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.cli_set(base_path + ['net', net])
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}', endsection='exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='exit')
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='^exit')
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
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"
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])
for interface in self._interfaces:
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='^exit')
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='^exit')
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='^exit')
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='^exit')
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='^exit')
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='^exit')
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}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' topology {topology}', tmp)
def test_isis_11_srv6(self):
locator = "TEST"
interface = 'lo'
self.cli_set(base_path + ['net', net])
self.cli_set(base_path + ['interface', interface])
self.cli_set(base_path + ['segment-routing', 'srv6', 'locator', locator])
# Commit main ISIS changes
self.cli_commit()
# Verify main ISIS changes
- tmp = self.getFRRconfig(f'router isis {domain}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router isis {domain}', stop_section='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' segment-routing srv6', tmp)
self.assertIn(f' locator {locator}', tmp)
# Commit for isis
self.cli_commit()
def test_isis_12_frr_interface_lfa_remotelfa(self):
interface = 'eth0'
rla_metric = '10'
frr_interface_base_path = base_path + ['interface', interface, 'fast-reroute']
self.cli_set(base_path + ['net', net])
self.cli_set(base_path + ['interface', interface])
self.cli_set(frr_interface_base_path + ['lfa', 'level-1', 'enable'])
self.cli_set(frr_interface_base_path + ['lfa', 'level-1', 'exclude',
'interface', interface])
self.cli_set(frr_interface_base_path + ['remote-lfa', 'level-1',
'maximum-metric', rla_metric])
self.cli_set(frr_interface_base_path + ['remote-lfa', 'level-1',
'tunnel', 'mpls-ldp'])
# Commit main ISIS changes
self.cli_commit()
# Verify interface ISIS changes
- tmp = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ tmp = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f' isis fast-reroute lfa level-1', tmp)
self.assertIn(f' isis fast-reroute lfa level-1 exclude interface {interface}', tmp)
self.assertIn(f' isis fast-reroute remote-lfa maximum-metric {rla_metric} level-1', tmp)
self.assertIn(f' isis fast-reroute remote-lfa tunnel mpls-ldp level-1', tmp)
def test_isis_13_frr_interface_tilfa(self):
interface = 'eth0'
frr_interface_base_path = base_path + ['interface', interface, 'fast-reroute']
self.cli_set(base_path + ['net', net])
self.cli_set(base_path + ['interface', interface])
self.cli_set(frr_interface_base_path + ['ti-lfa', 'level-1', 'node-protection',
'link-fallback'])
# Commit main ISIS changes
self.cli_commit()
# Verify interface ISIS changes
- tmp = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ tmp = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f' isis fast-reroute ti-lfa level-1 node-protection link-fallback', tmp)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_mpls.py b/smoketest/scripts/cli/test_protocols_mpls.py
index 1818b6fa6..cabaaf0ef 100755
--- a/smoketest/scripts/cli/test_protocols_mpls.py
+++ b/smoketest/scripts/cli/test_protocols_mpls.py
@@ -1,194 +1,191 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.frrender import ldpd_daemon
from vyos.utils.process import process_named_running
base_path = ['protocols', 'mpls', 'ldp']
peers = {
'192.0.2.10' : {
'intv_rx' : '500',
'intv_tx' : '600',
'multihop' : '',
'source_addr': '192.0.2.254',
},
'192.0.2.20' : {
'echo_mode' : '',
'intv_echo' : '100',
'intv_mult' : '100',
'intv_rx' : '222',
'intv_tx' : '333',
'passive' : '',
'shutdown' : '',
},
'2001:db8::a' : {
'source_addr': '2001:db8::1',
},
'2001:db8::b' : {
'source_addr': '2001:db8::1',
'multihop' : '',
},
}
profiles = {
'foo' : {
'echo_mode' : '',
'intv_echo' : '100',
'intv_mult' : '101',
'intv_rx' : '222',
'intv_tx' : '333',
'shutdown' : '',
},
'bar' : {
'intv_mult' : '102',
'intv_rx' : '444',
'passive' : '',
},
}
class TestProtocolsMPLS(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestProtocolsMPLS, cls).setUpClass()
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(ldpd_daemon)
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(ldpd_daemon))
def test_mpls_basic(self):
router_id = '1.2.3.4'
transport_ipv4_addr = '5.6.7.8'
interfaces = Section.interfaces('ethernet')
self.cli_set(base_path + ['router-id', router_id])
# At least one LDP interface must be configured
with self.assertRaises(ConfigSessionError):
self.cli_commit()
for interface in interfaces:
self.cli_set(base_path + ['interface', interface])
# LDP transport address missing
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + ['discovery', 'transport-ipv4-address', transport_ipv4_addr])
# Commit changes
self.cli_commit()
# Validate configuration
- frrconfig = self.getFRRconfig('mpls ldp', endsection='^exit')
+ frrconfig = self.getFRRconfig('mpls ldp', stop_section='^exit')
self.assertIn(f'mpls ldp', frrconfig)
self.assertIn(f' router-id {router_id}', frrconfig)
# Validate AFI IPv4
- afiv4_config = self.getFRRconfig('mpls ldp', endsection='^exit',
- substring=' address-family ipv4',
- endsubsection='^ exit-address-family')
+ afiv4_config = self.getFRRconfig('mpls ldp', stop_section='^exit',
+ start_subsection=' address-family ipv4',
+ stop_subsection='^ exit-address-family')
self.assertIn(f' discovery transport-address {transport_ipv4_addr}', afiv4_config)
for interface in interfaces:
self.assertIn(f' interface {interface}', afiv4_config)
def test_02_mpls_disable_establish_hello(self):
router_id = '1.2.3.4'
transport_ipv4_addr = '5.6.7.8'
transport_ipv6_addr = '2001:db8:1111::1111'
interfaces = Section.interfaces('ethernet')
self.cli_set(base_path + ['router-id', router_id])
# At least one LDP interface must be configured
with self.assertRaises(ConfigSessionError):
self.cli_commit()
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'disable-establish-hello'])
# LDP transport address missing
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + ['discovery', 'transport-ipv4-address', transport_ipv4_addr])
self.cli_set(base_path + ['discovery', 'transport-ipv6-address', transport_ipv6_addr])
# Commit changes
self.cli_commit()
# Validate configuration
- frrconfig = self.getFRRconfig('mpls ldp', endsection='^exit')
+ frrconfig = self.getFRRconfig('mpls ldp', stop_section='^exit')
self.assertIn(f'mpls ldp', frrconfig)
self.assertIn(f' router-id {router_id}', frrconfig)
# Validate AFI IPv4
- afiv4_config = self.getFRRconfig('mpls ldp', endsection='^exit',
- substring=' address-family ipv4',
- endsubsection='^ exit-address-family')
+ afiv4_config = self.getFRRconfig('mpls ldp', stop_section='^exit',
+ start_subsection=' address-family ipv4',
+ stop_subsection='^ exit-address-family')
self.assertIn(f' discovery transport-address {transport_ipv4_addr}', afiv4_config)
for interface in interfaces:
self.assertIn(f' interface {interface}', afiv4_config)
self.assertIn(f' disable-establish-hello', afiv4_config)
# Validate AFI IPv6
- afiv6_config = self.getFRRconfig('mpls ldp', endsection='^exit',
- substring=' address-family ipv6',
- endsubsection='^ exit-address-family')
+ afiv6_config = self.getFRRconfig('mpls ldp', stop_section='^exit',
+ start_subsection=' address-family ipv6',
+ stop_subsection='^ exit-address-family')
self.assertIn(f' discovery transport-address {transport_ipv6_addr}', afiv6_config)
for interface in interfaces:
self.assertIn(f' interface {interface}', afiv6_config)
self.assertIn(f' disable-establish-hello', afiv6_config)
# Delete disable-establish-hello
for interface in interfaces:
self.cli_delete(base_path + ['interface', interface, 'disable-establish-hello'])
# Commit changes
self.cli_commit()
# Validate AFI IPv4
- afiv4_config = self.getFRRconfig('mpls ldp', endsection='^exit',
- substring=' address-family ipv4',
- endsubsection='^ exit-address-family')
+ afiv4_config = self.getFRRconfig('mpls ldp', stop_section='^exit',
+ start_subsection=' address-family ipv4',
+ stop_subsection='^ exit-address-family')
# Validate AFI IPv6
- afiv6_config = self.getFRRconfig('mpls ldp', endsection='^exit',
- substring=' address-family ipv6',
- endsubsection='^ exit-address-family')
+ afiv6_config = self.getFRRconfig('mpls ldp', stop_section='^exit',
+ start_subsection=' address-family ipv6',
+ stop_subsection='^ exit-address-family')
# Check deleted 'disable-establish-hello' option per interface
for interface in interfaces:
self.assertIn(f' interface {interface}', afiv4_config)
self.assertNotIn(f' disable-establish-hello', afiv4_config)
self.assertIn(f' interface {interface}', afiv6_config)
self.assertNotIn(f' disable-establish-hello', afiv6_config)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_nhrp.py b/smoketest/scripts/cli/test_protocols_nhrp.py
index 29c14f74b..1f4b12a23 100755
--- a/smoketest/scripts/cli/test_protocols_nhrp.py
+++ b/smoketest/scripts/cli/test_protocols_nhrp.py
@@ -1,142 +1,142 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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.utils.process import process_named_running
tunnel_path = ['interfaces', 'tunnel']
nhrp_path = ['protocols', 'nhrp']
vpn_path = ['vpn', 'ipsec']
PROCESS_NAME = 'nhrpd'
class TestProtocolsNHRP(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestProtocolsNHRP, cls).setUpClass()
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, nhrp_path)
cls.cli_delete(cls, tunnel_path)
def tearDown(self):
self.cli_delete(nhrp_path)
self.cli_delete(tunnel_path)
self.cli_commit()
def test_01_nhrp_config(self):
tunnel_if = "tun100"
tunnel_ip = '172.16.253.134/32'
tunnel_source = "192.0.2.134"
tunnel_encapsulation = "gre"
esp_group = "ESP-HUB"
ike_group = "IKE-HUB"
nhrp_secret = "vyos123"
nhrp_profile = "NHRPVPN"
nhrp_holdtime = '300'
nhs_tunnelip = '172.16.253.1'
nhs_nbmaip = '192.0.2.1'
map_tunnelip = '172.16.253.135'
map_nbmaip = "192.0.2.135"
nhrp_networkid = '1'
ipsec_secret = "secret"
multicat_log_group = '2'
redirect_log_group = '1'
# Tunnel
self.cli_set(tunnel_path + [tunnel_if, "address", tunnel_ip])
self.cli_set(tunnel_path + [tunnel_if, "encapsulation", tunnel_encapsulation])
self.cli_set(tunnel_path + [tunnel_if, "source-address", tunnel_source])
self.cli_set(tunnel_path + [tunnel_if, "enable-multicast"])
self.cli_set(tunnel_path + [tunnel_if, "parameters", "ip", "key", "1"])
# NHRP
self.cli_set(nhrp_path + ["tunnel", tunnel_if, "authentication", nhrp_secret])
self.cli_set(nhrp_path + ["tunnel", tunnel_if, "holdtime", nhrp_holdtime])
self.cli_set(nhrp_path + ["tunnel", tunnel_if, "multicast", nhs_tunnelip])
self.cli_set(nhrp_path + ["tunnel", tunnel_if, "redirect"])
self.cli_set(nhrp_path + ["tunnel", tunnel_if, "shortcut"])
self.cli_set(nhrp_path + ["tunnel", tunnel_if, "registration-no-unique"])
self.cli_set(nhrp_path + ["tunnel", tunnel_if, "network-id", nhrp_networkid])
self.cli_set(nhrp_path + ["tunnel", tunnel_if, "nhs", "tunnel-ip", nhs_tunnelip, "nbma", nhs_nbmaip])
self.cli_set(nhrp_path + ["tunnel", tunnel_if, "map", "tunnel-ip", map_tunnelip, "nbma", map_nbmaip])
# IKE/ESP Groups
self.cli_set(vpn_path + ["esp-group", esp_group, "lifetime", "1800"])
self.cli_set(vpn_path + ["esp-group", esp_group, "mode", "transport"])
self.cli_set(vpn_path + ["esp-group", esp_group, "pfs", "dh-group2"])
self.cli_set(vpn_path + ["esp-group", esp_group, "proposal", "1", "encryption", "aes256"])
self.cli_set(vpn_path + ["esp-group", esp_group, "proposal", "1", "hash", "sha1"])
self.cli_set(vpn_path + ["esp-group", esp_group, "proposal", "2", "encryption", "3des"])
self.cli_set(vpn_path + ["esp-group", esp_group, "proposal", "2", "hash", "md5"])
self.cli_set(vpn_path + ["ike-group", ike_group, "key-exchange", "ikev1"])
self.cli_set(vpn_path + ["ike-group", ike_group, "lifetime", "3600"])
self.cli_set(vpn_path + ["ike-group", ike_group, "proposal", "1", "dh-group", "2"])
self.cli_set(vpn_path + ["ike-group", ike_group, "proposal", "1", "encryption", "aes256"])
self.cli_set(vpn_path + ["ike-group", ike_group, "proposal", "1", "hash", "sha1"])
self.cli_set(vpn_path + ["ike-group", ike_group, "proposal", "2", "dh-group", "2"])
self.cli_set(vpn_path + ["ike-group", ike_group, "proposal", "2", "encryption", "aes128"])
self.cli_set(vpn_path + ["ike-group", ike_group, "proposal", "2", "hash", "sha1"])
# Profile - Not doing full DMVPN checks here, just want to verify the profile name in the output
self.cli_set(vpn_path + ["interface", "eth0"])
self.cli_set(vpn_path + ["profile", nhrp_profile, "authentication", "mode", "pre-shared-secret"])
self.cli_set(vpn_path + ["profile", nhrp_profile, "authentication", "pre-shared-secret", ipsec_secret])
self.cli_set(vpn_path + ["profile", nhrp_profile, "bind", "tunnel", tunnel_if])
self.cli_set(vpn_path + ["profile", nhrp_profile, "esp-group", esp_group])
self.cli_set(vpn_path + ["profile", nhrp_profile, "ike-group", ike_group])
self.cli_commit()
- frrconfig = self.getFRRconfig(f'interface {tunnel_if}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {tunnel_if}', stop_section='^exit')
self.assertIn(f'interface {tunnel_if}', frrconfig)
self.assertIn(f' ip nhrp authentication {nhrp_secret}', frrconfig)
self.assertIn(f' ip nhrp holdtime {nhrp_holdtime}', frrconfig)
self.assertIn(f' ip nhrp map multicast {nhs_tunnelip}', frrconfig)
self.assertIn(f' ip nhrp redirect', frrconfig)
self.assertIn(f' ip nhrp registration no-unique', frrconfig)
self.assertIn(f' ip nhrp shortcut', frrconfig)
self.assertIn(f' ip nhrp network-id {nhrp_networkid}', frrconfig)
self.assertIn(f' ip nhrp nhs {nhs_tunnelip} nbma {nhs_nbmaip}', frrconfig)
self.assertIn(f' ip nhrp map {map_tunnelip} {map_nbmaip}', frrconfig)
self.assertIn(f' tunnel protection vici profile dmvpn-{nhrp_profile}-{tunnel_if}-child',
frrconfig)
nftables_search_multicast = [
['chain VYOS_NHRP_MULTICAST_OUTPUT'],
['type filter hook output priority filter + 10; policy accept;'],
[f'oifname "{tunnel_if}"', 'ip daddr 224.0.0.0/24', 'counter', f'log group {multicat_log_group}'],
[f'oifname "{tunnel_if}"', 'ip daddr 224.0.0.0/24', 'counter', 'drop'],
['chain VYOS_NHRP_MULTICAST_FORWARD'],
['type filter hook output priority filter + 10; policy accept;'],
[f'oifname "{tunnel_if}"', 'ip daddr 224.0.0.0/4', 'counter', f'log group {multicat_log_group}'],
[f'oifname "{tunnel_if}"', 'ip daddr 224.0.0.0/4', 'counter', 'drop']
]
nftables_search_redirect = [
['chain VYOS_NHRP_REDIRECT_FORWARD'],
['type filter hook forward priority filter + 10; policy accept;'],
[f'iifname "{tunnel_if}" oifname "{tunnel_if}"', 'meter loglimit-0 size 65535 { ip daddr & 255.255.255.0 . ip saddr & 255.255.255.0 timeout 1m limit rate 4/minute burst 1 packets }', 'counter', f'log group {redirect_log_group}']
]
self.verify_nftables(nftables_search_multicast, 'ip vyos_nhrp_multicast')
self.verify_nftables(nftables_search_redirect, 'ip vyos_nhrp_redirect')
self.assertTrue(process_named_running(PROCESS_NAME))
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_openfabric.py b/smoketest/scripts/cli/test_protocols_openfabric.py
index 8cb131e1b..c61e47768 100644
--- a/smoketest/scripts/cli/test_protocols_openfabric.py
+++ b/smoketest/scripts/cli/test_protocols_openfabric.py
@@ -1,189 +1,186 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.utils.process import process_named_running
from vyos.frrender import openfabric_daemon
base_path = ['protocols', 'openfabric']
domain = 'VyOS'
net = '49.0001.1111.1111.1111.00'
dummy_if = 'dum1234'
address_families = ['ipv4', 'ipv6']
path = base_path + ['domain', domain]
class TestProtocolsOpenFabric(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
# call base-classes classmethod
super(TestProtocolsOpenFabric, cls).setUpClass()
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(openfabric_daemon)
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(openfabric_daemon))
def openfabric_base_config(self):
self.cli_set(['interfaces', 'dummy', dummy_if])
self.cli_set(base_path + ['net', net])
for family in address_families:
self.cli_set(path + ['interface', dummy_if, 'address-family', family])
def test_openfabric_01_router_params(self):
fabric_tier = '5'
lsp_gen_interval = '20'
self.cli_set(base_path)
# verify() - net id and domain name are mandatory
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.openfabric_base_config()
self.cli_set(path + ['log-adjacency-changes'])
self.cli_set(path + ['set-overload-bit'])
self.cli_set(path + ['fabric-tier', fabric_tier])
self.cli_set(path + ['lsp-gen-interval', lsp_gen_interval])
# Commit all changes
self.cli_commit()
# Verify all changes
- tmp = self.getFRRconfig(f'router openfabric {domain}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router openfabric {domain}', stop_section='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' log-adjacency-changes', tmp)
self.assertIn(f' set-overload-bit', tmp)
self.assertIn(f' fabric-tier {fabric_tier}', tmp)
self.assertIn(f' lsp-gen-interval {lsp_gen_interval}', tmp)
- tmp = self.getFRRconfig(f'interface {dummy_if}', endsection='^exit')
+ tmp = self.getFRRconfig(f'interface {dummy_if}', stop_section='^exit')
self.assertIn(f' ip router openfabric {domain}', tmp)
self.assertIn(f' ipv6 router openfabric {domain}', tmp)
def test_openfabric_02_loopback_interface(self):
interface = 'lo'
hello_interval = '100'
metric = '24478'
self.openfabric_base_config()
self.cli_set(path + ['interface', interface, 'address-family', 'ipv4'])
self.cli_set(path + ['interface', interface, 'hello-interval', hello_interval])
self.cli_set(path + ['interface', interface, 'metric', metric])
# Commit all changes
self.cli_commit()
# Verify FRR openfabric configuration
- tmp = self.getFRRconfig(f'router openfabric {domain}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router openfabric {domain}', stop_section='^exit')
self.assertIn(f'router openfabric {domain}', tmp)
self.assertIn(f' net {net}', tmp)
# Verify interface configuration
- tmp = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ tmp = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f' ip router openfabric {domain}', tmp)
# for lo interface 'openfabric passive' is implied
self.assertIn(f' openfabric passive', tmp)
self.assertIn(f' openfabric metric {metric}', tmp)
def test_openfabric_03_password(self):
password = 'foo'
self.openfabric_base_config()
self.cli_set(path + ['interface', dummy_if, 'password', 'plaintext-password', f'{password}-{dummy_if}'])
self.cli_set(path + ['interface', dummy_if, 'password', 'md5', f'{password}-{dummy_if}'])
# verify() - can not use both md5 and plaintext-password for password for the interface
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(path + ['interface', dummy_if, 'password', 'md5'])
self.cli_set(path + ['domain-password', 'plaintext-password', password])
self.cli_set(path + ['domain-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(path + ['domain-password', 'md5'])
# Commit all changes
self.cli_commit()
# Verify all changes
- tmp = self.getFRRconfig(f'router openfabric {domain}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router openfabric {domain}', stop_section='^exit')
self.assertIn(f' net {net}', tmp)
self.assertIn(f' domain-password clear {password}', tmp)
- tmp = self.getFRRconfig(f'interface {dummy_if}', endsection='^exit')
+ tmp = self.getFRRconfig(f'interface {dummy_if}', stop_section='^exit')
self.assertIn(f' openfabric password clear {password}-{dummy_if}', tmp)
def test_openfabric_multiple_domains(self):
domain_2 = 'VyOS_2'
interface = 'dum5678'
new_path = base_path + ['domain', domain_2]
self.openfabric_base_config()
# set same interface for 2 OpenFabric domains
self.cli_set(['interfaces', 'dummy', interface])
self.cli_set(new_path + ['interface', interface, 'address-family', 'ipv4'])
self.cli_set(path + ['interface', interface, 'address-family', 'ipv4'])
# verify() - same interface can be used only for one OpenFabric instance
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(path + ['interface', interface])
# Commit all changes
self.cli_commit()
# Verify FRR openfabric configuration
- tmp = self.getFRRconfig(f'router openfabric {domain}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router openfabric {domain}', stop_section='^exit')
self.assertIn(f'router openfabric {domain}', tmp)
self.assertIn(f' net {net}', tmp)
- tmp = self.getFRRconfig(f'router openfabric {domain_2}', endsection='^exit')
+ tmp = self.getFRRconfig(f'router openfabric {domain_2}', stop_section='^exit')
self.assertIn(f'router openfabric {domain_2}', tmp)
self.assertIn(f' net {net}', tmp)
# Verify interface configuration
- tmp = self.getFRRconfig(f'interface {dummy_if}', endsection='^exit')
+ tmp = self.getFRRconfig(f'interface {dummy_if}', stop_section='^exit')
self.assertIn(f' ip router openfabric {domain}', tmp)
self.assertIn(f' ipv6 router openfabric {domain}', tmp)
- tmp = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ tmp = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f' ip router openfabric {domain_2}', tmp)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py
index c5ada032f..2c7c5837a 100755
--- a/smoketest/scripts/cli/test_protocols_ospf.py
+++ b/smoketest/scripts/cli/test_protocols_ospf.py
@@ -1,617 +1,614 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 time import sleep
from base_vyostest_shim import VyOSUnitTestSHIM
-from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.frrender import ospf_daemon
from vyos.utils.process import process_named_running
from vyos.xml_ref import default_value
base_path = ['protocols', 'ospf']
route_map = 'foo-bar-baz10'
dummy_if = 'dum3562'
class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestProtocolsOSPF, cls).setUpClass()
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(ospf_daemon)
cls.cli_set(cls, ['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'route-map', route_map, 'rule', '20', 'action', 'permit'])
cls.cli_set(cls, ['interfaces', 'dummy', dummy_if])
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
@classmethod
def tearDownClass(cls):
cls.cli_delete(cls, ['policy', 'route-map', route_map])
cls.cli_delete(cls, ['interfaces', 'dummy', dummy_if])
super(TestProtocolsOSPF, cls).tearDownClass()
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertNotIn(f'router ospf', frrconfig)
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(ospf_daemon))
def test_ospf_01_defaults(self):
# commit changes
self.cli_set(base_path)
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' auto-cost reference-bandwidth 100', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
def test_ospf_02_simple(self):
router_id = '127.0.0.1'
abr_type = 'ibm'
bandwidth = '1000'
metric = '123'
self.cli_set(base_path + ['auto-cost', 'reference-bandwidth', bandwidth])
self.cli_set(base_path + ['parameters', 'router-id', router_id])
self.cli_set(base_path + ['parameters', 'abr-type', abr_type])
self.cli_set(base_path + ['parameters', 'opaque-lsa'])
self.cli_set(base_path + ['parameters', 'rfc1583-compatibility'])
self.cli_set(base_path + ['log-adjacency-changes', 'detail'])
self.cli_set(base_path + ['default-metric', metric])
self.cli_set(base_path + ['passive-interface', 'default'])
self.cli_set(base_path + ['area', '10', 'area-type', 'stub'])
self.cli_set(base_path + ['area', '10', 'network', '10.0.0.0/16'])
self.cli_set(base_path + ['area', '10', 'range', '10.0.1.0/24'])
self.cli_set(base_path + ['area', '10', 'range', '10.0.2.0/24', 'not-advertise'])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' compatible rfc1583', frrconfig)
self.assertIn(f' auto-cost reference-bandwidth {bandwidth}', frrconfig)
self.assertIn(f' ospf router-id {router_id}', frrconfig)
self.assertIn(f' ospf abr-type {abr_type}', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
self.assertIn(f' capability opaque', frrconfig)
self.assertIn(f' default-metric {metric}', frrconfig)
self.assertIn(f' passive-interface default', frrconfig)
self.assertIn(f' area 10 stub', frrconfig)
self.assertIn(f' network 10.0.0.0/16 area 10', frrconfig)
self.assertIn(f' area 10 range 10.0.1.0/24', frrconfig)
self.assertNotIn(f' area 10 range 10.0.1.0/24 not-advertise', frrconfig)
self.assertIn(f' area 10 range 10.0.2.0/24 not-advertise', frrconfig)
def test_ospf_03_access_list(self):
acl = '100'
seq = '10'
protocols = ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static']
self.cli_set(['policy', 'access-list', acl, 'rule', seq, 'action', 'permit'])
self.cli_set(['policy', 'access-list', acl, 'rule', seq, 'source', 'any'])
self.cli_set(['policy', 'access-list', acl, 'rule', seq, 'destination', 'any'])
for ptotocol in protocols:
self.cli_set(base_path + ['access-list', acl, 'export', ptotocol])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
for ptotocol in protocols:
self.assertIn(f' distribute-list {acl} out {ptotocol}', frrconfig) # defaults
self.cli_delete(['policy', 'access-list', acl])
def test_ospf_04_default_originate(self):
seq = '100'
metric = '50'
metric_type = '1'
self.cli_set(base_path + ['default-information', 'originate', 'metric', metric])
self.cli_set(base_path + ['default-information', 'originate', 'metric-type', metric_type])
self.cli_set(base_path + ['default-information', 'originate', 'route-map', route_map])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
self.assertIn(f' default-information originate metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
# Now set 'always'
self.cli_set(base_path + ['default-information', 'originate', 'always'])
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f' default-information originate always metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
def test_ospf_05_options(self):
global_distance = '128'
intra_area = '100'
inter_area = '110'
external = '120'
on_startup = '30'
on_shutdown = '60'
refresh = '50'
aggregation_timer = '100'
summary_nets = {
'10.0.1.0/24' : {},
'10.0.2.0/24' : {'tag' : '50'},
'10.0.3.0/24' : {'no_advertise' : {}},
}
self.cli_set(base_path + ['distance', 'global', global_distance])
self.cli_set(base_path + ['distance', 'ospf', 'external', external])
self.cli_set(base_path + ['distance', 'ospf', 'intra-area', intra_area])
self.cli_set(base_path + ['max-metric', 'router-lsa', 'on-startup', on_startup])
self.cli_set(base_path + ['max-metric', 'router-lsa', 'on-shutdown', on_shutdown])
self.cli_set(base_path + ['mpls-te', 'enable'])
self.cli_set(base_path + ['refresh', 'timers', refresh])
self.cli_set(base_path + ['aggregation', 'timer', aggregation_timer])
for summary, summary_options in summary_nets.items():
self.cli_set(base_path + ['summary-address', summary])
if 'tag' in summary_options:
self.cli_set(base_path + ['summary-address', summary, 'tag', summary_options['tag']])
if 'no_advertise' in summary_options:
self.cli_set(base_path + ['summary-address', summary, 'no-advertise'])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' mpls-te on', frrconfig)
self.assertIn(f' mpls-te router-address 0.0.0.0', frrconfig) # default
self.assertIn(f' distance {global_distance}', frrconfig)
self.assertIn(f' distance ospf intra-area {intra_area} external {external}', frrconfig)
self.assertIn(f' max-metric router-lsa on-startup {on_startup}', frrconfig)
self.assertIn(f' max-metric router-lsa on-shutdown {on_shutdown}', frrconfig)
self.assertIn(f' refresh timer {refresh}', frrconfig)
self.assertIn(f' aggregation timer {aggregation_timer}', frrconfig)
for summary, summary_options in summary_nets.items():
self.assertIn(f' summary-address {summary}', frrconfig)
if 'tag' in summary_options:
tag = summary_options['tag']
self.assertIn(f' summary-address {summary} tag {tag}', frrconfig)
if 'no_advertise' in summary_options:
self.assertIn(f' summary-address {summary} no-advertise', frrconfig)
# enable inter-area
self.cli_set(base_path + ['distance', 'ospf', 'inter-area', inter_area])
self.cli_commit()
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f' distance ospf intra-area {intra_area} inter-area {inter_area} external {external}', frrconfig)
# https://github.com/FRRouting/frr/issues/17011
# We need to wait on_shutdown time, until the OSPF process is removed from the CLI
# otherwise the test in tearDown() will fail
self.cli_delete(base_path)
self.cli_commit()
sleep(int(on_shutdown) + 5) # additional grace period of 5 seconds
def test_ospf_06_neighbor(self):
priority = '10'
poll_interval = '20'
neighbors = ['1.1.1.1', '2.2.2.2', '3.3.3.3']
for neighbor in neighbors:
self.cli_set(base_path + ['neighbor', neighbor, 'priority', priority])
self.cli_set(base_path + ['neighbor', neighbor, 'poll-interval', poll_interval])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
for neighbor in neighbors:
self.assertIn(f' neighbor {neighbor} priority {priority} poll-interval {poll_interval}', frrconfig) # default
def test_ospf_07_redistribute(self):
metric = '15'
metric_type = '1'
table_id = '21'
redistribute = [
'babel',
'bgp',
'connected',
'isis',
'kernel',
'nhrp',
'rip',
'static',
'table',
]
for protocol in redistribute:
redistr_base = base_path + ['redistribute', protocol]
if protocol == 'table':
redistr_base += [table_id]
self.cli_set(redistr_base + ['metric', metric])
self.cli_set(redistr_base + ['route-map', route_map])
self.cli_set(redistr_base + ['metric-type', metric_type])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
for protocol in redistribute:
if protocol == 'table':
protocolstr = f'table-direct {table_id}'
else:
protocolstr = protocol
self.assertIn(
f' redistribute {protocolstr} metric {metric} metric-type {metric_type} route-map {route_map}',
frrconfig,
)
def test_ospf_08_virtual_link(self):
networks = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']
area = '10'
shortcut = 'enable'
virtual_link = '192.0.2.1'
hello = '6'
retransmit = '5'
transmit = '5'
dead = '40'
window_default = default_value(base_path + ['area', area, 'virtual-link', virtual_link, 'retransmit-window'])
self.cli_set(base_path + ['area', area, 'shortcut', shortcut])
self.cli_set(base_path + ['area', area, 'virtual-link', virtual_link, 'hello-interval', hello])
self.cli_set(base_path + ['area', area, 'virtual-link', virtual_link, 'retransmit-interval', retransmit])
self.cli_set(base_path + ['area', area, 'virtual-link', virtual_link, 'transmit-delay', transmit])
self.cli_set(base_path + ['area', area, 'virtual-link', virtual_link, 'dead-interval', dead])
for network in networks:
self.cli_set(base_path + ['area', area, 'network', network])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' area {area} shortcut {shortcut}', frrconfig)
self.assertIn(f' area {area} virtual-link {virtual_link} hello-interval {hello} retransmit-interval {retransmit} retransmit-window {window_default} transmit-delay {transmit} dead-interval {dead}', frrconfig)
for network in networks:
self.assertIn(f' network {network} area {area}', frrconfig)
def test_ospf_09_interface_configuration(self):
interfaces = Section.interfaces('ethernet')
password = 'vyos1234'
bandwidth = '10000'
cost = '150'
network = 'point-to-point'
priority = '200'
bfd_profile = 'vyos-test'
self.cli_set(base_path + ['passive-interface', 'default'])
for interface in interfaces:
base_interface = base_path + ['interface', interface]
self.cli_set(base_interface + ['authentication', 'plaintext-password', password])
self.cli_set(base_interface + ['bandwidth', bandwidth])
self.cli_set(base_interface + ['bfd', 'profile', bfd_profile])
self.cli_set(base_interface + ['cost', cost])
self.cli_set(base_interface + ['mtu-ignore'])
self.cli_set(base_interface + ['network', network])
self.cli_set(base_interface + ['priority', priority])
self.cli_set(base_interface + ['passive', 'disable'])
# commit changes
self.cli_commit()
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' passive-interface default', frrconfig)
for interface in interfaces:
# Can not use daemon for getFRRconfig() as bandwidth parameter belongs to zebra process
- config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ip ospf authentication-key {password}', config)
self.assertIn(f' ip ospf bfd', config)
self.assertIn(f' ip ospf bfd profile {bfd_profile}', config)
self.assertIn(f' ip ospf cost {cost}', config)
self.assertIn(f' ip ospf mtu-ignore', config)
self.assertIn(f' ip ospf network {network}', config)
self.assertIn(f' ip ospf priority {priority}', config)
self.assertIn(f' no ip ospf passive', config)
self.assertIn(f' bandwidth {bandwidth}', config)
# T5467: Remove interface from OSPF process and VRF
self.cli_delete(base_path + ['interface'])
self.cli_commit()
for interface in interfaces:
# T5467: It must also be removed from FRR config
- frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertNotIn(f'interface {interface}', frrconfig)
# There should be no OSPF related command at all under the interface
self.assertNotIn(f' ip ospf', frrconfig)
def test_ospf_11_interface_area(self):
area = '0'
interfaces = Section.interfaces('ethernet')
self.cli_set(base_path + ['area', area, 'network', '10.0.0.0/8'])
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'area', area])
# we can not have bot area network and interface area set
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(base_path + ['area', area, 'network'])
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ip ospf area {area}', config)
def test_ospf_12_vrfs(self):
# It is safe to assume that when the basic VRF test works, all
# other OSPF related features work, as we entirely inherit the CLI
# templates and Jinja2 FRR template.
table = '1000'
vrf = 'blue'
vrf_base = ['vrf', 'name', vrf]
vrf_iface = 'eth1'
area = '1'
self.cli_set(vrf_base + ['table', table])
self.cli_set(vrf_base + ['protocols', 'ospf', 'interface', vrf_iface, 'area', area])
self.cli_set(['interfaces', 'ethernet', vrf_iface, 'vrf', vrf])
# Also set a default VRF OSPF config
self.cli_set(base_path)
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' auto-cost reference-bandwidth 100', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
- frrconfig = self.getFRRconfig(f'router ospf vrf {vrf}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router ospf vrf {vrf}', stop_section='^exit')
self.assertIn(f'router ospf vrf {vrf}', frrconfig)
self.assertIn(f' auto-cost reference-bandwidth 100', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
- frrconfig = self.getFRRconfig(f'interface {vrf_iface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {vrf_iface}', stop_section='^exit')
self.assertIn(f'interface {vrf_iface}', frrconfig)
self.assertIn(f' ip ospf area {area}', frrconfig)
# T5467: Remove interface from OSPF process and VRF
self.cli_delete(vrf_base + ['protocols', 'ospf', 'interface'])
self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf'])
self.cli_commit()
# T5467: It must also be removed from FRR config
- frrconfig = self.getFRRconfig(f'interface {vrf_iface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {vrf_iface}', stop_section='^exit')
self.assertNotIn(f'interface {vrf_iface}', frrconfig)
# There should be no OSPF related command at all under the interface
self.assertNotIn(f' ip ospf', frrconfig)
# cleanup
self.cli_delete(['vrf', 'name', vrf])
self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf'])
def test_ospf_13_export_list(self):
# Verify explort-list works on ospf-area
acl = '100'
seq = '10'
area = '0.0.0.10'
network = '10.0.0.0/8'
self.cli_set(['policy', 'access-list', acl, 'rule', seq, 'action', 'permit'])
self.cli_set(['policy', 'access-list', acl, 'rule', seq, 'source', 'any'])
self.cli_set(['policy', 'access-list', acl, 'rule', seq, 'destination', 'any'])
self.cli_set(base_path + ['area', area, 'network', network])
self.cli_set(base_path + ['area', area, 'export-list', acl])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # default
self.assertIn(f' network {network} area {area}', frrconfig)
self.assertIn(f' area {area} export-list {acl}', frrconfig)
def test_ospf_14_segment_routing_configuration(self):
global_block_low = "300"
global_block_high = "399"
local_block_low = "400"
local_block_high = "499"
maximum_stack_size = '5'
prefix_one = '192.168.0.1/32'
prefix_two = '192.168.0.2/32'
prefix_one_value = '1'
prefix_two_value = '2'
self.cli_set(base_path + ['interface', dummy_if])
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'])
# Commit all changes
self.cli_commit()
# Verify all changes
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f' segment-routing on', frrconfig)
self.assertIn(f' segment-routing global-block {global_block_low} {global_block_high} local-block {local_block_low} {local_block_high}', frrconfig)
self.assertIn(f' segment-routing node-msd {maximum_stack_size}', frrconfig)
self.assertIn(f' segment-routing prefix {prefix_one} index {prefix_one_value} explicit-null', frrconfig)
self.assertIn(f' segment-routing prefix {prefix_two} index {prefix_two_value} no-php-flag', frrconfig)
def test_ospf_15_ldp_sync(self):
holddown = "500"
interfaces = Section.interfaces('ethernet')
self.cli_set(base_path + ['interface', dummy_if])
self.cli_set(base_path + ['ldp-sync', 'holddown', holddown])
# Commit main OSPF changes
self.cli_commit()
# Verify main OSPF changes
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig)
self.assertIn(f' mpls ldp-sync holddown {holddown}', frrconfig)
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'holddown', holddown])
# Commit interface changes for holddown
self.cli_commit()
for interface in interfaces:
# Verify interface changes for holddown
- config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ip ospf dead-interval 40', config)
self.assertIn(f' ip ospf mpls ldp-sync', config)
self.assertIn(f' ip ospf mpls ldp-sync holddown {holddown}', config)
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'disable'])
# Commit interface changes for disable
self.cli_commit()
for interface in interfaces:
# Verify interface changes for disable
- config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ip ospf dead-interval 40', config)
self.assertNotIn(f' ip ospf mpls ldp-sync', config)
def test_ospf_16_graceful_restart(self):
period = '300'
supported_grace_time = '400'
router_ids = ['192.0.2.1', '192.0.2.2']
self.cli_set(base_path + ['capability', 'opaque'])
self.cli_set(base_path + ['graceful-restart', 'grace-period', period])
self.cli_set(base_path + ['graceful-restart', 'helper', 'planned-only'])
self.cli_set(base_path + ['graceful-restart', 'helper', 'no-strict-lsa-checking'])
self.cli_set(base_path + ['graceful-restart', 'helper', 'supported-grace-time', supported_grace_time])
for router_id in router_ids:
self.cli_set(base_path + ['graceful-restart', 'helper', 'enable', 'router-id', router_id])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' capability opaque', frrconfig)
self.assertIn(f' graceful-restart grace-period {period}', frrconfig)
self.assertIn(f' graceful-restart helper planned-only', frrconfig)
self.assertIn(f' no graceful-restart helper strict-lsa-checking', frrconfig)
self.assertIn(f' graceful-restart helper supported-grace-time {supported_grace_time}', frrconfig)
for router_id in router_ids:
self.assertIn(f' graceful-restart helper enable {router_id}', frrconfig)
def test_ospf_17_duplicate_area_network(self):
area0 = '0'
area1 = '1'
network = '10.0.0.0/8'
self.cli_set(base_path + ['area', area0, 'network', network])
# we can not have the same network defined on two areas
self.cli_set(base_path + ['area', area1, 'network', network])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(base_path + ['area', area0])
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit', empty_retry=60)
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' network {network} area {area1}', frrconfig)
def test_ospf_18_area_translate_no_summary(self):
area = '11'
area_type = 'nssa'
network = '100.64.0.0/10'
self.cli_set(base_path + ['area', area, 'area-type', area_type, 'no-summary'])
self.cli_set(base_path + ['area', area, 'area-type', area_type, 'translate', 'never'])
self.cli_set(base_path + ['area', area, 'network', network])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf', stop_section='^exit')
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' area {area} {area_type} translate-never no-summary', frrconfig)
self.assertIn(f' network {network} area {area}', frrconfig)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_ospfv3.py b/smoketest/scripts/cli/test_protocols_ospfv3.py
index 1041ad52c..07da105ba 100755
--- a/smoketest/scripts/cli/test_protocols_ospfv3.py
+++ b/smoketest/scripts/cli/test_protocols_ospfv3.py
@@ -1,345 +1,342 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.frrender import ospf6_daemon
from vyos.utils.process import process_named_running
base_path = ['protocols', 'ospfv3']
route_map = 'foo-bar-baz-0815'
router_id = '192.0.2.1'
default_area = '0'
class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestProtocolsOSPFv3, cls).setUpClass()
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(ospf6_daemon)
cls.cli_set(cls, ['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'route-map', route_map, 'rule', '20', 'action', 'permit'])
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
@classmethod
def tearDownClass(cls):
cls.cli_delete(cls, ['policy', 'route-map', route_map])
super(TestProtocolsOSPFv3, cls).tearDownClass()
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf6', stop_section='^exit')
self.assertNotIn(f'router ospf6', frrconfig)
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(ospf6_daemon))
def test_ospfv3_01_basic(self):
seq = '10'
prefix = '2001:db8::/32'
acl_name = 'foo-acl-100'
self.cli_set(['policy', 'access-list6', acl_name, 'rule', seq, 'action', 'permit'])
self.cli_set(['policy', 'access-list6', acl_name, 'rule', seq, 'source', 'any'])
self.cli_set(base_path + ['parameters', 'router-id', router_id])
self.cli_set(base_path + ['area', default_area, 'range', prefix, 'advertise'])
self.cli_set(base_path + ['area', default_area, 'export-list', acl_name])
self.cli_set(base_path + ['area', default_area, 'import-list', acl_name])
interfaces = Section.interfaces('ethernet')
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'area', default_area])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf6', stop_section='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' area {default_area} range {prefix}', frrconfig)
self.assertIn(f' ospf6 router-id {router_id}', frrconfig)
self.assertIn(f' area {default_area} import-list {acl_name}', frrconfig)
self.assertIn(f' area {default_area} export-list {acl_name}', frrconfig)
for interface in interfaces:
- if_config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ if_config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'ipv6 ospf6 area {default_area}', if_config)
self.cli_delete(['policy', 'access-list6', acl_name])
def test_ospfv3_02_distance(self):
dist_global = '200'
dist_external = '110'
dist_inter_area = '120'
dist_intra_area = '130'
self.cli_set(base_path + ['distance', 'global', dist_global])
self.cli_set(base_path + ['distance', 'ospfv3', 'external', dist_external])
self.cli_set(base_path + ['distance', 'ospfv3', 'inter-area', dist_inter_area])
self.cli_set(base_path + ['distance', 'ospfv3', 'intra-area', dist_intra_area])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf6', stop_section='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' distance {dist_global}', frrconfig)
self.assertIn(f' distance ospf6 intra-area {dist_intra_area} inter-area {dist_inter_area} external {dist_external}', frrconfig)
def test_ospfv3_03_redistribute(self):
metric = '15'
metric_type = '1'
route_map = 'foo-bar'
route_map_seq = '10'
redistribute = ['babel', 'bgp', 'connected', 'isis', 'kernel', 'ripng', 'static']
self.cli_set(['policy', 'route-map', route_map, 'rule', route_map_seq, 'action', 'permit'])
for protocol in redistribute:
self.cli_set(base_path + ['redistribute', protocol, 'metric', metric])
self.cli_set(base_path + ['redistribute', protocol, 'route-map', route_map])
self.cli_set(base_path + ['redistribute', protocol, 'metric-type', metric_type])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf6', stop_section='^exit')
self.assertIn(f'router ospf6', frrconfig)
for protocol in redistribute:
self.assertIn(f' redistribute {protocol} metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
def test_ospfv3_04_interfaces(self):
bfd_profile = 'vyos-ipv6'
self.cli_set(base_path + ['parameters', 'router-id', router_id])
self.cli_set(base_path + ['area', default_area])
cost = '100'
priority = '10'
interfaces = Section.interfaces('ethernet')
for interface in interfaces:
if_base = base_path + ['interface', interface]
self.cli_set(if_base + ['bfd', 'profile', bfd_profile])
self.cli_set(if_base + ['cost', cost])
self.cli_set(if_base + ['instance-id', '0'])
self.cli_set(if_base + ['mtu-ignore'])
self.cli_set(if_base + ['network', 'point-to-point'])
self.cli_set(if_base + ['passive'])
self.cli_set(if_base + ['priority', priority])
cost = str(int(cost) + 10)
priority = str(int(priority) + 5)
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf6', stop_section='^exit')
self.assertIn(f'router ospf6', frrconfig)
cost = '100'
priority = '10'
for interface in interfaces:
- if_config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ if_config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', if_config)
self.assertIn(f' ipv6 ospf6 bfd', if_config)
self.assertIn(f' ipv6 ospf6 bfd profile {bfd_profile}', if_config)
self.assertIn(f' ipv6 ospf6 cost {cost}', if_config)
self.assertIn(f' ipv6 ospf6 mtu-ignore', if_config)
self.assertIn(f' ipv6 ospf6 network point-to-point', if_config)
self.assertIn(f' ipv6 ospf6 passive', if_config)
self.assertIn(f' ipv6 ospf6 priority {priority}', if_config)
cost = str(int(cost) + 10)
priority = str(int(priority) + 5)
# Cleanup interfaces
self.cli_delete(base_path + ['interface'])
self.cli_commit()
for interface in interfaces:
- if_config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ if_config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
# There should be no OSPF6 configuration at all after interface removal
self.assertNotIn(f' ipv6 ospf6', if_config)
def test_ospfv3_05_area_stub(self):
area_stub = '23'
area_stub_nosum = '26'
self.cli_set(base_path + ['area', area_stub, 'area-type', 'stub'])
self.cli_set(base_path + ['area', area_stub_nosum, 'area-type', 'stub', 'no-summary'])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf6', stop_section='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' area {area_stub} stub', frrconfig)
self.assertIn(f' area {area_stub_nosum} stub no-summary', frrconfig)
def test_ospfv3_06_area_nssa(self):
area_nssa = '1.1.1.1'
area_nssa_nosum = '2.2.2.2'
area_nssa_default = '3.3.3.3'
self.cli_set(base_path + ['area', area_nssa, 'area-type', 'nssa'])
self.cli_set(base_path + ['area', area_nssa, 'area-type', 'stub'])
# can only set one area-type per OSPFv3 area
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(base_path + ['area', area_nssa, 'area-type', 'stub'])
self.cli_set(base_path + ['area', area_nssa_nosum, 'area-type', 'nssa', 'no-summary'])
self.cli_set(base_path + ['area', area_nssa_nosum, 'area-type', 'nssa', 'default-information-originate'])
self.cli_set(base_path + ['area', area_nssa_default, 'area-type', 'nssa', 'default-information-originate'])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf6', stop_section='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' area {area_nssa} nssa', frrconfig)
self.assertIn(f' area {area_nssa_nosum} nssa default-information-originate no-summary', frrconfig)
self.assertIn(f' area {area_nssa_default} nssa default-information-originate', frrconfig)
def test_ospfv3_07_default_originate(self):
seq = '100'
metric = '50'
metric_type = '1'
self.cli_set(base_path + ['default-information', 'originate', 'metric', metric])
self.cli_set(base_path + ['default-information', 'originate', 'metric-type', metric_type])
self.cli_set(base_path + ['default-information', 'originate', 'route-map', route_map])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf6', stop_section='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' default-information originate metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
# Now set 'always'
self.cli_set(base_path + ['default-information', 'originate', 'always'])
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf6', stop_section='^exit')
self.assertIn(f' default-information originate always metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
def test_ospfv3_08_vrfs(self):
# It is safe to assume that when the basic VRF test works, all
# other OSPF related features work, as we entirely inherit the CLI
# templates and Jinja2 FRR template.
table = '1000'
vrf = 'blue'
vrf_base = ['vrf', 'name', vrf]
vrf_iface = 'eth1'
router_id = '1.2.3.4'
router_id_vrf = '1.2.3.5'
self.cli_set(vrf_base + ['table', table])
self.cli_set(vrf_base + ['protocols', 'ospfv3', 'interface', vrf_iface, 'bfd'])
self.cli_set(vrf_base + ['protocols', 'ospfv3', 'parameters', 'router-id', router_id_vrf])
self.cli_set(['interfaces', 'ethernet', vrf_iface, 'vrf', vrf])
# Also set a default VRF OSPF config
self.cli_set(base_path + ['parameters', 'router-id', router_id])
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf6', stop_section='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' ospf6 router-id {router_id}', frrconfig)
- frrconfig = self.getFRRconfig(f'interface {vrf_iface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {vrf_iface}', stop_section='^exit')
self.assertIn(f'interface {vrf_iface}', frrconfig)
self.assertIn(f' ipv6 ospf6 bfd', frrconfig)
- frrconfig = self.getFRRconfig(f'router ospf6 vrf {vrf}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'router ospf6 vrf {vrf}', stop_section='^exit')
self.assertIn(f'router ospf6 vrf {vrf}', frrconfig)
self.assertIn(f' ospf6 router-id {router_id_vrf}', frrconfig)
# T5467: Remove interface from OSPF process and VRF
self.cli_delete(vrf_base + ['protocols', 'ospfv3', 'interface'])
self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf'])
self.cli_commit()
# T5467: It must also be removed from FRR config
- frrconfig = self.getFRRconfig(f'interface {vrf_iface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {vrf_iface}', stop_section='^exit')
self.assertNotIn(f'interface {vrf_iface}', frrconfig)
# There should be no OSPF related command at all under the interface
self.assertNotIn(f' ipv6 ospf6', frrconfig)
# cleanup
self.cli_delete(['vrf', 'name', vrf])
self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf'])
def test_ospfv3_09_graceful_restart(self):
period = '300'
supported_grace_time = '400'
router_ids = ['192.0.2.1', '192.0.2.2']
self.cli_set(base_path + ['graceful-restart', 'grace-period', period])
self.cli_set(base_path + ['graceful-restart', 'helper', 'planned-only'])
self.cli_set(base_path + ['graceful-restart', 'helper', 'lsa-check-disable'])
self.cli_set(base_path + ['graceful-restart', 'helper', 'supported-grace-time', supported_grace_time])
for router_id in router_ids:
self.cli_set(base_path + ['graceful-restart', 'helper', 'enable', 'router-id', router_id])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ospf6', stop_section='^exit')
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' graceful-restart grace-period {period}', frrconfig)
self.assertIn(f' graceful-restart helper planned-only', frrconfig)
self.assertIn(f' graceful-restart helper lsa-check-disable', frrconfig)
self.assertIn(f' graceful-restart helper supported-grace-time {supported_grace_time}', frrconfig)
for router_id in router_ids:
self.assertIn(f' graceful-restart helper enable {router_id}', frrconfig)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_pim.py b/smoketest/scripts/cli/test_protocols_pim.py
index 7702c5de4..780d4af23 100755
--- a/smoketest/scripts/cli/test_protocols_pim.py
+++ b/smoketest/scripts/cli/test_protocols_pim.py
@@ -1,203 +1,200 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.frrender import pim_daemon
from vyos.ifconfig import Section
from vyos.utils.process import process_named_running
base_path = ['protocols', 'pim']
class TestProtocolsPIM(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
# call base-classes classmethod
super(TestProtocolsPIM, cls).setUpClass()
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
# pimd process must be running
self.assertTrue(process_named_running(pim_daemon))
self.cli_delete(base_path)
self.cli_commit()
# pimd process must be stopped by now
self.assertFalse(process_named_running(pim_daemon))
def test_01_pim_basic(self):
rp = '127.0.0.1'
group = '224.0.0.0/4'
hello = '100'
dr_priority = '64'
self.cli_set(base_path + ['rp', 'address', rp, 'group', group])
interfaces = Section.interfaces('ethernet')
for interface in interfaces:
self.cli_set(base_path + ['interface', interface , 'bfd'])
self.cli_set(base_path + ['interface', interface , 'dr-priority', dr_priority])
self.cli_set(base_path + ['interface', interface , 'hello', hello])
self.cli_set(base_path + ['interface', interface , 'no-bsm'])
self.cli_set(base_path + ['interface', interface , 'no-unicast-bsm'])
self.cli_set(base_path + ['interface', interface , 'passive'])
# commit changes
self.cli_commit()
# Verify FRR pimd configuration
- frrconfig = self.getFRRconfig('router pim', endsection='^exit')
+ frrconfig = self.getFRRconfig('router pim', stop_section='^exit')
self.assertIn(f' rp {rp} {group}', frrconfig)
for interface in interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', frrconfig)
self.assertIn(f' ip pim', frrconfig)
self.assertIn(f' ip pim bfd', frrconfig)
self.assertIn(f' ip pim drpriority {dr_priority}', frrconfig)
self.assertIn(f' ip pim hello {hello}', frrconfig)
self.assertIn(f' no ip pim bsm', frrconfig)
self.assertIn(f' no ip pim unicast-bsm', frrconfig)
self.assertIn(f' ip pim passive', frrconfig)
self.cli_commit()
def test_02_pim_advanced(self):
rp = '127.0.0.2'
group = '224.0.0.0/4'
join_prune_interval = '123'
rp_keep_alive_timer = '190'
keep_alive_timer = '180'
packets = '10'
prefix_list = 'pim-test'
register_suppress_time = '300'
self.cli_set(base_path + ['rp', 'address', rp, 'group', group])
self.cli_set(base_path + ['rp', 'keep-alive-timer', rp_keep_alive_timer])
self.cli_set(base_path + ['ecmp', 'rebalance'])
self.cli_set(base_path + ['join-prune-interval', join_prune_interval])
self.cli_set(base_path + ['keep-alive-timer', keep_alive_timer])
self.cli_set(base_path + ['packets', packets])
self.cli_set(base_path + ['register-accept-list', 'prefix-list', prefix_list])
self.cli_set(base_path + ['register-suppress-time', register_suppress_time])
self.cli_set(base_path + ['no-v6-secondary'])
self.cli_set(base_path + ['spt-switchover', 'infinity-and-beyond', 'prefix-list', prefix_list])
self.cli_set(base_path + ['ssm', 'prefix-list', prefix_list])
# check validate() - PIM require defined interfaces!
with self.assertRaises(ConfigSessionError):
self.cli_commit()
interfaces = Section.interfaces('ethernet')
for interface in interfaces:
self.cli_set(base_path + ['interface', interface])
# commit changes
self.cli_commit()
# Verify FRR pimd configuration
- frrconfig = self.getFRRconfig('router pim', endsection='^exit')
+ frrconfig = self.getFRRconfig('router pim', stop_section='^exit')
self.assertIn(f' no send-v6-secondary', frrconfig)
self.assertIn(f' rp {rp} {group}', frrconfig)
self.assertIn(f' register-suppress-time {register_suppress_time}', frrconfig)
self.assertIn(f' join-prune-interval {join_prune_interval}', frrconfig)
self.assertIn(f' packets {packets}', frrconfig)
self.assertIn(f' keep-alive-timer {keep_alive_timer}', frrconfig)
self.assertIn(f' rp keep-alive-timer {rp_keep_alive_timer}', frrconfig)
self.assertIn(f' ssm prefix-list {prefix_list}', frrconfig)
self.assertIn(f' register-accept-list {prefix_list}', frrconfig)
self.assertIn(f' spt-switchover infinity-and-beyond prefix-list {prefix_list}', frrconfig)
self.assertIn(f' ecmp rebalance', frrconfig)
def test_03_pim_igmp_proxy(self):
igmp_proxy = ['protocols', 'igmp-proxy']
rp = '127.0.0.1'
group = '224.0.0.0/4'
self.cli_set(base_path)
self.cli_set(igmp_proxy)
# check validate() - can not set both IGMP proxy and PIM
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(igmp_proxy)
self.cli_set(base_path + ['rp', 'address', rp, 'group', group])
interfaces = Section.interfaces('ethernet')
for interface in interfaces:
self.cli_set(base_path + ['interface', interface , 'bfd'])
# commit changes
self.cli_commit()
def test_04_igmp(self):
watermark_warning = '2000'
query_interval = '1000'
query_max_response_time = '200'
version = '2'
igmp_join = {
'224.1.1.1' : { 'source' : ['1.1.1.1', '2.2.2.2', '3.3.3.3'] },
'224.1.2.2' : { 'source' : [] },
'224.1.3.3' : {},
}
self.cli_set(base_path + ['igmp', 'watermark-warning', watermark_warning])
interfaces = Section.interfaces('ethernet')
for interface in interfaces:
self.cli_set(base_path + ['interface', interface , 'igmp', 'version', version])
self.cli_set(base_path + ['interface', interface , 'igmp', 'query-interval', query_interval])
self.cli_set(base_path + ['interface', interface , 'igmp', 'query-max-response-time', query_max_response_time])
for join, join_config in igmp_join.items():
self.cli_set(base_path + ['interface', interface , 'igmp', 'join', join])
if 'source' in join_config:
for source in join_config['source']:
self.cli_set(base_path + ['interface', interface , 'igmp', 'join', join, 'source-address', source])
self.cli_commit()
frrconfig = self.getFRRconfig()
self.assertIn(f'ip igmp watermark-warn {watermark_warning}', frrconfig)
for interface in interfaces:
- frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', frrconfig)
self.assertIn(f' ip igmp', frrconfig)
self.assertIn(f' ip igmp version {version}', frrconfig)
self.assertIn(f' ip igmp query-interval {query_interval}', frrconfig)
self.assertIn(f' ip igmp query-max-response-time {query_max_response_time}', frrconfig)
for join, join_config in igmp_join.items():
if 'source' in join_config:
for source in join_config['source']:
self.assertIn(f' ip igmp join-group {join} {source}', frrconfig)
else:
self.assertIn(f' ip igmp join-group {join}', frrconfig)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_pim6.py b/smoketest/scripts/cli/test_protocols_pim6.py
index 2e1ac6d6e..f0ad85007 100755
--- a/smoketest/scripts/cli/test_protocols_pim6.py
+++ b/smoketest/scripts/cli/test_protocols_pim6.py
@@ -1,150 +1,147 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
-
from vyos.configsession import ConfigSessionError
+
from vyos.ifconfig import Section
from vyos.frrender import pim6_daemon
from vyos.utils.process import process_named_running
base_path = ['protocols', 'pim6']
class TestProtocolsPIMv6(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
# call base-classes classmethod
super(TestProtocolsPIMv6, cls).setUpClass()
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(pim6_daemon)
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(pim6_daemon))
def test_pim6_01_mld_simple(self):
# commit changes
interfaces = Section.interfaces('ethernet')
for interface in interfaces:
self.cli_set(base_path + ['interface', interface])
self.cli_commit()
# Verify FRR pim6d configuration
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ipv6 mld', config)
self.assertNotIn(f' ipv6 mld version 1', config)
# Change to MLD version 1
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'mld', 'version', '1'])
self.cli_commit()
# Verify FRR pim6d configuration
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ipv6 mld', config)
self.assertIn(f' ipv6 mld version 1', config)
def test_pim6_02_mld_join(self):
interfaces = Section.interfaces('ethernet')
# Use an invalid multicast group address
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'mld', 'join', 'fd00::1234'])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(base_path + ['interface'])
# Use a valid multicast group address
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'mld', 'join', 'ff18::1234'])
self.cli_commit()
# Verify FRR pim6d configuration
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ipv6 mld join-group ff18::1234', config)
# Join a source-specific multicast group
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'mld', 'join', 'ff38::5678', 'source', '2001:db8::5678'])
self.cli_commit()
# Verify FRR pim6d configuration
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ipv6 mld join-group ff38::5678 2001:db8::5678', config)
def test_pim6_03_basic(self):
interfaces = Section.interfaces('ethernet')
join_prune_interval = '123'
keep_alive_timer = '77'
packets = '5'
register_suppress_time = '99'
dr_priority = '100'
hello = '50'
self.cli_set(base_path + ['join-prune-interval', join_prune_interval])
self.cli_set(base_path + ['keep-alive-timer', keep_alive_timer])
self.cli_set(base_path + ['packets', packets])
self.cli_set(base_path + ['register-suppress-time', register_suppress_time])
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'dr-priority', dr_priority])
self.cli_set(base_path + ['interface', interface, 'hello', hello])
self.cli_set(base_path + ['interface', interface, 'no-bsm'])
self.cli_set(base_path + ['interface', interface, 'no-unicast-bsm'])
self.cli_set(base_path + ['interface', interface, 'passive'])
self.cli_commit()
# Verify FRR pim6d configuration
- config = self.getFRRconfig('router pim6', endsection='^exit')
+ config = self.getFRRconfig('router pim6', stop_section='^exit')
self.assertIn(f' join-prune-interval {join_prune_interval}', config)
self.assertIn(f' keep-alive-timer {keep_alive_timer}', config)
self.assertIn(f' packets {packets}', config)
self.assertIn(f' register-suppress-time {register_suppress_time}', config)
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ config = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f' ipv6 pim drpriority {dr_priority}', config)
self.assertIn(f' ipv6 pim hello {hello}', config)
self.assertIn(f' no ipv6 pim bsm', config)
self.assertIn(f' no ipv6 pim unicast-bsm', config)
self.assertIn(f' ipv6 pim passive', config)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_rip.py b/smoketest/scripts/cli/test_protocols_rip.py
index f405702e5..784cddc5e 100755
--- a/smoketest/scripts/cli/test_protocols_rip.py
+++ b/smoketest/scripts/cli/test_protocols_rip.py
@@ -1,189 +1,186 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.ifconfig import Section
from vyos.frrender import rip_daemon
from vyos.utils.process import process_named_running
acl_in = '198'
acl_out = '199'
prefix_list_in = 'foo-prefix'
prefix_list_out = 'bar-prefix'
route_map = 'FooBar123'
base_path = ['protocols', 'rip']
class TestProtocolsRIP(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestProtocolsRIP, cls).setUpClass()
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(rip_daemon)
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
cls.cli_set(cls, ['policy', 'access-list', acl_in, 'rule', '10', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'access-list', acl_in, 'rule', '10', 'source', 'any'])
cls.cli_set(cls, ['policy', 'access-list', acl_in, 'rule', '10', 'destination', 'any'])
cls.cli_set(cls, ['policy', 'access-list', acl_out, 'rule', '20', 'action', 'deny'])
cls.cli_set(cls, ['policy', 'access-list', acl_out, 'rule', '20', 'source', 'any'])
cls.cli_set(cls, ['policy', 'access-list', acl_out, 'rule', '20', 'destination', 'any'])
cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_in, 'rule', '100', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_in, 'rule', '100', 'prefix', '192.0.2.0/24'])
cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_out, 'rule', '200', 'action', 'deny'])
cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_out, 'rule', '200', 'prefix', '192.0.2.0/24'])
cls.cli_set(cls, ['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
@classmethod
def tearDownClass(cls):
cls.cli_delete(cls, ['policy', 'access-list', acl_in])
cls.cli_delete(cls, ['policy', 'access-list', acl_out])
cls.cli_delete(cls, ['policy', 'prefix-list', prefix_list_in])
cls.cli_delete(cls, ['policy', 'prefix-list', prefix_list_out])
cls.cli_delete(cls, ['policy', 'route-map', route_map])
super(TestProtocolsRIP, cls).tearDownClass()
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
- frrconfig = self.getFRRconfig('router rip', endsection='^exit')
+ frrconfig = self.getFRRconfig('router rip', stop_section='^exit')
self.assertNotIn(f'router rip', frrconfig)
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(rip_daemon))
def test_rip_01_parameters(self):
distance = '40'
network_distance = '66'
metric = '8'
interfaces = Section.interfaces('ethernet')
neighbors = ['1.2.3.4', '1.2.3.5', '1.2.3.6']
networks = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']
redistribute = ['bgp', 'connected', 'isis', 'kernel', 'nhrp', 'ospf', 'static']
timer_garbage = '888'
timer_timeout = '1000'
timer_update = '90'
self.cli_set(base_path + ['default-distance', distance])
self.cli_set(base_path + ['default-information', 'originate'])
self.cli_set(base_path + ['default-metric', metric])
self.cli_set(base_path + ['distribute-list', 'access-list', 'in', acl_in])
self.cli_set(base_path + ['distribute-list', 'access-list', 'out', acl_out])
self.cli_set(base_path + ['distribute-list', 'prefix-list', 'in', prefix_list_in])
self.cli_set(base_path + ['distribute-list', 'prefix-list', 'out', prefix_list_out])
self.cli_set(base_path + ['passive-interface', 'default'])
self.cli_set(base_path + ['timers', 'garbage-collection', timer_garbage])
self.cli_set(base_path + ['timers', 'timeout', timer_timeout])
self.cli_set(base_path + ['timers', 'update', timer_update])
for interface in interfaces:
self.cli_set(base_path + ['interface', interface])
self.cli_set(base_path + ['distribute-list', 'interface', interface, 'access-list', 'in', acl_in])
self.cli_set(base_path + ['distribute-list', 'interface', interface, 'access-list', 'out', acl_out])
self.cli_set(base_path + ['distribute-list', 'interface', interface, 'prefix-list', 'in', prefix_list_in])
self.cli_set(base_path + ['distribute-list', 'interface', interface, 'prefix-list', 'out', prefix_list_out])
for neighbor in neighbors:
self.cli_set(base_path + ['neighbor', neighbor])
for network in networks:
self.cli_set(base_path + ['network', network])
self.cli_set(base_path + ['network-distance', network, 'distance', network_distance])
self.cli_set(base_path + ['route', network])
for proto in redistribute:
self.cli_set(base_path + ['redistribute', proto, 'metric', metric])
self.cli_set(base_path + ['redistribute', proto, 'route-map', route_map])
# commit changes
self.cli_commit()
# Verify FRR ripd configuration
- frrconfig = self.getFRRconfig('router rip', endsection='^exit')
+ frrconfig = self.getFRRconfig('router rip', stop_section='^exit')
self.assertIn(f'router rip', frrconfig)
self.assertIn(f' distance {distance}', frrconfig)
self.assertIn(f' default-information originate', frrconfig)
self.assertIn(f' default-metric {metric}', frrconfig)
self.assertIn(f' distribute-list {acl_in} in', frrconfig)
self.assertIn(f' distribute-list {acl_out} out', frrconfig)
self.assertIn(f' distribute-list prefix {prefix_list_in} in', frrconfig)
self.assertIn(f' distribute-list prefix {prefix_list_out} out', frrconfig)
self.assertIn(f' passive-interface default', frrconfig)
self.assertIn(f' timers basic {timer_update} {timer_timeout} {timer_garbage}', frrconfig)
for interface in interfaces:
self.assertIn(f' network {interface}', frrconfig)
self.assertIn(f' distribute-list {acl_in} in {interface}', frrconfig)
self.assertIn(f' distribute-list {acl_out} out {interface}', frrconfig)
self.assertIn(f' distribute-list prefix {prefix_list_in} in {interface}', frrconfig)
self.assertIn(f' distribute-list prefix {prefix_list_out} out {interface}', frrconfig)
for neighbor in neighbors:
self.assertIn(f' neighbor {neighbor}', frrconfig)
for network in networks:
self.assertIn(f' network {network}', frrconfig)
self.assertIn(f' distance {network_distance} {network}', frrconfig)
self.assertIn(f' route {network}', frrconfig)
for proto in redistribute:
self.assertIn(f' redistribute {proto} metric {metric} route-map {route_map}', frrconfig)
def test_rip_02_zebra_route_map(self):
# Implemented because of T3328
self.cli_set(base_path + ['route-map', route_map])
# commit changes
self.cli_commit()
# Verify FRR configuration
zebra_route_map = f'ip protocol rip route-map {route_map}'
frrconfig = self.getFRRconfig(zebra_route_map)
self.assertIn(zebra_route_map, frrconfig)
# Remove the route-map again
self.cli_delete(base_path + ['route-map'])
# commit changes
self.cli_commit()
# Verify FRR configuration
frrconfig = self.getFRRconfig(zebra_route_map)
self.assertNotIn(zebra_route_map, frrconfig)
def test_rip_03_version(self):
rx_version = '1'
tx_version = '2'
interface = 'eth0'
self.cli_set(base_path + ['version', tx_version])
self.cli_set(base_path + ['interface', interface, 'send', 'version', tx_version])
self.cli_set(base_path + ['interface', interface, 'receive', 'version', rx_version])
# commit changes
self.cli_commit()
# Verify FRR configuration
- frrconfig = self.getFRRconfig('router rip', endsection='^exit')
+ frrconfig = self.getFRRconfig('router rip', stop_section='^exit')
self.assertIn(f'version {tx_version}', frrconfig)
- frrconfig = self.getFRRconfig(f'interface {interface}', endsection='^exit')
+ frrconfig = self.getFRRconfig(f'interface {interface}', stop_section='^exit')
self.assertIn(f' ip rip receive version {rx_version}', frrconfig)
self.assertIn(f' ip rip send version {tx_version}', frrconfig)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_ripng.py b/smoketest/scripts/cli/test_protocols_ripng.py
index 305f31db5..c410f0f30 100755
--- a/smoketest/scripts/cli/test_protocols_ripng.py
+++ b/smoketest/scripts/cli/test_protocols_ripng.py
@@ -1,166 +1,163 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.ifconfig import Section
from vyos.frrender import ripng_daemon
from vyos.utils.process import process_named_running
acl_in = '198'
acl_out = '199'
prefix_list_in = 'foo-prefix'
prefix_list_out = 'bar-prefix'
route_map = 'FooBar123'
base_path = ['protocols', 'ripng']
class TestProtocolsRIPng(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
# call base-classes classmethod
super(TestProtocolsRIPng, cls).setUpClass()
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(ripng_daemon)
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
cls.cli_set(cls, ['policy', 'access-list6', acl_in, 'rule', '10', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'access-list6', acl_in, 'rule', '10', 'source', 'any'])
cls.cli_set(cls, ['policy', 'access-list6', acl_out, 'rule', '20', 'action', 'deny'])
cls.cli_set(cls, ['policy', 'access-list6', acl_out, 'rule', '20', 'source', 'any'])
cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_in, 'rule', '100', 'action', 'permit'])
cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_in, 'rule', '100', 'prefix', '2001:db8::/32'])
cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_out, 'rule', '200', 'action', 'deny'])
cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_out, 'rule', '200', 'prefix', '2001:db8::/32'])
cls.cli_set(cls, ['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
@classmethod
def tearDownClass(cls):
# call base-classes classmethod
super(TestProtocolsRIPng, cls).tearDownClass()
cls.cli_delete(cls, ['policy', 'access-list6', acl_in])
cls.cli_delete(cls, ['policy', 'access-list6', acl_out])
cls.cli_delete(cls, ['policy', 'prefix-list6', prefix_list_in])
cls.cli_delete(cls, ['policy', 'prefix-list6', prefix_list_out])
cls.cli_delete(cls, ['policy', 'route-map', route_map])
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
- frrconfig = self.getFRRconfig('router ripng', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ripng', stop_section='^exit')
self.assertNotIn(f'router ripng', frrconfig)
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(ripng_daemon))
def test_ripng_01_parameters(self):
metric = '8'
interfaces = Section.interfaces('ethernet')
aggregates = ['2001:db8:1000::/48', '2001:db8:2000::/48', '2001:db8:3000::/48']
networks = ['2001:db8:1000::/64', '2001:db8:1001::/64', '2001:db8:2000::/64', '2001:db8:2001::/64']
redistribute = ['bgp', 'connected', 'kernel', 'ospfv3', 'static']
timer_garbage = '888'
timer_timeout = '1000'
timer_update = '90'
self.cli_set(base_path + ['default-information', 'originate'])
self.cli_set(base_path + ['default-metric', metric])
self.cli_set(base_path + ['distribute-list', 'access-list', 'in', acl_in])
self.cli_set(base_path + ['distribute-list', 'access-list', 'out', acl_out])
self.cli_set(base_path + ['distribute-list', 'prefix-list', 'in', prefix_list_in])
self.cli_set(base_path + ['distribute-list', 'prefix-list', 'out', prefix_list_out])
self.cli_set(base_path + ['passive-interface', 'default'])
self.cli_set(base_path + ['timers', 'garbage-collection', timer_garbage])
self.cli_set(base_path + ['timers', 'timeout', timer_timeout])
self.cli_set(base_path + ['timers', 'update', timer_update])
for aggregate in aggregates:
self.cli_set(base_path + ['aggregate-address', aggregate])
for interface in interfaces:
self.cli_set(base_path + ['interface', interface])
self.cli_set(base_path + ['distribute-list', 'interface', interface, 'access-list', 'in', acl_in])
self.cli_set(base_path + ['distribute-list', 'interface', interface, 'access-list', 'out', acl_out])
self.cli_set(base_path + ['distribute-list', 'interface', interface, 'prefix-list', 'in', prefix_list_in])
self.cli_set(base_path + ['distribute-list', 'interface', interface, 'prefix-list', 'out', prefix_list_out])
for network in networks:
self.cli_set(base_path + ['network', network])
self.cli_set(base_path + ['route', network])
for proto in redistribute:
self.cli_set(base_path + ['redistribute', proto, 'metric', metric])
self.cli_set(base_path + ['redistribute', proto, 'route-map', route_map])
# commit changes
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ripng', endsection='^exit')
+ frrconfig = self.getFRRconfig('router ripng', stop_section='^exit')
self.assertIn(f'router ripng', frrconfig)
self.assertIn(f' default-information originate', frrconfig)
self.assertIn(f' default-metric {metric}', frrconfig)
self.assertIn(f' ipv6 distribute-list {acl_in} in', frrconfig)
self.assertIn(f' ipv6 distribute-list {acl_out} out', frrconfig)
self.assertIn(f' ipv6 distribute-list prefix {prefix_list_in} in', frrconfig)
self.assertIn(f' ipv6 distribute-list prefix {prefix_list_out} out', frrconfig)
self.assertIn(f' passive-interface default', frrconfig)
self.assertIn(f' timers basic {timer_update} {timer_timeout} {timer_garbage}', frrconfig)
for aggregate in aggregates:
self.assertIn(f' aggregate-address {aggregate}', frrconfig)
for interface in interfaces:
self.assertIn(f' network {interface}', frrconfig)
self.assertIn(f' ipv6 distribute-list {acl_in} in {interface}', frrconfig)
self.assertIn(f' ipv6 distribute-list {acl_out} out {interface}', frrconfig)
self.assertIn(f' ipv6 distribute-list prefix {prefix_list_in} in {interface}', frrconfig)
self.assertIn(f' ipv6 distribute-list prefix {prefix_list_out} out {interface}', frrconfig)
for network in networks:
self.assertIn(f' network {network}', frrconfig)
self.assertIn(f' route {network}', frrconfig)
for proto in redistribute:
if proto == 'ospfv3':
proto = 'ospf6'
self.assertIn(f' redistribute {proto} metric {metric} route-map {route_map}', frrconfig)
def test_ripng_02_zebra_route_map(self):
# Implemented because of T3328
self.cli_set(base_path + ['route-map', route_map])
# commit changes
self.cli_commit()
# Verify FRR configuration
zebra_route_map = f'ipv6 protocol ripng route-map {route_map}'
frrconfig = self.getFRRconfig(zebra_route_map)
self.assertIn(zebra_route_map, frrconfig)
# Remove the route-map again
self.cli_delete(base_path + ['route-map'])
# commit changes
self.cli_commit()
# Verify FRR configuration
frrconfig = self.getFRRconfig(zebra_route_map)
self.assertNotIn(zebra_route_map, frrconfig)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_rpki.py b/smoketest/scripts/cli/test_protocols_rpki.py
index 5a049dde1..d45245316 100755
--- a/smoketest/scripts/cli/test_protocols_rpki.py
+++ b/smoketest/scripts/cli/test_protocols_rpki.py
@@ -1,327 +1,324 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.frrender import bgp_daemon
from vyos.utils.file import read_file
from vyos.utils.process import process_named_running
base_path = ['protocols', 'rpki']
-base_frr_config_args = {'string': 'rpki', 'endsection': '^exit'}
+base_frr_config_args = {'start_section': 'rpki', 'stop_section': '^exit'}
vrf = 'blue'
vrf_path = ['vrf', 'name', vrf]
-vrf_frr_config_args = {'string': f'vrf {vrf}', 'endsection':'^exit-vrf',
- 'substring': ' rpki', 'endsubsection': '^ exit'}
+vrf_frr_config_args = {'start_section': f'vrf {vrf}', 'stop_section':'^exit-vrf',
+ 'start_subsection': ' rpki', 'stop_subsection': '^ exit'}
rpki_key_name = 'rpki-smoketest'
rpki_key_type = 'ssh-rsa'
rpki_ssh_key = """
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEAweDyflDFR4qyEwETbJkZ2ZZc+sJNiDTvYpwGsWIkju49lJSxHe1x
Kf8FhwfyMu40Snt1yDlRmmmz4CsbLgbuZGMPvXG11e34+C0pSVUvpF6aqRTeLl1pDRK7Rn
jgm3su+I8SRLQR4qbLG6VXWOFuVpwiqbExLaU0hFYTPNP+dArNpsWEEKsohk6pTXdhg3Vz
Wp3vCMjl2JTshDa3lD7p2xISSAReEY0fnfEAmQzH4Z6DIwwGdFuMWoQIg+oFBM9ARrO2/F
IjRsz6AecR/WeU72JEw4aJic1/cAJQA6PiQBHwkuo3Wll1tbpxeRZoB2NQG22ETyJLvhfT
aooNLT9HpQAAA8joU5dM6FOXTAAAAAdzc2gtcnNhAAABAQDB4PJ+UMVHirITARNsmRnZll
z6wk2INO9inAaxYiSO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV
7fj4LSlJVS+kXpqpFN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVh
M80/50Cs2mxYQQqyiGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfh
noMjDAZ0W4xahAiD6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS6j
daWXW1unF5FmgHY1AbbYRPIku+F9Nqig0tP0elAAAAAwEAAQAAAQACkDlUjzfUhtJs6uY5
WNrdJB5NmHUS+HQzzxFNlhkapK6+wKqI1UNaRUtq6iF7J+gcFf7MK2nXS098BsXguWm8fQ
zPuemoDvHsQhiaJhyvpSqRUrvPTB/f8t/0AhQiKiJIWgfpTaIw53inAGwjujNNxNm2eafH
TThhCYxOkRT7rsT6bnSio6yeqPy5QHg7IKFztp5FXDUyiOS3aX3SvzQcDUkMXALdvzX50t
1XIk+X48Rgkq72dL4VpV2oMNDu3hM6FqBUplf9Mv3s51FNSma/cibCQoVufrIfoqYjkNTj
IpYFUcq4zZ0/KvgXgzSsy9VN/4TtbalrOuu7X/SHJbvhAAAAgGPFsXgONYQvXxCnK1dIue
ozgaZg1I/n522E2ZCOXBW4dYJVyNpppwRreDzuFzTDEe061MpNHfScjVBJCCulivFYWscL
6oaGsryDbFxO3QmB4I98UBqrds2yan9/JGc6EYe299yvaHy7Y64+NC0+fN8H2RAZ61T4w1
0JrCaJRyvzAAAAgQDvBfuV1U7o9k/fbU+U7W2UYnWblpOZAMfi1XQP6IJJeyWs90PdTdXh
+l0eIQrCawIiRJytNfxMmbD4huwTf77fWiyCcPznmALQ7ex/yJ+W5Z0V4dPGF3h7o1uiS2
36JhQ7mfcliCkhp/1PIklBIMPcCp0zl+s9wMv2hX7w1Pah9QAAAIEAz6YgU9Xute+J+dBw
oWxEQ+igR6KE55Um7O9AvSrqnCm9r7lSFsXC2ErYOxoDSJ3yIBEV0b4XAGn6tbbVIs3jS8
BnLHxclAHQecOx1PGn7PKbnPW0oJRq/X9QCIEelKYvlykpayn7uZooTXqcDaPZxfPpmPdy
e8chVJvdygi7kPEAAAAMY3BvQExSMS53dWUzAQIDBAUGBw==
"""
rpki_ssh_pub = """
AAAAB3NzaC1yc2EAAAADAQABAAABAQDB4PJ+UMVHirITARNsmRnZllz6wk2INO9inAaxYi
SO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV7fj4LSlJVS+kXpqp
FN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVhM80/50Cs2mxYQQqy
iGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfhnoMjDAZ0W4xahAiD
6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS6jdaWXW1unF5FmgHY1
AbbYRPIku+F9Nqig0tP0el
"""
rpki_ssh_key_replacement = """
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEAtLPMwiGR3o6puPDbus9Yqoah9/7rv7i6ykykPmcEZ6ERnA0N6bl7
LkQxnCuX270ukTTZOhROvQnvQYIZohCMz27Q16z7r+I755QXL0x8x4Gqhg/hQUY7UtX6ts
db8+pO7G1PL4r9zT6/KJAF/wv86DezJ3I6TMaA7MCikXfQWJisBvhgAXF1+7V9CWaroGgV
/hHzQJu1yd4cfsYoHyeDaZ+lwFw4egNItIy63fIGDxrnXaonJ1ODGQh7zWlpl/cwQR/KyJ
P8vvOZ9olQ6syZV+DAcAo4Fe59wW2Zj4bl8bdGcdiDn0grkafxwTcg9ynr9kwQ8b66oXY4
hwB4vlPFPwAAA8jkGyX45Bsl+AAAAAdzc2gtcnNhAAABAQC0s8zCIZHejqm48Nu6z1iqhq
H3/uu/uLrKTKQ+ZwRnoRGcDQ3puXsuRDGcK5fbvS6RNNk6FE69Ce9BghmiEIzPbtDXrPuv
4jvnlBcvTHzHgaqGD+FBRjtS1fq2x1vz6k7sbU8viv3NPr8okAX/C/zoN7MncjpMxoDswK
KRd9BYmKwG+GABcXX7tX0JZqugaBX+EfNAm7XJ3hx+xigfJ4Npn6XAXDh6A0i0jLrd8gYP
GuddqicnU4MZCHvNaWmX9zBBH8rIk/y+85n2iVDqzJlX4MBwCjgV7n3BbZmPhuXxt0Zx2I
OfSCuRp/HBNyD3Kev2TBDxvrqhdjiHAHi+U8U/AAAAAwEAAQAAAQA99gkX5/rknXaE+9Hc
VIzKrC+NodOkgetKwszuuNRB1HD9WVyT8A3U5307V5dSuaPmFoEF8UCugWGQzNONRq+B0T
W7Po1u2dxAo/7vMQL4RfX60icjAroExWqakfFtycIWP8UPQFGWtxVFC12C/tFRrwe3Vuu2
t7otdEBKMRM3zU0Hj88/5FIk/MDhththDCKTMe4+iwNKo30dyqSCckpTd2k5de9JYz8Aom
87jtQcyDdynaELSo9CsA8KRPlozZ4VSWTVLH+Cv2TZWPL7hy79YvvIfuF/Sd6PGkNwG1Vj
TAbq2Wx4uq+HmpNiz7W0LnbZtQJ7dzLA3FZlvQMC8fVBAAAAgQDWvImVZCyVWpoG+LnKY3
joegjKRYKdgKRPCqGoIHiYsqCRxqSRW3jsuQCCvk4YO3/ZmqORiGktK+5r8R1QEtwg5qbi
N7GZD34m7USNuqG2G/4puEly8syMmR6VRRvEURFQrpv2wniXNSefvsDc+WDqTfXGUxr+FT
478wkzjwc/fAAAAIEA9uP0Ym3OC3cZ5FOvmu51lxo5lqPlUeE78axg2I4u/9Il8nOvSVuq
B9X5wAUyGAGcUjT3EZmRAtL2sQxc5T0Vw3bnxCjzukEbFM+DRtYy1hXSOoGTTwKoMWBpho
R3X5uRLUQL/22C4rd7tSJpjqnZXIH0B5z2fFh4vzu8/SrgCrUAAACBALtep4BcGJfjfhfF
ODzQe7Rk7tsaX8pfNv6bQu0sR5C9pDURFRf0fRC0oqgeTuzq/vHPyNLsUUgTCpKWiLFmvU
G9pelLT3XPPgzA+g0gycM0unuX8kkP3T5VQAM/7u0+h1CaJ8A6cCkzvDJxYdfio3WR60OP
ulHg7HCcyomFLaSjAAAADGNwb0BMUjEud3VlMwECAwQFBg==
"""
rpki_ssh_pub_replacement = """
AAAAB3NzaC1yc2EAAAADAQABAAABAQC0s8zCIZHejqm48Nu6z1iqhqH3/uu/uLrKTKQ+Zw
RnoRGcDQ3puXsuRDGcK5fbvS6RNNk6FE69Ce9BghmiEIzPbtDXrPuv4jvnlBcvTHzHgaqG
D+FBRjtS1fq2x1vz6k7sbU8viv3NPr8okAX/C/zoN7MncjpMxoDswKKRd9BYmKwG+GABcX
X7tX0JZqugaBX+EfNAm7XJ3hx+xigfJ4Npn6XAXDh6A0i0jLrd8gYPGuddqicnU4MZCHvN
aWmX9zBBH8rIk/y+85n2iVDqzJlX4MBwCjgV7n3BbZmPhuXxt0Zx2IOfSCuRp/HBNyD3Ke
v2TBDxvrqhdjiHAHi+U8U/
"""
class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
# call base-classes classmethod
super(TestProtocolsRPKI, cls).setUpClass()
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(bgp_daemon)
# 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_path)
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
self.cli_delete(base_path)
self.cli_delete(vrf_path)
self.cli_commit()
frrconfig = self.getFRRconfig(**base_frr_config_args)
self.assertNotIn(f'rpki', frrconfig)
frrconfig = self.getFRRconfig(**vrf_frr_config_args)
self.assertNotIn(f'rpki', frrconfig)
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(bgp_daemon))
def test_rpki(self):
expire_interval = '3600'
polling_period = '600'
retry_interval = '300'
cache = {
'192.0.2.1' : {
'port' : '8080',
'preference' : '10'
},
'2001:db8::1' : {
'port' : '1234',
'preference' : '30'
},
'rpki.vyos.net' : {
'port' : '5678',
'preference' : '40'
},
}
for test_set in [ {'path': base_path, 'frrargs': base_frr_config_args},
{'path': vrf_path + base_path, 'frrargs': vrf_frr_config_args} ]:
if 'vrf' in test_set['path']:
self.cli_set(vrf_path + ['table', '1000'])
self.cli_set(test_set['path'] + ['expire-interval', expire_interval])
self.cli_set(test_set['path'] + ['polling-period', polling_period])
self.cli_set(test_set['path'] + ['retry-interval', retry_interval])
for peer, peer_config in cache.items():
self.cli_set(test_set['path'] + ['cache', peer, 'port', peer_config['port']])
self.cli_set(test_set['path'] + ['cache', peer, 'preference', peer_config['preference']])
# commit changes
self.cli_commit()
# Verify FRR configuration
frrconfig = self.getFRRconfig(**test_set['frrargs'])
self.assertIn(f'rpki expire_interval {expire_interval}', frrconfig)
self.assertIn(f'rpki polling_period {polling_period}', frrconfig)
self.assertIn(f'rpki retry_interval {retry_interval}', frrconfig)
for peer, peer_config in cache.items():
port = peer_config['port']
preference = peer_config['preference']
self.assertIn(f'rpki cache tcp {peer} {port} preference {preference}', frrconfig)
def test_rpki_ssh(self):
polling = '7200'
cache = {
'192.0.2.3' : {
'port' : '1234',
'username' : 'foo',
'preference' : '10'
},
'192.0.2.4' : {
'port' : '5678',
'username' : 'bar',
'preference' : '20'
},
}
self.cli_set(['pki', 'openssh', rpki_key_name, 'private', 'key', rpki_ssh_key.replace('\n','')])
self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'key', rpki_ssh_pub.replace('\n','')])
self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'type', rpki_key_type])
for test_set in [ {'path': base_path, 'frrargs': base_frr_config_args},
{'path': vrf_path + base_path, 'frrargs': vrf_frr_config_args} ]:
if 'vrf' in test_set['path']:
self.cli_set(vrf_path + ['table', '1000'])
for cache_name, cache_config in cache.items():
self.cli_set(test_set['path'] + ['cache', cache_name, 'port', cache_config['port']])
self.cli_set(test_set['path'] + ['cache', cache_name, 'preference', cache_config['preference']])
self.cli_set(test_set['path'] + ['cache', cache_name, 'ssh', 'username', cache_config['username']])
self.cli_set(test_set['path'] + ['cache', cache_name, 'ssh', 'key', rpki_key_name])
# commit changes
self.cli_commit()
# Verify FRR configuration
frrconfig = self.getFRRconfig(**test_set['frrargs'])
for cache_name, cache_config in cache.items():
port = cache_config['port']
preference = cache_config['preference']
username = cache_config['username']
self.assertIn(f'rpki cache ssh {cache_name} {port} {username} /run/frr/id_rpki_{cache_name} /run/frr/id_rpki_{cache_name}.pub preference {preference}', frrconfig)
# Verify content of SSH keys
tmp = read_file(f'/run/frr/id_rpki_{cache_name}')
self.assertIn(rpki_ssh_key.replace('\n',''), tmp)
tmp = read_file(f'/run/frr/id_rpki_{cache_name}.pub')
self.assertIn(rpki_ssh_pub.replace('\n',''), tmp)
# Change OpenSSH key and verify it was properly written to filesystem
self.cli_set(['pki', 'openssh', rpki_key_name, 'private', 'key', rpki_ssh_key_replacement.replace('\n','')])
self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'key', rpki_ssh_pub_replacement.replace('\n','')])
# commit changes
self.cli_commit()
for test_set in [ {'path': base_path, 'frrargs': base_frr_config_args},
{'path': vrf_path + base_path, 'frrargs': vrf_frr_config_args} ]:
frrconfig = self.getFRRconfig(**test_set['frrargs'])
for cache_name, cache_config in cache.items():
port = cache_config['port']
preference = cache_config['preference']
username = cache_config['username']
self.assertIn(f'rpki cache ssh {cache_name} {port} {username} /run/frr/id_rpki_{cache_name} /run/frr/id_rpki_{cache_name}.pub preference {preference}', frrconfig)
# Verify content of SSH keys
tmp = read_file(f'/run/frr/id_rpki_{cache_name}')
self.assertIn(rpki_ssh_key_replacement.replace('\n',''), tmp)
tmp = read_file(f'/run/frr/id_rpki_{cache_name}.pub')
self.assertIn(rpki_ssh_pub_replacement.replace('\n',''), tmp)
self.cli_delete(['pki', 'openssh'])
def test_rpki_verify_preference(self):
cache = {
'192.0.2.1' : {
'port' : '8080',
'preference' : '1'
},
'192.0.2.2' : {
'port' : '9090',
'preference' : '1'
},
}
for test_set in [ {'path': base_path, 'frrargs': base_frr_config_args},
{'path': vrf_path + base_path, 'frrargs': vrf_frr_config_args} ]:
if 'vrf' in test_set['path']:
self.cli_set(vrf_path + ['table', '1000'])
for peer, peer_config in cache.items():
self.cli_set(test_set['path'] + ['cache', peer, 'port', peer_config['port']])
self.cli_set(test_set['path'] + ['cache', peer, 'preference', peer_config['preference']])
# check validate() - preferences must be unique
with self.assertRaises(ConfigSessionError):
self.cli_commit()
def test_rpki_source_address(self):
peer = '192.0.2.1'
port = '8080'
preference = '1'
username = 'foo'
source_address = '100.10.10.1'
self.cli_set(['interfaces', 'ethernet', 'eth0', 'address', f'{source_address}/24'])
for test_set in [ {'path': base_path, 'frrargs': base_frr_config_args},
{'path': vrf_path + base_path, 'frrargs': vrf_frr_config_args} ]:
if 'vrf' in test_set['path']:
self.cli_set(vrf_path + ['table', '1000'])
# Configure a TCP cache server
self.cli_set(test_set['path'] + ['cache', peer, 'port', port])
self.cli_set(test_set['path'] + ['cache', peer, 'preference', preference])
self.cli_set(test_set['path'] + ['cache', peer, 'source-address', source_address])
self.cli_commit()
# Verify FRR configuration
frrconfig = self.getFRRconfig(**test_set['frrargs'])
self.assertIn(f'rpki cache tcp {peer} {port} source {source_address} preference {preference}', frrconfig)
self.cli_set(['pki', 'openssh', rpki_key_name, 'private', 'key', rpki_ssh_key.replace('\n', '')])
self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'key', rpki_ssh_pub.replace('\n', '')])
self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'type', rpki_key_type])
# Configure a SSH cache server
self.cli_set(test_set['path'] + ['cache', peer, 'ssh', 'username', username])
self.cli_set(test_set['path'] + ['cache', peer, 'ssh', 'key', rpki_key_name])
self.cli_commit()
# Verify FRR configuration
frrconfig = self.getFRRconfig(**test_set['frrargs'])
self.assertIn(
f'rpki cache ssh {peer} {port} {username} /run/frr/id_rpki_{peer} /run/frr/id_rpki_{peer}.pub source {source_address} preference {preference}',
frrconfig,
)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_segment-routing.py b/smoketest/scripts/cli/test_protocols_segment-routing.py
index 258e23e75..41f33672b 100755
--- a/smoketest/scripts/cli/test_protocols_segment-routing.py
+++ b/smoketest/scripts/cli/test_protocols_segment-routing.py
@@ -1,190 +1,187 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.frrender import zebra_daemon
from vyos.utils.process import process_named_running
from vyos.utils.system import sysctl_read
base_path = ['protocols', 'segment-routing']
class TestProtocolsSegmentRouting(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
# call base-classes classmethod
super(TestProtocolsSegmentRouting, cls).setUpClass()
# Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same
cls.daemon_pid = process_named_running(zebra_daemon)
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(zebra_daemon))
def test_srv6(self):
interfaces = Section.interfaces('ethernet', vlan=False)
locators = {
'foo1': {'prefix': '2001:a::/64'},
'foo2': {'prefix': '2001:b::/64', 'usid': {}},
'foo3': {'prefix': '2001:c::/64', 'format': 'uncompressed-f4024'},
'foo4': {
'prefix': '2001:d::/48',
'block-len': '32',
'node-len': '16',
'func-bits': '16',
'usid': {},
'format': 'usid-f3216',
},
}
for locator, locator_config in locators.items():
self.cli_set(
base_path
+ ['srv6', 'locator', locator, 'prefix', locator_config['prefix']]
)
if 'block-len' in locator_config:
self.cli_set(
base_path
+ [
'srv6',
'locator',
locator,
'block-len',
locator_config['block-len'],
]
)
if 'node-len' in locator_config:
self.cli_set(
base_path
+ [
'srv6',
'locator',
locator,
'node-len',
locator_config['node-len'],
]
)
if 'func-bits' in locator_config:
self.cli_set(
base_path
+ [
'srv6',
'locator',
locator,
'func-bits',
locator_config['func-bits'],
]
)
if 'usid' in locator_config:
self.cli_set(base_path + ['srv6', 'locator', locator, 'behavior-usid'])
if 'format' in locator_config:
self.cli_set(
base_path
+ ['srv6', 'locator', locator, 'format', locator_config['format']]
)
# verify() - SRv6 should be enabled on at least one interface!
with self.assertRaises(ConfigSessionError):
self.cli_commit()
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'srv6'])
self.cli_commit()
for interface in interfaces:
self.assertEqual(
sysctl_read(f'net.ipv6.conf.{interface}.seg6_enabled'), '1'
)
self.assertEqual(
sysctl_read(f'net.ipv6.conf.{interface}.seg6_require_hmac'), '0'
) # default
- frrconfig = self.getFRRconfig('segment-routing', endsection='^exit')
+ frrconfig = self.getFRRconfig('segment-routing', stop_section='^exit')
self.assertIn('segment-routing', frrconfig)
self.assertIn(' srv6', frrconfig)
self.assertIn(' locators', frrconfig)
for locator, locator_config in locators.items():
prefix = locator_config['prefix']
block_len = locator_config.get('block-len', '40')
node_len = locator_config.get('node-len', '24')
func_bits = locator_config.get('func-bits', '16')
self.assertIn(f' locator {locator}', frrconfig)
self.assertIn(
f' prefix {prefix} block-len {block_len} node-len {node_len} func-bits {func_bits}',
frrconfig,
)
if 'format' in locator_config:
self.assertIn(f' format {locator_config["format"]}', frrconfig)
if 'usid' in locator_config:
self.assertIn(' behavior usid', frrconfig)
def test_srv6_sysctl(self):
interfaces = Section.interfaces('ethernet', vlan=False)
# HMAC accept
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'srv6'])
self.cli_set(base_path + ['interface', interface, 'srv6', 'hmac', 'ignore'])
self.cli_commit()
for interface in interfaces:
self.assertEqual(
sysctl_read(f'net.ipv6.conf.{interface}.seg6_enabled'), '1'
)
self.assertEqual(
sysctl_read(f'net.ipv6.conf.{interface}.seg6_require_hmac'), '-1'
) # ignore
# HMAC drop
for interface in interfaces:
self.cli_set(base_path + ['interface', interface, 'srv6'])
self.cli_set(base_path + ['interface', interface, 'srv6', 'hmac', 'drop'])
self.cli_commit()
for interface in interfaces:
self.assertEqual(
sysctl_read(f'net.ipv6.conf.{interface}.seg6_enabled'), '1'
)
self.assertEqual(
sysctl_read(f'net.ipv6.conf.{interface}.seg6_require_hmac'), '1'
) # drop
# Disable SRv6 on first interface
first_if = interfaces[-1]
self.cli_delete(base_path + ['interface', first_if])
self.cli_commit()
self.assertEqual(sysctl_read(f'net.ipv6.conf.{first_if}.seg6_enabled'), '0')
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py
index 8f01cd101..a8bb3dbae 100755
--- a/smoketest/scripts/cli/test_protocols_static.py
+++ b/smoketest/scripts/cli/test_protocols_static.py
@@ -1,655 +1,652 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 os
import unittest
from time import sleep
from base_vyostest_shim import VyOSUnitTestSHIM
-from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.template import is_ipv6
from vyos.template import get_dhcp_router
from vyos.utils.network import get_interface_config
from vyos.utils.network import get_vrf_tableid
from vyos.utils.process import process_named_running
from vyos.xml_ref import default_value
base_path = ['protocols', 'static']
vrf_path = ['protocols', 'vrf']
routes = {
'10.0.0.0/8' : {
'next_hop' : {
'192.0.2.100' : { 'distance' : '100' },
'192.0.2.110' : { 'distance' : '110', 'interface' : 'eth0' },
'192.0.2.120' : { 'distance' : '120', 'disable' : '' },
'192.0.2.130' : { 'bfd' : '' },
'192.0.2.131' : { 'bfd' : '',
'bfd_profile' : 'vyos1' },
'192.0.2.140' : { 'bfd' : '',
'bfd_source' : '192.0.2.10',
'bfd_profile' : 'vyos2' },
},
'interface' : {
'eth0' : { 'distance' : '130' },
'eth1' : { 'distance' : '140' },
},
'blackhole' : { 'distance' : '250', 'tag' : '500' },
},
'172.16.0.0/12' : {
'interface' : {
'eth0' : { 'distance' : '50', 'vrf' : 'black' },
'eth1' : { 'distance' : '60', 'vrf' : 'black' },
},
'blackhole' : { 'distance' : '90' },
},
'192.0.2.0/24' : {
'interface' : {
'eth0' : { 'distance' : '50', 'vrf' : 'black' },
'eth1' : { 'disable' : '' },
},
'blackhole' : { 'distance' : '90' },
},
'100.64.0.0/16' : {
'blackhole' : {},
},
'100.65.0.0/16' : {
'reject' : { 'distance' : '10', 'tag' : '200' },
},
'100.66.0.0/16' : {
'blackhole' : {},
'reject' : { 'distance' : '10', 'tag' : '200' },
},
'2001:db8:100::/40' : {
'next_hop' : {
'2001:db8::1' : { 'distance' : '10' },
'2001:db8::2' : { 'distance' : '20', 'interface' : 'eth0' },
'2001:db8::3' : { 'distance' : '30', 'disable' : '' },
'2001:db8::4' : { 'bfd' : '' },
'2001:db8::5' : { 'bfd_source' : '2001:db8::ffff' },
},
'interface' : {
'eth0' : { 'distance' : '40', 'vrf' : 'black' },
'eth1' : { 'distance' : '50', 'disable' : '' },
},
'blackhole' : { 'distance' : '250', 'tag' : '500' },
},
'2001:db8:200::/40' : {
'interface' : {
'eth0' : { 'distance' : '40' },
'eth1' : { 'distance' : '50', 'disable' : '' },
},
'blackhole' : { 'distance' : '250', 'tag' : '500' },
},
'2001:db8:300::/40' : {
'reject' : { 'distance' : '250', 'tag' : '500' },
},
'2001:db8:400::/40' : {
'next_hop' : {
'2001:db8::400' : { 'segments' : '2001:db8:aaaa::400/2002::400/2003::400/2004::400' },
},
},
'2001:db8:500::/40' : {
'next_hop' : {
'2001:db8::500' : { 'segments' : '2001:db8:aaaa::500/2002::500/2003::500/2004::500' },
},
},
'2001:db8:600::/40' : {
'interface' : {
'eth0' : { 'segments' : '2001:db8:aaaa::600/2002::600' },
},
},
'2001:db8:700::/40' : {
'interface' : {
'eth1' : { 'segments' : '2001:db8:aaaa::700' },
},
},
'2001:db8::/32' : {
'blackhole' : { 'distance' : '200', 'tag' : '600' }
},
}
multicast_routes = {
'224.0.0.0/24' : {
'next_hop' : {
'224.203.0.1' : { },
'224.203.0.2' : { 'distance' : '110'},
},
},
'224.1.0.0/24' : {
'next_hop' : {
'224.205.0.1' : { 'disable' : {} },
'224.205.0.2' : { 'distance' : '110'},
},
},
'224.2.0.0/24' : {
'next_hop' : {
'1.2.3.0' : { },
'1.2.3.1' : { 'distance' : '110'},
},
},
'224.10.0.0/24' : {
'interface' : {
'eth1' : { 'disable' : {} },
'eth2' : { 'distance' : '110'},
},
},
'224.11.0.0/24' : {
'interface' : {
'eth0' : { },
'eth1' : { 'distance' : '10'},
},
},
'224.12.0.0/24' : {
'interface' : {
'eth0' : { },
'eth1' : { 'distance' : '200'},
},
},
}
tables = ['80', '81', '82']
class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestProtocolsStatic, cls).setUpClass()
cls.cli_delete(cls, base_path)
cls.cli_delete(cls, ['vrf'])
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
@classmethod
def tearDownClass(cls):
cls.cli_delete(cls, base_path)
cls.cli_delete(cls, ['vrf'])
super(TestProtocolsStatic, cls).tearDownClass()
def tearDown(self):
self.cli_delete(base_path)
self.cli_delete(['vrf'])
self.cli_commit()
- v4route = self.getFRRconfig('ip route', end='')
+ v4route = self.getFRRconfig('ip route')
self.assertFalse(v4route)
- v6route = self.getFRRconfig('ipv6 route', end='')
+ v6route = self.getFRRconfig('ipv6 route')
self.assertFalse(v6route)
def test_01_static(self):
self.cli_set(['vrf', 'name', 'black', 'table', '43210'])
for route, route_config in routes.items():
route_type = 'route'
if is_ipv6(route):
route_type = 'route6'
base = base_path + [route_type, route]
if 'next_hop' in route_config:
for next_hop, next_hop_config in route_config['next_hop'].items():
self.cli_set(base + ['next-hop', next_hop])
if 'disable' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'disable'])
if 'distance' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
if 'interface' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']])
if 'vrf' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']])
if 'bfd' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'bfd'])
if 'bfd_profile' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'bfd', 'profile', next_hop_config['bfd_profile']])
if 'bfd_source' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'bfd', 'multi-hop', 'source-address', next_hop_config['bfd_source']])
if 'segments' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'segments', next_hop_config['segments']])
if 'interface' in route_config:
for interface, interface_config in route_config['interface'].items():
self.cli_set(base + ['interface', interface])
if 'disable' in interface_config:
self.cli_set(base + ['interface', interface, 'disable'])
if 'distance' in interface_config:
self.cli_set(base + ['interface', interface, 'distance', interface_config['distance']])
if 'vrf' in interface_config:
self.cli_set(base + ['interface', interface, 'vrf', interface_config['vrf']])
if 'segments' in interface_config:
self.cli_set(base + ['interface', interface, 'segments', interface_config['segments']])
if 'blackhole' in route_config:
self.cli_set(base + ['blackhole'])
if 'distance' in route_config['blackhole']:
self.cli_set(base + ['blackhole', 'distance', route_config['blackhole']['distance']])
if 'tag' in route_config['blackhole']:
self.cli_set(base + ['blackhole', 'tag', route_config['blackhole']['tag']])
if 'reject' in route_config:
self.cli_set(base + ['reject'])
if 'distance' in route_config['reject']:
self.cli_set(base + ['reject', 'distance', route_config['reject']['distance']])
if 'tag' in route_config['reject']:
self.cli_set(base + ['reject', 'tag', route_config['reject']['tag']])
if {'blackhole', 'reject'} <= set(route_config):
# Can not use blackhole and reject at the same time
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(base + ['blackhole'])
self.cli_delete(base + ['reject'])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig('ip route', end='')
+ frrconfig = self.getFRRconfig('ip route')
# Verify routes
for route, route_config in routes.items():
ip_ipv6 = 'ip'
if is_ipv6(route):
ip_ipv6 = 'ipv6'
if 'next_hop' in route_config:
for next_hop, next_hop_config in route_config['next_hop'].items():
tmp = f'{ip_ipv6} route {route} {next_hop}'
if 'interface' in next_hop_config:
tmp += ' ' + next_hop_config['interface']
if 'distance' in next_hop_config:
tmp += ' ' + next_hop_config['distance']
if 'vrf' in next_hop_config:
tmp += ' nexthop-vrf ' + next_hop_config['vrf']
if 'bfd' in next_hop_config:
tmp += ' bfd'
if 'bfd_source' in next_hop_config:
tmp += ' multi-hop source ' + next_hop_config['bfd_source']
if 'bfd_profile' in next_hop_config:
tmp += ' profile ' + next_hop_config['bfd_profile']
if 'segments' in next_hop_config:
tmp += ' segments ' + next_hop_config['segments']
if 'disable' in next_hop_config:
self.assertNotIn(tmp, frrconfig)
else:
self.assertIn(tmp, frrconfig)
if 'interface' in route_config:
for interface, interface_config in route_config['interface'].items():
tmp = f'{ip_ipv6} route {route} {interface}'
if 'interface' in interface_config:
tmp += ' ' + interface_config['interface']
if 'distance' in interface_config:
tmp += ' ' + interface_config['distance']
if 'vrf' in interface_config:
tmp += ' nexthop-vrf ' + interface_config['vrf']
if 'segments' in interface_config:
tmp += ' segments ' + interface_config['segments']
if 'disable' in interface_config:
self.assertNotIn(tmp, frrconfig)
else:
self.assertIn(tmp, frrconfig)
if {'blackhole', 'reject'} <= set(route_config):
# Can not use blackhole and reject at the same time
# Config error validated above - skip this route
continue
if 'blackhole' in route_config:
tmp = f'{ip_ipv6} route {route} blackhole'
if 'tag' in route_config['blackhole']:
tmp += ' tag ' + route_config['blackhole']['tag']
if 'distance' in route_config['blackhole']:
tmp += ' ' + route_config['blackhole']['distance']
self.assertIn(tmp, frrconfig)
if 'reject' in route_config:
tmp = f'{ip_ipv6} route {route} reject'
if 'tag' in route_config['reject']:
tmp += ' tag ' + route_config['reject']['tag']
if 'distance' in route_config['reject']:
tmp += ' ' + route_config['reject']['distance']
self.assertIn(tmp, frrconfig)
def test_02_static_table(self):
self.cli_set(['vrf', 'name', 'black', 'table', '43210'])
for table in tables:
for route, route_config in routes.items():
route_type = 'route'
if is_ipv6(route):
route_type = 'route6'
base = base_path + ['table', table, route_type, route]
if 'next_hop' in route_config:
for next_hop, next_hop_config in route_config['next_hop'].items():
self.cli_set(base + ['next-hop', next_hop])
if 'disable' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'disable'])
if 'distance' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
if 'interface' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']])
if 'vrf' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']])
if 'interface' in route_config:
for interface, interface_config in route_config['interface'].items():
self.cli_set(base + ['interface', interface])
if 'disable' in interface_config:
self.cli_set(base + ['interface', interface, 'disable'])
if 'distance' in interface_config:
self.cli_set(base + ['interface', interface, 'distance', interface_config['distance']])
if 'vrf' in interface_config:
self.cli_set(base + ['interface', interface, 'vrf', interface_config['vrf']])
if 'blackhole' in route_config:
self.cli_set(base + ['blackhole'])
if 'distance' in route_config['blackhole']:
self.cli_set(base + ['blackhole', 'distance', route_config['blackhole']['distance']])
if 'tag' in route_config['blackhole']:
self.cli_set(base + ['blackhole', 'tag', route_config['blackhole']['tag']])
# commit changes
self.cli_commit()
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig('ip route', end='')
+ frrconfig = self.getFRRconfig('ip route')
for table in tables:
# Verify routes
for route, route_config in routes.items():
ip_ipv6 = 'ip'
if is_ipv6(route):
ip_ipv6 = 'ipv6'
if 'next_hop' in route_config:
for next_hop, next_hop_config in route_config['next_hop'].items():
tmp = f'{ip_ipv6} route {route} {next_hop}'
if 'interface' in next_hop_config:
tmp += ' ' + next_hop_config['interface']
if 'distance' in next_hop_config:
tmp += ' ' + next_hop_config['distance']
if 'vrf' in next_hop_config:
tmp += ' nexthop-vrf ' + next_hop_config['vrf']
tmp += ' table ' + table
if 'disable' in next_hop_config:
self.assertNotIn(tmp, frrconfig)
else:
self.assertIn(tmp, frrconfig)
if 'interface' in route_config:
for interface, interface_config in route_config['interface'].items():
tmp = f'{ip_ipv6} route {route} {interface}'
if 'interface' in interface_config:
tmp += ' ' + interface_config['interface']
if 'distance' in interface_config:
tmp += ' ' + interface_config['distance']
if 'vrf' in interface_config:
tmp += ' nexthop-vrf ' + interface_config['vrf']
tmp += ' table ' + table
if 'disable' in interface_config:
self.assertNotIn(tmp, frrconfig)
else:
self.assertIn(tmp, frrconfig)
if 'blackhole' in route_config:
tmp = f'{ip_ipv6} route {route} blackhole'
if 'tag' in route_config['blackhole']:
tmp += ' tag ' + route_config['blackhole']['tag']
if 'distance' in route_config['blackhole']:
tmp += ' ' + route_config['blackhole']['distance']
tmp += ' table ' + table
self.assertIn(tmp, frrconfig)
def test_03_static_vrf(self):
self.cli_set(['vrf', 'name', 'black', 'table', '43210'])
# Create VRF instances and apply the static routes from above to FRR.
# Re-read the configured routes and match them if they are programmed
# properly. This also includes VRF leaking
vrfs = {
'red' : { 'table' : '1000' },
'green' : { 'table' : '2000' },
'blue' : { 'table' : '3000' },
}
for vrf, vrf_config in vrfs.items():
vrf_base_path = ['vrf', 'name', vrf]
self.cli_set(vrf_base_path + ['table', vrf_config['table']])
for route, route_config in routes.items():
route_type = 'route'
if is_ipv6(route):
route_type = 'route6'
route_base_path = vrf_base_path + ['protocols', 'static', route_type, route]
if 'next_hop' in route_config:
for next_hop, next_hop_config in route_config['next_hop'].items():
self.cli_set(route_base_path + ['next-hop', next_hop])
if 'disable' in next_hop_config:
self.cli_set(route_base_path + ['next-hop', next_hop, 'disable'])
if 'distance' in next_hop_config:
self.cli_set(route_base_path + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
if 'interface' in next_hop_config:
self.cli_set(route_base_path + ['next-hop', next_hop, 'interface', next_hop_config['interface']])
if 'vrf' in next_hop_config:
self.cli_set(route_base_path + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']])
if 'segments' in next_hop_config:
self.cli_set(route_base_path + ['next-hop', next_hop, 'segments', next_hop_config['segments']])
if 'interface' in route_config:
for interface, interface_config in route_config['interface'].items():
self.cli_set(route_base_path + ['interface', interface])
if 'disable' in interface_config:
self.cli_set(route_base_path + ['interface', interface, 'disable'])
if 'distance' in interface_config:
self.cli_set(route_base_path + ['interface', interface, 'distance', interface_config['distance']])
if 'vrf' in interface_config:
self.cli_set(route_base_path + ['interface', interface, 'vrf', interface_config['vrf']])
if 'segments' in interface_config:
self.cli_set(route_base_path + ['interface', interface, 'segments', interface_config['segments']])
if 'blackhole' in route_config:
self.cli_set(route_base_path + ['blackhole'])
if 'distance' in route_config['blackhole']:
self.cli_set(route_base_path + ['blackhole', 'distance', route_config['blackhole']['distance']])
if 'tag' in route_config['blackhole']:
self.cli_set(route_base_path + ['blackhole', 'tag', route_config['blackhole']['tag']])
# commit changes
self.cli_commit()
for vrf, vrf_config in vrfs.items():
tmp = get_interface_config(vrf)
# Compare VRF table ID
self.assertEqual(get_vrf_tableid(vrf), int(vrf_config['table']))
self.assertEqual(tmp['linkinfo']['info_kind'], 'vrf')
# Verify FRR bgpd configuration
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertIn(f'vrf {vrf}', frrconfig)
# Verify routes
for route, route_config in routes.items():
ip_ipv6 = 'ip'
if is_ipv6(route):
ip_ipv6 = 'ipv6'
if 'next_hop' in route_config:
for next_hop, next_hop_config in route_config['next_hop'].items():
tmp = f'{ip_ipv6} route {route} {next_hop}'
if 'interface' in next_hop_config:
tmp += ' ' + next_hop_config['interface']
if 'distance' in next_hop_config:
tmp += ' ' + next_hop_config['distance']
if 'vrf' in next_hop_config:
tmp += ' nexthop-vrf ' + next_hop_config['vrf']
if 'segments' in next_hop_config:
tmp += ' segments ' + next_hop_config['segments']
if 'disable' in next_hop_config:
self.assertNotIn(tmp, frrconfig)
else:
self.assertIn(tmp, frrconfig)
if 'interface' in route_config:
for interface, interface_config in route_config['interface'].items():
tmp = f'{ip_ipv6} route {route} {interface}'
if 'interface' in interface_config:
tmp += ' ' + interface_config['interface']
if 'distance' in interface_config:
tmp += ' ' + interface_config['distance']
if 'vrf' in interface_config:
tmp += ' nexthop-vrf ' + interface_config['vrf']
if 'segments' in interface_config:
tmp += ' segments ' + interface_config['segments']
if 'disable' in interface_config:
self.assertNotIn(tmp, frrconfig)
else:
self.assertIn(tmp, frrconfig)
if 'blackhole' in route_config:
tmp = f'{ip_ipv6} route {route} blackhole'
if 'tag' in route_config['blackhole']:
tmp += ' tag ' + route_config['blackhole']['tag']
if 'distance' in route_config['blackhole']:
tmp += ' ' + route_config['blackhole']['distance']
self.assertIn(tmp, frrconfig)
def test_04_static_multicast(self):
for route, route_config in multicast_routes.items():
if 'next_hop' in route_config:
base = base_path + ['mroute', route]
for next_hop, next_hop_config in route_config['next_hop'].items():
self.cli_set(base + ['next-hop', next_hop])
if 'distance' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
if 'disable' in next_hop_config:
self.cli_set(base + ['next-hop', next_hop, 'disable'])
if 'interface' in route_config:
base = base_path + ['mroute', route]
for next_hop, next_hop_config in route_config['interface'].items():
self.cli_set(base + ['interface', next_hop])
if 'distance' in next_hop_config:
self.cli_set(base + ['interface', next_hop, 'distance', next_hop_config['distance']])
self.cli_commit()
# Verify FRR configuration
- frrconfig = self.getFRRconfig('ip mroute', end='')
+ frrconfig = self.getFRRconfig('ip mroute')
for route, route_config in multicast_routes.items():
if 'next_hop' in route_config:
for next_hop, next_hop_config in route_config['next_hop'].items():
tmp = f'ip mroute {route} {next_hop}'
if 'distance' in next_hop_config:
tmp += ' ' + next_hop_config['distance']
if 'disable' in next_hop_config:
self.assertNotIn(tmp, frrconfig)
else:
self.assertIn(tmp, frrconfig)
if 'next_hop_interface' in route_config:
for next_hop, next_hop_config in route_config['next_hop_interface'].items():
tmp = f'ip mroute {route} {next_hop}'
if 'distance' in next_hop_config:
tmp += ' ' + next_hop_config['distance']
if 'disable' in next_hop_config:
self.assertNotIn(tmp, frrconfig)
else:
self.assertIn(tmp, frrconfig)
def test_05_dhcp_default_route(self):
# When running via vyos-build under the QEMU environment a local DHCP
# server is available. This test verifies that the default route is set.
# When not running under the VyOS QEMU environment, this test is skipped.
if not os.path.exists('/tmp/vyos.smoketests.hint'):
self.skipTest('Not running under VyOS CI/CD QEMU environment!')
interface = 'eth0'
interface_path = ['interfaces', 'ethernet', interface]
default_distance = default_value(interface_path + ['dhcp-options', 'default-route-distance'])
self.cli_set(interface_path + ['address', 'dhcp'])
self.cli_commit()
# Wait for dhclient to receive IP address and default gateway
sleep(5)
router = get_dhcp_router(interface)
- frrconfig = self.getFRRconfig('')
+ frrconfig = self.getFRRconfig()
self.assertIn(rf'ip route 0.0.0.0/0 {router} {interface} tag 210 {default_distance}', frrconfig)
# T6991: Default route is missing when there is no "protocols static"
# CLI node entry
self.cli_delete(base_path)
# We can trigger a FRR reconfiguration and config re-rendering when
# we simply disable IPv6 forwarding
self.cli_set(['system', 'ipv6', 'disable-forwarding'])
self.cli_commit()
# Re-check FRR configuration that default route is still present
- frrconfig = self.getFRRconfig('')
+ frrconfig = self.getFRRconfig()
self.assertIn(rf'ip route 0.0.0.0/0 {router} {interface} tag 210 {default_distance}', frrconfig)
self.cli_delete(interface_path + ['address'])
self.cli_commit()
# Wait for dhclient to stop
while process_named_running('dhclient', cmdline=interface, timeout=10):
sleep(0.250)
def test_06_dhcp_default_route_for_vrf(self):
# When running via vyos-build under the QEMU environment a local DHCP
# server is available. This test verifies that the default route is set.
# When not running under the VyOS QEMU environment, this test is skipped.
if not os.path.exists('/tmp/vyos.smoketests.hint'):
self.skipTest('Not running under VyOS CI/CD QEMU environment!')
interface = 'eth0'
vrf = 'red'
vrf_path = ['vrf', 'name', vrf]
interface_path = ['interfaces', 'ethernet', interface]
self.cli_set(vrf_path + ['table', '1000'])
default_distance = default_value(interface_path + ['dhcp-options', 'default-route-distance'])
self.cli_set(interface_path + ['address', 'dhcp'])
self.cli_set(interface_path + ['vrf', vrf])
self.cli_commit()
# Wait for dhclient to receive IP address and default gateway
sleep(5)
router = get_dhcp_router(interface)
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertIn(rf'ip route 0.0.0.0/0 {router} {interface} tag 210 {default_distance}', frrconfig)
self.cli_delete(interface_path + ['address'])
self.cli_delete(interface_path + ['vrf'])
self.cli_commit()
# Wait for dhclient to stop
while process_named_running('dhclient', cmdline=interface, timeout=10):
sleep(0.250)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_system_ip.py b/smoketest/scripts/cli/test_system_ip.py
index 57037fd8b..fdea3ab16 100755
--- a/smoketest/scripts/cli/test_system_ip.py
+++ b/smoketest/scripts/cli/test_system_ip.py
@@ -1,153 +1,155 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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.utils.system import sysctl_read
from vyos.xml_ref import default_value
base_path = ['system', 'ip']
class TestSystemIP(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestSystemIP, cls).setUpClass()
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
def test_system_ip_forwarding(self):
# Test if IPv4 forwarding can be disabled globally, default is '1'
# which means forwarding enabled
self.assertEqual(sysctl_read('net.ipv4.conf.all.forwarding'), '1')
self.cli_set(base_path + ['disable-forwarding'])
self.cli_commit()
+
self.assertEqual(sysctl_read('net.ipv4.conf.all.forwarding'), '0')
- frrconfig = self.getFRRconfig('', end='')
+ frrconfig = self.getFRRconfig()
self.assertIn('no ip forwarding', frrconfig)
self.cli_delete(base_path + ['disable-forwarding'])
self.cli_commit()
+
self.assertEqual(sysctl_read('net.ipv4.conf.all.forwarding'), '1')
- frrconfig = self.getFRRconfig('', end='')
+ frrconfig = self.getFRRconfig()
self.assertNotIn('no ip forwarding', frrconfig)
def test_system_ip_multipath(self):
# Test IPv4 multipathing options, options default to off -> '0'
self.assertEqual(sysctl_read('net.ipv4.fib_multipath_use_neigh'), '0')
self.assertEqual(sysctl_read('net.ipv4.fib_multipath_hash_policy'), '0')
self.cli_set(base_path + ['multipath', 'ignore-unreachable-nexthops'])
self.cli_set(base_path + ['multipath', 'layer4-hashing'])
self.cli_commit()
self.assertEqual(sysctl_read('net.ipv4.fib_multipath_use_neigh'), '1')
self.assertEqual(sysctl_read('net.ipv4.fib_multipath_hash_policy'), '1')
def test_system_ip_arp_table_size(self):
cli_default = int(default_value(base_path + ['arp', 'table-size']))
def _verify_gc_thres(table_size):
self.assertEqual(sysctl_read('net.ipv4.neigh.default.gc_thresh3'), str(table_size))
self.assertEqual(sysctl_read('net.ipv4.neigh.default.gc_thresh2'), str(table_size // 2))
self.assertEqual(sysctl_read('net.ipv4.neigh.default.gc_thresh1'), str(table_size // 8))
_verify_gc_thres(cli_default)
for size in [1024, 2048, 4096, 8192, 16384, 32768]:
self.cli_set(base_path + ['arp', 'table-size', str(size)])
self.cli_commit()
_verify_gc_thres(size)
def test_system_ip_protocol_route_map(self):
protocols = ['any', 'babel', 'bgp', 'connected', 'eigrp', 'isis',
'kernel', 'ospf', 'rip', 'static', 'table']
for protocol in protocols:
self.cli_set(['policy', 'route-map', f'route-map-{protocol}', 'rule', '10', 'action', 'permit'])
self.cli_set(base_path + ['protocol', protocol, 'route-map', f'route-map-{protocol}'])
self.cli_commit()
# Verify route-map properly applied to FRR
- frrconfig = self.getFRRconfig('ip protocol', end='')
+ frrconfig = self.getFRRconfig('ip protocol', stop_section='^end')
for protocol in protocols:
self.assertIn(f'ip protocol {protocol} route-map route-map-{protocol}', frrconfig)
# Delete route-maps
self.cli_delete(['policy', 'route-map'])
self.cli_delete(base_path + ['protocol'])
self.cli_commit()
# Verify route-map properly applied to FRR
- frrconfig = self.getFRRconfig('ip protocol', end='')
+ frrconfig = self.getFRRconfig('ip protocol', stop_section='^end')
self.assertNotIn(f'ip protocol', frrconfig)
def test_system_ip_protocol_non_existing_route_map(self):
non_existing = 'non-existing'
self.cli_set(base_path + ['protocol', 'static', 'route-map', non_existing])
# VRF does yet not exist - an error must be thrown
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(['policy', 'route-map', non_existing, 'rule', '10', 'action', 'deny'])
# Commit again
self.cli_commit()
def test_system_ip_nht(self):
self.cli_set(base_path + ['nht', 'no-resolve-via-default'])
self.cli_commit()
# Verify CLI config applied to FRR
- frrconfig = self.getFRRconfig('', end='')
+ frrconfig = self.getFRRconfig()
self.assertIn(f'no ip nht resolve-via-default', frrconfig)
self.cli_delete(base_path + ['nht', 'no-resolve-via-default'])
self.cli_commit()
# Verify CLI config removed to FRR
- frrconfig = self.getFRRconfig('', end='')
+ frrconfig = self.getFRRconfig()
self.assertNotIn(f'no ip nht resolve-via-default', frrconfig)
def test_system_ip_import_table(self):
table_num = '100'
distance = '200'
route_map_in = 'foo-map-in'
self.cli_set(['policy', 'route-map', route_map_in, 'rule', '10', 'action', 'permit'])
self.cli_set(base_path + ['import-table', table_num, 'distance', distance])
self.cli_set(base_path + ['import-table', table_num, 'route-map', route_map_in])
self.cli_commit()
# Verify CLI config applied to FRR
- frrconfig = self.getFRRconfig('', end='')
+ frrconfig = self.getFRRconfig()
self.assertIn(f'ip import-table {table_num} distance {distance} route-map {route_map_in}', frrconfig)
self.cli_delete(['policy', 'route-map', route_map_in])
self.cli_delete(base_path + ['import-table'])
self.cli_commit()
# Verify CLI config removed to FRR
- frrconfig = self.getFRRconfig('', end='')
+ frrconfig = self.getFRRconfig()
self.assertNotIn(f'ip import-table {table_num} distance {distance}', frrconfig)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_system_ipv6.py b/smoketest/scripts/cli/test_system_ipv6.py
index c6d278082..cd80efab4 100755
--- a/smoketest/scripts/cli/test_system_ipv6.py
+++ b/smoketest/scripts/cli/test_system_ipv6.py
@@ -1,153 +1,153 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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.utils.system import sysctl_read
from vyos.xml_ref import default_value
base_path = ['system', 'ipv6']
class TestSystemIPv6(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestSystemIPv6, cls).setUpClass()
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
def test_system_ipv6_forwarding(self):
# Test if IPv6 forwarding can be disabled globally, default is '1'
# which means forwearding enabled
self.assertEqual(sysctl_read('net.ipv6.conf.all.forwarding'), '1')
self.cli_set(base_path + ['disable-forwarding'])
self.cli_commit()
self.assertEqual(sysctl_read('net.ipv6.conf.all.forwarding'), '0')
- frrconfig = self.getFRRconfig('', end='')
+ frrconfig = self.getFRRconfig()
self.assertIn('no ipv6 forwarding', frrconfig)
self.cli_delete(base_path + ['disable-forwarding'])
self.cli_commit()
self.assertEqual(sysctl_read('net.ipv6.conf.all.forwarding'), '1')
- frrconfig = self.getFRRconfig('', end='')
+ frrconfig = self.getFRRconfig()
self.assertNotIn('no ipv6 forwarding', frrconfig)
def test_system_ipv6_strict_dad(self):
# This defaults to 1
self.assertEqual(sysctl_read('net.ipv6.conf.all.accept_dad'), '1')
# Do not assign any IPv6 address on interfaces, this requires a reboot
# which can not be tested, but we can read the config file :)
self.cli_set(base_path + ['strict-dad'])
self.cli_commit()
# Verify configuration file
self.assertEqual(sysctl_read('net.ipv6.conf.all.accept_dad'), '2')
def test_system_ipv6_multipath(self):
# This defaults to 0
self.assertEqual(sysctl_read('net.ipv6.fib_multipath_hash_policy'), '0')
# Do not assign any IPv6 address on interfaces, this requires a reboot
# which can not be tested, but we can read the config file :)
self.cli_set(base_path + ['multipath', 'layer4-hashing'])
self.cli_commit()
# Verify configuration file
self.assertEqual(sysctl_read('net.ipv6.fib_multipath_hash_policy'), '1')
def test_system_ipv6_neighbor_table_size(self):
# Maximum number of entries to keep in the ARP cache, the
# default is 8192
cli_default = int(default_value(base_path + ['neighbor', 'table-size']))
def _verify_gc_thres(table_size):
self.assertEqual(sysctl_read('net.ipv6.neigh.default.gc_thresh3'), str(table_size))
self.assertEqual(sysctl_read('net.ipv6.neigh.default.gc_thresh2'), str(table_size // 2))
self.assertEqual(sysctl_read('net.ipv6.neigh.default.gc_thresh1'), str(table_size // 8))
_verify_gc_thres(cli_default)
for size in [1024, 2048, 4096, 8192, 16384, 32768]:
self.cli_set(base_path + ['neighbor', 'table-size', str(size)])
self.cli_commit()
_verify_gc_thres(size)
def test_system_ipv6_protocol_route_map(self):
protocols = ['any', 'babel', 'bgp', 'connected', 'isis',
'kernel', 'ospfv3', 'ripng', 'static', 'table']
for protocol in protocols:
route_map = 'route-map-' + protocol.replace('ospfv3', 'ospf6')
self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
self.cli_set(base_path + ['protocol', protocol, 'route-map', route_map])
self.cli_commit()
# Verify route-map properly applied to FRR
- frrconfig = self.getFRRconfig('ipv6 protocol', end='')
+ frrconfig = self.getFRRconfig('ipv6 protocol', stop_section='^end')
for protocol in protocols:
# VyOS and FRR use a different name for OSPFv3 (IPv6)
if protocol == 'ospfv3':
protocol = 'ospf6'
self.assertIn(f'ipv6 protocol {protocol} route-map route-map-{protocol}', frrconfig)
# Delete route-maps
self.cli_delete(['policy', 'route-map'])
self.cli_delete(base_path + ['protocol'])
self.cli_commit()
# Verify route-map properly applied to FRR
- frrconfig = self.getFRRconfig('ipv6 protocol', end='')
+ frrconfig = self.getFRRconfig('ipv6 protocol', stop_section='^end')
self.assertNotIn(f'ipv6 protocol', frrconfig)
def test_system_ipv6_protocol_non_existing_route_map(self):
non_existing = 'non-existing6'
self.cli_set(base_path + ['protocol', 'static', 'route-map', non_existing])
# VRF does yet not exist - an error must be thrown
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(['policy', 'route-map', non_existing, 'rule', '10', 'action', 'deny'])
# Commit again
self.cli_commit()
def test_system_ipv6_nht(self):
self.cli_set(base_path + ['nht', 'no-resolve-via-default'])
self.cli_commit()
# Verify CLI config applied to FRR
- frrconfig = self.getFRRconfig('', end='')
+ frrconfig = self.getFRRconfig()
self.assertIn(f'no ipv6 nht resolve-via-default', frrconfig)
self.cli_delete(base_path + ['nht', 'no-resolve-via-default'])
self.cli_commit()
# Verify CLI config removed to FRR
- frrconfig = self.getFRRconfig('', end='')
+ frrconfig = self.getFRRconfig()
self.assertNotIn(f'no ipv6 nht resolve-via-default', frrconfig)
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py
index 82d5f3ddd..a69068c6e 100755
--- a/smoketest/scripts/cli/test_vrf.py
+++ b/smoketest/scripts/cli/test_vrf.py
@@ -1,998 +1,994 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 re
import os
import unittest
from json import loads
from jmespath import search
from base_vyostest_shim import VyOSUnitTestSHIM
-from base_vyostest_shim import CSTORE_GUARD_TIME
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Interface
from vyos.ifconfig import Section
from vyos.utils.file import read_file
from vyos.utils.network import get_interface_config
from vyos.utils.network import get_vrf_tableid
from vyos.utils.network import is_intf_addr_assigned
from vyos.utils.network import interface_exists
from vyos.utils.process import cmd
from vyos.utils.system import sysctl_read
from vyos.template import inc_ip
from vyos.utils.process import process_named_running
base_path = ['vrf']
vrfs = ['red', 'green', 'blue', 'foo-bar', 'baz_foo']
v4_protocols = ['any', 'babel', 'bgp', 'connected', 'eigrp', 'isis', 'kernel', 'ospf', 'rip', 'static', 'table']
v6_protocols = ['any', 'babel', 'bgp', 'connected', 'isis', 'kernel', 'ospfv3', 'ripng', 'static', 'table']
class VRFTest(VyOSUnitTestSHIM.TestCase):
_interfaces = []
@classmethod
def setUpClass(cls):
# we need to filter out VLAN interfaces identified by a dot (.)
# in their name - just in case!
if 'TEST_ETH' in os.environ:
tmp = os.environ['TEST_ETH'].split()
cls._interfaces = tmp
else:
for tmp in Section.interfaces('ethernet', vlan=False):
cls._interfaces.append(tmp)
- # Enable CSTORE guard time required by FRR related tests
- cls._commit_guard_time = CSTORE_GUARD_TIME
-
# call base-classes classmethod
super(VRFTest, cls).setUpClass()
def setUp(self):
# VRF strict_most ist always enabled
tmp = read_file('/proc/sys/net/vrf/strict_mode')
self.assertEqual(tmp, '1')
def tearDown(self):
# delete all VRFs
self.cli_delete(base_path)
self.cli_commit()
for vrf in vrfs:
self.assertFalse(interface_exists(vrf))
def walk_path(self, obj, path):
current = obj
for i, key in enumerate(path):
if isinstance(key, str):
self.assertTrue(isinstance(current, dict), msg=f'Failed path: {path}')
self.assertTrue(key in current, msg=f'Failed path: {path}')
elif isinstance(key, int):
self.assertTrue(isinstance(current, list), msg=f'Failed path: {path}')
self.assertTrue(0 <= key < len(current), msg=f'Failed path: {path}')
else:
assert False, 'Invalid type'
current = current[key]
return current
def verify_config_object(self, obj, path, value):
base_obj = self.walk_path(obj, path)
self.assertTrue(isinstance(base_obj, list))
self.assertTrue(any(True for v in base_obj if v == value))
def verify_config_value(self, obj, path, key, value):
base_obj = self.walk_path(obj, path)
if isinstance(base_obj, list):
self.assertTrue(any(True for v in base_obj if key in v and v[key] == value))
elif isinstance(base_obj, dict):
self.assertTrue(key in base_obj)
self.assertEqual(base_obj[key], value)
def verify_kea_service_running(self, process_name):
tmp = cmd('tail -n 100 /var/log/messages')
self.assertTrue(
process_named_running(process_name), msg=f'Service not running, log: {tmp}'
)
def test_vrf_vni_and_table_id(self):
base_table = '1000'
table = base_table
for vrf in vrfs:
base = base_path + ['name', vrf]
description = f'VyOS-VRF-{vrf}'
self.cli_set(base + ['description', description])
# check validate() - a table ID is mandatory
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base + ['table', table])
self.cli_set(base + ['vni', table])
if vrf == 'green':
self.cli_set(base + ['disable'])
table = str(int(table) + 1)
# commit changes
self.cli_commit()
# Verify VRF configuration
table = base_table
iproute2_config = read_file('/etc/iproute2/rt_tables.d/vyos-vrf.conf')
for vrf in vrfs:
description = f'VyOS-VRF-{vrf}'
self.assertTrue(interface_exists(vrf))
vrf_if = Interface(vrf)
# validate proper interface description
self.assertEqual(vrf_if.get_alias(), description)
# validate admin up/down state of VRF
state = 'up'
if vrf == 'green':
state = 'down'
self.assertEqual(vrf_if.get_admin_state(), state)
# Test the iproute2 lookup file, syntax is as follows:
#
# # id vrf name comment
# 1000 red # VyOS-VRF-red
# 1001 green # VyOS-VRF-green
# ...
regex = f'{table}\s+{vrf}\s+#\s+{description}'
self.assertTrue(re.findall(regex, iproute2_config))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
self.assertEqual(int(table), get_vrf_tableid(vrf))
# Increment table ID for the next run
table = str(int(table) + 1)
def test_vrf_loopbacks_ips(self):
table = '2000'
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_set(base + ['table', str(table)])
table = str(int(table) + 1)
# commit changes
self.cli_commit()
# Verify VRF configuration
loopbacks = ['127.0.0.1', '::1']
for vrf in vrfs:
# Ensure VRF was created
self.assertTrue(interface_exists(vrf))
# Verify IP forwarding is 1 (enabled)
self.assertEqual(sysctl_read(f'net.ipv4.conf.{vrf}.forwarding'), '1')
self.assertEqual(sysctl_read(f'net.ipv6.conf.{vrf}.forwarding'), '1')
# Test for proper loopback IP assignment
for addr in loopbacks:
self.assertTrue(is_intf_addr_assigned(vrf, addr))
def test_vrf_bind_all(self):
table = '2000'
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_set(base + ['table', str(table)])
table = str(int(table) + 1)
self.cli_set(base_path + ['bind-to-all'])
# commit changes
self.cli_commit()
# Verify VRF configuration
self.assertEqual(sysctl_read('net.ipv4.tcp_l3mdev_accept'), '1')
self.assertEqual(sysctl_read('net.ipv4.udp_l3mdev_accept'), '1')
# If there is any VRF defined, strict_mode should be on
self.assertEqual(sysctl_read('net.vrf.strict_mode'), '1')
def test_vrf_table_id_is_unalterable(self):
# Linux Kernel prohibits the change of a VRF table on the fly.
# VRF must be deleted and recreated!
table = '1000'
vrf = vrfs[0]
base = base_path + ['name', vrf]
self.cli_set(base + ['table', table])
# commit changes
self.cli_commit()
# Check if VRF has been created
self.assertTrue(interface_exists(vrf))
table = str(int(table) + 1)
self.cli_set(base + ['table', table])
# check validate() - table ID can not be altered!
with self.assertRaises(ConfigSessionError):
self.cli_commit()
def test_vrf_assign_interface(self):
vrf = vrfs[0]
table = '5000'
self.cli_set(['vrf', 'name', vrf, 'table', table])
for interface in self._interfaces:
section = Section.section(interface)
self.cli_set(['interfaces', section, interface, 'vrf', vrf])
# commit changes
self.cli_commit()
# Verify VRF assignmant
for interface in self._interfaces:
tmp = get_interface_config(interface)
self.assertEqual(vrf, tmp['master'])
# cleanup
section = Section.section(interface)
self.cli_delete(['interfaces', section, interface, 'vrf'])
def test_vrf_static_route(self):
base_table = '100'
table = base_table
for vrf in vrfs:
next_hop = f'192.0.{table}.1'
prefix = f'10.0.{table}.0/24'
base = base_path + ['name', vrf]
self.cli_set(base + ['vni', table])
# check validate() - a table ID is mandatory
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base + ['table', table])
self.cli_set(base + ['protocols', 'static', 'route', prefix, 'next-hop', next_hop])
table = str(int(table) + 1)
# commit changes
self.cli_commit()
# Verify VRF configuration
table = base_table
for vrf in vrfs:
next_hop = f'192.0.{table}.1'
prefix = f'10.0.{table}.0/24'
self.assertTrue(interface_exists(vrf))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
self.assertIn(f' ip route {prefix} {next_hop}', frrconfig)
# Increment table ID for the next run
table = str(int(table) + 1)
def test_vrf_link_local_ip_addresses(self):
# Testcase for issue T4331
table = '100'
vrf = 'orange'
interface = 'dum9998'
addresses = ['192.0.2.1/26', '2001:db8:9998::1/64', 'fe80::1/64']
for address in addresses:
self.cli_set(['interfaces', 'dummy', interface, 'address', address])
# Create dummy interfaces
self.cli_commit()
# ... and verify IP addresses got assigned
for address in addresses:
self.assertTrue(is_intf_addr_assigned(interface, address))
# Move interface to VRF
self.cli_set(base_path + ['name', vrf, 'table', table])
self.cli_set(['interfaces', 'dummy', interface, 'vrf', vrf])
# Apply VRF config
self.cli_commit()
# Ensure VRF got created
self.assertTrue(interface_exists(vrf))
# ... and IP addresses are still assigned
for address in addresses:
self.assertTrue(is_intf_addr_assigned(interface, address))
# Verify VRF table ID
self.assertEqual(int(table), get_vrf_tableid(vrf))
# Verify interface is assigned to VRF
tmp = get_interface_config(interface)
self.assertEqual(vrf, tmp['master'])
# Delete Interface
self.cli_delete(['interfaces', 'dummy', interface])
self.cli_commit()
def test_vrf_disable_forwarding(self):
table = '2000'
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_set(base + ['table', table])
self.cli_set(base + ['ip', 'disable-forwarding'])
self.cli_set(base + ['ipv6', 'disable-forwarding'])
table = str(int(table) + 1)
# commit changes
self.cli_commit()
# Verify VRF configuration
loopbacks = ['127.0.0.1', '::1']
for vrf in vrfs:
# Ensure VRF was created
self.assertTrue(interface_exists(vrf))
# Verify IP forwarding is 0 (disabled)
self.assertEqual(sysctl_read(f'net.ipv4.conf.{vrf}.forwarding'), '0')
self.assertEqual(sysctl_read(f'net.ipv6.conf.{vrf}.forwarding'), '0')
def test_vrf_ip_protocol_route_map(self):
table = '6000'
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_set(base + ['table', table])
for protocol in v4_protocols:
self.cli_set(['policy', 'route-map', f'route-map-{vrf}-{protocol}', 'rule', '10', 'action', 'permit'])
self.cli_set(base + ['ip', 'protocol', protocol, 'route-map', f'route-map-{vrf}-{protocol}'])
table = str(int(table) + 1)
self.cli_commit()
# Verify route-map properly applied to FRR
for vrf in vrfs:
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertIn(f'vrf {vrf}', frrconfig)
for protocol in v4_protocols:
self.assertIn(f' ip protocol {protocol} route-map route-map-{vrf}-{protocol}', frrconfig)
# Delete route-maps
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_delete(['policy', 'route-map', f'route-map-{vrf}-{protocol}'])
self.cli_delete(base + ['ip', 'protocol'])
self.cli_commit()
# Verify route-map properly is removed from FRR
for vrf in vrfs:
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertNotIn(f' ip protocol', frrconfig)
def test_vrf_ip_ipv6_protocol_non_existing_route_map(self):
table = '6100'
non_existing = 'non-existing'
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_set(base + ['table', table])
for protocol in v4_protocols:
self.cli_set(base + ['ip', 'protocol', protocol, 'route-map', f'v4-{non_existing}'])
for protocol in v6_protocols:
self.cli_set(base + ['ipv6', 'protocol', protocol, 'route-map', f'v6-{non_existing}'])
table = str(int(table) + 1)
# Both v4 and v6 route-maps do not exist yet
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(['policy', 'route-map', f'v4-{non_existing}', 'rule', '10', 'action', 'deny'])
# v6 route-map does not exist yet
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(['policy', 'route-map', f'v6-{non_existing}', 'rule', '10', 'action', 'deny'])
# Commit again
self.cli_commit()
def test_vrf_ipv6_protocol_route_map(self):
table = '6200'
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_set(base + ['table', table])
for protocol in v6_protocols:
route_map = f'route-map-{vrf}-{protocol.replace("ospfv3", "ospf6")}'
self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
self.cli_set(base + ['ipv6', 'protocol', protocol, 'route-map', route_map])
table = str(int(table) + 1)
self.cli_commit()
# Verify route-map properly applied to FRR
for vrf in vrfs:
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertIn(f'vrf {vrf}', frrconfig)
for protocol in v6_protocols:
# VyOS and FRR use a different name for OSPFv3 (IPv6)
if protocol == 'ospfv3':
protocol = 'ospf6'
route_map = f'route-map-{vrf}-{protocol}'
self.assertIn(f' ipv6 protocol {protocol} route-map {route_map}', frrconfig)
# Delete route-maps
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_delete(['policy', 'route-map', f'route-map-{vrf}-{protocol}'])
self.cli_delete(base + ['ipv6', 'protocol'])
self.cli_commit()
# Verify route-map properly is removed from FRR
for vrf in vrfs:
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertNotIn(f' ipv6 protocol', frrconfig)
def test_vrf_vni_duplicates(self):
base_table = '6300'
table = base_table
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_set(base + ['table', str(table)])
self.cli_set(base + ['vni', '100'])
table = str(int(table) + 1)
# L3VNIs can only be used once
with self.assertRaises(ConfigSessionError):
self.cli_commit()
table = base_table
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_set(base + ['vni', str(table)])
table = str(int(table) + 1)
# commit changes
self.cli_commit()
# Verify VRF configuration
table = base_table
for vrf in vrfs:
self.assertTrue(interface_exists(vrf))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
# Increment table ID for the next run
table = str(int(table) + 1)
def test_vrf_vni_add_change_remove(self):
base_table = '6300'
table = base_table
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_set(base + ['table', str(table)])
self.cli_set(base + ['vni', str(table)])
table = str(int(table) + 1)
# commit changes
self.cli_commit()
# Verify VRF configuration
table = base_table
for vrf in vrfs:
self.assertTrue(interface_exists(vrf))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
# Increment table ID for the next run
table = str(int(table) + 1)
# Now change all L3VNIs (increment 2)
# We must also change the base_table number as we probably could get
# duplicate VNI's during the test as VNIs are applied 1:1 to FRR
base_table = '5000'
table = base_table
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_set(base + ['vni', str(table)])
table = str(int(table) + 2)
# commit changes
self.cli_commit()
# Verify VRF configuration
table = base_table
for vrf in vrfs:
self.assertTrue(interface_exists(vrf))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
# Increment table ID for the next run
table = str(int(table) + 2)
# add a new VRF with VNI - this must not delete any existing VRF/VNI
purple = 'purple'
table = str(int(table) + 10)
self.cli_set(base_path + ['name', purple, 'table', table])
self.cli_set(base_path + ['name', purple, 'vni', table])
# commit changes
self.cli_commit()
# Verify VRF configuration
table = base_table
for vrf in vrfs:
self.assertTrue(interface_exists(vrf))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
# Increment table ID for the next run
table = str(int(table) + 2)
# Verify purple VRF/VNI
self.assertTrue(interface_exists(purple))
table = str(int(table) + 10)
- frrconfig = self.getFRRconfig(f'vrf {purple}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {purple}', stop_section='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
# Now delete all the VNIs
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_delete(base + ['vni'])
# commit changes
self.cli_commit()
# Verify no VNI is defined
for vrf in vrfs:
self.assertTrue(interface_exists(vrf))
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertNotIn('vni', frrconfig)
# Verify purple VNI remains
self.assertTrue(interface_exists(purple))
- frrconfig = self.getFRRconfig(f'vrf {purple}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {purple}', stop_section='^exit-vrf')
self.assertIn(f' vni {table}', frrconfig)
def test_vrf_ip_ipv6_nht(self):
table = '6910'
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_set(base + ['table', table])
self.cli_set(base + ['ip', 'nht', 'no-resolve-via-default'])
self.cli_set(base + ['ipv6', 'nht', 'no-resolve-via-default'])
table = str(int(table) + 1)
self.cli_commit()
# Verify route-map properly applied to FRR
for vrf in vrfs:
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertIn(f'vrf {vrf}', frrconfig)
self.assertIn(f' no ip nht resolve-via-default', frrconfig)
self.assertIn(f' no ipv6 nht resolve-via-default', frrconfig)
# Delete route-maps
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_delete(base + ['ip'])
self.cli_delete(base + ['ipv6'])
self.cli_commit()
# Verify route-map properly is removed from FRR
for vrf in vrfs:
- frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
+ frrconfig = self.getFRRconfig(f'vrf {vrf}', stop_section='^exit-vrf')
self.assertNotIn(f' no ip nht resolve-via-default', frrconfig)
self.assertNotIn(f' no ipv6 nht resolve-via-default', frrconfig)
def test_vrf_conntrack(self):
table = '8710'
nftables_rules = {
'vrf_zones_ct_in': ['ct original zone set iifname map @ct_iface_map'],
'vrf_zones_ct_out': ['ct original zone set oifname map @ct_iface_map']
}
self.cli_set(base_path + ['name', 'randomVRF', 'table', '1000'])
self.cli_commit()
# Conntrack rules should not be present
for chain, rule in nftables_rules.items():
self.verify_nftables_chain(rule, 'inet vrf_zones', chain, inverse=True)
# conntrack is only enabled once NAT, NAT66 or firewalling is enabled
self.cli_set(['nat'])
for vrf in vrfs:
base = base_path + ['name', vrf]
self.cli_set(base + ['table', table])
table = str(int(table) + 1)
# We need the commit inside the loop to trigger the bug in T6603
self.cli_commit()
# Conntrack rules should now be present
for chain, rule in nftables_rules.items():
self.verify_nftables_chain(rule, 'inet vrf_zones', chain, inverse=False)
# T6603: there should be only ONE entry for the iifname/oifname in the chains
tmp = loads(cmd('sudo nft -j list table inet vrf_zones'))
num_rules = len(search("nftables[].rule[].chain", tmp))
# ['vrf_zones_ct_in', 'vrf_zones_ct_out']
self.assertEqual(num_rules, 2)
self.cli_delete(['nat'])
def test_dhcp_single_pool(self):
# Prepare the vrf and options
table = '100'
vrf = 'dhcp_smoke'
interface = 'dum8888'
subnet = '192.0.2.0/25'
router = inc_ip(subnet, 1)
dns_1 = inc_ip(subnet, 2)
dns_2 = inc_ip(subnet, 3)
domain_name = 'vyos.net'
# declare fiels
process_name = 'kea-dhcp4'
kea4_conf = f'/var/run/kea/kea-{vrf}-dhcp4.conf'
# create interface
cidr_mask = subnet.split('/')[-1]
self.cli_set(
['interfaces', 'dummy', interface, 'address', f'{router}/{cidr_mask}']
)
self.cli_set(['interfaces', 'dummy', interface, 'vrf', f'{vrf}'])
# create the vrf with table
base = base_path + ['name', vrf]
self.cli_set(base + ['table', table])
# set the dhcp scope
base = base_path + ['name', vrf, 'service', 'dhcp-server']
shared_net_name = 'SMOKE-1'
range_0_start = inc_ip(subnet, 10)
range_0_stop = inc_ip(subnet, 20)
range_1_start = inc_ip(subnet, 40)
range_1_stop = inc_ip(subnet, 50)
self.cli_set(base + ['listen-interface', interface])
self.cli_set(base + ['shared-network-name', shared_net_name, 'ping-check'])
pool = base + ['shared-network-name', shared_net_name, 'subnet', subnet]
self.cli_set(pool + ['subnet-id', '1'])
self.cli_set(pool + ['ignore-client-id'])
self.cli_set(pool + ['ping-check'])
# we use the first subnet IP address as default gateway
self.cli_set(pool + ['option', 'default-router', router])
self.cli_set(pool + ['option', 'name-server', dns_1])
self.cli_set(pool + ['option', 'name-server', dns_2])
self.cli_set(pool + ['option', 'domain-name', domain_name])
# check validate() - No DHCP address range or active static-mapping set
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(pool + ['range', '0', 'start', range_0_start])
self.cli_set(pool + ['range', '0', 'stop', range_0_stop])
self.cli_set(pool + ['range', '1', 'start', range_1_start])
self.cli_set(pool + ['range', '1', 'stop', range_1_stop])
# commit changes
self.cli_commit()
config = read_file(kea4_conf)
obj = loads(config)
self.verify_config_value(
obj, ['Dhcp4', 'interfaces-config'], 'interfaces', [interface]
)
self.verify_config_value(
obj, ['Dhcp4', 'shared-networks'], 'name', shared_net_name
)
self.verify_config_value(
obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'subnet', subnet
)
self.verify_config_value(
obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'id', 1
)
self.verify_config_value(
obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'match-client-id', False
)
self.verify_config_value(
obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'valid-lifetime', 86400
)
self.verify_config_value(
obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'max-valid-lifetime', 86400
)
# Verify ping-check
self.verify_config_value(
obj,
['Dhcp4', 'shared-networks', 0, 'user-context'],
'enable-ping-check',
True,
)
self.verify_config_value(
obj,
['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'user-context'],
'enable-ping-check',
True,
)
# Verify options
self.verify_config_object(
obj,
['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'option-data'],
{'name': 'domain-name', 'data': domain_name},
)
self.verify_config_object(
obj,
['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'option-data'],
{'name': 'domain-name-servers', 'data': f'{dns_1}, {dns_2}'},
)
self.verify_config_object(
obj,
['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'option-data'],
{'name': 'routers', 'data': router},
)
# Verify pools
self.verify_config_object(
obj,
['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'pools'],
{'pool': f'{range_0_start} - {range_0_stop}'},
)
self.verify_config_object(
obj,
['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'pools'],
{'pool': f'{range_1_start} - {range_1_stop}'},
)
# Check for running process
self.verify_kea_service_running(process_name)
# perform cleanup
self.cli_delete(['interfaces', 'dummy', interface, 'address'])
self.cli_delete(['interfaces', 'dummy', interface, 'vrf'])
self.cli_delete(base)
self.cli_commit()
def test_dhcpv6_single_pool(self):
# Prepare the vrf and other options
table = '100'
vrf = 'dhcp_smoke'
subnet = '2001:db8:f00::/64'
dns_1 = '2001:db8::1'
dns_2 = '2001:db8::2'
domain = 'vyos.net'
nis_servers = ['2001:db8:ffff::1', '2001:db8:ffff::2']
interface = 'dum8888'
interface_addr = inc_ip(subnet, 1) + '/64'
# declare fiels
process_name = 'kea-dhcp6'
kea6_conf = f'/var/run/kea/kea-{vrf}-dhcp6.conf'
# create interface
self.cli_set(['interfaces', 'dummy', interface, 'address', f'{interface_addr}'])
self.cli_set(['interfaces', 'dummy', interface, 'vrf', f'{vrf}'])
# create the vrf with table
base = base_path + ['name', vrf]
self.cli_set(base + ['table', table])
# set the dhcp scope
base = base_path + ['name', vrf, 'service', 'dhcpv6-server']
shared_net_name = 'SMOKE-1'
search_domains = ['foo.vyos.net', 'bar.vyos.net']
lease_time = '1200'
max_lease_time = '72000'
min_lease_time = '600'
preference = '10'
sip_server = 'sip.vyos.net'
sntp_server = inc_ip(subnet, 100)
range_start = inc_ip(subnet, 256) # ::100
range_stop = inc_ip(subnet, 65535) # ::ffff
pool = base + ['shared-network-name', shared_net_name, 'subnet', subnet]
self.cli_set(base + ['preference', preference])
self.cli_set(pool + ['interface', interface])
self.cli_set(pool + ['subnet-id', '1'])
# we use the first subnet IP address as default gateway
self.cli_set(pool + ['lease-time', 'default', lease_time])
self.cli_set(pool + ['lease-time', 'maximum', max_lease_time])
self.cli_set(pool + ['lease-time', 'minimum', min_lease_time])
self.cli_set(pool + ['option', 'capwap-controller', dns_1])
self.cli_set(pool + ['option', 'name-server', dns_1])
self.cli_set(pool + ['option', 'name-server', dns_2])
self.cli_set(pool + ['option', 'name-server', dns_2])
self.cli_set(pool + ['option', 'nis-domain', domain])
self.cli_set(pool + ['option', 'nisplus-domain', domain])
self.cli_set(pool + ['option', 'sip-server', sip_server])
self.cli_set(pool + ['option', 'sntp-server', sntp_server])
self.cli_set(pool + ['range', '1', 'start', range_start])
self.cli_set(pool + ['range', '1', 'stop', range_stop])
for server in nis_servers:
self.cli_set(pool + ['option', 'nis-server', server])
self.cli_set(pool + ['option', 'nisplus-server', server])
for search_domain in search_domains:
self.cli_set(pool + ['option', 'domain-search', search_domain])
client_base = 1
for client in ['client1', 'client2', 'client3']:
duid = f'00:01:00:01:12:34:56:78:aa:bb:cc:dd:ee:{client_base:02}'
self.cli_set(pool + ['static-mapping', client, 'duid', duid])
self.cli_set(
pool
+ [
'static-mapping',
client,
'ipv6-address',
inc_ip(subnet, client_base),
]
)
self.cli_set(
pool
+ [
'static-mapping',
client,
'ipv6-prefix',
inc_ip(subnet, client_base << 64) + '/64',
]
)
client_base += 1
# cannot have both mac-address and duid set
with self.assertRaises(ConfigSessionError):
self.cli_set(
pool + ['static-mapping', 'client1', 'mac', '00:50:00:00:00:11']
)
self.cli_commit()
self.cli_delete(pool + ['static-mapping', 'client1', 'mac'])
# commit changes
self.cli_commit()
config = read_file(kea6_conf)
obj = loads(config)
self.verify_config_value(
obj, ['Dhcp6', 'shared-networks'], 'name', shared_net_name
)
self.verify_config_value(
obj, ['Dhcp6', 'shared-networks', 0, 'subnet6'], 'subnet', subnet
)
self.verify_config_value(
obj, ['Dhcp6', 'shared-networks', 0, 'subnet6'], 'interface', interface
)
self.verify_config_value(
obj, ['Dhcp6', 'shared-networks', 0, 'subnet6'], 'id', 1
)
self.verify_config_value(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6'],
'valid-lifetime',
int(lease_time),
)
self.verify_config_value(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6'],
'min-valid-lifetime',
int(min_lease_time),
)
self.verify_config_value(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6'],
'max-valid-lifetime',
int(max_lease_time),
)
# Verify options
self.verify_config_object(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6', 0, 'option-data'],
{'name': 'capwap-ac-v6', 'data': dns_1},
)
self.verify_config_object(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6', 0, 'option-data'],
{'name': 'dns-servers', 'data': f'{dns_1}, {dns_2}'},
)
self.verify_config_object(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6', 0, 'option-data'],
{'name': 'domain-search', 'data': ', '.join(search_domains)},
)
self.verify_config_object(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6', 0, 'option-data'],
{'name': 'nis-domain-name', 'data': domain},
)
self.verify_config_object(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6', 0, 'option-data'],
{'name': 'nis-servers', 'data': ', '.join(nis_servers)},
)
self.verify_config_object(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6', 0, 'option-data'],
{'name': 'nisp-domain-name', 'data': domain},
)
self.verify_config_object(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6', 0, 'option-data'],
{'name': 'nisp-servers', 'data': ', '.join(nis_servers)},
)
self.verify_config_object(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6', 0, 'option-data'],
{'name': 'sntp-servers', 'data': sntp_server},
)
self.verify_config_object(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6', 0, 'option-data'],
{'name': 'sip-server-dns', 'data': sip_server},
)
# Verify pools
self.verify_config_object(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6', 0, 'pools'],
{'pool': f'{range_start} - {range_stop}'},
)
client_base = 1
for client in ['client1', 'client2', 'client3']:
duid = f'00:01:00:01:12:34:56:78:aa:bb:cc:dd:ee:{client_base:02}'
ip = inc_ip(subnet, client_base)
prefix = inc_ip(subnet, client_base << 64) + '/64'
self.verify_config_object(
obj,
['Dhcp6', 'shared-networks', 0, 'subnet6', 0, 'reservations'],
{
'hostname': client,
'duid': duid,
'ip-addresses': [ip],
'prefixes': [prefix],
},
)
client_base += 1
# Check for running process
self.verify_kea_service_running(process_name)
# perform cleanup
self.cli_delete(['interfaces', 'dummy', interface, 'address'])
self.cli_delete(['interfaces', 'dummy', interface, 'vrf'])
self.cli_delete(base)
self.cli_commit()
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())

File Metadata

Mime Type
text/x-diff
Expires
Sat, Oct 17, 12:18 AM (1 d, 2 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4416521
Default Alt Text
(591 KB)

Event Timeline