Skip to content

Commit 6009cda

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Hide hypervisor id on windows guests"
2 parents 1da3c4c + ca54343 commit 6009cda

File tree

5 files changed

+97
-10
lines changed

5 files changed

+97
-10
lines changed

nova/tests/unit/virt/libvirt/test_config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2182,13 +2182,15 @@ def test_feature_hyperv_all(self):
21822182
obj.relaxed = True
21832183
obj.vapic = True
21842184
obj.spinlocks = True
2185+
obj.vendorid_spoof = True
21852186

21862187
xml = obj.to_xml()
21872188
self.assertXmlEqual(xml, """
21882189
<hyperv>
21892190
<relaxed state="on"/>
21902191
<vapic state="on"/>
21912192
<spinlocks state="on" retries="4095"/>
2193+
<vendor_id state="on" value="1234567890ab"/>
21922194
</hyperv>""")
21932195

21942196

nova/tests/unit/virt/libvirt/test_driver.py

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3812,13 +3812,17 @@ def test_get_guest_config_windows_timer(self, mock_get_arch):
38123812
self.assertIsInstance(cfg.features[2],
38133813
vconfig.LibvirtConfigGuestFeatureHyperV)
38143814

3815-
@mock.patch.object(host.Host, 'has_min_version')
3816-
def test_get_guest_config_windows_hyperv_feature2(self, mock_version):
3817-
mock_version.return_value = True
3815+
@mock.patch.object(host.Host, 'has_min_version',
3816+
new=mock.Mock(return_value=True))
3817+
def _test_get_guest_config_windows_hyperv(
3818+
self, flavor=None, image_meta=None, hvid_hidden=False):
38183819
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
38193820
instance_ref = objects.Instance(**self.test_instance)
38203821
instance_ref['os_type'] = 'windows'
3821-
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
3822+
if flavor is not None:
3823+
instance_ref.flavor = flavor
3824+
if image_meta is None:
3825+
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
38223826

38233827
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
38243828
instance_ref,
@@ -3831,18 +3835,67 @@ def test_get_guest_config_windows_hyperv_feature2(self, mock_version):
38313835
vconfig.LibvirtConfigGuestClock)
38323836
self.assertEqual(cfg.clock.offset, "localtime")
38333837

3834-
self.assertEqual(3, len(cfg.features))
3838+
num_features = 4 if hvid_hidden else 3
3839+
self.assertEqual(num_features, len(cfg.features))
38353840
self.assertIsInstance(cfg.features[0],
38363841
vconfig.LibvirtConfigGuestFeatureACPI)
38373842
self.assertIsInstance(cfg.features[1],
38383843
vconfig.LibvirtConfigGuestFeatureAPIC)
38393844
self.assertIsInstance(cfg.features[2],
38403845
vconfig.LibvirtConfigGuestFeatureHyperV)
3846+
if hvid_hidden:
3847+
self.assertIsInstance(cfg.features[3],
3848+
vconfig.LibvirtConfigGuestFeatureKvmHidden)
38413849

38423850
self.assertTrue(cfg.features[2].relaxed)
38433851
self.assertTrue(cfg.features[2].spinlocks)
38443852
self.assertEqual(8191, cfg.features[2].spinlock_retries)
38453853
self.assertTrue(cfg.features[2].vapic)
3854+
self.assertEqual(hvid_hidden, cfg.features[2].vendorid_spoof)
3855+
3856+
def test_get_guest_config_windows_hyperv_feature2(self):
3857+
self._test_get_guest_config_windows_hyperv()
3858+
3859+
def test_get_guest_config_windows_hyperv_all_hide_flv(self):
3860+
# Similar to test_get_guest_config_windows_hyperv_feature2
3861+
# but also test hiding the HyperV signature with the flavor
3862+
# extra_spec "hide_hypervisor_id"
3863+
flavor_hide_id = fake_flavor.fake_flavor_obj(self.context,
3864+
extra_specs={"hide_hypervisor_id": "true"},
3865+
expected_attrs={"extra_specs"})
3866+
# this works for kvm (the default, tested below) and qemu
3867+
self.flags(virt_type='qemu', group='libvirt')
3868+
3869+
self._test_get_guest_config_windows_hyperv(
3870+
flavor=flavor_hide_id, hvid_hidden=True)
3871+
3872+
def test_get_guest_config_windows_hyperv_all_hide_img(self):
3873+
# Similar to test_get_guest_config_windows_hyperv_feature2
3874+
# but also test hiding the HyperV signature with the image
3875+
# property "img_hide_hypervisor_id"
3876+
image_meta = objects.ImageMeta.from_dict({
3877+
"disk_format": "raw",
3878+
"properties": {"img_hide_hypervisor_id": "true"}})
3879+
3880+
self._test_get_guest_config_windows_hyperv(
3881+
image_meta=image_meta, hvid_hidden=True)
3882+
3883+
def test_get_guest_config_windows_hyperv_all_hide_flv_img(self):
3884+
# Similar to test_get_guest_config_windows_hyperv_feature2
3885+
# but also test hiding the HyperV signature with both the flavor
3886+
# extra_spec "hide_hypervisor_id" and the image property
3887+
# "img_hide_hypervisor_id"
3888+
flavor_hide_id = fake_flavor.fake_flavor_obj(self.context,
3889+
extra_specs={"hide_hypervisor_id": "true"},
3890+
expected_attrs={"extra_specs"})
3891+
self.flags(virt_type='qemu', group='libvirt')
3892+
3893+
image_meta = objects.ImageMeta.from_dict({
3894+
"disk_format": "raw",
3895+
"properties": {"img_hide_hypervisor_id": "true"}})
3896+
3897+
self._test_get_guest_config_windows_hyperv(
3898+
flavor=flavor_hide_id, image_meta=image_meta, hvid_hidden=True)
38463899

