use std::os::fd::RawFd;
use std::path::{Path, PathBuf};
use vmm::resources::PortConfig;
#[cfg(not(any(feature = "tee", feature = "aws-nitro")))]
use crate::backends::fs::DynFileSystem;
#[cfg(feature = "net")]
use std::os::fd::OwnedFd;
#[cfg(feature = "net")]
use crate::backends::net::NetBackend;
#[derive(Debug, Clone)]
pub struct MachineBuilder {
pub(crate) vcpus: u8,
pub(crate) memory_mib: usize,
pub(crate) hyperthreading: bool,
pub(crate) nested_virt: bool,
}
#[derive(Debug, Clone, Default)]
pub struct KernelBuilder {
pub(crate) cmdline: Option<String>,
pub(crate) krunfw_path: Option<PathBuf>,
pub(crate) init_path: Option<String>,
}
pub struct FsBuilder {
pub(crate) configs: Vec<FsConfig>,
current_tag: Option<String>,
current_shm_size: Option<usize>,
}
pub enum FsConfig {
Path {
tag: String,
path: PathBuf,
shm_size: Option<usize>,
},
#[cfg(not(any(feature = "tee", feature = "aws-nitro")))]
Custom {
tag: String,
backend: Box<dyn DynFileSystem + Send + Sync>,
},
}
#[cfg(feature = "net")]
pub struct NetBuilder {
pub(crate) configs: Vec<NetConfig>,
current_mac: Option<[u8; 6]>,
}
#[cfg(feature = "net")]
pub enum NetConfig {
UnixgramFd { mac: Option<[u8; 6]>, fd: OwnedFd },
UnixgramPath {
mac: Option<[u8; 6]>,
path: PathBuf,
send_vfkit_magic: bool,
},
UnixstreamFd { mac: Option<[u8; 6]>, fd: OwnedFd },
UnixstreamPath { mac: Option<[u8; 6]>, path: PathBuf },
#[cfg(target_os = "linux")]
Tap { mac: Option<[u8; 6]>, name: String },
Custom {
mac: Option<[u8; 6]>,
backend: Box<dyn NetBackend + Send>,
},
}
#[derive(Debug, Clone, Default)]
pub struct ConsoleBuilder {
pub(crate) output: Option<PathBuf>,
pub(crate) ports: Vec<PortConfig>,
pub(crate) disable_implicit: bool,
#[cfg(feature = "snd")]
pub(crate) sound: bool,
#[cfg(feature = "gpu")]
pub(crate) gpu_virgl_flags: Option<u32>,
#[cfg(feature = "gpu")]
pub(crate) gpu_shm_size: Option<usize>,
}
#[derive(Debug, Clone, Default)]
pub struct ExecBuilder {
pub(crate) path: Option<String>,
pub(crate) args: Vec<String>,
pub(crate) env: Vec<(String, String)>,
pub(crate) workdir: Option<String>,
pub(crate) rlimits: Vec<(String, u64, u64)>,
}
#[cfg(feature = "blk")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DiskImageFormat {
Raw,
Qcow2,
Vmdk,
}
#[cfg(feature = "blk")]
#[derive(Debug, Clone)]
pub struct DiskBuilder {
pub(crate) configs: Vec<DiskConfig>,
current_path: Option<PathBuf>,
current_read_only: bool,
current_format: DiskImageFormat,
}
#[cfg(feature = "blk")]
#[derive(Debug, Clone)]
pub struct DiskConfig {
pub path: PathBuf,
pub read_only: bool,
pub format: DiskImageFormat,
}
impl MachineBuilder {
pub fn new() -> Self {
Self {
vcpus: 1,
memory_mib: 512,
hyperthreading: false,
nested_virt: false,
}
}
pub fn vcpus(mut self, count: u8) -> Self {
self.vcpus = count;
self
}
pub fn memory_mib(mut self, mib: usize) -> Self {
self.memory_mib = mib;
self
}
pub fn hyperthreading(mut self, enabled: bool) -> Self {
self.hyperthreading = enabled;
self
}
pub fn nested_virt(mut self, enabled: bool) -> Self {
self.nested_virt = enabled;
self
}
}
impl Default for MachineBuilder {
fn default() -> Self {
Self::new()
}
}
impl KernelBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn cmdline(mut self, cmdline: &str) -> Self {
if let Some(ref mut existing) = self.cmdline {
existing.push(' ');
existing.push_str(cmdline);
} else {
self.cmdline = Some(cmdline.to_string());
}
self
}
pub fn krunfw_path(mut self, path: impl AsRef<Path>) -> Self {
self.krunfw_path = Some(path.as_ref().to_path_buf());
self
}
pub fn init_path(mut self, path: impl AsRef<Path>) -> Self {
self.init_path = Some(path.as_ref().to_string_lossy().to_string());
self
}
}
impl FsBuilder {
pub fn new() -> Self {
Self {
configs: Vec::new(),
current_tag: None,
current_shm_size: None,
}
}
pub fn root(mut self, path: impl AsRef<Path>) -> Self {
self.configs.push(FsConfig::Path {
tag: "/dev/root".to_string(),
path: path.as_ref().to_path_buf(),
shm_size: None,
});
self
}
pub fn tag(mut self, tag: &str) -> Self {
self.current_tag = Some(tag.to_string());
self
}
pub fn path(mut self, path: impl AsRef<Path>) -> Self {
let tag = self
.current_tag
.take()
.unwrap_or_else(|| format!("fs{}", self.configs.len()));
let shm_size = self.current_shm_size.take();
self.configs.push(FsConfig::Path {
tag,
path: path.as_ref().to_path_buf(),
shm_size,
});
self
}
pub fn shm_size(mut self, size: usize) -> Self {
self.current_shm_size = Some(size);
self
}
#[cfg(not(any(feature = "tee", feature = "aws-nitro")))]
pub fn custom(mut self, backend: Box<dyn DynFileSystem + Send + Sync>) -> Self {
let tag = self
.current_tag
.take()
.unwrap_or_else(|| format!("fs{}", self.configs.len()));
self.configs.push(FsConfig::Custom { tag, backend });
self
}
}
impl Default for FsBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "net")]
impl NetBuilder {
pub fn new() -> Self {
Self {
configs: Vec::new(),
current_mac: None,
}
}
pub fn mac(mut self, mac: [u8; 6]) -> Self {
self.current_mac = Some(mac);
self
}
pub fn unixgram(mut self, fd: OwnedFd) -> Self {
let mac = self.current_mac.take();
self.configs.push(NetConfig::UnixgramFd { mac, fd });
self
}
pub fn unixgram_path(mut self, path: impl AsRef<Path>, send_vfkit_magic: bool) -> Self {
let mac = self.current_mac.take();
self.configs.push(NetConfig::UnixgramPath {
mac,
path: path.as_ref().to_path_buf(),
send_vfkit_magic,
});
self
}
pub fn unixstream(mut self, fd: OwnedFd) -> Self {
let mac = self.current_mac.take();
self.configs.push(NetConfig::UnixstreamFd { mac, fd });
self
}
pub fn unixstream_path(mut self, path: impl AsRef<Path>) -> Self {
let mac = self.current_mac.take();
self.configs.push(NetConfig::UnixstreamPath {
mac,
path: path.as_ref().to_path_buf(),
});
self
}
#[cfg(target_os = "linux")]
pub fn tap(mut self, name: impl Into<String>) -> Self {
let mac = self.current_mac.take();
self.configs.push(NetConfig::Tap {
mac,
name: name.into(),
});
self
}
pub fn custom(mut self, backend: Box<dyn NetBackend + Send>) -> Self {
let mac = self.current_mac.take();
self.configs.push(NetConfig::Custom { mac, backend });
self
}
}
#[cfg(feature = "net")]
impl Default for NetBuilder {
fn default() -> Self {
Self::new()
}
}
impl ConsoleBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn output(mut self, path: impl AsRef<Path>) -> Self {
self.output = Some(path.as_ref().to_path_buf());
self
}
#[cfg(feature = "snd")]
pub fn sound(mut self, enabled: bool) -> Self {
self.sound = enabled;
self
}
#[cfg(feature = "gpu")]
pub fn gpu_virgl_flags(mut self, flags: u32) -> Self {
self.gpu_virgl_flags = Some(flags);
self
}
#[cfg(feature = "gpu")]
pub fn gpu_shm_size(mut self, size: usize) -> Self {
self.gpu_shm_size = Some(size);
self
}
pub fn port(mut self, name: &str, input_fd: RawFd, output_fd: RawFd) -> Self {
self.ports.push(PortConfig::InOut {
name: name.to_string(),
input_fd,
output_fd,
});
self
}
pub fn port_tty(mut self, name: &str, tty_fd: RawFd) -> Self {
self.ports.push(PortConfig::Tty {
name: name.to_string(),
tty_fd,
});
self
}
pub fn disable_implicit(mut self) -> Self {
self.disable_implicit = true;
self
}
}
impl ExecBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn path(mut self, path: impl AsRef<Path>) -> Self {
self.path = Some(path.as_ref().to_string_lossy().to_string());
self
}
pub fn args<I, S>(mut self, args: I) -> Self
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
self.args = args.into_iter().map(|s| s.as_ref().to_string()).collect();
self
}
pub fn env(mut self, key: &str, value: &str) -> Self {
self.env.push((key.to_string(), value.to_string()));
self
}
pub fn envs<I, K, V>(mut self, envs: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
K: AsRef<str>,
V: AsRef<str>,
{
self.env.extend(
envs.into_iter()
.map(|(k, v)| (k.as_ref().to_string(), v.as_ref().to_string())),
);
self
}
pub fn workdir(mut self, path: impl AsRef<Path>) -> Self {
self.workdir = Some(path.as_ref().to_string_lossy().to_string());
self
}
pub fn rlimit(mut self, resource: &str, soft: u64, hard: u64) -> Self {
self.rlimits.push((resource.to_string(), soft, hard));
self
}
}
#[cfg(feature = "blk")]
impl DiskBuilder {
pub fn new() -> Self {
Self {
configs: Vec::new(),
current_path: None,
current_read_only: false,
current_format: DiskImageFormat::Raw,
}
}
pub fn format(mut self, format: DiskImageFormat) -> Self {
self.current_format = format;
self
}
pub fn path(mut self, path: impl AsRef<Path>) -> Self {
if let Some(pending_path) = self.current_path.take() {
self.configs.push(DiskConfig {
path: pending_path,
read_only: self.current_read_only,
format: self.current_format,
});
self.current_read_only = false;
self.current_format = DiskImageFormat::Raw;
}
self.current_path = Some(path.as_ref().to_path_buf());
self
}
pub fn read_only(mut self, ro: bool) -> Self {
self.current_read_only = ro;
self
}
pub(crate) fn finalize(mut self) -> Self {
if let Some(path) = self.current_path.take() {
self.configs.push(DiskConfig {
path,
read_only: self.current_read_only,
format: self.current_format,
});
}
self
}
}
#[cfg(feature = "blk")]
impl Default for DiskBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "blk")]
impl From<DiskImageFormat> for devices::virtio::block::ImageType {
fn from(format: DiskImageFormat) -> Self {
match format {
DiskImageFormat::Raw => devices::virtio::block::ImageType::Raw,
DiskImageFormat::Qcow2 => devices::virtio::block::ImageType::Qcow2,
DiskImageFormat::Vmdk => devices::virtio::block::ImageType::Vmdk,
}
}
}