diff options
| -rw-r--r-- | interface-definitions/interfaces-bridge.xml.in | 6 | ||||
| -rw-r--r-- | python/vyos/ifconfig/bridge.py | 6 | ||||
| -rw-r--r-- | python/vyos/ifconfig/interface.py | 18 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_interfaces_bridge.py | 52 | 
4 files changed, 69 insertions, 13 deletions
| diff --git a/interface-definitions/interfaces-bridge.xml.in b/interface-definitions/interfaces-bridge.xml.in index c6de58424..1af002142 100644 --- a/interface-definitions/interfaces-bridge.xml.in +++ b/interface-definitions/interfaces-bridge.xml.in @@ -178,6 +178,12 @@                      </properties>                      <defaultValue>32</defaultValue>                    </leafNode> +                  <leafNode name="isolated"> +                    <properties> +                      <help>Port is isolated (also known as Private-VLAN)</help> +                      <valueless/> +                    </properties> +                  </leafNode>                  </children>                </tagNode>              </children> diff --git a/python/vyos/ifconfig/bridge.py b/python/vyos/ifconfig/bridge.py index 600bd3db8..14f64a8de 100644 --- a/python/vyos/ifconfig/bridge.py +++ b/python/vyos/ifconfig/bridge.py @@ -312,9 +312,15 @@ class BridgeIf(Interface):                  # not have any addresses configured by CLI so just flush any                  # remaining ones                  lower.flush_addrs() +                  # enslave interface port to bridge                  self.add_port(interface) +                # always set private-vlan/port isolation +                tmp = dict_search('isolated', interface_config) +                value = 'on' if (tmp != None) else 'off' +                lower.set_port_isolation(value) +                  # set bridge port path cost                  if 'cost' in interface_config:                      value = interface_config.get('cost') diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index fe6a3c95e..5a1605a18 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -113,6 +113,10 @@ class Interface(Control):              'convert': lambda name: name if name else '',              'shellcmd': 'ip link set dev {ifname} alias "{value}"',          }, +        'bridge_port_isolation': { +            'validate': lambda v: assert_list(v, ['on', 'off']), +            'shellcmd': 'bridge link set dev {ifname} isolated {value}', +        },          'mac': {              'validate': assert_mac,              'shellcmd': 'ip link set dev {ifname} address {value}', @@ -689,6 +693,20 @@ class Interface(Control):          """          self.set_interface('path_priority', priority) +    def set_port_isolation(self, on_or_off): +        """ +        Controls whether a given port will be isolated, which means it will be +        able to communicate with non-isolated ports only. By default this flag +        is off. + +        Use enable=1 to enable or enable=0 to disable + +        Example: +        >>> from vyos.ifconfig import Interface +        >>> Interface('eth1').set_port_isolation('on') +        """ +        self.set_interface('bridge_port_isolation', on_or_off) +      def set_proxy_arp(self, enable):          """          Set per interface proxy ARP configuration diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py index 5899d1620..21f20c781 100755 --- a/smoketest/scripts/cli/test_interfaces_bridge.py +++ b/smoketest/scripts/cli/test_interfaces_bridge.py @@ -25,6 +25,7 @@ from netifaces import interfaces  from vyos.ifconfig import Section  from vyos.util import cmd  from vyos.util import read_file +from vyos.util import get_interface_config  from vyos.validate import is_intf_addr_assigned  class BridgeInterfaceTest(BasicInterfaceTest.TestCase): @@ -62,6 +63,32 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase):          super().tearDown() +    def test_isolated_interfaces(self): +        # Add member interfaces to bridge and set STP cost/priority +        for interface in self._interfaces: +            base = self._base_path + [interface] +            self.cli_set(base + ['stp']) + +            # assign members to bridge interface +            for member in self._members: +                base_member = base + ['member', 'interface', member] +                self.cli_set(base_member + ['isolated']) + +        # commit config +        self.cli_commit() + +        for interface in self._interfaces: +            tmp = get_interface_config(interface) +            # STP must be enabled as configured above +            self.assertEqual(1, tmp['linkinfo']['info_data']['stp_state']) + +            # validate member interface configuration +            for member in self._members: +                tmp = get_interface_config(member) +                # Isolated must be enabled as configured above +                self.assertTrue(tmp['linkinfo']['info_slave_data']['isolated']) + +      def test_add_remove_bridge_member(self):          # Add member interfaces to bridge and set STP cost/priority          for interface in self._interfaces: @@ -82,19 +109,20 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase):          # commit config          self.cli_commit() -        # check member interfaces are added on the bridge -        bridge_members = [] -        for tmp in glob(f'/sys/class/net/{interface}/lower_*'): -            bridge_members.append(os.path.basename(tmp).replace('lower_', '')) - -        for member in self._members: -            self.assertIn(member, bridge_members) - -        # delete all members +        # Add member interfaces to bridge and set STP cost/priority          for interface in self._interfaces: -            self.cli_delete(self._base_path + [interface, 'member']) +            cost = 1000 +            priority = 10 +            for member in self._members: +                tmp = get_interface_config(member) +                self.assertEqual(interface, tmp['master']) +                self.assertFalse(           tmp['linkinfo']['info_slave_data']['isolated']) +                self.assertEqual(cost,      tmp['linkinfo']['info_slave_data']['cost']) +                self.assertEqual(priority,  tmp['linkinfo']['info_slave_data']['priority']) + +                cost += 1 +                priority += 1 -        self.cli_commit()      def test_vif_8021q_interfaces(self):          for interface in self._interfaces: @@ -109,7 +137,6 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase):          super().test_vif_8021q_interfaces()      def test_bridge_vlan_filter(self): -          vif_vlan = 2          # Add member interface to bridge and set VLAN filter          for interface in self._interfaces: @@ -217,4 +244,3 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase):  if __name__ == '__main__':      unittest.main(verbosity=2) - | 
