Skip to content

Commit ccab6fe

Browse files
committed
Generate request_id for Flavor based InstancePCIRequest
The InstancePCIRequest.request_id is used to correlate allocated PciDevice objects with the InstancePCIRequest object triggered the PCI allocation. For neutron port based PCI requests the IstancePCIRequest.request_id was already set to a generated UUID by nova. But for Flavor based request the request_id was kept None. The placement PCI scheduling code depends on the request_id to be a unique identifier of the request. So this patch starts filling the request_id for flavor based requests as well. This change showed than in some places nova still uses the request_id == None condition to distinguish between flavor based and neutron based requests. This logic is now adapted to use the newer and better InstancePCIRequest.source based approach. Also we took the opportunity to move the logic of querying PCI devices allocated to an instance to the Instance ovo. This change fills the request_id for newly created flavor based InstancePCIRequest ovos. But the change in logic to use the InstancePCIRequest.source property instead of the request_id == None condition works even if the request_id is None for already existing InstancePCIRequest objects. So this patch does not include a data migration logic to fill request_id for existing objects. blueprint: pci-device-tracking-in-placement Change-Id: I53e03ff7a0221db682b043fb6d5adba3f5c9fdbe
1 parent 06389f8 commit ccab6fe

File tree

9 files changed

+285
-102
lines changed

9 files changed

+285
-102
lines changed

nova/network/neutron.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
from nova.network import model as network_model
4444
from nova import objects
4545
from nova.objects import fields as obj_fields
46-
from nova.pci import manager as pci_manager
4746
from nova.pci import request as pci_request
4847
from nova.pci import utils as pci_utils
4948
from nova.pci import whitelist as pci_whitelist
@@ -1631,8 +1630,7 @@ def _populate_neutron_binding_profile(self, instance, pci_request_id,
16311630
pci_request_id cannot be found on the instance.
16321631
"""
16331632
if pci_request_id:
1634-
pci_devices = pci_manager.get_instance_pci_devs(
1635-
instance, pci_request_id)
1633+
pci_devices = instance.get_pci_devices(request_id=pci_request_id)
16361634
if not pci_devices:
16371635
# The pci_request_id likely won't mean much except for tracing
16381636
# through the logs since it is generated per request.
@@ -1662,8 +1660,7 @@ def _populate_pci_mac_address(instance, pci_request_id, port_req_body):
16621660
Currently this is done only for PF passthrough.
16631661
"""
16641662
if pci_request_id is not None:
1665-
pci_devs = pci_manager.get_instance_pci_devs(
1666-
instance, pci_request_id)
1663+
pci_devs = instance.get_pci_devices(request_id=pci_request_id)
16671664
if len(pci_devs) != 1:
16681665
# NOTE(ndipanov): We shouldn't ever get here since
16691666
# InstancePCIRequest instances built from network requests

nova/objects/instance.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# under the License.
1414

1515
import contextlib
16+
import typing as ty
1617

1718
from oslo_config import cfg
1819
from oslo_db import exception as db_exc
@@ -1226,6 +1227,46 @@ def remove_pci_device_and_request(self, pci_device):
12261227
pci_req for pci_req in self.pci_requests.requests
12271228
if pci_req.request_id != pci_device.request_id]
12281229

1230+
def get_pci_devices(
1231+
self,
1232+
source: ty.Optional[int] = None,
1233+
request_id: ty.Optional[str] = None,
1234+
) -> ty.List["objects.PciDevice"]:
1235+
"""Return the PCI devices allocated to the instance
1236+
1237+
:param source: Filter by source. It can be
1238+
InstancePCIRequest.FLAVOR_ALIAS or InstancePCIRequest.NEUTRON_PORT
1239+
or None. None means returns devices from both type of requests.
1240+
:param request_id: Filter by PciDevice.request_id. None means do not
1241+
filter by request_id.
1242+
:return: a list of matching PciDevice objects
1243+
"""
1244+
if not self.pci_devices:
1245+
# return early to avoid an extra lazy load on self.pci_requests
1246+
# if there are no devices allocated to be filtered
1247+
return []
1248+
else:
1249+
devs = self.pci_devices.objects
1250+
1251+
if request_id is not None:
1252+
devs = [dev for dev in devs if dev.request_id == request_id]
1253+
1254+
if source is not None:
1255+
# NOTE(gibi): this happens to work for the old requests when the
1256+
# request has request_id None and therefore the device allocated
1257+
# due to that request has request_id None too, so they will be
1258+
# mapped via the None key.
1259+
req_id_to_req = {
1260+
req.request_id: req for req in self.pci_requests.requests
1261+
}
1262+
devs = [
1263+
dev
1264+
for dev in devs
1265+
if (req_id_to_req[dev.request_id].source == source)
1266+
]
1267+
1268+
return devs
1269+
12291270

12301271
def _make_instance_list(context, inst_list, db_inst_list, expected_attrs):
12311272
get_fault = expected_attrs and 'fault' in expected_attrs

