Ensure that MAC address of the device is set correctly

For unknown (for me at least) reason sometimes we observed e.g. in the
CI jobs that interfaces created by e.g. L3 agent didn't had properly set
MAC address to the one generated by Neutron.
To avoid that this patch adds check if the requested MAC was actually
set on the device before moving on to configure MTU and other attributes
of the device.

Co-Authored-By: Brian Haley <haleyb.dev@gmail.com>

Closes-bug: #2000164
Change-Id: I23facc53795a9592ccb137c60fb1f356406a4e00
This commit is contained in:
Slawek Kaplonski 2023-01-04 13:40:45 +01:00
parent 4e26901feb
commit c362016620
2 changed files with 22 additions and 9 deletions

View File

@ -18,6 +18,7 @@ import time
import netaddr
from neutron_lib.agent.linux import interface
from neutron_lib.api import converters
from neutron_lib import constants
from neutron_lib import exceptions
from neutron_lib.plugins.ml2 import ovs_constants as ovs_const
@ -26,6 +27,7 @@ from oslo_utils import excutils
from pyroute2.netlink import exceptions \
as pyroute2_exc # pylint: disable=no-name-in-module
from neutron._i18n import _
from neutron.agent.common import ovs_lib
from neutron.agent.linux import ip_lib
from neutron.common import utils
@ -336,20 +338,29 @@ class OVSInterfaceDriver(LinuxInterfaceDriver):
ovs.replace_port(device_name, *attrs)
def _set_device_address(self, device, mac_address):
device.link.set_address(mac_address)
current_mac = converters.convert_to_sanitized_mac_address(
device.link.address)
if current_mac != mac_address:
msg = _("Failed to set mac address to: %s; "
"Current mac: %s") % (mac_address, current_mac)
raise RuntimeError(msg)
def _ensure_device_address(self, device, mac_address):
mac_address = converters.convert_to_sanitized_mac_address(mac_address)
for i in range(9):
# workaround for the OVS shy port syndrome. ports sometimes
# hide for a bit right after they are first created.
# see bug/1618987
try:
device.link.set_address(mac_address)
break
self._set_device_address(device, mac_address)
return
except RuntimeError as e:
LOG.warning("Got error trying to set mac, retrying: %s",
str(e))
time.sleep(1)
else:
# didn't break, we give it one last shot without catching
device.link.set_address(mac_address)
# didn't break, we give it one last shot without catching
self._set_device_address(device, mac_address)
def _add_device_to_namespace(self, ip_wrapper, device, namespace):
namespace_obj = ip_wrapper.ensure_namespace(namespace)
@ -406,7 +417,7 @@ class OVSInterfaceDriver(LinuxInterfaceDriver):
self._ovs_add_port(bridge, tap_name, port_id, mac_address,
internal=internal)
try:
self._set_device_address(ns_dev, mac_address)
self._ensure_device_address(ns_dev, mac_address)
except Exception:
LOG.warning("Failed to set mac for interface %s", ns_dev)
with excutils.save_and_reraise_exception():

View File

@ -72,6 +72,8 @@ class TestBase(base.BaseTestCase):
self.ip_dev = self.ip_dev_p.start()
self.ip_p = mock.patch.object(ip_lib, 'IPWrapper')
self.ip = self.ip_p.start()
link = self.ip.return_value.device.return_value.link
link.address = 'aa:bb:cc:dd:ee:ff'
self.device_exists_p = mock.patch.object(ip_lib, 'device_exists')
self.device_exists = self.device_exists_p.start()
self.get_devices_with_ip_p = mock.patch.object(ip_lib,
@ -492,12 +494,11 @@ class TestOVSInterfaceDriver(TestBase):
reraise = mock.patch.object(
excutils, 'save_and_reraise_exception')
reraise.start()
ip_wrapper = mock.Mock()
for exception in (OSError(),
pyroute2_exc.NetlinkError(22),
RuntimeError()):
ip_wrapper.ensure_namespace.side_effect = exception
self.ip.return_value = ip_wrapper
ip = self.ip.return_value
ip.ensure_namespace.side_effect = exception
delete_port.reset_mock()
ovs.plug_new(
'01234567-1234-1234-99',
@ -568,6 +569,7 @@ class TestOVSInterfaceDriverWithVeth(TestOVSInterfaceDriver):
root_dev = mock.Mock()
ns_dev = mock.Mock()
ns_dev.link.address = 'aa:bb:cc:dd:ee:ff'
self.ip().add_veth = mock.Mock(return_value=(root_dev, ns_dev))
mock.patch.object(
interface, '_get_veth',