From e7ae6c65cd24fb3e0776fac80fbab2ab16e9d9ed Mon Sep 17 00:00:00 2001 From: Sean Mooney Date: Tue, 2 Apr 2019 18:27:24 +0100 Subject: [PATCH] Libvirt: gracefully handle non-nic VFs As part of adding support for bandwidth based scheduling I038867c4094d79ae4a20615ab9c9f9e38fcc2e0a introduced automatic discovery of parent netdev names for PCIe virtual functions. Nova's PCI passthrough support was originally developed for Intel QAT devices and other generic PCI devices. Later support for Neutron based SR-IOV NIC was added. The PCI-SIG SR-IOV specification while most often used by NIC vendors to virtualise a NIC in hardware was designed for devices of any PCIe class. Support for Intel's QAT device and other accelerators like AMD's SRIOV based vGPU have therefore been regressed by the introduction of the new parent_ifname lookup code. This change simply catches the exception that would be raised when pci_utils.get_ifname_by_pci_address is called on generic VFs allowing a graceful fallback to the previous behaviour. Change-Id: Ib3811f828246311d90b0e3ba71c162c03fb8fe5a Closes-Bug: #1821938 --- nova/tests/unit/virt/libvirt/test_driver.py | 22 +++++++++++++++++++++ nova/virt/libvirt/driver.py | 16 +++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 8a1503c442..b48117455a 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -15103,6 +15103,28 @@ class LibvirtConnTestCase(test.NoDBTestCase, mock_get_net_name.called_once_with(parent_address) mock_dev_lookup.called_once_with(dev_name) + @mock.patch.object(pci_utils, 'get_ifname_by_pci_address') + def test_get_pcidev_info_non_nic(self, mock_get_ifname): + self.stub_out('nova.virt.libvirt.host.Host.device_lookup_by_name', + lambda self, name: FakeNodeDevice( + _fake_NodeDevXml[name])) + + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) + id = "pci_0000_04_10_7" + mock_get_ifname.side_effect = exception.PciDeviceNotFoundById(id=id) + actualvf = drvr._get_pcidev_info(id) + expect_vf = { + "dev_id": id, + "address": "0000:04:10.7", + "product_id": '1520', + "numa_node": None, + "vendor_id": '8086', + "label": 'label_8086_1520', + "dev_type": fields.PciDeviceType.SRIOV_VF, + 'parent_addr': '0000:04:00.3', + } + self.assertEqual(expect_vf, actualvf) + @mock.patch.object(pci_utils, 'get_ifname_by_pci_address', return_value='ens1') def test_get_pcidev_info(self, mock_get_ifname): diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index f4a9a3f1f2..c4a25d6efd 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -6040,13 +6040,21 @@ class LibvirtDriver(driver.ComputeDriver): fun_cap.device_addrs[0][1], fun_cap.device_addrs[0][2], fun_cap.device_addrs[0][3]) - return { + result = { 'dev_type': fields.PciDeviceType.SRIOV_VF, 'parent_addr': phys_address, - 'parent_ifname': - pci_utils.get_ifname_by_pci_address( - pci_address, pf_interface=True), } + parent_ifname = None + try: + parent_ifname = pci_utils.get_ifname_by_pci_address( + pci_address, pf_interface=True) + except exception.PciDeviceNotFoundById: + # NOTE(sean-k-mooney): we ignore this error as it + # is expected when the virtual function is not a NIC. + pass + if parent_ifname: + result['parent_ifname'] = parent_ifname + return result return {'dev_type': fields.PciDeviceType.STANDARD}