summaryrefslogtreecommitdiff
path: root/smoketest/scripts/cli
diff options
context:
space:
mode:
Diffstat (limited to 'smoketest/scripts/cli')
-rw-r--r--smoketest/scripts/cli/base_accel_ppp_test.py53
-rw-r--r--smoketest/scripts/cli/base_interfaces_test.py12
-rwxr-xr-xsmoketest/scripts/cli/test_firewall.py34
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_ethernet.py13
-rwxr-xr-xsmoketest/scripts/cli/test_nat.py20
-rwxr-xr-xsmoketest/scripts/cli/test_pki.py52
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bfd.py10
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bgp.py67
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcp-server.py185
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcpv6-server.py34
-rwxr-xr-xsmoketest/scripts/cli/test_service_dns_dynamic.py42
-rwxr-xr-xsmoketest/scripts/cli/test_service_dns_forwarding.py116
-rwxr-xr-xsmoketest/scripts/cli/test_service_https.py87
-rwxr-xr-xsmoketest/scripts/cli/test_service_ipoe-server.py41
-rwxr-xr-xsmoketest/scripts/cli/test_service_ntp.py33
-rwxr-xr-xsmoketest/scripts/cli/test_service_pppoe-server.py57
-rwxr-xr-xsmoketest/scripts/cli/test_system_conntrack.py8
-rwxr-xr-xsmoketest/scripts/cli/test_system_sflow.py28
-rwxr-xr-xsmoketest/scripts/cli/test_vpn_ipsec.py1
-rwxr-xr-xsmoketest/scripts/cli/test_vpn_l2tp.py54
-rwxr-xr-xsmoketest/scripts/cli/test_vpn_pptp.py6
21 files changed, 667 insertions, 286 deletions
diff --git a/smoketest/scripts/cli/base_accel_ppp_test.py b/smoketest/scripts/cli/base_accel_ppp_test.py
index 1ea5db898..6219a0a4c 100644
--- a/smoketest/scripts/cli/base_accel_ppp_test.py
+++ b/smoketest/scripts/cli/base_accel_ppp_test.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2020-2023 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -441,3 +441,54 @@ class BasicAccelPPPTest:
{second_subnet},name={second_pool},next={third_pool}
{first_subnet},name={first_pool},next={second_pool}"""
self.assertIn(pool_config, config)
+
+ def test_accel_ipv6_pool(self):
+ # Test configuration of IPv6 client pools
+ self.basic_config(is_gateway=False, is_client_pool=False)
+
+ # Enable IPv6
+ allow_ipv6 = 'allow'
+ self.set(['ppp-options', 'ipv6', allow_ipv6])
+
+ pool_name = 'ipv6_test_pool'
+ prefix_1 = '2001:db8:fffe::/56'
+ prefix_mask = '64'
+ prefix_2 = '2001:db8:ffff::/56'
+ client_prefix_1 = f'{prefix_1},{prefix_mask}'
+ client_prefix_2 = f'{prefix_2},{prefix_mask}'
+ self.set(
+ ['client-ipv6-pool', pool_name, 'prefix', prefix_1, 'mask',
+ prefix_mask])
+ self.set(
+ ['client-ipv6-pool', pool_name, 'prefix', prefix_2, 'mask',
+ prefix_mask])
+
+ delegate_1_prefix = '2001:db8:fff1::/56'
+ delegate_2_prefix = '2001:db8:fff2::/56'
+ delegate_mask = '64'
+ self.set(
+ ['client-ipv6-pool', pool_name, 'delegate', delegate_1_prefix,
+ 'delegation-prefix', delegate_mask])
+ self.set(
+ ['client-ipv6-pool', pool_name, 'delegate', delegate_2_prefix,
+ 'delegation-prefix', delegate_mask])
+
+ # commit changes
+ self.cli_commit()
+
+ # Validate configuration values
+ conf = ConfigParser(allow_no_value=True, delimiters='=',
+ strict=False)
+ conf.read(self._config_file)
+
+ for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
+ self.assertEqual(conf['modules'][tmp], None)
+
+ self.assertEqual(conf['ppp']['ipv6'], allow_ipv6)
+
+ config = self.getConfig("ipv6-pool")
+ pool_config = f"""{client_prefix_1},name={pool_name}
+{client_prefix_2},name={pool_name}
+delegate={delegate_1_prefix},{delegate_mask},name={pool_name}
+delegate={delegate_2_prefix},{delegate_mask},name={pool_name}"""
+ self.assertIn(pool_config, config)
diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py
index 3f42196f7..a40b762a8 100644
--- a/smoketest/scripts/cli/base_interfaces_test.py
+++ b/smoketest/scripts/cli/base_interfaces_test.py
@@ -179,7 +179,7 @@ class BasicInterfaceTest:
for interface in self._interfaces:
# Check if dhclient process runs
- dhclient_pid = process_named_running(dhclient_process_name, cmdline=interface)
+ 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')
@@ -216,7 +216,7 @@ class BasicInterfaceTest:
self.assertEqual(tmp, vrf_name)
# Check if dhclient process runs
- dhclient_pid = process_named_running(dhclient_process_name, cmdline=interface)
+ 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}')
@@ -251,7 +251,7 @@ class BasicInterfaceTest:
self.assertEqual(tmp, vrf_name)
# Check if dhclient process runs
- tmp = process_named_running(dhcp6c_process_name, cmdline=interface)
+ 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}')
@@ -945,7 +945,7 @@ class BasicInterfaceTest:
duid_base += 1
# Better ask the process about it's commandline in the future
- pid = process_named_running(dhcp6c_process_name, cmdline=interface)
+ pid = process_named_running(dhcp6c_process_name, cmdline=interface, timeout=10)
self.assertTrue(pid)
dhcp6c_options = read_file(f'/proc/{pid}/cmdline')
@@ -1004,7 +1004,7 @@ class BasicInterfaceTest:
address = str(int(address) + 1)
# Check for running process
- self.assertTrue(process_named_running(dhcp6c_process_name, cmdline=interface))
+ 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
@@ -1070,7 +1070,7 @@ class BasicInterfaceTest:
address = str(int(address) + 1)
# Check for running process
- self.assertTrue(process_named_running(dhcp6c_process_name, cmdline=interface))
+ 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
diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py
index 66684b265..a7dd11145 100755
--- a/smoketest/scripts/cli/test_firewall.py
+++ b/smoketest/scripts/cli/test_firewall.py
@@ -752,8 +752,10 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
### Zone
def test_zone_basic(self):
self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'default-action', 'drop'])
+ self.cli_set(['firewall', 'ipv6', 'name', 'smoketestv6', 'default-action', 'drop'])
self.cli_set(['firewall', 'zone', 'smoketest-eth0', 'interface', 'eth0'])
self.cli_set(['firewall', 'zone', 'smoketest-eth0', 'from', 'smoketest-local', 'firewall', 'name', 'smoketest'])
+ self.cli_set(['firewall', 'zone', 'smoketest-eth0', 'intra-zone-filtering', 'firewall', 'ipv6-name', 'smoketestv6'])
self.cli_set(['firewall', 'zone', 'smoketest-local', 'local-zone'])
self.cli_set(['firewall', 'zone', 'smoketest-local', 'from', 'smoketest-eth0', 'firewall', 'name', 'smoketest'])
self.cli_set(['firewall', 'global-options', 'state-policy', 'established', 'action', 'accept'])
@@ -785,16 +787,30 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
['ct state related', 'accept']
]
- nftables_output = cmd('sudo nft list table ip vyos_filter')
-
- 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(matched)
+ nftables_search_v6 = [
+ ['chain VYOS_ZONE_FORWARD'],
+ ['type filter hook forward priority filter + 1'],
+ ['chain VYOS_ZONE_OUTPUT'],
+ ['type filter hook output priority filter + 1'],
+ ['chain VYOS_ZONE_LOCAL'],
+ ['type filter hook input priority filter + 1'],
+ ['chain VZONE_smoketest-eth0'],
+ ['chain VZONE_smoketest-local_IN'],
+ ['chain VZONE_smoketest-local_OUT'],
+ ['oifname "eth0"', 'jump VZONE_smoketest-eth0'],
+ ['jump VZONE_smoketest-local_IN'],
+ ['jump VZONE_smoketest-local_OUT'],
+ ['iifname "eth0"', 'jump NAME6_smoketestv6'],
+ ['jump VYOS_STATE_POLICY6'],
+ ['chain VYOS_STATE_POLICY6'],
+ ['ct state established', 'log prefix "[STATE-POLICY-EST-A]"', 'accept'],
+ ['ct state invalid', 'drop'],
+ ['ct state related', 'accept']
+ ]
+ nftables_output = cmd('sudo nft list table ip vyos_filter')
+ self.verify_nftables(nftables_search, 'ip vyos_filter')
+ self.verify_nftables(nftables_search_v6, 'ip6 vyos_filter')
def test_flow_offload(self):
self.cli_set(['firewall', 'flowtable', 'smoketest', 'interface', 'eth0'])
diff --git a/smoketest/scripts/cli/test_interfaces_ethernet.py b/smoketest/scripts/cli/test_interfaces_ethernet.py
index a39b81348..e414f18cb 100755
--- a/smoketest/scripts/cli/test_interfaces_ethernet.py
+++ b/smoketest/scripts/cli/test_interfaces_ethernet.py
@@ -141,15 +141,18 @@ class EthernetInterfaceTest(BasicInterfaceTest.TestCase):
# Verify that no address remains on the system as this is an eternal
# interface.
- for intf in self._interfaces:
- self.assertNotIn(AF_INET, ifaddresses(intf))
+ for interface in self._interfaces:
+ self.assertNotIn(AF_INET, ifaddresses(interface))
# required for IPv6 link-local address
- self.assertIn(AF_INET6, ifaddresses(intf))
- for addr in ifaddresses(intf)[AF_INET6]:
+ 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(intf, addr['addr']))
+ 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,
diff --git a/smoketest/scripts/cli/test_nat.py b/smoketest/scripts/cli/test_nat.py
index 682fc141d..1e6435df8 100755
--- a/smoketest/scripts/cli/test_nat.py
+++ b/smoketest/scripts/cli/test_nat.py
@@ -292,5 +292,25 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):
self.verify_nftables(nftables_search, 'ip vyos_nat')
+ def test_snat_net_port_map(self):
+ self.cli_set(src_path + ['rule', '10', 'protocol', 'tcp_udp'])
+ self.cli_set(src_path + ['rule', '10', 'source', 'address', '100.64.0.0/25'])
+ self.cli_set(src_path + ['rule', '10', 'translation', 'address', '203.0.113.0/25'])
+ self.cli_set(src_path + ['rule', '10', 'translation', 'port', '1025-3072'])
+
+ self.cli_set(src_path + ['rule', '20', 'protocol', 'tcp_udp'])
+ self.cli_set(src_path + ['rule', '20', 'source', 'address', '100.64.0.128/25'])
+ self.cli_set(src_path + ['rule', '20', 'translation', 'address', '203.0.113.128/25'])
+ self.cli_set(src_path + ['rule', '20', 'translation', 'port', '1025-3072'])
+
+ self.cli_commit()
+
+ nftables_search = [
+ ['meta l4proto { tcp, udp }', 'snat ip prefix to ip saddr map { 100.64.0.0/25 : 203.0.113.0/25 . 1025-3072 }', 'comment "SRC-NAT-10"'],
+ ['meta l4proto { tcp, udp }', 'snat ip prefix to ip saddr map { 100.64.0.128/25 : 203.0.113.128/25 . 1025-3072 }', 'comment "SRC-NAT-20"']
+ ]
+
+ self.verify_nftables(nftables_search, 'ip vyos_nat')
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_pki.py b/smoketest/scripts/cli/test_pki.py
index 2ccc63b2c..02beafb26 100755
--- a/smoketest/scripts/cli/test_pki.py
+++ b/smoketest/scripts/cli/test_pki.py
@@ -19,6 +19,8 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
+from vyos.utils.file import read_file
+
base_path = ['pki']
valid_ca_cert = """
@@ -153,10 +155,10 @@ class TestPKI(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestPKI, 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, ['service', 'https'])
def tearDown(self):
self.cli_delete(base_path)
@@ -181,68 +183,72 @@ class TestPKI(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
def test_invalid_ca_valid_certificate(self):
- self.cli_set(base_path + ['ca', 'smoketest', 'certificate', valid_cert.replace('\n','')])
+ self.cli_set(base_path + ['ca', 'invalid-ca', 'certificate', valid_cert.replace('\n','')])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
def test_certificate_in_use(self):
- self.cli_set(base_path + ['certificate', 'smoketest', 'certificate', valid_ca_cert.replace('\n','')])
- self.cli_set(base_path + ['certificate', 'smoketest', 'private', 'key', valid_ca_private_key.replace('\n','')])
+ cert_name = 'smoketest'
+
+ self.cli_set(base_path + ['certificate', cert_name, 'certificate', valid_ca_cert.replace('\n','')])
+ self.cli_set(base_path + ['certificate', cert_name, 'private', 'key', valid_ca_private_key.replace('\n','')])
self.cli_commit()
- self.cli_set(['service', 'https', 'certificates', 'certificate', 'smoketest'])
+ self.cli_set(['service', 'https', 'certificates', 'certificate', cert_name])
self.cli_commit()
- self.cli_delete(base_path + ['certificate', 'smoketest'])
+ self.cli_delete(base_path + ['certificate', cert_name])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_delete(['service', 'https', 'certificates', 'certificate'])
def test_certificate_https_update(self):
- self.cli_set(base_path + ['certificate', 'smoketest', 'certificate', valid_ca_cert.replace('\n','')])
- self.cli_set(base_path + ['certificate', 'smoketest', 'private', 'key', valid_ca_private_key.replace('\n','')])
+ cert_name = 'smoke-test_foo'
+ cert_path = f'/run/nginx/certs/{cert_name}_cert.pem'
+ self.cli_set(base_path + ['certificate', cert_name, 'certificate', valid_ca_cert.replace('\n','')])
+ self.cli_set(base_path + ['certificate', cert_name, 'private', 'key', valid_ca_private_key.replace('\n','')])
self.cli_commit()
- self.cli_set(['service', 'https', 'certificates', 'certificate', 'smoketest'])
+ self.cli_set(['service', 'https', 'certificates', 'certificate', cert_name])
self.cli_commit()
cert_data = None
- with open('/etc/ssl/certs/smoketest.pem') as f:
- cert_data = f.read()
+ cert_data = read_file(cert_path)
- self.cli_set(base_path + ['certificate', 'smoketest', 'certificate', valid_update_cert.replace('\n','')])
- self.cli_set(base_path + ['certificate', 'smoketest', 'private', 'key', valid_update_private_key.replace('\n','')])
+ self.cli_set(base_path + ['certificate', cert_name, 'certificate', valid_update_cert.replace('\n','')])
+ self.cli_set(base_path + ['certificate', cert_name, 'private', 'key', valid_update_private_key.replace('\n','')])
self.cli_commit()
- with open('/etc/ssl/certs/smoketest.pem') as f:
- self.assertNotEqual(cert_data, f.read())
+ self.assertNotEqual(cert_data, read_file(cert_path))
self.cli_delete(['service', 'https', 'certificates', 'certificate'])
def test_certificate_eapol_update(self):
- self.cli_set(base_path + ['certificate', 'smoketest', 'certificate', valid_ca_cert.replace('\n','')])
- self.cli_set(base_path + ['certificate', 'smoketest', 'private', 'key', valid_ca_private_key.replace('\n','')])
+ cert_name = 'eapol'
+ interface = 'eth1'
+ self.cli_set(base_path + ['certificate', cert_name, 'certificate', valid_ca_cert.replace('\n','')])
+ self.cli_set(base_path + ['certificate', cert_name, 'private', 'key', valid_ca_private_key.replace('\n','')])
self.cli_commit()
- self.cli_set(['interfaces', 'ethernet', 'eth1', 'eapol', 'certificate', 'smoketest'])
+ self.cli_set(['interfaces', 'ethernet', interface, 'eapol', 'certificate', cert_name])
self.cli_commit()
cert_data = None
- with open('/run/wpa_supplicant/eth1_cert.pem') as f:
+ with open(f'/run/wpa_supplicant/{interface}_cert.pem') as f:
cert_data = f.read()
- self.cli_set(base_path + ['certificate', 'smoketest', 'certificate', valid_update_cert.replace('\n','')])
- self.cli_set(base_path + ['certificate', 'smoketest', 'private', 'key', valid_update_private_key.replace('\n','')])
+ self.cli_set(base_path + ['certificate', cert_name, 'certificate', valid_update_cert.replace('\n','')])
+ self.cli_set(base_path + ['certificate', cert_name, 'private', 'key', valid_update_private_key.replace('\n','')])
self.cli_commit()
- with open('/run/wpa_supplicant/eth1_cert.pem') as f:
+ with open(f'/run/wpa_supplicant/{interface}_cert.pem') as f:
self.assertNotEqual(cert_data, f.read())
- self.cli_delete(['interfaces', 'ethernet', 'eth1', 'eapol'])
+ self.cli_delete(['interfaces', 'ethernet', interface, 'eapol'])
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py
index f209eae3a..716d0a806 100755
--- a/smoketest/scripts/cli/test_protocols_bfd.py
+++ b/smoketest/scripts/cli/test_protocols_bfd.py
@@ -32,6 +32,7 @@ peers = {
'multihop' : '',
'source_addr': '192.0.2.254',
'profile' : 'foo-bar-baz',
+ 'minimum_ttl': '20',
},
'192.0.2.20' : {
'echo_mode' : '',
@@ -63,6 +64,7 @@ profiles = {
'intv_rx' : '222',
'intv_tx' : '333',
'shutdown' : '',
+ 'minimum_ttl': '40',
},
'foo-bar-baz' : {
'intv_mult' : '4',
@@ -109,6 +111,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase):
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:
@@ -152,6 +156,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase):
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:
@@ -173,6 +179,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase):
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:
@@ -210,6 +218,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase):
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:
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index ebc9eeaaa..2dbc30a41 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -1139,10 +1139,16 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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}')
@@ -1151,7 +1157,64 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' locator {locator_name}', frrconfig)
self.assertIn(f' sid vpn per-vrf export {sid}', frrconfig)
- def test_bgp_25_bmp(self):
+ # 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}')
+ 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(' address-family ipv4 unicast')
+ self.assertIn(f' sid vpn export {sid}', afiv4_config)
+ self.assertIn(f' nexthop vpn export {nexthop_ipv4}', afiv4_config)
+ afiv6_config = self.getFRRconfig(' address-family ipv6 unicast')
+ self.assertIn(f' sid vpn export {sid}', afiv6_config)
+ self.assertIn(f' nexthop vpn export {nexthop_ipv6}', afiv4_config)
+
+ def test_bgp_25_ipv4_ipv6_labeled_unicast_peer_group(self):
+ pg_ipv4 = 'foo4'
+ pg_ipv6 = 'foo6'
+
+ ipv4_max_prefix = '20'
+ ipv6_max_prefix = '200'
+ ipv4_prefix = '192.0.2.0/24'
+ ipv6_prefix = '2001:db8:1000::/64'
+
+ self.cli_set(base_path + ['listen', 'range', ipv4_prefix, 'peer-group', pg_ipv4])
+ self.cli_set(base_path + ['listen', 'range', ipv6_prefix, 'peer-group', pg_ipv6])
+
+ 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_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}')
+ 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' neighbor {pg_ipv6} peer-group', frrconfig)
+ self.assertIn(f' neighbor {pg_ipv6} remote-as external', frrconfig)
+ self.assertIn(f' bgp listen range {ipv4_prefix} peer-group {pg_ipv4}', frrconfig)
+ self.assertIn(f' bgp listen range {ipv6_prefix} peer-group {pg_ipv6}', frrconfig)
+
+ afiv4_config = self.getFRRconfig(' address-family ipv4 labeled-unicast')
+ self.assertIn(f' neighbor {pg_ipv4} activate', afiv4_config)
+ self.assertIn(f' neighbor {pg_ipv4} maximum-prefix {ipv4_max_prefix}', afiv4_config)
+
+ afiv6_config = self.getFRRconfig(' address-family ipv6 labeled-unicast')
+ 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_99_bmp(self):
target_name = 'instance-bmp'
target_address = '127.0.0.1'
target_port = '5000'
diff --git a/smoketest/scripts/cli/test_service_dhcp-server.py b/smoketest/scripts/cli/test_service_dhcp-server.py
index bf0c09965..194289567 100755
--- a/smoketest/scripts/cli/test_service_dhcp-server.py
+++ b/smoketest/scripts/cli/test_service_dhcp-server.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2021 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -32,6 +32,7 @@ CTRL_PROCESS_NAME = 'kea-ctrl-agent'
KEA4_CONF = '/run/kea/kea-dhcp4.conf'
KEA4_CTRL = '/run/kea/dhcp4-ctrl-socket'
base_path = ['service', 'dhcp-server']
+interface = 'dum8765'
subnet = '192.0.2.0/25'
router = inc_ip(subnet, 1)
dns_1 = inc_ip(subnet, 2)
@@ -46,11 +47,11 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
cls.cli_delete(cls, base_path)
cidr_mask = subnet.split('/')[-1]
- cls.cli_set(cls, ['interfaces', 'dummy', 'dum8765', 'address', f'{router}/{cidr_mask}'])
+ cls.cli_set(cls, ['interfaces', 'dummy', interface, 'address', f'{router}/{cidr_mask}'])
@classmethod
def tearDownClass(cls):
- cls.cli_delete(cls, ['interfaces', 'dummy', 'dum8765'])
+ cls.cli_delete(cls, ['interfaces', 'dummy', interface])
super(TestServiceDHCPServer, cls).tearDownClass()
def tearDown(self):
@@ -95,12 +96,15 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
range_1_start = inc_ip(subnet, 40)
range_1_stop = inc_ip(subnet, 50)
+ self.cli_set(base_path + ['listen-interface', interface])
+
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
+ self.cli_set(pool + ['subnet-id', '1'])
# we use the first subnet IP address as default gateway
- self.cli_set(pool + ['default-router', router])
- self.cli_set(pool + ['name-server', dns_1])
- self.cli_set(pool + ['name-server', dns_2])
- self.cli_set(pool + ['domain-name', domain_name])
+ 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):
@@ -116,8 +120,10 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
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'], 'valid-lifetime', 86400)
self.verify_config_value(obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'max-valid-lifetime', 86400)
@@ -164,30 +170,28 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
ipv6_only_preferred = '300'
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
+ self.cli_set(pool + ['subnet-id', '1'])
# we use the first subnet IP address as default gateway
- self.cli_set(pool + ['default-router', router])
- self.cli_set(pool + ['name-server', dns_1])
- self.cli_set(pool + ['name-server', dns_2])
- self.cli_set(pool + ['domain-name', domain_name])
- self.cli_set(pool + ['ip-forwarding'])
- self.cli_set(pool + ['smtp-server', smtp_server])
- self.cli_set(pool + ['pop-server', smtp_server])
- self.cli_set(pool + ['time-server', time_server])
- self.cli_set(pool + ['tftp-server-name', tftp_server])
+ 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])
+ self.cli_set(pool + ['option', 'ip-forwarding'])
+ self.cli_set(pool + ['option', 'smtp-server', smtp_server])
+ self.cli_set(pool + ['option', 'pop-server', smtp_server])
+ self.cli_set(pool + ['option', 'time-server', time_server])
+ self.cli_set(pool + ['option', 'tftp-server-name', tftp_server])
for search in search_domains:
- self.cli_set(pool + ['domain-search', search])
- self.cli_set(pool + ['bootfile-name', bootfile_name])
- self.cli_set(pool + ['bootfile-server', bootfile_server])
- self.cli_set(pool + ['wpad-url', wpad])
- self.cli_set(pool + ['server-identifier', server_identifier])
+ self.cli_set(pool + ['option', 'domain-search', search])
+ self.cli_set(pool + ['option', 'bootfile-name', bootfile_name])
+ self.cli_set(pool + ['option', 'bootfile-server', bootfile_server])
+ self.cli_set(pool + ['option', 'wpad-url', wpad])
+ self.cli_set(pool + ['option', 'server-identifier', server_identifier])
- self.cli_set(pool + ['static-route', '10.0.0.0/24', 'next-hop', '192.0.2.1'])
- self.cli_set(pool + ['ipv6-only-preferred', ipv6_only_preferred])
- self.cli_set(pool + ['time-zone', 'Europe/London'])
+ self.cli_set(pool + ['option', 'static-route', '10.0.0.0/24', 'next-hop', '192.0.2.1'])
+ self.cli_set(pool + ['option', 'ipv6-only-preferred', ipv6_only_preferred])
+ self.cli_set(pool + ['option', 'time-zone', 'Europe/London'])
- # 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])
@@ -281,16 +285,85 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
# Check for running process
self.assertTrue(process_named_running(PROCESS_NAME))
+ def test_dhcp_single_pool_options_scoped(self):
+ shared_net_name = 'SMOKE-2'
+
+ range_0_start = inc_ip(subnet, 10)
+ range_0_stop = inc_ip(subnet, 20)
+
+ range_router = inc_ip(subnet, 5)
+ range_dns_1 = inc_ip(subnet, 6)
+ range_dns_2 = inc_ip(subnet, 7)
+
+ shared_network = base_path + ['shared-network-name', shared_net_name]
+ pool = shared_network + ['subnet', subnet]
+
+ self.cli_set(pool + ['subnet-id', '1'])
+
+ # we use the first subnet IP address as default gateway
+ self.cli_set(shared_network + ['option', 'default-router', router])
+ self.cli_set(shared_network + ['option', 'name-server', dns_1])
+ self.cli_set(shared_network + ['option', 'name-server', dns_2])
+ self.cli_set(shared_network + ['option', 'domain-name', domain_name])
+
+ 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', '0', 'option', 'default-router', range_router])
+ self.cli_set(pool + ['range', '0', 'option', 'name-server', range_dns_1])
+ self.cli_set(pool + ['range', '0', 'option', 'name-server', range_dns_2])
+
+ # commit changes
+ self.cli_commit()
+
+ config = read_file(KEA4_CONF)
+ obj = loads(config)
+
+ 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'], 'valid-lifetime', 86400)
+ self.verify_config_value(obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'max-valid-lifetime', 86400)
+
+ # Verify shared-network options
+ self.verify_config_object(
+ obj,
+ ['Dhcp4', 'shared-networks', 0, 'option-data'],
+ {'name': 'domain-name', 'data': domain_name})
+ self.verify_config_object(
+ obj,
+ ['Dhcp4', 'shared-networks', 0, 'option-data'],
+ {'name': 'domain-name-servers', 'data': f'{dns_1}, {dns_2}'})
+ self.verify_config_object(
+ obj,
+ ['Dhcp4', 'shared-networks', 0, 'option-data'],
+ {'name': 'routers', 'data': router})
+
+ # Verify range options
+ self.verify_config_object(
+ obj,
+ ['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'pools', 0, 'option-data'],
+ {'name': 'domain-name-servers', 'data': f'{range_dns_1}, {range_dns_2}'})
+ self.verify_config_object(
+ obj,
+ ['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'pools', 0, 'option-data'],
+ {'name': 'routers', 'data': range_router})
+
+ # Verify pool
+ self.verify_config_value(obj, ['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'pools'], 'pool', f'{range_0_start} - {range_0_stop}')
+
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
def test_dhcp_single_pool_static_mapping(self):
shared_net_name = 'SMOKE-2'
domain_name = 'private'
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
+ self.cli_set(pool + ['subnet-id', '1'])
# we use the first subnet IP address as default gateway
- self.cli_set(pool + ['default-router', router])
- self.cli_set(pool + ['name-server', dns_1])
- self.cli_set(pool + ['name-server', dns_2])
- self.cli_set(pool + ['domain-name', domain_name])
+ 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):
@@ -309,6 +382,34 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
self.cli_delete(pool + ['static-mapping', 'client1', 'duid'])
+ # cannot have mappings with duplicate IP addresses
+ self.cli_set(pool + ['static-mapping', 'dupe1', 'mac', '00:50:00:00:fe:ff'])
+ self.cli_set(pool + ['static-mapping', 'dupe1', 'ip-address', inc_ip(subnet, 10)])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ # Should allow disabled duplicate
+ self.cli_set(pool + ['static-mapping', 'dupe1', 'disable'])
+ self.cli_commit()
+ self.cli_delete(pool + ['static-mapping', 'dupe1'])
+
+ # cannot have mappings with duplicate MAC addresses
+ self.cli_set(pool + ['static-mapping', 'dupe2', 'mac', '00:50:00:00:00:10'])
+ self.cli_set(pool + ['static-mapping', 'dupe2', 'ip-address', inc_ip(subnet, 120)])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(pool + ['static-mapping', 'dupe2'])
+
+
+ # cannot have mappings with duplicate MAC addresses
+ self.cli_set(pool + ['static-mapping', 'dupe3', 'duid', '00:01:02:03:04:05:06:07:aa:aa:aa:aa:aa:01'])
+ self.cli_set(pool + ['static-mapping', 'dupe3', 'ip-address', inc_ip(subnet, 121)])
+ self.cli_set(pool + ['static-mapping', 'dupe4', 'duid', '00:01:02:03:04:05:06:07:aa:aa:aa:aa:aa:01'])
+ self.cli_set(pool + ['static-mapping', 'dupe4', 'ip-address', inc_ip(subnet, 121)])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(pool + ['static-mapping', 'dupe3'])
+ self.cli_delete(pool + ['static-mapping', 'dupe4'])
+
# commit changes
self.cli_commit()
@@ -317,6 +418,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
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'], 'valid-lifetime', 86400)
self.verify_config_value(obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'max-valid-lifetime', 86400)
@@ -364,10 +466,11 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
range_1_stop = inc_ip(subnet, 40)
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
+ self.cli_set(pool + ['subnet-id', str(int(network) + 1)])
# we use the first subnet IP address as default gateway
- self.cli_set(pool + ['default-router', router])
- self.cli_set(pool + ['name-server', dns_1])
- self.cli_set(pool + ['domain-name', domain_name])
+ self.cli_set(pool + ['option', 'default-router', router])
+ self.cli_set(pool + ['option', 'name-server', dns_1])
+ self.cli_set(pool + ['option', 'domain-name', domain_name])
self.cli_set(pool + ['lease', lease_time])
self.cli_set(pool + ['range', '0', 'start', range_0_start])
@@ -401,6 +504,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
self.verify_config_value(obj, ['Dhcp4', 'shared-networks'], 'name', shared_net_name)
self.verify_config_value(obj, ['Dhcp4', 'shared-networks', int(network), 'subnet4'], 'subnet', subnet)
+ self.verify_config_value(obj, ['Dhcp4', 'shared-networks', int(network), 'subnet4'], 'id', int(network) + 1)
self.verify_config_value(obj, ['Dhcp4', 'shared-networks', int(network), 'subnet4'], 'valid-lifetime', int(lease_time))
self.verify_config_value(obj, ['Dhcp4', 'shared-networks', int(network), 'subnet4'], 'max-valid-lifetime', int(lease_time))
@@ -448,7 +552,8 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
range_0_stop = inc_ip(subnet, 20)
pool = base_path + ['shared-network-name', 'EXCLUDE-TEST', 'subnet', subnet]
- self.cli_set(pool + ['default-router', router])
+ self.cli_set(pool + ['subnet-id', '1'])
+ self.cli_set(pool + ['option', 'default-router', router])
self.cli_set(pool + ['exclude', router])
self.cli_set(pool + ['range', '0', 'start', range_0_start])
self.cli_set(pool + ['range', '0', 'stop', range_0_stop])
@@ -490,7 +595,8 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
range_0_start_excl = inc_ip(exclude_addr, 1)
pool = base_path + ['shared-network-name', 'EXCLUDE-TEST-2', 'subnet', subnet]
- self.cli_set(pool + ['default-router', router])
+ self.cli_set(pool + ['subnet-id', '1'])
+ self.cli_set(pool + ['option', 'default-router', router])
self.cli_set(pool + ['exclude', exclude_addr])
self.cli_set(pool + ['range', '0', 'start', range_0_start])
self.cli_set(pool + ['range', '0', 'stop', range_0_stop])
@@ -535,7 +641,8 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
range_0_stop = '10.0.250.255'
pool = base_path + ['shared-network-name', 'RELAY', 'subnet', relay_subnet]
- self.cli_set(pool + ['default-router', relay_router])
+ self.cli_set(pool + ['subnet-id', '1'])
+ self.cli_set(pool + ['option', 'default-router', relay_router])
self.cli_set(pool + ['range', '0', 'start', range_0_start])
self.cli_set(pool + ['range', '0', 'stop', range_0_stop])
@@ -545,6 +652,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
config = read_file(KEA4_CONF)
obj = loads(config)
+ self.verify_config_value(obj, ['Dhcp4', 'interfaces-config'], 'interfaces', [f'{interface}/{router}'])
self.verify_config_value(obj, ['Dhcp4', 'shared-networks'], 'name', 'RELAY')
self.verify_config_value(obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'subnet', relay_subnet)
@@ -571,8 +679,9 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
range_0_stop = inc_ip(subnet, 20)
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
+ self.cli_set(pool + ['subnet-id', '1'])
# we use the first subnet IP address as default gateway
- self.cli_set(pool + ['default-router', router])
+ self.cli_set(pool + ['option', 'default-router', router])
# check validate() - No DHCP address range or active static-mapping set
with self.assertRaises(ConfigSessionError):
diff --git a/smoketest/scripts/cli/test_service_dhcpv6-server.py b/smoketest/scripts/cli/test_service_dhcpv6-server.py
index f163cc69a..dcce30f55 100755
--- a/smoketest/scripts/cli/test_service_dhcpv6-server.py
+++ b/smoketest/scripts/cli/test_service_dhcpv6-server.py
@@ -102,26 +102,27 @@ class TestServiceDHCPv6Server(VyOSUnitTestSHIM.TestCase):
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
self.cli_set(base_path + ['preference', preference])
-
+ self.cli_set(pool + ['subnet-id', '1'])
# we use the first subnet IP address as default gateway
- self.cli_set(pool + ['name-server', dns_1])
- self.cli_set(pool + ['name-server', dns_2])
- self.cli_set(pool + ['name-server', dns_2])
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 + ['nis-domain', domain])
- self.cli_set(pool + ['nisplus-domain', domain])
- self.cli_set(pool + ['sip-server', sip_server])
- self.cli_set(pool + ['sntp-server', sntp_server])
- self.cli_set(pool + ['address-range', 'start', range_start, 'stop', range_stop])
+ 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 + ['nis-server', server])
- self.cli_set(pool + ['nisplus-server', server])
+ self.cli_set(pool + ['option', 'nis-server', server])
+ self.cli_set(pool + ['option', 'nisplus-server', server])
for search in search_domains:
- self.cli_set(pool + ['domain-search', search])
+ self.cli_set(pool + ['option', 'domain-search', search])
client_base = 1
for client in ['client1', 'client2', 'client3']:
@@ -145,6 +146,7 @@ class TestServiceDHCPv6Server(VyOSUnitTestSHIM.TestCase):
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'], '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))
@@ -215,8 +217,9 @@ class TestServiceDHCPv6Server(VyOSUnitTestSHIM.TestCase):
prefix_len = '56'
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
-
- self.cli_set(pool + ['address-range', 'start', range_start, 'stop', range_stop])
+ self.cli_set(pool + ['subnet-id', '1'])
+ self.cli_set(pool + ['range', '1', 'start', range_start])
+ self.cli_set(pool + ['range', '1', 'stop', range_stop])
self.cli_set(pool + ['prefix-delegation', 'prefix', delegate_start, 'delegated-length', delegate_len])
self.cli_set(pool + ['prefix-delegation', 'prefix', delegate_start, 'prefix-length', prefix_len])
@@ -250,7 +253,7 @@ class TestServiceDHCPv6Server(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['global-parameters', 'name-server', ns_global_1])
self.cli_set(base_path + ['global-parameters', 'name-server', ns_global_2])
- self.cli_set(base_path + ['shared-network-name', shared_net_name, 'subnet', subnet])
+ self.cli_set(base_path + ['shared-network-name', shared_net_name, 'subnet', subnet, 'subnet-id', '1'])
# commit changes
self.cli_commit()
@@ -260,6 +263,7 @@ class TestServiceDHCPv6Server(VyOSUnitTestSHIM.TestCase):
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'], 'id', 1)
self.verify_config_object(
obj,
diff --git a/smoketest/scripts/cli/test_service_dns_dynamic.py b/smoketest/scripts/cli/test_service_dns_dynamic.py
index ae46b18ba..c39d4467a 100755
--- a/smoketest/scripts/cli/test_service_dns_dynamic.py
+++ b/smoketest/scripts/cli/test_service_dns_dynamic.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -62,7 +62,7 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
'zoneedit': {'protocol': 'zoneedit1', 'username': username}}
for svc, details in services.items():
- self.cli_set(name_path + [svc, 'address', interface])
+ self.cli_set(name_path + [svc, 'address', 'interface', interface])
self.cli_set(name_path + [svc, 'host-name', hostname])
self.cli_set(name_path + [svc, 'password', password])
for opt, value in details.items():
@@ -118,7 +118,7 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
expiry_time_bad = '360'
self.cli_set(base_path + ['interval', interval])
- self.cli_set(svc_path + ['address', interface])
+ self.cli_set(svc_path + ['address', 'interface', interface])
self.cli_set(svc_path + ['ip-version', ip_version])
self.cli_set(svc_path + ['protocol', proto])
self.cli_set(svc_path + ['server', server])
@@ -156,7 +156,7 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
ip_version = 'both'
for name, details in services.items():
- self.cli_set(name_path + [name, 'address', interface])
+ self.cli_set(name_path + [name, 'address', 'interface', interface])
self.cli_set(name_path + [name, 'host-name', hostname])
self.cli_set(name_path + [name, 'password', password])
for opt, value in details.items():
@@ -201,7 +201,7 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
with tempfile.NamedTemporaryFile(prefix='/config/auth/') as key_file:
key_file.write(b'S3cretKey')
- self.cli_set(svc_path + ['address', interface])
+ self.cli_set(svc_path + ['address', 'interface', interface])
self.cli_set(svc_path + ['protocol', proto])
self.cli_set(svc_path + ['server', server])
self.cli_set(svc_path + ['zone', zone])
@@ -229,7 +229,7 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
hostnames = ['@', 'www', hostname, f'@.{hostname}']
for name in hostnames:
- self.cli_set(svc_path + ['address', interface])
+ self.cli_set(svc_path + ['address', 'interface', interface])
self.cli_set(svc_path + ['protocol', proto])
self.cli_set(svc_path + ['server', server])
self.cli_set(svc_path + ['username', username])
@@ -251,38 +251,38 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
# Check if DDNS service can be configured and runs
svc_path = name_path + ['cloudflare']
proto = 'cloudflare'
- web_url_good = 'https://ifconfig.me/ip'
- web_url_bad = 'http:/ifconfig.me/ip'
+ web_url = 'https://ifconfig.me/ip'
+ web_skip = 'Current IP Address:'
self.cli_set(svc_path + ['protocol', proto])
self.cli_set(svc_path + ['zone', zone])
self.cli_set(svc_path + ['password', password])
self.cli_set(svc_path + ['host-name', hostname])
- self.cli_set(svc_path + ['web-options', 'url', web_url_good])
- # web-options is supported only with web service based address lookup
- # exception is raised for interface based address lookup
+ # not specifying either 'interface' or 'web' will raise an exception
with self.assertRaises(ConfigSessionError):
- self.cli_set(svc_path + ['address', interface])
self.cli_commit()
self.cli_set(svc_path + ['address', 'web'])
- # commit changes
+ # specifying both 'interface' and 'web' will raise an exception as well
+ with self.assertRaises(ConfigSessionError):
+ self.cli_set(svc_path + ['address', 'interface', interface])
+ self.cli_commit()
+ self.cli_delete(svc_path + ['address', 'interface'])
self.cli_commit()
- # web-options must be a valid URL
+ # web option 'skip' is useless without the option 'url'
with self.assertRaises(ConfigSessionError):
- self.cli_set(svc_path + ['web-options', 'url', web_url_bad])
+ self.cli_set(svc_path + ['address', 'web', 'skip', web_skip])
self.cli_commit()
- self.cli_set(svc_path + ['web-options', 'url', web_url_good])
-
- # commit changes
+ self.cli_set(svc_path + ['address', 'web', 'url', web_url])
self.cli_commit()
# Check the generating config parameters
ddclient_conf = cmd(f'sudo cat {DDCLIENT_CONF}')
self.assertIn(f'usev4=webv4', ddclient_conf)
- self.assertIn(f'webv4={web_url_good}', ddclient_conf)
+ self.assertIn(f'webv4={web_url}', ddclient_conf)
+ self.assertIn(f'webv4-skip=\'{web_skip}\'', ddclient_conf)
self.assertIn(f'protocol={proto}', ddclient_conf)
self.assertIn(f'zone={zone}', ddclient_conf)
self.assertIn(f'password=\'{password}\'', ddclient_conf)
@@ -294,7 +294,7 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
proto = 'namecheap'
dyn_interface = 'pppoe587'
- self.cli_set(svc_path + ['address', dyn_interface])
+ self.cli_set(svc_path + ['address', 'interface', dyn_interface])
self.cli_set(svc_path + ['protocol', proto])
self.cli_set(svc_path + ['server', server])
self.cli_set(svc_path + ['username', username])
@@ -327,7 +327,7 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
self.cli_set(['vrf', 'name', vrf_name, 'table', vrf_table])
self.cli_set(base_path + ['vrf', vrf_name])
- self.cli_set(svc_path + ['address', interface])
+ self.cli_set(svc_path + ['address', 'interface', interface])
self.cli_set(svc_path + ['protocol', proto])
self.cli_set(svc_path + ['host-name', hostname])
self.cli_set(svc_path + ['zone', zone])
diff --git a/smoketest/scripts/cli/test_service_dns_forwarding.py b/smoketest/scripts/cli/test_service_dns_forwarding.py
index bc50a4ffe..079c584ba 100755
--- a/smoketest/scripts/cli/test_service_dns_forwarding.py
+++ b/smoketest/scripts/cli/test_service_dns_forwarding.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2022 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -24,9 +24,10 @@ from vyos.template import bracketize_ipv6
from vyos.utils.file import read_file
from vyos.utils.process import process_named_running
-CONFIG_FILE = '/run/powerdns/recursor.conf'
-FORWARD_FILE = '/run/powerdns/recursor.forward-zones.conf'
-HOSTSD_FILE = '/run/powerdns/recursor.vyos-hostsd.conf.lua'
+PDNS_REC_RUN_DIR = '/run/pdns-recursor'
+CONFIG_FILE = f'{PDNS_REC_RUN_DIR}/recursor.conf'
+FORWARD_FILE = f'{PDNS_REC_RUN_DIR}/recursor.forward-zones.conf'
+HOSTSD_FILE = f'{PDNS_REC_RUN_DIR}/recursor.vyos-hostsd.conf.lua'
PROCESS_NAME= 'pdns_recursor'
base_path = ['service', 'dns', 'forwarding']
@@ -43,7 +44,6 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestServicePowerDNS, 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)
@@ -59,11 +59,23 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
# Check for running process
self.assertFalse(process_named_running(PROCESS_NAME))
+ def setUp(self):
+ # forward to base class
+ super().setUp()
+ for network in allow_from:
+ self.cli_set(base_path + ['allow-from', network])
+ for address in listen_adress:
+ self.cli_set(base_path + ['listen-address', address])
+
def test_basic_forwarding(self):
# Check basic DNS forwarding settings
cache_size = '20'
negative_ttl = '120'
+ # remove code from setUp() as in this test-case we validate the proper
+ # handling of assertions when specific CLI nodes are missing
+ self.cli_delete(base_path)
+
self.cli_set(base_path + ['cache-size', cache_size])
self.cli_set(base_path + ['negative-ttl', negative_ttl])
@@ -118,12 +130,6 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
def test_dnssec(self):
# DNSSEC option testing
-
- for network in allow_from:
- self.cli_set(base_path + ['allow-from', network])
- for address in listen_adress:
- self.cli_set(base_path + ['listen-address', address])
-
options = ['off', 'process-no-validate', 'process', 'log-fail', 'validate']
for option in options:
self.cli_set(base_path + ['dnssec', option])
@@ -136,12 +142,6 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
def test_external_nameserver(self):
# Externe Domain Name Servers (DNS) addresses
-
- for network in allow_from:
- self.cli_set(base_path + ['allow-from', network])
- for address in listen_adress:
- self.cli_set(base_path + ['listen-address', address])
-
nameservers = {'192.0.2.1': {}, '192.0.2.2': {'port': '53'}, '2001:db8::1': {'port': '853'}}
for h,p in nameservers.items():
if 'port' in p:
@@ -163,11 +163,6 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
self.assertEqual(tmp, 'yes')
def test_domain_forwarding(self):
- for network in allow_from:
- self.cli_set(base_path + ['allow-from', network])
- for address in listen_adress:
- self.cli_set(base_path + ['listen-address', address])
-
domains = ['vyos.io', 'vyos.net', 'vyos.com']
nameservers = {'192.0.2.1': {}, '192.0.2.2': {'port': '53'}, '2001:db8::1': {'port': '853'}}
for domain in domains:
@@ -204,11 +199,6 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'addNTA("{domain}", "static")', hosts_conf)
def test_no_rfc1918_forwarding(self):
- for network in allow_from:
- self.cli_set(base_path + ['allow-from', network])
- for address in listen_adress:
- self.cli_set(base_path + ['listen-address', address])
-
self.cli_set(base_path + ['no-serve-rfc1918'])
# commit changes
@@ -220,12 +210,6 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
def test_dns64(self):
dns_prefix = '64:ff9b::/96'
-
- for network in allow_from:
- self.cli_set(base_path + ['allow-from', network])
- for address in listen_adress:
- self.cli_set(base_path + ['listen-address', address])
-
# Check dns64-prefix - must be prefix /96
self.cli_set(base_path + ['dns64-prefix', '2001:db8:aabb::/64'])
with self.assertRaises(ConfigSessionError):
@@ -239,21 +223,73 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
tmp = get_config_value('dns64-prefix')
self.assertEqual(tmp, dns_prefix)
+ def test_exclude_throttle_adress(self):
+ exclude_throttle_adress_examples = [
+ '192.168.128.255',
+ '10.0.0.0/25',
+ '2001:db8:85a3:8d3:1319:8a2e:370:7348',
+ '64:ff9b::/96'
+ ]
+ for exclude_throttle_adress in exclude_throttle_adress_examples:
+ self.cli_set(base_path + ['exclude-throttle-address', exclude_throttle_adress])
+
+ # commit changes
+ self.cli_commit()
+
+ # verify dont-throttle-netmasks configuration
+ tmp = get_config_value('dont-throttle-netmasks')
+ self.assertEqual(tmp, ','.join(exclude_throttle_adress_examples))
+
+ def test_serve_stale_extension(self):
+ server_stale = '20'
+ self.cli_set(base_path + ['serve-stale-extension', server_stale])
+ # commit changes
+ self.cli_commit()
+ # verify configuration
+ tmp = get_config_value('serve-stale-extensions')
+ self.assertEqual(tmp, server_stale)
+
def test_listening_port(self):
# We can listen on a different port compared to '53' but only one at a time
- for port in ['1053', '5353']:
+ for port in ['10053', '10054']:
self.cli_set(base_path + ['port', port])
- for network in allow_from:
- self.cli_set(base_path + ['allow-from', network])
- for address in listen_adress:
- self.cli_set(base_path + ['listen-address', address])
-
# commit changes
self.cli_commit()
-
# verify local-port configuration
tmp = get_config_value('local-port')
self.assertEqual(tmp, port)
+ def test_ecs_add_for(self):
+ options = ['0.0.0.0/0', '!10.0.0.0/8', 'fc00::/7', '!fe80::/10']
+ for param in options:
+ self.cli_set(base_path + ['options', 'ecs-add-for', param])
+
+ # commit changes
+ self.cli_commit()
+ # verify ecs_add_for configuration
+ tmp = get_config_value('ecs-add-for')
+ self.assertEqual(tmp, ','.join(options))
+
+ def test_ecs_ipv4_bits(self):
+ option_value = '24'
+ self.cli_set(base_path + ['options', 'ecs-ipv4-bits', option_value])
+ # commit changes
+ self.cli_commit()
+ # verify ecs_ipv4_bits configuration
+ tmp = get_config_value('ecs-ipv4-bits')
+ self.assertEqual(tmp, option_value)
+
+ def test_edns_subnet_allow_list(self):
+ options = ['192.0.2.1/32', 'example.com', 'fe80::/10']
+ for param in options:
+ self.cli_set(base_path + ['options', 'edns-subnet-allow-list', param])
+
+ # commit changes
+ self.cli_commit()
+
+ # verify edns_subnet_allow_list configuration
+ tmp = get_config_value('edns-subnet-allow-list')
+ self.assertEqual(tmp, ','.join(options))
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_https.py b/smoketest/scripts/cli/test_service_https.py
index 280932fd7..8d9b8459e 100755
--- a/smoketest/scripts/cli/test_service_https.py
+++ b/smoketest/scripts/cli/test_service_https.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -23,6 +23,7 @@ from urllib3.exceptions import InsecureRequestWarning
from base_vyostest_shim import VyOSUnitTestSHIM
from base_vyostest_shim import ignore_warning
from vyos.utils.file import read_file
+from vyos.utils.file import write_file
from vyos.utils.process import call
from vyos.utils.process import process_named_running
@@ -52,7 +53,22 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPLpD0Ohhoq0g4nhx
u8/3jHMM7sDwL3aWzW/zp54/LhCWUoLMjDdDEEigK4fal4ZF9aA9F0Ww
"""
+dh_1024 = """
+MIGHAoGBAM3nvMkHGi/xmRs8cYg4pcl5sAanxel9EM+1XobVhUViXw8JvlmSEVOj
+n2aXUifc4SEs3WDzVPRC8O8qQWjvErpTq/HOgt3aqBCabMgvflmt706XP0KiqnpW
+EyvNiI27J3wBUzEXLIS110MxPAX5Tcug974PecFcOxn1RWrbWcx/AgEC
+"""
+
+dh_2048 = """
+MIIBCAKCAQEA1mld/V7WnxxRinkOlhx/BoZkRELtIUQFYxyARBqYk4C5G3YnZNNu
+zjaGyPnfIKHu8SIUH85OecM+5/co9nYlcUJuph2tbR6qNgPw7LOKIhf27u7WhvJk
+iVsJhwZiWmvvMV4jTParNEI2svoooMyhHXzeweYsg6YtgLVmwiwKj3XP3gRH2i3B
+Mq8CDS7X6xaKvjfeMPZBFqOM5nb6HhsbaAUyiZxrfipLvXxtnbzd/eJUQVfVdxM3
+pn0i+QrO2tuNAzX7GoPc9pefrbb5xJmGS50G0uqsR59+7LhYmyZSBASA0lxTEW9t
+kv/0LPvaYTY57WL7hBeqqHy/WPZHPzDI3wIBAg==
+"""
# to test load config via HTTP URL
+nginx_tmp_site = '/etc/nginx/sites-enabled/smoketest'
nginx_conf_smoketest = """
server {
listen 8000;
@@ -81,6 +97,11 @@ class TestHTTPSService(VyOSUnitTestSHIM.TestCase):
cls.cli_delete(cls, base_path)
cls.cli_delete(cls, pki_base)
+ @classmethod
+ def tearDownClass(cls):
+ super(TestHTTPSService, cls).tearDownClass()
+ call(f'sudo rm -f {nginx_tmp_site}')
+
def tearDown(self):
self.cli_delete(base_path)
self.cli_delete(pki_base)
@@ -89,33 +110,31 @@ class TestHTTPSService(VyOSUnitTestSHIM.TestCase):
# Check for stopped process
self.assertFalse(process_named_running(PROCESS_NAME))
- def test_server_block(self):
- vhost_id = 'example'
- address = '0.0.0.0'
- port = '8443'
- name = 'example.org'
-
- test_path = base_path + ['virtual-host', vhost_id]
-
- self.cli_set(test_path + ['listen-address', address])
- self.cli_set(test_path + ['port', port])
- self.cli_set(test_path + ['server-name', name])
-
- self.cli_commit()
-
- nginx_config = read_file('/etc/nginx/sites-enabled/default')
- self.assertIn(f'listen {address}:{port} ssl;', nginx_config)
- self.assertIn(f'ssl_protocols TLSv1.2 TLSv1.3;', nginx_config)
- self.assertTrue(process_named_running(PROCESS_NAME))
-
def test_certificate(self):
- self.cli_set(pki_base + ['certificate', 'test_https', 'certificate', cert_data.replace('\n','')])
- self.cli_set(pki_base + ['certificate', 'test_https', 'private', 'key', key_data.replace('\n','')])
-
- self.cli_set(base_path + ['certificates', 'certificate', 'test_https'])
+ cert_name = 'test_https'
+ dh_name = 'dh-test'
+
+ self.cli_set(base_path + ['certificates', 'certificate', cert_name])
+ # verify() - certificates do not exist (yet)
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(pki_base + ['certificate', cert_name, 'certificate', cert_data.replace('\n','')])
+ self.cli_set(pki_base + ['certificate', cert_name, 'private', 'key', key_data.replace('\n','')])
+
+ self.cli_set(base_path + ['certificates', 'dh-params', dh_name])
+ # verify() - dh-params do not exist (yet)
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ self.cli_set(pki_base + ['dh', dh_name, 'parameters', dh_1024.replace('\n','')])
+ # verify() - dh-param minimum length is 2048 bit
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(pki_base + ['dh', dh_name, 'parameters', dh_2048.replace('\n','')])
self.cli_commit()
self.assertTrue(process_named_running(PROCESS_NAME))
+ self.debug = False
def test_api_missing_keys(self):
self.cli_set(base_path + ['api'])
@@ -135,15 +154,13 @@ class TestHTTPSService(VyOSUnitTestSHIM.TestCase):
key = 'MySuperSecretVyOS'
self.cli_set(base_path + ['api', 'keys', 'id', 'key-01', 'key', key])
- test_path = base_path + ['virtual-host', vhost_id]
- self.cli_set(test_path + ['listen-address', address])
- self.cli_set(test_path + ['server-name', name])
+ self.cli_set(base_path + ['listen-address', address])
self.cli_commit()
nginx_config = read_file('/etc/nginx/sites-enabled/default')
self.assertIn(f'listen {address}:{port} ssl;', nginx_config)
- self.assertIn(f'ssl_protocols TLSv1.2 TLSv1.3;', nginx_config)
+ self.assertIn(f'ssl_protocols TLSv1.2 TLSv1.3;', nginx_config) # default
url = f'https://{address}/retrieve'
payload = {'data': '{"op": "showConfig", "path": []}', 'key': f'{key}'}
@@ -402,19 +419,15 @@ class TestHTTPSService(VyOSUnitTestSHIM.TestCase):
url_config = f'https://{address}/configure'
headers = {}
tmp_file = 'tmp-config.boot'
- nginx_tmp_site = '/etc/nginx/sites-enabled/smoketest'
self.cli_set(base_path + ['api', 'keys', 'id', 'key-01', 'key', key])
self.cli_commit()
# load config via HTTP requires nginx config
call(f'sudo touch {nginx_tmp_site}')
- call(f'sudo chown vyos:vyattacfg {nginx_tmp_site}')
- call(f'sudo chmod +w {nginx_tmp_site}')
-
- with open(nginx_tmp_site, 'w') as f:
- f.write(nginx_conf_smoketest)
- call('sudo nginx -s reload')
+ call(f'sudo chmod 666 {nginx_tmp_site}')
+ write_file(nginx_tmp_site, nginx_conf_smoketest)
+ call('sudo systemctl reload nginx')
# save config
payload = {
@@ -441,8 +454,8 @@ class TestHTTPSService(VyOSUnitTestSHIM.TestCase):
self.assertEqual(r.status_code, 200)
# cleanup tmp nginx conf
- call(f'sudo rm -rf {nginx_tmp_site}')
- call('sudo nginx -s reload')
+ call(f'sudo rm -f {nginx_tmp_site}')
+ call('sudo systemctl reload nginx')
if __name__ == '__main__':
unittest.main(verbosity=5)
diff --git a/smoketest/scripts/cli/test_service_ipoe-server.py b/smoketest/scripts/cli/test_service_ipoe-server.py
index 6e95b3bd1..cec6adb09 100755
--- a/smoketest/scripts/cli/test_service_ipoe-server.py
+++ b/smoketest/scripts/cli/test_service_ipoe-server.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022-2023 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -188,6 +188,45 @@ gw-ip-address={third_gateway.split('/')[0]}
{first_subnet},name={first_pool},next={second_pool}"""
self.assertIn(pool_config, config)
+ def test_accel_ipv6_pool(self):
+ # Test configuration of IPv6 client pools
+ self.basic_config(is_gateway=False, is_client_pool=False)
+
+ pool_name = 'ipv6_test_pool'
+ prefix_1 = '2001:db8:fffe::/56'
+ prefix_mask = '64'
+ prefix_2 = '2001:db8:ffff::/56'
+ client_prefix_1 = f'{prefix_1},{prefix_mask}'
+ client_prefix_2 = f'{prefix_2},{prefix_mask}'
+ self.set(['client-ipv6-pool', pool_name, 'prefix', prefix_1, 'mask',
+ prefix_mask])
+ self.set(['client-ipv6-pool', pool_name, 'prefix', prefix_2, 'mask',
+ prefix_mask])
+
+ delegate_1_prefix = '2001:db8:fff1::/56'
+ delegate_2_prefix = '2001:db8:fff2::/56'
+ delegate_mask = '64'
+ self.set(['client-ipv6-pool', pool_name, 'delegate', delegate_1_prefix,
+ 'delegation-prefix', delegate_mask])
+ self.set(['client-ipv6-pool', pool_name, 'delegate', delegate_2_prefix,
+ 'delegation-prefix', delegate_mask])
+
+ # commit changes
+ self.cli_commit()
+
+ # Validate configuration values
+ conf = ConfigParser(allow_no_value=True, delimiters='=', strict=False)
+ conf.read(self._config_file)
+
+ for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
+ self.assertEqual(conf['modules'][tmp], None)
+
+ config = self.getConfig("ipv6-pool")
+ pool_config = f"""{client_prefix_1},name={pool_name}
+{client_prefix_2},name={pool_name}
+delegate={delegate_1_prefix},{delegate_mask},name={pool_name}
+delegate={delegate_2_prefix},{delegate_mask},name={pool_name}"""
+ self.assertIn(pool_config, config)
if __name__ == "__main__":
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_ntp.py b/smoketest/scripts/cli/test_service_ntp.py
index 5e385d5ad..ae45fe2f4 100755
--- a/smoketest/scripts/cli/test_service_ntp.py
+++ b/smoketest/scripts/cli/test_service_ntp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -43,7 +43,7 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
self.assertFalse(process_named_running(PROCESS_NAME))
- def test_01_ntp_options(self):
+ def test_base_options(self):
# Test basic NTP support with multiple servers and their options
servers = ['192.0.2.1', '192.0.2.2']
options = ['nts', 'noselect', 'prefer']
@@ -77,7 +77,7 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
for pool in pools:
self.assertIn(f'pool {pool} iburst', config)
- def test_02_ntp_clients(self):
+ def test_clients(self):
# Test the allowed-networks statement
listen_address = ['127.0.0.1', '::1']
for listen in listen_address:
@@ -107,7 +107,7 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
for listen in listen_address:
self.assertIn(f'bindaddress {listen}', config)
- def test_03_ntp_interface(self):
+ def test_interface(self):
interfaces = ['eth0']
for interface in interfaces:
self.cli_set(base_path + ['interface', interface])
@@ -124,7 +124,7 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
for interface in interfaces:
self.assertIn(f'binddevice {interface}', config)
- def test_04_ntp_vrf(self):
+ def test_vrf(self):
vrf_name = 'vyos-mgmt'
self.cli_set(['vrf', 'name', vrf_name, 'table', '12345'])
@@ -142,5 +142,28 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
self.cli_delete(['vrf', 'name', vrf_name])
+ def test_leap_seconds(self):
+ servers = ['time1.vyos.net', 'time2.vyos.net']
+ for server in servers:
+ self.cli_set(base_path + ['server', server])
+
+ self.cli_commit()
+
+ # Check generated client address configuration
+ # this file must be read with higher permissions
+ config = cmd(f'sudo cat {NTP_CONF}')
+ self.assertIn('leapsectz right/UTC', config) # CLI default
+
+ for mode in ['ignore', 'system', 'smear']:
+ self.cli_set(base_path + ['leap-second', mode])
+ self.cli_commit()
+ config = cmd(f'sudo cat {NTP_CONF}')
+ if mode != 'smear':
+ self.assertIn(f'leapsecmode {mode}', config)
+ else:
+ self.assertIn(f'leapsecmode slew', config)
+ self.assertIn(f'maxslewrate 1000', config)
+ self.assertIn(f'smoothtime 400 0.001024 leaponly', config)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_pppoe-server.py b/smoketest/scripts/cli/test_service_pppoe-server.py
index fa3bb87db..11d5b8b78 100755
--- a/smoketest/scripts/cli/test_service_pppoe-server.py
+++ b/smoketest/scripts/cli/test_service_pppoe-server.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022-2023 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -93,6 +93,13 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
interface_cache = '128000'
self.set(['ppp-options', 'interface-cache', interface_cache])
+ # ipv6
+ allow_ipv6 = 'allow'
+ random = 'random'
+ self.set(['ppp-options', 'ipv6', allow_ipv6])
+ self.set(['ppp-options', 'ipv6-intf-id', random])
+ self.set(['ppp-options', 'ipv6-accept-peer-intf-id'])
+ self.set(['ppp-options', 'ipv6-peer-intf-id', random])
# commit changes
self.cli_commit()
@@ -118,6 +125,15 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
# check interface-cache
self.assertEqual(conf['ppp']['unit-cache'], interface_cache)
+ #check ipv6
+ for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
+ self.assertEqual(conf['modules'][tmp], None)
+
+ self.assertEqual(conf['ppp']['ipv6'], allow_ipv6)
+ self.assertEqual(conf['ppp']['ipv6-intf-id'], random)
+ self.assertEqual(conf['ppp']['ipv6-peer-intf-id'], random)
+ self.assertTrue(conf['ppp'].getboolean('ipv6-accept-peer-intf-id'))
+
def test_pppoe_server_authentication_protocols(self):
# Test configuration of local authentication for PPPoE server
self.basic_config()
@@ -154,45 +170,6 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
self.assertEqual(conf['shaper']['fwmark'], fwmark)
self.assertEqual(conf['shaper']['down-limiter'], limiter)
- def test_pppoe_server_client_ipv6_pool(self):
- # Test configuration of IPv6 client pools
- self.basic_config()
-
- # Enable IPv6
- allow_ipv6 = 'allow'
- random = 'random'
- self.set(['ppp-options', 'ipv6', allow_ipv6])
- self.set(['ppp-options', 'ipv6-intf-id', random])
- self.set(['ppp-options', 'ipv6-accept-peer-intf-id'])
- self.set(['ppp-options', 'ipv6-peer-intf-id', random])
-
- prefix = '2001:db8:ffff::/64'
- prefix_mask = '128'
- client_prefix = f'{prefix},{prefix_mask}'
- self.set(['client-ipv6-pool', 'prefix', prefix, 'mask', prefix_mask])
-
- delegate_prefix = '2001:db8::/40'
- delegate_mask = '56'
- self.set(['client-ipv6-pool', 'delegate', delegate_prefix, 'delegation-prefix', delegate_mask])
-
- # commit changes
- self.cli_commit()
-
- # Validate configuration values
- conf = ConfigParser(allow_no_value=True, delimiters='=')
- conf.read(self._config_file)
-
- for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
- self.assertEqual(conf['modules'][tmp], None)
-
- self.assertEqual(conf['ppp']['ipv6'], allow_ipv6)
- self.assertEqual(conf['ppp']['ipv6-intf-id'], random)
- self.assertEqual(conf['ppp']['ipv6-peer-intf-id'], random)
- self.assertTrue(conf['ppp'].getboolean('ipv6-accept-peer-intf-id'))
-
- self.assertEqual(conf['ipv6-pool'][client_prefix], None)
- self.assertEqual(conf['ipv6-pool']['delegate'], f'{delegate_prefix},{delegate_mask}')
-
def test_accel_radius_authentication(self):
radius_called_sid = 'ifname:mac'
diff --git a/smoketest/scripts/cli/test_system_conntrack.py b/smoketest/scripts/cli/test_system_conntrack.py
index 0dbc97d49..cea34138e 100755
--- a/smoketest/scripts/cli/test_system_conntrack.py
+++ b/smoketest/scripts/cli/test_system_conntrack.py
@@ -31,6 +31,14 @@ def get_sysctl(parameter):
return read_file(f'/proc/sys/{tmp}')
class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ super(TestSystemConntrack, 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()
diff --git a/smoketest/scripts/cli/test_system_sflow.py b/smoketest/scripts/cli/test_system_sflow.py
index 63262db69..c0424d915 100755
--- a/smoketest/scripts/cli/test_system_sflow.py
+++ b/smoketest/scripts/cli/test_system_sflow.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -17,6 +17,7 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from time import sleep
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
@@ -26,12 +27,11 @@ from vyos.utils.file import read_file
PROCESS_NAME = 'hsflowd'
base_path = ['system', 'sflow']
+vrf = 'mgmt'
hsflowd_conf = '/run/sflow/hsflowd.conf'
-
class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
-
@classmethod
def setUpClass(cls):
super(TestSystemFlowAccounting, cls).setUpClass()
@@ -45,6 +45,7 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
self.assertTrue(process_named_running(PROCESS_NAME))
self.cli_delete(base_path)
+ self.cli_delete(['vrf', 'name', vrf])
self.cli_commit()
# after service removal process must no longer run
@@ -96,6 +97,27 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
for interface in Section.interfaces('ethernet'):
self.assertIn(f'pcap {{ dev={interface} }}', hsflowd)
+ def test_vrf(self):
+ interface = 'eth0'
+ server = '192.0.2.1'
+
+ # Check if sFlow service can be bound to given VRF
+ self.cli_set(['vrf', 'name', vrf, 'table', '10100'])
+ self.cli_set(base_path + ['interface', interface])
+ self.cli_set(base_path + ['server', server])
+ self.cli_set(base_path + ['vrf', vrf])
+
+ # commit changes
+ self.cli_commit()
+
+ # verify configuration
+ hsflowd = read_file(hsflowd_conf)
+ self.assertIn(f'collector {{ ip = {server} udpport = 6343 }}', hsflowd) # default port
+ self.assertIn(f'pcap {{ dev=eth0 }}', hsflowd)
+
+ # Check for process in VRF
+ tmp = cmd(f'ip vrf pids {vrf}')
+ self.assertIn(PROCESS_NAME, tmp)
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_vpn_ipsec.py b/smoketest/scripts/cli/test_vpn_ipsec.py
index 17e12bcaf..f5369ee7a 100755
--- a/smoketest/scripts/cli/test_vpn_ipsec.py
+++ b/smoketest/scripts/cli/test_vpn_ipsec.py
@@ -115,6 +115,7 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
# 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, ['pki'])
cls.cli_set(cls, base_path + ['interface', f'{interface}.{vif}'])
diff --git a/smoketest/scripts/cli/test_vpn_l2tp.py b/smoketest/scripts/cli/test_vpn_l2tp.py
index 5b3e419bd..129a9c602 100755
--- a/smoketest/scripts/cli/test_vpn_l2tp.py
+++ b/smoketest/scripts/cli/test_vpn_l2tp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -55,6 +55,13 @@ class TestVPNL2TPServer(BasicAccelPPPTest.TestCase):
self.set(['ppp-options', 'lcp-echo-interval', lcp_echo_interval])
self.set(['ppp-options', 'lcp-echo-timeout', lcp_echo_timeout])
+ allow_ipv6 = 'allow'
+ random = 'random'
+ self.set(['ppp-options', 'ipv6', allow_ipv6])
+ self.set(['ppp-options', 'ipv6-intf-id', random])
+ self.set(['ppp-options', 'ipv6-accept-peer-intf-id'])
+ self.set(['ppp-options', 'ipv6-peer-intf-id', random])
+
# commit changes
self.cli_commit()
@@ -76,6 +83,13 @@ class TestVPNL2TPServer(BasicAccelPPPTest.TestCase):
self.assertEqual(conf['ppp']['lcp-echo-timeout'], lcp_echo_timeout)
self.assertEqual(conf['ppp']['lcp-echo-failure'], lcp_echo_failure)
+ for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
+ self.assertEqual(conf['modules'][tmp], None)
+ self.assertEqual(conf['ppp']['ipv6'], allow_ipv6)
+ self.assertEqual(conf['ppp']['ipv6-intf-id'], random)
+ self.assertEqual(conf['ppp']['ipv6-peer-intf-id'], random)
+ self.assertTrue(conf['ppp'].getboolean('ipv6-accept-peer-intf-id'))
+
def test_l2tp_server_authentication_protocols(self):
# Test configuration of local authentication for PPPoE server
self.basic_config()
@@ -92,44 +106,6 @@ class TestVPNL2TPServer(BasicAccelPPPTest.TestCase):
self.assertEqual(conf['modules']['auth_mschap_v2'], None)
- def test_l2tp_server_client_ipv6_pool(self):
- # Test configuration of IPv6 client pools
- self.basic_config()
-
- # Enable IPv6
- allow_ipv6 = 'allow'
- random = 'random'
- self.set(['ppp-options', 'ipv6', allow_ipv6])
- self.set(['ppp-options', 'ipv6-intf-id', random])
- self.set(['ppp-options', 'ipv6-accept-peer-intf-id'])
- self.set(['ppp-options', 'ipv6-peer-intf-id', random])
-
- prefix = '2001:db8:ffff::/64'
- prefix_mask = '128'
- client_prefix = f'{prefix},{prefix_mask}'
- self.set(['client-ipv6-pool', 'prefix', prefix, 'mask', prefix_mask])
-
- delegate_prefix = '2001:db8::/40'
- delegate_mask = '56'
- self.set(['client-ipv6-pool', 'delegate', delegate_prefix, 'delegation-prefix', delegate_mask])
-
- # commit changes
- self.cli_commit()
-
- # Validate configuration values
- conf = ConfigParser(allow_no_value=True, delimiters='=')
- conf.read(self._config_file)
-
- for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
- self.assertEqual(conf['modules'][tmp], None)
-
- self.assertEqual(conf['ppp']['ipv6'], allow_ipv6)
- self.assertEqual(conf['ppp']['ipv6-intf-id'], random)
- self.assertEqual(conf['ppp']['ipv6-peer-intf-id'], random)
- self.assertTrue(conf['ppp'].getboolean('ipv6-accept-peer-intf-id'))
-
- self.assertEqual(conf['ipv6-pool'][client_prefix], None)
- self.assertEqual(conf['ipv6-pool']['delegate'], f'{delegate_prefix},{delegate_mask}')
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_vpn_pptp.py b/smoketest/scripts/cli/test_vpn_pptp.py
index 0d9ea312e..f3fce822b 100755
--- a/smoketest/scripts/cli/test_vpn_pptp.py
+++ b/smoketest/scripts/cli/test_vpn_pptp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -218,6 +218,10 @@ class TestVPNPPTPServer(BasicAccelPPPTest.TestCase):
self.assertEqual(f"req-limit=0", server[4])
self.assertEqual(f"fail-time=0", server[5])
+ @unittest.skip("IPv6 is not implemented in PPTP")
+ def test_accel_ipv6_pool(self):
+ pass
+
if __name__ == '__main__':
unittest.main(verbosity=2)