From c3620166204d2d12729ca1eba92feaadbe802d42 Mon Sep 17 00:00:00 2001 From: Slawek Kaplonski Date: Wed, 4 Jan 2023 13:40:45 +0100 Subject: [PATCH] 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 Closes-bug: #2000164 Change-Id: I23facc53795a9592ccb137c60fb1f356406a4e00 --- neutron/agent/linux/interface.py | 23 ++++++++++++++----- .../tests/unit/agent/linux/test_interface.py | 8 ++++--- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/neutron/agent/linux/interface.py b/neutron/agent/linux/interface.py index 870329174a2..abda59e89dd 100644 --- a/neutron/agent/linux/interface.py +++ b/neutron/agent/linux/interface.py @@ -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(): diff --git a/neutron/tests/unit/agent/linux/test_interface.py b/neutron/tests/unit/agent/linux/test_interface.py index 9b3b5ca13eb..1f35404467f 100644 --- a/neutron/tests/unit/agent/linux/test_interface.py +++ b/neutron/tests/unit/agent/linux/test_interface.py @@ -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',