diff --git a/releasenotes/notes/OVSVif-hybrid-unplug-f37bf57bc8e913de.yaml b/releasenotes/notes/OVSVif-hybrid-unplug-f37bf57bc8e913de.yaml new file mode 100644 index 00000000..11545a07 --- /dev/null +++ b/releasenotes/notes/OVSVif-hybrid-unplug-f37bf57bc8e913de.yaml @@ -0,0 +1,10 @@ +--- + +feature: + - | + The unplug() method for VIFOpenVSwitch type now checks for existence of + linux bridge used in hybrid plugging mechanism. In case it exists, the + interfaces related to the hybrid plugging are deleted too. This is useful + in particular for cold migration use case when target node has updated + port binding that doesn't use hybrid plugging, while the original plugging + was hybrid. diff --git a/vif_plug_ovs/ovs.py b/vif_plug_ovs/ovs.py index b4ad38e0..4368ba4e 100644 --- a/vif_plug_ovs/ovs.py +++ b/vif_plug_ovs/ovs.py @@ -371,7 +371,7 @@ class OvsPlugin(plugin.PluginBase): vif.id)) self._delete_bridge_if_trunk(vif) - def _unplug_bridge(self, vif, instance_info): + def _unplug_bridge(self, vif, instance_info, linux_bridge_name): """UnPlug using hybrid strategy Unhook port from OVS, unhook port from bridge, delete @@ -380,7 +380,7 @@ class OvsPlugin(plugin.PluginBase): v1_name, v2_name = self.get_veth_pair_names(vif) - linux_net.delete_bridge(vif.bridge_name, v1_name) + linux_net.delete_bridge(linux_bridge_name, v1_name) self.ovsdb.delete_ovs_vif_port(vif.network.bridge, v2_name) self._delete_bridge_if_trunk(vif) @@ -452,9 +452,13 @@ class OvsPlugin(plugin.PluginBase): if self.config.per_port_bridge: self._unplug_port_bridge(vif, instance_info) else: - self._unplug_vif_generic(vif, instance_info) + linux_bridge_name = self.gen_port_name('qbr', vif.id) + if ip_lib.exists(linux_bridge_name): + self._unplug_bridge(vif, instance_info, linux_bridge_name) + else: + self._unplug_vif_generic(vif, instance_info) elif isinstance(vif, objects.vif.VIFBridge): - self._unplug_bridge(vif, instance_info) + self._unplug_bridge(vif, instance_info, vif.bridge_name) elif isinstance(vif, objects.vif.VIFVHostUser): self._unplug_vhostuser(vif, instance_info) elif isinstance(vif, objects.vif.VIFHostDevice): diff --git a/vif_plug_ovs/tests/unit/test_plugin.py b/vif_plug_ovs/tests/unit/test_plugin.py index e779a1b4..d710c6cd 100644 --- a/vif_plug_ovs/tests/unit/test_plugin.py +++ b/vif_plug_ovs/tests/unit/test_plugin.py @@ -640,3 +640,17 @@ class PluginTest(testtools.TestCase): ] delete_ovs_vif_port.assert_has_calls(calls) delete_ovs_bridge.assert_called_once_with('pbb679325f-ca8') + + @mock.patch.object(ip_lib, 'exists', return_value=True) + @mock.patch.object(ovs.OvsPlugin, '_unplug_bridge') + def test_unplug_hybrid_bridge(self, m_unplug_bridge, m_ip_lib_exists): + plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME) + plugin.unplug(self.vif_ovs, self.instance) + m_unplug_bridge.assert_called_once() + + @mock.patch.object(ip_lib, 'exists', return_value=False) + @mock.patch.object(ovs.OvsPlugin, '_unplug_vif_generic') + def test_unplug_ovs(self, m_unplug_generic, m_ip_lib_exists): + plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME) + plugin.unplug(self.vif_ovs, self.instance) + m_unplug_generic.assert_called_once()