Skip to content

Commit b7334b5

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "pci: Add vDPA vnic to PCI request mapping and filtering"
2 parents bde5995 + ab04eb2 commit b7334b5

File tree

7 files changed

+283
-92
lines changed

7 files changed

+283
-92
lines changed

nova/objects/pci_device.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,9 @@ def claim(self, instance_uuid):
354354
self._bulk_update_status(vfs_list,
355355
fields.PciDeviceStatus.UNCLAIMABLE)
356356

357-
elif self.dev_type == fields.PciDeviceType.SRIOV_VF:
357+
elif self.dev_type in (
358+
fields.PciDeviceType.SRIOV_VF, fields.PciDeviceType.VDPA
359+
):
358360
# Update VF status to CLAIMED if it's parent has not been
359361
# previously allocated or claimed
360362
# When claiming/allocating a VF, it's parent PF becomes
@@ -414,7 +416,9 @@ def allocate(self, instance):
414416
self._bulk_update_status(vfs_list,
415417
fields.PciDeviceStatus.UNAVAILABLE)
416418

417-
elif (self.dev_type == fields.PciDeviceType.SRIOV_VF):
419+
elif self.dev_type in (
420+
fields.PciDeviceType.SRIOV_VF, fields.PciDeviceType.VDPA
421+
):
418422
parent = self.parent_device
419423
if parent:
420424
if parent.status not in parent_ok_statuses:
@@ -473,7 +477,9 @@ def free(self, instance=None):
473477
self._bulk_update_status(vfs_list,
474478
fields.PciDeviceStatus.AVAILABLE)
475479
free_devs.extend(vfs_list)
476-
if self.dev_type == fields.PciDeviceType.SRIOV_VF:
480+
if self.dev_type in (
481+
fields.PciDeviceType.SRIOV_VF, fields.PciDeviceType.VDPA
482+
):
477483
# Set PF status to AVAILABLE if all of it's VFs are free
478484
parent = self.parent_device
479485
if not parent:

nova/pci/manager.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,9 @@ def _build_device_tree(all_devs):
189189
if dev.dev_type == fields.PciDeviceType.SRIOV_PF:
190190
dev.child_devices = []
191191
parents[dev.address] = dev
192-
elif dev.dev_type == fields.PciDeviceType.SRIOV_VF:
192+
elif dev.dev_type in (
193+
fields.PciDeviceType.SRIOV_VF, fields.PciDeviceType.VDPA
194+
):
193195
dev.parent_device = parents.get(dev.parent_addr)
194196
if dev.parent_device:
195197
parents[dev.parent_addr].child_devices.append(dev)

nova/pci/request.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@
5656
PCI_DEVICE_TYPE_TAG = 'dev_type'
5757

5858
DEVICE_TYPE_FOR_VNIC_TYPE = {
59-
network_model.VNIC_TYPE_DIRECT_PHYSICAL: obj_fields.PciDeviceType.SRIOV_PF
59+
network_model.VNIC_TYPE_DIRECT_PHYSICAL: obj_fields.PciDeviceType.SRIOV_PF,
60+
network_model.VNIC_TYPE_VDPA: obj_fields.PciDeviceType.VDPA,
6061
}
6162

6263
CONF = nova.conf.CONF

nova/pci/stats.py

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -217,15 +217,18 @@ def _handle_device_dependents(self, pci_dev):
217217
218218
In case the device is a PF, all of it's dependent VFs should
219219
be removed from pools count, if these are present.
220-
When the device is a VF, it's parent PF pool count should be
221-
decreased, unless it is no longer in a pool.
220+
When the device is a VF, or a VDPA device, it's parent PF
221+
pool count should be decreased, unless it is no longer in a pool.
222222
"""
223223
if pci_dev.dev_type == fields.PciDeviceType.SRIOV_PF:
224224
vfs_list = pci_dev.child_devices
225225
if vfs_list:
226226
for vf in vfs_list:
227227
self.remove_device(vf)
228-
elif pci_dev.dev_type == fields.PciDeviceType.SRIOV_VF:
228+
elif pci_dev.dev_type in (
229+
fields.PciDeviceType.SRIOV_VF,
230+
fields.PciDeviceType.VDPA,
231+
):
229232
try:
230233
parent = pci_dev.parent_device
231234
# Make sure not to decrease PF pool count if this parent has
@@ -387,6 +390,28 @@ def _filter_pools_for_unrequested_pfs(self, pools, request):
387390
]
388391
return pools
389392

393+
def _filter_pools_for_unrequested_vdpa_devices(self, pools, request):
394+
"""Filter out pools with VDPA devices, unless these are required.
395+
396+
This is necessary as vdpa devices require special handling and
397+
should not be allocated to generic pci device requests.
398+
399+
:param pools: A list of PCI device pool dicts
400+
:param request: An InstancePCIRequest object describing the type,
401+
quantity and required NUMA affinity of device(s) we want.
402+
:returns: A list of pools that can be used to support the request if
403+
this is possible.
404+
"""
405+
if all(
406+
spec.get('dev_type') != fields.PciDeviceType.VDPA
407+
for spec in request.spec
408+
):
409+
pools = [
410+
pool for pool in pools
411+
if not pool.get('dev_type') == fields.PciDeviceType.VDPA
412+
]
413+
return pools
414+
390415
def _filter_pools(self, pools, request, numa_cells):
391416
"""Determine if an individual PCI request can be met.
392417
@@ -421,7 +446,7 @@ def _filter_pools(self, pools, request, numa_cells):
421446
)
422447

