summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2024-02-18 08:48:05 +0100
committerGitHub <noreply@github.com>2024-02-18 08:48:05 +0100
commit2b23be0cdb09ec1a7331624f0eea736d5b55ed4c (patch)
tree91b9b5eba2a6444b3fe2f4cbd33588429197620b
parent3230d09c292c89eddd34e33fda9570042e92e1fd (diff)
parent18d902ef3fd1aa6e0ad196eebed9b9e5c70fba07 (diff)
downloadvyos-1x-2b23be0cdb09ec1a7331624f0eea736d5b55ed4c.tar.gz
vyos-1x-2b23be0cdb09ec1a7331624f0eea736d5b55ed4c.zip
Merge pull request #3029 from vyos/mergify/bp/sagitta/pr-3026
bridge: T6043: do not call vxlan dependency if interface does not exist (yet) (backport #3026)
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bridge.py53
-rwxr-xr-xsrc/conf_mode/interfaces_bridge.py12
2 files changed, 57 insertions, 8 deletions
diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py
index cdff49f4b..6cd2cf760 100755
--- a/smoketest/scripts/cli/test_interfaces_bridge.py
+++ b/smoketest/scripts/cli/test_interfaces_bridge.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2023 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -21,13 +21,12 @@ import unittest
from base_interfaces_test import BasicInterfaceTest
from copy import deepcopy
from glob import glob
-from netifaces import interfaces
from vyos.ifconfig import Section
from vyos.utils.process import cmd
from vyos.utils.file import read_file
from vyos.utils.network import get_interface_config
-from vyos.utils.network import is_intf_addr_assigned
+from vyos.utils.network import interface_exists
class BridgeInterfaceTest(BasicInterfaceTest.TestCase):
@classmethod
@@ -388,5 +387,53 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase):
for vif_c in vifc:
self.cli_delete(['interfaces', 'bridge', interface, 'member', 'interface', f'{member}.{vif_s}.{vif_c}'])
+ def test_bridge_tunnel_vxlan_multicast(self):
+ # Testcase for T6043 running VXLAN over gretap
+ br_if = 'br0'
+ tunnel_if = 'tun0'
+ eth_if = 'eth1'
+ vxlan_if = 'vxlan0'
+ multicast_group = '239.0.0.241'
+ vni = '123'
+
+ self.cli_set(['interfaces', 'bridge', br_if, 'member', 'interface', eth_if])
+ self.cli_set(['interfaces', 'bridge', br_if, 'member', 'interface', vxlan_if])
+
+ self.cli_set(['interfaces', 'ethernet', 'eth0', 'address', '192.0.2.2/30'])
+
+ self.cli_set(['interfaces', 'tunnel', tunnel_if, 'address', '10.0.0.2/24'])
+ self.cli_set(['interfaces', 'tunnel', tunnel_if, 'enable-multicast'])
+ self.cli_set(['interfaces', 'tunnel', tunnel_if, 'encapsulation', 'gretap'])
+ self.cli_set(['interfaces', 'tunnel', tunnel_if, 'mtu', '1500'])
+ self.cli_set(['interfaces', 'tunnel', tunnel_if, 'parameters', 'ip', 'ignore-df'])
+ self.cli_set(['interfaces', 'tunnel', tunnel_if, 'parameters', 'ip', 'key', '1'])
+ self.cli_set(['interfaces', 'tunnel', tunnel_if, 'parameters', 'ip', 'no-pmtu-discovery'])
+ self.cli_set(['interfaces', 'tunnel', tunnel_if, 'parameters', 'ip', 'ttl', '0'])
+ self.cli_set(['interfaces', 'tunnel', tunnel_if, 'remote', '203.0.113.2'])
+ self.cli_set(['interfaces', 'tunnel', tunnel_if, 'source-address', '192.0.2.2'])
+
+ self.cli_set(['interfaces', 'vxlan', vxlan_if, 'group', multicast_group])
+ self.cli_set(['interfaces', 'vxlan', vxlan_if, 'mtu', '1426'])
+ self.cli_set(['interfaces', 'vxlan', vxlan_if, 'source-interface', tunnel_if])
+ self.cli_set(['interfaces', 'vxlan', vxlan_if, 'vni', vni])
+
+ self.cli_commit()
+
+ self.assertTrue(interface_exists(eth_if))
+ self.assertTrue(interface_exists(vxlan_if))
+ self.assertTrue(interface_exists(tunnel_if))
+
+ tmp = get_interface_config(vxlan_if)
+ self.assertEqual(tmp['ifname'], vxlan_if)
+ self.assertEqual(tmp['linkinfo']['info_data']['link'], tunnel_if)
+ self.assertEqual(tmp['linkinfo']['info_data']['group'], multicast_group)
+ self.assertEqual(tmp['linkinfo']['info_data']['id'], int(vni))
+
+ bridge_members = []
+ for tmp in glob(f'/sys/class/net/{br_if}/lower_*'):
+ bridge_members.append(os.path.basename(tmp).replace('lower_', ''))
+ self.assertIn(eth_if, bridge_members)
+ self.assertIn(vxlan_if, bridge_members)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/interfaces_bridge.py b/src/conf_mode/interfaces_bridge.py
index 29991e2da..9789f7bd3 100755
--- a/src/conf_mode/interfaces_bridge.py
+++ b/src/conf_mode/interfaces_bridge.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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
@@ -31,6 +31,7 @@ from vyos.configdict import has_vrf_configured
from vyos.configdep import set_dependents
from vyos.configdep import call_dependents
from vyos.utils.dict import dict_search
+from vyos.utils.network import interface_exists
from vyos import ConfigError
from vyos import airbag
@@ -85,9 +86,10 @@ def get_config(config=None):
bridge['member']['interface'][interface].update({'has_vlan' : ''})
# When using VXLAN member interfaces that are configured for Single
- # VXLAN Device (SVD) we need to call the VXLAN conf-mode script to re-create
- # VLAN to VNI mappings if required
- if interface.startswith('vxlan'):
+ # VXLAN Device (SVD) we need to call the VXLAN conf-mode script to
+ # re-create VLAN to VNI mappings if required, but only if the interface
+ # is already live on the system - this must not be done on first commit
+ if interface.startswith('vxlan') and interface_exists(interface):
set_dependents('vxlan', conf, interface)
# delete empty dictionary keys - no need to run code paths if nothing is there to do
@@ -167,7 +169,7 @@ def apply(bridge):
br.update(bridge)
for interface in dict_search('member.interface', bridge) or []:
- if interface.startswith('vxlan'):
+ if interface.startswith('vxlan') and interface_exists(interface):
try:
call_dependents()
except ConfigError: