diff --git a/interface-definitions/include/interface/parameters-innerproto.xml.i b/interface-definitions/include/interface/parameters-innerproto.xml.i new file mode 100644 index 000000000..9cafebd11 --- /dev/null +++ b/interface-definitions/include/interface/parameters-innerproto.xml.i @@ -0,0 +1,8 @@ +<!-- include start from interface/parameters-innerproto.xml.i --> +<leafNode name="innerproto"> + <properties> + <help>Use IPv4 as inner protocol instead of Ethernet</help> + <valueless/> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/interfaces-geneve.xml.in b/interface-definitions/interfaces-geneve.xml.in index 330dadd95..29b563a09 100644 --- a/interface-definitions/interfaces-geneve.xml.in +++ b/interface-definitions/interfaces-geneve.xml.in @@ -1,59 +1,60 @@ <?xml version="1.0"?> <interfaceDefinition> <node name="interfaces"> <children> <tagNode name="geneve" owner="${vyos_conf_scripts_dir}/interfaces-geneve.py"> <properties> <help>Generic Network Virtualization Encapsulation (GENEVE) Interface</help> <priority>460</priority> <constraint> <regex>gnv[0-9]+</regex> </constraint> <constraintErrorMessage>GENEVE interface must be named gnvN</constraintErrorMessage> <valueHelp> <format>gnvN</format> <description>GENEVE interface name</description> </valueHelp> </properties> <children> #include <include/interface/address-ipv4-ipv6.xml.i> #include <include/generic-description.xml.i> #include <include/interface/disable.xml.i> #include <include/interface/ipv4-options.xml.i> #include <include/interface/ipv6-options.xml.i> #include <include/interface/mac.xml.i> #include <include/interface/mtu-1200-16000.xml.i> <node name="parameters"> <properties> <help>GENEVE tunnel parameters</help> </properties> <children> <node name="ip"> <properties> <help>IPv4 specific tunnel parameters</help> </properties> <children> #include <include/interface/parameters-df.xml.i> #include <include/interface/parameters-tos.xml.i> #include <include/interface/parameters-ttl.xml.i> + #include <include/interface/parameters-innerproto.xml.i> </children> </node> <node name="ipv6"> <properties> <help>IPv6 specific tunnel parameters</help> </properties> <children> #include <include/interface/parameters-flowlabel.xml.i> </children> </node> </children> </node> #include <include/interface/mirror.xml.i> #include <include/interface/redirect.xml.i> #include <include/interface/tunnel-remote.xml.i> #include <include/vni.xml.i> </children> </tagNode> </children> </node> </interfaceDefinition> diff --git a/python/vyos/ifconfig/geneve.py b/python/vyos/ifconfig/geneve.py index 276c34cd7..7a05e47a7 100644 --- a/python/vyos/ifconfig/geneve.py +++ b/python/vyos/ifconfig/geneve.py @@ -1,64 +1,65 @@ # Copyright 2019-2021 VyOS maintainers and contributors <maintainers@vyos.io> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see <http://www.gnu.org/licenses/>. from vyos.ifconfig import Interface from vyos.util import dict_search @Interface.register class GeneveIf(Interface): """ Geneve: Generic Network Virtualization Encapsulation For more information please refer to: https://tools.ietf.org/html/draft-gross-geneve-00 https://www.redhat.com/en/blog/what-geneve https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels/#geneve https://lwn.net/Articles/644938/ """ iftype = 'geneve' definition = { **Interface.definition, **{ 'section': 'geneve', 'prefixes': ['gnv', ], 'bridgeable': True, } } def _create(self): # This table represents a mapping from VyOS internal config dict to # arguments used by iproute2. For more information please refer to: # - https://man7.org/linux/man-pages/man8/ip-link.8.html mapping = { 'parameters.ip.df' : 'df', 'parameters.ip.tos' : 'tos', 'parameters.ip.ttl' : 'ttl', + 'parameters.ip.innerproto' : 'innerprotoinherit', 'parameters.ipv6.flowlabel' : 'flowlabel', } cmd = 'ip link add name {ifname} type {type} id {vni} remote {remote}' for vyos_key, iproute2_key in mapping.items(): # dict_search will return an empty dict "{}" for valueless nodes like # "parameters.nolearning" - thus we need to test the nodes existence # by using isinstance() tmp = dict_search(vyos_key, self.config) if isinstance(tmp, dict): cmd += f' {iproute2_key}' elif tmp != None: cmd += f' {iproute2_key} {tmp}' self._cmd(cmd.format(**self.config)) # interface is always A/D down. It needs to be enabled explicitly self.set_admin_state('down') diff --git a/smoketest/scripts/cli/test_interfaces_geneve.py b/smoketest/scripts/cli/test_interfaces_geneve.py index 24d350aeb..b2efb0349 100755 --- a/smoketest/scripts/cli/test_interfaces_geneve.py +++ b/smoketest/scripts/cli/test_interfaces_geneve.py @@ -1,78 +1,84 @@ #!/usr/bin/env python3 # # Copyright (C) 2020-2022 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. import unittest from vyos.ifconfig import Interface from vyos.util import get_interface_config from base_interfaces_test import BasicInterfaceTest class GeneveInterfaceTest(BasicInterfaceTest.TestCase): @classmethod def setUpClass(cls): cls._base_path = ['interfaces', 'geneve'] 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) # call base-classes classmethod super(GeneveInterfaceTest, cls).setUpClass() def test_geneve_parameters(self): tos = '40' ttl = 20 for intf in self._interfaces: for option in self._options.get(intf, []): self.cli_set(self._base_path + [intf] + option.split()) self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'df', 'set']) self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'tos', tos]) + self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'innerproto']) self.cli_set(self._base_path + [intf, 'parameters', 'ip', 'ttl', str(ttl)]) ttl += 10 self.cli_commit() ttl = 20 for interface in self._interfaces: options = get_interface_config(interface) vni = options['linkinfo']['info_data']['id'] self.assertIn(f'vni {vni}', self._options[interface]) if any('remote' in s for s in self._options[interface]): key = 'remote' if 'remote6' in options['linkinfo']['info_data']: key = 'remote6' remote = options['linkinfo']['info_data'][key] self.assertIn(f'remote {remote}', self._options[interface]) if any('flowlabel' in s for s in self._options[interface]): label = options['linkinfo']['info_data']['label'] self.assertIn(f'parameters ipv6 flowlabel {label}', self._options[interface]) + if any('innerproto' in s for s in self._options[interface]): + inner = options['linkinfo']['info_data']['innerproto'] + self.assertIn(f'parameters ip {inner}', 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)