// 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, } #[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, #[serde(default)] pub kvm_hyperv: bool, #[serde(default = "default_cpuconfig_max_phys_bits")] pub max_phys_bits: u8, #[serde(default)] pub affinity: Option>, #[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>, #[serde(default)] pub serial_number: Option, #[serde(default)] pub uuid: Option, #[serde(default)] pub oem_strings: Option>, #[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, #[serde(default)] pub shared: bool, #[serde(default)] pub hugepages: bool, #[serde(default)] pub hugepage_size: Option, #[serde(default)] pub host_numa_node: Option, #[serde(default)] pub hotplug_size: Option, #[serde(default)] pub hotplugged_size: Option, #[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, #[serde(default)] pub hotplugged_size: Option, #[serde(default)] pub shared: bool, #[serde(default)] pub hugepages: bool, #[serde(default)] pub hugepage_size: Option, #[serde(default)] pub prefault: bool, #[serde(default)] pub zones: Option>, #[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, #[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, #[serde(default)] pub rate_limiter_config: Option, #[serde(default)] pub id: Option, // 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, } 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, #[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, #[serde(default)] pub mtu: Option, #[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, #[serde(default)] pub vhost_mode: VhostMode, #[serde(default)] pub id: Option, #[serde(default)] pub fds: Option>, #[serde(default)] pub rate_limiter_config: Option, #[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 { 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, #[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, #[serde(default)] pub iommu: bool, #[serde(default)] pub discard_writes: bool, #[serde(default)] pub id: Option, #[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, pub mode: ConsoleOutputMode, #[serde(default)] pub iommu: bool, pub socket: Option, } pub fn default_consoleconfig_file() -> Option { 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, #[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, #[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, #[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, #[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>, #[serde(default)] pub distances: Option>, #[serde(default)] pub memory_zones: Option>, #[cfg(target_arch = "x86_64")] #[serde(default)] pub sgx_epc_sections: Option>, #[serde(default)] pub pci_segments: Option>, } #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] pub struct PayloadConfig { #[serde(default)] pub firmware: Option, #[serde(default)] pub kernel: Option, #[serde(default)] pub cmdline: Option, #[serde(default)] pub initramfs: Option, #[cfg(feature = "igvm")] #[serde(default)] pub igvm: Option, } 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, pub disks: Option>, pub net: Option>, #[serde(default)] pub rng: RngConfig, pub balloon: Option, pub fs: Option>, pub pmem: Option>, #[serde(default = "default_serial")] pub serial: ConsoleConfig, #[serde(default = "default_console")] pub console: ConsoleConfig, pub devices: Option>, pub user_devices: Option>, pub vdpa: Option>, pub vsock: Option, #[serde(default)] pub pvpanic: bool, #[serde(default)] pub iommu: bool, #[cfg(target_arch = "x86_64")] pub sgx_epc: Option>, pub numa: Option>, #[serde(default)] pub watchdog: bool, #[cfg(feature = "guest_debug")] #[serde(default)] pub gdb: bool, pub platform: Option, pub tpm: Option, // 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>, }