summaryrefslogtreecommitdiff
path: root/smoketest/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'smoketest/scripts')
-rw-r--r--smoketest/scripts/cli/base_interfaces_test.py40
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bridge.py6
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_erspan.py74
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_geneve.py44
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_l2tpv3.py6
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_macsec.py34
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_tunnel.py159
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_vxlan.py58
-rwxr-xr-xsmoketest/scripts/cli/test_nat66.py35
-rwxr-xr-xsmoketest/scripts/cli/test_policy.py681
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bfd.py83
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bgp.py62
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ospf.py81
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ospfv3.py63
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_rip.py2
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_static.py54
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcp-server.py1
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcpv6-server.py21
-rwxr-xr-xsmoketest/scripts/cli/test_service_pppoe-server.py3
-rwxr-xr-xsmoketest/scripts/cli/test_vrf.py6
20 files changed, 1288 insertions, 225 deletions
diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py
index 1426e80c2..50cfa2607 100644
--- a/smoketest/scripts/cli/base_interfaces_test.py
+++ b/smoketest/scripts/cli/base_interfaces_test.py
@@ -14,7 +14,6 @@
import os
import unittest
-import json
from binascii import hexlify
@@ -30,6 +29,7 @@ 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
@@ -292,6 +292,42 @@ class BasicInterfaceTest:
self.assertEqual(tmp, self._mtu)
self.assertEqual(Interface(vif).get_admin_state(), 'up')
+ def test_vif_8021q_lower_up_down(self):
+ # Testcase for https://phabricator.vyos.net/T3349
+ if not self._test_vlan:
+ self.skipTest('not supported')
+
+ for interface in self._interfaces:
+ base = self._base_path + [interface]
+ for option in self._options.get(interface, []):
+ self.session.set(base + option.split())
+
+ # disable the lower interface
+ self.session.set(base + ['disable'])
+
+ for vlan in self._vlan_range:
+ vlan_base = self._base_path + [interface, 'vif', vlan]
+ # disable the vlan interface
+ self.session.set(vlan_base + ['disable'])
+
+ self.session.commit()
+
+ # re-enable all lower interfaces
+ for interface in self._interfaces:
+ base = self._base_path + [interface]
+ self.session.delete(base + ['disable'])
+
+ self.session.commit()
+
+ # verify that the lower interfaces are admin up and the vlan
+ # interfaces are all admin down
+ for interface in self._interfaces:
+ self.assertEqual(Interface(interface).get_admin_state(), 'up')
+
+ for vlan in self._vlan_range:
+ ifname = f'{interface}.{vlan}'
+ self.assertEqual(Interface(ifname).get_admin_state(), 'down')
+
def test_vif_s_8021ad_vlan_interfaces(self):
# XXX: This testcase is not allowed to run as first testcase, reason
@@ -317,7 +353,7 @@ class BasicInterfaceTest:
for interface in self._interfaces:
for vif_s in self._qinq_range:
- tmp = json.loads(cmd(f'ip -d -j link show dev {interface}.{vif_s}'))[0]
+ tmp = get_interface_config(f'{interface}.{vif_s}')
self.assertEqual(dict_search('linkinfo.info_data.protocol', tmp), '802.1ad')
for vif_c in self._vlan_range:
diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py
index f64b527b3..7e10f12c4 100755
--- a/smoketest/scripts/cli/test_interfaces_bridge.py
+++ b/smoketest/scripts/cli/test_interfaces_bridge.py
@@ -99,6 +99,12 @@ class BridgeInterfaceTest(BasicInterfaceTest.BaseTest):
self.session.set(base + ['enable-vlan'])
super().test_vif_8021q_interfaces()
+ def test_vif_8021q_lower_up_down(self):
+ for interface in self._interfaces:
+ base = self._base_path + [interface]
+ self.session.set(base + ['enable-vlan'])
+ super().test_vif_8021q_interfaces()
+
def test_bridge_vlan_filter(self):
vif_vlan = 2
diff --git a/smoketest/scripts/cli/test_interfaces_erspan.py b/smoketest/scripts/cli/test_interfaces_erspan.py
index c180f0a34..4575c61ce 100755
--- a/smoketest/scripts/cli/test_interfaces_erspan.py
+++ b/smoketest/scripts/cli/test_interfaces_erspan.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2021 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,65 +15,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import unittest
-import json
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
+from vyos.util import get_interface_config
from base_interfaces_test import BasicInterfaceTest
mtu = 1500
-def erspan_conf(interface):
- tmp = cmd(f'ip -d -j link show {interface}')
- '''
- [
- {
- "ifindex": 17,
- "link": null,
- "ifname": "ersp0",
- "flags": [
- "BROADCAST",
- "MULTICAST"
- ],
- "mtu": 1450,
- "qdisc": "noop",
- "operstate": "DOWN",
- "linkmode": "DEFAULT",
- "group": "default",
- "txqlen": 1000,
- "link_type": "ether",
- "address": "22:27:14:7b:0d:79",
- "broadcast": "ff:ff:ff:ff:ff:ff",
- "promiscuity": 0,
- "min_mtu": 68,
- "max_mtu": 0,
- "linkinfo": {
- "info_kind": "erspan",
- "info_data": {
- "remote": "10.2.2.2",
- "local": "10.1.1.1",
- "ttl": 0,
- "pmtudisc": true,
- "ikey": "0.0.0.123",
- "okey": "0.0.0.123",
- "iseq": true,
- "oseq": true,
- "erspan_index": 0,
- "erspan_ver": 1
- }
- },
- "inet6_addr_gen_mode": "eui64",
- "num_tx_queues": 1,
- "num_rx_queues": 1,
- "gso_max_size": 65536,
- "gso_max_segs": 65535
- }
- ]
- '''
- return json.loads(tmp)[0]
-
class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest):
def setUp(self):
super().setUp()
@@ -96,19 +46,19 @@ class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest):
key = 123
self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
- self.session.set(self._base_path + [interface, 'remote-ip', self.remote_v4])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.session.set(self._base_path + [interface, 'remote', self.remote_v4])
self.session.set(self._base_path + [interface, 'parameters', 'ip' , 'key', str(key)])
self.session.commit()
- conf = erspan_conf(interface)
+ conf = get_interface_config(interface)
self.assertEqual(interface, conf['ifname'])
self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
self.assertEqual(mtu, conf['mtu'])
- self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
- self.assertEqual(self.remote_v4, conf['linkinfo']['info_data']['remote'])
+ self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
+ self.assertEqual(self.remote_v4, conf['linkinfo']['info_data']['remote'])
def test_erspan_ipv6(self):
@@ -117,19 +67,19 @@ class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest):
key = 123
self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v6])
- self.session.set(self._base_path + [interface, 'remote-ip', self.remote_v6])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v6])
+ self.session.set(self._base_path + [interface, 'remote', self.remote_v6])
self.session.set(self._base_path + [interface, 'parameters', 'ip' , 'key', str(key)])
self.session.commit()
- conf = erspan_conf(interface)
+ conf = get_interface_config(interface)
self.assertEqual(interface, conf['ifname'])
self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
self.assertEqual(mtu, conf['mtu'])
- self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local'])
- self.assertEqual(self.remote_v6, conf['linkinfo']['info_data']['remote'])
+ self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local'])
+ self.assertEqual(self.remote_v6, conf['linkinfo']['info_data']['remote'])
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_geneve.py b/smoketest/scripts/cli/test_interfaces_geneve.py
index b708b5437..e8e8e5a2c 100755
--- a/smoketest/scripts/cli/test_interfaces_geneve.py
+++ b/smoketest/scripts/cli/test_interfaces_geneve.py
@@ -17,6 +17,9 @@
import unittest
from vyos.configsession import ConfigSession
+from vyos.ifconfig import Interface
+from vyos.util import get_interface_config
+
from base_interfaces_test import BasicInterfaceTest
class GeneveInterfaceTest(BasicInterfaceTest.BaseTest):
@@ -28,8 +31,49 @@ class GeneveInterfaceTest(BasicInterfaceTest.BaseTest):
cls._options = {
'gnv0': ['vni 10', 'remote 127.0.1.1'],
'gnv1': ['vni 20', 'remote 127.0.1.2'],
+ 'gnv1': ['vni 30', 'remote 2001:db8::1', 'parameters ipv6 flowlabel 0x1000'],
}
cls._interfaces = list(cls._options)
+ def test_geneve_parameters(self):
+ tos = '40'
+ ttl = 20
+ for intf in self._interfaces:
+ for option in self._options.get(intf, []):
+ self.session.set(self._base_path + [intf] + option.split())
+
+ self.session.set(self._base_path + [intf, 'parameters', 'ip', 'dont-fragment'])
+ self.session.set(self._base_path + [intf, 'parameters', 'ip', 'tos', tos])
+ self.session.set(self._base_path + [intf, 'parameters', 'ip', 'ttl', str(ttl)])
+ ttl += 10
+
+ self.session.commit()
+
+ ttl = 20
+ for interface in self._interfaces:
+ options = get_interface_config(interface)
+
+ vni = options['linkinfo']['info_data']['id']
+ self.assertIn(f'vni {vni}', self._options[interface])
+
+ if any('remote' in s for s in self._options[interface]):
+ key = 'remote'
+ if 'remote6' in options['linkinfo']['info_data']:
+ key = 'remote6'
+
+ remote = options['linkinfo']['info_data'][key]
+ self.assertIn(f'remote {remote}', self._options[interface])
+
+ if any('flowlabel' in s for s in self._options[interface]):
+ label = options['linkinfo']['info_data']['label']
+ self.assertIn(f'parameters ipv6 flowlabel {label}', 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'])
+ self.assertEqual(ttl, options['linkinfo']['info_data']['ttl'])
+ self.assertEqual(Interface(interface).get_admin_state(), 'up')
+ ttl += 10
+
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 a89895b92..74fd4f6c6 100755
--- a/smoketest/scripts/cli/test_interfaces_l2tpv3.py
+++ b/smoketest/scripts/cli/test_interfaces_l2tpv3.py
@@ -27,12 +27,12 @@ class GeneveInterfaceTest(BasicInterfaceTest.BaseTest):
cls._test_ipv6 = True
cls._base_path = ['interfaces', 'l2tpv3']
cls._options = {
- 'l2tpeth10': ['local-ip 127.0.0.1', 'remote-ip 127.10.10.10',
+ 'l2tpeth10': ['source-address 127.0.0.1', 'remote 127.10.10.10',
'tunnel-id 100', 'peer-tunnel-id 10',
'session-id 100', 'peer-session-id 10',
'source-port 1010', 'destination-port 10101'],
- 'l2tpeth20': ['local-ip 127.0.0.1', 'peer-session-id 20',
- 'peer-tunnel-id 200', 'remote-ip 127.20.20.20',
+ 'l2tpeth20': ['source-address 127.0.0.1', 'peer-session-id 20',
+ 'peer-tunnel-id 200', 'remote 127.20.20.20',
'session-id 20', 'tunnel-id 200',
'source-port 2020', 'destination-port 20202'],
}
diff --git a/smoketest/scripts/cli/test_interfaces_macsec.py b/smoketest/scripts/cli/test_interfaces_macsec.py
index 3a3e7bff3..31071a0f7 100755
--- a/smoketest/scripts/cli/test_interfaces_macsec.py
+++ b/smoketest/scripts/cli/test_interfaces_macsec.py
@@ -14,6 +14,7 @@
# 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 re
import unittest
@@ -22,7 +23,9 @@ 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
def get_config_value(interface, key):
@@ -30,6 +33,10 @@ def get_config_value(interface, key):
tmp = re.findall(r'\n?{}=(.*)'.format(key), tmp)
return tmp[0]
+def get_cipher(interface):
+ tmp = get_interface_config(interface)
+ return tmp['linkinfo']['info_data']['cipher_suite'].lower()
+
class MACsecInterfaceTest(BasicInterfaceTest.BaseTest):
@classmethod
def setUpClass(cls):
@@ -107,8 +114,30 @@ class MACsecInterfaceTest(BasicInterfaceTest.BaseTest):
# Check for running process
self.assertTrue(process_named_running('wpa_supplicant'))
- def test_macsec_mandatory_options(self):
+ def test_macsec_gcm_aes_128(self):
interface = 'macsec1'
+ cipher = 'gcm-aes-128'
+ self.session.set(self._base_path + [interface])
+
+ # check validate() - source interface is mandatory
+ with self.assertRaises(ConfigSessionError):
+ self.session.commit()
+ self.session.set(self._base_path + [interface, 'source-interface', 'eth0'])
+
+ # check validate() - cipher is mandatory
+ with self.assertRaises(ConfigSessionError):
+ self.session.commit()
+ self.session.set(self._base_path + [interface, 'security', 'cipher', cipher])
+
+ # final commit and verify
+ self.session.commit()
+ self.assertIn(interface, interfaces())
+ self.assertIn(interface, interfaces())
+ self.assertEqual(cipher, get_cipher(interface))
+
+ def test_macsec_gcm_aes_256(self):
+ interface = 'macsec4'
+ cipher = 'gcm-aes-256'
self.session.set(self._base_path + [interface])
# check validate() - source interface is mandatory
@@ -119,11 +148,12 @@ class MACsecInterfaceTest(BasicInterfaceTest.BaseTest):
# check validate() - cipher is mandatory
with self.assertRaises(ConfigSessionError):
self.session.commit()
- self.session.set(self._base_path + [interface, 'security', 'cipher', 'gcm-aes-128'])
+ self.session.set(self._base_path + [interface, 'security', 'cipher', cipher])
# final commit and verify
self.session.commit()
self.assertIn(interface, interfaces())
+ 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
diff --git a/smoketest/scripts/cli/test_interfaces_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py
index a9250e3e5..3dddb5ef0 100755
--- a/smoketest/scripts/cli/test_interfaces_tunnel.py
+++ b/smoketest/scripts/cli/test_interfaces_tunnel.py
@@ -15,11 +15,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import unittest
-import json
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
-from vyos.util import cmd
+from vyos.util import get_interface_config
+from vyos.template import inc_ip
from base_interfaces_test import BasicInterfaceTest
@@ -28,38 +28,6 @@ remote_ip6 = '2001:db8::ffff'
source_if = 'dum2222'
mtu = 1476
-def tunnel_conf(interface):
- tmp = cmd(f'ip -d -j link show {interface}')
- # {'address': '2.2.2.2',
- # 'broadcast': '192.0.2.10',
- # 'flags': ['POINTOPOINT', 'NOARP', 'UP', 'LOWER_UP'],
- # 'group': 'default',
- # 'gso_max_segs': 65535,
- # 'gso_max_size': 65536,
- # 'ifindex': 10,
- # 'ifname': 'tun10',
- # 'inet6_addr_gen_mode': 'none',
- # 'link': None,
- # 'link_pointtopoint': True,
- # 'link_type': 'gre',
- # 'linkinfo': {'info_data': {'local': '2.2.2.2',
- # 'pmtudisc': True,
- # 'remote': '192.0.2.10',
- # 'tos': '0x1',
- # 'ttl': 255},
- # 'info_kind': 'gre'},
- # 'linkmode': 'DEFAULT',
- # 'max_mtu': 65511,
- # 'min_mtu': 68,
- # 'mtu': 1476,
- # 'num_rx_queues': 1,
- # 'num_tx_queues': 1,
- # 'operstate': 'UNKNOWN',
- # 'promiscuity': 0,
- # 'qdisc': 'noqueue',
- # 'txqlen': 1000}
- return json.loads(tmp)[0]
-
class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
@classmethod
def setUpClass(cls):
@@ -70,8 +38,8 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
cls.local_v4 = '192.0.2.1'
cls.local_v6 = '2001:db8::1'
cls._options = {
- 'tun10': ['encapsulation ipip', 'remote-ip 192.0.2.10', 'local-ip ' + cls.local_v4],
- 'tun20': ['encapsulation gre', 'remote-ip 192.0.2.20', 'local-ip ' + cls.local_v4],
+ 'tun10': ['encapsulation ipip', 'remote 192.0.2.10', 'source-address ' + cls.local_v4],
+ 'tun20': ['encapsulation gre', 'remote 192.0.2.20', 'source-address ' + cls.local_v4],
}
cls._interfaces = list(cls._options)
@@ -90,25 +58,25 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
interface = f'tun1000'
local_if_addr = f'10.10.200.1/24'
- for encapsulation in ['ipip', 'sit', 'gre', 'gre-bridge']:
+ for encapsulation in ['ipip', 'sit', 'gre', 'gretap']:
self.session.set(self._base_path + [interface, 'address', local_if_addr])
self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v6])
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip6])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v6])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip6])
- # Encapsulation mode requires IPv4 local-ip
+ # Encapsulation mode requires IPv4 source-address
with self.assertRaises(ConfigSessionError):
self.session.commit()
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v4])
- # Encapsulation mode requires IPv4 local-ip
+ # Encapsulation mode requires IPv4 remote
with self.assertRaises(ConfigSessionError):
self.session.commit()
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip4])
self.session.set(self._base_path + [interface, 'source-interface', source_if])
- # Source interface can not be used with sit and gre-bridge
- if encapsulation in ['sit', 'gre-bridge']:
+ # Source interface can not be used with sit and gretap
+ if encapsulation in ['sit', 'gretap']:
with self.assertRaises(ConfigSessionError):
self.session.commit()
self.session.delete(self._base_path + [interface, 'source-interface'])
@@ -116,18 +84,15 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
# Check if commit is ok
self.session.commit()
- conf = tunnel_conf(interface)
- self.assertEqual(interface, conf['ifname'])
- self.assertEqual(mtu, conf['mtu'])
-
- if encapsulation not in ['sit', 'gre-bridge']:
+ conf = get_interface_config(interface)
+ if encapsulation not in ['sit', 'gretap']:
self.assertEqual(source_if, conf['link'])
- self.assertEqual(encapsulation, conf['link_type'])
- elif encapsulation in ['gre-bridge']:
- self.assertEqual('ether', conf['link_type'])
+ self.assertEqual(interface, conf['ifname'])
+ self.assertEqual(mtu, conf['mtu'])
+ self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
- self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
+ self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
self.assertTrue(conf['linkinfo']['info_data']['pmtudisc'])
# cleanup this instance
@@ -140,41 +105,49 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
interface = f'tun1010'
local_if_addr = f'10.10.200.1/24'
- for encapsulation in ['ipip6', 'ip6ip6', 'ip6gre']:
+ for encapsulation in ['ipip6', 'ip6ip6', 'ip6gre', 'ip6gretap']:
self.session.set(self._base_path + [interface, 'address', local_if_addr])
self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip4])
- # Encapsulation mode requires IPv6 local-ip
+ # Encapsulation mode requires IPv6 source-address
with self.assertRaises(ConfigSessionError):
self.session.commit()
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v6])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v6])
- # Encapsulation mode requires IPv6 local-ip
+ # Encapsulation mode requires IPv6 remote
with self.assertRaises(ConfigSessionError):
self.session.commit()
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip6])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip6])
# Configure Tunnel Source interface
self.session.set(self._base_path + [interface, 'source-interface', source_if])
+ # Source interface can not be used with ip6gretap
+ if encapsulation in ['ip6gretap']:
+ with self.assertRaises(ConfigSessionError):
+ self.session.commit()
+ self.session.delete(self._base_path + [interface, 'source-interface'])
# Check if commit is ok
self.session.commit()
- conf = tunnel_conf(interface)
+ conf = get_interface_config(interface)
+ if encapsulation not in ['ip6gretap']:
+ self.assertEqual(source_if, conf['link'])
+
self.assertEqual(interface, conf['ifname'])
self.assertEqual(mtu, conf['mtu'])
- self.assertEqual(source_if, conf['link'])
- # remap encapsulation protocol(s)
- if encapsulation in ['ipip6', 'ip6ip6']:
- encapsulation = 'tunnel6'
- elif encapsulation in ['ip6gre']:
- encapsulation = 'gre6'
+ # Not applicable for ip6gre
+ if 'proto' in conf['linkinfo']['info_data']:
+ self.assertEqual(encapsulation, conf['linkinfo']['info_data']['proto'])
- self.assertEqual(encapsulation, conf['link_type'])
+ # remap encapsulation protocol(s) only for ipip6, ip6ip6
+ if encapsulation in ['ipip6', 'ip6ip6']:
+ encapsulation = 'ip6tnl'
+ self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local'])
self.assertEqual(remote_ip6, conf['linkinfo']['info_data']['remote'])
@@ -183,18 +156,18 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
self.session.commit()
def test_tunnel_verify_local_dhcp(self):
- # We can not use local-ip and dhcp-interface at the same time
+ # We can not use source-address and dhcp-interface at the same time
interface = f'tun1020'
local_if_addr = f'10.0.0.1/24'
self.session.set(self._base_path + [interface, 'address', local_if_addr])
self.session.set(self._base_path + [interface, 'encapsulation', 'gre'])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip4])
self.session.set(self._base_path + [interface, 'dhcp-interface', 'eth0'])
- # local-ip and dhcp-interface can not be used at the same time
+ # source-address and dhcp-interface can not be used at the same time
with self.assertRaises(ConfigSessionError):
self.session.commit()
self.session.delete(self._base_path + [interface, 'dhcp-interface'])
@@ -209,8 +182,8 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
tos = '20'
self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip4])
self.session.set(self._base_path + [interface, 'parameters', 'ip', 'no-pmtu-discovery'])
self.session.set(self._base_path + [interface, 'parameters', 'ip', 'key', gre_key])
@@ -219,14 +192,44 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
# Check if commit is ok
self.session.commit()
- conf = tunnel_conf(interface)
+ conf = get_interface_config(interface)
self.assertEqual(mtu, conf['mtu'])
self.assertEqual(interface, conf['ifname'])
- self.assertEqual(encapsulation, conf['link_type'])
+ self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
self.assertEqual(0, conf['linkinfo']['info_data']['ttl'])
self.assertFalse( conf['linkinfo']['info_data']['pmtudisc'])
+ def test_gretap_parameters_change(self):
+ interface = f'tun1040'
+ gre_key = '10'
+ encapsulation = 'gretap'
+ tos = '20'
+
+ self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip4])
+
+ # Check if commit is ok
+ self.session.commit()
+
+ conf = get_interface_config(interface)
+ self.assertEqual(mtu, conf['mtu'])
+ self.assertEqual(interface, conf['ifname'])
+ self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
+ self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
+ self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
+ self.assertEqual(0, conf['linkinfo']['info_data']['ttl'])
+
+ # Change remote ip address (inc host by 2
+ new_remote = inc_ip(remote_ip4, 2)
+ self.session.set(self._base_path + [interface, 'remote', new_remote])
+ # Check if commit is ok
+ self.session.commit()
+
+ conf = get_interface_config(interface)
+ self.assertEqual(new_remote, conf['linkinfo']['info_data']['remote'])
+
if __name__ == '__main__':
- unittest.main(verbosity=2)
+ unittest.main(verbosity=2, failfast=True)
diff --git a/smoketest/scripts/cli/test_interfaces_vxlan.py b/smoketest/scripts/cli/test_interfaces_vxlan.py
index fcc1b15ce..2a04b0477 100755
--- a/smoketest/scripts/cli/test_interfaces_vxlan.py
+++ b/smoketest/scripts/cli/test_interfaces_vxlan.py
@@ -16,7 +16,10 @@
import unittest
-from vyos.configsession import ConfigSession, ConfigSessionError
+from vyos.configsession import ConfigSession
+from vyos.ifconfig import Interface
+from vyos.util import get_interface_config
+
from base_interfaces_test import BasicInterfaceTest
class VXLANInterfaceTest(BasicInterfaceTest.BaseTest):
@@ -27,10 +30,59 @@ class VXLANInterfaceTest(BasicInterfaceTest.BaseTest):
cls._test_mtu = True
cls._base_path = ['interfaces', 'vxlan']
cls._options = {
- 'vxlan0': ['vni 10', 'remote 127.0.0.2'],
- 'vxlan1': ['vni 20', 'group 239.1.1.1', 'source-interface eth0'],
+ 'vxlan10': ['vni 10', 'remote 127.0.0.2'],
+ 'vxlan20': ['vni 20', 'group 239.1.1.1', 'source-interface eth0'],
+ 'vxlan30': ['vni 30', 'remote 2001:db8:2000::1', 'source-address 2001:db8:1000::1', 'parameters ipv6 flowlabel 0x1000'],
}
cls._interfaces = list(cls._options)
+ def test_vxlan_parameters(self):
+ tos = '40'
+ ttl = 20
+ for intf in self._interfaces:
+ for option in self._options.get(intf, []):
+ self.session.set(self._base_path + [intf] + option.split())
+
+ self.session.set(self._base_path + [intf, 'parameters', 'ip', 'dont-fragment'])
+ self.session.set(self._base_path + [intf, 'parameters', 'ip', 'tos', tos])
+ self.session.set(self._base_path + [intf, 'parameters', 'ip', 'ttl', str(ttl)])
+ ttl += 10
+
+ self.session.commit()
+
+ ttl = 20
+ for interface in self._interfaces:
+ options = get_interface_config(interface)
+
+ vni = options['linkinfo']['info_data']['id']
+ self.assertIn(f'vni {vni}', self._options[interface])
+
+ if any('link' in s for s in self._options[interface]):
+ link = options['linkinfo']['info_data']['link']
+ self.assertIn(f'source-interface {link}', self._options[interface])
+
+ if any('local6' in s for s in self._options[interface]):
+ remote = options['linkinfo']['info_data']['local6']
+ self.assertIn(f'source-address {local6}', self._options[interface])
+
+ if any('remote6' in s for s in self._options[interface]):
+ remote = options['linkinfo']['info_data']['remote6']
+ self.assertIn(f'remote {remote}', self._options[interface])
+
+ if any('group' in s for s in self._options[interface]):
+ group = options['linkinfo']['info_data']['group']
+ self.assertIn(f'group {group}', self._options[interface])
+
+ if any('flowlabel' in s for s in self._options[interface]):
+ label = options['linkinfo']['info_data']['label']
+ self.assertIn(f'parameters ipv6 flowlabel {label}', self._options[interface])
+
+ self.assertEqual('vxlan', options['linkinfo']['info_kind'])
+ self.assertEqual('set', options['linkinfo']['info_data']['df'])
+ self.assertEqual(f'0x{tos}', options['linkinfo']['info_data']['tos'])
+ self.assertEqual(ttl, options['linkinfo']['info_data']['ttl'])
+ self.assertEqual(Interface(interface).get_admin_state(), 'up')
+ ttl += 10
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_nat66.py b/smoketest/scripts/cli/test_nat66.py
index ccc4196e0..4838fb8d8 100755
--- a/smoketest/scripts/cli/test_nat66.py
+++ b/smoketest/scripts/cli/test_nat66.py
@@ -44,7 +44,7 @@ class TestNAT66(unittest.TestCase):
translation_prefix = 'fc01::/64'
self.session.set(src_path + ['rule', '1', 'outbound-interface', 'eth1'])
self.session.set(src_path + ['rule', '1', 'source', 'prefix', source_prefix])
- self.session.set(src_path + ['rule', '1', 'translation', 'prefix', translation_prefix])
+ self.session.set(src_path + ['rule', '1', 'translation', 'address', translation_prefix])
# check validate() - outbound-interface must be defined
self.session.commit()
@@ -70,6 +70,36 @@ class TestNAT66(unittest.TestCase):
self.assertEqual(f'{translation_address}/{translation_mask}', translation_prefix)
self.assertEqual(f'{address}/{mask}', source_prefix)
+ def test_source_nat66_address(self):
+ source_prefix = 'fc00::/64'
+ translation_address = 'fc00::1'
+ self.session.set(src_path + ['rule', '1', 'outbound-interface', 'eth1'])
+ self.session.set(src_path + ['rule', '1', 'source', 'prefix', source_prefix])
+ self.session.set(src_path + ['rule', '1', 'translation', 'address', translation_address])
+
+ # check validate() - outbound-interface must be defined
+ self.session.commit()
+
+ tmp = cmd('sudo nft -j list table ip6 nat')
+ data_json = jmespath.search('nftables[?rule].rule[?chain]', json.loads(tmp))
+
+ for idx in range(0, len(data_json)):
+ data = data_json[idx]
+
+ self.assertEqual(data['chain'], 'POSTROUTING')
+ self.assertEqual(data['family'], 'ip6')
+ self.assertEqual(data['table'], 'nat')
+
+ iface = dict_search('match.right', data['expr'][0])
+ address = dict_search('match.right.prefix.addr', data['expr'][2])
+ mask = dict_search('match.right.prefix.len', data['expr'][2])
+ snat_address = dict_search('snat.addr', data['expr'][3])
+
+ self.assertEqual(iface, 'eth1')
+ # check for translation address
+ self.assertEqual(snat_address, translation_address)
+ self.assertEqual(f'{address}/{mask}', source_prefix)
+
def test_destination_nat66(self):
destination_address = 'fc00::1'
translation_address = 'fc01::1'
@@ -127,7 +157,6 @@ class TestNAT66(unittest.TestCase):
# T2813: Ensure translation address is specified
rule = '5'
source_prefix = 'fc00::/64'
- translation_prefix = 'fc00:2::/64'
self.session.set(src_path + ['rule', rule, 'source', 'prefix', source_prefix])
# check validate() - outbound-interface must be defined
@@ -139,7 +168,7 @@ class TestNAT66(unittest.TestCase):
with self.assertRaises(ConfigSessionError):
self.session.commit()
- self.session.set(src_path + ['rule', rule, 'translation', 'prefix', translation_prefix])
+ self.session.set(src_path + ['rule', rule, 'translation', 'address', 'masquerade'])
self.session.commit()
def test_nat66_no_rules(self):
diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py
new file mode 100755
index 000000000..8efbab7e5
--- /dev/null
+++ b/smoketest/scripts/cli/test_policy.py
@@ -0,0 +1,681 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 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 vyos.util import cmd
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
+
+base_path = ['policy']
+
+def getFRRconfig(section):
+ return cmd(f'vtysh -c "show run" | sed -n "/^{section}/,/^!/p"')
+
+class TestPolicy(unittest.TestCase):
+ def setUp(self):
+ self.session = ConfigSession(os.getpid())
+
+ def tearDown(self):
+ self.session.delete(base_path)
+ self.session.commit()
+ del self.session
+
+ def test_access_list(self):
+ acls = {
+ '50' : {
+ 'rule' : {
+ '5' : {
+ 'action' : 'permit',
+ 'source' : { 'any' : '' },
+ },
+ '10' : {
+ 'action' : 'deny',
+ 'source' : { 'host' : '1.2.3.4' },
+ },
+ },
+ },
+ '150' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'source' : { 'any' : '' },
+ 'destination' : { 'host' : '2.2.2.2' },
+ },
+ '10' : {
+ 'action' : 'deny',
+ 'source' : { 'any' : '' },
+ 'destination' : { 'any' : '' },
+ },
+ },
+ },
+ '2000' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'destination' : { 'any' : '' },
+ 'source' : { 'network' : '10.0.0.0', 'inverse-mask' : '0.255.255.255' },
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'destination' : { 'any' : '' },
+ 'source' : { 'network' : '172.16.0.0', 'inverse-mask' : '0.15.255.255' },
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'destination' : { 'any' : '' },
+ 'source' : { 'network' : '192.168.0.0', 'inverse-mask' : '0.0.255.255' },
+ },
+ '50' : {
+ 'action' : 'permit',
+ 'destination' : { 'network' : '172.16.0.0', 'inverse-mask' : '0.15.255.255' },
+ 'source' : { 'network' : '10.0.0.0', 'inverse-mask' : '0.255.255.255' },
+ },
+ '60' : {
+ 'action' : 'deny',
+ 'destination' : { 'network' : '192.168.0.0', 'inverse-mask' : '0.0.255.255' },
+ 'source' : { 'network' : '172.16.0.0', 'inverse-mask' : '0.15.255.255' },
+ },
+ '70' : {
+ 'action' : 'deny',
+ 'destination' : { 'any' : '' },
+ 'source' : { 'any' : '' },
+ },
+ },
+ },
+ }
+
+ for acl, acl_config in acls.items():
+ path = base_path + ['access-list', acl]
+ self.session.set(path + ['description', f'VyOS-ACL-{acl}'])
+ if 'rule' not in acl_config:
+ continue
+
+ for rule, rule_config in acl_config['rule'].items():
+ self.session.set(path + ['rule', rule, 'action', rule_config['action']])
+ for direction in ['source', 'destination']:
+ if direction in rule_config:
+ if 'any' in rule_config[direction]:
+ self.session.set(path + ['rule', rule, direction, 'any'])
+ if 'host' in rule_config[direction]:
+ self.session.set(path + ['rule', rule, direction, 'host', rule_config[direction]['host']])
+ if 'network' in rule_config[direction]:
+ self.session.set(path + ['rule', rule, direction, 'network', rule_config[direction]['network']])
+ self.session.set(path + ['rule', rule, direction, 'inverse-mask', rule_config[direction]['inverse-mask']])
+
+ self.session.commit()
+
+ config = getFRRconfig('access-list')
+ for acl, acl_config in acls.items():
+ seq = '5'
+ for rule, rule_config in acl_config['rule'].items():
+ tmp = f'access-list {acl} seq {seq}'
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ if {'source', 'destination'} <= set(rule_config):
+ tmp += ' ip'
+
+ for direction in ['source', 'destination']:
+ if direction in rule_config:
+ if 'any' in rule_config[direction]:
+ tmp += ' any'
+ if 'host' in rule_config[direction]:
+ tmp += ' ' + rule_config[direction]['host']
+ if 'network' in rule_config[direction]:
+ tmp += ' ' + rule_config[direction]['network'] + ' ' + rule_config[direction]['inverse-mask']
+
+ self.assertIn(tmp, config)
+ seq = int(seq) + 5
+
+ def test_access_list6(self):
+ acls = {
+ '50' : {
+ 'rule' : {
+ '5' : {
+ 'action' : 'permit',
+ 'source' : { 'any' : '' },
+ },
+ '10' : {
+ 'action' : 'deny',
+ 'source' : { 'network' : '2001:db8:10::/48', 'exact-match' : '' },
+ },
+ '10' : {
+ 'action' : 'deny',
+ 'source' : { 'network' : '2001:db8:20::/48' },
+ },
+ },
+ },
+ '100' : {
+ 'rule' : {
+ '5' : {
+ 'action' : 'deny',
+ 'source' : { 'network' : '2001:db8:10::/64', 'exact-match' : '' },
+ },
+ '10' : {
+ 'action' : 'deny',
+ 'source' : { 'network' : '2001:db8:20::/64', },
+ },
+ '15' : {
+ 'action' : 'deny',
+ 'source' : { 'network' : '2001:db8:30::/64', 'exact-match' : '' },
+ },
+ '20' : {
+ 'action' : 'deny',
+ 'source' : { 'network' : '2001:db8:40::/64', 'exact-match' : '' },
+ },
+ '100' : {
+ 'action' : 'deny',
+ 'source' : { 'any' : '' },
+ },
+ },
+ },
+ }
+
+ for acl, acl_config in acls.items():
+ path = base_path + ['access-list6', acl]
+ self.session.set(path + ['description', f'VyOS-ACL-{acl}'])
+ if 'rule' not in acl_config:
+ continue
+
+ for rule, rule_config in acl_config['rule'].items():
+ self.session.set(path + ['rule', rule, 'action', rule_config['action']])
+ for direction in ['source', 'destination']:
+ if direction in rule_config:
+ if 'any' in rule_config[direction]:
+ self.session.set(path + ['rule', rule, direction, 'any'])
+ if 'network' in rule_config[direction]:
+ self.session.set(path + ['rule', rule, direction, 'network', rule_config[direction]['network']])
+ if 'exact-match' in rule_config[direction]:
+ self.session.set(path + ['rule', rule, direction, 'exact-match'])
+
+ self.session.commit()
+
+ config = getFRRconfig('ipv6 access-list')
+ for acl, acl_config in acls.items():
+ seq = '5'
+ for rule, rule_config in acl_config['rule'].items():
+ tmp = f'ipv6 access-list {acl} seq {seq}'
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ if {'source', 'destination'} <= set(rule_config):
+ tmp += ' ip'
+
+ for direction in ['source', 'destination']:
+ if direction in rule_config:
+ if 'any' in rule_config[direction]:
+ tmp += ' any'
+ if 'network' in rule_config[direction]:
+ tmp += ' ' + rule_config[direction]['network']
+ if 'exact-match' in rule_config[direction]:
+ tmp += ' exact-match'
+
+ self.assertIn(tmp, config)
+ seq = int(seq) + 5
+
+
+ def test_as_path_list(self):
+ test_data = {
+ 'VyOS' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'regex' : '^44501 64502$',
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'regex' : '44501|44502|44503',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'regex' : '^44501_([0-9]+_)+',
+ },
+ },
+ },
+ 'Customers' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'regex' : '_10_',
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'regex' : '_20_',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'regex' : '_30_',
+ },
+ '30' : {
+ 'action' : 'deny',
+ 'regex' : '_40_',
+ },
+ },
+ },
+ 'bogons' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'regex' : '_0_',
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'regex' : '_23456_',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'regex' : '_6449[6-9]_|_65[0-4][0-9][0-9]_|_655[0-4][0-9]_|_6555[0-1]_',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'regex' : '_6555[2-9]_|_655[6-9][0-9]_|_65[6-9][0-9][0-9]_|_6[6-9][0-9][0-9][0-]_|_[7-9][0-9][0-9][0-9][0-9]_|_1[0-2][0-9][0-9][0-9][0-9]_|_130[0-9][0-9][0-9]_|_1310[0-6][0-9]_|_13107[01]_',
+ },
+ },
+ },
+ }
+
+ for as_path, as_path_config in test_data.items():
+ path = base_path + ['as-path-list', as_path]
+ self.session.set(path + ['description', f'VyOS-ASPATH-{as_path}'])
+ if 'rule' not in as_path_config:
+ continue
+
+ for rule, rule_config in as_path_config['rule'].items():
+ if 'action' in rule_config:
+ self.session.set(path + ['rule', rule, 'action', rule_config['action']])
+ if 'regex' in rule_config:
+ self.session.set(path + ['rule', rule, 'regex', rule_config['regex']])
+
+ self.session.commit()
+
+ config = getFRRconfig('bgp as-path access-list')
+ for as_path, as_path_config in test_data.items():
+ if 'rule' not in as_path_config:
+ continue
+
+ for rule, rule_config in as_path_config['rule'].items():
+ tmp = f'bgp as-path access-list {as_path}'
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ tmp += ' ' + rule_config['regex']
+
+ self.assertIn(tmp, config)
+
+ def test_community_list(self):
+ test_data = {
+ '100' : {
+ 'rule' : {
+ '4' : {
+ 'action' : 'permit',
+ 'regex' : '.*',
+ },
+ },
+ },
+ '200' : {
+ 'rule' : {
+ '1' : {
+ 'action' : 'deny',
+ 'regex' : '^1:201$',
+ },
+ '2' : {
+ 'action' : 'deny',
+ 'regex' : '1:101$',
+ },
+ '3' : {
+ 'action' : 'deny',
+ 'regex' : '^1:100$',
+ },
+ },
+ },
+ }
+
+ for comm_list, comm_list_config in test_data.items():
+ path = base_path + ['community-list', comm_list]
+ self.session.set(path + ['description', f'VyOS-COMM-{comm_list}'])
+ if 'rule' not in comm_list_config:
+ continue
+
+ for rule, rule_config in comm_list_config['rule'].items():
+ if 'action' in rule_config:
+ self.session.set(path + ['rule', rule, 'action', rule_config['action']])
+ if 'regex' in rule_config:
+ self.session.set(path + ['rule', rule, 'regex', rule_config['regex']])
+
+ self.session.commit()
+
+ config = getFRRconfig('bgp community-list')
+ for comm_list, comm_list_config in test_data.items():
+ if 'rule' not in comm_list_config:
+ continue
+
+ seq = '5'
+ for rule, rule_config in comm_list_config['rule'].items():
+ tmp = f'bgp community-list {comm_list} seq {seq}'
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ tmp += ' ' + rule_config['regex']
+
+ self.assertIn(tmp, config)
+ seq = int(seq) + 5
+
+ def test_extended_community_list(self):
+ test_data = {
+ 'foo' : {
+ 'rule' : {
+ '4' : {
+ 'action' : 'permit',
+ 'regex' : '.*',
+ },
+ },
+ },
+ '200' : {
+ 'rule' : {
+ '1' : {
+ 'action' : 'deny',
+ 'regex' : '^1:201$',
+ },
+ '2' : {
+ 'action' : 'deny',
+ 'regex' : '1:101$',
+ },
+ '3' : {
+ 'action' : 'deny',
+ 'regex' : '^1:100$',
+ },
+ },
+ },
+ }
+
+ for comm_list, comm_list_config in test_data.items():
+ path = base_path + ['extcommunity-list', comm_list]
+ self.session.set(path + ['description', f'VyOS-EXTCOMM-{comm_list}'])
+ if 'rule' not in comm_list_config:
+ continue
+
+ for rule, rule_config in comm_list_config['rule'].items():
+ if 'action' in rule_config:
+ self.session.set(path + ['rule', rule, 'action', rule_config['action']])
+ if 'regex' in rule_config:
+ self.session.set(path + ['rule', rule, 'regex', rule_config['regex']])
+
+ self.session.commit()
+
+ config = getFRRconfig('bgp extcommunity-list')
+ for comm_list, comm_list_config in test_data.items():
+ if 'rule' not in comm_list_config:
+ continue
+
+ seq = '5'
+ for rule, rule_config in comm_list_config['rule'].items():
+ # if the community is not a number but a name, the expanded
+ # keyword is used
+ expanded = ''
+ if not comm_list.isnumeric():
+ expanded = ' expanded'
+ tmp = f'bgp extcommunity-list{expanded} {comm_list} seq {seq}'
+
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ tmp += ' ' + rule_config['regex']
+
+ self.assertIn(tmp, config)
+ seq = int(seq) + 5
+
+
+ def test_large_community_list(self):
+ test_data = {
+ 'foo' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'regex' : '667:123:100',
+ },
+ },
+ },
+ 'bar' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'regex' : '65000:120:10',
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'regex' : '65000:120:20',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'regex' : '65000:120:30',
+ },
+ },
+ },
+ }
+
+ for comm_list, comm_list_config in test_data.items():
+ path = base_path + ['large-community-list', comm_list]
+ self.session.set(path + ['description', f'VyOS-LARGECOMM-{comm_list}'])
+ if 'rule' not in comm_list_config:
+ continue
+
+ for rule, rule_config in comm_list_config['rule'].items():
+ if 'action' in rule_config:
+ self.session.set(path + ['rule', rule, 'action', rule_config['action']])
+ if 'regex' in rule_config:
+ self.session.set(path + ['rule', rule, 'regex', rule_config['regex']])
+
+ self.session.commit()
+
+ config = getFRRconfig('bgp large-community-list')
+ for comm_list, comm_list_config in test_data.items():
+ if 'rule' not in comm_list_config:
+ continue
+
+ seq = '5'
+ for rule, rule_config in comm_list_config['rule'].items():
+ tmp = f'bgp large-community-list expanded {comm_list} seq {seq}'
+
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ tmp += ' ' + rule_config['regex']
+
+ self.assertIn(tmp, config)
+ seq = int(seq) + 5
+
+
+ def test_prefix_list(self):
+ test_data = {
+ 'foo' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'prefix' : '10.0.0.0/8',
+ 'ge' : '16',
+ 'le' : '24',
+ },
+ '20' : {
+ 'action' : 'deny',
+ 'prefix' : '172.16.0.0/12',
+ 'ge' : '16',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'prefix' : '192.168.0.0/16',
+ },
+ },
+ },
+ 'bar' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'prefix' : '10.0.10.0/24',
+ 'ge' : '25',
+ 'le' : '26',
+ },
+ '20' : {
+ 'action' : 'deny',
+ 'prefix' : '10.0.20.0/24',
+ 'le' : '25',
+ },
+ '25' : {
+ 'action' : 'permit',
+ 'prefix' : '10.0.25.0/24',
+ },
+ },
+ },
+ }
+
+ for prefix_list, prefix_list_config in test_data.items():
+ path = base_path + ['prefix-list', prefix_list]
+ self.session.set(path + ['description', f'VyOS-PFX-LIST-{prefix_list}'])
+ if 'rule' not in prefix_list_config:
+ continue
+
+ for rule, rule_config in prefix_list_config['rule'].items():
+ if 'action' in rule_config:
+ self.session.set(path + ['rule', rule, 'action', rule_config['action']])
+ if 'prefix' in rule_config:
+ self.session.set(path + ['rule', rule, 'prefix', rule_config['prefix']])
+ if 'ge' in rule_config:
+ self.session.set(path + ['rule', rule, 'ge', rule_config['ge']])
+ if 'le' in rule_config:
+ self.session.set(path + ['rule', rule, 'le', rule_config['le']])
+
+ self.session.commit()
+
+ config = getFRRconfig('ip prefix-list')
+ for prefix_list, prefix_list_config in test_data.items():
+ if 'rule' not in prefix_list_config:
+ continue
+
+ for rule, rule_config in prefix_list_config['rule'].items():
+ tmp = f'ip prefix-list {prefix_list} seq {rule}'
+
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ tmp += ' ' + rule_config['prefix']
+
+ if 'ge' in rule_config:
+ tmp += ' ge ' + rule_config['ge']
+ if 'le' in rule_config:
+ tmp += ' le ' + rule_config['le']
+
+ self.assertIn(tmp, config)
+
+
+ def test_prefix_list6(self):
+ test_data = {
+ 'foo' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'prefix' : '2001:db8::/32',
+ 'ge' : '40',
+ 'le' : '48',
+ },
+ '20' : {
+ 'action' : 'deny',
+ 'prefix' : '2001:db8::/32',
+ 'ge' : '48',
+ },
+ '30' : {
+ 'action' : 'permit',
+ 'prefix' : '2001:db8:1000::/64',
+ },
+ },
+ },
+ 'bar' : {
+ 'rule' : {
+ '10' : {
+ 'action' : 'permit',
+ 'prefix' : '2001:db8:100::/40',
+ 'ge' : '48',
+ },
+ '20' : {
+ 'action' : 'permit',
+ 'prefix' : '2001:db8:200::/40',
+ 'ge' : '48',
+ },
+ '25' : {
+ 'action' : 'deny',
+ 'prefix' : '2001:db8:300::/40',
+ 'le' : '64',
+ },
+ },
+ },
+ }
+
+ for prefix_list, prefix_list_config in test_data.items():
+ path = base_path + ['prefix-list6', prefix_list]
+ self.session.set(path + ['description', f'VyOS-PFX-LIST-{prefix_list}'])
+ if 'rule' not in prefix_list_config:
+ continue
+
+ for rule, rule_config in prefix_list_config['rule'].items():
+ if 'action' in rule_config:
+ self.session.set(path + ['rule', rule, 'action', rule_config['action']])
+ if 'prefix' in rule_config:
+ self.session.set(path + ['rule', rule, 'prefix', rule_config['prefix']])
+ if 'ge' in rule_config:
+ self.session.set(path + ['rule', rule, 'ge', rule_config['ge']])
+ if 'le' in rule_config:
+ self.session.set(path + ['rule', rule, 'le', rule_config['le']])
+
+ self.session.commit()
+
+ config = getFRRconfig('ipv6 prefix-list')
+ for prefix_list, prefix_list_config in test_data.items():
+ if 'rule' not in prefix_list_config:
+ continue
+
+ for rule, rule_config in prefix_list_config['rule'].items():
+ tmp = f'ipv6 prefix-list {prefix_list} seq {rule}'
+
+ if rule_config['action'] == 'permit':
+ tmp += ' permit'
+ else:
+ tmp += ' deny'
+
+ tmp += ' ' + rule_config['prefix']
+
+ if 'ge' in rule_config:
+ tmp += ' ge ' + rule_config['ge']
+ if 'le' in rule_config:
+ tmp += ' le ' + rule_config['le']
+
+ self.assertIn(tmp, config)
+
+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 044b4b92e..80e5daa7c 100755
--- a/smoketest/scripts/cli/test_protocols_bfd.py
+++ b/smoketest/scripts/cli/test_protocols_bfd.py
@@ -25,38 +25,57 @@ from vyos.util import process_named_running
PROCESS_NAME = 'bfdd'
base_path = ['protocols', 'bfd']
-neighbor_config = {
- '192.0.2.1' : {
+dum_if = 'dum1001'
+peers = {
+ '192.0.2.10' : {
'intv_rx' : '500',
'intv_tx' : '600',
'multihop' : '',
'source_addr': '192.0.2.254',
},
- '192.0.2.2' : {
+ '192.0.2.20' : {
'echo_mode' : '',
'intv_echo' : '100',
- 'intv_mult' : '111',
+ 'intv_mult' : '100',
'intv_rx' : '222',
'intv_tx' : '333',
'shutdown' : '',
- 'source_intf': 'lo',
+ 'source_intf': dum_if,
},
- '2001:db8::1' : {
- 'source_addr': 'fe80::1',
- 'source_intf': 'eth0',
+ '2001:db8::a' : {
+ 'source_addr': '2001:db8::1',
+ 'source_intf': dum_if,
},
- '2001:db8::2' : {
- 'source_addr': 'fe80::1',
+ '2001:db8::b' : {
+ 'source_addr': '2001:db8::1',
'multihop' : '',
},
}
+profiles = {
+ 'foo' : {
+ 'echo_mode' : '',
+ 'intv_echo' : '100',
+ 'intv_mult' : '101',
+ 'intv_rx' : '222',
+ 'intv_tx' : '333',
+ 'shutdown' : '',
+ },
+ 'bar' : {
+ 'intv_mult' : '102',
+ 'intv_rx' : '444',
+ },
+}
+
def getFRRconfig():
return cmd('vtysh -c "show run" | sed -n "/^bfd/,/^!/p"')
def getBFDPeerconfig(peer):
return cmd(f'vtysh -c "show run" | sed -n "/^ {peer}/,/^!/p"')
+def getBFDProfileconfig(profile):
+ return cmd(f'vtysh -c "show run" | sed -n "/^ {profile}/,/^!/p"')
+
class TestProtocolsBFD(unittest.TestCase):
def setUp(self):
self.session = ConfigSession(os.getpid())
@@ -69,8 +88,8 @@ class TestProtocolsBFD(unittest.TestCase):
# Check for running process
self.assertTrue(process_named_running(PROCESS_NAME))
- def test_bfd_simple(self):
- for peer, peer_config in neighbor_config.items():
+ def test_bfd_peer(self):
+ for peer, peer_config in peers.items():
if 'echo_mode' in peer_config:
self.session.set(base_path + ['peer', peer, 'echo-mode'])
if 'intv_echo' in peer_config:
@@ -95,7 +114,7 @@ class TestProtocolsBFD(unittest.TestCase):
# Verify FRR bgpd configuration
frrconfig = getFRRconfig()
- for peer, peer_config in neighbor_config.items():
+ for peer, peer_config in peers.items():
tmp = f'peer {peer}'
if 'multihop' in peer_config:
tmp += f' multihop'
@@ -120,5 +139,43 @@ class TestProtocolsBFD(unittest.TestCase):
if 'shutdown' not in peer_config:
self.assertIn(f' no shutdown', peerconfig)
+ def test_bfd_profile(self):
+ peer = '192.0.2.10'
+
+ for profile, profile_config in profiles.items():
+ if 'echo_mode' in profile_config:
+ self.session.set(base_path + ['profile', profile, 'echo-mode'])
+ if 'intv_echo' in profile_config:
+ self.session.set(base_path + ['profile', profile, 'interval', 'echo-interval', profile_config["intv_echo"]])
+ if 'intv_mult' in profile_config:
+ self.session.set(base_path + ['profile', profile, 'interval', 'multiplier', profile_config["intv_mult"]])
+ if 'intv_rx' in profile_config:
+ self.session.set(base_path + ['profile', profile, 'interval', 'receive', profile_config["intv_rx"]])
+ if 'intv_tx' in profile_config:
+ self.session.set(base_path + ['profile', profile, 'interval', 'transmit', profile_config["intv_tx"]])
+ if 'shutdown' in profile_config:
+ self.session.set(base_path + ['profile', profile, 'shutdown'])
+
+ self.session.set(base_path + ['peer', peer, 'profile', list(profiles)[0]])
+
+ # commit changes
+ self.session.commit()
+
+ # Verify FRR bgpd configuration
+ for profile, profile_config in profiles.items():
+ config = getBFDProfileconfig(f'profile {profile}')
+ if 'echo_mode' in profile_config:
+ self.assertIn(f' echo-mode', config)
+ if 'intv_echo' in profile_config:
+ self.assertIn(f' echo-interval {profile_config["intv_echo"]}', config)
+ if 'intv_mult' in profile_config:
+ self.assertIn(f' detect-multiplier {profile_config["intv_mult"]}', config)
+ if 'intv_rx' in profile_config:
+ self.assertIn(f' receive-interval {profile_config["intv_rx"]}', config)
+ if 'intv_tx' in profile_config:
+ self.assertIn(f' transmit-interval {profile_config["intv_tx"]}', config)
+ if 'shutdown' not in profile_config:
+ self.assertIn(f' no shutdown', config)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index 1de51a1fc..7d397b55e 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -128,14 +128,19 @@ peer_group_config = {
},
}
-def getFRRBGPconfig():
- return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN}/,/^!/p"')
+def getFRRBGPconfig(vrf=None):
+ if vrf:
+ return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN} vrf {vrf}$/,/^!/p"')
+ return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN}$/,/^!/p"')
+
+def getFRRBgpAfiConfig(afi):
+ return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN}$/,/^!/p" | sed -n "/^ address-family {afi} unicast/,/^ exit-address-family/p"')
def getFRRBGPVNIconfig(vni):
- return cmd(f'vtysh -c "show run" | sed -n "/^ vni {vni}/,/^!/p"')
+ return cmd(f'vtysh -c "show run" | sed -n "/^ vni {vni}$/,/^!/p"')
def getFRRRPKIconfig():
- return cmd(f'vtysh -c "show run" | sed -n "/^rpki/,/^!/p"')
+ return cmd(f'vtysh -c "show run" | sed -n "/^rpki$/,/^!/p"')
class TestProtocolsBGP(unittest.TestCase):
def setUp(self):
@@ -218,15 +223,26 @@ class TestProtocolsBGP(unittest.TestCase):
router_id = '127.0.0.1'
local_pref = '500'
stalepath_time = '60'
+ max_path_v4 = '2'
+ max_path_v4ibgp = '4'
+ max_path_v6 = '8'
+ max_path_v6ibgp = '16'
self.session.set(base_path + ['parameters', 'router-id', router_id])
self.session.set(base_path + ['parameters', 'log-neighbor-changes'])
- # Default local preference (higher=more preferred)
+ # Default local preference (higher = more preferred, default value is 100)
self.session.set(base_path + ['parameters', 'default', 'local-pref', local_pref])
# Deactivate IPv4 unicast for a peer by default
self.session.set(base_path + ['parameters', 'default', 'no-ipv4-unicast'])
self.session.set(base_path + ['parameters', 'graceful-restart', 'stalepath-time', stalepath_time])
self.session.set(base_path + ['parameters', 'graceful-shutdown'])
+ self.session.set(base_path + ['parameters', 'ebgp-requires-policy'])
+
+ # AFI maximum path support
+ self.session.set(base_path + ['address-family', 'ipv4-unicast', 'maximum-paths', 'ebgp', max_path_v4])
+ self.session.set(base_path + ['address-family', 'ipv4-unicast', 'maximum-paths', 'ibgp', max_path_v4ibgp])
+ self.session.set(base_path + ['address-family', 'ipv6-unicast', 'maximum-paths', 'ebgp', max_path_v6])
+ self.session.set(base_path + ['address-family', 'ipv6-unicast', 'maximum-paths', 'ibgp', max_path_v6ibgp])
# commit changes
self.session.commit()
@@ -240,6 +256,15 @@ class TestProtocolsBGP(unittest.TestCase):
self.assertIn(f' no bgp default ipv4-unicast', frrconfig)
self.assertIn(f' bgp graceful-restart stalepath-time {stalepath_time}', frrconfig)
self.assertIn(f' bgp graceful-shutdown', frrconfig)
+ self.assertNotIn(f'bgp ebgp-requires-policy', frrconfig)
+
+ afiv4_config = getFRRBgpAfiConfig('ipv4')
+ self.assertIn(f' maximum-paths {max_path_v4}', afiv4_config)
+ self.assertIn(f' maximum-paths ibgp {max_path_v4ibgp}', afiv4_config)
+
+ afiv6_config = getFRRBgpAfiConfig('ipv6')
+ 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):
@@ -388,7 +413,7 @@ class TestProtocolsBGP(unittest.TestCase):
}
# We want to redistribute ...
- redistributes = ['connected', 'kernel', 'ospf', 'rip', 'static']
+ redistributes = ['connected', 'isis', 'kernel', 'ospf', 'rip', 'static']
for redistribute in redistributes:
self.session.set(base_path + ['address-family', 'ipv4-unicast',
'redistribute', redistribute])
@@ -453,6 +478,9 @@ class TestProtocolsBGP(unittest.TestCase):
frrconfig = getFRRBGPconfig()
self.assertIn(f'router bgp {ASN}', frrconfig)
self.assertIn(f' address-family ipv6 unicast', frrconfig)
+ # T2100: By default ebgp-requires-policy is disabled to keep VyOS
+ # 1.3 and 1.2 backwards compatibility
+ self.assertIn(f' no bgp ebgp-requires-policy', frrconfig)
for redistribute in redistributes:
# FRR calls this OSPF6
@@ -525,5 +553,27 @@ class TestProtocolsBGP(unittest.TestCase):
self.assertIn(f' advertise-default-gw', vniconfig)
self.assertIn(f' advertise-svi-ip', vniconfig)
+ def test_bgp_08_vrf_simple(self):
+ router_id = '127.0.0.3'
+ vrfs = ['red', 'green', 'blue']
+ # It is safe to assume that when the basic VRF test works, all
+ # other OSPF related features work, as we entirely inherit the CLI
+ # templates and Jinja2 FRR template.
+ table = '1000'
+ for vrf in vrfs:
+ vrf_base = ['vrf', 'name', vrf]
+ self.session.set(vrf_base + ['table', table])
+ self.session.set(vrf_base + ['protocols', 'bgp', ASN, 'parameters', 'router-id', router_id])
+ table = str(int(table) + 1000)
+
+ self.session.commit()
+
+ for vrf in vrfs:
+ # Verify FRR bgpd configuration
+ frrconfig = getFRRBGPconfig(vrf)
+
+ self.assertIn(f'router bgp {ASN} vrf {vrf}', frrconfig)
+ self.assertIn(f' bgp router-id {router_id}', frrconfig)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py
index ce30f6a7d..532d84cc8 100755
--- a/smoketest/scripts/cli/test_protocols_ospf.py
+++ b/smoketest/scripts/cli/test_protocols_ospf.py
@@ -27,8 +27,10 @@ base_path = ['protocols', 'ospf']
route_map = 'foo-bar-baz10'
-def getFRROSPFconfig():
- return cmd('vtysh -c "show run" | sed -n "/router ospf/,/^!/p"')
+def getFRRconfig(vrf=None):
+ if vrf:
+ return cmd(f'vtysh -c "show run" | sed -n "/^router ospf vrf {vrf}$/,/^!/p"')
+ return cmd('vtysh -c "show run" | sed -n "/^router ospf$/,/^!/p"')
def getFRRInterfaceConfig(interface):
return cmd(f'vtysh -c "show run" | sed -n "/^interface {interface}$/,/^!/p"')
@@ -45,6 +47,7 @@ class TestProtocolsOSPF(unittest.TestCase):
self.session.delete(['policy', 'route-map', route_map])
self.session.delete(base_path)
+
self.session.commit()
del self.session
@@ -54,12 +57,11 @@ class TestProtocolsOSPF(unittest.TestCase):
self.session.commit()
# Verify FRR ospfd configuration
- frrconfig = getFRROSPFconfig()
+ frrconfig = getFRRconfig()
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' auto-cost reference-bandwidth 100', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
-
def test_ospf_02_simple(self):
router_id = '127.0.0.1'
abr_type = 'ibm'
@@ -76,7 +78,7 @@ class TestProtocolsOSPF(unittest.TestCase):
self.session.commit()
# Verify FRR ospfd configuration
- frrconfig = getFRROSPFconfig()
+ frrconfig = getFRRconfig()
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' auto-cost reference-bandwidth {bandwidth}', frrconfig)
self.assertIn(f' ospf router-id {router_id}', frrconfig)
@@ -88,7 +90,7 @@ class TestProtocolsOSPF(unittest.TestCase):
def test_ospf_03_access_list(self):
acl = '100'
seq = '10'
- protocols = ['bgp', 'connected', 'kernel', 'rip', 'static']
+ protocols = ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static']
self.session.set(['policy', 'access-list', acl, 'rule', seq, 'action', 'permit'])
self.session.set(['policy', 'access-list', acl, 'rule', seq, 'source', 'any'])
@@ -100,7 +102,7 @@ class TestProtocolsOSPF(unittest.TestCase):
self.session.commit()
# Verify FRR ospfd configuration
- frrconfig = getFRROSPFconfig()
+ frrconfig = getFRRconfig()
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults
for ptotocol in protocols:
@@ -121,7 +123,7 @@ class TestProtocolsOSPF(unittest.TestCase):
self.session.commit()
# Verify FRR ospfd configuration
- frrconfig = getFRROSPFconfig()
+ frrconfig = getFRRconfig()
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)
@@ -131,7 +133,7 @@ class TestProtocolsOSPF(unittest.TestCase):
self.session.commit()
# Verify FRR ospfd configuration
- frrconfig = getFRROSPFconfig()
+ frrconfig = getFRRconfig()
self.assertIn(f' default-information originate always metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
@@ -158,7 +160,7 @@ class TestProtocolsOSPF(unittest.TestCase):
self.session.commit()
# Verify FRR ospfd configuration
- frrconfig = getFRROSPFconfig()
+ frrconfig = getFRRconfig()
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
@@ -173,7 +175,7 @@ class TestProtocolsOSPF(unittest.TestCase):
self.session.set(base_path + ['distance', 'ospf', 'inter-area', inter_area])
self.session.commit()
- frrconfig = getFRROSPFconfig()
+ frrconfig = getFRRconfig()
self.assertIn(f' distance ospf intra-area {intra_area} inter-area {inter_area} external {external}', frrconfig)
@@ -189,7 +191,7 @@ class TestProtocolsOSPF(unittest.TestCase):
self.session.commit()
# Verify FRR ospfd configuration
- frrconfig = getFRROSPFconfig()
+ frrconfig = getFRRconfig()
self.assertIn(f'router ospf', frrconfig)
for neighbor in neighbors:
self.assertIn(f' neighbor {neighbor} priority {priority} poll-interval {poll_interval}', frrconfig) # default
@@ -205,7 +207,7 @@ class TestProtocolsOSPF(unittest.TestCase):
self.session.commit()
# Verify FRR ospfd configuration
- frrconfig = getFRROSPFconfig()
+ frrconfig = getFRRconfig()
self.assertIn(f'router ospf', frrconfig)
self.assertIn(f' passive-interface default', frrconfig) # default
for interface in interfaces:
@@ -215,7 +217,7 @@ class TestProtocolsOSPF(unittest.TestCase):
def test_ospf_08_redistribute(self):
metric = '15'
metric_type = '1'
- redistribute = ['bgp', 'connected', 'kernel', 'rip', 'static']
+ redistribute = ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static']
for protocol in redistribute:
self.session.set(base_path + ['redistribute', protocol, 'metric', metric])
@@ -227,7 +229,7 @@ class TestProtocolsOSPF(unittest.TestCase):
self.session.commit()
# Verify FRR ospfd configuration
- frrconfig = getFRROSPFconfig()
+ frrconfig = getFRRconfig()
self.assertIn(f'router ospf', frrconfig)
for protocol in redistribute:
if protocol in ['kernel', 'static']:
@@ -235,6 +237,7 @@ class TestProtocolsOSPF(unittest.TestCase):
else:
self.assertIn(f' redistribute {protocol} metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig)
+
def test_ospf_09_virtual_link(self):
networks = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']
area = '10'
@@ -257,13 +260,27 @@ class TestProtocolsOSPF(unittest.TestCase):
self.session.commit()
# Verify FRR ospfd configuration
- frrconfig = getFRROSPFconfig()
+ frrconfig = getFRRconfig()
+ import pprint
+ # From time to time the CI fails with an error like:
+ # ======================================================================
+ # FAIL: test_ospf_09_virtual_link (__main__.TestProtocolsOSPF)
+ # ----------------------------------------------------------------------
+ # Traceback (most recent call last):
+ # File "/usr/libexec/vyos/tests/smoke/cli/test_protocols_ospf.py", line 261, in test_ospf_09_virtual_link
+ # self.assertIn(f'router ospf', frrconfig)
+ # AssertionError: 'router ospf' not found in ''
+ #
+ # Add some debug code so we can find the root cause
+ pprint.pprint(frrconfig)
+
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)
for network in networks:
self.assertIn(f' network {network} area {area}', frrconfig)
+
def test_ospf_10_interface_configureation(self):
interfaces = Section.interfaces('ethernet')
password = 'vyos1234'
@@ -295,5 +312,37 @@ class TestProtocolsOSPF(unittest.TestCase):
self.assertIn(f' ip ospf priority {priority}', config)
self.assertIn(f' bandwidth {bandwidth}', config)
+
+ def test_ospf_11_vrfs(self):
+ vrfs = ['red', 'green', 'blue']
+ # It is safe to assume that when the basic VRF test works, all
+ # other OSPF related features work, as we entirely inherit the CLI
+ # templates and Jinja2 FRR template.
+ table = '1000'
+ for vrf in vrfs:
+ vrf_base = ['vrf', 'name', vrf]
+ self.session.set(vrf_base + ['table', table])
+ self.session.set(vrf_base + ['protocols', 'ospf'])
+ table = str(int(table) + 1000)
+
+ # Also set a default VRF OSPF config
+ self.session.set(base_path)
+ self.session.commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = getFRRconfig()
+ 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
+
+ for vrf in vrfs:
+ frrconfig = getFRRconfig(vrf)
+ 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
+
+ self.session.delete(['vrf', 'name', vrf])
+
+
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 297d5d996..754c4488f 100755
--- a/smoketest/scripts/cli/test_protocols_ospfv3.py
+++ b/smoketest/scripts/cli/test_protocols_ospfv3.py
@@ -25,10 +25,15 @@ from vyos.util import process_named_running
PROCESS_NAME = 'ospf6d'
base_path = ['protocols', 'ospfv3']
+router_id = '192.0.2.1'
+default_area = '0'
def getFRROSPFconfig():
return cmd('vtysh -c "show run" | sed -n "/router ospf6/,/^!/p"')
+def getFRRIFconfig(iface):
+ return cmd(f'vtysh -c "show run" | sed -n "/^interface {iface}/,/^!/p"')
+
class TestProtocolsOSPFv3(unittest.TestCase):
def setUp(self):
self.session = ConfigSession(os.getpid())
@@ -43,23 +48,21 @@ class TestProtocolsOSPFv3(unittest.TestCase):
def test_ospfv3_01_basic(self):
- area = '0'
seq = '10'
prefix = '2001:db8::/32'
acl_name = 'foo-acl-100'
- router_id = '192.0.2.1'
self.session.set(['policy', 'access-list6', acl_name, 'rule', seq, 'action', 'permit'])
self.session.set(['policy', 'access-list6', acl_name, 'rule', seq, 'source', 'any'])
self.session.set(base_path + ['parameters', 'router-id', router_id])
- self.session.set(base_path + ['area', area, 'range', prefix, 'advertise'])
- self.session.set(base_path + ['area', area, 'export-list', acl_name])
- self.session.set(base_path + ['area', area, 'import-list', acl_name])
+ self.session.set(base_path + ['area', default_area, 'range', prefix, 'advertise'])
+ self.session.set(base_path + ['area', default_area, 'export-list', acl_name])
+ self.session.set(base_path + ['area', default_area, 'import-list', acl_name])
interfaces = Section.interfaces('ethernet')
for interface in interfaces:
- self.session.set(base_path + ['area', area, 'interface', interface])
+ self.session.set(base_path + ['area', default_area, 'interface', interface])
# commit changes
self.session.commit()
@@ -67,13 +70,13 @@ class TestProtocolsOSPFv3(unittest.TestCase):
# Verify FRR ospfd configuration
frrconfig = getFRROSPFconfig()
self.assertIn(f'router ospf6', frrconfig)
- self.assertIn(f' area {area} range {prefix}', frrconfig)
+ self.assertIn(f' area {default_area} range {prefix}', frrconfig)
self.assertIn(f' ospf6 router-id {router_id}', frrconfig)
- self.assertIn(f' area {area} import-list {acl_name}', frrconfig)
- self.assertIn(f' area {area} export-list {acl_name}', frrconfig)
+ self.assertIn(f' area {default_area} import-list {acl_name}', frrconfig)
+ self.assertIn(f' area {default_area} export-list {acl_name}', frrconfig)
for interface in interfaces:
- self.assertIn(f' interface {interface} area {area}', frrconfig)
+ self.assertIn(f' interface {interface} area {default_area}', frrconfig)
self.session.delete(['policy', 'access-list6', acl_name])
@@ -118,6 +121,46 @@ class TestProtocolsOSPFv3(unittest.TestCase):
for protocol in redistribute:
self.assertIn(f' redistribute {protocol} route-map {route_map}', frrconfig)
+ def test_ospfv3_0104_interfaces(self):
+
+ self.session.set(base_path + ['parameters', 'router-id', router_id])
+ self.session.set(base_path + ['area', default_area])
+
+ cost = '100'
+ priority = '10'
+ interfaces = Section.interfaces('ethernet')
+ for interface in interfaces:
+ if_base = base_path + ['interface', interface]
+ self.session.set(if_base + ['bfd'])
+ self.session.set(if_base + ['cost', cost])
+ self.session.set(if_base + ['instance-id', '0'])
+ self.session.set(if_base + ['mtu-ignore'])
+ self.session.set(if_base + ['network', 'point-to-point'])
+ self.session.set(if_base + ['passive'])
+ self.session.set(if_base + ['priority', priority])
+ cost = str(int(cost) + 10)
+ priority = str(int(priority) + 5)
+
+ # commit changes
+ self.session.commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = getFRROSPFconfig()
+ self.assertIn(f'router ospf6', frrconfig)
+
+ cost = '100'
+ priority = '10'
+ for interface in interfaces:
+ if_config = getFRRIFconfig(interface)
+ self.assertIn(f'interface {interface}', if_config)
+ self.assertIn(f' ipv6 ospf6 bfd', if_config)
+ self.assertIn(f' ipv6 ospf6 cost {cost}', if_config)
+ self.assertIn(f' ipv6 ospf6 mtu-ignore', if_config)
+ self.assertIn(f' ipv6 ospf6 network point-to-point', if_config)
+ self.assertIn(f' ipv6 ospf6 passive', if_config)
+ self.assertIn(f' ipv6 ospf6 priority {priority}', if_config)
+ cost = str(int(cost) + 10)
+ priority = str(int(priority) + 5)
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 2c5c9030a..f42ea0c0a 100755
--- a/smoketest/scripts/cli/test_protocols_rip.py
+++ b/smoketest/scripts/cli/test_protocols_rip.py
@@ -71,7 +71,7 @@ class TestProtocolsRIP(unittest.TestCase):
interfaces = Section.interfaces('ethernet')
neighbors = ['1.2.3.4', '1.2.3.5', '1.2.3.6']
networks = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']
- redistribute = ['bgp', 'connected', 'kernel', 'ospf', 'static']
+ redistribute = ['bgp', 'connected', 'isis', 'kernel', 'ospf', 'static']
timer_garbage = '888'
timer_timeout = '1000'
timer_update = '90'
diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py
index cf591f060..28ae5e2dd 100755
--- a/smoketest/scripts/cli/test_protocols_static.py
+++ b/smoketest/scripts/cli/test_protocols_static.py
@@ -21,6 +21,7 @@ from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.template import is_ipv6
from vyos.util import cmd
+from vyos.util import get_interface_config
base_path = ['protocols', 'static']
vrf_path = ['protocols', 'vrf']
@@ -85,7 +86,6 @@ routes = {
},
}
-vrfs = ['red', 'green', 'blue']
tables = ['80', '81', '82']
class StaticRouteTest(unittest.TestCase):
@@ -99,9 +99,6 @@ class StaticRouteTest(unittest.TestCase):
route_type = 'route6'
self.session.delete(base_path + [route_type, route])
- for vrf in vrfs:
- self.session.delete(vrf_path + [vrf])
-
for table in tables:
self.session.delete(base_path + ['table', table])
@@ -290,47 +287,65 @@ class StaticRouteTest(unittest.TestCase):
def test_protocols_vrf_static(self):
- for vrf in vrfs:
+ # Create VRF instances and apply the static routes from above to FRR.
+ # Re-read the configured routes and match them if they are programmed
+ # properly. This also includes VRF leaking
+ vrfs = {
+ 'red' : { 'table' : '1000' },
+ 'green' : { 'table' : '2000' },
+ 'blue' : { 'table' : '3000' },
+ }
+
+ for vrf, vrf_config in vrfs.items():
+ vrf_base_path = ['vrf', 'name', vrf]
+ self.session.set(vrf_base_path + ['table', vrf_config['table']])
+
for route, route_config in routes.items():
route_type = 'route'
if is_ipv6(route):
route_type = 'route6'
- base = vrf_path + [vrf, 'static', route_type, route]
+ route_base_path = vrf_base_path + ['protocols', 'static', route_type, route]
if 'next_hop' in route_config:
for next_hop, next_hop_config in route_config['next_hop'].items():
- self.session.set(base + ['next-hop', next_hop])
+ self.session.set(route_base_path + ['next-hop', next_hop])
if 'disable' in next_hop_config:
- self.session.set(base + ['next-hop', next_hop, 'disable'])
+ self.session.set(route_base_path + ['next-hop', next_hop, 'disable'])
if 'distance' in next_hop_config:
- self.session.set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
+ self.session.set(route_base_path + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
if 'interface' in next_hop_config:
- self.session.set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']])
+ self.session.set(route_base_path + ['next-hop', next_hop, 'interface', next_hop_config['interface']])
if 'vrf' in next_hop_config:
- self.session.set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']])
+ self.session.set(route_base_path + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']])
if 'interface' in route_config:
for interface, interface_config in route_config['interface'].items():
- self.session.set(base + ['interface', interface])
+ self.session.set(route_base_path + ['interface', interface])
if 'disable' in interface_config:
- self.session.set(base + ['interface', interface, 'disable'])
+ self.session.set(route_base_path + ['interface', interface, 'disable'])
if 'distance' in interface_config:
- self.session.set(base + ['interface', interface, 'distance', interface_config['distance']])
+ self.session.set(route_base_path + ['interface', interface, 'distance', interface_config['distance']])
if 'vrf' in interface_config:
- self.session.set(base + ['interface', interface, 'vrf', interface_config['vrf']])
+ self.session.set(route_base_path + ['interface', interface, 'vrf', interface_config['vrf']])
if 'blackhole' in route_config:
- self.session.set(base + ['blackhole'])
+ self.session.set(route_base_path + ['blackhole'])
if 'distance' in route_config['blackhole']:
- self.session.set(base + ['blackhole', 'distance', route_config['blackhole']['distance']])
+ self.session.set(route_base_path + ['blackhole', 'distance', route_config['blackhole']['distance']])
if 'tag' in route_config['blackhole']:
- self.session.set(base + ['blackhole', 'tag', route_config['blackhole']['tag']])
+ self.session.set(route_base_path + ['blackhole', 'tag', route_config['blackhole']['tag']])
# commit changes
self.session.commit()
- for vrf in vrfs:
+ for vrf, vrf_config in vrfs.items():
+ tmp = get_interface_config(vrf)
+
+ # Compare VRF table ID
+ self.assertEqual(tmp['linkinfo']['info_data']['table'], int(vrf_config['table']))
+ self.assertEqual(tmp['linkinfo']['info_kind'], 'vrf')
+
# Verify FRR bgpd configuration
frrconfig = getFRRCconfig(vrf)
self.assertIn(f'vrf {vrf}', frrconfig)
@@ -380,6 +395,7 @@ class StaticRouteTest(unittest.TestCase):
self.assertIn(tmp, frrconfig)
+ self.session.delete(['vrf'])
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 db7b2dda4..e74e22a5c 100755
--- a/smoketest/scripts/cli/test_service_dhcp-server.py
+++ b/smoketest/scripts/cli/test_service_dhcp-server.py
@@ -200,6 +200,7 @@ class TestServiceDHCPServer(unittest.TestCase):
def test_dhcp_single_pool_static_mapping(self):
shared_net_name = 'SMOKE-2'
+ domain_name = 'private'
pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet]
# we use the first subnet IP address as default gateway
diff --git a/smoketest/scripts/cli/test_service_dhcpv6-server.py b/smoketest/scripts/cli/test_service_dhcpv6-server.py
index 319891a94..a364eee11 100755
--- a/smoketest/scripts/cli/test_service_dhcpv6-server.py
+++ b/smoketest/scripts/cli/test_service_dhcpv6-server.py
@@ -151,5 +151,26 @@ class TestServiceDHCPServer(unittest.TestCase):
# Check for running process
self.assertTrue(process_named_running(PROCESS_NAME))
+ def test_global_nameserver(self):
+ shared_net_name = 'SMOKE-3'
+ ns_global_1 = '2001:db8::1111'
+ ns_global_2 = '2001:db8::2222'
+
+ self.session.set(base_path + ['global-parameters', 'name-server', ns_global_1])
+ self.session.set(base_path + ['global-parameters', 'name-server', ns_global_2])
+ self.session.set(base_path + ['shared-network-name', shared_net_name, 'subnet', subnet])
+
+ # commit changes
+ self.session.commit()
+
+ config = read_file(DHCPD_CONF)
+ self.assertIn(f'option dhcp6.name-servers {ns_global_1};', config)
+ self.assertIn(f'option dhcp6.name-servers {ns_global_2};', config)
+ self.assertIn(f'subnet6 {subnet}' + r' {', config)
+ self.assertIn(f'set shared-networkname = "{shared_net_name}";', 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_pppoe-server.py b/smoketest/scripts/cli/test_service_pppoe-server.py
index a4bb6e9f9..e8f9facbb 100755
--- a/smoketest/scripts/cli/test_service_pppoe-server.py
+++ b/smoketest/scripts/cli/test_service_pppoe-server.py
@@ -144,7 +144,8 @@ class TestServicePPPoEServer(BasicAccelPPPTest.BaseTest):
start = '192.0.2.10'
stop = '192.0.2.20'
- start_stop = f'{start}-{stop}'
+ stop_octet = stop.split('.')[3]
+ start_stop = f'{start}-{stop_octet}'
self.set(['client-ip-pool', 'start', start])
self.set(['client-ip-pool', 'stop', stop])
diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py
index 8e977d407..aac115663 100755
--- a/smoketest/scripts/cli/test_vrf.py
+++ b/smoketest/scripts/cli/test_vrf.py
@@ -33,12 +33,6 @@ from vyos.validate import is_intf_addr_assigned
base_path = ['vrf']
vrfs = ['red', 'green', 'blue', 'foo-bar', 'baz_foo']
-def get_vrf_ipv4_routes(vrf):
- return json.loads(cmd(f'ip -4 -j route show vrf {vrf}'))
-
-def get_vrf_ipv6_routes(vrf):
- return json.loads(cmd(f'ip -6 -j route show vrf {vrf}'))
-
class VRFTest(unittest.TestCase):
_interfaces = []