vmm: add enum PayloadConfigError validation to improve error reporting

Currently, the following scenarios are supported by Cloud Hypervisor to
bootstrap a VM:

1. provide firmware
2. provide kernel
3. provide kernel + cmdline
4. provide kernel + initrd
5. provide kernel + cmdline + initrd

As the difference between `--firmware` and `--kernel` is not very clear
currently, especially as both use/support a Xen PVH entry, adding this
helps to identify the cause of misconfiguration.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
This commit is contained in:
Philipp Schuster
2025-06-25 13:49:05 +02:00
committed by Bo Chen
parent dac0638fe8
commit dd8687aebb
4 changed files with 75 additions and 18 deletions

View File

@@ -10,6 +10,7 @@ use std::{fs, result};
use net_util::MacAddr;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use virtio_devices::RateLimiterConfig;
use crate::landlock::LandlockError;
@@ -705,6 +706,21 @@ pub struct NumaConfig {
pub pci_segments: Option<Vec<u16>>,
}
/// Errors describing a misconfigured payload, i.e., a configuration that
/// can't be booted by Cloud Hypervisor.
///
/// This typically is the case for invalid combinations of cmdline, kernel,
/// firmware, and initrd.
#[derive(Debug, Error, PartialEq, Eq)]
pub enum PayloadConfigError {
/// Specifying a kernel is not supported when a firmware is provided.
#[error("Specifying a kernel is not supported when a firmware is provided")]
FirmwarePlusOtherPayloads,
/// No bootitem provided: neither firmware nor kernel.
#[error("No bootitem provided: neither firmware nor kernel")]
MissingBootitem,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct PayloadConfig {
#[serde(default)]
@@ -796,6 +812,35 @@ impl FromStr for FwCfgItemList {
}
}
impl PayloadConfig {
/// Validates the payload config.
///
/// Succeeds if Cloud Hypervisor will be able to boot the configuration.
/// Further, warns for some odd configurations.
pub fn validate(&mut self) -> Result<(), PayloadConfigError> {
match (&self.firmware, &self.kernel) {
(Some(_firmware), Some(_kernel)) => Err(PayloadConfigError::FirmwarePlusOtherPayloads),
(Some(_firmware), None) => {
if self.cmdline.is_some() {
log::warn!("Ignoring cmdline parameter as firmware is provided as the payload");
self.cmdline = None;
}
if self.initramfs.is_some() {
log::warn!(
"Ignoring initramfs parameter as firmware is provided as the payload"
);
self.initramfs = None;
}
Ok(())
}
(None, Some(_kernel)) => Ok(()),
(None, None) => Err(PayloadConfigError::MissingBootitem),
}?;
Ok(())
}
}
impl ApplyLandlock for PayloadConfig {
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
// Payload only needs read access