diff options
Diffstat (limited to 'smoketest/scripts')
-rwxr-xr-x | smoketest/scripts/cli/test_load_balancning_wan.py | 257 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_pki.py | 57 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_policy.py | 82 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_protocols_rip.py | 66 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_system_flow-accounting.py | 94 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_system_frr.py | 146 |
6 files changed, 659 insertions, 43 deletions
diff --git a/smoketest/scripts/cli/test_load_balancning_wan.py b/smoketest/scripts/cli/test_load_balancning_wan.py new file mode 100755 index 000000000..303dece86 --- /dev/null +++ b/smoketest/scripts/cli/test_load_balancning_wan.py @@ -0,0 +1,257 @@ +#!/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 +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 + + +base_path = ['load-balancing'] + + +def create_netns(name): + return call(f'sudo ip netns add {name}') + +def create_veth_pair(local='veth0', peer='ceth0'): + return call(f'sudo ip link add {local} type veth peer name {peer}') + +def move_interface_to_netns(iface, netns_name): + return call(f'sudo ip link set {iface} netns {netns_name}') + +def rename_interface(iface, new_name): + return call(f'sudo ip link set {iface} name {new_name}') + +def cmd_in_netns(netns, cmd): + return call(f'sudo ip netns exec {netns} {cmd}') + +def delete_netns(name): + return call(f'sudo ip netns del {name}') + + +class TestLoadBalancingWan(VyOSUnitTestSHIM.TestCase): + @classmethod + def setUpClass(cls): + super(TestLoadBalancingWan, cls).setUpClass() + + # ensure we can also run this test on a live system - so lets clean + # out the current configuration :) + cls.cli_delete(cls, base_path) + + def tearDown(self): + self.cli_delete(base_path) + self.cli_commit() + + def test_table_routes(self): + + ns1 = 'ns201' + ns2 = 'ns202' + ns3 = 'ns203' + iface1 = 'eth201' + iface2 = 'eth202' + iface3 = 'eth203' + container_iface1 = 'ceth0' + container_iface2 = 'ceth1' + container_iface3 = 'ceth2' + + # Create network namespeces + create_netns(ns1) + create_netns(ns2) + create_netns(ns3) + 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) + 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') + 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') + cmd_in_netns(ns1, 'ip address add 203.0.113.1/24 dev eth0') + cmd_in_netns(ns2, 'ip address add 192.0.2.1/24 dev eth0') + cmd_in_netns(ns3, 'ip address add 198.51.100.1/24 dev eth0') + cmd_in_netns(ns1, 'ip link set dev eth0 up') + cmd_in_netns(ns2, 'ip link set dev eth0 up') + cmd_in_netns(ns3, 'ip link set dev eth0 up') + + # Set load-balancing configuration + self.cli_set(base_path + ['wan', 'interface-health', iface1, 'failure-count', '2']) + self.cli_set(base_path + ['wan', 'interface-health', iface1, 'nexthop', '203.0.113.1']) + self.cli_set(base_path + ['wan', 'interface-health', iface1, 'success-count', '1']) + self.cli_set(base_path + ['wan', 'interface-health', iface2, 'failure-count', '2']) + self.cli_set(base_path + ['wan', 'interface-health', iface2, 'nexthop', '192.0.2.1']) + self.cli_set(base_path + ['wan', 'interface-health', iface2, 'success-count', '1']) + + self.cli_set(base_path + ['wan', 'rule', '10', 'inbound-interface', iface3]) + self.cli_set(base_path + ['wan', 'rule', '10', 'source', 'address', '198.51.100.0/24']) + + + # commit changes + self.cli_commit() + + time.sleep(5) + # Check default routes in tables 201, 202 + # Expected values + original = 'default via 203.0.113.1 dev eth201' + tmp = cmd('sudo ip route show table 201') + self.assertEqual(tmp, original) + + original = 'default via 192.0.2.1 dev eth202' + tmp = cmd('sudo ip route show table 202') + self.assertEqual(tmp, original) + + # Delete veth interfaces and netns + for iface in [iface1, iface2]: + call(f'sudo ip link del dev {iface}') + + delete_netns(ns1) + delete_netns(ns2) + + def test_check_chains(self): + + ns1 = 'nsA' + ns2 = 'nsB' + ns3 = 'nsC' + iface1 = 'veth1' + iface2 = 'veth2' + iface3 = 'veth3' + container_iface1 = 'ceth0' + container_iface2 = 'ceth1' + container_iface3 = 'ceth2' + mangle_isp1 = """table ip mangle { + chain ISP_veth1 { + 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 accept + } +}""" + mangle_prerouting = """table ip mangle { + chain PREROUTING { + type filter hook prerouting priority mangle; policy accept; + counter jump WANLOADBALANCE_PRE + } +}""" + 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 counter jump ISP_veth2 + iifname "veth3" ip saddr 198.51.100.0/24 counter meta mark set ct mark + } +}""" + nat_wanloadbalance = """table ip nat { + chain WANLOADBALANCE { + ct mark 0xc9 counter snat to 203.0.113.10 + ct mark 0xca counter snat to 192.0.2.10 + } +}""" + nat_vyos_pre_snat_hook = """table ip nat { + chain VYOS_PRE_SNAT_HOOK { + counter jump WANLOADBALANCE + return + } +}""" + + # Create network namespeces + create_netns(ns1) + create_netns(ns2) + create_netns(ns3) + 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) + 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') + 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') + cmd_in_netns(ns1, 'ip address add 203.0.113.1/24 dev eth0') + cmd_in_netns(ns2, 'ip address add 192.0.2.1/24 dev eth0') + cmd_in_netns(ns3, 'ip address add 198.51.100.1/24 dev eth0') + cmd_in_netns(ns1, 'ip link set dev eth0 up') + cmd_in_netns(ns2, 'ip link set dev eth0 up') + cmd_in_netns(ns3, 'ip link set dev eth0 up') + + # Set load-balancing configuration + self.cli_set(base_path + ['wan', 'interface-health', iface1, 'failure-count', '2']) + self.cli_set(base_path + ['wan', 'interface-health', iface1, 'nexthop', '203.0.113.1']) + self.cli_set(base_path + ['wan', 'interface-health', iface1, 'success-count', '1']) + self.cli_set(base_path + ['wan', 'interface-health', iface2, 'failure-count', '2']) + self.cli_set(base_path + ['wan', 'interface-health', iface2, 'nexthop', '192.0.2.1']) + self.cli_set(base_path + ['wan', 'interface-health', iface2, 'success-count', '1']) + self.cli_set(base_path + ['wan', 'rule', '10', 'inbound-interface', iface3]) + self.cli_set(base_path + ['wan', 'rule', '10', 'source', 'address', '198.51.100.0/24']) + self.cli_set(base_path + ['wan', 'rule', '10', 'interface', iface1]) + self.cli_set(base_path + ['wan', 'rule', '10', 'interface', iface2]) + + # commit changes + self.cli_commit() + + time.sleep(5) + + # Check mangle chains + tmp = cmd(f'sudo nft -s list chain mangle ISP_{iface1}') + self.assertEqual(tmp, mangle_isp1) + + tmp = cmd(f'sudo nft -s list chain mangle ISP_{iface2}') + self.assertEqual(tmp, mangle_isp2) + + tmp = cmd(f'sudo nft -s list chain mangle PREROUTING') + self.assertEqual(tmp, mangle_prerouting) + + tmp = cmd(f'sudo nft -s list chain mangle WANLOADBALANCE_PRE') + self.assertEqual(tmp, mangle_wanloadbalance_pre) + + # Check nat chains + tmp = cmd(f'sudo nft -s list chain nat WANLOADBALANCE') + self.assertEqual(tmp, nat_wanloadbalance) + + tmp = cmd(f'sudo nft -s list chain nat VYOS_PRE_SNAT_HOOK') + self.assertEqual(tmp, nat_vyos_pre_snat_hook) + + # Delete veth interfaces and netns + for iface in [iface1, iface2]: + call(f'sudo ip link del dev {iface}') + + delete_netns(ns1) + delete_netns(ns2) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_pki.py b/smoketest/scripts/cli/test_pki.py index e92123dbc..cba5ffdde 100755 --- a/smoketest/scripts/cli/test_pki.py +++ b/smoketest/scripts/cli/test_pki.py @@ -128,6 +128,27 @@ g6a75NnEXo0J6YLAOOxd8fD2/HidhbceCmTF+3msidIzCsBidBkgn6V5TXx2IyMS xGsJxVHfSKeooUQn6q76sg== """ +valid_update_cert = """ +MIICJTCCAcugAwIBAgIUZJqjNmPfVQwePjNFBtB6WI31ThMwCgYIKoZIzj0EAwIw +VzELMAkGA1UEBhMCR0IxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAcMCVNv +bWUtQ2l0eTENMAsGA1UECgwEVnlPUzEQMA4GA1UEAwwHdnlvcy5pbzAeFw0yMjA1 +MzExNTE3NDlaFw0yMzA1MzExNTE3NDlaMFcxCzAJBgNVBAYTAkdCMRMwEQYDVQQI +DApTb21lLVN0YXRlMRIwEAYDVQQHDAlTb21lLUNpdHkxDTALBgNVBAoMBFZ5T1Mx +EDAOBgNVBAMMB3Z5b3MuaW8wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQMe0h/ +3CdD8mEgy+klk55QfJ8R3ZycefxCn4abWjzTXz/TuCIxqb4wpRT8DZtIn4NRimFT +mODYdEDOYxFtZm37o3UwczAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDAT +BgNVHSUEDDAKBggrBgEFBQcDAjAdBgNVHQ4EFgQUqH7KSZpzArpMFuxLXqI8e1QD +fBkwHwYDVR0jBBgwFoAUqH7KSZpzArpMFuxLXqI8e1QDfBkwCgYIKoZIzj0EAwID +SAAwRQIhAKofUgRtcUljmbubPF6sqHtn/3TRvuafl8VfPbk3s2bJAiBp3Q1AnU/O +i7t5FGhCgnv5m8DW2F3LZPCJdW4ELQ3d9A== +""" + +valid_update_private_key = """ +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgvyODf22w/p7Zgfz9 +dyLIT09LqLOrUN6zbAecfukiiiyhRANCAAQMe0h/3CdD8mEgy+klk55QfJ8R3Zyc +efxCn4abWjzTXz/TuCIxqb4wpRT8DZtIn4NRimFTmODYdEDOYxFtZm37 +""" + class TestPKI(VyOSUnitTestSHIM.TestCase): @classmethod def setUpClass(cls): @@ -189,5 +210,41 @@ class TestPKI(VyOSUnitTestSHIM.TestCase): with self.assertRaises(ConfigSessionError): self.cli_commit() + def test_certificate_in_use(self): + self.cli_set(base_path + ['certificate', 'smoketest', 'certificate', valid_ca_cert.replace('\n','')]) + self.cli_set(base_path + ['certificate', 'smoketest', 'private', 'key', valid_ca_private_key.replace('\n','')]) + self.cli_commit() + + self.cli_set(['service', 'https', 'certificates', 'certificate', 'smoketest']) + self.cli_commit() + + self.cli_delete(base_path + ['certificate', 'smoketest']) + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_delete(['service', 'https', 'certificates', 'certificate']) + + def test_certificate_https_update(self): + self.cli_set(base_path + ['certificate', 'smoketest', 'certificate', valid_ca_cert.replace('\n','')]) + self.cli_set(base_path + ['certificate', 'smoketest', 'private', 'key', valid_ca_private_key.replace('\n','')]) + self.cli_commit() + + self.cli_set(['service', 'https', 'certificates', 'certificate', 'smoketest']) + self.cli_commit() + + cert_data = None + + with open('/etc/ssl/certs/smoketest.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('/etc/ssl/certs/smoketest.pem') as f: + self.assertNotEqual(cert_data, f.read()) + + self.cli_delete(['service', 'https', 'certificates', 'certificate']) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py index e8c6ff19b..f175d7df7 100755 --- a/smoketest/scripts/cli/test_policy.py +++ b/smoketest/scripts/cli/test_policy.py @@ -711,13 +711,20 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): large_community_list = 'bgp-large-community-123456' prefix_list = 'foo-pfx-list' - ipv6_nexthop = 'fe80::1' + ipv6_nexthop_address = 'fe80::1' local_pref = '300' metric = '50' peer = '2.3.4.5' tag = '6542' goto = '25' + ipv4_nexthop_address= '192.0.2.2' + ipv4_prefix_len= '18' + ipv6_prefix_len= '122' + ipv4_nexthop_type= 'blackhole' + ipv6_nexthop_type= 'blackhole' + + test_data = { 'foo-map-bar' : { 'rule' : { @@ -785,7 +792,11 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): '30' : { 'action' : 'permit', 'match' : { - 'ipv6-nexthop' : ipv6_nexthop, + 'ipv6-nexthop-address' : ipv6_nexthop_address, + 'ipv6-nexthop-access-list' : access_list, + 'ipv6-nexthop-prefix-list' : prefix_list, + 'ipv6-nexthop-type' : ipv6_nexthop_type, + 'ipv6-address-pfx-len' : ipv6_prefix_len, 'large-community' : large_community_list, 'local-pref' : local_pref, 'metric': metric, @@ -793,6 +804,25 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): 'peer' : peer, }, }, + '40' : { + 'action' : 'permit', + 'match' : { + 'ip-nexthop-addr' : ipv4_nexthop_address, + 'ip-address-pfx-len' : ipv4_prefix_len, + }, + }, + '42' : { + 'action' : 'deny', + 'match' : { + 'ip-nexthop-plen' : ipv4_prefix_len, + }, + }, + '44' : { + 'action' : 'permit', + 'match' : { + 'ip-nexthop-type' : ipv4_nexthop_type, + }, + }, }, }, 'complicated-configuration' : { @@ -917,10 +947,18 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.cli_set(path + ['rule', rule, 'match', 'ip', 'address', 'access-list', rule_config['match']['ip-address-acl']]) if 'ip-address-pfx' in rule_config['match']: self.cli_set(path + ['rule', rule, 'match', 'ip', 'address', 'prefix-list', rule_config['match']['ip-address-pfx']]) + if 'ip-address-pfx-len' in rule_config['match']: + self.cli_set(path + ['rule', rule, 'match', 'ip', 'address', 'prefix-len', rule_config['match']['ip-address-pfx-len']]) if 'ip-nexthop-acl' in rule_config['match']: self.cli_set(path + ['rule', rule, 'match', 'ip', 'nexthop', 'access-list', rule_config['match']['ip-nexthop-acl']]) if 'ip-nexthop-pfx' in rule_config['match']: self.cli_set(path + ['rule', rule, 'match', 'ip', 'nexthop', 'prefix-list', rule_config['match']['ip-nexthop-pfx']]) + if 'ip-nexthop-addr' in rule_config['match']: + self.cli_set(path + ['rule', rule, 'match', 'ip', 'nexthop', 'address', rule_config['match']['ip-nexthop-addr']]) + if 'ip-nexthop-plen' in rule_config['match']: + self.cli_set(path + ['rule', rule, 'match', 'ip', 'nexthop', 'prefix-len', rule_config['match']['ip-nexthop-plen']]) + if 'ip-nexthop-type' in rule_config['match']: + self.cli_set(path + ['rule', rule, 'match', 'ip', 'nexthop', 'type', rule_config['match']['ip-nexthop-type']]) if 'ip-route-source-acl' in rule_config['match']: self.cli_set(path + ['rule', rule, 'match', 'ip', 'route-source', 'access-list', rule_config['match']['ip-route-source-acl']]) if 'ip-route-source-pfx' in rule_config['match']: @@ -929,8 +967,16 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'address', 'access-list', rule_config['match']['ipv6-address-acl']]) if 'ipv6-address-pfx' in rule_config['match']: self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'address', 'prefix-list', rule_config['match']['ipv6-address-pfx']]) - if 'ipv6-nexthop' in rule_config['match']: - self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'nexthop', rule_config['match']['ipv6-nexthop']]) + if 'ipv6-address-pfx-len' in rule_config['match']: + self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'address', 'prefix-len', rule_config['match']['ipv6-address-pfx-len']]) + if 'ipv6-nexthop-address' in rule_config['match']: + self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'nexthop', 'address', rule_config['match']['ipv6-nexthop-address']]) + if 'ipv6-nexthop-access-list' in rule_config['match']: + self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'nexthop', 'access-list', rule_config['match']['ipv6-nexthop-access-list']]) + if 'ipv6-nexthop-prefix-list' in rule_config['match']: + self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'nexthop', 'prefix-list', rule_config['match']['ipv6-nexthop-prefix-list']]) + if 'ipv6-nexthop-type' in rule_config['match']: + self.cli_set(path + ['rule', rule, 'match', 'ipv6', 'nexthop', 'type', rule_config['match']['ipv6-nexthop-type']]) if 'large-community' in rule_config['match']: self.cli_set(path + ['rule', rule, 'match', 'large-community', 'large-community-list', rule_config['match']['large-community']]) if 'local-pref' in rule_config['match']: @@ -1057,12 +1103,24 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): if 'ip-address-pfx' in rule_config['match']: tmp = f'match ip address prefix-list {rule_config["match"]["ip-address-pfx"]}' self.assertIn(tmp, config) + if 'ip-address-pfx-len' in rule_config['match']: + tmp = f'match ip address prefix-len {rule_config["match"]["ip-address-pfx-len"]}' + self.assertIn(tmp, config) if 'ip-nexthop-acl' in rule_config['match']: tmp = f'match ip next-hop {rule_config["match"]["ip-nexthop-acl"]}' self.assertIn(tmp, config) if 'ip-nexthop-pfx' in rule_config['match']: tmp = f'match ip next-hop prefix-list {rule_config["match"]["ip-nexthop-pfx"]}' self.assertIn(tmp, config) + if 'ip-nexthop-addr' in rule_config['match']: + tmp = f'match ip next-hop address {rule_config["match"]["ip-nexthop-addr"]}' + self.assertIn(tmp, config) + if 'ip-nexthop-plen' in rule_config['match']: + tmp = f'match ip next-hop prefix-len {rule_config["match"]["ip-nexthop-plen"]}' + self.assertIn(tmp, config) + if 'ip-nexthop-type' in rule_config['match']: + tmp = f'match ip next-hop type {rule_config["match"]["ip-nexthop-type"]}' + self.assertIn(tmp, config) if 'ip-route-source-acl' in rule_config['match']: tmp = f'match ip route-source {rule_config["match"]["ip-route-source-acl"]}' self.assertIn(tmp, config) @@ -1075,8 +1133,20 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase): if 'ipv6-address-pfx' in rule_config['match']: tmp = f'match ipv6 address prefix-list {rule_config["match"]["ipv6-address-pfx"]}' self.assertIn(tmp, config) - if 'ipv6-nexthop' in rule_config['match']: - tmp = f'match ipv6 next-hop address {rule_config["match"]["ipv6-nexthop"]}' + if 'ipv6-address-pfx-len' in rule_config['match']: + tmp = f'match ipv6 address prefix-len {rule_config["match"]["ipv6-address-pfx-len"]}' + self.assertIn(tmp, config) + if 'ipv6-nexthop-address' in rule_config['match']: + tmp = f'match ipv6 next-hop address {rule_config["match"]["ipv6-nexthop-address"]}' + self.assertIn(tmp, config) + if 'ipv6-nexthop-access-list' in rule_config['match']: + tmp = f'match ipv6 next-hop {rule_config["match"]["ipv6-nexthop-access-list"]}' + self.assertIn(tmp, config) + if 'ipv6-nexthop-prefix-list' in rule_config['match']: + tmp = f'match ipv6 next-hop prefix-list {rule_config["match"]["ipv6-nexthop-prefix-list"]}' + self.assertIn(tmp, config) + if 'ipv6-nexthop-type' in rule_config['match']: + tmp = f'match ipv6 next-hop type {rule_config["match"]["ipv6-nexthop-type"]}' self.assertIn(tmp, config) if 'large-community' in rule_config['match']: tmp = f'match large-community {rule_config["match"]["large-community"]}' diff --git a/smoketest/scripts/cli/test_protocols_rip.py b/smoketest/scripts/cli/test_protocols_rip.py index 80d4e79f9..11385adb5 100755 --- a/smoketest/scripts/cli/test_protocols_rip.py +++ b/smoketest/scripts/cli/test_protocols_rip.py @@ -31,26 +31,38 @@ route_map = 'FooBar123' base_path = ['protocols', 'rip'] class TestProtocolsRIP(VyOSUnitTestSHIM.TestCase): - def setUp(self): - self.cli_set(['policy', 'access-list', acl_in, 'rule', '10', 'action', 'permit']) - self.cli_set(['policy', 'access-list', acl_in, 'rule', '10', 'source', 'any']) - self.cli_set(['policy', 'access-list', acl_in, 'rule', '10', 'destination', 'any']) - self.cli_set(['policy', 'access-list', acl_out, 'rule', '20', 'action', 'deny']) - self.cli_set(['policy', 'access-list', acl_out, 'rule', '20', 'source', 'any']) - self.cli_set(['policy', 'access-list', acl_out, 'rule', '20', 'destination', 'any']) - self.cli_set(['policy', 'prefix-list', prefix_list_in, 'rule', '100', 'action', 'permit']) - self.cli_set(['policy', 'prefix-list', prefix_list_in, 'rule', '100', 'prefix', '192.0.2.0/24']) - self.cli_set(['policy', 'prefix-list', prefix_list_out, 'rule', '200', 'action', 'deny']) - self.cli_set(['policy', 'prefix-list', prefix_list_out, 'rule', '200', 'prefix', '192.0.2.0/24']) - self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) + @classmethod + def setUpClass(cls): + super(TestProtocolsRIP, 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, ['policy', 'access-list', acl_in, 'rule', '10', 'action', 'permit']) + cls.cli_set(cls, ['policy', 'access-list', acl_in, 'rule', '10', 'source', 'any']) + cls.cli_set(cls, ['policy', 'access-list', acl_in, 'rule', '10', 'destination', 'any']) + cls.cli_set(cls, ['policy', 'access-list', acl_out, 'rule', '20', 'action', 'deny']) + cls.cli_set(cls, ['policy', 'access-list', acl_out, 'rule', '20', 'source', 'any']) + cls.cli_set(cls, ['policy', 'access-list', acl_out, 'rule', '20', 'destination', 'any']) + cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_in, 'rule', '100', 'action', 'permit']) + cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_in, 'rule', '100', 'prefix', '192.0.2.0/24']) + cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_out, 'rule', '200', 'action', 'deny']) + cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_out, 'rule', '200', 'prefix', '192.0.2.0/24']) + cls.cli_set(cls, ['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) + + @classmethod + def tearDownClass(cls): + cls.cli_delete(cls, ['policy', 'access-list', acl_in]) + cls.cli_delete(cls, ['policy', 'access-list', acl_out]) + cls.cli_delete(cls, ['policy', 'prefix-list', prefix_list_in]) + cls.cli_delete(cls, ['policy', 'prefix-list', prefix_list_out]) + cls.cli_delete(cls, ['policy', 'route-map', route_map]) + + super(TestProtocolsRIP, cls).tearDownClass() def tearDown(self): self.cli_delete(base_path) - self.cli_delete(['policy', 'access-list', acl_in]) - self.cli_delete(['policy', 'access-list', acl_out]) - self.cli_delete(['policy', 'prefix-list', prefix_list_in]) - self.cli_delete(['policy', 'prefix-list', prefix_list_out]) - self.cli_delete(['policy', 'route-map', route_map]) self.cli_commit() # Check for running process @@ -146,5 +158,25 @@ class TestProtocolsRIP(VyOSUnitTestSHIM.TestCase): frrconfig = self.getFRRconfig(zebra_route_map) self.assertNotIn(zebra_route_map, frrconfig) + def test_rip_03_version(self): + rx_version = '1' + tx_version = '2' + interface = 'eth0' + + self.cli_set(base_path + ['version', tx_version]) + self.cli_set(base_path + ['interface', interface, 'send', 'version', tx_version]) + self.cli_set(base_path + ['interface', interface, 'receive', 'version', rx_version]) + + # commit changes + self.cli_commit() + + # Verify FRR configuration + frrconfig = self.getFRRconfig('router rip') + self.assertIn(f'version {tx_version}', frrconfig) + + frrconfig = self.getFRRconfig(f'interface {interface}') + self.assertIn(f' ip rip receive version {rx_version}', frrconfig) + self.assertIn(f' ip rip send version {tx_version}', frrconfig) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_system_flow-accounting.py b/smoketest/scripts/cli/test_system_flow-accounting.py index 5a73ebc7d..a6eef3fb6 100755 --- a/smoketest/scripts/cli/test_system_flow-accounting.py +++ b/smoketest/scripts/cli/test_system_flow-accounting.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-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 @@ -20,6 +20,8 @@ from base_vyostest_shim import VyOSUnitTestSHIM 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 @@ -103,14 +105,12 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase): agent_address = '192.0.2.2' sflow_server = { - '1.2.3.4' : { - }, - '5.6.7.8' : { - 'port' : '6000' - } + '1.2.3.4' : { }, + '5.6.7.8' : { 'port' : '6000' }, } self.cli_set(['interfaces', 'dummy', dummy_if, 'address', agent_address + '/32']) + self.cli_set(['interfaces', 'dummy', dummy_if, 'address', source_address + '/32']) self.cli_set(base_path + ['disable-imt']) # You need to configure at least one interface for flow-accounting @@ -155,6 +155,54 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase): self.cli_delete(['interfaces', 'dummy', dummy_if]) + def test_sflow_ipv6(self): + sampling_rate = '100' + sflow_server = { + '2001:db8::1' : { }, + '2001:db8::2' : { 'port' : '6000' }, + } + + self.cli_set(base_path + ['disable-imt']) + + # You need to configure at least one interface for flow-accounting + with self.assertRaises(ConfigSessionError): + self.cli_commit() + for interface in Section.interfaces('ethernet'): + self.cli_set(base_path + ['interface', interface]) + + + # You need to configure at least one sFlow or NetFlow protocol, or not + # set "disable-imt" for flow-accounting + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_set(base_path + ['sflow', 'sampling-rate', sampling_rate]) + for server, server_config in sflow_server.items(): + self.cli_set(base_path + ['sflow', 'server', server]) + if 'port' in server_config: + self.cli_set(base_path + ['sflow', 'server', server, 'port', server_config['port']]) + + # commit changes + self.cli_commit() + + uacctd = read_file(uacctd_conf) + + # when 'disable-imt' is not configured on the CLI it must be present + self.assertNotIn(f'imt_path: /tmp/uacctd.pipe', uacctd) + self.assertNotIn(f'imt_mem_pools_number: 169', uacctd) + self.assertNotIn(f'plugins: memory', uacctd) + + for server, server_config in sflow_server.items(): + tmp_srv = server + if is_ipv6(tmp_srv): + tmp_srv = tmp_srv.replace(':', '.') + + if 'port' in server_config: + self.assertIn(f'sfprobe_receiver[sf_{tmp_srv}]: {bracketize_ipv6(server)}', uacctd) + else: + self.assertIn(f'sfprobe_receiver[sf_{tmp_srv}]: {bracketize_ipv6(server)}:6343', uacctd) + self.assertIn(f'sampling_rate[sf_{tmp_srv}]: {sampling_rate}', uacctd) + def test_netflow(self): engine_id = '33' max_flows = '667' @@ -173,14 +221,13 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase): tmo_udp = '10' netflow_server = { - '11.22.33.44' : { - }, - '55.66.77.88' : { - 'port' : '6000' - } + '11.22.33.44' : { }, + '55.66.77.88' : { 'port' : '6000' }, + '2001:db8::1' : { }, } self.cli_set(['interfaces', 'dummy', dummy_if, 'address', agent_address + '/32']) + self.cli_set(['interfaces', 'dummy', dummy_if, 'address', source_address + '/32']) for interface in Section.interfaces('ethernet'): self.cli_set(base_path + ['interface', interface]) @@ -217,23 +264,30 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase): tmp = [] for server, server_config in netflow_server.items(): - tmp.append(f'nfprobe[nf_{server}]') + tmp_srv = server + if is_ipv6(tmp_srv): + tmp_srv = tmp_srv.replace(':', '.') + tmp.append(f'nfprobe[nf_{tmp_srv}]') tmp.append('memory') self.assertIn('plugins: ' + ','.join(tmp), uacctd) for server, server_config in netflow_server.items(): - self.assertIn(f'nfprobe_engine[nf_{server}]: {engine_id}', uacctd) - self.assertIn(f'nfprobe_maxflows[nf_{server}]: {max_flows}', uacctd) - self.assertIn(f'sampling_rate[nf_{server}]: {sampling_rate}', uacctd) - self.assertIn(f'nfprobe_source_ip[nf_{server}]: {source_address}', uacctd) - self.assertIn(f'nfprobe_version[nf_{server}]: {version}', uacctd) + tmp_srv = server + if is_ipv6(tmp_srv): + tmp_srv = tmp_srv.replace(':', '.') + + self.assertIn(f'nfprobe_engine[nf_{tmp_srv}]: {engine_id}', uacctd) + self.assertIn(f'nfprobe_maxflows[nf_{tmp_srv}]: {max_flows}', uacctd) + self.assertIn(f'sampling_rate[nf_{tmp_srv}]: {sampling_rate}', uacctd) + self.assertIn(f'nfprobe_source_ip[nf_{tmp_srv}]: {source_address}', uacctd) + self.assertIn(f'nfprobe_version[nf_{tmp_srv}]: {version}', uacctd) if 'port' in server_config: - self.assertIn(f'nfprobe_receiver[nf_{server}]: {server}', uacctd) + self.assertIn(f'nfprobe_receiver[nf_{tmp_srv}]: {bracketize_ipv6(server)}', uacctd) else: - self.assertIn(f'nfprobe_receiver[nf_{server}]: {server}:2055', uacctd) + self.assertIn(f'nfprobe_receiver[nf_{tmp_srv}]: {bracketize_ipv6(server)}:2055', uacctd) - self.assertIn(f'nfprobe_timeouts[nf_{server}]: expint={tmo_expiry}:general={tmo_flow}:icmp={tmo_icmp}:maxlife={tmo_max}:tcp.fin={tmo_tcp_fin}:tcp={tmo_tcp_generic}:tcp.rst={tmo_tcp_rst}:udp={tmo_udp}', uacctd) + self.assertIn(f'nfprobe_timeouts[nf_{tmp_srv}]: expint={tmo_expiry}:general={tmo_flow}:icmp={tmo_icmp}:maxlife={tmo_max}:tcp.fin={tmo_tcp_fin}:tcp={tmo_tcp_generic}:tcp.rst={tmo_tcp_rst}:udp={tmo_udp}', uacctd) self.cli_delete(['interfaces', 'dummy', dummy_if]) diff --git a/smoketest/scripts/cli/test_system_frr.py b/smoketest/scripts/cli/test_system_frr.py new file mode 100755 index 000000000..331133ed4 --- /dev/null +++ b/smoketest/scripts/cli/test_system_frr.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019-2020 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 re +import unittest +from base_vyostest_shim import VyOSUnitTestSHIM +from vyos.util import read_file + +config_file = '/etc/frr/daemons' +base_path = ['system', 'frr'] + + +def daemons_config_parse(daemons_config): + # create regex for parsing daemons options + regex_daemon_config = re.compile( + r'^(?P<daemon_name>\w+)_options="(?P<daemon_options>.*)"$', re.M) + # create empty dict for config + daemons_config_dict = {} + # fill dictionary with actual config + for daemon in regex_daemon_config.finditer(daemons_config): + daemon_name = daemon.group('daemon_name') + daemon_options = daemon.group('daemon_options') + daemons_config_dict[daemon_name] = daemon_options + + # return daemons config + return (daemons_config_dict) + + +class TestSystemFRR(VyOSUnitTestSHIM.TestCase): + + def tearDown(self): + self.cli_delete(base_path) + self.cli_commit() + + def test_frr_snmp_multipledaemons(self): + # test SNMP integration for multiple daemons + test_daemon_names = ['ospfd', 'bgpd'] + for test_daemon_name in test_daemon_names: + self.cli_set(base_path + ['snmp', test_daemon_name]) + self.cli_commit() + + # read the config file and check content + daemons_config = read_file(config_file) + daemons_config_dict = daemons_config_parse(daemons_config) + # prepare regex for matching SNMP integration + regex_snmp = re.compile(r'^.* -M snmp.*$') + for (daemon_name, daemon_options) in daemons_config_dict.items(): + snmp_enabled = regex_snmp.match(daemon_options) + if daemon_name in test_daemon_names: + self.assertTrue(snmp_enabled) + else: + self.assertFalse(snmp_enabled) + + def test_frr_snmp_addandremove(self): + # test enabling and disabling of SNMP integration + test_daemon_names = ['ospfd', 'bgpd'] + for test_daemon_name in test_daemon_names: + self.cli_set(base_path + ['snmp', test_daemon_name]) + self.cli_commit() + + self.cli_delete(base_path) + self.cli_commit() + + # read the config file and check content + daemons_config = read_file(config_file) + daemons_config_dict = daemons_config_parse(daemons_config) + # prepare regex for matching SNMP integration + regex_snmp = re.compile(r'^.* -M snmp.*$') + for test_daemon_name in test_daemon_names: + snmp_enabled = regex_snmp.match( + daemons_config_dict[test_daemon_name]) + self.assertFalse(snmp_enabled) + + def test_frr_snmp_empty(self): + # test empty config section + self.cli_set(base_path + ['snmp']) + self.cli_commit() + + # read the config file and check content + daemons_config = read_file(config_file) + daemons_config_dict = daemons_config_parse(daemons_config) + # prepare regex for matching SNMP integration + regex_snmp = re.compile(r'^.* -M snmp.*$') + for daemon_options in daemons_config_dict.values(): + snmp_enabled = regex_snmp.match(daemon_options) + self.assertFalse(snmp_enabled) + + def test_frr_bmp(self): + # test BMP + self.cli_set(base_path + ['bmp']) + self.cli_commit() + + # read the config file and check content + daemons_config = read_file(config_file) + daemons_config_dict = daemons_config_parse(daemons_config) + # prepare regex + regex_bmp = re.compile(r'^.* -M bmp.*$') + bmp_enabled = regex_bmp.match(daemons_config_dict['bgpd']) + self.assertTrue(bmp_enabled) + + def test_frr_irdp(self): + # test IRDP + self.cli_set(base_path + ['irdp']) + self.cli_commit() + + # read the config file and check content + daemons_config = read_file(config_file) + daemons_config_dict = daemons_config_parse(daemons_config) + # prepare regex + regex_irdp = re.compile(r'^.* -M irdp.*$') + irdp_enabled = regex_irdp.match(daemons_config_dict['zebra']) + self.assertTrue(irdp_enabled) + + def test_frr_bmpandsnmp(self): + # test empty config section + self.cli_set(base_path + ['bmp']) + self.cli_set(base_path + ['snmp', 'bgpd']) + self.cli_commit() + + # read the config file and check content + daemons_config = read_file(config_file) + daemons_config_dict = daemons_config_parse(daemons_config) + # prepare regex + regex_snmp = re.compile(r'^.* -M bmp.*$') + regex_snmp = re.compile(r'^.* -M snmp.*$') + bmp_enabled = regex_snmp.match(daemons_config_dict['bgpd']) + snmp_enabled = regex_snmp.match(daemons_config_dict['bgpd']) + self.assertTrue(bmp_enabled) + self.assertTrue(snmp_enabled) + + +if __name__ == '__main__': + unittest.main(verbosity=2, failfast=True) |