38473900
def test_get_guest_config_with_two_nics(self):
38483901
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)

nova/virt/libvirt/config.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2334,6 +2334,8 @@ class LibvirtConfigGuestFeatureHyperV(LibvirtConfigGuestFeature):
23342334

23352335
# QEMU requires at least this value to be set
23362336
MIN_SPINLOCK_RETRIES = 4095
2337+
# The spoofed vendor_id can be any alphanumeric string
2338+
SPOOFED_VENDOR_ID = "1234567890ab"
23372339

23382340
def __init__(self, **kwargs):
23392341
super(LibvirtConfigGuestFeatureHyperV, self).__init__("hyperv",
@@ -2343,6 +2345,8 @@ def __init__(self, **kwargs):
23432345
self.vapic = False
23442346
self.spinlocks = False
23452347
self.spinlock_retries = self.MIN_SPINLOCK_RETRIES
2348+
self.vendorid_spoof = False
2349+
self.vendorid = self.SPOOFED_VENDOR_ID
23462350

23472351
def format_dom(self):
23482352
root = super(LibvirtConfigGuestFeatureHyperV, self).format_dom()
@@ -2354,6 +2358,9 @@ def format_dom(self):
23542358
if self.spinlocks:
23552359
root.append(etree.Element("spinlocks", state="on",
23562360
retries=str(self.spinlock_retries)))
2361+
if self.vendorid_spoof:
2362+
root.append(etree.Element("vendor_id", state="on",
2363+
value=self.vendorid))
23572364

23582365
return root
23592366

nova/virt/libvirt/driver.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4760,6 +4760,10 @@ def _set_kvm_timers(self, clk, os_type, image_meta):
47604760

47614761
def _set_features(self, guest, os_type, caps, virt_type, image_meta,
47624762
flavor):
4763+
hide_hypervisor_id = (strutils.bool_from_string(
4764+
flavor.extra_specs.get('hide_hypervisor_id')) or
4765+
image_meta.properties.get('img_hide_hypervisor_id'))
4766+
47634767
if virt_type == "xen":
47644768
# PAE only makes sense in X86
47654769
if caps.host.cpu.arch in (fields.Architecture.I686,
@@ -4782,13 +4786,23 @@ def _set_features(self, guest, os_type, caps, virt_type, image_meta,
47824786
# with Microsoft
47834787
hv.spinlock_retries = 8191
47844788
hv.vapic = True
4789+
4790+
# NOTE(kosamara): Spoofing the vendor_id aims to allow the nvidia
4791+
# driver to work on windows VMs. At the moment, the nvidia driver
4792+
# checks for the hyperv vendorid, and if it doesn't find that, it
4793+
# works. In the future, its behaviour could become more strict,
4794+
# checking for the presence of other hyperv feature flags to
4795+
# determine that it's loaded in a VM. If that happens, this
4796+
# workaround will not be enough, and we'll need to drop the whole
4797+
# hyperv element.
4798+
# That would disable some optimizations, reducing the guest's
4799+
# performance.
4800+
if hide_hypervisor_id:
4801+
hv.vendorid_spoof = True
4802+
47854803
guest.features.append(hv)
47864804

4787-
flavor_hide_kvm = strutils.bool_from_string(
4788-
flavor.get('extra_specs', {}).get('hide_hypervisor_id'))
4789-
if (virt_type in ("qemu", "kvm") and
4790-
(image_meta.properties.get('img_hide_hypervisor_id') or
4791-
flavor_hide_kvm)):
4805+
if (virt_type in ("qemu", "kvm") and hide_hypervisor_id):
47924806
guest.features.append(vconfig.LibvirtConfigGuestFeatureKvmHidden())
47934807

47944808
def _check_number_of_serial_console(self, num_ports):
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
fixes:
3+
- |
4+
Blueprints `hide-hypervisor-id-flavor-extra-spec`_ and
5+
`add-kvm-hidden-feature`_ enabled NVIDIA drivers in Linux guests using KVM
6+
and QEMU, but support was not included for Windows guests. This is now
7+
fixed. See `bug 1779845`_ for details.
8+
9+
.. _hide-hypervisor-id-flavor-extra-spec: https://blueprints.launchpad.net/nova/+spec/hide-hypervisor-id-flavor-extra-spec
10+
.. _add-kvm-hidden-feature: https://blueprints.launchpad.net/nova/+spec/add-kvm-hidden-feature
11+
.. _bug 1779845: https://bugs.launchpad.net/nova/+bug/1779845

0 commit comments

Comments
 (0)