diff --git a/nova/tests/fixtures/libvirt.py b/nova/tests/fixtures/libvirt.py index b74c13fb5a41..dd161b1d7000 100644 --- a/nova/tests/fixtures/libvirt.py +++ b/nova/tests/fixtures/libvirt.py @@ -519,7 +519,7 @@ class HostPCIDevicesInfo(object): def __init__(self, num_pci=0, num_pfs=2, num_vfs=8, num_mdevcap=0, numa_node=None, multiple_gpu_types=False, - generic_types=False): + generic_types=False, bus=0x81, product_ids=["1515"]): """Create a new HostPCIDevicesInfo object. :param num_pci: (int) The number of (non-SR-IOV) and (non-MDEV capable) @@ -533,6 +533,14 @@ class HostPCIDevicesInfo(object): split between ``$TOTAL_NUMA_NODES`` nodes. :param multiple_gpu_types: (bool) Supports different vGPU types :param generic_types: (bool) Supports both nvidia-12 and mlx5 types + :param bus: (int) PCI bus number, allow to specify a different bus to + have an asymmetric configuration between src and dst computes. + :param product_ids: (list) List of product IDs. + Warning: This multiplies the number of PF and VF devices + by the number of product IDs. It creates separate sets of VF + devices, one for each product ID. + The first set is assigned to slot 0, and each subsequent set + is assigned to the next slot incrementally. """ self.devices = {} @@ -545,7 +553,7 @@ class HostPCIDevicesInfo(object): if num_pfs and num_vfs % num_pfs: raise ValueError('num_vfs must be a factor of num_pfs') - bus = 0x81 + bus = bus slot = 0x0 function = 0 iommu_group = 40 # totally arbitrary number @@ -581,41 +589,43 @@ class HostPCIDevicesInfo(object): vf_ratio = num_vfs // num_pfs if num_pfs else 0 # Generate PFs - for dev in range(num_pfs): - function = 0 - numa_node_pf = self._calc_numa_node(dev, numa_node) - - self.add_device( - dev_type='PF', - bus=bus, - slot=slot, - function=function, - iommu_group=iommu_group, - numa_node=numa_node_pf, - vf_ratio=vf_ratio) - - parent = (bus, slot, function) - # Generate VFs - for _ in range(vf_ratio): - function += 1 - iommu_group += 1 - - if function % 8 == 0: - # functions must be 0-7 - slot += 1 - function = 0 + for prod_id in product_ids: + for dev in range(num_pfs): + function = 0 + numa_node_pf = self._calc_numa_node(dev, numa_node) self.add_device( - dev_type='VF', + dev_type='PF', bus=bus, slot=slot, function=function, iommu_group=iommu_group, numa_node=numa_node_pf, - vf_ratio=vf_ratio, - parent=parent) + vf_ratio=vf_ratio) - slot += 1 + parent = (bus, slot, function) + # Generate VFs + for _ in range(vf_ratio): + function += 1 + iommu_group += 1 + + if function % 8 == 0: + # functions must be 0-7 + slot += 1 + function = 0 + + self.add_device( + dev_type='VF', + bus=bus, + prod_id=prod_id, + slot=slot, + function=function, + iommu_group=iommu_group, + numa_node=numa_node_pf, + vf_ratio=vf_ratio, + parent=parent) + + slot += 1 def add_device( self, dev_type, bus, slot, function, iommu_group, numa_node, @@ -952,6 +962,23 @@ def _parse_nic_info(element): return nic_info +def _parse_hostdev_info(element): + hostdev_info = {} + hostdev_info['type'] = element.get('type', 'pci') + hostdev_info['managed'] = element.get('managed', 'pci') + + source = element.find('./source') + if source is not None: + address = source.find('./address') + if address is not None: + hostdev_info['domain'] = address.get('domain') + hostdev_info['bus'] = address.get('bus') + hostdev_info['slot'] = address.get('slot') + hostdev_info['function'] = address.get('function') + + return hostdev_info + + def disable_event_thread(self): """Disable nova libvirt driver event thread. @@ -1252,6 +1279,8 @@ class Domain(object): 'model': hostdev.get('model'), 'address_uuid': address.get('uuid') }) + if dev_type == 'pci': + hostdev_info.append(_parse_hostdev_info(hostdev)) devices['hostdevs'] = hostdev_info vpmem_info = [] @@ -1384,11 +1413,12 @@ class Domain(object): nic_info['_attached'] = True self._def['devices']['nics'] += [nic_info] result = True + elif xml.startswith(" + if hostdev['type'] == 'mdev': + hostdevs += '''
+ + ''' % hostdev # noqa + if hostdev['type'] == 'pci': + hostdevs += ''' + +
+ ''' % hostdev # noqa diff --git a/nova/tests/functional/libvirt/test_pci_sriov_servers.py b/nova/tests/functional/libvirt/test_pci_sriov_servers.py index 37b0c645012c..458cd7b2bb14 100644 --- a/nova/tests/functional/libvirt/test_pci_sriov_servers.py +++ b/nova/tests/functional/libvirt/test_pci_sriov_servers.py @@ -1160,8 +1160,15 @@ class SRIOVServersTest(_PCIServersWithMigrationTestBase): pf_port['binding:profile'], ) - # now live migrate that server - self._live_migrate(server, 'completed') + # By mocking threading.Event.wait we prevent the test to wait until the + # timeout happens. + # We return True signalling that the event is set, i.e. the libvirt + # event the caller is waiting for has been received. + # Note: This mock behavior cannot be added to the fixture because + # many unit tests rely on it for different side effects. + with mock.patch("threading.Event.wait", side_effect=[True]): + # now live migrate that server + self._live_migrate(server, "completed") # we should now have transitioned our usage to the destination, freeing # up the source in the process