summaryrefslogtreecommitdiff
path: root/nova/pci
diff options
context:
space:
mode:
authorArtom Lifshitz <alifshit@redhat.com>2021-01-27 17:03:09 -0500
committerArtom Lifshitz <alifshit@redhat.com>2021-03-10 17:06:03 -0500
commitb2471dd5780ae4173aeea9229645bbe5116fa817 (patch)
treefd3cf29e051c4c846bdc48ed1882887c89d0b7b3 /nova/pci
parent890b6d54a6f885cb6dd032dbf8186116df14eb6b (diff)
downloadnova-b2471dd5780ae4173aeea9229645bbe5116fa817.tar.gz
pci: implement the 'socket' NUMA affinity policy
This patch enables the 'socket' PCI NUMA affinity policy. The PCI manager gets a new method to implement it, and the libvirt driver starts reporting the necessary trait, enabling it to receive instances with the 'socket' policy. Implements: blueprint pci-socket-affinity Change-Id: Ia875c9c3542ef4138d0d7a2c26c0cf49dcca0761
Diffstat (limited to 'nova/pci')
-rw-r--r--nova/pci/stats.py46
1 files changed, 44 insertions, 2 deletions
diff --git a/nova/pci/stats.py b/nova/pci/stats.py
index cb36cbadc1..937c130dc8 100644
--- a/nova/pci/stats.py
+++ b/nova/pci/stats.py
@@ -298,6 +298,15 @@ class PciDeviceStats(object):
pool['count'] for pool in filtered_pools) >= requested_count:
return filtered_pools
+ # the SOCKET policy is a bit of a special case. It's less strict than
+ # REQUIRED (so REQUIRED will automatically fulfil SOCKET, at least
+ # with our assumption of never having multiple sockets per NUMA node),
+ # but not always more strict than LEGACY: a PCI device with no NUMA
+ # affinity will fulfil LEGACY but not SOCKET. If we have SOCKET,
+ # process it here and don't continue.
+ if requested_policy == fields.PCINUMAAffinityPolicy.SOCKET:
+ return self._filter_pools_for_socket_affinity(pools, numa_cells)
+
# some systems don't report NUMA node info for PCI devices, in which
# case None is reported in 'pci_device.numa_node'. The LEGACY policy
# allows us to use these devices so we include None in the list of
@@ -323,6 +332,39 @@ class PciDeviceStats(object):
return sorted(
pools, key=lambda pool: pool.get('numa_node') not in numa_cell_ids)
+ def _filter_pools_for_socket_affinity(self, pools, numa_cells):
+ host_cells = self.numa_topology.cells
+ # bail early if we don't have socket information for all host_cells.
+ # This could happen if we're running on an weird older system with
+ # multiple sockets per NUMA node, which is a configuration that we
+ # explicitly chose not to support.
+ if any(cell.socket is None for cell in host_cells):
+ LOG.debug('No socket information in host NUMA cell(s).')
+ return []
+
+ # get a set of host sockets that the guest cells are in. Since guest
+ # cell IDs map to host cell IDs, we can just lookup the latter's
+ # socket.
+ socket_ids = set()
+ for guest_cell in numa_cells:
+ for host_cell in host_cells:
+ if guest_cell.id == host_cell.id:
+ socket_ids.add(host_cell.socket)
+
+ # now get a set of host NUMA nodes that are in the above sockets
+ allowed_numa_nodes = set()
+ for host_cell in host_cells:
+ if host_cell.socket in socket_ids:
+ allowed_numa_nodes.add(host_cell.id)
+
+ # filter out pools that are not in one of the correct host NUMA nodes.
+ return [
+ pool for pool in pools if any(
+ utils.pci_device_prop_match(pool, [{'numa_node': numa_node}])
+ for numa_node in allowed_numa_nodes
+ )
+ ]
+
def _filter_pools_for_unrequested_pfs(self, pools, request):
"""Filter out pools with PFs, unless these are required.
@@ -383,8 +425,8 @@ class PciDeviceStats(object):
return None
# Next, let's exclude all devices that aren't on the correct NUMA node
- # *assuming* we have devices and care about that, as determined by
- # policy
+ # or socket, *assuming* we have devices and care about that, as
+ # determined by policy
before_count = after_count
pools = self._filter_pools_for_numa_cells(pools, request, numa_cells)
after_count = sum([pool['count'] for pool in pools])