summaryrefslogtreecommitdiff
path: root/nova/objects
diff options
context:
space:
mode:
authorBalazs Gibizer <gibi@redhat.com>2022-08-16 17:24:28 +0200
committerBalazs Gibizer <gibi@redhat.com>2022-10-17 13:56:18 +0200
commitb10482cbc00518853485d83a9ace35c8d5172749 (patch)
treeb00d8d1052e8253c74a8d57383104636d7abca76 /nova/objects
parent745921338c8338e39267dce2cdf8877877326212 (diff)
downloadnova-b10482cbc00518853485d83a9ace35c8d5172749.tar.gz
Support resource_class and traits in PCI alias
The [pci]alias configuration option now accepts two new optional fields: * resource_class: that can be used to request PCI device by placement RC name. * traits: a comma separated list of placement trait names that can be used to filter placement PCI resource provider by traits. These fields has the matching counterpart in [pci]device_spec implemented already. These fields are matched by the Placement GET allocation_candidates query therefore these fields are ignored when PCI device pools are matched against IntancePCIRequest by nova. Note that InstancePCIRequest object spec field is defined as a list of dicts. But in reality nova creates the request always with a single dict. So we restricted the placement logic to handle a single spec. blueprint: pci-device-tracking-in-placement Change-Id: I5c8f05c3c5d7597175e60b29e4ab2f22e6496ecd
Diffstat (limited to 'nova/objects')
-rw-r--r--nova/objects/request_spec.py65
1 files changed, 52 insertions, 13 deletions
diff --git a/nova/objects/request_spec.py b/nova/objects/request_spec.py
index 00521c3678..6a22131901 100644
--- a/nova/objects/request_spec.py
+++ b/nova/objects/request_spec.py
@@ -14,12 +14,14 @@
import copy
import itertools
+import typing as ty
import os_resource_classes as orc
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import versionutils
+from nova.compute import pci_placement_translator
from nova.db.api import api as api_db_api
from nova.db.api import models as api_models
from nova import exception
@@ -474,14 +476,16 @@ class RequestSpec(base.NovaObject):
return filt_props
@staticmethod
- def _rc_from_request(pci_request: 'objects.InstancePCIRequest') -> str:
- # FIXME(gibi): refactor this and the copy of the logic from the
- # translator to a common function
- # FIXME(gibi): handle directly requested resource_class
- # ??? can there be more than one spec???
- spec = pci_request.spec[0]
- rc = f"CUSTOM_PCI_{spec['vendor_id']}_{spec['product_id']}".upper()
- return rc
+ def _rc_from_request(spec: ty.Dict[str, ty.Any]) -> str:
+ return pci_placement_translator.get_resource_class(
+ spec.get("resource_class"),
+ spec.get("vendor_id"),
+ spec.get("product_id"),
+ )
+
+ @staticmethod
+ def _traits_from_request(spec: ty.Dict[str, ty.Any]) -> ty.Set[str]:
+ return pci_placement_translator.get_traits(spec.get("traits", ""))
# This is here temporarily until the PCI placement scheduling is under
# implementation. When that is done there will be a config option
@@ -501,6 +505,34 @@ class RequestSpec(base.NovaObject):
# cycle.
continue
+ if len(pci_request.spec) != 1:
+ # We are instantiating InstancePCIRequest objects with spec in
+ # two cases:
+ # 1) when a neutron port is translated to InstancePCIRequest
+ # object in
+ # nova.network.neutron.API.create_resource_requests
+ # 2) when the pci_passthrough:alias flavor extra_spec is
+ # translated to InstancePCIRequest objects in
+ # nova.pci.request._get_alias_from_config which enforces the
+ # json schema defined in nova.pci.request.
+ #
+ # In both cases only a single dict is added to the spec list.
+ # If we ever want to add support for multiple specs per request
+ # then we have to solve the issue that each spec can request a
+ # different resource class from placement. The only place in
+ # nova that currently handles multiple specs per request is
+ # nova.pci.utils.pci_device_prop_match() and it considers them
+ # as alternatives. So specs with different resource classes
+ # would mean alternative resource_class requests. This cannot
+ # be expressed today in the allocation_candidate query towards
+ # placement.
+ raise ValueError(
+ "PCI tracking in placement does not support multiple "
+ "specs per PCI request"
+ )
+
+ spec = pci_request.spec[0]
+
# The goal is to translate InstancePCIRequest to RequestGroup. Each
# InstancePCIRequest can be fulfilled from the whole RP tree. And
# a flavor based InstancePCIRequest might request more than one
@@ -533,9 +565,13 @@ class RequestSpec(base.NovaObject):
# per requested device. So for InstancePCIRequest(count=2) we need
# to generate two separate RequestGroup(RC:1) objects.
- # FIXME(gibi): make sure that if we have count=2 requests then
- # group_policy=none is in the request as group_policy=isolate
- # would prevent allocating two VFs from the same PF.
+ # NOTE(gibi): If we have count=2 requests then the multiple
+ # RequestGroup split below only works if group_policy is set to
+ # none as group_policy=isolate would prevent allocating two VFs
+ # from the same PF. Fortunately
+ # nova.scheduler.utils.resources_from_request_spec() already
+ # defaults group_policy to none if it is not specified in the
+ # flavor and there are multiple RequestGroups in the RequestSpec.
for i in range(pci_request.count):
rg = objects.RequestGroup(
@@ -546,8 +582,11 @@ class RequestSpec(base.NovaObject):
# as we split count >= 2 requests to independent groups
# each group will have a resource request of one
resources={
- self._rc_from_request(pci_request): 1}
- # FIXME(gibi): handle traits requested from alias
+ self._rc_from_request(spec): 1
+ },
+ required_traits=self._traits_from_request(spec),
+ # TODO(gibi): later we can add support for complex trait
+ # queries here including forbidden_traits.
)
self.requested_resources.append(rg)