Skip to content

Commit 3fe7098

Browse files
imranh2kashyapc
authored andcommitted
[nova/libvirt] Support for checking and enabling SMM when needed
Check the features list we get from the firmware descriptor file to see if we need SMM (requires-smm), if so then enable it as we aren't using the libvirt built in mechanism to enable it when grabbing the right firmware. Closes-Bug: 1958636 Change-Id: I890b3021a29fa546d9e36b21b1111e8537cd0020 Signed-off-by: Imran Hussain <[email protected]> (cherry picked from commit 6ad7890) (cherry picked from commit 62e1a62)
1 parent 7074ac0 commit 3fe7098

File tree

7 files changed

+82
-5
lines changed

7 files changed

+82
-5
lines changed

nova/exception.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,6 +1903,10 @@ class SecureBootNotSupported(Invalid):
19031903
msg_fmt = _("Secure Boot is not supported by host")
19041904

19051905

1906+
class FirmwareSMMNotSupported(Invalid):
1907+
msg_fmt = _("This firmware doesn't require (support) SMM")
1908+
1909+
19061910
class TriggerCrashDumpNotSupported(Invalid):
19071911
msg_fmt = _("Triggering crash dump is not supported")
19081912

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5054,6 +5054,44 @@ def test_get_guest_config_with_uefi(self):
50545054
self.assertEqual('/usr/share/OVMF/OVMF_CODE.fd', cfg.os_loader)
50555055
self.assertEqual('/usr/share/OVMF/OVMF_VARS.fd', cfg.os_nvram_template)
50565056

5057+
def test_get_guest_config_with_secure_boot_and_smm_required(self):
5058+
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
5059+
# uefi only used with secure boot
5060+
drvr._host._supports_uefi = True
5061+
# smm only used with secure boot
5062+
drvr._host._supports_secure_boot = True
5063+
5064+
# NOTE(imranh2): Current way of gathering firmwares is inflexible
5065+
# nova/tests/fixtures/libvirt.py FakeLoaders has requires-smm
5066+
# defined. do the following to make sure we get this programtically
5067+
# in the future we should test firmwares that both do and don't
5068+
# require smm but the current way firmware is selected doesn't
5069+
# make it possible to do so.
5070+
loader, nvram_template, requires_smm = drvr._host.get_loader(
5071+
'x86_64', 'q35', True)
5072+
5073+
image_meta = objects.ImageMeta.from_dict({
5074+
'disk_format': 'raw',
5075+
# secure boot requires UEFI
5076+
'properties': {
5077+
'hw_firmware_type': 'uefi',
5078+
'hw_machine_type': 'q35',
5079+
'os_secure_boot': 'required',
5080+
},
5081+
})
5082+
instance_ref = objects.Instance(**self.test_instance)
5083+
5084+
disk_info = blockinfo.get_disk_info(
5085+
CONF.libvirt.virt_type, instance_ref, image_meta)
5086+
5087+
cfg = drvr._get_guest_config(
5088+
instance_ref, [], image_meta, disk_info)
5089+
# if we require it make sure it's there
5090+
if requires_smm:
5091+
self.assertTrue(any(isinstance(feature,
5092+
vconfig.LibvirtConfigGuestFeatureSMM)
5093+
for feature in cfg.features))
5094+
50575095
@ddt.data(True, False)
50585096
def test_get_guest_config_with_secure_boot_required(
50595097
self, host_has_support,

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,6 +1793,14 @@ def fake_get_mtype(arch, machine):
17931793
loader = self.host.get_loader('x86_64', 'q35', has_secure_boot=True)
17941794
self.assertIsNotNone(loader)
17951795

1796+
# check that SMM bool is false as we don't need it
1797+
self.assertFalse(loader[2])
1798+
1799+
# check that we get SMM bool correctly (True) when required
1800+
loaders[0]['features'].append('requires-smm')
1801+
loader = self.host.get_loader('x86_64', 'q35', has_secure_boot=True)
1802+
self.assertTrue(loader[2])
1803+
17961804
# while it should fail here since we don't want it now
17971805
self.assertRaises(
17981806
exception.UEFINotSupported,

nova/virt/libvirt/config.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2687,6 +2687,19 @@ def format_dom(self):
26872687
return root
26882688

26892689

2690+
class LibvirtConfigGuestFeatureSMM(LibvirtConfigGuestFeature):
2691+
2692+
def __init__(self, **kwargs):
2693+
super(LibvirtConfigGuestFeatureSMM, self).__init__("smm", **kwargs)
2694+
2695+
def format_dom(self):
2696+
root = super(LibvirtConfigGuestFeatureSMM, self).format_dom()
2697+
2698+
root.append(etree.Element("smm", state="on"))
2699+
2700+
return root
2701+
2702+
26902703
class LibvirtConfigGuestFeaturePMU(LibvirtConfigGuestFeature):
26912704

26922705
def __init__(self, state, **kwargs):

nova/virt/libvirt/driver.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6252,9 +6252,10 @@ def _configure_guest_by_virt_type(
62526252
guest.os_loader_secure = False
62536253

62546254
try:
6255-
loader, nvram_template = self._host.get_loader(
6255+
loader, nvram_template, requires_smm = (
6256+
self._host.get_loader(
62566257
arch, mach_type,
6257-
has_secure_boot=guest.os_loader_secure)
6258+
has_secure_boot=guest.os_loader_secure))
62586259
except exception.UEFINotSupported as exc:
62596260
if guest.os_loader_secure:
62606261
# we raise a specific exception if we requested secure
@@ -6266,6 +6267,11 @@ def _configure_guest_by_virt_type(
62666267
guest.os_loader_type = 'pflash'
62676268
guest.os_nvram_template = nvram_template
62686269

6270+
# if the feature set says we need SMM then enable it
6271+
if requires_smm:
6272+
guest.features.append(
6273+
vconfig.LibvirtConfigGuestFeatureSMM())
6274+
62696275
# NOTE(lyarwood): If the machine type isn't recorded in the stashed
62706276
# image metadata then record it through the system metadata table.
62716277
# This will allow the host configuration to change in the future

nova/virt/libvirt/host.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,11 +1625,11 @@ def get_loader(
16251625
arch: str,
16261626
machine: str,
16271627
has_secure_boot: bool,
1628-
) -> ty.Tuple[str, str]:
1628+
) -> ty.Tuple[str, str, bool]:
16291629
"""Get loader for the specified architecture and machine type.
16301630
1631-
:returns: A tuple of the bootloader executable path and the NVRAM
1632-
template path.
1631+
:returns: A the bootloader executable path and the NVRAM
1632+
template path and a bool indicating if we need to enable SMM.
16331633
"""
16341634

16351635
machine = self.get_canonical_machine_type(arch, machine)
@@ -1659,6 +1659,7 @@ def get_loader(
16591659
return (
16601660
loader['mapping']['executable']['filename'],
16611661
loader['mapping']['nvram-template']['filename'],
1662+
'requires-smm' in loader['features'],
16621663
)
16631664

16641665
raise exception.UEFINotSupported()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
fixes:
3+
- |
4+
[`bug 1958636 <https://bugs.launchpad.net/nova/+bug/1958636>`_]
5+
Explicitly check for and enable SMM when firmware requires it.
6+
Previously we assumed libvirt would do this for us but this is
7+
not true in all cases.

0 commit comments

Comments
 (0)