libvirt: Handle alternative UEFI firmware binary paths
The OVMF binary paths differ based on the Linux distribution:
- Debian and Ubuntu:
- /usr/share/OVMF/OVMF_CODE.fd
- Fedora:
- /usr/share/edk2/ovmf/OVMF_CODE.fd
(`symlink`s to /usr/share/OVMF/OVMF_CODE.fd)
- /usr/share/edk2/ovmf/OVMF_CODE.secboot.fd (`symlink`s to
/usr/share/OVMF/OVMF_CODE.secboot.fd)
- CentOS and RHEL:
- /usr/share/OVMF/OVMF_CODE.secboot.fd
- SUSE:
- /usr/share/qemu/ovmf-x86_64-opensuse-code.bin
Currently, Nova only checks for one location OVMF_CODE.fd. Let's also
check for the other two common distributions, SUSE and CentOS OVMF
binary paths. This is a short-term solution to fix two bugs.
In the long run:
- We will get rid of the "DEFAULT_UEFI_LOADER_PATH", which is used to
probe for firmware file paths. Instead, we'll use the more robust
approach of the recently introduced[1] get_domain_capabilities()[1]
to query for the firmware binary paths (as reported in the 'loader'
attribute).
- Use libvirt's (>=5.3) firmware auto-selection feature. Which is a
more robust way to decide UEFI boot (secure or otherwise). More
details of it in the spec here[2].
[1] https://opendev.org/openstack/nova/commit/297f3ba687 -- Add
infrastructure for invoking libvirt's getDomainCapabilities API
[2] http://specs.openstack.org/openstack/nova-specs/specs/train/approved/allow-secure-boot-for-qemu-kvm-guests.html
Co-Authored-By: Kashyap Chamarthy <kchamart@redhat.com>
Closes-Bug: 1607400
Closes-Bug: 1825386
blueprint: allow-secure-boot-for-qemu-kvm-guests
Signed-off-by: Kashyap Chamarthy <kchamart@redhat.com>
Change-Id: I28afdb09d300be39981606d5234fd837ea738e1d
This commit is contained in:
committed by
Kashyap Chamarthy
parent
8ad437d142
commit
363710b655
@@ -6423,8 +6423,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
||||
_fake_network_info(self, 1),
|
||||
image_meta, disk_info)
|
||||
self.assertTrue(mock_path_exists.called)
|
||||
mock_path_exists.assert_called_with(
|
||||
libvirt_driver.DEFAULT_UEFI_LOADER_PATH['aarch64'])
|
||||
mock_path_exists.assert_any_call(
|
||||
libvirt_driver.DEFAULT_UEFI_LOADER_PATH['aarch64'][0])
|
||||
self.assertEqual(cfg.os_mach_type, "virt")
|
||||
|
||||
num_ports = 0
|
||||
@@ -6468,8 +6468,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
||||
cfg = self._get_guest_config_with_graphics()
|
||||
|
||||
self.assertTrue(mock_path_exists.called)
|
||||
mock_path_exists.assert_called_with(
|
||||
libvirt_driver.DEFAULT_UEFI_LOADER_PATH['aarch64'])
|
||||
mock_path_exists.assert_any_call(
|
||||
libvirt_driver.DEFAULT_UEFI_LOADER_PATH['aarch64'][0])
|
||||
self.assertEqual(cfg.os_mach_type, "virt")
|
||||
|
||||
usbhost_exists = False
|
||||
|
||||
@@ -139,8 +139,11 @@ DEFAULT_FIREWALL_DRIVER = "%s.%s" % (
|
||||
libvirt_firewall.IptablesFirewallDriver.__name__)
|
||||
|
||||
DEFAULT_UEFI_LOADER_PATH = {
|
||||
"x86_64": "/usr/share/OVMF/OVMF_CODE.fd",
|
||||
"aarch64": "/usr/share/AAVMF/AAVMF_CODE.fd"
|
||||
"x86_64": ['/usr/share/OVMF/OVMF_CODE.fd',
|
||||
'/usr/share/OVMF/OVMF_CODE.secboot.fd',
|
||||
'/usr/share/qemu/ovmf-x86_64-code.bin'],
|
||||
"aarch64": ['/usr/share/AAVMF/AAVMF_CODE.fd',
|
||||
'/usr/share/qemu/aavmf-aarch64-code.bin']
|
||||
}
|
||||
|
||||
MAX_CONSOLE_BYTES = 100 * units.Ki
|
||||
@@ -4959,12 +4962,33 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
return instance.flavor
|
||||
|
||||
def _has_uefi_support(self):
|
||||
# This means that the host can support uefi booting for guests
|
||||
# This means that the host can support UEFI booting for guests
|
||||
supported_archs = [fields.Architecture.X86_64,
|
||||
fields.Architecture.AARCH64]
|
||||
caps = self._host.get_capabilities()
|
||||
# TODO(dmllr, kchamart): Get rid of probing the OVMF binary file
|
||||
# paths, it is not robust, because nothing but the binary's
|
||||
# filename is reported, which means you have to detect its
|
||||
# architecture and features by other means. To solve this,
|
||||
# query the libvirt's getDomainCapabilities() to get the
|
||||
# firmware paths (as reported in the 'loader' value). Nova now
|
||||
# has a wrapper method for this, get_domain_capabilities().
|
||||
# This is a more reliable way to detect UEFI boot support.
|
||||
#
|
||||
# Further, with libvirt 5.3 onwards, support for UEFI boot is
|
||||
# much more simplified by the "firmware auto-selection" feature.
|
||||
# When using this, Nova doesn't need to query OVMF file paths at
|
||||
# all; libvirt will take care of it. This is done by taking
|
||||
# advantage of the so-called firmware "descriptor files" --
|
||||
# small JSON files (which will be shipped by Linux
|
||||
# distributions) that describe a UEFI firmware binary's
|
||||
# "characteristics", such as the binary's file path, its
|
||||
# features, architecture, supported machine type, NVRAM template
|
||||
# and so forth.
|
||||
|
||||
return ((caps.host.cpu.arch in supported_archs) and
|
||||
os.path.exists(DEFAULT_UEFI_LOADER_PATH[caps.host.cpu.arch]))
|
||||
any((os.path.exists(p)
|
||||
for p in DEFAULT_UEFI_LOADER_PATH[caps.host.cpu.arch])))
|
||||
|
||||
def _get_supported_perf_events(self):
|
||||
|
||||
@@ -5023,8 +5047,9 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
"functional testing and therefore "
|
||||
"considered experimental.")
|
||||
uefi_logged = True
|
||||
guest.os_loader = DEFAULT_UEFI_LOADER_PATH[
|
||||
caps.host.cpu.arch]
|
||||
for lpath in DEFAULT_UEFI_LOADER_PATH[caps.host.cpu.arch]:
|
||||
if os.path.exists(lpath):
|
||||
guest.os_loader = lpath
|
||||
guest.os_loader_type = "pflash"
|
||||
else:
|
||||
raise exception.UEFINotSupported()
|
||||
|
||||
Reference in New Issue
Block a user