Support Cpu Compararion on Aarch64 Platform
The general use case of libvirt's compareCPU() API is to allow comparing a guest CPU to a host CPU. However, for AArch64, the _only_ use case libvirt supports is to allow comparing host CPU with a destination CPU which is accomplished with the help of this patch[1]. So what we're talking about here, in context of AArch64, is comparing source _host_ CPU to destination _host_ CPU, so as to prevent a guest from migrating to a completely different host. For AArch64, in the past we skipped[2] _guest_ CPU to host CPU comparison (the "traditional" use case) check for AArch64 for two main reasons, and these reasons are still valid: 1. There are lots of vendors making different AArch64 CPUs, and they are all not easily comparable because they all differ in various ways. 2. QEMU AArch64 developers themselves recommend that using 'host- passthrough' is the way to run KVM guests on AArch64. In sum, for AArch64, (a) guests should use 'host-passthrough'; and (b) src host to dest host CPU comparison only makes sense to know about _host_ CPU compatibility, but you will not get any CPU config that you can give to a guest. For more detail discussion, please check link [3] and discussion [4]. [1] https://listman.redhat.com/archives/libvir-list/2020-September/msg01391.html — Modify virCPUarmCompare to perform compare actions [2] https://review.opendev.org/c/openstack/nova/+/589769/1/nova/virt/libvirt/driver.py#6892 [3] https://www.redhat.com/archives/libvir-list/2020-September/msg00262.html [4] https://www.redhat.com/archives/libvir-list/2020-September/msg00328.html, Change-Id: I9026f2ec39660408e4ac66fc0a85223e4b25e4d1 Signed-off-by: Kevin Zhao <kevin.zhao@linaro.org>
This commit is contained in:
parent
370830e944
commit
a6ef502aa0
|
@ -11020,22 +11020,49 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||
instance)
|
||||
self.assertIsNone(ret)
|
||||
|
||||
@mock.patch.object(host.Host, 'compare_cpu')
|
||||
@mock.patch.object(fakelibvirt.Connection, 'getLibVersion',
|
||||
return_value=versionutils.convert_version_to_int(
|
||||
libvirt_driver.MIN_LIBVIRT_AARCH64_CPU_COMPARE) - 1
|
||||
)
|
||||
@mock.patch.object(nova.virt.libvirt, 'config')
|
||||
def test_compare_cpu_aarch64_skip_comparison(self,
|
||||
mock_vconfig,
|
||||
mock_compare):
|
||||
mock_get_libversion):
|
||||
instance = objects.Instance(**self.test_instance)
|
||||
skip_comparison_exc = fakelibvirt.make_libvirtError(
|
||||
fakelibvirt.libvirtError,
|
||||
'Host CPU compatibility check does not make '
|
||||
'sense on AArch64; skip CPU comparison')
|
||||
mock_compare.side_effect = skip_comparison_exc
|
||||
self.mock_uname.return_value = fakelibvirt.os_uname(
|
||||
'Linux', '', '5.4.0-0-generic', '', fields.Architecture.AARCH64)
|
||||
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
ret = conn._compare_cpu(None, jsonutils.dumps(_fake_cpu_info_aarch64),
|
||||
instance)
|
||||
self.assertIsNone(ret)
|
||||
|
||||
@mock.patch.object(host.Host, 'get_capabilities')
|
||||
@mock.patch.object(fakelibvirt.Connection, 'getLibVersion',
|
||||
return_value=versionutils.convert_version_to_int(
|
||||
libvirt_driver.MIN_LIBVIRT_AARCH64_CPU_COMPARE))
|
||||
@mock.patch.object(host.Host, 'compare_cpu')
|
||||
def test_compare_cpu_host_aarch64(self,
|
||||
mock_compare,
|
||||
mock_get_libversion,
|
||||
mock_caps):
|
||||
instance = objects.Instance(**self.test_instance)
|
||||
mock_compare.return_value = 6
|
||||
caps = vconfig.LibvirtConfigCaps()
|
||||
caps.host = vconfig.LibvirtConfigCapsHost()
|
||||
caps.host.cpu = vconfig.LibvirtConfigCPU()
|
||||
caps.host.cpu.arch = fields.Architecture.AARCH64
|
||||
caps.host.topology = fakelibvirt.NUMATopology()
|
||||
|
||||
mock_caps.return_value = caps
|
||||
self.mock_uname.return_value = fakelibvirt.os_uname(
|
||||
'Linux', '', '5.4.0-0-generic', '', fields.Architecture.AARCH64)
|
||||
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
ret = conn._compare_cpu(None,
|
||||
jsonutils.dumps(_fake_cpu_info_aarch64),
|
||||
instance)
|
||||
mock_compare.assert_called_once_with(caps.host.cpu.to_xml())
|
||||
self.assertIsNone(ret)
|
||||
|
||||
@mock.patch.object(host.Host, 'compare_cpu')
|
||||
@mock.patch.object(nova.virt.libvirt.LibvirtDriver,
|
||||
'_vcpu_model_to_cpu_config')
|
||||
|
|
|
@ -689,6 +689,23 @@ class HostTestCase(test.NoDBTestCase):
|
|||
self.assertIsNone(caps.host.cpu.model)
|
||||
self.assertEqual(0, len(caps.host.cpu.features))
|
||||
|
||||
def test_get_capabilities_on_aarch64(self):
|
||||
"""Tests that cpu features are not retrieved on aarch64 platform.
|
||||
"""
|
||||
fake_caps_xml = '''
|
||||
<capabilities>
|
||||
<host>
|
||||
<uuid>cef19ce0-0ca2-11df-855d-b193fbce7686</uuid>
|
||||
<cpu>
|
||||
<arch>aarch64</arch>
|
||||
</cpu>
|
||||
</host>
|
||||
</capabilities>'''
|
||||
with mock.patch.object(fakelibvirt.virConnect, 'getCapabilities',
|
||||
return_value=fake_caps_xml):
|
||||
caps = self.host.get_capabilities()
|
||||
self.assertEqual(0, len(caps.host.cpu.features))
|
||||
|
||||
def test__get_machine_types(self):
|
||||
expected = [
|
||||
# NOTE(aspiers): in the real world, i686 would probably
|
||||
|
|
|
@ -219,6 +219,8 @@ MIN_QEMU_VERSION = (4, 2, 0)
|
|||
NEXT_MIN_LIBVIRT_VERSION = (7, 0, 0)
|
||||
NEXT_MIN_QEMU_VERSION = (5, 2, 0)
|
||||
|
||||
MIN_LIBVIRT_AARCH64_CPU_COMPARE = (6, 9, 0)
|
||||
|
||||
# Virtuozzo driver support
|
||||
MIN_VIRTUOZZO_VERSION = (7, 0, 0)
|
||||
|
||||
|
@ -9350,6 +9352,20 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
else:
|
||||
cpu = self._vcpu_model_to_cpu_config(guest_cpu)
|
||||
|
||||
host_cpu = self._host.get_capabilities().host.cpu
|
||||
if host_cpu.arch == fields.Architecture.AARCH64:
|
||||
if self._host.has_min_version(MIN_LIBVIRT_AARCH64_CPU_COMPARE):
|
||||
LOG.debug("On AArch64 hosts, source and destination host "
|
||||
"CPUs are compared to check if they're compatible"
|
||||
"(the only use-case supported by libvirt for "
|
||||
"Arm64/AArch64)")
|
||||
cpu = host_cpu
|
||||
else:
|
||||
LOG.debug("You need %s libvirt version to be able to compare "
|
||||
"source host CPU with destination host CPU; skip "
|
||||
"CPU comparison", MIN_LIBVIRT_AARCH64_CPU_COMPARE)
|
||||
return
|
||||
|
||||
u = ("http://libvirt.org/html/libvirt-libvirt-host.html#"
|
||||
"virCPUCompareResult")
|
||||
m = _("CPU doesn't have compatibility.\n\n%(ret)s\n\nRefer to %(u)s")
|
||||
|
@ -9359,10 +9375,6 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
LOG.debug("cpu compare xml: %s", cpu_xml, instance=instance)
|
||||
ret = self._host.compare_cpu(cpu_xml)
|
||||
except libvirt.libvirtError as e:
|
||||
if cpu.arch == fields.Architecture.AARCH64:
|
||||
LOG.debug("Host CPU compatibility check does not make "
|
||||
"sense on AArch64; skip CPU comparison")
|
||||
return
|
||||
error_code = e.get_error_code()
|
||||
if error_code == libvirt.VIR_ERR_NO_SUPPORT:
|
||||
LOG.debug("URI %(uri)s does not support cpu comparison. "
|
||||
|
|
|
@ -793,13 +793,17 @@ class Host(object):
|
|||
xml_str = self._caps.host.cpu.to_xml()
|
||||
if isinstance(xml_str, bytes):
|
||||
xml_str = xml_str.decode('utf-8')
|
||||
features = self.get_connection().baselineCPU(
|
||||
[xml_str],
|
||||
libvirt.VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES)
|
||||
if features:
|
||||
cpu = vconfig.LibvirtConfigCPU()
|
||||
cpu.parse_str(features)
|
||||
self._caps.host.cpu.features = cpu.features
|
||||
# NOTE(kevinz): The baseline CPU info on Aarch64 will not
|
||||
# include any features. So on Aarch64, we use the original
|
||||
# features from LibvirtConfigCaps.
|
||||
if self._caps.host.cpu.arch != fields.Architecture.AARCH64:
|
||||
features = self.get_connection().baselineCPU(
|
||||
[xml_str],
|
||||
libvirt.VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES)
|
||||
if features:
|
||||
cpu = vconfig.LibvirtConfigCPU()
|
||||
cpu.parse_str(features)
|
||||
self._caps.host.cpu.features = cpu.features
|
||||
except libvirt.libvirtError as ex:
|
||||
error_code = ex.get_error_code()
|
||||
if error_code == libvirt.VIR_ERR_NO_SUPPORT:
|
||||
|
|
Loading…
Reference in New Issue