diff --git a/nova/objects/pci_device.py b/nova/objects/pci_device.py index 2119a9ccdcc0..bf5fac68b04e 100644 --- a/nova/objects/pci_device.py +++ b/nova/objects/pci_device.py @@ -354,7 +354,9 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject): self._bulk_update_status(vfs_list, fields.PciDeviceStatus.UNCLAIMABLE) - elif self.dev_type == fields.PciDeviceType.SRIOV_VF: + elif self.dev_type in ( + fields.PciDeviceType.SRIOV_VF, fields.PciDeviceType.VDPA + ): # Update VF status to CLAIMED if it's parent has not been # previously allocated or claimed # When claiming/allocating a VF, it's parent PF becomes @@ -414,7 +416,9 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject): self._bulk_update_status(vfs_list, fields.PciDeviceStatus.UNAVAILABLE) - elif (self.dev_type == fields.PciDeviceType.SRIOV_VF): + elif self.dev_type in ( + fields.PciDeviceType.SRIOV_VF, fields.PciDeviceType.VDPA + ): parent = self.parent_device if parent: if parent.status not in parent_ok_statuses: @@ -473,7 +477,9 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject): self._bulk_update_status(vfs_list, fields.PciDeviceStatus.AVAILABLE) free_devs.extend(vfs_list) - if self.dev_type == fields.PciDeviceType.SRIOV_VF: + if self.dev_type in ( + fields.PciDeviceType.SRIOV_VF, fields.PciDeviceType.VDPA + ): # Set PF status to AVAILABLE if all of it's VFs are free parent = self.parent_device if not parent: diff --git a/nova/pci/manager.py b/nova/pci/manager.py index 9ce50f5d9f01..b124b994d845 100644 --- a/nova/pci/manager.py +++ b/nova/pci/manager.py @@ -189,7 +189,9 @@ class PciDevTracker(object): if dev.dev_type == fields.PciDeviceType.SRIOV_PF: dev.child_devices = [] parents[dev.address] = dev - elif dev.dev_type == fields.PciDeviceType.SRIOV_VF: + elif dev.dev_type in ( + fields.PciDeviceType.SRIOV_VF, fields.PciDeviceType.VDPA + ): dev.parent_device = parents.get(dev.parent_addr) if dev.parent_device: parents[dev.parent_addr].child_devices.append(dev) diff --git a/nova/pci/request.py b/nova/pci/request.py index 5a9c08232d6f..1924925c5530 100644 --- a/nova/pci/request.py +++ b/nova/pci/request.py @@ -56,7 +56,8 @@ PCI_TRUSTED_TAG = 'trusted' PCI_DEVICE_TYPE_TAG = 'dev_type' DEVICE_TYPE_FOR_VNIC_TYPE = { - network_model.VNIC_TYPE_DIRECT_PHYSICAL: obj_fields.PciDeviceType.SRIOV_PF + network_model.VNIC_TYPE_DIRECT_PHYSICAL: obj_fields.PciDeviceType.SRIOV_PF, + network_model.VNIC_TYPE_VDPA: obj_fields.PciDeviceType.VDPA, } CONF = nova.conf.CONF diff --git a/nova/pci/stats.py b/nova/pci/stats.py index 937c130dc8be..bac61dae7b82 100644 --- a/nova/pci/stats.py +++ b/nova/pci/stats.py @@ -217,15 +217,18 @@ class PciDeviceStats(object): In case the device is a PF, all of it's dependent VFs should be removed from pools count, if these are present. - When the device is a VF, it's parent PF pool count should be - decreased, unless it is no longer in a pool. + When the device is a VF, or a VDPA device, it's parent PF + pool count should be decreased, unless it is no longer in a pool. """ if pci_dev.dev_type == fields.PciDeviceType.SRIOV_PF: vfs_list = pci_dev.child_devices if vfs_list: for vf in vfs_list: self.remove_device(vf) - elif pci_dev.dev_type == fields.PciDeviceType.SRIOV_VF: + elif pci_dev.dev_type in ( + fields.PciDeviceType.SRIOV_VF, + fields.PciDeviceType.VDPA, + ): try: parent = pci_dev.parent_device # Make sure not to decrease PF pool count if this parent has @@ -387,6 +390,28 @@ class PciDeviceStats(object): ] return pools + def _filter_pools_for_unrequested_vdpa_devices(self, pools, request): + """Filter out pools with VDPA devices, unless these are required. + + This is necessary as vdpa devices require special handling and + should not be allocated to generic pci device requests. + + :param pools: A list of PCI device pool dicts + :param request: An InstancePCIRequest object describing the type, + quantity and required NUMA affinity of device(s) we want. + :returns: A list of pools that can be used to support the request if + this is possible. + """ + if all( + spec.get('dev_type') != fields.PciDeviceType.VDPA + for spec in request.spec + ): + pools = [ + pool for pool in pools + if not pool.get('dev_type') == fields.PciDeviceType.VDPA + ] + return pools + def _filter_pools(self, pools, request, numa_cells): """Determine if an individual PCI request can be met. @@ -421,7 +446,7 @@ class PciDeviceStats(object): ) if after_count < request.count: - LOG.debug('Not enough PCI devices left to satify request') + LOG.debug('Not enough PCI devices left to satisfy request') return None # Next, let's exclude all devices that aren't on the correct NUMA node @@ -438,10 +463,10 @@ class PciDeviceStats(object): ) if after_count < request.count: - LOG.debug('Not enough PCI devices left to satify request') + LOG.debug('Not enough PCI devices left to satisfy request') return None - # Finally, if we're not requesting PFs then we should not use these. + # If we're not requesting PFs then we should not use these. # Exclude them. before_count = after_count pools = self._filter_pools_for_unrequested_pfs(pools, request) @@ -455,7 +480,24 @@ class PciDeviceStats(object): ) if after_count < request.count: - LOG.debug('Not enough PCI devices left to satify request') + LOG.debug('Not enough PCI devices left to satisfy request') + return None + + # If we're not requesting VDPA devices then we should not use these + # either. Exclude them. + before_count = after_count + pools = self._filter_pools_for_unrequested_vdpa_devices(pools, request) + after_count = sum([pool['count'] for pool in pools]) + + if after_count < before_count: + LOG.debug( + 'Dropped %d devices as they are VDPA devices which we have ' + 'not requested', + before_count - after_count + ) + + if after_count < request.count: + LOG.debug('Not enough PCI devices left to satisfy request') return None return pools diff --git a/nova/tests/unit/network/test_neutron.py b/nova/tests/unit/network/test_neutron.py index b039c75b26a6..5ec7ff3de89b 100644 --- a/nova/tests/unit/network/test_neutron.py +++ b/nova/tests/unit/network/test_neutron.py @@ -5772,7 +5772,8 @@ class TestAPI(TestAPIBase): objects.NetworkRequest(port_id=uuids.portid_3), objects.NetworkRequest(port_id=uuids.portid_4), objects.NetworkRequest(port_id=uuids.portid_5), - objects.NetworkRequest(port_id=uuids.trusted_port)]) + objects.NetworkRequest(port_id=uuids.trusted_port), + objects.NetworkRequest(port_id=uuids.portid_vdpa)]) pci_requests = objects.InstancePCIRequests(requests=[]) # _get_port_vnic_info should be called for every NetworkRequest with a # port_id attribute (so six times) @@ -5785,13 +5786,14 @@ class TestAPI(TestAPIBase): (model.VNIC_TYPE_DIRECT_PHYSICAL, None, 'netN', None, None), (model.VNIC_TYPE_DIRECT, True, 'netN', mock.sentinel.resource_request2, None), + (model.VNIC_TYPE_VDPA, None, 'netN', None, None), ] # _get_physnet_tunneled_info should be called for every NetworkRequest # (so seven times) mock_get_physnet_tunneled_info.side_effect = [ ('physnet1', False), ('physnet1', False), ('', True), ('physnet1', False), ('physnet2', False), ('physnet3', False), - ('physnet4', False), + ('physnet4', False), ('physnet1', False) ] api = neutronapi.API() @@ -5808,12 +5810,13 @@ class TestAPI(TestAPIBase): mock.sentinel.request_group1, mock.sentinel.request_group2], port_resource_requests) - self.assertEqual(5, len(pci_requests.requests)) + self.assertEqual(6, len(pci_requests.requests)) has_pci_request_id = [net.pci_request_id is not None for net in requested_networks.objects] self.assertEqual(pci_requests.requests[3].spec[0]["dev_type"], "type-PF") - expected_results = [True, False, False, True, True, True, True] + self.assertEqual(pci_requests.requests[5].spec[0]["dev_type"], "vdpa") + expected_results = [True, False, False, True, True, True, True, True] self.assertEqual(expected_results, has_pci_request_id) # Make sure only the trusted VF has the 'trusted' tag set in the spec. for pci_req in pci_requests.requests: @@ -5827,7 +5830,7 @@ class TestAPI(TestAPIBase): # Only the port with a resource_request will have pci_req.requester_id. self.assertEqual( - [None, None, None, None, uuids.trusted_port], + [None, None, None, None, uuids.trusted_port, None], [pci_req.requester_id for pci_req in pci_requests.requests]) self.assertCountEqual( diff --git a/nova/tests/unit/objects/test_pci_device.py b/nova/tests/unit/objects/test_pci_device.py index 845333622ca9..baf8d4797b19 100644 --- a/nova/tests/unit/objects/test_pci_device.py +++ b/nova/tests/unit/objects/test_pci_device.py @@ -523,18 +523,20 @@ class TestPciDeviceListObjectRemote(test_objects._RemoteTest, class _TestSRIOVPciDeviceObject(object): def _create_pci_devices(self, vf_product_id=1515, pf_product_id=1528, - num_pfs=2, num_vfs=8): + num_pfs=2, num_vfs=8, num_vdpa=0): self.sriov_pf_devices = [] for dev in range(num_pfs): - pci_dev = {'compute_node_id': 1, - 'address': '0000:81:00.%d' % dev, - 'vendor_id': '8086', - 'product_id': '%d' % pf_product_id, - 'status': 'available', - 'request_id': None, - 'dev_type': fields.PciDeviceType.SRIOV_PF, - 'parent_addr': None, - 'numa_node': 0} + pci_dev = { + 'compute_node_id': 1, + 'address': '0000:81:00.%d' % dev, + 'vendor_id': '8086', + 'product_id': '%d' % pf_product_id, + 'status': 'available', + 'request_id': None, + 'dev_type': fields.PciDeviceType.SRIOV_PF, + 'parent_addr': None, + 'numa_node': 0 + } pci_dev_obj = objects.PciDevice.create(None, pci_dev) pci_dev_obj.id = dev + 81 pci_dev_obj.child_devices = [] @@ -542,21 +544,42 @@ class _TestSRIOVPciDeviceObject(object): self.sriov_vf_devices = [] for dev in range(num_vfs): - pci_dev = {'compute_node_id': 1, - 'address': '0000:81:10.%d' % dev, - 'vendor_id': '8086', - 'product_id': '%d' % vf_product_id, - 'status': 'available', - 'request_id': None, - 'dev_type': fields.PciDeviceType.SRIOV_VF, - 'parent_addr': '0000:81:00.%d' % int(dev / 4), - 'numa_node': 0} + pci_dev = { + 'compute_node_id': 1, + 'address': '0000:81:10.%d' % dev, + 'vendor_id': '8086', + 'product_id': '%d' % vf_product_id, + 'status': 'available', + 'request_id': None, + 'dev_type': fields.PciDeviceType.SRIOV_VF, + 'parent_addr': '0000:81:00.%d' % int(dev / 4), + 'numa_node': 0 + } pci_dev_obj = objects.PciDevice.create(None, pci_dev) pci_dev_obj.id = dev + 1 pci_dev_obj.parent_device = self.sriov_pf_devices[int(dev / 4)] pci_dev_obj.parent_device.child_devices.append(pci_dev_obj) self.sriov_vf_devices.append(pci_dev_obj) + self.sriov_vdpa_devices = [] + for dev in range(num_vdpa): + pci_dev = { + 'compute_node_id': 1, + 'address': '0000:81:11.%d' % dev, + 'vendor_id': '8086', + 'product_id': '%d' % vf_product_id, + 'status': 'available', + 'request_id': None, + 'dev_type': fields.PciDeviceType.VDPA, + 'parent_addr': '0000:81:00.%d' % (dev % num_pfs), + 'numa_node': 0 + } + pci_dev_obj = objects.PciDevice.create(None, pci_dev) + pci_dev_obj.id = dev + 1 + pci_dev_obj.parent_device = self.sriov_pf_devices[dev % num_pfs] + pci_dev_obj.parent_device.child_devices.append(pci_dev_obj) + self.sriov_vdpa_devices.append(pci_dev_obj) + def _create_fake_instance(self): self.inst = instance.Instance() self.inst.uuid = uuids.instance @@ -587,26 +610,35 @@ class _TestSRIOVPciDeviceObject(object): self._create_pci_devices() devobj = self.sriov_pf_devices[0] devobj.claim(self.inst.uuid) - self.assertEqual(devobj.status, - fields.PciDeviceStatus.CLAIMED) - self.assertEqual(devobj.instance_uuid, - self.inst.uuid) + self.assertEqual(devobj.status, fields.PciDeviceStatus.CLAIMED) + self.assertEqual(devobj.instance_uuid, self.inst.uuid) self.assertEqual(len(self.inst.pci_devices), 0) # check if the all the dependants are UNCLAIMABLE self.assertTrue(all( - [dev.status == fields.PciDeviceStatus.UNCLAIMABLE for - dev in self._get_children_by_parent_address( - self.sriov_pf_devices[0].address)])) + [dev.status == fields.PciDeviceStatus.UNCLAIMABLE for + dev in self._get_children_by_parent_address( + self.sriov_pf_devices[0].address)])) def test_claim_VF(self): self._create_fake_instance() self._create_pci_devices() devobj = self.sriov_vf_devices[0] devobj.claim(self.inst.uuid) - self.assertEqual(devobj.status, - fields.PciDeviceStatus.CLAIMED) - self.assertEqual(devobj.instance_uuid, - self.inst.uuid) + self.assertEqual(devobj.status, fields.PciDeviceStatus.CLAIMED) + self.assertEqual(devobj.instance_uuid, self.inst.uuid) + self.assertEqual(len(self.inst.pci_devices), 0) + + # check if parent device status has been changed to UNCLAIMABLE + parent = self._get_parent_by_address(devobj.parent_addr) + self.assertEqual(fields.PciDeviceStatus.UNCLAIMABLE, parent.status) + + def test_claim_VDPA(self): + self._create_fake_instance() + self._create_pci_devices(num_pfs=1, num_vfs=0, num_vdpa=2) + devobj = self.sriov_vdpa_devices[0] + devobj.claim(self.inst.uuid) + self.assertEqual(devobj.status, fields.PciDeviceStatus.CLAIMED) + self.assertEqual(devobj.instance_uuid, self.inst.uuid) self.assertEqual(len(self.inst.pci_devices), 0) # check if parent device status has been changed to UNCLAIMABLE @@ -619,10 +651,8 @@ class _TestSRIOVPciDeviceObject(object): devobj = self.sriov_pf_devices[0] devobj.claim(self.inst.uuid) devobj.allocate(self.inst) - self.assertEqual(devobj.status, - fields.PciDeviceStatus.ALLOCATED) - self.assertEqual(devobj.instance_uuid, - self.inst.uuid) + self.assertEqual(devobj.status, fields.PciDeviceStatus.ALLOCATED) + self.assertEqual(devobj.instance_uuid, self.inst.uuid) self.assertEqual(len(self.inst.pci_devices), 1) # check if the all the dependants are UNAVAILABLE self.assertTrue(all( @@ -636,10 +666,22 @@ class _TestSRIOVPciDeviceObject(object): devobj = self.sriov_vf_devices[0] devobj.claim(self.inst.uuid) devobj.allocate(self.inst) - self.assertEqual(devobj.status, - fields.PciDeviceStatus.ALLOCATED) - self.assertEqual(devobj.instance_uuid, - self.inst.uuid) + self.assertEqual(devobj.status, fields.PciDeviceStatus.ALLOCATED) + self.assertEqual(devobj.instance_uuid, self.inst.uuid) + self.assertEqual(len(self.inst.pci_devices), 1) + + # check if parent device status has been changed to UNAVAILABLE + parent = self._get_parent_by_address(devobj.parent_addr) + self.assertEqual(fields.PciDeviceStatus.UNAVAILABLE, parent.status) + + def test_allocate_VDPA(self): + self._create_fake_instance() + self._create_pci_devices(num_pfs=1, num_vfs=0, num_vdpa=2) + devobj = self.sriov_vdpa_devices[0] + devobj.claim(self.inst.uuid) + devobj.allocate(self.inst) + self.assertEqual(devobj.status, fields.PciDeviceStatus.ALLOCATED) + self.assertEqual(devobj.instance_uuid, self.inst.uuid) self.assertEqual(len(self.inst.pci_devices), 1) # check if parent device status has been changed to UNAVAILABLE @@ -652,8 +694,17 @@ class _TestSRIOVPciDeviceObject(object): devobj = self.sriov_pf_devices[0] self.sriov_vf_devices[0].status = fields.PciDeviceStatus.CLAIMED - self.assertRaises(exception.PciDeviceVFInvalidStatus, - devobj.claim, self.inst) + self.assertRaises( + exception.PciDeviceVFInvalidStatus, devobj.claim, self.inst) + + def test_claim_PF_fail_VDPA(self): + self._create_fake_instance() + self._create_pci_devices(num_pfs=1, num_vfs=0, num_vdpa=2) + devobj = self.sriov_pf_devices[0] + self.sriov_vdpa_devices[0].status = fields.PciDeviceStatus.CLAIMED + + self.assertRaises( + exception.PciDeviceVFInvalidStatus, devobj.claim, self.inst) def test_claim_VF_fail(self): self._create_fake_instance() @@ -662,8 +713,17 @@ class _TestSRIOVPciDeviceObject(object): parent = self._get_parent_by_address(devobj.parent_addr) parent.status = fields.PciDeviceStatus.CLAIMED - self.assertRaises(exception.PciDevicePFInvalidStatus, - devobj.claim, self.inst) + self.assertRaises( + exception.PciDevicePFInvalidStatus, devobj.claim, self.inst) + + def test_claim_VDPA_fail(self): + self._create_fake_instance() + self._create_pci_devices(num_pfs=1, num_vfs=0, num_vdpa=2) + devobj = self.sriov_vdpa_devices[0] + parent = self._get_parent_by_address(devobj.parent_addr) + parent.status = fields.PciDeviceStatus.CLAIMED + self.assertRaises( + exception.PciDevicePFInvalidStatus, devobj.claim, self.inst) def test_allocate_PF_fail(self): self._create_fake_instance() @@ -671,8 +731,8 @@ class _TestSRIOVPciDeviceObject(object): devobj = self.sriov_pf_devices[0] self.sriov_vf_devices[0].status = fields.PciDeviceStatus.CLAIMED - self.assertRaises(exception.PciDeviceVFInvalidStatus, - devobj.allocate, self.inst) + self.assertRaises( + exception.PciDeviceVFInvalidStatus, devobj.allocate, self.inst) def test_allocate_VF_fail(self): self._create_fake_instance() @@ -681,8 +741,27 @@ class _TestSRIOVPciDeviceObject(object): parent = self._get_parent_by_address(devobj.parent_addr) parent.status = fields.PciDeviceStatus.CLAIMED - self.assertRaises(exception.PciDevicePFInvalidStatus, - devobj.allocate, self.inst) + self.assertRaises( + exception.PciDevicePFInvalidStatus, devobj.allocate, self.inst) + + def test_allocate_PF_fail_VDPA(self): + self._create_fake_instance() + self._create_pci_devices(num_pfs=1, num_vfs=0, num_vdpa=2) + devobj = self.sriov_pf_devices[0] + self.sriov_vdpa_devices[0].status = fields.PciDeviceStatus.CLAIMED + + self.assertRaises( + exception.PciDeviceVFInvalidStatus, devobj.allocate, self.inst) + + def test_allocate_VDPA_fail(self): + self._create_fake_instance() + self._create_pci_devices(num_pfs=1, num_vfs=0, num_vdpa=2) + devobj = self.sriov_vdpa_devices[0] + parent = self._get_parent_by_address(devobj.parent_addr) + parent.status = fields.PciDeviceStatus.CLAIMED + + self.assertRaises( + exception.PciDevicePFInvalidStatus, devobj.allocate, self.inst) def test_free_allocated_PF(self): self._create_fake_instance() @@ -691,14 +770,13 @@ class _TestSRIOVPciDeviceObject(object): devobj.claim(self.inst.uuid) devobj.allocate(self.inst) devobj.free(self.inst) - self.assertEqual(devobj.status, - fields.PciDeviceStatus.AVAILABLE) + self.assertEqual(devobj.status, fields.PciDeviceStatus.AVAILABLE) self.assertIsNone(devobj.instance_uuid) # check if the all the dependants are AVAILABLE self.assertTrue(all( - [dev.status == fields.PciDeviceStatus.AVAILABLE for - dev in self._get_children_by_parent_address( - self.sriov_pf_devices[0].address)])) + [dev.status == fields.PciDeviceStatus.AVAILABLE for + dev in self._get_children_by_parent_address( + self.sriov_pf_devices[0].address)])) def test_free_allocated_VF(self): self._create_fake_instance() @@ -708,20 +786,41 @@ class _TestSRIOVPciDeviceObject(object): for devobj in dependents: devobj.claim(self.inst.uuid) devobj.allocate(self.inst) - self.assertEqual(devobj.status, - fields.PciDeviceStatus.ALLOCATED) + self.assertEqual(devobj.status, fields.PciDeviceStatus.ALLOCATED) for devobj in dependents[:-1]: devobj.free(self.inst) # check if parent device status is still UNAVAILABLE parent = self._get_parent_by_address(devobj.parent_addr) - self.assertEqual(fields.PciDeviceStatus.UNAVAILABLE, - parent.status) + self.assertEqual( + fields.PciDeviceStatus.UNAVAILABLE, parent.status) devobj = dependents[-1] devobj.free(self.inst) # check if parent device status is now AVAILABLE parent = self._get_parent_by_address(devobj.parent_addr) - self.assertEqual(fields.PciDeviceStatus.AVAILABLE, - parent.status) + self.assertEqual( + fields.PciDeviceStatus.AVAILABLE, parent.status) + + def test_free_allocated_VDPA(self): + self._create_fake_instance() + self._create_pci_devices(num_pfs=2, num_vfs=0, num_vdpa=8) + vdpa = self.sriov_vdpa_devices[0] + dependents = self._get_children_by_parent_address(vdpa.parent_addr) + for devobj in dependents: + devobj.claim(self.inst.uuid) + devobj.allocate(self.inst) + self.assertEqual(devobj.status, fields.PciDeviceStatus.ALLOCATED) + for devobj in dependents[:-1]: + devobj.free(self.inst) + # check if parent device status is still UNAVAILABLE + parent = self._get_parent_by_address(devobj.parent_addr) + self.assertEqual( + fields.PciDeviceStatus.UNAVAILABLE, parent.status) + for devobj in dependents[-1:]: + devobj.free(self.inst) + # check if parent device status is now AVAILABLE + parent = self._get_parent_by_address(devobj.parent_addr) + self.assertEqual( + fields.PciDeviceStatus.AVAILABLE, parent.status) class TestSRIOVPciDeviceListObject(test_objects._LocalTest, diff --git a/nova/tests/unit/pci/test_stats.py b/nova/tests/unit/pci/test_stats.py index c87a171a505a..394a07f9ebf8 100644 --- a/nova/tests/unit/pci/test_stats.py +++ b/nova/tests/unit/pci/test_stats.py @@ -629,37 +629,75 @@ class PciDeviceVFPFStatsTestCase(test.NoDBTestCase): def _create_pci_devices(self, vf_product_id=1515, pf_product_id=1528): self.sriov_pf_devices = [] for dev in range(2): - pci_dev = {'compute_node_id': 1, - 'address': '0000:81:00.%d' % dev, - 'vendor_id': '8086', - 'product_id': '%d' % pf_product_id, - 'status': 'available', - 'request_id': None, - 'dev_type': fields.PciDeviceType.SRIOV_PF, - 'parent_addr': None, - 'numa_node': 0} + pci_dev = { + 'compute_node_id': 1, + 'address': '0000:81:00.%d' % dev, + 'vendor_id': '8086', + 'product_id': '%d' % pf_product_id, + 'status': 'available', + 'request_id': None, + 'dev_type': fields.PciDeviceType.SRIOV_PF, + 'parent_addr': None, + 'numa_node': 0 + } dev_obj = objects.PciDevice.create(None, pci_dev) dev_obj.child_devices = [] self.sriov_pf_devices.append(dev_obj) self.sriov_vf_devices = [] for dev in range(8): - pci_dev = {'compute_node_id': 1, - 'address': '0000:81:10.%d' % dev, - 'vendor_id': '8086', - 'product_id': '%d' % vf_product_id, - 'status': 'available', - 'request_id': None, - 'dev_type': fields.PciDeviceType.SRIOV_VF, - 'parent_addr': '0000:81:00.%d' % int(dev / 4), - 'numa_node': 0} + pci_dev = { + 'compute_node_id': 1, + 'address': '0000:81:10.%d' % dev, + 'vendor_id': '8086', + 'product_id': '%d' % vf_product_id, + 'status': 'available', + 'request_id': None, + 'dev_type': fields.PciDeviceType.SRIOV_VF, + 'parent_addr': '0000:81:00.%d' % int(dev / 4), + 'numa_node': 0 + } dev_obj = objects.PciDevice.create(None, pci_dev) dev_obj.parent_device = self.sriov_pf_devices[int(dev / 4)] dev_obj.parent_device.child_devices.append(dev_obj) self.sriov_vf_devices.append(dev_obj) + self.vdpa_devices = [] + for dev in range(8): + pci_dev = { + 'compute_node_id': 1, + 'address': '0000:82:10.%d' % dev, + 'vendor_id': '8086', + 'product_id': '%d' % vf_product_id, + 'status': 'available', + 'request_id': None, + 'dev_type': fields.PciDeviceType.VDPA, + 'parent_addr': '0000:81:00.%d' % int(dev / 4), + 'numa_node': 0 + } + dev_obj = objects.PciDevice.create(None, pci_dev) + dev_obj.parent_device = self.sriov_pf_devices[int(dev / 4)] + dev_obj.parent_device.child_devices.append(dev_obj) + self.vdpa_devices.append(dev_obj) + list(map(self.pci_stats.add_device, self.sriov_pf_devices)) list(map(self.pci_stats.add_device, self.sriov_vf_devices)) + list(map(self.pci_stats.add_device, self.vdpa_devices)) + + def test_consume_VDPA_requests(self): + self._create_pci_devices() + pci_requests = [ + objects.InstancePCIRequest( + count=8, spec=[{'dev_type': 'vdpa'}])] + devs = self.pci_stats.consume_requests(pci_requests) + self.assertEqual(8, len(devs)) + self.assertEqual('vdpa', devs[0].dev_type) + free_devs = self.pci_stats.get_free_devs() + # Validate that the parents of these devs has been removed + # from pools. + for dev in devs: + self.assertNotIn(dev.parent_addr, + [free_dev.address for free_dev in free_devs]) def test_consume_VF_requests(self): self._create_pci_devices()