tests: verify pci passthrough with numa
Adding a functional test to verify the allocation of pci devices with the numa a topology in play. Change-Id: I1c6f922bd31937521815758bd0794fe4a28a0ed9
This commit is contained in:
parent
b0a451d428
commit
61bcb831af
|
@ -256,3 +256,69 @@ class SRIOVServersTest(ServersTestBase):
|
|||
|
||||
self._delete_server(pf_server['id'])
|
||||
self._delete_server(vf_server['id'])
|
||||
|
||||
@mock.patch('nova.virt.libvirt.LibvirtDriver._create_image')
|
||||
def test_create_server_with_pci_dev_and_numa(self, img_mock):
|
||||
"""Verifies that an instance can be booted with cpu pinning and with an
|
||||
assigned pci device.
|
||||
"""
|
||||
|
||||
host_info = NumaHostInfo(cpu_nodes=2, cpu_sockets=1, cpu_cores=2,
|
||||
cpu_threads=2, kB_mem=15740000)
|
||||
pci_info = fakelibvirt.HostPciSRIOVDevicesInfo()
|
||||
pci_info.create_pci_devices(num_pfs=1, numa_node=1)
|
||||
fake_connection = self._get_connection(host_info, pci_info)
|
||||
|
||||
# Create a flavor
|
||||
extra_spec = {"pci_passthrough:alias": "%s:1" % self.pfs_alias_name,
|
||||
'hw:numa_nodes': '1',
|
||||
'hw:cpu_policy': 'dedicated',
|
||||
'hw:cpu_thread_policy': 'prefer'}
|
||||
flavor_id = self._create_flavor(extra_spec=extra_spec)
|
||||
host_pass_mock = self._get_pci_passthrough_filter_spy()
|
||||
with test.nested(
|
||||
mock.patch('nova.virt.libvirt.host.Host.get_connection',
|
||||
return_value=fake_connection),
|
||||
mock.patch('nova.scheduler.filters'
|
||||
'.pci_passthrough_filter.PciPassthroughFilter'
|
||||
'.host_passes',
|
||||
side_effect=host_pass_mock)) as (conn_mock,
|
||||
filter_mock):
|
||||
pf_server = self._run_build_test(flavor_id, filter_mock)
|
||||
self._delete_server(pf_server['id'])
|
||||
|
||||
@mock.patch('nova.virt.libvirt.LibvirtDriver._create_image')
|
||||
def test_create_server_with_pci_dev_and_numa_fails(self, img_mock):
|
||||
"""This test ensures that it is not possible to allocated CPU and
|
||||
memory resources from one NUMA node and a PCI device from another.
|
||||
"""
|
||||
|
||||
host_info = NumaHostInfo(cpu_nodes=2, cpu_sockets=1, cpu_cores=2,
|
||||
cpu_threads=2, kB_mem=15740000)
|
||||
pci_info = fakelibvirt.HostPciSRIOVDevicesInfo()
|
||||
pci_info.create_pci_devices(num_pfs=1, numa_node=0)
|
||||
fake_connection = self._get_connection(host_info, pci_info)
|
||||
|
||||
# Create a flavor
|
||||
extra_spec_vm = {'hw:cpu_policy': 'dedicated',
|
||||
'hw:numa_node': '1'}
|
||||
extra_spec = {'pci_passthrough:alias': '%s:1' % self.pfs_alias_name,
|
||||
'hw:numa_nodes': '1',
|
||||
'hw:cpu_policy': 'dedicated',
|
||||
'hw:cpu_thread_policy': 'prefer'}
|
||||
vm_flavor_id = self._create_flavor(vcpu=4, extra_spec=extra_spec_vm)
|
||||
pf_flavor_id = self._create_flavor(extra_spec=extra_spec)
|
||||
host_pass_mock = self._get_pci_passthrough_filter_spy()
|
||||
with test.nested(
|
||||
mock.patch('nova.virt.libvirt.host.Host.get_connection',
|
||||
return_value=fake_connection),
|
||||
mock.patch('nova.scheduler.filters'
|
||||
'.pci_passthrough_filter.PciPassthroughFilter'
|
||||
'.host_passes',
|
||||
side_effect=host_pass_mock)) as (conn_mock,
|
||||
filter_mock):
|
||||
vm_server = self._run_build_test(vm_flavor_id, filter_mock)
|
||||
pf_server = self._run_build_test(pf_flavor_id, filter_mock,
|
||||
end_status='ERROR')
|
||||
self._delete_server(vm_server['id'])
|
||||
self._delete_server(pf_server['id'])
|
||||
|
|
|
@ -189,7 +189,7 @@ class FakePciDevice(object):
|
|||
<iommuGroup number='%(group_id)d'>
|
||||
<address domain='0x0000' bus='0x81' slot='0x%(slot)s' function='0x%(dev)d'/>
|
||||
</iommuGroup>
|
||||
<numa node='0'/>
|
||||
<numa node='%(numa_node)s'/>
|
||||
<pci-express>
|
||||
<link validity='cap' port='0' speed='5' width='8'/>
|
||||
<link validity='sta' speed='5' width='8'/>
|
||||
|
@ -197,7 +197,7 @@ class FakePciDevice(object):
|
|||
</capability>
|
||||
</device>"""
|
||||
|
||||
def __init__(self, dev_type, vf_ratio, group, dev, product_id):
|
||||
def __init__(self, dev_type, vf_ratio, group, dev, product_id, numa_node):
|
||||
"""Populate pci devices
|
||||
|
||||
:param dev_type: (string) Indicates the type of the device (PF, VF)
|
||||
|
@ -205,6 +205,7 @@ class FakePciDevice(object):
|
|||
:param group: (int) iommu group id
|
||||
:param dev: (int) function number of the device
|
||||
:param product_id: (int) Device product ID
|
||||
:param numa_node: (int) NUMA node of the device
|
||||
"""
|
||||
addr_templ = (" <address domain='0x0000' bus='0x81' slot='0x%(slot)s'"
|
||||
" function='0x%(dev)d'/>")
|
||||
|
@ -218,7 +219,7 @@ class FakePciDevice(object):
|
|||
'prod': product_id, 'group_id': group,
|
||||
'functions': '\n'.join(pf_caps), 'slot': 0,
|
||||
'cap_type': PF_CAP_TYPE, 'prod_name': PF_PROD_NAME,
|
||||
'driver': PF_DRIVER_NAME}
|
||||
'driver': PF_DRIVER_NAME, 'numa_node': numa_node}
|
||||
elif dev_type == 'VF':
|
||||
vf_caps = [addr_templ % {'dev': int(dev / vf_ratio),
|
||||
'slot': PF_SLOT}]
|
||||
|
@ -226,7 +227,7 @@ class FakePciDevice(object):
|
|||
'prod': product_id, 'group_id': group,
|
||||
'functions': '\n'.join(vf_caps), 'slot': VF_SLOT,
|
||||
'cap_type': VF_CAP_TYPE, 'prod_name': VF_PROD_NAME,
|
||||
'driver': VF_DRIVER_NAME}
|
||||
'driver': VF_DRIVER_NAME, 'numa_node': numa_node}
|
||||
|
||||
def XMLDesc(self, flags):
|
||||
return self.pci_dev
|
||||
|
@ -238,7 +239,8 @@ class HostPciSRIOVDevicesInfo(object):
|
|||
self.sriov_devices = {}
|
||||
|
||||
def create_pci_devices(self, vf_product_id=1515, pf_product_id=1528,
|
||||
num_pfs=2, num_vfs=8, group=47):
|
||||
num_pfs=2, num_vfs=8, group=47, numa_node=None,
|
||||
total_numa_nodes=2):
|
||||
"""Populate pci devices
|
||||
|
||||
:param vf_product_id: (int) Product ID of the Virtual Functions
|
||||
|
@ -246,7 +248,12 @@ class HostPciSRIOVDevicesInfo(object):
|
|||
:param num_pfs: (int) The number of the Physical Functions
|
||||
:param num_vfs: (int) The number of the Virtual Functions
|
||||
:param group: (int) Initial group id
|
||||
:param numa_node: (int) NUMA node of the device, if set all of the
|
||||
device will be created in the provided node
|
||||
:param total_numa_nodes: (int) total number of NUMA nodes
|
||||
"""
|
||||
def _calc_numa_node(dev):
|
||||
return dev % total_numa_nodes if numa_node is None else numa_node
|
||||
|
||||
vf_ratio = num_vfs / num_pfs
|
||||
|
||||
|
@ -257,7 +264,8 @@ class HostPciSRIOVDevicesInfo(object):
|
|||
'dev': dev}
|
||||
self.sriov_devices[pci_dev_name] = FakePciDevice('PF', vf_ratio,
|
||||
dev_group, dev,
|
||||
pf_product_id)
|
||||
pf_product_id,
|
||||
_calc_numa_node(dev))
|
||||
|
||||
# Generate VFs
|
||||
for dev in range(num_vfs):
|
||||
|
@ -266,7 +274,8 @@ class HostPciSRIOVDevicesInfo(object):
|
|||
'dev': dev}
|
||||
self.sriov_devices[pci_dev_name] = FakePciDevice('VF', vf_ratio,
|
||||
dev_group, dev,
|
||||
vf_product_id)
|
||||
vf_product_id,
|
||||
_calc_numa_node(dev))
|
||||
|
||||
def get_all_devices(self):
|
||||
return self.sriov_devices.keys()
|
||||
|
|
Loading…
Reference in New Issue