cloud-hypervisor/vmm/src/vm_config.rs

630 lines
16 KiB
Rust
Raw Normal View History

// Copyright © 2022 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
use net_util::MacAddr;
use serde::{Deserialize, Serialize};
use std::{net::Ipv4Addr, path::PathBuf};
use virtio_devices::RateLimiterConfig;
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct CpuAffinity {
pub vcpu: u8,
pub host_cpus: Vec<u8>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct CpuFeatures {
#[cfg(target_arch = "x86_64")]
#[serde(default)]
pub amx: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct CpuTopology {
pub threads_per_core: u8,
pub cores_per_die: u8,
pub dies_per_package: u8,
pub packages: u8,
}
// When booting with PVH boot the maximum physical addressable size
// is a 46 bit address space even when the host supports with 5-level
// paging.
pub const DEFAULT_MAX_PHYS_BITS: u8 = 46;
pub fn default_cpuconfig_max_phys_bits() -> u8 {
DEFAULT_MAX_PHYS_BITS
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct CpusConfig {
pub boot_vcpus: u8,
pub max_vcpus: u8,
#[serde(default)]
pub topology: Option<CpuTopology>,
#[serde(default)]
pub kvm_hyperv: bool,
#[serde(default = "default_cpuconfig_max_phys_bits")]
pub max_phys_bits: u8,
#[serde(default)]
pub affinity: Option<Vec<CpuAffinity>>,
#[serde(default)]
pub features: CpuFeatures,
}
pub const DEFAULT_VCPUS: u8 = 1;
impl Default for CpusConfig {
fn default() -> Self {
CpusConfig {
boot_vcpus: DEFAULT_VCPUS,
max_vcpus: DEFAULT_VCPUS,
topology: None,
kvm_hyperv: false,
max_phys_bits: DEFAULT_MAX_PHYS_BITS,
affinity: None,
features: CpuFeatures::default(),
}
}
}
pub const DEFAULT_NUM_PCI_SEGMENTS: u16 = 1;
pub fn default_platformconfig_num_pci_segments() -> u16 {
DEFAULT_NUM_PCI_SEGMENTS
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct PlatformConfig {
#[serde(default = "default_platformconfig_num_pci_segments")]
pub num_pci_segments: u16,
#[serde(default)]
pub iommu_segments: Option<Vec<u16>>,
#[serde(default)]
pub serial_number: Option<String>,
#[serde(default)]
pub uuid: Option<String>,
#[serde(default)]
pub oem_strings: Option<Vec<String>>,
#[cfg(feature = "tdx")]
#[serde(default)]
pub tdx: bool,
#[cfg(feature = "sev_snp")]
#[serde(default)]
pub sev_snp: bool,
}
impl Default for PlatformConfig {
fn default() -> Self {
PlatformConfig {
num_pci_segments: DEFAULT_NUM_PCI_SEGMENTS,
iommu_segments: None,
serial_number: None,
uuid: None,
oem_strings: None,
#[cfg(feature = "tdx")]
tdx: false,
#[cfg(feature = "sev_snp")]
sev_snp: false,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct MemoryZoneConfig {
pub id: String,
pub size: u64,
#[serde(default)]
pub file: Option<PathBuf>,
#[serde(default)]
pub shared: bool,
#[serde(default)]
pub hugepages: bool,
#[serde(default)]
pub hugepage_size: Option<u64>,
#[serde(default)]
pub host_numa_node: Option<u32>,
#[serde(default)]
pub hotplug_size: Option<u64>,
#[serde(default)]
pub hotplugged_size: Option<u64>,
#[serde(default)]
pub prefault: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub enum HotplugMethod {
#[default]
Acpi,
VirtioMem,
}
fn default_memoryconfig_thp() -> bool {
true
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct MemoryConfig {
pub size: u64,
#[serde(default)]
pub mergeable: bool,
#[serde(default)]
pub hotplug_method: HotplugMethod,
#[serde(default)]
pub hotplug_size: Option<u64>,
#[serde(default)]
pub hotplugged_size: Option<u64>,
#[serde(default)]
pub shared: bool,
#[serde(default)]
pub hugepages: bool,
#[serde(default)]
pub hugepage_size: Option<u64>,
#[serde(default)]
pub prefault: bool,
#[serde(default)]
pub zones: Option<Vec<MemoryZoneConfig>>,
#[serde(default = "default_memoryconfig_thp")]
pub thp: bool,
}
pub const DEFAULT_MEMORY_MB: u64 = 512;
impl Default for MemoryConfig {
fn default() -> Self {
MemoryConfig {
size: DEFAULT_MEMORY_MB << 20,
mergeable: false,
hotplug_method: HotplugMethod::Acpi,
hotplug_size: None,
hotplugged_size: None,
shared: false,
hugepages: false,
hugepage_size: None,
prefault: false,
zones: None,
thp: true,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub enum VhostMode {
#[default]
Client,
Server,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct DiskConfig {
pub path: Option<PathBuf>,
#[serde(default)]
pub readonly: bool,
#[serde(default)]
pub direct: bool,
#[serde(default)]
pub iommu: bool,
#[serde(default = "default_diskconfig_num_queues")]
pub num_queues: usize,
#[serde(default = "default_diskconfig_queue_size")]
pub queue_size: u16,
#[serde(default)]
pub vhost_user: bool,
pub vhost_socket: Option<String>,
#[serde(default)]
pub rate_limiter_config: Option<RateLimiterConfig>,
#[serde(default)]
pub id: Option<String>,
// For testing use only. Not exposed in API.
#[serde(default)]
pub disable_io_uring: bool,
// For testing use only. Not exposed in API.
#[serde(default)]
pub disable_aio: bool,
#[serde(default)]
pub pci_segment: u16,
#[serde(default)]
pub serial: Option<String>,
}
pub const DEFAULT_DISK_NUM_QUEUES: usize = 1;
pub fn default_diskconfig_num_queues() -> usize {
DEFAULT_DISK_NUM_QUEUES
}
pub const DEFAULT_DISK_QUEUE_SIZE: u16 = 128;
pub fn default_diskconfig_queue_size() -> u16 {
DEFAULT_DISK_QUEUE_SIZE
}
impl Default for DiskConfig {
fn default() -> Self {
Self {
path: None,
readonly: false,
direct: false,
iommu: false,
num_queues: default_diskconfig_num_queues(),
queue_size: default_diskconfig_queue_size(),
vhost_user: false,
vhost_socket: None,
id: None,
disable_io_uring: false,
disable_aio: false,
rate_limiter_config: None,
pci_segment: 0,
serial: None,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct NetConfig {
#[serde(default = "default_netconfig_tap")]
pub tap: Option<String>,
#[serde(default = "default_netconfig_ip")]
pub ip: Ipv4Addr,
#[serde(default = "default_netconfig_mask")]
pub mask: Ipv4Addr,
#[serde(default = "default_netconfig_mac")]
pub mac: MacAddr,
#[serde(default)]
pub host_mac: Option<MacAddr>,
#[serde(default)]
pub mtu: Option<u16>,
#[serde(default)]
pub iommu: bool,
#[serde(default = "default_netconfig_num_queues")]
pub num_queues: usize,
#[serde(default = "default_netconfig_queue_size")]
pub queue_size: u16,
#[serde(default)]
pub vhost_user: bool,
pub vhost_socket: Option<String>,
#[serde(default)]
pub vhost_mode: VhostMode,
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub fds: Option<Vec<i32>>,
#[serde(default)]
pub rate_limiter_config: Option<RateLimiterConfig>,
#[serde(default)]
pub pci_segment: u16,
#[serde(default = "default_netconfig_true")]
pub offload_tso: bool,
#[serde(default = "default_netconfig_true")]
pub offload_ufo: bool,
#[serde(default = "default_netconfig_true")]
pub offload_csum: bool,
}
pub fn default_netconfig_true() -> bool {
true
}
pub fn default_netconfig_tap() -> Option<String> {
None
}
pub fn default_netconfig_ip() -> Ipv4Addr {
Ipv4Addr::new(192, 168, 249, 1)
}
pub fn default_netconfig_mask() -> Ipv4Addr {
Ipv4Addr::new(255, 255, 255, 0)
}
pub fn default_netconfig_mac() -> MacAddr {
MacAddr::local_random()
}
pub const DEFAULT_NET_NUM_QUEUES: usize = 2;
pub fn default_netconfig_num_queues() -> usize {
DEFAULT_NET_NUM_QUEUES
}
pub const DEFAULT_NET_QUEUE_SIZE: u16 = 256;
pub fn default_netconfig_queue_size() -> u16 {
DEFAULT_NET_QUEUE_SIZE
}
impl Default for NetConfig {
fn default() -> Self {
Self {
tap: default_netconfig_tap(),
ip: default_netconfig_ip(),
mask: default_netconfig_mask(),
mac: default_netconfig_mac(),
host_mac: None,
mtu: None,
iommu: false,
num_queues: default_netconfig_num_queues(),
queue_size: default_netconfig_queue_size(),
vhost_user: false,
vhost_socket: None,
vhost_mode: VhostMode::Client,
id: None,
fds: None,
rate_limiter_config: None,
pci_segment: 0,
offload_tso: true,
offload_ufo: true,
offload_csum: true,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct RngConfig {
pub src: PathBuf,
#[serde(default)]
pub iommu: bool,
}
pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom";
impl Default for RngConfig {
fn default() -> Self {
RngConfig {
src: PathBuf::from(DEFAULT_RNG_SOURCE),
iommu: false,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct BalloonConfig {
pub size: u64,
/// Option to deflate the balloon in case the guest is out of memory.
#[serde(default)]
pub deflate_on_oom: bool,
/// Option to enable free page reporting from the guest.
#[serde(default)]
pub free_page_reporting: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct FsConfig {
pub tag: String,
pub socket: PathBuf,
#[serde(default = "default_fsconfig_num_queues")]
pub num_queues: usize,
#[serde(default = "default_fsconfig_queue_size")]
pub queue_size: u16,
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub pci_segment: u16,
}
pub fn default_fsconfig_num_queues() -> usize {
1
}
pub fn default_fsconfig_queue_size() -> u16 {
1024
}
impl Default for FsConfig {
fn default() -> Self {
Self {
tag: "".to_owned(),
socket: PathBuf::new(),
num_queues: default_fsconfig_num_queues(),
queue_size: default_fsconfig_queue_size(),
id: None,
pci_segment: 0,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct PmemConfig {
pub file: PathBuf,
#[serde(default)]
pub size: Option<u64>,
#[serde(default)]
pub iommu: bool,
#[serde(default)]
pub discard_writes: bool,
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub pci_segment: u16,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum ConsoleOutputMode {
Off,
Pty,
Tty,
File,
Socket,
Null,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct ConsoleConfig {
#[serde(default = "default_consoleconfig_file")]
pub file: Option<PathBuf>,
pub mode: ConsoleOutputMode,
#[serde(default)]
pub iommu: bool,
pub socket: Option<PathBuf>,
}
pub fn default_consoleconfig_file() -> Option<PathBuf> {
None
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct DeviceConfig {
pub path: PathBuf,
#[serde(default)]
pub iommu: bool,
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub pci_segment: u16,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct UserDeviceConfig {
pub socket: PathBuf,
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub pci_segment: u16,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct VdpaConfig {
pub path: PathBuf,
#[serde(default = "default_vdpaconfig_num_queues")]
pub num_queues: usize,
#[serde(default)]
pub iommu: bool,
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub pci_segment: u16,
}
pub fn default_vdpaconfig_num_queues() -> usize {
1
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct VsockConfig {
pub cid: u64,
pub socket: PathBuf,
#[serde(default)]
pub iommu: bool,
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub pci_segment: u16,
}
#[cfg(target_arch = "x86_64")]
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct SgxEpcConfig {
pub id: String,
#[serde(default)]
pub size: u64,
#[serde(default)]
pub prefault: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct NumaDistance {
#[serde(default)]
pub destination: u32,
#[serde(default)]
pub distance: u8,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct NumaConfig {
#[serde(default)]
pub guest_numa_id: u32,
#[serde(default)]
pub cpus: Option<Vec<u8>>,
#[serde(default)]
pub distances: Option<Vec<NumaDistance>>,
#[serde(default)]
pub memory_zones: Option<Vec<String>>,
#[cfg(target_arch = "x86_64")]
#[serde(default)]
pub sgx_epc_sections: Option<Vec<String>>,
#[serde(default)]
pub pci_segments: Option<Vec<u16>>,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct PayloadConfig {
#[serde(default)]
pub firmware: Option<PathBuf>,
#[serde(default)]
pub kernel: Option<PathBuf>,
#[serde(default)]
pub cmdline: Option<String>,
#[serde(default)]
pub initramfs: Option<PathBuf>,
#[cfg(feature = "igvm")]
#[serde(default)]
pub igvm: Option<PathBuf>,
}
pub fn default_serial() -> ConsoleConfig {
ConsoleConfig {
file: None,
mode: ConsoleOutputMode::Null,
iommu: false,
socket: None,
}
}
pub fn default_console() -> ConsoleConfig {
ConsoleConfig {
file: None,
mode: ConsoleOutputMode::Tty,
iommu: false,
socket: None,
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct TpmConfig {
pub socket: PathBuf,
}
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct VmConfig {
#[serde(default)]
pub cpus: CpusConfig,
#[serde(default)]
pub memory: MemoryConfig,
pub payload: Option<PayloadConfig>,
pub disks: Option<Vec<DiskConfig>>,
pub net: Option<Vec<NetConfig>>,
#[serde(default)]
pub rng: RngConfig,
pub balloon: Option<BalloonConfig>,
pub fs: Option<Vec<FsConfig>>,
pub pmem: Option<Vec<PmemConfig>>,
#[serde(default = "default_serial")]
pub serial: ConsoleConfig,
#[serde(default = "default_console")]
pub console: ConsoleConfig,
pub devices: Option<Vec<DeviceConfig>>,
pub user_devices: Option<Vec<UserDeviceConfig>>,
pub vdpa: Option<Vec<VdpaConfig>>,
pub vsock: Option<VsockConfig>,
#[serde(default)]
pub pvpanic: bool,
#[serde(default)]
pub iommu: bool,
#[cfg(target_arch = "x86_64")]
pub sgx_epc: Option<Vec<SgxEpcConfig>>,
pub numa: Option<Vec<NumaConfig>>,
#[serde(default)]
pub watchdog: bool,
#[cfg(feature = "guest_debug")]
#[serde(default)]
pub gdb: bool,
pub platform: Option<PlatformConfig>,
pub tpm: Option<TpmConfig>,
// Preserved FDs are the ones that share the same life-time as its holding
// VmConfig instance, such as FDs for creating TAP devices.
// Preserved FDs will stay open as long as the holding VmConfig instance is
// valid, and will be closed when the holding VmConfig instance is destroyed.
#[serde(skip)]
pub preserved_fds: Option<Vec<i32>>,
}