Delete ovs port if namespace is corrupted

This patch isolates a corrupted dhcp
namespace and protects the ovs from being
blasted by thousands of dangling ovs
ports created by dhcp agent.

Change-Id: I80138b3c37f41a18dc488a306768b8e2fa299eda
Closes-bug: #1728642
This commit is contained in:
yong sheng gong 2017-10-31 00:05:20 +08:00 committed by Brian Haley
parent da1bb4e492
commit 4f2f5eeb8b
2 changed files with 50 additions and 2 deletions

View File

@ -19,6 +19,7 @@ import time
import netaddr
from neutron_lib import constants
from oslo_log import log as logging
from oslo_utils import excutils
import six
from neutron.agent.common import ovs_lib
@ -377,8 +378,21 @@ class OVSInterfaceDriver(LinuxInterfaceDriver):
# Add an interface created by ovs to the namespace.
if not self.conf.ovs_use_veth and namespace:
namespace_obj = ip.ensure_namespace(namespace)
namespace_obj.add_device_to_namespace(ns_dev)
try:
namespace_obj = ip.ensure_namespace(namespace)
namespace_obj.add_device_to_namespace(ns_dev)
except exceptions.ProcessExecutionError:
# To prevent the namespace failure from blasting
# ovs, the ovs port created should be reverted
# When the namespace is corrupted, the ProcessExecutionError
# has execption message as:
# Exit code: 2; Stdin: ; Stdout: ; Stderr: RTNETLINK
# answers: Invalid argument
LOG.warning("Failed to plug interface %s into bridge %s, "
"cleaning up", device_name, bridge)
with excutils.save_and_reraise_exception():
ovs = ovs_lib.OVSBridge(bridge)
ovs.delete_port(tap_name)
# NOTE(ihrachys): the order here is significant: we must set MTU after
# the device is moved into a namespace, otherwise OVS bridge does not

View File

@ -15,10 +15,12 @@
import mock
from neutron_lib import constants
from oslo_utils import excutils
from neutron.agent.common import ovs_lib
from neutron.agent.linux import interface
from neutron.agent.linux import ip_lib
from neutron.common import exceptions
from neutron.conf.agent import common as config
from neutron.tests import base
@ -457,6 +459,32 @@ class TestOVSInterfaceDriver(TestBase):
self.ip.assert_has_calls(expected)
def test_plug_new(self):
with mock.patch('neutron.agent.ovsdb.impl_idl._connection'):
bridge = 'br-int'
namespace = '01234567-1234-1234-99'
with mock.patch.object(ovs_lib.OVSBridge,
'delete_port') as delete_port:
with mock.patch.object(ovs_lib.OVSBridge, 'replace_port'):
ovs = interface.OVSInterfaceDriver(self.conf)
reraise = mock.patch.object(
excutils, 'save_and_reraise_exception')
reraise.start()
proEr = exceptions.ProcessExecutionError('', 2)
processExecutionError = mock.Mock(side_effect=proEr)
ip = self.ip.return_value
ip.ensure_namespace.side_effect = processExecutionError
ovs.plug_new(
'01234567-1234-1234-99',
'port-1234',
'tap0',
'aa:bb:cc:dd:ee:ff',
bridge=bridge,
namespace=namespace,
prefix='veth',
mtu=9000)
delete_port.assert_called_once_with('tap0')
def test_unplug(self, bridge=None):
if not bridge:
bridge = 'br-int'
@ -533,6 +561,12 @@ class TestOVSInterfaceDriverWithVeth(TestOVSInterfaceDriver):
root_dev.assert_has_calls([mock.call.link.set_up()])
ns_dev.assert_has_calls([mock.call.link.set_up()])
def test_plug_new(self, bridge=None, namespace=None):
# The purpose of test_plug_new in parent class(TestOVSInterfaceDriver)
# is to test exception(exceptions.ProcessExecutionError), method here
# would not go through that code, So just pass
pass
def test_unplug(self, bridge=None):
if not bridge:
bridge = 'br-int'