diff --git a/nova/pci/devspec.py b/nova/pci/devspec.py index 8346367596b8..9f05c33df0a0 100644 --- a/nova/pci/devspec.py +++ b/nova/pci/devspec.py @@ -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): diff --git a/nova/tests/unit/pci/test_devspec.py b/nova/tests/unit/pci/test_devspec.py index 6d91b3be5cc3..2aabbf2bc027 100644 --- a/nova/tests/unit/pci/test_devspec.py +++ b/nova/tests/unit/pci/test_devspec.py @@ -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):