From 97a806b7900d9e55ad15c10184d2bd48f23efff0 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 (cherry picked from commit e7ae6c65cd24fb3e0776fac80fbab2ab16e9d9ed) --- 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 a3208facf2e7..abdd0943233e 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 608ac874296c..83f11ea933cf 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -6013,13 +6013,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}