Fix - os-vif fails to get the correct UpLink Representor
Till kernel 5.7 PF and VF representors are exposed as virtual device.
They are not linked to its parent PCI device like how uplink
representor is linked.
Starting from kernel 5.8 due to new change [1] the PF and VF representors are
linked to their parent PCI device, and so "get_ifname_by_pci_address" fails
to get the correct UpLink Representor.
This patch modifys the behviour of "get_ifname_by_pci_address" to
check the physical port name of the netdev in
vf_pci_addr_path/physfn/net to match the formart for the uplink "p\d+".
[1] https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=123f0f53dd64b67e34142485fe866a8a581f12f1
Closes-Bug: #1892132
Change-Id: I49f6ae3f0e6bfbf555c8284bfd70371ce90da0c7
(cherry picked from commit b37de19c58
)
This commit is contained in:
parent
167bb030f1
commit
a28aafa796
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in New Issue