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