summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNataliia Solomko <natalirs1985@gmail.com>2026-02-26 15:27:27 +0200
committerNataliia Solomko <natalirs1985@gmail.com>2026-02-27 21:26:00 +0200
commit3755dfa7612ffa7edc94537220340a00c9db13ad (patch)
tree5ab1f39a140deec9c2c3f98e502b7551848b8125
parentbfb8537c4e79e18e960cf15064658d3ee50fd05a (diff)
downloadvyos-1x-3755dfa7612ffa7edc94537220340a00c9db13ad.tar.gz
vyos-1x-3755dfa7612ffa7edc94537220340a00c9db13ad.zip
vpp: T8296: Move vxlan interface from vpp section to 'interfaces vpp vxlan'
-rw-r--r--interface-definitions/vpp.xml.in22
-rw-r--r--interface-definitions/vpp_interface_vxlan.xml.in35
-rw-r--r--python/vyos/ifconfig/vpp/__init__.py2
-rw-r--r--python/vyos/ifconfig/vpp/vxlan.py125
-rw-r--r--python/vyos/vpp/config_verify.py2
-rw-r--r--python/vyos/vpp/interface/__init__.py2
-rw-r--r--python/vyos/vpp/interface/vxlan.py106
-rw-r--r--python/vyos/vpp/interface/xconnect.py8
-rw-r--r--python/vyos/vpp/utils.py18
-rw-r--r--smoketest/configs/assert/vpp6
-rwxr-xr-xsmoketest/scripts/cli/test_vpp.py123
-rw-r--r--src/conf_mode/vpp_interfaces_bridge.py6
-rw-r--r--src/conf_mode/vpp_interfaces_vxlan.py118
-rw-r--r--src/migration-scripts/vpp/5-to-6106
14 files changed, 320 insertions, 359 deletions
diff --git a/interface-definitions/vpp.xml.in b/interface-definitions/vpp.xml.in
index 9f245aaf3..cf947a29d 100644
--- a/interface-definitions/vpp.xml.in
+++ b/interface-definitions/vpp.xml.in
@@ -186,28 +186,6 @@
#include <include/kernel-interface-tun.xml.i>
</children>
</tagNode>
- <tagNode name="vxlan" owner="${vyos_conf_scripts_dir}/vpp_interfaces_vxlan.py">
- <properties>
- <priority>325</priority>
- <help>Virtual Extensible LAN (VXLAN) Interface</help>
- <constraint>
- <regex>vxlan[0-9]+</regex>
- </constraint>
- <constraintErrorMessage>VXLAN interface must be named vxlanN</constraintErrorMessage>
- <valueHelp>
- <format>vxlanN</format>
- <description>VXLAN interface name</description>
- </valueHelp>
- </properties>
- <children>
- #include <include/generic-description.xml.i>
- #include <include/interface/disable.xml.i>
- #include <include/source-address-ipv4-ipv6.xml.i>
- #include <include/interface/tunnel-remote.xml.i>
- #include <include/vni.xml.i>
- #include <include/kernel-interface-tap.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_vxlan.xml.in b/interface-definitions/vpp_interface_vxlan.xml.in
new file mode 100644
index 000000000..2d0ae42ab
--- /dev/null
+++ b/interface-definitions/vpp_interface_vxlan.xml.in
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name='interfaces'>
+ <children>
+ <node name='vpp'>
+ <children>
+ <tagNode name="vxlan" owner="${vyos_conf_scripts_dir}/vpp_interfaces_vxlan.py">
+ <properties>
+ <priority>325</priority>
+ <help>Virtual Extensible LAN (VXLAN) Interface</help>
+ <constraint>
+ <regex>vppvxlan[0-9]+</regex>
+ </constraint>
+ <constraintErrorMessage>VXLAN interface must be named vppvxlanN</constraintErrorMessage>
+ <valueHelp>
+ <format>vppvxlanN</format>
+ <description>VXLAN interface name</description>
+ </valueHelp>
+ </properties>
+ <children>
+ #include <include/generic-description.xml.i>
+ #include <include/interface/disable.xml.i>
+ #include <include/source-address-ipv4-ipv6.xml.i>
+ #include <include/interface/tunnel-remote.xml.i>
+ #include <include/vni.xml.i>
+ #include <include/interface/address-ipv4-ipv6.xml.i>
+ #include <include/interface/mtu-68-16000.xml.i>
+ #include <include/vpp/vif.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 117acb8d0..bda2f76c8 100644
--- a/python/vyos/ifconfig/vpp/__init__.py
+++ b/python/vyos/ifconfig/vpp/__init__.py
@@ -17,8 +17,10 @@
from .bond import VPPBondInterface
from .interface import VPPInterface
+from .vxlan import VPPVXLANInterface
__all__ = [
'VPPBondInterface',
'VPPInterface',
+ 'VPPVXLANInterface',
]
diff --git a/python/vyos/ifconfig/vpp/vxlan.py b/python/vyos/ifconfig/vpp/vxlan.py
new file mode 100644
index 000000000..8ca9bee70
--- /dev/null
+++ b/python/vyos/ifconfig/vpp/vxlan.py
@@ -0,0 +1,125 @@
+# VyOS implementation of VPP VXLAN 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 VPPVXLANInterface(Interface, VPPInterface):
+ """Interface VXLAN"""
+
+ def __init__(self, ifname, config):
+ self.ifname = ifname
+ self.instance = int(ifname.removeprefix('vppvxlan'))
+ self.vpp_ifname = f'vxlan_tunnel{self.instance}'
+
+ super().__init__(ifname)
+ VPPInterface.__init__(self, self.vpp_ifname)
+
+ self.index = self.vpp.get_sw_if_index(self.vpp_ifname)
+ self.src_address = config.get('source_address')
+ self.dst_address = config.get('remote')
+ self.vni = int(config.get('vni', 0))
+ self.state = 'up' if 'disable' not in config else 'down'
+
+ def _create(self):
+ pass
+
+ def get_vxlan(self):
+ tunnels = self.vpp.api.vxlan_tunnel_dump(sw_if_index=self.index)
+ return tunnels[0] if tunnels else None
+
+ def add_vxlan(self):
+ """Create VXLAN interface
+ https://github.com/FDio/vpp/blob/stable/2306/src/plugins/vxlan/vxlan.api
+
+ Example:
+ from vyos.ifconfig.vpp import VPPVXLANInterface
+ a = VPPVXLANInterface(ifname='vppvxlan23', config)
+ a.add_vxlan()
+ """
+ self.vpp.api.vxlan_add_del_tunnel_v3(
+ is_add=True,
+ src_address=self.src_address,
+ dst_address=self.dst_address,
+ vni=self.vni,
+ instance=self.instance,
+ decap_next_index=1,
+ is_l3=False,
+ )
+ # 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_vxlan(self):
+ """Delete VXLAN interface
+ Example:
+ from vyos.ifconfig.vpp import VPPVXLANInterface
+ a = VPPVXLANInterface(ifname='vppvxlan23', config)
+ a.delete_vxlan()
+ """
+ vxlan = self.get_vxlan()
+ if vxlan:
+ return self.vpp.api.vxlan_add_del_tunnel_v3(
+ is_add=False,
+ src_address=vxlan.src_address,
+ dst_address=vxlan.dst_address,
+ vni=vxlan.vni,
+ is_l3=False,
+ )
+
+ def kernel_add(self):
+ """Add LCP pair
+ Example:
+ from vyos.ifconfig.vpp import VPPVXLANInterface
+ a = VPPVXLANInterface(ifname='vppvxlan23', config)
+ a.kernel_add()
+ """
+ self.vpp.lcp_pair_add(self.vpp_ifname, self.ifname)
+
+ def kernel_delete(self):
+ """Delete LCP pair
+ Example:
+ from vyos.ifconfig.vpp import VPPVXLANInterface
+ a = VPPVXLANInterface(ifname='vppvxlan23', 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 vxlan interface
+ self.delete_vxlan()
+
+ def update(self, config):
+ # Add vxlan interface
+ self.add_vxlan()
+
+ # 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/config_verify.py b/python/vyos/vpp/config_verify.py
index 1e56457da..84c32f1e6 100644
--- a/python/vyos/vpp/config_verify.py
+++ b/python/vyos/vpp/config_verify.py
@@ -98,7 +98,7 @@ def verify_vpp_exists_kernel_interface(config: dict):
def verify_vpp_remove_xconnect_interface(config: dict):
- if not config.get('remove'):
+ if not 'deleted' in config:
return
for xconn_member, xconn_iface in config.get('xconn_members').items():
if xconn_member == config.get('ifname'):
diff --git a/python/vyos/vpp/interface/__init__.py b/python/vyos/vpp/interface/__init__.py
index c54e5ca60..f17a12d43 100644
--- a/python/vyos/vpp/interface/__init__.py
+++ b/python/vyos/vpp/interface/__init__.py
@@ -22,7 +22,6 @@ from .gre import GREInterface
from .interface import Interface
from .ipip import IPIPInterface
from .loopback import LoopbackInterface
-from .vxlan import VXLANInterface
from .wireguard import WireguardInterface
from .xconnect import XconnectInterface
@@ -34,7 +33,6 @@ __all__ = [
'Interface',
'IPIPInterface',
'LoopbackInterface',
- 'VXLANInterface',
'WireguardInterface',
'XconnectInterface',
]
diff --git a/python/vyos/vpp/interface/vxlan.py b/python/vyos/vpp/interface/vxlan.py
deleted file mode 100644
index 4be5b5ec9..000000000
--- a/python/vyos/vpp/interface/vxlan.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# VyOS implementation of VPP VXLAN 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 VXLAN interface
- Example:
- from vyos.vpp.interface import vxlan
- vxlan.show()
- """
- vpp = VPPControl()
- return vpp.api.vxlan_tunnel_dump()
-
-
-class VXLANInterface(Interface):
- """Interface VXLAN"""
-
- def __init__(
- self,
- ifname,
- source_address,
- remote,
- vni,
- kernel_interface: str = '',
- state: str = 'up',
- ):
- super().__init__(ifname)
- self.instance = int(ifname.removeprefix('vxlan'))
- self.ifname = f'vxlan_tunnel{self.instance}'
- self.src_address = source_address
- self.dst_address = remote
- self.vni = vni
- self.kernel_interface = kernel_interface
- self.initial_state = state
-
- def add(self):
- """Create VXLAN interface
- https://github.com/FDio/vpp/blob/stable/2306/src/plugins/vxlan/vxlan.api
-
- Example:
- from vyos.vpp.interface import VXLANInterface
- a = VXLANInterface(ifname='vxlan23', source_address='192.0.2.1', remote='203.0.113.23', vni=23)
- a.add()
- """
- self.vpp.api.vxlan_add_del_tunnel_v3(
- is_add=True,
- src_address=self.src_address,
- dst_address=self.dst_address,
- vni=self.vni,
- instance=self.instance,
- decap_next_index=1,
- is_l3=False,
- )
- # Set interface state
- self.set_state(self.initial_state)
-
- def delete(self):
- """Delete VXLAN interface
- Example:
- from vyos.vpp.interface import VXLANInterface
- a = VXLANInterface(ifname='vxlan23', source_address='192.0.2.1', remote='203.0.113.23', vni=23)
- a.delete()
- """
- return self.vpp.api.vxlan_add_del_tunnel_v3(
- is_add=False,
- src_address=self.src_address,
- dst_address=self.dst_address,
- vni=self.vni,
- is_l3=False,
- )
-
- def kernel_add(self):
- """Add LCP pair
- Example:
- from vyos.vpp.interface import VXLANInterface
- a = VXLANInterface(ifname='vxlan23', source_address='192.0.2.1', remote='203.0.113.23', vni=23, kernel_interface='vpptap10')
- a.kernel_add()
- """
- self.vpp.lcp_pair_add(self.ifname, self.kernel_interface)
-
- def kernel_delete(self):
- """Delete LCP pair
- Example:
- from vyos.vpp.interface import VXLANInterface
- a = VXLANInterface(ifname='vxlan23', source_address='192.0.2.1', remote='203.0.113.23', vni=23)
- 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 299a61405..603f7f90b 100644
--- a/python/vyos/vpp/interface/xconnect.py
+++ b/python/vyos/vpp/interface/xconnect.py
@@ -42,8 +42,8 @@ class XconnectInterface:
a.add_l2_xconnect()
"""
interface_transform_filter = ('vxlan', 'gre')
- first_member = self.members[0]
- second_member = self.members[1]
+ 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'
if first_member.startswith(interface_transform_filter):
first_member = iftunnel_transform(first_member)
@@ -73,8 +73,8 @@ class XconnectInterface:
a.del_l2_xconnect()
"""
interface_transform_filter = ('vxlan', 'gre')
- first_member = self.members[0]
- second_member = self.members[1]
+ 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'
if first_member.startswith(interface_transform_filter):
first_member = iftunnel_transform(first_member)
diff --git a/python/vyos/vpp/utils.py b/python/vyos/vpp/utils.py
index 5ae4cd296..5976b2189 100644
--- a/python/vyos/vpp/utils.py
+++ b/python/vyos/vpp/utils.py
@@ -27,7 +27,7 @@ mem_shift = {'K': 10, 'KB': 10, 'M': 20, 'MB': 20, 'G': 30, 'GB': 30}
def iftunnel_transform(iface: str) -> str:
- """Transform interface name from `xxxNN` to `xxx_tunnelNN`
+ """Transform interface name from `vppxxxNN` to `xxx_tunnelNN`
Args:
iface (str): original interface name
@@ -38,6 +38,8 @@ def iftunnel_transform(iface: str) -> str:
Returns:
str: Transformed interface name
"""
+ # Remove vpp prefix
+ iface = iface.removeprefix('vpp')
# Check format
if not iface[0].isascii() or not iface[-1].isdecimal():
raise ValueError(f'Wrong interface name format: {iface}')
@@ -87,6 +89,15 @@ def cli_ifaces_list(config_instance, mode: str = 'candidate') -> list[str]:
with_recursive_defaults=True,
)
+ interfaces_config = config_instance.get_config_dict(
+ ['interfaces', 'vpp'],
+ key_mangling=('-', '_'),
+ effective=effective_mode,
+ get_first_key=True,
+ no_tag_node_value_mangle=True,
+ with_recursive_defaults=True,
+ )
+
vpp_ifaces: list[str] = []
# Get a list of Ethernet interfaces
@@ -98,6 +109,11 @@ def cli_ifaces_list(config_instance, mode: str = 'candidate') -> list[str]:
for iface in config.get('interfaces', {}).get(iface_type, {}).keys():
vpp_ifaces.append(iface)
+ # Get a list of interfaces VPP
+ for iface_type in interfaces_config.keys():
+ for iface in interfaces_config.get(iface_type, {}).keys():
+ vpp_ifaces.append(iface)
+
return vpp_ifaces
diff --git a/smoketest/configs/assert/vpp b/smoketest/configs/assert/vpp
index 0859e7a1a..495b41f36 100644
--- a/smoketest/configs/assert/vpp
+++ b/smoketest/configs/assert/vpp
@@ -39,9 +39,9 @@ set vpp interfaces gre gre12 tunnel-type 'l3'
set vpp interfaces ipip ipip20 remote '192.0.2.2'
set vpp interfaces ipip ipip20 source-address '192.0.2.1'
set vpp interfaces loopback lo12 description 'Loop12'
-set vpp interfaces vxlan vxlan10 remote '192.0.2.2'
-set vpp interfaces vxlan vxlan10 source-address '192.0.2.1'
-set vpp interfaces vxlan vxlan10 vni '10'
+set interfaces vpp vxlan vppvxlan10 remote '192.0.2.2'
+set interfaces vpp vxlan vppvxlan10 source-address '192.0.2.1'
+set interfaces vpp vxlan vppvxlan10 vni '10'
set vpp settings interface eth1
set vpp settings interface eth2
set vpp settings interface eth3
diff --git a/smoketest/scripts/cli/test_vpp.py b/smoketest/scripts/cli/test_vpp.py
index db4c811cc..c2a903229 100755
--- a/smoketest/scripts/cli/test_vpp.py
+++ b/smoketest/scripts/cli/test_vpp.py
@@ -211,57 +211,34 @@ class TestVPP(VyOSUnitTestSHIM.TestCase):
self.assertTrue(icmpv6_ra_punt_feature.is_enabled)
def test_02_vpp_vxlan(self):
+ vxlan_path = interfaces_path + ['vxlan']
vni = '23'
- interface_vxlan = f'vxlan{vni}'
- interface_kernel = f'vpptap{vni}'
- new_interface_kernel = f'vpptap1{vni}'
+ interface_vxlan = f'vppvxlan{vni}'
source_address = '192.0.2.1'
new_source_address = '192.0.2.3'
remote_address = '192.0.2.254'
- kernel_address = '203.0.113.1'
+ address = '203.0.113.1'
self.cli_set(['interfaces', 'ethernet', interface, 'address', '192.0.2.1/24'])
- self.cli_set(
- base_path
- + ['interfaces', 'vxlan', interface_vxlan, 'source-address', source_address]
- )
- self.cli_set(base_path + ['interfaces', 'vxlan', interface_vxlan, 'vni', vni])
+ self.cli_set(vxlan_path + [interface_vxlan, 'source-address', source_address])
+ self.cli_set(vxlan_path + [interface_vxlan, 'vni', vni])
# remote and source address must not be the same
# expect raise ConfigError
- self.cli_set(
- base_path
- + ['interfaces', 'vxlan', interface_vxlan, 'remote', source_address]
- )
+ self.cli_set(vxlan_path + [interface_vxlan, 'remote', source_address])
with self.assertRaises(ConfigSessionError):
self.cli_commit()
- self.cli_set(
- base_path
- + ['interfaces', 'vxlan', interface_vxlan, 'remote', remote_address]
- )
- self.cli_set(
- base_path
- + [
- 'interfaces',
- 'vxlan',
- interface_vxlan,
- 'kernel-interface',
- interface_kernel,
- ]
- )
- self.cli_set(
- base_path
- + ['kernel-interfaces', interface_kernel, 'address', f'{kernel_address}/24']
- )
+ self.cli_set(vxlan_path + [interface_vxlan, 'remote', remote_address])
+ self.cli_set(vxlan_path + [interface_vxlan, 'address', f'{address}/24'])
# commit changes
self.cli_commit()
- self.assertTrue(os.path.isdir(f'/sys/class/net/{interface_kernel}'))
+ self.assertTrue(os.path.isdir(f'/sys/class/net/{interface_vxlan}'))
- current_address = get_address(interface_kernel)
- self.assertEqual(kernel_address, current_address)
+ current_address = get_address(interface_vxlan)
+ self.assertEqual(address, current_address)
# check vxlan interface
_, out = rc_cmd('sudo vppctl show vxlan tunnel')
@@ -270,14 +247,7 @@ class TestVPP(VyOSUnitTestSHIM.TestCase):
# update vxlan interface
self.cli_set(
- base_path
- + [
- 'interfaces',
- 'vxlan',
- interface_vxlan,
- 'source-address',
- new_source_address,
- ]
+ vxlan_path + [interface_vxlan, 'source-address', new_source_address]
)
# source address of the tunnel interface should be configured
@@ -304,8 +274,8 @@ class TestVPP(VyOSUnitTestSHIM.TestCase):
f'[0] instance {vni} 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)
+ self.assertTrue(os.path.isdir(f'/sys/class/net/{interface_vxlan}'))
+ self.assertEqual(address, current_address)
# change vpp settings
self.cli_set(base_path + ['settings', 'poll-sleep-usec', '5'])
@@ -314,49 +284,8 @@ class TestVPP(VyOSUnitTestSHIM.TestCase):
config = read_file(VPP_CONF)
self.assertIn('poll-sleep-usec 5', config)
- # delete vxlan kernel-interface but do not delete 'vpp kernel-interface'
- # expect raise ConfigError
- self.cli_delete(
- base_path
- + [
- 'interfaces',
- 'vxlan',
- interface_vxlan,
- 'kernel-interface',
- interface_kernel,
- ]
- )
- with self.assertRaises(ConfigSessionError):
- self.cli_commit()
-
- # update vxlan kernel-interface but do not change 'vpp kernel-interface'
- # expect raise ConfigError
- self.cli_set(
- base_path
- + [
- 'interfaces',
- 'vxlan',
- interface_vxlan,
- 'kernel-interface',
- new_interface_kernel,
- ]
- )
- with self.assertRaises(ConfigSessionError):
- self.cli_commit()
-
- # delete vpp kernel-interface
- self.cli_delete(base_path + ['kernel-interfaces', interface_kernel])
- self.cli_commit()
-
- # delete vxlan kernel-interface
- self.cli_delete(
- base_path + ['interfaces', 'vxlan', interface_vxlan, 'kernel-interface']
- )
- self.cli_commit()
- self.assertFalse(os.path.isdir(f'/sys/class/net/{interface_kernel}'))
-
# delete vxlan interface
- self.cli_delete(base_path + ['interfaces', 'vxlan', interface_vxlan])
+ self.cli_delete(vxlan_path + [interface_vxlan])
self.cli_commit()
# delete vif Ethernet interface
@@ -756,7 +685,7 @@ class TestVPP(VyOSUnitTestSHIM.TestCase):
members = [interface]
interface_bridge = 'br10'
vni = '23'
- interface_vxlan = f'vxlan{vni}'
+ interface_vxlan = f'vppvxlan{vni}'
source_address = '192.0.2.1'
remote_address = '192.0.2.254'
@@ -822,14 +751,13 @@ class TestVPP(VyOSUnitTestSHIM.TestCase):
# Add VXLAN to the bridge
self.cli_set(
- base_path
- + ['interfaces', 'vxlan', interface_vxlan, 'source-address', source_address]
+ interfaces_path
+ + ['vxlan', interface_vxlan, 'source-address', source_address]
)
self.cli_set(
- base_path
- + ['interfaces', 'vxlan', interface_vxlan, 'remote', remote_address]
+ interfaces_path + ['vxlan', interface_vxlan, 'remote', remote_address]
)
- self.cli_set(base_path + ['interfaces', 'vxlan', interface_vxlan, 'vni', vni])
+ self.cli_set(interfaces_path + ['vxlan', interface_vxlan, 'vni', vni])
self.cli_set(
base_path
+ [
@@ -1017,21 +945,20 @@ class TestVPP(VyOSUnitTestSHIM.TestCase):
def test_09_vpp_xconnect(self):
vni = '23'
- interface_vxlan = f'vxlan{vni}'
+ interface_vxlan = f'vppvxlan{vni}'
interface_xconnect = f'xcon{vni}'
source_address = '192.0.2.1'
remote_address = '192.0.2.254'
self.cli_set(['interfaces', 'ethernet', interface, 'address', '192.0.2.1/24'])
self.cli_set(
- base_path
- + ['interfaces', 'vxlan', interface_vxlan, 'source-address', source_address]
+ interfaces_path
+ + ['vxlan', interface_vxlan, 'source-address', source_address]
)
self.cli_set(
- base_path
- + ['interfaces', 'vxlan', interface_vxlan, 'remote', remote_address]
+ interfaces_path + ['vxlan', interface_vxlan, 'remote', remote_address]
)
- self.cli_set(base_path + ['interfaces', 'vxlan', interface_vxlan, 'vni', vni])
+ self.cli_set(interfaces_path + ['vxlan', interface_vxlan, 'vni', vni])
# Add xconneect
self.cli_set(
diff --git a/src/conf_mode/vpp_interfaces_bridge.py b/src/conf_mode/vpp_interfaces_bridge.py
index e86381cc3..8d25cba00 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', 'lo', 'vxlan')
+ allowed_prefixes = ('vppbond', 'gre', 'geneve', 'lo', 'vppvxlan')
if 'member' in config:
bvi_exists = False
@@ -130,8 +130,8 @@ def apply(config):
return None
ifname = config.get('ifname')
- # vxlan10 in the vpp is vxlan_tunnel10
- interface_transform_filter = ('geneve', 'vxlan')
+ # vppvxlan10 in the vpp is vxlan_tunnel10
+ interface_transform_filter = ('geneve', 'vppvxlan')
# update members
if 'members_removed' in config:
i = BridgeInterface(ifname)
diff --git a/src/conf_mode/vpp_interfaces_vxlan.py b/src/conf_mode/vpp_interfaces_vxlan.py
index 4a0b157e5..9c24b6a01 100644
--- a/src/conf_mode/vpp_interfaces_vxlan.py
+++ b/src/conf_mode/vpp_interfaces_vxlan.py
@@ -16,26 +16,21 @@
# 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 VXLANInterface
+from vyos.ifconfig.vpp import VPPVXLANInterface
from vyos.vpp.config_deps import deps_bridge_dict
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:
@@ -51,55 +46,14 @@ def get_config(config=None) -> dict:
else:
conf = Config()
- base = ['vpp', 'interfaces', 'vxlan']
- base_kernel_interfaces = ['vpp', 'kernel-interfaces']
-
- ifname = os.environ['VYOS_TAGNODE_VALUE']
+ base = ['interfaces', 'vpp', 'vxlan']
- # 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)
@@ -114,11 +68,14 @@ def get_config(config=None) -> dict:
for bridge_iface in config['bridge_members'][ifname]:
set_dependents('vpp_interfaces_bridge', conf, bridge_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 with default values
+ config['vpp_settings'] = conf.get_config_dict(
+ ['vpp', 'settings'],
+ key_mangling=('-', '_'),
+ get_first_key=True,
+ no_tag_node_value_mangle=True,
+ with_defaults=True,
+ )
# NAT dependency
if conf.exists(['vpp', 'nat', 'nat44']):
@@ -130,7 +87,6 @@ def get_config(config=None) -> dict:
if conf.exists(['vpp', 'acl']):
set_dependents('vpp_acl', conf)
- config['ifname'] = ifname
return config
@@ -139,16 +95,16 @@ def verify(config):
if 'remove_vpp' in config:
return None
- # Verify that removed kernel interface is not used in 'vpp kernel-interfaces'.
- # vpp interfaces vxlan vxlanX kernel-interface vpp-tunX
- # vpp kernel-interface vpp-tunX
- verify_vpp_remove_kernel_interface(config)
-
verify_vpp_remove_xconnect_interface(config)
- if 'remove' in config:
+ if 'deleted' in config:
return None
+ if not is_systemd_service_active('vpp.service'):
+ raise ConfigError(
+ 'Cannot configure VPP vxlan interface: vpp.service is not running'
+ )
+
required_keys = {'source_address', 'remote', 'vni'}
if not all(key in config for key in required_keys):
missing_keys = required_keys - set(config.keys())
@@ -161,12 +117,6 @@ def verify(config):
if config.get('source_address') == config.get('remote'):
raise ConfigError('Remote address must not be the same as source address')
- # Change 'vpp interfaces vxlan greX kernel-interface vpp-tunX'
- # => 'vpp interfaces gre vxlanX 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)
-
def generate(config):
pass
@@ -178,29 +128,13 @@ def apply(config):
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')
- vni = int(remove_config.get('vni'))
- i = VXLANInterface(ifname, src_addr, dst_addr, vni)
- i.delete()
-
- if 'remove' in config:
+ vxlan = VPPVXLANInterface(ifname, config)
+ vxlan.remove()
+
+ if 'deleted' in config:
return None
- # Add interface
- src_addr = config.get('source_address')
- dst_addr = config.get('remote')
- vni = int(config.get('vni'))
- kernel_interface = config.get('kernel_interface', '')
- state = 'up' if 'disable' not in config else 'down'
- i = VXLANInterface(ifname, src_addr, dst_addr, vni, kernel_interface, state)
- i.add()
-
- # Add kernel-interface (LCP) if interface is not exist
- if 'kernel_interface' in config and not is_interface(kernel_interface):
- i.kernel_add()
+ vxlan.update(config)
call_dependents()
diff --git a/src/migration-scripts/vpp/5-to-6 b/src/migration-scripts/vpp/5-to-6
index 84b91ce40..25529cf36 100644
--- a/src/migration-scripts/vpp/5-to-6
+++ b/src/migration-scripts/vpp/5-to-6
@@ -39,6 +39,8 @@
#
# Move bonding interface from vpp section to 'interfaces vpp bonding' (T8283)
#
+# Move vxlan interface from vpp section to 'interfaces vpp vxlan' (T8296)
+#
from vyos.configtree import ConfigTree
@@ -290,6 +292,55 @@ def _migrate_vpp_resources(config: ConfigTree) -> None:
config.delete(new_base)
+def _migrate_interface(config, type, ifname):
+ base = ['vpp', 'interfaces', type]
+ new_base = ['interfaces', 'vpp', type]
+ kernel_interface_base = ['vpp', 'kernel-interfaces']
+
+ kernel_interface_path = base + [ifname, 'kernel-interface']
+ kernel_iface = None
+ if config.exists(kernel_interface_path):
+ kernel_iface = config.return_value(kernel_interface_path)
+ config.delete(kernel_interface_path)
+ new_ifname = f'vpp{ifname}'
+ iface_base = new_base + [new_ifname]
+ config.copy(base + [ifname], iface_base)
+ config.set_tag(new_base)
+
+ if kernel_iface and config.exists(kernel_interface_base + [kernel_iface]):
+ if config.exists(kernel_interface_base + [kernel_iface, 'vif']):
+ config.copy(kernel_interface_base + [kernel_iface, 'vif'], iface_base + ['vif'])
+ if config.exists(kernel_interface_base + [kernel_iface, 'mtu']):
+ config.copy(kernel_interface_base + [kernel_iface, 'mtu'], iface_base + ['mtu'])
+ if config.exists(kernel_interface_base + [kernel_iface, 'address']):
+ config.copy(kernel_interface_base + [kernel_iface, 'address'], iface_base + ['address'])
+ config.delete(kernel_interface_base + [kernel_iface])
+
+
+def _migrate_members_bridge(config, ifname):
+ bridge_path = ['vpp', 'interfaces', 'bridge']
+ if config.exists(bridge_path):
+ for iface in config.list_nodes(bridge_path):
+ tmp = bridge_path + [iface, 'member', 'interface']
+ if config.exists(tmp):
+ for name in config.list_nodes(tmp):
+ if name == ifname:
+ new_name = f'vpp{name}'
+ config.rename(tmp + [name], new_name)
+
+
+def _migrate_members_xconnect(config, ifname):
+ xconnect_path = ['vpp', 'interfaces', 'xconnect']
+ if config.exists(xconnect_path):
+ for iface in config.list_nodes(xconnect_path):
+ tmp = xconnect_path + [iface, 'member', 'interface']
+ if config.exists(tmp):
+ for name in config.return_values(tmp):
+ if name == ifname:
+ new_name = f'vpp{name}'
+ config.delete_value(tmp, name)
+ config.set(tmp, value=new_name, replace=False)
+
def _migrate_vpp_bonding_interface(config: ConfigTree) -> None:
base = ['vpp', 'interfaces', 'bonding']
new_base = ['interfaces', 'vpp', 'bonding']
@@ -301,24 +352,7 @@ def _migrate_vpp_bonding_interface(config: ConfigTree) -> None:
config.set(new_base)
for ifname in config.list_nodes(base):
- bond_kernel_interface_path = base + [ifname, 'kernel-interface']
- kernel_iface = None
- if config.exists(bond_kernel_interface_path):
- kernel_iface = config.return_value(bond_kernel_interface_path)
- config.delete(bond_kernel_interface_path)
- new_ifname = f'vpp{ifname}'
- iface_base = new_base + [new_ifname]
- config.copy(base + [ifname], iface_base)
- config.set_tag(new_base)
-
- if kernel_iface and config.exists(kernel_interface_base + [kernel_iface]):
- if config.exists(kernel_interface_base + [kernel_iface, 'vif']):
- config.copy(kernel_interface_base + [kernel_iface, 'vif'], iface_base + ['vif'])
- if config.exists(kernel_interface_base + [kernel_iface, 'mtu']):
- config.copy(kernel_interface_base + [kernel_iface, 'mtu'], iface_base + ['mtu'])
- if config.exists(kernel_interface_base + [kernel_iface, 'address']):
- config.copy(kernel_interface_base + [kernel_iface, 'address'], iface_base + ['address'])
- config.delete(kernel_interface_base + [kernel_iface])
+ _migrate_interface(config, 'bonding', ifname)
for feature in ['nat44', 'cgnat']:
for direction in ['inside', 'outside']:
@@ -341,15 +375,32 @@ def _migrate_vpp_bonding_interface(config: ConfigTree) -> None:
new_name = f'vpp{name}'
config.rename(ipfix_path + [name], new_name)
- bridge_path = ['vpp', 'interfaces', 'bridge']
- if config.exists(bridge_path):
- for iface in config.list_nodes(bridge_path):
- tmp = bridge_path + [iface, 'member', 'interface']
- if config.exists(tmp):
- for name in config.list_nodes(tmp):
- if name == ifname:
- new_name = f'vpp{name}'
- config.rename(tmp + [name], new_name)
+ _migrate_members_bridge(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_vpp_vxlan_interface(config: ConfigTree) -> None:
+ base = ['vpp', 'interfaces', 'vxlan']
+ new_base = ['interfaces', 'vpp', 'vxlan']
+ kernel_interface_base = ['vpp', 'kernel-interfaces']
+
+ if not config.exists(base):
+ return
+
+ config.set(new_base)
+
+ for ifname in config.list_nodes(base):
+ _migrate_interface(config, 'vxlan', ifname)
+
+ _migrate_members_bridge(config, ifname)
+ _migrate_members_xconnect(config, ifname)
config.delete(base)
@@ -376,3 +427,4 @@ def migrate(config: ConfigTree) -> None:
_migrate_vpp_dpdk_options(config)
_migrate_vpp_resources(config)
_migrate_vpp_bonding_interface(config)
+ _migrate_vpp_vxlan_interface(config)