Merge "Fix - os-vif fails to get the correct UpLink Representor"

This commit is contained in:
Zuul 2020-10-22 04:49:08 +00:00 committed by Gerrit Code Review
commit cb21c4ed8d
3 changed files with 74 additions and 8 deletions

View File

@ -0,0 +1,10 @@
---
fixes:
- |
Linux kernel 5.8 changed the sysfs interface that is used to
discover the interfaces used for OVS offloads for certain NIC
models. This results in network plugging failure, as described
in `bug #1892132`_. This release fixes the plugging issue by
properly handling the new sysfs structure.
.. _bug #1892132: https://bugs.launchpad.net/os-vif/+bug/1892132

View File

@ -45,6 +45,8 @@ VF_RE = re.compile(r"vf(\d+)", re.IGNORECASE)
PF_RE = re.compile(r"pf(\d+)", re.IGNORECASE)
# bus_info (bdf) contains <bus>:<dev>.<func>
PF_FUNC_RE = re.compile(r"\.(\d+)", 0)
# phys_port_name contains p##
UPLINK_PORT_RE = re.compile(r"p(\d+)", re.IGNORECASE)
_SRIOV_TOTALVFS = "sriov_totalvfs"
NIC_NAME_LEN = 14
@ -328,12 +330,28 @@ def get_ifname_by_pci_address(pci_addr, pf_interface=False, switchdev=False):
itself based on the argument of pf_interface.
"""
dev_path = _get_sysfs_netdev_path(pci_addr, pf_interface)
# make the if statement later more readable
ignore_switchdev = not switchdev
try:
for netdev in os.listdir(dev_path):
if ignore_switchdev or _is_switchdev(netdev):
return netdev
devices = os.listdir(dev_path)
# Return the first netdev in case of switchdev=False
if not switchdev:
return devices[0]
elif pf_interface:
fallback_netdev = None
for netdev in devices:
# Return the uplink representor in case of switchdev=True
if _is_switchdev(netdev):
fallback_netdev = netdev if fallback_netdev is None \
else fallback_netdev
phys_port_name = _get_phys_port_name(netdev)
if phys_port_name is not None and \
UPLINK_PORT_RE.search(phys_port_name):
return netdev
# Fallback to first switchdev netdev in case of switchdev=True
if fallback_netdev is not None:
return fallback_netdev
except Exception:
raise exception.PciDeviceNotFoundById(id=pci_addr)
raise exception.PciDeviceNotFoundById(id=pci_addr)

View File

@ -261,26 +261,64 @@ class LinuxNetTest(testtools.TestCase):
@mock.patch.object(os, 'listdir')
@mock.patch.object(linux_net, '_get_phys_switch_id')
@mock.patch.object(linux_net, "_get_phys_port_name")
def test_physical_function_interface_name(
self, mock__get_phys_switch_id, mock_listdir):
self, mock__get_phys_port_name, mock__get_phys_switch_id,
mock_listdir):
mock_listdir.return_value = ['foo', 'bar']
mock__get_phys_switch_id.side_effect = (
['', 'valid_switch'])
mock__get_phys_port_name.side_effect = (["p1"])
ifname = linux_net.get_ifname_by_pci_address(
'0000:00:00.1', pf_interface=True, switchdev=False)
self.assertEqual(ifname, 'foo')
@mock.patch.object(os, 'listdir')
@mock.patch.object(linux_net, '_get_phys_switch_id')
@mock.patch.object(linux_net, "_get_phys_switch_id")
@mock.patch.object(linux_net, "_get_phys_port_name")
def test_physical_function_interface_name_with_switchdev(
self, mock__get_phys_switch_id, mock_listdir):
self, mock__get_phys_port_name, mock__get_phys_switch_id,
mock_listdir):
mock_listdir.return_value = ['foo', 'bar']
mock__get_phys_switch_id.side_effect = (
['', 'valid_switch'])
mock__get_phys_port_name.side_effect = (["p1s0"])
ifname = linux_net.get_ifname_by_pci_address(
'0000:00:00.1', pf_interface=True, switchdev=True)
self.assertEqual(ifname, 'bar')
@mock.patch.object(os, 'listdir')
@mock.patch.object(linux_net, "_get_phys_switch_id")
@mock.patch.object(linux_net, "_get_phys_port_name")
def test_physical_function_interface_name_with_representors(
self, mock__get_phys_port_name, mock__get_phys_switch_id,
mock_listdir):
# Get the PF that matches the phys_port_name regex
mock_listdir.return_value = ['enp2s0f0_0', 'enp2s0f0_1', 'enp2s0f0']
mock__get_phys_switch_id.side_effect = (
['valid_switch', 'valid_switch', 'valid_switch'])
mock__get_phys_port_name.side_effect = (["pf0vf0", "pf0vf1", "p0"])
ifname = linux_net.get_ifname_by_pci_address(
'0000:00:00.1', pf_interface=True, switchdev=True)
self.assertEqual(ifname, 'enp2s0f0')
@mock.patch.object(os, 'listdir')
@mock.patch.object(linux_net, "_get_phys_switch_id")
@mock.patch.object(linux_net, "_get_phys_port_name")
def test_physical_function_interface_name_with_fallback_To_first_netdev(
self, mock__get_phys_port_name, mock__get_phys_switch_id,
mock_listdir):
# Try with switchdev mode to get PF but fail because there is no match
# for the phys_port_name then fallback to first interface found
mock_listdir.return_value = ['enp2s0f0_0', 'enp2s0f0_1', 'enp2s0f0']
mock__get_phys_switch_id.side_effect = (['valid_switch',
'valid_switch',
'valid_switch'])
mock__get_phys_port_name.side_effect = (["pf0vf0", "pf0vf1", "pf0vf2"])
ifname = linux_net.get_ifname_by_pci_address(
'0000:00:00.1', pf_interface=True, switchdev=True)
self.assertEqual(ifname, 'enp2s0f0_0')
@mock.patch.object(os, 'listdir')
def test_get_ifname_by_pci_address_exception(self, mock_listdir):
mock_listdir.side_effect = OSError('No such file or directory')