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