Browse Source

libvirt: check qemu version for NUMA & hugepage support

In commit 945ab28 the libvirt driver was modified to validate the
libvirt version before enabling NUMA and hugepage support.

While good, it's not sufficient.  We also need to check the qemu
version since NUMA hugepage support wasn't added until version 2.1.
(See http://wiki.qemu.org/ChangeLog/2.1#x86, specifically the
memory-backend-* objects.)

We know that qemu on the s390x doesn't support NUMA or hugepages.
Support for ppc64 is possible but not yet determined...we can
update the supported list once we find out for sure.

Change-Id: Ib31c4f806e30a8b33669d5a15bd1578050c7e352
Closes-Bug: #1422775
changes/80/170780/11
Chris Friesen 7 years ago
parent
commit
7f4d7e0b67
  1. 1
      nova/tests/functional/libvirt/test_numa_servers.py
  2. 5
      nova/tests/unit/virt/libvirt/fakelibvirt.py
  3. 111
      nova/tests/unit/virt/libvirt/test_driver.py
  4. 35
      nova/virt/libvirt/driver.py

1
nova/tests/functional/libvirt/test_numa_servers.py

@ -127,6 +127,7 @@ class NUMAServersTest(ServersTestBase):
cpu_threads=2, kB_mem=15740000)
fake_connection = fakelibvirt.Connection('qemu:///system',
version=1002007,
hv_version=2001000,
host_info=host_info)
# Create a flavor

5
nova/tests/unit/virt/libvirt/fakelibvirt.py

@ -743,7 +743,8 @@ class DomainSnapshot(object):
class Connection(object):
def __init__(self, uri=None, readonly=False, version=9011, host_info=None):
def __init__(self, uri=None, readonly=False, version=9011,
hv_version=1001000, host_info=None):
if not uri or uri == '':
if allow_default_uri_connection:
uri = 'qemu:///session'
@ -775,7 +776,7 @@ class Connection(object):
self._nodedevs = {}
self._event_callbacks = {}
self.fakeLibVersion = version
self.fakeVersion = version
self.fakeVersion = hv_version
self.host_info = host_info or HostInfo()
def _add_filter(self, nwfilter):

111
nova/tests/unit/virt/libvirt/test_driver.py