nova/pci/manager.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -480,24 +480,3 @@ def clean_usage(
480480
devs = self.allocations.pop(uuid, [])
481481
for dev in devs:
482482
self._free_device(dev)
483-
484-
485-
def get_instance_pci_devs(
486-
inst: 'objects.Instance', request_id: str = None,
487-
) -> ty.List['objects.PciDevice']:
488-
"""Get the devices allocated to one or all requests for an instance.
489-
490-
- For generic PCI request, the request id is None.
491-
- For sr-iov networking, the request id is a valid uuid
492-
- There are a couple of cases where all the PCI devices allocated to an
493-
instance need to be returned. Refer to libvirt driver that handles
494-
soft_reboot and hard_boot of 'xen' instances.
495-
"""
496-
pci_devices = inst.pci_devices
497-
if pci_devices is None:
498-
return []
499-
500-
return [
501-
device for device in pci_devices if
502-
device.request_id == request_id or request_id == 'all'
503-
]

nova/pci/request.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import jsonschema
4444
from oslo_log import log as logging
4545
from oslo_serialization import jsonutils
46+
from oslo_utils import uuidutils
4647

4748
import nova.conf
4849
from nova import context as ctx
@@ -183,7 +184,9 @@ def _translate_alias_to_requests(
183184
count=int(count),
184185
spec=spec,
185186
alias_name=name,
186-
numa_policy=policy))
187+
numa_policy=policy,
188+
request_id=uuidutils.generate_uuid(),
189+
))
187190
return pci_requests
188191

189192

nova/tests/unit/network/test_neutron.py

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
from nova.objects import fields as obj_fields
4343
from nova.objects import network_request as net_req_obj
4444
from nova.objects import virtual_interface as obj_vif
45-
from nova.pci import manager as pci_manager
4645
from nova.pci import request as pci_request
4746
from nova.pci import utils as pci_utils
4847
from nova.pci import whitelist as pci_whitelist
@@ -7738,11 +7737,11 @@ def test_populate_neutron_extension_values_binding(self, mock_get_client):
77387737
'vf_num': 1,
77397738
}))
77407739
@mock.patch.object(pci_whitelist.Whitelist, 'get_devspec')
7741-
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
7740+
@mock.patch('nova.objects.Instance.get_pci_devices')
77427741
def test_populate_neutron_extension_values_binding_sriov(
77437742
self, mock_get_instance_pci_devs, mock_get_pci_device_devspec):
77447743
host_id = 'my_host_id'
7745-
instance = {'host': host_id}
7744+
instance = objects.Instance(host=host_id)
77467745
port_req_body = {'port': {}}
77477746
pci_req_id = 'my_req_id'
77487747
pci_dev = {'vendor_id': '1377',
@@ -7783,11 +7782,11 @@ def test_populate_neutron_extension_values_binding_sriov(
77837782
})
77847783
)
77857784
@mock.patch.object(pci_whitelist.Whitelist, 'get_devspec')
7786-
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
7785+
@mock.patch('nova.objects.Instance.get_pci_devices')
77877786
def test_populate_neutron_extension_values_binding_sriov_card_serial(
77887787
self, mock_get_instance_pci_devs, mock_get_pci_device_devspec):
77897788
host_id = 'my_host_id'
7790-
instance = {'host': host_id}
7789+
instance = objects.Instance(host=host_id)
77917790
port_req_body = {'port': {}}
77927791
pci_req_id = 'my_req_id'
77937792
pci_dev = {'vendor_id': 'a2d6',
@@ -7867,11 +7866,11 @@ def test_populate_neutron_extension_values_with_arq(self,
78677866
})
78687867
)
78697868
@mock.patch.object(pci_whitelist.Whitelist, 'get_devspec')
7870-
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
7869+
@mock.patch('nova.objects.Instance.get_pci_devices')
78717870
def test_populate_neutron_extension_values_binding_sriov_with_cap(
78727871
self, mock_get_instance_pci_devs, mock_get_pci_device_devspec):
78737872
host_id = 'my_host_id'
7874-
instance = {'host': host_id}
7873+
instance = objects.Instance(host=host_id)
78757874
port_req_body = {'port': {
78767875
constants.BINDING_PROFILE: {
78777876
'capabilities': ['switchdev']}}}
@@ -7907,12 +7906,12 @@ def test_populate_neutron_extension_values_binding_sriov_with_cap(
79077906
constants.BINDING_PROFILE])
79087907

79097908
@mock.patch.object(pci_whitelist.Whitelist, 'get_devspec')
7910-
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
7909+
@mock.patch('nova.objects.Instance.get_pci_devices')
79117910
def test_populate_neutron_extension_values_binding_sriov_pf(
79127911
self, mock_get_instance_pci_devs, mock_get_devspec
79137912
):
79147913
host_id = 'my_host_id'
7915-
instance = {'host': host_id}
7914+
instance = objects.Instance(host=host_id)
79167915
port_req_body = {'port': {}}
79177916

79187917
pci_dev = objects.PciDevice(
@@ -8041,11 +8040,11 @@ def test__get_pci_device_profile_pf(self, mock_get_pci_device_devspec):
80418040
)
80428041

