diff options
| author | Christian Breunig <christian@breunig.cc> | 2026-03-03 13:28:20 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-03 13:28:20 +0100 |
| commit | d47be4a8e2119e2be0be5fe9d7c29d7d8eaf24d9 (patch) | |
| tree | 9101e996fd134a83cb2708e104bcdd7a85caa197 | |
| parent | 00361b88005948802344adbe6184057cee91cde4 (diff) | |
| parent | 99f617c88e57453315ee97cba88d3de1a24a5f01 (diff) | |
| download | vyos-1x-d47be4a8e2119e2be0be5fe9d7c29d7d8eaf24d9.tar.gz vyos-1x-d47be4a8e2119e2be0be5fe9d7c29d7d8eaf24d9.zip | |
Merge pull request #5020 from natali-rs1985/T8325
vpp: T8325: Migrate gre interface to 'interfaces vpp gre'
| -rw-r--r-- | interface-definitions/vpp.xml.in | 67 | ||||
| -rw-r--r-- | interface-definitions/vpp_interface_gre.xml.in | 81 | ||||
| -rw-r--r-- | python/vyos/ifconfig/vpp/__init__.py | 2 | ||||
| -rw-r--r-- | python/vyos/ifconfig/vpp/gre.py | 138 | ||||
| -rw-r--r-- | python/vyos/vpp/interface/__init__.py | 2 | ||||
| -rw-r--r-- | python/vyos/vpp/interface/gre.py | 140 | ||||
| -rw-r--r-- | python/vyos/vpp/interface/xconnect.py | 4 | ||||
| -rw-r--r-- | smoketest/configs/assert/vpp | 22 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_vpp.py | 77 | ||||
| -rwxr-xr-x | src/conf_mode/vpp.py | 33 | ||||
| -rw-r--r-- | src/conf_mode/vpp_interfaces_bridge.py | 2 | ||||
| -rw-r--r-- | src/conf_mode/vpp_interfaces_gre.py | 159 | ||||
| -rw-r--r-- | src/migration-scripts/vpp/5-to-6 | 34 |
13 files changed, 342 insertions, 419 deletions
diff --git a/interface-definitions/vpp.xml.in b/interface-definitions/vpp.xml.in index 733e8eb83..517129e78 100644 --- a/interface-definitions/vpp.xml.in +++ b/interface-definitions/vpp.xml.in @@ -79,73 +79,6 @@ <!-- #include <include/kernel-interface-tun.xml.i> --> <!-- </children> --> <!-- </tagNode> --> - <tagNode name="gre" owner="${vyos_conf_scripts_dir}/vpp_interfaces_gre.py"> - <properties> - <priority>325</priority> - <help>Generic Network Encapsulation (GRE) Interface</help> - <constraint> - <regex>gre[0-9]+</regex> - </constraint> - <constraintErrorMessage>GRE interface must be named greN</constraintErrorMessage> - <valueHelp> - <format>greN</format> - <description>GRE interface name</description> - </valueHelp> - </properties> - <children> - #include <include/generic-description.xml.i> - #include <include/interface/disable.xml.i> - <leafNode name="mode"> - <properties> - <help>GRE tunnel mode</help> - <completionHelp> - <list>point-to-point point-to-multipoint</list> - </completionHelp> - <valueHelp> - <format>point-to-point</format> - <description>Point to point mode</description> - </valueHelp> - <valueHelp> - <format>point-to-multipoint</format> - <description>Point to multipoint mode</description> - </valueHelp> - <constraint> - <regex>(point-to-point|point-to-multipoint)</regex> - </constraint> - <constraintErrorMessage>Invalid mode, must be one of: point-to-point or point-to-multipoint</constraintErrorMessage> - </properties> - <defaultValue>point-to-point</defaultValue> - </leafNode> - <leafNode name="tunnel-type"> - <properties> - <help>GRE tunnel type</help> - <completionHelp> - <list>erspan l3 teb</list> - </completionHelp> - <valueHelp> - <format>erspan</format> - <description>Encapsulated Remote Switched Port Analyzer</description> - </valueHelp> - <valueHelp> - <format>l3</format> - <description>Generic Routing Encapsulation (network layer)</description> - </valueHelp> - <valueHelp> - <format>teb</format> - <description>L2 Transparent Ethernet Bridge</description> - </valueHelp> - <constraint> - <regex>(erspan|l3|teb)</regex> - </constraint> - <constraintErrorMessage>Invalid encapsulation, must be one of: l3, teb or erspan</constraintErrorMessage> - </properties> - <defaultValue>l3</defaultValue> - </leafNode> - #include <include/source-address-ipv4-ipv6.xml.i> - #include <include/interface/tunnel-remote.xml.i> - #include <include/kernel-interface-tun.xml.i> - </children> - </tagNode> <tagNode name="xconnect" owner="${vyos_conf_scripts_dir}/vpp_interfaces_xconnect.py"> <properties> <help>Layer 2 cross connect</help> diff --git a/interface-definitions/vpp_interface_gre.xml.in b/interface-definitions/vpp_interface_gre.xml.in new file mode 100644 index 000000000..7636c6e2f --- /dev/null +++ b/interface-definitions/vpp_interface_gre.xml.in @@ -0,0 +1,81 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name='interfaces'> + <children> + <node name='vpp'> + <children> + <tagNode name="gre" owner="${vyos_conf_scripts_dir}/vpp_interfaces_gre.py"> + <properties> + <priority>325</priority> + <help>Generic Network Encapsulation (GRE) Interface</help> + <constraint> + <regex>vppgre[0-9]+</regex> + </constraint> + <constraintErrorMessage>GRE interface must be named vppgreN</constraintErrorMessage> + <valueHelp> + <format>vppgreN</format> + <description>GRE interface name</description> + </valueHelp> + </properties> + <children> + #include <include/generic-description.xml.i> + #include <include/interface/disable.xml.i> + <!-- Disable as point-to-multipoint mode does not work without 'teib' feature that is not implemented yet --> + <!-- <leafNode name="mode"> + <leafNode name="mode"> + <properties> + <help>GRE tunnel mode</help> + <completionHelp> + <list>point-to-point point-to-multipoint</list> + </completionHelp> + <valueHelp> + <format>point-to-point</format> + <description>Point to point mode</description> + </valueHelp> + <valueHelp> + <format>point-to-multipoint</format> + <description>Point to multipoint mode</description> + </valueHelp> + <constraint> + <regex>(point-to-point|point-to-multipoint)</regex> + </constraint> + <constraintErrorMessage>Invalid mode, must be one of: point-to-point or point-to-multipoint</constraintErrorMessage> + </properties> + <defaultValue>point-to-point</defaultValue> + </leafNode> --> + <leafNode name="tunnel-type"> + <properties> + <help>GRE tunnel type</help> + <completionHelp> + <list>erspan l3 teb</list> + </completionHelp> + <valueHelp> + <format>erspan</format> + <description>Encapsulated Remote Switched Port Analyzer</description> + </valueHelp> + <valueHelp> + <format>l3</format> + <description>Generic Routing Encapsulation (network layer)</description> + </valueHelp> + <valueHelp> + <format>teb</format> + <description>L2 Transparent Ethernet Bridge</description> + </valueHelp> + <constraint> + <regex>(erspan|l3|teb)</regex> + </constraint> + <constraintErrorMessage>Invalid encapsulation, must be one of: l3, teb or erspan</constraintErrorMessage> + </properties> + <defaultValue>l3</defaultValue> + </leafNode> + #include <include/source-address-ipv4-ipv6.xml.i> + #include <include/interface/tunnel-remote.xml.i> + #include <include/interface/address-ipv4-ipv6.xml.i> + #include <include/interface/mtu-68-16000.xml.i> + </children> + </tagNode> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/python/vyos/ifconfig/vpp/__init__.py b/python/vyos/ifconfig/vpp/__init__.py index b0a477c28..7abe402c6 100644 --- a/python/vyos/ifconfig/vpp/__init__.py +++ b/python/vyos/ifconfig/vpp/__init__.py @@ -16,6 +16,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from .bond import VPPBondInterface +from .gre import VPPGREInterface from .interface import VPPInterface from .ipip import VPPIPIPInterface from .loopback import VPPLoopbackInterface @@ -23,6 +24,7 @@ from .vxlan import VPPVXLANInterface __all__ = [ 'VPPBondInterface', + 'VPPGREInterface', 'VPPInterface', 'VPPIPIPInterface', 'VPPLoopbackInterface', diff --git a/python/vyos/ifconfig/vpp/gre.py b/python/vyos/ifconfig/vpp/gre.py new file mode 100644 index 000000000..7ab600998 --- /dev/null +++ b/python/vyos/ifconfig/vpp/gre.py @@ -0,0 +1,138 @@ +# VyOS implementation of VPP GRE interface +# +# Copyright (C) VyOS Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from vyos.ifconfig import Interface +from vyos.ifconfig.vpp.interface import VPPInterface + + +class VPPGREInterface(Interface, VPPInterface): + """ + Class representing a GRE (Generic Routing Encapsulation) interface. + """ + + # Mapping of tunnel types https://github.com/FDio/vpp/blob/stable/2406/src/plugins/gre/gre.api#L25-L35 + TUNNEL_TYPE_MAP = { + 'l3': 0, + 'teb': 1, + 'erspan': 2, + } + + MODE_MAP = { + 'point-to-point': 0, + # 'point-to-multipoint': 1, + } + + def __init__(self, ifname, config): + self.ifname = ifname + self.instance = int(ifname.removeprefix('vppgre')) + self.vpp_ifname = f'gre{self.instance}' + + # Initialize Interface (kernel) and VPP part + super().__init__(ifname) + VPPInterface.__init__(self, self.vpp_ifname) + + self.index = self.vpp.get_sw_if_index(self.vpp_ifname) + self.state = 'up' if 'disable' not in config else 'down' + self.src_address = config.get('source_address') + self.dst_address = config.get('remote') + self.tunnel_type = self.TUNNEL_TYPE_MAP.get(config.get('tunnel_type'), 0) + self.mode = self.MODE_MAP['point-to-point'] + + def _create(self): + pass + + def get_gre(self): + tunnels = self.vpp.api.gre_tunnel_dump(sw_if_index=self.index) + return tunnels if tunnels else None + + def add_gre(self): + """Create GRE interface + https://github.com/FDio/vpp/blob/stable/2406/src/plugins/gre/gre.api + Example: + from vyos.ifconfig.vpp import VPPGREInterface + a = VPPGREInterface(ifname='vppgre0', config) + a.add_gre() + """ + self.vpp.api.gre_tunnel_add_del( + is_add=True, + tunnel={ + 'src': self.src_address, + 'dst': self.dst_address, + 'instance': self.instance, + 'mode': self.mode, + 'type': self.tunnel_type, + }, + ) + # Add LCP pair (kernel) interface + self.kernel_add() + # Set interface state + self.set_state(self.state) + self.set_admin_state(self.state) + self.index = self.vpp.get_sw_if_index(self.vpp_ifname) + + def delete_gre(self): + """Delete GRE interface + Example: + from vyos.ifconfig.vpp import VPPGREInterface + a = VPPGREInterface(ifname='vppgre0', config) + a.delete_gre() + """ + gre = self.get_gre() + if gre: + return self.vpp.api.gre_tunnel_add_del( + is_add=False, + tunnel={'src': gre.tunnel.src, 'dst': gre.tunnel.dst}, + ) + + def kernel_add(self): + """Add LCP pair + Example: + from vyos.ifconfig.vpp import VPPGREInterface + a = VPPGREInterface(ifname='vppgre0', config) + a.kernel_add() + """ + self.vpp.lcp_pair_add(self.vpp_ifname, self.ifname, 'tun') + + def kernel_delete(self): + """Delete LCP pair + Example: + from vyos.ifconfig.vpp import VPPGREInterface + a = VPPGREInterface(ifname='vppgre0', config) + a.kernel_delete() + """ + self.vpp.lcp_pair_del(self.vpp_ifname, self.ifname) + + def remove(self): + if self.index: + # Delete lcp pair interface + if self.vpp.lcp_pair_find(vpp_name_hw=self.vpp_ifname): + self.kernel_delete() + + # Delete gre interface + self.delete_gre() + + def update(self, config): + # Add gre interface + self.add_gre() + + # Set rx-mode + rx_mode = config.get('vpp_settings', {}).get('interface_rx_mode') + if rx_mode: + self.set_rx_mode(rx_mode) + + super().update(config) diff --git a/python/vyos/vpp/interface/__init__.py b/python/vyos/vpp/interface/__init__.py index 4ae96f486..cdfb0c0b8 100644 --- a/python/vyos/vpp/interface/__init__.py +++ b/python/vyos/vpp/interface/__init__.py @@ -18,7 +18,6 @@ from .bridge import BridgeInterface from .ethernet import EthernetInterface from .geneve import GeneveInterface -from .gre import GREInterface from .interface import Interface from .wireguard import WireguardInterface from .xconnect import XconnectInterface @@ -27,7 +26,6 @@ __all__ = [ 'BridgeInterface', 'EthernetInterface', 'GeneveInterface', - 'GREInterface', 'Interface', 'WireguardInterface', 'XconnectInterface', diff --git a/python/vyos/vpp/interface/gre.py b/python/vyos/vpp/interface/gre.py deleted file mode 100644 index bc278d2a0..000000000 --- a/python/vyos/vpp/interface/gre.py +++ /dev/null @@ -1,140 +0,0 @@ -# VyOS implementation of VPP GRE interface -# -# Copyright (C) VyOS Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -from vyos.vpp import VPPControl -from vyos.vpp.interface.interface import Interface - - -def show(): - """Show GRE interface - Example: - from vyos.vpp.interface import gre - gre.show() - """ - vpp = VPPControl() - return vpp.api.gre_tunnel_dump() - - -class GREInterface(Interface): - """ - Class representing a GRE (Generic Routing Encapsulation) interface. - - Attributes: - ifname (str): The interface name. - source_address (str): The source IP address for the GRE tunnel. - remote (str): The remote IP address for the GRE tunnel. - tunnel_type (str): The type of GRE tunnel. Defaults to 'l3'. - mode (str): The mode of the GRE tunnel. Options are 'point-to-point' and 'point-to-multipoint'. Defaults to 'point-to-point'. - kernel_interface (str): The associated kernel interface. Defaults to an empty string. - instance (int): The instance number derived from the interface name. - vpp (VPPControl): An instance of the VPPControl class for interacting with the VPP API. - """ - - # Mapping of tunnel types https://github.com/FDio/vpp/blob/stable/2406/src/plugins/gre/gre.api#L25-L35 - TUNNEL_TYPE_MAP = { - 'l3': 0, - 'teb': 1, - 'erspan': 2, - } - - MODE_MAP = { - 'point-to-point': 0, - 'point-to-multipoint': 1, - } - - def __init__( - self, - ifname, - source_address, - remote, - tunnel_type: str = 'l3', - mode: str = 'point-to-point', - kernel_interface: str = '', - state: str = 'up', - ): - """ - Initialize a GREInterface instance. - - Args: - ifname (str): The interface name. - source_address (str): The source IP address for the GRE tunnel. - remote (str): The remote IP address for the GRE tunnel. - mode (str): The mode of the GRE tunnel. Options are 'point-to-point' and 'point-to-multipoint'. Defaults to 'point-to-point'. - tunnel_type (str): The type of GRE tunnel. Defaults to 'l3'. - kernel_interface (str): The associated kernel interface. Defaults to an empty string. - state (str): The state of the interface. Defaults to 'up'. - """ - super().__init__(ifname) - self.instance = int(ifname.removeprefix('gre')) - self.ifname = ifname - self.src_address = source_address - self.dst_address = remote - self.tunnel_type = self.TUNNEL_TYPE_MAP[tunnel_type] - self.mode = self.MODE_MAP[mode] - self.kernel_interface = kernel_interface - self.initial_state = state - - def add(self): - """Create GRE interface - https://github.com/FDio/vpp/blob/stable/2406/src/plugins/gre/gre.api - Example: - from vyos.vpp.interface import GREInterface - a = GREInterface(ifname='gre0', source_address='192.0.2.1', remote='203.0.113.25', tunnel_type='l3') - a.add() - """ - self.vpp.api.gre_tunnel_add_del( - is_add=True, - tunnel={ - 'src': self.src_address, - 'dst': self.dst_address, - 'instance': self.instance, - 'mode': self.mode, - 'type': self.tunnel_type, - }, - ) - # Set interface state - self.set_state(self.initial_state) - - def delete(self): - """Delete GRE interface - Example: - from vyos.vpp.interface import GREInterface - a = GREInterface(ifname='gre0', source_address='192.0.2.1', remote='203.0.113.25') - a.delete() - """ - return self.vpp.api.gre_tunnel_add_del( - is_add=False, tunnel={'src': self.src_address, 'dst': self.dst_address} - ) - - def kernel_add(self): - """Add LCP pair - Example: - from vyos.vpp.interface import GREInterface - a = GREInterface(ifname='gre0', source_address='192.0.2.1', remote='203.0.113.25') - a.kernel_add() - """ - self.vpp.lcp_pair_add(self.ifname, self.kernel_interface, 'tun') - - def kernel_delete(self): - """Delete LCP pair - Example: - from vyos.vpp.interface import GREInterface - a = GREInterface(ifname='gre0', source_address='192.0.2.1', remote='203.0.113.25') - a.kernel_delete() - """ - self.vpp.lcp_pair_del(self.ifname, self.kernel_interface) diff --git a/python/vyos/vpp/interface/xconnect.py b/python/vyos/vpp/interface/xconnect.py index 603f7f90b..dd61d7146 100644 --- a/python/vyos/vpp/interface/xconnect.py +++ b/python/vyos/vpp/interface/xconnect.py @@ -41,7 +41,7 @@ class XconnectInterface: a = XconnectInterface(ifname='xcon0', members=['eth0', 'vxlan0']) a.add_l2_xconnect() """ - interface_transform_filter = ('vxlan', 'gre') + interface_transform_filter = ('vxlan', 'geneve') first_member = self.members[0].removeprefix('vpp') second_member = self.members[1].removeprefix('vpp') # Check if member in required filter to transform 'vxlanX' => 'vxlan_tunnelX' @@ -72,7 +72,7 @@ class XconnectInterface: a = XconnectInterface(ifname='xcon0', members=['eth0', 'vxlan0']) a.del_l2_xconnect() """ - interface_transform_filter = ('vxlan', 'gre') + interface_transform_filter = ('vxlan', 'geneve') first_member = self.members[0].removeprefix('vpp') second_member = self.members[1].removeprefix('vpp') # Check if member in required filter to transform 'vxlanX' => 'vxlan_tunnelX' diff --git a/smoketest/configs/assert/vpp b/smoketest/configs/assert/vpp index f8cab98f4..1e89dc324 100644 --- a/smoketest/configs/assert/vpp +++ b/smoketest/configs/assert/vpp @@ -22,20 +22,14 @@ set system syslog local facility local7 level 'debug' set interfaces vpp bonding vppbond0 hash-policy 'layer2+3' set interfaces vpp bonding vppbond0 member interface 'eth4' set interfaces vpp bonding vppbond0 mode '802.3ad' -set vpp interfaces gre gre10 description 'Layer-3' -set vpp interfaces gre gre10 mode 'point-to-point' -set vpp interfaces gre gre10 remote '192.0.2.2' -set vpp interfaces gre gre10 source-address '192.0.2.1' -set vpp interfaces gre gre10 tunnel-type 'l3' -set vpp interfaces gre gre11 description 'L2-bridge-to-eth2' -set vpp interfaces gre gre11 remote '192.0.2.123' -set vpp interfaces gre gre11 source-address '192.0.2.1' -set vpp interfaces gre gre11 tunnel-type 'teb' -set vpp interfaces gre gre12 description 'Multipoint' -set vpp interfaces gre gre12 mode 'point-to-multipoint' -set vpp interfaces gre gre12 remote '0.0.0.0' -set vpp interfaces gre gre12 source-address '192.0.2.21' -set vpp interfaces gre gre12 tunnel-type 'l3' +set interfaces vpp gre vppgre10 description 'Layer-3' +set interfaces vpp gre vppgre10 remote '192.0.2.2' +set interfaces vpp gre vppgre10 source-address '192.0.2.1' +set interfaces vpp gre vppgre10 tunnel-type 'l3' +set interfaces vpp gre vppgre11 description 'L2-bridge-to-eth2' +set interfaces vpp gre vppgre11 remote '192.0.2.123' +set interfaces vpp gre vppgre11 source-address '192.0.2.1' +set interfaces vpp gre vppgre11 tunnel-type 'teb' set interfaces vpp ipip vppipip20 remote '192.0.2.2' set interfaces vpp ipip vppipip20 source-address '192.0.2.1' set interfaces vpp loopback vpplo12 description 'Loop12' diff --git a/smoketest/scripts/cli/test_vpp.py b/smoketest/scripts/cli/test_vpp.py index 90e4e4538..a16e9af11 100755 --- a/smoketest/scripts/cli/test_vpp.py +++ b/smoketest/scripts/cli/test_vpp.py @@ -293,29 +293,16 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): self.cli_commit() def test_03_vpp_gre(self): - interface_gre = 'gre12' - interface_kernel = 'vpptun12' - new_interface_kernel = 'vpptun123' + gre_path = interfaces_path + ['gre'] + interface_gre = 'vppgre12' source_address = '192.0.2.1' new_source_address = '192.0.2.2' remote_address = '192.0.2.254' - kernel_address = '10.0.0.0' + address = '10.0.0.0' - self.cli_set( - base_path - + ['interfaces', 'gre', interface_gre, 'source-address', source_address] - ) - self.cli_set( - base_path + ['interfaces', 'gre', interface_gre, 'remote', remote_address] - ) - self.cli_set( - base_path - + ['interfaces', 'gre', interface_gre, 'kernel-interface', interface_kernel] - ) - self.cli_set( - base_path - + ['kernel-interfaces', interface_kernel, 'address', f'{kernel_address}/31'] - ) + self.cli_set(gre_path + [interface_gre, 'source-address', source_address]) + self.cli_set(gre_path + [interface_gre, 'remote', remote_address]) + self.cli_set(gre_path + [interface_gre, 'address', f'{address}/31']) # source address of the tunnel interface should be configured # expect raise ConfigError @@ -329,9 +316,9 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): # commit changes self.cli_commit() - self.assertTrue(os.path.isdir(f'/sys/class/net/{interface_kernel}')) - current_address = get_address(interface_kernel) - self.assertEqual(kernel_address, current_address) + self.assertTrue(os.path.isdir(f'/sys/class/net/{interface_gre}')) + current_address = get_address(interface_gre) + self.assertEqual(address, current_address) # check gre interface _, out = rc_cmd('sudo vppctl show gre tunnel') @@ -339,10 +326,7 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): self.assertIn(required_str, out) # update gre interface - self.cli_set( - base_path - + ['interfaces', 'gre', interface_gre, 'source-address', new_source_address] - ) + self.cli_set(gre_path + [interface_gre, 'source-address', new_source_address]) self.cli_set( ['interfaces', 'ethernet', interface, 'address', f'{new_source_address}/24'] @@ -353,46 +337,11 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): _, out = rc_cmd('sudo vppctl show gre tunnel') required_str = f'[0] instance 12 src {new_source_address} dst {remote_address}' self.assertIn(required_str, out) - self.assertTrue(os.path.isdir(f'/sys/class/net/{interface_kernel}')) - self.assertEqual(kernel_address, current_address) - - # delete gre kernel-interface but do not delete 'vpp kernel-interface' - # expect raise ConfigError - self.cli_delete( - base_path - + ['interfaces', 'gre', interface_gre, 'kernel-interface', interface_kernel] - ) - with self.assertRaises(ConfigSessionError): - self.cli_commit() - - # update gre kernel-interface but do not change 'vpp kernel-interface' - # expect raise ConfigError - self.cli_set( - base_path - + [ - 'interfaces', - 'gre', - interface_gre, - 'kernel-interface', - new_interface_kernel, - ] - ) - with self.assertRaises(ConfigSessionError): - self.cli_commit() - - # delete kernel interface - self.cli_delete(base_path + ['kernel-interfaces', interface_kernel]) - self.cli_commit() - - # delete gre kernel-interface - self.cli_delete( - base_path + ['interfaces', 'gre', interface_gre, 'kernel-interface'] - ) - self.cli_commit() - self.assertFalse(os.path.isdir(f'/sys/class/net/{interface_kernel}')) + self.assertTrue(os.path.isdir(f'/sys/class/net/{interface_gre}')) + self.assertEqual(address, current_address) # delete gre interface - self.cli_delete(base_path + ['interfaces', 'gre', interface_gre]) + self.cli_delete(gre_path + [interface_gre]) self.cli_commit() @unittest.skip('Skipping this test geneve index always is 0') diff --git a/src/conf_mode/vpp.py b/src/conf_mode/vpp.py index 6d2e2866f..92777a16a 100755 --- a/src/conf_mode/vpp.py +++ b/src/conf_mode/vpp.py @@ -612,17 +612,17 @@ def verify(config): ) # check GRE tunnels as part of the bridge, only tunnel-type teb is allowed - # set vpp interfaces bridge br1 member interface gre1 - # set vpp interfaces gre gre1 tunnel-type teb + # set vpp interfaces bridge br1 member interface vppgre1 + # set interfaces vpp gre vppgre1 tunnel-type teb if 'interfaces' in config: if 'bridge' in config['interfaces']: for iface, iface_config in config['interfaces']['bridge'].items(): if 'member' in iface_config: for member in iface_config['member'].get('interface', []): - if member.startswith('gre'): + if member.startswith('vppgre'): if ( - 'gre' in config['interfaces'] - and config['interfaces']['gre'] + 'gre' in config['interfaces_vpp'] + and config['interfaces_vpp']['gre'] .get(member, {}) .get('tunnel_type') != 'teb' @@ -631,29 +631,6 @@ def verify(config): f'Only tunnel-type teb is allowed for GRE interfaces in bridge {iface}' ) - # Only one multipoint GRE tunnel is allowed from the same source address - # set vpp interfaces gre gre0 mode 'point-to-multipoint' - # set vpp interfaces gre gre0 remote '0.0.0.0' - # set vpp interfaces gre gre0 source-address '192.0.2.1' - # set vpp interfaces gre gre1 mode 'point-to-multipoint' - # set vpp interfaces gre gre1 remote '0.0.0.0' - # set vpp interfaces gre gre1 source-address '192.0.2.1' - if 'gre' in config['interfaces']: - for iface, iface_config in config['interfaces']['gre'].items(): - if iface_config['mode'] == 'point-to-multipoint': - for other_iface, other_iface_config in config['interfaces'][ - 'gre' - ].items(): - if ( - other_iface_config['mode'] == 'point-to-multipoint' - and other_iface_config['source_address'] - == iface_config['source_address'] - and iface != other_iface - ): - raise ConfigError( - 'Only one multipoint GRE tunnel is allowed from the same source address' - ) - # Check if deleted interfaces are not xconnect memebrs for iface_config in config.get('removed_ifaces', []): if iface_config['iface_name'] in config.get('xconn_members', {}): diff --git a/src/conf_mode/vpp_interfaces_bridge.py b/src/conf_mode/vpp_interfaces_bridge.py index d53173f04..edf3f2dd2 100644 --- a/src/conf_mode/vpp_interfaces_bridge.py +++ b/src/conf_mode/vpp_interfaces_bridge.py @@ -96,7 +96,7 @@ def verify(config): # Check if interface exists in vpp before adding to bridge-domain - allowed_prefixes = ('vppbond', 'gre', 'geneve', 'vpplo', 'vppvxlan') + allowed_prefixes = ('vppbond', 'vppgre', 'geneve', 'vpplo', 'vppvxlan') if 'member' in config: bvi_exists = False diff --git a/src/conf_mode/vpp_interfaces_gre.py b/src/conf_mode/vpp_interfaces_gre.py index 53a423dd9..453845bcf 100644 --- a/src/conf_mode/vpp_interfaces_gre.py +++ b/src/conf_mode/vpp_interfaces_gre.py @@ -16,25 +16,20 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -import os - from vyos import ConfigError from vyos.config import Config -from vyos.configdict import leaf_node_changed +from vyos.configdict import get_interface_dict from vyos.configdep import set_dependents, call_dependents -from vyos.template import is_interface +from vyos.utils.process import is_systemd_service_active -from vyos.vpp.interface import GREInterface +from vyos.ifconfig.vpp import VPPGREInterface from vyos.vpp.config_deps import deps_xconnect_dict from vyos.vpp.config_verify import ( - verify_vpp_remove_kernel_interface, - verify_vpp_change_kernel_interface, verify_vpp_remove_xconnect_interface, - verify_vpp_exists_kernel_interface, verify_vpp_tunnel_source_address, ) -from vyos.vpp.utils import cli_ifaces_lcp_kernel_list, cli_ethernet_with_vifs_ifaces +from vyos.vpp.utils import cli_ethernet_with_vifs_ifaces def get_config(config=None) -> dict: @@ -50,55 +45,14 @@ def get_config(config=None) -> dict: else: conf = Config() - base = ['vpp', 'interfaces', 'gre'] - base_kernel_interfaces = ['vpp', 'kernel-interfaces'] - - ifname = os.environ['VYOS_TAGNODE_VALUE'] + base = ['interfaces', 'vpp', 'gre'] - # Get config_dict with default values - config = conf.get_config_dict( - base + [ifname], - key_mangling=('-', '_'), - get_first_key=True, - no_tag_node_value_mangle=True, - with_defaults=True, - with_recursive_defaults=True, - ) + ifname, config = get_interface_dict(conf, base) - if not conf.exists(['vpp']): + if not conf.exists(['vpp']) and not conf.exists(base): config['remove_vpp'] = True return config - # Get effective config as we need full dicitonary per interface delete - effective_config = conf.get_config_dict( - base + [ifname], - key_mangling=('-', '_'), - effective=True, - get_first_key=True, - no_tag_node_value_mangle=True, - ) - - if effective_config: - config.update({'effective': effective_config}) - - if not conf.exists(base + [ifname]): - config['remove'] = True - - # Get global 'vpp kernel-interfaces' for verify - config['vpp_kernel_interfaces'] = conf.get_config_dict( - base_kernel_interfaces, - key_mangling=('-', '_'), - get_first_key=True, - no_tag_node_value_mangle=True, - ) - - tmp = leaf_node_changed(conf, base + [ifname, 'kernel-interface']) - if tmp: - config['kernel_interface_removed'] = tmp - - # list of all kernel interfaces `vpp interface xxx kernel-interface xxx` - config['candidate_kernel_interfaces'] = cli_ifaces_lcp_kernel_list(conf) - # list of all Ethernet interfaces with vifs config['vpp_ether_vif_ifaces'] = cli_ethernet_with_vifs_ifaces(conf) @@ -108,11 +62,23 @@ def get_config(config=None) -> dict: for xconn_iface in config['xconn_members'][ifname]: set_dependents('vpp_interfaces_xconnect', conf, xconn_iface) - if effective_config.get('kernel_interface'): - if conf.exists(base + [ifname, 'kernel-interface']): - iface = config.get('kernel_interface') - if conf.exists(['vpp', 'kernel-interfaces', iface]): - set_dependents('vpp_kernel_interface', conf, iface) + # Get 'vpp settings' config + config['vpp_settings'] = conf.get_config_dict( + ['vpp', 'settings'], + key_mangling=('-', '_'), + get_first_key=True, + no_tag_node_value_mangle=True, + ) + + # Get all gre interfaces config + config['gre_interfaces'] = conf.get_config_dict( + base, + key_mangling=('-', '_'), + get_first_key=True, + no_tag_node_value_mangle=True, + with_defaults=True, + with_recursive_defaults=True, + ) # NAT dependency if conf.exists(['vpp', 'nat', 'nat44']): @@ -124,7 +90,6 @@ def get_config(config=None) -> dict: if conf.exists(['vpp', 'acl']): set_dependents('vpp_acl', conf) - config['ifname'] = ifname return config @@ -133,19 +98,19 @@ def verify(config): if 'remove_vpp' in config: return None - # Verify that removed kernel interface is not used in 'vpp kernel-interfaces'. - # vpp interfaces gre greX kernel-interface vpp-tunX - # vpp kernel-interface vpp-tunX - verify_vpp_remove_kernel_interface(config) - verify_vpp_remove_xconnect_interface(config) # config removed - if 'remove' in config: + if 'deleted' in config: return None + if not is_systemd_service_active('vpp.service'): + raise ConfigError( + 'Cannot configure VPP GRE interface: vpp.service is not running' + ) + # source-address and remote are mandatory options - required_keys = {'source_address', 'remote', 'mode', 'tunnel_type'} + required_keys = {'source_address', 'remote', 'tunnel_type'} if not all(key in config for key in required_keys): missing_keys = required_keys - set(config.keys()) raise ConfigError( @@ -157,17 +122,28 @@ def verify(config): if config.get('source_address') == config.get('remote'): raise ConfigError('Remote address must not be the same as source address') - # check multipoint mode - if config.get('mode') == 'point-to-multipoint': - # For multipoint mode, remote IP must be 0.0.0.0 - if config.get('remote') != '0.0.0.0': - raise ConfigError('For point-to-multipoint mode, remote must be 0.0.0.0') - - # Change 'vpp interfaces gre greX kernel-interface vpp-tunX' - # => 'vpp interfaces gre greX kernel-interface vpp-tunY' - # check if we have kernel interface config 'vpp kernel-interface vpp-tunX' - verify_vpp_change_kernel_interface(config) - verify_vpp_exists_kernel_interface(config) + # Disable checks as point-to-multipoint mode does not work without 'teib' feature that is not implemented yet + # # check multipoint mode + # if config.get('mode') == 'point-to-multipoint': + # # For multipoint mode, remote IP must be 0.0.0.0 + # if config.get('remote') != '0.0.0.0': + # raise ConfigError('For point-to-multipoint mode, remote must be 0.0.0.0') + # + # # Only one multipoint GRE tunnel is allowed from the same source address + # # set interfaces vpp gre vppgre0 mode 'point-to-multipoint' + # # set interfaces vpp gre vppgre0 remote '0.0.0.0' + # # set interfaces vpp gre vppgre0 source-address '192.0.2.1' + # # set interfaces vpp gre vppgre1 mode 'point-to-multipoint' + # # set interfaces vpp gre vppgre1 remote '0.0.0.0' + # # set interfaces vpp gre vppgre1 source-address '192.0.2.1' + # for other_iface, other_iface_config in config['gre_interfaces'].items(): + # if other_iface == config['ifname']: + # continue + # if other_iface_config['mode'] == 'point-to-multipoint': + # if config['source_address'] == other_iface_config.get('source_address'): + # raise ConfigError( + # 'Only one multipoint GRE tunnel is allowed from the same source address' + # ) def generate(config): @@ -179,32 +155,13 @@ def apply(config): return None ifname = config.get('ifname') - # Delete interface - if 'effective' in config: - remove_config = config.get('effective') - src_addr = remove_config.get('source_address') - dst_addr = remove_config.get('remote') - i = GREInterface(ifname, src_addr, dst_addr) - i.delete() - - if 'remove' in config: - return None + gre = VPPGREInterface(ifname, config) + gre.remove() - # Add interface - src_addr = config.get('source_address') - dst_addr = config.get('remote') - kernel_interface = config.get('kernel_interface', '') - mode = config.get('mode') - tunnel_type = config.get('tunnel_type') - state = 'up' if 'disable' not in config else 'down' - i = GREInterface( - ifname, src_addr, dst_addr, tunnel_type, mode, kernel_interface, state - ) - i.add() + if 'deleted' in config: + return - # Add kernel-interface (LCP) if interface is not exist - if 'kernel_interface' in config and not is_interface(kernel_interface): - i.kernel_add() + gre.update(config) call_dependents() diff --git a/src/migration-scripts/vpp/5-to-6 b/src/migration-scripts/vpp/5-to-6 index 23b2d4eaa..03c20d970 100644 --- a/src/migration-scripts/vpp/5-to-6 +++ b/src/migration-scripts/vpp/5-to-6 @@ -45,6 +45,8 @@ # # Migrate loopback interface from vpp section to 'interfaces vpp loopback' (T8324) # +# Migrate gre interface to 'interfaces vpp gre', remove interfaces with mode "point-to-multipoint" (T8325) +# from vyos.configtree import ConfigTree @@ -463,6 +465,37 @@ def _migrate_vpp_loopback_interface(config: ConfigTree) -> None: config.delete(['vpp', 'interfaces']) +def _migrate_vpp_gre_interface(config: ConfigTree) -> None: + base = ['vpp', 'interfaces', 'gre'] + new_base = ['interfaces', 'vpp', 'gre'] + kernel_interface_base = ['vpp', 'kernel-interfaces'] + + if not config.exists(base): + return + + config.set(new_base) + + for ifname in config.list_nodes(base): + if config.exists(base + [ifname, 'mode']): + if config.return_value(base + [ifname, 'mode']) == 'point-to-multipoint': + config.delete(base + [ifname]) + continue + config.delete(base + [ifname, 'mode']) + + _migrate_interface(config, 'gre', ifname) + + _migrate_members_bridge(config, ifname) + _migrate_members_xconnect(config, ifname) + + config.delete(base) + + if config.exists(kernel_interface_base) and len(config.list_nodes(kernel_interface_base)) == 0: + config.delete(['vpp', 'kernel-interfaces']) + + if len(config.list_nodes(['vpp', 'interfaces'])) == 0: + config.delete(['vpp', 'interfaces']) + + def migrate(config: ConfigTree) -> None: if not config.exists(['vpp']): # Nothing to do @@ -482,3 +515,4 @@ def migrate(config: ConfigTree) -> None: _migrate_vpp_vxlan_interface(config) _migrate_vpp_ipip_interface(config) _migrate_vpp_loopback_interface(config) + _migrate_vpp_gre_interface(config) |
