xref: /cloud-hypervisor/vmm/src/lib.rs (revision d7edd9d51fbe16067f06ccb3014a012861a0c52b)
116f2bedbSSamuel Ortiz // Copyright © 2019 Intel Corporation
216f2bedbSSamuel Ortiz //
316f2bedbSSamuel Ortiz // SPDX-License-Identifier: Apache-2.0
416f2bedbSSamuel Ortiz //
516f2bedbSSamuel Ortiz 
69260c4c1SRob Bradford #[macro_use]
79260c4c1SRob Bradford extern crate event_monitor;
88bb71fadSSamuel Ortiz #[macro_use]
98bb71fadSSamuel Ortiz extern crate log;
1016f2bedbSSamuel Ortiz 
1188a9f799SRob Bradford use std::collections::HashMap;
1288a9f799SRob Bradford use std::fs::File;
1388a9f799SRob Bradford use std::io::{stdout, Read, Write};
14909e1bc3SJinrong Liang use std::net::{TcpListener, TcpStream};
1588a9f799SRob Bradford use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
1661e57e1cSRuoqing He use std::os::unix::net::{UnixListener, UnixStream};
1788a9f799SRob Bradford use std::panic::AssertUnwindSafe;
1888a9f799SRob Bradford use std::path::PathBuf;
1988a9f799SRob Bradford use std::rc::Rc;
2088a9f799SRob Bradford use std::sync::mpsc::{Receiver, RecvError, SendError, Sender};
2188a9f799SRob Bradford use std::sync::{Arc, Mutex};
22c99660a8SRuoqing He #[cfg(not(target_arch = "riscv64"))]
2388a9f799SRob Bradford use std::time::Instant;
2461e57e1cSRuoqing He use std::{io, result, thread};
2588a9f799SRob Bradford 
2688a9f799SRob Bradford use anyhow::anyhow;
2788a9f799SRob Bradford #[cfg(feature = "dbus_api")]
2888a9f799SRob Bradford use api::dbus::{DBusApiOptions, DBusApiShutdownChannels};
2988a9f799SRob Bradford use api::http::HttpApiHandle;
3088a9f799SRob Bradford use console_devices::{pre_create_console_devices, ConsoleInfo};
3188a9f799SRob Bradford use landlock::LandlockError;
3288a9f799SRob Bradford use libc::{tcsetattr, termios, EFD_NONBLOCK, SIGINT, SIGTERM, TCSANOW};
3388a9f799SRob Bradford use memory_manager::MemoryManagerSnapshotData;
3488a9f799SRob Bradford use pci::PciBdf;
3588a9f799SRob Bradford use seccompiler::{apply_filter, SeccompAction};
3688a9f799SRob Bradford use serde::ser::{SerializeStruct, Serializer};
3788a9f799SRob Bradford use serde::{Deserialize, Serialize};
3888a9f799SRob Bradford use signal_hook::iterator::{Handle, Signals};
3988a9f799SRob Bradford use thiserror::Error;
4088a9f799SRob Bradford use tracer::trace_scoped;
41909e1bc3SJinrong Liang use vm_memory::bitmap::{AtomicBitmap, BitmapSlice};
42909e1bc3SJinrong Liang use vm_memory::{ReadVolatile, VolatileMemoryError, VolatileSlice, WriteVolatile};
4361e57e1cSRuoqing He use vm_migration::protocol::*;
4461e57e1cSRuoqing He use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
4588a9f799SRob Bradford use vmm_sys_util::eventfd::EventFd;
4688a9f799SRob Bradford use vmm_sys_util::signal::unblock_signal;
4788a9f799SRob Bradford use vmm_sys_util::sock_ctrl_msg::ScmSocket;
4888a9f799SRob Bradford 
497ac76451SRob Bradford use crate::api::{
504ca18c08SAlyssa Ross     ApiRequest, ApiResponse, RequestHandler, VmInfoResponse, VmReceiveMigrationData,
517ac76451SRob Bradford     VmSendMigrationData, VmmPingResponse,
527ac76451SRob Bradford };
5333c15ca2SSongqian Li use crate::config::{add_to_config, RestoreConfig};
54cefbf6b4SRob Bradford #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
558b585b96SYi Wang use crate::coredump::GuestDebuggable;
568c76a3e4SPraveen K Paladugu use crate::landlock::Landlock;
57c52ccf39SSebastien Boeuf use crate::memory_manager::MemoryManager;
5810676b74SSebastien Boeuf #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
5910676b74SSebastien Boeuf use crate::migration::get_vm_snapshot;
6010676b74SSebastien Boeuf use crate::migration::{recv_vm_config, recv_vm_state};
61feb8d7aeSSebastien Boeuf use crate::seccomp_filters::{get_seccomp_filter, Thread};
621298b508SSamuel Ortiz use crate::vm::{Error as VmError, Vm, VmState};
6333c15ca2SSongqian Li use crate::vm_config::{
6433c15ca2SSongqian Li     DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, UserDeviceConfig, VdpaConfig,
6533c15ca2SSongqian Li     VmConfig, VsockConfig,
6633c15ca2SSongqian Li };
671853b350SSamuel Ortiz 
68c99660a8SRuoqing He #[cfg(not(target_arch = "riscv64"))]
6984fc0e09SRob Bradford mod acpi;
7003ab6839SSamuel Ortiz pub mod api;
71330b5ea3SAlyssa Ross mod clone3;
72e5e65189SSebastien Boeuf pub mod config;
73cf6115a7SPraveen K Paladugu pub mod console_devices;
74cefbf6b4SRob Bradford #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
7590034fd6SYi Wang mod coredump;
766958ec49SRob Bradford pub mod cpu;
779ac967e3SRob Bradford pub mod device_manager;
7864e01684SSebastien Boeuf pub mod device_tree;
7906eb82d2SRob Bradford #[cfg(feature = "guest_debug")]
80f1c47056SAkira Moroo mod gdb;
817030b15eSMuminul Islam #[cfg(feature = "igvm")]
827030b15eSMuminul Islam mod igvm;
830f727127SSebastien Boeuf pub mod interrupt;
841d89f98eSPraveen K Paladugu pub mod landlock;
85260cebb8SRob Bradford pub mod memory_manager;
86b55b83c6SSamuel Ortiz pub mod migration;
8784fc0e09SRob Bradford mod pci_segment;
88db62cb3fSSebastien Boeuf pub mod seccomp_filters;
8946f6d959SWilliam Douglas mod serial_manager;
9084fc0e09SRob Bradford mod sigwinch_listener;
9184fc0e09SRob Bradford pub mod vm;
927ad58457SRob Bradford pub mod vm_config;
930319a4a0SRob Bradford 
94b5bcdbafSBo Chen type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
95b5bcdbafSBo Chen type GuestRegionMmap = vm_memory::GuestRegionMmap<AtomicBitmap>;
96b5bcdbafSBo Chen 
972f1ff230SSamuel Ortiz /// Errors associated with VMM management
98dfd21cbfSRob Bradford #[derive(Debug, Error)]
992c945296SSamuel Ortiz pub enum Error {
1002f1ff230SSamuel Ortiz     /// API request receive error
101*d7edd9d5SPhilipp Schuster     #[error("Error receiving API request")]
102dfd21cbfSRob Bradford     ApiRequestRecv(#[source] RecvError),
1032f1ff230SSamuel Ortiz 
1042f1ff230SSamuel Ortiz     /// API response send error
105*d7edd9d5SPhilipp Schuster     #[error("Error sending API request")]
106dfd21cbfSRob Bradford     ApiResponseSend(#[source] SendError<ApiResponse>),
1072f1ff230SSamuel Ortiz 
1082371325fSSamuel Ortiz     /// Cannot bind to the UNIX domain socket path
109*d7edd9d5SPhilipp Schuster     #[error("Error binding to UNIX domain socket")]
110dfd21cbfSRob Bradford     Bind(#[source] io::Error),
1112371325fSSamuel Ortiz 
1122f1ff230SSamuel Ortiz     /// Cannot clone EventFd.
113*d7edd9d5SPhilipp Schuster     #[error("Error cloning EventFd")]
114dfd21cbfSRob Bradford     EventFdClone(#[source] io::Error),
1152f1ff230SSamuel Ortiz 
1166710a39bSSamuel Ortiz     /// Cannot create EventFd.
117*d7edd9d5SPhilipp Schuster     #[error("Error creating EventFd")]
118dfd21cbfSRob Bradford     EventFdCreate(#[source] io::Error),
1196710a39bSSamuel Ortiz 
1202f1ff230SSamuel Ortiz     /// Cannot read from EventFd.
121*d7edd9d5SPhilipp Schuster     #[error("Error reading from EventFd")]
122dfd21cbfSRob Bradford     EventFdRead(#[source] io::Error),
1232c945296SSamuel Ortiz 
1242f1ff230SSamuel Ortiz     /// Cannot create epoll context.
125*d7edd9d5SPhilipp Schuster     #[error("Error creating epoll context")]
126dfd21cbfSRob Bradford     Epoll(#[source] io::Error),
1272f1ff230SSamuel Ortiz 
1282371325fSSamuel Ortiz     /// Cannot create HTTP thread
129*d7edd9d5SPhilipp Schuster     #[error("Error spawning HTTP thread")]
130dfd21cbfSRob Bradford     HttpThreadSpawn(#[source] io::Error),
1312371325fSSamuel Ortiz 
132c016a0d4SOmer Faruk Bayram     /// Cannot create D-Bus thread
133c016a0d4SOmer Faruk Bayram     #[cfg(feature = "dbus_api")]
134*d7edd9d5SPhilipp Schuster     #[error("Error spawning D-Bus thread")]
135c016a0d4SOmer Faruk Bayram     DBusThreadSpawn(#[source] io::Error),
136c016a0d4SOmer Faruk Bayram 
137c016a0d4SOmer Faruk Bayram     /// Cannot start D-Bus session
138c016a0d4SOmer Faruk Bayram     #[cfg(feature = "dbus_api")]
139*d7edd9d5SPhilipp Schuster     #[error("Error starting D-Bus session")]
140c016a0d4SOmer Faruk Bayram     CreateDBusSession(#[source] zbus::Error),
141c016a0d4SOmer Faruk Bayram 
14202e1c544SOmer Faruk Bayram     /// Cannot create `event-monitor` thread
143*d7edd9d5SPhilipp Schuster     #[error("Error spawning `event-monitor` thread")]
14402e1c544SOmer Faruk Bayram     EventMonitorThreadSpawn(#[source] io::Error),
14502e1c544SOmer Faruk Bayram 
1462f1ff230SSamuel Ortiz     /// Cannot handle the VM STDIN stream
147*d7edd9d5SPhilipp Schuster     #[error("Error handling VM stdin")]
148a2123439SPhilipp Schuster     Stdin(#[source] VmError),
1492f1ff230SSamuel Ortiz 
15048963e32SWilliam Douglas     /// Cannot handle the VM pty stream
151*d7edd9d5SPhilipp Schuster     #[error("Error handling VM pty")]
152a2123439SPhilipp Schuster     Pty(#[source] VmError),
15348963e32SWilliam Douglas 
15443b36429SSamuel Ortiz     /// Cannot reboot the VM
155*d7edd9d5SPhilipp Schuster     #[error("Error rebooting VM")]
156a2123439SPhilipp Schuster     VmReboot(#[source] VmError),
157b7034415SSamuel Ortiz 
158151f96e4SSamuel Ortiz     /// Cannot create VMM thread
159*d7edd9d5SPhilipp Schuster     #[error("Error spawning VMM thread")]
160dfd21cbfSRob Bradford     VmmThreadSpawn(#[source] io::Error),
161a95fa1c4SSamuel Ortiz 
162a95fa1c4SSamuel Ortiz     /// Cannot shut the VMM down
163*d7edd9d5SPhilipp Schuster     #[error("Error shutting down VMM")]
164a2123439SPhilipp Schuster     VmmShutdown(#[source] VmError),
165b04eb477SRob Bradford 
166db62cb3fSSebastien Boeuf     /// Cannot create seccomp filter
167*d7edd9d5SPhilipp Schuster     #[error("Error creating seccomp filter")]
168a2123439SPhilipp Schuster     CreateSeccompFilter(#[source] seccompiler::Error),
169db62cb3fSSebastien Boeuf 
170db62cb3fSSebastien Boeuf     /// Cannot apply seccomp filter
171*d7edd9d5SPhilipp Schuster     #[error("Error applying seccomp filter")]
172a2123439SPhilipp Schuster     ApplySeccompFilter(#[source] seccompiler::Error),
17303db4830SRob Bradford 
17403db4830SRob Bradford     /// Error activating virtio devices
175*d7edd9d5SPhilipp Schuster     #[error("Error activating virtio devices")]
176a2123439SPhilipp Schuster     ActivateVirtioDevices(#[source] VmError),
17794403041SRob Bradford 
17894403041SRob Bradford     /// Error creating API server
179*d7edd9d5SPhilipp Schuster     // TODO We should add #[source] here once the type implements Error.
180*d7edd9d5SPhilipp Schuster     // Then we also can remove the `: {}` to align with the other errors.
181*d7edd9d5SPhilipp Schuster     #[error("Error creating API server: {0}")]
1829762c8bcSRob Bradford     CreateApiServer(micro_http::ServerError),
183b8779ddcSWilliam Douglas 
184b8779ddcSWilliam Douglas     /// Error binding API server socket
185*d7edd9d5SPhilipp Schuster     #[error("Error creation API server's socket")]
186b8779ddcSWilliam Douglas     CreateApiServerSocket(#[source] io::Error),
1872451c4d8SAkira Moroo 
18806eb82d2SRob Bradford     #[cfg(feature = "guest_debug")]
189*d7edd9d5SPhilipp Schuster     #[error("Failed to start the GDB thread")]
190a2123439SPhilipp Schuster     GdbThreadSpawn(#[source] io::Error),
1912451c4d8SAkira Moroo 
1922451c4d8SAkira Moroo     /// GDB request receive error
19306eb82d2SRob Bradford     #[cfg(feature = "guest_debug")]
194*d7edd9d5SPhilipp Schuster     #[error("Error receiving GDB request")]
1952451c4d8SAkira Moroo     GdbRequestRecv(#[source] RecvError),
1962451c4d8SAkira Moroo 
1972451c4d8SAkira Moroo     /// GDB response send error
19806eb82d2SRob Bradford     #[cfg(feature = "guest_debug")]
199*d7edd9d5SPhilipp Schuster     #[error("Error sending GDB request")]
2002451c4d8SAkira Moroo     GdbResponseSend(#[source] SendError<gdb::GdbResponse>),
201121729a3SRob Bradford 
202*d7edd9d5SPhilipp Schuster     #[error("Cannot spawn a signal handler thread")]
203121729a3SRob Bradford     SignalHandlerSpawn(#[source] io::Error),
204121729a3SRob Bradford 
205121729a3SRob Bradford     #[error("Failed to join on threads: {0:?}")]
206121729a3SRob Bradford     ThreadCleanup(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
2078c76a3e4SPraveen K Paladugu 
2088c76a3e4SPraveen K Paladugu     /// Cannot create Landlock object
209*d7edd9d5SPhilipp Schuster     #[error("Error creating landlock object")]
210a2123439SPhilipp Schuster     CreateLandlock(#[source] LandlockError),
2118c76a3e4SPraveen K Paladugu 
2128c76a3e4SPraveen K Paladugu     /// Cannot apply landlock based sandboxing
213*d7edd9d5SPhilipp Schuster     #[error("Error applying landlock")]
214a2123439SPhilipp Schuster     ApplyLandlock(#[source] LandlockError),
2152c945296SSamuel Ortiz }
2162c945296SSamuel Ortiz pub type Result<T> = result::Result<T, Error>;
2172c945296SSamuel Ortiz 
2182716bc33SRob Bradford #[derive(Debug, Clone, Copy, PartialEq, Eq)]
21963637ebaSRob Bradford #[repr(u64)]
2204671a583SSamuel Ortiz pub enum EpollDispatch {
22163637ebaSRob Bradford     Exit = 0,
22263637ebaSRob Bradford     Reset = 1,
22346f6d959SWilliam Douglas     Api = 2,
22446f6d959SWilliam Douglas     ActivateVirtioDevices = 3,
2252451c4d8SAkira Moroo     Debug = 4,
22663637ebaSRob Bradford     Unknown,
22763637ebaSRob Bradford }
22863637ebaSRob Bradford 
22963637ebaSRob Bradford impl From<u64> for EpollDispatch {
from(v: u64) -> Self23063637ebaSRob Bradford     fn from(v: u64) -> Self {
23163637ebaSRob Bradford         use EpollDispatch::*;
23263637ebaSRob Bradford         match v {
23363637ebaSRob Bradford             0 => Exit,
23463637ebaSRob Bradford             1 => Reset,
23546f6d959SWilliam Douglas             2 => Api,
23646f6d959SWilliam Douglas             3 => ActivateVirtioDevices,
2372451c4d8SAkira Moroo             4 => Debug,
23863637ebaSRob Bradford             _ => Unknown,
23963637ebaSRob Bradford         }
24063637ebaSRob Bradford     }
2414671a583SSamuel Ortiz }
2424671a583SSamuel Ortiz 
243909e1bc3SJinrong Liang enum SocketStream {
244909e1bc3SJinrong Liang     Unix(UnixStream),
245909e1bc3SJinrong Liang     Tcp(TcpStream),
246909e1bc3SJinrong Liang }
247909e1bc3SJinrong Liang 
248909e1bc3SJinrong Liang impl Read for SocketStream {
read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>249909e1bc3SJinrong Liang     fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
250909e1bc3SJinrong Liang         match self {
251909e1bc3SJinrong Liang             SocketStream::Unix(stream) => stream.read(buf),
252909e1bc3SJinrong Liang             SocketStream::Tcp(stream) => stream.read(buf),
253909e1bc3SJinrong Liang         }
254909e1bc3SJinrong Liang     }
255909e1bc3SJinrong Liang }
256909e1bc3SJinrong Liang 
257909e1bc3SJinrong Liang impl Write for SocketStream {
write(&mut self, buf: &[u8]) -> std::io::Result<usize>258909e1bc3SJinrong Liang     fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
259909e1bc3SJinrong Liang         match self {
260909e1bc3SJinrong Liang             SocketStream::Unix(stream) => stream.write(buf),
261909e1bc3SJinrong Liang             SocketStream::Tcp(stream) => stream.write(buf),
262909e1bc3SJinrong Liang         }
263909e1bc3SJinrong Liang     }
264909e1bc3SJinrong Liang 
flush(&mut self) -> std::io::Result<()>265909e1bc3SJinrong Liang     fn flush(&mut self) -> std::io::Result<()> {
266909e1bc3SJinrong Liang         match self {
267909e1bc3SJinrong Liang             SocketStream::Unix(stream) => stream.flush(),
268909e1bc3SJinrong Liang             SocketStream::Tcp(stream) => stream.flush(),
269909e1bc3SJinrong Liang         }
270909e1bc3SJinrong Liang     }
271909e1bc3SJinrong Liang }
272909e1bc3SJinrong Liang 
273909e1bc3SJinrong Liang impl AsRawFd for SocketStream {
as_raw_fd(&self) -> RawFd274909e1bc3SJinrong Liang     fn as_raw_fd(&self) -> RawFd {
275909e1bc3SJinrong Liang         match self {
276909e1bc3SJinrong Liang             SocketStream::Unix(s) => s.as_raw_fd(),
277909e1bc3SJinrong Liang             SocketStream::Tcp(s) => s.as_raw_fd(),
278909e1bc3SJinrong Liang         }
279909e1bc3SJinrong Liang     }
280909e1bc3SJinrong Liang }
281909e1bc3SJinrong Liang 
282909e1bc3SJinrong Liang impl ReadVolatile for SocketStream {
read_volatile<B: BitmapSlice>( &mut self, buf: &mut VolatileSlice<B>, ) -> std::result::Result<usize, VolatileMemoryError>283909e1bc3SJinrong Liang     fn read_volatile<B: BitmapSlice>(
284909e1bc3SJinrong Liang         &mut self,
285909e1bc3SJinrong Liang         buf: &mut VolatileSlice<B>,
286909e1bc3SJinrong Liang     ) -> std::result::Result<usize, VolatileMemoryError> {
287909e1bc3SJinrong Liang         match self {
288909e1bc3SJinrong Liang             SocketStream::Unix(s) => s.read_volatile(buf),
289909e1bc3SJinrong Liang             SocketStream::Tcp(s) => s.read_volatile(buf),
290909e1bc3SJinrong Liang         }
291909e1bc3SJinrong Liang     }
292909e1bc3SJinrong Liang 
read_exact_volatile<B: BitmapSlice>( &mut self, buf: &mut VolatileSlice<B>, ) -> std::result::Result<(), VolatileMemoryError>293909e1bc3SJinrong Liang     fn read_exact_volatile<B: BitmapSlice>(
294909e1bc3SJinrong Liang         &mut self,
295909e1bc3SJinrong Liang         buf: &mut VolatileSlice<B>,
296909e1bc3SJinrong Liang     ) -> std::result::Result<(), VolatileMemoryError> {
297909e1bc3SJinrong Liang         match self {
298909e1bc3SJinrong Liang             SocketStream::Unix(s) => s.read_exact_volatile(buf),
299909e1bc3SJinrong Liang             SocketStream::Tcp(s) => s.read_exact_volatile(buf),
300909e1bc3SJinrong Liang         }
301909e1bc3SJinrong Liang     }
302909e1bc3SJinrong Liang }
303909e1bc3SJinrong Liang 
304909e1bc3SJinrong Liang impl WriteVolatile for SocketStream {
write_volatile<B: BitmapSlice>( &mut self, buf: &VolatileSlice<B>, ) -> std::result::Result<usize, VolatileMemoryError>305909e1bc3SJinrong Liang     fn write_volatile<B: BitmapSlice>(
306909e1bc3SJinrong Liang         &mut self,
307909e1bc3SJinrong Liang         buf: &VolatileSlice<B>,
308909e1bc3SJinrong Liang     ) -> std::result::Result<usize, VolatileMemoryError> {
309909e1bc3SJinrong Liang         match self {
310909e1bc3SJinrong Liang             SocketStream::Unix(s) => s.write_volatile(buf),
311909e1bc3SJinrong Liang             SocketStream::Tcp(s) => s.write_volatile(buf),
312909e1bc3SJinrong Liang         }
313909e1bc3SJinrong Liang     }
314909e1bc3SJinrong Liang 
write_all_volatile<B: BitmapSlice>( &mut self, buf: &VolatileSlice<B>, ) -> std::result::Result<(), VolatileMemoryError>315909e1bc3SJinrong Liang     fn write_all_volatile<B: BitmapSlice>(
316909e1bc3SJinrong Liang         &mut self,
317909e1bc3SJinrong Liang         buf: &VolatileSlice<B>,
318909e1bc3SJinrong Liang     ) -> std::result::Result<(), VolatileMemoryError> {
319909e1bc3SJinrong Liang         match self {
320909e1bc3SJinrong Liang             SocketStream::Unix(s) => s.write_all_volatile(buf),
321909e1bc3SJinrong Liang             SocketStream::Tcp(s) => s.write_all_volatile(buf),
322909e1bc3SJinrong Liang         }
323909e1bc3SJinrong Liang     }
324909e1bc3SJinrong Liang }
325909e1bc3SJinrong Liang 
3264671a583SSamuel Ortiz pub struct EpollContext {
3277c3e19c6SBo Chen     epoll_file: File,
3284671a583SSamuel Ortiz }
3294671a583SSamuel Ortiz 
3304671a583SSamuel Ortiz impl EpollContext {
new() -> result::Result<EpollContext, io::Error>3314671a583SSamuel Ortiz     pub fn new() -> result::Result<EpollContext, io::Error> {
3327c3e19c6SBo Chen         let epoll_fd = epoll::create(true)?;
3337c3e19c6SBo Chen         // Use 'File' to enforce closing on 'epoll_fd'
334ff0e92abSWei Liu         // SAFETY: the epoll_fd returned by epoll::create is valid and owned by us.
3357c3e19c6SBo Chen         let epoll_file = unsafe { File::from_raw_fd(epoll_fd) };
3364671a583SSamuel Ortiz 
33763637ebaSRob Bradford         Ok(EpollContext { epoll_file })
3384671a583SSamuel Ortiz     }
3394671a583SSamuel Ortiz 
add_event<T>(&mut self, fd: &T, token: EpollDispatch) -> result::Result<(), io::Error> where T: AsRawFd,340eb056d37SBo Chen     pub fn add_event<T>(&mut self, fd: &T, token: EpollDispatch) -> result::Result<(), io::Error>
3414671a583SSamuel Ortiz     where
3424671a583SSamuel Ortiz         T: AsRawFd,
3434671a583SSamuel Ortiz     {
34463637ebaSRob Bradford         let dispatch_index = token as u64;
3454671a583SSamuel Ortiz         epoll::ctl(
3467c3e19c6SBo Chen             self.epoll_file.as_raw_fd(),
3474671a583SSamuel Ortiz             epoll::ControlOptions::EPOLL_CTL_ADD,
3484671a583SSamuel Ortiz             fd.as_raw_fd(),
3494671a583SSamuel Ortiz             epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index),
3504671a583SSamuel Ortiz         )?;
3514671a583SSamuel Ortiz 
3524671a583SSamuel Ortiz         Ok(())
3534671a583SSamuel Ortiz     }
354ec94ae31SBo Chen 
355ec94ae31SBo Chen     #[cfg(fuzzing)]
add_event_custom<T>( &mut self, fd: &T, id: u64, evts: epoll::Events, ) -> result::Result<(), io::Error> where T: AsRawFd,356ec94ae31SBo Chen     pub fn add_event_custom<T>(
357ec94ae31SBo Chen         &mut self,
358ec94ae31SBo Chen         fd: &T,
359ec94ae31SBo Chen         id: u64,
360ec94ae31SBo Chen         evts: epoll::Events,
361ec94ae31SBo Chen     ) -> result::Result<(), io::Error>
362ec94ae31SBo Chen     where
363ec94ae31SBo Chen         T: AsRawFd,
364ec94ae31SBo Chen     {
365ec94ae31SBo Chen         epoll::ctl(
366ec94ae31SBo Chen             self.epoll_file.as_raw_fd(),
367ec94ae31SBo Chen             epoll::ControlOptions::EPOLL_CTL_ADD,
368ec94ae31SBo Chen             fd.as_raw_fd(),
369ec94ae31SBo Chen             epoll::Event::new(evts, id),
370ec94ae31SBo Chen         )?;
371ec94ae31SBo Chen 
372ec94ae31SBo Chen         Ok(())
373ec94ae31SBo Chen     }
3744671a583SSamuel Ortiz }
3754671a583SSamuel Ortiz 
3764671a583SSamuel Ortiz impl AsRawFd for EpollContext {
as_raw_fd(&self) -> RawFd3774671a583SSamuel Ortiz     fn as_raw_fd(&self) -> RawFd {
3787c3e19c6SBo Chen         self.epoll_file.as_raw_fd()
3794671a583SSamuel Ortiz     }
3804671a583SSamuel Ortiz }
3814671a583SSamuel Ortiz 
382f08e9b6aSSebastien Boeuf pub struct PciDeviceInfo {
383f08e9b6aSSebastien Boeuf     pub id: String,
384ae83e3b3SRob Bradford     pub bdf: PciBdf,
385f08e9b6aSSebastien Boeuf }
386f08e9b6aSSebastien Boeuf 
3874fe7347fSSebastien Boeuf impl Serialize for PciDeviceInfo {
serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> where S: Serializer,3884fe7347fSSebastien Boeuf     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
3894fe7347fSSebastien Boeuf     where
3904fe7347fSSebastien Boeuf         S: Serializer,
3914fe7347fSSebastien Boeuf     {
392ae83e3b3SRob Bradford         let bdf_str = self.bdf.to_string();
3934fe7347fSSebastien Boeuf 
3944fe7347fSSebastien Boeuf         // Serialize the structure.
3954fe7347fSSebastien Boeuf         let mut state = serializer.serialize_struct("PciDeviceInfo", 2)?;
3964fe7347fSSebastien Boeuf         state.serialize_field("id", &self.id)?;
3974fe7347fSSebastien Boeuf         state.serialize_field("bdf", &bdf_str)?;
3984fe7347fSSebastien Boeuf         state.end()
3994fe7347fSSebastien Boeuf     }
4004fe7347fSSebastien Boeuf }
4014fe7347fSSebastien Boeuf 
feature_list() -> Vec<String>402ff651e0eSBo Chen pub fn feature_list() -> Vec<String> {
403ff651e0eSBo Chen     vec![
404ff651e0eSBo Chen         #[cfg(feature = "dbus_api")]
405ff651e0eSBo Chen         "dbus_api".to_string(),
406ff651e0eSBo Chen         #[cfg(feature = "dhat-heap")]
407ff651e0eSBo Chen         "dhat-heap".to_string(),
408ff651e0eSBo Chen         #[cfg(feature = "guest_debug")]
409ff651e0eSBo Chen         "guest_debug".to_string(),
41013ef424bSMuminul Islam         #[cfg(feature = "igvm")]
41113ef424bSMuminul Islam         "igvm".to_string(),
412ff651e0eSBo Chen         #[cfg(feature = "io_uring")]
413ff651e0eSBo Chen         "io_uring".to_string(),
414ff651e0eSBo Chen         #[cfg(feature = "kvm")]
415ff651e0eSBo Chen         "kvm".to_string(),
416ff651e0eSBo Chen         #[cfg(feature = "mshv")]
417ff651e0eSBo Chen         "mshv".to_string(),
418ff651e0eSBo Chen         #[cfg(feature = "sev_snp")]
419ff651e0eSBo Chen         "sev_snp".to_string(),
420ff651e0eSBo Chen         #[cfg(feature = "tdx")]
421ff651e0eSBo Chen         "tdx".to_string(),
422ff651e0eSBo Chen         #[cfg(feature = "tracing")]
423ff651e0eSBo Chen         "tracing".to_string(),
424ff651e0eSBo Chen     ]
425ff651e0eSBo Chen }
426ff651e0eSBo Chen 
start_event_monitor_thread( mut monitor: event_monitor::Monitor, seccomp_action: &SeccompAction, landlock_enable: bool, hypervisor_type: hypervisor::HypervisorType, exit_event: EventFd, ) -> Result<thread::JoinHandle<Result<()>>>42702e1c544SOmer Faruk Bayram pub fn start_event_monitor_thread(
42802e1c544SOmer Faruk Bayram     mut monitor: event_monitor::Monitor,
429a0c8bf4fSOmer Faruk Bayram     seccomp_action: &SeccompAction,
4308c76a3e4SPraveen K Paladugu     landlock_enable: bool,
431a0c8bf4fSOmer Faruk Bayram     hypervisor_type: hypervisor::HypervisorType,
43202e1c544SOmer Faruk Bayram     exit_event: EventFd,
433a0c8bf4fSOmer Faruk Bayram ) -> Result<thread::JoinHandle<Result<()>>> {
434a0c8bf4fSOmer Faruk Bayram     // Retrieve seccomp filter
435a0c8bf4fSOmer Faruk Bayram     let seccomp_filter = get_seccomp_filter(seccomp_action, Thread::EventMonitor, hypervisor_type)
436a0c8bf4fSOmer Faruk Bayram         .map_err(Error::CreateSeccompFilter)?;
437a0c8bf4fSOmer Faruk Bayram 
43802e1c544SOmer Faruk Bayram     thread::Builder::new()
43902e1c544SOmer Faruk Bayram         .name("event-monitor".to_owned())
44002e1c544SOmer Faruk Bayram         .spawn(move || {
441a0c8bf4fSOmer Faruk Bayram             // Apply seccomp filter
442a0c8bf4fSOmer Faruk Bayram             if !seccomp_filter.is_empty() {
443a0c8bf4fSOmer Faruk Bayram                 apply_filter(&seccomp_filter)
444a0c8bf4fSOmer Faruk Bayram                     .map_err(Error::ApplySeccompFilter)
445a0c8bf4fSOmer Faruk Bayram                     .map_err(|e| {
446a0c8bf4fSOmer Faruk Bayram                         error!("Error applying seccomp filter: {:?}", e);
447a0c8bf4fSOmer Faruk Bayram                         exit_event.write(1).ok();
448a0c8bf4fSOmer Faruk Bayram                         e
449a0c8bf4fSOmer Faruk Bayram                     })?;
450a0c8bf4fSOmer Faruk Bayram             }
4518c76a3e4SPraveen K Paladugu             if landlock_enable {
4528c76a3e4SPraveen K Paladugu                 Landlock::new()
4538c76a3e4SPraveen K Paladugu                     .map_err(Error::CreateLandlock)?
4548c76a3e4SPraveen K Paladugu                     .restrict_self()
4558c76a3e4SPraveen K Paladugu                     .map_err(Error::ApplyLandlock)
4568c76a3e4SPraveen K Paladugu                     .map_err(|e| {
4578c76a3e4SPraveen K Paladugu                         error!("Error applying landlock to event monitor thread: {:?}", e);
4588c76a3e4SPraveen K Paladugu                         exit_event.write(1).ok();
4598c76a3e4SPraveen K Paladugu                         e
4608c76a3e4SPraveen K Paladugu                     })?;
4618c76a3e4SPraveen K Paladugu             }
462a0c8bf4fSOmer Faruk Bayram 
46302e1c544SOmer Faruk Bayram             std::panic::catch_unwind(AssertUnwindSafe(move || {
46402e1c544SOmer Faruk Bayram                 while let Ok(event) = monitor.rx.recv() {
465e02efe9bSOmer Faruk Bayram                     let event = Arc::new(event);
466e02efe9bSOmer Faruk Bayram 
4672ed96cd3SOmer Faruk Bayram                     if let Some(ref mut file) = monitor.file {
4682ed96cd3SOmer Faruk Bayram                         file.write_all(event.as_bytes().as_ref()).ok();
4692ed96cd3SOmer Faruk Bayram                         file.write_all(b"\n\n").ok();
4702ed96cd3SOmer Faruk Bayram                     }
471e02efe9bSOmer Faruk Bayram 
472e02efe9bSOmer Faruk Bayram                     for tx in monitor.broadcast.iter() {
473e02efe9bSOmer Faruk Bayram                         tx.send(event.clone()).ok();
474e02efe9bSOmer Faruk Bayram                     }
47502e1c544SOmer Faruk Bayram                 }
47602e1c544SOmer Faruk Bayram             }))
47702e1c544SOmer Faruk Bayram             .map_err(|_| {
47802e1c544SOmer Faruk Bayram                 error!("`event-monitor` thread panicked");
47902e1c544SOmer Faruk Bayram                 exit_event.write(1).ok();
48002e1c544SOmer Faruk Bayram             })
481a0c8bf4fSOmer Faruk Bayram             .ok();
482a0c8bf4fSOmer Faruk Bayram 
483a0c8bf4fSOmer Faruk Bayram             Ok(())
48402e1c544SOmer Faruk Bayram         })
48502e1c544SOmer Faruk Bayram         .map_err(Error::EventMonitorThreadSpawn)
48602e1c544SOmer Faruk Bayram }
48702e1c544SOmer Faruk Bayram 
4882451c4d8SAkira Moroo #[allow(unused_variables)]
489767b4f0eSWilliam Douglas #[allow(clippy::too_many_arguments)]
start_vmm_thread( vmm_version: VmmVersionInfo, http_path: &Option<String>, http_fd: Option<RawFd>, #[cfg(feature = "dbus_api")] dbus_options: Option<DBusApiOptions>, api_event: EventFd, api_sender: Sender<ApiRequest>, api_receiver: Receiver<ApiRequest>, #[cfg(feature = "guest_debug")] debug_path: Option<PathBuf>, #[cfg(feature = "guest_debug")] debug_event: EventFd, #[cfg(feature = "guest_debug")] vm_debug_event: EventFd, exit_event: EventFd, seccomp_action: &SeccompAction, hypervisor: Arc<dyn hypervisor::Hypervisor>, landlock_enable: bool, ) -> Result<VmmThreadHandle>490151f96e4SSamuel Ortiz pub fn start_vmm_thread(
491346ee09eSOmer Faruk Bayram     vmm_version: VmmVersionInfo,
4929b0996a7SRob Bradford     http_path: &Option<String>,
493767b4f0eSWilliam Douglas     http_fd: Option<RawFd>,
4947a458d85SOmer Faruk Bayram     #[cfg(feature = "dbus_api")] dbus_options: Option<DBusApiOptions>,
495151f96e4SSamuel Ortiz     api_event: EventFd,
496aa317487SSamuel Ortiz     api_sender: Sender<ApiRequest>,
497151f96e4SSamuel Ortiz     api_receiver: Receiver<ApiRequest>,
49806eb82d2SRob Bradford     #[cfg(feature = "guest_debug")] debug_path: Option<PathBuf>,
49906eb82d2SRob Bradford     #[cfg(feature = "guest_debug")] debug_event: EventFd,
50006eb82d2SRob Bradford     #[cfg(feature = "guest_debug")] vm_debug_event: EventFd,
50121d40d74SAlyssa Ross     exit_event: EventFd,
502b41884a4SBo Chen     seccomp_action: &SeccompAction,
503e4dee57eSMuminul Islam     hypervisor: Arc<dyn hypervisor::Hypervisor>,
504130c9883SPraveen K Paladugu     landlock_enable: bool,
505f00df25dSOmer Faruk Bayram ) -> Result<VmmThreadHandle> {
50606eb82d2SRob Bradford     #[cfg(feature = "guest_debug")]
507d66d64c3SMichael Zhao     let gdb_hw_breakpoints = hypervisor.get_guest_debug_hw_bps();
50806eb82d2SRob Bradford     #[cfg(feature = "guest_debug")]
5092451c4d8SAkira Moroo     let (gdb_sender, gdb_receiver) = std::sync::mpsc::channel();
51006eb82d2SRob Bradford     #[cfg(feature = "guest_debug")]
5112451c4d8SAkira Moroo     let gdb_debug_event = debug_event.try_clone().map_err(Error::EventFdClone)?;
51206eb82d2SRob Bradford     #[cfg(feature = "guest_debug")]
5132451c4d8SAkira Moroo     let gdb_vm_debug_event = vm_debug_event.try_clone().map_err(Error::EventFdClone)?;
5142451c4d8SAkira Moroo 
515c016a0d4SOmer Faruk Bayram     let api_event_clone = api_event.try_clone().map_err(Error::EventFdClone)?;
516ad33f7c5SWei Liu     let hypervisor_type = hypervisor.hypervisor_type();
517aa317487SSamuel Ortiz 
518db62cb3fSSebastien Boeuf     // Retrieve seccomp filter
519ad33f7c5SWei Liu     let vmm_seccomp_filter = get_seccomp_filter(seccomp_action, Thread::Vmm, hypervisor_type)
520ad33f7c5SWei Liu         .map_err(Error::CreateSeccompFilter)?;
521db62cb3fSSebastien Boeuf 
522ff7ed8f6SBo Chen     let vmm_seccomp_action = seccomp_action.clone();
523b6b686c7SRob Bradford     let thread = {
52421d40d74SAlyssa Ross         let exit_event = exit_event.try_clone().map_err(Error::EventFdClone)?;
525b6b686c7SRob Bradford         thread::Builder::new()
526151f96e4SSamuel Ortiz             .name("vmm".to_string())
527151f96e4SSamuel Ortiz             .spawn(move || {
528db62cb3fSSebastien Boeuf                 // Apply seccomp filter for VMM thread.
5297d38a184SBo Chen                 if !vmm_seccomp_filter.is_empty() {
53008ac3405SBo Chen                     apply_filter(&vmm_seccomp_filter).map_err(Error::ApplySeccompFilter)?;
5317d38a184SBo Chen                 }
532db62cb3fSSebastien Boeuf 
533ff7ed8f6SBo Chen                 let mut vmm = Vmm::new(
534346ee09eSOmer Faruk Bayram                     vmm_version,
535ff7ed8f6SBo Chen                     api_event,
53606eb82d2SRob Bradford                     #[cfg(feature = "guest_debug")]
5372451c4d8SAkira Moroo                     debug_event,
53806eb82d2SRob Bradford                     #[cfg(feature = "guest_debug")]
5392451c4d8SAkira Moroo                     vm_debug_event,
540ff7ed8f6SBo Chen                     vmm_seccomp_action,
541ff7ed8f6SBo Chen                     hypervisor,
54221d40d74SAlyssa Ross                     exit_event,
543ff7ed8f6SBo Chen                 )?;
544151f96e4SSamuel Ortiz 
545130c9883SPraveen K Paladugu                 vmm.setup_signal_handler(landlock_enable)?;
546121729a3SRob Bradford 
5472451c4d8SAkira Moroo                 vmm.control_loop(
54863226e2bSYu Li                     Rc::new(api_receiver),
54906eb82d2SRob Bradford                     #[cfg(feature = "guest_debug")]
55063226e2bSYu Li                     Rc::new(gdb_receiver),
5512451c4d8SAkira Moroo                 )
552151f96e4SSamuel Ortiz             })
553b6b686c7SRob Bradford             .map_err(Error::VmmThreadSpawn)?
554b6b686c7SRob Bradford     };
555aa317487SSamuel Ortiz 
556c016a0d4SOmer Faruk Bayram     // The VMM thread is started, we can start the dbus thread
557c016a0d4SOmer Faruk Bayram     // and start serving HTTP requests
558c016a0d4SOmer Faruk Bayram     #[cfg(feature = "dbus_api")]
5597a458d85SOmer Faruk Bayram     let dbus_shutdown_chs = match dbus_options {
5607a458d85SOmer Faruk Bayram         Some(opts) => {
5617a458d85SOmer Faruk Bayram             let (_, chs) = api::start_dbus_thread(
5627a458d85SOmer Faruk Bayram                 opts,
563c016a0d4SOmer Faruk Bayram                 api_event_clone.try_clone().map_err(Error::EventFdClone)?,
564c016a0d4SOmer Faruk Bayram                 api_sender.clone(),
565c016a0d4SOmer Faruk Bayram                 seccomp_action,
566c016a0d4SOmer Faruk Bayram                 exit_event.try_clone().map_err(Error::EventFdClone)?,
567c016a0d4SOmer Faruk Bayram                 hypervisor_type,
568c016a0d4SOmer Faruk Bayram             )?;
5697a458d85SOmer Faruk Bayram             Some(chs)
5707a458d85SOmer Faruk Bayram         }
5717a458d85SOmer Faruk Bayram         None => None,
5727a458d85SOmer Faruk Bayram     };
573c016a0d4SOmer Faruk Bayram 
57410914943SAlexandru Matei     let http_api_handle = if let Some(http_path) = http_path {
57510914943SAlexandru Matei         Some(api::start_http_path_thread(
576b6b686c7SRob Bradford             http_path,
577c016a0d4SOmer Faruk Bayram             api_event_clone,
578b6b686c7SRob Bradford             api_sender,
579b6b686c7SRob Bradford             seccomp_action,
58021d40d74SAlyssa Ross             exit_event,
581ad33f7c5SWei Liu             hypervisor_type,
5821dd53c3dSPraveen K Paladugu             landlock_enable,
58310914943SAlexandru Matei         )?)
584767b4f0eSWilliam Douglas     } else if let Some(http_fd) = http_fd {
58510914943SAlexandru Matei         Some(api::start_http_fd_thread(
586b6b686c7SRob Bradford             http_fd,
587c016a0d4SOmer Faruk Bayram             api_event_clone,
588b6b686c7SRob Bradford             api_sender,
589b6b686c7SRob Bradford             seccomp_action,
59021d40d74SAlyssa Ross             exit_event,
591ad33f7c5SWei Liu             hypervisor_type,
5921dd53c3dSPraveen K Paladugu             landlock_enable,
59310914943SAlexandru Matei         )?)
59410914943SAlexandru Matei     } else {
59510914943SAlexandru Matei         None
59610914943SAlexandru Matei     };
5972451c4d8SAkira Moroo 
59806eb82d2SRob Bradford     #[cfg(feature = "guest_debug")]
5992451c4d8SAkira Moroo     if let Some(debug_path) = debug_path {
600d66d64c3SMichael Zhao         let target = gdb::GdbStub::new(
601d66d64c3SMichael Zhao             gdb_sender,
602d66d64c3SMichael Zhao             gdb_debug_event,
603d66d64c3SMichael Zhao             gdb_vm_debug_event,
604d66d64c3SMichael Zhao             gdb_hw_breakpoints,
605d66d64c3SMichael Zhao         );
6062451c4d8SAkira Moroo         thread::Builder::new()
6072451c4d8SAkira Moroo             .name("gdb".to_owned())
6082451c4d8SAkira Moroo             .spawn(move || gdb::gdb_thread(target, &debug_path))
6092451c4d8SAkira Moroo             .map_err(Error::GdbThreadSpawn)?;
6102451c4d8SAkira Moroo     }
6112451c4d8SAkira Moroo 
612f00df25dSOmer Faruk Bayram     Ok(VmmThreadHandle {
613f00df25dSOmer Faruk Bayram         thread_handle: thread,
614f00df25dSOmer Faruk Bayram         #[cfg(feature = "dbus_api")]
615f00df25dSOmer Faruk Bayram         dbus_shutdown_chs,
61610914943SAlexandru Matei         http_api_handle,
617f00df25dSOmer Faruk Bayram     })
618151f96e4SSamuel Ortiz }
619151f96e4SSamuel Ortiz 
6206d9c1eb6SBo Chen #[derive(Clone, Deserialize, Serialize)]
6216d9c1eb6SBo Chen struct VmMigrationConfig {
6226d9c1eb6SBo Chen     vm_config: Arc<Mutex<VmConfig>>,
6236d9c1eb6SBo Chen     #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
62408135fa0SWei Liu     common_cpuid: Vec<hypervisor::arch::x86::CpuIdEntry>,
62558d8206eSSebastien Boeuf     memory_manager_data: MemoryManagerSnapshotData,
6266d9c1eb6SBo Chen }
6276d9c1eb6SBo Chen 
628346ee09eSOmer Faruk Bayram #[derive(Debug, Clone)]
629346ee09eSOmer Faruk Bayram pub struct VmmVersionInfo {
630346ee09eSOmer Faruk Bayram     pub build_version: String,
631346ee09eSOmer Faruk Bayram     pub version: String,
632346ee09eSOmer Faruk Bayram }
633346ee09eSOmer Faruk Bayram 
634346ee09eSOmer Faruk Bayram impl VmmVersionInfo {
new(build_version: &str, version: &str) -> Self635346ee09eSOmer Faruk Bayram     pub fn new(build_version: &str, version: &str) -> Self {
636346ee09eSOmer Faruk Bayram         Self {
637346ee09eSOmer Faruk Bayram             build_version: build_version.to_owned(),
638346ee09eSOmer Faruk Bayram             version: version.to_owned(),
639346ee09eSOmer Faruk Bayram         }
640346ee09eSOmer Faruk Bayram     }
641346ee09eSOmer Faruk Bayram }
642346ee09eSOmer Faruk Bayram 
643f00df25dSOmer Faruk Bayram pub struct VmmThreadHandle {
644f00df25dSOmer Faruk Bayram     pub thread_handle: thread::JoinHandle<Result<()>>,
645f00df25dSOmer Faruk Bayram     #[cfg(feature = "dbus_api")]
6467a458d85SOmer Faruk Bayram     pub dbus_shutdown_chs: Option<DBusApiShutdownChannels>,
64710914943SAlexandru Matei     pub http_api_handle: Option<HttpApiHandle>,
648f00df25dSOmer Faruk Bayram }
649f00df25dSOmer Faruk Bayram 
6502f1ff230SSamuel Ortiz pub struct Vmm {
6512f1ff230SSamuel Ortiz     epoll: EpollContext,
6522f1ff230SSamuel Ortiz     exit_evt: EventFd,
6532f1ff230SSamuel Ortiz     reset_evt: EventFd,
6542f1ff230SSamuel Ortiz     api_evt: EventFd,
65506eb82d2SRob Bradford     #[cfg(feature = "guest_debug")]
6562451c4d8SAkira Moroo     debug_evt: EventFd,
65706eb82d2SRob Bradford     #[cfg(feature = "guest_debug")]
6582451c4d8SAkira Moroo     vm_debug_evt: EventFd,
659346ee09eSOmer Faruk Bayram     version: VmmVersionInfo,
6602f1ff230SSamuel Ortiz     vm: Option<Vm>,
66117227086SRob Bradford     vm_config: Option<Arc<Mutex<VmConfig>>>,
662ff7ed8f6SBo Chen     seccomp_action: SeccompAction,
663e4dee57eSMuminul Islam     hypervisor: Arc<dyn hypervisor::Hypervisor>,
66403db4830SRob Bradford     activate_evt: EventFd,
665121729a3SRob Bradford     signals: Option<Handle>,
666121729a3SRob Bradford     threads: Vec<thread::JoinHandle<()>>,
667c90a0fffSAlyssa Ross     original_termios_opt: Arc<Mutex<Option<termios>>>,
6684bfeba96SAlyssa Ross     console_resize_pipe: Option<Arc<File>>,
669380ba564SPraveen K Paladugu     console_info: Option<ConsoleInfo>,
6702f1ff230SSamuel Ortiz }
6712f1ff230SSamuel Ortiz 
6722f1ff230SSamuel Ortiz impl Vmm {
673121729a3SRob Bradford     pub const HANDLED_SIGNALS: [i32; 2] = [SIGTERM, SIGINT];
674121729a3SRob Bradford 
signal_handler( mut signals: Signals, original_termios_opt: Arc<Mutex<Option<termios>>>, exit_evt: &EventFd, )675c90a0fffSAlyssa Ross     fn signal_handler(
676c90a0fffSAlyssa Ross         mut signals: Signals,
677c90a0fffSAlyssa Ross         original_termios_opt: Arc<Mutex<Option<termios>>>,
678c90a0fffSAlyssa Ross         exit_evt: &EventFd,
679c90a0fffSAlyssa Ross     ) {
680121729a3SRob Bradford         for sig in &Self::HANDLED_SIGNALS {
681121729a3SRob Bradford             unblock_signal(*sig).unwrap();
682121729a3SRob Bradford         }
683121729a3SRob Bradford 
684121729a3SRob Bradford         for signal in signals.forever() {
685121729a3SRob Bradford             match signal {
686121729a3SRob Bradford                 SIGTERM | SIGINT => {
687121729a3SRob Bradford                     if exit_evt.write(1).is_err() {
688121729a3SRob Bradford                         // Resetting the terminal is usually done as the VMM exits
689c90a0fffSAlyssa Ross                         if let Ok(lock) = original_termios_opt.lock() {
690c90a0fffSAlyssa Ross                             if let Some(termios) = *lock {
691c90a0fffSAlyssa Ross                                 // SAFETY: FFI call
692c90a0fffSAlyssa Ross                                 let _ = unsafe {
693c90a0fffSAlyssa Ross                                     tcsetattr(stdout().lock().as_raw_fd(), TCSANOW, &termios)
694c90a0fffSAlyssa Ross                                 };
695121729a3SRob Bradford                             }
696c90a0fffSAlyssa Ross                         } else {
697c90a0fffSAlyssa Ross                             warn!("Failed to lock original termios");
698c90a0fffSAlyssa Ross                         }
699c90a0fffSAlyssa Ross 
700121729a3SRob Bradford                         std::process::exit(1);
701121729a3SRob Bradford                     }
702121729a3SRob Bradford                 }
703121729a3SRob Bradford                 _ => (),
704121729a3SRob Bradford             }
705121729a3SRob Bradford         }
706121729a3SRob Bradford     }
707121729a3SRob Bradford 
setup_signal_handler(&mut self, landlock_enable: bool) -> Result<()>708130c9883SPraveen K Paladugu     fn setup_signal_handler(&mut self, landlock_enable: bool) -> Result<()> {
709f32487f8SRob Bradford         let signals = Signals::new(Self::HANDLED_SIGNALS);
710121729a3SRob Bradford         match signals {
711121729a3SRob Bradford             Ok(signals) => {
712121729a3SRob Bradford                 self.signals = Some(signals.handle());
713121729a3SRob Bradford                 let exit_evt = self.exit_evt.try_clone().map_err(Error::EventFdClone)?;
714c90a0fffSAlyssa Ross                 let original_termios_opt = Arc::clone(&self.original_termios_opt);
715121729a3SRob Bradford 
716ad33f7c5SWei Liu                 let signal_handler_seccomp_filter = get_seccomp_filter(
717ad33f7c5SWei Liu                     &self.seccomp_action,
718ad33f7c5SWei Liu                     Thread::SignalHandler,
719ad33f7c5SWei Liu                     self.hypervisor.hypervisor_type(),
720ad33f7c5SWei Liu                 )
721121729a3SRob Bradford                 .map_err(Error::CreateSeccompFilter)?;
722121729a3SRob Bradford                 self.threads.push(
723121729a3SRob Bradford                     thread::Builder::new()
724121729a3SRob Bradford                         .name("vmm_signal_handler".to_string())
725121729a3SRob Bradford                         .spawn(move || {
726121729a3SRob Bradford                             if !signal_handler_seccomp_filter.is_empty() {
727121729a3SRob Bradford                                 if let Err(e) = apply_filter(&signal_handler_seccomp_filter)
728121729a3SRob Bradford                                     .map_err(Error::ApplySeccompFilter)
729121729a3SRob Bradford                                 {
730121729a3SRob Bradford                                     error!("Error applying seccomp filter: {:?}", e);
731121729a3SRob Bradford                                     exit_evt.write(1).ok();
732121729a3SRob Bradford                                     return;
733121729a3SRob Bradford                                 }
734121729a3SRob Bradford                             }
735130c9883SPraveen K Paladugu                             if landlock_enable{
736130c9883SPraveen K Paladugu                                 match Landlock::new() {
737130c9883SPraveen K Paladugu                                     Ok(landlock) => {
738130c9883SPraveen K Paladugu                                         let _ = landlock.restrict_self().map_err(Error::ApplyLandlock).map_err(|e| {
739130c9883SPraveen K Paladugu                                             error!("Error applying Landlock to signal handler thread: {:?}", e);
740130c9883SPraveen K Paladugu                                             exit_evt.write(1).ok();
741130c9883SPraveen K Paladugu                                         });
742130c9883SPraveen K Paladugu                                     }
743130c9883SPraveen K Paladugu                                     Err(e) => {
744130c9883SPraveen K Paladugu                                         error!("Error creating Landlock object: {:?}", e);
745130c9883SPraveen K Paladugu                                         exit_evt.write(1).ok();
746130c9883SPraveen K Paladugu                                     }
747130c9883SPraveen K Paladugu                                 };
748130c9883SPraveen K Paladugu                             }
749130c9883SPraveen K Paladugu 
750121729a3SRob Bradford                             std::panic::catch_unwind(AssertUnwindSafe(|| {
751c90a0fffSAlyssa Ross                                 Vmm::signal_handler(signals, original_termios_opt, &exit_evt);
752121729a3SRob Bradford                             }))
753121729a3SRob Bradford                             .map_err(|_| {
75434b31706SWei Liu                                 error!("vmm signal_handler thread panicked");
755121729a3SRob Bradford                                 exit_evt.write(1).ok()
756121729a3SRob Bradford                             })
757121729a3SRob Bradford                             .ok();
758121729a3SRob Bradford                         })
759121729a3SRob Bradford                         .map_err(Error::SignalHandlerSpawn)?,
760121729a3SRob Bradford                 );
761121729a3SRob Bradford             }
762121729a3SRob Bradford             Err(e) => error!("Signal not found {}", e),
763121729a3SRob Bradford         }
764121729a3SRob Bradford         Ok(())
765121729a3SRob Bradford     }
766121729a3SRob Bradford 
767249e362cSPraveen K Paladugu     #[allow(clippy::too_many_arguments)]
new( vmm_version: VmmVersionInfo, api_evt: EventFd, #[cfg(feature = "guest_debug")] debug_evt: EventFd, #[cfg(feature = "guest_debug")] vm_debug_evt: EventFd, seccomp_action: SeccompAction, hypervisor: Arc<dyn hypervisor::Hypervisor>, exit_evt: EventFd, ) -> Result<Self>768e4dee57eSMuminul Islam     fn new(
769346ee09eSOmer Faruk Bayram         vmm_version: VmmVersionInfo,
770e4dee57eSMuminul Islam         api_evt: EventFd,
77106eb82d2SRob Bradford         #[cfg(feature = "guest_debug")] debug_evt: EventFd,
77206eb82d2SRob Bradford         #[cfg(feature = "guest_debug")] vm_debug_evt: EventFd,
773ff7ed8f6SBo Chen         seccomp_action: SeccompAction,
774e4dee57eSMuminul Islam         hypervisor: Arc<dyn hypervisor::Hypervisor>,
775b6b686c7SRob Bradford         exit_evt: EventFd,
776e4dee57eSMuminul Islam     ) -> Result<Self> {
7772f1ff230SSamuel Ortiz         let mut epoll = EpollContext::new().map_err(Error::Epoll)?;
7782f1ff230SSamuel Ortiz         let reset_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
77903db4830SRob Bradford         let activate_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
7802f1ff230SSamuel Ortiz 
7812f1ff230SSamuel Ortiz         epoll
7822f1ff230SSamuel Ortiz             .add_event(&exit_evt, EpollDispatch::Exit)
7832f1ff230SSamuel Ortiz             .map_err(Error::Epoll)?;
7842f1ff230SSamuel Ortiz 
7852f1ff230SSamuel Ortiz         epoll
7862f1ff230SSamuel Ortiz             .add_event(&reset_evt, EpollDispatch::Reset)
7872f1ff230SSamuel Ortiz             .map_err(Error::Epoll)?;
7882f1ff230SSamuel Ortiz 
7892f1ff230SSamuel Ortiz         epoll
79003db4830SRob Bradford             .add_event(&activate_evt, EpollDispatch::ActivateVirtioDevices)
79103db4830SRob Bradford             .map_err(Error::Epoll)?;
79203db4830SRob Bradford 
79303db4830SRob Bradford         epoll
7942f1ff230SSamuel Ortiz             .add_event(&api_evt, EpollDispatch::Api)
7952f1ff230SSamuel Ortiz             .map_err(Error::Epoll)?;
7962f1ff230SSamuel Ortiz 
79706eb82d2SRob Bradford         #[cfg(feature = "guest_debug")]
7982451c4d8SAkira Moroo         epoll
7992451c4d8SAkira Moroo             .add_event(&debug_evt, EpollDispatch::Debug)
8002451c4d8SAkira Moroo             .map_err(Error::Epoll)?;
8012451c4d8SAkira Moroo 
8022f1ff230SSamuel Ortiz         Ok(Vmm {
8032f1ff230SSamuel Ortiz             epoll,
8042f1ff230SSamuel Ortiz             exit_evt,
8052f1ff230SSamuel Ortiz             reset_evt,
8062f1ff230SSamuel Ortiz             api_evt,
80706eb82d2SRob Bradford             #[cfg(feature = "guest_debug")]
8082451c4d8SAkira Moroo             debug_evt,
80906eb82d2SRob Bradford             #[cfg(feature = "guest_debug")]
8102451c4d8SAkira Moroo             vm_debug_evt,
8111d852e9cSJose Carlos Venegas Munoz             version: vmm_version,
8122f1ff230SSamuel Ortiz             vm: None,
8137e0cb078SSamuel Ortiz             vm_config: None,
814ff7ed8f6SBo Chen             seccomp_action,
815e4dee57eSMuminul Islam             hypervisor,
81603db4830SRob Bradford             activate_evt,
817121729a3SRob Bradford             signals: None,
818121729a3SRob Bradford             threads: vec![],
819c90a0fffSAlyssa Ross             original_termios_opt: Arc::new(Mutex::new(None)),
820385f9a9aSPraveen K Paladugu             console_resize_pipe: None,
821380ba564SPraveen K Paladugu             console_info: None,
8222f1ff230SSamuel Ortiz         })
8232f1ff230SSamuel Ortiz     }
8242f1ff230SSamuel Ortiz 
vm_receive_config<T>( &mut self, req: &Request, socket: &mut T, existing_memory_files: Option<HashMap<u32, File>>, ) -> std::result::Result<Arc<Mutex<MemoryManager>>, MigratableError> where T: Read + Write,8254ca18c08SAlyssa Ross     fn vm_receive_config<T>(
8264ca18c08SAlyssa Ross         &mut self,
8274ca18c08SAlyssa Ross         req: &Request,
8284ca18c08SAlyssa Ross         socket: &mut T,
8294ca18c08SAlyssa Ross         existing_memory_files: Option<HashMap<u32, File>>,
8304ca18c08SAlyssa Ross     ) -> std::result::Result<Arc<Mutex<MemoryManager>>, MigratableError>
8314ca18c08SAlyssa Ross     where
8324ca18c08SAlyssa Ross         T: Read + Write,
8334ca18c08SAlyssa Ross     {
8344ca18c08SAlyssa Ross         // Read in config data along with memory manager data
8354ca18c08SAlyssa Ross         let mut data: Vec<u8> = Vec::new();
8364ca18c08SAlyssa Ross         data.resize_with(req.length() as usize, Default::default);
8374ca18c08SAlyssa Ross         socket
8384ca18c08SAlyssa Ross             .read_exact(&mut data)
8394ca18c08SAlyssa Ross             .map_err(MigratableError::MigrateSocket)?;
8404ca18c08SAlyssa Ross 
8414ca18c08SAlyssa Ross         let vm_migration_config: VmMigrationConfig =
8424ca18c08SAlyssa Ross             serde_json::from_slice(&data).map_err(|e| {
8434ca18c08SAlyssa Ross                 MigratableError::MigrateReceive(anyhow!("Error deserialising config: {}", e))
8444ca18c08SAlyssa Ross             })?;
8454ca18c08SAlyssa Ross 
8464ca18c08SAlyssa Ross         #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
8474ca18c08SAlyssa Ross         self.vm_check_cpuid_compatibility(
8484ca18c08SAlyssa Ross             &vm_migration_config.vm_config,
8494ca18c08SAlyssa Ross             &vm_migration_config.common_cpuid,
8504ca18c08SAlyssa Ross         )?;
8514ca18c08SAlyssa Ross 
8524ca18c08SAlyssa Ross         let config = vm_migration_config.vm_config.clone();
8534ca18c08SAlyssa Ross         self.vm_config = Some(vm_migration_config.vm_config);
854c3fcddf8SPraveen K Paladugu         self.console_info = Some(pre_create_console_devices(self).map_err(|e| {
855c3fcddf8SPraveen K Paladugu             MigratableError::MigrateReceive(anyhow!("Error creating console devices: {:?}", e))
856c3fcddf8SPraveen K Paladugu         })?);
8574ca18c08SAlyssa Ross 
858d2f0e8aeSPraveen K Paladugu         if self
859d2f0e8aeSPraveen K Paladugu             .vm_config
860d2f0e8aeSPraveen K Paladugu             .as_ref()
861d2f0e8aeSPraveen K Paladugu             .unwrap()
862d2f0e8aeSPraveen K Paladugu             .lock()
863d2f0e8aeSPraveen K Paladugu             .unwrap()
864d2f0e8aeSPraveen K Paladugu             .landlock_enable
865d2f0e8aeSPraveen K Paladugu         {
866d2f0e8aeSPraveen K Paladugu             apply_landlock(self.vm_config.as_ref().unwrap().clone()).map_err(|e| {
867457fd9efSPraveen K Paladugu                 MigratableError::MigrateReceive(anyhow!("Error applying landlock: {:?}", e))
868457fd9efSPraveen K Paladugu             })?;
869457fd9efSPraveen K Paladugu         }
870457fd9efSPraveen K Paladugu 
8714ca18c08SAlyssa Ross         let vm = Vm::create_hypervisor_vm(
8724ca18c08SAlyssa Ross             &self.hypervisor,
8734ca18c08SAlyssa Ross             #[cfg(feature = "tdx")]
8744ca18c08SAlyssa Ross             false,
8754ca18c08SAlyssa Ross             #[cfg(feature = "sev_snp")]
8764ca18c08SAlyssa Ross             false,
877149c3428SMuminul Islam             #[cfg(feature = "sev_snp")]
878149c3428SMuminul Islam             config.lock().unwrap().memory.total_size(),
8794ca18c08SAlyssa Ross         )
8804ca18c08SAlyssa Ross         .map_err(|e| {
8814ca18c08SAlyssa Ross             MigratableError::MigrateReceive(anyhow!(
8824ca18c08SAlyssa Ross                 "Error creating hypervisor VM from snapshot: {:?}",
8834ca18c08SAlyssa Ross                 e
8844ca18c08SAlyssa Ross             ))
8854ca18c08SAlyssa Ross         })?;
8864ca18c08SAlyssa Ross 
8874ca18c08SAlyssa Ross         let phys_bits =
8884ca18c08SAlyssa Ross             vm::physical_bits(&self.hypervisor, config.lock().unwrap().cpus.max_phys_bits);
8894ca18c08SAlyssa Ross 
8904ca18c08SAlyssa Ross         let memory_manager = MemoryManager::new(
8914ca18c08SAlyssa Ross             vm,
8924ca18c08SAlyssa Ross             &config.lock().unwrap().memory.clone(),
8934ca18c08SAlyssa Ross             None,
8944ca18c08SAlyssa Ross             phys_bits,
8954ca18c08SAlyssa Ross             #[cfg(feature = "tdx")]
8964ca18c08SAlyssa Ross             false,
8974ca18c08SAlyssa Ross             Some(&vm_migration_config.memory_manager_data),
8984ca18c08SAlyssa Ross             existing_memory_files,
8994ca18c08SAlyssa Ross             #[cfg(target_arch = "x86_64")]
9004ca18c08SAlyssa Ross             None,
9014ca18c08SAlyssa Ross         )
9024ca18c08SAlyssa Ross         .map_err(|e| {
9034ca18c08SAlyssa Ross             MigratableError::MigrateReceive(anyhow!(
9044ca18c08SAlyssa Ross                 "Error creating MemoryManager from snapshot: {:?}",
9054ca18c08SAlyssa Ross                 e
9064ca18c08SAlyssa Ross             ))
9074ca18c08SAlyssa Ross         })?;
9084ca18c08SAlyssa Ross 
9094ca18c08SAlyssa Ross         Response::ok().write_to(socket)?;
9104ca18c08SAlyssa Ross 
9114ca18c08SAlyssa Ross         Ok(memory_manager)
9124ca18c08SAlyssa Ross     }
9134ca18c08SAlyssa Ross 
vm_receive_state<T>( &mut self, req: &Request, socket: &mut T, mm: Arc<Mutex<MemoryManager>>, ) -> std::result::Result<(), MigratableError> where T: Read + Write,9144ca18c08SAlyssa Ross     fn vm_receive_state<T>(
9154ca18c08SAlyssa Ross         &mut self,
9164ca18c08SAlyssa Ross         req: &Request,
9174ca18c08SAlyssa Ross         socket: &mut T,
9184ca18c08SAlyssa Ross         mm: Arc<Mutex<MemoryManager>>,
9194ca18c08SAlyssa Ross     ) -> std::result::Result<(), MigratableError>
9204ca18c08SAlyssa Ross     where
9214ca18c08SAlyssa Ross         T: Read + Write,
9224ca18c08SAlyssa Ross     {
9234ca18c08SAlyssa Ross         // Read in state data
9244ca18c08SAlyssa Ross         let mut data: Vec<u8> = Vec::new();
9254ca18c08SAlyssa Ross         data.resize_with(req.length() as usize, Default::default);
9264ca18c08SAlyssa Ross         socket
9274ca18c08SAlyssa Ross             .read_exact(&mut data)
9284ca18c08SAlyssa Ross             .map_err(MigratableError::MigrateSocket)?;
9294ca18c08SAlyssa Ross         let snapshot: Snapshot = serde_json::from_slice(&data).map_err(|e| {
9304ca18c08SAlyssa Ross             MigratableError::MigrateReceive(anyhow!("Error deserialising snapshot: {}", e))
9314ca18c08SAlyssa Ross         })?;
9324ca18c08SAlyssa Ross 
9334ca18c08SAlyssa Ross         let exit_evt = self.exit_evt.try_clone().map_err(|e| {
9344ca18c08SAlyssa Ross             MigratableError::MigrateReceive(anyhow!("Error cloning exit EventFd: {}", e))
9354ca18c08SAlyssa Ross         })?;
9364ca18c08SAlyssa Ross         let reset_evt = self.reset_evt.try_clone().map_err(|e| {
9374ca18c08SAlyssa Ross             MigratableError::MigrateReceive(anyhow!("Error cloning reset EventFd: {}", e))
9384ca18c08SAlyssa Ross         })?;
9394ca18c08SAlyssa Ross         #[cfg(feature = "guest_debug")]
9404ca18c08SAlyssa Ross         let debug_evt = self.vm_debug_evt.try_clone().map_err(|e| {
9414ca18c08SAlyssa Ross             MigratableError::MigrateReceive(anyhow!("Error cloning debug EventFd: {}", e))
9424ca18c08SAlyssa Ross         })?;
9434ca18c08SAlyssa Ross         let activate_evt = self.activate_evt.try_clone().map_err(|e| {
9444ca18c08SAlyssa Ross             MigratableError::MigrateReceive(anyhow!("Error cloning activate EventFd: {}", e))
9454ca18c08SAlyssa Ross         })?;
9464ca18c08SAlyssa Ross 
947c99660a8SRuoqing He         #[cfg(not(target_arch = "riscv64"))]
9484ca18c08SAlyssa Ross         let timestamp = Instant::now();
9494ca18c08SAlyssa Ross         let hypervisor_vm = mm.lock().unwrap().vm.clone();
9504ca18c08SAlyssa Ross         let mut vm = Vm::new_from_memory_manager(
9514ca18c08SAlyssa Ross             self.vm_config.clone().unwrap(),
9524ca18c08SAlyssa Ross             mm,
9534ca18c08SAlyssa Ross             hypervisor_vm,
9544ca18c08SAlyssa Ross             exit_evt,
9554ca18c08SAlyssa Ross             reset_evt,
9564ca18c08SAlyssa Ross             #[cfg(feature = "guest_debug")]
9574ca18c08SAlyssa Ross             debug_evt,
9584ca18c08SAlyssa Ross             &self.seccomp_action,
9594ca18c08SAlyssa Ross             self.hypervisor.clone(),
9604ca18c08SAlyssa Ross             activate_evt,
961c99660a8SRuoqing He             #[cfg(not(target_arch = "riscv64"))]
9624ca18c08SAlyssa Ross             timestamp,
963c3fcddf8SPraveen K Paladugu             self.console_info.clone(),
964ab12e7c2SSongqian Li             self.console_resize_pipe.clone(),
9654ca18c08SAlyssa Ross             Arc::clone(&self.original_termios_opt),
9664ca18c08SAlyssa Ross             Some(snapshot),
9674ca18c08SAlyssa Ross         )
9684ca18c08SAlyssa Ross         .map_err(|e| {
9694ca18c08SAlyssa Ross             MigratableError::MigrateReceive(anyhow!("Error creating VM from snapshot: {:?}", e))
9704ca18c08SAlyssa Ross         })?;
9714ca18c08SAlyssa Ross 
9724ca18c08SAlyssa Ross         // Create VM
9734ca18c08SAlyssa Ross         vm.restore().map_err(|e| {
9744ca18c08SAlyssa Ross             Response::error().write_to(socket).ok();
9754ca18c08SAlyssa Ross             MigratableError::MigrateReceive(anyhow!("Failed restoring the Vm: {}", e))
9764ca18c08SAlyssa Ross         })?;
9774ca18c08SAlyssa Ross         self.vm = Some(vm);
9784ca18c08SAlyssa Ross 
9794ca18c08SAlyssa Ross         Response::ok().write_to(socket)?;
9804ca18c08SAlyssa Ross 
9814ca18c08SAlyssa Ross         Ok(())
9824ca18c08SAlyssa Ross     }
9834ca18c08SAlyssa Ross 
vm_receive_memory<T>( &mut self, req: &Request, socket: &mut T, memory_manager: &mut MemoryManager, ) -> std::result::Result<(), MigratableError> where T: Read + ReadVolatile + Write,9844ca18c08SAlyssa Ross     fn vm_receive_memory<T>(
9854ca18c08SAlyssa Ross         &mut self,
9864ca18c08SAlyssa Ross         req: &Request,
9874ca18c08SAlyssa Ross         socket: &mut T,
9884ca18c08SAlyssa Ross         memory_manager: &mut MemoryManager,
9894ca18c08SAlyssa Ross     ) -> std::result::Result<(), MigratableError>
9904ca18c08SAlyssa Ross     where
9914ca18c08SAlyssa Ross         T: Read + ReadVolatile + Write,
9924ca18c08SAlyssa Ross     {
9934ca18c08SAlyssa Ross         // Read table
9944ca18c08SAlyssa Ross         let table = MemoryRangeTable::read_from(socket, req.length())?;
9954ca18c08SAlyssa Ross 
9964ca18c08SAlyssa Ross         // And then read the memory itself
9974ca18c08SAlyssa Ross         memory_manager
9984ca18c08SAlyssa Ross             .receive_memory_regions(&table, socket)
999bd8c28d3SWei Liu             .inspect_err(|_| {
10004ca18c08SAlyssa Ross                 Response::error().write_to(socket).ok();
10014ca18c08SAlyssa Ross             })?;
10024ca18c08SAlyssa Ross         Response::ok().write_to(socket)?;
10034ca18c08SAlyssa Ross         Ok(())
10044ca18c08SAlyssa Ross     }
10054ca18c08SAlyssa Ross 
socket_url_to_path(url: &str) -> result::Result<PathBuf, MigratableError>10064ca18c08SAlyssa Ross     fn socket_url_to_path(url: &str) -> result::Result<PathBuf, MigratableError> {
10074ca18c08SAlyssa Ross         url.strip_prefix("unix:")
10084ca18c08SAlyssa Ross             .ok_or_else(|| {
10094ca18c08SAlyssa Ross                 MigratableError::MigrateSend(anyhow!("Could not extract path from URL: {}", url))
10104ca18c08SAlyssa Ross             })
10114ca18c08SAlyssa Ross             .map(|s| s.into())
10124ca18c08SAlyssa Ross     }
10134ca18c08SAlyssa Ross 
send_migration_socket( destination_url: &str, ) -> std::result::Result<SocketStream, MigratableError>1014909e1bc3SJinrong Liang     fn send_migration_socket(
1015909e1bc3SJinrong Liang         destination_url: &str,
1016909e1bc3SJinrong Liang     ) -> std::result::Result<SocketStream, MigratableError> {
1017909e1bc3SJinrong Liang         if let Some(address) = destination_url.strip_prefix("tcp:") {
1018909e1bc3SJinrong Liang             info!("Connecting to TCP socket at {}", address);
1019909e1bc3SJinrong Liang 
1020909e1bc3SJinrong Liang             let socket = TcpStream::connect(address).map_err(|e| {
1021909e1bc3SJinrong Liang                 MigratableError::MigrateSend(anyhow!("Error connecting to TCP socket: {}", e))
1022909e1bc3SJinrong Liang             })?;
1023909e1bc3SJinrong Liang 
1024909e1bc3SJinrong Liang             Ok(SocketStream::Tcp(socket))
1025909e1bc3SJinrong Liang         } else {
1026909e1bc3SJinrong Liang             let path = Vmm::socket_url_to_path(destination_url)?;
1027909e1bc3SJinrong Liang             info!("Connecting to UNIX socket at {:?}", path);
1028909e1bc3SJinrong Liang 
1029909e1bc3SJinrong Liang             let socket = UnixStream::connect(&path).map_err(|e| {
1030909e1bc3SJinrong Liang                 MigratableError::MigrateSend(anyhow!("Error connecting to UNIX socket: {}", e))
1031909e1bc3SJinrong Liang             })?;
1032909e1bc3SJinrong Liang 
1033909e1bc3SJinrong Liang             Ok(SocketStream::Unix(socket))
1034909e1bc3SJinrong Liang         }
1035909e1bc3SJinrong Liang     }
1036909e1bc3SJinrong Liang 
receive_migration_socket( receiver_url: &str, ) -> std::result::Result<SocketStream, MigratableError>1037909e1bc3SJinrong Liang     fn receive_migration_socket(
1038909e1bc3SJinrong Liang         receiver_url: &str,
1039909e1bc3SJinrong Liang     ) -> std::result::Result<SocketStream, MigratableError> {
1040909e1bc3SJinrong Liang         if let Some(address) = receiver_url.strip_prefix("tcp:") {
1041909e1bc3SJinrong Liang             let listener = TcpListener::bind(address).map_err(|e| {
1042909e1bc3SJinrong Liang                 MigratableError::MigrateReceive(anyhow!("Error binding to TCP socket: {}", e))
1043909e1bc3SJinrong Liang             })?;
1044909e1bc3SJinrong Liang 
1045909e1bc3SJinrong Liang             let (socket, _addr) = listener.accept().map_err(|e| {
1046909e1bc3SJinrong Liang                 MigratableError::MigrateReceive(anyhow!(
1047909e1bc3SJinrong Liang                     "Error accepting connection on TCP socket: {}",
1048909e1bc3SJinrong Liang                     e
1049909e1bc3SJinrong Liang                 ))
1050909e1bc3SJinrong Liang             })?;
1051909e1bc3SJinrong Liang 
1052909e1bc3SJinrong Liang             Ok(SocketStream::Tcp(socket))
1053909e1bc3SJinrong Liang         } else {
1054909e1bc3SJinrong Liang             let path = Vmm::socket_url_to_path(receiver_url)?;
1055909e1bc3SJinrong Liang             let listener = UnixListener::bind(&path).map_err(|e| {
1056909e1bc3SJinrong Liang                 MigratableError::MigrateReceive(anyhow!("Error binding to UNIX socket: {}", e))
1057909e1bc3SJinrong Liang             })?;
1058909e1bc3SJinrong Liang 
1059909e1bc3SJinrong Liang             let (socket, _addr) = listener.accept().map_err(|e| {
1060909e1bc3SJinrong Liang                 MigratableError::MigrateReceive(anyhow!(
1061909e1bc3SJinrong Liang                     "Error accepting connection on UNIX socket: {}",
1062909e1bc3SJinrong Liang                     e
1063909e1bc3SJinrong Liang                 ))
1064909e1bc3SJinrong Liang             })?;
1065909e1bc3SJinrong Liang 
1066909e1bc3SJinrong Liang             // Remove the UNIX socket file after accepting the connection
1067909e1bc3SJinrong Liang             std::fs::remove_file(&path).map_err(|e| {
1068909e1bc3SJinrong Liang                 MigratableError::MigrateReceive(anyhow!("Error removing UNIX socket file: {}", e))
1069909e1bc3SJinrong Liang             })?;
1070909e1bc3SJinrong Liang 
1071909e1bc3SJinrong Liang             Ok(SocketStream::Unix(socket))
1072909e1bc3SJinrong Liang         }
1073909e1bc3SJinrong Liang     }
1074909e1bc3SJinrong Liang 
10754ca18c08SAlyssa Ross     // Returns true if there were dirty pages to send
vm_maybe_send_dirty_pages( vm: &mut Vm, socket: &mut SocketStream, ) -> result::Result<bool, MigratableError>1076909e1bc3SJinrong Liang     fn vm_maybe_send_dirty_pages(
10774ca18c08SAlyssa Ross         vm: &mut Vm,
1078909e1bc3SJinrong Liang         socket: &mut SocketStream,
1079909e1bc3SJinrong Liang     ) -> result::Result<bool, MigratableError> {
10804ca18c08SAlyssa Ross         // Send (dirty) memory table
10814ca18c08SAlyssa Ross         let table = vm.dirty_log()?;
10824ca18c08SAlyssa Ross 
10834ca18c08SAlyssa Ross         // But if there are no regions go straight to pause
10844ca18c08SAlyssa Ross         if table.regions().is_empty() {
10854ca18c08SAlyssa Ross             return Ok(false);
10864ca18c08SAlyssa Ross         }
10874ca18c08SAlyssa Ross 
10884ca18c08SAlyssa Ross         Request::memory(table.length()).write_to(socket).unwrap();
10894ca18c08SAlyssa Ross         table.write_to(socket)?;
10904ca18c08SAlyssa Ross         // And then the memory itself
10914ca18c08SAlyssa Ross         vm.send_memory_regions(&table, socket)?;
1092de1abe0eSRob Bradford         Response::read_from(socket)?.ok_or_abandon(
1093de1abe0eSRob Bradford             socket,
1094de1abe0eSRob Bradford             MigratableError::MigrateSend(anyhow!("Error during dirty memory migration")),
1095de1abe0eSRob Bradford         )?;
10964ca18c08SAlyssa Ross 
10974ca18c08SAlyssa Ross         Ok(true)
10984ca18c08SAlyssa Ross     }
10994ca18c08SAlyssa Ross 
send_migration( vm: &mut Vm, #[cfg(all(feature = "kvm", target_arch = "x86_64"))] hypervisor: Arc< dyn hypervisor::Hypervisor, >, send_data_migration: VmSendMigrationData, ) -> result::Result<(), MigratableError>11004ca18c08SAlyssa Ross     fn send_migration(
11014ca18c08SAlyssa Ross         vm: &mut Vm,
11024ca18c08SAlyssa Ross         #[cfg(all(feature = "kvm", target_arch = "x86_64"))] hypervisor: Arc<
11034ca18c08SAlyssa Ross             dyn hypervisor::Hypervisor,
11044ca18c08SAlyssa Ross         >,
11054ca18c08SAlyssa Ross         send_data_migration: VmSendMigrationData,
11064ca18c08SAlyssa Ross     ) -> result::Result<(), MigratableError> {
1107909e1bc3SJinrong Liang         // Set up the socket connection
1108909e1bc3SJinrong Liang         let mut socket = Self::send_migration_socket(&send_data_migration.destination_url)?;
11094ca18c08SAlyssa Ross 
11104ca18c08SAlyssa Ross         // Start the migration
11114ca18c08SAlyssa Ross         Request::start().write_to(&mut socket)?;
1112de1abe0eSRob Bradford         Response::read_from(&mut socket)?.ok_or_abandon(
1113de1abe0eSRob Bradford             &mut socket,
1114de1abe0eSRob Bradford             MigratableError::MigrateSend(anyhow!("Error starting migration")),
1115de1abe0eSRob Bradford         )?;
11164ca18c08SAlyssa Ross 
11174ca18c08SAlyssa Ross         // Send config
11184ca18c08SAlyssa Ross         let vm_config = vm.get_config();
11194ca18c08SAlyssa Ross         #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
11204ca18c08SAlyssa Ross         let common_cpuid = {
11214ca18c08SAlyssa Ross             #[cfg(feature = "tdx")]
11224ca18c08SAlyssa Ross             if vm_config.lock().unwrap().is_tdx_enabled() {
11234ca18c08SAlyssa Ross                 return Err(MigratableError::MigrateSend(anyhow!(
11244ca18c08SAlyssa Ross                     "Live Migration is not supported when TDX is enabled"
11254ca18c08SAlyssa Ross                 )));
11264ca18c08SAlyssa Ross             };
11274ca18c08SAlyssa Ross 
11284ca18c08SAlyssa Ross             let amx = vm_config.lock().unwrap().cpus.features.amx;
11294ca18c08SAlyssa Ross             let phys_bits =
11304ca18c08SAlyssa Ross                 vm::physical_bits(&hypervisor, vm_config.lock().unwrap().cpus.max_phys_bits);
11314ca18c08SAlyssa Ross             arch::generate_common_cpuid(
11324ca18c08SAlyssa Ross                 &hypervisor,
11334ca18c08SAlyssa Ross                 &arch::CpuidConfig {
11344ca18c08SAlyssa Ross                     sgx_epc_sections: None,
11354ca18c08SAlyssa Ross                     phys_bits,
11364ca18c08SAlyssa Ross                     kvm_hyperv: vm_config.lock().unwrap().cpus.kvm_hyperv,
11374ca18c08SAlyssa Ross                     #[cfg(feature = "tdx")]
11384ca18c08SAlyssa Ross                     tdx: false,
11394ca18c08SAlyssa Ross                     amx,
11404ca18c08SAlyssa Ross                 },
11414ca18c08SAlyssa Ross             )
11424ca18c08SAlyssa Ross             .map_err(|e| {
11434ca18c08SAlyssa Ross                 MigratableError::MigrateSend(anyhow!("Error generating common cpuid': {:?}", e))
11444ca18c08SAlyssa Ross             })?
11454ca18c08SAlyssa Ross         };
11464ca18c08SAlyssa Ross 
11474ca18c08SAlyssa Ross         if send_data_migration.local {
1148909e1bc3SJinrong Liang             match &mut socket {
1149909e1bc3SJinrong Liang                 SocketStream::Unix(unix_socket) => {
1150909e1bc3SJinrong Liang                     // Proceed with sending memory file descriptors over UNIX socket
1151909e1bc3SJinrong Liang                     vm.send_memory_fds(unix_socket)?;
1152909e1bc3SJinrong Liang                 }
1153909e1bc3SJinrong Liang                 SocketStream::Tcp(_tcp_socket) => {
1154909e1bc3SJinrong Liang                     return Err(MigratableError::MigrateSend(anyhow!(
1155909e1bc3SJinrong Liang                         "--local option is not supported with TCP sockets",
1156909e1bc3SJinrong Liang                     )));
1157909e1bc3SJinrong Liang                 }
1158909e1bc3SJinrong Liang             }
11594ca18c08SAlyssa Ross         }
11604ca18c08SAlyssa Ross 
11614ca18c08SAlyssa Ross         let vm_migration_config = VmMigrationConfig {
11624ca18c08SAlyssa Ross             vm_config,
11634ca18c08SAlyssa Ross             #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
11644ca18c08SAlyssa Ross             common_cpuid,
11654ca18c08SAlyssa Ross             memory_manager_data: vm.memory_manager_data(),
11664ca18c08SAlyssa Ross         };
11674ca18c08SAlyssa Ross         let config_data = serde_json::to_vec(&vm_migration_config).unwrap();
11684ca18c08SAlyssa Ross         Request::config(config_data.len() as u64).write_to(&mut socket)?;
11694ca18c08SAlyssa Ross         socket
11704ca18c08SAlyssa Ross             .write_all(&config_data)
11714ca18c08SAlyssa Ross             .map_err(MigratableError::MigrateSocket)?;
1172de1abe0eSRob Bradford         Response::read_from(&mut socket)?.ok_or_abandon(
1173de1abe0eSRob Bradford             &mut socket,
1174de1abe0eSRob Bradford             MigratableError::MigrateSend(anyhow!("Error during config migration")),
1175de1abe0eSRob Bradford         )?;
11764ca18c08SAlyssa Ross 
11774ca18c08SAlyssa Ross         // Let every Migratable object know about the migration being started.
11784ca18c08SAlyssa Ross         vm.start_migration()?;
11794ca18c08SAlyssa Ross 
11804ca18c08SAlyssa Ross         if send_data_migration.local {
11814ca18c08SAlyssa Ross             // Now pause VM
11824ca18c08SAlyssa Ross             vm.pause()?;
11834ca18c08SAlyssa Ross         } else {
11844ca18c08SAlyssa Ross             // Start logging dirty pages
11854ca18c08SAlyssa Ross             vm.start_dirty_log()?;
11864ca18c08SAlyssa Ross 
11874ca18c08SAlyssa Ross             // Send memory table
11884ca18c08SAlyssa Ross             let table = vm.memory_range_table()?;
11894ca18c08SAlyssa Ross             Request::memory(table.length())
11904ca18c08SAlyssa Ross                 .write_to(&mut socket)
11914ca18c08SAlyssa Ross                 .unwrap();
11924ca18c08SAlyssa Ross             table.write_to(&mut socket)?;
11934ca18c08SAlyssa Ross             // And then the memory itself
11944ca18c08SAlyssa Ross             vm.send_memory_regions(&table, &mut socket)?;
1195de1abe0eSRob Bradford             Response::read_from(&mut socket)?.ok_or_abandon(
1196de1abe0eSRob Bradford                 &mut socket,
1197de1abe0eSRob Bradford                 MigratableError::MigrateSend(anyhow!("Error during dirty memory migration")),
1198de1abe0eSRob Bradford             )?;
11994ca18c08SAlyssa Ross 
12004ca18c08SAlyssa Ross             // Try at most 5 passes of dirty memory sending
12014ca18c08SAlyssa Ross             const MAX_DIRTY_MIGRATIONS: usize = 5;
12024ca18c08SAlyssa Ross             for i in 0..MAX_DIRTY_MIGRATIONS {
12034ca18c08SAlyssa Ross                 info!("Dirty memory migration {} of {}", i, MAX_DIRTY_MIGRATIONS);
12044ca18c08SAlyssa Ross                 if !Self::vm_maybe_send_dirty_pages(vm, &mut socket)? {
12054ca18c08SAlyssa Ross                     break;
12064ca18c08SAlyssa Ross                 }
12074ca18c08SAlyssa Ross             }
12084ca18c08SAlyssa Ross 
12094ca18c08SAlyssa Ross             // Now pause VM
12104ca18c08SAlyssa Ross             vm.pause()?;
12114ca18c08SAlyssa Ross 
12124ca18c08SAlyssa Ross             // Send last batch of dirty pages
12134ca18c08SAlyssa Ross             Self::vm_maybe_send_dirty_pages(vm, &mut socket)?;
12144ca18c08SAlyssa Ross         }
121505968f5cSPhilipp Schuster 
121605968f5cSPhilipp Schuster         // We release the locks early to enable locking them on the destination host.
121705968f5cSPhilipp Schuster         // The VM is already stopped.
121805968f5cSPhilipp Schuster         vm.release_disk_locks()
121905968f5cSPhilipp Schuster             .map_err(|e| MigratableError::UnlockError(anyhow!("{e}")))?;
122005968f5cSPhilipp Schuster 
12214ca18c08SAlyssa Ross         // Capture snapshot and send it
12224ca18c08SAlyssa Ross         let vm_snapshot = vm.snapshot()?;
12234ca18c08SAlyssa Ross         let snapshot_data = serde_json::to_vec(&vm_snapshot).unwrap();
12244ca18c08SAlyssa Ross         Request::state(snapshot_data.len() as u64).write_to(&mut socket)?;
12254ca18c08SAlyssa Ross         socket
12264ca18c08SAlyssa Ross             .write_all(&snapshot_data)
12274ca18c08SAlyssa Ross             .map_err(MigratableError::MigrateSocket)?;
1228de1abe0eSRob Bradford         Response::read_from(&mut socket)?.ok_or_abandon(
1229de1abe0eSRob Bradford             &mut socket,
1230de1abe0eSRob Bradford             MigratableError::MigrateSend(anyhow!("Error during state migration")),
1231de1abe0eSRob Bradford         )?;
12324ca18c08SAlyssa Ross         // Complete the migration
123305968f5cSPhilipp Schuster         // At this step, the receiving VMM will acquire disk locks again.
12344ca18c08SAlyssa Ross         Request::complete().write_to(&mut socket)?;
1235de1abe0eSRob Bradford         Response::read_from(&mut socket)?.ok_or_abandon(
1236de1abe0eSRob Bradford             &mut socket,
1237de1abe0eSRob Bradford             MigratableError::MigrateSend(anyhow!("Error completing migration")),
1238de1abe0eSRob Bradford         )?;
1239de1abe0eSRob Bradford 
12409d93df4cSJinrong Liang         // Stop logging dirty pages
12419d93df4cSJinrong Liang         if !send_data_migration.local {
12429d93df4cSJinrong Liang             vm.stop_dirty_log()?;
12439d93df4cSJinrong Liang         }
12449d93df4cSJinrong Liang 
12454ca18c08SAlyssa Ross         info!("Migration complete");
12464ca18c08SAlyssa Ross 
12474ca18c08SAlyssa Ross         // Let every Migratable object know about the migration being complete
12484ca18c08SAlyssa Ross         vm.complete_migration()
12494ca18c08SAlyssa Ross     }
12504ca18c08SAlyssa Ross 
12514ca18c08SAlyssa Ross     #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
vm_check_cpuid_compatibility( &self, src_vm_config: &Arc<Mutex<VmConfig>>, src_vm_cpuid: &[hypervisor::arch::x86::CpuIdEntry], ) -> result::Result<(), MigratableError>12524ca18c08SAlyssa Ross     fn vm_check_cpuid_compatibility(
12534ca18c08SAlyssa Ross         &self,
12544ca18c08SAlyssa Ross         src_vm_config: &Arc<Mutex<VmConfig>>,
12554ca18c08SAlyssa Ross         src_vm_cpuid: &[hypervisor::arch::x86::CpuIdEntry],
12564ca18c08SAlyssa Ross     ) -> result::Result<(), MigratableError> {
12574ca18c08SAlyssa Ross         #[cfg(feature = "tdx")]
12584ca18c08SAlyssa Ross         if src_vm_config.lock().unwrap().is_tdx_enabled() {
12594ca18c08SAlyssa Ross             return Err(MigratableError::MigrateReceive(anyhow!(
12604ca18c08SAlyssa Ross                 "Live Migration is not supported when TDX is enabled"
12614ca18c08SAlyssa Ross             )));
12624ca18c08SAlyssa Ross         };
12634ca18c08SAlyssa Ross 
12644ca18c08SAlyssa Ross         // We check the `CPUID` compatibility of between the source vm and destination, which is
12654ca18c08SAlyssa Ross         // mostly about feature compatibility and "topology/sgx" leaves are not relevant.
12664ca18c08SAlyssa Ross         let dest_cpuid = &{
12674ca18c08SAlyssa Ross             let vm_config = &src_vm_config.lock().unwrap();
12684ca18c08SAlyssa Ross 
12694ca18c08SAlyssa Ross             let phys_bits = vm::physical_bits(&self.hypervisor, vm_config.cpus.max_phys_bits);
12704ca18c08SAlyssa Ross             arch::generate_common_cpuid(
12714ca18c08SAlyssa Ross                 &self.hypervisor.clone(),
12724ca18c08SAlyssa Ross                 &arch::CpuidConfig {
12734ca18c08SAlyssa Ross                     sgx_epc_sections: None,
12744ca18c08SAlyssa Ross                     phys_bits,
12754ca18c08SAlyssa Ross                     kvm_hyperv: vm_config.cpus.kvm_hyperv,
12764ca18c08SAlyssa Ross                     #[cfg(feature = "tdx")]
12774ca18c08SAlyssa Ross                     tdx: false,
12784ca18c08SAlyssa Ross                     amx: vm_config.cpus.features.amx,
12794ca18c08SAlyssa Ross                 },
12804ca18c08SAlyssa Ross             )
12814ca18c08SAlyssa Ross             .map_err(|e| {
12824ca18c08SAlyssa Ross                 MigratableError::MigrateReceive(anyhow!("Error generating common cpuid: {:?}", e))
12834ca18c08SAlyssa Ross             })?
12844ca18c08SAlyssa Ross         };
12854ca18c08SAlyssa Ross         arch::CpuidFeatureEntry::check_cpuid_compatibility(src_vm_cpuid, dest_cpuid).map_err(|e| {
12864ca18c08SAlyssa Ross             MigratableError::MigrateReceive(anyhow!(
12874ca18c08SAlyssa Ross                 "Error checking cpu feature compatibility': {:?}",
12884ca18c08SAlyssa Ross                 e
12894ca18c08SAlyssa Ross             ))
12904ca18c08SAlyssa Ross         })
12914ca18c08SAlyssa Ross     }
12924ca18c08SAlyssa Ross 
vm_restore( &mut self, source_url: &str, vm_config: Arc<Mutex<VmConfig>>, prefault: bool, ) -> std::result::Result<(), VmError>12938f98fabdSBo Chen     fn vm_restore(
12948f98fabdSBo Chen         &mut self,
12958f98fabdSBo Chen         source_url: &str,
12968f98fabdSBo Chen         vm_config: Arc<Mutex<VmConfig>>,
12978f98fabdSBo Chen         prefault: bool,
12988f98fabdSBo Chen     ) -> std::result::Result<(), VmError> {
12998f98fabdSBo Chen         let snapshot = recv_vm_state(source_url).map_err(VmError::Restore)?;
13008f98fabdSBo Chen         #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
13018f98fabdSBo Chen         let vm_snapshot = get_vm_snapshot(&snapshot).map_err(VmError::Restore)?;
13028f98fabdSBo Chen 
13038f98fabdSBo Chen         #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
13048f98fabdSBo Chen         self.vm_check_cpuid_compatibility(&vm_config, &vm_snapshot.common_cpuid)
13058f98fabdSBo Chen             .map_err(VmError::Restore)?;
13068f98fabdSBo Chen 
13078f98fabdSBo Chen         self.vm_config = Some(Arc::clone(&vm_config));
13088f98fabdSBo Chen 
13098f98fabdSBo Chen         // Always re-populate the 'console_info' based on the new 'vm_config'
13108f98fabdSBo Chen         self.console_info =
13118f98fabdSBo Chen             Some(pre_create_console_devices(self).map_err(VmError::CreateConsoleDevices)?);
13128f98fabdSBo Chen 
13138f98fabdSBo Chen         let exit_evt = self.exit_evt.try_clone().map_err(VmError::EventFdClone)?;
13148f98fabdSBo Chen         let reset_evt = self.reset_evt.try_clone().map_err(VmError::EventFdClone)?;
13158f98fabdSBo Chen         #[cfg(feature = "guest_debug")]
13168f98fabdSBo Chen         let debug_evt = self
13178f98fabdSBo Chen             .vm_debug_evt
13188f98fabdSBo Chen             .try_clone()
13198f98fabdSBo Chen             .map_err(VmError::EventFdClone)?;
13208f98fabdSBo Chen         let activate_evt = self
13218f98fabdSBo Chen             .activate_evt
13228f98fabdSBo Chen             .try_clone()
13238f98fabdSBo Chen             .map_err(VmError::EventFdClone)?;
13248f98fabdSBo Chen 
13258f98fabdSBo Chen         let vm = Vm::new(
13268f98fabdSBo Chen             vm_config,
13278f98fabdSBo Chen             exit_evt,
13288f98fabdSBo Chen             reset_evt,
13298f98fabdSBo Chen             #[cfg(feature = "guest_debug")]
13308f98fabdSBo Chen             debug_evt,
13318f98fabdSBo Chen             &self.seccomp_action,
13328f98fabdSBo Chen             self.hypervisor.clone(),
13338f98fabdSBo Chen             activate_evt,
13348f98fabdSBo Chen             self.console_info.clone(),
13358f98fabdSBo Chen             self.console_resize_pipe.clone(),
13368f98fabdSBo Chen             Arc::clone(&self.original_termios_opt),
13378f98fabdSBo Chen             Some(snapshot),
13388f98fabdSBo Chen             Some(source_url),
13398f98fabdSBo Chen             Some(prefault),
13408f98fabdSBo Chen         )?;
13418f98fabdSBo Chen         self.vm = Some(vm);
13428f98fabdSBo Chen 
13438f98fabdSBo Chen         if self
13448f98fabdSBo Chen             .vm_config
13458f98fabdSBo Chen             .as_ref()
13468f98fabdSBo Chen             .unwrap()
13478f98fabdSBo Chen             .lock()
13488f98fabdSBo Chen             .unwrap()
13498f98fabdSBo Chen             .landlock_enable
13508f98fabdSBo Chen         {
13518f98fabdSBo Chen             apply_landlock(self.vm_config.as_ref().unwrap().clone())
13528f98fabdSBo Chen                 .map_err(VmError::ApplyLandlock)?;
13538f98fabdSBo Chen         }
13548f98fabdSBo Chen 
13558f98fabdSBo Chen         // Now we can restore the rest of the VM.
13568f98fabdSBo Chen         if let Some(ref mut vm) = self.vm {
13578f98fabdSBo Chen             vm.restore()
13588f98fabdSBo Chen         } else {
13598f98fabdSBo Chen             Err(VmError::VmNotCreated)
13608f98fabdSBo Chen         }
13618f98fabdSBo Chen     }
13628f98fabdSBo Chen 
control_loop( &mut self, api_receiver: Rc<Receiver<ApiRequest>>, #[cfg(feature = "guest_debug")] gdb_receiver: Rc<Receiver<gdb::GdbRequest>>, ) -> Result<()>13634ca18c08SAlyssa Ross     fn control_loop(
13644ca18c08SAlyssa Ross         &mut self,
13654ca18c08SAlyssa Ross         api_receiver: Rc<Receiver<ApiRequest>>,
13664ca18c08SAlyssa Ross         #[cfg(feature = "guest_debug")] gdb_receiver: Rc<Receiver<gdb::GdbRequest>>,
13674ca18c08SAlyssa Ross     ) -> Result<()> {
13684ca18c08SAlyssa Ross         const EPOLL_EVENTS_LEN: usize = 100;
13694ca18c08SAlyssa Ross 
13704ca18c08SAlyssa Ross         let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN];
13714ca18c08SAlyssa Ross         let epoll_fd = self.epoll.as_raw_fd();
13724ca18c08SAlyssa Ross 
13734ca18c08SAlyssa Ross         'outer: loop {
13744ca18c08SAlyssa Ross             let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) {
13754ca18c08SAlyssa Ross                 Ok(res) => res,
13764ca18c08SAlyssa Ross                 Err(e) => {
13774ca18c08SAlyssa Ross                     if e.kind() == io::ErrorKind::Interrupted {
13784ca18c08SAlyssa Ross                         // It's well defined from the epoll_wait() syscall
13794ca18c08SAlyssa Ross                         // documentation that the epoll loop can be interrupted
13804ca18c08SAlyssa Ross                         // before any of the requested events occurred or the
13814ca18c08SAlyssa Ross                         // timeout expired. In both those cases, epoll_wait()
13824ca18c08SAlyssa Ross                         // returns an error of type EINTR, but this should not
13834ca18c08SAlyssa Ross                         // be considered as a regular error. Instead it is more
13844ca18c08SAlyssa Ross                         // appropriate to retry, by calling into epoll_wait().
13854ca18c08SAlyssa Ross                         continue;
13864ca18c08SAlyssa Ross                     }
13874ca18c08SAlyssa Ross                     return Err(Error::Epoll(e));
13884ca18c08SAlyssa Ross                 }
13894ca18c08SAlyssa Ross             };
13904ca18c08SAlyssa Ross 
13914ca18c08SAlyssa Ross             for event in events.iter().take(num_events) {
13924ca18c08SAlyssa Ross                 let dispatch_event: EpollDispatch = event.data.into();
13934ca18c08SAlyssa Ross                 match dispatch_event {
13944ca18c08SAlyssa Ross                     EpollDispatch::Unknown => {
13954ca18c08SAlyssa Ross                         let event = event.data;
13964ca18c08SAlyssa Ross                         warn!("Unknown VMM loop event: {}", event);
13974ca18c08SAlyssa Ross                     }
13984ca18c08SAlyssa Ross                     EpollDispatch::Exit => {
13994ca18c08SAlyssa Ross                         info!("VM exit event");
14004ca18c08SAlyssa Ross                         // Consume the event.
14014ca18c08SAlyssa Ross                         self.exit_evt.read().map_err(Error::EventFdRead)?;
14024ca18c08SAlyssa Ross                         self.vmm_shutdown().map_err(Error::VmmShutdown)?;
14034ca18c08SAlyssa Ross 
14044ca18c08SAlyssa Ross                         break 'outer;
14054ca18c08SAlyssa Ross                     }
14064ca18c08SAlyssa Ross                     EpollDispatch::Reset => {
14074ca18c08SAlyssa Ross                         info!("VM reset event");
14084ca18c08SAlyssa Ross                         // Consume the event.
14094ca18c08SAlyssa Ross                         self.reset_evt.read().map_err(Error::EventFdRead)?;
14104ca18c08SAlyssa Ross                         self.vm_reboot().map_err(Error::VmReboot)?;
14114ca18c08SAlyssa Ross                     }
14124ca18c08SAlyssa Ross                     EpollDispatch::ActivateVirtioDevices => {
14134ca18c08SAlyssa Ross                         if let Some(ref vm) = self.vm {
14144ca18c08SAlyssa Ross                             let count = self.activate_evt.read().map_err(Error::EventFdRead)?;
14154ca18c08SAlyssa Ross                             info!(
14164ca18c08SAlyssa Ross                                 "Trying to activate pending virtio devices: count = {}",
14174ca18c08SAlyssa Ross                                 count
14184ca18c08SAlyssa Ross                             );
14194ca18c08SAlyssa Ross                             vm.activate_virtio_devices()
14204ca18c08SAlyssa Ross                                 .map_err(Error::ActivateVirtioDevices)?;
14214ca18c08SAlyssa Ross                         }
14224ca18c08SAlyssa Ross                     }
14234ca18c08SAlyssa Ross                     EpollDispatch::Api => {
14244ca18c08SAlyssa Ross                         // Consume the events.
14254ca18c08SAlyssa Ross                         for _ in 0..self.api_evt.read().map_err(Error::EventFdRead)? {
14264ca18c08SAlyssa Ross                             // Read from the API receiver channel
14274ca18c08SAlyssa Ross                             let api_request = api_receiver.recv().map_err(Error::ApiRequestRecv)?;
14284ca18c08SAlyssa Ross 
14294ca18c08SAlyssa Ross                             if api_request(self)? {
14304ca18c08SAlyssa Ross                                 break 'outer;
14314ca18c08SAlyssa Ross                             }
14324ca18c08SAlyssa Ross                         }
14334ca18c08SAlyssa Ross                     }
14344ca18c08SAlyssa Ross                     #[cfg(feature = "guest_debug")]
14354ca18c08SAlyssa Ross                     EpollDispatch::Debug => {
14364ca18c08SAlyssa Ross                         // Consume the events.
14374ca18c08SAlyssa Ross                         for _ in 0..self.debug_evt.read().map_err(Error::EventFdRead)? {
14384ca18c08SAlyssa Ross                             // Read from the API receiver channel
14394ca18c08SAlyssa Ross                             let gdb_request = gdb_receiver.recv().map_err(Error::GdbRequestRecv)?;
14404ca18c08SAlyssa Ross 
14414ca18c08SAlyssa Ross                             let response = if let Some(ref mut vm) = self.vm {
14424ca18c08SAlyssa Ross                                 vm.debug_request(&gdb_request.payload, gdb_request.cpu_id)
14434ca18c08SAlyssa Ross                             } else {
14444ca18c08SAlyssa Ross                                 Err(VmError::VmNotRunning)
14454ca18c08SAlyssa Ross                             }
14464ca18c08SAlyssa Ross                             .map_err(gdb::Error::Vm);
14474ca18c08SAlyssa Ross 
14484ca18c08SAlyssa Ross                             gdb_request
14494ca18c08SAlyssa Ross                                 .sender
14504ca18c08SAlyssa Ross                                 .send(response)
14514ca18c08SAlyssa Ross                                 .map_err(Error::GdbResponseSend)?;
14524ca18c08SAlyssa Ross                         }
14534ca18c08SAlyssa Ross                     }
14544ca18c08SAlyssa Ross                     #[cfg(not(feature = "guest_debug"))]
14554ca18c08SAlyssa Ross                     EpollDispatch::Debug => {}
14564ca18c08SAlyssa Ross                 }
14574ca18c08SAlyssa Ross             }
14584ca18c08SAlyssa Ross         }
14594ca18c08SAlyssa Ross 
14604ca18c08SAlyssa Ross         // Trigger the termination of the signal_handler thread
14614ca18c08SAlyssa Ross         if let Some(signals) = self.signals.take() {
14624ca18c08SAlyssa Ross             signals.close();
14634ca18c08SAlyssa Ross         }
14644ca18c08SAlyssa Ross 
14654ca18c08SAlyssa Ross         // Wait for all the threads to finish
14664ca18c08SAlyssa Ross         for thread in self.threads.drain(..) {
14674ca18c08SAlyssa Ross             thread.join().map_err(Error::ThreadCleanup)?
14684ca18c08SAlyssa Ross         }
14694ca18c08SAlyssa Ross 
14704ca18c08SAlyssa Ross         Ok(())
14714ca18c08SAlyssa Ross     }
14724ca18c08SAlyssa Ross }
14734ca18c08SAlyssa Ross 
apply_landlock(vm_config: Arc<Mutex<VmConfig>>) -> result::Result<(), LandlockError>1474d2f0e8aeSPraveen K Paladugu fn apply_landlock(vm_config: Arc<Mutex<VmConfig>>) -> result::Result<(), LandlockError> {
1475d2f0e8aeSPraveen K Paladugu     vm_config.lock().unwrap().apply_landlock()?;
1476249e362cSPraveen K Paladugu     Ok(())
1477249e362cSPraveen K Paladugu }
1478249e362cSPraveen K Paladugu 
14794ca18c08SAlyssa Ross impl RequestHandler for Vmm {
vm_create(&mut self, config: Box<VmConfig>) -> result::Result<(), VmError>1480cc9899e0SSongqian Li     fn vm_create(&mut self, config: Box<VmConfig>) -> result::Result<(), VmError> {
14811075209eSBo Chen         // We only store the passed VM config.
14821075209eSBo Chen         // The VM will be created when being asked to boot it.
14831075209eSBo Chen         if self.vm_config.is_none() {
1484cc9899e0SSongqian Li             self.vm_config = Some(Arc::new(Mutex::new(*config)));
1485380ba564SPraveen K Paladugu             self.console_info =
1486380ba564SPraveen K Paladugu                 Some(pre_create_console_devices(self).map_err(VmError::CreateConsoleDevices)?);
1487249e362cSPraveen K Paladugu 
1488d2f0e8aeSPraveen K Paladugu             if self
1489d2f0e8aeSPraveen K Paladugu                 .vm_config
1490d2f0e8aeSPraveen K Paladugu                 .as_ref()
1491d2f0e8aeSPraveen K Paladugu                 .unwrap()
1492d2f0e8aeSPraveen K Paladugu                 .lock()
1493d2f0e8aeSPraveen K Paladugu                 .unwrap()
1494d2f0e8aeSPraveen K Paladugu                 .landlock_enable
1495d2f0e8aeSPraveen K Paladugu             {
1496d2f0e8aeSPraveen K Paladugu                 apply_landlock(self.vm_config.as_ref().unwrap().clone())
1497249e362cSPraveen K Paladugu                     .map_err(VmError::ApplyLandlock)?;
1498249e362cSPraveen K Paladugu             }
14991075209eSBo Chen             Ok(())
15001075209eSBo Chen         } else {
15011075209eSBo Chen             Err(VmError::VmAlreadyCreated)
15021075209eSBo Chen         }
15031075209eSBo Chen     }
15041075209eSBo Chen 
vm_boot(&mut self) -> result::Result<(), VmError>1505f9daf2e2SSamuel Ortiz     fn vm_boot(&mut self) -> result::Result<(), VmError> {
15061202b9a0SRob Bradford         tracer::start();
15075997cfacSBo Chen         info!("Booting VM");
15085997cfacSBo Chen         event!("vm", "booting");
15091202b9a0SRob Bradford         let r = {
15101202b9a0SRob Bradford             trace_scoped!("vm_boot");
15115768dcc3SBo Chen             // If we don't have a config, we cannot boot a VM.
15125768dcc3SBo Chen             if self.vm_config.is_none() {
15135768dcc3SBo Chen                 return Err(VmError::VmMissingConfig);
15145768dcc3SBo Chen             };
15155768dcc3SBo Chen 
1516380ba564SPraveen K Paladugu             // console_info is set to None in vm_shutdown. re-populate here if empty
1517380ba564SPraveen K Paladugu             if self.console_info.is_none() {
1518380ba564SPraveen K Paladugu                 self.console_info =
1519380ba564SPraveen K Paladugu                     Some(pre_create_console_devices(self).map_err(VmError::CreateConsoleDevices)?);
1520380ba564SPraveen K Paladugu             }
1521380ba564SPraveen K Paladugu 
15228160c288SDayu Liu             // Create a new VM if we don't have one yet.
1523f9daf2e2SSamuel Ortiz             if self.vm.is_none() {
1524f9daf2e2SSamuel Ortiz                 let exit_evt = self.exit_evt.try_clone().map_err(VmError::EventFdClone)?;
1525f9daf2e2SSamuel Ortiz                 let reset_evt = self.reset_evt.try_clone().map_err(VmError::EventFdClone)?;
152606eb82d2SRob Bradford                 #[cfg(feature = "guest_debug")]
15272451c4d8SAkira Moroo                 let vm_debug_evt = self
15282451c4d8SAkira Moroo                     .vm_debug_evt
15292451c4d8SAkira Moroo                     .try_clone()
15302451c4d8SAkira Moroo                     .map_err(VmError::EventFdClone)?;
153103db4830SRob Bradford                 let activate_evt = self
153203db4830SRob Bradford                     .activate_evt
153303db4830SRob Bradford                     .try_clone()
153403db4830SRob Bradford                     .map_err(VmError::EventFdClone)?;
1535f9daf2e2SSamuel Ortiz 
1536f9daf2e2SSamuel Ortiz                 if let Some(ref vm_config) = self.vm_config {
1537b04eb477SRob Bradford                     let vm = Vm::new(
1538b04eb477SRob Bradford                         Arc::clone(vm_config),
1539b04eb477SRob Bradford                         exit_evt,
1540b04eb477SRob Bradford                         reset_evt,
154106eb82d2SRob Bradford                         #[cfg(feature = "guest_debug")]
15422451c4d8SAkira Moroo                         vm_debug_evt,
1543ff7ed8f6SBo Chen                         &self.seccomp_action,
1544e4dee57eSMuminul Islam                         self.hypervisor.clone(),
154503db4830SRob Bradford                         activate_evt,
154652eebaf6SPraveen K Paladugu                         self.console_info.clone(),
1547ab12e7c2SSongqian Li                         self.console_resize_pipe.clone(),
1548c90a0fffSAlyssa Ross                         Arc::clone(&self.original_termios_opt),
1549e8c6d83fSSebastien Boeuf                         None,
1550e8c6d83fSSebastien Boeuf                         None,
1551e8c6d83fSSebastien Boeuf                         None,
1552b04eb477SRob Bradford                     )?;
1553c2144b56SRob Bradford 
1554f9daf2e2SSamuel Ortiz                     self.vm = Some(vm);
1555f9daf2e2SSamuel Ortiz                 }
1556f9daf2e2SSamuel Ortiz             }
1557f9daf2e2SSamuel Ortiz 
1558f9daf2e2SSamuel Ortiz             // Now we can boot the VM.
1559f9daf2e2SSamuel Ortiz             if let Some(ref mut vm) = self.vm {
1560f9daf2e2SSamuel Ortiz                 vm.boot()
1561f9daf2e2SSamuel Ortiz             } else {
1562f9daf2e2SSamuel Ortiz                 Err(VmError::VmNotCreated)
1563f9daf2e2SSamuel Ortiz             }
15641202b9a0SRob Bradford         };
15651202b9a0SRob Bradford         tracer::end();
15665997cfacSBo Chen         if r.is_ok() {
15675997cfacSBo Chen             event!("vm", "booted");
15685997cfacSBo Chen         }
15691202b9a0SRob Bradford         r
1570f9daf2e2SSamuel Ortiz     }
1571f9daf2e2SSamuel Ortiz 
vm_pause(&mut self) -> result::Result<(), VmError>15724ac0cb9cSSamuel Ortiz     fn vm_pause(&mut self) -> result::Result<(), VmError> {
15734ac0cb9cSSamuel Ortiz         if let Some(ref mut vm) = self.vm {
157437557c8bSSamuel Ortiz             vm.pause().map_err(VmError::Pause)
15754ac0cb9cSSamuel Ortiz         } else {
1576d2d3abb1SSamuel Ortiz             Err(VmError::VmNotRunning)
15774ac0cb9cSSamuel Ortiz         }
15784ac0cb9cSSamuel Ortiz     }
15794ac0cb9cSSamuel Ortiz 
vm_resume(&mut self) -> result::Result<(), VmError>1580dbbd04a4SSamuel Ortiz     fn vm_resume(&mut self) -> result::Result<(), VmError> {
1581dbbd04a4SSamuel Ortiz         if let Some(ref mut vm) = self.vm {
158237557c8bSSamuel Ortiz             vm.resume().map_err(VmError::Resume)
1583dbbd04a4SSamuel Ortiz         } else {
1584d2d3abb1SSamuel Ortiz             Err(VmError::VmNotRunning)
1585dbbd04a4SSamuel Ortiz         }
1586dbbd04a4SSamuel Ortiz     }
1587dbbd04a4SSamuel Ortiz 
vm_snapshot(&mut self, destination_url: &str) -> result::Result<(), VmError>158853613319SSebastien Boeuf     fn vm_snapshot(&mut self, destination_url: &str) -> result::Result<(), VmError> {
158953613319SSebastien Boeuf         if let Some(ref mut vm) = self.vm {
1590380ba564SPraveen K Paladugu             // Drain console_info so that FDs are not reused
1591380ba564SPraveen K Paladugu             let _ = self.console_info.take();
159253613319SSebastien Boeuf             vm.snapshot()
159353613319SSebastien Boeuf                 .map_err(VmError::Snapshot)
159453613319SSebastien Boeuf                 .and_then(|snapshot| {
159553613319SSebastien Boeuf                     vm.send(&snapshot, destination_url)
159653613319SSebastien Boeuf                         .map_err(VmError::SnapshotSend)
159753613319SSebastien Boeuf                 })
159853613319SSebastien Boeuf         } else {
159953613319SSebastien Boeuf             Err(VmError::VmNotRunning)
160053613319SSebastien Boeuf         }
1601cf8f8ce9SSamuel Ortiz     }
1602cf8f8ce9SSamuel Ortiz 
vm_restore(&mut self, restore_cfg: RestoreConfig) -> result::Result<(), VmError>1603a517ca23SSebastien Boeuf     fn vm_restore(&mut self, restore_cfg: RestoreConfig) -> result::Result<(), VmError> {
16046eb72130SSebastien Boeuf         if self.vm.is_some() || self.vm_config.is_some() {
16056eb72130SSebastien Boeuf             return Err(VmError::VmAlreadyCreated);
16066eb72130SSebastien Boeuf         }
16076eb72130SSebastien Boeuf 
1608a517ca23SSebastien Boeuf         let source_url = restore_cfg.source_url.as_path().to_str();
1609a517ca23SSebastien Boeuf         if source_url.is_none() {
161062f17ccfSRob Bradford             return Err(VmError::InvalidRestoreSourceUrl);
1611a517ca23SSebastien Boeuf         }
1612a517ca23SSebastien Boeuf         // Safe to unwrap as we checked it was Some(&str).
1613a517ca23SSebastien Boeuf         let source_url = source_url.unwrap();
1614a517ca23SSebastien Boeuf 
161510676b74SSebastien Boeuf         let vm_config = Arc::new(Mutex::new(
161610676b74SSebastien Boeuf             recv_vm_config(source_url).map_err(VmError::Restore)?,
161710676b74SSebastien Boeuf         ));
1618584784a0SPurna Pavan Chandra         restore_cfg
1619584784a0SPurna Pavan Chandra             .validate(&vm_config.lock().unwrap().clone())
1620584784a0SPurna Pavan Chandra             .map_err(VmError::ConfigValidation)?;
1621584784a0SPurna Pavan Chandra 
1622584784a0SPurna Pavan Chandra         // Update VM's net configurations with new fds received for restore operation
1623584784a0SPurna Pavan Chandra         if let (Some(restored_nets), Some(vm_net_configs)) =
1624584784a0SPurna Pavan Chandra             (restore_cfg.net_fds, &mut vm_config.lock().unwrap().net)
1625584784a0SPurna Pavan Chandra         {
1626584784a0SPurna Pavan Chandra             for net in restored_nets.iter() {
1627584784a0SPurna Pavan Chandra                 for net_config in vm_net_configs.iter_mut() {
1628584784a0SPurna Pavan Chandra                     // update only if the net dev is backed by FDs
1629584784a0SPurna Pavan Chandra                     if net_config.id == Some(net.id.clone()) && net_config.fds.is_some() {
1630584784a0SPurna Pavan Chandra                         net_config.fds.clone_from(&net.fds);
1631584784a0SPurna Pavan Chandra                     }
1632584784a0SPurna Pavan Chandra                 }
1633584784a0SPurna Pavan Chandra             }
1634584784a0SPurna Pavan Chandra         }
1635584784a0SPurna Pavan Chandra 
16368f98fabdSBo Chen         self.vm_restore(source_url, vm_config, restore_cfg.prefault)
16378f98fabdSBo Chen             .map_err(|vm_restore_err| {
16388f98fabdSBo Chen                 error!("VM Restore failed: {:?}", vm_restore_err);
16396eb72130SSebastien Boeuf 
16408f98fabdSBo Chen                 // Cleanup the VM being created while vm restore
16418f98fabdSBo Chen                 if let Err(e) = self.vm_delete() {
16428f98fabdSBo Chen                     return e;
1643eea45a2cSPraveen K Paladugu                 }
1644eea45a2cSPraveen K Paladugu 
16458f98fabdSBo Chen                 vm_restore_err
16468f98fabdSBo Chen             })
164792c73c3bSSamuel Ortiz     }
164892c73c3bSSamuel Ortiz 
1649cefbf6b4SRob Bradford     #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
vm_coredump(&mut self, destination_url: &str) -> result::Result<(), VmError>16508b585b96SYi Wang     fn vm_coredump(&mut self, destination_url: &str) -> result::Result<(), VmError> {
16518b585b96SYi Wang         if let Some(ref mut vm) = self.vm {
16528b585b96SYi Wang             vm.coredump(destination_url).map_err(VmError::Coredump)
16538b585b96SYi Wang         } else {
16548b585b96SYi Wang             Err(VmError::VmNotRunning)
16558b585b96SYi Wang         }
16568b585b96SYi Wang     }
16578b585b96SYi Wang 
vm_shutdown(&mut self) -> result::Result<(), VmError>1658f9daf2e2SSamuel Ortiz     fn vm_shutdown(&mut self) -> result::Result<(), VmError> {
16596922e25eSBo Chen         let r = if let Some(ref mut vm) = self.vm.take() {
1660380ba564SPraveen K Paladugu             // Drain console_info so that the FDs are not reused
1661380ba564SPraveen K Paladugu             let _ = self.console_info.take();
1662f9daf2e2SSamuel Ortiz             vm.shutdown()
1663f9daf2e2SSamuel Ortiz         } else {
1664d2d3abb1SSamuel Ortiz             Err(VmError::VmNotRunning)
16656922e25eSBo Chen         };
16666922e25eSBo Chen 
16676922e25eSBo Chen         if r.is_ok() {
16686922e25eSBo Chen             event!("vm", "shutdown");
1669f9daf2e2SSamuel Ortiz         }
16706922e25eSBo Chen 
16716922e25eSBo Chen         r
1672f9daf2e2SSamuel Ortiz     }
1673f9daf2e2SSamuel Ortiz 
vm_reboot(&mut self) -> result::Result<(), VmError>167443b36429SSamuel Ortiz     fn vm_reboot(&mut self) -> result::Result<(), VmError> {
167555678b23SWei Liu         event!("vm", "rebooting");
167655678b23SWei Liu 
16779c95109aSSebastien Boeuf         // First we stop the current VM
1678a0ae3ad1SBharatNarasimman         let config = if let Some(mut vm) = self.vm.take() {
16798a5e47f9SSamuel Ortiz             let config = vm.get_config();
16809c95109aSSebastien Boeuf             vm.shutdown()?;
1681a0ae3ad1SBharatNarasimman             config
16829c95109aSSebastien Boeuf         } else {
16839c95109aSSebastien Boeuf             return Err(VmError::VmNotCreated);
16849c95109aSSebastien Boeuf         };
16858a5e47f9SSamuel Ortiz 
1686380ba564SPraveen K Paladugu         // vm.shutdown() closes all the console devices, so set console_info to None
1687380ba564SPraveen K Paladugu         // so that the closed FD #s are not reused.
1688380ba564SPraveen K Paladugu         let _ = self.console_info.take();
1689380ba564SPraveen K Paladugu 
169043b36429SSamuel Ortiz         let exit_evt = self.exit_evt.try_clone().map_err(VmError::EventFdClone)?;
169143b36429SSamuel Ortiz         let reset_evt = self.reset_evt.try_clone().map_err(VmError::EventFdClone)?;
169206eb82d2SRob Bradford         #[cfg(feature = "guest_debug")]
16932451c4d8SAkira Moroo         let debug_evt = self
16942451c4d8SAkira Moroo             .vm_debug_evt
16952451c4d8SAkira Moroo             .try_clone()
16962451c4d8SAkira Moroo             .map_err(VmError::EventFdClone)?;
169703db4830SRob Bradford         let activate_evt = self
169803db4830SRob Bradford             .activate_evt
169903db4830SRob Bradford             .try_clone()
170003db4830SRob Bradford             .map_err(VmError::EventFdClone)?;
17018a5e47f9SSamuel Ortiz 
1702ed1e7817SRob Bradford         // The Linux kernel fires off an i8042 reset after doing the ACPI reset so there may be
1703ed1e7817SRob Bradford         // an event sitting in the shared reset_evt. Without doing this we get very early reboots
1704ed1e7817SRob Bradford         // during the boot process.
1705ed1e7817SRob Bradford         if self.reset_evt.read().is_ok() {
1706ed1e7817SRob Bradford             warn!("Spurious second reset event received. Ignoring.");
1707ed1e7817SRob Bradford         }
17089c95109aSSebastien Boeuf 
1709380ba564SPraveen K Paladugu         self.console_info =
1710380ba564SPraveen K Paladugu             Some(pre_create_console_devices(self).map_err(VmError::CreateConsoleDevices)?);
1711380ba564SPraveen K Paladugu 
17129c95109aSSebastien Boeuf         // Then we create the new VM
17139c95109aSSebastien Boeuf         let mut vm = Vm::new(
1714e4dee57eSMuminul Islam             config,
1715e4dee57eSMuminul Islam             exit_evt,
1716e4dee57eSMuminul Islam             reset_evt,
171706eb82d2SRob Bradford             #[cfg(feature = "guest_debug")]
17182451c4d8SAkira Moroo             debug_evt,
1719ff7ed8f6SBo Chen             &self.seccomp_action,
1720e4dee57eSMuminul Islam             self.hypervisor.clone(),
172103db4830SRob Bradford             activate_evt,
172252eebaf6SPraveen K Paladugu             self.console_info.clone(),
1723ab12e7c2SSongqian Li             self.console_resize_pipe.clone(),
1724c90a0fffSAlyssa Ross             Arc::clone(&self.original_termios_opt),
1725e8c6d83fSSebastien Boeuf             None,
1726e8c6d83fSSebastien Boeuf             None,
1727e8c6d83fSSebastien Boeuf             None,
17289c95109aSSebastien Boeuf         )?;
17298a5e47f9SSamuel Ortiz 
17309c95109aSSebastien Boeuf         // And we boot it
17319c95109aSSebastien Boeuf         vm.boot()?;
17329c95109aSSebastien Boeuf 
17339c95109aSSebastien Boeuf         self.vm = Some(vm);
17349c95109aSSebastien Boeuf 
173555678b23SWei Liu         event!("vm", "rebooted");
173655678b23SWei Liu 
17379c95109aSSebastien Boeuf         Ok(())
17388a5e47f9SSamuel Ortiz     }
17398a5e47f9SSamuel Ortiz 
vm_info(&self) -> result::Result<VmInfoResponse, VmError>17404ca18c08SAlyssa Ross     fn vm_info(&self) -> result::Result<VmInfoResponse, VmError> {
174142758244SSamuel Ortiz         match &self.vm_config {
1742cc9899e0SSongqian Li             Some(vm_config) => {
174342758244SSamuel Ortiz                 let state = match &self.vm {
174443b36429SSamuel Ortiz                     Some(vm) => vm.get_state()?,
174542758244SSamuel Ortiz                     None => VmState::Created,
174642758244SSamuel Ortiz                 };
1747cc9899e0SSongqian Li                 let config = vm_config.lock().unwrap().clone();
174842758244SSamuel Ortiz 
1749cc9899e0SSongqian Li                 let mut memory_actual_size = config.memory.total_size();
1750c75f8b2fSHui Zhu                 if let Some(vm) = &self.vm {
175135946852SSebastien Boeuf                     memory_actual_size -= vm.balloon_size();
1752c75f8b2fSHui Zhu                 }
1753c75f8b2fSHui Zhu 
1754cc9899e0SSongqian Li                 let device_tree = self
1755cc9899e0SSongqian Li                     .vm
1756cc9899e0SSongqian Li                     .as_ref()
1757cc9899e0SSongqian Li                     .map(|vm| vm.device_tree().lock().unwrap().clone());
1758280d4fb2SRob Bradford 
17594ca18c08SAlyssa Ross                 Ok(VmInfoResponse {
1760cc9899e0SSongqian Li                     config: Box::new(config),
176142758244SSamuel Ortiz                     state,
1762c75f8b2fSHui Zhu                     memory_actual_size,
1763280d4fb2SRob Bradford                     device_tree,
176442758244SSamuel Ortiz                 })
176542758244SSamuel Ortiz             }
176643b36429SSamuel Ortiz             None => Err(VmError::VmNotCreated),
176742758244SSamuel Ortiz         }
176842758244SSamuel Ortiz     }
176942758244SSamuel Ortiz 
vmm_ping(&self) -> VmmPingResponse17709c5be6f6SRob Bradford     fn vmm_ping(&self) -> VmmPingResponse {
1771346ee09eSOmer Faruk Bayram         let VmmVersionInfo {
1772346ee09eSOmer Faruk Bayram             build_version,
1773346ee09eSOmer Faruk Bayram             version,
1774346ee09eSOmer Faruk Bayram         } = self.version.clone();
1775346ee09eSOmer Faruk Bayram 
17769c5be6f6SRob Bradford         VmmPingResponse {
1777346ee09eSOmer Faruk Bayram             build_version,
1778346ee09eSOmer Faruk Bayram             version,
1779346ee09eSOmer Faruk Bayram             pid: std::process::id() as i64,
1780ff651e0eSBo Chen             features: feature_list(),
17819c5be6f6SRob Bradford         }
1782a5186514SJose Carlos Venegas Munoz     }
1783a5186514SJose Carlos Venegas Munoz 
vm_delete(&mut self) -> result::Result<(), VmError>17847328ecdbSSamuel Ortiz     fn vm_delete(&mut self) -> result::Result<(), VmError> {
17857328ecdbSSamuel Ortiz         if self.vm_config.is_none() {
17867328ecdbSSamuel Ortiz             return Ok(());
17877328ecdbSSamuel Ortiz         }
17887328ecdbSSamuel Ortiz 
1789625bab69SBo Chen         // If a VM is booted, we first try to shut it down.
1790625bab69SBo Chen         if self.vm.is_some() {
1791228adebcSSamuel Ortiz             self.vm_shutdown()?;
1792625bab69SBo Chen         }
17937328ecdbSSamuel Ortiz 
1794228adebcSSamuel Ortiz         self.vm_config = None;
17957328ecdbSSamuel Ortiz 
17969260c4c1SRob Bradford         event!("vm", "deleted");
17979260c4c1SRob Bradford 
17987328ecdbSSamuel Ortiz         Ok(())
17997328ecdbSSamuel Ortiz     }
18007328ecdbSSamuel Ortiz 
vmm_shutdown(&mut self) -> result::Result<(), VmError>1801a95fa1c4SSamuel Ortiz     fn vmm_shutdown(&mut self) -> result::Result<(), VmError> {
18029260c4c1SRob Bradford         self.vm_delete()?;
18039260c4c1SRob Bradford         event!("vmm", "shutdown");
18049260c4c1SRob Bradford         Ok(())
1805a95fa1c4SSamuel Ortiz     }
1806a95fa1c4SSamuel Ortiz 
vm_resize( &mut self, desired_vcpus: Option<u8>, desired_ram: Option<u64>, desired_balloon: Option<u64>, ) -> result::Result<(), VmError>180782fce5a4SRob Bradford     fn vm_resize(
180882fce5a4SRob Bradford         &mut self,
180982fce5a4SRob Bradford         desired_vcpus: Option<u8>,
181082fce5a4SRob Bradford         desired_ram: Option<u64>,
181135946852SSebastien Boeuf         desired_balloon: Option<u64>,
181282fce5a4SRob Bradford     ) -> result::Result<(), VmError> {
18135d2db68fSFabiano Fidêncio         self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
18145d2db68fSFabiano Fidêncio 
181586339b4cSRob Bradford         if let Some(ref mut vm) = self.vm {
181635946852SSebastien Boeuf             if let Err(e) = vm.resize(desired_vcpus, desired_ram, desired_balloon) {
18173901a1ddSRob Bradford                 error!("Error when resizing VM: {:?}", e);
18183901a1ddSRob Bradford                 Err(e)
18193901a1ddSRob Bradford             } else {
18203901a1ddSRob Bradford                 Ok(())
18213901a1ddSRob Bradford             }
182286339b4cSRob Bradford         } else {
18235d2db68fSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
18245d2db68fSFabiano Fidêncio             if let Some(desired_vcpus) = desired_vcpus {
18255d2db68fSFabiano Fidêncio                 config.cpus.boot_vcpus = desired_vcpus;
18265d2db68fSFabiano Fidêncio             }
18275d2db68fSFabiano Fidêncio             if let Some(desired_ram) = desired_ram {
18285d2db68fSFabiano Fidêncio                 config.memory.size = desired_ram;
18295d2db68fSFabiano Fidêncio             }
18305d2db68fSFabiano Fidêncio             if let Some(desired_balloon) = desired_balloon {
18315d2db68fSFabiano Fidêncio                 if let Some(balloon_config) = &mut config.balloon {
18325d2db68fSFabiano Fidêncio                     balloon_config.size = desired_balloon;
18335d2db68fSFabiano Fidêncio                 }
18345d2db68fSFabiano Fidêncio             }
18355d2db68fSFabiano Fidêncio             Ok(())
183686339b4cSRob Bradford         }
183786339b4cSRob Bradford     }
183886339b4cSRob Bradford 
vm_resize_zone(&mut self, id: String, desired_ram: u64) -> result::Result<(), VmError>1839015c7841SSebastien Boeuf     fn vm_resize_zone(&mut self, id: String, desired_ram: u64) -> result::Result<(), VmError> {
18405d2db68fSFabiano Fidêncio         self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
18415d2db68fSFabiano Fidêncio 
1842015c7841SSebastien Boeuf         if let Some(ref mut vm) = self.vm {
1843015c7841SSebastien Boeuf             if let Err(e) = vm.resize_zone(id, desired_ram) {
1844015c7841SSebastien Boeuf                 error!("Error when resizing VM: {:?}", e);
1845015c7841SSebastien Boeuf                 Err(e)
1846015c7841SSebastien Boeuf             } else {
1847015c7841SSebastien Boeuf                 Ok(())
1848015c7841SSebastien Boeuf             }
1849015c7841SSebastien Boeuf         } else {
18505d2db68fSFabiano Fidêncio             // Update VmConfig by setting the new desired ram.
18515d2db68fSFabiano Fidêncio             let memory_config = &mut self.vm_config.as_ref().unwrap().lock().unwrap().memory;
18525d2db68fSFabiano Fidêncio 
18535d2db68fSFabiano Fidêncio             if let Some(zones) = &mut memory_config.zones {
18545d2db68fSFabiano Fidêncio                 for zone in zones.iter_mut() {
18555d2db68fSFabiano Fidêncio                     if zone.id == id {
18565d2db68fSFabiano Fidêncio                         zone.size = desired_ram;
18575d2db68fSFabiano Fidêncio                         return Ok(());
18585d2db68fSFabiano Fidêncio                     }
1859015c7841SSebastien Boeuf                 }
1860015c7841SSebastien Boeuf             }
1861015c7841SSebastien Boeuf 
18625d2db68fSFabiano Fidêncio             error!("Could not find the memory zone {} for the resize", id);
18635d2db68fSFabiano Fidêncio             Err(VmError::ResizeZone)
18645d2db68fSFabiano Fidêncio         }
18655d2db68fSFabiano Fidêncio     }
18665d2db68fSFabiano Fidêncio 
vm_add_device( &mut self, device_cfg: DeviceConfig, ) -> result::Result<Option<Vec<u8>>, VmError>18675d2db68fSFabiano Fidêncio     fn vm_add_device(
18685d2db68fSFabiano Fidêncio         &mut self,
18695d2db68fSFabiano Fidêncio         device_cfg: DeviceConfig,
18705d2db68fSFabiano Fidêncio     ) -> result::Result<Option<Vec<u8>>, VmError> {
187116782e8cSFabiano Fidêncio         self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
187216782e8cSFabiano Fidêncio 
187316782e8cSFabiano Fidêncio         {
187416782e8cSFabiano Fidêncio             // Validate the configuration change in a cloned configuration
187516782e8cSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
187616782e8cSFabiano Fidêncio             add_to_config(&mut config.devices, device_cfg.clone());
187716782e8cSFabiano Fidêncio             config.validate().map_err(VmError::ConfigValidation)?;
187816782e8cSFabiano Fidêncio         }
187916782e8cSFabiano Fidêncio 
18800e58741aSSebastien Boeuf         if let Some(ref mut vm) = self.vm {
188183cd9969SSebastien Boeuf             let info = vm.add_device(device_cfg).map_err(|e| {
18820e58741aSSebastien Boeuf                 error!("Error when adding new device to the VM: {:?}", e);
188383cd9969SSebastien Boeuf                 e
188483cd9969SSebastien Boeuf             })?;
18855d2db68fSFabiano Fidêncio             serde_json::to_vec(&info)
18865d2db68fSFabiano Fidêncio                 .map(Some)
18875d2db68fSFabiano Fidêncio                 .map_err(VmError::SerializeJson)
18880e58741aSSebastien Boeuf         } else {
18895d2db68fSFabiano Fidêncio             // Update VmConfig by adding the new device.
18905d2db68fSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
18915d2db68fSFabiano Fidêncio             add_to_config(&mut config.devices, device_cfg);
18925d2db68fSFabiano Fidêncio             Ok(None)
18930e58741aSSebastien Boeuf         }
18940e58741aSSebastien Boeuf     }
18950e58741aSSebastien Boeuf 
vm_add_user_device( &mut self, device_cfg: UserDeviceConfig, ) -> result::Result<Option<Vec<u8>>, VmError>189653b2e199SRob Bradford     fn vm_add_user_device(
189753b2e199SRob Bradford         &mut self,
189853b2e199SRob Bradford         device_cfg: UserDeviceConfig,
18995d2db68fSFabiano Fidêncio     ) -> result::Result<Option<Vec<u8>>, VmError> {
190016782e8cSFabiano Fidêncio         self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
190116782e8cSFabiano Fidêncio 
190216782e8cSFabiano Fidêncio         {
190316782e8cSFabiano Fidêncio             // Validate the configuration change in a cloned configuration
190416782e8cSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
190516782e8cSFabiano Fidêncio             add_to_config(&mut config.user_devices, device_cfg.clone());
190616782e8cSFabiano Fidêncio             config.validate().map_err(VmError::ConfigValidation)?;
190716782e8cSFabiano Fidêncio         }
190816782e8cSFabiano Fidêncio 
190953b2e199SRob Bradford         if let Some(ref mut vm) = self.vm {
191053b2e199SRob Bradford             let info = vm.add_user_device(device_cfg).map_err(|e| {
191153b2e199SRob Bradford                 error!("Error when adding new user device to the VM: {:?}", e);
191253b2e199SRob Bradford                 e
191353b2e199SRob Bradford             })?;
19145d2db68fSFabiano Fidêncio             serde_json::to_vec(&info)
19155d2db68fSFabiano Fidêncio                 .map(Some)
19165d2db68fSFabiano Fidêncio                 .map_err(VmError::SerializeJson)
191753b2e199SRob Bradford         } else {
19185d2db68fSFabiano Fidêncio             // Update VmConfig by adding the new device.
19195d2db68fSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
19205d2db68fSFabiano Fidêncio             add_to_config(&mut config.user_devices, device_cfg);
19215d2db68fSFabiano Fidêncio             Ok(None)
192253b2e199SRob Bradford         }
192353b2e199SRob Bradford     }
192453b2e199SRob Bradford 
vm_remove_device(&mut self, id: String) -> result::Result<(), VmError>19256cbdb9aaSSebastien Boeuf     fn vm_remove_device(&mut self, id: String) -> result::Result<(), VmError> {
19266cbdb9aaSSebastien Boeuf         if let Some(ref mut vm) = self.vm {
19276cbdb9aaSSebastien Boeuf             if let Err(e) = vm.remove_device(id) {
192869bd0036SAlyssa Ross                 error!("Error when removing device from the VM: {:?}", e);
19296cbdb9aaSSebastien Boeuf                 Err(e)
19306cbdb9aaSSebastien Boeuf             } else {
19316cbdb9aaSSebastien Boeuf                 Ok(())
19326cbdb9aaSSebastien Boeuf             }
193369bd0036SAlyssa Ross         } else if let Some(ref config) = self.vm_config {
193469bd0036SAlyssa Ross             let mut config = config.lock().unwrap();
193569bd0036SAlyssa Ross             if config.remove_device(&id) {
193669bd0036SAlyssa Ross                 Ok(())
19376cbdb9aaSSebastien Boeuf             } else {
193869bd0036SAlyssa Ross                 Err(VmError::NoDeviceToRemove(id))
193969bd0036SAlyssa Ross             }
194069bd0036SAlyssa Ross         } else {
194169bd0036SAlyssa Ross             Err(VmError::VmNotCreated)
19426cbdb9aaSSebastien Boeuf         }
19436cbdb9aaSSebastien Boeuf     }
19446cbdb9aaSSebastien Boeuf 
vm_add_disk(&mut self, disk_cfg: DiskConfig) -> result::Result<Option<Vec<u8>>, VmError>19455d2db68fSFabiano Fidêncio     fn vm_add_disk(&mut self, disk_cfg: DiskConfig) -> result::Result<Option<Vec<u8>>, VmError> {
194616782e8cSFabiano Fidêncio         self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
194716782e8cSFabiano Fidêncio 
194816782e8cSFabiano Fidêncio         {
194916782e8cSFabiano Fidêncio             // Validate the configuration change in a cloned configuration
195016782e8cSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
195116782e8cSFabiano Fidêncio             add_to_config(&mut config.disks, disk_cfg.clone());
195216782e8cSFabiano Fidêncio             config.validate().map_err(VmError::ConfigValidation)?;
195316782e8cSFabiano Fidêncio         }
195416782e8cSFabiano Fidêncio 
1955f2151b27SRob Bradford         if let Some(ref mut vm) = self.vm {
195683cd9969SSebastien Boeuf             let info = vm.add_disk(disk_cfg).map_err(|e| {
1957f2151b27SRob Bradford                 error!("Error when adding new disk to the VM: {:?}", e);
195883cd9969SSebastien Boeuf                 e
195983cd9969SSebastien Boeuf             })?;
19605d2db68fSFabiano Fidêncio             serde_json::to_vec(&info)
19615d2db68fSFabiano Fidêncio                 .map(Some)
19625d2db68fSFabiano Fidêncio                 .map_err(VmError::SerializeJson)
1963f2151b27SRob Bradford         } else {
19645d2db68fSFabiano Fidêncio             // Update VmConfig by adding the new device.
19655d2db68fSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
19665d2db68fSFabiano Fidêncio             add_to_config(&mut config.disks, disk_cfg);
19675d2db68fSFabiano Fidêncio             Ok(None)
1968f2151b27SRob Bradford         }
1969f2151b27SRob Bradford     }
1970f2151b27SRob Bradford 
vm_add_fs(&mut self, fs_cfg: FsConfig) -> result::Result<Option<Vec<u8>>, VmError>19715d2db68fSFabiano Fidêncio     fn vm_add_fs(&mut self, fs_cfg: FsConfig) -> result::Result<Option<Vec<u8>>, VmError> {
197216782e8cSFabiano Fidêncio         self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
197316782e8cSFabiano Fidêncio 
197416782e8cSFabiano Fidêncio         {
197516782e8cSFabiano Fidêncio             // Validate the configuration change in a cloned configuration
197616782e8cSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
197716782e8cSFabiano Fidêncio             add_to_config(&mut config.fs, fs_cfg.clone());
197816782e8cSFabiano Fidêncio             config.validate().map_err(VmError::ConfigValidation)?;
197916782e8cSFabiano Fidêncio         }
198016782e8cSFabiano Fidêncio 
1981c2abadc2SDean Sheather         if let Some(ref mut vm) = self.vm {
198283cd9969SSebastien Boeuf             let info = vm.add_fs(fs_cfg).map_err(|e| {
1983c2abadc2SDean Sheather                 error!("Error when adding new fs to the VM: {:?}", e);
198483cd9969SSebastien Boeuf                 e
198583cd9969SSebastien Boeuf             })?;
19865d2db68fSFabiano Fidêncio             serde_json::to_vec(&info)
19875d2db68fSFabiano Fidêncio                 .map(Some)
19885d2db68fSFabiano Fidêncio                 .map_err(VmError::SerializeJson)
1989c2abadc2SDean Sheather         } else {
19905d2db68fSFabiano Fidêncio             // Update VmConfig by adding the new device.
19915d2db68fSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
19925d2db68fSFabiano Fidêncio             add_to_config(&mut config.fs, fs_cfg);
19935d2db68fSFabiano Fidêncio             Ok(None)
1994c2abadc2SDean Sheather         }
1995c2abadc2SDean Sheather     }
1996c2abadc2SDean Sheather 
vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> result::Result<Option<Vec<u8>>, VmError>19975d2db68fSFabiano Fidêncio     fn vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> result::Result<Option<Vec<u8>>, VmError> {
199816782e8cSFabiano Fidêncio         self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
199916782e8cSFabiano Fidêncio 
200016782e8cSFabiano Fidêncio         {
200116782e8cSFabiano Fidêncio             // Validate the configuration change in a cloned configuration
200216782e8cSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
200316782e8cSFabiano Fidêncio             add_to_config(&mut config.pmem, pmem_cfg.clone());
200416782e8cSFabiano Fidêncio             config.validate().map_err(VmError::ConfigValidation)?;
200516782e8cSFabiano Fidêncio         }
200616782e8cSFabiano Fidêncio 
2007f6f4c68fSRob Bradford         if let Some(ref mut vm) = self.vm {
200883cd9969SSebastien Boeuf             let info = vm.add_pmem(pmem_cfg).map_err(|e| {
2009f6f4c68fSRob Bradford                 error!("Error when adding new pmem device to the VM: {:?}", e);
201083cd9969SSebastien Boeuf                 e
201183cd9969SSebastien Boeuf             })?;
20125d2db68fSFabiano Fidêncio             serde_json::to_vec(&info)
20135d2db68fSFabiano Fidêncio                 .map(Some)
20145d2db68fSFabiano Fidêncio                 .map_err(VmError::SerializeJson)
2015f6f4c68fSRob Bradford         } else {
20165d2db68fSFabiano Fidêncio             // Update VmConfig by adding the new device.
20175d2db68fSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
20185d2db68fSFabiano Fidêncio             add_to_config(&mut config.pmem, pmem_cfg);
20195d2db68fSFabiano Fidêncio             Ok(None)
2020f6f4c68fSRob Bradford         }
2021f6f4c68fSRob Bradford     }
2022f6f4c68fSRob Bradford 
vm_add_net(&mut self, net_cfg: NetConfig) -> result::Result<Option<Vec<u8>>, VmError>20235d2db68fSFabiano Fidêncio     fn vm_add_net(&mut self, net_cfg: NetConfig) -> result::Result<Option<Vec<u8>>, VmError> {
202416782e8cSFabiano Fidêncio         self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
202516782e8cSFabiano Fidêncio 
202616782e8cSFabiano Fidêncio         {
202716782e8cSFabiano Fidêncio             // Validate the configuration change in a cloned configuration
202816782e8cSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
202916782e8cSFabiano Fidêncio             add_to_config(&mut config.net, net_cfg.clone());
203016782e8cSFabiano Fidêncio             config.validate().map_err(VmError::ConfigValidation)?;
203116782e8cSFabiano Fidêncio         }
203216782e8cSFabiano Fidêncio 
203357c3fa4bSRob Bradford         if let Some(ref mut vm) = self.vm {
203483cd9969SSebastien Boeuf             let info = vm.add_net(net_cfg).map_err(|e| {
203557c3fa4bSRob Bradford                 error!("Error when adding new network device to the VM: {:?}", e);
203683cd9969SSebastien Boeuf                 e
203783cd9969SSebastien Boeuf             })?;
20385d2db68fSFabiano Fidêncio             serde_json::to_vec(&info)
20395d2db68fSFabiano Fidêncio                 .map(Some)
20405d2db68fSFabiano Fidêncio                 .map_err(VmError::SerializeJson)
204157c3fa4bSRob Bradford         } else {
20425d2db68fSFabiano Fidêncio             // Update VmConfig by adding the new device.
20435d2db68fSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
20445d2db68fSFabiano Fidêncio             add_to_config(&mut config.net, net_cfg);
20455d2db68fSFabiano Fidêncio             Ok(None)
204657c3fa4bSRob Bradford         }
204757c3fa4bSRob Bradford     }
204857c3fa4bSRob Bradford 
vm_add_vdpa(&mut self, vdpa_cfg: VdpaConfig) -> result::Result<Option<Vec<u8>>, VmError>20493fea5f53SSebastien Boeuf     fn vm_add_vdpa(&mut self, vdpa_cfg: VdpaConfig) -> result::Result<Option<Vec<u8>>, VmError> {
20503fea5f53SSebastien Boeuf         self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
20513fea5f53SSebastien Boeuf 
20523fea5f53SSebastien Boeuf         {
20533fea5f53SSebastien Boeuf             // Validate the configuration change in a cloned configuration
20543fea5f53SSebastien Boeuf             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
20553fea5f53SSebastien Boeuf             add_to_config(&mut config.vdpa, vdpa_cfg.clone());
20563fea5f53SSebastien Boeuf             config.validate().map_err(VmError::ConfigValidation)?;
20573fea5f53SSebastien Boeuf         }
20583fea5f53SSebastien Boeuf 
20593fea5f53SSebastien Boeuf         if let Some(ref mut vm) = self.vm {
20603fea5f53SSebastien Boeuf             let info = vm.add_vdpa(vdpa_cfg).map_err(|e| {
20613fea5f53SSebastien Boeuf                 error!("Error when adding new vDPA device to the VM: {:?}", e);
20623fea5f53SSebastien Boeuf                 e
20633fea5f53SSebastien Boeuf             })?;
20643fea5f53SSebastien Boeuf             serde_json::to_vec(&info)
20653fea5f53SSebastien Boeuf                 .map(Some)
20663fea5f53SSebastien Boeuf                 .map_err(VmError::SerializeJson)
20673fea5f53SSebastien Boeuf         } else {
20683fea5f53SSebastien Boeuf             // Update VmConfig by adding the new device.
20693fea5f53SSebastien Boeuf             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
20703fea5f53SSebastien Boeuf             add_to_config(&mut config.vdpa, vdpa_cfg);
20713fea5f53SSebastien Boeuf             Ok(None)
20723fea5f53SSebastien Boeuf         }
20733fea5f53SSebastien Boeuf     }
20743fea5f53SSebastien Boeuf 
vm_add_vsock(&mut self, vsock_cfg: VsockConfig) -> result::Result<Option<Vec<u8>>, VmError>20755d2db68fSFabiano Fidêncio     fn vm_add_vsock(&mut self, vsock_cfg: VsockConfig) -> result::Result<Option<Vec<u8>>, VmError> {
207616782e8cSFabiano Fidêncio         self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
207716782e8cSFabiano Fidêncio 
207816782e8cSFabiano Fidêncio         {
207916782e8cSFabiano Fidêncio             // Validate the configuration change in a cloned configuration
208016782e8cSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
208116782e8cSFabiano Fidêncio 
208216782e8cSFabiano Fidêncio             if config.vsock.is_some() {
208316782e8cSFabiano Fidêncio                 return Err(VmError::TooManyVsockDevices);
208416782e8cSFabiano Fidêncio             }
208516782e8cSFabiano Fidêncio 
208616782e8cSFabiano Fidêncio             config.vsock = Some(vsock_cfg.clone());
208716782e8cSFabiano Fidêncio             config.validate().map_err(VmError::ConfigValidation)?;
208816782e8cSFabiano Fidêncio         }
208916782e8cSFabiano Fidêncio 
20908de7448dSRob Bradford         if let Some(ref mut vm) = self.vm {
209183cd9969SSebastien Boeuf             let info = vm.add_vsock(vsock_cfg).map_err(|e| {
20928de7448dSRob Bradford                 error!("Error when adding new vsock device to the VM: {:?}", e);
209383cd9969SSebastien Boeuf                 e
209483cd9969SSebastien Boeuf             })?;
20955d2db68fSFabiano Fidêncio             serde_json::to_vec(&info)
20965d2db68fSFabiano Fidêncio                 .map(Some)
20975d2db68fSFabiano Fidêncio                 .map_err(VmError::SerializeJson)
20988de7448dSRob Bradford         } else {
20995d2db68fSFabiano Fidêncio             // Update VmConfig by adding the new device.
21005d2db68fSFabiano Fidêncio             let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
21015d2db68fSFabiano Fidêncio             config.vsock = Some(vsock_cfg);
21025d2db68fSFabiano Fidêncio             Ok(None)
21038de7448dSRob Bradford         }
21048de7448dSRob Bradford     }
21058de7448dSRob Bradford 
vm_counters(&mut self) -> result::Result<Option<Vec<u8>>, VmError>21065d2db68fSFabiano Fidêncio     fn vm_counters(&mut self) -> result::Result<Option<Vec<u8>>, VmError> {
2107bca8a192SRob Bradford         if let Some(ref mut vm) = self.vm {
2108bca8a192SRob Bradford             let info = vm.counters().map_err(|e| {
2109bca8a192SRob Bradford                 error!("Error when getting counters from the VM: {:?}", e);
2110bca8a192SRob Bradford                 e
2111bca8a192SRob Bradford             })?;
21125d2db68fSFabiano Fidêncio             serde_json::to_vec(&info)
21135d2db68fSFabiano Fidêncio                 .map(Some)
21145d2db68fSFabiano Fidêncio                 .map_err(VmError::SerializeJson)
2115bca8a192SRob Bradford         } else {
2116bca8a192SRob Bradford             Err(VmError::VmNotRunning)
2117bca8a192SRob Bradford         }
2118bca8a192SRob Bradford     }
2119bca8a192SRob Bradford 
vm_power_button(&mut self) -> result::Result<(), VmError>2120981bb72aSRob Bradford     fn vm_power_button(&mut self) -> result::Result<(), VmError> {
2121981bb72aSRob Bradford         if let Some(ref mut vm) = self.vm {
2122981bb72aSRob Bradford             vm.power_button()
2123981bb72aSRob Bradford         } else {
2124981bb72aSRob Bradford             Err(VmError::VmNotRunning)
2125981bb72aSRob Bradford         }
2126981bb72aSRob Bradford     }
2127981bb72aSRob Bradford 
vm_nmi(&mut self) -> result::Result<(), VmError>2128f40dd4a9SYi Wang     fn vm_nmi(&mut self) -> result::Result<(), VmError> {
2129f40dd4a9SYi Wang         if let Some(ref mut vm) = self.vm {
2130c72bf0b3SYi Wang             vm.nmi()
2131f40dd4a9SYi Wang         } else {
2132f40dd4a9SYi Wang             Err(VmError::VmNotRunning)
2133f40dd4a9SYi Wang         }
2134f40dd4a9SYi Wang     }
2135f40dd4a9SYi Wang 
vm_receive_migration( &mut self, receive_data_migration: VmReceiveMigrationData, ) -> result::Result<(), MigratableError>21367ac76451SRob Bradford     fn vm_receive_migration(
21377ac76451SRob Bradford         &mut self,
21387ac76451SRob Bradford         receive_data_migration: VmReceiveMigrationData,
21397ac76451SRob Bradford     ) -> result::Result<(), MigratableError> {
21407ac76451SRob Bradford         info!(
2141ca60addaSRob Bradford             "Receiving migration: receiver_url = {}",
21427ac76451SRob Bradford             receive_data_migration.receiver_url
21437ac76451SRob Bradford         );
2144ca60addaSRob Bradford 
2145909e1bc3SJinrong Liang         // Accept the connection and get the socket
2146909e1bc3SJinrong Liang         let mut socket = Vmm::receive_migration_socket(&receive_data_migration.receiver_url)?;
2147ca60addaSRob Bradford 
2148ca60addaSRob Bradford         let mut started = false;
2149c52ccf39SSebastien Boeuf         let mut memory_manager: Option<Arc<Mutex<MemoryManager>>> = None;
21501daef5e8SRob Bradford         let mut existing_memory_files = None;
2151ca60addaSRob Bradford         loop {
2152ca60addaSRob Bradford             let req = Request::read_from(&mut socket)?;
2153ca60addaSRob Bradford             match req.command() {
2154ca60addaSRob Bradford                 Command::Invalid => info!("Invalid Command Received"),
2155ca60addaSRob Bradford                 Command::Start => {
2156ca60addaSRob Bradford                     info!("Start Command Received");
2157ca60addaSRob Bradford                     started = true;
2158ca60addaSRob Bradford 
2159ca60addaSRob Bradford                     Response::ok().write_to(&mut socket)?;
2160ca60addaSRob Bradford                 }
216111a69450SRob Bradford                 Command::Config => {
216211a69450SRob Bradford                     info!("Config Command Received");
216311a69450SRob Bradford 
216411a69450SRob Bradford                     if !started {
216511a69450SRob Bradford                         warn!("Migration not started yet");
216611a69450SRob Bradford                         Response::error().write_to(&mut socket)?;
216711a69450SRob Bradford                         continue;
216811a69450SRob Bradford                     }
2169c52ccf39SSebastien Boeuf                     memory_manager = Some(self.vm_receive_config(
21701daef5e8SRob Bradford                         &req,
21711daef5e8SRob Bradford                         &mut socket,
21721daef5e8SRob Bradford                         existing_memory_files.take(),
21731daef5e8SRob Bradford                     )?);
217411a69450SRob Bradford                 }
2175ca60addaSRob Bradford                 Command::State => {
2176ca60addaSRob Bradford                     info!("State Command Received");
2177ca60addaSRob Bradford 
2178ca60addaSRob Bradford                     if !started {
2179ca60addaSRob Bradford                         warn!("Migration not started yet");
2180ca60addaSRob Bradford                         Response::error().write_to(&mut socket)?;
2181ca60addaSRob Bradford                         continue;
2182ca60addaSRob Bradford                     }
2183c52ccf39SSebastien Boeuf                     if let Some(mm) = memory_manager.take() {
2184c52ccf39SSebastien Boeuf                         self.vm_receive_state(&req, &mut socket, mm)?;
218511a69450SRob Bradford                     } else {
218611a69450SRob Bradford                         warn!("Configuration not sent yet");
2187ca60addaSRob Bradford                         Response::error().write_to(&mut socket)?;
2188ca60addaSRob Bradford                     }
2189ca60addaSRob Bradford                 }
2190ca60addaSRob Bradford                 Command::Memory => {
2191ca60addaSRob Bradford                     info!("Memory Command Received");
2192ca60addaSRob Bradford 
2193ca60addaSRob Bradford                     if !started {
2194ca60addaSRob Bradford                         warn!("Migration not started yet");
2195ca60addaSRob Bradford                         Response::error().write_to(&mut socket)?;
2196ca60addaSRob Bradford                         continue;
2197ca60addaSRob Bradford                     }
2198c52ccf39SSebastien Boeuf                     if let Some(mm) = memory_manager.as_ref() {
2199c52ccf39SSebastien Boeuf                         self.vm_receive_memory(&req, &mut socket, &mut mm.lock().unwrap())?;
220011a69450SRob Bradford                     } else {
220111a69450SRob Bradford                         warn!("Configuration not sent yet");
220211a69450SRob Bradford                         Response::error().write_to(&mut socket)?;
220311a69450SRob Bradford                     }
2204ca60addaSRob Bradford                 }
2205735658a4SRob Bradford                 Command::MemoryFd => {
220688952cc5SRob Bradford                     info!("MemoryFd Command Received");
220788952cc5SRob Bradford 
220888952cc5SRob Bradford                     if !started {
220988952cc5SRob Bradford                         warn!("Migration not started yet");
221088952cc5SRob Bradford                         Response::error().write_to(&mut socket)?;
221188952cc5SRob Bradford                         continue;
221288952cc5SRob Bradford                     }
221388952cc5SRob Bradford 
2214909e1bc3SJinrong Liang                     match &mut socket {
2215909e1bc3SJinrong Liang                         SocketStream::Unix(unix_socket) => {
221688952cc5SRob Bradford                             let mut buf = [0u8; 4];
2217909e1bc3SJinrong Liang                             let (_, file) = unix_socket.recv_with_fd(&mut buf).map_err(|e| {
221888952cc5SRob Bradford                                 MigratableError::MigrateReceive(anyhow!(
221988952cc5SRob Bradford                                     "Error receiving slot from socket: {}",
222088952cc5SRob Bradford                                     e
222188952cc5SRob Bradford                                 ))
222288952cc5SRob Bradford                             })?;
222388952cc5SRob Bradford 
222488952cc5SRob Bradford                             if existing_memory_files.is_none() {
222588952cc5SRob Bradford                                 existing_memory_files = Some(HashMap::default())
222688952cc5SRob Bradford                             }
222788952cc5SRob Bradford 
222888952cc5SRob Bradford                             if let Some(ref mut existing_memory_files) = existing_memory_files {
222988952cc5SRob Bradford                                 let slot = u32::from_le_bytes(buf);
223088952cc5SRob Bradford                                 existing_memory_files.insert(slot, file.unwrap());
223188952cc5SRob Bradford                             }
223288952cc5SRob Bradford 
223388952cc5SRob Bradford                             Response::ok().write_to(&mut socket)?;
2234735658a4SRob Bradford                         }
2235909e1bc3SJinrong Liang                         SocketStream::Tcp(_tcp_socket) => {
2236909e1bc3SJinrong Liang                             // For TCP sockets, we cannot transfer file descriptors
2237909e1bc3SJinrong Liang                             warn!(
2238909e1bc3SJinrong Liang                                 "MemoryFd command received over TCP socket, which is not supported"
2239909e1bc3SJinrong Liang                             );
2240909e1bc3SJinrong Liang                             Response::error().write_to(&mut socket)?;
2241909e1bc3SJinrong Liang                         }
2242909e1bc3SJinrong Liang                     }
2243909e1bc3SJinrong Liang                 }
2244ca60addaSRob Bradford                 Command::Complete => {
2245ca60addaSRob Bradford                     info!("Complete Command Received");
22463ac9b6c4SRob Bradford                     if let Some(ref mut vm) = self.vm.as_mut() {
22473ac9b6c4SRob Bradford                         vm.resume()?;
2248ca60addaSRob Bradford                         Response::ok().write_to(&mut socket)?;
22493ac9b6c4SRob Bradford                     } else {
22503ac9b6c4SRob Bradford                         warn!("VM not created yet");
22513ac9b6c4SRob Bradford                         Response::error().write_to(&mut socket)?;
22523ac9b6c4SRob Bradford                     }
2253ca60addaSRob Bradford                     break;
2254ca60addaSRob Bradford                 }
2255ca60addaSRob Bradford                 Command::Abandon => {
2256ca60addaSRob Bradford                     info!("Abandon Command Received");
2257ca60addaSRob Bradford                     self.vm = None;
2258b5b97f7bSRob Bradford                     self.vm_config = None;
2259ca60addaSRob Bradford                     Response::ok().write_to(&mut socket).ok();
2260ca60addaSRob Bradford                     break;
2261ca60addaSRob Bradford                 }
2262ca60addaSRob Bradford             }
2263ca60addaSRob Bradford         }
2264ca60addaSRob Bradford 
22657ac76451SRob Bradford         Ok(())
22667ac76451SRob Bradford     }
22677ac76451SRob Bradford 
vm_send_migration( &mut self, send_data_migration: VmSendMigrationData, ) -> result::Result<(), MigratableError>226871c7dff3SSebastien Boeuf     fn vm_send_migration(
226971c7dff3SSebastien Boeuf         &mut self,
227071c7dff3SSebastien Boeuf         send_data_migration: VmSendMigrationData,
227171c7dff3SSebastien Boeuf     ) -> result::Result<(), MigratableError> {
227271c7dff3SSebastien Boeuf         info!(
2273b9c260c0SRob Bradford             "Sending migration: destination_url = {}, local = {}",
2274b9c260c0SRob Bradford             send_data_migration.destination_url, send_data_migration.local
227571c7dff3SSebastien Boeuf         );
22761676fffaSRob Bradford 
22771676fffaSRob Bradford         if !self
22781676fffaSRob Bradford             .vm_config
22791676fffaSRob Bradford             .as_ref()
22801676fffaSRob Bradford             .unwrap()
22811676fffaSRob Bradford             .lock()
22821676fffaSRob Bradford             .unwrap()
2283f4495de1SRob Bradford             .backed_by_shared_memory()
22841676fffaSRob Bradford             && send_data_migration.local
22851676fffaSRob Bradford         {
22861676fffaSRob Bradford             return Err(MigratableError::MigrateSend(anyhow!(
2287f4495de1SRob Bradford                 "Local migration requires shared memory or hugepages enabled"
22881676fffaSRob Bradford             )));
22891676fffaSRob Bradford         }
22901676fffaSRob Bradford 
229171c7dff3SSebastien Boeuf         if let Some(vm) = self.vm.as_mut() {
229271c7dff3SSebastien Boeuf             Self::send_migration(
229371c7dff3SSebastien Boeuf                 vm,
229471c7dff3SSebastien Boeuf                 #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
229571c7dff3SSebastien Boeuf                 self.hypervisor.clone(),
22964c27572bSJinrong Liang                 send_data_migration.clone(),
229771c7dff3SSebastien Boeuf             )
229871c7dff3SSebastien Boeuf             .map_err(|migration_err| {
229971c7dff3SSebastien Boeuf                 error!("Migration failed: {:?}", migration_err);
230071c7dff3SSebastien Boeuf 
23014c27572bSJinrong Liang                 // Stop logging dirty pages only for non-local migrations
23024c27572bSJinrong Liang                 if !send_data_migration.local {
230371c7dff3SSebastien Boeuf                     if let Err(e) = vm.stop_dirty_log() {
230471c7dff3SSebastien Boeuf                         return e;
230571c7dff3SSebastien Boeuf                     }
23064c27572bSJinrong Liang                 }
230771c7dff3SSebastien Boeuf 
230871c7dff3SSebastien Boeuf                 if vm.get_state().unwrap() == VmState::Paused {
230971c7dff3SSebastien Boeuf                     if let Err(e) = vm.resume() {
231071c7dff3SSebastien Boeuf                         return e;
231171c7dff3SSebastien Boeuf                     }
231271c7dff3SSebastien Boeuf                 }
231371c7dff3SSebastien Boeuf 
231471c7dff3SSebastien Boeuf                 migration_err
231571c7dff3SSebastien Boeuf             })?;
231671c7dff3SSebastien Boeuf 
2317db444715SSebastien Boeuf             // Shutdown the VM after the migration succeeded
2318db444715SSebastien Boeuf             self.exit_evt.write(1).map_err(|e| {
2319db444715SSebastien Boeuf                 MigratableError::MigrateSend(anyhow!(
2320db444715SSebastien Boeuf                     "Failed shutting down the VM after migration: {:?}",
2321db444715SSebastien Boeuf                     e
2322db444715SSebastien Boeuf                 ))
232371c7dff3SSebastien Boeuf             })
2324ca60addaSRob Bradford         } else {
2325ca60addaSRob Bradford             Err(MigratableError::MigrateSend(anyhow!("VM is not running")))
2326ca60addaSRob Bradford         }
23277ac76451SRob Bradford     }
23282f1ff230SSamuel Ortiz }
23291ed357cfSSamuel Ortiz 
23301ed357cfSSamuel Ortiz const CPU_MANAGER_SNAPSHOT_ID: &str = "cpu-manager";
23311ed357cfSSamuel Ortiz const MEMORY_MANAGER_SNAPSHOT_ID: &str = "memory-manager";
23321ed357cfSSamuel Ortiz const DEVICE_MANAGER_SNAPSHOT_ID: &str = "device-manager";
2333b780a916SFabiano Fidêncio 
2334b780a916SFabiano Fidêncio #[cfg(test)]
2335b780a916SFabiano Fidêncio mod unit_tests {
233688a9f799SRob Bradford     use super::*;
233788a9f799SRob Bradford     #[cfg(target_arch = "x86_64")]
233833c15ca2SSongqian Li     use crate::vm_config::DebugConsoleConfig;
233933c15ca2SSongqian Li     use crate::vm_config::{
234033c15ca2SSongqian Li         ConsoleConfig, ConsoleOutputMode, CpuFeatures, CpusConfig, HotplugMethod, MemoryConfig,
234133c15ca2SSongqian Li         PayloadConfig, RngConfig,
234233c15ca2SSongqian Li     };
234388a9f799SRob Bradford 
create_dummy_vmm() -> Vmm2344b780a916SFabiano Fidêncio     fn create_dummy_vmm() -> Vmm {
2345b780a916SFabiano Fidêncio         Vmm::new(
2346346ee09eSOmer Faruk Bayram             VmmVersionInfo::new("dummy", "dummy"),
2347b780a916SFabiano Fidêncio             EventFd::new(EFD_NONBLOCK).unwrap(),
234806eb82d2SRob Bradford             #[cfg(feature = "guest_debug")]
23492451c4d8SAkira Moroo             EventFd::new(EFD_NONBLOCK).unwrap(),
235006eb82d2SRob Bradford             #[cfg(feature = "guest_debug")]
23512451c4d8SAkira Moroo             EventFd::new(EFD_NONBLOCK).unwrap(),
2352b780a916SFabiano Fidêncio             SeccompAction::Allow,
2353b780a916SFabiano Fidêncio             hypervisor::new().unwrap(),
2354b780a916SFabiano Fidêncio             EventFd::new(EFD_NONBLOCK).unwrap(),
2355b780a916SFabiano Fidêncio         )
2356b780a916SFabiano Fidêncio         .unwrap()
2357b780a916SFabiano Fidêncio     }
2358b780a916SFabiano Fidêncio 
create_dummy_vm_config() -> Box<VmConfig>2359cc9899e0SSongqian Li     fn create_dummy_vm_config() -> Box<VmConfig> {
2360cc9899e0SSongqian Li         Box::new(VmConfig {
2361b780a916SFabiano Fidêncio             cpus: CpusConfig {
2362b780a916SFabiano Fidêncio                 boot_vcpus: 1,
2363b780a916SFabiano Fidêncio                 max_vcpus: 1,
2364b780a916SFabiano Fidêncio                 topology: None,
2365b780a916SFabiano Fidêncio                 kvm_hyperv: false,
2366b780a916SFabiano Fidêncio                 max_phys_bits: 46,
2367b780a916SFabiano Fidêncio                 affinity: None,
236833c15ca2SSongqian Li                 features: CpuFeatures::default(),
2369b780a916SFabiano Fidêncio             },
2370b780a916SFabiano Fidêncio             memory: MemoryConfig {
2371b780a916SFabiano Fidêncio                 size: 536_870_912,
2372b780a916SFabiano Fidêncio                 mergeable: false,
2373b780a916SFabiano Fidêncio                 hotplug_method: HotplugMethod::Acpi,
2374b780a916SFabiano Fidêncio                 hotplug_size: None,
2375b780a916SFabiano Fidêncio                 hotplugged_size: None,
2376b780a916SFabiano Fidêncio                 shared: true,
2377b780a916SFabiano Fidêncio                 hugepages: false,
2378b780a916SFabiano Fidêncio                 hugepage_size: None,
2379b780a916SFabiano Fidêncio                 prefault: false,
2380b780a916SFabiano Fidêncio                 zones: None,
2381f603afc4SRob Bradford                 thp: true,
2382b780a916SFabiano Fidêncio             },
2383cef51a9dSRob Bradford             payload: Some(PayloadConfig {
2384cef51a9dSRob Bradford                 kernel: Some(PathBuf::from("/path/to/kernel")),
238576741961SAlyssa Ross                 firmware: None,
238676741961SAlyssa Ross                 cmdline: None,
238776741961SAlyssa Ross                 initramfs: None,
238876741961SAlyssa Ross                 #[cfg(feature = "igvm")]
238976741961SAlyssa Ross                 igvm: None,
2390aa6c486aSMuminul Islam                 #[cfg(feature = "sev_snp")]
2391aa6c486aSMuminul Islam                 host_data: None,
2392cef51a9dSRob Bradford             }),
2393c297d8d7SThomas Barrett             rate_limit_groups: None,
2394b780a916SFabiano Fidêncio             disks: None,
2395b780a916SFabiano Fidêncio             net: None,
2396b780a916SFabiano Fidêncio             rng: RngConfig {
2397b780a916SFabiano Fidêncio                 src: PathBuf::from("/dev/urandom"),
2398b780a916SFabiano Fidêncio                 iommu: false,
2399b780a916SFabiano Fidêncio             },
2400b780a916SFabiano Fidêncio             balloon: None,
2401b780a916SFabiano Fidêncio             fs: None,
2402b780a916SFabiano Fidêncio             pmem: None,
2403b780a916SFabiano Fidêncio             serial: ConsoleConfig {
2404b780a916SFabiano Fidêncio                 file: None,
2405b780a916SFabiano Fidêncio                 mode: ConsoleOutputMode::Null,
2406b780a916SFabiano Fidêncio                 iommu: false,
24076d1077fcSPraveen K Paladugu                 socket: None,
2408b780a916SFabiano Fidêncio             },
2409b780a916SFabiano Fidêncio             console: ConsoleConfig {
2410b780a916SFabiano Fidêncio                 file: None,
2411b780a916SFabiano Fidêncio                 mode: ConsoleOutputMode::Tty,
2412b780a916SFabiano Fidêncio                 iommu: false,
24136d1077fcSPraveen K Paladugu                 socket: None,
2414b780a916SFabiano Fidêncio             },
2415e50a6411SPhilipp Schuster             #[cfg(target_arch = "x86_64")]
2416e50a6411SPhilipp Schuster             debug_console: DebugConsoleConfig::default(),
2417b780a916SFabiano Fidêncio             devices: None,
2418b780a916SFabiano Fidêncio             user_devices: None,
241972169686SSebastien Boeuf             vdpa: None,
2420b780a916SFabiano Fidêncio             vsock: None,
24215f18ac3bSYuanchu Xie             #[cfg(feature = "pvmemcontrol")]
24225f18ac3bSYuanchu Xie             pvmemcontrol: None,
2423d99c0c0dSYi Wang             pvpanic: false,
2424b780a916SFabiano Fidêncio             iommu: false,
2425b780a916SFabiano Fidêncio             #[cfg(target_arch = "x86_64")]
2426b780a916SFabiano Fidêncio             sgx_epc: None,
2427b780a916SFabiano Fidêncio             numa: None,
2428b780a916SFabiano Fidêncio             watchdog: false,
242906eb82d2SRob Bradford             #[cfg(feature = "guest_debug")]
24302451c4d8SAkira Moroo             gdb: false,
2431e7e856d8SThomas Barrett             pci_segments: None,
2432b780a916SFabiano Fidêncio             platform: None,
24337122e298SPraveen K Paladugu             tpm: None,
2434a84b540bSBo Chen             preserved_fds: None,
2435d2f0e8aeSPraveen K Paladugu             landlock_enable: false,
2436bd180bc3SPraveen K Paladugu             landlock_rules: None,
2437cc9899e0SSongqian Li         })
2438b780a916SFabiano Fidêncio     }
2439b780a916SFabiano Fidêncio 
2440b780a916SFabiano Fidêncio     #[test]
test_vmm_vm_create()2441b780a916SFabiano Fidêncio     fn test_vmm_vm_create() {
2442b780a916SFabiano Fidêncio         let mut vmm = create_dummy_vmm();
2443b780a916SFabiano Fidêncio         let config = create_dummy_vm_config();
2444b780a916SFabiano Fidêncio 
2445b780a916SFabiano Fidêncio         assert!(matches!(vmm.vm_create(config.clone()), Ok(())));
2446b780a916SFabiano Fidêncio         assert!(matches!(
2447b780a916SFabiano Fidêncio             vmm.vm_create(config),
2448b780a916SFabiano Fidêncio             Err(VmError::VmAlreadyCreated)
2449b780a916SFabiano Fidêncio         ));
2450b780a916SFabiano Fidêncio     }
2451b780a916SFabiano Fidêncio 
2452b780a916SFabiano Fidêncio     #[test]
test_vmm_vm_cold_add_device()2453b780a916SFabiano Fidêncio     fn test_vmm_vm_cold_add_device() {
2454b780a916SFabiano Fidêncio         let mut vmm = create_dummy_vmm();
2455b780a916SFabiano Fidêncio         let device_config = DeviceConfig::parse("path=/path/to/device").unwrap();
2456b780a916SFabiano Fidêncio 
2457b780a916SFabiano Fidêncio         assert!(matches!(
2458b780a916SFabiano Fidêncio             vmm.vm_add_device(device_config.clone()),
2459b780a916SFabiano Fidêncio             Err(VmError::VmNotCreated)
2460b780a916SFabiano Fidêncio         ));
2461b780a916SFabiano Fidêncio 
2462b780a916SFabiano Fidêncio         let _ = vmm.vm_create(create_dummy_vm_config());
24635d2db68fSFabiano Fidêncio         assert!(vmm
24645d2db68fSFabiano Fidêncio             .vm_config
24655d2db68fSFabiano Fidêncio             .as_ref()
24665d2db68fSFabiano Fidêncio             .unwrap()
24675d2db68fSFabiano Fidêncio             .lock()
24685d2db68fSFabiano Fidêncio             .unwrap()
24695d2db68fSFabiano Fidêncio             .devices
24705d2db68fSFabiano Fidêncio             .is_none());
2471b780a916SFabiano Fidêncio 
2472297236a7SRuoqing He         assert!(vmm.vm_add_device(device_config.clone()).unwrap().is_none());
24735d2db68fSFabiano Fidêncio         assert_eq!(
24745d2db68fSFabiano Fidêncio             vmm.vm_config
24755d2db68fSFabiano Fidêncio                 .as_ref()
24765d2db68fSFabiano Fidêncio                 .unwrap()
24775d2db68fSFabiano Fidêncio                 .lock()
24785d2db68fSFabiano Fidêncio                 .unwrap()
24795d2db68fSFabiano Fidêncio                 .devices
24805d2db68fSFabiano Fidêncio                 .clone()
24815d2db68fSFabiano Fidêncio                 .unwrap()
24825d2db68fSFabiano Fidêncio                 .len(),
24835d2db68fSFabiano Fidêncio             1
24845d2db68fSFabiano Fidêncio         );
24855d2db68fSFabiano Fidêncio         assert_eq!(
24865d2db68fSFabiano Fidêncio             vmm.vm_config
24875d2db68fSFabiano Fidêncio                 .as_ref()
24885d2db68fSFabiano Fidêncio                 .unwrap()
24895d2db68fSFabiano Fidêncio                 .lock()
24905d2db68fSFabiano Fidêncio                 .unwrap()
24915d2db68fSFabiano Fidêncio                 .devices
24925d2db68fSFabiano Fidêncio                 .clone()
24935d2db68fSFabiano Fidêncio                 .unwrap()[0],
24945d2db68fSFabiano Fidêncio             device_config
24955d2db68fSFabiano Fidêncio         );
2496b780a916SFabiano Fidêncio     }
2497b780a916SFabiano Fidêncio 
2498b780a916SFabiano Fidêncio     #[test]
test_vmm_vm_cold_add_user_device()2499b780a916SFabiano Fidêncio     fn test_vmm_vm_cold_add_user_device() {
2500b780a916SFabiano Fidêncio         let mut vmm = create_dummy_vmm();
2501b780a916SFabiano Fidêncio         let user_device_config =
2502b780a916SFabiano Fidêncio             UserDeviceConfig::parse("socket=/path/to/socket,id=8,pci_segment=2").unwrap();
2503b780a916SFabiano Fidêncio 
2504b780a916SFabiano Fidêncio         assert!(matches!(
2505b780a916SFabiano Fidêncio             vmm.vm_add_user_device(user_device_config.clone()),
2506b780a916SFabiano Fidêncio             Err(VmError::VmNotCreated)
2507b780a916SFabiano Fidêncio         ));
2508b780a916SFabiano Fidêncio 
2509b780a916SFabiano Fidêncio         let _ = vmm.vm_create(create_dummy_vm_config());
25105d2db68fSFabiano Fidêncio         assert!(vmm
25115d2db68fSFabiano Fidêncio             .vm_config
25125d2db68fSFabiano Fidêncio             .as_ref()
25135d2db68fSFabiano Fidêncio             .unwrap()
25145d2db68fSFabiano Fidêncio             .lock()
25155d2db68fSFabiano Fidêncio             .unwrap()
25165d2db68fSFabiano Fidêncio             .user_devices
25175d2db68fSFabiano Fidêncio             .is_none());
2518b780a916SFabiano Fidêncio 
2519297236a7SRuoqing He         assert!(vmm
2520297236a7SRuoqing He             .vm_add_user_device(user_device_config.clone())
2521297236a7SRuoqing He             .unwrap()
2522297236a7SRuoqing He             .is_none());
25235d2db68fSFabiano Fidêncio         assert_eq!(
25245d2db68fSFabiano Fidêncio             vmm.vm_config
25255d2db68fSFabiano Fidêncio                 .as_ref()
25265d2db68fSFabiano Fidêncio                 .unwrap()
25275d2db68fSFabiano Fidêncio                 .lock()
25285d2db68fSFabiano Fidêncio                 .unwrap()
25295d2db68fSFabiano Fidêncio                 .user_devices
25305d2db68fSFabiano Fidêncio                 .clone()
25315d2db68fSFabiano Fidêncio                 .unwrap()
25325d2db68fSFabiano Fidêncio                 .len(),
25335d2db68fSFabiano Fidêncio             1
25345d2db68fSFabiano Fidêncio         );
25355d2db68fSFabiano Fidêncio         assert_eq!(
25365d2db68fSFabiano Fidêncio             vmm.vm_config
25375d2db68fSFabiano Fidêncio                 .as_ref()
25385d2db68fSFabiano Fidêncio                 .unwrap()
25395d2db68fSFabiano Fidêncio                 .lock()
25405d2db68fSFabiano Fidêncio                 .unwrap()
25415d2db68fSFabiano Fidêncio                 .user_devices
25425d2db68fSFabiano Fidêncio                 .clone()
25435d2db68fSFabiano Fidêncio                 .unwrap()[0],
25445d2db68fSFabiano Fidêncio             user_device_config
25455d2db68fSFabiano Fidêncio         );
2546b780a916SFabiano Fidêncio     }
2547b780a916SFabiano Fidêncio 
2548b780a916SFabiano Fidêncio     #[test]
test_vmm_vm_cold_add_disk()2549b780a916SFabiano Fidêncio     fn test_vmm_vm_cold_add_disk() {
2550b780a916SFabiano Fidêncio         let mut vmm = create_dummy_vmm();
2551b780a916SFabiano Fidêncio         let disk_config = DiskConfig::parse("path=/path/to_file").unwrap();
2552b780a916SFabiano Fidêncio 
2553b780a916SFabiano Fidêncio         assert!(matches!(
2554b780a916SFabiano Fidêncio             vmm.vm_add_disk(disk_config.clone()),
2555b780a916SFabiano Fidêncio             Err(VmError::VmNotCreated)
2556b780a916SFabiano Fidêncio         ));
2557b780a916SFabiano Fidêncio 
2558b780a916SFabiano Fidêncio         let _ = vmm.vm_create(create_dummy_vm_config());
25595d2db68fSFabiano Fidêncio         assert!(vmm
25605d2db68fSFabiano Fidêncio             .vm_config
25615d2db68fSFabiano Fidêncio             .as_ref()
25625d2db68fSFabiano Fidêncio             .unwrap()
25635d2db68fSFabiano Fidêncio             .lock()
25645d2db68fSFabiano Fidêncio             .unwrap()
25655d2db68fSFabiano Fidêncio             .disks
25665d2db68fSFabiano Fidêncio             .is_none());
2567b780a916SFabiano Fidêncio 
2568297236a7SRuoqing He         assert!(vmm.vm_add_disk(disk_config.clone()).unwrap().is_none());
25695d2db68fSFabiano Fidêncio         assert_eq!(
25705d2db68fSFabiano Fidêncio             vmm.vm_config
25715d2db68fSFabiano Fidêncio                 .as_ref()
25725d2db68fSFabiano Fidêncio                 .unwrap()
25735d2db68fSFabiano Fidêncio                 .lock()
25745d2db68fSFabiano Fidêncio                 .unwrap()
25755d2db68fSFabiano Fidêncio                 .disks
25765d2db68fSFabiano Fidêncio                 .clone()
25775d2db68fSFabiano Fidêncio                 .unwrap()
25785d2db68fSFabiano Fidêncio                 .len(),
25795d2db68fSFabiano Fidêncio             1
25805d2db68fSFabiano Fidêncio         );
25815d2db68fSFabiano Fidêncio         assert_eq!(
25825d2db68fSFabiano Fidêncio             vmm.vm_config
25835d2db68fSFabiano Fidêncio                 .as_ref()
25845d2db68fSFabiano Fidêncio                 .unwrap()
25855d2db68fSFabiano Fidêncio                 .lock()
25865d2db68fSFabiano Fidêncio                 .unwrap()
25875d2db68fSFabiano Fidêncio                 .disks
25885d2db68fSFabiano Fidêncio                 .clone()
25895d2db68fSFabiano Fidêncio                 .unwrap()[0],
25905d2db68fSFabiano Fidêncio             disk_config
25915d2db68fSFabiano Fidêncio         );
2592b780a916SFabiano Fidêncio     }
2593b780a916SFabiano Fidêncio 
2594b780a916SFabiano Fidêncio     #[test]
test_vmm_vm_cold_add_fs()2595b780a916SFabiano Fidêncio     fn test_vmm_vm_cold_add_fs() {
2596b780a916SFabiano Fidêncio         let mut vmm = create_dummy_vmm();
2597b780a916SFabiano Fidêncio         let fs_config = FsConfig::parse("tag=mytag,socket=/tmp/sock").unwrap();
2598b780a916SFabiano Fidêncio 
2599b780a916SFabiano Fidêncio         assert!(matches!(
2600b780a916SFabiano Fidêncio             vmm.vm_add_fs(fs_config.clone()),
2601b780a916SFabiano Fidêncio             Err(VmError::VmNotCreated)
2602b780a916SFabiano Fidêncio         ));
2603b780a916SFabiano Fidêncio 
2604b780a916SFabiano Fidêncio         let _ = vmm.vm_create(create_dummy_vm_config());
26055d2db68fSFabiano Fidêncio         assert!(vmm.vm_config.as_ref().unwrap().lock().unwrap().fs.is_none());
2606b780a916SFabiano Fidêncio 
2607297236a7SRuoqing He         assert!(vmm.vm_add_fs(fs_config.clone()).unwrap().is_none());
26085d2db68fSFabiano Fidêncio         assert_eq!(
26095d2db68fSFabiano Fidêncio             vmm.vm_config
26105d2db68fSFabiano Fidêncio                 .as_ref()
26115d2db68fSFabiano Fidêncio                 .unwrap()
26125d2db68fSFabiano Fidêncio                 .lock()
26135d2db68fSFabiano Fidêncio                 .unwrap()
26145d2db68fSFabiano Fidêncio                 .fs
26155d2db68fSFabiano Fidêncio                 .clone()
26165d2db68fSFabiano Fidêncio                 .unwrap()
26175d2db68fSFabiano Fidêncio                 .len(),
26185d2db68fSFabiano Fidêncio             1
26195d2db68fSFabiano Fidêncio         );
26205d2db68fSFabiano Fidêncio         assert_eq!(
26215d2db68fSFabiano Fidêncio             vmm.vm_config
26225d2db68fSFabiano Fidêncio                 .as_ref()
26235d2db68fSFabiano Fidêncio                 .unwrap()
26245d2db68fSFabiano Fidêncio                 .lock()
26255d2db68fSFabiano Fidêncio                 .unwrap()
26265d2db68fSFabiano Fidêncio                 .fs
26275d2db68fSFabiano Fidêncio                 .clone()
26285d2db68fSFabiano Fidêncio                 .unwrap()[0],
26295d2db68fSFabiano Fidêncio             fs_config
26305d2db68fSFabiano Fidêncio         );
2631b780a916SFabiano Fidêncio     }
2632b780a916SFabiano Fidêncio 
2633b780a916SFabiano Fidêncio     #[test]
test_vmm_vm_cold_add_pmem()2634b780a916SFabiano Fidêncio     fn test_vmm_vm_cold_add_pmem() {
2635b780a916SFabiano Fidêncio         let mut vmm = create_dummy_vmm();
2636b780a916SFabiano Fidêncio         let pmem_config = PmemConfig::parse("file=/tmp/pmem,size=128M").unwrap();
2637b780a916SFabiano Fidêncio 
2638b780a916SFabiano Fidêncio         assert!(matches!(
2639b780a916SFabiano Fidêncio             vmm.vm_add_pmem(pmem_config.clone()),
2640b780a916SFabiano Fidêncio             Err(VmError::VmNotCreated)
2641b780a916SFabiano Fidêncio         ));
2642b780a916SFabiano Fidêncio 
2643b780a916SFabiano Fidêncio         let _ = vmm.vm_create(create_dummy_vm_config());
26445d2db68fSFabiano Fidêncio         assert!(vmm
26455d2db68fSFabiano Fidêncio             .vm_config
26465d2db68fSFabiano Fidêncio             .as_ref()
26475d2db68fSFabiano Fidêncio             .unwrap()
26485d2db68fSFabiano Fidêncio             .lock()
26495d2db68fSFabiano Fidêncio             .unwrap()
26505d2db68fSFabiano Fidêncio             .pmem
26515d2db68fSFabiano Fidêncio             .is_none());
2652b780a916SFabiano Fidêncio 
2653297236a7SRuoqing He         assert!(vmm.vm_add_pmem(pmem_config.clone()).unwrap().is_none());
26545d2db68fSFabiano Fidêncio         assert_eq!(
26555d2db68fSFabiano Fidêncio             vmm.vm_config
26565d2db68fSFabiano Fidêncio                 .as_ref()
26575d2db68fSFabiano Fidêncio                 .unwrap()
26585d2db68fSFabiano Fidêncio                 .lock()
26595d2db68fSFabiano Fidêncio                 .unwrap()
26605d2db68fSFabiano Fidêncio                 .pmem
26615d2db68fSFabiano Fidêncio                 .clone()
26625d2db68fSFabiano Fidêncio                 .unwrap()
26635d2db68fSFabiano Fidêncio                 .len(),
26645d2db68fSFabiano Fidêncio             1
26655d2db68fSFabiano Fidêncio         );
26665d2db68fSFabiano Fidêncio         assert_eq!(
26675d2db68fSFabiano Fidêncio             vmm.vm_config
26685d2db68fSFabiano Fidêncio                 .as_ref()
26695d2db68fSFabiano Fidêncio                 .unwrap()
26705d2db68fSFabiano Fidêncio                 .lock()
26715d2db68fSFabiano Fidêncio                 .unwrap()
26725d2db68fSFabiano Fidêncio                 .pmem
26735d2db68fSFabiano Fidêncio                 .clone()
26745d2db68fSFabiano Fidêncio                 .unwrap()[0],
26755d2db68fSFabiano Fidêncio             pmem_config
26765d2db68fSFabiano Fidêncio         );
2677b780a916SFabiano Fidêncio     }
2678b780a916SFabiano Fidêncio 
2679b780a916SFabiano Fidêncio     #[test]
test_vmm_vm_cold_add_net()2680b780a916SFabiano Fidêncio     fn test_vmm_vm_cold_add_net() {
2681b780a916SFabiano Fidêncio         let mut vmm = create_dummy_vmm();
2682b780a916SFabiano Fidêncio         let net_config = NetConfig::parse(
2683b780a916SFabiano Fidêncio             "mac=de:ad:be:ef:12:34,host_mac=12:34:de:ad:be:ef,vhost_user=true,socket=/tmp/sock",
2684b780a916SFabiano Fidêncio         )
2685b780a916SFabiano Fidêncio         .unwrap();
2686b780a916SFabiano Fidêncio 
2687b780a916SFabiano Fidêncio         assert!(matches!(
2688b780a916SFabiano Fidêncio             vmm.vm_add_net(net_config.clone()),
2689b780a916SFabiano Fidêncio             Err(VmError::VmNotCreated)
2690b780a916SFabiano Fidêncio         ));
2691b780a916SFabiano Fidêncio 
2692b780a916SFabiano Fidêncio         let _ = vmm.vm_create(create_dummy_vm_config());
26935d2db68fSFabiano Fidêncio         assert!(vmm
26945d2db68fSFabiano Fidêncio             .vm_config
26955d2db68fSFabiano Fidêncio             .as_ref()
26965d2db68fSFabiano Fidêncio             .unwrap()
26975d2db68fSFabiano Fidêncio             .lock()
26985d2db68fSFabiano Fidêncio             .unwrap()
26995d2db68fSFabiano Fidêncio             .net
27005d2db68fSFabiano Fidêncio             .is_none());
2701b780a916SFabiano Fidêncio 
2702297236a7SRuoqing He         assert!(vmm.vm_add_net(net_config.clone()).unwrap().is_none());
27035d2db68fSFabiano Fidêncio         assert_eq!(
27045d2db68fSFabiano Fidêncio             vmm.vm_config
27055d2db68fSFabiano Fidêncio                 .as_ref()
27065d2db68fSFabiano Fidêncio                 .unwrap()
27075d2db68fSFabiano Fidêncio                 .lock()
27085d2db68fSFabiano Fidêncio                 .unwrap()
27095d2db68fSFabiano Fidêncio                 .net
27105d2db68fSFabiano Fidêncio                 .clone()
27115d2db68fSFabiano Fidêncio                 .unwrap()
27125d2db68fSFabiano Fidêncio                 .len(),
27135d2db68fSFabiano Fidêncio             1
27145d2db68fSFabiano Fidêncio         );
27155d2db68fSFabiano Fidêncio         assert_eq!(
27165d2db68fSFabiano Fidêncio             vmm.vm_config
27175d2db68fSFabiano Fidêncio                 .as_ref()
27185d2db68fSFabiano Fidêncio                 .unwrap()
27195d2db68fSFabiano Fidêncio                 .lock()
27205d2db68fSFabiano Fidêncio                 .unwrap()
27215d2db68fSFabiano Fidêncio                 .net
27225d2db68fSFabiano Fidêncio                 .clone()
27235d2db68fSFabiano Fidêncio                 .unwrap()[0],
27245d2db68fSFabiano Fidêncio             net_config
27255d2db68fSFabiano Fidêncio         );
2726b780a916SFabiano Fidêncio     }
2727b780a916SFabiano Fidêncio 
2728b780a916SFabiano Fidêncio     #[test]
test_vmm_vm_cold_add_vdpa()27293fea5f53SSebastien Boeuf     fn test_vmm_vm_cold_add_vdpa() {
27303fea5f53SSebastien Boeuf         let mut vmm = create_dummy_vmm();
27313fea5f53SSebastien Boeuf         let vdpa_config = VdpaConfig::parse("path=/dev/vhost-vdpa,num_queues=2").unwrap();
27323fea5f53SSebastien Boeuf 
27333fea5f53SSebastien Boeuf         assert!(matches!(
27343fea5f53SSebastien Boeuf             vmm.vm_add_vdpa(vdpa_config.clone()),
27353fea5f53SSebastien Boeuf             Err(VmError::VmNotCreated)
27363fea5f53SSebastien Boeuf         ));
27373fea5f53SSebastien Boeuf 
27383fea5f53SSebastien Boeuf         let _ = vmm.vm_create(create_dummy_vm_config());
27393fea5f53SSebastien Boeuf         assert!(vmm
27403fea5f53SSebastien Boeuf             .vm_config
27413fea5f53SSebastien Boeuf             .as_ref()
27423fea5f53SSebastien Boeuf             .unwrap()
27433fea5f53SSebastien Boeuf             .lock()
27443fea5f53SSebastien Boeuf             .unwrap()
27453fea5f53SSebastien Boeuf             .vdpa
27463fea5f53SSebastien Boeuf             .is_none());
27473fea5f53SSebastien Boeuf 
2748297236a7SRuoqing He         assert!(vmm.vm_add_vdpa(vdpa_config.clone()).unwrap().is_none());
27493fea5f53SSebastien Boeuf         assert_eq!(
27503fea5f53SSebastien Boeuf             vmm.vm_config
27513fea5f53SSebastien Boeuf                 .as_ref()
27523fea5f53SSebastien Boeuf                 .unwrap()
27533fea5f53SSebastien Boeuf                 .lock()
27543fea5f53SSebastien Boeuf                 .unwrap()
27553fea5f53SSebastien Boeuf                 .vdpa
27563fea5f53SSebastien Boeuf                 .clone()
27573fea5f53SSebastien Boeuf                 .unwrap()
27583fea5f53SSebastien Boeuf                 .len(),
27593fea5f53SSebastien Boeuf             1
27603fea5f53SSebastien Boeuf         );
27613fea5f53SSebastien Boeuf         assert_eq!(
27623fea5f53SSebastien Boeuf             vmm.vm_config
27633fea5f53SSebastien Boeuf                 .as_ref()
27643fea5f53SSebastien Boeuf                 .unwrap()
27653fea5f53SSebastien Boeuf                 .lock()
27663fea5f53SSebastien Boeuf                 .unwrap()
27673fea5f53SSebastien Boeuf                 .vdpa
27683fea5f53SSebastien Boeuf                 .clone()
27693fea5f53SSebastien Boeuf                 .unwrap()[0],
27703fea5f53SSebastien Boeuf             vdpa_config
27713fea5f53SSebastien Boeuf         );
27723fea5f53SSebastien Boeuf     }
27733fea5f53SSebastien Boeuf 
27743fea5f53SSebastien Boeuf     #[test]
test_vmm_vm_cold_add_vsock()2775b780a916SFabiano Fidêncio     fn test_vmm_vm_cold_add_vsock() {
2776b780a916SFabiano Fidêncio         let mut vmm = create_dummy_vmm();
27777d0b85d7SAlyssa Ross         let vsock_config = VsockConfig::parse("socket=/tmp/sock,cid=3,iommu=on").unwrap();
2778b780a916SFabiano Fidêncio 
2779b780a916SFabiano Fidêncio         assert!(matches!(
2780b780a916SFabiano Fidêncio             vmm.vm_add_vsock(vsock_config.clone()),
2781b780a916SFabiano Fidêncio             Err(VmError::VmNotCreated)
2782b780a916SFabiano Fidêncio         ));
2783b780a916SFabiano Fidêncio 
2784b780a916SFabiano Fidêncio         let _ = vmm.vm_create(create_dummy_vm_config());
27855d2db68fSFabiano Fidêncio         assert!(vmm
27865d2db68fSFabiano Fidêncio             .vm_config
27875d2db68fSFabiano Fidêncio             .as_ref()
27885d2db68fSFabiano Fidêncio             .unwrap()
27895d2db68fSFabiano Fidêncio             .lock()
27905d2db68fSFabiano Fidêncio             .unwrap()
27915d2db68fSFabiano Fidêncio             .vsock
27925d2db68fSFabiano Fidêncio             .is_none());
2793b780a916SFabiano Fidêncio 
2794297236a7SRuoqing He         assert!(vmm.vm_add_vsock(vsock_config.clone()).unwrap().is_none());
27955d2db68fSFabiano Fidêncio         assert_eq!(
27965d2db68fSFabiano Fidêncio             vmm.vm_config
27975d2db68fSFabiano Fidêncio                 .as_ref()
27985d2db68fSFabiano Fidêncio                 .unwrap()
27995d2db68fSFabiano Fidêncio                 .lock()
28005d2db68fSFabiano Fidêncio                 .unwrap()
28015d2db68fSFabiano Fidêncio                 .vsock
28025d2db68fSFabiano Fidêncio                 .clone()
28035d2db68fSFabiano Fidêncio                 .unwrap(),
28045d2db68fSFabiano Fidêncio             vsock_config
28055d2db68fSFabiano Fidêncio         );
2806b780a916SFabiano Fidêncio     }
2807b780a916SFabiano Fidêncio }
2808