]> xenbits.xensource.com Git - osstest/openstack-nova.git/commitdiff
PCI: Fix PCI with fully qualified address
authorLudovic Beliveau <ludovic.beliveau@windriver.com>
Wed, 31 Aug 2016 18:27:43 +0000 (14:27 -0400)
committerLudovic Beliveau <ludovic.beliveau@windriver.com>
Thu, 3 Nov 2016 14:12:37 +0000 (10:12 -0400)
Specifying a PF passthrough device in the pci_passthrough_whitelist using its
fully qualified PCI address (no wildcard) causes the device to not be
properly loaded.  The PCI device is then not available to be assigned to any
guest.

In this case, the hypervisor reports the PF device without a 'parent_addr'.
But in the PciAddress, match() is using it when doing the comparison to its
own address.

This commit changes the logic of the address matching method in PciDevSpec to
only try to match the address with a physical function device when a
'parent_addr' is reported by the hypervisor.

Change-Id: I5255240871d8ad5c216500f39520339efe46e84b
Closes-Bug: #1613434

nova/pci/devspec.py
nova/tests/unit/pci/test_devspec.py

index 8346367596b8111eae3c8f5c25dc1e68ca8ca025..9f05c33df0a0ff93547f188e466505594ba1f151 100644 (file)
@@ -106,25 +106,36 @@ class PciAddress(object):
             self._check_physical_function()
 
     def match(self, pci_addr, pci_phys_addr):
-        # Assume this is called given pci_add and pci_phys_addr from libvirt,
-        # no attempt is made to verify pci_addr is a VF of pci_phys_addr
-        if self.is_physical_function:
-            if not pci_phys_addr:
-                return False
+        """Match a device to this PciAddress.  Assume this is called given
+        pci_addr and pci_phys_addr reported by libvirt, no attempt is made to
+        verify if pci_addr is a VF of pci_phys_addr.
+
+        :param pci_addr: PCI address of the device to match.
+        :param pci_phys_addr: PCI address of the parent of the device to match
+                              (or None if the device is not a VF).
+        """
+
+        # Try to match on the parent PCI address if the PciDeviceSpec is a
+        # PF (sriov is available) and the device to match is a VF.  This
+        # makes possible to specify the PCI address of a PF in the
+        # pci_passthrough_whitelist to match any of it's VFs PCI devices.
+        if self.is_physical_function and pci_phys_addr:
             domain, bus, slot, func = (
                 utils.get_pci_address_fields(pci_phys_addr))
-            return (self.domain == domain and self.bus == bus and
-                    self.slot == slot and self.func == func)
-        else:
-            domain, bus, slot, func = (
-                utils.get_pci_address_fields(pci_addr))
-            conditions = [
-                self.domain in (ANY, domain),
-                self.bus in (ANY, bus),
-                self.slot in (ANY, slot),
-                self.func in (ANY, func)
-            ]
-            return all(conditions)
+            if (self.domain == domain and self.bus == bus and
+                    self.slot == slot and self.func == func):
+                return True
+
+        # Try to match on the device PCI address only.
+        domain, bus, slot, func = (
+            utils.get_pci_address_fields(pci_addr))
+        conditions = [
+            self.domain in (ANY, domain),
+            self.bus in (ANY, bus),
+            self.slot in (ANY, slot),
+            self.func in (ANY, func)
+        ]
+        return all(conditions)
 
 
 class PciDeviceSpec(object):
index 6d91b3be5cc3da23f55e0218d1f38f9342e00544..2aabbf2bc027cda59d7d67edb6e869cd9915066c 100644 (file)
@@ -22,7 +22,7 @@ from nova import test
 
 dev = {"vendor_id": "8086",
        "product_id": "5057",
-       "address": "1234:5678:8988.5",
+       "address": "0000:0b:00.5",
        "parent_addr": "0000:0a:00.0"}
 
 
@@ -95,12 +95,20 @@ class PciAddressTestCase(test.NoDBTestCase):
                "parent_addr": "0000:0a:00.0"}
         self.assertTrue(pci.match(dev))
 
-    @mock.patch('nova.pci.utils.is_physical_function', return_value = True)
+    @mock.patch('nova.pci.utils.is_physical_function', return_value=True)
     def test_address_is_pf(self, mock_is_physical_function):
         pci_info = {"address": "0000:0a:00.0", "physical_network": "hr_net"}
         pci = devspec.PciDeviceSpec(pci_info)
         self.assertTrue(pci.match(dev))
 
+    @mock.patch('nova.pci.utils.is_physical_function', return_value=True)
+    def test_address_pf_no_parent_addr(self, mock_is_physical_function):
+        _dev = dev.copy()
+        _dev.pop('parent_addr')
+        pci_info = {"address": "0000:0b:00.5", "physical_network": "hr_net"}
+        pci = devspec.PciDeviceSpec(pci_info)
+        self.assertTrue(pci.match(_dev))
+
 
 class PciDevSpecTestCase(test.NoDBTestCase):
     def test_spec_match(self):