diff options
author | Daniil Baturin <daniil@vyos.io> | 2025-05-27 14:53:54 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-05-27 14:53:54 +0100 |
commit | eb07e3131ae3ea6a58ac85340a5ce049ce3e6eb2 (patch) | |
tree | e0d3e70141f8b8cbfe6cbd516358790cce327010 | |
parent | 1dc6a82211635c64852cdd50c656fe1ab3013c0b (diff) | |
parent | e5b613191a60f0de4a231d35aa48e3f0e90a05ab (diff) | |
download | vyos-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.in | 12 | ||||
-rwxr-xr-x | op-mode-definitions/show-log.xml.in | 6 | ||||
-rw-r--r-- | python/vyos/ifconfig/bridge.py | 10 | ||||
-rw-r--r-- | python/vyos/ifconfig/interface.py | 32 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_bridge.py | 25 | ||||
-rwxr-xr-x | src/conf_mode/interfaces_bridge.py | 3 |
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!') |