12ed17abbSSamuel Ortiz // Copyright © 2019 Intel Corporation
22ed17abbSSamuel Ortiz //
32ed17abbSSamuel Ortiz // SPDX-License-Identifier: Apache-2.0
42ed17abbSSamuel Ortiz //
52ed17abbSSamuel Ortiz
61f13165fSPhilipp Schuster #[cfg(test)]
71f13165fSPhilipp Schuster mod test_util;
81f13165fSPhilipp Schuster
988a9f799SRob Bradford use std::fs::File;
1088a9f799SRob Bradford use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
1188a9f799SRob Bradford use std::sync::mpsc::channel;
1288a9f799SRob Bradford use std::sync::Mutex;
1388a9f799SRob Bradford use std::{env, io};
1488a9f799SRob Bradford
157bc34521SWei Liu use clap::{Arg, ArgAction, ArgGroup, ArgMatches, Command};
1633c15ca2SSongqian Li use event_monitor::event;
1781880743SSamuel Ortiz use libc::EFD_NONBLOCK;
1821d40d74SAlyssa Ross use log::{warn, LevelFilter};
19b65502c3SRob Bradford use option_parser::OptionParser;
2008ac3405SBo Chen use seccompiler::SeccompAction;
2137ea979eSRob Bradford use signal_hook::consts::SIGSYS;
22c22b788bSRob Bradford use thiserror::Error;
23f00df25dSOmer Faruk Bayram #[cfg(feature = "dbus_api")]
247a458d85SOmer Faruk Bayram use vmm::api::dbus::{dbus_api_graceful_shutdown, DBusApiOptions};
2510914943SAlexandru Matei use vmm::api::http::http_api_graceful_shutdown;
264ca18c08SAlyssa Ross use vmm::api::ApiAction;
2733c15ca2SSongqian Li use vmm::config::{RestoreConfig, VmParams};
2811c17ca3SPraveen K Paladugu use vmm::landlock::{Landlock, LandlockError};
2933c15ca2SSongqian Li use vmm::vm_config;
3033c15ca2SSongqian Li #[cfg(target_arch = "x86_64")]
3133c15ca2SSongqian Li use vmm::vm_config::SgxEpcConfig;
3233c15ca2SSongqian Li use vmm::vm_config::{
3333c15ca2SSongqian Li BalloonConfig, DeviceConfig, DiskConfig, FsConfig, LandlockConfig, NetConfig, NumaConfig,
3433c15ca2SSongqian Li PciSegmentConfig, PmemConfig, RateLimiterGroupConfig, TpmConfig, UserDeviceConfig, VdpaConfig,
3533c15ca2SSongqian Li VmConfig, VsockConfig,
3633c15ca2SSongqian Li };
3781880743SSamuel Ortiz use vmm_sys_util::eventfd::EventFd;
387549149bSAlyssa Ross use vmm_sys_util::signal::block_signal;
391853b350SSamuel Ortiz
403a81f932SRob Bradford #[cfg(feature = "dhat-heap")]
413a81f932SRob Bradford #[global_allocator]
423a81f932SRob Bradford static ALLOC: dhat::Alloc = dhat::Alloc;
433a81f932SRob Bradford
44c22b788bSRob Bradford #[derive(Error, Debug)]
45c22b788bSRob Bradford enum Error {
461b03e591SPhilipp Schuster #[error("Failed to create API EventFd")]
4719c5e91bSRob Bradford CreateApiEventFd(#[source] std::io::Error),
4806eb82d2SRob Bradford #[cfg(feature = "guest_debug")]
491b03e591SPhilipp Schuster #[error("Failed to create Debug EventFd")]
502451c4d8SAkira Moroo CreateDebugEventFd(#[source] std::io::Error),
511b03e591SPhilipp Schuster #[error("Failed to create exit EventFd")]
5221d40d74SAlyssa Ross CreateExitEventFd(#[source] std::io::Error),
531b03e591SPhilipp Schuster #[error("Failed to open hypervisor interface (is hypervisor interface available?)")]
54c22b788bSRob Bradford CreateHypervisor(#[source] hypervisor::HypervisorError),
551b03e591SPhilipp Schuster #[error("Failed to start the VMM thread")]
5619c5e91bSRob Bradford StartVmmThread(#[source] vmm::Error),
571b03e591SPhilipp Schuster #[error("Error parsing config")]
58a2123439SPhilipp Schuster ParsingConfig(#[source] vmm::config::Error),
591b03e591SPhilipp Schuster #[error("Error creating VM")]
60a2123439SPhilipp Schuster VmCreate(#[source] vmm::api::ApiError),
611b03e591SPhilipp Schuster #[error("Error booting VM")]
62a2123439SPhilipp Schuster VmBoot(#[source] vmm::api::ApiError),
631b03e591SPhilipp Schuster #[error("Error restoring VM")]
64a2123439SPhilipp Schuster VmRestore(#[source] vmm::api::ApiError),
651b03e591SPhilipp Schuster #[error("Error parsing restore")]
66a2123439SPhilipp Schuster ParsingRestore(#[source] vmm::config::Error),
67c22b788bSRob Bradford #[error("Failed to join on VMM thread: {0:?}")]
68c22b788bSRob Bradford ThreadJoin(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
691b03e591SPhilipp Schuster #[error("VMM thread exited with error")]
70c22b788bSRob Bradford VmmThread(#[source] vmm::Error),
711b03e591SPhilipp Schuster #[error("Error parsing --api-socket")]
72a2123439SPhilipp Schuster ParsingApiSocket(#[source] std::num::ParseIntError),
731b03e591SPhilipp Schuster #[error("Error parsing --event-monitor")]
74a2123439SPhilipp Schuster ParsingEventMonitor(#[source] option_parser::OptionParserError),
757a458d85SOmer Faruk Bayram #[cfg(feature = "dbus_api")]
767a458d85SOmer Faruk Bayram #[error("`--dbus-object-path` option isn't provided")]
777a458d85SOmer Faruk Bayram MissingDBusObjectPath,
787a458d85SOmer Faruk Bayram #[cfg(feature = "dbus_api")]
797a458d85SOmer Faruk Bayram #[error("`--dbus-service-name` option isn't provided")]
807a458d85SOmer Faruk Bayram MissingDBusServiceName,
81af02262bSRob Bradford #[error("Error parsing --event-monitor: path or fd required")]
82af02262bSRob Bradford BareEventMonitor,
831b03e591SPhilipp Schuster #[error("Error doing event monitor I/O")]
84a2123439SPhilipp Schuster EventMonitorIo(#[source] std::io::Error),
851b03e591SPhilipp Schuster #[error("Event monitor thread failed")]
8602e1c544SOmer Faruk Bayram EventMonitorThread(#[source] vmm::Error),
8706eb82d2SRob Bradford #[cfg(feature = "guest_debug")]
881b03e591SPhilipp Schuster #[error("Error parsing --gdb")]
89fff62d93SPhilipp Schuster ParsingGdb(#[source] option_parser::OptionParserError),
9006eb82d2SRob Bradford #[cfg(feature = "guest_debug")]
912451c4d8SAkira Moroo #[error("Error parsing --gdb: path required")]
922451c4d8SAkira Moroo BareGdb,
931b03e591SPhilipp Schuster #[error("Error creating log file")]
94fff62d93SPhilipp Schuster LogFileCreation(#[source] std::io::Error),
951b03e591SPhilipp Schuster #[error("Error setting up logger")]
96fff62d93SPhilipp Schuster LoggerSetup(#[source] log::SetLoggerError),
971b03e591SPhilipp Schuster #[error("Failed to gracefully shutdown http api")]
9810914943SAlexandru Matei HttpApiShutdown(#[source] vmm::Error),
991b03e591SPhilipp Schuster #[error("Failed to create Landlock object")]
10011c17ca3SPraveen K Paladugu CreateLandlock(#[source] LandlockError),
1011b03e591SPhilipp Schuster #[error("Failed to apply Landlock")]
10211c17ca3SPraveen K Paladugu ApplyLandlock(#[source] LandlockError),
103c22b788bSRob Bradford }
104c22b788bSRob Bradford
105f13d8f14SAlexandru Matei #[derive(Error, Debug)]
106f13d8f14SAlexandru Matei enum FdTableError {
1071b03e591SPhilipp Schuster #[error("Failed to create event fd")]
108a2123439SPhilipp Schuster CreateEventFd(#[source] std::io::Error),
1091b03e591SPhilipp Schuster #[error("Failed to obtain file limit")]
110a2123439SPhilipp Schuster GetRLimit(#[source] std::io::Error),
1111b03e591SPhilipp Schuster #[error("Error calling fcntl with F_GETFD")]
112a2123439SPhilipp Schuster GetFd(#[source] std::io::Error),
1131b03e591SPhilipp Schuster #[error("Failed to duplicate file handle")]
114a2123439SPhilipp Schuster Dup2(#[source] std::io::Error),
115f13d8f14SAlexandru Matei }
116f13d8f14SAlexandru Matei
117fca911e5SRob Bradford struct Logger {
118658c076eSSebastien Boeuf output: Mutex<Box<dyn std::io::Write + Send>>,
119fca911e5SRob Bradford start: std::time::Instant,
120fca911e5SRob Bradford }
121fca911e5SRob Bradford
122fca911e5SRob Bradford impl log::Log for Logger {
enabled(&self, _metadata: &log::Metadata) -> bool123fca911e5SRob Bradford fn enabled(&self, _metadata: &log::Metadata) -> bool {
124fca911e5SRob Bradford true
125fca911e5SRob Bradford }
126fca911e5SRob Bradford
log(&self, record: &log::Record)127fca911e5SRob Bradford fn log(&self, record: &log::Record) {
128fca911e5SRob Bradford if !self.enabled(record.metadata()) {
129fca911e5SRob Bradford return;
130fca911e5SRob Bradford }
131fca911e5SRob Bradford
132fca911e5SRob Bradford let now = std::time::Instant::now();
133fca911e5SRob Bradford let duration = now.duration_since(self.start);
134fca911e5SRob Bradford
135bc053f1bSRob Bradford if record.file().is_some() && record.line().is_some() {
136499989fbSYu Li write!(
137fca911e5SRob Bradford *(*(self.output.lock().unwrap())),
138499989fbSYu Li "cloud-hypervisor: {:.6?}: <{}> {}:{}:{} -- {}\r\n",
139fca911e5SRob Bradford duration,
1408a277358SRob Bradford std::thread::current().name().unwrap_or("anonymous"),
141fca911e5SRob Bradford record.level(),
142fca911e5SRob Bradford record.file().unwrap(),
143fca911e5SRob Bradford record.line().unwrap(),
144fca911e5SRob Bradford record.args()
145fca911e5SRob Bradford )
146fca911e5SRob Bradford } else {
147499989fbSYu Li write!(
148fca911e5SRob Bradford *(*(self.output.lock().unwrap())),
149499989fbSYu Li "cloud-hypervisor: {:.6?}: <{}> {}:{} -- {}\r\n",
150fca911e5SRob Bradford duration,
1518a277358SRob Bradford std::thread::current().name().unwrap_or("anonymous"),
152fca911e5SRob Bradford record.level(),
153fca911e5SRob Bradford record.target(),
154fca911e5SRob Bradford record.args()
155fca911e5SRob Bradford )
1566e6b2b84SRob Bradford }
1576e6b2b84SRob Bradford .ok();
158fca911e5SRob Bradford }
flush(&self)159fca911e5SRob Bradford fn flush(&self) {}
160fca911e5SRob Bradford }
161fca911e5SRob Bradford
prepare_default_values() -> (String, String, String)1627bc34521SWei Liu fn prepare_default_values() -> (String, String, String) {
1637bc34521SWei Liu (default_vcpus(), default_memory(), default_rng())
1647bc34521SWei Liu }
1657bc34521SWei Liu
default_vcpus() -> String166fe490561SWei Liu fn default_vcpus() -> String {
167fe490561SWei Liu format!(
168fe490561SWei Liu "boot={},max_phys_bits={}",
16933c15ca2SSongqian Li vm_config::DEFAULT_VCPUS,
17033c15ca2SSongqian Li vm_config::DEFAULT_MAX_PHYS_BITS
171fe490561SWei Liu )
172fe490561SWei Liu }
173fe490561SWei Liu
default_memory() -> String174fe490561SWei Liu fn default_memory() -> String {
17533c15ca2SSongqian Li format!("size={}M", vm_config::DEFAULT_MEMORY_MB)
176fe490561SWei Liu }
177fe490561SWei Liu
default_rng() -> String178fe490561SWei Liu fn default_rng() -> String {
17933c15ca2SSongqian Li format!("src={}", vm_config::DEFAULT_RNG_SOURCE)
18017a167dbSSebastien Boeuf }
18117a167dbSSebastien Boeuf
182fa58b725SPhilipp Schuster /// Returns all [`Arg`]s in alphabetical order. This is the order used in the
183fa58b725SPhilipp Schuster /// `--help` output.
get_cli_options_sorted( default_vcpus: String, default_memory: String, default_rng: String, ) -> Box<[Arg]>184fa58b725SPhilipp Schuster fn get_cli_options_sorted(
185fa58b725SPhilipp Schuster default_vcpus: String,
186fa58b725SPhilipp Schuster default_memory: String,
187fa58b725SPhilipp Schuster default_rng: String,
188fa58b725SPhilipp Schuster ) -> Box<[Arg]> {
189fa58b725SPhilipp Schuster [
190fa58b725SPhilipp Schuster Arg::new("api-socket")
191fa58b725SPhilipp Schuster .long("api-socket")
192fa58b725SPhilipp Schuster .help("HTTP API socket (UNIX domain socket): path=</path/to/a/file> or fd=<fd>.")
193fa58b725SPhilipp Schuster .num_args(1)
194fa58b725SPhilipp Schuster .group("vmm-config"),
195fa58b725SPhilipp Schuster Arg::new("balloon")
196fa58b725SPhilipp Schuster .long("balloon")
197fa58b725SPhilipp Schuster .help(BalloonConfig::SYNTAX)
198fa58b725SPhilipp Schuster .num_args(1)
199fa58b725SPhilipp Schuster .group("vm-config"),
200fa58b725SPhilipp Schuster Arg::new("cmdline")
201fa58b725SPhilipp Schuster .long("cmdline")
202fa58b725SPhilipp Schuster .help("Kernel command line")
203fa58b725SPhilipp Schuster .num_args(1)
204fa58b725SPhilipp Schuster .group("vm-config"), Arg::new("console")
205fa58b725SPhilipp Schuster .long("console")
206fa58b725SPhilipp Schuster .help(
207fa58b725SPhilipp Schuster "Control (virtio) console: \"off|null|pty|tty|file=</path/to/a/file>,iommu=on|off\"",
208fa58b725SPhilipp Schuster )
209fa58b725SPhilipp Schuster .default_value("tty")
210fa58b725SPhilipp Schuster .group("vm-config"),
2117bc34521SWei Liu Arg::new("cpus")
2127bc34521SWei Liu .long("cpus")
2137bc34521SWei Liu .help(
2147bc34521SWei Liu "boot=<boot_vcpus>,max=<max_vcpus>,\
2157bc34521SWei Liu topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>,\
2167bc34521SWei Liu kvm_hyperv=on|off,max_phys_bits=<maximum_number_of_physical_bits>,\
2177bc34521SWei Liu affinity=<list_of_vcpus_with_their_associated_cpuset>,\
2187bc34521SWei Liu features=<list_of_features_to_enable>",
2197bc34521SWei Liu )
2207bc34521SWei Liu .default_value(default_vcpus)
2217bc34521SWei Liu .group("vm-config"),
222fa58b725SPhilipp Schuster #[cfg(target_arch = "x86_64")]
223fa58b725SPhilipp Schuster Arg::new("debug-console")
224fa58b725SPhilipp Schuster .long("debug-console")
225fa58b725SPhilipp Schuster .help("Debug console: off|pty|tty|file=</path/to/a/file>,iobase=<port in hex>")
226fa58b725SPhilipp Schuster .default_value("off,iobase=0xe9")
227fa58b725SPhilipp Schuster .group("vm-config"),
228fa58b725SPhilipp Schuster #[cfg(feature = "dbus_api")]
229fa58b725SPhilipp Schuster Arg::new("dbus-service-name")
230fa58b725SPhilipp Schuster .long("dbus-service-name")
231fa58b725SPhilipp Schuster .help("Well known name of the device")
232fa58b725SPhilipp Schuster .num_args(1)
233fa58b725SPhilipp Schuster .group("vmm-config"),
234fa58b725SPhilipp Schuster #[cfg(feature = "dbus_api")]
235fa58b725SPhilipp Schuster Arg::new("dbus-object-path")
236fa58b725SPhilipp Schuster .long("dbus-object-path")
237fa58b725SPhilipp Schuster .help("Object path to serve the dbus interface")
238fa58b725SPhilipp Schuster .num_args(1)
239fa58b725SPhilipp Schuster .group("vmm-config"),
240fa58b725SPhilipp Schuster #[cfg(feature = "dbus_api")]
241fa58b725SPhilipp Schuster Arg::new("dbus-system-bus")
242fa58b725SPhilipp Schuster .long("dbus-system-bus")
243fa58b725SPhilipp Schuster .action(ArgAction::SetTrue)
244fa58b725SPhilipp Schuster .help("Use the system bus instead of a session bus")
245fa58b725SPhilipp Schuster .num_args(0)
246fa58b725SPhilipp Schuster .group("vmm-config"),
247fa58b725SPhilipp Schuster Arg::new("device")
248fa58b725SPhilipp Schuster .long("device")
249fa58b725SPhilipp Schuster .help(DeviceConfig::SYNTAX)
250fa58b725SPhilipp Schuster .num_args(1..)
251fa58b725SPhilipp Schuster .group("vm-config"),
252fa58b725SPhilipp Schuster Arg::new("disk")
253fa58b725SPhilipp Schuster .long("disk")
254fa58b725SPhilipp Schuster .help(DiskConfig::SYNTAX)
255fa58b725SPhilipp Schuster .num_args(1..)
256fa58b725SPhilipp Schuster .group("vm-config"),
257fa58b725SPhilipp Schuster Arg::new("event-monitor")
258fa58b725SPhilipp Schuster .long("event-monitor")
259fa58b725SPhilipp Schuster .help("File to report events on: path=</path/to/a/file> or fd=<fd>")
260fa58b725SPhilipp Schuster .num_args(1)
261fa58b725SPhilipp Schuster .group("vmm-config"),
262fa58b725SPhilipp Schuster Arg::new("firmware")
263fa58b725SPhilipp Schuster .long("firmware")
264fa58b725SPhilipp Schuster .help("Path to firmware that is loaded in an architectural specific way")
265fa58b725SPhilipp Schuster .num_args(1)
266fa58b725SPhilipp Schuster .group("vm-payload"),
267fa58b725SPhilipp Schuster Arg::new("fs")
268fa58b725SPhilipp Schuster .long("fs")
269fa58b725SPhilipp Schuster .help(FsConfig::SYNTAX)
270fa58b725SPhilipp Schuster .num_args(1..)
271fa58b725SPhilipp Schuster .group("vm-config"),
272fa58b725SPhilipp Schuster #[cfg(feature = "guest_debug")]
273fa58b725SPhilipp Schuster Arg::new("gdb")
274fa58b725SPhilipp Schuster .long("gdb")
275fa58b725SPhilipp Schuster .help("GDB socket (UNIX domain socket): path=</path/to/a/file>")
276fa58b725SPhilipp Schuster .num_args(1)
277fa58b725SPhilipp Schuster .group("vmm-config"),
278fa58b725SPhilipp Schuster #[cfg(feature = "igvm")]
279fa58b725SPhilipp Schuster Arg::new("igvm")
280fa58b725SPhilipp Schuster .long("igvm")
281fa58b725SPhilipp Schuster .help("Path to IGVM file to load.")
282fa58b725SPhilipp Schuster .num_args(1)
283fa58b725SPhilipp Schuster .group("vm-payload"),
284fa58b725SPhilipp Schuster #[cfg(feature = "sev_snp")]
285fa58b725SPhilipp Schuster Arg::new("host-data")
286fa58b725SPhilipp Schuster .long("host-data")
287fa58b725SPhilipp Schuster .help("Host specific data to SEV SNP guest")
2887bc34521SWei Liu .num_args(1)
2897bc34521SWei Liu .group("vm-config"),
290fa58b725SPhilipp Schuster Arg::new("initramfs")
291fa58b725SPhilipp Schuster .long("initramfs")
292fa58b725SPhilipp Schuster .help("Path to initramfs image")
293fa58b725SPhilipp Schuster .num_args(1)
294fa58b725SPhilipp Schuster .group("vm-config"),
295fa58b725SPhilipp Schuster Arg::new("kernel")
296fa58b725SPhilipp Schuster .long("kernel")
297fa58b725SPhilipp Schuster .help(
298fa58b725SPhilipp Schuster "Path to kernel to load. This may be a kernel or firmware that supports a PVH \
299fa58b725SPhilipp Schuster entry point (e.g. vmlinux) or architecture equivalent",
3007bc34521SWei Liu )
301fa58b725SPhilipp Schuster .num_args(1)
302fa58b725SPhilipp Schuster .group("vm-payload"),
303fa58b725SPhilipp Schuster Arg::new("landlock")
304fa58b725SPhilipp Schuster .long("landlock")
305fa58b725SPhilipp Schuster .num_args(0)
306fa58b725SPhilipp Schuster .help(
307fa58b725SPhilipp Schuster "enable/disable Landlock.",
308fa58b725SPhilipp Schuster )
309fa58b725SPhilipp Schuster .action(ArgAction::SetTrue)
310fa58b725SPhilipp Schuster .default_value("false")
311fa58b725SPhilipp Schuster .group("vm-config"),
312fa58b725SPhilipp Schuster Arg::new("landlock-rules")
313fa58b725SPhilipp Schuster .long("landlock-rules")
314fa58b725SPhilipp Schuster .help(LandlockConfig::SYNTAX)
315fa58b725SPhilipp Schuster .num_args(1..)
316fa58b725SPhilipp Schuster .group("vm-config"),
317fa58b725SPhilipp Schuster Arg::new("log-file")
318fa58b725SPhilipp Schuster .long("log-file")
319fa58b725SPhilipp Schuster .help("Log file. Standard error is used if not specified")
320fa58b725SPhilipp Schuster .num_args(1)
321fa58b725SPhilipp Schuster .group("logging"),
3227bc34521SWei Liu Arg::new("memory")
3237bc34521SWei Liu .long("memory")
3247bc34521SWei Liu .help(
3257bc34521SWei Liu "Memory parameters \
3267bc34521SWei Liu \"size=<guest_memory_size>,mergeable=on|off,shared=on|off,\
3277bc34521SWei Liu hugepages=on|off,hugepage_size=<hugepage_size>,\
3287bc34521SWei Liu hotplug_method=acpi|virtio-mem,\
3297bc34521SWei Liu hotplug_size=<hotpluggable_memory_size>,\
3307bc34521SWei Liu hotplugged_size=<hotplugged_memory_size>,\
3317bc34521SWei Liu prefault=on|off,thp=on|off\"",
3327bc34521SWei Liu )
3337bc34521SWei Liu .default_value(default_memory)
3347bc34521SWei Liu .group("vm-config"),
3357bc34521SWei Liu Arg::new("memory-zone")
3367bc34521SWei Liu .long("memory-zone")
3377bc34521SWei Liu .help(
3387bc34521SWei Liu "User defined memory zone parameters \
3397bc34521SWei Liu \"size=<guest_memory_region_size>,file=<backing_file>,\
3407bc34521SWei Liu shared=on|off,\
3417bc34521SWei Liu hugepages=on|off,hugepage_size=<hugepage_size>,\
3427bc34521SWei Liu host_numa_node=<node_id>,\
3437bc34521SWei Liu id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,\
3447bc34521SWei Liu hotplugged_size=<hotplugged_memory_size>,\
3457bc34521SWei Liu prefault=on|off\"",
3467bc34521SWei Liu )
3477bc34521SWei Liu .num_args(1..)
3487bc34521SWei Liu .group("vm-config"),
3497bc34521SWei Liu Arg::new("net")
3507bc34521SWei Liu .long("net")
35133c15ca2SSongqian Li .help(NetConfig::SYNTAX)
3527bc34521SWei Liu .num_args(1..)
3537bc34521SWei Liu .group("vm-config"),
354fa58b725SPhilipp Schuster Arg::new("numa")
355fa58b725SPhilipp Schuster .long("numa")
356fa58b725SPhilipp Schuster .help(NumaConfig::SYNTAX)
357fa58b725SPhilipp Schuster .num_args(1..)
358fa58b725SPhilipp Schuster .group("vm-config"),
359fa58b725SPhilipp Schuster Arg::new("pci-segment")
360fa58b725SPhilipp Schuster .long("pci-segment")
361fa58b725SPhilipp Schuster .help(PciSegmentConfig::SYNTAX)
362fa58b725SPhilipp Schuster .num_args(1..)
363fa58b725SPhilipp Schuster .group("vm-config"),
364fa58b725SPhilipp Schuster Arg::new("platform")
365fa58b725SPhilipp Schuster .long("platform")
366fa58b725SPhilipp Schuster .help(
367fa58b725SPhilipp Schuster "num_pci_segments=<num_pci_segments>,iommu_segments=<list_of_segments>,iommu_address_width=<bits>,serial_number=<dmi_device_serial_number>,uuid=<dmi_device_uuid>,oem_strings=<list_of_strings>"
3687bc34521SWei Liu )
369fa58b725SPhilipp Schuster .num_args(1)
370fa58b725SPhilipp Schuster .group("vm-config"),
371fa58b725SPhilipp Schuster Arg::new("pmem")
372fa58b725SPhilipp Schuster .long("pmem")
373fa58b725SPhilipp Schuster .help(PmemConfig::SYNTAX)
374fa58b725SPhilipp Schuster .num_args(1..)
375fa58b725SPhilipp Schuster .group("vm-config"),
376fa58b725SPhilipp Schuster #[cfg(feature = "pvmemcontrol")]
377fa58b725SPhilipp Schuster Arg::new("pvmemcontrol")
378fa58b725SPhilipp Schuster .long("pvmemcontrol")
379fa58b725SPhilipp Schuster .help("Pvmemcontrol device")
380fa58b725SPhilipp Schuster .num_args(0)
381fa58b725SPhilipp Schuster .action(ArgAction::SetTrue)
382fa58b725SPhilipp Schuster .group("vm-config"),
383fa58b725SPhilipp Schuster Arg::new("pvpanic")
384fa58b725SPhilipp Schuster .long("pvpanic")
385fa58b725SPhilipp Schuster .help("Enable pvpanic device")
386fa58b725SPhilipp Schuster .num_args(0)
387fa58b725SPhilipp Schuster .action(ArgAction::SetTrue)
388fa58b725SPhilipp Schuster .group("vm-config"),
389fa58b725SPhilipp Schuster Arg::new("rate-limit-group")
390fa58b725SPhilipp Schuster .long("rate-limit-group")
391fa58b725SPhilipp Schuster .help(RateLimiterGroupConfig::SYNTAX)
392fa58b725SPhilipp Schuster .num_args(1..)
393fa58b725SPhilipp Schuster .group("vm-config"),
394fa58b725SPhilipp Schuster Arg::new("restore")
395fa58b725SPhilipp Schuster .long("restore")
396fa58b725SPhilipp Schuster .help(RestoreConfig::SYNTAX)
397fa58b725SPhilipp Schuster .num_args(1)
398fa58b725SPhilipp Schuster .group("vmm-config"),
3997bc34521SWei Liu Arg::new("rng")
4007bc34521SWei Liu .long("rng")
4017bc34521SWei Liu .help(
4027bc34521SWei Liu "Random number generator parameters \"src=<entropy_source_path>,iommu=on|off\"",
4037bc34521SWei Liu )
4047bc34521SWei Liu .default_value(default_rng)
4057bc34521SWei Liu .group("vm-config"),
4067bc34521SWei Liu Arg::new("seccomp")
4077bc34521SWei Liu .long("seccomp")
4087bc34521SWei Liu .num_args(1)
4097bc34521SWei Liu .value_parser(["true", "false", "log"])
4107bc34521SWei Liu .default_value("true"),
411fa58b725SPhilipp Schuster Arg::new("serial")
412fa58b725SPhilipp Schuster .long("serial")
413fa58b725SPhilipp Schuster .help("Control serial port: off|null|pty|tty|file=</path/to/a/file>|socket=</path/to/a/file>")
414fa58b725SPhilipp Schuster .default_value("null")
4152ef04671SRob Bradford .group("vm-config"),
416d9244e9fSSebastien Boeuf #[cfg(target_arch = "x86_64")]
4177bc34521SWei Liu Arg::new("sgx-epc")
4187bc34521SWei Liu .long("sgx-epc")
41933c15ca2SSongqian Li .help(SgxEpcConfig::SYNTAX)
4207bc34521SWei Liu .num_args(1..)
4217bc34521SWei Liu .group("vm-config"),
422fa58b725SPhilipp Schuster Arg::new("tpm")
423fa58b725SPhilipp Schuster .long("tpm")
424fa58b725SPhilipp Schuster .num_args(1)
425fa58b725SPhilipp Schuster .help(TpmConfig::SYNTAX)
426e50a6411SPhilipp Schuster .group("vm-config"),
427fa58b725SPhilipp Schuster Arg::new("user-device")
428fa58b725SPhilipp Schuster .long("user-device")
429fa58b725SPhilipp Schuster .help(UserDeviceConfig::SYNTAX)
430fa58b725SPhilipp Schuster .num_args(1..)
431aa6c486aSMuminul Islam .group("vm-config"),
432fa58b725SPhilipp Schuster Arg::new("v")
433fa58b725SPhilipp Schuster .short('v')
434fa58b725SPhilipp Schuster .action(ArgAction::Count)
435fa58b725SPhilipp Schuster .help("Sets the level of debugging output")
436fa58b725SPhilipp Schuster .group("logging"),
437fa58b725SPhilipp Schuster Arg::new("vdpa")
438fa58b725SPhilipp Schuster .long("vdpa")
439fa58b725SPhilipp Schuster .help(VdpaConfig::SYNTAX)
440fa58b725SPhilipp Schuster .num_args(1..)
4415f18ac3bSYuanchu Xie .group("vm-config"),
4427bc34521SWei Liu Arg::new("version")
4437bc34521SWei Liu .short('V')
4447bc34521SWei Liu .long("version")
4457bc34521SWei Liu .action(ArgAction::SetTrue)
4467bc34521SWei Liu .help("Print version")
4477bc34521SWei Liu .num_args(0),
448fa58b725SPhilipp Schuster Arg::new("vsock")
449fa58b725SPhilipp Schuster .long("vsock")
450fa58b725SPhilipp Schuster .help(VsockConfig::SYNTAX)
451fa58b725SPhilipp Schuster .num_args(1)
452fa58b725SPhilipp Schuster .group("vm-config"),
453fa58b725SPhilipp Schuster Arg::new("watchdog")
454fa58b725SPhilipp Schuster .long("watchdog")
455fa58b725SPhilipp Schuster .help("Enable virtio-watchdog")
456fa58b725SPhilipp Schuster .num_args(0)
457fa58b725SPhilipp Schuster .action(ArgAction::SetTrue)
458fa58b725SPhilipp Schuster .group("vm-config"),
459fa58b725SPhilipp Schuster ].to_vec().into_boxed_slice()
460fa58b725SPhilipp Schuster }
461fa58b725SPhilipp Schuster
462fa58b725SPhilipp Schuster /// Creates the CLI definition of Cloud Hypervisor.
create_app(default_vcpus: String, default_memory: String, default_rng: String) -> Command463fa58b725SPhilipp Schuster fn create_app(default_vcpus: String, default_memory: String, default_rng: String) -> Command {
464fa58b725SPhilipp Schuster let groups = [
465fa58b725SPhilipp Schuster ArgGroup::new("vm-config")
466fa58b725SPhilipp Schuster .multiple(true)
467fa58b725SPhilipp Schuster .requires("vm-payload"),
468fa58b725SPhilipp Schuster ArgGroup::new("vmm-config").multiple(true),
469fa58b725SPhilipp Schuster ArgGroup::new("logging").multiple(true),
470fa58b725SPhilipp Schuster ArgGroup::new("vm-payload").multiple(true),
471fa58b725SPhilipp Schuster ];
472fa58b725SPhilipp Schuster
473fa58b725SPhilipp Schuster let args = get_cli_options_sorted(default_vcpus, default_memory, default_rng);
474fa58b725SPhilipp Schuster
475fa58b725SPhilipp Schuster Command::new("cloud-hypervisor")
476fa58b725SPhilipp Schuster // 'BUILD_VERSION' is set by the build script 'build.rs' at
477fa58b725SPhilipp Schuster // compile time
478fa58b725SPhilipp Schuster .author(env!("CARGO_PKG_AUTHORS"))
479fa58b725SPhilipp Schuster .about("Launch a cloud-hypervisor VMM.")
480fa58b725SPhilipp Schuster .arg_required_else_help(true)
481fa58b725SPhilipp Schuster .groups(groups)
482fa58b725SPhilipp Schuster .args(args)
4839c3a7ddcSSebastien Boeuf }
4849c3a7ddcSSebastien Boeuf
start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error>4857bc34521SWei Liu fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
4867bc34521SWei Liu let log_level = match cmd_arguments.get_count("v") {
4872d262323SRob Bradford 0 => LevelFilter::Warn,
4882d262323SRob Bradford 1 => LevelFilter::Info,
4892d262323SRob Bradford 2 => LevelFilter::Debug,
4902d262323SRob Bradford _ => LevelFilter::Trace,
4912d262323SRob Bradford };
4922d262323SRob Bradford
4937bc34521SWei Liu let log_file: Box<dyn std::io::Write + Send> = if let Some(ref file) =
4947bc34521SWei Liu cmd_arguments.get_one::<String>("log-file")
4957bc34521SWei Liu {
4962d262323SRob Bradford Box::new(std::fs::File::create(std::path::Path::new(file)).map_err(Error::LogFileCreation)?)
4972d262323SRob Bradford } else {
4982d262323SRob Bradford Box::new(std::io::stderr())
4992d262323SRob Bradford };
5002d262323SRob Bradford
5012d262323SRob Bradford log::set_boxed_logger(Box::new(Logger {
5022d262323SRob Bradford output: Mutex::new(log_file),
5032d262323SRob Bradford start: std::time::Instant::now(),
5042d262323SRob Bradford }))
5052d262323SRob Bradford .map(|()| log::set_max_level(log_level))
5062d262323SRob Bradford .map_err(Error::LoggerSetup)?;
5072d262323SRob Bradford
5087bc34521SWei Liu let (api_socket_path, api_socket_fd) =
5097bc34521SWei Liu if let Some(socket_config) = cmd_arguments.get_one::<String>("api-socket") {
510767b4f0eSWilliam Douglas let mut parser = OptionParser::new();
511767b4f0eSWilliam Douglas parser.add("path").add("fd");
512767b4f0eSWilliam Douglas parser.parse(socket_config).unwrap_or_default();
513767b4f0eSWilliam Douglas
514767b4f0eSWilliam Douglas if let Some(fd) = parser.get("fd") {
515767b4f0eSWilliam Douglas (
516767b4f0eSWilliam Douglas None,
517767b4f0eSWilliam Douglas Some(fd.parse::<RawFd>().map_err(Error::ParsingApiSocket)?),
518767b4f0eSWilliam Douglas )
519767b4f0eSWilliam Douglas } else if let Some(path) = parser.get("path") {
520767b4f0eSWilliam Douglas (Some(path), None)
521767b4f0eSWilliam Douglas } else {
5227bc34521SWei Liu (
5237bc34521SWei Liu cmd_arguments
5247bc34521SWei Liu .get_one::<String>("api-socket")
5257bc34521SWei Liu .map(|s| s.to_string()),
5267bc34521SWei Liu None,
5277bc34521SWei Liu )
528767b4f0eSWilliam Douglas }
529767b4f0eSWilliam Douglas } else {
530767b4f0eSWilliam Douglas (None, None)
531767b4f0eSWilliam Douglas };
532767b4f0eSWilliam Douglas
53381880743SSamuel Ortiz let (api_request_sender, api_request_receiver) = channel();
53419c5e91bSRob Bradford let api_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateApiEventFd)?;
53581880743SSamuel Ortiz
536c016a0d4SOmer Faruk Bayram let api_request_sender_clone = api_request_sender.clone();
5377bc34521SWei Liu let seccomp_action = if let Some(seccomp_value) = cmd_arguments.get_one::<String>("seccomp") {
5387bc34521SWei Liu match seccomp_value as &str {
539b41884a4SBo Chen "true" => SeccompAction::Trap,
540b41884a4SBo Chen "false" => SeccompAction::Allow,
5418e74637eSBo Chen "log" => SeccompAction::Log,
542111225a2SWei Liu val => {
543111225a2SWei Liu // The user providing an invalid value will be rejected
544111225a2SWei Liu panic!("Invalid parameter {val} for \"--seccomp\" flag");
5455120c275SSebastien Boeuf }
5467bc34521SWei Liu }
5477bc34521SWei Liu } else {
5487bc34521SWei Liu SeccompAction::Trap
5495120c275SSebastien Boeuf };
55039d080e0SRob Bradford
55139d080e0SRob Bradford if seccomp_action == SeccompAction::Trap {
55237ea979eSRob Bradford // SAFETY: We only using signal_hook for managing signals and only execute signal
55337ea979eSRob Bradford // handler safe functions (writing to stderr) and manipulating signals.
55437ea979eSRob Bradford unsafe {
55537ea979eSRob Bradford signal_hook::low_level::register(signal_hook::consts::SIGSYS, || {
55639d080e0SRob Bradford eprint!(
55737ea979eSRob Bradford "\n==== Possible seccomp violation ====\n\
55839d080e0SRob Bradford Try running with `strace -ff` to identify the cause and open an issue: \
55939d080e0SRob Bradford https://github.com/cloud-hypervisor/cloud-hypervisor/issues/new\n"
56039d080e0SRob Bradford );
56139d080e0SRob Bradford signal_hook::low_level::emulate_default_handler(SIGSYS).unwrap();
56239d080e0SRob Bradford })
56337ea979eSRob Bradford }
5645e527294SRob Bradford .map_err(|e| eprintln!("Error adding SIGSYS signal handler: {e}"))
56537ea979eSRob Bradford .ok();
56639d080e0SRob Bradford }
56739d080e0SRob Bradford
56809f36589SChris Webb // SAFETY: Trivially safe.
56909f36589SChris Webb unsafe {
57009f36589SChris Webb libc::signal(libc::SIGCHLD, libc::SIG_IGN);
57109f36589SChris Webb }
57209f36589SChris Webb
5737549149bSAlyssa Ross // Before we start any threads, mask the signals we'll be
5747549149bSAlyssa Ross // installing handlers for, to make sure they only ever run on the
5757549149bSAlyssa Ross // dedicated signal handling thread we'll start in a bit.
576121729a3SRob Bradford for sig in &vmm::vm::Vm::HANDLED_SIGNALS {
577121729a3SRob Bradford if let Err(e) = block_signal(*sig) {
5785e527294SRob Bradford eprintln!("Error blocking signals: {e}");
579121729a3SRob Bradford }
580121729a3SRob Bradford }
581121729a3SRob Bradford
582121729a3SRob Bradford for sig in &vmm::Vmm::HANDLED_SIGNALS {
583e08c7476SBarret Rhoden if let Err(e) = block_signal(*sig) {
5845e527294SRob Bradford eprintln!("Error blocking signals: {e}");
58534f220edSRob Bradford }
5867549149bSAlyssa Ross }
5877549149bSAlyssa Ross
588c22b788bSRob Bradford let hypervisor = hypervisor::new().map_err(Error::CreateHypervisor)?;
5892451c4d8SAkira Moroo
59006eb82d2SRob Bradford #[cfg(feature = "guest_debug")]
5917bc34521SWei Liu let gdb_socket_path = if let Some(gdb_config) = cmd_arguments.get_one::<String>("gdb") {
5922451c4d8SAkira Moroo let mut parser = OptionParser::new();
5932451c4d8SAkira Moroo parser.add("path");
5942451c4d8SAkira Moroo parser.parse(gdb_config).map_err(Error::ParsingGdb)?;
5952451c4d8SAkira Moroo
5962451c4d8SAkira Moroo if parser.is_set("path") {
5972451c4d8SAkira Moroo Some(std::path::PathBuf::from(parser.get("path").unwrap()))
5982451c4d8SAkira Moroo } else {
5992451c4d8SAkira Moroo return Err(Error::BareGdb);
6002451c4d8SAkira Moroo }
6012451c4d8SAkira Moroo } else {
6022451c4d8SAkira Moroo None
6032451c4d8SAkira Moroo };
60406eb82d2SRob Bradford #[cfg(feature = "guest_debug")]
6052451c4d8SAkira Moroo let debug_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateDebugEventFd)?;
60606eb82d2SRob Bradford #[cfg(feature = "guest_debug")]
6072451c4d8SAkira Moroo let vm_debug_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateDebugEventFd)?;
6082451c4d8SAkira Moroo
60921d40d74SAlyssa Ross let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateExitEventFd)?;
6108c76a3e4SPraveen K Paladugu let landlock_enable = cmd_arguments.get_flag("landlock");
61121d40d74SAlyssa Ross
6122ed96cd3SOmer Faruk Bayram #[allow(unused_mut)]
6137bc34521SWei Liu let mut event_monitor = cmd_arguments
6147bc34521SWei Liu .get_one::<String>("event-monitor")
6152ed96cd3SOmer Faruk Bayram .as_ref()
6162ed96cd3SOmer Faruk Bayram .map(|monitor_config| {
61702e1c544SOmer Faruk Bayram let mut parser = OptionParser::new();
61802e1c544SOmer Faruk Bayram parser.add("path").add("fd");
61902e1c544SOmer Faruk Bayram parser
62002e1c544SOmer Faruk Bayram .parse(monitor_config)
62102e1c544SOmer Faruk Bayram .map_err(Error::ParsingEventMonitor)?;
62202e1c544SOmer Faruk Bayram
6232ed96cd3SOmer Faruk Bayram if parser.is_set("fd") {
62402e1c544SOmer Faruk Bayram let fd = parser
62502e1c544SOmer Faruk Bayram .convert("fd")
62602e1c544SOmer Faruk Bayram .map_err(Error::ParsingEventMonitor)?
62702e1c544SOmer Faruk Bayram .unwrap();
62802e1c544SOmer Faruk Bayram // SAFETY: fd is valid
6292ed96cd3SOmer Faruk Bayram Ok(Some(unsafe { File::from_raw_fd(fd) }))
63002e1c544SOmer Faruk Bayram } else if parser.is_set("path") {
6312ed96cd3SOmer Faruk Bayram Ok(Some(
63202e1c544SOmer Faruk Bayram std::fs::OpenOptions::new()
63302e1c544SOmer Faruk Bayram .write(true)
63402e1c544SOmer Faruk Bayram .create(true)
635c1f4a7b2SBo Chen .truncate(true)
63602e1c544SOmer Faruk Bayram .open(parser.get("path").unwrap())
6372ed96cd3SOmer Faruk Bayram .map_err(Error::EventMonitorIo)?,
6382ed96cd3SOmer Faruk Bayram ))
63902e1c544SOmer Faruk Bayram } else {
6402ed96cd3SOmer Faruk Bayram Err(Error::BareEventMonitor)
6412ed96cd3SOmer Faruk Bayram }
6422ed96cd3SOmer Faruk Bayram })
6432ed96cd3SOmer Faruk Bayram .transpose()?
6442ed96cd3SOmer Faruk Bayram .map(|event_monitor_file| {
6452ed96cd3SOmer Faruk Bayram event_monitor::set_monitor(event_monitor_file).map_err(Error::EventMonitorIo)
6462ed96cd3SOmer Faruk Bayram })
6472ed96cd3SOmer Faruk Bayram .transpose()?;
6482ed96cd3SOmer Faruk Bayram
6492ed96cd3SOmer Faruk Bayram #[cfg(feature = "dbus_api")]
6507bc34521SWei Liu let dbus_options = match (
6517bc34521SWei Liu cmd_arguments.get_one::<String>("dbus-service-name"),
6527bc34521SWei Liu cmd_arguments.get_one::<String>("dbus-object-path"),
6537bc34521SWei Liu ) {
6547bc34521SWei Liu (Some(name), Some(path)) => {
6552ed96cd3SOmer Faruk Bayram // monitor is either set (file based) or not.
6562ed96cd3SOmer Faruk Bayram // if it's not set, create one without file support.
6572ed96cd3SOmer Faruk Bayram let mut monitor = match event_monitor.take() {
6582ed96cd3SOmer Faruk Bayram Some(monitor) => monitor,
6592ed96cd3SOmer Faruk Bayram None => event_monitor::set_monitor(None).map_err(Error::EventMonitorIo)?,
6602ed96cd3SOmer Faruk Bayram };
6612ed96cd3SOmer Faruk Bayram let options = DBusApiOptions {
6627bc34521SWei Liu service_name: name.to_string(),
6637bc34521SWei Liu object_path: path.to_string(),
6647bc34521SWei Liu system_bus: cmd_arguments.get_flag("dbus-system-bus"),
6652ed96cd3SOmer Faruk Bayram event_monitor_rx: monitor.subscribe(),
66602e1c544SOmer Faruk Bayram };
66702e1c544SOmer Faruk Bayram
6682ed96cd3SOmer Faruk Bayram event_monitor = Some(monitor);
6692ed96cd3SOmer Faruk Bayram Ok(Some(options))
6702ed96cd3SOmer Faruk Bayram }
6712ed96cd3SOmer Faruk Bayram (Some(_), None) => Err(Error::MissingDBusObjectPath),
6722ed96cd3SOmer Faruk Bayram (None, Some(_)) => Err(Error::MissingDBusServiceName),
6732ed96cd3SOmer Faruk Bayram (None, None) => Ok(None),
6742ed96cd3SOmer Faruk Bayram }?;
6752ed96cd3SOmer Faruk Bayram
6762ed96cd3SOmer Faruk Bayram if let Some(monitor) = event_monitor {
677a0c8bf4fSOmer Faruk Bayram vmm::start_event_monitor_thread(
678a0c8bf4fSOmer Faruk Bayram monitor,
679a0c8bf4fSOmer Faruk Bayram &seccomp_action,
6808c76a3e4SPraveen K Paladugu landlock_enable,
681a0c8bf4fSOmer Faruk Bayram hypervisor.hypervisor_type(),
682a0c8bf4fSOmer Faruk Bayram exit_evt.try_clone().unwrap(),
683a0c8bf4fSOmer Faruk Bayram )
68402e1c544SOmer Faruk Bayram .map_err(Error::EventMonitorThread)?;
68502e1c544SOmer Faruk Bayram }
68602e1c544SOmer Faruk Bayram
68702e1c544SOmer Faruk Bayram event!("vmm", "starting");
68802e1c544SOmer Faruk Bayram
689f00df25dSOmer Faruk Bayram let vmm_thread_handle = vmm::start_vmm_thread(
690346ee09eSOmer Faruk Bayram vmm::VmmVersionInfo::new(env!("BUILD_VERSION"), env!("CARGO_PKG_VERSION")),
691767b4f0eSWilliam Douglas &api_socket_path,
692767b4f0eSWilliam Douglas api_socket_fd,
6937a458d85SOmer Faruk Bayram #[cfg(feature = "dbus_api")]
6947a458d85SOmer Faruk Bayram dbus_options,
695aa317487SSamuel Ortiz api_evt.try_clone().unwrap(),
696c016a0d4SOmer Faruk Bayram api_request_sender_clone,
697aa317487SSamuel Ortiz api_request_receiver,
69806eb82d2SRob Bradford #[cfg(feature = "guest_debug")]
6992451c4d8SAkira Moroo gdb_socket_path,
70006eb82d2SRob Bradford #[cfg(feature = "guest_debug")]
7012451c4d8SAkira Moroo debug_evt.try_clone().unwrap(),
70206eb82d2SRob Bradford #[cfg(feature = "guest_debug")]
7032451c4d8SAkira Moroo vm_debug_evt.try_clone().unwrap(),
70421d40d74SAlyssa Ross exit_evt.try_clone().unwrap(),
705b41884a4SBo Chen &seccomp_action,
706085d165fSWei Liu hypervisor,
707130c9883SPraveen K Paladugu landlock_enable,
708c22b788bSRob Bradford )
70919c5e91bSRob Bradford .map_err(Error::StartVmmThread)?;
71081880743SSamuel Ortiz
71121d40d74SAlyssa Ross let r: Result<(), Error> = (|| {
71256dbb8f0SMuminul Islam #[cfg(feature = "igvm")]
71356dbb8f0SMuminul Islam let payload_present = cmd_arguments.contains_id("kernel")
71456dbb8f0SMuminul Islam || cmd_arguments.contains_id("firmware")
71556dbb8f0SMuminul Islam || cmd_arguments.contains_id("igvm");
71656dbb8f0SMuminul Islam #[cfg(not(feature = "igvm"))]
7177bc34521SWei Liu let payload_present =
7187bc34521SWei Liu cmd_arguments.contains_id("kernel") || cmd_arguments.contains_id("firmware");
7198ec5a248SRob Bradford
7208ec5a248SRob Bradford if payload_present {
72133c15ca2SSongqian Li let vm_params = VmParams::from_arg_matches(&cmd_arguments);
72233c15ca2SSongqian Li let vm_config = VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
72311dd609fSRob Bradford
72446cde1a3SSamuel Ortiz // Create and boot the VM based off the VM config we just built.
72581880743SSamuel Ortiz let sender = api_request_sender.clone();
7264ca18c08SAlyssa Ross vmm::api::VmCreate
7274ca18c08SAlyssa Ross .send(
72881880743SSamuel Ortiz api_evt.try_clone().unwrap(),
72981880743SSamuel Ortiz api_request_sender,
730cc9899e0SSongqian Li Box::new(vm_config),
73181880743SSamuel Ortiz )
732c22b788bSRob Bradford .map_err(Error::VmCreate)?;
7334ca18c08SAlyssa Ross vmm::api::VmBoot
7344ca18c08SAlyssa Ross .send(api_evt.try_clone().unwrap(), sender, ())
7354ca18c08SAlyssa Ross .map_err(Error::VmBoot)?;
7367bc34521SWei Liu } else if let Some(restore_params) = cmd_arguments.get_one::<String>("restore") {
7374ca18c08SAlyssa Ross vmm::api::VmRestore
7384ca18c08SAlyssa Ross .send(
739fe2d8846SSamuel Ortiz api_evt.try_clone().unwrap(),
740fe2d8846SSamuel Ortiz api_request_sender,
74133c15ca2SSongqian Li RestoreConfig::parse(restore_params).map_err(Error::ParsingRestore)?,
742fe2d8846SSamuel Ortiz )
743c22b788bSRob Bradford .map_err(Error::VmRestore)?;
744b14fd37dSSamuel Ortiz }
74581880743SSamuel Ortiz
74621d40d74SAlyssa Ross Ok(())
74721d40d74SAlyssa Ross })();
74821d40d74SAlyssa Ross
74921d40d74SAlyssa Ross if r.is_err() {
75021d40d74SAlyssa Ross if let Err(e) = exit_evt.write(1) {
75121d40d74SAlyssa Ross warn!("writing to exit EventFd: {e}");
75221d40d74SAlyssa Ross }
75321d40d74SAlyssa Ross }
75421d40d74SAlyssa Ross
75511c17ca3SPraveen K Paladugu if landlock_enable {
75611c17ca3SPraveen K Paladugu Landlock::new()
75711c17ca3SPraveen K Paladugu .map_err(Error::CreateLandlock)?
75811c17ca3SPraveen K Paladugu .restrict_self()
75911c17ca3SPraveen K Paladugu .map_err(Error::ApplyLandlock)?;
76011c17ca3SPraveen K Paladugu }
76111c17ca3SPraveen K Paladugu
762f00df25dSOmer Faruk Bayram vmm_thread_handle
763f00df25dSOmer Faruk Bayram .thread_handle
764c22b788bSRob Bradford .join()
765c22b788bSRob Bradford .map_err(Error::ThreadJoin)?
766767b4f0eSWilliam Douglas .map_err(Error::VmmThread)?;
767767b4f0eSWilliam Douglas
76810914943SAlexandru Matei if let Some(api_handle) = vmm_thread_handle.http_api_handle {
76910914943SAlexandru Matei http_api_graceful_shutdown(api_handle).map_err(Error::HttpApiShutdown)?
77010914943SAlexandru Matei }
77110914943SAlexandru Matei
772f00df25dSOmer Faruk Bayram #[cfg(feature = "dbus_api")]
7737a458d85SOmer Faruk Bayram if let Some(chs) = vmm_thread_handle.dbus_shutdown_chs {
7747a458d85SOmer Faruk Bayram dbus_api_graceful_shutdown(chs);
7757a458d85SOmer Faruk Bayram }
776f00df25dSOmer Faruk Bayram
77719761577SRafael Mendonca r.map(|_| api_socket_path)
77873337c8bSSamuel Ortiz }
779ddce3df8SRob Bradford
780f13d8f14SAlexandru Matei // This is a best-effort solution to the latency induced by the RCU
781f13d8f14SAlexandru Matei // synchronization that happens in the kernel whenever the file descriptor table
782f13d8f14SAlexandru Matei // fills up.
783f13d8f14SAlexandru Matei // The table has initially 64 entries on amd64 and every time it fills up, a new
784f13d8f14SAlexandru Matei // table is created, double the size of the current one, and the entries are
785f13d8f14SAlexandru Matei // copied to the new table. The filesystem code that does this uses
78642e9632cSJosh Soref // synchronize_rcu() to ensure all preexisting RCU read-side critical sections
787f13d8f14SAlexandru Matei // have completed:
788f13d8f14SAlexandru Matei //
789f13d8f14SAlexandru Matei // https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/fs/file.c?h=v6.9.1#n162
790f13d8f14SAlexandru Matei //
791f13d8f14SAlexandru Matei // Rust programs that create lots of file handles or use
792f13d8f14SAlexandru Matei // {File,EventFd}::try_clone() to share them are impacted by this issue. This
793f13d8f14SAlexandru Matei // behavior is quite noticeable in the snapshot restore scenario, the latency is
794f13d8f14SAlexandru Matei // a big chunk of the total time required to start cloud-hypervisor and restore
795f13d8f14SAlexandru Matei // the snapshot.
796f13d8f14SAlexandru Matei //
797f13d8f14SAlexandru Matei // The kernel has an optimization in code, where it doesn't call
798f13d8f14SAlexandru Matei // synchronize_rcu() if there is only one thread in the process. We can take
799f13d8f14SAlexandru Matei // advantage of this optimization by expanding the descriptor table at
800f13d8f14SAlexandru Matei // application start, when it has only one thread.
801f13d8f14SAlexandru Matei //
802f13d8f14SAlexandru Matei // The code tries to resize the table to an adequate size for most use cases,
803f13d8f14SAlexandru Matei // 4096, this way we avoid any expansion that might take place later.
expand_fdtable() -> Result<(), FdTableError>804f13d8f14SAlexandru Matei fn expand_fdtable() -> Result<(), FdTableError> {
805f13d8f14SAlexandru Matei let mut limits = libc::rlimit {
806f13d8f14SAlexandru Matei rlim_cur: 0,
807f13d8f14SAlexandru Matei rlim_max: 0,
808f13d8f14SAlexandru Matei };
809f13d8f14SAlexandru Matei
810f13d8f14SAlexandru Matei // SAFETY: FFI call with valid arguments
811f13d8f14SAlexandru Matei if unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &mut limits) } < 0 {
812f13d8f14SAlexandru Matei return Err(FdTableError::GetRLimit(io::Error::last_os_error()));
813f13d8f14SAlexandru Matei }
814f13d8f14SAlexandru Matei
815f13d8f14SAlexandru Matei let table_size = if limits.rlim_cur == libc::RLIM_INFINITY {
816f13d8f14SAlexandru Matei 4096
817f13d8f14SAlexandru Matei } else {
818f13d8f14SAlexandru Matei std::cmp::min(limits.rlim_cur, 4096) as libc::c_int
819f13d8f14SAlexandru Matei };
820f13d8f14SAlexandru Matei
821f13d8f14SAlexandru Matei // The first 3 handles are stdin, stdout, stderr. We don't want to touch
822091ce854SAlexandru Matei // any of them.
823f13d8f14SAlexandru Matei if table_size <= 3 {
824f13d8f14SAlexandru Matei return Ok(());
825f13d8f14SAlexandru Matei }
826f13d8f14SAlexandru Matei
827f13d8f14SAlexandru Matei let dummy_evt = EventFd::new(0).map_err(FdTableError::CreateEventFd)?;
828f13d8f14SAlexandru Matei
829f13d8f14SAlexandru Matei // Test if the file descriptor is empty
830f13d8f14SAlexandru Matei // SAFETY: FFI call with valid arguments
831f13d8f14SAlexandru Matei let flags: i32 = unsafe { libc::fcntl(table_size - 1, libc::F_GETFD) };
832f13d8f14SAlexandru Matei if flags >= 0 {
833f13d8f14SAlexandru Matei // Nothing to do, the table is already big enough
834f13d8f14SAlexandru Matei return Ok(());
835f13d8f14SAlexandru Matei }
836f13d8f14SAlexandru Matei
837f13d8f14SAlexandru Matei let err = io::Error::last_os_error();
838f13d8f14SAlexandru Matei if err.raw_os_error() != Some(libc::EBADF) {
839f13d8f14SAlexandru Matei return Err(FdTableError::GetFd(err));
840f13d8f14SAlexandru Matei }
841f13d8f14SAlexandru Matei // SAFETY: FFI call with valid arguments
842f13d8f14SAlexandru Matei if unsafe { libc::dup2(dummy_evt.as_raw_fd(), table_size - 1) } < 0 {
843f13d8f14SAlexandru Matei return Err(FdTableError::Dup2(io::Error::last_os_error()));
844f13d8f14SAlexandru Matei }
845f13d8f14SAlexandru Matei // SAFETY: FFI call, trivially
846f13d8f14SAlexandru Matei unsafe { libc::close(table_size - 1) };
847f13d8f14SAlexandru Matei
848f13d8f14SAlexandru Matei Ok(())
849f13d8f14SAlexandru Matei }
850f13d8f14SAlexandru Matei
main()851b8518877SRob Bradford fn main() {
8521b9ce69aSJinank Jain #[cfg(all(feature = "tdx", feature = "sev_snp"))]
8531b9ce69aSJinank Jain compile_error!("Feature 'tdx' and 'sev_snp' are mutually exclusive.");
85442477207SJinank Jain #[cfg(all(feature = "sev_snp", not(target_arch = "x86_64")))]
85542477207SJinank Jain compile_error!("Feature 'sev_snp' needs target 'x86_64'");
85642477207SJinank Jain
8573a81f932SRob Bradford #[cfg(feature = "dhat-heap")]
8583a81f932SRob Bradford let _profiler = dhat::Profiler::new_heap();
8593a81f932SRob Bradford
8603497eeffSRob Bradford // Ensure all created files (.e.g sockets) are only accessible by this user
861d5f294b3SWei Liu // SAFETY: trivially safe
8623497eeffSRob Bradford let _ = unsafe { libc::umask(0o077) };
8633497eeffSRob Bradford
8647bc34521SWei Liu let (default_vcpus, default_memory, default_rng) = prepare_default_values();
8657bc34521SWei Liu let cmd_arguments = create_app(default_vcpus, default_memory, default_rng).get_matches();
866111225a2SWei Liu
8677bc34521SWei Liu if cmd_arguments.get_flag("version") {
86859012cccSOmer Faruk Bayram println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
8691e01b5eaSBo Chen
8707bc34521SWei Liu if cmd_arguments.get_count("v") != 0 {
8711e01b5eaSBo Chen println!("Enabled features: {:?}", vmm::feature_list());
8721e01b5eaSBo Chen }
8731e01b5eaSBo Chen
874111225a2SWei Liu return;
875111225a2SWei Liu }
876111225a2SWei Liu
877f13d8f14SAlexandru Matei if let Err(e) = expand_fdtable() {
878f13d8f14SAlexandru Matei warn!("Error expanding FD table: {e}");
879f13d8f14SAlexandru Matei }
880f13d8f14SAlexandru Matei
8817bc34521SWei Liu let exit_code = match start_vmm(cmd_arguments) {
882767b4f0eSWilliam Douglas Ok(path) => {
883767b4f0eSWilliam Douglas path.map(|s| std::fs::remove_file(s).ok());
884767b4f0eSWilliam Douglas 0
885767b4f0eSWilliam Douglas }
886060c9de0SPhilipp Schuster Err(top_error) => {
887*190a11f2SPhilipp Schuster cloud_hypervisor::cli_print_error_chain(&top_error, "Cloud Hypervisor", |_, _, _| None);
8889b0996a7SRob Bradford 1
889767b4f0eSWilliam Douglas }
8909b0996a7SRob Bradford };
8919b0996a7SRob Bradford
8923a81f932SRob Bradford #[cfg(feature = "dhat-heap")]
8933a81f932SRob Bradford drop(_profiler);
8943a81f932SRob Bradford
8959b0996a7SRob Bradford std::process::exit(exit_code);
896be1b6bc1SRob Bradford }
897b8518877SRob Bradford
898ddce3df8SRob Bradford #[cfg(test)]
89943d2e09eSSebastien Boeuf mod unit_tests {
90043d2e09eSSebastien Boeuf use std::path::PathBuf;
90188a9f799SRob Bradford
90233c15ca2SSongqian Li use vmm::config::VmParams;
903e50a6411SPhilipp Schuster #[cfg(target_arch = "x86_64")]
904e50a6411SPhilipp Schuster use vmm::vm_config::DebugConsoleConfig;
90533c15ca2SSongqian Li use vmm::vm_config::{
90633c15ca2SSongqian Li ConsoleConfig, ConsoleOutputMode, CpuFeatures, CpusConfig, HotplugMethod, MemoryConfig,
90733c15ca2SSongqian Li PayloadConfig, RngConfig, VmConfig,
90833c15ca2SSongqian Li };
90943d2e09eSSebastien Boeuf
91053e9c94eSPhilipp Schuster use crate::test_util::assert_args_sorted;
911fa58b725SPhilipp Schuster use crate::{create_app, get_cli_options_sorted, prepare_default_values};
91288a9f799SRob Bradford
get_vm_config_from_vec(args: &[&str]) -> VmConfig913111225a2SWei Liu fn get_vm_config_from_vec(args: &[&str]) -> VmConfig {
9147bc34521SWei Liu let (default_vcpus, default_memory, default_rng) = prepare_default_values();
9157bc34521SWei Liu let cmd_arguments =
9167bc34521SWei Liu create_app(default_vcpus, default_memory, default_rng).get_matches_from(args);
9177bc34521SWei Liu let vm_params = VmParams::from_arg_matches(&cmd_arguments);
91843d2e09eSSebastien Boeuf
91943d2e09eSSebastien Boeuf VmConfig::parse(vm_params).unwrap()
92043d2e09eSSebastien Boeuf }
92143d2e09eSSebastien Boeuf
compare_vm_config_cli_vs_json( cli: &[&str], openapi: &str, equal: bool, ) -> (VmConfig, VmConfig)92243d2e09eSSebastien Boeuf fn compare_vm_config_cli_vs_json(
92343d2e09eSSebastien Boeuf cli: &[&str],
92443d2e09eSSebastien Boeuf openapi: &str,
92543d2e09eSSebastien Boeuf equal: bool,
92643d2e09eSSebastien Boeuf ) -> (VmConfig, VmConfig) {
92743d2e09eSSebastien Boeuf let cli_vm_config = get_vm_config_from_vec(cli);
92843d2e09eSSebastien Boeuf let openapi_vm_config: VmConfig = serde_json::from_str(openapi).unwrap();
92943d2e09eSSebastien Boeuf
93043d2e09eSSebastien Boeuf if equal {
931e4763b47SRob Bradford assert_eq!(cli_vm_config, openapi_vm_config);
93243d2e09eSSebastien Boeuf } else {
933e4763b47SRob Bradford assert_ne!(cli_vm_config, openapi_vm_config);
93443d2e09eSSebastien Boeuf }
93543d2e09eSSebastien Boeuf
93643d2e09eSSebastien Boeuf (cli_vm_config, openapi_vm_config)
93743d2e09eSSebastien Boeuf }
93843d2e09eSSebastien Boeuf
93943d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_default()94043d2e09eSSebastien Boeuf fn test_valid_vm_config_default() {
941aaf382eeSRob Bradford let cli = vec!["cloud-hypervisor", "--kernel", "/path/to/kernel"];
942cef51a9dSRob Bradford let openapi = r#"{ "payload": {"kernel": "/path/to/kernel"} }"#;
94343d2e09eSSebastien Boeuf
94443d2e09eSSebastien Boeuf // First we check we get identical VmConfig structures.
94543d2e09eSSebastien Boeuf let (result_vm_config, _) = compare_vm_config_cli_vs_json(&cli, openapi, true);
94643d2e09eSSebastien Boeuf
94743d2e09eSSebastien Boeuf // As a second step, we validate all the default values.
94843d2e09eSSebastien Boeuf let expected_vm_config = VmConfig {
94943d2e09eSSebastien Boeuf cpus: CpusConfig {
95043d2e09eSSebastien Boeuf boot_vcpus: 1,
95143d2e09eSSebastien Boeuf max_vcpus: 1,
9524a0439a9SRob Bradford topology: None,
9535495ab74SRob Bradford kvm_hyperv: false,
95483066cf5SRob Bradford max_phys_bits: 46,
955932c8c97SSebastien Boeuf affinity: None,
9566b0df31eSWilliam Douglas features: CpuFeatures::default(),
95743d2e09eSSebastien Boeuf },
95843d2e09eSSebastien Boeuf memory: MemoryConfig {
95943d2e09eSSebastien Boeuf size: 536_870_912,
96043d2e09eSSebastien Boeuf mergeable: false,
961e6b934a5SHui Zhu hotplug_method: HotplugMethod::Acpi,
962f5137e84SRob Bradford hotplug_size: None,
9634e1b78e1SSebastien Boeuf hotplugged_size: None,
9643f42f86dSBo Chen shared: false,
9653f42f86dSBo Chen hugepages: false,
96629607f38SRob Bradford hugepage_size: None,
96708021087SYu Li prefault: false,
96808021087SYu Li zones: None,
969f603afc4SRob Bradford thp: true,
97043d2e09eSSebastien Boeuf },
971cef51a9dSRob Bradford payload: Some(PayloadConfig {
972cef51a9dSRob Bradford kernel: Some(PathBuf::from("/path/to/kernel")),
97376741961SAlyssa Ross firmware: None,
97476741961SAlyssa Ross cmdline: None,
97576741961SAlyssa Ross initramfs: None,
97676741961SAlyssa Ross #[cfg(feature = "igvm")]
97776741961SAlyssa Ross igvm: None,
978aa6c486aSMuminul Islam #[cfg(feature = "sev_snp")]
979aa6c486aSMuminul Islam host_data: None,
980cef51a9dSRob Bradford }),
981c297d8d7SThomas Barrett rate_limit_groups: None,
98243d2e09eSSebastien Boeuf disks: None,
98343d2e09eSSebastien Boeuf net: None,
98443d2e09eSSebastien Boeuf rng: RngConfig {
98543d2e09eSSebastien Boeuf src: PathBuf::from("/dev/urandom"),
98643d2e09eSSebastien Boeuf iommu: false,
98743d2e09eSSebastien Boeuf },
9881d479e5eSSebastien Boeuf balloon: None,
98943d2e09eSSebastien Boeuf fs: None,
99043d2e09eSSebastien Boeuf pmem: None,
99143d2e09eSSebastien Boeuf serial: ConsoleConfig {
99243d2e09eSSebastien Boeuf file: None,
99343d2e09eSSebastien Boeuf mode: ConsoleOutputMode::Null,
99443d2e09eSSebastien Boeuf iommu: false,
9956d1077fcSPraveen K Paladugu socket: None,
99643d2e09eSSebastien Boeuf },
99743d2e09eSSebastien Boeuf console: ConsoleConfig {
99843d2e09eSSebastien Boeuf file: None,
99943d2e09eSSebastien Boeuf mode: ConsoleOutputMode::Tty,
100043d2e09eSSebastien Boeuf iommu: false,
10016d1077fcSPraveen K Paladugu socket: None,
100243d2e09eSSebastien Boeuf },
1003e50a6411SPhilipp Schuster #[cfg(target_arch = "x86_64")]
1004e50a6411SPhilipp Schuster debug_console: DebugConsoleConfig::default(),
100543d2e09eSSebastien Boeuf devices: None,
10067fbec711SRob Bradford user_devices: None,
100772169686SSebastien Boeuf vdpa: None,
100843d2e09eSSebastien Boeuf vsock: None,
1009d99c0c0dSYi Wang pvpanic: false,
10105f18ac3bSYuanchu Xie #[cfg(feature = "pvmemcontrol")]
10115f18ac3bSYuanchu Xie pvmemcontrol: None,
101243d2e09eSSebastien Boeuf iommu: false,
1013d9244e9fSSebastien Boeuf #[cfg(target_arch = "x86_64")]
1014d9244e9fSSebastien Boeuf sgx_epc: None,
101542f963d6SSebastien Boeuf numa: None,
1016885ee956SRob Bradford watchdog: false,
101706eb82d2SRob Bradford #[cfg(feature = "guest_debug")]
10182451c4d8SAkira Moroo gdb: false,
1019e7e856d8SThomas Barrett pci_segments: None,
1020f8d9c073SRob Bradford platform: None,
10217122e298SPraveen K Paladugu tpm: None,
1022a84b540bSBo Chen preserved_fds: None,
1023d2f0e8aeSPraveen K Paladugu landlock_enable: false,
1024bd180bc3SPraveen K Paladugu landlock_rules: None,
102543d2e09eSSebastien Boeuf };
102643d2e09eSSebastien Boeuf
1027e4763b47SRob Bradford assert_eq!(expected_vm_config, result_vm_config);
102843d2e09eSSebastien Boeuf }
102943d2e09eSSebastien Boeuf
103043d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_cpus()103143d2e09eSSebastien Boeuf fn test_valid_vm_config_cpus() {
1032d0dbc7fbSYu Li [
103343d2e09eSSebastien Boeuf (
1034aaf382eeSRob Bradford vec![
1035aaf382eeSRob Bradford "cloud-hypervisor",
1036aaf382eeSRob Bradford "--kernel",
1037aaf382eeSRob Bradford "/path/to/kernel",
1038aaf382eeSRob Bradford "--cpus",
1039aaf382eeSRob Bradford "boot=1",
1040aaf382eeSRob Bradford ],
104143d2e09eSSebastien Boeuf r#"{
1042cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
104343d2e09eSSebastien Boeuf "cpus": {"boot_vcpus": 1, "max_vcpus": 1}
104443d2e09eSSebastien Boeuf }"#,
104543d2e09eSSebastien Boeuf true,
104643d2e09eSSebastien Boeuf ),
104743d2e09eSSebastien Boeuf (
1048aaf382eeSRob Bradford vec![
1049aaf382eeSRob Bradford "cloud-hypervisor",
1050aaf382eeSRob Bradford "--kernel",
1051aaf382eeSRob Bradford "/path/to/kernel",
1052aaf382eeSRob Bradford "--cpus",
1053aaf382eeSRob Bradford "boot=1,max=3",
1054aaf382eeSRob Bradford ],
105543d2e09eSSebastien Boeuf r#"{
1056cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
105743d2e09eSSebastien Boeuf "cpus": {"boot_vcpus": 1, "max_vcpus": 3}
105843d2e09eSSebastien Boeuf }"#,
105943d2e09eSSebastien Boeuf true,
106043d2e09eSSebastien Boeuf ),
106143d2e09eSSebastien Boeuf (
1062aaf382eeSRob Bradford vec![
1063aaf382eeSRob Bradford "cloud-hypervisor",
1064aaf382eeSRob Bradford "--kernel",
1065aaf382eeSRob Bradford "/path/to/kernel",
1066aaf382eeSRob Bradford "--cpus",
1067aaf382eeSRob Bradford "boot=2,max=4",
1068aaf382eeSRob Bradford ],
106943d2e09eSSebastien Boeuf r#"{
1070cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
107143d2e09eSSebastien Boeuf "cpus": {"boot_vcpus": 1, "max_vcpus": 3}
107243d2e09eSSebastien Boeuf }"#,
107343d2e09eSSebastien Boeuf false,
107443d2e09eSSebastien Boeuf ),
107543d2e09eSSebastien Boeuf ]
107643d2e09eSSebastien Boeuf .iter()
107743d2e09eSSebastien Boeuf .for_each(|(cli, openapi, equal)| {
107843d2e09eSSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
107943d2e09eSSebastien Boeuf });
108043d2e09eSSebastien Boeuf }
108143d2e09eSSebastien Boeuf
108243d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_memory()108343d2e09eSSebastien Boeuf fn test_valid_vm_config_memory() {
108443d2e09eSSebastien Boeuf vec![
108543d2e09eSSebastien Boeuf (
1086aaf382eeSRob Bradford vec!["cloud-hypervisor", "--kernel", "/path/to/kernel", "--memory", "size=1073741824"],
108743d2e09eSSebastien Boeuf r#"{
1088cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
108943d2e09eSSebastien Boeuf "memory": {"size": 1073741824}
109043d2e09eSSebastien Boeuf }"#,
109143d2e09eSSebastien Boeuf true,
109243d2e09eSSebastien Boeuf ),
109343d2e09eSSebastien Boeuf (
1094aaf382eeSRob Bradford vec!["cloud-hypervisor", "--kernel", "/path/to/kernel", "--memory", "size=1G"],
109543d2e09eSSebastien Boeuf r#"{
1096cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
109743d2e09eSSebastien Boeuf "memory": {"size": 1073741824}
109843d2e09eSSebastien Boeuf }"#,
109943d2e09eSSebastien Boeuf true,
110043d2e09eSSebastien Boeuf ),
110143d2e09eSSebastien Boeuf (
1102aaf382eeSRob Bradford vec!["cloud-hypervisor", "--kernel", "/path/to/kernel", "--memory", "size=1G,mergeable=on"],
110343d2e09eSSebastien Boeuf r#"{
1104cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
110543d2e09eSSebastien Boeuf "memory": {"size": 1073741824, "mergeable": true}
110643d2e09eSSebastien Boeuf }"#,
110743d2e09eSSebastien Boeuf true,
110843d2e09eSSebastien Boeuf ),
110943d2e09eSSebastien Boeuf (
1110aaf382eeSRob Bradford vec!["cloud-hypervisor", "--kernel", "/path/to/kernel", "--memory", "size=1G,mergeable=off"],
111143d2e09eSSebastien Boeuf r#"{
1112cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
111343d2e09eSSebastien Boeuf "memory": {"size": 1073741824, "mergeable": false}
111443d2e09eSSebastien Boeuf }"#,
111543d2e09eSSebastien Boeuf true,
111643d2e09eSSebastien Boeuf ),
111743d2e09eSSebastien Boeuf (
1118aaf382eeSRob Bradford vec!["cloud-hypervisor", "--kernel", "/path/to/kernel", "--memory", "size=1G,mergeable=on"],
111943d2e09eSSebastien Boeuf r#"{
1120cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
112143d2e09eSSebastien Boeuf "memory": {"size": 1073741824, "mergeable": false}
112243d2e09eSSebastien Boeuf }"#,
112343d2e09eSSebastien Boeuf false,
112443d2e09eSSebastien Boeuf ),
11254a7a2cffSHui Zhu (
1126aaf382eeSRob Bradford vec!["cloud-hypervisor", "--kernel", "/path/to/kernel", "--memory", "size=1G,hotplug_size=1G"],
11274a7a2cffSHui Zhu r#"{
1128cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
11294a7a2cffSHui Zhu "memory": {"size": 1073741824, "hotplug_method": "Acpi", "hotplug_size": 1073741824}
11304a7a2cffSHui Zhu }"#,
11314a7a2cffSHui Zhu true,
11324a7a2cffSHui Zhu ),
11334a7a2cffSHui Zhu (
1134aaf382eeSRob Bradford vec!["cloud-hypervisor", "--kernel", "/path/to/kernel", "--memory", "size=1G,hotplug_method=virtio-mem,hotplug_size=1G"],
11354a7a2cffSHui Zhu r#"{
1136cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
11374a7a2cffSHui Zhu "memory": {"size": 1073741824, "hotplug_method": "VirtioMem", "hotplug_size": 1073741824}
11384a7a2cffSHui Zhu }"#,
11394a7a2cffSHui Zhu true,
11404a7a2cffSHui Zhu ),
114143d2e09eSSebastien Boeuf ]
114243d2e09eSSebastien Boeuf .iter()
114343d2e09eSSebastien Boeuf .for_each(|(cli, openapi, equal)| {
114443d2e09eSSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
114543d2e09eSSebastien Boeuf });
114643d2e09eSSebastien Boeuf }
114743d2e09eSSebastien Boeuf
114843d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_kernel()114943d2e09eSSebastien Boeuf fn test_valid_vm_config_kernel() {
1150d0dbc7fbSYu Li [(
115143d2e09eSSebastien Boeuf vec!["cloud-hypervisor", "--kernel", "/path/to/kernel"],
115243d2e09eSSebastien Boeuf r#"{
1153cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"}
115443d2e09eSSebastien Boeuf }"#,
115543d2e09eSSebastien Boeuf true,
115643d2e09eSSebastien Boeuf )]
115743d2e09eSSebastien Boeuf .iter()
115843d2e09eSSebastien Boeuf .for_each(|(cli, openapi, equal)| {
115943d2e09eSSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
116043d2e09eSSebastien Boeuf });
116143d2e09eSSebastien Boeuf }
116243d2e09eSSebastien Boeuf
116343d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_cmdline()116443d2e09eSSebastien Boeuf fn test_valid_vm_config_cmdline() {
1165d0dbc7fbSYu Li [(
1166aaf382eeSRob Bradford vec![
1167aaf382eeSRob Bradford "cloud-hypervisor",
1168aaf382eeSRob Bradford "--kernel",
1169aaf382eeSRob Bradford "/path/to/kernel",
1170aaf382eeSRob Bradford "--cmdline",
1171aaf382eeSRob Bradford "arg1=foo arg2=bar",
1172aaf382eeSRob Bradford ],
117343d2e09eSSebastien Boeuf r#"{
1174cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel", "cmdline": "arg1=foo arg2=bar"}
117543d2e09eSSebastien Boeuf }"#,
117643d2e09eSSebastien Boeuf true,
117743d2e09eSSebastien Boeuf )]
117843d2e09eSSebastien Boeuf .iter()
117943d2e09eSSebastien Boeuf .for_each(|(cli, openapi, equal)| {
118043d2e09eSSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
118143d2e09eSSebastien Boeuf });
118243d2e09eSSebastien Boeuf }
118343d2e09eSSebastien Boeuf
118443d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_disks()118543d2e09eSSebastien Boeuf fn test_valid_vm_config_disks() {
1186d0dbc7fbSYu Li [
118743d2e09eSSebastien Boeuf (
118843d2e09eSSebastien Boeuf vec![
118943d2e09eSSebastien Boeuf "cloud-hypervisor",
1190aaf382eeSRob Bradford "--kernel",
1191aaf382eeSRob Bradford "/path/to/kernel",
119243d2e09eSSebastien Boeuf "--disk",
119343d2e09eSSebastien Boeuf "path=/path/to/disk/1",
119443d2e09eSSebastien Boeuf "path=/path/to/disk/2",
119543d2e09eSSebastien Boeuf ],
119643d2e09eSSebastien Boeuf r#"{
1197cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
119843d2e09eSSebastien Boeuf "disks": [
119943d2e09eSSebastien Boeuf {"path": "/path/to/disk/1"},
120043d2e09eSSebastien Boeuf {"path": "/path/to/disk/2"}
120143d2e09eSSebastien Boeuf ]
120243d2e09eSSebastien Boeuf }"#,
120343d2e09eSSebastien Boeuf true,
120443d2e09eSSebastien Boeuf ),
120543d2e09eSSebastien Boeuf (
120643d2e09eSSebastien Boeuf vec![
120743d2e09eSSebastien Boeuf "cloud-hypervisor",
1208aaf382eeSRob Bradford "--kernel",
1209aaf382eeSRob Bradford "/path/to/kernel",
121043d2e09eSSebastien Boeuf "--disk",
121143d2e09eSSebastien Boeuf "path=/path/to/disk/1",
121243d2e09eSSebastien Boeuf "path=/path/to/disk/2",
121343d2e09eSSebastien Boeuf ],
121443d2e09eSSebastien Boeuf r#"{
1215cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
121643d2e09eSSebastien Boeuf "disks": [
121743d2e09eSSebastien Boeuf {"path": "/path/to/disk/1"}
121843d2e09eSSebastien Boeuf ]
121943d2e09eSSebastien Boeuf }"#,
122043d2e09eSSebastien Boeuf false,
122143d2e09eSSebastien Boeuf ),
1222b4d04bdfSRob Bradford (
1223b4d04bdfSRob Bradford vec![
1224b4d04bdfSRob Bradford "cloud-hypervisor",
1225aaf382eeSRob Bradford "--kernel",
1226aaf382eeSRob Bradford "/path/to/kernel",
12277481e4d9SRob Bradford "--memory",
12287481e4d9SRob Bradford "shared=true",
1229b4d04bdfSRob Bradford "--disk",
1230a8cdf2f0SBo Chen "vhost_user=true,socket=/tmp/sock1",
1231b4d04bdfSRob Bradford ],
1232b4d04bdfSRob Bradford r#"{
1233cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
12347481e4d9SRob Bradford "memory" : { "shared": true, "size": 536870912 },
1235b4d04bdfSRob Bradford "disks": [
12360005d11eSRob Bradford {"vhost_user":true, "vhost_socket":"/tmp/sock1"}
1237b4d04bdfSRob Bradford ]
1238b4d04bdfSRob Bradford }"#,
1239b4d04bdfSRob Bradford true,
1240b4d04bdfSRob Bradford ),
1241b4d04bdfSRob Bradford (
1242b4d04bdfSRob Bradford vec![
1243b4d04bdfSRob Bradford "cloud-hypervisor",
1244aaf382eeSRob Bradford "--kernel",
1245aaf382eeSRob Bradford "/path/to/kernel",
12467481e4d9SRob Bradford "--memory",
12477481e4d9SRob Bradford "shared=true",
1248b4d04bdfSRob Bradford "--disk",
1249a8cdf2f0SBo Chen "vhost_user=true,socket=/tmp/sock1",
1250b4d04bdfSRob Bradford ],
1251b4d04bdfSRob Bradford r#"{
1252cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
12537481e4d9SRob Bradford "memory" : { "shared": true, "size": 536870912 },
1254b4d04bdfSRob Bradford "disks": [
12550005d11eSRob Bradford {"vhost_user":true, "vhost_socket":"/tmp/sock1"}
1256b4d04bdfSRob Bradford ]
1257b4d04bdfSRob Bradford }"#,
1258b4d04bdfSRob Bradford true,
1259b4d04bdfSRob Bradford ),
1260c297d8d7SThomas Barrett (
1261c297d8d7SThomas Barrett vec![
1262c297d8d7SThomas Barrett "cloud-hypervisor",
1263c297d8d7SThomas Barrett "--kernel",
1264c297d8d7SThomas Barrett "/path/to/kernel",
1265c297d8d7SThomas Barrett "--disk",
1266c297d8d7SThomas Barrett "path=/path/to/disk/1,rate_limit_group=group0",
1267c297d8d7SThomas Barrett "path=/path/to/disk/2,rate_limit_group=group0",
1268c297d8d7SThomas Barrett "--rate-limit-group",
1269c297d8d7SThomas Barrett "id=group0,bw_size=1000,bw_refill_time=100",
1270c297d8d7SThomas Barrett ],
1271c297d8d7SThomas Barrett r#"{
1272c297d8d7SThomas Barrett "payload": {"kernel": "/path/to/kernel"},
1273c297d8d7SThomas Barrett "disks": [
1274c297d8d7SThomas Barrett {"path": "/path/to/disk/1", "rate_limit_group": "group0"},
1275c297d8d7SThomas Barrett {"path": "/path/to/disk/2", "rate_limit_group": "group0"}
1276c297d8d7SThomas Barrett ],
1277c297d8d7SThomas Barrett "rate_limit_groups": [
1278c297d8d7SThomas Barrett {"id": "group0", "rate_limiter_config": {"bandwidth": {"size": 1000, "one_time_burst": 0, "refill_time": 100}}}
1279c297d8d7SThomas Barrett ]
1280c297d8d7SThomas Barrett }"#,
1281c297d8d7SThomas Barrett true,
1282c297d8d7SThomas Barrett ),
128343d2e09eSSebastien Boeuf ]
128443d2e09eSSebastien Boeuf .iter()
128543d2e09eSSebastien Boeuf .for_each(|(cli, openapi, equal)| {
128643d2e09eSSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
128743d2e09eSSebastien Boeuf });
128843d2e09eSSebastien Boeuf }
128943d2e09eSSebastien Boeuf
129043d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_net()129143d2e09eSSebastien Boeuf fn test_valid_vm_config_net() {
129243d2e09eSSebastien Boeuf vec![
129343d2e09eSSebastien Boeuf // This test is expected to fail because the default MAC address is
129443d2e09eSSebastien Boeuf // randomly generated. There's no way we can have twice the same
129543d2e09eSSebastien Boeuf // default value.
129643d2e09eSSebastien Boeuf (
1297aaf382eeSRob Bradford vec!["cloud-hypervisor", "--kernel", "/path/to/kernel", "--net", "mac="],
129843d2e09eSSebastien Boeuf r#"{
1299cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
130043d2e09eSSebastien Boeuf "net": []
130143d2e09eSSebastien Boeuf }"#,
130243d2e09eSSebastien Boeuf false,
130343d2e09eSSebastien Boeuf ),
130443d2e09eSSebastien Boeuf (
13051b8b5ac1SRob Bradford vec!["cloud-hypervisor", "--kernel", "/path/to/kernel", "--net", "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd"],
130643d2e09eSSebastien Boeuf r#"{
1307cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
130843d2e09eSSebastien Boeuf "net": [
13091b8b5ac1SRob Bradford {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd"}
131043d2e09eSSebastien Boeuf ]
131143d2e09eSSebastien Boeuf }"#,
131243d2e09eSSebastien Boeuf true,
131343d2e09eSSebastien Boeuf ),
131443d2e09eSSebastien Boeuf (
131543d2e09eSSebastien Boeuf vec![
1316aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
131743d2e09eSSebastien Boeuf "--net",
13181b8b5ac1SRob Bradford "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0",
131943d2e09eSSebastien Boeuf ],
132043d2e09eSSebastien Boeuf r#"{
1321cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
132243d2e09eSSebastien Boeuf "net": [
13231b8b5ac1SRob Bradford {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0"}
132443d2e09eSSebastien Boeuf ]
132543d2e09eSSebastien Boeuf }"#,
132643d2e09eSSebastien Boeuf true,
132743d2e09eSSebastien Boeuf ),
132843d2e09eSSebastien Boeuf (
132943d2e09eSSebastien Boeuf vec![
1330aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
133143d2e09eSSebastien Boeuf "--net",
13321b8b5ac1SRob Bradford "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4",
133343d2e09eSSebastien Boeuf ],
133443d2e09eSSebastien Boeuf r#"{
1335cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
133643d2e09eSSebastien Boeuf "net": [
13371b8b5ac1SRob Bradford {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4"}
133843d2e09eSSebastien Boeuf ]
133943d2e09eSSebastien Boeuf }"#,
134043d2e09eSSebastien Boeuf true,
134143d2e09eSSebastien Boeuf ),
134243d2e09eSSebastien Boeuf (
134343d2e09eSSebastien Boeuf vec![
1344aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
134543d2e09eSSebastien Boeuf "--net",
13461b8b5ac1SRob Bradford "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4,mask=5.6.7.8",
134743d2e09eSSebastien Boeuf ],
134843d2e09eSSebastien Boeuf r#"{
1349cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
135043d2e09eSSebastien Boeuf "net": [
13511b8b5ac1SRob Bradford {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8"}
135243d2e09eSSebastien Boeuf ]
135343d2e09eSSebastien Boeuf }"#,
135443d2e09eSSebastien Boeuf true,
135543d2e09eSSebastien Boeuf ),
135643d2e09eSSebastien Boeuf (
135743d2e09eSSebastien Boeuf vec![
1358aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
13597e0ccce2SRob Bradford "--cpus", "boot=2",
136043d2e09eSSebastien Boeuf "--net",
13611b8b5ac1SRob Bradford "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,num_queues=4",
136243d2e09eSSebastien Boeuf ],
136343d2e09eSSebastien Boeuf r#"{
1364cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
13657e0ccce2SRob Bradford "cpus": {"boot_vcpus": 2, "max_vcpus": 2},
136643d2e09eSSebastien Boeuf "net": [
13671b8b5ac1SRob Bradford {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "num_queues": 4}
13684885dc0eSCathy Zhang ]
13694885dc0eSCathy Zhang }"#,
13704885dc0eSCathy Zhang true,
13714885dc0eSCathy Zhang ),
13724885dc0eSCathy Zhang (
13734885dc0eSCathy Zhang vec![
1374aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
13757e0ccce2SRob Bradford "--cpus", "boot=2",
13764885dc0eSCathy Zhang "--net",
13771b8b5ac1SRob Bradford "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,num_queues=4,queue_size=128",
13784885dc0eSCathy Zhang ],
13794885dc0eSCathy Zhang r#"{
1380cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
13817e0ccce2SRob Bradford "cpus": {"boot_vcpus": 2, "max_vcpus": 2},
13824885dc0eSCathy Zhang "net": [
13831b8b5ac1SRob Bradford {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "num_queues": 4, "queue_size": 128}
13844885dc0eSCathy Zhang ]
13854885dc0eSCathy Zhang }"#,
13864885dc0eSCathy Zhang true,
13874885dc0eSCathy Zhang ),
13884885dc0eSCathy Zhang (
13894885dc0eSCathy Zhang vec![
1390aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
13914885dc0eSCathy Zhang "--net",
13921b8b5ac1SRob Bradford "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,num_queues=2,queue_size=256",
13934885dc0eSCathy Zhang ],
13944885dc0eSCathy Zhang r#"{
1395cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
13964885dc0eSCathy Zhang "net": [
13971b8b5ac1SRob Bradford {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8"}
13984885dc0eSCathy Zhang ]
13994885dc0eSCathy Zhang }"#,
14004885dc0eSCathy Zhang true,
14014885dc0eSCathy Zhang ),
14024885dc0eSCathy Zhang (
14034885dc0eSCathy Zhang vec![
1404aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
14054885dc0eSCathy Zhang "--net",
14061b8b5ac1SRob Bradford "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4,mask=5.6.7.8",
14074885dc0eSCathy Zhang ],
14084885dc0eSCathy Zhang r#"{
1409cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
14104885dc0eSCathy Zhang "net": [
14111b8b5ac1SRob Bradford {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "num_queues": 2, "queue_size": 256}
14124885dc0eSCathy Zhang ]
14134885dc0eSCathy Zhang }"#,
14144885dc0eSCathy Zhang true,
14154885dc0eSCathy Zhang ),
141699e72be1SHenry Wang #[cfg(target_arch = "x86_64")]
14174885dc0eSCathy Zhang (
14184885dc0eSCathy Zhang vec![
1419aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
14204885dc0eSCathy Zhang "--net",
14211b8b5ac1SRob Bradford "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,num_queues=2,queue_size=256,iommu=on",
14224885dc0eSCathy Zhang ],
14234885dc0eSCathy Zhang r#"{
1424cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
14254885dc0eSCathy Zhang "net": [
14261b8b5ac1SRob Bradford {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "num_queues": 2, "queue_size": 256, "iommu": true}
142743d2e09eSSebastien Boeuf ]
142843d2e09eSSebastien Boeuf }"#,
142943d2e09eSSebastien Boeuf false,
143043d2e09eSSebastien Boeuf ),
143199e72be1SHenry Wang #[cfg(target_arch = "x86_64")]
143243d2e09eSSebastien Boeuf (
143343d2e09eSSebastien Boeuf vec![
1434aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
143543d2e09eSSebastien Boeuf "--net",
14361b8b5ac1SRob Bradford "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,num_queues=2,queue_size=256,iommu=on",
143743d2e09eSSebastien Boeuf ],
143843d2e09eSSebastien Boeuf r#"{
1439cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
144043d2e09eSSebastien Boeuf "net": [
14411b8b5ac1SRob Bradford {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "num_queues": 2, "queue_size": 256, "iommu": true}
144243d2e09eSSebastien Boeuf ],
144343d2e09eSSebastien Boeuf "iommu": true
144443d2e09eSSebastien Boeuf }"#,
144543d2e09eSSebastien Boeuf true,
144643d2e09eSSebastien Boeuf ),
144743d2e09eSSebastien Boeuf (
144843d2e09eSSebastien Boeuf vec![
1449aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
145043d2e09eSSebastien Boeuf "--net",
14511b8b5ac1SRob Bradford "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,num_queues=2,queue_size=256,iommu=off",
145243d2e09eSSebastien Boeuf ],
145343d2e09eSSebastien Boeuf r#"{
1454cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
145543d2e09eSSebastien Boeuf "net": [
14561b8b5ac1SRob Bradford {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "num_queues": 2, "queue_size": 256, "iommu": false}
145743d2e09eSSebastien Boeuf ]
145843d2e09eSSebastien Boeuf }"#,
145943d2e09eSSebastien Boeuf true,
146043d2e09eSSebastien Boeuf ),
14614888dd2eSRob Bradford (
1462a8cdf2f0SBo Chen vec!["cloud-hypervisor", "--kernel", "/path/to/kernel", "--memory", "shared=true", "--net", "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,vhost_user=true,socket=/tmp/sock"],
14634888dd2eSRob Bradford r#"{
1464cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
14657481e4d9SRob Bradford "memory" : { "shared": true, "size": 536870912 },
14664888dd2eSRob Bradford "net": [
1467a8cdf2f0SBo Chen {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "vhost_user": true, "vhost_socket": "/tmp/sock"}
14684888dd2eSRob Bradford ]
14694888dd2eSRob Bradford }"#,
14704888dd2eSRob Bradford true,
14714888dd2eSRob Bradford ),
147243d2e09eSSebastien Boeuf ]
147343d2e09eSSebastien Boeuf .iter()
147443d2e09eSSebastien Boeuf .for_each(|(cli, openapi, equal)| {
147543d2e09eSSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
147643d2e09eSSebastien Boeuf });
147743d2e09eSSebastien Boeuf }
147843d2e09eSSebastien Boeuf
147943d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_rng()148043d2e09eSSebastien Boeuf fn test_valid_vm_config_rng() {
1481d0dbc7fbSYu Li [(
1482aaf382eeSRob Bradford vec![
1483aaf382eeSRob Bradford "cloud-hypervisor",
1484aaf382eeSRob Bradford "--kernel",
1485aaf382eeSRob Bradford "/path/to/kernel",
1486aaf382eeSRob Bradford "--rng",
1487aaf382eeSRob Bradford "src=/path/to/entropy/source",
1488aaf382eeSRob Bradford ],
148943d2e09eSSebastien Boeuf r#"{
1490cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
149143d2e09eSSebastien Boeuf "rng": {"src": "/path/to/entropy/source"}
149243d2e09eSSebastien Boeuf }"#,
149343d2e09eSSebastien Boeuf true,
149443d2e09eSSebastien Boeuf )]
149543d2e09eSSebastien Boeuf .iter()
149643d2e09eSSebastien Boeuf .for_each(|(cli, openapi, equal)| {
149743d2e09eSSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
149843d2e09eSSebastien Boeuf });
149943d2e09eSSebastien Boeuf }
150043d2e09eSSebastien Boeuf
150143d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_fs()150243d2e09eSSebastien Boeuf fn test_valid_vm_config_fs() {
1503d0dbc7fbSYu Li [(
150443d2e09eSSebastien Boeuf vec![
1505aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
15067481e4d9SRob Bradford "--memory", "shared=true",
150743d2e09eSSebastien Boeuf "--fs",
1508a8cdf2f0SBo Chen "tag=virtiofs1,socket=/path/to/sock1",
1509a8cdf2f0SBo Chen "tag=virtiofs2,socket=/path/to/sock2",
151043d2e09eSSebastien Boeuf ],
151143d2e09eSSebastien Boeuf r#"{
1512cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
15137481e4d9SRob Bradford "memory" : { "shared": true, "size": 536870912 },
151443d2e09eSSebastien Boeuf "fs": [
1515a8cdf2f0SBo Chen {"tag": "virtiofs1", "socket": "/path/to/sock1"},
1516a8cdf2f0SBo Chen {"tag": "virtiofs2", "socket": "/path/to/sock2"}
151743d2e09eSSebastien Boeuf ]
151843d2e09eSSebastien Boeuf }"#,
151943d2e09eSSebastien Boeuf true,
152043d2e09eSSebastien Boeuf ),
152143d2e09eSSebastien Boeuf (
152243d2e09eSSebastien Boeuf vec![
1523aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
15247481e4d9SRob Bradford "--memory", "shared=true",
152543d2e09eSSebastien Boeuf "--fs",
1526a8cdf2f0SBo Chen "tag=virtiofs1,socket=/path/to/sock1",
1527a8cdf2f0SBo Chen "tag=virtiofs2,socket=/path/to/sock2",
152843d2e09eSSebastien Boeuf ],
152943d2e09eSSebastien Boeuf r#"{
1530cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
15317481e4d9SRob Bradford "memory" : { "shared": true, "size": 536870912 },
153243d2e09eSSebastien Boeuf "fs": [
1533a8cdf2f0SBo Chen {"tag": "virtiofs1", "socket": "/path/to/sock1"}
153443d2e09eSSebastien Boeuf ]
153543d2e09eSSebastien Boeuf }"#,
153643d2e09eSSebastien Boeuf false,
153743d2e09eSSebastien Boeuf ),
153843d2e09eSSebastien Boeuf (
153943d2e09eSSebastien Boeuf vec![
1540aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
15417e0ccce2SRob Bradford "--memory", "shared=true", "--cpus", "boot=4",
154243d2e09eSSebastien Boeuf "--fs",
1543a8cdf2f0SBo Chen "tag=virtiofs1,socket=/path/to/sock1,num_queues=4",
154443d2e09eSSebastien Boeuf ],
154543d2e09eSSebastien Boeuf r#"{
1546cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
15477481e4d9SRob Bradford "memory" : { "shared": true, "size": 536870912 },
15487e0ccce2SRob Bradford "cpus": {"boot_vcpus": 4, "max_vcpus": 4},
154943d2e09eSSebastien Boeuf "fs": [
1550a8cdf2f0SBo Chen {"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4}
155143d2e09eSSebastien Boeuf ]
155243d2e09eSSebastien Boeuf }"#,
155343d2e09eSSebastien Boeuf true,
155443d2e09eSSebastien Boeuf ),
155543d2e09eSSebastien Boeuf (
155643d2e09eSSebastien Boeuf vec![
1557aaf382eeSRob Bradford "cloud-hypervisor", "--kernel", "/path/to/kernel",
15587e0ccce2SRob Bradford "--memory", "shared=true", "--cpus", "boot=4",
155943d2e09eSSebastien Boeuf "--fs",
1560a8cdf2f0SBo Chen "tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128"
156143d2e09eSSebastien Boeuf ],
156243d2e09eSSebastien Boeuf r#"{
1563cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
15647481e4d9SRob Bradford "memory" : { "shared": true, "size": 536870912 },
15657e0ccce2SRob Bradford "cpus": {"boot_vcpus": 4, "max_vcpus": 4},
156643d2e09eSSebastien Boeuf "fs": [
1567a8cdf2f0SBo Chen {"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128}
156843d2e09eSSebastien Boeuf ]
156943d2e09eSSebastien Boeuf }"#,
157043d2e09eSSebastien Boeuf true,
1571d0dbc7fbSYu Li )]
157243d2e09eSSebastien Boeuf .iter()
157343d2e09eSSebastien Boeuf .for_each(|(cli, openapi, equal)| {
157443d2e09eSSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
157543d2e09eSSebastien Boeuf });
157643d2e09eSSebastien Boeuf }
157743d2e09eSSebastien Boeuf
157843d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_pmem()157943d2e09eSSebastien Boeuf fn test_valid_vm_config_pmem() {
1580d0dbc7fbSYu Li [
158143d2e09eSSebastien Boeuf (
158243d2e09eSSebastien Boeuf vec![
158343d2e09eSSebastien Boeuf "cloud-hypervisor",
1584aaf382eeSRob Bradford "--kernel",
1585aaf382eeSRob Bradford "/path/to/kernel",
158643d2e09eSSebastien Boeuf "--pmem",
158743d2e09eSSebastien Boeuf "file=/path/to/img/1,size=1G",
158843d2e09eSSebastien Boeuf "file=/path/to/img/2,size=2G",
158943d2e09eSSebastien Boeuf ],
159043d2e09eSSebastien Boeuf r#"{
1591cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
159243d2e09eSSebastien Boeuf "pmem": [
159343d2e09eSSebastien Boeuf {"file": "/path/to/img/1", "size": 1073741824},
159443d2e09eSSebastien Boeuf {"file": "/path/to/img/2", "size": 2147483648}
159543d2e09eSSebastien Boeuf ]
159643d2e09eSSebastien Boeuf }"#,
159743d2e09eSSebastien Boeuf true,
159843d2e09eSSebastien Boeuf ),
159999e72be1SHenry Wang #[cfg(target_arch = "x86_64")]
160043d2e09eSSebastien Boeuf (
160143d2e09eSSebastien Boeuf vec![
160243d2e09eSSebastien Boeuf "cloud-hypervisor",
1603aaf382eeSRob Bradford "--kernel",
1604aaf382eeSRob Bradford "/path/to/kernel",
160543d2e09eSSebastien Boeuf "--pmem",
160643d2e09eSSebastien Boeuf "file=/path/to/img/1,size=1G,iommu=on",
160743d2e09eSSebastien Boeuf ],
160843d2e09eSSebastien Boeuf r#"{
1609cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
161043d2e09eSSebastien Boeuf "pmem": [
161143d2e09eSSebastien Boeuf {"file": "/path/to/img/1", "size": 1073741824, "iommu": true}
161243d2e09eSSebastien Boeuf ],
161343d2e09eSSebastien Boeuf "iommu": true
161443d2e09eSSebastien Boeuf }"#,
161543d2e09eSSebastien Boeuf true,
161643d2e09eSSebastien Boeuf ),
161799e72be1SHenry Wang #[cfg(target_arch = "x86_64")]
161843d2e09eSSebastien Boeuf (
161943d2e09eSSebastien Boeuf vec![
162043d2e09eSSebastien Boeuf "cloud-hypervisor",
1621aaf382eeSRob Bradford "--kernel",
1622aaf382eeSRob Bradford "/path/to/kernel",
162343d2e09eSSebastien Boeuf "--pmem",
162443d2e09eSSebastien Boeuf "file=/path/to/img/1,size=1G,iommu=on",
162543d2e09eSSebastien Boeuf ],
162643d2e09eSSebastien Boeuf r#"{
1627cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
162843d2e09eSSebastien Boeuf "pmem": [
162943d2e09eSSebastien Boeuf {"file": "/path/to/img/1", "size": 1073741824, "iommu": true}
163043d2e09eSSebastien Boeuf ]
163143d2e09eSSebastien Boeuf }"#,
163243d2e09eSSebastien Boeuf false,
163343d2e09eSSebastien Boeuf ),
163443d2e09eSSebastien Boeuf ]
163543d2e09eSSebastien Boeuf .iter()
163643d2e09eSSebastien Boeuf .for_each(|(cli, openapi, equal)| {
163743d2e09eSSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
163843d2e09eSSebastien Boeuf });
163943d2e09eSSebastien Boeuf }
164043d2e09eSSebastien Boeuf
1641e50a6411SPhilipp Schuster #[cfg(target_arch = "x86_64")]
1642e50a6411SPhilipp Schuster #[test]
test_valid_vm_config_debug_console()1643e50a6411SPhilipp Schuster fn test_valid_vm_config_debug_console() {
1644e50a6411SPhilipp Schuster [(
1645e50a6411SPhilipp Schuster vec![
1646e50a6411SPhilipp Schuster "cloud-hypervisor",
1647e50a6411SPhilipp Schuster "--kernel",
1648e50a6411SPhilipp Schuster "/path/to/kernel",
1649e50a6411SPhilipp Schuster "--debug-console",
1650e50a6411SPhilipp Schuster "tty,iobase=0xe9",
1651e50a6411SPhilipp Schuster ],
1652e50a6411SPhilipp Schuster // 233 == 0xe9
1653e50a6411SPhilipp Schuster r#"{
1654e50a6411SPhilipp Schuster "payload": {"kernel": "/path/to/kernel" },
1655e50a6411SPhilipp Schuster "debug_console": {"mode": "Tty", "iobase": 233 }
1656e50a6411SPhilipp Schuster }"#,
1657e50a6411SPhilipp Schuster true,
1658e50a6411SPhilipp Schuster )]
1659e50a6411SPhilipp Schuster .iter()
1660e50a6411SPhilipp Schuster .for_each(|(cli, openapi, equal)| {
1661e50a6411SPhilipp Schuster compare_vm_config_cli_vs_json(cli, openapi, *equal);
1662e50a6411SPhilipp Schuster });
1663e50a6411SPhilipp Schuster }
1664e50a6411SPhilipp Schuster
166543d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_serial_console()166643d2e09eSSebastien Boeuf fn test_valid_vm_config_serial_console() {
1667d0dbc7fbSYu Li [
166843d2e09eSSebastien Boeuf (
1669aaf382eeSRob Bradford vec!["cloud-hypervisor", "--kernel", "/path/to/kernel"],
167043d2e09eSSebastien Boeuf r#"{
1671cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
167243d2e09eSSebastien Boeuf "serial": {"mode": "Null"},
167343d2e09eSSebastien Boeuf "console": {"mode": "Tty"}
167443d2e09eSSebastien Boeuf }"#,
167543d2e09eSSebastien Boeuf true,
167643d2e09eSSebastien Boeuf ),
167743d2e09eSSebastien Boeuf (
1678aaf382eeSRob Bradford vec![
1679aaf382eeSRob Bradford "cloud-hypervisor",
1680aaf382eeSRob Bradford "--kernel",
1681aaf382eeSRob Bradford "/path/to/kernel",
1682aaf382eeSRob Bradford "--serial",
1683aaf382eeSRob Bradford "null",
1684aaf382eeSRob Bradford "--console",
1685aaf382eeSRob Bradford "tty",
1686aaf382eeSRob Bradford ],
1687aaf382eeSRob Bradford r#"{
1688cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"}
1689aaf382eeSRob Bradford }"#,
169043d2e09eSSebastien Boeuf true,
169143d2e09eSSebastien Boeuf ),
169243d2e09eSSebastien Boeuf (
1693aaf382eeSRob Bradford vec![
1694aaf382eeSRob Bradford "cloud-hypervisor",
1695aaf382eeSRob Bradford "--kernel",
1696aaf382eeSRob Bradford "/path/to/kernel",
1697aaf382eeSRob Bradford "--serial",
1698aaf382eeSRob Bradford "tty",
1699aaf382eeSRob Bradford "--console",
1700aaf382eeSRob Bradford "off",
1701aaf382eeSRob Bradford ],
170243d2e09eSSebastien Boeuf r#"{
1703cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
170443d2e09eSSebastien Boeuf "serial": {"mode": "Tty"},
170543d2e09eSSebastien Boeuf "console": {"mode": "Off"}
170643d2e09eSSebastien Boeuf }"#,
170743d2e09eSSebastien Boeuf true,
170843d2e09eSSebastien Boeuf ),
170943d2e09eSSebastien Boeuf ]
171043d2e09eSSebastien Boeuf .iter()
171143d2e09eSSebastien Boeuf .for_each(|(cli, openapi, equal)| {
171243d2e09eSSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
171343d2e09eSSebastien Boeuf });
171443d2e09eSSebastien Boeuf }
171543d2e09eSSebastien Boeuf
171643d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_serial_pty_console_pty()171748963e32SWilliam Douglas fn test_valid_vm_config_serial_pty_console_pty() {
1718d0dbc7fbSYu Li [
171948963e32SWilliam Douglas (
172048963e32SWilliam Douglas vec!["cloud-hypervisor", "--kernel", "/path/to/kernel"],
172148963e32SWilliam Douglas r#"{
1722cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
172348963e32SWilliam Douglas "serial": {"mode": "Null"},
172448963e32SWilliam Douglas "console": {"mode": "Tty"}
172548963e32SWilliam Douglas }"#,
172648963e32SWilliam Douglas true,
172748963e32SWilliam Douglas ),
172848963e32SWilliam Douglas (
172948963e32SWilliam Douglas vec![
173048963e32SWilliam Douglas "cloud-hypervisor",
173148963e32SWilliam Douglas "--kernel",
173248963e32SWilliam Douglas "/path/to/kernel",
173348963e32SWilliam Douglas "--serial",
173448963e32SWilliam Douglas "null",
173548963e32SWilliam Douglas "--console",
173648963e32SWilliam Douglas "tty",
173748963e32SWilliam Douglas ],
173848963e32SWilliam Douglas r#"{
1739cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"}
174048963e32SWilliam Douglas }"#,
174148963e32SWilliam Douglas true,
174248963e32SWilliam Douglas ),
174348963e32SWilliam Douglas (
174448963e32SWilliam Douglas vec![
174548963e32SWilliam Douglas "cloud-hypervisor",
174648963e32SWilliam Douglas "--kernel",
174748963e32SWilliam Douglas "/path/to/kernel",
174848963e32SWilliam Douglas "--serial",
174948963e32SWilliam Douglas "pty",
175048963e32SWilliam Douglas "--console",
175148963e32SWilliam Douglas "pty",
175248963e32SWilliam Douglas ],
175348963e32SWilliam Douglas r#"{
1754cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
175548963e32SWilliam Douglas "serial": {"mode": "Pty"},
175648963e32SWilliam Douglas "console": {"mode": "Pty"}
175748963e32SWilliam Douglas }"#,
175848963e32SWilliam Douglas true,
175948963e32SWilliam Douglas ),
176048963e32SWilliam Douglas ]
176148963e32SWilliam Douglas .iter()
176248963e32SWilliam Douglas .for_each(|(cli, openapi, equal)| {
176348963e32SWilliam Douglas compare_vm_config_cli_vs_json(cli, openapi, *equal);
176448963e32SWilliam Douglas });
176548963e32SWilliam Douglas }
176648963e32SWilliam Douglas
176748963e32SWilliam Douglas #[test]
176899e72be1SHenry Wang #[cfg(target_arch = "x86_64")]
test_valid_vm_config_devices()176943d2e09eSSebastien Boeuf fn test_valid_vm_config_devices() {
177043d2e09eSSebastien Boeuf vec![
177143d2e09eSSebastien Boeuf (
177243d2e09eSSebastien Boeuf vec![
177343d2e09eSSebastien Boeuf "cloud-hypervisor",
1774aaf382eeSRob Bradford "--kernel",
1775aaf382eeSRob Bradford "/path/to/kernel",
177643d2e09eSSebastien Boeuf "--device",
177743d2e09eSSebastien Boeuf "path=/path/to/device/1",
177843d2e09eSSebastien Boeuf "path=/path/to/device/2",
177943d2e09eSSebastien Boeuf ],
178043d2e09eSSebastien Boeuf r#"{
1781cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
178243d2e09eSSebastien Boeuf "devices": [
178343d2e09eSSebastien Boeuf {"path": "/path/to/device/1"},
178443d2e09eSSebastien Boeuf {"path": "/path/to/device/2"}
178543d2e09eSSebastien Boeuf ]
178643d2e09eSSebastien Boeuf }"#,
178743d2e09eSSebastien Boeuf true,
178843d2e09eSSebastien Boeuf ),
178943d2e09eSSebastien Boeuf (
179043d2e09eSSebastien Boeuf vec![
179143d2e09eSSebastien Boeuf "cloud-hypervisor",
1792aaf382eeSRob Bradford "--kernel",
1793aaf382eeSRob Bradford "/path/to/kernel",
179443d2e09eSSebastien Boeuf "--device",
179543d2e09eSSebastien Boeuf "path=/path/to/device/1",
179643d2e09eSSebastien Boeuf "path=/path/to/device/2",
179743d2e09eSSebastien Boeuf ],
179843d2e09eSSebastien Boeuf r#"{
1799cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
180043d2e09eSSebastien Boeuf "devices": [
180143d2e09eSSebastien Boeuf {"path": "/path/to/device/1"}
180243d2e09eSSebastien Boeuf ]
180343d2e09eSSebastien Boeuf }"#,
180443d2e09eSSebastien Boeuf false,
180543d2e09eSSebastien Boeuf ),
180643d2e09eSSebastien Boeuf (
180743d2e09eSSebastien Boeuf vec![
180843d2e09eSSebastien Boeuf "cloud-hypervisor",
1809aaf382eeSRob Bradford "--kernel",
1810aaf382eeSRob Bradford "/path/to/kernel",
181143d2e09eSSebastien Boeuf "--device",
181243d2e09eSSebastien Boeuf "path=/path/to/device,iommu=on",
181343d2e09eSSebastien Boeuf ],
181443d2e09eSSebastien Boeuf r#"{
1815cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
181643d2e09eSSebastien Boeuf "devices": [
181743d2e09eSSebastien Boeuf {"path": "/path/to/device", "iommu": true}
181843d2e09eSSebastien Boeuf ],
181943d2e09eSSebastien Boeuf "iommu": true
182043d2e09eSSebastien Boeuf }"#,
182143d2e09eSSebastien Boeuf true,
182243d2e09eSSebastien Boeuf ),
182343d2e09eSSebastien Boeuf (
182443d2e09eSSebastien Boeuf vec![
182543d2e09eSSebastien Boeuf "cloud-hypervisor",
1826aaf382eeSRob Bradford "--kernel",
1827aaf382eeSRob Bradford "/path/to/kernel",
182843d2e09eSSebastien Boeuf "--device",
182943d2e09eSSebastien Boeuf "path=/path/to/device,iommu=on",
183043d2e09eSSebastien Boeuf ],
183143d2e09eSSebastien Boeuf r#"{
1832cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
183343d2e09eSSebastien Boeuf "devices": [
183443d2e09eSSebastien Boeuf {"path": "/path/to/device", "iommu": true}
183543d2e09eSSebastien Boeuf ]
183643d2e09eSSebastien Boeuf }"#,
183743d2e09eSSebastien Boeuf false,
183843d2e09eSSebastien Boeuf ),
183943d2e09eSSebastien Boeuf (
184043d2e09eSSebastien Boeuf vec![
184143d2e09eSSebastien Boeuf "cloud-hypervisor",
1842aaf382eeSRob Bradford "--kernel",
1843aaf382eeSRob Bradford "/path/to/kernel",
184443d2e09eSSebastien Boeuf "--device",
184543d2e09eSSebastien Boeuf "path=/path/to/device,iommu=off",
184643d2e09eSSebastien Boeuf ],
184743d2e09eSSebastien Boeuf r#"{
1848cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
184943d2e09eSSebastien Boeuf "devices": [
185043d2e09eSSebastien Boeuf {"path": "/path/to/device", "iommu": false}
185143d2e09eSSebastien Boeuf ]
185243d2e09eSSebastien Boeuf }"#,
185343d2e09eSSebastien Boeuf true,
185443d2e09eSSebastien Boeuf ),
185543d2e09eSSebastien Boeuf ]
185643d2e09eSSebastien Boeuf .iter()
185743d2e09eSSebastien Boeuf .for_each(|(cli, openapi, equal)| {
185843d2e09eSSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
185943d2e09eSSebastien Boeuf });
186043d2e09eSSebastien Boeuf }
186143d2e09eSSebastien Boeuf
186243d2e09eSSebastien Boeuf #[test]
test_valid_vm_config_vdpa()186372169686SSebastien Boeuf fn test_valid_vm_config_vdpa() {
1864d0dbc7fbSYu Li [
186572169686SSebastien Boeuf (
186672169686SSebastien Boeuf vec![
186772169686SSebastien Boeuf "cloud-hypervisor",
186872169686SSebastien Boeuf "--kernel",
186972169686SSebastien Boeuf "/path/to/kernel",
187072169686SSebastien Boeuf "--vdpa",
187172169686SSebastien Boeuf "path=/path/to/device/1",
187272169686SSebastien Boeuf "path=/path/to/device/2,num_queues=2",
187372169686SSebastien Boeuf ],
187472169686SSebastien Boeuf r#"{
1875cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
187672169686SSebastien Boeuf "vdpa": [
187772169686SSebastien Boeuf {"path": "/path/to/device/1", "num_queues": 1},
187872169686SSebastien Boeuf {"path": "/path/to/device/2", "num_queues": 2}
187972169686SSebastien Boeuf ]
188072169686SSebastien Boeuf }"#,
188172169686SSebastien Boeuf true,
188272169686SSebastien Boeuf ),
188372169686SSebastien Boeuf (
188472169686SSebastien Boeuf vec![
188572169686SSebastien Boeuf "cloud-hypervisor",
188672169686SSebastien Boeuf "--kernel",
188772169686SSebastien Boeuf "/path/to/kernel",
188872169686SSebastien Boeuf "--vdpa",
188972169686SSebastien Boeuf "path=/path/to/device/1",
189072169686SSebastien Boeuf "path=/path/to/device/2",
189172169686SSebastien Boeuf ],
189272169686SSebastien Boeuf r#"{
1893cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
189472169686SSebastien Boeuf "vdpa": [
189572169686SSebastien Boeuf {"path": "/path/to/device/1"}
189672169686SSebastien Boeuf ]
189772169686SSebastien Boeuf }"#,
189872169686SSebastien Boeuf false,
189972169686SSebastien Boeuf ),
190072169686SSebastien Boeuf ]
190172169686SSebastien Boeuf .iter()
190272169686SSebastien Boeuf .for_each(|(cli, openapi, equal)| {
190372169686SSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
190472169686SSebastien Boeuf });
190572169686SSebastien Boeuf }
190672169686SSebastien Boeuf
190772169686SSebastien Boeuf #[test]
test_valid_vm_config_vsock()190843d2e09eSSebastien Boeuf fn test_valid_vm_config_vsock() {
1909d0dbc7fbSYu Li [
191043d2e09eSSebastien Boeuf (
191143d2e09eSSebastien Boeuf vec![
191243d2e09eSSebastien Boeuf "cloud-hypervisor",
1913aaf382eeSRob Bradford "--kernel",
1914aaf382eeSRob Bradford "/path/to/kernel",
191543d2e09eSSebastien Boeuf "--vsock",
1916a8cdf2f0SBo Chen "cid=123,socket=/path/to/sock/1",
191743d2e09eSSebastien Boeuf ],
191843d2e09eSSebastien Boeuf r#"{
1919cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
1920a8cdf2f0SBo Chen "vsock": {"cid": 123, "socket": "/path/to/sock/1"}
192143d2e09eSSebastien Boeuf }"#,
192243d2e09eSSebastien Boeuf true,
192343d2e09eSSebastien Boeuf ),
192443d2e09eSSebastien Boeuf (
192543d2e09eSSebastien Boeuf vec![
192643d2e09eSSebastien Boeuf "cloud-hypervisor",
1927aaf382eeSRob Bradford "--kernel",
1928aaf382eeSRob Bradford "/path/to/kernel",
192943d2e09eSSebastien Boeuf "--vsock",
1930a8cdf2f0SBo Chen "cid=124,socket=/path/to/sock/1",
193143d2e09eSSebastien Boeuf ],
193243d2e09eSSebastien Boeuf r#"{
1933cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
1934a8cdf2f0SBo Chen "vsock": {"cid": 123, "socket": "/path/to/sock/1"}
193543d2e09eSSebastien Boeuf }"#,
193643d2e09eSSebastien Boeuf false,
193743d2e09eSSebastien Boeuf ),
193899e72be1SHenry Wang #[cfg(target_arch = "x86_64")]
193943d2e09eSSebastien Boeuf (
194043d2e09eSSebastien Boeuf vec![
194143d2e09eSSebastien Boeuf "cloud-hypervisor",
1942aaf382eeSRob Bradford "--kernel",
1943aaf382eeSRob Bradford "/path/to/kernel",
194443d2e09eSSebastien Boeuf "--vsock",
1945a8cdf2f0SBo Chen "cid=123,socket=/path/to/sock/1,iommu=on",
194643d2e09eSSebastien Boeuf ],
194743d2e09eSSebastien Boeuf r#"{
1948cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
1949a8cdf2f0SBo Chen "vsock": {"cid": 123, "socket": "/path/to/sock/1", "iommu": true},
195043d2e09eSSebastien Boeuf "iommu": true
195143d2e09eSSebastien Boeuf }"#,
195243d2e09eSSebastien Boeuf true,
195343d2e09eSSebastien Boeuf ),
195499e72be1SHenry Wang #[cfg(target_arch = "x86_64")]
195543d2e09eSSebastien Boeuf (
195643d2e09eSSebastien Boeuf vec![
195743d2e09eSSebastien Boeuf "cloud-hypervisor",
1958aaf382eeSRob Bradford "--kernel",
1959aaf382eeSRob Bradford "/path/to/kernel",
196043d2e09eSSebastien Boeuf "--vsock",
1961a8cdf2f0SBo Chen "cid=123,socket=/path/to/sock/1,iommu=on",
196243d2e09eSSebastien Boeuf ],
196343d2e09eSSebastien Boeuf r#"{
1964cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
1965a8cdf2f0SBo Chen "vsock": {"cid": 123, "socket": "/path/to/sock/1", "iommu": true}
196643d2e09eSSebastien Boeuf }"#,
196743d2e09eSSebastien Boeuf false,
196843d2e09eSSebastien Boeuf ),
196943d2e09eSSebastien Boeuf (
197043d2e09eSSebastien Boeuf vec![
197143d2e09eSSebastien Boeuf "cloud-hypervisor",
1972aaf382eeSRob Bradford "--kernel",
1973aaf382eeSRob Bradford "/path/to/kernel",
197443d2e09eSSebastien Boeuf "--vsock",
1975a8cdf2f0SBo Chen "cid=123,socket=/path/to/sock/1,iommu=off",
197643d2e09eSSebastien Boeuf ],
197743d2e09eSSebastien Boeuf r#"{
1978cef51a9dSRob Bradford "payload": {"kernel": "/path/to/kernel"},
1979a8cdf2f0SBo Chen "vsock": {"cid": 123, "socket": "/path/to/sock/1", "iommu": false}
198043d2e09eSSebastien Boeuf }"#,
198143d2e09eSSebastien Boeuf true,
198243d2e09eSSebastien Boeuf ),
198343d2e09eSSebastien Boeuf ]
198443d2e09eSSebastien Boeuf .iter()
198543d2e09eSSebastien Boeuf .for_each(|(cli, openapi, equal)| {
198643d2e09eSSebastien Boeuf compare_vm_config_cli_vs_json(cli, openapi, *equal);
198743d2e09eSSebastien Boeuf });
198843d2e09eSSebastien Boeuf }
19897122e298SPraveen K Paladugu
19907122e298SPraveen K Paladugu #[test]
test_valid_vm_config_tpm_socket()19917122e298SPraveen K Paladugu fn test_valid_vm_config_tpm_socket() {
1992d0dbc7fbSYu Li [(
19937122e298SPraveen K Paladugu vec![
19947122e298SPraveen K Paladugu "cloud-hypervisor",
19957122e298SPraveen K Paladugu "--kernel",
19967122e298SPraveen K Paladugu "/path/to/kernel",
19977122e298SPraveen K Paladugu "--tpm",
19987122e298SPraveen K Paladugu "socket=/path/to/tpm/sock",
19997122e298SPraveen K Paladugu ],
20007122e298SPraveen K Paladugu r#"{
20017122e298SPraveen K Paladugu "payload": {"kernel": "/path/to/kernel"},
20027122e298SPraveen K Paladugu "tpm": {"socket": "/path/to/tpm/sock"}
20037122e298SPraveen K Paladugu }"#,
20047122e298SPraveen K Paladugu true,
20057122e298SPraveen K Paladugu )]
20067122e298SPraveen K Paladugu .iter()
20077122e298SPraveen K Paladugu .for_each(|(cli, openapi, equal)| {
20087122e298SPraveen K Paladugu compare_vm_config_cli_vs_json(cli, openapi, *equal);
20097122e298SPraveen K Paladugu });
20107122e298SPraveen K Paladugu }
2011fa58b725SPhilipp Schuster
2012fa58b725SPhilipp Schuster // TODO the check for the option list being sorted could be moved into the
2013fa58b725SPhilipp Schuster // getter itself, when the getter becomes a const function. This however
2014fa58b725SPhilipp Schuster // needs more support by Rust (as of March 2025).
2015fa58b725SPhilipp Schuster #[test]
test_cli_options_sorted()2016fa58b725SPhilipp Schuster fn test_cli_options_sorted() {
2017fa58b725SPhilipp Schuster let (default_vcpus, default_memory, default_rng) = prepare_default_values();
2018fa58b725SPhilipp Schuster let args = get_cli_options_sorted(default_vcpus, default_memory, default_rng);
2019fa58b725SPhilipp Schuster
20201f13165fSPhilipp Schuster assert_args_sorted(|| args.iter())
2021fa58b725SPhilipp Schuster }
202243d2e09eSSebastien Boeuf }
2023