summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface-definitions/interfaces-vxlan.xml.in6
-rw-r--r--python/vyos/ifconfig/vxlan.py10
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_vxlan.py29
-rwxr-xr-xsrc/conf_mode/interfaces-vxlan.py24
4 files changed, 63 insertions, 6 deletions
diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in
index 0a8a88596..caeb58116 100644
--- a/interface-definitions/interfaces-vxlan.xml.in
+++ b/interface-definitions/interfaces-vxlan.xml.in
@@ -19,6 +19,12 @@
#include <include/interface/address-ipv4-ipv6.xml.i>
#include <include/interface/description.xml.i>
#include <include/interface/disable.xml.i>
+ <leafNode name="external">
+ <properties>
+ <help>Use external control plane</help>
+ <valueless/>
+ </properties>
+ </leafNode>
<leafNode name="group">
<properties>
<help>Multicast group address for VXLAN interface</help>
diff --git a/python/vyos/ifconfig/vxlan.py b/python/vyos/ifconfig/vxlan.py
index d73fb47b8..9615f396d 100644
--- a/python/vyos/ifconfig/vxlan.py
+++ b/python/vyos/ifconfig/vxlan.py
@@ -54,18 +54,20 @@ class VXLANIf(Interface):
# arguments used by iproute2. For more information please refer to:
# - https://man7.org/linux/man-pages/man8/ip-link.8.html
mapping = {
- 'source_address' : 'local',
- 'source_interface' : 'dev',
- 'remote' : 'remote',
'group' : 'group',
+ 'external' : 'external',
'parameters.ip.dont_fragment': 'df set',
'parameters.ip.tos' : 'tos',
'parameters.ip.ttl' : 'ttl',
'parameters.ipv6.flowlabel' : 'flowlabel',
'parameters.nolearning' : 'nolearning',
+ 'remote' : 'remote',
+ 'source_address' : 'local',
+ 'source_interface' : 'dev',
+ 'vni' : 'id',
}
- cmd = 'ip link add {ifname} type {type} id {vni} dstport {port}'
+ cmd = 'ip link add {ifname} type {type} dstport {port}'
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
diff --git a/smoketest/scripts/cli/test_interfaces_vxlan.py b/smoketest/scripts/cli/test_interfaces_vxlan.py
index f63c850d8..17874af89 100755
--- a/smoketest/scripts/cli/test_interfaces_vxlan.py
+++ b/smoketest/scripts/cli/test_interfaces_vxlan.py
@@ -16,6 +16,7 @@
import unittest
+from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Interface
from vyos.util import get_interface_config
@@ -78,6 +79,9 @@ class VXLANInterfaceTest(BasicInterfaceTest.TestCase):
label = options['linkinfo']['info_data']['label']
self.assertIn(f'parameters ipv6 flowlabel {label}', self._options[interface])
+ if any('external' in s for s in self._options[interface]):
+ self.assertTrue(options['linkinfo']['info_data']['external'])
+
self.assertEqual('vxlan', options['linkinfo']['info_kind'])
self.assertEqual('set', options['linkinfo']['info_data']['df'])
self.assertEqual(f'0x{tos}', options['linkinfo']['info_data']['tos'])
@@ -85,5 +89,30 @@ class VXLANInterfaceTest(BasicInterfaceTest.TestCase):
self.assertEqual(Interface(interface).get_admin_state(), 'up')
ttl += 10
+ def test_vxlan_external(self):
+ interface = 'vxlan0'
+ source_address = '192.0.2.1'
+ self.cli_set(self._base_path + [interface, 'external'])
+ self.cli_set(self._base_path + [interface, 'source-address', source_address])
+
+ # Now add some more interfaces - this must fail and a CLI error needs
+ # to be generated as Linux can only handle one VXLAN tunnel when using
+ # external mode.
+ for intf in self._interfaces:
+ for option in self._options.get(intf, []):
+ self.cli_set(self._base_path + [intf] + option.split())
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ # Remove those test interfaces again
+ for intf in self._interfaces:
+ self.cli_delete(self._base_path + [intf])
+
+ self.cli_commit()
+
+ options = get_interface_config(interface)
+ self.assertTrue(options['linkinfo']['info_data']['external'])
+ self.assertEqual('vxlan', options['linkinfo']['info_kind'])
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py
index 804f2d14f..b197d08a6 100755
--- a/src/conf_mode/interfaces-vxlan.py
+++ b/src/conf_mode/interfaces-vxlan.py
@@ -44,6 +44,20 @@ def get_config(config=None):
base = ['interfaces', 'vxlan']
vxlan = get_interface_dict(conf, base)
+ # We need to verify that no other VXLAN tunnel is configured when external
+ # mode is in use - Linux Kernel limitation
+ conf.set_level(base)
+ vxlan['other_tunnels'] = conf.get_config_dict([], key_mangling=('-', '_'),
+ get_first_key=True,
+ no_tag_node_value_mangle=True)
+
+ # This if-clause is just to be sure - it will always evaluate to true
+ ifname = vxlan['ifname']
+ if ifname in vxlan['other_tunnels']:
+ del vxlan['other_tunnels'][ifname]
+ if len(vxlan['other_tunnels']) == 0:
+ del vxlan['other_tunnels']
+
return vxlan
def verify(vxlan):
@@ -63,8 +77,14 @@ def verify(vxlan):
if not any(tmp in ['group', 'remote', 'source_address'] for tmp in vxlan):
raise ConfigError('Group, remote or source-address must be configured')
- if 'vni' not in vxlan:
- raise ConfigError('Must configure VNI for VXLAN')
+ if 'vni' not in vxlan and 'external' not in vxlan:
+ raise ConfigError(
+ 'Must either configure VXLAN "vni" or use "external" CLI option!')
+
+ if {'external', 'other_tunnels'} <= set(vxlan):
+ other_tunnels = ', '.join(vxlan['other_tunnels'])
+ raise ConfigError(f'Only one VXLAN tunnel is supported when "external" '\
+ f'CLI option is used. Additional tunnels: {other_tunnels}')
if 'source_interface' in vxlan:
# VXLAN adds at least an overhead of 50 byte - we need to check the