423448
if after_count < request.count:
424-
LOG.debug('Not enough PCI devices left to satify request')
449+
LOG.debug('Not enough PCI devices left to satisfy request')
425450
return None
426451

427452
# Next, let's exclude all devices that aren't on the correct NUMA node
@@ -438,10 +463,10 @@ def _filter_pools(self, pools, request, numa_cells):
438463
)
439464

440465
if after_count < request.count:
441-
LOG.debug('Not enough PCI devices left to satify request')
466+
LOG.debug('Not enough PCI devices left to satisfy request')
442467
return None
443468

444-
# Finally, if we're not requesting PFs then we should not use these.
469+
# If we're not requesting PFs then we should not use these.
445470
# Exclude them.
446471
before_count = after_count
447472
pools = self._filter_pools_for_unrequested_pfs(pools, request)
@@ -455,7 +480,24 @@ def _filter_pools(self, pools, request, numa_cells):
455480
)
456481

457482
if after_count < request.count:
458-
LOG.debug('Not enough PCI devices left to satify request')
483+
LOG.debug('Not enough PCI devices left to satisfy request')
484+
return None
485+
486+
# If we're not requesting VDPA devices then we should not use these
487+
# either. Exclude them.
488+
before_count = after_count
489+
pools = self._filter_pools_for_unrequested_vdpa_devices(pools, request)
490+
after_count = sum([pool['count'] for pool in pools])
491+
492+
if after_count < before_count:
493+
LOG.debug(
494+
'Dropped %d devices as they are VDPA devices which we have '
495+
'not requested',
496+
before_count - after_count
497+
)
498+
499+
if after_count < request.count:
500+
LOG.debug('Not enough PCI devices left to satisfy request')
459501
return None
460502

461503
return pools

nova/tests/unit/network/test_neutron.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5772,7 +5772,8 @@ def test_create_resource_requests(self, getclient,
57725772
objects.NetworkRequest(port_id=uuids.portid_3),
57735773
objects.NetworkRequest(port_id=uuids.portid_4),
57745774
objects.NetworkRequest(port_id=uuids.portid_5),
5775-
objects.NetworkRequest(port_id=uuids.trusted_port)])
5775+
objects.NetworkRequest(port_id=uuids.trusted_port),
5776+
objects.NetworkRequest(port_id=uuids.portid_vdpa)])
57765777
pci_requests = objects.InstancePCIRequests(requests=[])
57775778
# _get_port_vnic_info should be called for every NetworkRequest with a
57785779
# port_id attribute (so six times)
@@ -5785,13 +5786,14 @@ def test_create_resource_requests(self, getclient,
57855786
(model.VNIC_TYPE_DIRECT_PHYSICAL, None, 'netN', None, None),
57865787
(model.VNIC_TYPE_DIRECT, True, 'netN',
57875788
mock.sentinel.resource_request2, None),
5789+
(model.VNIC_TYPE_VDPA, None, 'netN', None, None),
57885790
]
57895791
# _get_physnet_tunneled_info should be called for every NetworkRequest
57905792
# (so seven times)
57915793
mock_get_physnet_tunneled_info.side_effect = [
57925794
('physnet1', False), ('physnet1', False), ('', True),
57935795
('physnet1', False), ('physnet2', False), ('physnet3', False),
5794-
('physnet4', False),
5796+
('physnet4', False), ('physnet1', False)
57955797
]
57965798
api = neutronapi.API()
57975799

@@ -5808,12 +5810,13 @@ def test_create_resource_requests(self, getclient,
58085810
mock.sentinel.request_group1,
58095811
mock.sentinel.request_group2],
58105812
port_resource_requests)
5811-
self.assertEqual(5, len(pci_requests.requests))
5813+
self.assertEqual(6, len(pci_requests.requests))
58125814
has_pci_request_id = [net.pci_request_id is not None for net in
58135815
requested_networks.objects]
58145816
self.assertEqual(pci_requests.requests[3].spec[0]["dev_type"],
58155817
"type-PF")
5816-
expected_results = [True, False, False, True, True, True, True]
5818+
self.assertEqual(pci_requests.requests[5].spec[0]["dev_type"], "vdpa")
5819+
expected_results = [True, False, False, True, True, True, True, True]
58175820
self.assertEqual(expected_results, has_pci_request_id)
58185821
# Make sure only the trusted VF has the 'trusted' tag set in the spec.
58195822
for pci_req in pci_requests.requests:
@@ -5827,7 +5830,7 @@ def test_create_resource_requests(self, getclient,
58275830

58285831
# Only the port with a resource_request will have pci_req.requester_id.
58295832
self.assertEqual(
5830-
[None, None, None, None, uuids.trusted_port],
5833+
[None, None, None, None, uuids.trusted_port, None],
58315834
[pci_req.requester_id for pci_req in pci_requests.requests])
58325835

58335836
self.assertCountEqual(

0 commit comments

Comments
 (0)