diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index d2998bfbe590..298b182ec034 100755 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -5826,6 +5826,38 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertEqual(conf.cpu.cores, 1) self.assertEqual(conf.cpu.threads, 1) + def test_get_guest_cpu_config_host_passthrough_aarch64(self): + expected = { + fields.Architecture.X86_64: "host-model", + fields.Architecture.I686: "host-model", + fields.Architecture.PPC: "host-model", + fields.Architecture.PPC64: "host-model", + fields.Architecture.ARMV7: "host-model", + fields.Architecture.AARCH64: "host-passthrough", + } + for guestarch, expect_mode in expected.items(): + caps = vconfig.LibvirtConfigCaps() + caps.host = vconfig.LibvirtConfigCapsHost() + caps.host.cpu = vconfig.LibvirtConfigCPU() + caps.host.cpu.arch = guestarch + with mock.patch.object(host.Host, "get_capabilities", + return_value=caps): + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) + if caps.host.cpu.arch == fields.Architecture.AARCH64: + drvr._has_uefi_support = mock.Mock(return_value=True) + instance_ref = objects.Instance(**self.test_instance) + image_meta = objects.ImageMeta.from_dict(self.test_image_meta) + + disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, + instance_ref, + image_meta) + conf = drvr._get_guest_config(instance_ref, + _fake_network_info(self, 1), + image_meta, disk_info) + self.assertIsInstance(conf.cpu, + vconfig.LibvirtConfigGuestCPU) + self.assertEqual(conf.cpu.mode, expect_mode) + def test_get_guest_cpu_config_host_model(self): drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) instance_ref = objects.Instance(**self.test_instance) diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index ce24cd2be9bc..4209af1a62b0 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -3551,7 +3551,23 @@ class LibvirtDriver(driver.ComputeDriver): if (CONF.libvirt.virt_type == "kvm" or CONF.libvirt.virt_type == "qemu"): if mode is None: - mode = "host-model" + caps = self._host.get_capabilities() + # AArch64 lacks 'host-model' support because neither libvirt + # nor QEMU are able to tell what the host CPU model exactly is. + # And there is no CPU description code for ARM(64) at this + # point. + + # Also worth noting: 'host-passthrough' mode will completely + # break live migration, *unless* all the Compute nodes (running + # libvirtd) have *identical* CPUs. + if caps.host.cpu.arch == fields.Architecture.AARCH64: + mode = "host-passthrough" + LOG.info('CPU mode "host-passthrough" was chosen. Live ' + 'migration can break unless all compute nodes ' + 'have identical cpus. AArch64 does not support ' + 'other modes.') + else: + mode = "host-model" if mode == "none": return vconfig.LibvirtConfigGuestCPU() else: diff --git a/releasenotes/notes/aarch64-set-proper-cpu-mode-8455bad7d69dc6fd.yaml b/releasenotes/notes/aarch64-set-proper-cpu-mode-8455bad7d69dc6fd.yaml new file mode 100644 index 000000000000..6458fbe74c8e --- /dev/null +++ b/releasenotes/notes/aarch64-set-proper-cpu-mode-8455bad7d69dc6fd.yaml @@ -0,0 +1,13 @@ +--- +upgrade: + - | + On AArch64 architecture ``cpu_mode`` for libvirt is set to ``host-passthrough`` + by default. + + AArch64 currently lacks ``host-model`` support because neither libvirt nor + QEMU are able to tell what the host CPU model exactly is and there is no + CPU description code for ARM(64) at this point. + + .. warning:: ``host-passthrough`` mode will completely break live + migration, *unless* all the Compute nodes (running libvirtd) have + *identical* CPUs.