diff --git a/interface-definitions/include/interface/interface-parameters-ttl.xml.i b/interface-definitions/include/interface/interface-parameters-ttl.xml.i index aa7c9d27b..21a5e5cd9 100644 --- a/interface-definitions/include/interface/interface-parameters-ttl.xml.i +++ b/interface-definitions/include/interface/interface-parameters-ttl.xml.i @@ -1,20 +1,20 @@ <!-- include start from interface/interface-parameters-ttl.xml.i --> <leafNode name="ttl"> <properties> - <help>Specifies TTL value to use in outgoing packets (default: 0)</help> + <help>Specifies TTL value to use in outgoing packets</help> <valueHelp> <format>0</format> <description>Copy value from original IP header</description> </valueHelp> <valueHelp> <format>1-255</format> <description>Time to Live</description> </valueHelp> <constraint> <validator name="numeric" argument="--range 0-255"/> </constraint> <constraintErrorMessage>TTL must be between 0 and 255</constraintErrorMessage> </properties> <defaultValue>0</defaultValue> </leafNode> <!-- include end --> diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in index f7af93f42..2b425f865 100644 --- a/interface-definitions/interfaces-tunnel.xml.in +++ b/interface-definitions/interfaces-tunnel.xml.in @@ -1,252 +1,255 @@ <?xml version="1.0"?> <interfaceDefinition> <node name="interfaces"> <children> <tagNode name="tunnel" owner="${vyos_conf_scripts_dir}/interfaces-tunnel.py"> <properties> <help>Tunnel interface</help> <priority>380</priority> <constraint> <regex>^tun[0-9]+$</regex> </constraint> <constraintErrorMessage>tunnel interface must be named tunN</constraintErrorMessage> <valueHelp> <format>tunN</format> <description>Tunnel interface name</description> </valueHelp> </properties> <children> #include <include/interface/interface-description.xml.i> #include <include/interface/address-ipv4-ipv6.xml.i> #include <include/interface/interface-disable.xml.i> #include <include/interface/interface-disable-link-detect.xml.i> #include <include/interface/interface-vrf.xml.i> #include <include/interface/interface-mtu-64-8024.xml.i> <leafNode name="mtu"> <defaultValue>1476</defaultValue> </leafNode> #include <include/interface/interface-ipv4-options.xml.i> #include <include/interface/interface-ipv6-options.xml.i> <leafNode name="local-ip"> <properties> <help>Local IP address for this tunnel</help> <valueHelp> <format>ipv4</format> <description>Local IPv4 address for this tunnel</description> </valueHelp> <valueHelp> <format>ipv6</format> <description>Local IPv6 address for this tunnel [NOTICE: unavailable for mGRE tunnels]</description> </valueHelp> <completionHelp> <script>${vyos_completion_dir}/list_local_ips.sh --both</script> </completionHelp> <constraint> <validator name="ip-address"/> </constraint> </properties> </leafNode> <leafNode name="remote-ip"> <properties> <help>Remote IP address for this tunnel</help> <valueHelp> <format>ipv4</format> <description>Remote IPv4 address for this tunnel</description> </valueHelp> <valueHelp> <format>ipv6</format> <description>Remote IPv6 address for this tunnel</description> </valueHelp> <constraint> <!-- does it need fixing/changing to be more restrictive ? --> <validator name="ip-address"/> </constraint> </properties> </leafNode> <leafNode name="source-interface"> <properties> <help>Physical Interface used for underlaying traffic</help> <completionHelp> <script>${vyos_completion_dir}/list_interfaces.py</script> </completionHelp> </properties> </leafNode> <leafNode name="6rd-prefix"> <properties> <help>6rd network prefix</help> <valueHelp> <format>ipv6</format> <description>IPv6 address and prefix length</description> </valueHelp> <constraint> <validator name="ipv6-prefix"/> </constraint> </properties> </leafNode> <leafNode name="6rd-relay-prefix"> <properties> <help>6rd relay prefix</help> <valueHelp> <format>ipv4net</format> <description>IPv4 prefix of interface for 6rd</description> </valueHelp> <constraint> <validator name="ipv4-prefix"/> </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> <completionHelp> <list>gre gre-bridge ip6gre ip6ip6 ipip ipip6 sit</list> </completionHelp> <valueHelp> <format>gre</format> <description>Generic Routing Encapsulation</description> </valueHelp> <valueHelp> <format>gre-bridge</format> <description>Generic Routing Encapsulation bridge interface</description> </valueHelp> <valueHelp> <format>ip6gre</format> <description>GRE over IPv6 network</description> </valueHelp> <valueHelp> <format>ip6ip6</format> <description>IP6 in IP6 encapsulation</description> </valueHelp> <valueHelp> <format>ipip</format> <description>IP in IP encapsulation</description> </valueHelp> <valueHelp> <format>ipip6</format> <description>IP in IP6 encapsulation</description> </valueHelp> <valueHelp> <format>sit</format> <description>Simple Internet Transition encapsulation</description> </valueHelp> <constraint> <regex>^(gre|gre-bridge|ip6gre|ip6ip6|ipip|ipip6|sit)$</regex> </constraint> <constraintErrorMessage>Invalid encapsulation, must be one of: gre, gre-bridge, ipip, sit, ipip6, ip6ip6, ip6gre</constraintErrorMessage> </properties> </leafNode> <leafNode name="multicast"> <properties> <help>Multicast operation over tunnel</help> <completionHelp> <list>enable disable</list> </completionHelp> <valueHelp> <format>enable</format> <description>Enable Multicast</description> </valueHelp> <valueHelp> <format>disable</format> <description>Disable Multicast (default)</description> </valueHelp> <constraint> <regex>^(enable|disable)$</regex> </constraint> <constraintErrorMessage>Must be 'disable' or 'enable'</constraintErrorMessage> </properties> </leafNode> <node name="parameters"> <properties> <help>Tunnel parameters</help> </properties> <children> <node name="ip"> <properties> <help>IPv4 specific tunnel parameters</help> </properties> <children> #include <include/interface/interface-parameters-key.xml.i> #include <include/interface/interface-parameters-tos.xml.i> #include <include/interface/interface-parameters-ttl.xml.i> + <leafNode name="ttl"> + <defaultValue>64</defaultValue> + </leafNode> </children> </node> <node name="ipv6"> <properties> <help>IPv6 specific tunnel parameters</help> </properties> <children> <leafNode name="encaplimit"> <properties> <help>Set fixed encapsulation limit</help> <completionHelp> <list>none</list> </completionHelp> <valueHelp> <format>0-255</format> <description>Encaplimit (default 4)</description> </valueHelp> <valueHelp> <format>none</format> <description>Encaplimit disabled</description> </valueHelp> <constraint> <regex>^(none)$</regex> <validator name="numeric" argument="--range 0-255"/> </constraint> <constraintErrorMessage>Tunnel encaplimit must be 0-255 or none</constraintErrorMessage> </properties> <defaultValue>4</defaultValue> </leafNode> #include <include/interface/interface-parameters-flowlabel.xml.i> <leafNode name="hoplimit"> <properties> <help>Hoplimit</help> <valueHelp> <format>0-255</format> <description>Hoplimit (default 64)</description> </valueHelp> <constraint> <validator name="numeric" argument="--range 0-255"/> </constraint> <constraintErrorMessage>hoplimit must be between 0-255</constraintErrorMessage> </properties> <defaultValue>64</defaultValue> </leafNode> <leafNode name="tclass"> <properties> <help>Traffic class (Tclass)</help> <valueHelp> <format>0x0-0x0FFFFF</format> <description>Traffic class, 'inherit' or hex value</description> </valueHelp> <constraint> <regex>(0x){0,1}(0?[0-9A-Fa-f]{1,2})</regex> </constraint> <constraintErrorMessage>Must be 'inherit' or a number</constraintErrorMessage> </properties> <defaultValue>inherit</defaultValue> </leafNode> </children> </node> </children> </node> </children> </tagNode> </children> </node> </interfaceDefinition> diff --git a/smoketest/scripts/cli/test_interfaces_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py index 0c562b7d9..bbdfc2f0e 100755 --- a/smoketest/scripts/cli/test_interfaces_tunnel.py +++ b/smoketest/scripts/cli/test_interfaces_tunnel.py @@ -1,227 +1,231 @@ #!/usr/bin/env python3 # # 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 # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. import unittest from vyos.configsession import ConfigSession from vyos.configsession import ConfigSessionError from vyos.util import get_interface_config from vyos.template import inc_ip from vyos.util import cmd from base_interfaces_test import BasicInterfaceTest remote_ip4 = '192.0.2.100' remote_ip6 = '2001:db8::ffff' source_if = 'dum2222' mtu = 1476 class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): @classmethod def setUpClass(cls): cls._test_ip = True cls._test_ipv6 = True cls._test_mtu = True cls._base_path = ['interfaces', 'tunnel'] cls.local_v4 = '192.0.2.1' cls.local_v6 = '2001:db8::1' 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], } cls._interfaces = list(cls._options) def setUp(self): super().setUp() self.session.set(['interfaces', 'dummy', source_if, 'address', self.local_v4 + '/32']) self.session.set(['interfaces', 'dummy', source_if, 'address', self.local_v6 + '/128']) def tearDown(self): self.session.delete(['interfaces', 'dummy', source_if]) super().tearDown() def test_ipv4_encapsulations(self): # When running tests ensure that for certain encapsulation types the # local and remote IP address is actually an IPv4 address interface = f'tun1000' local_if_addr = f'10.10.200.1/24' for encapsulation in ['ipip', 'sit', 'gre', 'gre-bridge']: 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]) # Encapsulation mode requires IPv4 local-ip with self.assertRaises(ConfigSessionError): self.session.commit() self.session.set(self._base_path + [interface, 'local-ip', self.local_v4]) # Encapsulation mode requires IPv4 local-ip 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, 'source-interface', source_if]) # Source interface can not be used with sit and gre-bridge if encapsulation in ['sit', 'gre-bridge']: 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 = get_interface_config(interface) if encapsulation not in ['sit', 'gre-bridge']: self.assertEqual(source_if, conf['link']) self.assertEqual(interface, conf['ifname']) self.assertEqual(mtu, conf['mtu']) self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local']) self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote']) # cleanup this instance self.session.delete(self._base_path + [interface]) self.session.commit() def test_ipv6_encapsulations(self): # When running tests ensure that for certain encapsulation types the # local and remote IP address is actually an IPv6 address interface = f'tun1010' local_if_addr = f'10.10.200.1/24' for encapsulation in ['ipip6', 'ip6ip6', 'ip6gre']: 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]) # Encapsulation mode requires IPv6 local-ip with self.assertRaises(ConfigSessionError): self.session.commit() self.session.set(self._base_path + [interface, 'local-ip', self.local_v6]) # Encapsulation mode requires IPv6 local-ip with self.assertRaises(ConfigSessionError): self.session.commit() self.session.set(self._base_path + [interface, 'remote-ip', remote_ip6]) # Configure Tunnel Source interface self.session.set(self._base_path + [interface, 'source-interface', source_if]) # Check if commit is ok self.session.commit() conf = get_interface_config(interface) self.assertEqual(interface, conf['ifname']) self.assertEqual(mtu, conf['mtu']) self.assertEqual(source_if, conf['link']) # Not applicable for ip6gre if 'proto' in conf['linkinfo']['info_data']: self.assertEqual(encapsulation, conf['linkinfo']['info_data']['proto']) # 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']) # cleanup this instance self.session.delete(self._base_path + [interface]) self.session.commit() def test_tunnel_verify_local_dhcp(self): # We can not use local-ip 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, 'dhcp-interface', 'eth0']) # local-ip 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']) # Check if commit is ok self.session.commit() def test_tunnel_parameters_gre(self): interface = f'tun1030' gre_key = '10' encapsulation = 'gre' tos = '20' + ttl = 0 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, 'parameters', 'ip', 'key', gre_key]) self.session.set(self._base_path + [interface, 'parameters', 'ip', 'tos', tos]) + self.session.set(self._base_path + [interface, 'parameters', 'ip', 'ttl', str(ttl)]) # 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']) + self.assertEqual(ttl, conf['linkinfo']['info_data']['ttl']) def test_gretap_parameters_change(self): interface = f'tun1040' gre_key = '10' encapsulation = 'gre-bridge' 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]) # 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('gretap', 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']) + # TTL uses a default value + self.assertEqual(64, 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-ip', 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)