Merge "libvirt: Set driver_iommu when attaching virtio devices to SEV instance" into stable/wallaby

This commit is contained in:
Zuul 2021-06-27 07:27:03 +00:00 committed by Gerrit Code Review
commit 90455cdae3
6 changed files with 215 additions and 74 deletions

View File

@ -244,7 +244,7 @@ class DesignerTestCase(test.NoDBTestCase):
designer.set_vif_mtu_config(conf, 9000)
self.assertEqual(9000, conf.mtu)
def test_set_driver_iommu_for_sev(self):
def test_set_driver_iommu(self):
conf = fake_libvirt_data.fake_kvm_guest()
# obj.devices[11]
@ -253,7 +253,7 @@ class DesignerTestCase(test.NoDBTestCase):
controller.index = 0
conf.add_device(controller)
designer.set_driver_iommu_for_sev(conf)
designer.set_driver_iommu_for_all_devices(conf)
# All disks/interfaces/memballoon are expected to be virtio,
# thus driver_iommu should be on

View File

@ -3299,7 +3299,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
self._setup_sev_guest)
@mock.patch.object(host.Host, 'get_domain_capabilities')
@mock.patch.object(designer, 'set_driver_iommu_for_sev')
@mock.patch.object(designer, 'set_driver_iommu_for_all_devices')
def test_get_guest_config_sev(self, mock_designer, fake_domain_caps):
self._setup_fake_domain_caps(fake_domain_caps)
cfg = self._setup_sev_guest()
@ -6459,7 +6459,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
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')
@mock.patch.object(designer, 'set_driver_iommu_for_all_devices')
def test_get_guest_config_with_qga_through_image_meta_with_sev(
self, mock_designer, fake_domain_caps,
):
@ -8817,22 +8817,60 @@ class LibvirtConnTestCase(test.NoDBTestCase,
return fake_config
@mock.patch.object(libvirt_driver.LibvirtDriver, '_sev_enabled',
new=mock.Mock(return_value=False))
@mock.patch.object(volume_drivers.LibvirtFakeVolumeDriver, 'get_config')
@mock.patch.object(libvirt_driver.LibvirtDriver, '_set_cache_mode')
def test_get_volume_config(self, _set_cache_mode, get_config):
def test_get_volume_config(self, mock_set_cache_mode, mock_get_config):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
connection_info = {'driver_volume_type': 'fake',
'data': {'device_path': '/fake',
'access_mode': 'rw'}}
disk_info = {'bus': 'fake-bus', 'type': 'fake-type',
'dev': 'vdb'}
config_guest_disk = self._fake_libvirt_config_guest_disk()
instance = objects.Instance(**self.test_instance)
connection_info = {
'driver_volume_type': 'fake',
'data': {
'device_path': '/fake',
'access_mode': 'rw'
}
}
generated_config = self._fake_libvirt_config_guest_disk()
mock_get_config.return_value = copy.deepcopy(generated_config)
get_config.return_value = copy.deepcopy(config_guest_disk)
config = drvr._get_volume_config(connection_info, disk_info)
get_config.assert_called_once_with(connection_info, disk_info)
_set_cache_mode.assert_called_once_with(config)
self.assertEqual(config_guest_disk.to_xml(), config.to_xml())
returned_config = drvr._get_volume_config(
instance,
connection_info,
mock.sentinel.disk_info)
mock_get_config.assert_called_once_with(
connection_info,
mock.sentinel.disk_info)
mock_set_cache_mode.assert_called_once_with(returned_config)
self.assertEqual(generated_config.to_xml(), returned_config.to_xml())
@mock.patch.object(libvirt_driver.LibvirtDriver, '_sev_enabled',
new=mock.Mock(return_value=True))
@mock.patch.object(libvirt_driver.LibvirtDriver, '_set_cache_mode',
new=mock.Mock())
@mock.patch.object(volume_drivers.LibvirtFakeVolumeDriver, 'get_config')
def test_get_volume_config_sev(self, mock_get_config):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
instance = objects.Instance(**self.test_instance)
connection_info = {
'driver_volume_type': 'fake',
'data': {
'device_path': '/fake',
'access_mode': 'rw'
}
}
generated_config = self._fake_libvirt_config_guest_disk()
generated_config.target_bus = 'virtio'
mock_get_config.return_value = copy.deepcopy(generated_config)
returned_config = drvr._get_volume_config(
instance,
connection_info,
mock.sentinel.disk_info)
# Assert that driver_iommu is enabled for this virtio volume
self.assertTrue(returned_config.driver_iommu)
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_volume_driver')
@mock.patch.object(libvirt_driver.LibvirtDriver, '_attach_encryptor')
@ -9292,7 +9330,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
mock_connect_volume.assert_called_with(
self.context, connection_info, instance, encryption=None)
mock_get_volume_config.assert_called_with(
connection_info, disk_info)
instance, connection_info, disk_info)
mock_dom.attachDeviceFlags.assert_called_with(
mock_conf.to_xml(), flags=flags)
mock_check_discard.assert_called_with(mock_conf, instance)
@ -11492,8 +11530,13 @@ class LibvirtConnTestCase(test.NoDBTestCase,
drvr._live_migration_uri(target_connection),
params=params, flags=0)
mock_updated_guest_xml.assert_called_once_with(
guest, migrate_data, mock.ANY, get_vif_config=None,
new_resources=None)
instance_ref,
guest,
migrate_data,
mock.ANY,
get_vif_config=None,
new_resources=None
)
def test_live_migration_update_vifs_xml(self):
"""Tests that when migrate_data.vifs is populated, the destination
@ -11519,9 +11562,14 @@ class LibvirtConnTestCase(test.NoDBTestCase,
guest = libvirt_guest.Guest(mock.MagicMock())
fake_xml = '<domain type="qemu"/>'
def fake_get_updated_guest_xml(guest, migrate_data, get_volume_config,
get_vif_config=None,
new_resources=None):
def fake_get_updated_guest_xml(
instance,
guest,
migrate_data,
get_volume_config,
get_vif_config=None,
new_resources=None
):
self.assertIsNotNone(get_vif_config)
return fake_xml
@ -11688,18 +11736,30 @@ class LibvirtConnTestCase(test.NoDBTestCase,
conf.source_type = "block"
conf.source_path = bdmi.connection_info['data'].get('device_path')
instance = objects.Instance(**self.test_instance)
guest = libvirt_guest.Guest(mock.MagicMock())
with test.nested(
mock.patch.object(drvr, '_get_volume_config',
return_value=conf),
mock.patch.object(guest, 'get_xml_desc',
return_value=initial_xml)):
config = libvirt_migrate.get_updated_guest_xml(guest,
objects.LibvirtLiveMigrateData(
bdms=[bdmi],
serial_listen_addr='127.0.0.1',
serial_listen_ports=[1234]),
drvr._get_volume_config)
mock.patch.object(
drvr, '_get_volume_config', return_value=conf
),
mock.patch.object(
guest, 'get_xml_desc', return_value=initial_xml
),
mock.patch.object(
drvr, '_sev_enabled', new=mock.Mock(return_value=False)
)
):
config = libvirt_migrate.get_updated_guest_xml(
instance,
guest,
objects.LibvirtLiveMigrateData(
bdms=[bdmi],
serial_listen_addr='127.0.0.1',
serial_listen_ports=[1234]
),
drvr._get_volume_config
)
parser = etree.XMLParser(remove_blank_text=True)
config = etree.fromstring(config, parser)
target_xml = etree.fromstring(target_xml, parser)
@ -11884,18 +11944,30 @@ class LibvirtConnTestCase(test.NoDBTestCase,
conf.source_type = "block"
conf.source_path = bdmi.connection_info['data'].get('device_path')
instance = objects.Instance(**self.test_instance)
guest = libvirt_guest.Guest(mock.MagicMock())
with test.nested(
mock.patch.object(drvr, '_get_volume_config',
return_value=conf),
mock.patch.object(guest, 'get_xml_desc',
return_value=initial_xml)):
config = libvirt_migrate.get_updated_guest_xml(guest,
mock.patch.object(
drvr, '_get_volume_config', return_value=conf
),
mock.patch.object(
guest, 'get_xml_desc', return_value=initial_xml
),
mock.patch.object(
drvr, '_sev_enabled', new=mock.Mock(return_value=False)
)
):
config = libvirt_migrate.get_updated_guest_xml(
instance,
guest,
objects.LibvirtLiveMigrateData(
bdms=[bdmi],
serial_listen_addr = '127.0.0.1',
serial_listen_ports = [1234]),
drvr._get_volume_config)
serial_listen_ports = [1234]
),
drvr._get_volume_config
)
self.assertEqual(target_xml, config)
def test_update_volume_xml_no_connection_info(self):
@ -11918,19 +11990,30 @@ class LibvirtConnTestCase(test.NoDBTestCase,
format='qcow')
bdmi.connection_info = {}
conf = vconfig.LibvirtConfigGuestDisk()
instance = objects.Instance(**self.test_instance)
guest = libvirt_guest.Guest(mock.MagicMock())
with test.nested(
mock.patch.object(drvr, '_get_volume_config',
return_value=conf),
mock.patch.object(guest, 'get_xml_desc',
return_value=initial_xml)):
mock.patch.object(
drvr, '_get_volume_config', return_value=conf
),
mock.patch.object(
guest, 'get_xml_desc', return_value=initial_xml
),
mock.patch.object(
drvr, '_sev_enabled', new=mock.Mock(return_value=False)
)
):
config = libvirt_migrate.get_updated_guest_xml(
instance,
guest,
objects.LibvirtLiveMigrateData(
bdms=[bdmi],
serial_listen_addr='127.0.0.1',
serial_listen_ports=[1234]),
drvr._get_volume_config)
serial_listen_ports=[1234]
),
drvr._get_volume_config
)
self.assertEqual(target_xml, config)
@mock.patch.object(host.Host, 'has_min_version', return_value=True)
@ -19077,7 +19160,9 @@ class LibvirtConnTestCase(test.NoDBTestCase,
self.assertIsNone(instance.default_swap_device)
connect_volume.assert_called_with(self.context,
bdm['connection_info'], instance)
get_volume_config.assert_called_with(bdm['connection_info'],
get_volume_config.assert_called_with(
instance,
bdm['connection_info'],
{'bus': 'virtio', 'type': 'disk', 'dev': 'vdc'})
volume_save.assert_called_once_with()
@ -22855,6 +22940,8 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
mock_save.assert_called_once_with()
mock_set_metadata.assert_called_once_with(config_meta)
@mock.patch('nova.virt.libvirt.designer.set_driver_iommu_for_device')
@mock.patch.object(libvirt_driver.LibvirtDriver, '_sev_enabled')
@mock.patch.object(objects.Instance, 'get_network_info')
@mock.patch.object(objects.Instance, 'save')
@mock.patch.object(libvirt_driver.LibvirtDriver, '_build_device_metadata')
@ -22862,9 +22949,10 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
@mock.patch.object(FakeVirtDomain, 'attachDeviceFlags')
@mock.patch.object(host.Host, '_get_domain')
def _test_attach_interface(self, power_state, expected_flags,
mock_get_domain, mock_attach,
mock_info, mock_build, mock_save,
mock_get_network_info):
mock_get_domain, mock_attach, mock_info,
mock_build, mock_save, mock_get_network_info,
mock_sev_enabled, mock_designer_set_iommu,
sev_enabled=False):
instance = self._create_instance()
network_info = _fake_network_info(self)
domain = FakeVirtDomain(fake_xml="""
@ -22882,6 +22970,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
</domain>""")
mock_get_domain.return_value = domain
mock_info.return_value = [power_state, 1, 2, 3, 4]
mock_sev_enabled.return_value = sev_enabled
fake_image_meta = objects.ImageMeta.from_dict(
{'id': instance.image_ref})
@ -22907,6 +22996,8 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
mock_get_network_info.assert_called_once_with()
mock_attach.assert_called_once_with(expected.to_xml(),
flags=expected_flags)
if sev_enabled:
mock_designer_set_iommu.assert_called_once_with(expected)
def test_attach_interface_with_running_instance(self):
self._test_attach_interface(
@ -22914,6 +23005,13 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
(fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG |
fakelibvirt.VIR_DOMAIN_AFFECT_LIVE))
def test_attach_interface_with_sev(self):
self._test_attach_interface(
power_state.RUNNING,
(fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG |
fakelibvirt.VIR_DOMAIN_AFFECT_LIVE),
sev_enabled=True)
def test_attach_interface_with_pause_instance(self):
self._test_attach_interface(
power_state.PAUSED,

View File

@ -79,10 +79,12 @@ class UtilityMigrationTestCase(test.NoDBTestCase):
get_volume_config = mock.MagicMock()
mock_guest.get_xml_desc.return_value = '<domain></domain>'
migration.get_updated_guest_xml(mock_guest, data, get_volume_config)
migration.get_updated_guest_xml(
mock.sentinel.instance, mock_guest, data, get_volume_config)
mock_graphics.assert_called_once_with(mock.ANY, data)
mock_serial.assert_called_once_with(mock.ANY, data)
mock_volume.assert_called_once_with(mock.ANY, data, get_volume_config)
mock_volume.assert_called_once_with(
mock.ANY, data, mock.sentinel.instance, get_volume_config)
mock_perf_events_xml.assert_called_once_with(mock.ANY, data)
mock_memory_backing.assert_called_once_with(mock.ANY, data)
self.assertEqual(1, mock_tostring.called)
@ -353,8 +355,15 @@ class UtilityMigrationTestCase(test.NoDBTestCase):
get_volume_config = mock.MagicMock(return_value=conf)
doc = etree.fromstring(xml)
res = etree.tostring(migration._update_volume_xml(
doc, data, get_volume_config), encoding='unicode')
res = etree.tostring(
migration._update_volume_xml(
doc,
data,
mock.sentinel.instance,
get_volume_config
),
encoding='unicode'
)
new_xml = xml.replace('ip-1.2.3.4:3260-iqn.abc.12345.opst-lun-X',
'ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z')
self.assertXmlEqual(res, new_xml)
@ -420,10 +429,16 @@ class UtilityMigrationTestCase(test.NoDBTestCase):
get_volume_config = mock.MagicMock(return_value=conf)
doc = etree.fromstring(xml)
res = etree.tostring(migration._update_volume_xml(
doc, data, get_volume_config), encoding='unicode')
new_xml = xml.replace('sdb',
'sdc')
res = etree.tostring(
migration._update_volume_xml(
doc,
data,
mock.sentinel.instance,
get_volume_config
),
encoding='unicode'
)
new_xml = xml.replace('sdb', 'sdc')
self.assertXmlEqual(res, new_xml)
def test_update_volume_xml_add_encryption(self):
@ -509,8 +524,15 @@ class UtilityMigrationTestCase(test.NoDBTestCase):
get_volume_config = mock.MagicMock(return_value=conf)
doc = etree.fromstring(xml)
res = etree.tostring(migration._update_volume_xml(
doc, data, get_volume_config), encoding='unicode')
res = etree.tostring(
migration._update_volume_xml(
doc,
data,
mock.sentinel.instance,
get_volume_config
),
encoding='unicode'
)
self.assertXmlEqual(res, new_xml)
def test_update_volume_xml_update_encryption(self):
@ -577,8 +599,15 @@ class UtilityMigrationTestCase(test.NoDBTestCase):
get_volume_config = mock.MagicMock(return_value=conf)
doc = etree.fromstring(xml)
res = etree.tostring(migration._update_volume_xml(
doc, data, get_volume_config), encoding='unicode')
res = etree.tostring(
migration._update_volume_xml(
doc,
data,
mock.sentinel.instance,
get_volume_config
),
encoding='unicode'
)
new_xml = xml.replace(uuids.encryption_secret_uuid_old,
uuids.encryption_secret_uuid_new)
self.assertXmlEqual(res, new_xml)

View File

@ -205,7 +205,11 @@ def set_vcpu_realtime_scheduler(conf, vcpus_rt, priority):
conf.priority = priority
def set_driver_iommu_for_sev(conf):
def set_driver_iommu_for_device(dev):
if dev.uses_virtio:
dev.driver_iommu = True
def set_driver_iommu_for_all_devices(conf):
for dev in conf.devices:
if dev.uses_virtio:
dev.driver_iommu = True
set_driver_iommu_for_device(dev)

View File

@ -1877,9 +1877,13 @@ class LibvirtDriver(driver.ComputeDriver):
provider = encryptors.LEGACY_PROVIDER_CLASS_TO_FORMAT_MAP[provider]
return provider == encryptors.LUKS
def _get_volume_config(self, connection_info, disk_info):
def _get_volume_config(self, instance, connection_info, disk_info):
vol_driver = self._get_volume_driver(connection_info)
conf = vol_driver.get_config(connection_info, disk_info)
if self._sev_enabled(instance.flavor, instance.image_meta):
designer.set_driver_iommu_for_device(conf)
self._set_cache_mode(conf)
return conf
@ -2037,7 +2041,7 @@ class LibvirtDriver(driver.ComputeDriver):
if disk_info['bus'] == 'scsi':
disk_info['unit'] = self._get_scsi_controller_next_unit(guest)
conf = self._get_volume_config(connection_info, disk_info)
conf = self._get_volume_config(instance, connection_info, disk_info)
self._check_discard_for_attach_volume(conf, instance)
@ -2159,7 +2163,8 @@ class LibvirtDriver(driver.ComputeDriver):
# this to the BDM here as the upper compute swap_volume method will
# eventually do this for us.
self._connect_volume(context, new_connection_info, instance)
conf = self._get_volume_config(new_connection_info, disk_info)
conf = self._get_volume_config(
instance, new_connection_info, disk_info)
hw_firmware_type = instance.image_meta.properties.get(
'hw_firmware_type')
@ -2686,6 +2691,10 @@ class LibvirtDriver(driver.ComputeDriver):
cfg = self.vif_driver.get_config(instance, vif, image_meta,
instance.flavor,
CONF.libvirt.virt_type)
if self._sev_enabled(instance.flavor, image_meta):
designer.set_driver_iommu_for_device(cfg)
try:
state = guest.get_power_state(self._host)
live = state in (power_state.RUNNING, power_state.PAUSED)
@ -5257,7 +5266,7 @@ class LibvirtDriver(driver.ComputeDriver):
else:
info['unit'] = disk_mapping['unit']
disk_mapping['unit'] += 1
cfg = self._get_volume_config(connection_info, info)
cfg = self._get_volume_config(instance, connection_info, info)
devices.append(cfg)
vol['connection_info'] = connection_info
vol.save()
@ -6754,7 +6763,7 @@ class LibvirtDriver(driver.ComputeDriver):
raise exception.MissingDomainCapabilityFeatureException(
feature='sev')
designer.set_driver_iommu_for_sev(guest)
designer.set_driver_iommu_for_all_devices(guest)
self._guest_add_launch_security(guest, sev)
def _guest_add_launch_security(self, guest, sev):
@ -9518,7 +9527,7 @@ class LibvirtDriver(driver.ComputeDriver):
# TODO(sahid): It's not a really good idea to pass
# the method _get_volume_config and we should to find
# a way to avoid this in future.
guest, migrate_data, self._get_volume_config,
instance, guest, migrate_data, self._get_volume_config,
get_vif_config=get_vif_config, new_resources=new_resources)
# NOTE(pkoniszewski): Because of precheck which blocks

View File

@ -53,12 +53,13 @@ def graphics_listen_addrs(migrate_data):
return listen_addrs
def get_updated_guest_xml(guest, migrate_data, get_volume_config,
def get_updated_guest_xml(instance, guest, migrate_data, get_volume_config,
get_vif_config=None, new_resources=None):
xml_doc = etree.fromstring(guest.get_xml_desc(dump_migratable=True))
xml_doc = _update_graphics_xml(xml_doc, migrate_data)
xml_doc = _update_serial_xml(xml_doc, migrate_data)
xml_doc = _update_volume_xml(xml_doc, migrate_data, get_volume_config)
xml_doc = _update_volume_xml(
xml_doc, migrate_data, instance, get_volume_config)
xml_doc = _update_perf_events_xml(xml_doc, migrate_data)
xml_doc = _update_memory_backing_xml(xml_doc, migrate_data)
if get_vif_config is not None:
@ -192,7 +193,7 @@ def _update_serial_xml(xml_doc, migrate_data):
return xml_doc
def _update_volume_xml(xml_doc, migrate_data, get_volume_config):
def _update_volume_xml(xml_doc, migrate_data, instance, get_volume_config):
"""Update XML using device information of destination host."""
migrate_bdm_info = migrate_data.bdms
@ -209,7 +210,7 @@ def _update_volume_xml(xml_doc, migrate_data, get_volume_config):
serial_source not in bdm_info_by_serial):
continue
conf = get_volume_config(
bdm_info.connection_info, bdm_info.as_disk_info())
instance, bdm_info.connection_info, bdm_info.as_disk_info())
if bdm_info.obj_attr_is_set('encryption_secret_uuid'):
conf.encryption = vconfig.LibvirtConfigGuestDiskEncryption()