80438042
@mock.patch.object(pci_whitelist.Whitelist, 'get_devspec')
8044-
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
8043+
@mock.patch('nova.objects.Instance.get_pci_devices')
80458044
def test_populate_neutron_extension_values_binding_sriov_fail(
80468045
self, mock_get_instance_pci_devs, mock_get_pci_device_devspec):
80478046
host_id = 'my_host_id'
8048-
instance = {'host': host_id}
8047+
instance = objects.Instance(host=host_id)
80498048
port_req_body = {'port': {}}
80508049
pci_req_id = 'my_req_id'
80518050
pci_objs = [objects.PciDevice(vendor_id='1377',
@@ -8062,7 +8061,7 @@ def test_populate_neutron_extension_values_binding_sriov_fail(
80628061
self.api._populate_neutron_binding_profile,
80638062
instance, pci_req_id, port_req_body, None)
80648063

8065-
@mock.patch.object(pci_manager, 'get_instance_pci_devs', return_value=[])
8064+
@mock.patch('nova.objects.Instance.get_pci_devices', return_value=[])
80668065
def test_populate_neutron_binding_profile_pci_dev_not_found(
80678066
self, mock_get_instance_pci_devs):
80688067
api = neutronapi.API()
@@ -8073,7 +8072,7 @@ def test_populate_neutron_binding_profile_pci_dev_not_found(
80738072
api._populate_neutron_binding_profile,
80748073
instance, pci_req_id, port_req_body, None)
80758074
mock_get_instance_pci_devs.assert_called_once_with(
8076-
instance, pci_req_id)
8075+
request_id=pci_req_id)
80778076

80788077
@mock.patch.object(
80798078
pci_utils, 'is_physical_function',
@@ -8089,7 +8088,7 @@ def test_populate_neutron_binding_profile_pci_dev_not_found(
80898088
new=mock.MagicMock(side_effect=(lambda vf_a: {
80908089
'0000:0a:00.0': '52:54:00:1e:59:c6'}.get(vf_a)))
80918090
)
8092-
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
8091+
@mock.patch('nova.objects.Instance.get_pci_devices')
80938092
def test_pci_parse_whitelist_called_once(
80948093
self, mock_get_instance_pci_devs
80958094
):
@@ -8108,7 +8107,7 @@ def test_pci_parse_whitelist_called_once(
81088107
# after the 'device_spec' is set in this test case.
81098108
api = neutronapi.API()
81108109
host_id = 'my_host_id'
8111-
instance = {'host': host_id}
8110+
instance = objects.Instance(host=host_id)
81128111
pci_req_id = 'my_req_id'
81138112
port_req_body = {'port': {}}
81148113
pci_dev = {'vendor_id': '1377',
@@ -8144,7 +8143,7 @@ def _populate_pci_mac_address_fakes(self):
81448143
vf.update_device(pci_dev)
81458144
return instance, pf, vf
81468145

8147-
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
8146+
@mock.patch('nova.objects.Instance.get_pci_devices')
81488147
@mock.patch.object(pci_utils, 'get_mac_by_pci_address')
81498148
def test_populate_pci_mac_address_pf(self, mock_get_mac_by_pci_address,
81508149
mock_get_instance_pci_devs):
@@ -8158,7 +8157,7 @@ def test_populate_pci_mac_address_pf(self, mock_get_mac_by_pci_address,
81588157
self.api._populate_pci_mac_address(instance, 0, req)
81598158
self.assertEqual(expected_port_req_body, req)
81608159

8161-
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
8160+
@mock.patch('nova.objects.Instance.get_pci_devices')
81628161
@mock.patch.object(pci_utils, 'get_mac_by_pci_address')
81638162
def test_populate_pci_mac_address_vf(self, mock_get_mac_by_pci_address,
81648163
mock_get_instance_pci_devs):
@@ -8170,7 +8169,7 @@ def test_populate_pci_mac_address_vf(self, mock_get_mac_by_pci_address,
81708169
self.api._populate_pci_mac_address(instance, 42, port_req_body)
81718170
self.assertEqual(port_req_body, req)
81728171

8173-
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
8172+
@mock.patch('nova.objects.Instance.get_pci_devices')
81748173
@mock.patch.object(pci_utils, 'get_mac_by_pci_address')
81758174
def test_populate_pci_mac_address_vf_fail(self,
81768175
mock_get_mac_by_pci_address,
@@ -8185,7 +8184,7 @@ def test_populate_pci_mac_address_vf_fail(self,
81858184
self.api._populate_pci_mac_address(instance, 42, port_req_body)
81868185
self.assertEqual(port_req_body, req)
81878186

8188-
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
8187+
@mock.patch('nova.objects.Instance.get_pci_devices')
81898188
@mock.patch('nova.network.neutron.LOG.error')
81908189
def test_populate_pci_mac_address_no_device(self, mock_log_error,
81918190
mock_get_instance_pci_devs):

0 commit comments

Comments
 (0)