summaryrefslogtreecommitdiff
path: root/smoketest
diff options
context:
space:
mode:
Diffstat (limited to 'smoketest')
-rwxr-xr-xsmoketest/bin/vyos-configtest23
-rwxr-xr-xsmoketest/bin/vyos-smoketest2
-rw-r--r--smoketest/config-tests/basic-vyos62
-rw-r--r--smoketest/config-tests/dialup-router-medium-vpn321
-rw-r--r--smoketest/configs/basic-vyos46
-rw-r--r--smoketest/configs/dialup-router-complex4
-rw-r--r--smoketest/configs/dialup-router-medium-vpn24
-rw-r--r--smoketest/configs/egb-igp-route-maps127
-rw-r--r--smoketest/configs/qos-basic56
-rw-r--r--smoketest/configs/vrf-bgp-pppoe-underlay473
-rw-r--r--smoketest/scripts/cli/base_accel_ppp_test.py8
-rw-r--r--smoketest/scripts/cli/base_interfaces_test.py354
-rw-r--r--smoketest/scripts/cli/base_vyostest_shim.py20
-rwxr-xr-xsmoketest/scripts/cli/test_configd_init.py5
-rwxr-xr-xsmoketest/scripts/cli/test_container.py11
-rwxr-xr-xsmoketest/scripts/cli/test_firewall.py576
-rwxr-xr-xsmoketest/scripts/cli/test_ha_virtual_server.py44
-rwxr-xr-xsmoketest/scripts/cli/test_ha_vrrp.py47
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bonding.py19
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bridge.py21
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_ethernet.py27
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_geneve.py10
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_input.py51
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_l2tpv3.py4
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_loopback.py7
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_macsec.py109
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_openvpn.py15
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_pppoe.py80
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_pseudo_ethernet.py8
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_tunnel.py5
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_virtual_ethernet.py62
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_vti.py5
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_vxlan.py59
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_wireguard.py58
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_wireless.py60
-rwxr-xr-xsmoketest/scripts/cli/test_load_balancing_reverse_proxy.py112
-rwxr-xr-xsmoketest/scripts/cli/test_load_balancing_wan.py (renamed from smoketest/scripts/cli/test_load_balancning_wan.py)33
-rwxr-xr-xsmoketest/scripts/cli/test_nat.py106
-rwxr-xr-xsmoketest/scripts/cli/test_nat66.py8
-rwxr-xr-xsmoketest/scripts/cli/test_netns.py (renamed from smoketest/scripts/cli/test_interfaces_netns.py)56
-rwxr-xr-xsmoketest/scripts/cli/test_pki.py22
-rwxr-xr-xsmoketest/scripts/cli/test_policy.py30
-rwxr-xr-xsmoketest/scripts/cli/test_policy_route.py104
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bfd.py2
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bgp.py233
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_igmp-proxy.py4
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_isis.py82
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_mpls.py2
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_nhrp.py8
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ospf.py192
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ospfv3.py74
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_pim6.py110
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_rip.py2
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ripng.py2
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_rpki.py4
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_static.py43
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_static_arp.py2
-rwxr-xr-xsmoketest/scripts/cli/test_qos.py547
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcp-relay.py41
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcp-server.py27
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcpv6-relay.py32
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcpv6-server.py4
-rwxr-xr-xsmoketest/scripts/cli/test_service_dns_dynamic.py237
-rwxr-xr-xsmoketest/scripts/cli/test_service_dns_forwarding.py51
-rwxr-xr-xsmoketest/scripts/cli/test_service_https.py9
-rwxr-xr-xsmoketest/scripts/cli/test_service_ids.py4
-rwxr-xr-xsmoketest/scripts/cli/test_service_ipoe-server.py95
-rwxr-xr-xsmoketest/scripts/cli/test_service_lldp.py6
-rwxr-xr-xsmoketest/scripts/cli/test_service_mdns-repeater.py37
-rwxr-xr-xsmoketest/scripts/cli/test_service_monitoring_telegraf.py4
-rwxr-xr-xsmoketest/scripts/cli/test_service_monitoring_zabbix-agent.py89
-rwxr-xr-xsmoketest/scripts/cli/test_service_ntp.py (renamed from smoketest/scripts/cli/test_system_ntp.py)75
-rwxr-xr-xsmoketest/scripts/cli/test_service_pppoe-server.py42
-rwxr-xr-xsmoketest/scripts/cli/test_service_router-advert.py43
-rwxr-xr-xsmoketest/scripts/cli/test_service_salt.py8
-rwxr-xr-xsmoketest/scripts/cli/test_service_snmp.py30
-rwxr-xr-xsmoketest/scripts/cli/test_service_ssh.py24
-rwxr-xr-xsmoketest/scripts/cli/test_service_tftp-server.py39
-rwxr-xr-xsmoketest/scripts/cli/test_service_upnp.py4
-rwxr-xr-xsmoketest/scripts/cli/test_service_webproxy.py6
-rwxr-xr-xsmoketest/scripts/cli/test_system_conntrack.py63
-rwxr-xr-xsmoketest/scripts/cli/test_system_flow-accounting.py6
-rwxr-xr-xsmoketest/scripts/cli/test_system_frr.py4
-rwxr-xr-xsmoketest/scripts/cli/test_system_ip.py42
-rwxr-xr-xsmoketest/scripts/cli/test_system_ipv6.py51
-rwxr-xr-xsmoketest/scripts/cli/test_system_lcd.py2
-rwxr-xr-xsmoketest/scripts/cli/test_system_login.py73
-rwxr-xr-xsmoketest/scripts/cli/test_system_logs.py2
-rwxr-xr-xsmoketest/scripts/cli/test_system_nameserver.py2
-rwxr-xr-xsmoketest/scripts/cli/test_system_sflow.py101
-rwxr-xr-xsmoketest/scripts/cli/test_vpn_ipsec.py88
-rwxr-xr-xsmoketest/scripts/cli/test_vpn_openconnect.py19
-rwxr-xr-xsmoketest/scripts/cli/test_vpn_sstp.py2
-rwxr-xr-xsmoketest/scripts/cli/test_vrf.py225
-rwxr-xr-xsmoketest/scripts/system/test_kernel_options.py38
-rwxr-xr-xsmoketest/scripts/system/test_module_load.py6
96 files changed, 5110 insertions, 1102 deletions
diff --git a/smoketest/bin/vyos-configtest b/smoketest/bin/vyos-configtest
index 3e42b0380..c1b602737 100755
--- a/smoketest/bin/vyos-configtest
+++ b/smoketest/bin/vyos-configtest
@@ -24,6 +24,7 @@ from vyos.configsession import ConfigSession, ConfigSessionError
from vyos import ConfigError
config_dir = '/usr/libexec/vyos/tests/config'
+config_test_dir = '/usr/libexec/vyos/tests/config-tests'
save_config = '/tmp/vyos-configtest-save'
class DynamicClassBase(unittest.TestCase):
@@ -42,7 +43,7 @@ class DynamicClassBase(unittest.TestCase):
except OSError:
pass
-def make_test_function(filename):
+def make_test_function(filename, test_path=None):
def test_config_load(self):
config_path = os.path.join(config_dir, filename)
self.session.migrate_and_load_config(config_path)
@@ -51,6 +52,16 @@ def make_test_function(filename):
except (ConfigError, ConfigSessionError):
self.session.discard()
self.fail()
+
+ if test_path:
+ config_commands = self.session.show(['configuration', 'commands'])
+
+ with open(test_path, 'r') as f:
+ for line in f.readlines():
+ if not line or line.startswith("#"):
+ continue
+
+ self.assertIn(line, config_commands)
return test_config_load
def class_name_from_func_name(s):
@@ -69,10 +80,18 @@ if __name__ == '__main__':
config_list.sort()
for config in config_list:
- test_func = make_test_function(config)
+ test_path = os.path.join(config_test_dir, config)
+
+ if not os.path.exists(test_path):
+ test_path = None
+ else:
+ log.info(f'Loaded migration result test for config "{config}"')
+
+ test_func = make_test_function(config, test_path)
func_name = config.replace('-', '_')
klassname = f'TestConfig{class_name_from_func_name(func_name)}'
+
globals()[klassname] = type(klassname,
(DynamicClassBase,),
{f'test_{func_name}': test_func})
diff --git a/smoketest/bin/vyos-smoketest b/smoketest/bin/vyos-smoketest
index cb039db42..135388afe 100755
--- a/smoketest/bin/vyos-smoketest
+++ b/smoketest/bin/vyos-smoketest
@@ -26,7 +26,7 @@ for root, dirs, files in os.walk('/usr/libexec/vyos/tests/smoke'):
test_file = os.path.join(root, name)
mode = os.stat(test_file).st_mode
- if mode & S_IXOTH:
+ if name.startswith("test_") and mode & S_IXOTH:
print('Running Testcase: ' + test_file)
process = Popen([test_file], stdout=PIPE)
(output, err) = process.communicate()
diff --git a/smoketest/config-tests/basic-vyos b/smoketest/config-tests/basic-vyos
new file mode 100644
index 000000000..ef8bf374a
--- /dev/null
+++ b/smoketest/config-tests/basic-vyos
@@ -0,0 +1,62 @@
+set interfaces ethernet eth0 address '192.168.0.1/24'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 speed 'auto'
+set interfaces ethernet eth2 duplex 'auto'
+set interfaces ethernet eth2 speed 'auto'
+set interfaces ethernet eth2 vif 100 address '100.100.0.1/24'
+set interfaces ethernet eth2 vif-s 200 address '100.64.200.254/24'
+set interfaces ethernet eth2 vif-s 200 vif-c 201 address '100.64.201.254/24'
+set interfaces ethernet eth2 vif-s 200 vif-c 202 address '100.64.202.254/24'
+set interfaces loopback lo
+set protocols static arp interface eth0 address 192.168.0.20 mac '00:50:00:00:00:20'
+set protocols static arp interface eth0 address 192.168.0.30 mac '00:50:00:00:00:30'
+set protocols static arp interface eth0 address 192.168.0.40 mac '00:50:00:00:00:40'
+set protocols static arp interface eth2.100 address 100.100.0.2 mac '00:50:00:00:02:02'
+set protocols static arp interface eth2.100 address 100.100.0.3 mac '00:50:00:00:02:03'
+set protocols static arp interface eth2.100 address 100.100.0.4 mac '00:50:00:00:02:04'
+set protocols static arp interface eth2.200 address 100.64.200.1 mac '00:50:00:00:00:01'
+set protocols static arp interface eth2.200 address 100.64.200.2 mac '00:50:00:00:00:02'
+set protocols static arp interface eth2.200.201 address 100.64.201.10 mac '00:50:00:00:00:10'
+set protocols static arp interface eth2.200.201 address 100.64.201.20 mac '00:50:00:00:00:20'
+set protocols static arp interface eth2.200.202 address 100.64.202.30 mac '00:50:00:00:00:30'
+set protocols static arp interface eth2.200.202 address 100.64.202.40 mac '00:50:00:00:00:40'
+set protocols static route 0.0.0.0/0 next-hop 100.64.0.1
+set service dhcp-server shared-network-name LAN authoritative
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 default-router '192.168.0.1'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 domain-name 'vyos.net'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 domain-search 'vyos.net'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 name-server '192.168.0.1'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 range LANDynamic start '192.168.0.20'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 range LANDynamic stop '192.168.0.240'
+set service dns forwarding allow-from '192.168.0.0/16'
+set service dns forwarding cache-size '10000'
+set service dns forwarding dnssec 'off'
+set service dns forwarding listen-address '192.168.0.1'
+set service ssh ciphers 'aes128-ctr'
+set service ssh ciphers 'aes192-ctr'
+set service ssh ciphers 'aes256-ctr'
+set service ssh ciphers 'chacha20-poly1305@openssh.com'
+set service ssh ciphers 'rijndael-cbc@lysator.liu.se'
+set service ssh key-exchange 'curve25519-sha256@libssh.org'
+set service ssh key-exchange 'diffie-hellman-group1-sha1'
+set service ssh key-exchange 'diffie-hellman-group-exchange-sha1'
+set service ssh key-exchange 'diffie-hellman-group-exchange-sha256'
+set service ssh listen-address '192.168.0.1'
+set service ssh port '22'
+set system config-management commit-revisions '100'
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system name-server '192.168.0.1'
+set system syslog console facility all level 'emerg'
+set system syslog console facility mail level 'info'
+set system syslog global facility all level 'info'
+set system syslog global facility auth level 'info'
+set system syslog global facility local7 level 'debug'
+set system syslog global preserve-fqdn
+set system syslog host syslog.vyos.net facility auth level 'warning'
+set system syslog host syslog.vyos.net facility local7 level 'notice'
+set system syslog host syslog.vyos.net format octet-counted
+set system syslog host syslog.vyos.net port '8000'
+set system time-zone 'Europe/Berlin'
diff --git a/smoketest/config-tests/dialup-router-medium-vpn b/smoketest/config-tests/dialup-router-medium-vpn
new file mode 100644
index 000000000..37baee0fd
--- /dev/null
+++ b/smoketest/config-tests/dialup-router-medium-vpn
@@ -0,0 +1,321 @@
+set firewall global-options all-ping 'enable'
+set firewall global-options broadcast-ping 'disable'
+set firewall global-options ip-src-route 'disable'
+set firewall global-options ipv6-receive-redirects 'disable'
+set firewall global-options ipv6-src-route 'disable'
+set firewall global-options log-martians 'enable'
+set firewall global-options receive-redirects 'disable'
+set firewall global-options send-redirects 'enable'
+set firewall global-options source-validation 'disable'
+set firewall global-options syn-cookies 'disable'
+set firewall global-options twa-hazards-protection 'enable'
+set firewall ipv4 name test_tcp_flags rule 1 action 'drop'
+set firewall ipv4 name test_tcp_flags rule 1 protocol 'tcp'
+set firewall ipv4 name test_tcp_flags rule 1 tcp flags ack
+set firewall ipv4 name test_tcp_flags rule 1 tcp flags not fin
+set firewall ipv4 name test_tcp_flags rule 1 tcp flags not rst
+set firewall ipv4 name test_tcp_flags rule 1 tcp flags syn
+set high-availability vrrp group LAN address 192.168.0.1/24
+set high-availability vrrp group LAN hello-source-address '192.168.0.250'
+set high-availability vrrp group LAN interface 'eth1'
+set high-availability vrrp group LAN peer-address '192.168.0.251'
+set high-availability vrrp group LAN priority '200'
+set high-availability vrrp group LAN vrid '1'
+set high-availability vrrp sync-group failover-group member 'LAN'
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 mtu '9000'
+set interfaces ethernet eth0 offload gro
+set interfaces ethernet eth0 offload gso
+set interfaces ethernet eth0 offload sg
+set interfaces ethernet eth0 offload tso
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth1 address '192.168.0.250/24'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 ip source-validation 'strict'
+set interfaces ethernet eth1 mtu '9000'
+set interfaces ethernet eth1 offload gro
+set interfaces ethernet eth1 offload gso
+set interfaces ethernet eth1 offload sg
+set interfaces ethernet eth1 offload tso
+set interfaces ethernet eth1 speed 'auto'
+set interfaces loopback lo
+set interfaces openvpn vtun0 encryption cipher 'aes256'
+set interfaces openvpn vtun0 hash 'sha512'
+set interfaces openvpn vtun0 ip adjust-mss '1380'
+set interfaces openvpn vtun0 ip source-validation 'strict'
+set interfaces openvpn vtun0 keep-alive failure-count '3'
+set interfaces openvpn vtun0 keep-alive interval '30'
+set interfaces openvpn vtun0 mode 'client'
+set interfaces openvpn vtun0 openvpn-option 'comp-lzo adaptive'
+set interfaces openvpn vtun0 openvpn-option 'fast-io'
+set interfaces openvpn vtun0 openvpn-option 'persist-key'
+set interfaces openvpn vtun0 openvpn-option 'reneg-sec 86400'
+set interfaces openvpn vtun0 persistent-tunnel
+set interfaces openvpn vtun0 remote-host '192.0.2.10'
+set interfaces openvpn vtun0 tls auth-key 'openvpn_vtun0_auth'
+set interfaces openvpn vtun0 tls ca-certificate 'openvpn_vtun0_1'
+set interfaces openvpn vtun0 tls ca-certificate 'openvpn_vtun0_2'
+set interfaces openvpn vtun0 tls certificate 'openvpn_vtun0'
+set interfaces openvpn vtun1 authentication password 'vyos1'
+set interfaces openvpn vtun1 authentication username 'vyos1'
+set interfaces openvpn vtun1 encryption cipher 'aes256'
+set interfaces openvpn vtun1 hash 'sha1'
+set interfaces openvpn vtun1 ip adjust-mss '1380'
+set interfaces openvpn vtun1 keep-alive failure-count '3'
+set interfaces openvpn vtun1 keep-alive interval '30'
+set interfaces openvpn vtun1 mode 'client'
+set interfaces openvpn vtun1 openvpn-option 'comp-lzo adaptive'
+set interfaces openvpn vtun1 openvpn-option 'tun-mtu 1500'
+set interfaces openvpn vtun1 openvpn-option 'tun-mtu-extra 32'
+set interfaces openvpn vtun1 openvpn-option 'mssfix 1300'
+set interfaces openvpn vtun1 openvpn-option 'persist-key'
+set interfaces openvpn vtun1 openvpn-option 'mute 10'
+set interfaces openvpn vtun1 openvpn-option 'route-nopull'
+set interfaces openvpn vtun1 openvpn-option 'fast-io'
+set interfaces openvpn vtun1 openvpn-option 'reneg-sec 86400'
+set interfaces openvpn vtun1 persistent-tunnel
+set interfaces openvpn vtun1 protocol 'udp'
+set interfaces openvpn vtun1 remote-host '01.foo.com'
+set interfaces openvpn vtun1 remote-port '1194'
+set interfaces openvpn vtun1 tls auth-key 'openvpn_vtun1_auth'
+set interfaces openvpn vtun1 tls ca-certificate 'openvpn_vtun1_1'
+set interfaces openvpn vtun1 tls ca-certificate 'openvpn_vtun1_2'
+set interfaces openvpn vtun2 authentication password 'vyos2'
+set interfaces openvpn vtun2 authentication username 'vyos2'
+set interfaces openvpn vtun2 disable
+set interfaces openvpn vtun2 encryption cipher 'aes256'
+set interfaces openvpn vtun2 hash 'sha512'
+set interfaces openvpn vtun2 ip adjust-mss '1380'
+set interfaces openvpn vtun2 keep-alive failure-count '3'
+set interfaces openvpn vtun2 keep-alive interval '30'
+set interfaces openvpn vtun2 mode 'client'
+set interfaces openvpn vtun2 openvpn-option 'tun-mtu 1500'
+set interfaces openvpn vtun2 openvpn-option 'tun-mtu-extra 32'
+set interfaces openvpn vtun2 openvpn-option 'mssfix 1300'
+set interfaces openvpn vtun2 openvpn-option 'persist-key'
+set interfaces openvpn vtun2 openvpn-option 'mute 10'
+set interfaces openvpn vtun2 openvpn-option 'route-nopull'
+set interfaces openvpn vtun2 openvpn-option 'fast-io'
+set interfaces openvpn vtun2 openvpn-option 'remote-random'
+set interfaces openvpn vtun2 openvpn-option 'reneg-sec 86400'
+set interfaces openvpn vtun2 persistent-tunnel
+set interfaces openvpn vtun2 protocol 'udp'
+set interfaces openvpn vtun2 remote-host '01.myvpn.com'
+set interfaces openvpn vtun2 remote-host '02.myvpn.com'
+set interfaces openvpn vtun2 remote-host '03.myvpn.com'
+set interfaces openvpn vtun2 remote-port '1194'
+set interfaces openvpn vtun2 tls auth-key 'openvpn_vtun2_auth'
+set interfaces openvpn vtun2 tls ca-certificate 'openvpn_vtun2_1'
+set interfaces pppoe pppoe0 authentication password 'password'
+set interfaces pppoe pppoe0 authentication username 'vyos'
+set interfaces pppoe pppoe0 mtu '1500'
+set interfaces pppoe pppoe0 source-interface 'eth0'
+set interfaces wireguard wg0 address '192.168.10.1/24'
+set interfaces wireguard wg0 ip adjust-mss '1380'
+set interfaces wireguard wg0 peer blue allowed-ips '192.168.10.3/32'
+set interfaces wireguard wg0 peer blue persistent-keepalive '20'
+set interfaces wireguard wg0 peer blue preshared-key 'ztFDOY9UyaDvn8N3X97SFMDwIfv7EEfuUIPP2yab6UI='
+set interfaces wireguard wg0 peer blue public-key 'G4pZishpMRrLmd96Kr6V7LIuNGdcUb81gWaYZ+FWkG0='
+set interfaces wireguard wg0 peer green allowed-ips '192.168.10.21/32'
+set interfaces wireguard wg0 peer green persistent-keepalive '25'
+set interfaces wireguard wg0 peer green preshared-key 'LQ9qmlTh9G4nZu4UgElxRUwg7JB/qoV799aADJOijnY='
+set interfaces wireguard wg0 peer green public-key '5iQUD3VoCDBTPXAPHOwUJ0p7xzKGHEY/wQmgvBVmaFI='
+set interfaces wireguard wg0 peer pink allowed-ips '192.168.10.14/32'
+set interfaces wireguard wg0 peer pink allowed-ips '192.168.10.16/32'
+set interfaces wireguard wg0 peer pink persistent-keepalive '25'
+set interfaces wireguard wg0 peer pink preshared-key 'Qi9Odyx0/5itLPN5C5bEy3uMX+tmdl15QbakxpKlWqQ='
+set interfaces wireguard wg0 peer pink public-key 'i4qNPmxyy9EETL4tIoZOLKJF4p7IlVmpAE15gglnAk4='
+set interfaces wireguard wg0 peer red allowed-ips '192.168.10.4/32'
+set interfaces wireguard wg0 peer red persistent-keepalive '20'
+set interfaces wireguard wg0 peer red preshared-key 'CumyXX7osvUT9AwnS+m2TEfCaL0Ptc2LfuZ78Sujuk8='
+set interfaces wireguard wg0 peer red public-key 'ALGWvMJCKpHF2tVH3hEIHqUe9iFfAmZATUUok/WQzks='
+set interfaces wireguard wg0 port '7777'
+set interfaces wireguard wg1 address '10.89.90.2/30'
+set interfaces wireguard wg1 ip adjust-mss '1380'
+set interfaces wireguard wg1 peer sam address '192.0.2.45'
+set interfaces wireguard wg1 peer sam allowed-ips '10.1.1.0/24'
+set interfaces wireguard wg1 peer sam allowed-ips '10.89.90.1/32'
+set interfaces wireguard wg1 peer sam persistent-keepalive '20'
+set interfaces wireguard wg1 peer sam port '1200'
+set interfaces wireguard wg1 peer sam preshared-key 'XpFtzx2Z+nR8pBv9/sSf7I94OkZkVYTz0AeU5Q/QQUE='
+set interfaces wireguard wg1 peer sam public-key 'v5zfKGvH6W/lfDXJ0en96lvKo1gfFxMUWxe02+Fj5BU='
+set interfaces wireguard wg1 port '7778'
+set nat destination rule 50 destination port '49371'
+set nat destination rule 50 inbound-interface 'pppoe0'
+set nat destination rule 50 protocol 'tcp_udp'
+set nat destination rule 50 translation address '192.168.0.5'
+set nat destination rule 51 destination port '58050-58051'
+set nat destination rule 51 inbound-interface 'pppoe0'
+set nat destination rule 51 protocol 'tcp'
+set nat destination rule 51 translation address '192.168.0.5'
+set nat destination rule 52 destination port '22067-22070'
+set nat destination rule 52 inbound-interface 'pppoe0'
+set nat destination rule 52 protocol 'tcp'
+set nat destination rule 52 translation address '192.168.0.5'
+set nat destination rule 53 destination port '34342'
+set nat destination rule 53 inbound-interface 'pppoe0'
+set nat destination rule 53 protocol 'tcp_udp'
+set nat destination rule 53 translation address '192.168.0.121'
+set nat destination rule 54 destination port '45459'
+set nat destination rule 54 inbound-interface 'pppoe0'
+set nat destination rule 54 protocol 'tcp_udp'
+set nat destination rule 54 translation address '192.168.0.120'
+set nat destination rule 55 destination port '22'
+set nat destination rule 55 inbound-interface 'pppoe0'
+set nat destination rule 55 protocol 'tcp'
+set nat destination rule 55 translation address '192.168.0.5'
+set nat destination rule 56 destination port '8920'
+set nat destination rule 56 inbound-interface 'pppoe0'
+set nat destination rule 56 protocol 'tcp'
+set nat destination rule 56 translation address '192.168.0.5'
+set nat destination rule 60 destination port '80,443'
+set nat destination rule 60 inbound-interface 'pppoe0'
+set nat destination rule 60 protocol 'tcp'
+set nat destination rule 60 translation address '192.168.0.5'
+set nat destination rule 70 destination port '5001'
+set nat destination rule 70 inbound-interface 'pppoe0'
+set nat destination rule 70 protocol 'tcp'
+set nat destination rule 70 translation address '192.168.0.5'
+set nat destination rule 80 destination port '25'
+set nat destination rule 80 inbound-interface 'pppoe0'
+set nat destination rule 80 protocol 'tcp'
+set nat destination rule 80 translation address '192.168.0.5'
+set nat destination rule 90 destination port '8123'
+set nat destination rule 90 inbound-interface 'pppoe0'
+set nat destination rule 90 protocol 'tcp'
+set nat destination rule 90 translation address '192.168.0.7'
+set nat destination rule 91 destination port '1880'
+set nat destination rule 91 inbound-interface 'pppoe0'
+set nat destination rule 91 protocol 'tcp'
+set nat destination rule 91 translation address '192.168.0.7'
+set nat destination rule 500 destination address '!192.168.0.0/24'
+set nat destination rule 500 destination port '53'
+set nat destination rule 500 inbound-interface 'eth1'
+set nat destination rule 500 protocol 'tcp_udp'
+set nat destination rule 500 source address '!192.168.0.1-192.168.0.5'
+set nat destination rule 500 translation address '192.168.0.1'
+set nat source rule 1000 outbound-interface 'pppoe0'
+set nat source rule 1000 translation address 'masquerade'
+set nat source rule 2000 outbound-interface 'vtun0'
+set nat source rule 2000 source address '192.168.0.0/16'
+set nat source rule 2000 translation address 'masquerade'
+set nat source rule 3000 outbound-interface 'vtun1'
+set nat source rule 3000 translation address 'masquerade'
+set policy prefix-list user1-routes rule 1 action 'permit'
+set policy prefix-list user1-routes rule 1 prefix '192.168.0.0/24'
+set policy prefix-list user2-routes rule 1 action 'permit'
+set policy prefix-list user2-routes rule 1 prefix '10.1.1.0/24'
+set policy route LAN-POLICY-BASED-ROUTING interface 'eth1'
+set policy route LAN-POLICY-BASED-ROUTING rule 10 destination
+set policy route LAN-POLICY-BASED-ROUTING rule 10 disable
+set policy route LAN-POLICY-BASED-ROUTING rule 10 set table '10'
+set policy route LAN-POLICY-BASED-ROUTING rule 10 source address '192.168.0.119/32'
+set policy route LAN-POLICY-BASED-ROUTING rule 20 destination
+set policy route LAN-POLICY-BASED-ROUTING rule 20 set table '100'
+set policy route LAN-POLICY-BASED-ROUTING rule 20 source address '192.168.0.240'
+set policy route-map rm-static-to-bgp rule 10 action 'permit'
+set policy route-map rm-static-to-bgp rule 10 match ip address prefix-list 'user1-routes'
+set policy route-map rm-static-to-bgp rule 100 action 'deny'
+set policy route6 LAN6-POLICY-BASED-ROUTING interface 'eth1'
+set policy route6 LAN6-POLICY-BASED-ROUTING rule 10 destination
+set policy route6 LAN6-POLICY-BASED-ROUTING rule 10 disable
+set policy route6 LAN6-POLICY-BASED-ROUTING rule 10 set table '10'
+set policy route6 LAN6-POLICY-BASED-ROUTING rule 10 source address '2002::1'
+set policy route6 LAN6-POLICY-BASED-ROUTING rule 20 destination
+set policy route6 LAN6-POLICY-BASED-ROUTING rule 20 set table '100'
+set policy route6 LAN6-POLICY-BASED-ROUTING rule 20 source address '2008::f'
+set protocols bgp address-family ipv4-unicast redistribute connected route-map 'rm-static-to-bgp'
+set protocols bgp neighbor 10.89.90.1 address-family ipv4-unicast nexthop-self
+set protocols bgp neighbor 10.89.90.1 address-family ipv4-unicast prefix-list export 'user1-routes'
+set protocols bgp neighbor 10.89.90.1 address-family ipv4-unicast prefix-list import 'user2-routes'
+set protocols bgp neighbor 10.89.90.1 address-family ipv4-unicast soft-reconfiguration inbound
+set protocols bgp neighbor 10.89.90.1 password 'ericandre2020'
+set protocols bgp neighbor 10.89.90.1 remote-as '64589'
+set protocols bgp parameters log-neighbor-changes
+set protocols bgp parameters router-id '10.89.90.2'
+set protocols bgp system-as '64590'
+set protocols static route 100.64.160.23/32 interface pppoe0
+set protocols static route 100.64.165.25/32 interface pppoe0
+set protocols static route 100.64.165.26/32 interface pppoe0
+set protocols static route 100.64.198.0/24 interface vtun0
+set protocols static table 10 route 0.0.0.0/0 interface vtun1
+set protocols static table 100 route 0.0.0.0/0 next-hop 192.168.10.5
+set service conntrack-sync accept-protocol 'tcp'
+set service conntrack-sync accept-protocol 'udp'
+set service conntrack-sync accept-protocol 'icmp'
+set service conntrack-sync disable-external-cache
+set service conntrack-sync event-listen-queue-size '8'
+set service conntrack-sync expect-sync 'all'
+set service conntrack-sync failover-mechanism vrrp sync-group 'failover-group'
+set service conntrack-sync interface eth1 peer '192.168.0.251'
+set service conntrack-sync sync-queue-size '8'
+set service dhcp-server failover name 'DHCP02'
+set service dhcp-server failover remote '192.168.0.251'
+set service dhcp-server failover source-address '192.168.0.250'
+set service dhcp-server failover status 'primary'
+set service dhcp-server shared-network-name LAN authoritative
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 default-router '192.168.0.1'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 domain-name 'vyos.net'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 domain-search 'vyos.net'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 enable-failover
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 lease '86400'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 name-server '192.168.0.1'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 range LANDynamic start '192.168.0.200'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 range LANDynamic stop '192.168.0.240'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping Audio ip-address '192.168.0.107'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping Audio mac-address '00:50:01:dc:91:14'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping IPTV ip-address '192.168.0.104'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping IPTV mac-address '00:50:01:31:b5:f6'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping McPrintus ip-address '192.168.0.60'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping McPrintus mac-address '00:50:01:58:ac:95'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping McPrintus static-mapping-parameters 'option domain-name-servers 192.168.0.6,192.168.0.17;'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping Mobile01 ip-address '192.168.0.109'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping Mobile01 mac-address '00:50:01:bc:ac:51'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping Mobile01 static-mapping-parameters 'option domain-name-servers 192.168.0.6,192.168.0.17;'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping camera1 ip-address '192.168.0.11'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping camera1 mac-address '00:50:01:70:b9:4d'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping camera1 static-mapping-parameters 'option domain-name-servers 192.168.0.6,192.168.0.17;'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping camera2 ip-address '192.168.0.12'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping camera2 mac-address '00:50:01:70:b7:4f'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping camera2 static-mapping-parameters 'option domain-name-servers 192.168.0.6,192.168.0.17;'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping pearTV ip-address '192.168.0.101'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping pearTV mac-address '00:50:01:ba:62:79'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping sand ip-address '192.168.0.110'
+set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 static-mapping sand mac-address '00:50:01:af:c5:d2'
+set service dns forwarding allow-from '192.168.0.0/16'
+set service dns forwarding cache-size '8192'
+set service dns forwarding dnssec 'off'
+set service dns forwarding listen-address '192.168.0.1'
+set service dns forwarding name-server 100.64.0.1
+set service dns forwarding name-server 100.64.0.2
+set service ntp allow-client address '192.168.0.0/16'
+set service ntp server nz.pool.ntp.org prefer
+set service snmp community AwesomeCommunity authorization 'ro'
+set service snmp community AwesomeCommunity client '127.0.0.1'
+set service snmp community AwesomeCommunity network '192.168.0.0/24'
+set service ssh access-control allow user 'vyos'
+set service ssh client-keepalive-interval '60'
+set service ssh listen-address '192.168.0.1'
+set service ssh listen-address '192.168.10.1'
+set service ssh listen-address '192.168.0.250'
+set system config-management commit-revisions '100'
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system ip arp table-size '1024'
+set system name-server '192.168.0.1'
+set system name-server 'pppoe0'
+set system option ctrl-alt-delete 'ignore'
+set system option reboot-on-panic
+set system option startup-beep
+set system static-host-mapping host-name host60.vyos.net inet '192.168.0.60'
+set system static-host-mapping host-name host104.vyos.net inet '192.168.0.104'
+set system static-host-mapping host-name host107.vyos.net inet '192.168.0.107'
+set system static-host-mapping host-name host109.vyos.net inet '192.168.0.109'
+set system sysctl parameter net.core.default_qdisc value 'fq'
+set system sysctl parameter net.ipv4.tcp_congestion_control value 'bbr'
+set system syslog global facility all level 'info'
+set system syslog host 192.168.0.252 facility all level 'debug'
+set system syslog host 192.168.0.252 protocol 'udp'
+set system task-scheduler task Update-Blacklists executable path '/config/scripts/vyos-foo-update.script'
+set system task-scheduler task Update-Blacklists interval '3h'
+set system time-zone 'Pacific/Auckland'
diff --git a/smoketest/configs/basic-vyos b/smoketest/configs/basic-vyos
index 23186b9b8..78dba3ee2 100644
--- a/smoketest/configs/basic-vyos
+++ b/smoketest/configs/basic-vyos
@@ -116,6 +116,18 @@ system {
speed 115200
}
}
+ conntrack {
+ ignore {
+ rule 1 {
+ destination {
+ address 192.0.2.2
+ }
+ source {
+ address 192.0.2.1
+ }
+ }
+ }
+ }
host-name vyos
login {
user vyos {
@@ -127,14 +139,40 @@ system {
}
name-server 192.168.0.1
syslog {
- global {
- archive {
- file 5
- size 512
+ console {
+ facility all {
+ level emerg
}
+ facility mail {
+ level info
+ }
+ }
+ global {
facility all {
level info
}
+ facility protocols {
+ level debug
+ }
+ facility security {
+ level info
+ }
+ preserve-fqdn
+ }
+ host syslog.vyos.net {
+ facility local7 {
+ level notice
+ }
+ facility protocols {
+ level alert
+ }
+ facility security {
+ level warning
+ }
+ format {
+ octet-counted
+ }
+ port 8000
}
}
time-zone Europe/Berlin
diff --git a/smoketest/configs/dialup-router-complex b/smoketest/configs/dialup-router-complex
index 909e6d17b..aa9837fe9 100644
--- a/smoketest/configs/dialup-router-complex
+++ b/smoketest/configs/dialup-router-complex
@@ -1094,6 +1094,10 @@ firewall {
adjust-mss 1452
adjust-mss6 1432
}
+ interface eth0.10 {
+ adjust-mss 1320
+ adjust-mss6 1300
+ }
}
receive-redirects disable
send-redirects enable
diff --git a/smoketest/configs/dialup-router-medium-vpn b/smoketest/configs/dialup-router-medium-vpn
index 56722d222..503280017 100644
--- a/smoketest/configs/dialup-router-medium-vpn
+++ b/smoketest/configs/dialup-router-medium-vpn
@@ -68,9 +68,6 @@ interfaces {
mtu 1500
name-server auto
password password
- traffic-policy {
- out shape-17mbit
- }
user-id vyos
password vyos
}
@@ -96,9 +93,6 @@ interfaces {
}
smp-affinity auto
speed auto
- traffic-policy {
- out shape-94mbit
- }
}
loopback lo {
}
@@ -719,24 +713,6 @@ system {
}
time-zone Pacific/Auckland
}
-traffic-policy {
- shaper shape-17mbit {
- bandwidth 17mbit
- default {
- bandwidth 100%
- burst 15k
- queue-type fq-codel
- }
- }
- shaper shape-94mbit {
- bandwidth 94mbit
- default {
- bandwidth 100%
- burst 15k
- queue-type fq-codel
- }
- }
-}
/* Warning: Do not remove the following line. */
/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@9:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */
/* Release version: 1.2.6 */
diff --git a/smoketest/configs/egb-igp-route-maps b/smoketest/configs/egb-igp-route-maps
new file mode 100644
index 000000000..ca36691d4
--- /dev/null
+++ b/smoketest/configs/egb-igp-route-maps
@@ -0,0 +1,127 @@
+interfaces {
+ ethernet eth0 {
+ address 192.0.2.1/25
+ duplex auto
+ smp-affinity auto
+ speed auto
+ }
+ ethernet eth1 {
+ address 192.0.2.129/25
+ address 2001:db8::1234/64
+ duplex auto
+ smp-affinity auto
+ speed auto
+ }
+ loopback lo {
+ }
+}
+policy {
+ route-map zebra-bgp {
+ rule 10 {
+ action permit
+ }
+ }
+ route-map zebra-isis {
+ rule 10 {
+ action permit
+ }
+ }
+ route-map zebra-ospf {
+ rule 10 {
+ action permit
+ }
+ }
+ route-map zebra-ospfv3 {
+ rule 10 {
+ action permit
+ }
+ }
+ route-map zebra-ripng {
+ rule 10 {
+ action permit
+ }
+ }
+ route-map zebra-static {
+ rule 10 {
+ action permit
+ }
+ }
+}
+protocols {
+ bgp 100 {
+ route-map zebra-bgp
+ }
+ isis {
+ interface eth0 {
+ }
+ net 49.0001.1921.6800.1002.00
+ route-map zebra-isis
+ }
+ ospf {
+ area 0 {
+ network 192.0.2.0/25
+ network 192.0.2.128/25
+ }
+ log-adjacency-changes {
+ }
+ parameters {
+ abr-type cisco
+ router-id 1.1.1.1
+ }
+ passive-interface default
+ passive-interface-exclude eth0
+ passive-interface-exclude eth1
+ route-map zebra-ospf
+ }
+ ospfv3 {
+ area 0 {
+ interface eth1
+ }
+ parameters {
+ router-id 1.1.1.1
+ }
+ route-map zebra-ospfv3
+ }
+ ripng {
+ interface eth1
+ route-map zebra-ripng
+ }
+ static {
+ route-map zebra-static
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ name-server 192.168.0.1
+ syslog {
+ global {
+ archive {
+ file 5
+ size 512
+ }
+ facility all {
+ level info
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+// Warning: Do not remove the following line.
+// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@3:conntrack-sync@2:dhcp-relay@2:dhcp-server@6:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@22:ipoe-server@1:ipsec@5:isis@1:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@8:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@21:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1"
+// Release version: 1.3.2
diff --git a/smoketest/configs/qos-basic b/smoketest/configs/qos-basic
index f94a5650d..65a888d38 100644
--- a/smoketest/configs/qos-basic
+++ b/smoketest/configs/qos-basic
@@ -8,7 +8,7 @@ interfaces {
ethernet eth1 {
address 10.2.1.1/24
traffic-policy {
- out M2
+ out ISPC
}
}
ethernet eth2 {
@@ -16,19 +16,14 @@ interfaces {
traffic-policy {
out MY-HTB
}
- }
- loopback lo {
- }
-}
-protocols {
- static {
- route 0.0.0.0/0 {
- next-hop 10.9.9.2 {
- }
- next-hop 10.1.1.1 {
+ vif 200 {
+ traffic-policy {
+ out foo-emulate
}
}
}
+ loopback lo {
+ }
}
system {
config-management {
@@ -79,24 +74,15 @@ system {
}
}
traffic-policy {
- shaper M2 {
- bandwidth auto
- class 10 {
- bandwidth 100%
- burst 15k
- match ADDRESS10 {
- ip {
- dscp CS4
- }
- }
- queue-type fair-queue
- set-dscp CS5
- }
+ shaper ISPC {
+ bandwidth 600Mbit
default {
- bandwidth 10mbit
- burst 15k
- queue-type fair-queue
+ bandwidth 50%
+ burst 768k
+ ceiling 100%
+ queue-type fq-codel
}
+ description "Outbound Traffic Shaper - ISPC"
}
shaper MY-HTB {
bandwidth 10mbit
@@ -120,7 +106,6 @@ traffic-policy {
ceiling 100%
match ADDRESS40 {
ip {
- dscp CS4
source {
address 10.2.1.0/24
}
@@ -133,12 +118,13 @@ traffic-policy {
bandwidth 100%
burst 15k
match ADDRESS50 {
- ip {
- dscp CS5
+ ipv6 {
+ source {
+ address "2001:db8::1/64"
+ }
}
}
queue-type fair-queue
- set-dscp CS7
}
default {
bandwidth 10%
@@ -146,7 +132,6 @@ traffic-policy {
ceiling 100%
priority 7
queue-type fair-queue
- set-dscp CS1
}
}
shaper FS {
@@ -162,7 +147,6 @@ traffic-policy {
}
}
queue-type fair-queue
- set-dscp CS4
}
class 20 {
bandwidth 100%
@@ -175,7 +159,6 @@ traffic-policy {
}
}
queue-type fair-queue
- set-dscp CS5
}
class 30 {
bandwidth 100%
@@ -188,7 +171,6 @@ traffic-policy {
}
}
queue-type fair-queue
- set-dscp CS6
}
default {
bandwidth 10%
@@ -198,6 +180,10 @@ traffic-policy {
queue-type fair-queue
}
}
+ network-emulator foo-emulate {
+ bandwidth 300mbit
+ burst 20000
+ }
}
// Warning: Do not remove the following line.
// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@3:conntrack-sync@2:dhcp-relay@2:dhcp-server@6:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@22:ipoe-server@1:ipsec@5:isis@1:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@8:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@21:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1"
diff --git a/smoketest/configs/vrf-bgp-pppoe-underlay b/smoketest/configs/vrf-bgp-pppoe-underlay
new file mode 100644
index 000000000..cba35eab1
--- /dev/null
+++ b/smoketest/configs/vrf-bgp-pppoe-underlay
@@ -0,0 +1,473 @@
+interfaces {
+ bridge br50 {
+ address 192.168.0.1/24
+ member {
+ interface eth0.50 {
+ }
+ interface eth2 {
+ }
+ interface eth3 {
+ }
+ }
+ }
+ dummy dum0 {
+ address 100.64.51.252/32
+ address 2001:db8:200:ffff::1/128
+ vrf vyos-test-01
+ }
+ ethernet eth0 {
+ offload {
+ gro
+ gso
+ rps
+ sg
+ tso
+ }
+ ring-buffer {
+ rx 256
+ tx 256
+ }
+ vif 5 {
+ address 2001:db8:200:f0::114/64
+ address 100.64.50.121/28
+ vrf vyos-test-01
+ }
+ vif 10 {
+ address 2001:db8:200:10::ffff/64
+ address 2001:db8:200::ffff/64
+ address 100.64.50.62/26
+ vrf vyos-test-01
+ }
+ vif 15 {
+ address 100.64.50.78/28
+ address 2001:db8:200:15::ffff/64
+ vrf vyos-test-01
+ }
+ vif 50 {
+ description "Member of bridge br50"
+ }
+ vif 110 {
+ address 100.64.51.190/27
+ address 100.64.51.158/28
+ address 2001:db8:200:101::ffff/64
+ vrf vyos-test-01
+ }
+ vif 410 {
+ address 100.64.51.206/28
+ address 2001:db8:200:104::ffff/64
+ vrf vyos-test-01
+ }
+ vif 500 {
+ address 100.64.51.238/28
+ address 2001:db8:200:50::ffff/64
+ vrf vyos-test-01
+ }
+ vif 520 {
+ address 100.64.50.190/28
+ address 2001:db8:200:520::ffff/64
+ vrf vyos-test-01
+ }
+ vif 666 {
+ address 2001:db8:200:ff::101:1/112
+ address 100.64.51.223/31
+ vrf vyos-test-01
+ }
+ vif 800 {
+ address 2001:db8:200:ff::104:1/112
+ address 100.64.51.212/31
+ vrf vyos-test-01
+ }
+ vif 810 {
+ address 100.64.51.30/27
+ address 2001:db8:200:102::ffff/64
+ vrf vyos-test-01
+ }
+ }
+ ethernet eth1 {
+ offload {
+ gro
+ gso
+ rps
+ sg
+ tso
+ }
+ ring-buffer {
+ rx 256
+ tx 256
+ }
+ }
+ ethernet eth2 {
+ offload {
+ gro
+ gso
+ sg
+ tso
+ }
+ }
+ ethernet eth3 {
+ offload {
+ gro
+ gso
+ sg
+ tso
+ }
+ }
+ loopback lo {
+ }
+ pppoe pppoe7 {
+ authentication {
+ password vyos
+ username vyos
+ }
+ dhcpv6-options {
+ pd 0 {
+ interface br50 {
+ address 1
+ }
+ length 56
+ }
+ }
+ ip {
+ adjust-mss 1452
+ }
+ ipv6 {
+ address {
+ autoconf
+ }
+ adjust-mss 1432
+ }
+ mtu 1492
+ no-peer-dns
+ source-interface eth1
+ }
+ virtual-ethernet veth0 {
+ address 100.64.51.220/31
+ address 2001:db8:200:ff::105:1/112
+ description "Core: connect vyos-test-01 and default VRF"
+ peer-name veth1
+ }
+ virtual-ethernet veth1 {
+ address 100.64.51.221/31
+ address 2001:db8:200:ff::105:2/112
+ description "Core: connect vyos-test-01 and default VRF"
+ peer-name veth0
+ vrf vyos-test-01
+ }
+ wireguard wg500 {
+ address 100.64.51.209/31
+ mtu 1500
+ peer A {
+ address 192.0.2.1
+ allowed-ips 0.0.0.0/0
+ port 5500
+ public-key KGSXF4QckzGe7f7CT+r6VZ5brOD/pVYk8yvrxOQ+X0Y=
+ }
+ port 5500
+ private-key iLJh6Me6AdPJtNv3dgGhUbtyFxExxmNU4v0Fs6YE2Xc=
+ vrf vyos-test-01
+ }
+ wireguard wg501 {
+ address 2001:db8:200:ff::102:2/112
+ mtu 1500
+ peer A {
+ address 2001:db8:300::1
+ allowed-ips ::/0
+ port 5501
+ public-key OF+1OJ+VfQ0Yw1mgVtQ2ion4CnAdy8Bvx7yEiO4+Pn8=
+ }
+ port 5501
+ private-key 0MP5X0PW58O4q2LDpuIXgZ0ySyAoWH8/kdpvQccCbUU=
+ vrf vyos-test-01
+ }
+ wireguard wg666 {
+ address 172.29.0.0/31
+ mtu 1500
+ peer B {
+ allowed-ips 0.0.0.0/0
+ public-key 2HT+RfwcqJMYNYzdmtmpem8Ht0dL37o31APHVwmh024=
+ }
+ port 50666
+ private-key zvPnp2MLAoX7SotuHLFLDyy4sdlD7ttbD1xNEqA3mkU=
+ }
+}
+nat {
+ source {
+ rule 100 {
+ outbound-interface pppoe7
+ source {
+ address 192.168.0.0/24
+ }
+ translation {
+ address masquerade
+ }
+ }
+ }
+}
+policy {
+ prefix-list AS100-origin-v4 {
+ rule 10 {
+ action permit
+ prefix 100.64.0.0/12
+ }
+ rule 100 {
+ action permit
+ prefix 0.0.0.0/0
+ }
+ }
+ prefix-list AS200-origin-v4 {
+ rule 10 {
+ action permit
+ prefix 10.0.0.0/8
+ }
+ rule 20 {
+ action permit
+ prefix 172.16.0.0/12
+ }
+
+ }
+ prefix-list6 AS100-origin-v6 {
+ rule 10 {
+ action permit
+ prefix 2001:db8:200::/40
+ }
+ }
+ prefix-list6 AS200-origin-v6 {
+ rule 10 {
+ action permit
+ prefix 2001:db8:100::/40
+ }
+ }
+}
+protocols {
+ static {
+ route 192.0.2.255/32 {
+ interface pppoe7 {
+ }
+ }
+ route 100.64.50.0/23 {
+ next-hop 100.64.51.221 {
+ }
+ }
+ route6 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff/128 {
+ interface pppoe7 {
+ }
+ }
+ }
+}
+qos {
+ interface pppoe7 {
+ egress isp-out
+ }
+ policy {
+ shaper isp-out {
+ bandwidth 38mbit
+ default {
+ bandwidth 100%
+ burst 15k
+ queue-limit 1000
+ queue-type fq-codel
+ }
+ }
+ }
+}
+service {
+ router-advert {
+ interface br50 {
+ prefix ::/64 {
+ preferred-lifetime 2700
+ valid-lifetime 5400
+ }
+ }
+ interface eth0.500 {
+ default-preference high
+ name-server 2001:db8:200::1
+ name-server 2001:db8:200::2
+ prefix 2001:db8:200:50::/64 {
+ valid-lifetime infinity
+ }
+ }
+ interface eth0.520 {
+ default-preference high
+ name-server 2001:db8:200::1
+ name-server 2001:db8:200::2
+ prefix 2001:db8:200:520::/64 {
+ valid-lifetime infinity
+ }
+ }
+ }
+ ssh {
+ disable-host-validation
+ dynamic-protection {
+ allow-from 100.64.0.0/10
+ allow-from 2001:db8:200::/40
+ }
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ conntrack {
+ modules {
+ ftp
+ h323
+ nfs
+ pptp
+ sip
+ sqlnet
+ tftp
+ }
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ domain-name vyos.net
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ name-server 192.168.0.1
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+ time-zone Europe/Berlin
+}
+vrf {
+ bind-to-all
+ name vyos-test-01 {
+ protocols {
+ bgp {
+ address-family {
+ ipv4-unicast {
+ network 100.64.50.0/23 {
+ }
+ }
+ ipv6-unicast {
+ network 2001:db8:200:ffff::1/128 {
+ }
+ }
+ }
+ neighbor 100.64.51.208 {
+ peer-group AS100v4
+ }
+ neighbor 100.64.51.222 {
+ address-family {
+ ipv4-unicast {
+ default-originate {
+ }
+ maximum-prefix 10
+ prefix-list {
+ export AS100-origin-v4
+ import AS200-origin-v4
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as 200
+ }
+ neighbor 100.64.51.251 {
+ peer-group AS100v4
+ shutdown
+ }
+ neighbor 100.64.51.254 {
+ peer-group AS100v4
+ shutdown
+ }
+ neighbor 2001:db8:200:ffff::2 {
+ peer-group AS100v6
+ shutdown
+ }
+ neighbor 2001:db8:200:ffff::a {
+ peer-group AS100v6
+ }
+ neighbor 2001:db8:200:ff::101:2 {
+ address-family {
+ ipv6-unicast {
+ maximum-prefix 10
+ prefix-list {
+ export AS100-origin-v6
+ import AS200-origin-v6
+ }
+ soft-reconfiguration {
+ inbound
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as 200
+ }
+ peer-group AS100v4 {
+ address-family {
+ ipv4-unicast {
+ nexthop-self {
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as internal
+ update-source dum0
+ }
+ peer-group AS100v6 {
+ address-family {
+ ipv6-unicast {
+ nexthop-self {
+ }
+ }
+ }
+ capability {
+ dynamic
+ }
+ remote-as internal
+ update-source dum0
+ }
+ system-as 100
+ }
+ static {
+ route 192.168.0.0/24 {
+ next-hop 100.64.51.220 {
+ }
+ }
+ route 100.64.50.0/23 {
+ blackhole {
+ }
+ }
+ route 100.64.51.32/27 {
+ next-hop 100.64.51.5 {
+ }
+ }
+ route6 2001:db8:2fe:ffff::/64 {
+ next-hop 2001:db8:200:102::5 {
+ }
+ }
+ }
+ }
+ table 1000
+ }
+}
+
+// Warning: Do not remove the following line.
+// vyos-config-version: "bgp@3:broadcast-relay@1:cluster@1:config-management@1:conntrack@3:conntrack-sync@2:container@1:dhcp-relay@2:dhcp-server@6:dhcpv6-server@1:dns-forwarding@3:firewall@9:flow-accounting@1:https@4:ids@1:interfaces@28:ipoe-server@1:ipsec@12:isis@2:l2tp@4:lldp@1:mdns@1:monitoring@1:nat@5:nat66@1:ntp@2:openconnect@2:ospf@1:policy@5:pppoe-server@6:pptp@2:qos@2:quagga@10:rpki@1:salt@1:snmp@3:ssh@2:sstp@4:system@25:vrf@3:vrrp@3:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2"
+// Release version: 1.4-rolling-202303160317
diff --git a/smoketest/scripts/cli/base_accel_ppp_test.py b/smoketest/scripts/cli/base_accel_ppp_test.py
index 471bdaffb..989028f64 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-2022 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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
@@ -21,9 +21,9 @@ from configparser import ConfigParser
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.template import is_ipv4
-from vyos.util import cmd
-from vyos.util import get_half_cpus
-from vyos.util import process_named_running
+from vyos.utils.system import get_half_cpus
+from vyos.utils.process import process_named_running
+from vyos.utils.process import cmd
class BasicAccelPPPTest:
class TestCase(VyOSUnitTestSHIM.TestCase):
diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py
index 55343b893..51ccbc9e6 100644
--- a/smoketest/scripts/cli/base_interfaces_test.py
+++ b/smoketest/scripts/cli/base_interfaces_test.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2019-2022 VyOS maintainers and contributors
+# Copyright (C) 2019-2023 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
@@ -26,15 +26,23 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
+from vyos.defaults import directories
from vyos.ifconfig import Interface
from vyos.ifconfig import Section
-from vyos.util import read_file
-from vyos.util import cmd
-from vyos.util import dict_search
-from vyos.util import process_named_running
-from vyos.util import get_interface_config
-from vyos.validate import is_intf_addr_assigned
-from vyos.validate import is_ipv6_link_local
+from vyos.utils.file import read_file
+from vyos.utils.dict import dict_search
+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.process import cmd
+from vyos.utils.network import is_intf_addr_assigned
+from vyos.utils.network import is_ipv6_link_local
+from vyos.xml_ref import cli_defined
+
+dhclient_base_dir = directories['isc_dhclient_dir']
+dhclient_process_name = 'dhclient'
+dhcp6c_base_dir = directories['dhcp6_client_dir']
+dhcp6c_process_name = 'dhcp6c'
def is_mirrored_to(interface, mirror_if, qdisc):
"""
@@ -65,6 +73,7 @@ class BasicInterfaceTest:
_test_ipv6_pd = False
_test_ipv6_dhcpc6 = False
_test_mirror = False
+ _test_vrf = False
_base_path = []
_options = {}
@@ -82,6 +91,18 @@ class BasicInterfaceTest:
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_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)
@@ -104,9 +125,15 @@ class BasicInterfaceTest:
for intf in self._interfaces:
self.assertNotIn(intf, interfaces())
- # No daemon that was started during a test should remain running
+ # No daemon started during tests should remain running
for daemon in ['dhcp6c', 'dhclient']:
- self.assertFalse(process_named_running(daemon))
+ # 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:
@@ -119,11 +146,9 @@ class BasicInterfaceTest:
for option in self._options.get(interface, []):
self.cli_set(self._base_path + [interface] + option.split())
- self.cli_set(self._base_path + [interface, 'disable'])
-
# Also enable DHCP (ISC DHCP always places interface in admin up
# state so we check that we do not start DHCP client.
- # https://phabricator.vyos.net/T2767
+ # https://vyos.dev/T2767
self.cli_set(self._base_path + [interface, 'address', 'dhcp'])
self.cli_commit()
@@ -133,6 +158,99 @@ class BasicInterfaceTest:
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('not supported')
+
+ distance = '100'
+
+ 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', 'default-route-distance', distance])
+
+ self.cli_commit()
+
+ for interface in self._interfaces:
+ # Check if dhclient process runs
+ dhclient_pid = process_named_running(dhclient_process_name, cmdline=interface)
+ self.assertTrue(dhclient_pid)
+
+ dhclient_config = read_file(f'{dhclient_base_dir}/dhclient_{interface}.conf')
+ self.assertIn('request subnet-mask, broadcast-address, routers, domain-name-servers', dhclient_config)
+ self.assertIn('require subnet-mask;', 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('not supported')
+
+ 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)
+ 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('-e\x00IF_METRIC=210', cmdline) # 210 is the default value
+
+ 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('not supported')
+
+ 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)
+ self.assertTrue(tmp)
+ # .. inside the appropriate VRF instance
+ vrf_pids = cmd(f'ip vrf pids {vrf_name}')
+ self.assertIn(str(tmp), vrf_pids)
+
+ self.cli_delete(['vrf', 'name', vrf_name])
+
def test_span_mirror(self):
if not self._mirror_interfaces:
self.skipTest('not supported')
@@ -360,7 +478,7 @@ class BasicInterfaceTest:
# 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:
+ if not self._test_vlan or not self._test_mtu:
self.skipTest('not supported')
mtu_1500 = '1500'
@@ -476,7 +594,7 @@ class BasicInterfaceTest:
self.assertEqual(to_key, new_egress_qos_to)
def test_vif_8021q_lower_up_down(self):
- # Testcase for https://phabricator.vyos.net/T3349
+ # Testcase for https://vyos.dev/T3349
if not self._test_vlan:
self.skipTest('not supported')
@@ -634,58 +752,94 @@ class BasicInterfaceTest:
self.cli_set(path + option.split())
# Options
- self.cli_set(path + ['ip', 'adjust-mss', mss])
- self.cli_set(path + ['ip', 'arp-cache-timeout', arp_tmo])
- self.cli_set(path + ['ip', 'disable-arp-filter'])
- self.cli_set(path + ['ip', 'disable-forwarding'])
- self.cli_set(path + ['ip', 'enable-directed-broadcast'])
- self.cli_set(path + ['ip', 'enable-arp-accept'])
- self.cli_set(path + ['ip', 'enable-arp-announce'])
- self.cli_set(path + ['ip', 'enable-arp-ignore'])
- self.cli_set(path + ['ip', 'enable-proxy-arp'])
- self.cli_set(path + ['ip', 'proxy-arp-pvlan'])
- self.cli_set(path + ['ip', 'source-validation', 'loose'])
+ 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:
- 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'], '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)
- 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
+ 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}'
- tmp = read_file(f'{proc_base}/arp_filter')
- self.assertEqual('0', tmp)
+ if cli_defined(self._base_path + ['ip'], 'disable-arp-filter'):
+ tmp = read_file(f'{proc_base}/arp_filter')
+ self.assertEqual('0', tmp)
- tmp = read_file(f'{proc_base}/arp_accept')
- self.assertEqual('1', tmp)
+ if cli_defined(self._base_path + ['ip'], 'enable-arp-accept'):
+ tmp = read_file(f'{proc_base}/arp_accept')
+ self.assertEqual('1', tmp)
- tmp = read_file(f'{proc_base}/arp_announce')
- 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)
- tmp = read_file(f'{proc_base}/arp_ignore')
- 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)
- tmp = read_file(f'{proc_base}/forwarding')
- self.assertEqual('0', tmp)
+ if cli_defined(self._base_path + ['ip'], 'disable-forwarding'):
+ tmp = read_file(f'{proc_base}/forwarding')
+ self.assertEqual('0', tmp)
- tmp = read_file(f'{proc_base}/bc_forwarding')
- self.assertEqual('1', tmp)
+ if cli_defined(self._base_path + ['ip'], 'enable-directed-broadcast'):
+ tmp = read_file(f'{proc_base}/bc_forwarding')
+ self.assertEqual('1', tmp)
- tmp = read_file(f'{proc_base}/proxy_arp')
- 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)
- tmp = read_file(f'{proc_base}/proxy_arp_pvlan')
- 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)
- tmp = read_file(f'{proc_base}/rp_filter')
- self.assertEqual('2', 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:
@@ -693,6 +847,8 @@ class BasicInterfaceTest:
mss = '1400'
dad_transmits = '10'
+ accept_dad = '0'
+ source_validation = 'strict'
for interface in self._interfaces:
path = self._base_path + [interface]
@@ -700,26 +856,51 @@ class BasicInterfaceTest:
self.cli_set(path + option.split())
# Options
- self.cli_set(path + ['ipv6', 'adjust-mss', mss])
- self.cli_set(path + ['ipv6', 'disable-forwarding'])
- self.cli_set(path + ['ipv6', 'dup-addr-detect-transmits', dad_transmits])
+ if cli_defined(self._base_path + ['ipv6'], 'adjust-mss'):
+ self.cli_set(path + ['ipv6', 'adjust-mss', mss])
- self.cli_commit()
+ if cli_defined(self._base_path + ['ipv6'], 'accept-dad'):
+ self.cli_set(path + ['ipv6', 'accept-dad', accept_dad])
- for interface in self._interfaces:
- 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'], 'dup-addr-detect-transmits'):
+ self.cli_set(path + ['ipv6', 'dup-addr-detect-transmits', dad_transmits])
- proc_base = f'/proc/sys/net/ipv6/conf/{interface}'
+ if cli_defined(self._base_path + ['ipv6'], 'disable-forwarding'):
+ self.cli_set(path + ['ipv6', 'disable-forwarding'])
- tmp = read_file(f'{proc_base}/forwarding')
- self.assertEqual('0', tmp)
+ if cli_defined(self._base_path + ['ipv6'], 'source-validation'):
+ self.cli_set(path + ['ipv6', 'source-validation', source_validation])
- tmp = read_file(f'{proc_base}/dad_transmits')
- self.assertEqual(dad_transmits, tmp)
+ 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)
def test_dhcpv6_client_options(self):
if not self._test_ipv6_dhcpc6:
@@ -734,6 +915,7 @@ class BasicInterfaceTest:
# 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])
@@ -744,7 +926,7 @@ class BasicInterfaceTest:
duid_base = 10
for interface in self._interfaces:
duid = '00:01:00:01:27:71:db:f0:00:50:00:00:00:{}'.format(duid_base)
- dhcpc6_config = read_file(f'/run/dhcp6c/dhcp6c.{interface}.conf')
+ 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)
@@ -755,8 +937,12 @@ class BasicInterfaceTest:
self.assertIn('};', dhcpc6_config)
duid_base += 1
- # Check for running process
- self.assertTrue(process_named_running('dhcp6c'))
+ # Better ask the process about it's commandline in the future
+ pid = process_named_running(dhcp6c_process_name, cmdline=interface)
+ self.assertTrue(pid)
+
+ 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:
@@ -765,7 +951,14 @@ class BasicInterfaceTest:
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]
@@ -778,8 +971,6 @@ class BasicInterfaceTest:
self.cli_set(pd_base + ['length', prefix_len])
for delegatee in delegatees:
- section = Section.section(delegatee)
- self.cli_set(['interfaces', section, delegatee])
self.cli_set(pd_base + ['interface', delegatee, 'address', address])
# increment interface address
address = str(int(address) + 1)
@@ -787,7 +978,7 @@ class BasicInterfaceTest:
self.cli_commit()
for interface in self._interfaces:
- dhcpc6_config = read_file(f'/run/dhcp6c/dhcp6c.{interface}.conf')
+ dhcpc6_config = read_file(f'{dhcp6c_base_dir}/dhcp6c.{interface}.conf')
# verify DHCPv6 prefix delegation
self.assertIn(f'prefix ::/{prefix_len} infinity;', dhcpc6_config)
@@ -805,8 +996,8 @@ class BasicInterfaceTest:
# increment interface address
address = str(int(address) + 1)
- # Check for running process
- self.assertTrue(process_named_running('dhcp6c'))
+ # Check for running process
+ self.assertTrue(process_named_running(dhcp6c_process_name, cmdline=interface))
for delegatee in delegatees:
# we can already cleanup the test delegatee interface here
@@ -821,7 +1012,14 @@ class BasicInterfaceTest:
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]
@@ -835,8 +1033,6 @@ class BasicInterfaceTest:
self.cli_set(pd_base + ['length', prefix_len])
for delegatee in delegatees:
- section = Section.section(delegatee)
- self.cli_set(['interfaces', section, delegatee])
self.cli_set(pd_base + ['interface', delegatee, 'address', address])
self.cli_set(pd_base + ['interface', delegatee, 'sla-id', sla_id])
@@ -850,7 +1046,7 @@ class BasicInterfaceTest:
for interface in self._interfaces:
address = '1'
sla_id = '1'
- dhcpc6_config = read_file(f'/run/dhcp6c/dhcp6c.{interface}.conf')
+ dhcpc6_config = read_file(f'{dhcp6c_base_dir}/dhcp6c.{interface}.conf')
# verify DHCPv6 prefix delegation
self.assertIn(f'prefix ::/{prefix_len} infinity;', dhcpc6_config)
@@ -866,8 +1062,8 @@ class BasicInterfaceTest:
# increment interface address
address = str(int(address) + 1)
- # Check for running process
- self.assertTrue(process_named_running('dhcp6c'))
+ # Check for running process
+ self.assertTrue(process_named_running(dhcp6c_process_name, cmdline=interface))
for delegatee in delegatees:
# we can already cleanup the test delegatee interface here
diff --git a/smoketest/scripts/cli/base_vyostest_shim.py b/smoketest/scripts/cli/base_vyostest_shim.py
index 7cfb53045..f694f539d 100644
--- a/smoketest/scripts/cli/base_vyostest_shim.py
+++ b/smoketest/scripts/cli/base_vyostest_shim.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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
@@ -14,6 +14,7 @@
import os
import unittest
+import paramiko
from time import sleep
from typing import Type
@@ -22,8 +23,8 @@ from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos import ConfigError
from vyos.defaults import commit_lock
-from vyos.util import cmd
-from vyos.util import run
+from vyos.utils.process import cmd
+from vyos.utils.process import run
save_config = '/tmp/vyos-smoketest-save'
@@ -87,6 +88,19 @@ class VyOSUnitTestSHIM:
pprint.pprint(out)
return out
+ @staticmethod
+ def ssh_send_cmd(command, username, password, 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)
+ _, stdout, stderr = ssh_client.exec_command(command)
+ output = stdout.read().decode().strip()
+ error = stderr.read().decode().strip()
+ ssh_client.close()
+ return output, error
+
# standard construction; typing suggestion: https://stackoverflow.com/a/70292317
def ignore_warning(warning: Type[Warning]):
import warnings
diff --git a/smoketest/scripts/cli/test_configd_init.py b/smoketest/scripts/cli/test_configd_init.py
index 5dec89963..245c03824 100755
--- a/smoketest/scripts/cli/test_configd_init.py
+++ b/smoketest/scripts/cli/test_configd_init.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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,7 +17,8 @@
import unittest
from time import sleep
-from vyos.util import cmd, is_systemd_service_running
+from vyos.utils.process import is_systemd_service_running
+from vyos.utils.process import cmd
class TestConfigdInit(unittest.TestCase):
def setUp(self):
diff --git a/smoketest/scripts/cli/test_container.py b/smoketest/scripts/cli/test_container.py
index b9d308ae1..b43c05fae 100755
--- a/smoketest/scripts/cli/test_container.py
+++ b/smoketest/scripts/cli/test_container.py
@@ -21,9 +21,9 @@ import json
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import cmd
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
base_path = ['container']
cont_image = 'busybox:stable' # busybox is included in vyos-build
@@ -47,7 +47,10 @@ class TestContainer(VyOSUnitTestSHIM.TestCase):
super(TestContainer, cls).setUpClass()
# Load image for smoketest provided in vyos-build
- cmd(f'cat {busybox_image_path} | sudo podman load')
+ try:
+ cmd(f'cat {busybox_image_path} | sudo podman load')
+ except:
+ cls.skipTest(cls, reason='busybox image not available')
@classmethod
def tearDownClass(cls):
diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py
index 821925bcd..391ef03ff 100755
--- a/smoketest/scripts/cli/test_firewall.py
+++ b/smoketest/scripts/cli/test_firewall.py
@@ -17,11 +17,13 @@
import unittest
from glob import glob
+from time import sleep
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
+from vyos.utils.process import cmd
+from vyos.utils.process import run
sysfs_config = {
'all_ping': {'sysfs': '/proc/sys/net/ipv4/icmp_echo_ignore_all', 'default': '0', 'test_value': 'disable'},
@@ -76,20 +78,42 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
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 wait_for_domain_resolver(self, table, set_name, element, max_wait=10):
+ # Resolver no longer blocks commit, need to wait for daemon to populate set
+ count = 0
+ while count < max_wait:
+ code = run(f'sudo nft get element {table} {set_name} {{ {element} }}')
+ if code == 0:
+ return True
+ count += 1
+ sleep(1)
+ return False
+
def test_geoip(self):
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'action', 'drop'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'source', 'geoip', 'country-code', 'se'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'source', 'geoip', 'country-code', 'gb'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'action', 'accept'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'source', 'geoip', 'country-code', 'de'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'source', 'geoip', 'country-code', 'fr'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'source', 'geoip', 'inverse-match'])
+ self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'rule', '1', 'action', 'drop'])
+ self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'rule', '1', 'source', 'geoip', 'country-code', 'se'])
+ self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'rule', '1', 'source', 'geoip', 'country-code', 'gb'])
+ self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'rule', '2', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'rule', '2', 'source', 'geoip', 'country-code', 'de'])
+ self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'rule', '2', 'source', 'geoip', 'country-code', 'fr'])
+ self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'rule', '2', 'source', 'geoip', 'inverse-match'])
self.cli_commit()
nftables_search = [
- ['ip saddr @GEOIP_CC_smoketest_1', 'drop'],
- ['ip saddr != @GEOIP_CC_smoketest_2', 'return']
+ ['ip saddr @GEOIP_CC_name_smoketest_1', 'drop'],
+ ['ip saddr != @GEOIP_CC_name_smoketest_2', 'accept']
]
# -t prevents 1000+ GeoIP elements being returned
@@ -111,31 +135,36 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_set(['firewall', 'group', 'port-group', 'smoketest_port', 'port', '123'])
self.cli_set(['firewall', 'group', 'domain-group', 'smoketest_domain', 'address', 'example.com'])
self.cli_set(['firewall', 'group', 'domain-group', 'smoketest_domain', 'address', 'example.org'])
+ self.cli_set(['firewall', 'group', 'interface-group', 'smoketest_interface', 'interface', 'eth0'])
+ self.cli_set(['firewall', 'group', 'interface-group', 'smoketest_interface', 'interface', 'vtun0'])
+
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'source', 'group', 'network-group', 'smoketest_network'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'destination', 'address', '172.16.10.10'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'destination', 'group', 'port-group', 'smoketest_port'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'protocol', 'tcp_udp'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '2', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '2', 'source', 'group', 'mac-group', 'smoketest_mac'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '3', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '3', 'source', 'group', 'domain-group', 'smoketest_domain'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '4', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '4', 'outbound-interface', 'interface-group', '!smoketest_interface'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'action', 'accept'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'source', 'group', 'network-group', 'smoketest_network'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'destination', 'address', '172.16.10.10'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'destination', 'group', 'port-group', 'smoketest_port'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'protocol', 'tcp_udp'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'action', 'accept'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'source', 'group', 'mac-group', 'smoketest_mac'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '3', 'action', 'accept'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '3', 'source', 'group', 'domain-group', 'smoketest_domain'])
+ self.cli_commit()
- self.cli_set(['firewall', 'interface', 'eth0', 'in', 'name', 'smoketest'])
+ self.wait_for_domain_resolver('ip vyos_filter', 'D_smoketest_domain', '192.0.2.5')
- self.cli_commit()
nftables_search = [
- ['iifname "eth0"', 'jump NAME_smoketest'],
- ['ip saddr @N_smoketest_network', 'ip daddr 172.16.10.10', 'th dport @P_smoketest_port', 'return'],
+ ['ip saddr @N_smoketest_network', 'ip daddr 172.16.10.10', 'th dport @P_smoketest_port', 'accept'],
['elements = { 172.16.99.0/24 }'],
['elements = { 53, 123 }'],
- ['ether saddr @M_smoketest_mac', 'return'],
+ ['ether saddr @M_smoketest_mac', 'accept'],
['elements = { 00:01:02:03:04:05 }'],
['set D_smoketest_domain'],
['elements = { 192.0.2.5, 192.0.2.8,'],
['192.0.2.10, 192.0.2.11 }'],
- ['ip saddr @D_smoketest_domain', 'return']
+ ['ip saddr @D_smoketest_domain', 'accept'],
+ ['oifname != @I_smoketest_interface', 'accept']
]
self.verify_nftables(nftables_search, 'ip vyos_filter')
@@ -149,12 +178,10 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_set(['firewall', 'group', 'port-group', 'smoketest_port', 'port', '53'])
self.cli_set(['firewall', 'group', 'port-group', 'smoketest_port1', 'port', '123'])
self.cli_set(['firewall', 'group', 'port-group', 'smoketest_port1', 'include', 'smoketest_port'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'action', 'accept'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'source', 'group', 'network-group', 'smoketest_network1'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'destination', 'group', 'port-group', 'smoketest_port1'])
- self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'protocol', 'tcp_udp'])
-
- self.cli_set(['firewall', 'interface', 'eth0', 'in', 'name', 'smoketest'])
+ self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'rule', '1', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'rule', '1', 'source', 'group', 'network-group', 'smoketest_network1'])
+ self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'rule', '1', 'destination', 'group', 'port-group', 'smoketest_port1'])
+ self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'rule', '1', 'protocol', 'tcp_udp'])
self.cli_commit()
@@ -166,8 +193,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_delete(['firewall', 'group', 'network-group', 'smoketest_network', 'include', 'smoketest_network1'])
nftables_search = [
- ['iifname "eth0"', 'jump NAME_smoketest'],
- ['ip saddr @N_smoketest_network1', 'th dport @P_smoketest_port1', 'return'],
+ ['ip saddr @N_smoketest_network1', 'th dport @P_smoketest_port1', 'accept'],
['elements = { 172.16.99.0/24, 172.16.101.0/24 }'],
['elements = { 53, 123 }']
]
@@ -177,56 +203,80 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
def test_ipv4_basic_rules(self):
name = 'smoketest'
interface = 'eth0'
+ interface_inv = '!eth0'
+ interface_wc = 'l2tp*'
mss_range = '501-1460'
-
- self.cli_set(['firewall', 'name', name, 'default-action', 'drop'])
- self.cli_set(['firewall', 'name', name, 'enable-default-log'])
- self.cli_set(['firewall', 'name', name, 'rule', '1', 'action', 'accept'])
- self.cli_set(['firewall', 'name', name, 'rule', '1', 'source', 'address', '172.16.20.10'])
- self.cli_set(['firewall', 'name', name, 'rule', '1', 'destination', 'address', '172.16.10.10'])
- self.cli_set(['firewall', 'name', name, 'rule', '1', 'log', 'enable'])
- self.cli_set(['firewall', 'name', name, 'rule', '1', 'log-level', 'debug'])
- self.cli_set(['firewall', 'name', name, 'rule', '1', 'ttl', 'eq', '15'])
- self.cli_set(['firewall', 'name', name, 'rule', '2', 'action', 'reject'])
- self.cli_set(['firewall', 'name', name, 'rule', '2', 'protocol', 'tcp'])
- self.cli_set(['firewall', 'name', name, 'rule', '2', 'destination', 'port', '8888'])
- self.cli_set(['firewall', 'name', name, 'rule', '2', 'log', 'enable'])
- self.cli_set(['firewall', 'name', name, 'rule', '2', 'log-level', 'err'])
- self.cli_set(['firewall', 'name', name, 'rule', '2', 'tcp', 'flags', 'syn'])
- self.cli_set(['firewall', 'name', name, 'rule', '2', 'tcp', 'flags', 'not', 'ack'])
- self.cli_set(['firewall', 'name', name, 'rule', '2', 'ttl', 'gt', '102'])
- self.cli_set(['firewall', 'name', name, 'rule', '3', 'action', 'accept'])
- self.cli_set(['firewall', 'name', name, 'rule', '3', 'protocol', 'tcp'])
- self.cli_set(['firewall', 'name', name, 'rule', '3', 'destination', 'port', '22'])
- self.cli_set(['firewall', 'name', name, 'rule', '3', 'limit', 'rate', '5/minute'])
- self.cli_set(['firewall', 'name', name, 'rule', '3', 'log', 'disable'])
- self.cli_set(['firewall', 'name', name, 'rule', '4', 'action', 'drop'])
- self.cli_set(['firewall', 'name', name, 'rule', '4', 'protocol', 'tcp'])
- self.cli_set(['firewall', 'name', name, 'rule', '4', 'destination', 'port', '22'])
- self.cli_set(['firewall', 'name', name, 'rule', '4', 'recent', 'count', '10'])
- self.cli_set(['firewall', 'name', name, 'rule', '4', 'recent', 'time', 'minute'])
- self.cli_set(['firewall', 'name', name, 'rule', '5', 'action', 'accept'])
- self.cli_set(['firewall', 'name', name, 'rule', '5', 'protocol', 'tcp'])
- self.cli_set(['firewall', 'name', name, 'rule', '5', 'tcp', 'flags', 'syn'])
- self.cli_set(['firewall', 'name', name, 'rule', '5', 'tcp', 'mss', mss_range])
- self.cli_set(['firewall', 'name', name, 'rule', '5', 'inbound-interface', interface])
- self.cli_set(['firewall', 'name', name, 'rule', '6', 'action', 'return'])
- self.cli_set(['firewall', 'name', name, 'rule', '6', 'protocol', 'gre'])
- self.cli_set(['firewall', 'name', name, 'rule', '6', 'outbound-interface', interface])
-
- self.cli_set(['firewall', 'interface', interface, 'in', 'name', name])
+ conn_mark = '555'
+
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'default-action', 'drop'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'enable-default-log'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'source', 'address', '172.16.20.10'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'destination', 'address', '172.16.10.10'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'log', 'enable'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'log-options', 'level', 'debug'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'ttl', 'eq', '15'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'action', 'reject'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'protocol', 'tcp'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'destination', 'port', '8888'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'log', 'enable'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'log-options', 'level', 'err'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'tcp', 'flags', 'syn'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'tcp', 'flags', 'not', 'ack'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'ttl', 'gt', '102'])
+
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'default-action', 'drop'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '3', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '3', 'protocol', 'tcp'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '3', 'destination', 'port', '22'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '3', 'limit', 'rate', '5/minute'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '3', 'log', 'disable'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '4', 'action', 'drop'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '4', 'protocol', 'tcp'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '4', 'destination', 'port', '22'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '4', 'recent', 'count', '10'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '4', 'recent', 'time', 'minute'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '4', 'packet-type', 'host'])
+
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '5', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '5', 'protocol', 'tcp'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '5', 'tcp', 'flags', 'syn'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '5', 'tcp', 'mss', mss_range])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '5', 'packet-type', 'broadcast'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '5', 'inbound-interface', 'interface-name', interface_wc])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '6', 'action', 'return'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '6', 'protocol', 'gre'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '6', 'connection-mark', conn_mark])
+
+ self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'default-action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '5', 'action', 'drop'])
+ self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '5', 'protocol', 'gre'])
+ self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '5', 'outbound-interface', 'interface-name', interface_inv])
+ self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '6', 'action', 'return'])
+ self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '6', 'protocol', 'icmp'])
+ self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '6', 'connection-mark', conn_mark])
self.cli_commit()
+ mark_hex = "{0:#010x}".format(int(conn_mark))
+
nftables_search = [
- [f'iifname "{interface}"', f'jump NAME_{name}'],
- ['saddr 172.16.20.10', 'daddr 172.16.10.10', 'log prefix "[smoketest-1-A]" level debug', 'ip ttl 15', 'return'],
- ['tcp flags syn / syn,ack', 'tcp dport 8888', 'log prefix "[smoketest-2-R]" level err', 'ip ttl > 102', 'reject'],
- ['tcp dport 22', 'limit rate 5/minute', 'return'],
- ['log prefix "[smoketest-default-D]"','smoketest default-action', 'drop'],
- ['tcp dport 22', 'add @RECENT_smoketest_4 { ip saddr limit rate over 10/minute burst 10 packets }', 'drop'],
- ['tcp flags & syn == syn', f'tcp option maxseg size {mss_range}', f'iifname "{interface}"'],
- ['meta l4proto gre', f'oifname "{interface}"', 'return']
+ ['chain VYOS_FORWARD_filter'],
+ ['type filter hook forward priority filter; policy drop;'],
+ ['tcp dport 22', 'limit rate 5/minute', 'accept'],
+ ['tcp dport 22', 'add @RECENT_FWD_filter_4 { ip saddr limit rate over 10/minute burst 10 packets }', 'meta pkttype host', 'drop'],
+ ['chain VYOS_INPUT_filter'],
+ ['type filter hook input priority filter; policy accept;'],
+ ['tcp flags & syn == syn', f'tcp option maxseg size {mss_range}', f'iifname "{interface_wc}"', 'meta pkttype broadcast', 'accept'],
+ ['meta l4proto gre', f'ct mark {mark_hex}', 'return'],
+ ['chain VYOS_OUTPUT_filter'],
+ ['type filter hook output priority filter; policy accept;'],
+ ['meta l4proto gre', f'oifname != "{interface}"', 'drop'],
+ ['meta l4proto icmp', f'ct mark {mark_hex}', 'return'],
+ ['chain NAME_smoketest'],
+ ['saddr 172.16.20.10', 'daddr 172.16.10.10', 'log prefix "[ipv4-NAM-smoketest-1-A]" log level debug', 'ip ttl 15', 'accept'],
+ ['tcp flags syn / syn,ack', 'tcp dport 8888', 'log prefix "[ipv4-NAM-smoketest-2-R]" log level err', 'ip ttl > 102', 'reject'],
+ ['log prefix "[smoketest-default-D]"','smoketest default-action', 'drop']
]
self.verify_nftables(nftables_search, 'ip vyos_filter')
@@ -236,76 +286,134 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
name2 = 'smoketest-adv2'
interface = 'eth0'
- self.cli_set(['firewall', 'name', name, 'default-action', 'drop'])
- self.cli_set(['firewall', 'name', name, 'enable-default-log'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'default-action', 'drop'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'enable-default-log'])
+
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '6', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '6', 'packet-length', '64'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '6', 'packet-length', '512'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '6', 'packet-length', '1024'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '6', 'dscp', '17'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '6', 'dscp', '52'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '6', 'log', 'enable'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '6', 'log-options', 'group', '66'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '6', 'log-options', 'snapshot-length', '6666'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '6', 'log-options', 'queue-threshold','32000'])
+
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '7', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '7', 'packet-length', '1-30000'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '7', 'packet-length-exclude', '60000-65535'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '7', 'dscp', '3-11'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '7', 'dscp-exclude', '21-25'])
+
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'default-action', 'drop'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'source', 'address', '198.51.100.1'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'action', 'jump'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'jump-target', name])
+
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '2', 'protocol', 'tcp'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '2', 'action', 'queue'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '2', 'queue', '3'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '3', 'protocol', 'udp'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '3', 'action', 'queue'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '3', 'queue-options', 'fanout'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '3', 'queue-options', 'bypass'])
+ self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '3', 'queue', '0-15'])
+
+ self.cli_commit()
+
+ nftables_search = [
+ ['chain VYOS_FORWARD_filter'],
+ ['type filter hook forward priority filter; policy drop;'],
+ ['ip saddr 198.51.100.1', f'jump NAME_{name}'],
+ ['chain VYOS_INPUT_filter'],
+ ['type filter hook input priority filter; policy accept;'],
+ [f'meta l4proto tcp','queue to 3'],
+ [f'meta l4proto udp','queue flags bypass,fanout to 0-15'],
+ [f'chain NAME_{name}'],
+ ['ip length { 64, 512, 1024 }', 'ip dscp { 0x11, 0x34 }', f'log prefix "[ipv4-NAM-{name}-6-A]" log group 66 snaplen 6666 queue-threshold 32000', 'accept'],
+ ['ip length 1-30000', 'ip length != 60000-65535', 'ip dscp 0x03-0x0b', 'ip dscp != 0x15-0x19', 'accept'],
+ [f'log prefix "[{name}-default-D]"', 'drop']
+ ]
+
+ self.verify_nftables(nftables_search, 'ip vyos_filter')
+
+ def test_ipv4_mask(self):
+ name = 'smoketest-mask'
+ interface = 'eth0'
+
+ self.cli_set(['firewall', 'group', 'address-group', 'mask_group', 'address', '1.1.1.1'])
- self.cli_set(['firewall', 'name', name, 'rule', '6', 'action', 'accept'])
- self.cli_set(['firewall', 'name', name, 'rule', '6', 'packet-length', '64'])
- self.cli_set(['firewall', 'name', name, 'rule', '6', 'packet-length', '512'])
- self.cli_set(['firewall', 'name', name, 'rule', '6', 'packet-length', '1024'])
- self.cli_set(['firewall', 'name', name, 'rule', '6', 'dscp', '17'])
- self.cli_set(['firewall', 'name', name, 'rule', '6', 'dscp', '52'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'default-action', 'drop'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'enable-default-log'])
- self.cli_set(['firewall', 'name', name, 'rule', '7', 'action', 'accept'])
- self.cli_set(['firewall', 'name', name, 'rule', '7', 'packet-length', '1-30000'])
- self.cli_set(['firewall', 'name', name, 'rule', '7', 'packet-length-exclude', '60000-65535'])
- self.cli_set(['firewall', 'name', name, 'rule', '7', 'dscp', '3-11'])
- self.cli_set(['firewall', 'name', name, 'rule', '7', 'dscp-exclude', '21-25'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'action', 'drop'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'destination', 'address', '0.0.1.2'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'destination', 'address-mask', '0.0.255.255'])
- self.cli_set(['firewall', 'name', name2, 'default-action', 'jump'])
- self.cli_set(['firewall', 'name', name2, 'default-jump-target', name])
- self.cli_set(['firewall', 'name', name2, 'enable-default-log'])
- self.cli_set(['firewall', 'name', name2, 'rule', '1', 'source', 'address', '198.51.100.1'])
- self.cli_set(['firewall', 'name', name2, 'rule', '1', 'action', 'jump'])
- self.cli_set(['firewall', 'name', name2, 'rule', '1', 'jump-target', name])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'source', 'address', '!0.0.3.4'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'source', 'address-mask', '0.0.255.255'])
- self.cli_set(['firewall', 'interface', interface, 'in', 'name', name])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '3', 'action', 'drop'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '3', 'source', 'group', 'address-group', 'mask_group'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '3', 'source', 'address-mask', '0.0.255.255'])
self.cli_commit()
nftables_search = [
- [f'iifname "{interface}"', f'jump NAME_{name}'],
- ['ip length { 64, 512, 1024 }', 'ip dscp { 0x11, 0x34 }', 'return'],
- ['ip length 1-30000', 'ip length != 60000-65535', 'ip dscp 0x03-0x0b', 'ip dscp != 0x15-0x19', 'return'],
- [f'log prefix "[{name}-default-D]"', 'drop'],
- ['ip saddr 198.51.100.1', f'jump NAME_{name}'],
- [f'log prefix "[{name2}-default-J]"', f'jump NAME_{name}']
+ [f'daddr & 0.0.255.255 == 0.0.1.2'],
+ [f'saddr & 0.0.255.255 != 0.0.3.4'],
+ [f'saddr & 0.0.255.255 == @A_mask_group']
]
self.verify_nftables(nftables_search, 'ip vyos_filter')
+
def test_ipv6_basic_rules(self):
name = 'v6-smoketest'
interface = 'eth0'
- self.cli_set(['firewall', 'ipv6-name', name, 'default-action', 'drop'])
- self.cli_set(['firewall', 'ipv6-name', name, 'enable-default-log'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'default-action', 'drop'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'enable-default-log'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '1', 'action', 'accept'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '1', 'source', 'address', '2002::1'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '1', 'destination', 'address', '2002::1:1'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '1', 'log', 'enable'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '1', 'log-level', 'crit'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '1', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '1', 'source', 'address', '2002::1'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '1', 'destination', 'address', '2002::1:1'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '1', 'log', 'enable'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '1', 'log-options', 'level', 'crit'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '2', 'action', 'reject'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '2', 'protocol', 'tcp_udp'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '2', 'destination', 'port', '8888'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '2', 'inbound-interface', interface])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'default-action', 'accept'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '2', 'action', 'reject'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '2', 'protocol', 'tcp_udp'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '2', 'destination', 'port', '8888'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '2', 'inbound-interface', 'interface-name', interface])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '3', 'action', 'return'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '3', 'protocol', 'gre'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '3', 'outbound-interface', interface])
+ self.cli_set(['firewall', 'ipv6', 'output', 'filter', 'default-action', 'drop'])
+ self.cli_set(['firewall', 'ipv6', 'output', 'filter', 'rule', '3', 'action', 'return'])
+ self.cli_set(['firewall', 'ipv6', 'output', 'filter', 'rule', '3', 'protocol', 'gre'])
+ self.cli_set(['firewall', 'ipv6', 'output', 'filter', 'rule', '3', 'outbound-interface', 'interface-name', interface])
- self.cli_set(['firewall', 'interface', interface, 'in', 'ipv6-name', name])
+ self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '3', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '3', 'protocol', 'udp'])
+ self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '3', 'source', 'address', '2002::1:2'])
+ self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '3', 'inbound-interface', 'interface-name', interface])
self.cli_commit()
nftables_search = [
- [f'iifname "{interface}"', f'jump NAME6_{name}'],
- ['saddr 2002::1', 'daddr 2002::1:1', 'log prefix "[v6-smoketest-1-A]" level crit', 'return'],
+ ['chain VYOS_IPV6_FORWARD_filter'],
+ ['type filter hook forward priority filter; policy accept;'],
['meta l4proto { tcp, udp }', 'th dport 8888', f'iifname "{interface}"', 'reject'],
+ ['chain VYOS_IPV6_INPUT_filter'],
+ ['type filter hook input priority filter; policy accept;'],
+ ['meta l4proto udp', 'ip6 saddr 2002::1:2', f'iifname "{interface}"', 'accept'],
+ ['chain VYOS_IPV6_OUTPUT_filter'],
+ ['type filter hook output priority filter; policy drop;'],
['meta l4proto gre', f'oifname "{interface}"', 'return'],
- ['smoketest default-action', f'log prefix "[{name}-default-D]"', 'drop']
+ [f'chain NAME6_{name}'],
+ ['saddr 2002::1', 'daddr 2002::1:1', 'log prefix "[ipv6-NAM-v6-smoketest-1-A]" log level crit', 'accept'],
+ [f'"{name} default-action drop"', f'log prefix "[{name}-default-D]"', 'drop']
]
self.verify_nftables(nftables_search, 'ip6 vyos_filter')
@@ -315,95 +423,169 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
name2 = 'v6-smoketest-adv2'
interface = 'eth0'
- self.cli_set(['firewall', 'ipv6-name', name, 'default-action', 'drop'])
- self.cli_set(['firewall', 'ipv6-name', name, 'enable-default-log'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'default-action', 'drop'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'enable-default-log'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '3', 'action', 'accept'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '3', 'packet-length', '65'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '3', 'packet-length', '513'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '3', 'packet-length', '1025'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '3', 'dscp', '18'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '3', 'dscp', '53'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '3', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '3', 'packet-length', '65'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '3', 'packet-length', '513'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '3', 'packet-length', '1025'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '3', 'dscp', '18'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '3', 'dscp', '53'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '4', 'action', 'accept'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '4', 'packet-length', '1-1999'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '4', 'packet-length-exclude', '60000-65535'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '4', 'dscp', '4-14'])
- self.cli_set(['firewall', 'ipv6-name', name, 'rule', '4', 'dscp-exclude', '31-35'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '4', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '4', 'packet-length', '1-1999'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '4', 'packet-length-exclude', '60000-65535'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '4', 'dscp', '4-14'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '4', 'dscp-exclude', '31-35'])
- self.cli_set(['firewall', 'ipv6-name', name2, 'default-action', 'jump'])
- self.cli_set(['firewall', 'ipv6-name', name2, 'default-jump-target', name])
- self.cli_set(['firewall', 'ipv6-name', name2, 'enable-default-log'])
- self.cli_set(['firewall', 'ipv6-name', name2, 'rule', '1', 'source', 'address', '2001:db8::/64'])
- self.cli_set(['firewall', 'ipv6-name', name2, 'rule', '1', 'action', 'jump'])
- self.cli_set(['firewall', 'ipv6-name', name2, 'rule', '1', 'jump-target', name])
-
- self.cli_set(['firewall', 'interface', interface, 'in', 'ipv6-name', name])
+ self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'default-action', 'accept'])
+ self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '1', 'source', 'address', '2001:db8::/64'])
+ self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '1', 'action', 'jump'])
+ self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '1', 'jump-target', name])
self.cli_commit()
nftables_search = [
- [f'iifname "{interface}"', f'jump NAME6_{name}'],
- ['ip6 length { 65, 513, 1025 }', 'ip6 dscp { af21, 0x35 }', 'return'],
- ['ip6 length 1-1999', 'ip6 length != 60000-65535', 'ip6 dscp 0x04-0x0e', 'ip6 dscp != 0x1f-0x23', 'return'],
- [f'log prefix "[{name}-default-D]"', 'drop'],
+ ['chain VYOS_IPV6_FORWARD_filter'],
+ ['type filter hook forward priority filter; policy accept;'],
+ ['ip6 length 1-1999', 'ip6 length != 60000-65535', 'ip6 dscp 0x04-0x0e', 'ip6 dscp != 0x1f-0x23', 'accept'],
+ ['chain VYOS_IPV6_INPUT_filter'],
+ ['type filter hook input priority filter; policy accept;'],
['ip6 saddr 2001:db8::/64', f'jump NAME6_{name}'],
- [f'log prefix "[{name2}-default-J]"', f'jump NAME6_{name}']
+ [f'chain NAME6_{name}'],
+ ['ip6 length { 65, 513, 1025 }', 'ip6 dscp { af21, 0x35 }', 'accept'],
+ [f'log prefix "[{name}-default-D]"', 'drop']
]
self.verify_nftables(nftables_search, 'ip6 vyos_filter')
- def test_state_policy(self):
- self.cli_set(['firewall', 'state-policy', 'established', 'action', 'accept'])
- self.cli_set(['firewall', 'state-policy', 'related', 'action', 'accept'])
- self.cli_set(['firewall', 'state-policy', 'invalid', 'action', 'drop'])
+ def test_ipv6_mask(self):
+ name = 'v6-smoketest-mask'
+ interface = 'eth0'
+
+ self.cli_set(['firewall', 'group', 'ipv6-address-group', 'mask_group', 'address', '::beef'])
+
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'default-action', 'drop'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'enable-default-log'])
+
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '1', 'action', 'drop'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '1', 'destination', 'address', '::1111:2222:3333:4444'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '1', 'destination', 'address-mask', '::ffff:ffff:ffff:ffff'])
+
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '2', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '2', 'source', 'address', '!::aaaa:bbbb:cccc:dddd'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '2', 'source', 'address-mask', '::ffff:ffff:ffff:ffff'])
+
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '3', 'action', 'drop'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '3', 'source', 'group', 'address-group', 'mask_group'])
+ self.cli_set(['firewall', 'ipv6', 'name', name, 'rule', '3', 'source', 'address-mask', '::ffff:ffff:ffff:ffff'])
self.cli_commit()
- chains = {
- 'ip vyos_filter': ['VYOS_FW_FORWARD', 'VYOS_FW_OUTPUT', 'VYOS_FW_LOCAL'],
- 'ip6 vyos_filter': ['VYOS_FW6_FORWARD', 'VYOS_FW6_OUTPUT', 'VYOS_FW6_LOCAL']
- }
+ nftables_search = [
+ ['daddr & ::ffff:ffff:ffff:ffff == ::1111:2222:3333:4444'],
+ ['saddr & ::ffff:ffff:ffff:ffff != ::aaaa:bbbb:cccc:dddd'],
+ ['saddr & ::ffff:ffff:ffff:ffff == @A6_mask_group']
+ ]
- for table in ['ip vyos_filter', 'ip6 vyos_filter']:
- for chain in chains[table]:
- nftables_output = cmd(f'sudo nft list chain {table} {chain}')
- self.assertTrue('jump VYOS_STATE_POLICY' in nftables_output)
+ self.verify_nftables(nftables_search, 'ip6 vyos_filter')
def test_ipv4_state_and_status_rules(self):
name = 'smoketest-state'
interface = 'eth0'
- self.cli_set(['firewall', 'name', name, 'default-action', 'drop'])
- self.cli_set(['firewall', 'name', name, 'rule', '1', 'action', 'accept'])
- self.cli_set(['firewall', 'name', name, 'rule', '1', 'state', 'established', 'enable'])
- self.cli_set(['firewall', 'name', name, 'rule', '1', 'state', 'related', 'enable'])
- self.cli_set(['firewall', 'name', name, 'rule', '2', 'action', 'reject'])
- self.cli_set(['firewall', 'name', name, 'rule', '2', 'state', 'invalid', 'enable'])
- self.cli_set(['firewall', 'name', name, 'rule', '3', 'action', 'accept'])
- self.cli_set(['firewall', 'name', name, 'rule', '3', 'state', 'new', 'enable'])
-
- self.cli_set(['firewall', 'name', name, 'rule', '3', 'connection-status', 'nat', 'destination'])
- self.cli_set(['firewall', 'name', name, 'rule', '4', 'action', 'accept'])
- self.cli_set(['firewall', 'name', name, 'rule', '4', 'state', 'new', 'enable'])
- self.cli_set(['firewall', 'name', name, 'rule', '4', 'state', 'established', 'enable'])
- self.cli_set(['firewall', 'name', name, 'rule', '4', 'connection-status', 'nat', 'source'])
-
- self.cli_set(['firewall', 'interface', interface, 'in', 'name', name])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'default-action', 'drop'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'state', 'established', 'enable'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'state', 'related', 'enable'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'action', 'reject'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'state', 'invalid', 'enable'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '3', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '3', 'state', 'new', 'enable'])
+
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '3', 'connection-status', 'nat', 'destination'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '4', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '4', 'state', 'new', 'enable'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '4', 'state', 'established', 'enable'])
+ self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '4', 'connection-status', 'nat', 'source'])
self.cli_commit()
nftables_search = [
- [f'iifname "{interface}"', f'jump NAME_{name}'],
- ['ct state { established, related }', 'return'],
+ ['ct state { established, related }', 'accept'],
['ct state invalid', 'reject'],
- ['ct state new', 'ct status dnat', 'return'],
- ['ct state { established, new }', 'ct status snat', 'return'],
+ ['ct state new', 'ct status dnat', 'accept'],
+ ['ct state { established, new }', 'ct status snat', 'accept'],
['drop', f'comment "{name} default-action drop"']
]
self.verify_nftables(nftables_search, 'ip vyos_filter')
+ # Check conntrack
+ self.verify_nftables_chain([['accept']], 'raw', 'FW_CONNTRACK')
+ self.verify_nftables_chain([['return']], 'ip6 raw', 'FW_CONNTRACK')
+
+ def test_bridge_basic_rules(self):
+ name = 'smoketest'
+ interface_in = 'eth0'
+ mac_address = '00:53:00:00:00:01'
+ vlan_id = '12'
+ vlan_prior = '3'
+
+ self.cli_set(['firewall', 'bridge', 'name', name, 'default-action', 'accept'])
+ self.cli_set(['firewall', 'bridge', 'name', name, 'enable-default-log'])
+ self.cli_set(['firewall', 'bridge', 'name', name, 'rule', '1', 'action', 'accept'])
+ self.cli_set(['firewall', 'bridge', 'name', name, 'rule', '1', 'source', 'mac-address', mac_address])
+ self.cli_set(['firewall', 'bridge', 'name', name, 'rule', '1', 'inbound-interface', 'interface-name', interface_in])
+ self.cli_set(['firewall', 'bridge', 'name', name, 'rule', '1', 'log', 'enable'])
+ self.cli_set(['firewall', 'bridge', 'name', name, 'rule', '1', 'log-options', 'level', 'crit'])
+
+ self.cli_set(['firewall', 'bridge', 'forward', 'filter', 'default-action', 'drop'])
+ self.cli_set(['firewall', 'bridge', 'forward', 'filter', 'rule', '1', 'action', 'accept'])
+ self.cli_set(['firewall', 'bridge', 'forward', 'filter', 'rule', '1', 'vlan', 'id', vlan_id])
+ self.cli_set(['firewall', 'bridge', 'forward', 'filter', 'rule', '2', 'action', 'jump'])
+ self.cli_set(['firewall', 'bridge', 'forward', 'filter', 'rule', '2', 'jump-target', name])
+ self.cli_set(['firewall', 'bridge', 'forward', 'filter', 'rule', '2', 'vlan', 'priority', vlan_prior])
+
+ self.cli_commit()
+
+ nftables_search = [
+ ['chain VYOS_FORWARD_filter'],
+ ['type filter hook forward priority filter; policy drop;'],
+ [f'vlan id {vlan_id}', 'accept'],
+ [f'vlan pcp {vlan_prior}', f'jump NAME_{name}'],
+ [f'chain NAME_{name}'],
+ [f'ether saddr {mac_address}', f'iifname "{interface_in}"', f'log prefix "[bri-NAM-{name}-1-A]" log level crit', 'accept']
+ ]
+
+ self.verify_nftables(nftables_search, 'bridge vyos_filter')
+
+ def test_source_validation(self):
+ # Strict
+ self.cli_set(['firewall', 'global-options', 'source-validation', 'strict'])
+ self.cli_set(['firewall', 'global-options', 'ipv6-source-validation', 'strict'])
+ self.cli_commit()
+
+ nftables_strict_search = [
+ ['fib saddr . iif oif 0', 'drop']
+ ]
+
+ self.verify_nftables_chain(nftables_strict_search, 'ip raw', 'vyos_global_rpfilter')
+ self.verify_nftables_chain(nftables_strict_search, 'ip6 raw', 'vyos_global_rpfilter')
+
+ # Loose
+ self.cli_set(['firewall', 'global-options', 'source-validation', 'loose'])
+ self.cli_set(['firewall', 'global-options', 'ipv6-source-validation', 'loose'])
+ self.cli_commit()
+
+ nftables_loose_search = [
+ ['fib saddr oif 0', 'drop']
+ ]
+
+ self.verify_nftables_chain(nftables_loose_search, 'ip raw', 'vyos_global_rpfilter')
+ self.verify_nftables_chain(nftables_loose_search, 'ip6 raw', 'vyos_global_rpfilter')
+
def test_sysfs(self):
for name, conf in sysfs_config.items():
paths = glob(conf['sysfs'])
@@ -411,7 +593,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
with open(path, 'r') as f:
self.assertEqual(f.read().strip(), conf['default'], msg=path)
- self.cli_set(['firewall', name.replace("_", "-"), conf['test_value']])
+ self.cli_set(['firewall', 'global-options', name.replace("_", "-"), conf['test_value']])
self.cli_commit()
@@ -421,35 +603,17 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
with open(path, 'r') as f:
self.assertNotEqual(f.read().strip(), conf['default'], msg=path)
- def test_zone_basic(self):
- self.cli_set(['firewall', 'name', 'smoketest', '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-local', 'local-zone'])
- self.cli_set(['firewall', 'zone', 'smoketest-local', 'from', 'smoketest-eth0', 'firewall', 'name', 'smoketest'])
-
+ def test_flow_offload_software(self):
+ self.cli_set(['firewall', 'global-options', 'flow-offload', 'software', 'interface', 'eth0'])
self.cli_commit()
-
nftables_search = [
- ['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 NAME_smoketest'],
- ['oifname "eth0"', 'jump NAME_smoketest']
+ ['flowtable VYOS_FLOWTABLE_software'],
+ ['hook ingress priority filter - 1'],
+ ['devices = { eth0 }'],
+ ['flow add @VYOS_FLOWTABLE_software'],
]
+ self.verify_nftables(nftables_search, 'inet vyos_offload')
- 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)
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_ha_virtual_server.py b/smoketest/scripts/cli/test_ha_virtual_server.py
index e3a91283e..51ccfa4df 100755
--- a/smoketest/scripts/cli/test_ha_virtual_server.py
+++ b/smoketest/scripts/cli/test_ha_virtual_server.py
@@ -20,9 +20,9 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig.vrrp import VRRP
-from vyos.util import cmd
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import cmd
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
from vyos.template import inc_ip
PROCESS_NAME = 'keepalived'
@@ -47,6 +47,7 @@ class TestHAVirtualServer(VyOSUnitTestSHIM.TestCase):
delay = '10'
method = 'nat'
persistence_timeout = '600'
+ vs = 'serv-one'
vip = '203.0.113.111'
vport = '2222'
rservers = ['192.0.2.21', '192.0.2.22', '192.0.2.23']
@@ -56,21 +57,23 @@ class TestHAVirtualServer(VyOSUnitTestSHIM.TestCase):
vserver_base = base_path + ['virtual-server']
- self.cli_set(vserver_base + [vip, 'algorithm', algo])
- self.cli_set(vserver_base + [vip, 'delay-loop', delay])
- self.cli_set(vserver_base + [vip, 'forward-method', method])
- self.cli_set(vserver_base + [vip, 'persistence-timeout', persistence_timeout])
- self.cli_set(vserver_base + [vip, 'port', vport])
- self.cli_set(vserver_base + [vip, 'protocol', proto])
+ self.cli_set(vserver_base + [vs, 'address', vip])
+ self.cli_set(vserver_base + [vs, 'algorithm', algo])
+ self.cli_set(vserver_base + [vs, 'delay-loop', delay])
+ self.cli_set(vserver_base + [vs, 'forward-method', method])
+ self.cli_set(vserver_base + [vs, 'persistence-timeout', persistence_timeout])
+ self.cli_set(vserver_base + [vs, 'port', vport])
+ self.cli_set(vserver_base + [vs, 'protocol', proto])
for rs in rservers:
- self.cli_set(vserver_base + [vip, 'real-server', rs, 'connection-timeout', connection_timeout])
- self.cli_set(vserver_base + [vip, 'real-server', rs, 'port', rport])
+ self.cli_set(vserver_base + [vs, 'real-server', rs, 'connection-timeout', connection_timeout])
+ self.cli_set(vserver_base + [vs, 'real-server', rs, 'port', rport])
# commit changes
self.cli_commit()
config = read_file(KEEPALIVED_CONF)
+ self.assertIn(f'virtual_server {vip} {vport}', config)
self.assertIn(f'delay_loop {delay}', config)
self.assertIn(f'lb_algo lc', config)
self.assertIn(f'lb_kind {method.upper()}', config)
@@ -86,6 +89,7 @@ class TestHAVirtualServer(VyOSUnitTestSHIM.TestCase):
delay = '15'
method = 'nat'
persistence_timeout = '300'
+ vs = 'serv-two'
vip = '203.0.113.222'
vport = '22322'
rservers = ['192.0.2.11', '192.0.2.12']
@@ -107,15 +111,16 @@ class TestHAVirtualServer(VyOSUnitTestSHIM.TestCase):
self.cli_set(vrrp_base + [group, 'vrid', vrid])
# Virtual-server config
- self.cli_set(vserver_base + [vip, 'algorithm', algo])
- self.cli_set(vserver_base + [vip, 'delay-loop', delay])
- self.cli_set(vserver_base + [vip, 'forward-method', method])
- self.cli_set(vserver_base + [vip, 'persistence-timeout', persistence_timeout])
- self.cli_set(vserver_base + [vip, 'port', vport])
- self.cli_set(vserver_base + [vip, 'protocol', proto])
+ self.cli_set(vserver_base + [vs, 'address', vip])
+ self.cli_set(vserver_base + [vs, 'algorithm', algo])
+ self.cli_set(vserver_base + [vs, 'delay-loop', delay])
+ self.cli_set(vserver_base + [vs, 'forward-method', method])
+ self.cli_set(vserver_base + [vs, 'persistence-timeout', persistence_timeout])
+ self.cli_set(vserver_base + [vs, 'port', vport])
+ self.cli_set(vserver_base + [vs, 'protocol', proto])
for rs in rservers:
- self.cli_set(vserver_base + [vip, 'real-server', rs, 'connection-timeout', connection_timeout])
- self.cli_set(vserver_base + [vip, 'real-server', rs, 'port', rport])
+ self.cli_set(vserver_base + [vs, 'real-server', rs, 'connection-timeout', connection_timeout])
+ self.cli_set(vserver_base + [vs, 'real-server', rs, 'port', rport])
# commit changes
self.cli_commit()
@@ -131,6 +136,7 @@ class TestHAVirtualServer(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'preempt_delay 0', config) # default value
# Keepalived virtual-server
+ self.assertIn(f'virtual_server {vip} {vport}', config)
self.assertIn(f'delay_loop {delay}', config)
self.assertIn(f'lb_algo lc', config)
self.assertIn(f'lb_kind {method.upper()}', config)
diff --git a/smoketest/scripts/cli/test_ha_vrrp.py b/smoketest/scripts/cli/test_ha_vrrp.py
index 68905e447..98259d830 100755
--- a/smoketest/scripts/cli/test_ha_vrrp.py
+++ b/smoketest/scripts/cli/test_ha_vrrp.py
@@ -20,9 +20,9 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig.vrrp import VRRP
-from vyos.util import cmd
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import cmd
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
from vyos.template import inc_ip
PROCESS_NAME = 'keepalived'
@@ -87,11 +87,22 @@ class TestVRRP(VyOSUnitTestSHIM.TestCase):
advertise_interval = '77'
priority = '123'
preempt_delay = '400'
+ startup_delay = '120'
+ garp_master_delay = '2'
+ garp_master_repeat = '3'
+ garp_master_refresh = '4'
+ garp_master_refresh_repeat = '5'
+ garp_interval = '1.5'
+ group_garp_master_delay = '12'
+ group_garp_master_repeat = '13'
+ group_garp_master_refresh = '14'
+ vrrp_version = '3'
for group in groups:
vlan_id = group.lstrip('VLAN')
vip = f'100.64.{vlan_id}.1/24'
group_base = base_path + ['vrrp', 'group', group]
+ global_param_base = base_path + ['vrrp', 'global-parameters']
self.cli_set(['interfaces', 'ethernet', vrrp_interface, 'vif', vlan_id, 'address', inc_ip(vip, 1) + '/' + vip.split('/')[-1]])
@@ -110,9 +121,34 @@ class TestVRRP(VyOSUnitTestSHIM.TestCase):
self.cli_set(group_base + ['authentication', 'type', 'plaintext-password'])
self.cli_set(group_base + ['authentication', 'password', f'{group}'])
+ # GARP
+ self.cli_set(group_base + ['garp', 'master-delay', group_garp_master_delay])
+ self.cli_set(group_base + ['garp', 'master-repeat', group_garp_master_repeat])
+ self.cli_set(group_base + ['garp', 'master-refresh', group_garp_master_refresh])
+
+ # Global parameters
+ #config = getConfig(f'global_defs')
+ self.cli_set(global_param_base + ['startup-delay', f'{startup_delay}'])
+ self.cli_set(global_param_base + ['garp', 'interval', f'{garp_interval}'])
+ self.cli_set(global_param_base + ['garp', 'master-delay', f'{garp_master_delay}'])
+ self.cli_set(global_param_base + ['garp', 'master-repeat', f'{garp_master_repeat}'])
+ self.cli_set(global_param_base + ['garp', 'master-refresh', f'{garp_master_refresh}'])
+ self.cli_set(global_param_base + ['garp', 'master-refresh-repeat', f'{garp_master_refresh_repeat}'])
+ self.cli_set(global_param_base + ['version', vrrp_version])
+
# commit changes
self.cli_commit()
+ # Check Global parameters
+ config = getConfig(f'global_defs')
+ self.assertIn(f'vrrp_startup_delay {startup_delay}', config)
+ self.assertIn(f'vrrp_garp_interval {garp_interval}', config)
+ self.assertIn(f'vrrp_garp_master_delay {garp_master_delay}', config)
+ self.assertIn(f'vrrp_garp_master_repeat {garp_master_repeat}', config)
+ self.assertIn(f'vrrp_garp_master_refresh {garp_master_refresh}', config)
+ self.assertIn(f'vrrp_garp_master_refresh_repeat {garp_master_refresh_repeat}', config)
+ self.assertIn(f'vrrp_version {vrrp_version}', config)
+
for group in groups:
vlan_id = group.lstrip('VLAN')
vip = f'100.64.{vlan_id}.1/24'
@@ -132,6 +168,11 @@ class TestVRRP(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'auth_pass "{group}"', config)
self.assertIn(f'auth_type PASS', config)
+ #GARP
+ self.assertIn(f'garp_master_delay {group_garp_master_delay}', config)
+ self.assertIn(f'garp_master_refresh {group_garp_master_refresh}', config)
+ self.assertIn(f'garp_master_repeat {group_garp_master_repeat}', config)
+
def test_03_sync_group(self):
sync_group = 'VyOS'
diff --git a/smoketest/scripts/cli/test_interfaces_bonding.py b/smoketest/scripts/cli/test_interfaces_bonding.py
index cd3995ed9..8867cb427 100755
--- a/smoketest/scripts/cli/test_interfaces_bonding.py
+++ b/smoketest/scripts/cli/test_interfaces_bonding.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2022 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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
@@ -22,20 +22,12 @@ from base_interfaces_test import BasicInterfaceTest
from vyos.ifconfig import Section
from vyos.ifconfig.interface import Interface
from vyos.configsession import ConfigSessionError
-from vyos.util import get_interface_config
-from vyos.util import read_file
+from vyos.utils.network import get_interface_config
+from vyos.utils.file import read_file
class BondingInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
- cls._test_dhcp = True
- cls._test_ip = True
- cls._test_ipv6 = True
- cls._test_ipv6_pd = True
- cls._test_ipv6_dhcpc6 = True
- cls._test_mtu = True
- cls._test_vlan = True
- cls._test_qinq = True
cls._base_path = ['interfaces', 'bonding']
cls._mirror_interfaces = ['dum21354']
cls._members = []
@@ -45,9 +37,8 @@ class BondingInterfaceTest(BasicInterfaceTest.TestCase):
if 'TEST_ETH' in os.environ:
cls._members = os.environ['TEST_ETH'].split()
else:
- for tmp in Section.interfaces('ethernet'):
- if not '.' in tmp:
- cls._members.append(tmp)
+ for tmp in Section.interfaces('ethernet', vlan=False):
+ cls._members.append(tmp)
cls._options = {'bond0' : []}
for member in cls._members:
diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py
index 6d7af78eb..cdff49f4b 100755
--- a/smoketest/scripts/cli/test_interfaces_bridge.py
+++ b/smoketest/scripts/cli/test_interfaces_bridge.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2022 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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,20 +24,14 @@ from glob import glob
from netifaces import interfaces
from vyos.ifconfig import Section
-from vyos.util import cmd
-from vyos.util import read_file
-from vyos.util import get_interface_config
-from vyos.validate import is_intf_addr_assigned
+from vyos.utils.process import cmd
+from vyos.utils.file import read_file
+from vyos.utils.network import get_interface_config
+from vyos.utils.network import is_intf_addr_assigned
class BridgeInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
- cls._test_dhcp = True
- cls._test_ip = True
- cls._test_ipv6 = True
- cls._test_ipv6_pd = True
- cls._test_ipv6_dhcpc6 = True
- cls._test_vlan = True
cls._base_path = ['interfaces', 'bridge']
cls._mirror_interfaces = ['dum21354']
cls._members = []
@@ -47,9 +41,8 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase):
if 'TEST_ETH' in os.environ:
cls._members = os.environ['TEST_ETH'].split()
else:
- for tmp in Section.interfaces('ethernet'):
- if not '.' in tmp:
- cls._members.append(tmp)
+ for tmp in Section.interfaces('ethernet', vlan=False):
+ cls._members.append(tmp)
cls._options['br0'] = []
for member in cls._members:
diff --git a/smoketest/scripts/cli/test_interfaces_ethernet.py b/smoketest/scripts/cli/test_interfaces_ethernet.py
index ed611062a..a39b81348 100755
--- a/smoketest/scripts/cli/test_interfaces_ethernet.py
+++ b/smoketest/scripts/cli/test_interfaces_ethernet.py
@@ -28,10 +28,10 @@ from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.pki import CERT_BEGIN
from vyos.template import is_ipv6
-from vyos.util import cmd
-from vyos.util import process_named_running
-from vyos.util import read_file
-from vyos.validate import is_ipv6_link_local
+from vyos.utils.process import cmd
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
+from vyos.utils.network import is_ipv6_link_local
server_ca_root_cert_data = """
MIIBcTCCARagAwIBAgIUDcAf1oIQV+6WRaW7NPcSnECQ/lUwCgYIKoZIzj0EAwIw
@@ -109,14 +109,6 @@ def get_certificate_count(interface, cert_type):
class EthernetInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
- cls._test_dhcp = True
- cls._test_ip = True
- cls._test_ipv6 = True
- cls._test_ipv6_pd = True
- cls._test_ipv6_dhcpc6 = True
- cls._test_mtu = True
- cls._test_vlan = True
- cls._test_qinq = True
cls._base_path = ['interfaces', 'ethernet']
cls._mirror_interfaces = ['dum21354']
@@ -160,7 +152,7 @@ class EthernetInterfaceTest(BasicInterfaceTest.TestCase):
self.assertFalse(is_intf_addr_assigned(intf, addr['addr']))
def test_offloading_rps(self):
- # enable RPS on all available CPUs, RPS works woth a CPU bitmask,
+ # 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
@@ -258,10 +250,19 @@ class EthernetInterfaceTest(BasicInterfaceTest.TestCase):
for interface in self._interfaces:
# 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()
+
# Check for running process
self.assertTrue(process_named_running('wpa_supplicant'))
diff --git a/smoketest/scripts/cli/test_interfaces_geneve.py b/smoketest/scripts/cli/test_interfaces_geneve.py
index 0e5098aa7..5f8fae91e 100755
--- a/smoketest/scripts/cli/test_interfaces_geneve.py
+++ b/smoketest/scripts/cli/test_interfaces_geneve.py
@@ -17,15 +17,13 @@
import unittest
from vyos.ifconfig import Interface
-from vyos.util import get_interface_config
+from vyos.utils.network import get_interface_config
from base_interfaces_test import BasicInterfaceTest
class GeneveInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
- cls._test_ip = True
- cls._test_ipv6 = True
cls._base_path = ['interfaces', 'geneve']
cls._options = {
'gnv0': ['vni 10', 'remote 127.0.1.1'],
@@ -45,6 +43,7 @@ class GeneveInterfaceTest(BasicInterfaceTest.TestCase):
self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'df', 'set'])
self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'tos', tos])
+ self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'innerproto'])
self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'ttl', str(ttl)])
ttl += 10
@@ -69,6 +68,11 @@ class GeneveInterfaceTest(BasicInterfaceTest.TestCase):
label = options['linkinfo']['info_data']['label']
self.assertIn(f'parameters ipv6 flowlabel {label}', self._options[interface])
+ if any('innerproto' in s for s in self._options[interface]):
+ inner = options['linkinfo']['info_data']['innerproto']
+ self.assertIn(f'parameters ip {inner}', self._options[interface])
+
+
self.assertEqual('geneve', options['linkinfo']['info_kind'])
self.assertEqual('set', options['linkinfo']['info_data']['df'])
self.assertEqual(f'0x{tos}', options['linkinfo']['info_data']['tos'])
diff --git a/smoketest/scripts/cli/test_interfaces_input.py b/smoketest/scripts/cli/test_interfaces_input.py
new file mode 100755
index 000000000..3ddf86000
--- /dev/null
+++ b/smoketest/scripts/cli/test_interfaces_input.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from vyos.utils.file import read_file
+from vyos.ifconfig import Interface
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+base_path = ['interfaces', 'input']
+
+# add a classmethod to setup a temporaray PPPoE server for "proper" validation
+class InputInterfaceTest(VyOSUnitTestSHIM.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ super(InputInterfaceTest, cls).setUpClass()
+ cls._interfaces = ['ifb10', 'ifb20', 'ifb30']
+
+ def tearDown(self):
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ def test_01_description(self):
+ # Check if PPPoE dialer can be configured and runs
+ for interface in self._interfaces:
+ self.cli_set(base_path + [interface, 'description', f'foo-{interface}'])
+
+ # commit changes
+ self.cli_commit()
+
+ # Validate remove interface description "empty"
+ for interface in self._interfaces:
+ tmp = read_file(f'/sys/class/net/{interface}/ifalias')
+ self.assertEqual(tmp, f'foo-{interface}')
+ self.assertEqual(Interface(interface).get_alias(), f'foo-{interface}')
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_l2tpv3.py b/smoketest/scripts/cli/test_interfaces_l2tpv3.py
index aed8e6f15..af3d49f75 100755
--- a/smoketest/scripts/cli/test_interfaces_l2tpv3.py
+++ b/smoketest/scripts/cli/test_interfaces_l2tpv3.py
@@ -19,13 +19,11 @@ import json
import unittest
from base_interfaces_test import BasicInterfaceTest
-from vyos.util import cmd
+from vyos.utils.process import cmd
class L2TPv3InterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
- cls._test_ip = True
- cls._test_ipv6 = True
cls._base_path = ['interfaces', 'l2tpv3']
cls._options = {
'l2tpeth10': ['source-address 127.0.0.1', 'remote 127.10.10.10',
diff --git a/smoketest/scripts/cli/test_interfaces_loopback.py b/smoketest/scripts/cli/test_interfaces_loopback.py
index 5ff9c250e..0454dc658 100755
--- a/smoketest/scripts/cli/test_interfaces_loopback.py
+++ b/smoketest/scripts/cli/test_interfaces_loopback.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2021 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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
@@ -19,7 +19,7 @@ import unittest
from base_interfaces_test import BasicInterfaceTest
from netifaces import interfaces
-from vyos.validate import is_intf_addr_assigned
+from vyos.utils.network import is_intf_addr_assigned
loopbacks = ['127.0.0.1', '::1']
@@ -31,6 +31,9 @@ class LoopbackInterfaceTest(BasicInterfaceTest.TestCase):
# call base-classes classmethod
super(LoopbackInterfaceTest, cls).setUpClass()
+ # we need to override tearDown() as loopback interfaces are ephemeral and
+ # will always be present on the system - the base class check will fail as
+ # the loopback interface will still exist.
def tearDown(self):
self.cli_delete(self._base_path)
self.cli_commit()
diff --git a/smoketest/scripts/cli/test_interfaces_macsec.py b/smoketest/scripts/cli/test_interfaces_macsec.py
index f141cc6d3..ea0f00071 100755
--- a/smoketest/scripts/cli/test_interfaces_macsec.py
+++ b/smoketest/scripts/cli/test_interfaces_macsec.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2022 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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,10 +23,10 @@ from netifaces import interfaces
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
-from vyos.util import cmd
-from vyos.util import read_file
-from vyos.util import get_interface_config
-from vyos.util import process_named_running
+from vyos.utils.process import cmd
+from vyos.utils.file import read_file
+from vyos.utils.network import get_interface_config
+from vyos.utils.process import process_named_running
PROCESS_NAME = 'wpa_supplicant'
@@ -42,9 +42,6 @@ def get_cipher(interface):
class MACsecInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
- cls._test_dhcp = True
- cls._test_ip = True
- cls._test_ipv6 = True
cls._base_path = ['interfaces', 'macsec']
cls._options = { 'macsec0': ['source-interface eth0', 'security cipher gcm-aes-128'] }
@@ -142,15 +139,9 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase):
# final commit and verify
self.cli_commit()
self.assertIn(interface, interfaces())
- self.assertIn(interface, interfaces())
- self.assertEqual(cipher, get_cipher(interface))
- # check that we use the new macsec_csindex option (T4537)
- tmp = get_config_value(src_interface, 'macsec_csindex')
- self.assertIn("0", tmp)
-
- # Check for running process
- self.assertTrue(process_named_running(PROCESS_NAME))
+ # Verify proper cipher suite (T4537)
+ self.assertEqual(cipher, get_cipher(interface))
def test_macsec_gcm_aes_256(self):
src_interface = 'eth0'
@@ -171,18 +162,12 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase):
# final commit and verify
self.cli_commit()
self.assertIn(interface, interfaces())
- self.assertEqual(cipher, get_cipher(interface))
- # check that we use the new macsec_csindex option (T4537)
- tmp = get_config_value(src_interface, 'macsec_csindex')
- self.assertIn("1", tmp)
-
- # Check for running process
- self.assertTrue(process_named_running(PROCESS_NAME))
+ # Verify proper cipher suite (T4537)
+ self.assertEqual(cipher, get_cipher(interface))
def test_macsec_source_interface(self):
# Ensure source-interface can bot be part of any other bond or bridge
-
base_bridge = ['interfaces', 'bridge', 'br200']
base_bond = ['interfaces', 'bonding', 'bond200']
@@ -208,9 +193,77 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase):
self.cli_commit()
self.assertIn(interface, interfaces())
- # Check for running process
- self.assertTrue(process_named_running(PROCESS_NAME))
+ def test_macsec_static_keys(self):
+ src_interface = 'eth0'
+ interface = 'macsec5'
+ cipher1 = 'gcm-aes-128'
+ cipher2 = 'gcm-aes-256'
+ tx_key_1 = '71a82a48eddfa12c08a19792ca20c4bb'
+ tx_key_2 = 'dd487b2958e855ea35a5d43a5ecb3dcfbe7889ffcb877770252feb13b734478d'
+ rx_key_1 = '0022d00f57e75241a230cdf7118dfcc5'
+ rx_key_2 = 'b7d6d7ad075e02323fdeb845217b884d3f93ff36b2cdaf6b07eeb189b877245f'
+ peer_mac = '00:11:22:33:44:55'
+ self.cli_set(self._base_path + [interface])
-if __name__ == '__main__':
- unittest.main(verbosity=2, failfast=True)
+ # Encrypt link
+ self.cli_set(self._base_path + [interface, 'security', 'encrypt'])
+ # check validate() - source interface is mandatory
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'source-interface', src_interface])
+
+ # check validate() - cipher is mandatory
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'security', 'cipher', cipher1])
+
+ # check validate() - only static or mka config is allowed
+ self.cli_set(self._base_path + [interface, 'security', 'static'])
+ self.cli_set(self._base_path + [interface, 'security', 'mka', 'cak', tx_key_1])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(self._base_path + [interface, 'security', 'mka'])
+
+ # check validate() - tx-key required
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ # check validate() - tx-key length must match cipher
+ self.cli_set(self._base_path + [interface, 'security', 'static', 'key', tx_key_2])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'security', 'static', 'key', tx_key_1])
+
+ # check validate() - at least one peer must be defined
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ # check validate() - enabled peer must have both rx-key and MAC defined
+ self.cli_set(self._base_path + [interface, 'security', 'static', 'peer', 'TESTPEER'])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'security', 'static', 'peer', 'TESTPEER', 'mac', peer_mac])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(self._base_path + [interface, 'security', 'static', 'peer', 'TESTPEER', 'mac'])
+ self.cli_set(self._base_path + [interface, 'security', 'static', 'peer', 'TESTPEER', 'key', rx_key_1])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'security', 'static', 'peer', 'TESTPEER', 'mac', peer_mac])
+
+ # check validate() - peer rx-key length must match cipher
+ self.cli_set(self._base_path + [interface, 'security', 'cipher', cipher2])
+ self.cli_set(self._base_path + [interface, 'security', 'static', 'key', tx_key_2])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(self._base_path + [interface, 'security', 'static', 'peer', 'TESTPEER', 'key', rx_key_2])
+
+ # final commit and verify
+ self.cli_commit()
+ self.assertIn(interface, interfaces())
+ self.assertEqual(cipher2, get_cipher(interface))
+ self.assertTrue(os.path.isdir(f'/sys/class/net/{interface}'))
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_openvpn.py b/smoketest/scripts/cli/test_interfaces_openvpn.py
index b2143d16e..d1ece84d6 100755
--- a/smoketest/scripts/cli/test_interfaces_openvpn.py
+++ b/smoketest/scripts/cli/test_interfaces_openvpn.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2022 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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,9 @@ from netifaces import interfaces
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import cmd
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
from vyos.template import address_from_cidr
from vyos.template import dec_ip
from vyos.template import inc_ip
@@ -337,10 +337,6 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
self.cli_delete(path + ['protocol'])
-
- # check validate() - must specify "tls dh-params" when "tls role" is "passive"
- with self.assertRaises(ConfigSessionError):
- self.cli_commit()
self.cli_set(path + ['tls', 'dh-params', 'ovpn_test'])
self.cli_commit()
@@ -368,6 +364,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):
self.cli_set(path + ['hash', auth_hash])
self.cli_set(path + ['mode', 'server'])
self.cli_set(path + ['local-port', port])
+ self.cli_set(path + ['server', 'mfa', 'totp'])
self.cli_set(path + ['server', 'subnet', subnet])
self.cli_set(path + ['server', 'topology', 'subnet'])
self.cli_set(path + ['keep-alive', 'failure-count', '5'])
@@ -388,6 +385,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):
for ii in num_range:
interface = f'vtun{ii}'
+ plugin = f'plugin "/usr/lib/openvpn/openvpn-otp.so" "otp_secrets=/config/auth/openvpn/{interface}-otp-secrets otp_slop=180 totp_t0=0 totp_step=30 totp_digits=6 password_is_cr=1"'
subnet = f'192.0.{ii}.0/24'
start_addr = inc_ip(subnet, '2')
@@ -411,6 +409,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'topology subnet', config)
self.assertIn(f'lport {port}', config)
self.assertIn(f'push "redirect-gateway def1"', config)
+ self.assertIn(f'{plugin}', config)
self.assertIn(f'keepalive 5 25', config)
# TLS options
diff --git a/smoketest/scripts/cli/test_interfaces_pppoe.py b/smoketest/scripts/cli/test_interfaces_pppoe.py
index 8927121a8..0ce5e2fe0 100755
--- a/smoketest/scripts/cli/test_interfaces_pppoe.py
+++ b/smoketest/scripts/cli/test_interfaces_pppoe.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2022 VyOS maintainers and contributors
+# Copyright (C) 2019-2023 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
@@ -14,7 +14,6 @@
# 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 unittest
from psutil import process_iter
@@ -57,11 +56,11 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):
def test_01_pppoe_client(self):
# Check if PPPoE dialer can be configured and runs
for interface in self._interfaces:
- user = 'VyOS-user-' + interface
- passwd = 'VyOS-passwd-' + interface
+ user = f'VyOS-user-{interface}'
+ passwd = f'VyOS-passwd-{interface}'
mtu = '1400'
- self.cli_set(base_path + [interface, 'authentication', 'user', user])
+ 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'])
@@ -76,23 +75,26 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):
# verify configuration file(s)
for interface in self._interfaces:
- user = 'VyOS-user-' + interface
- password = 'VyOS-passwd-' + interface
+ user = f'VyOS-user-{interface}'
+ passwd = f'VyOS-passwd-{interface}'
tmp = get_config_value(interface, 'mtu')[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, password)
+ self.assertEqual(tmp, passwd)
tmp = get_config_value(interface, 'ifname')[1]
self.assertEqual(tmp, interface)
def test_02_pppoe_client_disabled_interface(self):
# Check if PPPoE Client can be disabled
for interface in self._interfaces:
- self.cli_set(base_path + [interface, 'authentication', 'user', 'vyos'])
- self.cli_set(base_path + [interface, 'authentication', 'password', 'vyos'])
+ user = f'VyOS-user-{interface}'
+ passwd = f'VyOS-passwd-{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'])
@@ -117,7 +119,10 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):
def test_03_pppoe_authentication(self):
# When username or password is set - so must be the other
for interface in self._interfaces:
- self.cli_set(base_path + [interface, 'authentication', 'user', 'vyos'])
+ user = f'VyOS-user-{interface}'
+ passwd = f'VyOS-passwd-{interface}'
+
+ self.cli_set(base_path + [interface, 'authentication', 'username', user])
self.cli_set(base_path + [interface, 'source-interface', self._source_interface])
self.cli_set(base_path + [interface, 'ipv6', 'address', 'autoconf'])
@@ -125,7 +130,7 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):
with self.assertRaises(ConfigSessionError):
self.cli_commit()
- self.cli_set(base_path + [interface, 'authentication', 'password', 'vyos'])
+ self.cli_set(base_path + [interface, 'authentication', 'password', passwd])
self.cli_commit()
@@ -136,8 +141,11 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):
sla_len = '8'
for interface in self._interfaces:
- self.cli_set(base_path + [interface, 'authentication', 'user', 'vyos'])
- self.cli_set(base_path + [interface, 'authentication', 'password', 'vyos'])
+ user = f'VyOS-user-{interface}'
+ passwd = f'VyOS-passwd-{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, 'no-default-route'])
self.cli_set(base_path + [interface, 'no-peer-dns'])
self.cli_set(base_path + [interface, 'source-interface', self._source_interface])
@@ -149,18 +157,54 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):
self.cli_set(dhcpv6_pd_base + ['interface', self._source_interface, 'address', address])
self.cli_set(dhcpv6_pd_base + ['interface', self._source_interface, 'sla-id', sla_id])
- # commit changes
- self.cli_commit()
+ # commit changes
+ self.cli_commit()
+
+ for interface in self._interfaces:
+ user = f'VyOS-user-{interface}'
+ passwd = f'VyOS-passwd-{interface}'
# verify "normal" PPPoE value - 1492 is default MTU
tmp = get_config_value(interface, 'mtu')[1]
self.assertEqual(tmp, '1492')
tmp = get_config_value(interface, 'user')[1].replace('"', '')
- self.assertEqual(tmp, 'vyos')
+ self.assertEqual(tmp, user)
tmp = get_config_value(interface, 'password')[1].replace('"', '')
- self.assertEqual(tmp, 'vyos')
+ self.assertEqual(tmp, passwd)
tmp = get_config_value(interface, '+ipv6 ipv6cp-use-ipaddr')
self.assertListEqual(tmp, ['+ipv6', 'ipv6cp-use-ipaddr'])
+ def test_05_pppoe_options(self):
+ # Check if PPPoE dialer can be configured with DHCPv6-PD
+ for interface in self._interfaces:
+ user = f'VyOS-user-{interface}'
+ passwd = f'VyOS-passwd-{interface}'
+ ac_name = f'AC{interface}'
+ service_name = f'SRV{interface}'
+ host_uniq = 'cafebeefBABE123456'
+
+ 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()
+
+ for interface in self._interfaces:
+ ac_name = f'AC{interface}'
+ service_name = f'SRV{interface}'
+ host_uniq = 'cafebeefBABE123456'
+
+ 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}"')
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py b/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py
index a51b8d52c..0d6f5bc1f 100755
--- a/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py
+++ b/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py
@@ -23,14 +23,6 @@ from base_interfaces_test import BasicInterfaceTest
class PEthInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
- cls._test_dhcp = True
- cls._test_ip = True
- cls._test_ipv6 = True
- cls._test_ipv6_pd = True
- cls._test_ipv6_dhcpc6 = True
- cls._test_mtu = True
- cls._test_vlan = True
- cls._test_qinq = True
cls._base_path = ['interfaces', 'pseudo-ethernet']
cls._options = {}
diff --git a/smoketest/scripts/cli/test_interfaces_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py
index 44bfbb5f0..2a7a519fd 100755
--- a/smoketest/scripts/cli/test_interfaces_tunnel.py
+++ b/smoketest/scripts/cli/test_interfaces_tunnel.py
@@ -19,7 +19,7 @@ import unittest
from base_interfaces_test import BasicInterfaceTest
from vyos.configsession import ConfigSessionError
-from vyos.util import get_interface_config
+from vyos.utils.network import get_interface_config
from vyos.template import inc_ip
remote_ip4 = '192.0.2.100'
@@ -30,9 +30,6 @@ mtu = 1476
class TunnelInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
- cls._test_ip = True
- cls._test_ipv6 = True
- cls._test_mtu = True
cls._base_path = ['interfaces', 'tunnel']
cls.local_v4 = '192.0.2.1'
cls.local_v6 = '2001:db8::1'
diff --git a/smoketest/scripts/cli/test_interfaces_virtual_ethernet.py b/smoketest/scripts/cli/test_interfaces_virtual_ethernet.py
new file mode 100755
index 000000000..7874589ca
--- /dev/null
+++ b/smoketest/scripts/cli/test_interfaces_virtual_ethernet.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from netifaces import interfaces
+
+from vyos.ifconfig import Section
+from vyos.utils.process import process_named_running
+from base_interfaces_test import BasicInterfaceTest
+
+class VEthInterfaceTest(BasicInterfaceTest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls._base_path = ['interfaces', 'virtual-ethernet']
+ cls._options = {
+ 'veth0': ['peer-name veth1'],
+ 'veth1': ['peer-name veth0'],
+ }
+
+ cls._interfaces = list(cls._options)
+ # call base-classes classmethod
+ super(VEthInterfaceTest, cls).setUpClass()
+
+ def test_vif_8021q_mtu_limits(self):
+ self.skipTest('not supported')
+
+ # As we always need a pair of veth interfaces, we can not rely on the base
+ # class check to determine if there is a dhcp6c or dhclient instance running.
+ # This test will always fail as there is an instance running on the peer
+ # interface.
+ def tearDown(self):
+ self.cli_delete(self._base_path)
+ self.cli_commit()
+
+ # Verify that no previously interface remained on the system
+ for intf in self._interfaces:
+ self.assertNotIn(intf, interfaces())
+
+ @classmethod
+ def tearDownClass(cls):
+ # No daemon started during tests should remain running
+ for daemon in ['dhcp6c', 'dhclient']:
+ cls.assertFalse(cls, process_named_running(daemon))
+
+ super(VEthInterfaceTest, cls).tearDownClass()
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_vti.py b/smoketest/scripts/cli/test_interfaces_vti.py
index 9cbf104f0..7f13575a3 100755
--- a/smoketest/scripts/cli/test_interfaces_vti.py
+++ b/smoketest/scripts/cli/test_interfaces_vti.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2023 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
@@ -21,9 +21,6 @@ from base_interfaces_test import BasicInterfaceTest
class VTIInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
- cls._test_ip = True
- cls._test_ipv6 = True
- cls._test_mtu = True
cls._base_path = ['interfaces', 'vti']
cls._interfaces = ['vti10', 'vti20', 'vti30']
diff --git a/smoketest/scripts/cli/test_interfaces_vxlan.py b/smoketest/scripts/cli/test_interfaces_vxlan.py
index 058f13721..e9c9e68fd 100755
--- a/smoketest/scripts/cli/test_interfaces_vxlan.py
+++ b/smoketest/scripts/cli/test_interfaces_vxlan.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2022 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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
@@ -18,17 +18,16 @@ import unittest
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Interface
-from vyos.util import get_bridge_fdb
-from vyos.util import get_interface_config
+from vyos.utils.network import get_bridge_fdb
+from vyos.utils.network import get_interface_config
+from vyos.utils.network import interface_exists
+from vyos.utils.network import get_vxlan_vlan_tunnels
from vyos.template import is_ipv6
from base_interfaces_test import BasicInterfaceTest
class VXLANInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
- cls._test_ip = True
- cls._test_ipv6 = True
- cls._test_mtu = True
cls._base_path = ['interfaces', 'vxlan']
cls._options = {
'vxlan10': ['vni 10', 'remote 127.0.0.2'],
@@ -136,5 +135,53 @@ class VXLANInterfaceTest(BasicInterfaceTest.TestCase):
self.assertTrue(options['linkinfo']['info_data']['external'])
self.assertEqual('vxlan', options['linkinfo']['info_kind'])
+ def test_vxlan_vlan_vni_mapping(self):
+ bridge = 'br0'
+ interface = 'vxlan0'
+ source_interface = 'eth0'
+
+ vlan_to_vni = {
+ '10': '10010',
+ '11': '10011',
+ '12': '10012',
+ '13': '10013',
+ '20': '10020',
+ '30': '10030',
+ '31': '10031',
+ }
+
+ self.cli_set(self._base_path + [interface, 'external'])
+ self.cli_set(self._base_path + [interface, 'source-interface', source_interface])
+
+ for vlan, vni in vlan_to_vni.items():
+ self.cli_set(self._base_path + [interface, 'vlan-to-vni', vlan, 'vni', vni])
+
+ # This must fail as this VXLAN interface is not associated with any bridge
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(['interfaces', 'bridge', bridge, 'member', 'interface', interface])
+
+ # It is not allowed to use duplicate VNIs
+ self.cli_set(self._base_path + [interface, 'vlan-to-vni', '11', 'vni', vlan_to_vni['10']])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ # restore VLAN - VNI mappings
+ for vlan, vni in vlan_to_vni.items():
+ self.cli_set(self._base_path + [interface, 'vlan-to-vni', vlan, 'vni', vni])
+
+ # commit configuration
+ self.cli_commit()
+
+ self.assertTrue(interface_exists(bridge))
+ self.assertTrue(interface_exists(interface))
+
+ tmp = get_interface_config(interface)
+ self.assertEqual(tmp['master'], bridge)
+
+ tmp = get_vxlan_vlan_tunnels('vxlan0')
+ self.assertEqual(tmp, list(vlan_to_vni))
+
+ self.cli_delete(['interfaces', 'bridge', bridge])
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_wireguard.py b/smoketest/scripts/cli/test_interfaces_wireguard.py
index 14fc8d109..48c7cb6a1 100755
--- a/smoketest/scripts/cli/test_interfaces_wireguard.py
+++ b/smoketest/scripts/cli/test_interfaces_wireguard.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2021 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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
@@ -19,6 +19,7 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
+from vyos.utils.file import read_file
base_path = ['interfaces', 'wireguard']
@@ -35,7 +36,7 @@ class WireGuardInterfaceTest(VyOSUnitTestSHIM.TestCase):
self.cli_delete(base_path)
self.cli_commit()
- def test_wireguard_peer(self):
+ def test_01_wireguard_peer(self):
# Create WireGuard interfaces with associated peers
for intf in self._interfaces:
peer = 'foo-' + intf
@@ -62,7 +63,7 @@ class WireGuardInterfaceTest(VyOSUnitTestSHIM.TestCase):
self.assertTrue(os.path.isdir(f'/sys/class/net/{intf}'))
- def test_wireguard_add_remove_peer(self):
+ def test_02_wireguard_add_remove_peer(self):
# T2939: Create WireGuard interfaces with associated peers.
# Remove one of the configured peers.
# T4774: Test prevention of duplicate peer public keys
@@ -100,5 +101,56 @@ class WireGuardInterfaceTest(VyOSUnitTestSHIM.TestCase):
self.cli_delete(base_path + [interface, 'peer', 'PEER01'])
self.cli_commit()
+ def test_03_wireguard_same_public_key(self):
+ # T5413: Test prevention of equality interface public key and peer's
+ # public key
+ interface = 'wg0'
+ port = '12345'
+ privkey = 'OOjcXGfgQlAuM6q8Z9aAYduCua7pxf7UKYvIqoUPoGQ='
+ pubkey_fail = 'eiVeYKq66mqKLbrZLzlckSP9voaw8jSFyVNiNTdZDjU='
+ pubkey_ok = 'ebFx/1G0ti8tvuZd94sEIosAZZIznX+dBAKG/8DFm0I='
+
+ self.cli_set(base_path + [interface, 'address', '172.16.0.1/24'])
+ self.cli_set(base_path + [interface, 'private-key', privkey])
+
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'public-key', pubkey_fail])
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'port', port])
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'allowed-ips', '10.205.212.10/32'])
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'address', '192.0.2.1'])
+
+ # The same pubkey as the interface wg0
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'public-key', pubkey_ok])
+
+ # Commit peers
+ self.cli_commit()
+
+ self.assertTrue(os.path.isdir(f'/sys/class/net/{interface}'))
+
+ def test_04_wireguard_threaded(self):
+ # T5409: Test adding threaded option on interface.
+ # Test prevention for adding threaded
+ # if no enabled peer is configured.
+ interface = 'wg0'
+ port = '12345'
+ privkey = 'OOjcXGfgQlAuM6q8Z9aAYduCua7pxf7UKYvIqoUPoGQ='
+ pubkey = 'ebFx/1G0ti8tvuZd94sEIosAZZIznX+dBAKG/8DFm0I='
+
+ self.cli_set(base_path + [interface, 'address', '172.16.0.1/24'])
+ self.cli_set(base_path + [interface, 'private-key', privkey])
+
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'port', port])
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'public-key', pubkey])
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'allowed-ips', '10.205.212.10/32'])
+ self.cli_set(base_path + [interface, 'peer', 'PEER01', 'address', '192.0.2.1'])
+ self.cli_set(base_path + [interface, 'per-client-thread'])
+
+ # Commit peers
+ self.cli_commit()
+ tmp = read_file(f'/sys/class/net/{interface}/threaded')
+ self.assertTrue(tmp, "1")
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_wireless.py b/smoketest/scripts/cli/test_interfaces_wireless.py
index a24f37d8d..95246a7b9 100755
--- a/smoketest/scripts/cli/test_interfaces_wireless.py
+++ b/smoketest/scripts/cli/test_interfaces_wireless.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2021 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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
@@ -22,9 +22,9 @@ from base_interfaces_test import BasicInterfaceTest
from glob import glob
from vyos.configsession import ConfigSessionError
-from vyos.util import process_named_running
-from vyos.util import check_kmod
-from vyos.util import read_file
+from vyos.utils.process import process_named_running
+from vyos.utils.kernel import check_kmod
+from vyos.utils.file import read_file
def get_config_value(interface, key):
tmp = read_file(f'/run/hostapd/{interface}.conf')
@@ -34,7 +34,6 @@ def get_config_value(interface, key):
class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
def setUpClass(cls):
- cls._test_ip = True
cls._base_path = ['interfaces', 'wireless']
cls._options = {
'wlan0': ['physical-device phy0', 'ssid VyOS-WIFI-0',
@@ -50,6 +49,10 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
# call base-classes classmethod
super(WirelessInterfaceTest, cls).setUpClass()
+ # T5245 - currently testcases are disabled
+ cls._test_ipv6 = False
+ cls._test_vlan = False
+
def test_wireless_add_single_ip_address(self):
# derived method to check if member interfaces are enslaved properly
super().test_add_single_ip_address()
@@ -94,6 +97,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
vht_opt = {
# VyOS CLI option hostapd - ht_capab setting
+ 'channel-set-width 3' : '[VHT160-80PLUS80]',
'stbc tx' : '[TX-STBC-2BY1]',
'stbc rx 12' : '[RX-STBC-12]',
'ldpc' : '[RXLDPC]',
@@ -101,7 +105,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
'vht-cf' : '[HTC-VHT]',
'antenna-pattern-fixed' : '[RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN]',
'max-mpdu 11454' : '[MAX-MPDU-11454]',
- 'max-mpdu-exp 2' : '[MAX-A-MPDU-LEN-EXP-2][VHT160]',
+ 'max-mpdu-exp 2' : '[MAX-A-MPDU-LEN-EXP-2]',
'link-adaptation both' : '[VHT-LINK-ADAPT3]',
'short-gi 80' : '[SHORT-GI-80]',
'short-gi 160' : '[SHORT-GI-160]',
@@ -231,9 +235,51 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
self.assertIn(interface, bridge_members)
self.cli_delete(bridge_path)
- self.cli_delete(self._base_path)
+
+ def test_wireless_security_station_address(self):
+ interface = 'wlan0'
+ ssid = 'VyOS-ACL'
+
+ hostapd_accept_station_conf = f'/run/hostapd/{interface}_station_accept.conf'
+ hostapd_deny_station_conf = f'/run/hostapd/{interface}_station_deny.conf'
+
+ accept_mac = ['00:00:00:00:ac:01', '00:00:00:00:ac:02', '00:00:00:00:ac:03', '00:00:00:00:ac:04']
+ deny_mac = ['00:00:00:00:de:01', '00:00:00:00:de:02', '00:00:00:00:de:03', '00:00:00:00:de:04']
+
+ self.cli_set(self._base_path + [interface, 'ssid', ssid])
+ self.cli_set(self._base_path + [interface, 'country-code', 'se'])
+ self.cli_set(self._base_path + [interface, 'type', 'access-point'])
+ self.cli_set(self._base_path + [interface, 'security', 'station-address', 'mode', 'accept'])
+
+ for mac in accept_mac:
+ self.cli_set(self._base_path + [interface, 'security', 'station-address', 'accept', 'mac', mac])
+ for mac in deny_mac:
+ self.cli_set(self._base_path + [interface, 'security', 'station-address', 'deny', 'mac', mac])
+
self.cli_commit()
+ # in accept mode all addresses are allowed unless specified in the deny list
+ tmp = get_config_value(interface, 'macaddr_acl')
+ self.assertEqual(tmp, '0')
+
+ accept_list = read_file(hostapd_accept_station_conf)
+ for mac in accept_mac:
+ self.assertIn(mac, accept_list)
+
+ deny_list = read_file(hostapd_deny_station_conf)
+ for mac in deny_mac:
+ self.assertIn(mac, deny_list)
+
+ # Switch mode accept -> deny
+ self.cli_set(self._base_path + [interface, 'security', 'station-address', 'mode', 'deny'])
+ self.cli_commit()
+ # In deny mode all addresses are denied unless specified in the allow list
+ tmp = get_config_value(interface, 'macaddr_acl')
+ self.assertEqual(tmp, '1')
+
+ # Check for running process
+ self.assertTrue(process_named_running('hostapd'))
+
if __name__ == '__main__':
check_kmod('mac80211_hwsim')
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_load_balancing_reverse_proxy.py b/smoketest/scripts/cli/test_load_balancing_reverse_proxy.py
new file mode 100755
index 000000000..a33fd5c18
--- /dev/null
+++ b/smoketest/scripts/cli/test_load_balancing_reverse_proxy.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSessionError
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
+
+PROCESS_NAME = 'haproxy'
+HAPROXY_CONF = '/run/haproxy/haproxy.cfg'
+base_path = ['load-balancing', 'reverse-proxy']
+proxy_interface = 'eth1'
+
+
+class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase):
+ def tearDown(self):
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
+ self.cli_delete(['interfaces', 'ethernet', proxy_interface, 'address'])
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ # Process must be terminated after deleting the config
+ self.assertFalse(process_named_running(PROCESS_NAME))
+
+ def test_01_lb_reverse_proxy_domain(self):
+ domains_bk_first = ['n1.example.com', 'n2.example.com', 'n3.example.com']
+ domain_bk_second = 'n5.example.com'
+ frontend = 'https_front'
+ front_port = '4433'
+ bk_server_first = '192.0.2.11'
+ bk_server_second = '192.0.2.12'
+ bk_first_name = 'bk-01'
+ bk_second_name = 'bk-02'
+ bk_server_port = '9090'
+ mode = 'http'
+ rule_ten = '10'
+ rule_twenty = '20'
+ send_proxy = 'send-proxy'
+ max_connections = '1000'
+
+ back_base = base_path + ['backend']
+
+ self.cli_set(base_path + ['service', frontend, 'mode', mode])
+ self.cli_set(base_path + ['service', frontend, 'port', front_port])
+ for domain in domains_bk_first:
+ self.cli_set(base_path + ['service', frontend, 'rule', rule_ten, 'domain-name', domain])
+ self.cli_set(base_path + ['service', frontend, 'rule', rule_ten, 'set', 'backend', bk_first_name])
+ self.cli_set(base_path + ['service', frontend, 'rule', rule_twenty, 'domain-name', domain_bk_second])
+ self.cli_set(base_path + ['service', frontend, 'rule', rule_twenty, 'set', 'backend', bk_second_name])
+
+ self.cli_set(back_base + [bk_first_name, 'mode', mode])
+ self.cli_set(back_base + [bk_first_name, 'server', bk_first_name, 'address', bk_server_first])
+ self.cli_set(back_base + [bk_first_name, 'server', bk_first_name, 'port', bk_server_port])
+ self.cli_set(back_base + [bk_first_name, 'server', bk_first_name, send_proxy])
+
+ self.cli_set(back_base + [bk_second_name, 'mode', mode])
+ self.cli_set(back_base + [bk_second_name, 'server', bk_second_name, 'address', bk_server_second])
+ self.cli_set(back_base + [bk_second_name, 'server', bk_second_name, 'port', bk_server_port])
+
+ self.cli_set(base_path + ['global-parameters', 'max-connections', max_connections])
+
+ # commit changes
+ self.cli_commit()
+
+ config = read_file(HAPROXY_CONF)
+
+ # Global
+ self.assertIn(f'maxconn {max_connections}', config)
+
+ # Frontend
+ self.assertIn(f'frontend {frontend}', config)
+ self.assertIn(f'bind :::{front_port} v4v6', config)
+ self.assertIn(f'mode {mode}', config)
+ for domain in domains_bk_first:
+ self.assertIn(f'acl {rule_ten} hdr(host) -i {domain}', config)
+ self.assertIn(f'use_backend {bk_first_name} if {rule_ten}', config)
+ self.assertIn(f'acl {rule_twenty} hdr(host) -i {domain_bk_second}', config)
+ self.assertIn(f'use_backend {bk_second_name} if {rule_twenty}', config)
+
+ # Backend
+ self.assertIn(f'backend {bk_first_name}', config)
+ self.assertIn(f'balance roundrobin', config)
+ self.assertIn(f'option forwardfor', config)
+ self.assertIn('http-request add-header X-Forwarded-Proto https if { ssl_fc }', config)
+ self.assertIn(f'mode {mode}', config)
+ self.assertIn(f'server {bk_first_name} {bk_server_first}:{bk_server_port} send-proxy', config)
+
+ self.assertIn(f'backend {bk_second_name}', config)
+ self.assertIn(f'mode {mode}', config)
+ self.assertIn(f'server {bk_second_name} {bk_server_second}:{bk_server_port}', config)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_load_balancning_wan.py b/smoketest/scripts/cli/test_load_balancing_wan.py
index 23020b9b1..47ca19b27 100755
--- a/smoketest/scripts/cli/test_load_balancning_wan.py
+++ b/smoketest/scripts/cli/test_load_balancing_wan.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2023 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
@@ -21,8 +21,8 @@ import time
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
-from vyos.util import call
-from vyos.util import cmd
+from vyos.utils.process import call
+from vyos.utils.process import cmd
base_path = ['load-balancing']
@@ -46,7 +46,6 @@ def cmd_in_netns(netns, cmd):
def delete_netns(name):
return call(f'sudo ip netns del {name}')
-
class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
@@ -61,7 +60,6 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
def test_table_routes(self):
-
ns1 = 'ns201'
ns2 = 'ns202'
ns3 = 'ns203'
@@ -79,6 +77,7 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):
create_veth_pair(iface1, container_iface1)
create_veth_pair(iface2, container_iface2)
create_veth_pair(iface3, container_iface3)
+
move_interface_to_netns(container_iface1, ns1)
move_interface_to_netns(container_iface2, ns2)
move_interface_to_netns(container_iface3, ns3)
@@ -125,11 +124,12 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):
self.assertEqual(tmp, original)
# Delete veth interfaces and netns
- for iface in [iface1, iface2]:
+ for iface in [iface1, iface2, iface3]:
call(f'sudo ip link del dev {iface}')
delete_netns(ns1)
delete_netns(ns2)
+ delete_netns(ns3)
def test_check_chains(self):
@@ -144,15 +144,15 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):
container_iface3 = 'ceth2'
mangle_isp1 = """table ip mangle {
chain ISP_veth1 {
- counter ct mark set 0xc9
- counter meta mark set 0xc9
+ counter ct mark set 0xc9
+ counter meta mark set 0xc9
counter accept
}
}"""
mangle_isp2 = """table ip mangle {
chain ISP_veth2 {
- counter ct mark set 0xca
- counter meta mark set 0xca
+ counter ct mark set 0xca
+ counter meta mark set 0xca
counter accept
}
}"""
@@ -164,7 +164,7 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):
}"""
mangle_wanloadbalance_pre = """table ip mangle {
chain WANLOADBALANCE_PRE {
- iifname "veth3" ip saddr 198.51.100.0/24 ct state new counter jump ISP_veth1
+ iifname "veth3" ip saddr 198.51.100.0/24 ct state new meta random & 2147483647 < 1073741824 counter jump ISP_veth1
iifname "veth3" ip saddr 198.51.100.0/24 ct state new counter jump ISP_veth2
iifname "veth3" ip saddr 198.51.100.0/24 counter meta mark set ct mark
}
@@ -179,7 +179,6 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):
chain VYOS_PRE_SNAT_HOOK {
type nat hook postrouting priority srcnat - 1; policy accept;
counter jump WANLOADBALANCE
- return
}
}"""
@@ -196,9 +195,10 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):
call(f'sudo ip address add 203.0.113.10/24 dev {iface1}')
call(f'sudo ip address add 192.0.2.10/24 dev {iface2}')
call(f'sudo ip address add 198.51.100.10/24 dev {iface3}')
- call(f'sudo ip link set dev {iface1} up')
- call(f'sudo ip link set dev {iface2} up')
- call(f'sudo ip link set dev {iface3} up')
+
+ for iface in [iface1, iface2, iface3]:
+ call(f'sudo ip link set dev {iface} up')
+
cmd_in_netns(ns1, f'ip link set {container_iface1} name eth0')
cmd_in_netns(ns2, f'ip link set {container_iface2} name eth0')
cmd_in_netns(ns3, f'ip link set {container_iface3} name eth0')
@@ -247,11 +247,12 @@ class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase):
self.assertEqual(tmp, nat_vyos_pre_snat_hook)
# Delete veth interfaces and netns
- for iface in [iface1, iface2]:
+ for iface in [iface1, iface2, iface3]:
call(f'sudo ip link del dev {iface}')
delete_netns(ns1)
delete_netns(ns2)
+ delete_netns(ns3)
if __name__ == '__main__':
diff --git a/smoketest/scripts/cli/test_nat.py b/smoketest/scripts/cli/test_nat.py
index 2ae90fcaf..31dfcef87 100755
--- a/smoketest/scripts/cli/test_nat.py
+++ b/smoketest/scripts/cli/test_nat.py
@@ -21,8 +21,8 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
-from vyos.util import dict_search
+from vyos.utils.process import cmd
+from vyos.utils.dict import dict_search
base_path = ['nat']
src_path = base_path + ['source']
@@ -58,6 +58,17 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):
break
self.assertTrue(not matched if inverse else matched, msg=search)
+ def wait_for_domain_resolver(self, table, set_name, element, max_wait=10):
+ # Resolver no longer blocks commit, need to wait for daemon to populate set
+ count = 0
+ while count < max_wait:
+ code = run(f'sudo nft get element {table} {set_name} {{ {element} }}')
+ if code == 0:
+ return True
+ count += 1
+ sleep(1)
+ return False
+
def test_snat(self):
rules = ['100', '110', '120', '130', '200', '210', '220', '230']
outbound_iface_100 = 'eth0'
@@ -84,6 +95,30 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):
self.verify_nftables(nftables_search, 'ip vyos_nat')
+ def test_snat_groups(self):
+ address_group = 'smoketest_addr'
+ address_group_member = '192.0.2.1'
+ rule = '100'
+ outbound_iface = 'eth0'
+
+ self.cli_set(['firewall', 'group', 'address-group', address_group, 'address', address_group_member])
+
+ self.cli_set(src_path + ['rule', rule, 'source', 'group', 'address-group', address_group])
+ self.cli_set(src_path + ['rule', rule, 'outbound-interface', outbound_iface])
+ self.cli_set(src_path + ['rule', rule, 'translation', 'address', 'masquerade'])
+
+ self.cli_commit()
+
+ nftables_search = [
+ [f'set A_{address_group}'],
+ [f'elements = {{ {address_group_member} }}'],
+ [f'ip saddr @A_{address_group}', f'oifname "{outbound_iface}"', 'masquerade']
+ ]
+
+ self.verify_nftables(nftables_search, 'ip vyos_nat')
+
+ self.cli_delete(['firewall'])
+
def test_dnat(self):
rules = ['100', '110', '120', '130', '200', '210', '220', '230']
inbound_iface_100 = 'eth0'
@@ -159,12 +194,13 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):
self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'eth1'])
self.cli_set(dst_path + ['rule', '1', 'destination', 'port', '443'])
self.cli_set(dst_path + ['rule', '1', 'protocol', 'tcp'])
+ self.cli_set(dst_path + ['rule', '1', 'packet-type', 'host'])
self.cli_set(dst_path + ['rule', '1', 'translation', 'port', '443'])
self.cli_commit()
nftables_search = [
- ['iifname "eth1"', 'tcp dport 443', 'dnat to :443']
+ ['iifname "eth1"', 'tcp dport 443', 'pkttype host', 'dnat to :443']
]
self.verify_nftables(nftables_search, 'ip vyos_nat')
@@ -195,5 +231,69 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):
self.verify_nftables(nftables_search, 'ip vyos_static_nat')
+ def test_dnat_redirect(self):
+ dst_addr_1 = '10.0.1.1'
+ dest_port = '5122'
+ protocol = 'tcp'
+ redirected_port = '22'
+ ifname = 'eth0'
+
+ self.cli_set(dst_path + ['rule', '10', 'destination', 'address', dst_addr_1])
+ self.cli_set(dst_path + ['rule', '10', 'destination', 'port', dest_port])
+ self.cli_set(dst_path + ['rule', '10', 'protocol', protocol])
+ self.cli_set(dst_path + ['rule', '10', 'inbound-interface', ifname])
+ self.cli_set(dst_path + ['rule', '10', 'translation', 'redirect', 'port', redirected_port])
+
+ self.cli_set(dst_path + ['rule', '20', 'destination', 'address', dst_addr_1])
+ self.cli_set(dst_path + ['rule', '20', 'destination', 'port', dest_port])
+ self.cli_set(dst_path + ['rule', '20', 'protocol', protocol])
+ self.cli_set(dst_path + ['rule', '20', 'inbound-interface', ifname])
+ self.cli_set(dst_path + ['rule', '20', 'translation', 'redirect'])
+
+ self.cli_commit()
+
+ nftables_search = [
+ [f'iifname "{ifname}"', f'ip daddr {dst_addr_1}', f'{protocol} dport {dest_port}', f'redirect to :{redirected_port}'],
+ [f'iifname "{ifname}"', f'ip daddr {dst_addr_1}', f'{protocol} dport {dest_port}', f'redirect']
+ ]
+
+ self.verify_nftables(nftables_search, 'ip vyos_nat')
+
+ def test_nat_balance(self):
+ ifname = 'eth0'
+ member_1 = '198.51.100.1'
+ weight_1 = '10'
+ member_2 = '198.51.100.2'
+ weight_2 = '90'
+ member_3 = '192.0.2.1'
+ weight_3 = '35'
+ member_4 = '192.0.2.2'
+ weight_4 = '65'
+ dst_port = '443'
+
+ self.cli_set(dst_path + ['rule', '1', 'inbound-interface', ifname])
+ self.cli_set(dst_path + ['rule', '1', 'protocol', 'tcp'])
+ self.cli_set(dst_path + ['rule', '1', 'destination', 'port', dst_port])
+ self.cli_set(dst_path + ['rule', '1', 'load-balance', 'hash', 'source-address'])
+ self.cli_set(dst_path + ['rule', '1', 'load-balance', 'hash', 'source-port'])
+ self.cli_set(dst_path + ['rule', '1', 'load-balance', 'hash', 'destination-address'])
+ self.cli_set(dst_path + ['rule', '1', 'load-balance', 'hash', 'destination-port'])
+ self.cli_set(dst_path + ['rule', '1', 'load-balance', 'backend', member_1, 'weight', weight_1])
+ self.cli_set(dst_path + ['rule', '1', 'load-balance', 'backend', member_2, 'weight', weight_2])
+
+ self.cli_set(src_path + ['rule', '1', 'outbound-interface', ifname])
+ self.cli_set(src_path + ['rule', '1', 'load-balance', 'hash', 'random'])
+ self.cli_set(src_path + ['rule', '1', 'load-balance', 'backend', member_3, 'weight', weight_3])
+ self.cli_set(src_path + ['rule', '1', 'load-balance', 'backend', member_4, 'weight', weight_4])
+
+ self.cli_commit()
+
+ nftables_search = [
+ [f'iifname "{ifname}"', f'tcp dport {dst_port}', f'dnat to jhash ip saddr . tcp sport . ip daddr . tcp dport mod 100 map', f'0-9 : {member_1}, 10-99 : {member_2}'],
+ [f'oifname "{ifname}"', f'snat to numgen random mod 100 map', f'0-34 : {member_3}, 35-99 : {member_4}']
+ ]
+
+ self.verify_nftables(nftables_search, 'ip vyos_nat')
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_nat66.py b/smoketest/scripts/cli/test_nat66.py
index 6cf7ca0a1..e062f28a6 100755
--- a/smoketest/scripts/cli/test_nat66.py
+++ b/smoketest/scripts/cli/test_nat66.py
@@ -22,8 +22,8 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
-from vyos.util import dict_search
+from vyos.utils.process import cmd
+from vyos.utils.dict import dict_search
base_path = ['nat66']
src_path = base_path + ['source']
@@ -136,7 +136,7 @@ class TestNAT66(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
nftables_search = [
- ['iifname "eth1"', 'tcp dport 4545', 'ip6 saddr 2001:db8:2222::/64', 'tcp sport 8080', 'dnat to 2001:db8:1111::1:5555']
+ ['iifname "eth1"', 'tcp dport 4545', 'ip6 saddr 2001:db8:2222::/64', 'tcp sport 8080', 'dnat to [2001:db8:1111::1]:5555']
]
self.verify_nftables(nftables_search, 'ip6 vyos_nat')
@@ -208,7 +208,7 @@ class TestNAT66(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
nftables_search = [
- ['oifname "eth1"', 'ip6 saddr 2001:db8:2222::/64', 'tcp dport 9999', 'tcp sport 8080', 'snat to 2001:db8:1111::1:80']
+ ['oifname "eth1"', 'ip6 saddr 2001:db8:2222::/64', 'tcp dport 9999', 'tcp sport 8080', 'snat to [2001:db8:1111::1]:80']
]
self.verify_nftables(nftables_search, 'ip6 vyos_nat')
diff --git a/smoketest/scripts/cli/test_interfaces_netns.py b/smoketest/scripts/cli/test_netns.py
index 9975a6b09..fd04dd520 100755
--- a/smoketest/scripts/cli/test_interfaces_netns.py
+++ b/smoketest/scripts/cli/test_netns.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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
@@ -14,70 +14,70 @@
# 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 json
import unittest
-from netifaces import interfaces
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Interface
from vyos.ifconfig import Section
-from vyos.util import cmd
+from vyos.utils.process import cmd
+from vyos.utils.network import is_netns_interface
+from vyos.utils.network import get_netns_all
base_path = ['netns']
-namespaces = ['mgmt', 'front', 'back', 'ams-ix']
+interfaces = ['dum10', 'dum12', 'dum50']
-class NETNSTest(VyOSUnitTestSHIM.TestCase):
+class NetNSTest(VyOSUnitTestSHIM.TestCase):
+ def tearDown(self):
+ self.cli_delete(base_path)
+ # commit changes
+ self.cli_commit()
- def setUp(self):
- self._interfaces = ['dum10', 'dum12', 'dum50']
+ # There should be no network namespace remaining
+ tmp = cmd('ip netns ls')
+ self.assertFalse(tmp)
- def test_create_netns(self):
+ super(NetNSTest, self).tearDown()
+
+ def test_netns_create(self):
+ namespaces = ['mgmt', 'front', 'back']
for netns in namespaces:
- base = base_path + ['name', netns]
- self.cli_set(base)
+ self.cli_set(base_path + ['name', netns])
# commit changes
self.cli_commit()
- netns_list = cmd('ip netns ls')
-
# Verify NETNS configuration
for netns in namespaces:
- self.assertTrue(netns in netns_list)
+ self.assertIn(netns, get_netns_all())
-
- def test_netns_assign_interface(self):
+ def test_netns_interface(self):
netns = 'foo'
- self.cli_set(['netns', 'name', netns])
+ self.cli_set(base_path + ['name', netns])
# Set
- for iface in self._interfaces:
+ for iface in interfaces:
self.cli_set(['interfaces', 'dummy', iface, 'netns', netns])
# commit changes
self.cli_commit()
- netns_iface_list = cmd(f'sudo ip netns exec {netns} ip link show')
-
- for iface in self._interfaces:
- self.assertTrue(iface in netns_iface_list)
+ for interface in interfaces:
+ self.assertTrue(is_netns_interface(interface, netns))
# Delete
- for iface in self._interfaces:
- self.cli_delete(['interfaces', 'dummy', iface, 'netns', netns])
+ for interface in interfaces:
+ self.cli_delete(['interfaces', 'dummy', interface])
# commit changes
self.cli_commit()
netns_iface_list = cmd(f'sudo ip netns exec {netns} ip link show')
- for iface in self._interfaces:
- self.assertNotIn(iface, netns_iface_list)
+ for interface in interfaces:
+ self.assertFalse(is_netns_interface(interface, netns))
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_pki.py b/smoketest/scripts/cli/test_pki.py
index cba5ffdde..b18b0b039 100755
--- a/smoketest/scripts/cli/test_pki.py
+++ b/smoketest/scripts/cli/test_pki.py
@@ -246,5 +246,27 @@ class TestPKI(VyOSUnitTestSHIM.TestCase):
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','')])
+ self.cli_commit()
+
+ self.cli_set(['interfaces', 'ethernet', 'eth1', 'eapol', 'certificate', 'smoketest'])
+ self.cli_commit()
+
+ cert_data = None
+
+ with open('/run/wpa_supplicant/eth1_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_commit()
+
+ with open('/run/wpa_supplicant/eth1_cert.pem') as f:
+ self.assertNotEqual(cert_data, f.read())
+
+ self.cli_delete(['interfaces', 'ethernet', 'eth1', 'eapol'])
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py
index 2166e63ec..354f791bd 100755
--- a/smoketest/scripts/cli/test_policy.py
+++ b/smoketest/scripts/cli/test_policy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2022 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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
@@ -19,7 +19,7 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
+from vyos.utils.process import cmd
base_path = ['policy']
@@ -1030,6 +1030,7 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
'metric' : '150',
'metric-type' : 'type-1',
'origin' : 'incomplete',
+ 'l3vpn' : '',
'originator-id' : '172.16.10.1',
'src' : '100.0.0.1',
'tag' : '65530',
@@ -1070,6 +1071,22 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
},
},
},
+ 'match-protocol' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'match' : {
+ 'protocol' : 'static',
+ },
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'match' : {
+ 'protocol' : 'bgp',
+ },
+ },
+ },
+ },
'relative-metric' : {
'rule' : {
'10' : {
@@ -1201,6 +1218,8 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
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 'protocol' in rule_config['match']:
+ self.cli_set(path + ['rule', rule, 'match', 'protocol', rule_config['match']['protocol']])
if 'tag' in rule_config['match']:
self.cli_set(path + ['rule', rule, 'match', 'tag', rule_config['match']['tag']])
@@ -1229,6 +1248,8 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
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']:
@@ -1365,6 +1386,9 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
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)
@@ -1408,6 +1432,8 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
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']:
diff --git a/smoketest/scripts/cli/test_policy_route.py b/smoketest/scripts/cli/test_policy_route.py
index 046e385bb..118b1d3a2 100755
--- a/smoketest/scripts/cli/test_policy_route.py
+++ b/smoketest/scripts/cli/test_policy_route.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2022 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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
@@ -18,12 +18,15 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
-from vyos.util import cmd
+from vyos.utils.process import cmd
mark = '100'
+conn_mark = '555'
+conn_mark_set = '111'
table_mark_offset = 0x7fffffff
table_id = '101'
interface = 'eth0'
+interface_wc = 'ppp*'
interface_ip = '172.16.10.1/24'
class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
@@ -42,18 +45,25 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
super(TestPolicyRoute, cls).tearDownClass()
def tearDown(self):
- self.cli_delete(['interfaces', 'ethernet', interface, 'policy'])
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 mangle', inverse=True)
+ 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 verify_nftables(self, nftables_search, table, inverse=False):
nftables_output = cmd(f'sudo nft list table {table}')
@@ -66,6 +76,17 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
break
self.assertTrue(not matched if inverse else matched, msg=search)
+ def verify_rules(self, rules_search, inverse=False):
+ rule_output = cmd('ip 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)
+
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'])
@@ -74,17 +95,16 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
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(['interfaces', 'ethernet', interface, 'policy', 'route', 'smoketest'])
+ self.cli_set(['policy', 'route', 'smoketest', 'interface', interface])
self.cli_commit()
nftables_search = [
- [f'iifname "{interface}"','jump VYOS_PBR_smoketest'],
+ [f'iifname "{interface}"','jump VYOS_PBR_UD_smoketest'],
['ip daddr @N_smoketest_network1', 'ip saddr @N_smoketest_network'],
]
- self.verify_nftables(nftables_search, 'ip mangle')
+ self.verify_nftables(nftables_search, 'ip vyos_mangle')
self.cli_delete(['firewall'])
@@ -92,19 +112,37 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
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(['interfaces', 'ethernet', interface, 'policy', 'route', 'smoketest'])
+ 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_smoketest'],
+ [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 mangle')
+ 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'])
@@ -116,8 +154,8 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
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(['interfaces', 'ethernet', interface, 'policy', 'route', 'smoketest'])
- self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route6', 'smoketest6'])
+ self.cli_set(['policy', 'route', 'smoketest', 'interface', interface])
+ self.cli_set(['policy', 'route6', 'smoketest6', 'interface', interface])
self.cli_commit()
@@ -126,20 +164,20 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
# IPv4
nftables_search = [
- [f'iifname "{interface}"', 'jump VYOS_PBR_smoketest'],
+ [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 mangle')
+ self.verify_nftables(nftables_search, 'ip vyos_mangle')
# IPv6
nftables6_search = [
- [f'iifname "{interface}"', 'jump VYOS_PBR6_smoketest'],
+ [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 mangle')
+ self.verify_nftables(nftables6_search, 'ip6 vyos_mangle')
# IP rule fwmark -> table
@@ -147,15 +185,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
['fwmark ' + hex(table_mark_offset - int(table_id)), 'lookup ' + table_id]
]
- ip_rule_output = cmd('ip rule show')
-
- for search in ip_rule_search:
- matched = False
- for line in ip_rule_output.split("\n"):
- if all(item in line for item in search):
- matched = True
- break
- self.assertTrue(matched)
+ self.verify_rules(ip_rule_search)
def test_pbr_matching_criteria(self):
@@ -175,6 +205,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
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', 'enable'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'set', 'table', table_id])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '5', 'dscp', '41'])
@@ -197,14 +228,17 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
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', 'enable'])
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(['interfaces', 'ethernet', interface, 'policy', 'route', 'smoketest'])
- self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route6', 'smoketest6'])
+ 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()
@@ -212,27 +246,27 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
# IPv4
nftables_search = [
- [f'iifname "{interface}"', 'jump VYOS_PBR_smoketest'],
+ ['iifname { "' + interface + '", "' + interface_wc + '" }', 'jump VYOS_PBR_UD_smoketest'],
['meta l4proto udp', 'drop'],
['tcp flags syn / syn,ack', 'meta mark set ' + mark_hex],
['ct state new', 'tcp dport 22', 'ip saddr 198.51.100.0/24', 'ip ttl > 2', 'meta mark set ' + mark_hex],
- ['meta l4proto icmp', 'log prefix "[smoketest-4-A]"', 'icmp type echo-request', 'ip length { 128, 1024-2048 }', 'meta mark set ' + mark_hex],
+ ['meta l4proto icmp', '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 set ' + mark_hex]
]
- self.verify_nftables(nftables_search, 'ip mangle')
+ self.verify_nftables(nftables_search, 'ip vyos_mangle')
# IPv6
nftables6_search = [
- [f'iifname "{interface}"', 'jump VYOS_PBR6_smoketest'],
+ [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],
- ['meta l4proto ipv6-icmp', 'log prefix "[smoketest6-4-A]"', 'icmpv6 type echo-request', 'ip6 length != { 128, 1024-2048 }', 'meta mark set ' + mark_hex],
+ ['meta l4proto ipv6-icmp', '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]
]
- self.verify_nftables(nftables6_search, 'ip6 mangle')
+ self.verify_nftables(nftables6_search, 'ip6 vyos_mangle')
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 fdc254a05..451565664 100755
--- a/smoketest/scripts/cli/test_protocols_bfd.py
+++ b/smoketest/scripts/cli/test_protocols_bfd.py
@@ -18,7 +18,7 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import process_named_running
+from vyos.utils.process import process_named_running
PROCESS_NAME = 'bfdd'
base_path = ['protocols', 'bfd']
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index d2dad8c1a..77952d8d9 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2022 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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
@@ -18,9 +18,10 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.ifconfig import Section
from vyos.configsession import ConfigSessionError
from vyos.template import is_ipv6
-from vyos.util import process_named_running
+from vyos.utils.process import process_named_running
PROCESS_NAME = 'bgpd'
ASN = '64512'
@@ -34,6 +35,10 @@ 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' : '',
@@ -51,6 +56,7 @@ neighbor_config = {
'route_map_out' : route_map_out,
'no_send_comm_ext' : '',
'addpath_all' : '',
+ 'p_attr_discard' : '123',
},
'192.0.2.2' : {
'bfd_profile' : bfd_profile,
@@ -64,6 +70,7 @@ neighbor_config = {
'pfx_list_in' : prefix_list_in,
'pfx_list_out' : prefix_list_out,
'no_send_comm_std' : '',
+ 'local_role' : 'rs-client',
},
'192.0.2.3' : {
'advertise_map' : route_map_in,
@@ -94,6 +101,8 @@ neighbor_config = {
'no_send_comm_std' : '',
'addpath_per_as' : '',
'peer_group' : 'foo-bar',
+ 'local_role' : 'customer',
+ 'local_role_strict': '',
},
'2001:db8::2' : {
'remote_as' : '456',
@@ -122,10 +131,12 @@ peer_group_config = {
'cap_over' : '',
'ttl_security' : '5',
'disable_conn_chk' : '',
+ 'p_attr_discard' : '250',
},
'bar' : {
'remote_as' : '111',
- 'graceful_rst_no' : ''
+ 'graceful_rst_no' : '',
+ 'port' : '667',
},
'foo-bar' : {
'advertise_map' : route_map_in,
@@ -150,9 +161,10 @@ peer_group_config = {
'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):
@@ -189,6 +201,11 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
# Check for running process
self.assertTrue(process_named_running(PROCESS_NAME))
+ 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:
@@ -208,12 +225,19 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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:
@@ -238,6 +262,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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:
+ self.assertIn(f' neighbor {peer} path-attribute discard {peer_config["p_attr_discard"]}', 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:
@@ -256,7 +282,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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'
@@ -267,6 +292,9 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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', 'router-id', router_id])
self.cli_set(base_path + ['parameters', 'log-neighbor-changes'])
@@ -294,8 +322,12 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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', '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])
@@ -322,8 +354,10 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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' 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)
@@ -335,7 +369,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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!
@@ -365,6 +398,10 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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:
@@ -385,6 +422,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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:
+ self.cli_set(base_path + ['neighbor', peer, 'path-attribute', 'discard', peer_config["p_attr_discard"]])
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:
@@ -434,8 +473,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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 'port' in peer_config:
- self.assertIn(f' neighbor {peer} port {peer_config["port"]}', frrconfig)
if 'cap_strict' in peer_config:
self.assertIn(f' neighbor {peer} strict-capability-match', frrconfig)
@@ -461,12 +498,18 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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 'shutdown' in config:
@@ -499,6 +542,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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:
+ self.cli_set(base_path + ['peer-group', peer_group, 'path-attribute', 'discard', config["p_attr_discard"]])
# Conditional advertisement
if 'advertise_map' in config:
@@ -518,7 +563,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
if 'peer_group' in peer_config:
self.cli_set(base_path + ['neighbor', peer, 'peer-group', peer_config['peer_group']])
-
# commit changes
self.cli_commit()
@@ -534,7 +578,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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' : {
@@ -582,7 +625,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
if 'summary_only' in network_config:
self.assertIn(f' aggregate-address {network} summary-only', frrconfig)
-
def test_bgp_05_afi_ipv6(self):
networks = {
'2001:db8:100::/48' : {
@@ -629,7 +671,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
if 'as_set' in network_config:
self.assertIn(f' aggregate-address {network} summary-only', frrconfig)
-
def test_bgp_06_listen_range(self):
# Implemented via T1875
limit = '64'
@@ -662,7 +703,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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']
neighbors = ['192.0.2.10', '192.0.2.20', '192.0.2.30']
@@ -692,26 +732,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' advertise-default-gw', vniconfig)
self.assertIn(f' advertise-svi-ip', vniconfig)
- def test_bgp_08_zebra_route_map(self):
- # Implemented because of T3328
- self.cli_set(base_path + ['route-map', route_map_in])
- # commit changes
- self.cli_commit()
-
- # Verify FRR configuration
- zebra_route_map = f'ip protocol bgp route-map {route_map_in}'
- 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_bgp_09_distance_and_flowspec(self):
distance_external = '25'
distance_internal = '30'
@@ -761,7 +781,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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']
@@ -771,15 +790,12 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
# templates and Jinja2 FRR template.
table = '1000'
- self.cli_set(base_path + ['system-as', ASN])
# 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])
- self.cli_set(vrf_base + ['protocols', 'bgp', 'route-map', route_map_in])
table = str(int(table) + 1000)
# import VRF routes do main RIB
@@ -792,7 +808,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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)
@@ -801,21 +816,11 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'router bgp {ASN} vrf {vrf}', frr_vrf_config)
self.assertIn(f' bgp router-id {router_id}', frr_vrf_config)
- # XXX: Currently this is not working as FRR() class does not support
- # route-maps for multiple vrfs because the modify_section() only works
- # on lines and not text blocks.
- #
- # vrfconfig = self.getFRRconfig(f'vrf {vrf}')
- # zebra_route_map = f' ip protocol bgp route-map {route_map_in}'
- # self.assertIn(zebra_route_map, vrfconfig)
-
-
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 + ['system-as', ASN])
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():
@@ -831,12 +836,10 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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 + ['system-as', ASN])
self.cli_set(base_path + ['neighbor', interface, 'address-family', 'ipv6-unicast'])
self.cli_set(base_path + ['neighbor', interface, 'interface', 'v6only', 'remote-as', remote_asn])
@@ -851,7 +854,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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'
@@ -861,12 +863,12 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
rt_export = f'{neighbor}:1002 1.2.3.4:567'
rt_import = f'{neighbor}:1003 500:100'
- self.cli_set(base_path + ['system-as', ASN])
# 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])
@@ -886,6 +888,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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)
@@ -900,7 +903,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
peer_group = 'bar'
interface = 'eth0'
- self.cli_set(base_path + ['system-as', ASN])
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])
@@ -933,14 +935,13 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' neighbor {peer_group} remote-as {remote_asn}', frrconfig)
def test_bgp_15_local_as_ebgp(self):
- # https://phabricator.vyos.net/T4560
+ # 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 + ['system-as', ASN])
self.cli_set(base_path + ['neighbor', neighbor, 'remote-as', ASN])
self.cli_set(base_path + ['neighbor', neighbor, 'local-as', local_asn])
@@ -957,6 +958,128 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
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}')
+ frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}')
+
+ 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}')
+ frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}')
+ 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}')
+ frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}')
+ 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}')
+ frrconfig_vrf = self.getFRRconfig(f'router bgp {ASN} vrf {import_vrf}')
+ 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}')
+ 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}')
+ self.assertIn(f'interface {interface}', frrconfig)
+ self.assertIn(f' mpls bgp forwarding', frrconfig)
+ self.cli_delete(['interfaces', 'ethernet', interface, 'vrf'])
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_igmp-proxy.py b/smoketest/scripts/cli/test_protocols_igmp-proxy.py
index 079b5bee5..a75003b12 100755
--- a/smoketest/scripts/cli/test_protocols_igmp-proxy.py
+++ b/smoketest/scripts/cli/test_protocols_igmp-proxy.py
@@ -19,8 +19,8 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import read_file
-from vyos.util import process_named_running
+from vyos.utils.file import read_file
+from vyos.utils.process import process_named_running
PROCESS_NAME = 'igmpproxy'
IGMP_PROXY_CONF = '/etc/igmpproxy.conf'
diff --git a/smoketest/scripts/cli/test_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py
index d11d80a1f..5ab7fae14 100755
--- a/smoketest/scripts/cli/test_protocols_isis.py
+++ b/smoketest/scripts/cli/test_protocols_isis.py
@@ -19,7 +19,7 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
-from vyos.util import process_named_running
+from vyos.utils.process import process_named_running
PROCESS_NAME = 'isisd'
base_path = ['protocols', 'isis']
@@ -119,39 +119,6 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.cli_delete(['vrf', 'name', vrf])
self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf'])
- def test_isis_03_zebra_route_map(self):
- # Implemented because of T3328
- route_map = 'foo-isis-in'
-
- self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
-
- self.isis_base_config()
- self.cli_set(base_path + ['redistribute', 'ipv4', 'connected', 'level-2', 'route-map', route_map])
- self.cli_set(base_path + ['route-map', route_map])
- self.cli_set(base_path + ['level', 'level-2'])
-
- # commit changes
- self.cli_commit()
-
- # Verify FRR configuration
- zebra_route_map = f'ip protocol isis route-map {route_map}'
- frrconfig = self.getFRRconfig(zebra_route_map, daemon='zebra')
- self.assertIn(zebra_route_map, frrconfig)
-
- tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd')
- self.assertIn(' is-type level-2-only', tmp)
-
- # 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, daemon='zebra')
- self.assertNotIn(zebra_route_map, frrconfig)
-
- self.cli_delete(['policy', 'route-map', route_map])
-
def test_isis_04_default_information(self):
metric = '50'
route_map = 'default-foo-'
@@ -293,7 +260,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
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()
@@ -308,5 +275,50 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' segment-routing prefix {prefix_three} absolute {prefix_three_value} explicit-null', tmp)
self.assertIn(f' segment-routing prefix {prefix_four} absolute {prefix_four_value} no-php-flag', tmp)
+ def test_isis_08_ldp_sync(self):
+ holddown = "500"
+ interface = 'lo'
+
+ self.cli_set(base_path + ['net', net])
+ self.cli_set(base_path + ['interface', interface])
+ self.cli_set(base_path + ['ldp-sync', 'holddown', holddown])
+
+ # Commit main ISIS changes
+ self.cli_commit()
+
+ # Verify main ISIS changes
+ tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd')
+ self.assertIn(f' net {net}', tmp)
+ self.assertIn(f' mpls ldp-sync', tmp)
+ self.assertIn(f' mpls ldp-sync holddown {holddown}', tmp)
+
+ for interface in self._interfaces:
+ self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'holddown', holddown])
+
+ # Commit interface changes for holddown
+ self.cli_commit()
+
+ for interface in self._interfaces:
+ # Verify interface changes for holddown
+ tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd')
+ self.assertIn(f'interface {interface}', tmp)
+ self.assertIn(f' ip router isis {domain}', tmp)
+ self.assertIn(f' ipv6 router isis {domain}', tmp)
+ self.assertIn(f' isis mpls ldp-sync holddown {holddown}', tmp)
+
+ for interface in self._interfaces:
+ self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'disable'])
+
+ # Commit interface changes for disable
+ self.cli_commit()
+
+ for interface in self._interfaces:
+ # Verify interface changes for disable
+ tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd')
+ self.assertIn(f'interface {interface}', tmp)
+ self.assertIn(f' ip router isis {domain}', tmp)
+ self.assertIn(f' ipv6 router isis {domain}', tmp)
+ self.assertIn(f' no isis mpls ldp-sync', tmp)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_mpls.py b/smoketest/scripts/cli/test_protocols_mpls.py
index 76e6ca35a..06f21c6e1 100755
--- a/smoketest/scripts/cli/test_protocols_mpls.py
+++ b/smoketest/scripts/cli/test_protocols_mpls.py
@@ -19,7 +19,7 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
-from vyos.util import process_named_running
+from vyos.utils.process import process_named_running
PROCESS_NAME = 'ldpd'
base_path = ['protocols', 'mpls', 'ldp']
diff --git a/smoketest/scripts/cli/test_protocols_nhrp.py b/smoketest/scripts/cli/test_protocols_nhrp.py
index 59252875b..45ef539f6 100755
--- a/smoketest/scripts/cli/test_protocols_nhrp.py
+++ b/smoketest/scripts/cli/test_protocols_nhrp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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
@@ -19,7 +19,9 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.firewall import find_nftables_rule
-from vyos.util import call, process_named_running, read_file
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
+from vyos.utils.process import call
tunnel_path = ['interfaces', 'tunnel']
nhrp_path = ['protocols', 'nhrp']
@@ -54,7 +56,7 @@ class TestProtocolsNHRP(VyOSUnitTestSHIM.TestCase):
self.cli_set(tunnel_path + [tunnel_if, "address", "172.16.253.134/29"])
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, "multicast", "enable"])
+ self.cli_set(tunnel_path + [tunnel_if, "enable-multicast"])
self.cli_set(tunnel_path + [tunnel_if, "parameters", "ip", "key", "1"])
# NHRP
diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py
index 51c947537..a6850db71 100755
--- a/smoketest/scripts/cli/test_protocols_ospf.py
+++ b/smoketest/scripts/cli/test_protocols_ospf.py
@@ -20,7 +20,7 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
-from vyos.util import process_named_running
+from vyos.utils.process import process_named_running
PROCESS_NAME = 'ospfd'
base_path = ['protocols', 'ospf']
@@ -56,7 +56,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
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
@@ -70,20 +70,35 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
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')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
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):
@@ -101,7 +116,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
for ptotocol in protocols:
@@ -122,7 +137,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
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)
@@ -132,7 +147,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
self.assertIn(f' default-information originate always metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
@@ -144,6 +159,12 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
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])
@@ -155,11 +176,20 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
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')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
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
@@ -169,12 +199,20 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
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')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
self.assertIn(f' distance ospf intra-area {intra_area} inter-area {inter_area} external {external}', frrconfig)
@@ -190,7 +228,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
self.assertIn(f'router ospf', frrconfig)
for neighbor in neighbors:
self.assertIn(f' neighbor {neighbor} priority {priority} poll-interval {poll_interval}', frrconfig) # default
@@ -209,7 +247,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
self.assertIn(f'router ospf', frrconfig)
for protocol in redistribute:
self.assertIn(f' redistribute {protocol} metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
@@ -236,7 +274,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
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} transmit-delay {transmit} dead-interval {dead}', frrconfig)
@@ -268,7 +306,12 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
# commit changes
self.cli_commit()
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
+ 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}')
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ip ospf authentication-key {password}', config)
@@ -281,25 +324,16 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' no ip ospf passive', config)
self.assertIn(f' bandwidth {bandwidth}', config)
- def test_ospf_10_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 ospf 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
+ # T5467: Remove interface from OSPF process and VRF
+ self.cli_delete(base_path + ['interface'])
self.cli_commit()
- # Verify FRR configuration
- frrconfig = self.getFRRconfig(zebra_route_map)
- self.assertNotIn(zebra_route_map, frrconfig)
+ for interface in interfaces:
+ # T5467: It must also be removed from FRR config
+ frrconfig = self.getFRRconfig(f'interface {interface}', daemon=PROCESS_NAME)
+ 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'
@@ -317,11 +351,11 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
self.assertIn(f'router ospf', frrconfig)
for interface in interfaces:
- config = self.getFRRconfig(f'interface {interface}')
+ config = self.getFRRconfig(f'interface {interface}', daemon=PROCESS_NAME)
self.assertIn(f'interface {interface}', config)
self.assertIn(f' ip ospf area {area}', config)
@@ -333,8 +367,10 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
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])
+ 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
@@ -342,16 +378,31 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
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}')
+ frrconfig = self.getFRRconfig(f'router ospf vrf {vrf}', daemon=PROCESS_NAME)
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}', daemon=PROCESS_NAME)
+ 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}', daemon=PROCESS_NAME)
+ 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'])
@@ -363,7 +414,6 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
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'])
@@ -374,7 +424,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
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)
@@ -408,13 +458,83 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify all changes
- frrconfig = self.getFRRconfig('router ospf')
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
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"
+ interface = 'lo'
+ interfaces = Section.interfaces('ethernet')
+
+ self.cli_set(base_path + ['interface', interface])
+ 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', daemon=PROCESS_NAME)
+ 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}', daemon=PROCESS_NAME)
+ 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}', daemon=PROCESS_NAME)
+ self.assertIn(f'interface {interface}', config)
+ self.assertIn(f' ip ospf dead-interval 40', config)
+ self.assertIn(f' no 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', daemon=PROCESS_NAME)
+ 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)
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_ospfv3.py b/smoketest/scripts/cli/test_protocols_ospfv3.py
index fa80ad555..0d6c6c691 100755
--- a/smoketest/scripts/cli/test_protocols_ospfv3.py
+++ b/smoketest/scripts/cli/test_protocols_ospfv3.py
@@ -20,7 +20,7 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
-from vyos.util import process_named_running
+from vyos.utils.process import process_named_running
PROCESS_NAME = 'ospf6d'
base_path = ['protocols', 'ospfv3']
@@ -74,7 +74,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', daemon='ospf6d')
+ frrconfig = self.getFRRconfig('router ospf6', daemon=PROCESS_NAME)
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' area {default_area} range {prefix}', frrconfig)
self.assertIn(f' ospf6 router-id {router_id}', frrconfig)
@@ -82,7 +82,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' area {default_area} export-list {acl_name}', frrconfig)
for interface in interfaces:
- if_config = self.getFRRconfig(f'interface {interface}', daemon='ospf6d')
+ if_config = self.getFRRconfig(f'interface {interface}', daemon=PROCESS_NAME)
self.assertIn(f'ipv6 ospf6 area {default_area}', if_config)
self.cli_delete(['policy', 'access-list6', acl_name])
@@ -103,7 +103,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', daemon='ospf6d')
+ frrconfig = self.getFRRconfig('router ospf6', daemon=PROCESS_NAME)
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)
@@ -123,7 +123,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', daemon='ospf6d')
+ frrconfig = self.getFRRconfig('router ospf6', daemon=PROCESS_NAME)
self.assertIn(f'router ospf6', frrconfig)
for protocol in redistribute:
self.assertIn(f' redistribute {protocol} route-map {route_map}', frrconfig)
@@ -154,13 +154,13 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', daemon='ospf6d')
+ frrconfig = self.getFRRconfig('router ospf6', daemon=PROCESS_NAME)
self.assertIn(f'router ospf6', frrconfig)
cost = '100'
priority = '10'
for interface in interfaces:
- if_config = self.getFRRconfig(f'interface {interface}', daemon='ospf6d')
+ if_config = self.getFRRconfig(f'interface {interface}', daemon=PROCESS_NAME)
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)
@@ -172,6 +172,15 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
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}', daemon=PROCESS_NAME)
+ # 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'
@@ -184,7 +193,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', daemon='ospf6d')
+ frrconfig = self.getFRRconfig('router ospf6', daemon=PROCESS_NAME)
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)
@@ -210,7 +219,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', daemon='ospf6d')
+ frrconfig = self.getFRRconfig('router ospf6', daemon=PROCESS_NAME)
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)
@@ -230,7 +239,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', daemon='ospf6d')
+ frrconfig = self.getFRRconfig('router ospf6', daemon=PROCESS_NAME)
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' default-information originate metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
@@ -239,7 +248,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', daemon='ospf6d')
+ frrconfig = self.getFRRconfig('router ospf6', daemon=PROCESS_NAME)
self.assertIn(f' default-information originate always metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
@@ -265,21 +274,58 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify FRR ospfd configuration
- frrconfig = self.getFRRconfig('router ospf6', daemon='ospf6d')
+ frrconfig = self.getFRRconfig('router ospf6', daemon=PROCESS_NAME)
self.assertIn(f'router ospf6', frrconfig)
self.assertIn(f' ospf6 router-id {router_id}', frrconfig)
- frrconfig = self.getFRRconfig(f'interface {vrf_iface}', daemon='ospf6d')
+ frrconfig = self.getFRRconfig(f'interface {vrf_iface}', daemon=PROCESS_NAME)
self.assertIn(f'interface {vrf_iface}', frrconfig)
self.assertIn(f' ipv6 ospf6 bfd', frrconfig)
- frrconfig = self.getFRRconfig(f'router ospf6 vrf {vrf}', daemon='ospf6d')
+ frrconfig = self.getFRRconfig(f'router ospf6 vrf {vrf}', daemon=PROCESS_NAME)
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}', daemon=PROCESS_NAME)
+ 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', daemon=PROCESS_NAME)
+ 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)
diff --git a/smoketest/scripts/cli/test_protocols_pim6.py b/smoketest/scripts/cli/test_protocols_pim6.py
new file mode 100755
index 000000000..1be12836d
--- /dev/null
+++ b/smoketest/scripts/cli/test_protocols_pim6.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.configsession import ConfigSessionError
+from vyos.ifconfig import Section
+from vyos.utils.process import process_named_running
+
+PROCESS_NAME = 'pim6d'
+base_path = ['protocols', 'pim6']
+
+
+class TestProtocolsPIMv6(VyOSUnitTestSHIM.TestCase):
+ def tearDown(self):
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ 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}', daemon=PROCESS_NAME)
+ 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}', daemon=PROCESS_NAME)
+ 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):
+ # commit changes
+ interfaces = Section.interfaces('ethernet')
+
+ # Use an invalid multiple 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 multiple 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}', daemon=PROCESS_NAME)
+ self.assertIn(f'interface {interface}', config)
+ self.assertIn(f' ipv6 mld join 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}', daemon=PROCESS_NAME)
+ self.assertIn(f'interface {interface}', config)
+ self.assertIn(f' ipv6 mld join ff38::5678 2001:db8::5678', config)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_rip.py b/smoketest/scripts/cli/test_protocols_rip.py
index 11385adb5..925499fc8 100755
--- a/smoketest/scripts/cli/test_protocols_rip.py
+++ b/smoketest/scripts/cli/test_protocols_rip.py
@@ -19,7 +19,7 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.ifconfig import Section
-from vyos.util import process_named_running
+from vyos.utils.process import process_named_running
PROCESS_NAME = 'ripd'
acl_in = '198'
diff --git a/smoketest/scripts/cli/test_protocols_ripng.py b/smoketest/scripts/cli/test_protocols_ripng.py
index 53336a533..0a8ce7eef 100755
--- a/smoketest/scripts/cli/test_protocols_ripng.py
+++ b/smoketest/scripts/cli/test_protocols_ripng.py
@@ -19,7 +19,7 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.ifconfig import Section
-from vyos.util import process_named_running
+from vyos.utils.process import process_named_running
PROCESS_NAME = 'ripngd'
acl_in = '198'
diff --git a/smoketest/scripts/cli/test_protocols_rpki.py b/smoketest/scripts/cli/test_protocols_rpki.py
index e5e45565b..f4aedcbc3 100755
--- a/smoketest/scripts/cli/test_protocols_rpki.py
+++ b/smoketest/scripts/cli/test_protocols_rpki.py
@@ -20,8 +20,8 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
-from vyos.util import process_named_running
+from vyos.utils.process import cmd
+from vyos.utils.process import process_named_running
base_path = ['protocols', 'rpki']
PROCESS_NAME = 'bgpd'
diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py
index 19efe7786..abf1080ab 100755
--- a/smoketest/scripts/cli/test_protocols_static.py
+++ b/smoketest/scripts/cli/test_protocols_static.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2022 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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
@@ -20,7 +20,7 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.template import is_ipv6
-from vyos.util import get_interface_config
+from vyos.utils.network import get_interface_config
base_path = ['protocols', 'static']
vrf_path = ['protocols', 'vrf']
@@ -31,6 +31,8 @@ routes = {
'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.140' : { 'bfd_source' : '192.0.2.10' },
},
'interface' : {
'eth0' : { 'distance' : '130' },
@@ -67,6 +69,8 @@ routes = {
'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' },
@@ -95,6 +99,7 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestProtocolsStatic, cls).setUpClass()
+ cls.cli_delete(cls, ['vrf'])
cls.cli_set(cls, ['vrf', 'name', 'black', 'table', '43210'])
@classmethod
@@ -116,6 +121,7 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
def test_01_static(self):
+ bfd_profile = 'vyos-test'
for route, route_config in routes.items():
route_type = 'route'
if is_ipv6(route):
@@ -132,6 +138,10 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
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', 'profile', bfd_profile ])
+ if 'bfd_source' in next_hop_config:
+ self.cli_set(base + ['next-hop', next_hop, 'bfd', 'multi-hop', 'source', next_hop_config['bfd_source'], 'profile', bfd_profile])
if 'interface' in route_config:
@@ -186,6 +196,10 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
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 profile ' + bfd_profile
+ if 'bfd_source' in next_hop_config:
+ tmp += ' bfd multi-hop source ' + next_hop_config['bfd_source'] + ' profile ' + bfd_profile
if 'disable' in next_hop_config:
self.assertNotIn(tmp, frrconfig)
@@ -433,30 +447,5 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
self.assertIn(tmp, frrconfig)
- def test_04_static_zebra_route_map(self):
- # Implemented because of T3328
- route_map = 'foo-static-in'
- self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit'])
-
- self.cli_set(base_path + ['route-map', route_map])
- # commit changes
- self.cli_commit()
-
- # Verify FRR configuration
- zebra_route_map = f'ip protocol static 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)
-
- self.cli_delete(['policy', 'route-map', route_map])
-
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_static_arp.py b/smoketest/scripts/cli/test_protocols_static_arp.py
index b61d8f854..7f8047249 100755
--- a/smoketest/scripts/cli/test_protocols_static_arp.py
+++ b/smoketest/scripts/cli/test_protocols_static_arp.py
@@ -19,7 +19,7 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
-from vyos.util import cmd
+from vyos.utils.process import cmd
base_path = ['protocols', 'static', 'arp']
interface = 'eth0'
diff --git a/smoketest/scripts/cli/test_qos.py b/smoketest/scripts/cli/test_qos.py
new file mode 100755
index 000000000..3743be788
--- /dev/null
+++ b/smoketest/scripts/cli/test_qos.py
@@ -0,0 +1,547 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import unittest
+
+from json import loads
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSessionError
+from vyos.ifconfig import Section
+from vyos.utils.process import cmd
+
+base_path = ['qos']
+
+def get_tc_qdisc_json(interface) -> dict:
+ tmp = cmd(f'tc -detail -json qdisc show dev {interface}')
+ tmp = loads(tmp)
+ return next(iter(tmp))
+
+def get_tc_filter_json(interface, direction) -> list:
+ if direction not in ['ingress', 'egress']:
+ raise ValueError()
+ tmp = cmd(f'tc -detail -json filter show dev {interface} {direction}')
+ tmp = loads(tmp)
+ return tmp
+
+class TestQoS(VyOSUnitTestSHIM.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ super(TestQoS, 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)
+
+ # We only test on physical interfaces and not VLAN (sub-)interfaces
+ cls._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)
+
+ def tearDown(self):
+ # delete testing SSH config
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ def test_01_cake(self):
+ bandwidth = 1000000
+ rtt = 200
+
+ for interface in self._interfaces:
+ policy_name = f'qos-policy-{interface}'
+ self.cli_set(base_path + ['interface', interface, 'egress', policy_name])
+ self.cli_set(base_path + ['policy', 'cake', policy_name, 'bandwidth', str(bandwidth)])
+ self.cli_set(base_path + ['policy', 'cake', policy_name, 'rtt', str(rtt)])
+ self.cli_set(base_path + ['policy', 'cake', policy_name, 'flow-isolation', 'dual-src-host'])
+
+ bandwidth += 1000000
+ rtt += 20
+
+ # commit changes
+ self.cli_commit()
+
+ bandwidth = 1000000
+ rtt = 200
+ for interface in self._interfaces:
+ tmp = get_tc_qdisc_json(interface)
+
+ self.assertEqual('cake', tmp['kind'])
+ # TC store rates as a 32-bit unsigned integer in bps (Bytes per second)
+ self.assertEqual(int(bandwidth *125), tmp['options']['bandwidth'])
+ # RTT internally is in us
+ self.assertEqual(int(rtt *1000), tmp['options']['rtt'])
+ self.assertEqual('dual-srchost', tmp['options']['flowmode'])
+ self.assertFalse(tmp['options']['ingress'])
+ self.assertFalse(tmp['options']['nat'])
+ self.assertTrue(tmp['options']['raw'])
+
+ bandwidth += 1000000
+ rtt += 20
+
+ def test_02_drop_tail(self):
+ queue_limit = 50
+
+ first = True
+ for interface in self._interfaces:
+ policy_name = f'qos-policy-{interface}'
+
+ if first:
+ self.cli_set(base_path + ['interface', interface, 'ingress', policy_name])
+ # verify() - selected QoS policy on interface only supports egress
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['interface', interface, 'ingress', policy_name])
+ first = False
+
+ self.cli_set(base_path + ['interface', interface, 'egress', policy_name])
+ self.cli_set(base_path + ['policy', 'drop-tail', policy_name, 'queue-limit', str(queue_limit)])
+
+ queue_limit += 10
+
+ # commit changes
+ self.cli_commit()
+
+ queue_limit = 50
+ for interface in self._interfaces:
+ tmp = get_tc_qdisc_json(interface)
+
+ self.assertEqual('pfifo', tmp['kind'])
+ self.assertEqual(queue_limit, tmp['options']['limit'])
+
+ queue_limit += 10
+
+ def test_03_fair_queue(self):
+ hash_interval = 10
+ queue_limit = 5
+ policy_type = 'fair-queue'
+
+ first = True
+ for interface in self._interfaces:
+ policy_name = f'qos-policy-{interface}'
+
+ if first:
+ self.cli_set(base_path + ['interface', interface, 'ingress', policy_name])
+ # verify() - selected QoS policy on interface only supports egress
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['interface', interface, 'ingress', policy_name])
+ first = False
+
+ self.cli_set(base_path + ['interface', interface, 'egress', policy_name])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'hash-interval', str(hash_interval)])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'queue-limit', str(queue_limit)])
+
+ hash_interval += 1
+ queue_limit += 1
+
+ # commit changes
+ self.cli_commit()
+
+ hash_interval = 10
+ queue_limit = 5
+ for interface in self._interfaces:
+ tmp = get_tc_qdisc_json(interface)
+
+ self.assertEqual('sfq', tmp['kind'])
+ self.assertEqual(hash_interval, tmp['options']['perturb'])
+ self.assertEqual(queue_limit, tmp['options']['limit'])
+
+ hash_interval += 1
+ queue_limit += 1
+
+ def test_04_fq_codel(self):
+ policy_type = 'fq-codel'
+ codel_quantum = 1500
+ flows = 512
+ interval = 100
+ queue_limit = 2048
+ target = 5
+
+ first = True
+ for interface in self._interfaces:
+ policy_name = f'qos-policy-{interface}'
+
+ if first:
+ self.cli_set(base_path + ['interface', interface, 'ingress', policy_name])
+ # verify() - selected QoS policy on interface only supports egress
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['interface', interface, 'ingress', policy_name])
+ first = False
+
+ self.cli_set(base_path + ['interface', interface, 'egress', policy_name])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'codel-quantum', str(codel_quantum)])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'flows', str(flows)])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'interval', str(interval)])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'queue-limit', str(queue_limit)])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'target', str(target)])
+
+ codel_quantum += 10
+ flows += 2
+ interval += 10
+ queue_limit += 512
+ target += 1
+
+ # commit changes
+ self.cli_commit()
+
+ codel_quantum = 1500
+ flows = 512
+ interval = 100
+ queue_limit = 2048
+ target = 5
+ for interface in self._interfaces:
+ tmp = get_tc_qdisc_json(interface)
+
+ self.assertEqual('fq_codel', tmp['kind'])
+ self.assertEqual(codel_quantum, tmp['options']['quantum'])
+ self.assertEqual(flows, tmp['options']['flows'])
+ self.assertEqual(queue_limit, tmp['options']['limit'])
+
+ # due to internal rounding we need to substract 1 from interval and target after converting to milliseconds
+ # configuration of:
+ # tc qdisc add dev eth0 root fq_codel quantum 1500 flows 512 interval 100ms limit 2048 target 5ms noecn
+ # results in: tc -j qdisc show dev eth0
+ # [{"kind":"fq_codel","handle":"8046:","root":true,"refcnt":3,"options":{"limit":2048,"flows":512,
+ # "quantum":1500,"target":4999,"interval":99999,"memory_limit":33554432,"drop_batch":64}}]
+ self.assertAlmostEqual(tmp['options']['interval'], interval *1000, delta=1)
+ self.assertAlmostEqual(tmp['options']['target'], target *1000 -1, delta=1)
+
+ codel_quantum += 10
+ flows += 2
+ interval += 10
+ queue_limit += 512
+ target += 1
+
+ def test_05_limiter(self):
+ qos_config = {
+ '1' : {
+ 'bandwidth' : '1000000',
+ 'match4' : {
+ 'ssh' : { 'dport' : '22', },
+ },
+ },
+ '2' : {
+ 'bandwidth' : '1000000',
+ 'match6' : {
+ 'ssh' : { 'dport' : '22', },
+ },
+ },
+ }
+
+ first = True
+ for interface in self._interfaces:
+ policy_name = f'qos-policy-{interface}'
+
+ if first:
+ self.cli_set(base_path + ['interface', interface, 'egress', policy_name])
+ # verify() - selected QoS policy on interface only supports egress
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['interface', interface, 'egress', policy_name])
+ first = False
+
+ self.cli_set(base_path + ['interface', interface, 'ingress', policy_name])
+ # set default bandwidth parameter for all remaining connections
+ self.cli_set(base_path + ['policy', 'limiter', policy_name, 'default', 'bandwidth', '500000'])
+
+ for qos_class, qos_class_config in qos_config.items():
+ qos_class_base = base_path + ['policy', 'limiter', policy_name, 'class', qos_class]
+
+ if 'match4' in qos_class_config:
+ for match, match_config in qos_class_config['match4'].items():
+ if 'dport' in match_config:
+ self.cli_set(qos_class_base + ['match', match, 'ip', 'destination', 'port', match_config['dport']])
+
+ if 'match6' in qos_class_config:
+ for match, match_config in qos_class_config['match6'].items():
+ if 'dport' in match_config:
+ self.cli_set(qos_class_base + ['match', match, 'ipv6', 'destination', 'port', match_config['dport']])
+
+ if 'bandwidth' in qos_class_config:
+ self.cli_set(qos_class_base + ['bandwidth', qos_class_config['bandwidth']])
+
+
+ # commit changes
+ self.cli_commit()
+
+ for interface in self._interfaces:
+ for filter in get_tc_filter_json(interface, 'ingress'):
+ # bail out early if filter has no attached action
+ if 'options' not in filter or 'actions' not in filter['options']:
+ continue
+
+ for qos_class, qos_class_config in qos_config.items():
+ # Every flowid starts with ffff and we encopde the class number after the colon
+ if 'flowid' not in filter['options'] or filter['options']['flowid'] != f'ffff:{qos_class}':
+ continue
+
+ ip_hdr_offset = 20
+ if 'match6' in qos_class_config:
+ ip_hdr_offset = 40
+
+ self.assertEqual(ip_hdr_offset, filter['options']['match']['off'])
+ if 'dport' in match_config:
+ dport = int(match_config['dport'])
+ self.assertEqual(f'{dport:x}', filter['options']['match']['value'])
+
+ def test_06_network_emulator(self):
+ policy_type = 'network-emulator'
+
+ bandwidth = 1000000
+ corruption = 1
+ delay = 2
+ duplicate = 3
+ loss = 4
+ queue_limit = 5
+ reordering = 6
+
+ first = True
+ for interface in self._interfaces:
+ policy_name = f'qos-policy-{interface}'
+
+ if first:
+ self.cli_set(base_path + ['interface', interface, 'ingress', policy_name])
+ # verify() - selected QoS policy on interface only supports egress
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['interface', interface, 'ingress', policy_name])
+ first = False
+
+ self.cli_set(base_path + ['interface', interface, 'egress', policy_name])
+
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'bandwidth', str(bandwidth)])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'corruption', str(corruption)])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'delay', str(delay)])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'duplicate', str(duplicate)])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'loss', str(loss)])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'queue-limit', str(queue_limit)])
+ self.cli_set(base_path + ['policy', policy_type, policy_name, 'reordering', str(reordering)])
+
+ bandwidth += 1000000
+ corruption += 1
+ delay += 1
+ duplicate +=1
+ loss += 1
+ queue_limit += 1
+ reordering += 1
+
+ # commit changes
+ self.cli_commit()
+
+ bandwidth = 1000000
+ corruption = 1
+ delay = 2
+ duplicate = 3
+ loss = 4
+ queue_limit = 5
+ reordering = 6
+ for interface in self._interfaces:
+ tmp = get_tc_qdisc_json(interface)
+ self.assertEqual('netem', tmp['kind'])
+
+ self.assertEqual(int(bandwidth *125), tmp['options']['rate']['rate'])
+ # values are in %
+ self.assertEqual(corruption/100, tmp['options']['corrupt']['corrupt'])
+ self.assertEqual(duplicate/100, tmp['options']['duplicate']['duplicate'])
+ self.assertEqual(loss/100, tmp['options']['loss-random']['loss'])
+ self.assertEqual(reordering/100, tmp['options']['reorder']['reorder'])
+ self.assertEqual(delay/1000, tmp['options']['delay']['delay'])
+
+ self.assertEqual(queue_limit, tmp['options']['limit'])
+
+ bandwidth += 1000000
+ corruption += 1
+ delay += 1
+ duplicate += 1
+ loss += 1
+ queue_limit += 1
+ reordering += 1
+
+ def test_07_priority_queue(self):
+ priorities = ['1', '2', '3', '4', '5']
+
+ first = True
+ for interface in self._interfaces:
+ policy_name = f'qos-policy-{interface}'
+
+ if first:
+ self.cli_set(base_path + ['interface', interface, 'ingress', policy_name])
+ # verify() - selected QoS policy on interface only supports egress
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['interface', interface, 'ingress', policy_name])
+ first = False
+
+ self.cli_set(base_path + ['interface', interface, 'egress', policy_name])
+ self.cli_set(base_path + ['policy', 'priority-queue', policy_name, 'default', 'queue-limit', '10'])
+
+ for priority in priorities:
+ prio_base = base_path + ['policy', 'priority-queue', policy_name, 'class', priority]
+ self.cli_set(prio_base + ['match', f'prio-{priority}', 'ip', 'destination', 'port', str(1000 + int(priority))])
+
+ # commit changes
+ self.cli_commit()
+
+ def test_08_random_detect(self):
+ self.skipTest('tc returns invalid JSON here - needs iproute2 fix')
+ bandwidth = 5000
+
+ first = True
+ for interface in self._interfaces:
+ policy_name = f'qos-policy-{interface}'
+
+ if first:
+ self.cli_set(base_path + ['interface', interface, 'ingress', policy_name])
+ # verify() - selected QoS policy on interface only supports egress
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['interface', interface, 'ingress', policy_name])
+ first = False
+
+ self.cli_set(base_path + ['interface', interface, 'egress', policy_name])
+ self.cli_set(base_path + ['policy', 'random-detect', policy_name, 'bandwidth', str(bandwidth)])
+
+ bandwidth += 1000
+
+ # commit changes
+ self.cli_commit()
+
+ bandwidth = 5000
+ for interface in self._interfaces:
+ tmp = get_tc_qdisc_json(interface)
+ import pprint
+ pprint.pprint(tmp)
+
+ def test_09_rate_control(self):
+ bandwidth = 5000
+ burst = 20
+ latency = 5
+
+ first = True
+ for interface in self._interfaces:
+ policy_name = f'qos-policy-{interface}'
+
+ if first:
+ self.cli_set(base_path + ['interface', interface, 'ingress', policy_name])
+ # verify() - selected QoS policy on interface only supports egress
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['interface', interface, 'ingress', policy_name])
+ first = False
+
+ self.cli_set(base_path + ['interface', interface, 'egress', policy_name])
+ self.cli_set(base_path + ['policy', 'rate-control', policy_name, 'bandwidth', str(bandwidth)])
+ self.cli_set(base_path + ['policy', 'rate-control', policy_name, 'burst', str(burst)])
+ self.cli_set(base_path + ['policy', 'rate-control', policy_name, 'latency', str(latency)])
+
+ bandwidth += 1000
+ burst += 5
+ latency += 1
+ # commit changes
+ self.cli_commit()
+
+ bandwidth = 5000
+ burst = 20
+ latency = 5
+ for interface in self._interfaces:
+ tmp = get_tc_qdisc_json(interface)
+
+ self.assertEqual('tbf', tmp['kind'])
+ self.assertEqual(0, tmp['options']['mpu'])
+ # TC store rates as a 32-bit unsigned integer in bps (Bytes per second)
+ self.assertEqual(int(bandwidth * 125), tmp['options']['rate'])
+
+ bandwidth += 1000
+ burst += 5
+ latency += 1
+
+ def test_10_round_robin(self):
+ qos_config = {
+ '1' : {
+ 'match4' : {
+ 'ssh' : { 'dport' : '22', },
+ },
+ },
+ '2' : {
+ 'match6' : {
+ 'ssh' : { 'dport' : '22', },
+ },
+ },
+ }
+
+ first = True
+ for interface in self._interfaces:
+ policy_name = f'qos-policy-{interface}'
+
+ if first:
+ self.cli_set(base_path + ['interface', interface, 'ingress', policy_name])
+ # verify() - selected QoS policy on interface only supports egress
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['interface', interface, 'ingress', policy_name])
+ first = False
+
+ self.cli_set(base_path + ['interface', interface, 'egress', policy_name])
+
+ for qos_class, qos_class_config in qos_config.items():
+ qos_class_base = base_path + ['policy', 'round-robin', policy_name, 'class', qos_class]
+
+ if 'match4' in qos_class_config:
+ for match, match_config in qos_class_config['match4'].items():
+ if 'dport' in match_config:
+ self.cli_set(qos_class_base + ['match', match, 'ip', 'destination', 'port', match_config['dport']])
+
+ if 'match6' in qos_class_config:
+ for match, match_config in qos_class_config['match6'].items():
+ if 'dport' in match_config:
+ self.cli_set(qos_class_base + ['match', match, 'ipv6', 'destination', 'port', match_config['dport']])
+
+
+ # commit changes
+ self.cli_commit()
+
+ for interface in self._interfaces:
+ import pprint
+ tmp = get_tc_qdisc_json(interface)
+ self.assertEqual('drr', tmp['kind'])
+
+ for filter in get_tc_filter_json(interface, 'ingress'):
+ # bail out early if filter has no attached action
+ if 'options' not in filter or 'actions' not in filter['options']:
+ continue
+
+ for qos_class, qos_class_config in qos_config.items():
+ # Every flowid starts with ffff and we encopde the class number after the colon
+ if 'flowid' not in filter['options'] or filter['options']['flowid'] != f'ffff:{qos_class}':
+ continue
+
+ ip_hdr_offset = 20
+ if 'match6' in qos_class_config:
+ ip_hdr_offset = 40
+
+ self.assertEqual(ip_hdr_offset, filter['options']['match']['off'])
+ if 'dport' in match_config:
+ dport = int(match_config['dport'])
+ self.assertEqual(f'{dport:x}', filter['options']['match']['value'])
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_dhcp-relay.py b/smoketest/scripts/cli/test_service_dhcp-relay.py
index bbfd9e032..59c4b59a9 100755
--- a/smoketest/scripts/cli/test_service_dhcp-relay.py
+++ b/smoketest/scripts/cli/test_service_dhcp-relay.py
@@ -20,8 +20,8 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
PROCESS_NAME = 'dhcrelay'
RELAY_CONF = '/run/dhcp-relay/dhcrelay.conf'
@@ -82,6 +82,43 @@ class TestServiceDHCPRelay(VyOSUnitTestSHIM.TestCase):
# Check for running process
self.assertTrue(process_named_running(PROCESS_NAME))
+ def test_relay_interfaces(self):
+ max_size = '800'
+ hop_count = '20'
+ agents_packets = 'append'
+ servers = ['192.0.2.1', '192.0.2.2']
+ listen_iface = 'eth0'
+ up_iface = 'eth1'
+
+ self.cli_set(base_path + ['interface', up_iface])
+ self.cli_set(base_path + ['listen-interface', listen_iface])
+ # check validate() - backward interface plus listen_interface
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['interface'])
+
+ self.cli_set(base_path + ['upstream-interface', up_iface])
+
+ for server in servers:
+ self.cli_set(base_path + ['server', server])
+
+ # commit changes
+ self.cli_commit()
+
+ # Check configured port
+ config = read_file(RELAY_CONF)
+
+ # Test configured relay interfaces
+ self.assertIn(f'-id {listen_iface}', config)
+ self.assertIn(f'-iu {up_iface}', config)
+
+ # Test relay servers
+ for server in servers:
+ self.assertIn(f' {server}', config)
+
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_dhcp-server.py b/smoketest/scripts/cli/test_service_dhcp-server.py
index 9c9d6d9f1..093e43494 100755
--- a/smoketest/scripts/cli/test_service_dhcp-server.py
+++ b/smoketest/scripts/cli/test_service_dhcp-server.py
@@ -19,8 +19,8 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
from vyos.template import address_from_cidr
from vyos.template import inc_ip
from vyos.template import dec_ip
@@ -102,16 +102,17 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
def test_dhcp_single_pool_options(self):
shared_net_name = 'SMOKE-0815'
- range_0_start = inc_ip(subnet, 10)
- range_0_stop = inc_ip(subnet, 20)
- smtp_server = '1.2.3.4'
- time_server = '4.3.2.1'
- tftp_server = 'tftp.vyos.io'
- search_domains = ['foo.vyos.net', 'bar.vyos.net']
- bootfile_name = 'vyos'
- bootfile_server = '192.0.2.1'
- wpad = 'http://wpad.vyos.io/foo/bar'
- server_identifier = bootfile_server
+ range_0_start = inc_ip(subnet, 10)
+ range_0_stop = inc_ip(subnet, 20)
+ smtp_server = '1.2.3.4'
+ time_server = '4.3.2.1'
+ tftp_server = 'tftp.vyos.io'
+ search_domains = ['foo.vyos.net', 'bar.vyos.net']
+ bootfile_name = 'vyos'
+ bootfile_server = '192.0.2.1'
+ wpad = 'http://wpad.vyos.io/foo/bar'
+ server_identifier = bootfile_server
+ ipv6_only_preferred = '300'
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
# we use the first subnet IP address as default gateway
@@ -132,6 +133,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
self.cli_set(pool + ['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])
# check validate() - No DHCP address range or active static-mapping set
with self.assertRaises(ConfigSessionError):
@@ -169,6 +171,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'max-lease-time 86400;', config)
self.assertIn(f'range {range_0_start} {range_0_stop};', config)
self.assertIn(f'set shared-networkname = "{shared_net_name}";', config)
+ self.assertIn(f'option rfc8925-ipv6-only-preferred {ipv6_only_preferred};', config)
# weird syntax for those static routes
self.assertIn(f'option rfc3442-static-route 24,10,0,0,192,0,2,1, 0,192,0,2,1;', config)
diff --git a/smoketest/scripts/cli/test_service_dhcpv6-relay.py b/smoketest/scripts/cli/test_service_dhcpv6-relay.py
index fc206435b..4487f4b0f 100755
--- a/smoketest/scripts/cli/test_service_dhcpv6-relay.py
+++ b/smoketest/scripts/cli/test_service_dhcpv6-relay.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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
@@ -21,8 +21,8 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.template import address_from_cidr
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
PROCESS_NAME = 'dhcrelay'
RELAY_CONF = '/run/dhcp-relay/dhcrelay6.conf'
@@ -34,22 +34,30 @@ listen_addr = '2001:db8:ffff::1/64'
interfaces = []
class TestServiceDHCPv6Relay(VyOSUnitTestSHIM.TestCase):
- def setUp(self):
- for tmp in interfaces:
+ @classmethod
+ def setUpClass(cls):
+ super(TestServiceDHCPv6Relay, 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)
+
+ for tmp in Section.interfaces('ethernet', vlan=False):
+ interfaces.append(tmp)
listen = listen_addr
if tmp == upstream_if:
listen = upstream_if_addr
- self.cli_set(['interfaces', 'ethernet', tmp, 'address', listen])
+ cls.cli_set(cls, ['interfaces', 'ethernet', tmp, 'address', listen])
- def tearDown(self):
- self.cli_delete(base_path)
+ @classmethod
+ def tearDownClass(cls):
for tmp in interfaces:
listen = listen_addr
if tmp == upstream_if:
listen = upstream_if_addr
- self.cli_delete(['interfaces', 'ethernet', tmp, 'address', listen])
+ cls.cli_delete(cls, ['interfaces', 'ethernet', tmp, 'address', listen])
- self.cli_commit()
+ super(TestServiceDHCPv6Relay, cls).tearDownClass()
def test_relay_default(self):
dhcpv6_server = '2001:db8::ffff'
@@ -100,9 +108,5 @@ class TestServiceDHCPv6Relay(VyOSUnitTestSHIM.TestCase):
self.assertTrue(process_named_running(PROCESS_NAME))
if __name__ == '__main__':
- for tmp in Section.interfaces('ethernet'):
- if '.' not in tmp:
- interfaces.append(tmp)
-
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_dhcpv6-server.py b/smoketest/scripts/cli/test_service_dhcpv6-server.py
index f83453323..4d9dabc3f 100755
--- a/smoketest/scripts/cli/test_service_dhcpv6-server.py
+++ b/smoketest/scripts/cli/test_service_dhcpv6-server.py
@@ -20,8 +20,8 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.template import inc_ip
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
PROCESS_NAME = 'dhcpd'
DHCPD_CONF = '/run/dhcp-server/dhcpdv6.conf'
diff --git a/smoketest/scripts/cli/test_service_dns_dynamic.py b/smoketest/scripts/cli/test_service_dns_dynamic.py
index 90d10d40b..ee8a07b37 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-2020 VyOS maintainers and contributors
+# Copyright (C) 2019-2023 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
@@ -14,148 +14,179 @@
# 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
+import tempfile
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import cmd
+from vyos.utils.process import process_running
-PROCESS_NAME = 'ddclient'
DDCLIENT_CONF = '/run/ddclient/ddclient.conf'
+DDCLIENT_PID = '/run/ddclient/ddclient.pid'
base_path = ['service', 'dns', 'dynamic']
hostname = 'test.ddns.vyos.io'
+zone = 'vyos.io'
+password = 'paSS_@4ord'
interface = 'eth0'
-def get_config_value(key):
- tmp = cmd(f'sudo cat {DDCLIENT_CONF}')
- tmp = re.findall(r'\n?{}=+(.*)'.format(key), tmp)
- tmp = tmp[0].rstrip(',')
- return tmp
-
class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
+ # Check for running process
+ self.assertTrue(process_running(DDCLIENT_PID))
+
# Delete DDNS configuration
self.cli_delete(base_path)
self.cli_commit()
- def test_dyndns_service(self):
- ddns = ['interface', interface, 'service']
- services = ['cloudflare', 'afraid', 'dyndns', 'zoneedit']
+ # PID file must no londer exist after process exited
+ self.assertFalse(os.path.exists(DDCLIENT_PID))
- for service in services:
- user = 'vyos_user'
- password = 'vyos_pass'
- zone = 'vyos.io'
+ # IPv4 standard DDNS service configuration
+ def test_01_dyndns_service_standard(self):
+ ddns = ['address', interface, 'service']
+ services = {'cloudflare': {'protocol': 'cloudflare'},
+ 'freedns': {'protocol': 'freedns', 'username': 'vyos_user'},
+ 'zoneedit': {'protocol': 'zoneedit1', 'username': 'vyos_user'}}
+
+ for svc, details in services.items():
+ # Always start with a clean CLI instance
self.cli_delete(base_path)
- self.cli_set(base_path + ddns + [service, 'host-name', hostname])
- self.cli_set(base_path + ddns + [service, 'login', user])
- self.cli_set(base_path + ddns + [service, 'password', password])
- self.cli_set(base_path + ddns + [service, 'zone', zone])
+
+ self.cli_set(base_path + ddns + [svc, 'host-name', hostname])
+ self.cli_set(base_path + ddns + [svc, 'password', password])
+ self.cli_set(base_path + ddns + [svc, 'zone', zone])
+ for opt, value in details.items():
+ self.cli_set(base_path + ddns + [svc, opt, value])
# commit changes
- if service == 'cloudflare':
- self.cli_commit()
+ if details['protocol'] == 'cloudflare':
+ pass
else:
- # zone option only works on cloudflare, an exception is raised
- # for all others
+ # zone option does not work on all protocols, an exception is
+ # raised for all others
with self.assertRaises(ConfigSessionError):
self.cli_commit()
- self.cli_delete(base_path + ddns + [service, 'zone', 'vyos.io'])
- # commit changes again - now it should work
- self.cli_commit()
-
- # we can only read the configuration file when we operate as 'root'
- protocol = get_config_value('protocol')
- login = get_config_value('login')
- pwd = get_config_value('password')
-
- # some services need special treatment
- protoname = service
- if service == 'cloudflare':
- tmp = get_config_value('zone')
- self.assertTrue(tmp == zone)
- elif service == 'afraid':
- protoname = 'freedns'
- elif service == 'dyndns':
- protoname = 'dyndns2'
- elif service == 'zoneedit':
- protoname = 'zoneedit1'
-
- self.assertTrue(protocol == protoname)
- self.assertTrue(login == user)
- self.assertTrue(pwd == "'" + password + "'")
-
- # Check for running process
- self.assertTrue(process_named_running(PROCESS_NAME))
-
- def test_dyndns_rfc2136(self):
- # Check if DDNS service can be configured and runs
- ddns = ['interface', interface, 'rfc2136', 'vyos']
- ddns_key_file = '/config/auth/my.key'
-
- self.cli_set(base_path + ddns + ['key', ddns_key_file])
- self.cli_set(base_path + ddns + ['record', 'test.ddns.vyos.io'])
- self.cli_set(base_path + ddns + ['server', 'ns1.vyos.io'])
- self.cli_set(base_path + ddns + ['ttl', '300'])
- self.cli_set(base_path + ddns + ['zone', 'vyos.io'])
+ self.cli_delete(base_path + ddns + [svc, 'zone', zone])
- # ensure an exception will be raised as no key is present
- if os.path.exists(ddns_key_file):
- os.unlink(ddns_key_file)
-
- # check validate() - the key file does not exist yet
- with self.assertRaises(ConfigSessionError):
+ # commit changes
self.cli_commit()
- with open(ddns_key_file, 'w') as f:
- f.write('S3cretKey')
-
- # commit changes
- self.cli_commit()
-
- # TODO: inspect generated configuration file
-
- # Check for running process
- self.assertTrue(process_named_running(PROCESS_NAME))
-
- def test_dyndns_ipv6(self):
- ddns = ['interface', interface, 'service', 'dynv6']
+ # Check the generating config parameters
+ ddclient_conf = cmd(f'sudo cat {DDCLIENT_CONF}')
+ # default value 300 seconds
+ self.assertIn(f'daemon=300', ddclient_conf)
+ self.assertIn(f'use=if', ddclient_conf)
+ self.assertIn(f'if={interface}', ddclient_conf)
+ self.assertIn(f'password={password}', ddclient_conf)
+
+ for opt in details.keys():
+ if opt == 'username':
+ login = details[opt]
+ self.assertIn(f'login={login}', ddclient_conf)
+ else:
+ tmp = details[opt]
+ self.assertIn(f'{opt}={tmp}', ddclient_conf)
+
+ # IPv6 only DDNS service configuration
+ def test_02_dyndns_service_ipv6(self):
+ timeout = '60'
+ ddns = ['address', interface, 'service', 'dynv6']
proto = 'dyndns2'
user = 'none'
password = 'paSS_4ord'
srv = 'ddns.vyos.io'
+ ip_version = 'ipv6'
- self.cli_set(base_path + ['interface', interface, 'ipv6-enable'])
- self.cli_set(base_path + ddns + ['host-name', hostname])
- self.cli_set(base_path + ddns + ['login', user])
- self.cli_set(base_path + ddns + ['password', password])
+ self.cli_set(base_path + ['timeout', timeout])
+ self.cli_set(base_path + ddns + ['ip-version', ip_version])
self.cli_set(base_path + ddns + ['protocol', proto])
self.cli_set(base_path + ddns + ['server', srv])
+ self.cli_set(base_path + ddns + ['username', user])
+ self.cli_set(base_path + ddns + ['password', password])
+ self.cli_set(base_path + ddns + ['host-name', hostname])
# commit changes
self.cli_commit()
- # Check for running process
- self.assertTrue(process_named_running(PROCESS_NAME))
-
- protocol = get_config_value('protocol')
- login = get_config_value('login')
- pwd = get_config_value('password')
- server = get_config_value('server')
- usev6 = get_config_value('usev6')
-
- # Check some generating config parameters
- self.assertEqual(protocol, proto)
- self.assertEqual(login, user)
- self.assertEqual(pwd, f"'{password}'")
- self.assertEqual(server, srv)
- self.assertEqual(usev6, f"if, if={interface}")
+ # Check the generating config parameters
+ ddclient_conf = cmd(f'sudo cat {DDCLIENT_CONF}')
+ self.assertIn(f'daemon={timeout}', ddclient_conf)
+ self.assertIn(f'usev6=ifv6', ddclient_conf)
+ self.assertIn(f'ifv6={interface}', ddclient_conf)
+ self.assertIn(f'protocol={proto}', ddclient_conf)
+ self.assertIn(f'server={srv}', ddclient_conf)
+ self.assertIn(f'login={user}', ddclient_conf)
+ self.assertIn(f'password={password}', ddclient_conf)
+
+ # IPv4+IPv6 dual DDNS service configuration
+ def test_03_dyndns_service_dual_stack(self):
+ ddns = ['address', interface, 'service']
+ services = {'cloudflare': {'protocol': 'cloudflare', 'zone': 'vyos.io'},
+ 'freedns': {'protocol': 'freedns', 'username': 'vyos_user'}}
+ password = 'vyos_pass'
+ ip_version = 'both'
+
+ for svc, details in services.items():
+ # Always start with a clean CLI instance
+ self.cli_delete(base_path)
+
+ self.cli_set(base_path + ddns + [svc, 'host-name', hostname])
+ self.cli_set(base_path + ddns + [svc, 'password', password])
+ self.cli_set(base_path + ddns + [svc, 'ip-version', ip_version])
+ for opt, value in details.items():
+ self.cli_set(base_path + ddns + [svc, opt, value])
+
+ # commit changes
+ self.cli_commit()
+
+ # Check the generating config parameters
+ ddclient_conf = cmd(f'sudo cat {DDCLIENT_CONF}')
+ self.assertIn(f'usev4=ifv4', ddclient_conf)
+ self.assertIn(f'usev6=ifv6', ddclient_conf)
+ self.assertIn(f'ifv4={interface}', ddclient_conf)
+ self.assertIn(f'ifv6={interface}', ddclient_conf)
+ self.assertIn(f'password={password}', ddclient_conf)
+
+ for opt in details.keys():
+ if opt == 'username':
+ login = details[opt]
+ self.assertIn(f'login={login}', ddclient_conf)
+ else:
+ tmp = details[opt]
+ self.assertIn(f'{opt}={tmp}', ddclient_conf)
+
+ def test_04_dyndns_rfc2136(self):
+ # Check if DDNS service can be configured and runs
+ ddns = ['address', interface, 'rfc2136', 'vyos']
+ srv = 'ns1.vyos.io'
+ zone = 'vyos.io'
+ ttl = '300'
+
+ with tempfile.NamedTemporaryFile(prefix='/config/auth/') as key_file:
+ key_file.write(b'S3cretKey')
+
+ self.cli_set(base_path + ddns + ['server', srv])
+ self.cli_set(base_path + ddns + ['zone', zone])
+ self.cli_set(base_path + ddns + ['key', key_file.name])
+ self.cli_set(base_path + ddns + ['ttl', ttl])
+ self.cli_set(base_path + ddns + ['host-name', hostname])
+
+ # commit changes
+ self.cli_commit()
+
+ # Check some generating config parameters
+ ddclient_conf = cmd(f'sudo cat {DDCLIENT_CONF}')
+ self.assertIn(f'use=if', ddclient_conf)
+ self.assertIn(f'if={interface}', ddclient_conf)
+ self.assertIn(f'protocol=nsupdate', ddclient_conf)
+ self.assertIn(f'server={srv}', ddclient_conf)
+ self.assertIn(f'zone={zone}', ddclient_conf)
+ self.assertIn(f'password={key_file.name}', ddclient_conf)
+ self.assertIn(f'ttl={ttl}', ddclient_conf)
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_dns_forwarding.py b/smoketest/scripts/cli/test_service_dns_forwarding.py
index fe2682d50..bc50a4ffe 100755
--- a/smoketest/scripts/cli/test_service_dns_forwarding.py
+++ b/smoketest/scripts/cli/test_service_dns_forwarding.py
@@ -20,8 +20,9 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import read_file
-from vyos.util import process_named_running
+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'
@@ -111,6 +112,10 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
tmp = get_config_value('serve-rfc1918')
self.assertEqual(tmp, 'yes')
+ # verify default port configuration
+ tmp = get_config_value('local-port')
+ self.assertEqual(tmp, '53')
+
def test_dnssec(self):
# DNSSEC option testing
@@ -137,15 +142,20 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
for address in listen_adress:
self.cli_set(base_path + ['listen-address', address])
- nameservers = ['192.0.2.1', '192.0.2.2']
- for nameserver in nameservers:
- self.cli_set(base_path + ['name-server', nameserver])
+ 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:
+ self.cli_set(base_path + ['name-server', h, 'port', p['port']])
+ else:
+ self.cli_set(base_path + ['name-server', h])
# commit changes
self.cli_commit()
tmp = get_config_value(r'\+.', file=FORWARD_FILE)
- self.assertEqual(tmp, ', '.join(nameservers))
+ canonical_entries = [(lambda h, p: f"{bracketize_ipv6(h)}:{p['port'] if 'port' in p else 53}")(h, p)
+ for (h, p) in nameservers.items()]
+ self.assertEqual(tmp, ', '.join(canonical_entries))
# Do not use local /etc/hosts file in name resolution
# default: yes
@@ -159,10 +169,13 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['listen-address', address])
domains = ['vyos.io', 'vyos.net', 'vyos.com']
- nameservers = ['192.0.2.1', '192.0.2.2']
+ nameservers = {'192.0.2.1': {}, '192.0.2.2': {'port': '53'}, '2001:db8::1': {'port': '853'}}
for domain in domains:
- for nameserver in nameservers:
- self.cli_set(base_path + ['domain', domain, 'server', nameserver])
+ for h,p in nameservers.items():
+ if 'port' in p:
+ self.cli_set(base_path + ['domain', domain, 'name-server', h, 'port', p['port']])
+ else:
+ self.cli_set(base_path + ['domain', domain, 'name-server', h])
# Test 'recursion-desired' flag for only one domain
if domain == domains[0]:
@@ -182,7 +195,9 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
if domain == domains[0]: key =f'\+{domain}'
else: key =f'{domain}'
tmp = get_config_value(key, file=FORWARD_FILE)
- self.assertEqual(tmp, ', '.join(nameservers))
+ canonical_entries = [(lambda h, p: f"{bracketize_ipv6(h)}:{p['port'] if 'port' in p else 53}")(h, p)
+ for (h, p) in nameservers.items()]
+ self.assertEqual(tmp, ', '.join(canonical_entries))
# Test 'negative trust anchor' flag for the second domain only
if domain == domains[1]:
@@ -224,5 +239,21 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
tmp = get_config_value('dns64-prefix')
self.assertEqual(tmp, dns_prefix)
+ 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']:
+ 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)
+
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 0f4b1393c..1ae5c104c 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-2022 VyOS maintainers and contributors
+# Copyright (C) 2019-2023 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
@@ -21,8 +21,8 @@ from urllib3.exceptions import InsecureRequestWarning
from base_vyostest_shim import VyOSUnitTestSHIM
from base_vyostest_shim import ignore_warning
-from vyos.util import read_file
-from vyos.util import run
+from vyos.utils.file import read_file
+from vyos.utils.process import run
base_path = ['service', 'https']
pki_base = ['pki']
@@ -193,7 +193,8 @@ class TestHTTPSService(VyOSUnitTestSHIM.TestCase):
"""
r = request('POST', graphql_url, verify=False, headers=headers, json={'query': query_no_key})
- self.assertEqual(r.status_code, 400)
+ success = r.json()['data']['SystemStatus']['success']
+ self.assertFalse(success)
# GraphQL token authentication test: request token; pass in header
# of query.
diff --git a/smoketest/scripts/cli/test_service_ids.py b/smoketest/scripts/cli/test_service_ids.py
index dcf2bcefe..91b056eea 100755
--- a/smoketest/scripts/cli/test_service_ids.py
+++ b/smoketest/scripts/cli/test_service_ids.py
@@ -20,8 +20,8 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
PROCESS_NAME = 'fastnetmon'
FASTNETMON_CONF = '/run/fastnetmon/fastnetmon.conf'
diff --git a/smoketest/scripts/cli/test_service_ipoe-server.py b/smoketest/scripts/cli/test_service_ipoe-server.py
index bdab35834..4dd3e761c 100755
--- a/smoketest/scripts/cli/test_service_ipoe-server.py
+++ b/smoketest/scripts/cli/test_service_ipoe-server.py
@@ -19,13 +19,20 @@ import unittest
from base_accel_ppp_test import BasicAccelPPPTest
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
+from vyos.utils.process import cmd
from configparser import ConfigParser
ac_name = 'ACN'
interface = 'eth0'
+
+def getConfig(string, end='cli'):
+ command = f'cat /run/accel-pppd/ipoe.conf | sed -n "/^{string}/,/^{end}/p"'
+ out = cmd(command)
+ return out
+
+
class TestServiceIPoEServer(BasicAccelPPPTest.TestCase):
@classmethod
def setUpClass(cls):
@@ -86,6 +93,92 @@ class TestServiceIPoEServer(BasicAccelPPPTest.TestCase):
tmp = re.findall(regex, tmp)
self.assertTrue(tmp)
+ def test_accel_named_pool(self):
+ first_pool = 'VyOS-pool1'
+ first_subnet = '192.0.2.0/25'
+ first_gateway = '192.0.2.1'
+ second_pool = 'Vyos-pool2'
+ second_subnet = '203.0.113.0/25'
+ second_gateway = '203.0.113.1'
+
+ self.set(['authentication', 'mode', 'noauth'])
+ self.set(['client-ip-pool', 'name', first_pool, 'gateway-address', first_gateway])
+ self.set(['client-ip-pool', 'name', first_pool, 'subnet', first_subnet])
+ self.set(['client-ip-pool', 'name', second_pool, 'gateway-address', second_gateway])
+ self.set(['client-ip-pool', 'name', second_pool, 'subnet', second_subnet])
+ self.set(['interface', interface])
+
+ # commit changes
+ self.cli_commit()
+
+
+ # Validate configuration values
+ conf = ConfigParser(allow_no_value=True, delimiters='=', strict=False)
+ conf.read(self._config_file)
+
+ self.assertTrue(conf['ipoe']['interface'], f'{interface},shared=1,mode=L2,ifcfg=1,start=dhcpv4,ipv6=1')
+ self.assertTrue(conf['ipoe']['noauth'], '1')
+ self.assertTrue(conf['ipoe']['ip-pool'], first_pool)
+ self.assertTrue(conf['ipoe']['ip-pool'], second_pool)
+ self.assertTrue(conf['ipoe']['gw-ip-address'], f'{first_gateway}/25')
+ self.assertTrue(conf['ipoe']['gw-ip-address'], f'{second_gateway}/25')
+
+ config = getConfig('[ip-pool]')
+ pool_config = f'''{second_subnet},name={second_pool}
+{first_subnet},name={first_pool}
+gw-ip-address={second_gateway}/25
+gw-ip-address={first_gateway}/25'''
+ self.assertIn(pool_config, config)
+
+
+ def test_accel_next_pool(self):
+ first_pool = 'VyOS-pool1'
+ first_subnet = '192.0.2.0/25'
+ first_gateway = '192.0.2.1'
+ second_pool = 'Vyos-pool2'
+ second_subnet = '203.0.113.0/25'
+ second_gateway = '203.0.113.1'
+ third_pool = 'Vyos-pool3'
+ third_subnet = '198.51.100.0/24'
+ third_gateway = '198.51.100.1'
+
+ self.set(['authentication', 'mode', 'noauth'])
+ self.set(['client-ip-pool', 'name', first_pool, 'gateway-address', first_gateway])
+ self.set(['client-ip-pool', 'name', first_pool, 'subnet', first_subnet])
+ self.set(['client-ip-pool', 'name', first_pool, 'next-pool', second_pool])
+ self.set(['client-ip-pool', 'name', second_pool, 'gateway-address', second_gateway])
+ self.set(['client-ip-pool', 'name', second_pool, 'subnet', second_subnet])
+ self.set(['client-ip-pool', 'name', second_pool, 'next-pool', third_pool])
+ self.set(['client-ip-pool', 'name', third_pool, 'gateway-address', third_gateway])
+ self.set(['client-ip-pool', 'name', third_pool, 'subnet', third_subnet])
+ self.set(['interface', interface])
+
+ # commit changes
+ self.cli_commit()
+
+
+ # Validate configuration values
+ conf = ConfigParser(allow_no_value=True, delimiters='=', strict=False)
+ conf.read(self._config_file)
+
+ self.assertTrue(conf['ipoe']['interface'], f'{interface},shared=1,mode=L2,ifcfg=1,start=dhcpv4,ipv6=1')
+ self.assertTrue(conf['ipoe']['noauth'], '1')
+ self.assertTrue(conf['ipoe']['ip-pool'], first_pool)
+ self.assertTrue(conf['ipoe']['gw-ip-address'], f'{first_gateway}/25')
+ self.assertTrue(conf['ipoe']['gw-ip-address'], f'{second_gateway}/25')
+ self.assertTrue(conf['ipoe']['gw-ip-address'], f'{third_gateway}/24')
+
+ config = getConfig('[ip-pool]')
+ # T5099 required specific order
+ pool_config = f'''{third_subnet},name={third_pool}
+{second_subnet},name={second_pool},next={third_pool}
+{first_subnet},name={first_pool},next={second_pool}
+gw-ip-address={third_gateway}/24
+gw-ip-address={second_gateway}/25
+gw-ip-address={first_gateway}/25'''
+ self.assertIn(pool_config, config)
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_lldp.py b/smoketest/scripts/cli/test_service_lldp.py
index 439c96c33..ee26844ab 100755
--- a/smoketest/scripts/cli/test_service_lldp.py
+++ b/smoketest/scripts/cli/test_service_lldp.py
@@ -22,9 +22,9 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
-from vyos.util import cmd
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import cmd
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
from vyos.version import get_version_data
PROCESS_NAME = 'lldpd'
diff --git a/smoketest/scripts/cli/test_service_mdns-repeater.py b/smoketest/scripts/cli/test_service_mdns-repeater.py
index f99a98da1..9a9839025 100755
--- a/smoketest/scripts/cli/test_service_mdns-repeater.py
+++ b/smoketest/scripts/cli/test_service_mdns-repeater.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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
@@ -18,30 +18,57 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
-from vyos.util import process_named_running
+from configparser import ConfigParser
+from vyos.utils.process import process_named_running
base_path = ['service', 'mdns', 'repeater']
intf_base = ['interfaces', 'dummy']
+config_file = '/run/avahi-daemon/avahi-daemon.conf'
+
class TestServiceMDNSrepeater(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
+ # Check for running process
+ self.assertTrue(process_named_running('avahi-daemon'))
+
self.cli_delete(base_path)
self.cli_delete(intf_base + ['dum10'])
self.cli_delete(intf_base + ['dum20'])
self.cli_commit()
+ # Check that there is no longer a running process
+ self.assertFalse(process_named_running('avahi-daemon'))
+
def test_service(self):
- # Service required a configured IP address on the interface
+ # mDNS browsing domains in addition to the default one (local)
+ domains = ['dom1.home.arpa', 'dom2.home.arpa']
+
+ # mDNS services to be repeated
+ services = ['_ipp._tcp', '_smb._tcp', '_ssh._tcp']
+ # Service required a configured IP address on the interface
self.cli_set(intf_base + ['dum10', 'address', '192.0.2.1/30'])
self.cli_set(intf_base + ['dum20', 'address', '192.0.2.5/30'])
self.cli_set(base_path + ['interface', 'dum10'])
self.cli_set(base_path + ['interface', 'dum20'])
+
+ for domain in domains:
+ self.cli_set(base_path + ['browse-domain', domain])
+
+ for service in services:
+ self.cli_set(base_path + ['allow-service', service])
+
self.cli_commit()
- # Check for running process
- self.assertTrue(process_named_running('avahi-daemon'))
+ # Validate configuration values
+ conf = ConfigParser(delimiters='=')
+ conf.read(config_file)
+
+ self.assertEqual(conf['server']['allow-interfaces'], 'dum10, dum20')
+ self.assertEqual(conf['server']['browse-domains'], ', '.join(domains))
+ self.assertEqual(conf['reflector']['enable-reflector'], 'yes')
+ self.assertEqual(conf['reflector']['reflect-filters'], ', '.join(services))
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_monitoring_telegraf.py b/smoketest/scripts/cli/test_service_monitoring_telegraf.py
index ed486c3b9..f3355b735 100755
--- a/smoketest/scripts/cli/test_service_monitoring_telegraf.py
+++ b/smoketest/scripts/cli/test_service_monitoring_telegraf.py
@@ -20,8 +20,8 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
PROCESS_NAME = 'telegraf'
TELEGRAF_CONF = '/run/telegraf/telegraf.conf'
diff --git a/smoketest/scripts/cli/test_service_monitoring_zabbix-agent.py b/smoketest/scripts/cli/test_service_monitoring_zabbix-agent.py
new file mode 100755
index 000000000..cb5f84406
--- /dev/null
+++ b/smoketest/scripts/cli/test_service_monitoring_zabbix-agent.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.configsession import ConfigSessionError
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
+
+
+PROCESS_NAME = 'zabbix_agent2'
+ZABBIX_AGENT_CONF = '/run/zabbix/zabbix-agent2.conf'
+base_path = ['service', 'monitoring', 'zabbix-agent']
+
+
+class TestZabbixAgent(VyOSUnitTestSHIM.TestCase):
+ def tearDown(self):
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ # Process must be terminated after deleting the config
+ self.assertFalse(process_named_running(PROCESS_NAME))
+
+ def test_01_zabbix_agent(self):
+ directory = '/tmp'
+ buffer_send = '8'
+ buffer_size = '120'
+ log_level = {'warning': '3'}
+ log_size = '1'
+ servers = ['192.0.2.1', '2001:db8::1']
+ servers_active = {'192.0.2.5': {'port': '10051'}, '2001:db8::123': {'port': '10052'}}
+ port = '10050'
+ timeout = '5'
+ listen_ip = '0.0.0.0'
+ hostname = 'r-vyos'
+
+ self.cli_set(base_path + ['directory', directory])
+ self.cli_set(base_path + ['limits', 'buffer-flush-interval', buffer_send])
+ self.cli_set(base_path + ['limits', 'buffer-size', buffer_size])
+ self.cli_set(base_path + ['log', 'debug-level', next(iter(log_level))])
+ self.cli_set(base_path + ['log', 'size', log_size])
+ for server in servers:
+ self.cli_set(base_path + ['server', server])
+ for server_active, server_config in servers_active.items():
+ self.cli_set(base_path + ['server-active', server_active, 'port', server_config['port']])
+ self.cli_set(base_path + ['timeout', timeout])
+ self.cli_set(base_path + ['host-name', hostname])
+
+ # commit changes
+ self.cli_commit()
+
+ config = read_file(ZABBIX_AGENT_CONF)
+
+ self.assertIn(f'LogFileSize={log_size}', config)
+ self.assertIn(f'DebugLevel={log_level.get("warning")}', config)
+
+ self.assertIn(f'Server={",".join(sorted(servers))}', config)
+ tmp = 'ServerActive=192.0.2.5:10051,[2001:db8::123]:10052'
+ self.assertIn(tmp, config)
+
+ self.assertIn(f'ListenPort={port}', config)
+ self.assertIn(f'ListenIP={listen_ip}', config)
+ self.assertIn(f'BufferSend={buffer_send}', config)
+ self.assertIn(f'BufferSize={buffer_size}', config)
+ self.assertIn(f'Include={directory}/*.conf', config)
+ self.assertIn(f'Timeout={timeout}', config)
+ self.assertIn(f'Hostname={hostname}', config)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_ntp.py b/smoketest/scripts/cli/test_service_ntp.py
index a0806acf0..5e385d5ad 100755
--- a/smoketest/scripts/cli/test_system_ntp.py
+++ b/smoketest/scripts/cli/test_service_ntp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2022 VyOS maintainers and contributors
+# Copyright (C) 2019-2023 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
@@ -19,14 +19,12 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.template import address_from_cidr
-from vyos.template import netmask_from_cidr
-from vyos.util import read_file
-from vyos.util import process_named_running
+from vyos.utils.process import cmd
+from vyos.utils.process import process_named_running
-PROCESS_NAME = 'ntpd'
-NTP_CONF = '/run/ntpd/ntpd.conf'
-base_path = ['system', 'ntp']
+PROCESS_NAME = 'chronyd'
+NTP_CONF = '/run/chrony/chrony.conf'
+base_path = ['service', 'ntp']
class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
@classmethod
@@ -38,6 +36,8 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
cls.cli_delete(cls, base_path)
def tearDown(self):
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
self.cli_delete(base_path)
self.cli_commit()
@@ -46,7 +46,7 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
def test_01_ntp_options(self):
# Test basic NTP support with multiple servers and their options
servers = ['192.0.2.1', '192.0.2.2']
- options = ['noselect', 'preempt', 'prefer']
+ options = ['nts', 'noselect', 'prefer']
pools = ['pool.vyos.io']
for server in servers:
@@ -61,12 +61,15 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Check generated configuration
- config = read_file(NTP_CONF)
- self.assertIn('driftfile /var/lib/ntp/ntp.drift', config)
- self.assertIn('restrict default noquery nopeer notrap nomodify', config)
- self.assertIn('restrict source nomodify notrap noquery', config)
- self.assertIn('restrict 127.0.0.1', config)
- self.assertIn('restrict -6 ::1', config)
+ # this file must be read with higher permissions
+ config = cmd(f'sudo cat {NTP_CONF}')
+ self.assertIn('driftfile /run/chrony/drift', config)
+ self.assertIn('dumpdir /run/chrony', config)
+ self.assertIn('ntsdumpdir /run/chrony', config)
+ self.assertIn('clientloglimit 1048576', config)
+ self.assertIn('rtcsync', config)
+ self.assertIn('makestep 1.0 3', config)
+ self.assertIn('leapsectz right/UTC', config)
for server in servers:
self.assertIn(f'server {server} iburst ' + ' '.join(options), config)
@@ -80,9 +83,9 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
for listen in listen_address:
self.cli_set(base_path + ['listen-address', listen])
- networks = ['192.0.2.0/24', '2001:db8:1000::/64']
+ networks = ['192.0.2.0/24', '2001:db8:1000::/64', '100.64.0.0', '2001:db8::ffff']
for network in networks:
- self.cli_set(base_path + ['allow-clients', 'address', network])
+ self.cli_set(base_path + ['allow-client', 'address', network])
# Verify "NTP server not configured" verify() statement
with self.assertRaises(ConfigSessionError):
@@ -95,21 +98,17 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Check generated client address configuration
- config = read_file(NTP_CONF)
- self.assertIn('restrict default ignore', config)
-
+ # this file must be read with higher permissions
+ config = cmd(f'sudo cat {NTP_CONF}')
for network in networks:
- network_address = address_from_cidr(network)
- network_netmask = netmask_from_cidr(network)
- self.assertIn(f'restrict {network_address} mask {network_netmask} nomodify notrap nopeer', config)
+ self.assertIn(f'allow {network}', config)
# Check listen address
- self.assertIn('interface ignore wildcard', config)
for listen in listen_address:
- self.assertIn(f'interface listen {listen}', config)
+ self.assertIn(f'bindaddress {listen}', config)
def test_03_ntp_interface(self):
- interfaces = ['eth0', 'eth1']
+ interfaces = ['eth0']
for interface in interfaces:
self.cli_set(base_path + ['interface', interface])
@@ -120,10 +119,28 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Check generated client address configuration
- config = read_file(NTP_CONF)
- self.assertIn('interface ignore wildcard', config)
+ # this file must be read with higher permissions
+ config = cmd(f'sudo cat {NTP_CONF}')
for interface in interfaces:
- self.assertIn(f'interface listen {interface}', config)
+ self.assertIn(f'binddevice {interface}', config)
+
+ def test_04_ntp_vrf(self):
+ vrf_name = 'vyos-mgmt'
+
+ self.cli_set(['vrf', 'name', vrf_name, 'table', '12345'])
+ self.cli_set(base_path + ['vrf', vrf_name])
+
+ servers = ['time1.vyos.net', 'time2.vyos.net']
+ for server in servers:
+ self.cli_set(base_path + ['server', server])
+
+ self.cli_commit()
+
+ # Check for process in VRF
+ tmp = cmd(f'ip vrf pids {vrf_name}')
+ self.assertIn(PROCESS_NAME, tmp)
+
+ self.cli_delete(['vrf', 'name', vrf_name])
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 7546c2e3d..963784f0a 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 VyOS maintainers and contributors
+# Copyright (C) 2022-2023 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
@@ -19,7 +19,7 @@ import unittest
from base_accel_ppp_test import BasicAccelPPPTest
from configparser import ConfigParser
-from vyos.util import read_file
+from vyos.utils.file import read_file
from vyos.template import range_to_regex
local_if = ['interfaces', 'dummy', 'dum667']
@@ -143,6 +143,9 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
self.basic_config()
subnet = '172.18.0.0/24'
+ fwmark = '223'
+ limiter = 'htb'
+
self.set(['client-ip-pool', 'subnet', subnet])
start = '192.0.2.10'
@@ -151,6 +154,7 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
start_stop = f'{start}-{stop_octet}'
self.set(['client-ip-pool', 'start', start])
self.set(['client-ip-pool', 'stop', stop])
+ self.set(['shaper', 'fwmark', fwmark])
# commit changes
self.cli_commit()
@@ -163,6 +167,37 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
self.assertEqual(conf['ip-pool'][subnet], None)
self.assertEqual(conf['ip-pool'][start_stop], None)
self.assertEqual(conf['ip-pool']['gw-ip-address'], self._gateway)
+ self.assertEqual(conf['shaper']['fwmark'], fwmark)
+ self.assertEqual(conf['shaper']['down-limiter'], limiter)
+
+
+ def test_pppoe_server_client_ip_pool_name(self):
+ # Test configuration of named client pools
+ self.basic_config()
+
+ subnet = '192.0.2.0/24'
+ gateway = '192.0.2.1'
+ pool = 'VYOS'
+
+ subnet_name = f'{subnet},name'
+ gw_ip_prefix = f'{gateway}/24'
+
+ self.set(['client-ip-pool', 'name', pool, 'subnet', subnet])
+ self.set(['client-ip-pool', 'name', pool, 'gateway-address', gateway])
+ self.cli_delete(self._base_path + ['gateway-address'])
+
+ # commit changes
+ self.cli_commit()
+
+ # Validate configuration values
+ conf = ConfigParser(allow_no_value=True, delimiters='=')
+ conf.read(self._config_file)
+
+ # Validate configuration
+ self.assertEqual(conf['ip-pool'][subnet_name], pool)
+ self.assertEqual(conf['ip-pool']['gw-ip-address'], gateway)
+ self.assertEqual(conf['pppoe']['ip-pool'], pool)
+ self.assertEqual(conf['pppoe']['gw-ip-address'], gw_ip_prefix)
def test_pppoe_server_client_ipv6_pool(self):
@@ -208,9 +243,11 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
def test_accel_radius_authentication(self):
radius_called_sid = 'ifname:mac'
radius_acct_interim_jitter = '9'
+ radius_acct_interim_interval = '60'
self.set(['authentication', 'radius', 'called-sid-format', radius_called_sid])
self.set(['authentication', 'radius', 'acct-interim-jitter', radius_acct_interim_jitter])
+ self.set(['authentication', 'radius', 'accounting-interim-interval', radius_acct_interim_interval])
# run common tests
super().test_accel_radius_authentication()
@@ -222,6 +259,7 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
# Validate configuration
self.assertEqual(conf['pppoe']['called-sid'], radius_called_sid)
self.assertEqual(conf['radius']['acct-interim-jitter'], radius_acct_interim_jitter)
+ self.assertEqual(conf['radius']['acct-interim-interval'], radius_acct_interim_interval)
def test_pppoe_server_vlan(self):
diff --git a/smoketest/scripts/cli/test_service_router-advert.py b/smoketest/scripts/cli/test_service_router-advert.py
index 873be7df0..5fc2019fd 100755
--- a/smoketest/scripts/cli/test_service_router-advert.py
+++ b/smoketest/scripts/cli/test_service_router-advert.py
@@ -20,8 +20,8 @@ import unittest
from vyos.configsession import ConfigSessionError
from base_vyostest_shim import VyOSUnitTestSHIM
-from vyos.util import read_file
-from vyos.util import process_named_running
+from vyos.utils.file import read_file
+from vyos.utils.process import process_named_running
PROCESS_NAME = 'radvd'
RADVD_CONF = '/run/radvd/radvd.conf'
@@ -37,7 +37,6 @@ def get_config_value(key):
return tmp[0].split()[0].replace(';','')
class TestServiceRADVD(VyOSUnitTestSHIM.TestCase):
-
@classmethod
def setUpClass(cls):
super(TestServiceRADVD, cls).setUpClass()
@@ -114,7 +113,6 @@ class TestServiceRADVD(VyOSUnitTestSHIM.TestCase):
tmp = get_config_value('DecrementLifetimes')
self.assertEqual(tmp, 'off')
-
def test_dns(self):
nameserver = ['2001:db8::1', '2001:db8::2']
dnssl = ['vyos.net', 'vyos.io']
@@ -150,7 +148,6 @@ class TestServiceRADVD(VyOSUnitTestSHIM.TestCase):
tmp = 'DNSSL ' + ' '.join(dnssl) + ' {'
self.assertIn(tmp, config)
-
def test_deprecate_prefix(self):
self.cli_set(base_path + ['prefix', prefix, 'valid-lifetime', 'infinity'])
self.cli_set(base_path + ['prefix', prefix, 'deprecate-prefix'])
@@ -159,13 +156,45 @@ class TestServiceRADVD(VyOSUnitTestSHIM.TestCase):
# commit changes
self.cli_commit()
- config = read_file(RADVD_CONF)
-
tmp = get_config_value('DeprecatePrefix')
self.assertEqual(tmp, 'on')
tmp = get_config_value('DecrementLifetimes')
self.assertEqual(tmp, 'on')
+ def test_route(self):
+ route = '2001:db8:1000::/64'
+
+ self.cli_set(base_path + ['prefix', prefix])
+ self.cli_set(base_path + ['route', route])
+
+ # commit changes
+ self.cli_commit()
+
+ config = read_file(RADVD_CONF)
+
+ tmp = f'route {route}' + ' {'
+ self.assertIn(tmp, config)
+
+ self.assertIn('AdvRouteLifetime 1800;', config)
+ self.assertIn('AdvRoutePreference medium;', config)
+ self.assertIn('RemoveRoute on;', config)
+
+ def test_rasrcaddress(self):
+ ra_src = ['fe80::1', 'fe80::2']
+
+ self.cli_set(base_path + ['prefix', prefix])
+ for src in ra_src:
+ self.cli_set(base_path + ['source-address', src])
+
+ # commit changes
+ self.cli_commit()
+
+ config = read_file(RADVD_CONF)
+ self.assertIn('AdvRASrcAddress {', config)
+ for src in ra_src:
+ self.assertIn(f' {src};', config)
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_salt.py b/smoketest/scripts/cli/test_service_salt.py
index 00a4f2020..48a588b72 100755
--- a/smoketest/scripts/cli/test_service_salt.py
+++ b/smoketest/scripts/cli/test_service_salt.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2023 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
@@ -19,9 +19,9 @@ import unittest
from socket import gethostname
from base_vyostest_shim import VyOSUnitTestSHIM
-from vyos.util import process_named_running
-from vyos.util import read_file
-from vyos.util import cmd
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
+from vyos.utils.process import cmd
PROCESS_NAME = 'salt-minion'
SALT_CONF = '/etc/salt/minion'
diff --git a/smoketest/scripts/cli/test_service_snmp.py b/smoketest/scripts/cli/test_service_snmp.py
index e80c689cc..52a72ec4f 100755
--- a/smoketest/scripts/cli/test_service_snmp.py
+++ b/smoketest/scripts/cli/test_service_snmp.py
@@ -22,10 +22,10 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.template import is_ipv4
from vyos.template import address_from_cidr
-from vyos.util import call
-from vyos.util import DEVNULL
-from vyos.util import read_file
-from vyos.util import process_named_running
+from vyos.utils.process import call
+from vyos.utils.process import DEVNULL
+from vyos.utils.file import read_file
+from vyos.utils.process import process_named_running
from vyos.version import get_version_data
PROCESS_NAME = 'snmpd'
@@ -123,6 +123,28 @@ class TestSNMPService(VyOSUnitTestSHIM.TestCase):
self.assertTrue(process_named_running(PROCESS_NAME))
self.cli_delete(['interfaces', 'dummy', dummy_if])
+ ## Check communities and default view RESTRICTED
+ for auth in ['ro', 'rw']:
+ community = 'VyOS' + auth
+ for addr in clients:
+ if is_ipv4(addr):
+ entry = auth + 'community ' + community + ' ' + addr + ' -V'
+ else:
+ entry = auth + 'community6 ' + community + ' ' + addr + ' -V'
+ config = get_config_value(entry)
+ expected = 'RESTRICTED'
+ self.assertIn(expected, config)
+ for addr in networks:
+ if is_ipv4(addr):
+ entry = auth + 'community ' + community + ' ' + addr + ' -V'
+ else:
+ entry = auth + 'community6 ' + community + ' ' + addr + ' -V'
+ config = get_config_value(entry)
+ expected = 'RESTRICTED'
+ self.assertIn(expected, config)
+ # And finally check global entry for RESTRICTED view
+ config = get_config_value('view RESTRICTED included .1')
+ self.assertIn('80', config)
def test_snmpv3_sha(self):
# Check if SNMPv3 can be configured with SHA authentication
diff --git a/smoketest/scripts/cli/test_service_ssh.py b/smoketest/scripts/cli/test_service_ssh.py
index 8de98f34f..947d7d568 100755
--- a/smoketest/scripts/cli/test_service_ssh.py
+++ b/smoketest/scripts/cli/test_service_ssh.py
@@ -24,10 +24,10 @@ from pwd import getpwall
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
-from vyos.util import is_systemd_service_running
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import cmd
+from vyos.utils.process import is_systemd_service_running
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
PROCESS_NAME = 'sshd'
SSHD_CONF = '/run/sshd/sshd_config'
@@ -174,18 +174,6 @@ class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
#
# We also try to login as an invalid user - this is not allowed to work.
- def ssh_send_cmd(command, username, password, host='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='localhost', username=username, password=password)
- _, stdout, stderr = ssh_client.exec_command(command)
- output = stdout.read().decode().strip()
- error = stderr.read().decode().strip()
- ssh_client.close()
- return output, error
-
test_user = 'ssh_test'
test_pass = 'v2i57DZs8idUwMN3VC92'
test_command = 'uname -a'
@@ -197,14 +185,14 @@ class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Login with proper credentials
- output, error = ssh_send_cmd(test_command, test_user, test_pass)
+ output, error = self.ssh_send_cmd(test_command, test_user, test_pass)
# verify login
self.assertFalse(error)
self.assertEqual(output, cmd(test_command))
# Login with invalid credentials
with self.assertRaises(paramiko.ssh_exception.AuthenticationException):
- output, error = ssh_send_cmd(test_command, 'invalid_user', 'invalid_password')
+ output, error = self.ssh_send_cmd(test_command, 'invalid_user', 'invalid_password')
self.cli_delete(['system', 'login', 'user', test_user])
self.cli_commit()
diff --git a/smoketest/scripts/cli/test_service_tftp-server.py b/smoketest/scripts/cli/test_service_tftp-server.py
index b57c33f26..d60794980 100755
--- a/smoketest/scripts/cli/test_service_tftp-server.py
+++ b/smoketest/scripts/cli/test_service_tftp-server.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2020 VyOS maintainers and contributors
+# Copyright (C) 2019-2023 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
@@ -20,9 +20,9 @@ from psutil import process_iter
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
-from vyos.util import read_file
-from vyos.util import process_named_running
+from vyos.utils.process import cmd
+from vyos.utils.file import read_file
+from vyos.utils.process import process_named_running
from vyos.template import is_ipv6
PROCESS_NAME = 'in.tftpd'
@@ -33,15 +33,32 @@ address_ipv6 = '2001:db8::1'
vrf = 'mgmt'
class TestServiceTFTPD(VyOSUnitTestSHIM.TestCase):
- def setUp(self):
- self.cli_set(dummy_if_path + ['address', address_ipv4 + '/32'])
- self.cli_set(dummy_if_path + ['address', address_ipv6 + '/128'])
+ @classmethod
+ def setUpClass(cls):
+ super(TestServiceTFTPD, 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_set(cls, dummy_if_path + ['address', address_ipv4 + '/32'])
+ cls.cli_set(cls, dummy_if_path + ['address', address_ipv6 + '/128'])
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.cli_delete(cls, dummy_if_path)
+ super(TestServiceTFTPD, cls).tearDownClass()
def tearDown(self):
+ # Check for running process
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
self.cli_delete(base_path)
- self.cli_delete(dummy_if_path)
self.cli_commit()
+ # Check for no longer running process
+ self.assertFalse(process_named_running(PROCESS_NAME))
+
def test_01_tftpd_single(self):
directory = '/tmp'
port = '69' # default port
@@ -61,9 +78,6 @@ class TestServiceTFTPD(VyOSUnitTestSHIM.TestCase):
# verify upload
self.assertIn('--create --umask 000', config)
- # Check for running process
- self.assertTrue(process_named_running(PROCESS_NAME))
-
def test_02_tftpd_multi(self):
directory = '/tmp'
address = [address_ipv4, address_ipv6]
@@ -125,9 +139,6 @@ class TestServiceTFTPD(VyOSUnitTestSHIM.TestCase):
# verify upload
self.assertIn('--create --umask 000', config)
- # Check for running process
- self.assertTrue(process_named_running(PROCESS_NAME))
-
# Check for process in VRF
tmp = cmd(f'ip vrf pids {vrf}')
self.assertIn(PROCESS_NAME, tmp)
diff --git a/smoketest/scripts/cli/test_service_upnp.py b/smoketest/scripts/cli/test_service_upnp.py
index e4df88c1e..c3fb0ec9d 100755
--- a/smoketest/scripts/cli/test_service_upnp.py
+++ b/smoketest/scripts/cli/test_service_upnp.py
@@ -22,8 +22,8 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.template import ip_from_cidr
-from vyos.util import read_file
-from vyos.util import process_named_running
+from vyos.utils.file import read_file
+from vyos.utils.process import process_named_running
UPNP_CONF = '/run/upnp/miniupnp.conf'
DAEMON = 'miniupnpd'
diff --git a/smoketest/scripts/cli/test_service_webproxy.py b/smoketest/scripts/cli/test_service_webproxy.py
index fb9b46a06..2b3f6d21c 100755
--- a/smoketest/scripts/cli/test_service_webproxy.py
+++ b/smoketest/scripts/cli/test_service_webproxy.py
@@ -19,9 +19,9 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import cmd
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
PROCESS_NAME = 'squid'
PROXY_CONF = '/etc/squid/squid.conf'
diff --git a/smoketest/scripts/cli/test_system_conntrack.py b/smoketest/scripts/cli/test_system_conntrack.py
index fd16146b1..ea304783d 100755
--- a/smoketest/scripts/cli/test_system_conntrack.py
+++ b/smoketest/scripts/cli/test_system_conntrack.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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
@@ -21,8 +21,8 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.firewall import find_nftables_rule
-from vyos.util import cmd
-from vyos.util import read_file
+from vyos.utils.process import cmd
+from vyos.utils.file import read_file
base_path = ['system', 'conntrack']
@@ -35,6 +35,17 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
self.cli_delete(base_path)
self.cli_commit()
+ 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 test_conntrack_options(self):
conntrack_config = {
'net.netfilter.nf_conntrack_expect_max' : {
@@ -232,5 +243,51 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
tmp = read_file('/etc/modprobe.d/vyatta_nf_conntrack.conf')
self.assertIn(hash_size_default, tmp)
+ def test_conntrack_ignore(self):
+ address_group = 'conntracktest'
+ address_group_member = '192.168.0.1'
+ ipv6_address_group = 'conntracktest6'
+ ipv6_address_group_member = 'dead:beef::1'
+
+ self.cli_set(['firewall', 'group', 'address-group', address_group, 'address', address_group_member])
+ self.cli_set(['firewall', 'group', 'ipv6-address-group', ipv6_address_group, 'address', ipv6_address_group_member])
+
+ self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'source', 'address', '192.0.2.1'])
+ self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'destination', 'address', '192.0.2.2'])
+ self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'destination', 'port', '22'])
+ self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'protocol', 'tcp'])
+
+ self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '2', 'source', 'address', '192.0.2.1'])
+ self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '2', 'destination', 'group', 'address-group', address_group])
+
+ self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '11', 'source', 'address', 'fe80::1'])
+ self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '11', 'destination', 'address', 'fe80::2'])
+ self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '11', 'destination', 'port', '22'])
+ self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '11', 'protocol', 'tcp'])
+
+ self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '12', 'source', 'address', 'fe80::1'])
+ self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '12', 'destination', 'group', 'address-group', ipv6_address_group])
+
+ self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '13', 'source', 'address', 'fe80::1'])
+ self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '13', 'destination', 'address', '!fe80::3'])
+
+ self.cli_commit()
+
+ nftables_search = [
+ ['ip saddr 192.0.2.1', 'ip daddr 192.0.2.2', 'tcp dport 22', 'notrack'],
+ ['ip saddr 192.0.2.1', 'ip daddr @A_conntracktest', 'notrack']
+ ]
+
+ nftables6_search = [
+ ['ip6 saddr fe80::1', 'ip6 daddr fe80::2', 'tcp dport 22', 'notrack'],
+ ['ip6 saddr fe80::1', 'ip6 daddr @A6_conntracktest6', 'notrack'],
+ ['ip6 saddr fe80::1', 'ip6 daddr != fe80::3', 'notrack']
+ ]
+
+ self.verify_nftables(nftables_search, 'raw')
+ self.verify_nftables(nftables6_search, 'ip6 raw')
+
+ self.cli_delete(['firewall'])
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_flow-accounting.py b/smoketest/scripts/cli/test_system_flow-accounting.py
index df60b9613..d55ea616e 100755
--- a/smoketest/scripts/cli/test_system_flow-accounting.py
+++ b/smoketest/scripts/cli/test_system_flow-accounting.py
@@ -22,9 +22,9 @@ from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
from vyos.template import bracketize_ipv6
from vyos.template import is_ipv6
-from vyos.util import cmd
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import cmd
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
PROCESS_NAME = 'uacctd'
base_path = ['system', 'flow-accounting']
diff --git a/smoketest/scripts/cli/test_system_frr.py b/smoketest/scripts/cli/test_system_frr.py
index 331133ed4..3eb0cd0ab 100755
--- a/smoketest/scripts/cli/test_system_frr.py
+++ b/smoketest/scripts/cli/test_system_frr.py
@@ -17,7 +17,7 @@
import re
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
-from vyos.util import read_file
+from vyos.utils.file import read_file
config_file = '/etc/frr/daemons'
base_path = ['system', 'frr']
@@ -143,4 +143,4 @@ class TestSystemFRR(VyOSUnitTestSHIM.TestCase):
if __name__ == '__main__':
- unittest.main(verbosity=2, failfast=True)
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_ip.py b/smoketest/scripts/cli/test_system_ip.py
index f71ef5b3f..567416774 100755
--- a/smoketest/scripts/cli/test_system_ip.py
+++ b/smoketest/scripts/cli/test_system_ip.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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,7 +17,8 @@
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
-from vyos.util import read_file
+from vyos.configsession import ConfigSessionError
+from vyos.utils.file import read_file
base_path = ['system', 'ip']
@@ -82,5 +83,42 @@ class TestSystemIP(VyOSUnitTestSHIM.TestCase):
self.assertEqual(read_file(gc_thresh2), str(size // 2))
self.assertEqual(read_file(gc_thresh1), str(size // 8))
+ 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='', daemon='zebra')
+ 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='', daemon='zebra')
+ 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()
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_ipv6.py b/smoketest/scripts/cli/test_system_ipv6.py
index c8aea9100..225c2d666 100755
--- a/smoketest/scripts/cli/test_system_ipv6.py
+++ b/smoketest/scripts/cli/test_system_ipv6.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2022 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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
@@ -18,10 +18,11 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.configsession import ConfigSessionError
from vyos.template import is_ipv4
-from vyos.util import read_file
-from vyos.util import get_interface_config
-from vyos.validate import is_intf_addr_assigned
+from vyos.utils.file import read_file
+from vyos.utils.network import get_interface_config
+from vyos.utils.network import is_intf_addr_assigned
base_path = ['system', 'ipv6']
@@ -88,5 +89,47 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase):
self.assertEqual(read_file(gc_thresh2), str(size // 2))
self.assertEqual(read_file(gc_thresh1), str(size // 8))
+ 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='', daemon='zebra')
+ 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='', daemon='zebra')
+ 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()
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_lcd.py b/smoketest/scripts/cli/test_system_lcd.py
index 831fba979..fc440ca8a 100755
--- a/smoketest/scripts/cli/test_system_lcd.py
+++ b/smoketest/scripts/cli/test_system_lcd.py
@@ -19,7 +19,7 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from configparser import ConfigParser
-from vyos.util import process_named_running
+from vyos.utils.process import process_named_running
config_file = '/run/LCDd/LCDd.conf'
base_path = ['system', 'lcd']
diff --git a/smoketest/scripts/cli/test_system_login.py b/smoketest/scripts/cli/test_system_login.py
index 6006fe0f6..195b127a4 100755
--- a/smoketest/scripts/cli/test_system_login.py
+++ b/smoketest/scripts/cli/test_system_login.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2022 VyOS maintainers and contributors
+# Copyright (C) 2019-2023 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,17 +17,17 @@
import re
import platform
import unittest
+import paramiko
from base_vyostest_shim import VyOSUnitTestSHIM
-from distutils.version import LooseVersion
-from platform import release as kernel_version
from subprocess import Popen, PIPE
from pwd import getpwall
+from time import sleep
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
-from vyos.util import read_file
+from vyos.utils.process import cmd
+from vyos.utils.file import read_file
from vyos.template import inc_ip
base_path = ['system', 'login']
@@ -53,12 +53,16 @@ class TestSystemLogin(VyOSUnitTestSHIM.TestCase):
# ensure we can also run this test on a live system - so lets clean
# out the current configuration which will break this test
cls.cli_delete(cls, base_path + ['radius'])
+ cls.cli_delete(cls, base_path + ['tacacs'])
def tearDown(self):
# Delete individual users from configuration
for user in users:
self.cli_delete(base_path + ['user', user])
+ self.cli_delete(base_path + ['radius'])
+ self.cli_delete(base_path + ['tacacs'])
+
self.cli_commit()
# After deletion, a user is not allowed to remain in /etc/passwd
@@ -149,9 +153,6 @@ class TestSystemLogin(VyOSUnitTestSHIM.TestCase):
# T2886 - RADIUS authentication - check for statically compiled options
options = ['CONFIG_AUDIT', 'CONFIG_AUDITSYSCALL', 'CONFIG_AUDIT_ARCH']
- if LooseVersion(kernel_version()) < LooseVersion('5.0'):
- options.append('CONFIG_AUDIT_WATCH')
- options.append('CONFIG_AUDIT_TREE')
for option in options:
self.assertIn(f'{option}=y', kernel_config)
@@ -264,5 +265,61 @@ class TestSystemLogin(VyOSUnitTestSHIM.TestCase):
tmp = re.findall(r'group:\s+mapname\s+files', nsswitch_conf)
self.assertTrue(tmp)
+ def test_system_login_max_login_session(self):
+ max_logins = '2'
+ timeout = '600'
+
+ self.cli_set(base_path + ['max-login-session', max_logins])
+
+ # 'max-login-session' must be only with 'timeout' option
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ self.cli_set(base_path + ['timeout', timeout])
+
+ self.cli_commit()
+
+ security_limits = read_file('/etc/security/limits.d/10-vyos.conf')
+ self.assertIn(f'* - maxsyslogins {max_logins}', security_limits)
+
+ self.cli_delete(base_path + ['timeout'])
+ self.cli_delete(base_path + ['max-login-session'])
+
+ def test_system_login_tacacs(self):
+ tacacs_secret = 'tac_plus_key'
+ tacacs_servers = ['100.64.0.11', '100.64.0.12']
+
+ # Enable TACACS
+ for server in tacacs_servers:
+ self.cli_set(base_path + ['tacacs', 'server', server, 'key', tacacs_secret])
+
+ self.cli_commit()
+
+ # NSS
+ nsswitch_conf = read_file('/etc/nsswitch.conf')
+ tmp = re.findall(r'passwd:\s+tacplus\s+files', nsswitch_conf)
+ self.assertTrue(tmp)
+
+ tmp = re.findall(r'group:\s+tacplus\s+files', nsswitch_conf)
+ self.assertTrue(tmp)
+
+ # PAM TACACS configuration
+ pam_tacacs_conf = read_file('/etc/tacplus_servers')
+ # NSS TACACS configuration
+ nss_tacacs_conf = read_file('/etc/tacplus_nss.conf')
+ # Users have individual home directories
+ self.assertIn('user_homedir=1', pam_tacacs_conf)
+
+ # specify services
+ self.assertIn('service=shell', pam_tacacs_conf)
+ self.assertIn('protocol=ssh', pam_tacacs_conf)
+
+ for server in tacacs_servers:
+ self.assertIn(f'secret={tacacs_secret}', pam_tacacs_conf)
+ self.assertIn(f'server={server}', pam_tacacs_conf)
+
+ self.assertIn(f'secret={tacacs_secret}', nss_tacacs_conf)
+ self.assertIn(f'server={server}', nss_tacacs_conf)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_logs.py b/smoketest/scripts/cli/test_system_logs.py
index 92fa9c3d9..17cce5ca1 100755
--- a/smoketest/scripts/cli/test_system_logs.py
+++ b/smoketest/scripts/cli/test_system_logs.py
@@ -17,7 +17,7 @@
import re
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
-from vyos.util import read_file
+from vyos.utils.file import read_file
# path to logrotate configs
logrotate_atop_file = '/etc/logrotate.d/vyos-atop'
diff --git a/smoketest/scripts/cli/test_system_nameserver.py b/smoketest/scripts/cli/test_system_nameserver.py
index 58c84988e..4979a7c72 100755
--- a/smoketest/scripts/cli/test_system_nameserver.py
+++ b/smoketest/scripts/cli/test_system_nameserver.py
@@ -21,7 +21,7 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.util import read_file
+from vyos.utils.file import read_file
RESOLV_CONF = '/etc/resolv.conf'
diff --git a/smoketest/scripts/cli/test_system_sflow.py b/smoketest/scripts/cli/test_system_sflow.py
new file mode 100755
index 000000000..63262db69
--- /dev/null
+++ b/smoketest/scripts/cli/test_system_sflow.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+
+from vyos.configsession import ConfigSessionError
+from vyos.ifconfig import Section
+from vyos.utils.process import cmd
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
+
+PROCESS_NAME = 'hsflowd'
+base_path = ['system', 'sflow']
+
+hsflowd_conf = '/run/sflow/hsflowd.conf'
+
+
+class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestSystemFlowAccounting, 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):
+ # after service removal process must no longer run
+ self.assertTrue(process_named_running(PROCESS_NAME))
+
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ # after service removal process must no longer run
+ self.assertFalse(process_named_running(PROCESS_NAME))
+
+ def test_sflow(self):
+ agent_address = '192.0.2.5'
+ agent_interface = 'eth0'
+ polling = '24'
+ sampling_rate = '128'
+ server = '192.0.2.254'
+ local_server = '127.0.0.1'
+ port = '8192'
+ default_port = '6343'
+ mon_limit = '50'
+
+ self.cli_set(
+ ['interfaces', 'dummy', 'dum0', 'address', f'{agent_address}/24'])
+ self.cli_set(base_path + ['agent-address', agent_address])
+ self.cli_set(base_path + ['agent-interface', agent_interface])
+
+ # You need to configure at least one interface for sflow
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ for interface in Section.interfaces('ethernet'):
+ self.cli_set(base_path + ['interface', interface])
+
+ self.cli_set(base_path + ['polling', polling])
+ self.cli_set(base_path + ['sampling-rate', sampling_rate])
+ self.cli_set(base_path + ['server', server, 'port', port])
+ self.cli_set(base_path + ['server', local_server])
+ self.cli_set(base_path + ['drop-monitor-limit', mon_limit])
+
+ # commit changes
+ self.cli_commit()
+
+ # verify configuration
+ hsflowd = read_file(hsflowd_conf)
+
+ self.assertIn(f'polling={polling}', hsflowd)
+ self.assertIn(f'sampling={sampling_rate}', hsflowd)
+ self.assertIn(f'agentIP={agent_address}', hsflowd)
+ self.assertIn(f'agent={agent_interface}', hsflowd)
+ self.assertIn(f'collector {{ ip = {server} udpport = {port} }}', hsflowd)
+ self.assertIn(f'collector {{ ip = {local_server} udpport = {default_port} }}', hsflowd)
+ self.assertIn(f'dropmon {{ limit={mon_limit} start=on sw=on hw=off }}', hsflowd)
+ self.assertIn('dbus { }', hsflowd)
+
+ for interface in Section.interfaces('ethernet'):
+ self.assertIn(f'pcap {{ dev={interface} }}', hsflowd)
+
+
+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 bd242104f..01b0406bf 100755
--- a/smoketest/scripts/cli/test_vpn_ipsec.py
+++ b/smoketest/scripts/cli/test_vpn_ipsec.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2022 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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
@@ -18,9 +18,9 @@ import os
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
-from vyos.util import call
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.utils.process import call
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
ethernet_path = ['interfaces', 'ethernet']
tunnel_path = ['interfaces', 'tunnel']
@@ -34,11 +34,15 @@ swanctl_file = '/etc/swanctl/swanctl.conf'
peer_ip = '203.0.113.45'
connection_name = 'main-branch'
+local_id = 'left'
+remote_id = 'right'
interface = 'eth1'
vif = '100'
esp_group = 'MyESPGroup'
ike_group = 'MyIKEGroup'
secret = 'MYSECRETKEY'
+PROCESS_NAME = 'charon-systemd'
+regex_uuid4 = '[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}'
ca_pem = """
MIIDSzCCAjOgAwIBAgIUQHK+ZgTUYZksvXY2/MyW+Jiels4wDQYJKoZIhvcNAQEL
@@ -113,6 +117,8 @@ rgiyCHemtMepq57Pl1Nmj49eEA==
"""
class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
+ skip_process_check = False
+
@classmethod
def setUpClass(cls):
super(TestVPNIPsec, cls).setUpClass()
@@ -137,23 +143,34 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
def tearDown(self):
# Check for running process
- self.assertTrue(process_named_running('charon'))
+ if not self.skip_process_check:
+ self.assertTrue(process_named_running(PROCESS_NAME))
+ else:
+ self.skip_process_check = False # Reset
self.cli_delete(base_path)
self.cli_delete(tunnel_path)
self.cli_commit()
# Check for no longer running process
- self.assertFalse(process_named_running('charon'))
+ self.assertFalse(process_named_running(PROCESS_NAME))
def test_01_dhcp_fail_handling(self):
+ # Skip process check - connection is not created for this test
+ self.skip_process_check = True
+
# Interface for dhcp-interface
self.cli_set(ethernet_path + [interface, 'vif', vif, 'address', 'dhcp']) # Use VLAN to avoid getting IP from qemu dhcp server
+ # vpn ipsec auth psk <tag> id <x.x.x.x>
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', local_id])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', remote_id])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', peer_ip])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'secret', secret])
+
# Site to site
peer_base_path = base_path + ['site-to-site', 'peer', connection_name]
self.cli_set(peer_base_path + ['authentication', 'mode', 'pre-shared-secret'])
- self.cli_set(peer_base_path + ['authentication', 'pre-shared-secret', secret])
self.cli_set(peer_base_path + ['ike-group', ike_group])
self.cli_set(peer_base_path + ['default-esp-group', esp_group])
self.cli_set(peer_base_path + ['dhcp-interface', f'{interface}.{vif}'])
@@ -166,21 +183,30 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
dhcp_waiting = read_file(dhcp_waiting_file)
self.assertIn(f'{interface}.{vif}', dhcp_waiting) # Ensure dhcp-failed interface was added for dhclient hook
+ self.cli_delete(ethernet_path + [interface, 'vif', vif, 'address'])
+
def test_02_site_to_site(self):
self.cli_set(base_path + ['ike-group', ike_group, 'key-exchange', 'ikev2'])
- # Site to site
local_address = '192.0.2.10'
priority = '20'
life_bytes = '100000'
life_packets = '2000000'
+
+ # vpn ipsec auth psk <tag> id <x.x.x.x>
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', local_id])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', remote_id])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', local_address])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', peer_ip])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'secret', secret])
+
+ # Site to site
peer_base_path = base_path + ['site-to-site', 'peer', connection_name]
self.cli_set(base_path + ['esp-group', esp_group, 'life-bytes', life_bytes])
self.cli_set(base_path + ['esp-group', esp_group, 'life-packets', life_packets])
self.cli_set(peer_base_path + ['authentication', 'mode', 'pre-shared-secret'])
- self.cli_set(peer_base_path + ['authentication', 'pre-shared-secret', secret])
self.cli_set(peer_base_path + ['ike-group', ike_group])
self.cli_set(peer_base_path + ['default-esp-group', esp_group])
self.cli_set(peer_base_path + ['local-address', local_address])
@@ -227,12 +253,14 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
self.assertIn(line, swanctl_conf)
swanctl_secrets_lines = [
- f'id-local = {local_address} # dhcp:no',
- f'id-remote_{peer_ip.replace(".","-")} = {peer_ip}',
+ f'id-{regex_uuid4} = "{local_id}"',
+ f'id-{regex_uuid4} = "{remote_id}"',
+ f'id-{regex_uuid4} = "{local_address}"',
+ f'id-{regex_uuid4} = "{peer_ip}"',
f'secret = "{secret}"'
]
for line in swanctl_secrets_lines:
- self.assertIn(line, swanctl_conf)
+ self.assertRegex(swanctl_conf, fr'{line}')
def test_03_site_to_site_vti(self):
@@ -246,10 +274,15 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
# VTI interface
self.cli_set(vti_path + [vti, 'address', '10.1.1.1/24'])
+ # vpn ipsec auth psk <tag> id <x.x.x.x>
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', local_id])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', remote_id])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', peer_ip])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'secret', secret])
+
# Site to site
peer_base_path = base_path + ['site-to-site', 'peer', connection_name]
self.cli_set(peer_base_path + ['authentication', 'mode', 'pre-shared-secret'])
- self.cli_set(peer_base_path + ['authentication', 'pre-shared-secret', secret])
self.cli_set(peer_base_path + ['connection-type', 'none'])
self.cli_set(peer_base_path + ['force-udp-encapsulation'])
self.cli_set(peer_base_path + ['ike-group', ike_group])
@@ -292,12 +325,12 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
self.assertIn(line, swanctl_conf)
swanctl_secrets_lines = [
- f'id-local = {local_address} # dhcp:no',
- f'id-remote_{peer_ip.replace(".","-")} = {peer_ip}',
+ f'id-{regex_uuid4} = "{local_id}"',
+ f'id-{regex_uuid4} = "{remote_id}"',
f'secret = "{secret}"'
]
for line in swanctl_secrets_lines:
- self.assertIn(line, swanctl_conf)
+ self.assertRegex(swanctl_conf, fr'{line}')
def test_04_dmvpn(self):
@@ -310,7 +343,7 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
self.cli_set(tunnel_path + [tunnel_if, 'address', '172.16.253.134/29'])
self.cli_set(tunnel_path + [tunnel_if, 'encapsulation', 'gre'])
self.cli_set(tunnel_path + [tunnel_if, 'source-address', '192.0.2.1'])
- self.cli_set(tunnel_path + [tunnel_if, 'multicast', 'enable'])
+ self.cli_set(tunnel_path + [tunnel_if, 'enable-multicast'])
self.cli_set(tunnel_path + [tunnel_if, 'parameters', 'ip', 'key', '1'])
# NHRP
@@ -334,6 +367,7 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['ike-group', ike_group, 'proposal', '2', 'dh-group', '2'])
self.cli_set(base_path + ['ike-group', ike_group, 'proposal', '2', 'encryption', 'aes256'])
self.cli_set(base_path + ['ike-group', ike_group, 'proposal', '2', 'hash', 'sha1'])
+ self.cli_set(base_path + ['ike-group', ike_group, 'proposal', '2', 'prf', 'prfsha1'])
# Profile
self.cli_set(base_path + ['profile', 'NHRPVPN', 'authentication', 'mode', 'pre-shared-secret'])
@@ -346,7 +380,7 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
swanctl_conf = read_file(swanctl_file)
swanctl_lines = [
- f'proposals = aes128-sha1-modp1024,aes256-sha1-modp1024',
+ f'proposals = aes128-sha1-modp1024,aes256-sha1-prfsha1-modp1024',
f'version = 1',
f'rekey_time = {ike_lifetime}s',
f'rekey_time = {esp_lifetime}s',
@@ -450,9 +484,15 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['options', 'interface', 'tun1'])
self.cli_set(base_path + ['ike-group', ike_group, 'key-exchange', 'ikev2'])
+ # vpn ipsec auth psk <tag> id <x.x.x.x>
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', local_id])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', remote_id])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', local_address])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', peer_ip])
+ self.cli_set(base_path + ['authentication', 'psk', connection_name, 'secret', secret])
+
self.cli_set(peer_base_path + ['authentication', 'local-id', local_id])
self.cli_set(peer_base_path + ['authentication', 'mode', 'pre-shared-secret'])
- self.cli_set(peer_base_path + ['authentication', 'pre-shared-secret', secret])
self.cli_set(peer_base_path + ['authentication', 'remote-id', remote_id])
self.cli_set(peer_base_path + ['connection-type', 'initiate'])
self.cli_set(peer_base_path + ['ike-group', ike_group])
@@ -482,15 +522,15 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
self.assertIn(line, swanctl_conf)
swanctl_secrets_lines = [
- f'id-local = {local_address} # dhcp:no',
- f'id-remote_{peer_ip.replace(".","-")} = {peer_ip}',
- f'id-localid = {local_id}',
- f'id-remoteid = {remote_id}',
+ f'id-{regex_uuid4} = "{local_id}"',
+ f'id-{regex_uuid4} = "{remote_id}"',
+ f'id-{regex_uuid4} = "{peer_ip}"',
+ f'id-{regex_uuid4} = "{local_address}"',
f'secret = "{secret}"',
]
for line in swanctl_secrets_lines:
- self.assertIn(line, swanctl_conf)
+ self.assertRegex(swanctl_conf, fr'{line}')
# Verify charon configuration
charon_conf = read_file(charon_file)
diff --git a/smoketest/scripts/cli/test_vpn_openconnect.py b/smoketest/scripts/cli/test_vpn_openconnect.py
index 8572d6d66..04abeb1aa 100755
--- a/smoketest/scripts/cli/test_vpn_openconnect.py
+++ b/smoketest/scripts/cli/test_vpn_openconnect.py
@@ -18,8 +18,9 @@ import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
-from vyos.util import process_named_running
-from vyos.util import read_file
+from vyos.template import ip_from_cidr
+from vyos.utils.process import process_named_running
+from vyos.utils.file import read_file
OCSERV_CONF = '/run/ocserv/ocserv.conf'
base_path = ['vpn', 'openconnect']
@@ -52,6 +53,9 @@ config_file = '/run/ocserv/ocserv.conf'
auth_file = '/run/ocserv/ocpasswd'
otp_file = '/run/ocserv/users.oath'
+listen_if = 'dum116'
+listen_address = '100.64.0.1/32'
+
class TestVPNOpenConnect(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
@@ -61,6 +65,8 @@ class TestVPNOpenConnect(VyOSUnitTestSHIM.TestCase):
# out the current configuration :)
cls.cli_delete(cls, base_path)
+ cls.cli_set(cls, ['interfaces', 'dummy', listen_if, 'address', listen_address])
+
cls.cli_set(cls, pki_path + ['ca', 'openconnect', 'certificate', cert_data.replace('\n','')])
cls.cli_set(cls, pki_path + ['certificate', 'openconnect', 'certificate', cert_data.replace('\n','')])
cls.cli_set(cls, pki_path + ['certificate', 'openconnect', 'private', 'key', key_data.replace('\n','')])
@@ -68,6 +74,7 @@ class TestVPNOpenConnect(VyOSUnitTestSHIM.TestCase):
@classmethod
def tearDownClass(cls):
cls.cli_delete(cls, pki_path)
+ cls.cli_delete(cls, ['interfaces', 'dummy', listen_if])
super(TestVPNOpenConnect, cls).tearDownClass()
def tearDown(self):
@@ -104,6 +111,9 @@ class TestVPNOpenConnect(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['ssl', 'ca-certificate', 'openconnect'])
self.cli_set(base_path + ['ssl', 'certificate', 'openconnect'])
+ listen_ip_no_cidr = ip_from_cidr(listen_address)
+ self.cli_set(base_path + ['listen-address', listen_ip_no_cidr])
+
self.cli_commit()
# Verify configuration
@@ -111,10 +121,15 @@ class TestVPNOpenConnect(VyOSUnitTestSHIM.TestCase):
# authentication mode local password-otp
self.assertIn(f'auth = "plain[passwd=/run/ocserv/ocpasswd,otp=/run/ocserv/users.oath]"', daemon_config)
+ self.assertIn(f'listen-host = {listen_ip_no_cidr}', daemon_config)
self.assertIn(f'ipv4-network = {v4_subnet}', daemon_config)
self.assertIn(f'ipv6-network = {v6_prefix}', daemon_config)
self.assertIn(f'ipv6-subnet-prefix = {v6_len}', daemon_config)
+ # defaults
+ self.assertIn(f'tcp-port = 443', daemon_config)
+ self.assertIn(f'udp-port = 443', daemon_config)
+
for ns in name_server:
self.assertIn(f'dns = {ns}', daemon_config)
for domain in split_dns:
diff --git a/smoketest/scripts/cli/test_vpn_sstp.py b/smoketest/scripts/cli/test_vpn_sstp.py
index 434e3aa05..232eafcf2 100755
--- a/smoketest/scripts/cli/test_vpn_sstp.py
+++ b/smoketest/scripts/cli/test_vpn_sstp.py
@@ -17,7 +17,7 @@
import unittest
from base_accel_ppp_test import BasicAccelPPPTest
-from vyos.util import read_file
+from vyos.utils.file import read_file
pki_path = ['pki']
diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py
index 176c095fb..0f658f366 100755
--- a/smoketest/scripts/cli/test_vrf.py
+++ b/smoketest/scripts/cli/test_vrf.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2022 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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
@@ -26,13 +26,15 @@ from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Interface
from vyos.ifconfig import Section
from vyos.template import is_ipv4
-from vyos.util import cmd
-from vyos.util import read_file
-from vyos.util import get_interface_config
-from vyos.validate import is_intf_addr_assigned
+from vyos.utils.process import cmd
+from vyos.utils.file import read_file
+from vyos.utils.network import get_interface_config
+from vyos.utils.network import is_intf_addr_assigned
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 = []
@@ -45,9 +47,8 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
tmp = os.environ['TEST_ETH'].split()
cls._interfaces = tmp
else:
- for tmp in Section.interfaces('ethernet'):
- if not '.' in tmp:
- cls._interfaces.append(tmp)
+ for tmp in Section.interfaces('ethernet', vlan=False):
+ cls._interfaces.append(tmp)
# call base-classes classmethod
super(VRFTest, cls).setUpClass()
@@ -59,7 +60,8 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
self.assertNotIn(vrf, interfaces())
def test_vrf_vni_and_table_id(self):
- table = '1000'
+ base_table = '1000'
+ table = base_table
for vrf in vrfs:
base = base_path + ['name', vrf]
description = f'VyOS-VRF-{vrf}'
@@ -80,7 +82,7 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify VRF configuration
- table = '1000'
+ table = base_table
iproute2_config = read_file('/etc/iproute2/rt_tables.d/vyos-vrf.conf')
for vrf in vrfs:
description = f'VyOS-VRF-{vrf}'
@@ -194,7 +196,8 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
self.cli_delete(['interfaces', section, interface, 'vrf'])
def test_vrf_static_route(self):
- table = '100'
+ base_table = '100'
+ table = base_table
for vrf in vrfs:
next_hop = f'192.0.{table}.1'
prefix = f'10.0.{table}.0/24'
@@ -215,13 +218,12 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# Verify VRF configuration
- table = '100'
+ table = base_table
for vrf in vrfs:
next_hop = f'192.0.{table}.1'
prefix = f'10.0.{table}.0/24'
self.assertTrue(vrf in interfaces())
- vrf_if = Interface(vrf)
frrconfig = self.getFRRconfig(f'vrf {vrf}')
self.assertIn(f' vni {table}', frrconfig)
@@ -291,5 +293,200 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
self.assertEqual(read_file(f'/proc/sys/net/ipv4/conf/{vrf}/forwarding'), '0')
self.assertEqual(read_file(f'/proc/sys/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}', daemon='zebra')
+ 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}', daemon='zebra')
+ self.assertNotIn(f'vrf {vrf}', 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}', daemon='zebra')
+ 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}', daemon='zebra')
+ self.assertNotIn(f'vrf {vrf}', 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(vrf in interfaces())
+
+ frrconfig = self.getFRRconfig(f'vrf {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(vrf in interfaces())
+
+ frrconfig = self.getFRRconfig(f'vrf {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(vrf in interfaces())
+
+ frrconfig = self.getFRRconfig(f'vrf {vrf}')
+ self.assertIn(f' vni {table}', frrconfig)
+ # Increment table ID for the next run
+ table = str(int(table) + 2)
+
+ # 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(vrf in interfaces())
+
+ frrconfig = self.getFRRconfig(f'vrf {vrf}')
+ self.assertNotIn('vni', frrconfig)
+
+
if __name__ == '__main__':
- unittest.main(verbosity=2)
+ unittest.main(verbosity=2, failfast=True)
diff --git a/smoketest/scripts/system/test_kernel_options.py b/smoketest/scripts/system/test_kernel_options.py
index 4d9cbacbe..a39ae50bc 100755
--- a/smoketest/scripts/system/test_kernel_options.py
+++ b/smoketest/scripts/system/test_kernel_options.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2023 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
@@ -14,14 +14,18 @@
# 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 gzip
import re
+import os
import platform
import unittest
-from vyos.util import read_file
+from vyos.utils.process import call
+from vyos.utils.file import read_file
kernel = platform.release()
config = read_file(f'/boot/config-{kernel}')
+CONFIG = '/proc/config.gz'
class TestKernelModules(unittest.TestCase):
""" VyOS makes use of a lot of Kernel drivers, modules and features. The
@@ -42,6 +46,35 @@ class TestKernelModules(unittest.TestCase):
tmp = re.findall(f'{option}=(y|m)', config)
self.assertTrue(tmp)
+ def test_dropmon_enabled(self):
+ options_to_check = [
+ 'CONFIG_NET_DROP_MONITOR=y',
+ 'CONFIG_UPROBE_EVENTS=y',
+ 'CONFIG_BPF_EVENTS=y',
+ 'CONFIG_TRACEPOINTS=y'
+ ]
+ if not os.path.isfile(CONFIG):
+ call('sudo modprobe configs')
+
+ with gzip.open(CONFIG, 'rt') as f:
+ config_data = f.read()
+ for option in options_to_check:
+ self.assertIn(option, config_data,
+ f"Option {option} is not present in /proc/config.gz")
+
+ def test_synproxy_enabled(self):
+ options_to_check = [
+ 'CONFIG_NFT_SYNPROXY',
+ 'CONFIG_IP_NF_TARGET_SYNPROXY'
+ ]
+ if not os.path.isfile(CONFIG):
+ call('sudo modprobe configs')
+ with gzip.open(CONFIG, 'rt') as f:
+ config_data = f.read()
+ for option in options_to_check:
+ tmp = re.findall(f'{option}=(y|m)', config_data)
+ self.assertTrue(tmp)
+
def test_qemu_support(self):
# The bond/lacp interface must be enabled in the OS Kernel
for option in ['CONFIG_VIRTIO_BLK', 'CONFIG_SCSI_VIRTIO',
@@ -58,6 +91,7 @@ class TestKernelModules(unittest.TestCase):
tmp = re.findall(f'{option}=(y|m)', config)
self.assertTrue(tmp)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/system/test_module_load.py b/smoketest/scripts/system/test_module_load.py
index 76a41ac4d..9d94f01e6 100755
--- a/smoketest/scripts/system/test_module_load.py
+++ b/smoketest/scripts/system/test_module_load.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2020 VyOS maintainers and contributors
+# Copyright (C) 2019-2023 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
@@ -15,7 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import unittest
-from vyos.util import cmd
+from vyos.utils.process import cmd
modules = {
"intel": ["e1000", "e1000e", "igb", "ixgb", "ixgbe", "ixgbevf", "i40e",
@@ -24,7 +24,7 @@ modules = {
"qat_c62x", "qat_c62xvf", "qat_d15xx", "qat_d15xxvf",
"qat_dh895xcc", "qat_dh895xccvf"],
"accel_ppp": ["ipoe", "vlan_mon"],
- "misc": ["wireguard"]
+ "openvpn": ["ovpn-dco-v2"]
}
class TestKernelModules(unittest.TestCase):