pci: related updates are done without DB lookups
Now that we have all relationships recorded on objects kept in the master-list in memory, we can use those links to do updates (that eventually get saved on pci_tracker.save()) without wrongfully updating objects within the local scope and losing changes immediately. As a convenience, we add two properties to the PciDevice object that take care of fetching related objects without worrying about missing or unset values. We also clarify a bit more how to use PciDevTracker.pci_devs attribute and why we can't just randomly fish PciDevices out of the DB for the purposes of updating them. Change-Id: I118ba35f464afc970fef54759d5560ba20ff9c52 Closes-bug: #1565785
This commit is contained in:
parent
c469b8466f
commit
0b85bb4b42
@ -279,10 +279,7 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject):
|
||||
if self.dev_type == fields.PciDeviceType.SRIOV_PF:
|
||||
# Update PF status to CLAIMED if all of it dependants are free
|
||||
# and set their status to UNCLAIMABLE
|
||||
vfs_list = objects.PciDeviceList.get_by_parent_address(
|
||||
self._context,
|
||||
self.compute_node_id,
|
||||
self.address)
|
||||
vfs_list = self.child_devices
|
||||
if not all([vf.is_available() for vf in vfs_list]):
|
||||
raise exception.PciDeviceVFInvalidStatus(
|
||||
compute_node_id=self.compute_node_id,
|
||||
@ -301,10 +298,8 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject):
|
||||
parent_ok_statuses = (fields.PciDeviceStatus.AVAILABLE,
|
||||
fields.PciDeviceStatus.UNCLAIMABLE,
|
||||
fields.PciDeviceStatus.UNAVAILABLE)
|
||||
try:
|
||||
parent = self.get_by_dev_addr(self._context,
|
||||
self.compute_node_id,
|
||||
self.parent_addr)
|
||||
parent = self.parent_device
|
||||
if parent:
|
||||
if parent.status not in parent_ok_statuses:
|
||||
raise exception.PciDevicePFInvalidStatus(
|
||||
compute_node_id=self.compute_node_id,
|
||||
@ -314,11 +309,11 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject):
|
||||
# Set PF status
|
||||
if parent.status == fields.PciDeviceStatus.AVAILABLE:
|
||||
parent.status = fields.PciDeviceStatus.UNCLAIMABLE
|
||||
except exception.PciDeviceNotFound:
|
||||
else:
|
||||
LOG.debug('Physical function addr: %(pf_addr)s parent of '
|
||||
'VF addr: %(vf_addr)s was not found',
|
||||
{'pf_addr': self.parent_addr,
|
||||
'vf_addr': self.address})
|
||||
'VF addr: %(vf_addr)s was not found',
|
||||
{'pf_addr': self.parent_addr,
|
||||
'vf_addr': self.address})
|
||||
|
||||
self.status = fields.PciDeviceStatus.CLAIMED
|
||||
self.instance_uuid = instance_uuid
|
||||
@ -343,10 +338,7 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject):
|
||||
address=self.address, owner=self.instance_uuid,
|
||||
hopeowner=instance['uuid'])
|
||||
if self.dev_type == fields.PciDeviceType.SRIOV_PF:
|
||||
vfs_list = objects.PciDeviceList.get_by_parent_address(
|
||||
self._context,
|
||||
self.compute_node_id,
|
||||
self.address)
|
||||
vfs_list = self.child_devices
|
||||
if not all([vf.status in dependatns_ok_statuses for
|
||||
vf in vfs_list]):
|
||||
raise exception.PciDeviceVFInvalidStatus(
|
||||
@ -356,10 +348,8 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject):
|
||||
fields.PciDeviceStatus.UNAVAILABLE)
|
||||
|
||||
elif (self.dev_type == fields.PciDeviceType.SRIOV_VF):
|
||||
try:
|
||||
parent = self.get_by_dev_addr(self._context,
|
||||
self.compute_node_id,
|
||||
self.parent_addr)
|
||||
parent = self.parent_device
|
||||
if parent:
|
||||
if parent.status not in parent_ok_statuses:
|
||||
raise exception.PciDevicePFInvalidStatus(
|
||||
compute_node_id=self.compute_node_id,
|
||||
@ -368,7 +358,7 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject):
|
||||
hopestatus=parent_ok_statuses)
|
||||
# Set PF status
|
||||
parent.status = fields.PciDeviceStatus.UNAVAILABLE
|
||||
except exception.PciDeviceNotFound:
|
||||
else:
|
||||
LOG.debug('Physical function addr: %(pf_addr)s parent of '
|
||||
'VF addr: %(vf_addr)s was not found',
|
||||
{'pf_addr': self.parent_addr,
|
||||
@ -412,31 +402,23 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject):
|
||||
hopeowner=instance['uuid'])
|
||||
if self.dev_type == fields.PciDeviceType.SRIOV_PF:
|
||||
# Set all PF dependants status to AVAILABLE
|
||||
vfs_list = objects.PciDeviceList.get_by_parent_address(
|
||||
self._context,
|
||||
self.compute_node_id,
|
||||
self.address)
|
||||
vfs_list = self.child_devices
|
||||
self._bulk_update_status(vfs_list,
|
||||
fields.PciDeviceStatus.AVAILABLE)
|
||||
free_devs.extend(vfs_list)
|
||||
if self.dev_type == fields.PciDeviceType.SRIOV_VF:
|
||||
# Set PF status to AVAILABLE if all of it's VFs are free
|
||||
vfs_list = objects.PciDeviceList.get_by_parent_address(
|
||||
self._context,
|
||||
self.compute_node_id,
|
||||
self.parent_addr)
|
||||
if all([vf.is_available() for vf in vfs_list if vf.id != self.id]):
|
||||
try:
|
||||
parent = self.get_by_dev_addr(self._context,
|
||||
self.compute_node_id,
|
||||
self.parent_addr)
|
||||
parent.status = fields.PciDeviceStatus.AVAILABLE
|
||||
parent = self.parent_device
|
||||
if not parent:
|
||||
LOG.debug('Physical function addr: %(pf_addr)s parent of '
|
||||
'VF addr: %(vf_addr)s was not found',
|
||||
{'pf_addr': self.parent_addr,
|
||||
'vf_addr': self.address})
|
||||
else:
|
||||
vfs_list = parent.child_devices
|
||||
if all([vf.is_available() for vf in vfs_list
|
||||
if vf.id != self.id]):
|
||||
free_devs.append(parent)
|
||||
except exception.PciDeviceNotFound:
|
||||
LOG.debug('Physical function addr: %(pf_addr)s parent of '
|
||||
'VF addr: %(vf_addr)s was not found',
|
||||
{'pf_addr': self.parent_addr,
|
||||
'vf_addr': self.address})
|
||||
old_status = self.status
|
||||
self.status = fields.PciDeviceStatus.AVAILABLE
|
||||
free_devs.append(self)
|
||||
|
@ -40,8 +40,18 @@ class PciDevTracker(object):
|
||||
|
||||
It's called by compute node resource tracker to allocate and free
|
||||
devices to/from instances, and to update the available pci passthrough
|
||||
devices information from hypervisor periodically. The devices
|
||||
information is updated to DB when devices information is changed.
|
||||
devices information from hypervisor periodically.
|
||||
|
||||
`pci_devs` attribute of this class is the in-memory "master copy" of all
|
||||
devices on each compute host, and all data changes that happen when
|
||||
claiming/allocating/freeing
|
||||
devices HAVE TO be made against instances contained in `pci_devs` list,
|
||||
because they are periodically flushed to the DB when the save()
|
||||
method is called.
|
||||
|
||||
It is unsafe to fetch PciDevice objects elsewhere in the code for update
|
||||
purposes as those changes will end up being overwritten when the `pci_devs`
|
||||
are saved.
|
||||
"""
|
||||
|
||||
def __init__(self, context, node_id=None):
|
||||
|
@ -22,7 +22,6 @@ import six
|
||||
|
||||
from nova import exception
|
||||
from nova.i18n import _LE
|
||||
from nova import objects
|
||||
from nova.objects import fields
|
||||
from nova.objects import pci_device_pool
|
||||
from nova.pci import utils
|
||||
@ -192,18 +191,13 @@ class PciDeviceStats(object):
|
||||
decreased, unless it is no longer in a pool.
|
||||
"""
|
||||
if pci_dev.dev_type == fields.PciDeviceType.SRIOV_PF:
|
||||
vfs_list = objects.PciDeviceList.get_by_parent_address(
|
||||
pci_dev._context,
|
||||
pci_dev.compute_node_id,
|
||||
pci_dev.address)
|
||||
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:
|
||||
try:
|
||||
parent = pci_dev.get_by_dev_addr(pci_dev._context,
|
||||
pci_dev.compute_node_id,
|
||||
pci_dev.parent_addr)
|
||||
parent = pci_dev.parent_device
|
||||
# Make sure not to decrease PF pool count if this parent has
|
||||
# been already removed from pools
|
||||
if parent in self.get_free_devs():
|
||||
|
@ -25,7 +25,6 @@ from nova import objects
|
||||
from nova.objects import fields
|
||||
from nova.objects import instance
|
||||
from nova.objects import pci_device
|
||||
from nova import test
|
||||
from nova.tests.unit.objects import test_objects
|
||||
from nova.tests import uuidsentinel as uuids
|
||||
|
||||
@ -523,6 +522,7 @@ class _TestSRIOVPciDeviceObject(object):
|
||||
'numa_node': 0}
|
||||
pci_dev_obj = objects.PciDevice.create(None, pci_dev)
|
||||
pci_dev_obj.id = num_pfs + 81
|
||||
pci_dev_obj.child_devices = []
|
||||
self.sriov_pf_devices.append(pci_dev_obj)
|
||||
|
||||
self.sriov_vf_devices = []
|
||||
@ -538,6 +538,8 @@ class _TestSRIOVPciDeviceObject(object):
|
||||
'numa_node': 0}
|
||||
pci_dev_obj = objects.PciDevice.create(None, pci_dev)
|
||||
pci_dev_obj.id = num_vfs + 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)
|
||||
|
||||
def _create_fake_instance(self):
|
||||
@ -553,188 +555,158 @@ class _TestSRIOVPciDeviceObject(object):
|
||||
self.mox.ReplayAll()
|
||||
self.pci_device = pci_device.PciDevice.get_by_dev_addr(ctxt, 1, 'a')
|
||||
|
||||
def _fake_get_by_parent_address(self, ctxt, node_id, addr):
|
||||
def _get_children_by_parent_address(self, addr):
|
||||
vf_devs = []
|
||||
for dev in self.sriov_vf_devices:
|
||||
if dev.parent_addr == addr:
|
||||
vf_devs.append(dev)
|
||||
return vf_devs
|
||||
|
||||
def _fake_pci_device_get_by_addr(self, ctxt, id, addr):
|
||||
def _get_parent_by_address(self, addr):
|
||||
for dev in self.sriov_pf_devices:
|
||||
if dev.address == addr:
|
||||
return dev
|
||||
|
||||
def test_claim_PF(self):
|
||||
self._create_fake_instance()
|
||||
with mock.patch.object(objects.PciDeviceList, 'get_by_parent_address',
|
||||
side_effect=self._fake_get_by_parent_address):
|
||||
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(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._fake_get_by_parent_address(None, None,
|
||||
self.sriov_pf_devices[0].address)]))
|
||||
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(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)]))
|
||||
|
||||
def test_claim_VF(self):
|
||||
self._create_fake_instance()
|
||||
with mock.patch.object(objects.PciDevice, 'get_by_dev_addr',
|
||||
side_effect=self._fake_pci_device_get_by_addr):
|
||||
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(len(self.inst.pci_devices), 0)
|
||||
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(len(self.inst.pci_devices), 0)
|
||||
|
||||
# check if parent device status has been changed to UNCLAIMABLE
|
||||
parent = self._fake_pci_device_get_by_addr(None, None,
|
||||
devobj.parent_addr)
|
||||
self.assertTrue(fields.PciDeviceStatus.UNCLAIMABLE, parent.status)
|
||||
# check if parent device status has been changed to UNCLAIMABLE
|
||||
parent = self._get_parent_by_address(devobj.parent_addr)
|
||||
self.assertTrue(fields.PciDeviceStatus.UNCLAIMABLE, parent.status)
|
||||
|
||||
def test_allocate_PF(self):
|
||||
self._create_fake_instance()
|
||||
with mock.patch.object(objects.PciDeviceList, 'get_by_parent_address',
|
||||
side_effect=self._fake_get_by_parent_address):
|
||||
self._create_pci_devices()
|
||||
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(len(self.inst.pci_devices), 1)
|
||||
# check if the all the dependants are UNAVAILABLE
|
||||
self.assertTrue(all(
|
||||
[dev.status == fields.PciDeviceStatus.UNAVAILABLE for
|
||||
dev in self._fake_get_by_parent_address(None, None,
|
||||
self.sriov_pf_devices[0].address)]))
|
||||
self._create_pci_devices()
|
||||
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(len(self.inst.pci_devices), 1)
|
||||
# check if the all the dependants are UNAVAILABLE
|
||||
self.assertTrue(all(
|
||||
[dev.status == fields.PciDeviceStatus.UNAVAILABLE for
|
||||
dev in self._get_children_by_parent_address(
|
||||
self.sriov_pf_devices[0].address)]))
|
||||
|
||||
def test_allocate_VF(self):
|
||||
self._create_fake_instance()
|
||||
with mock.patch.object(objects.PciDevice, 'get_by_dev_addr',
|
||||
side_effect=self._fake_pci_device_get_by_addr):
|
||||
self._create_pci_devices()
|
||||
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(len(self.inst.pci_devices), 1)
|
||||
self._create_pci_devices()
|
||||
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(len(self.inst.pci_devices), 1)
|
||||
|
||||
# check if parent device status has been changed to UNAVAILABLE
|
||||
parent = self._fake_pci_device_get_by_addr(None, None,
|
||||
devobj.parent_addr)
|
||||
self.assertTrue(fields.PciDeviceStatus.UNAVAILABLE, parent.status)
|
||||
# check if parent device status has been changed to UNAVAILABLE
|
||||
parent = self._get_parent_by_address(devobj.parent_addr)
|
||||
self.assertTrue(fields.PciDeviceStatus.UNAVAILABLE, parent.status)
|
||||
|
||||
def test_claim_PF_fail(self):
|
||||
self._create_fake_instance()
|
||||
with mock.patch.object(objects.PciDeviceList, 'get_by_parent_address',
|
||||
side_effect=self._fake_get_by_parent_address):
|
||||
self._create_pci_devices()
|
||||
devobj = self.sriov_pf_devices[0]
|
||||
self.sriov_vf_devices[0].status = fields.PciDeviceStatus.CLAIMED
|
||||
self._create_pci_devices()
|
||||
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_VF_fail(self):
|
||||
self._create_fake_instance()
|
||||
with mock.patch.object(objects.PciDevice, 'get_by_dev_addr',
|
||||
side_effect=self._fake_pci_device_get_by_addr):
|
||||
self._create_pci_devices()
|
||||
devobj = self.sriov_vf_devices[0]
|
||||
parent = self._fake_pci_device_get_by_addr(None, None,
|
||||
devobj.parent_addr)
|
||||
parent.status = fields.PciDeviceStatus.CLAIMED
|
||||
self._create_pci_devices()
|
||||
devobj = self.sriov_vf_devices[0]
|
||||
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_allocate_PF_fail(self):
|
||||
self._create_fake_instance()
|
||||
with mock.patch.object(objects.PciDeviceList, 'get_by_parent_address',
|
||||
side_effect=self._fake_get_by_parent_address):
|
||||
self._create_pci_devices()
|
||||
devobj = self.sriov_pf_devices[0]
|
||||
self.sriov_vf_devices[0].status = fields.PciDeviceStatus.CLAIMED
|
||||
self._create_pci_devices()
|
||||
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()
|
||||
with mock.patch.object(objects.PciDevice, 'get_by_dev_addr',
|
||||
side_effect=self._fake_pci_device_get_by_addr):
|
||||
self._create_pci_devices()
|
||||
devobj = self.sriov_vf_devices[0]
|
||||
parent = self._fake_pci_device_get_by_addr(None, None,
|
||||
devobj.parent_addr)
|
||||
parent.status = fields.PciDeviceStatus.CLAIMED
|
||||
self._create_pci_devices()
|
||||
devobj = self.sriov_vf_devices[0]
|
||||
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_free_allocated_PF(self):
|
||||
self._create_fake_instance()
|
||||
with mock.patch.object(objects.PciDeviceList, 'get_by_parent_address',
|
||||
side_effect=self._fake_get_by_parent_address):
|
||||
self._create_pci_devices()
|
||||
devobj = self.sriov_pf_devices[0]
|
||||
devobj.claim(self.inst.uuid)
|
||||
devobj.allocate(self.inst)
|
||||
devobj.free(self.inst)
|
||||
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._fake_get_by_parent_address(None, None,
|
||||
self.sriov_pf_devices[0].address)]))
|
||||
self._create_pci_devices()
|
||||
devobj = self.sriov_pf_devices[0]
|
||||
devobj.claim(self.inst.uuid)
|
||||
devobj.allocate(self.inst)
|
||||
devobj.free(self.inst)
|
||||
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)]))
|
||||
|
||||
def test_free_allocated_VF(self):
|
||||
self._create_fake_instance()
|
||||
with test.nested(
|
||||
mock.patch.object(objects.PciDevice, 'get_by_dev_addr',
|
||||
side_effect=self._fake_pci_device_get_by_addr),
|
||||
mock.patch.object(objects.PciDeviceList, 'get_by_parent_address',
|
||||
side_effect=self._fake_get_by_parent_address)):
|
||||
self._create_pci_devices()
|
||||
vf = self.sriov_vf_devices[0]
|
||||
dependents = self._fake_get_by_parent_address(None, None,
|
||||
vf.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[:3]:
|
||||
devobj.free(self.inst)
|
||||
# check if parent device status is still UNAVAILABLE
|
||||
parent = self._fake_pci_device_get_by_addr(None, None,
|
||||
devobj.parent_addr)
|
||||
self.assertTrue(fields.PciDeviceStatus.UNAVAILABLE,
|
||||
parent.status)
|
||||
for devobj in dependents[3:]:
|
||||
devobj.free(self.inst)
|
||||
# check if parent device status is now AVAILABLE
|
||||
parent = self._fake_pci_device_get_by_addr(None, None,
|
||||
devobj.parent_addr)
|
||||
self.assertTrue(fields.PciDeviceStatus.AVAILABLE,
|
||||
parent.status)
|
||||
self._create_pci_devices()
|
||||
vf = self.sriov_vf_devices[0]
|
||||
dependents = self._get_children_by_parent_address(vf.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[:3]:
|
||||
devobj.free(self.inst)
|
||||
# check if parent device status is still UNAVAILABLE
|
||||
parent = self._get_parent_by_address(devobj.parent_addr)
|
||||
self.assertTrue(fields.PciDeviceStatus.UNAVAILABLE,
|
||||
parent.status)
|
||||
for devobj in dependents[3:]:
|
||||
devobj.free(self.inst)
|
||||
# check if parent device status is now AVAILABLE
|
||||
parent = self._get_parent_by_address(devobj.parent_addr)
|
||||
self.assertTrue(fields.PciDeviceStatus.AVAILABLE,
|
||||
parent.status)
|
||||
|
||||
|
||||
class TestSRIOVPciDeviceListObject(test_objects._LocalTest,
|
||||
|
@ -367,8 +367,9 @@ class PciDeviceVFPFStatsTestCase(test.NoDBTestCase):
|
||||
'dev_type': fields.PciDeviceType.SRIOV_PF,
|
||||
'parent_addr': None,
|
||||
'numa_node': 0}
|
||||
self.sriov_pf_devices.append(objects.PciDevice.create(None,
|
||||
pci_dev))
|
||||
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):
|
||||
@ -381,95 +382,66 @@ class PciDeviceVFPFStatsTestCase(test.NoDBTestCase):
|
||||
'dev_type': fields.PciDeviceType.SRIOV_VF,
|
||||
'parent_addr': '0000:81:00.%d' % int(dev / 4),
|
||||
'numa_node': 0}
|
||||
self.sriov_vf_devices.append(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.child_devices.append(dev_obj)
|
||||
self.sriov_vf_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))
|
||||
|
||||
def _fake_get_by_parent_address(self, ctxt, node_id, addr):
|
||||
vf_devs = []
|
||||
for dev in self.sriov_vf_devices:
|
||||
if dev.parent_addr == addr:
|
||||
vf_devs.append(dev)
|
||||
return vf_devs
|
||||
|
||||
def _fake_pci_device_get_by_addr(self, ctxt, id, addr):
|
||||
for dev in self.sriov_pf_devices:
|
||||
if dev.address == addr:
|
||||
return dev
|
||||
|
||||
def test_consume_VF_requests(self):
|
||||
with mock.patch.object(objects.PciDevice, 'get_by_dev_addr',
|
||||
side_effect=self._fake_pci_device_get_by_addr):
|
||||
self._create_pci_devices()
|
||||
pci_requests = [objects.InstancePCIRequest(count=2,
|
||||
spec=[{'product_id': '1515'}])]
|
||||
devs = self.pci_stats.consume_requests(pci_requests)
|
||||
self.assertEqual(2, len(devs))
|
||||
self.assertEqual(set(['1515']),
|
||||
set([dev.product_id for dev in devs]))
|
||||
free_devs = self.pci_stats.get_free_devs()
|
||||
# Validate that the parents of these VFs has been removed
|
||||
# from pools.
|
||||
for dev in devs:
|
||||
self.assertTrue(all(dev.parent_addr != free_dev.address
|
||||
for free_dev in free_devs))
|
||||
self._create_pci_devices()
|
||||
pci_requests = [objects.InstancePCIRequest(count=2,
|
||||
spec=[{'product_id': '1515'}])]
|
||||
devs = self.pci_stats.consume_requests(pci_requests)
|
||||
self.assertEqual(2, len(devs))
|
||||
self.assertEqual(set(['1515']),
|
||||
set([dev.product_id for dev in devs]))
|
||||
free_devs = self.pci_stats.get_free_devs()
|
||||
# Validate that the parents of these VFs has been removed
|
||||
# from pools.
|
||||
for dev in devs:
|
||||
self.assertTrue(all(dev.parent_addr != free_dev.address
|
||||
for free_dev in free_devs))
|
||||
|
||||
def test_consume_PF_requests(self):
|
||||
with mock.patch.object(objects.PciDeviceList, 'get_by_parent_address',
|
||||
side_effect=self._fake_get_by_parent_address):
|
||||
self._create_pci_devices()
|
||||
pci_requests = [objects.InstancePCIRequest(count=2,
|
||||
spec=[{'product_id': '1528',
|
||||
'dev_type': 'type-PF'}])]
|
||||
devs = self.pci_stats.consume_requests(pci_requests)
|
||||
self.assertEqual(2, len(devs))
|
||||
self.assertEqual(set(['1528']),
|
||||
set([dev.product_id for dev in devs]))
|
||||
free_devs = self.pci_stats.get_free_devs()
|
||||
# Validate that there are no free devices left, as when allocating
|
||||
# both available PFs, its VFs should not be available.
|
||||
self.assertEqual(0, len(free_devs))
|
||||
self._create_pci_devices()
|
||||
pci_requests = [objects.InstancePCIRequest(count=2,
|
||||
spec=[{'product_id': '1528',
|
||||
'dev_type': 'type-PF'}])]
|
||||
devs = self.pci_stats.consume_requests(pci_requests)
|
||||
self.assertEqual(2, len(devs))
|
||||
self.assertEqual(set(['1528']),
|
||||
set([dev.product_id for dev in devs]))
|
||||
free_devs = self.pci_stats.get_free_devs()
|
||||
# Validate that there are no free devices left, as when allocating
|
||||
# both available PFs, its VFs should not be available.
|
||||
self.assertEqual(0, len(free_devs))
|
||||
|
||||
def test_consume_VF_and_PF_requests(self):
|
||||
with test.nested(
|
||||
mock.patch.object(objects.PciDevice, 'get_by_dev_addr',
|
||||
side_effect=self._fake_pci_device_get_by_addr),
|
||||
mock.patch.object(objects.PciDeviceList, 'get_by_parent_address',
|
||||
side_effect=self._fake_get_by_parent_address)):
|
||||
self._create_pci_devices()
|
||||
pci_requests = [objects.InstancePCIRequest(count=2,
|
||||
spec=[{'product_id': '1515'}]),
|
||||
objects.InstancePCIRequest(count=1,
|
||||
spec=[{'product_id': '1528',
|
||||
'dev_type': 'type-PF'}])]
|
||||
devs = self.pci_stats.consume_requests(pci_requests)
|
||||
self.assertEqual(3, len(devs))
|
||||
self.assertEqual(set(['1528', '1515']),
|
||||
set([dev.product_id for dev in devs]))
|
||||
self._create_pci_devices()
|
||||
pci_requests = [objects.InstancePCIRequest(count=2,
|
||||
spec=[{'product_id': '1515'}]),
|
||||
objects.InstancePCIRequest(count=1,
|
||||
spec=[{'product_id': '1528',
|
||||
'dev_type': 'type-PF'}])]
|
||||
devs = self.pci_stats.consume_requests(pci_requests)
|
||||
self.assertEqual(3, len(devs))
|
||||
self.assertEqual(set(['1528', '1515']),
|
||||
set([dev.product_id for dev in devs]))
|
||||
|
||||
def test_consume_VF_and_PF_requests_failed(self):
|
||||
with test.nested(
|
||||
mock.patch.object(objects.PciDevice, 'get_by_dev_addr',
|
||||
side_effect=self._fake_pci_device_get_by_addr),
|
||||
mock.patch.object(objects.PciDeviceList, 'get_by_parent_address',
|
||||
side_effect=self._fake_get_by_parent_address)):
|
||||
self._create_pci_devices()
|
||||
pci_requests = [objects.InstancePCIRequest(count=5,
|
||||
spec=[{'product_id': '1515'}]),
|
||||
objects.InstancePCIRequest(count=1,
|
||||
spec=[{'product_id': '1528',
|
||||
'dev_type': 'type-PF'}])]
|
||||
self.assertIsNone(self.pci_stats.consume_requests(pci_requests))
|
||||
self._create_pci_devices()
|
||||
pci_requests = [objects.InstancePCIRequest(count=5,
|
||||
spec=[{'product_id': '1515'}]),
|
||||
objects.InstancePCIRequest(count=1,
|
||||
spec=[{'product_id': '1528',
|
||||
'dev_type': 'type-PF'}])]
|
||||
self.assertIsNone(self.pci_stats.consume_requests(pci_requests))
|
||||
|
||||
def test_consume_VF_and_PF_same_prodict_id_failed(self):
|
||||
with test.nested(
|
||||
mock.patch.object(objects.PciDevice, 'get_by_dev_addr',
|
||||
side_effect=self._fake_pci_device_get_by_addr),
|
||||
mock.patch.object(objects.PciDeviceList, 'get_by_parent_address',
|
||||
side_effect=self._fake_get_by_parent_address)):
|
||||
self._create_pci_devices(pf_product_id=1515)
|
||||
pci_requests = [objects.InstancePCIRequest(count=9,
|
||||
spec=[{'product_id': '1515'}])]
|
||||
self.assertIsNone(self.pci_stats.consume_requests(pci_requests))
|
||||
self._create_pci_devices(pf_product_id=1515)
|
||||
pci_requests = [objects.InstancePCIRequest(count=9,
|
||||
spec=[{'product_id': '1515'}])]
|
||||
self.assertIsNone(self.pci_stats.consume_requests(pci_requests))
|
||||
|
Loading…
Reference in New Issue
Block a user