diff --git a/neutron/agent/linux/ip_lib.py b/neutron/agent/linux/ip_lib.py index 5e380913cef..849b33320e8 100644 --- a/neutron/agent/linux/ip_lib.py +++ b/neutron/agent/linux/ip_lib.py @@ -508,6 +508,10 @@ class IpLinkCommand(IpDeviceCommandBase): return privileged.get_link_attributes(self.name, self._parent.namespace) + @property + def exists(self): + return privileged.interface_exists(self.name, self._parent.namespace) + class IpAddrCommand(IpDeviceCommandBase): COMMAND = 'addr' @@ -945,8 +949,8 @@ def ensure_device_is_ready(device_name, namespace=None): dev = IPDevice(device_name, namespace=namespace) try: # Ensure the device has a MAC address and is up, even if it is already - # up. If the device doesn't exist, a RuntimeError will be raised. - if not dev.link.address: + # up. + if not dev.link.exists or not dev.link.address: LOG.error("Device %s cannot be used as it has no MAC " "address", device_name) return False diff --git a/neutron/privileged/agent/linux/ip_lib.py b/neutron/privileged/agent/linux/ip_lib.py index 0ec3173561a..bda6b49cfe7 100644 --- a/neutron/privileged/agent/linux/ip_lib.py +++ b/neutron/privileged/agent/linux/ip_lib.py @@ -17,6 +17,7 @@ import socket from neutron_lib import constants from oslo_concurrency import lockutils +from oslo_log import log as logging import pyroute2 from pyroute2 import netlink from pyroute2.netlink import exceptions as netlink_exceptions @@ -31,6 +32,8 @@ from neutron._i18n import _ from neutron import privileged +LOG = logging.getLogger(__name__) + _IP_VERSION_FAMILY_MAP = {4: socket.AF_INET, 6: socket.AF_INET6} NETNS_RUN_DIR = '/var/run/netns' @@ -240,11 +243,16 @@ def _translate_ip_device_exception(e, device=None, namespace=None): namespace=namespace) -def get_link_id(device, namespace): +def get_link_id(device, namespace, raise_exception=True): with get_iproute(namespace) as ip: link_id = ip.link_lookup(ifname=device) if not link_id or len(link_id) < 1: - raise NetworkInterfaceNotFound(device=device, namespace=namespace) + if raise_exception: + raise NetworkInterfaceNotFound(device=device, namespace=namespace) + else: + LOG.debug('Interface %(dev)s not found in namespace %(namespace)s', + {'dev': device, 'namespace': namespace}) + return None return link_id[0] @@ -376,10 +384,8 @@ def delete_interface(ifname, namespace, **kwargs): @privileged.default.entrypoint def interface_exists(ifname, namespace): try: - idx = get_link_id(ifname, namespace) + idx = get_link_id(ifname, namespace, raise_exception=False) return bool(idx) - except NetworkInterfaceNotFound: - return False except OSError as e: if e.errno == errno.ENOENT: return False diff --git a/neutron/tests/unit/agent/linux/test_ip_lib.py b/neutron/tests/unit/agent/linux/test_ip_lib.py index f24b17dd787..25c584f71d6 100644 --- a/neutron/tests/unit/agent/linux/test_ip_lib.py +++ b/neutron/tests/unit/agent/linux/test_ip_lib.py @@ -937,15 +937,21 @@ class TestDeviceExists(base.BaseTestCase): def test_ensure_device_is_ready_no_link_address(self): with mock.patch.object( - priv_lib, 'get_link_attributes' - ) as get_link_attributes, mock.patch.object( - priv_lib, 'set_link_attribute' - ) as set_link_attribute: + priv_lib, 'get_link_attributes') as get_link_attributes, \ + mock.patch.object(priv_lib, 'set_link_attribute') as \ + set_link_attribute, \ + mock.patch.object(priv_lib, 'interface_exists', + return_value=True): get_link_attributes.return_value = {} self.assertFalse(ip_lib.ensure_device_is_ready("lo")) get_link_attributes.assert_called_once_with("lo", None) set_link_attribute.assert_not_called() + def test_ensure_device_is_ready_no_device(self): + with mock.patch.object(priv_lib, 'interface_exists', + return_value=False): + self.assertFalse(ip_lib.ensure_device_is_ready("lo")) + class TestGetRoutingTable(base.BaseTestCase): ip_db_interfaces = {