def test_spec_list(self): self.assertTrue(utils.pci_device_prop_match( self.fake_pci_1, [{'vendor_id': 'v1', 'device_id': 'd1', 'capabilities_network': ['cap1', 'cap2', 'cap3']}])) self.assertTrue(utils.pci_device_prop_match( self.fake_pci_1, [{'vendor_id': 'v1', 'device_id': 'd1', 'capabilities_network': ['cap3', 'cap1']}]))
def test_single_spec_match(self): self.assertTrue( utils.pci_device_prop_match(self.fake_pci_1, [{ 'vendor_id': 'v1', 'device_id': 'd1' }])) self.assertTrue( utils.pci_device_prop_match(self.fake_pci_1, [{ 'vendor_id': 'V1', 'device_id': 'D1' }]))
def test_spec_extra_key(self): self.assertFalse( utils.pci_device_prop_match(self.fake_pci_1, [{ 'vendor_id': 'v1', 'device_id': 'd1', 'wrong_key': 'k1' }]))
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 test_spec_list_no_matching(self): self.assertFalse( utils.pci_device_prop_match( self.fake_pci_1, [{ 'vendor_id': 'v1', 'device_id': 'd1', 'capabilities_network': ['cap1', 'cap33'] }]))
def test_spec_dismatch(self): self.assertFalse( utils.pci_device_prop_match(self.fake_pci_1, [{ 'vendor_id': 'v4', 'device_id': 'd4' }, { 'vendor_id': 'v3', 'device_id': 'd3' }]))
def test_multiple_spec_match(self): self.assertTrue( utils.pci_device_prop_match(self.fake_pci_1, [{ 'vendor_id': 'v1', 'device_id': 'd1' }, { 'vendor_id': 'v3', 'device_id': 'd3' }]))
def _filter_pools_for_numa_cells(pools, numa_cells): # Some systems don't report numa node info for pci devices, in # that case None is reported in pci_device.numa_node, by adding None # to numa_cells we allow assigning those devices to instances with # numa topology numa_cells = [None] + [cell.id for cell in numa_cells] # filter out pools which numa_node is not included in numa_cells return [pool for pool in pools if any(utils.pci_device_prop_match( pool, [{'numa_node': cell}]) for cell in numa_cells)]
def _filter_pools_for_spec(self, pools, request): """Filter out pools that don't match the request's device spec. Exclude pools that do not match the specified ``vendor_id``, ``product_id`` and/or ``device_type`` field, or any of the other arbitrary tags such as ``physical_network``, specified in the request. :param pools: A list of PCI device pool dicts :param request: An InstancePCIRequest object describing the type, quantity and required NUMA affinity of device(s) we want. :returns: A list of pools that can be used to support the request if this is possible. """ request_specs = request.spec return [ pool for pool in pools if utils.pci_device_prop_match(pool, request_specs) ]
def _filter_pools_for_spec(pools, request_specs): return [ pool for pool in pools if utils.pci_device_prop_match(pool, request_specs) ]
def _filter_pools_for_numa_cells(cls, pools, numa_cells, numa_policy, requested_count): """Filter out pools with the wrong NUMA affinity, if required. Exclude pools that do not have *suitable* PCI NUMA affinity. ``numa_policy`` determines what *suitable* means, being one of PREFERRED (nice-to-have), LEGACY (must-have-if-available) and REQUIRED (must-have). We iterate through the various policies in order of strictness. This means that even if we only *prefer* PCI-NUMA affinity, we will still attempt to provide it if possible. :param pools: A list of PCI device pool dicts :param numa_cells: A list of InstanceNUMACell objects whose ``id`` corresponds to the ``id`` of host NUMACells. :param numa_policy: The PCI NUMA affinity policy to apply. :param requested_count: The number of PCI devices requested. :returns: A list of pools that can, together, provide at least ``requested_count`` PCI devices with the level of NUMA affinity required by ``numa_policy``, else all pools that can satisfy this policy even if it's not enough. """ # NOTE(stephenfin): We may wish to change the default policy at a later # date requested_policy = numa_policy or fields.PCINUMAAffinityPolicy.LEGACY numa_cell_ids = [cell.id for cell in numa_cells] # filter out pools which numa_node is not included in numa_cell_ids filtered_pools = [ pool for pool in pools if any( utils.pci_device_prop_match(pool, [{ 'numa_node': cell }]) for cell in numa_cell_ids) ] # we can't apply a less strict policy than the one requested, so we # need to return if we've demanded a NUMA affinity of REQUIRED. # However, NUMA affinity is a good thing. If we can get enough devices # with the stricter policy then we will use them. if requested_policy == fields.PCINUMAAffinityPolicy.REQUIRED or sum( pool['count'] for pool in filtered_pools) >= requested_count: return filtered_pools # 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 # suitable NUMA cells. numa_cell_ids.append(None) # filter out pools which numa_node is not included in numa_cell_ids filtered_pools = [ pool for pool in pools if any( utils.pci_device_prop_match(pool, [{ 'numa_node': cell }]) for cell in numa_cell_ids) ] # once again, we can't apply a less strict policy than the one # requested, so we need to return if we've demanded a NUMA affinity of # LEGACY. Similarly, we will also return if we have enough devices to # satisfy this somewhat strict policy. if requested_policy == fields.PCINUMAAffinityPolicy.LEGACY or sum( pool['count'] for pool in filtered_pools) >= requested_count: return filtered_pools # if we've got here, we're using the PREFERRED policy and weren't able # to provide anything with stricter affinity. Use whatever devices you # can, folks. return sorted( pools, key=lambda pool: pool.get('numa_node') not in numa_cell_ids)
def test_spec_list_wrong_type(self): self.assertFalse(utils.pci_device_prop_match( self.fake_pci_1, [{'vendor_id': 'v1', 'device_id': ['d1']}]))
def _filter_pools_for_spec(pools, request_specs): return [pool for pool in pools if utils.pci_device_prop_match(pool, request_specs)]
def test_spec_dismatch(self): self.assertFalse( utils.pci_device_prop_match( self.fake_pci_1, [{"vendor_id": "v4", "device_id": "d4"}, {"vendor_id": "v3", "device_id": "d3"}] ) )
def test_spec_list_no_matching(self): self.assertFalse(utils.pci_device_prop_match( self.fake_pci_1, [{'vendor_id': 'v1', 'device_id': 'd1', 'capabilities_network': ['cap1', 'cap33']}]))
def test_spec_dismatch(self): self.assertFalse(utils.pci_device_prop_match( self.fake_pci_1, [{'vendor_id': 'v4', 'device_id': 'd4'}, {'vendor_id': 'v3', 'device_id': 'd3'}]))
def test_spec_extra_key(self): self.assertFalse(utils.pci_device_prop_match( self.fake_pci_1, [{'vendor_id': 'v1', 'device_id': 'd1', 'wrong_key': 'k1'}]))
def test_single_spec_match(self): self.assertTrue(utils.pci_device_prop_match( self.fake_pci_1, [{'vendor_id': 'v1', 'device_id': 'd1'}])) self.assertTrue(utils.pci_device_prop_match( self.fake_pci_1, [{'vendor_id': 'V1', 'device_id': 'D1'}]))
def test_multiple_spec_match(self): self.assertTrue(utils.pci_device_prop_match( self.fake_pci_1, [{'vendor_id': 'v1', 'device_id': 'd1'}, {'vendor_id': 'v3', 'device_id': 'd3'}]))
def test_spec_extra_key(self): self.assertFalse( utils.pci_device_prop_match(self.fake_pci_1, [{"vendor_id": "v1", "device_id": "d1", "wrong_key": "k1"}]) )
def _filter_pools_for_numa_cells(self, pools, request, numa_cells): """Filter out pools with the wrong NUMA affinity, if required. Exclude pools that do not have *suitable* PCI NUMA affinity. ``numa_policy`` determines what *suitable* means, being one of PREFERRED (nice-to-have), LEGACY (must-have-if-available) and REQUIRED (must-have). We iterate through the various policies in order of strictness. This means that even if we only *prefer* PCI-NUMA affinity, we will still attempt to provide it if possible. :param pools: A list of PCI device pool dicts :param request: An InstancePCIRequest object describing the type, quantity and required NUMA affinity of device(s) we want. :param numa_cells: A list of InstanceNUMACell objects whose ``id`` corresponds to the ``id`` of host NUMACells. :returns: A list of pools that can, together, provide at least ``requested_count`` PCI devices with the level of NUMA affinity required by ``numa_policy``, else all pools that can satisfy this policy even if it's not enough. """ if not numa_cells: return pools # we default to the 'legacy' policy for...of course...legacy reasons requested_policy = fields.PCINUMAAffinityPolicy.LEGACY if 'numa_policy' in request: requested_policy = request.numa_policy or requested_policy requested_count = request.count numa_cell_ids = [cell.id for cell in numa_cells] # filter out pools which numa_node is not included in numa_cell_ids filtered_pools = [ pool for pool in pools if any( utils.pci_device_prop_match(pool, [{ 'numa_node': cell }]) for cell in numa_cell_ids) ] # we can't apply a less strict policy than the one requested, so we # need to return if we've demanded a NUMA affinity of REQUIRED. # However, NUMA affinity is a good thing. If we can get enough devices # with the stricter policy then we will use them. if requested_policy == fields.PCINUMAAffinityPolicy.REQUIRED or sum( 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 # suitable NUMA cells. numa_cell_ids.append(None) # filter out pools which numa_node is not included in numa_cell_ids filtered_pools = [ pool for pool in pools if any( utils.pci_device_prop_match(pool, [{ 'numa_node': cell }]) for cell in numa_cell_ids) ] # once again, we can't apply a less strict policy than the one # requested, so we need to return if we've demanded a NUMA affinity of # LEGACY. Similarly, we will also return if we have enough devices to # satisfy this somewhat strict policy. if requested_policy == fields.PCINUMAAffinityPolicy.LEGACY or sum( pool['count'] for pool in filtered_pools) >= requested_count: return filtered_pools # if we've got here, we're using the PREFERRED policy and weren't able # to provide anything with stricter affinity. Use whatever devices you # can, folks. return sorted( pools, key=lambda pool: pool.get('numa_node') not in numa_cell_ids)
def test_multiple_spec_match(self): self.assertTrue( utils.pci_device_prop_match( self.fake_pci_1, [{"vendor_id": "v1", "device_id": "d1"}, {"vendor_id": "v3", "device_id": "d3"}] ) )
def _filter_pools_for_numa_cells(cls, pools, numa_cells, numa_policy, requested_count): """Filter out pools with the wrong NUMA affinity, if required. Exclude pools that do not have *suitable* PCI NUMA affinity. ``numa_policy`` determines what *suitable* means, being one of PREFERRED (nice-to-have), LEGACY (must-have-if-available) and REQUIRED (must-have). We iterate through the various policies in order of strictness. This means that even if we only *prefer* PCI-NUMA affinity, we will still attempt to provide it if possible. :param pools: A list of PCI device pool dicts :param numa_cells: A list of InstanceNUMACell objects whose ``id`` corresponds to the ``id`` of host NUMACells. :param numa_policy: The PCI NUMA affinity policy to apply. :param requested_count: The number of PCI devices requested. :returns: A list of pools that can, together, provide at least ``requested_count`` PCI devices with the level of NUMA affinity required by ``numa_policy``, else all pools that can satisfy this policy even if it's not enough. """ # NOTE(stephenfin): We may wish to change the default policy at a later # date requested_policy = numa_policy or fields.PCINUMAAffinityPolicy.LEGACY numa_cell_ids = [cell.id for cell in numa_cells] # filter out pools which numa_node is not included in numa_cell_ids filtered_pools = [ pool for pool in pools if any(utils.pci_device_prop_match( pool, [{'numa_node': cell}]) for cell in numa_cell_ids)] # we can't apply a less strict policy than the one requested, so we # need to return if we've demanded a NUMA affinity of REQUIRED. # However, NUMA affinity is a good thing. If we can get enough devices # with the stricter policy then we will use them. if requested_policy == fields.PCINUMAAffinityPolicy.REQUIRED or sum( pool['count'] for pool in filtered_pools) >= requested_count: return filtered_pools # 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 # suitable NUMA cells. numa_cell_ids.append(None) # filter out pools which numa_node is not included in numa_cell_ids filtered_pools = [ pool for pool in pools if any(utils.pci_device_prop_match( pool, [{'numa_node': cell}]) for cell in numa_cell_ids)] # once again, we can't apply a less strict policy than the one # requested, so we need to return if we've demanded a NUMA affinity of # LEGACY. Similarly, we will also return if we have enough devices to # satisfy this somewhat strict policy. if requested_policy == fields.PCINUMAAffinityPolicy.LEGACY or sum( pool['count'] for pool in filtered_pools) >= requested_count: return filtered_pools # if we've got here, we're using the PREFERRED policy and weren't able # to provide anything with stricter affinity. Use whatever devices you # can, folks. return sorted( pools, key=lambda pool: pool.get('numa_node') not in numa_cell_ids)
def test_spec_list_wrong_type(self): self.assertFalse( utils.pci_device_prop_match(self.fake_pci_1, [{ 'vendor_id': 'v1', 'device_id': ['d1'] }]))