diff --git a/config.yaml b/config.yaml index 0e84d6e3..d49981de 100644 --- a/config.yaml +++ b/config.yaml @@ -68,6 +68,9 @@ options: bridge:mac for the same bridge so as to be able to configure multiple units. In this case the charm will run through the provided MAC addresses for each bridge until it finds one it can resolve to an interface name. + Port can also be a linuxbridge bridge. In this case a veth pair will be + created, the ovs bridge and the linuxbridge bridge will be connected. It + can be useful to connect the ovs bridge to juju bridge. disable-security-groups: type: boolean default: false diff --git a/hooks/neutron_ovs_utils.py b/hooks/neutron_ovs_utils.py index 65982388..7227c93f 100644 --- a/hooks/neutron_ovs_utils.py +++ b/hooks/neutron_ovs_utils.py @@ -44,6 +44,8 @@ import neutron_ovs_context from charmhelpers.contrib.network.ovs import ( add_bridge, add_bridge_port, + is_linuxbridge_interface, + add_ovsbridge_linuxbridge, full_restart, ) from charmhelpers.core.hookenv import ( @@ -414,7 +416,10 @@ def configure_ovs(): for port, _br in portmaps.iteritems(): if _br == br: - add_bridge_port(br, port, promisc=True) + if not is_linuxbridge_interface(port): + add_bridge_port(br, port, promisc=True) + else: + add_ovsbridge_linuxbridge(br, port) else: # NOTE: when in dpdk mode, add based on pci bus order # with type 'dpdk' diff --git a/unit_tests/test_neutron_ovs_utils.py b/unit_tests/test_neutron_ovs_utils.py index 8f3da8bc..e292bc4a 100644 --- a/unit_tests/test_neutron_ovs_utils.py +++ b/unit_tests/test_neutron_ovs_utils.py @@ -31,6 +31,8 @@ import charmhelpers.core.hookenv as hookenv TO_PATCH = [ 'add_bridge', 'add_bridge_port', + 'add_ovsbridge_linuxbridge', + 'is_linuxbridge_interface', 'dpdk_add_bridge_port', 'apt_install', 'apt_update', @@ -331,6 +333,7 @@ class TestNeutronOVSUtils(CharmTestCase): @patch('charmhelpers.contrib.openstack.context.config') def test_configure_ovs_ovs_data_port(self, mock_config, _use_dvr): _use_dvr.return_value = False + self.is_linuxbridge_interface.return_value = False mock_config.side_effect = self.test_config.get self.config.side_effect = self.test_config.get self.ExternalPortContext.return_value = \ @@ -359,6 +362,24 @@ class TestNeutronOVSUtils(CharmTestCase): # Not called since we have a bogus bridge in data-ports self.assertFalse(self.add_bridge_port.called) + @patch.object(nutils, 'use_dvr') + @patch('charmhelpers.contrib.openstack.context.config') + def test_configure_ovs_data_port_with_bridge(self, mock_config, _use_dvr): + _use_dvr.return_value = False + self.is_linuxbridge_interface.return_value = True + mock_config.side_effect = self.test_config.get + self.config.side_effect = self.test_config.get + self.ExternalPortContext.return_value = \ + DummyContext(return_value=None) + + # Now test with bridge:bridge format + self.test_config.set('bridge-mappings', 'physnet1:br-foo') + self.test_config.set('data-port', 'br-foo:br-juju') + self.add_bridge.reset_mock() + self.add_bridge_port.reset_mock() + nutils.configure_ovs() + self.assertTrue(self.add_ovsbridge_linuxbridge.called) + @patch.object(nutils, 'use_dvr') @patch('charmhelpers.contrib.openstack.context.config') def test_configure_ovs_starts_service_if_required(self, mock_config,