162 lines
6.7 KiB
Diff
162 lines
6.7 KiB
Diff
From 24bf6147712655fc36a5d714a081853ea37e0312 Mon Sep 17 00:00:00 2001
|
|
From: Anh Vo <anhvo@microsoft.com>
|
|
Date: Fri, 18 Nov 2022 14:31:27 -0500
|
|
Subject: [PATCH] net: skip duplicate mac check for netvsc nic and its VF
|
|
(#1853)
|
|
|
|
Reference:https://github.com/canonical/cloud-init/commit/24bf6147712655fc36a5d714a081853ea37e0312
|
|
Conflict:format diff.
|
|
|
|
When accelerated network is enabled on Azure, the host presents
|
|
two network interfaces with the same mac address to the VM:
|
|
a synthetic nic (netvsc) and a VF nic, which is enslaved to the synthetic
|
|
nic.
|
|
|
|
The net module is already excluding slave nics when enumerating
|
|
interfaces. However, if cloud-init starts enumerating after the kernel
|
|
makes the VF visible to userspace, but before the enslaving has finished,
|
|
cloud-init will see two nics with duplicate mac.
|
|
|
|
This change will skip the duplicate mac error if one of the two nics
|
|
with duplicate mac is a netvsc nic
|
|
|
|
LP: #1844191
|
|
---
|
|
cloudinit/net/__init__.py | 39 +++++++++++++++++++++++++++++++++----
|
|
tests/unittests/test_net.py | 32 ++++++++++++++++++++++++++----
|
|
2 files changed, 63 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py
|
|
index fba133e..96ce6f5 100644
|
|
--- a/cloudinit/net/__init__.py
|
|
+++ b/cloudinit/net/__init__.py
|
|
@@ -896,13 +896,44 @@ def get_interfaces_by_mac_on_linux(blacklist_drivers=None) -> dict:
|
|
|
|
Bridges and any devices that have a 'stolen' mac are excluded."""
|
|
ret = {}
|
|
- for name, mac, _driver, _devid in get_interfaces(
|
|
+ driver_map: dict = {}
|
|
+ for name, mac, driver, _devid in get_interfaces(
|
|
blacklist_drivers=blacklist_drivers):
|
|
if mac in ret:
|
|
- raise RuntimeError(
|
|
- "duplicate mac found! both '%s' and '%s' have mac '%s'" %
|
|
- (name, ret[mac], mac))
|
|
+ raise_duplicate_mac_error = True
|
|
+ msg = "duplicate mac found! both '%s' and '%s' have mac '%s'." % (
|
|
+ name,
|
|
+ ret[mac],
|
|
+ mac,
|
|
+ )
|
|
+ # Hyper-V netvsc driver will register a VF with the same mac
|
|
+ #
|
|
+ # The VF will be enslaved to the master nic shortly after
|
|
+ # registration. If cloud-init starts enumerating the interfaces
|
|
+ # before the completion of the enslaving process, it will see
|
|
+ # two different nics with duplicate mac. Cloud-init should ignore
|
|
+ # the slave nic (which does not have hv_netvsc driver).
|
|
+ if driver != driver_map[mac]:
|
|
+ if driver_map[mac] == "hv_netvsc":
|
|
+ LOG.warning(
|
|
+ msg + " Ignoring '%s' due to driver '%s' and "
|
|
+ "'%s' having driver hv_netvsc."
|
|
+ % (name, driver, ret[mac])
|
|
+ )
|
|
+ continue
|
|
+ if driver == "hv_netvsc":
|
|
+ raise_duplicate_mac_error = False
|
|
+ LOG.warning(
|
|
+ msg + " Ignoring '%s' due to driver '%s' and "
|
|
+ "'%s' having driver hv_netvsc."
|
|
+ % (ret[mac], driver_map[mac], name)
|
|
+ )
|
|
+
|
|
+ if raise_duplicate_mac_error:
|
|
+ raise RuntimeError(msg)
|
|
+
|
|
ret[mac] = name
|
|
+ driver_map[mac] = driver
|
|
|
|
# Pretend that an Infiniband GUID is an ethernet address for Openstack
|
|
# configuration purposes
|
|
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
|
|
index ce19498..0db4442 100644
|
|
--- a/tests/unittests/test_net.py
|
|
+++ b/tests/unittests/test_net.py
|
|
@@ -5519,7 +5519,8 @@ class TestGetInterfacesByMac(CiTestCase):
|
|
'bridges': ['bridge1'],
|
|
'vlans': ['bond1.101'],
|
|
'own_macs': ['enp0s1', 'enp0s2', 'bridge1-nic', 'bridge1',
|
|
- 'bond1.101', 'lo'],
|
|
+ 'bond1.101', 'lo',
|
|
+ "netvsc0-vf", "netvsc0", "netvsc1","netvsc1-vf"],
|
|
'macs': {'enp0s1': 'aa:aa:aa:aa:aa:01',
|
|
'enp0s2': 'aa:aa:aa:aa:aa:02',
|
|
'bond1': 'aa:aa:aa:aa:aa:01',
|
|
@@ -5528,12 +5529,27 @@ class TestGetInterfacesByMac(CiTestCase):
|
|
'bridge1-nic': 'aa:aa:aa:aa:aa:03',
|
|
'lo': '00:00:00:00:00:00',
|
|
'greptap0': '00:00:00:00:00:00',
|
|
- 'tun0': None}}
|
|
+ "greptap0": "00:00:00:00:00:00",
|
|
+ "netvsc0-vf": "aa:aa:aa:aa:aa:04",
|
|
+ "netvsc0": "aa:aa:aa:aa:aa:04",
|
|
+ "netvsc1-vf": "aa:aa:aa:aa:aa:05",
|
|
+ "netvsc1": "aa:aa:aa:aa:aa:05",
|
|
+ 'tun0': None},
|
|
+ "drivers": {
|
|
+ "netvsc0": "hv_netvsc",
|
|
+ "netvsc0-vf": "foo",
|
|
+ "netvsc1": "hv_netvsc",
|
|
+ "netvsc1-vf": "bar",
|
|
+ },
|
|
+ }
|
|
data = {}
|
|
|
|
def _se_get_devicelist(self):
|
|
return list(self.data['devices'])
|
|
|
|
+ def _se_device_driver(self, name):
|
|
+ return self.data["drivers"].get(name, None)
|
|
+
|
|
def _se_get_interface_mac(self, name):
|
|
return self.data['macs'][name]
|
|
|
|
@@ -5553,7 +5569,7 @@ class TestGetInterfacesByMac(CiTestCase):
|
|
def _mock_setup(self):
|
|
self.data = copy.deepcopy(self._data)
|
|
self.data['devices'] = set(list(self.data['macs'].keys()))
|
|
- mocks = ('get_devicelist', 'get_interface_mac', 'is_bridge',
|
|
+ mocks = ('get_devicelist', "device_driver", 'get_interface_mac', 'is_bridge',
|
|
'interface_has_own_mac', 'is_vlan', 'get_ib_interface_hwaddr')
|
|
self.mocks = {}
|
|
for n in mocks:
|
|
@@ -5567,6 +5583,11 @@ class TestGetInterfacesByMac(CiTestCase):
|
|
self.data['macs']['bridge1-nic'] = self.data['macs']['enp0s1']
|
|
self.assertRaises(RuntimeError, net.get_interfaces_by_mac)
|
|
|
|
+ def test_raise_exception_on_duplicate_netvsc_macs(self):
|
|
+ self._mock_setup()
|
|
+ self.data["macs"]["netvsc0"] = self.data["macs"]["netvsc1"]
|
|
+ self.assertRaises(RuntimeError, net.get_interfaces_by_mac)
|
|
+
|
|
def test_excludes_any_without_mac_address(self):
|
|
self._mock_setup()
|
|
ret = net.get_interfaces_by_mac()
|
|
@@ -5580,7 +5601,10 @@ class TestGetInterfacesByMac(CiTestCase):
|
|
[mock.call('enp0s1'), mock.call('bond1')], any_order=True)
|
|
self.assertEqual(
|
|
{'aa:aa:aa:aa:aa:01': 'enp0s1', 'aa:aa:aa:aa:aa:02': 'enp0s2',
|
|
- 'aa:aa:aa:aa:aa:03': 'bridge1-nic', '00:00:00:00:00:00': 'lo'},
|
|
+ 'aa:aa:aa:aa:aa:03': 'bridge1-nic', '00:00:00:00:00:00': 'lo',
|
|
+ "aa:aa:aa:aa:aa:04": "netvsc0",
|
|
+ "aa:aa:aa:aa:aa:05": "netvsc1",
|
|
+ },
|
|
ret)
|
|
|
|
def test_excludes_bridges(self):
|
|
--
|
|
2.33.0
|
|
|
|
|