@ -1338,13 +1338,17 @@ class LibvirtConnTestCase(test.NoDBTestCase):
self.assertEqual(0, len(cfg.cputune.vcpupin))
self.assertIsNone(cfg.cpu.numa)
@mock.patch.object(fakelibvirt.Connection, 'getType')
@mock.patch.object(fakelibvirt.Connection, 'getVersion')
@mock.patch.object(fakelibvirt.Connection, 'getLibVersion')
@mock.patch.object(host.Host, 'get_capabilities')
@mock.patch.object(libvirt_driver.LibvirtDriver, '_set_host_enabled')
def _test_get_guest_config_numa_unsupported(self, fake_version,
exception_class, pagesize,
mock_host,
mock_caps, mock_version):
def _test_get_guest_config_numa_unsupported(self, fake_lib_version,
fake_version, fake_type,
fake_arch, exception_class,
pagesize, mock_host,
mock_caps, mock_lib_version,
mock_version, mock_type):
instance_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=0, cpuset=set([0]),
@ -1360,10 +1364,12 @@ class LibvirtConnTestCase(test.NoDBTestCase):
caps = vconfig.LibvirtConfigCaps()
caps.host = vconfig.LibvirtConfigCapsHost()
caps.host.cpu = vconfig.LibvirtConfigCPU()
caps.host.cpu.arch = "x86_64"
caps.host.cpu.arch = fake_arch
caps.host.topology = self._fake_caps_numa_topology()
mock_type.return_value = fake_type
mock_version.return_value = fake_version
mock_lib_version.return_value = fake_lib_version
mock_caps.return_value = caps
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
@ -1375,12 +1381,42 @@ class LibvirtConnTestCase(test.NoDBTestCase):
drvr._get_guest_config,
instance_ref, [], {}, disk_info)
def test_get_guest_config_numa_old_version(self):
def test_get_guest_config_numa_old_version_libvirt(self):
self.flags(virt_type='kvm', group='libvirt')
self._test_get_guest_config_numa_unsupported(
utils.convert_version_to_int(
libvirt_driver.MIN_LIBVIRT_NUMA_VERSION) - 1,
utils.convert_version_to_int(
libvirt_driver.MIN_QEMU_NUMA_HUGEPAGE_VERSION),
libvirt_driver.REQ_HYPERVISOR_NUMA_HUGEPAGE,
arch.X86_64,
exception.NUMATopologyUnsupported,
None)
def test_get_guest_config_numa_old_version_qemu(self):
self.flags(virt_type='kvm', group='libvirt')
self._test_get_guest_config_numa_unsupported(
utils.convert_version_to_int(
libvirt_driver.MIN_LIBVIRT_NUMA_VERSION),
utils.convert_version_to_int(
libvirt_driver.MIN_QEMU_NUMA_HUGEPAGE_VERSION) - 1,
libvirt_driver.REQ_HYPERVISOR_NUMA_HUGEPAGE,
arch.X86_64,
exception.NUMATopologyUnsupported,
None)
def test_get_guest_config_numa_other_arch_qemu(self):
self.flags(virt_type='kvm', group='libvirt')
self._test_get_guest_config_numa_unsupported(
utils.convert_version_to_int(
libvirt_driver.MIN_LIBVIRT_NUMA_VERSION),
utils.convert_version_to_int(
libvirt_driver.MIN_QEMU_NUMA_HUGEPAGE_VERSION),
libvirt_driver.REQ_HYPERVISOR_NUMA_HUGEPAGE,
arch.PPC64,
exception.NUMATopologyUnsupported,
None)
@ -1390,18 +1426,38 @@ class LibvirtConnTestCase(test.NoDBTestCase):
self._test_get_guest_config_numa_unsupported(
utils.convert_version_to_int(
libvirt_driver.MIN_LIBVIRT_NUMA_VERSION),
utils.convert_version_to_int((4, 5, 0)),
'XEN',
arch.X86_64,
exception.NUMATopologyUnsupported,
None)
def test_get_guest_config_numa_old_pages(self):
def test_get_guest_config_numa_old_pages_libvirt(self):
self.flags(virt_type='kvm', group='libvirt')
self._test_get_guest_config_numa_unsupported(
utils.convert_version_to_int(
libvirt_driver.MIN_LIBVIRT_HUGEPAGE_VERSION) - 1,
utils.convert_version_to_int(
libvirt_driver.MIN_QEMU_NUMA_HUGEPAGE_VERSION),
libvirt_driver.REQ_HYPERVISOR_NUMA_HUGEPAGE,
arch.X86_64,
exception.MemoryPagesUnsupported,
2048)
def test_get_guest_config_numa_old_pages_qemu(self):
self.flags(virt_type='kvm', group='libvirt')
self._test_get_guest_config_numa_unsupported(
utils.convert_version_to_int(
libvirt_driver.MIN_LIBVIRT_HUGEPAGE_VERSION),
utils.convert_version_to_int(
libvirt_driver.MIN_QEMU_NUMA_HUGEPAGE_VERSION) - 1,
libvirt_driver.REQ_HYPERVISOR_NUMA_HUGEPAGE,
arch.X86_64,
exception.NUMATopologyUnsupported,
2048)
def test_get_guest_config_numa_host_instance_fit_w_cpu_pinset(self):
instance_ref = objects.Instance(**self.test_instance)
image_meta = {}
@ -8816,6 +8872,8 @@ class LibvirtConnTestCase(test.NoDBTestCase):
def _test_get_host_numa_topology(self, mempages):
caps = vconfig.LibvirtConfigCaps()
caps.host = vconfig.LibvirtConfigCapsHost()
caps.host.cpu = vconfig.LibvirtConfigCPU()
caps.host.cpu.arch = arch.X86_64
caps.host.topology = self._fake_caps_numa_topology()
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
@ -8873,17 +8931,24 @@ class LibvirtConnTestCase(test.NoDBTestCase):
def test_get_host_numa_topology(self, mock_version):
self._test_get_host_numa_topology(mempages=True)
@mock.patch.object(fakelibvirt.Connection, 'getType')
@mock.patch.object(fakelibvirt.Connection, 'getVersion')
@mock.patch.object(fakelibvirt.Connection, 'getLibVersion')
def test_get_host_numa_topology_no_mempages(self, mock_version):
def test_get_host_numa_topology_no_mempages(self, mock_lib_version,
mock_version, mock_type):
self.flags(virt_type='kvm', group='libvirt')
mock_version.return_value = utils.convert_version_to_int(
mock_lib_version.return_value = utils.convert_version_to_int(
libvirt_driver.MIN_LIBVIRT_HUGEPAGE_VERSION) - 1
mock_version.return_value = utils.convert_version_to_int(
libvirt_driver.MIN_QEMU_NUMA_HUGEPAGE_VERSION)
mock_type.return_value = libvirt_driver.REQ_HYPERVISOR_NUMA_HUGEPAGE
self._test_get_host_numa_topology(mempages=False)
def test_get_host_numa_topology_empty(self):
caps = vconfig.LibvirtConfigCaps()
caps.host = vconfig.LibvirtConfigCapsHost()
caps.host.cpu = vconfig.LibvirtConfigCPU()
caps.host.cpu.arch = arch.X86_64
caps.host.topology = None
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
@ -8893,22 +8958,36 @@ class LibvirtConnTestCase(test.NoDBTestCase):
return_value=caps)
) as (has_min_version, get_caps):
self.assertIsNone(drvr._get_host_numa_topology())
get_caps.assert_called_once_with()
self.assertEqual(2, get_caps.call_count)
@mock.patch.object(fakelibvirt.Connection, 'getType')
@mock.patch.object(fakelibvirt.Connection, 'getVersion')
@mock.patch.object(fakelibvirt.Connection, 'getLibVersion')
def test_get_host_numa_topology_old_version(self, mock_version):
def test_get_host_numa_topology_old_version(self, mock_lib_version,
mock_version, mock_type):
self.flags(virt_type='kvm', group='libvirt')
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
mock_version.side_effect = utils.convert_version_to_int(
mock_lib_version.return_value = utils.convert_version_to_int(
libvirt_driver.MIN_LIBVIRT_NUMA_VERSION) - 1
mock_version.return_value = utils.convert_version_to_int(
libvirt_driver.MIN_QEMU_NUMA_HUGEPAGE_VERSION)
mock_type.return_value = libvirt_driver.REQ_HYPERVISOR_NUMA_HUGEPAGE
self.assertIsNone(drvr._get_host_numa_topology())
@mock.patch.object(host.Host, 'has_min_version', return_value=True)
def test_get_host_numa_topology_xen(self, mock_version):
@mock.patch.object(fakelibvirt.Connection, 'getType')
@mock.patch.object(fakelibvirt.Connection, 'getVersion')
@mock.patch.object(fakelibvirt.Connection, 'getLibVersion')
def test_get_host_numa_topology_xen(self, mock_lib_version,
mock_version, mock_type):
self.flags(virt_type='xen', group='libvirt')
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
mock_lib_version.return_value = utils.convert_version_to_int(
libvirt_driver.MIN_LIBVIRT_NUMA_VERSION)
mock_version.return_value = utils.convert_version_to_int(
libvirt_driver.MIN_QEMU_NUMA_HUGEPAGE_VERSION)
mock_type.return_value = 'xen'
self.assertIsNone(drvr._get_host_numa_topology())
def test_diagnostic_vcpus_exception(self):
@ -11160,7 +11239,7 @@ class HostStateTestCase(test.NoDBTestCase):
self.assertEqual(stats["memory_mb_used"], 88)
self.assertEqual(stats["local_gb_used"], 20)
self.assertEqual(stats["hypervisor_type"], 'QEMU')
self.assertEqual(stats["hypervisor_version"], 9011)
self.assertEqual(stats["hypervisor_version"], 1001000)
self.assertEqual(stats["hypervisor_hostname"], 'compute1')
cpu_info = jsonutils.loads(stats["cpu_info"])
self.assertEqual(cpu_info,

35
nova/virt/libvirt/driver.py

@ -364,6 +364,11 @@ MIN_LIBVIRT_NUMA_VERSION = (1, 2, 7)
MIN_LIBVIRT_HUGEPAGE_VERSION = (1, 2, 8)
# missing libvirt cpu pinning support
BAD_LIBVIRT_CPU_POLICY_VERSIONS = [(1, 2, 9, 2), (1, 2, 10)]
# qemu 2.1 introduces support for pinning memory on host
# NUMA nodes, along with the ability to specify hugepage
# sizes per guest NUMA node
MIN_QEMU_NUMA_HUGEPAGE_VERSION = (2, 1, 0)
REQ_HYPERVISOR_NUMA_HUGEPAGE = "QEMU"
# fsFreeze/fsThaw requirement
MIN_LIBVIRT_FSFREEZE_VERSION = (1, 2, 5)
@ -4741,22 +4746,24 @@ class LibvirtDriver(driver.ComputeDriver):
return jsonutils.dumps(pci_info)
def _has_numa_support(self):
if not self._host.has_min_version(MIN_LIBVIRT_NUMA_VERSION):
return False
if CONF.libvirt.virt_type not in ['qemu', 'kvm']:
return False
return True
# This means that the host can support LibvirtConfigGuestNUMATune
# and the nodeset field in LibvirtConfigGuestMemoryBackingPage
supported_archs = [arch.I686, arch.X86_64]
caps = self._host.get_capabilities()
return ((caps.host.cpu.arch in supported_archs) and
self._host.has_min_version(MIN_LIBVIRT_NUMA_VERSION,
MIN_QEMU_NUMA_HUGEPAGE_VERSION,
REQ_HYPERVISOR_NUMA_HUGEPAGE))
def _has_hugepage_support(self):
if not self._host.has_min_version(MIN_LIBVIRT_HUGEPAGE_VERSION):
return False
if CONF.libvirt.virt_type not in ['qemu', 'kvm']:
return False
return True
# This means that the host can support multiple values for the size
# field in LibvirtConfigGuestMemoryBackingPage
supported_archs = [arch.I686, arch.X86_64]
caps = self._host.get_capabilities()
return ((caps.host.cpu.arch in supported_archs) and
self._host.has_min_version(MIN_LIBVIRT_HUGEPAGE_VERSION,
MIN_QEMU_NUMA_HUGEPAGE_VERSION,
REQ_HYPERVISOR_NUMA_HUGEPAGE))
def _get_host_numa_topology(self):
if not self._has_numa_support():

Loading…
Cancel
Save