summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniil Baturin <daniil@vyos.io>2025-05-27 14:53:54 +0100
committerGitHub <noreply@github.com>2025-05-27 14:53:54 +0100
commiteb07e3131ae3ea6a58ac85340a5ce049ce3e6eb2 (patch)
treee0d3e70141f8b8cbfe6cbd516358790cce327010
parent1dc6a82211635c64852cdd50c656fe1ab3013c0b (diff)
parente5b613191a60f0de4a231d35aa48e3f0e90a05ab (diff)
downloadvyos-1x-eb07e3131ae3ea6a58ac85340a5ce049ce3e6eb2.tar.gz
vyos-1x-eb07e3131ae3ea6a58ac85340a5ce049ce3e6eb2.zip
Merge pull request #4496 from l0crian1/add-root-bpdu-guard
Bridge: T7430: Add BPDU Guard and Root Guard support
-rw-r--r--interface-definitions/interfaces_bridge.xml.in12
-rwxr-xr-xop-mode-definitions/show-log.xml.in6
-rw-r--r--python/vyos/ifconfig/bridge.py10
-rw-r--r--python/vyos/ifconfig/interface.py32
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bridge.py25
-rwxr-xr-xsrc/conf_mode/interfaces_bridge.py3
6 files changed, 88 insertions, 0 deletions
diff --git a/interface-definitions/interfaces_bridge.xml.in b/interface-definitions/interfaces_bridge.xml.in
index 667ae3b19..b360f34f1 100644
--- a/interface-definitions/interfaces_bridge.xml.in
+++ b/interface-definitions/interfaces_bridge.xml.in
@@ -201,6 +201,18 @@
<valueless/>
</properties>
</leafNode>
+ <leafNode name="bpdu-guard">
+ <properties>
+ <help>Enable BPDU Guard</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="root-guard">
+ <properties>
+ <help>Enable Root Guard</help>
+ <valueless/>
+ </properties>
+ </leafNode>
</children>
</tagNode>
</children>
diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in
index b616f7ab9..fcde76e60 100755
--- a/op-mode-definitions/show-log.xml.in
+++ b/op-mode-definitions/show-log.xml.in
@@ -831,6 +831,12 @@
</properties>
<command>journalctl --no-hostname --boot --unit snmpd.service</command>
</leafNode>
+ <leafNode name="spanning-tree">
+ <properties>
+ <help>Show log for Spanning Tree Protocol (STP)</help>
+ </properties>
+ <command>journalctl --dmesg --no-hostname --boot --grep='br[0-9].*(stp|bpdu|blocking|disabled|forwarding|listening|root port)'</command>
+ </leafNode>
<node name="ssh">
<properties>
<help>Show log for Secure Shell (SSH)</help>
diff --git a/python/vyos/ifconfig/bridge.py b/python/vyos/ifconfig/bridge.py
index f81026965..69dae42d3 100644
--- a/python/vyos/ifconfig/bridge.py
+++ b/python/vyos/ifconfig/bridge.py
@@ -376,6 +376,16 @@ class BridgeIf(Interface):
if 'priority' in interface_config:
lower.set_path_priority(interface_config['priority'])
+ # set BPDU guard
+ tmp = dict_search('bpdu_guard', interface_config)
+ value = '1' if (tmp != None) else '0'
+ lower.set_bpdu_guard(value)
+
+ # set root guard
+ tmp = dict_search('root_guard', interface_config)
+ value = '1' if (tmp != None) else '0'
+ lower.set_root_guard(value)
+
if 'enable_vlan' in config:
add_vlan = []
native_vlan_id = None
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index 003a273c0..91b3a0c28 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -217,6 +217,16 @@ class Interface(Control):
'location': '/sys/class/net/{ifname}/brport/priority',
'errormsg': '{ifname} is not a bridge port member'
},
+ 'bpdu_guard': {
+ 'validate': assert_boolean,
+ 'location': '/sys/class/net/{ifname}/brport/bpdu_guard',
+ 'errormsg': '{ifname} is not a bridge port member'
+ },
+ 'root_guard': {
+ 'validate': assert_boolean,
+ 'location': '/sys/class/net/{ifname}/brport/root_block',
+ 'errormsg': '{ifname} is not a bridge port member'
+ },
'proxy_arp': {
'validate': assert_boolean,
'location': '/proc/sys/net/ipv4/conf/{ifname}/proxy_arp',
@@ -1106,6 +1116,28 @@ class Interface(Control):
"""
self.set_interface('path_priority', priority)
+ def set_bpdu_guard(self, state):
+ """
+ Set BPDU guard state for a bridge port. When enabled, the port will be
+ disabled if it receives a BPDU packet.
+
+ Example:
+ >>> from vyos.ifconfig import Interface
+ >>> Interface('eth0').set_bpdu_guard(1)
+ """
+ self.set_interface('bpdu_guard', state)
+
+ def set_root_guard(self, state):
+ """
+ Set root guard state for a bridge port. When enabled, the port will be
+ disabled if it receives a superior BPDU that would make it a root port.
+
+ Example:
+ >>> from vyos.ifconfig import Interface
+ >>> Interface('eth0').set_root_guard(1)
+ """
+ self.set_interface('root_guard', state)
+
def set_port_isolation(self, on_or_off):
"""
Controls whether a given port will be isolated, which means it will be
diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py
index 4041b3ef3..c18be7e99 100755
--- a/smoketest/scripts/cli/test_interfaces_bridge.py
+++ b/smoketest/scripts/cli/test_interfaces_bridge.py
@@ -508,6 +508,31 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase):
self.cli_delete(['interfaces', 'vxlan', vxlan_if])
self.cli_delete(['interfaces', 'ethernet', 'eth0', 'address', eth0_addr])
+ def test_bridge_root_bpdu_guard(self):
+ # Test if both bpdu_guard and root_guard configured
+ self.cli_set(['interfaces', 'bridge', 'br0', 'stp'])
+ self.cli_set(['interfaces', 'bridge', 'br0', 'member', 'interface', 'eth0', 'bpdu-guard'])
+ self.cli_set(['interfaces', 'bridge', 'br0', 'member', 'interface', 'eth0', 'root-guard'])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_discard()
+
+ # Test if bpdu_guard configured
+ self.cli_set(['interfaces', 'bridge', 'br0', 'stp'])
+ self.cli_set(['interfaces', 'bridge', 'br0', 'member', 'interface', 'eth0', 'bpdu-guard'])
+ self.cli_commit()
+
+ tmp = read_file(f'/sys/class/net/eth0/brport/bpdu_guard')
+ self.assertEqual(tmp, '1')
+
+ # Test if root_guard configured
+ self.cli_delete(['interfaces', 'bridge', 'br0'])
+ self.cli_set(['interfaces', 'bridge', 'br0', 'stp'])
+ self.cli_set(['interfaces', 'bridge', 'br0', 'member', 'interface', 'eth0', 'root-guard'])
+ self.cli_commit()
+
+ tmp = read_file(f'/sys/class/net/eth0/brport/root_block')
+ self.assertEqual(tmp, '1')
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/interfaces_bridge.py b/src/conf_mode/interfaces_bridge.py
index 95dcc543e..c14e6a599 100755
--- a/src/conf_mode/interfaces_bridge.py
+++ b/src/conf_mode/interfaces_bridge.py
@@ -167,6 +167,9 @@ def verify(bridge):
if 'has_vrf' in interface_config:
raise ConfigError(error_msg + 'it has a VRF assigned!')
+ if 'bpdu_guard' in interface_config and 'root_guard' in interface_config:
+ raise ConfigError(error_msg + 'bpdu-guard and root-guard cannot be configured at the same time!')
+
if 'enable_vlan' in bridge:
if 'has_vlan' in interface_config:
raise ConfigError(error_msg + 'it has VLAN subinterface(s) assigned!')