diff options
Diffstat (limited to 'smoketest')
19 files changed, 2052 insertions, 178 deletions
diff --git a/smoketest/configs/bgp-bfd-communities b/smoketest/configs/bgp-bfd-communities new file mode 100644 index 000000000..3b3056a51 --- /dev/null +++ b/smoketest/configs/bgp-bfd-communities @@ -0,0 +1,533 @@ +interfaces { + ethernet eth0 { + address 192.0.2.100/25 + address 2001:db8::ffff/64 + } + loopback lo { + } +} +policy { + large-community-list ANYCAST_ALL { + rule 10 { + action permit + description "Allow all anycast from anywhere" + regex "4242420696:100:.*" + } + } + large-community-list ANYCAST_INT { + rule 10 { + action permit + description "Allow all anycast from int" + regex 4242420696:100:1 + } + } + prefix-list BGP-BACKBONE-IN { + description "Inbound backbone routes from other sites" + rule 10 { + action deny + description "Block default route" + prefix 0.0.0.0/0 + } + rule 20 { + action deny + description "Block int primary" + ge 21 + prefix 192.168.0.0/20 + } + rule 30 { + action deny + description "Block loopbacks" + ge 25 + prefix 192.168.253.0/24 + } + rule 40 { + action deny + description "Block backbone peering" + ge 25 + prefix 192.168.254.0/24 + } + rule 999 { + action permit + description "Allow everything else" + ge 1 + prefix 0.0.0.0/0 + } + } + prefix-list BGP-BACKBONE-OUT { + description "Outbound backbone routes to other sites" + rule 10 { + action permit + description "Int primary" + ge 23 + prefix 192.168.0.0/20 + } + } + prefix-list GLOBAL { + description "Globally redistributed routes" + rule 10 { + action permit + prefix 192.168.100.1/32 + } + rule 20 { + action permit + prefix 192.168.7.128/25 + } + } + prefix-list6 BGP-BACKBONE-IN-V6 { + description "Inbound backbone routes from other sites" + rule 10 { + action deny + description "Block default route" + prefix ::/0 + } + rule 20 { + action deny + description "Block int primary" + ge 53 + prefix fd52:d62e:8011::/52 + } + rule 30 { + action deny + description "Block peering and stuff" + ge 53 + prefix fd52:d62e:8011:f000::/52 + } + rule 999 { + action permit + description "Allow everything else" + ge 1 + prefix ::/0 + } + } + prefix-list6 BGP-BACKBONE-OUT-V6 { + description "Outbound backbone routes to other sites" + rule 10 { + action permit + ge 64 + prefix fd52:d62e:8011::/52 + } + } + prefix-list6 GLOBAL-V6 { + description "Globally redistributed routes" + rule 10 { + action permit + ge 64 + prefix fd52:d62e:8011:2::/63 + } + } + route-map BGP-REDISTRIBUTE { + rule 10 { + action permit + description "Prepend AS and allow VPN and modem" + match { + ip { + address { + prefix-list GLOBAL + } + } + } + set { + as-path-prepend 4242420666 + } + } + rule 20 { + action permit + description "Allow VPN" + match { + ipv6 { + address { + prefix-list GLOBAL-V6 + } + } + } + } + } + route-map BGP-BACKBONE-IN { + rule 10 { + action permit + match { + ip { + address { + prefix-list BGP-BACKBONE-IN + } + } + } + } + rule 20 { + action permit + match { + ipv6 { + address { + prefix-list BGP-BACKBONE-IN-V6 + } + } + } + } + rule 30 { + action permit + match { + large-community { + large-community-list ANYCAST_ALL + } + } + } + } + route-map BGP-BACKBONE-OUT { + rule 10 { + action permit + match { + ip { + address { + prefix-list BGP-BACKBONE-OUT + } + } + } + } + rule 20 { + action permit + match { + ipv6 { + address { + prefix-list BGP-BACKBONE-OUT-V6 + } + } + } + } + rule 30 { + action permit + match { + large-community { + large-community-list ANYCAST_INT + } + } + set { + as-path-prepend 4242420666 + } + } + } +} +protocols { + bfd { + peer 192.168.253.1 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address 192.168.253.3 + } + } + peer 192.168.253.2 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address 192.168.253.3 + } + } + peer 192.168.253.6 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address 192.168.253.3 + } + } + peer 192.168.253.7 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address 192.168.253.3 + } + } + peer 192.168.253.12 { + interval { + receive 100 + transmit 100 + } + multihop + source { + address 192.168.253.3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:1 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:2 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:6 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:7 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:12 { + interval { + receive 100 + transmit 100 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + } + bgp 4242420666 { + address-family { + ipv4-unicast { + redistribute { + connected { + route-map BGP-REDISTRIBUTE + } + static { + route-map BGP-REDISTRIBUTE + } + } + } + ipv6-unicast { + redistribute { + connected { + route-map BGP-REDISTRIBUTE + } + } + } + } + neighbor 192.168.253.1 { + peer-group INT + } + neighbor 192.168.253.2 { + peer-group INT + } + neighbor 192.168.253.6 { + peer-group DAL13 + } + neighbor 192.168.253.7 { + peer-group DAL13 + } + neighbor 192.168.253.12 { + address-family { + ipv4-unicast { + route-map { + export BGP-BACKBONE-OUT + import BGP-BACKBONE-IN + } + soft-reconfiguration { + inbound + } + } + } + bfd { + } + ebgp-multihop 2 + remote-as 4242420669 + update-source dum0 + } + neighbor fd52:d62e:8011:fffe:192:168:253:1 { + address-family { + ipv6-unicast { + peer-group INTv6 + } + } + } + neighbor fd52:d62e:8011:fffe:192:168:253:2 { + address-family { + ipv6-unicast { + peer-group INTv6 + } + } + } + neighbor fd52:d62e:8011:fffe:192:168:253:6 { + address-family { + ipv6-unicast { + peer-group DAL13v6 + } + } + } + neighbor fd52:d62e:8011:fffe:192:168:253:7 { + address-family { + ipv6-unicast { + peer-group DAL13v6 + } + } + } + neighbor fd52:d62e:8011:fffe:192:168:253:12 { + address-family { + ipv6-unicast { + route-map { + export BGP-BACKBONE-OUT + import BGP-BACKBONE-IN + } + soft-reconfiguration { + inbound + } + } + } + bfd { + } + ebgp-multihop 2 + remote-as 4242420669 + update-source dum0 + } + parameters { + confederation { + identifier 4242420696 + peers 4242420668 + peers 4242420669 + } + default { + no-ipv4-unicast + } + distance { + global { + external 220 + internal 220 + local 220 + } + } + graceful-restart { + } + } + peer-group DAL13 { + address-family { + ipv4-unicast { + route-map { + export BGP-BACKBONE-OUT + import BGP-BACKBONE-IN + } + soft-reconfiguration { + inbound + } + } + } + bfd + ebgp-multihop 2 + remote-as 4242420668 + update-source dum0 + } + peer-group DAL13v6 { + address-family { + ipv6-unicast { + route-map { + export BGP-BACKBONE-OUT + import BGP-BACKBONE-IN + } + soft-reconfiguration { + inbound + } + } + } + bfd + ebgp-multihop 2 + remote-as 4242420668 + update-source dum0 + } + peer-group INT { + address-family { + ipv4-unicast { + default-originate { + } + soft-reconfiguration { + inbound + } + } + } + bfd + remote-as 4242420666 + update-source dum0 + } + peer-group INTv6 { + address-family { + ipv6-unicast { + default-originate { + } + soft-reconfiguration { + inbound + } + } + } + bfd + remote-as 4242420666 + update-source dum0 + } + } +} +system { + config-management { + commit-revisions 200 + } + console { + device ttyS0 { + speed 115200 + } + } + host-name vyos + login { + user vyos { + authentication { + encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/ + plaintext-password "" + } + level admin + } + } + ntp { + server 0.pool.ntp.org { + } + server 1.pool.ntp.org { + } + server 2.pool.ntp.org { + } + } + syslog { + global { + facility all { + level info + } + facility protocols { + level debug + } + } + } + time-zone Europe/Berlin +} + +/* Warning: Do not remove the following line. */ +/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@10:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */ +/* Release version: 1.2.6-S1 */ diff --git a/smoketest/configs/bgp-small-internet-exchange b/smoketest/configs/bgp-small-internet-exchange index de6213b50..d51f87c4a 100644 --- a/smoketest/configs/bgp-small-internet-exchange +++ b/smoketest/configs/bgp-small-internet-exchange @@ -11,6 +11,100 @@ interfaces { } } policy { + as-path-list bogon-asns { + rule 10 { + action permit + description "RFC 7607" + regex _0_ + } + rule 20 { + action permit + description "RFC 4893" + regex _23456_ + } + rule 30 { + action permit + description "RFC 5398/6996/7300" + regex _6449[6-9]_|_65[0-4][0-9][0-9]_|_655[0-4][0-9]_|_6555[0-1]_ + } + rule 40 { + action permit + description "IANA reserved" + 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]_ + } + } + prefix-list bogon-v4 { + rule 10 { + action permit + le 32 + prefix 0.0.0.0/8 + } + rule 20 { + action permit + le 32 + prefix 10.0.0.0/8 + } + rule 30 { + action permit + le 32 + prefix 100.64.0.0/10 + } + rule 40 { + action permit + le 32 + prefix 127.0.0.0/8 + } + rule 50 { + action permit + le 32 + prefix 169.254.0.0/16 + } + rule 60 { + action permit + le 32 + prefix 172.16.0.0/12 + } + rule 70 { + action permit + le 32 + prefix 192.0.2.0/24 + } + rule 80 { + action permit + le 32 + prefix 192.88.99.0/24 + } + rule 90 { + action permit + le 32 + prefix 192.168.0.0/16 + } + rule 100 { + action permit + le 32 + prefix 198.18.0.0/15 + } + rule 110 { + action permit + le 32 + prefix 198.51.100.0/24 + } + rule 120 { + action permit + le 32 + prefix 203.0.113.0/24 + } + rule 130 { + action permit + le 32 + prefix 224.0.0.0/4 + } + rule 140 { + action permit + le 32 + prefix 240.0.0.0/4 + } + } prefix-list IX-out-v4 { rule 10 { action permit @@ -21,6 +115,88 @@ policy { prefix 10.0.128.0/23 } } + prefix-list prefix-filter-v4 { + rule 10 { + action permit + ge 25 + prefix 0.0.0.0/0 + } + } + prefix-list6 bogon-v6 { + rule 10 { + action permit + description "RFC 4291 IPv4-compatible, loopback, et al" + le 128 + prefix ::/8 + } + rule 20 { + action permit + description "RFC 6666 Discard-Only" + le 128 + prefix 0100::/64 + } + rule 30 { + action permit + description "RFC 5180 BMWG" + le 128 + prefix 2001:2::/48 + } + rule 40 { + action permit + description "RFC 4843 ORCHID" + le 128 + prefix 2001:10::/28 + } + rule 50 { + action permit + description "RFC 3849 documentation" + le 128 + prefix 2001:db8::/32 + } + rule 60 { + action permit + description "RFC 7526 6to4 anycast relay" + le 128 + prefix 2002::/16 + } + rule 70 { + action permit + description "RFC 3701 old 6bone" + le 128 + prefix 3ffe::/16 + } + rule 80 { + action permit + description "RFC 4193 unique local unicast" + le 128 + prefix fc00::/7 + } + rule 90 { + action permit + description "RFC 4291 link local unicast" + le 128 + prefix fe80::/10 + } + rule 100 { + action permit + description "RFC 3879 old site local unicast" + le 128 + prefix fec0::/10 + } + rule 110 { + action permit + description "RFC 4291 multicast" + le 128 + prefix ff00::/8 + } + } + prefix-list6 prefix-filter-v6 { + rule 10 { + action permit + ge 49 + prefix ::/0 + } + } prefix-list6 IX-out-v6 { rule 10 { action permit @@ -31,6 +207,88 @@ policy { prefix 2001:db8:200::/40 } } + route-map eBGP-IN-v4 { + rule 10 { + action deny + match { + as-path bogon-asns + } + } + rule 20 { + action deny + match { + ip { + address { + prefix-list bogon-v4 + } + } + } + } + rule 30 { + action deny + match { + ip { + address { + prefix-list prefix-filter-v4 + } + } + } + } + rule 40 { + action permit + set { + local-preference 100 + metric 0 + } + } + } + route-map eBGP-IN-v6 { + rule 10 { + action deny + match { + as-path bogon-asns + } + } + rule 20 { + action deny + match { + ipv6 { + address { + prefix-list bogon-v6 + } + } + } + } + rule 30 { + action deny + match { + ipv6 { + address { + prefix-list prefix-filter-v6 + } + } + } + } + rule 40 { + action permit + set { + local-preference 100 + metric 0 + } + } + } + route-map IX-in-v4 { + rule 5 { + action permit + call eBGP-IN-v4 + on-match { + next + } + } + rule 10 { + action permit + } + } route-map IX-out-v4 { rule 10 { action permit @@ -43,6 +301,18 @@ policy { } } } + route-map IX-in-v6 { + rule 5 { + action permit + call eBGP-IN-v6 + on-match { + next + } + } + rule 10 { + action permit + } + } route-map IX-out-v6 { rule 10 { action permit diff --git a/smoketest/configs/tunnel-broker b/smoketest/configs/tunnel-broker new file mode 100644 index 000000000..b52ba2541 --- /dev/null +++ b/smoketest/configs/tunnel-broker @@ -0,0 +1,142 @@ +interfaces { + dummy dum0 { + address 192.0.2.0/32 + } + dummy dum1 { + address 192.0.2.1/32 + } + dummy dum2 { + address 192.0.2.2/32 + } + dummy dum3 { + address 192.0.2.3/32 + } + dummy dum4 { + address 192.0.2.4/32 + } + ethernet eth0 { + duplex auto + smp-affinity auto + speed auto + address 172.18.202.10/24 + } + l2tpv3 l2tpeth10 { + description "L2 VPN Tunnel" + destination-port 5010 + encapsulation ip + local-ip 172.18.202.10 + mtu 1500 + peer-session-id 110 + peer-tunnel-id 10 + remote-ip 172.18.254.201 + session-id 110 + source-port 5010 + tunnel-id 10 + } + l2tpv3 l2tpeth20 { + description "L2 VPN Tunnel" + destination-port 5020 + encapsulation ip + local-ip 172.18.202.10 + mtu 1500 + peer-session-id 120 + peer-tunnel-id 20 + remote-ip 172.18.254.202 + session-id 120 + source-port 5020 + tunnel-id 20 + } + l2tpv3 l2tpeth30 { + description "L2 VPN Tunnel" + destination-port 5030 + encapsulation ip + local-ip 172.18.202.10 + mtu 1500 + peer-session-id 130 + peer-tunnel-id 30 + remote-ip 172.18.254.203 + session-id 130 + source-port 5030 + tunnel-id 30 + } + tunnel tun100 { + address 172.16.0.1/30 + encapsulation gre-bridge + local-ip 192.0.2.0 + remote-ip 192.0.2.100 + } + tunnel tun200 { + address 172.16.0.5/30 + encapsulation gre + local-ip 192.0.2.1 + remote-ip 192.0.2.101 + } + tunnel tun300 { + address 172.16.0.9/30 + encapsulation ipip + local-ip 192.0.2.2 + remote-ip 192.0.2.102 + } + tunnel tun400 { + address 172.16.0.13/30 + encapsulation gre-bridge + local-ip 192.0.2.3 + remote-ip 192.0.2.103 + } + tunnel tun500 { + address 172.16.0.17/30 + encapsulation gre + local-ip 192.0.2.4 + remote-ip 192.0.2.104 + } +} +protocols { + static { + route 0.0.0.0/0 { + next-hop 172.18.202.1 { + distance 10 + } + } + } +} +system { + config-management { + commit-revisions 100 + } + console { + device ttyS0 { + speed 115200 + } + } + host-name vyos + login { + user vyos { + authentication { + encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0 + plaintext-password "" + } + } + } + ntp { + server 0.pool.ntp.org { + } + server 1.pool.ntp.org { + } + server 2.pool.ntp.org { + } + } + syslog { + global { + facility all { + level info + } + facility protocols { + level debug + } + } + } +} + +/* Warning: Do not remove the following line. */ +/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@10:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */ +/* Release version: 1.2.6-S1 */ diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py index 1426e80c2..d038e9cb8 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_json_iface_options 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_json_iface_options(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..cbb41d0c9 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_json_iface_options 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_json_iface_options(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_json_iface_options(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..7edd4528e 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_json_iface_options + 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_json_iface_options(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..2f1898b6f 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_json_iface_options 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_json_iface_options(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..cad6764e6 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_json_iface_options +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_json_iface_options(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_json_iface_options(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_json_iface_options(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_json_iface_options(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_json_iface_options(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..b66315c5e 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_json_iface_options + 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_json_iface_options(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_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..8d42fafc3 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -221,12 +221,13 @@ class TestProtocolsBGP(unittest.TestCase): 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']) # commit changes self.session.commit() @@ -240,6 +241,7 @@ 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) def test_bgp_02_neighbors(self): @@ -388,7 +390,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 +455,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 diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py index ce30f6a7d..0ca8bb3bd 100755 --- a/smoketest/scripts/cli/test_protocols_ospf.py +++ b/smoketest/scripts/cli/test_protocols_ospf.py @@ -88,7 +88,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']) @@ -215,7 +215,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]) 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_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) |