runtime-rs: ch: Generate Cloud Hypervisor config for confidential guests

This change provides a preliminary implementation for the Cloud Hypervisor (CH) feature ([currently
disabled](https://github.com/kata-containers/kata-containers/pull/6201))
to allow it to generate the CH configuration for handling confidential guests.

This change also introduces concrete errors using the `thiserror` crate
(see `src/runtime-rs/crates/hypervisor/ch-config/src/errors.rs`) and a
lot of unit tests for the conversion code that generates the CH
configuration from the generic Hypervisor configuration.

Fixes: #6430.

Signed-off-by: James O. D. Hunt <james.o.hunt@intel.com>
This commit is contained in:
James O. D. Hunt 2023-03-08 15:49:03 +00:00
parent 96555186b3
commit ac58588682
6 changed files with 1806 additions and 99 deletions

View File

@ -423,6 +423,7 @@ dependencies = [
"nix 0.26.2",
"serde",
"serde_json",
"thiserror",
"tokio",
]

View File

@ -23,3 +23,4 @@ api_client = { git = "https://github.com/cloud-hypervisor/cloud-hypervisor", cra
kata-types = { path = "../../../../libs/kata-types"}
nix = "0.26.2"
thiserror = "1.0.38"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,107 @@
// Copyright (c) 2023 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
use std::convert::TryFrom;
use thiserror::Error;
#[derive(Error, Debug, PartialEq)]
pub enum VmConfigError {
#[error("empty sandbox path")]
EmptySandboxPath,
#[error("empty VSOCK socket path")]
EmptyVsockSocketPath,
#[error("cannot specify image and initrd")]
MultipleBootFiles,
#[error("missing boot image (no rootfs image or initrd)")]
NoBootFile,
#[error("CPU config error: {0}")]
CPUError(CpusConfigError),
#[error("Pmem config error: {0}")]
PmemError(PmemConfigError),
#[error("Payload config error: {0}")]
PayloadError(PayloadConfigError),
#[error("Disk config error: {0}")]
DiskError(DiskConfigError),
#[error("Memory config error: {0}")]
MemoryError(MemoryConfigError),
// The 2nd arg is actually a std::io::Error but that doesn't implement
// PartialEq, so we convert it to a String.
#[error("Failed to create sandbox path ({0}: {1}")]
SandboxError(String, String),
#[error("VSOCK config error: {0}")]
VsockError(VsockConfigError),
}
#[derive(Error, Debug, PartialEq)]
pub enum PmemConfigError {
#[error("Need rootfs image for PmemConfig")]
MissingImage,
}
#[derive(Error, Debug, PartialEq)]
pub enum DiskConfigError {
#[error("Need path for DiskConfig")]
MissingPath,
#[error("Found unexpected path for DiskConfig with TDX: {0}")]
UnexpectedPathForTDX(String),
}
#[derive(Error, Debug, PartialEq)]
pub enum CpusConfigError {
#[error("Too many boot vCPUs specified: {0}")]
BootVCPUsTooBig(<u8 as TryFrom<i32>>::Error),
#[error("Too many max vCPUs specified: {0}")]
MaxVCPUsTooBig(<u8 as TryFrom<u32>>::Error),
}
#[derive(Error, Debug, PartialEq)]
pub enum PayloadConfigError {
#[error("No kernel specified")]
NoKernel,
#[error("No initrd/initramfs specified")]
NoInitrd,
#[error("Need firmware for TDX")]
TDXFirmwareMissing,
}
#[derive(Error, Debug, PartialEq)]
pub enum MemoryConfigError {
#[error("No default memory specified")]
NoDefaultMemory,
#[error("Default memory size > available RAM")]
DefaultMemSizeTooBig,
#[error("Cannot convert default memory to bytes: {0}")]
BadDefaultMemSize(u32),
#[error("Cannot calculate hotplug memory size from default memory: {0}")]
BadMemSizeForHotplug(u64),
#[error("Cannot align hotplug memory size from pmem: {0}")]
BadPmemAlign(u64),
#[error("Failed to query system memory information: {0}")]
SysInfoFail(#[source] nix::errno::Errno),
}
#[derive(Error, Debug, PartialEq)]
pub enum VsockConfigError {
#[error("Missing VSOCK socket path")]
NoVsockSocketPath,
}

View File

@ -17,6 +17,8 @@ pub use net_util::MacAddr;
pub const MAX_NUM_PCI_SEGMENTS: u16 = 16;
mod errors;
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct BalloonConfig {
pub size: u64,
@ -330,7 +332,6 @@ pub struct PlatformConfig {
pub uuid: Option<String>,
#[serde(default)]
pub oem_strings: Option<Vec<String>>,
#[cfg(feature = "tdx")]
#[serde(default)]
pub tdx: bool,
}
@ -425,9 +426,7 @@ pub struct VmConfig {
pub fs: Option<Vec<FsConfig>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pmem: Option<Vec<PmemConfig>>,
//#[serde(default = "ConsoleConfig::default_serial")]
pub serial: ConsoleConfig,
//#[serde(default = "ConsoleConfig::default_console")]
pub console: ConsoleConfig,
#[serde(skip_serializing_if = "Option::is_none")]
pub devices: Option<Vec<DeviceConfig>>,
@ -484,12 +483,13 @@ fn u16_is_zero(v: &u16) -> bool {
// Type used to simplify conversion from a generic Hypervisor config
// to a CH specific VmConfig.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct NamedHypervisorConfig {
pub kernel_params: String,
pub sandbox_path: String,
pub vsock_socket_path: String,
pub cfg: HypervisorConfig,
pub tdx_enabled: bool,
pub shared_fs_devices: Option<Vec<FsConfig>>,
}

View File

@ -68,6 +68,8 @@ impl CloudHypervisorInner {
let enable_debug = cfg.debug_info.enable_debug;
let confidential_guest = cfg.security_info.confidential_guest;
// Note that the configuration option hypervisor.block_device_driver is not used.
let rootfs_driver = VM_ROOTFS_DRIVER_PMEM;
@ -81,6 +83,18 @@ impl CloudHypervisorInner {
let mut rootfs_param = KernelParams::new_rootfs_kernel_params(rootfs_driver, rootfs_type)?;
let mut extra_params = if enable_debug {
if confidential_guest {
KernelParams::from_string("console=hvc0")
} else {
KernelParams::from_string("console=ttyS0,115200n8")
}
} else {
KernelParams::from_string("quiet")
};
params.append(&mut extra_params);
// Add the rootfs device
params.append(&mut rootfs_param);
@ -121,11 +135,18 @@ impl CloudHypervisorInner {
let kernel_params = self.get_kernel_params().await?;
// FIXME: See:
//
// - https://github.com/kata-containers/kata-containers/issues/6383
// - https://github.com/kata-containers/kata-containers/pull/6257
let tdx_enabled = false;
let named_cfg = NamedHypervisorConfig {
kernel_params,
sandbox_path,
vsock_socket_path,
cfg: hypervisor_config.clone(),
tdx_enabled,
shared_fs_devices,
};