Merge "pci: Add vDPA vnic to PCI request mapping and filtering"

This commit is contained in:
Zuul 2021-03-17 18:06:41 +00:00 committed by Gerrit Code Review
commit b7334b5089
7 changed files with 283 additions and 92 deletions

View File

@ -354,7 +354,9 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject):
self._bulk_update_status(vfs_list, self._bulk_update_status(vfs_list,
fields.PciDeviceStatus.UNCLAIMABLE) 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 # Update VF status to CLAIMED if it's parent has not been
# previously allocated or claimed # previously allocated or claimed
# When claiming/allocating a VF, it's parent PF becomes # 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, self._bulk_update_status(vfs_list,
fields.PciDeviceStatus.UNAVAILABLE) 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 parent = self.parent_device
if parent: if parent:
if parent.status not in parent_ok_statuses: if parent.status not in parent_ok_statuses:
@ -473,7 +477,9 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject):
self._bulk_update_status(vfs_list, self._bulk_update_status(vfs_list,
fields.PciDeviceStatus.AVAILABLE) fields.PciDeviceStatus.AVAILABLE)
free_devs.extend(vfs_list) 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 # Set PF status to AVAILABLE if all of it's VFs are free
parent = self.parent_device parent = self.parent_device
if not parent: if not parent:

View File

@ -189,7 +189,9 @@ class PciDevTracker(object):
if dev.dev_type == fields.PciDeviceType.SRIOV_PF: if dev.dev_type == fields.PciDeviceType.SRIOV_PF:
dev.child_devices = [] dev.child_devices = []
parents[dev.address] = dev 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) dev.parent_device = parents.get(dev.parent_addr)
if dev.parent_device: if dev.parent_device:
parents[dev.parent_addr].child_devices.append(dev) parents[dev.parent_addr].child_devices.append(dev)

View File

@ -56,7 +56,8 @@ PCI_TRUSTED_TAG = 'trusted'
PCI_DEVICE_TYPE_TAG = 'dev_type' PCI_DEVICE_TYPE_TAG = 'dev_type'
DEVICE_TYPE_FOR_VNIC_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 CONF = nova.conf.CONF

View File

@ -217,15 +217,18 @@ class PciDeviceStats(object):
In case the device is a PF, all of it's dependent VFs should In case the device is a PF, all of it's dependent VFs should
be removed from pools count, if these are present. be removed from pools count, if these are present.
When the device is a VF, it's parent PF pool count should be When the device is a VF, or a VDPA device, it's parent PF
decreased, unless it is no longer in a pool. pool count should be decreased, unless it is no longer in a pool.
""" """
if pci_dev.dev_type == fields.PciDeviceType.SRIOV_PF: if pci_dev.dev_type == fields.PciDeviceType.SRIOV_PF:
vfs_list = pci_dev.child_devices vfs_list = pci_dev.child_devices
if vfs_list: if vfs_list:
for vf in vfs_list: for vf in vfs_list:
self.remove_device(vf) 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: try:
parent = pci_dev.parent_device parent = pci_dev.parent_device
# Make sure not to decrease PF pool count if this parent has # Make sure not to decrease PF pool count if this parent has
@ -387,6 +390,28 @@ class PciDeviceStats(object):
] ]
return pools 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): def _filter_pools(self, pools, request, numa_cells):
"""Determine if an individual PCI request can be met. """Determine if an individual PCI request can be met.
@ -421,7 +446,7 @@ class PciDeviceStats(object):
) )
if after_count < request.count: 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 return None
# Next, let's exclude all devices that aren't on the correct NUMA node # 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: 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 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. # Exclude them.
before_count = after_count before_count = after_count
pools = self._filter_pools_for_unrequested_pfs(pools, request) pools = self._filter_pools_for_unrequested_pfs(pools, request)
@ -455,7 +480,24 @@ class PciDeviceStats(object):
) )
if after_count < request.count: 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 None
return pools return pools

View File

