Add sleep before checking if ovs port is in the namespace

When network device which is ovs internal port is moved to the namespace
it may happend sometimes that it will have "shy port syndrome" [1].
Even though there is wait for device to be in namespace in the set_netns
method it may happend that device is in namespace during this check but
it dissapears for short time later and that causes failures e.g. in
functional tests like described in [2].
To avoid that, this patch proposed simple (and ugly) sleep for 1 second
before checking if port really exists in the namespace. If it will be
"shy" port it should already flap during that 1 second.

[1] https://bugs.launchpad.net/neutron/+bug/1618987
[2] https://bugs.launchpad.net/neutron/+bug/1961740

Related-Bug: #1961740
Related-Bug: #1998337
Change-Id: I442587e7ef55917f4ea873e190bf8afbc0e911e1
This commit is contained in:
Slawek Kaplonski 2023-02-28 18:27:29 +01:00
parent c178c28fb8
commit 2af5fd889b
4 changed files with 14 additions and 8 deletions

View File

@ -365,7 +365,7 @@ class OVSInterfaceDriver(LinuxInterfaceDriver):
namespace_obj = ip_wrapper.ensure_namespace(namespace)
for i in range(9):
try:
namespace_obj.add_device_to_namespace(device)
namespace_obj.add_device_to_namespace(device, is_ovs_port=True)
break
except ip_lib.NetworkInterfaceNotFound:
# NOTE(slaweq): if the exception was NetworkInterfaceNotFound

View File

@ -265,9 +265,9 @@ class IPWrapper(SubProcessBase):
return True
return False
def add_device_to_namespace(self, device):
def add_device_to_namespace(self, device, is_ovs_port=False):
if self.namespace:
device.link.set_netns(self.namespace)
device.link.set_netns(self.namespace, is_ovs_port=is_ovs_port)
def add_vlan(self, name, physical_interface, vlan_id):
privileged.create_interface(name,
@ -457,10 +457,15 @@ class IpLinkCommand(IpDeviceCommandBase):
privileged.set_link_attribute(
self.name, self._parent.namespace, state='down')
def set_netns(self, namespace):
def set_netns(self, namespace, is_ovs_port=False):
privileged.set_link_attribute(
self.name, self._parent.namespace, net_ns_fd=namespace)
self._parent.namespace = namespace
if is_ovs_port:
# NOTE(slaweq): because of the "shy port" which may dissapear for
# short time after it's moved to the namespace we need to wait
# a bit before checking if port really exists in the namespace
time.sleep(1)
common_utils.wait_until_true(lambda: self.exists, timeout=5,
sleep=0.5)

View File

@ -470,11 +470,11 @@ class TestOVSInterfaceDriver(TestBase):
expected.extend(
[mock.call().ensure_namespace(namespace),
mock.call().ensure_namespace().add_device_to_namespace(
mock.ANY),
mock.ANY, is_ovs_port=True),
mock.call().ensure_namespace().add_device_to_namespace(
mock.ANY),
mock.ANY, is_ovs_port=True),
mock.call().ensure_namespace().add_device_to_namespace(
mock.ANY)])
mock.ANY, is_ovs_port=True)])
expected.extend([
mock.call(namespace=namespace),
mock.call().device('tap0'),

View File

@ -507,7 +507,8 @@ class TestIpWrapper(base.BaseTestCase):
def test_add_device_to_namespace(self):
dev = mock.Mock()
ip_lib.IPWrapper(namespace='ns').add_device_to_namespace(dev)
dev.assert_has_calls([mock.call.link.set_netns('ns')])
dev.assert_has_calls(
[mock.call.link.set_netns('ns', is_ovs_port=False)])
def test_add_device_to_namespace_is_none(self):
dev = mock.Mock()