diff --git a/config.yaml b/config.yaml index 36e5298d..eb6ae10c 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 24b4b5df..0db4166a 100644 --- a/hooks/neutron_ovs_utils.py +++ b/hooks/neutron_ovs_utils.py @@ -43,6 +43,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 ( @@ -410,7 +412,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 aef7b3d3..a2f30b28 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', @@ -322,6 +324,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 = \ @@ -350,6 +353,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,