diff options
-rw-r--r-- | interface-definitions/interfaces-tunnel.xml.in | 15 | ||||
-rw-r--r-- | python/vyos/configverify.py | 7 | ||||
-rw-r--r-- | smoketest/configs/tunnel-broker | 2 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_tunnel.py | 20 | ||||
-rwxr-xr-x | src/conf_mode/dhcp_server.py | 12 | ||||
-rwxr-xr-x | src/conf_mode/dhcpv6_server.py | 2 | ||||
-rwxr-xr-x | src/conf_mode/interfaces-tunnel.py | 4 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/21-to-22 | 46 |
8 files changed, 63 insertions, 45 deletions
diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in index df9b58992..2c15abec7 100644 --- a/interface-definitions/interfaces-tunnel.xml.in +++ b/interface-definitions/interfaces-tunnel.xml.in @@ -54,21 +54,6 @@ </constraint> </properties> </leafNode> - <leafNode name="dhcp-interface"> - <properties> - <help>dhcp interface</help> - <valueHelp> - <format>interface</format> - <description>DHCP interface that supplies the local IP address for this tunnel</description> - </valueHelp> - <completionHelp> - <script>${vyos_completion_dir}/list_interfaces.py</script> - </completionHelp> - <constraint> - <validator name="interface-name"/> - </constraint> - </properties> - </leafNode> <leafNode name="encapsulation"> <properties> <help>Encapsulation of this tunnel interface</help> diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py index ce7e76eb4..3aece499e 100644 --- a/python/vyos/configverify.py +++ b/python/vyos/configverify.py @@ -95,15 +95,12 @@ def verify_tunnel(config): raise ConfigError('Must configure the tunnel encapsulation for '\ '{ifname}!'.format(**config)) - if 'source_address' not in config and 'dhcp_interface' not in config: - raise ConfigError('source-address is mandatory for tunnel') + if 'source_address' not in config and 'source_interface' not in config: + raise ConfigError('source-address or source-interface required for tunnel!') if 'remote' not in config and config['encapsulation'] != 'gre': raise ConfigError('remote-ip address is mandatory for tunnel') - if {'source_address', 'dhcp_interface'} <= set(config): - raise ConfigError('Can not use both source-address and dhcp-interface') - if config['encapsulation'] in ['ipip6', 'ip6ip6', 'ip6gre']: error_ipv6 = 'Encapsulation mode requires IPv6' if 'source_address' in config and not is_ipv6(config['source_address']): diff --git a/smoketest/configs/tunnel-broker b/smoketest/configs/tunnel-broker index d4a5c2dfc..03ac0db41 100644 --- a/smoketest/configs/tunnel-broker +++ b/smoketest/configs/tunnel-broker @@ -56,7 +56,7 @@ interfaces { tunnel tun100 { address 172.16.0.1/30 encapsulation gre-bridge - local-ip 192.0.2.0 + dhcp-interface eth0 remote-ip 192.0.2.100 } tunnel tun200 { diff --git a/smoketest/scripts/cli/test_interfaces_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py index 3aed498b4..ff8778828 100755 --- a/smoketest/scripts/cli/test_interfaces_tunnel.py +++ b/smoketest/scripts/cli/test_interfaces_tunnel.py @@ -156,26 +156,6 @@ class TunnelInterfaceTest(BasicInterfaceTest.TestCase): self.cli_delete(self._base_path + [interface]) self.cli_commit() - def test_tunnel_verify_local_dhcp(self): - # 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.cli_set(self._base_path + [interface, 'address', local_if_addr]) - self.cli_set(self._base_path + [interface, 'encapsulation', 'gre']) - self.cli_set(self._base_path + [interface, 'source-address', self.local_v4]) - self.cli_set(self._base_path + [interface, 'remote', remote_ip4]) - self.cli_set(self._base_path + [interface, 'dhcp-interface', 'eth0']) - - # source-address and dhcp-interface can not be used at the same time - with self.assertRaises(ConfigSessionError): - self.cli_commit() - self.cli_delete(self._base_path + [interface, 'dhcp-interface']) - - # Check if commit is ok - self.cli_commit() - def test_tunnel_parameters_gre(self): interface = f'tun1030' gre_key = '10' diff --git a/src/conf_mode/dhcp_server.py b/src/conf_mode/dhcp_server.py index 28f2a4ca5..a8cef5ebf 100755 --- a/src/conf_mode/dhcp_server.py +++ b/src/conf_mode/dhcp_server.py @@ -151,9 +151,15 @@ def verify(dhcp): listen_ok = False subnets = [] failover_ok = False + shared_networks = len(dhcp['shared_network_name']) + disabled_shared_networks = 0 + # A shared-network requires a subnet definition for network, network_config in dhcp['shared_network_name'].items(): + if 'disable' in network_config: + disabled_shared_networks += 1 + if 'subnet' not in network_config: raise ConfigError(f'No subnets defined for {network}. At least one\n' \ 'lease subnet must be configured.') @@ -226,7 +232,7 @@ def verify(dhcp): # There must be one subnet connected to a listen interface. # This only counts if the network itself is not disabled! if 'disable' not in network_config: - if is_subnet_connected(subnet, primary=True): + if is_subnet_connected(subnet, primary=False): listen_ok = True # Subnets must be non overlapping @@ -243,6 +249,10 @@ def verify(dhcp): if net.overlaps(net2): raise ConfigError('Conflicting subnet ranges: "{net}" overlaps "{net2}"!') + # Prevent 'disable' for shared-network if only one network is configured + if (shared_networks - disabled_shared_networks) < 1: + raise ConfigError(f'At least one shared network must be active!') + if 'failover' in dhcp: if not failover_ok: raise ConfigError('DHCP failover must be enabled for at least one subnet!') diff --git a/src/conf_mode/dhcpv6_server.py b/src/conf_mode/dhcpv6_server.py index 175300bb0..e6a2e4486 100755 --- a/src/conf_mode/dhcpv6_server.py +++ b/src/conf_mode/dhcpv6_server.py @@ -128,7 +128,7 @@ def verify(dhcpv6): # Subnets must be unique if subnet in subnets: - raise ConfigError('DHCPv6 subnets must be unique! Subnet {0} defined multiple times!'.format(subnet['network'])) + raise ConfigError(f'DHCPv6 subnets must be unique! Subnet {subnet} defined multiple times!') subnets.append(subnet) # DHCPv6 requires at least one configured address range or one static mapping diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py index 5fa165190..4db564e6d 100755 --- a/src/conf_mode/interfaces-tunnel.py +++ b/src/conf_mode/interfaces-tunnel.py @@ -78,7 +78,7 @@ def verify(tunnel): # If tunnel source address any and key not set if tunnel['encapsulation'] in ['gre'] and \ - tunnel['source_address'] == '0.0.0.0' and \ + dict_search('source_address', tunnel) == '0.0.0.0' and \ dict_search('parameters.ip.key', tunnel) == None: raise ConfigError('Tunnel parameters ip key must be set!') @@ -91,7 +91,7 @@ def verify(tunnel): # no match on encapsulation - bail out if dict_search('linkinfo.info_kind', tunnel_cfg) != tunnel['encapsulation']: continue - new_source_address = tunnel['source_address'] + new_source_address = dict_search('source_address', tunnel) # Convert tunnel key to ip key, format "ip -j link show" # 1 => 0.0.0.1, 999 => 0.0.3.231 orig_new_key = dict_search('parameters.ip.key', tunnel) diff --git a/src/migration-scripts/interfaces/21-to-22 b/src/migration-scripts/interfaces/21-to-22 new file mode 100755 index 000000000..098102102 --- /dev/null +++ b/src/migration-scripts/interfaces/21-to-22 @@ -0,0 +1,46 @@ +#!/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/>. + +from sys import argv +from vyos.configtree import ConfigTree + +if (len(argv) < 1): + print("Must specify file name!") + exit(1) + +file_name = argv[1] +with open(file_name, 'r') as f: + config_file = f.read() + +config = ConfigTree(config_file) +base = ['interfaces', 'tunnel'] + +if not config.exists(base): + exit(0) + +for interface in config.list_nodes(base): + path = base + [interface, 'dhcp-interface'] + if config.exists(path): + tmp = config.return_value(path) + config.delete(path) + config.set(base + [interface, 'source-interface'], value=tmp) + +try: + with open(file_name, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print("Failed to save the modified config: {}".format(e)) + exit(1) |