@ -5772,7 +5772,8 @@ class TestAPI(TestAPIBase):
objects.NetworkRequest(port_id=uuids.portid_3), objects.NetworkRequest(port_id=uuids.portid_3),
objects.NetworkRequest(port_id=uuids.portid_4), objects.NetworkRequest(port_id=uuids.portid_4),
objects.NetworkRequest(port_id=uuids.portid_5), 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=[]) pci_requests = objects.InstancePCIRequests(requests=[])
# _get_port_vnic_info should be called for every NetworkRequest with a # _get_port_vnic_info should be called for every NetworkRequest with a
# port_id attribute (so six times) # 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_PHYSICAL, None, 'netN', None, None),
(model.VNIC_TYPE_DIRECT, True, 'netN', (model.VNIC_TYPE_DIRECT, True, 'netN',
mock.sentinel.resource_request2, None), mock.sentinel.resource_request2, None),
(model.VNIC_TYPE_VDPA, None, 'netN', None, None),
] ]
# _get_physnet_tunneled_info should be called for every NetworkRequest # _get_physnet_tunneled_info should be called for every NetworkRequest
# (so seven times) # (so seven times)
mock_get_physnet_tunneled_info.side_effect = [ mock_get_physnet_tunneled_info.side_effect = [
('physnet1', False), ('physnet1', False), ('', True), ('physnet1', False), ('physnet1', False), ('', True),
('physnet1', False), ('physnet2', False), ('physnet3', False), ('physnet1', False), ('physnet2', False), ('physnet3', False),
('physnet4', False), ('physnet4', False), ('physnet1', False)
] ]
api = neutronapi.API() api = neutronapi.API()
@ -5808,12 +5810,13 @@ class TestAPI(TestAPIBase):
mock.sentinel.request_group1, mock.sentinel.request_group1,
mock.sentinel.request_group2], mock.sentinel.request_group2],
port_resource_requests) 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 has_pci_request_id = [net.pci_request_id is not None for net in
requested_networks.objects] requested_networks.objects]
self.assertEqual(pci_requests.requests[3].spec[0]["dev_type"], self.assertEqual(pci_requests.requests[3].spec[0]["dev_type"],
"type-PF") "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) self.assertEqual(expected_results, has_pci_request_id)
# Make sure only the trusted VF has the 'trusted' tag set in the spec. # Make sure only the trusted VF has the 'trusted' tag set in the spec.
for pci_req in pci_requests.requests: 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. # Only the port with a resource_request will have pci_req.requester_id.
self.assertEqual( 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]) [pci_req.requester_id for pci_req in pci_requests.requests])
self.assertCountEqual( self.assertCountEqual(

View File

@ -523,18 +523,20 @@ class TestPciDeviceListObjectRemote(test_objects._RemoteTest,
class _TestSRIOVPciDeviceObject(object): class _TestSRIOVPciDeviceObject(object):
def _create_pci_devices(self, vf_product_id=1515, pf_product_id=1528, 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 = [] self.sriov_pf_devices = []
for dev in range(num_pfs): for dev in range(num_pfs):
pci_dev = {'compute_node_id': 1, pci_dev = {
'address': '0000:81:00.%d' % dev, 'compute_node_id': 1,
'vendor_id': '8086', 'address': '0000:81:00.%d' % dev,
'product_id': '%d' % pf_product_id, 'vendor_id': '8086',
'status': 'available', 'product_id': '%d' % pf_product_id,
'request_id': None, 'status': 'available',
'dev_type': fields.PciDeviceType.SRIOV_PF, 'request_id': None,
'parent_addr': None, 'dev_type': fields.PciDeviceType.SRIOV_PF,
'numa_node': 0} 'parent_addr': None,
'numa_node': 0
}
pci_dev_obj = objects.PciDevice.create(None, pci_dev) pci_dev_obj = objects.PciDevice.create(None, pci_dev)
pci_dev_obj.id = dev + 81 pci_dev_obj.id = dev + 81
pci_dev_obj.child_devices = [] pci_dev_obj.child_devices = []
@ -542,21 +544,42 @@ class _TestSRIOVPciDeviceObject(object):
self.sriov_vf_devices = [] self.sriov_vf_devices = []
for dev in range(num_vfs): for dev in range(num_vfs):
pci_dev = {'compute_node_id': 1, pci_dev = {
'address': '0000:81:10.%d' % dev, 'compute_node_id': 1,
'vendor_id': '8086', 'address': '0000:81:10.%d' % dev,
'product_id': '%d' % vf_product_id, 'vendor_id': '8086',
'status': 'available', 'product_id': '%d' % vf_product_id,
'request_id': None, 'status': 'available',
'dev_type': fields.PciDeviceType.SRIOV_VF, 'request_id': None,
'parent_addr': '0000:81:00.%d' % int(dev / 4), 'dev_type': fields.PciDeviceType.SRIOV_VF,
'numa_node': 0} 'parent_addr': '0000:81:00.%d' % int(dev / 4),
'numa_node': 0
}
pci_dev_obj = objects.PciDevice.create(None, pci_dev) pci_dev_obj = objects.PciDevice.create(None, pci_dev)
pci_dev_obj.id = dev + 1 pci_dev_obj.id = dev + 1
pci_dev_obj.parent_device = self.sriov_pf_devices[int(dev / 4)] pci_dev_obj.parent_device = self.sriov_pf_devices[int(dev / 4)]
pci_dev_obj.parent_device.child_devices.append(pci_dev_obj) pci_dev_obj.parent_device.child_devices.append(pci_dev_obj)
self.sriov_vf_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): def _create_fake_instance(self):
self.inst = instance.Instance() self.inst = instance.Instance()
self.inst.uuid = uuids.instance self.inst.uuid = uuids.instance
@ -587,26 +610,35 @@ class _TestSRIOVPciDeviceObject(object):
self._create_pci_devices() self._create_pci_devices()
devobj = self.sriov_pf_devices[0] devobj = self.sriov_pf_devices[0]
devobj.claim(self.inst.uuid) devobj.claim(self.inst.uuid)
self.assertEqual(devobj.status, self.assertEqual(devobj.status, fields.PciDeviceStatus.CLAIMED)
fields.PciDeviceStatus.CLAIMED) self.assertEqual(devobj.instance_uuid, self.inst.uuid)
self.assertEqual(devobj.instance_uuid,
self.inst.uuid)
self.assertEqual(len(self.inst.pci_devices), 0) self.assertEqual(len(self.inst.pci_devices), 0)
# check if the all the dependants are UNCLAIMABLE # check if the all the dependants are UNCLAIMABLE
self.assertTrue(all( self.assertTrue(all(
[dev.status == fields.PciDeviceStatus.UNCLAIMABLE for [dev.status == fields.PciDeviceStatus.UNCLAIMABLE for
dev in self._get_children_by_parent_address( dev in self._get_children_by_parent_address(
self.sriov_pf_devices[0].address)])) self.sriov_pf_devices[0].address)]))
def test_claim_VF(self): def test_claim_VF(self):
self._create_fake_instance() self._create_fake_instance()
self._create_pci_devices() self._create_pci_devices()
devobj = self.sriov_vf_devices[0] devobj = self.sriov_vf_devices[0]
devobj.claim(self.inst.uuid) devobj.claim(self.inst.uuid)
self.assertEqual(devobj.status, self.assertEqual(devobj.status, fields.PciDeviceStatus.CLAIMED)
fields.PciDeviceStatus.CLAIMED) self.assertEqual(devobj.instance_uuid, self.inst.uuid)
self.assertEqual(devobj.instance_uuid, self.assertEqual(len(self.inst.pci_devices), 0)
self.inst.uuid)
# 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) self.assertEqual(len(self.inst.pci_devices), 0)
# check if parent device status has been changed to UNCLAIMABLE # check if parent device status has been changed to UNCLAIMABLE
@ -619,10 +651,8 @@ class _TestSRIOVPciDeviceObject(object):
devobj = self.sriov_pf_devices[0] devobj = self.sriov_pf_devices[0]
devobj.claim(self.inst.uuid) devobj.claim(self.inst.uuid)
devobj.allocate(self.inst) devobj.allocate(self.inst)
self.assertEqual(devobj.status, self.assertEqual(devobj.status, fields.PciDeviceStatus.ALLOCATED)
fields.PciDeviceStatus.ALLOCATED) self.assertEqual(devobj.instance_uuid, self.inst.uuid)
self.assertEqual(devobj.instance_uuid,
self.inst.uuid)
self.assertEqual(len(self.inst.pci_devices), 1) self.assertEqual(len(self.inst.pci_devices), 1)
# check if the all the dependants are UNAVAILABLE # check if the all the dependants are UNAVAILABLE
self.assertTrue(all( self.assertTrue(all(
@ -636,10 +666,22 @@ class _TestSRIOVPciDeviceObject(object):
devobj = self.sriov_vf_devices[0] devobj = self.sriov_vf_devices[0]
devobj.claim(self.inst.uuid) devobj.claim(self.inst.uuid)
devobj.allocate(self.inst) devobj.allocate(self.inst)
self.assertEqual(devobj.status, self.assertEqual(devobj.status, fields.PciDeviceStatus.ALLOCATED)
fields.PciDeviceStatus.ALLOCATED) self.assertEqual(devobj.instance_uuid, self.inst.uuid)
self.assertEqual(devobj.instance_uuid, self.assertEqual(len(self.inst.pci_devices), 1)
self.inst.uuid)
# 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) self.assertEqual(len(self.inst.pci_devices), 1)
# check if parent device status has been changed to UNAVAILABLE # check if parent device status has been changed to UNAVAILABLE
@ -652,8 +694,17 @@ class _TestSRIOVPciDeviceObject(object):
devobj = self.sriov_pf_devices[0] devobj = self.sriov_pf_devices[0]
self.sriov_vf_devices[0].status = fields.PciDeviceStatus.CLAIMED self.sriov_vf_devices[0].status = fields.PciDeviceStatus.CLAIMED
self.assertRaises(exception.PciDeviceVFInvalidStatus, self.assertRaises(
devobj.claim, self.inst) 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): def test_claim_VF_fail(self):
self._create_fake_instance() self._create_fake_instance()
@ -662,8 +713,17 @@ class _TestSRIOVPciDeviceObject(object):
parent = self._get_parent_by_address(devobj.parent_addr) parent = self._get_parent_by_address(devobj.parent_addr)
parent.status = fields.PciDeviceStatus.CLAIMED parent.status = fields.PciDeviceStatus.CLAIMED
self.assertRaises(exception.PciDevicePFInvalidStatus, self.assertRaises(
devobj.claim, self.inst) 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): def test_allocate_PF_fail(self):
self._create_fake_instance() self._create_fake_instance()
@ -671,8 +731,8 @@ class _TestSRIOVPciDeviceObject(object):
devobj = self.sriov_pf_devices[0] devobj = self.sriov_pf_devices[0]
self.sriov_vf_devices[0].status = fields.PciDeviceStatus.CLAIMED self.sriov_vf_devices[0].status = fields.PciDeviceStatus.CLAIMED
self.assertRaises(exception.PciDeviceVFInvalidStatus, self.assertRaises(
devobj.allocate, self.inst) exception.PciDeviceVFInvalidStatus, devobj.allocate, self.inst)
def test_allocate_VF_fail(self): def test_allocate_VF_fail(self):
self._create_fake_instance() self._create_fake_instance()
@ -681,8 +741,27 @@ class _TestSRIOVPciDeviceObject(object):
parent = self._get_parent_by_address(devobj.parent_addr) parent = self._get_parent_by_address(devobj.parent_addr)
parent.status = fields.PciDeviceStatus.CLAIMED parent.status = fields.PciDeviceStatus.CLAIMED
self.assertRaises(exception.PciDevicePFInvalidStatus, self.assertRaises(
devobj.allocate, self.inst) 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): def test_free_allocated_PF(self):
self._create_fake_instance() self._create_fake_instance()
@ -691,14 +770,13 @@ class _TestSRIOVPciDeviceObject(object):
devobj.claim(self.inst.uuid) devobj.claim(self.inst.uuid)
devobj.allocate(self.inst) devobj.allocate(self.inst)
devobj.free(self.inst) devobj.free(self.inst)
self.assertEqual(devobj.status, self.assertEqual(devobj.status, fields.PciDeviceStatus.AVAILABLE)
fields.PciDeviceStatus.AVAILABLE)
self.assertIsNone(devobj.instance_uuid) self.assertIsNone(devobj.instance_uuid)
# check if the all the dependants are AVAILABLE # check if the all the dependants are AVAILABLE
self.assertTrue(all( self.assertTrue(all(
[dev.status == fields.PciDeviceStatus.AVAILABLE for [dev.status == fields.PciDeviceStatus.AVAILABLE for
dev in self._get_children_by_parent_address( dev in self._get_children_by_parent_address(
self.sriov_pf_devices[0].address)])) self.sriov_pf_devices[0].address)]))
def test_free_allocated_VF(self): def test_free_allocated_VF(self):
self._create_fake_instance() self._create_fake_instance()
@ -708,20 +786,41 @@ class _TestSRIOVPciDeviceObject(object):
for devobj in dependents: for devobj in dependents:
devobj.claim(self.inst.uuid) devobj.claim(self.inst.uuid)
devobj.allocate(self.inst) devobj.allocate(self.inst)
self.assertEqual(devobj.status, self.assertEqual(devobj.status, fields.PciDeviceStatus.ALLOCATED)
fields.PciDeviceStatus.ALLOCATED)
for devobj in dependents[:-1]: for devobj in dependents[:-1]:
devobj.free(self.inst) devobj.free(self.inst)
# check if parent device status is still UNAVAILABLE # check if parent device status is still UNAVAILABLE
parent = self._get_parent_by_address(devobj.parent_addr) parent = self._get_parent_by_address(devobj.parent_addr)
self.assertEqual(fields.PciDeviceStatus.UNAVAILABLE, self.assertEqual(
parent.status) fields.PciDeviceStatus.UNAVAILABLE, parent.status)
devobj = dependents[-1] devobj = dependents[-1]
devobj.free(self.inst) devobj.free(self.inst)
# check if parent device status is now AVAILABLE # check if parent device status is now AVAILABLE
parent = self._get_parent_by_address(devobj.parent_addr) parent = self._get_parent_by_address(devobj.parent_addr)
self.assertEqual(fields.PciDeviceStatus.AVAILABLE, self.assertEqual(
parent.status) 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, class TestSRIOVPciDeviceListObject(test_objects._LocalTest,

View File

@ -629,37 +629,75 @@ class PciDeviceVFPFStatsTestCase(test.NoDBTestCase):
def _create_pci_devices(self, vf_product_id=1515, pf_product_id=1528): def _create_pci_devices(self, vf_product_id=1515, pf_product_id=1528):
self.sriov_pf_devices = [] self.sriov_pf_devices = []
for dev in range(2): for dev in range(2):
pci_dev = {'compute_node_id': 1, pci_dev = {
'address': '0000:81:00.%d' % dev, 'compute_node_id': 1,
'vendor_id': '8086', 'address': '0000:81:00.%d' % dev,
'product_id': '%d' % pf_product_id, 'vendor_id': '8086',
'status': 'available', 'product_id': '%d' % pf_product_id,
'request_id': None, 'status': 'available',
'dev_type': fields.PciDeviceType.SRIOV_PF, 'request_id': None,
'parent_addr': None, 'dev_type': fields.PciDeviceType.SRIOV_PF,
'numa_node': 0} 'parent_addr': None,
'numa_node': 0
}
dev_obj = objects.PciDevice.create(None, pci_dev) dev_obj = objects.PciDevice.create(None, pci_dev)
dev_obj.child_devices = [] dev_obj.child_devices = []
self.sriov_pf_devices.append(dev_obj) self.sriov_pf_devices.append(dev_obj)
self.sriov_vf_devices = [] self.sriov_vf_devices = []
for dev in range(8): for dev in range(8):
pci_dev = {'compute_node_id': 1, pci_dev = {
'address': '0000:81:10.%d' % dev, 'compute_node_id': 1,
'vendor_id': '8086', 'address': '0000:81:10.%d' % dev,
'product_id': '%d' % vf_product_id, 'vendor_id': '8086',
'status': 'available', 'product_id': '%d' % vf_product_id,
'request_id': None, 'status': 'available',
'dev_type': fields.PciDeviceType.SRIOV_VF, 'request_id': None,
'parent_addr': '0000:81:00.%d' % int(dev / 4), 'dev_type': fields.PciDeviceType.SRIOV_VF,
'numa_node': 0} 'parent_addr': '0000:81:00.%d' % int(dev / 4),
'numa_node': 0
}
dev_obj = objects.PciDevice.create(None, pci_dev) dev_obj = objects.PciDevice.create(None, pci_dev)
dev_obj.parent_device = self.sriov_pf_devices[int(dev / 4)] dev_obj.parent_device = self.sriov_pf_devices[int(dev / 4)]
dev_obj.parent_device.child_devices.append(dev_obj) dev_obj.parent_device.child_devices.append(dev_obj)
self.sriov_vf_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_pf_devices))
list(map(self.pci_stats.add_device, self.sriov_vf_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): def test_consume_VF_requests(self):
self._create_pci_devices() self._create_pci_devices()