From c2fd8294fdb615d5229c4eb2abef1226b7cc580b Mon Sep 17 00:00:00 2001 From: Boris Bobrov Date: Tue, 5 Nov 2019 20:06:29 +0100 Subject: [PATCH] Create a controller for qga when SEV is used When a guest agent is requested, it requires a virtio-serial controller. If the controller is not created explicitly, it will be created by libvirt. But if AMD SEV is also requested, the controller is expected to use the iommu driver. In order to achive that, the controller is created explicitly with the required driver. Change-Id: I47c248649b9d77e8bd7c5350fc84d89342be4623 Closes-Bug: 1845986 --- nova/tests/unit/virt/libvirt/test_designer.py | 11 +++++-- nova/tests/unit/virt/libvirt/test_driver.py | 29 ++++++++++++++++--- nova/virt/libvirt/config.py | 4 ++- nova/virt/libvirt/driver.py | 13 +++++++++ .../notes/bug-1845986-70730d9f6c09e68b.yaml | 14 +++++++++ 5 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 releasenotes/notes/bug-1845986-70730d9f6c09e68b.yaml diff --git a/nova/tests/unit/virt/libvirt/test_designer.py b/nova/tests/unit/virt/libvirt/test_designer.py index 750db6ebc1a3..c556cf981764 100644 --- a/nova/tests/unit/virt/libvirt/test_designer.py +++ b/nova/tests/unit/virt/libvirt/test_designer.py @@ -228,12 +228,19 @@ class DesignerTestCase(test.NoDBTestCase): def test_set_driver_iommu_for_sev(self): conf = fake_libvirt_data.fake_kvm_guest() + + # obj.devices[11] + controller = config.LibvirtConfigGuestController() + controller.type = 'virtio-serial' + controller.index = 0 + conf.add_device(controller) + designer.set_driver_iommu_for_sev(conf) # All disks/interfaces/memballoon are expected to be virtio, # thus driver_iommu should be on - self.assertEqual(10, len(conf.devices)) - for i in (0, 2, 3, 6, 8, 9): + self.assertEqual(11, len(conf.devices)) + for i in (0, 2, 3, 6, 8, 9, 10): dev = conf.devices[i] self.assertTrue( dev.driver_iommu, diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index e1083d2a5a10..9c69b796d834 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -3073,7 +3073,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, @mock.patch.object(libvirt_driver.LibvirtDriver, "_has_uefi_support", new=mock.Mock(return_value=True)) - def _setup_sev_guest(self): + def _setup_sev_guest(self, extra_image_properties=None): drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) drvr._host._supports_amd_sev = True @@ -3095,13 +3095,16 @@ class LibvirtConnTestCase(test.NoDBTestCase, instance_ref = objects.Instance(**self.test_instance) instance_ref.flavor = flavor + image_meta_properties = { + 'hw_firmware_type': 'uefi', + 'hw_machine_type': 'q35'} + if extra_image_properties: + image_meta_properties.update(extra_image_properties) image_meta = objects.ImageMeta.from_dict({ 'id': 'd9c6aeee-8258-4bdb-bca4-39940461b182', 'name': 'fakeimage', 'disk_format': 'raw', - 'properties': {'hw_firmware_type': 'uefi', - 'hw_machine_type': 'q35'} - }) + 'properties': image_meta_properties}) disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, instance_ref, @@ -5994,6 +5997,24 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertEqual(cfg.devices[6].type, "unix") self.assertEqual(cfg.devices[6].target_name, "org.qemu.guest_agent.0") + @mock.patch.object(host.Host, 'get_domain_capabilities') + @mock.patch.object(designer, 'set_driver_iommu_for_sev') + def test_get_guest_config_with_qga_through_image_meta_with_sev( + self, mock_designer, fake_domain_caps): + self._setup_fake_domain_caps(fake_domain_caps) + extra_properties = {"hw_qemu_guest_agent": "yes"} + cfg = self._setup_sev_guest(extra_properties) + + self.assertIsInstance(cfg.devices[8], + vconfig.LibvirtConfigGuestController) + self.assertIsInstance(cfg.devices[9], + vconfig.LibvirtConfigGuestChannel) + + self.assertEqual(cfg.devices[8].type, "virtio-serial") + self.assertTrue(cfg.devices[8].uses_virtio) + self.assertEqual(cfg.devices[9].type, "unix") + self.assertEqual(cfg.devices[9].target_name, "org.qemu.guest_agent.0") + def test_get_guest_config_with_video_driver_vram(self): self.flags(enabled=False, group='vnc') self.flags(virt_type='kvm', group='libvirt') diff --git a/nova/virt/libvirt/config.py b/nova/virt/libvirt/config.py index 6e06bcdee0e2..2aafc4b142c6 100644 --- a/nova/virt/libvirt/config.py +++ b/nova/virt/libvirt/config.py @@ -1933,7 +1933,9 @@ class LibvirtConfigGuestController(LibvirtConfigGuestDevice): @property def uses_virtio(self): - return 'virtio-scsi' == self.model + model_is_virtio = 'virtio-scsi' == self.model + type_is_virtio = 'virtio-serial' == self.type + return model_is_virtio or type_is_virtio def format_dom(self): controller = super(LibvirtConfigGuestController, self).format_dom() diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 3cca56d5c2de..61826414f715 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -5147,9 +5147,22 @@ class LibvirtDriver(driver.ComputeDriver): rng_device.backend = rng_path guest.add_device(rng_device) + def _add_virtio_serial_controller(self, guest, instance): + virtio_controller = vconfig.LibvirtConfigGuestController() + virtio_controller.type = 'virtio-serial' + guest.add_device(virtio_controller) + def _set_qemu_guest_agent(self, guest, flavor, instance, image_meta): # Enable qga only if the 'hw_qemu_guest_agent' is equal to yes if image_meta.properties.get('hw_qemu_guest_agent', False): + # a virtio-serial controller is required for qga. If it is not + # created explicitly, libvirt will do it by itself. But in case + # of AMD SEV, any virtio device should use iommu driver, and + # libvirt does not know about it. That is why the controller + # should be created manually. + if self._sev_enabled(flavor, image_meta): + self._add_virtio_serial_controller(guest, instance) + LOG.debug("Qemu guest agent is enabled through image " "metadata", instance=instance) self._add_qga_device(guest, instance) diff --git a/releasenotes/notes/bug-1845986-70730d9f6c09e68b.yaml b/releasenotes/notes/bug-1845986-70730d9f6c09e68b.yaml new file mode 100644 index 000000000000..d50f38290a7d --- /dev/null +++ b/releasenotes/notes/bug-1845986-70730d9f6c09e68b.yaml @@ -0,0 +1,14 @@ +--- +fixes: + - | + `Bug 1845986`_ has been fixed by adding iommu driver when the following + metadata options are used with AMD SEV: + + - ``hw_scsi_model=virtio-scsi`` and either ``hw_disk_bus=scsi`` or + ``hw_cdrom_bus=scsi`` + - ``hw_video_model=virtio`` + + Also a virtio-serial controller is created when ``hw_qemu_guest_agent=yes`` + option is used, together with iommu driver for it. + + .. _Bug 1845986: https://launchpad.net/bugs/1845986