diff --git a/vif_plug_ovs/linux_net.py b/vif_plug_ovs/linux_net.py index 8816127b..c73c7842 100644 --- a/vif_plug_ovs/linux_net.py +++ b/vif_plug_ovs/linux_net.py @@ -107,6 +107,12 @@ def device_exists(device): return os.path.exists('/sys/class/net/%s' % device) +def interface_in_bridge(bridge, device): + """Check if an ethernet device belongs to a Linux Bridge.""" + return os.path.exists('/sys/class/net/%(bridge)s/brif/%(device)s' % + {'bridge': bridge, 'device': device}) + + def _delete_net_dev(dev): """Delete a network device only if it exists.""" if device_exists(dev): @@ -172,7 +178,8 @@ def ensure_bridge(bridge): @privsep.vif_plug.entrypoint def delete_bridge(bridge, dev): if device_exists(bridge): - processutils.execute('brctl', 'delif', bridge, dev) + if interface_in_bridge(bridge, dev): + processutils.execute('brctl', 'delif', bridge, dev) processutils.execute('ip', 'link', 'set', bridge, 'down') processutils.execute('brctl', 'delbr', bridge) diff --git a/vif_plug_ovs/tests/unit/test_linux_net.py b/vif_plug_ovs/tests/unit/test_linux_net.py index 16f4849b..d4fb5ff1 100644 --- a/vif_plug_ovs/tests/unit/test_linux_net.py +++ b/vif_plug_ovs/tests/unit/test_linux_net.py @@ -84,15 +84,20 @@ class LinuxNetTest(testtools.TestCase): @mock.patch.object(processutils, "execute") @mock.patch.object(linux_net, "device_exists", return_value=False) - def test_delete_bridge_none(self, mock_dev_exists, mock_execute): + @mock.patch.object(linux_net, "interface_in_bridge", return_value=False) + def test_delete_bridge_none(self, mock_interface_br, mock_dev_exists, + mock_execute,): linux_net.delete_bridge("br0", "vnet1") mock_execute.assert_not_called() mock_dev_exists.assert_has_calls([mock.call("br0")]) + mock_interface_br.assert_not_called() @mock.patch.object(processutils, "execute") @mock.patch.object(linux_net, "device_exists", return_value=True) - def test_delete_bridge_exists(self, mock_dev_exists, mock_execute): + @mock.patch.object(linux_net, "interface_in_bridge", return_value=True) + def test_delete_bridge_exists(self, mock_interface_br, mock_dev_exists, + mock_execute): linux_net.delete_bridge("br0", "vnet1") calls = [ @@ -101,6 +106,21 @@ class LinuxNetTest(testtools.TestCase): mock.call('brctl', 'delbr', 'br0')] mock_execute.assert_has_calls(calls) mock_dev_exists.assert_has_calls([mock.call("br0")]) + mock_interface_br.assert_called_once_with("br0", "vnet1") + + @mock.patch.object(processutils, "execute") + @mock.patch.object(linux_net, "device_exists", return_value=True) + @mock.patch.object(linux_net, "interface_in_bridge", return_value=False) + def test_delete_interface_not_present(self, mock_interface_br, + mock_dev_exists, mock_execute): + linux_net.delete_bridge("br0", "vnet1") + + calls = [ + mock.call('ip', 'link', 'set', 'br0', 'down'), + mock.call('brctl', 'delbr', 'br0')] + mock_execute.assert_has_calls(calls) + mock_dev_exists.assert_has_calls([mock.call("br0")]) + mock_interface_br.assert_called_once_with("br0", "vnet1") @mock.patch.object(processutils, "execute") def test_add_bridge_port(self, mock_execute):