1 // Copyright © 2019 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5
6 #[macro_use]
7 extern crate event_monitor;
8 #[macro_use]
9 extern crate log;
10
11 use std::collections::HashMap;
12 use std::fs::File;
13 use std::io::{stdout, Read, Write};
14 use std::net::{TcpListener, TcpStream};
15 use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
16 use std::os::unix::net::{UnixListener, UnixStream};
17 use std::panic::AssertUnwindSafe;
18 use std::path::PathBuf;
19 use std::rc::Rc;
20 use std::sync::mpsc::{Receiver, RecvError, SendError, Sender};
21 use std::sync::{Arc, Mutex};
22 #[cfg(not(target_arch = "riscv64"))]
23 use std::time::Instant;
24 use std::{io, result, thread};
25
26 use anyhow::anyhow;
27 #[cfg(feature = "dbus_api")]
28 use api::dbus::{DBusApiOptions, DBusApiShutdownChannels};
29 use api::http::HttpApiHandle;
30 use console_devices::{pre_create_console_devices, ConsoleInfo};
31 use landlock::LandlockError;
32 use libc::{tcsetattr, termios, EFD_NONBLOCK, SIGINT, SIGTERM, TCSANOW};
33 use memory_manager::MemoryManagerSnapshotData;
34 use pci::PciBdf;
35 use seccompiler::{apply_filter, SeccompAction};
36 use serde::ser::{SerializeStruct, Serializer};
37 use serde::{Deserialize, Serialize};
38 use signal_hook::iterator::{Handle, Signals};
39 use thiserror::Error;
40 use tracer::trace_scoped;
41 use vm_memory::bitmap::{AtomicBitmap, BitmapSlice};
42 use vm_memory::{ReadVolatile, VolatileMemoryError, VolatileSlice, WriteVolatile};
43 use vm_migration::protocol::*;
44 use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
45 use vmm_sys_util::eventfd::EventFd;
46 use vmm_sys_util::signal::unblock_signal;
47 use vmm_sys_util::sock_ctrl_msg::ScmSocket;
48
49 use crate::api::{
50 ApiRequest, ApiResponse, RequestHandler, VmInfoResponse, VmReceiveMigrationData,
51 VmSendMigrationData, VmmPingResponse,
52 };
53 use crate::config::{add_to_config, RestoreConfig};
54 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
55 use crate::coredump::GuestDebuggable;
56 use crate::landlock::Landlock;
57 use crate::memory_manager::MemoryManager;
58 #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
59 use crate::migration::get_vm_snapshot;
60 use crate::migration::{recv_vm_config, recv_vm_state};
61 use crate::seccomp_filters::{get_seccomp_filter, Thread};
62 use crate::vm::{Error as VmError, Vm, VmState};
63 use crate::vm_config::{
64 DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, UserDeviceConfig, VdpaConfig,
65 VmConfig, VsockConfig,
66 };
67
68 #[cfg(not(target_arch = "riscv64"))]
69 mod acpi;
70 pub mod api;
71 mod clone3;
72 pub mod config;
73 pub mod console_devices;
74 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
75 mod coredump;
76 pub mod cpu;
77 pub mod device_manager;
78 pub mod device_tree;
79 #[cfg(feature = "guest_debug")]
80 mod gdb;
81 #[cfg(feature = "igvm")]
82 mod igvm;
83 pub mod interrupt;
84 pub mod landlock;
85 pub mod memory_manager;
86 pub mod migration;
87 mod pci_segment;
88 pub mod seccomp_filters;
89 mod serial_manager;
90 mod sigwinch_listener;
91 pub mod vm;
92 pub mod vm_config;
93
94 type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
95 type GuestRegionMmap = vm_memory::GuestRegionMmap<AtomicBitmap>;
96
97 /// Errors associated with VMM management
98 #[derive(Debug, Error)]
99 pub enum Error {
100 /// API request receive error
101 #[error("Error receiving API request")]
102 ApiRequestRecv(#[source] RecvError),
103
104 /// API response send error
105 #[error("Error sending API request")]
106 ApiResponseSend(#[source] SendError<ApiResponse>),
107
108 /// Cannot bind to the UNIX domain socket path
109 #[error("Error binding to UNIX domain socket")]
110 Bind(#[source] io::Error),
111
112 /// Cannot clone EventFd.
113 #[error("Error cloning EventFd")]
114 EventFdClone(#[source] io::Error),
115
116 /// Cannot create EventFd.
117 #[error("Error creating EventFd")]
118 EventFdCreate(#[source] io::Error),
119
120 /// Cannot read from EventFd.
121 #[error("Error reading from EventFd")]
122 EventFdRead(#[source] io::Error),
123
124 /// Cannot create epoll context.
125 #[error("Error creating epoll context")]
126 Epoll(#[source] io::Error),
127
128 /// Cannot create HTTP thread
129 #[error("Error spawning HTTP thread")]
130 HttpThreadSpawn(#[source] io::Error),
131
132 /// Cannot create D-Bus thread
133 #[cfg(feature = "dbus_api")]
134 #[error("Error spawning D-Bus thread")]
135 DBusThreadSpawn(#[source] io::Error),
136
137 /// Cannot start D-Bus session
138 #[cfg(feature = "dbus_api")]
139 #[error("Error starting D-Bus session")]
140 CreateDBusSession(#[source] zbus::Error),
141
142 /// Cannot create `event-monitor` thread
143 #[error("Error spawning `event-monitor` thread")]
144 EventMonitorThreadSpawn(#[source] io::Error),
145
146 /// Cannot handle the VM STDIN stream
147 #[error("Error handling VM stdin")]
148 Stdin(#[source] VmError),
149
150 /// Cannot handle the VM pty stream
151 #[error("Error handling VM pty")]
152 Pty(#[source] VmError),
153
154 /// Cannot reboot the VM
155 #[error("Error rebooting VM")]
156 VmReboot(#[source] VmError),
157
158 /// Cannot create VMM thread
159 #[error("Error spawning VMM thread")]
160 VmmThreadSpawn(#[source] io::Error),
161
162 /// Cannot shut the VMM down
163 #[error("Error shutting down VMM")]
164 VmmShutdown(#[source] VmError),
165
166 /// Cannot create seccomp filter
167 #[error("Error creating seccomp filter")]
168 CreateSeccompFilter(#[source] seccompiler::Error),
169
170 /// Cannot apply seccomp filter
171 #[error("Error applying seccomp filter")]
172 ApplySeccompFilter(#[source] seccompiler::Error),
173
174 /// Error activating virtio devices
175 #[error("Error activating virtio devices")]
176 ActivateVirtioDevices(#[source] VmError),
177
178 /// Error creating API server
179 // TODO We should add #[source] here once the type implements Error.
180 // Then we also can remove the `: {}` to align with the other errors.
181 #[error("Error creating API server: {0}")]
182 CreateApiServer(micro_http::ServerError),
183
184 /// Error binding API server socket
185 #[error("Error creation API server's socket")]
186 CreateApiServerSocket(#[source] io::Error),
187
188 #[cfg(feature = "guest_debug")]
189 #[error("Failed to start the GDB thread")]
190 GdbThreadSpawn(#[source] io::Error),
191
192 /// GDB request receive error
193 #[cfg(feature = "guest_debug")]
194 #[error("Error receiving GDB request")]
195 GdbRequestRecv(#[source] RecvError),
196
197 /// GDB response send error
198 #[cfg(feature = "guest_debug")]
199 #[error("Error sending GDB request")]
200 GdbResponseSend(#[source] SendError<gdb::GdbResponse>),
201
202 #[error("Cannot spawn a signal handler thread")]
203 SignalHandlerSpawn(#[source] io::Error),
204
205 #[error("Failed to join on threads: {0:?}")]
206 ThreadCleanup(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
207
208 /// Cannot create Landlock object
209 #[error("Error creating landlock object")]
210 CreateLandlock(#[source] LandlockError),
211
212 /// Cannot apply landlock based sandboxing
213 #[error("Error applying landlock")]
214 ApplyLandlock(#[source] LandlockError),
215 }
216 pub type Result<T> = result::Result<T, Error>;
217
218 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
219 #[repr(u64)]
220 pub enum EpollDispatch {
221 Exit = 0,
222 Reset = 1,
223 Api = 2,
224 ActivateVirtioDevices = 3,
225 Debug = 4,
226 Unknown,
227 }
228
229 impl From<u64> for EpollDispatch {
from(v: u64) -> Self230 fn from(v: u64) -> Self {
231 use EpollDispatch::*;
232 match v {
233 0 => Exit,
234 1 => Reset,
235 2 => Api,
236 3 => ActivateVirtioDevices,
237 4 => Debug,
238 _ => Unknown,
239 }
240 }
241 }
242
243 enum SocketStream {
244 Unix(UnixStream),
245 Tcp(TcpStream),
246 }
247
248 impl Read for SocketStream {
read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>249 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
250 match self {
251 SocketStream::Unix(stream) => stream.read(buf),
252 SocketStream::Tcp(stream) => stream.read(buf),
253 }
254 }
255 }
256
257 impl Write for SocketStream {
write(&mut self, buf: &[u8]) -> std::io::Result<usize>258 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
259 match self {
260 SocketStream::Unix(stream) => stream.write(buf),
261 SocketStream::Tcp(stream) => stream.write(buf),
262 }
263 }
264
flush(&mut self) -> std::io::Result<()>265 fn flush(&mut self) -> std::io::Result<()> {
266 match self {
267 SocketStream::Unix(stream) => stream.flush(),
268 SocketStream::Tcp(stream) => stream.flush(),
269 }
270 }
271 }
272
273 impl AsRawFd for SocketStream {
as_raw_fd(&self) -> RawFd274 fn as_raw_fd(&self) -> RawFd {
275 match self {
276 SocketStream::Unix(s) => s.as_raw_fd(),
277 SocketStream::Tcp(s) => s.as_raw_fd(),
278 }
279 }
280 }
281
282 impl ReadVolatile for SocketStream {
read_volatile<B: BitmapSlice>( &mut self, buf: &mut VolatileSlice<B>, ) -> std::result::Result<usize, VolatileMemoryError>283 fn read_volatile<B: BitmapSlice>(
284 &mut self,
285 buf: &mut VolatileSlice<B>,
286 ) -> std::result::Result<usize, VolatileMemoryError> {
287 match self {
288 SocketStream::Unix(s) => s.read_volatile(buf),
289 SocketStream::Tcp(s) => s.read_volatile(buf),
290 }
291 }
292
read_exact_volatile<B: BitmapSlice>( &mut self, buf: &mut VolatileSlice<B>, ) -> std::result::Result<(), VolatileMemoryError>293 fn read_exact_volatile<B: BitmapSlice>(
294 &mut self,
295 buf: &mut VolatileSlice<B>,
296 ) -> std::result::Result<(), VolatileMemoryError> {
297 match self {
298 SocketStream::Unix(s) => s.read_exact_volatile(buf),
299 SocketStream::Tcp(s) => s.read_exact_volatile(buf),
300 }
301 }
302 }
303
304 impl WriteVolatile for SocketStream {
write_volatile<B: BitmapSlice>( &mut self, buf: &VolatileSlice<B>, ) -> std::result::Result<usize, VolatileMemoryError>305 fn write_volatile<B: BitmapSlice>(
306 &mut self,
307 buf: &VolatileSlice<B>,
308 ) -> std::result::Result<usize, VolatileMemoryError> {
309 match self {
310 SocketStream::Unix(s) => s.write_volatile(buf),
311 SocketStream::Tcp(s) => s.write_volatile(buf),
312 }
313 }
314
write_all_volatile<B: BitmapSlice>( &mut self, buf: &VolatileSlice<B>, ) -> std::result::Result<(), VolatileMemoryError>315 fn write_all_volatile<B: BitmapSlice>(
316 &mut self,
317 buf: &VolatileSlice<B>,
318 ) -> std::result::Result<(), VolatileMemoryError> {
319 match self {
320 SocketStream::Unix(s) => s.write_all_volatile(buf),
321 SocketStream::Tcp(s) => s.write_all_volatile(buf),
322 }
323 }
324 }
325
326 pub struct EpollContext {
327 epoll_file: File,
328 }
329
330 impl EpollContext {
new() -> result::Result<EpollContext, io::Error>331 pub fn new() -> result::Result<EpollContext, io::Error> {
332 let epoll_fd = epoll::create(true)?;
333 // Use 'File' to enforce closing on 'epoll_fd'
334 // SAFETY: the epoll_fd returned by epoll::create is valid and owned by us.
335 let epoll_file = unsafe { File::from_raw_fd(epoll_fd) };
336
337 Ok(EpollContext { epoll_file })
338 }
339
add_event<T>(&mut self, fd: &T, token: EpollDispatch) -> result::Result<(), io::Error> where T: AsRawFd,340 pub fn add_event<T>(&mut self, fd: &T, token: EpollDispatch) -> result::Result<(), io::Error>
341 where
342 T: AsRawFd,
343 {
344 let dispatch_index = token as u64;
345 epoll::ctl(
346 self.epoll_file.as_raw_fd(),
347 epoll::ControlOptions::EPOLL_CTL_ADD,
348 fd.as_raw_fd(),
349 epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index),
350 )?;
351
352 Ok(())
353 }
354
355 #[cfg(fuzzing)]
add_event_custom<T>( &mut self, fd: &T, id: u64, evts: epoll::Events, ) -> result::Result<(), io::Error> where T: AsRawFd,356 pub fn add_event_custom<T>(
357 &mut self,
358 fd: &T,
359 id: u64,
360 evts: epoll::Events,
361 ) -> result::Result<(), io::Error>
362 where
363 T: AsRawFd,
364 {
365 epoll::ctl(
366 self.epoll_file.as_raw_fd(),
367 epoll::ControlOptions::EPOLL_CTL_ADD,
368 fd.as_raw_fd(),
369 epoll::Event::new(evts, id),
370 )?;
371
372 Ok(())
373 }
374 }
375
376 impl AsRawFd for EpollContext {
as_raw_fd(&self) -> RawFd377 fn as_raw_fd(&self) -> RawFd {
378 self.epoll_file.as_raw_fd()
379 }
380 }
381
382 pub struct PciDeviceInfo {
383 pub id: String,
384 pub bdf: PciBdf,
385 }
386
387 impl Serialize for PciDeviceInfo {
serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> where S: Serializer,388 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
389 where
390 S: Serializer,
391 {
392 let bdf_str = self.bdf.to_string();
393
394 // Serialize the structure.
395 let mut state = serializer.serialize_struct("PciDeviceInfo", 2)?;
396 state.serialize_field("id", &self.id)?;
397 state.serialize_field("bdf", &bdf_str)?;
398 state.end()
399 }
400 }
401
feature_list() -> Vec<String>402 pub fn feature_list() -> Vec<String> {
403 vec![
404 #[cfg(feature = "dbus_api")]
405 "dbus_api".to_string(),
406 #[cfg(feature = "dhat-heap")]
407 "dhat-heap".to_string(),
408 #[cfg(feature = "guest_debug")]
409 "guest_debug".to_string(),
410 #[cfg(feature = "igvm")]
411 "igvm".to_string(),
412 #[cfg(feature = "io_uring")]
413 "io_uring".to_string(),
414 #[cfg(feature = "kvm")]
415 "kvm".to_string(),
416 #[cfg(feature = "mshv")]
417 "mshv".to_string(),
418 #[cfg(feature = "sev_snp")]
419 "sev_snp".to_string(),
420 #[cfg(feature = "tdx")]
421 "tdx".to_string(),
422 #[cfg(feature = "tracing")]
423 "tracing".to_string(),
424 ]
425 }
426
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<()>>>427 pub fn start_event_monitor_thread(
428 mut monitor: event_monitor::Monitor,
429 seccomp_action: &SeccompAction,
430 landlock_enable: bool,
431 hypervisor_type: hypervisor::HypervisorType,
432 exit_event: EventFd,
433 ) -> Result<thread::JoinHandle<Result<()>>> {
434 // Retrieve seccomp filter
435 let seccomp_filter = get_seccomp_filter(seccomp_action, Thread::EventMonitor, hypervisor_type)
436 .map_err(Error::CreateSeccompFilter)?;
437
438 thread::Builder::new()
439 .name("event-monitor".to_owned())
440 .spawn(move || {
441 // Apply seccomp filter
442 if !seccomp_filter.is_empty() {
443 apply_filter(&seccomp_filter)
444 .map_err(Error::ApplySeccompFilter)
445 .map_err(|e| {
446 error!("Error applying seccomp filter: {:?}", e);
447 exit_event.write(1).ok();
448 e
449 })?;
450 }
451 if landlock_enable {
452 Landlock::new()
453 .map_err(Error::CreateLandlock)?
454 .restrict_self()
455 .map_err(Error::ApplyLandlock)
456 .map_err(|e| {
457 error!("Error applying landlock to event monitor thread: {:?}", e);
458 exit_event.write(1).ok();
459 e
460 })?;
461 }
462
463 std::panic::catch_unwind(AssertUnwindSafe(move || {
464 while let Ok(event) = monitor.rx.recv() {
465 let event = Arc::new(event);
466
467 if let Some(ref mut file) = monitor.file {
468 file.write_all(event.as_bytes().as_ref()).ok();
469 file.write_all(b"\n\n").ok();
470 }
471
472 for tx in monitor.broadcast.iter() {
473 tx.send(event.clone()).ok();
474 }
475 }
476 }))
477 .map_err(|_| {
478 error!("`event-monitor` thread panicked");
479 exit_event.write(1).ok();
480 })
481 .ok();
482
483 Ok(())
484 })
485 .map_err(Error::EventMonitorThreadSpawn)
486 }
487
488 #[allow(unused_variables)]
489 #[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>490 pub fn start_vmm_thread(
491 vmm_version: VmmVersionInfo,
492 http_path: &Option<String>,
493 http_fd: Option<RawFd>,
494 #[cfg(feature = "dbus_api")] dbus_options: Option<DBusApiOptions>,
495 api_event: EventFd,
496 api_sender: Sender<ApiRequest>,
497 api_receiver: Receiver<ApiRequest>,
498 #[cfg(feature = "guest_debug")] debug_path: Option<PathBuf>,
499 #[cfg(feature = "guest_debug")] debug_event: EventFd,
500 #[cfg(feature = "guest_debug")] vm_debug_event: EventFd,
501 exit_event: EventFd,
502 seccomp_action: &SeccompAction,
503 hypervisor: Arc<dyn hypervisor::Hypervisor>,
504 landlock_enable: bool,
505 ) -> Result<VmmThreadHandle> {
506 #[cfg(feature = "guest_debug")]
507 let gdb_hw_breakpoints = hypervisor.get_guest_debug_hw_bps();
508 #[cfg(feature = "guest_debug")]
509 let (gdb_sender, gdb_receiver) = std::sync::mpsc::channel();
510 #[cfg(feature = "guest_debug")]
511 let gdb_debug_event = debug_event.try_clone().map_err(Error::EventFdClone)?;
512 #[cfg(feature = "guest_debug")]
513 let gdb_vm_debug_event = vm_debug_event.try_clone().map_err(Error::EventFdClone)?;
514
515 let api_event_clone = api_event.try_clone().map_err(Error::EventFdClone)?;
516 let hypervisor_type = hypervisor.hypervisor_type();
517
518 // Retrieve seccomp filter
519 let vmm_seccomp_filter = get_seccomp_filter(seccomp_action, Thread::Vmm, hypervisor_type)
520 .map_err(Error::CreateSeccompFilter)?;
521
522 let vmm_seccomp_action = seccomp_action.clone();
523 let thread = {
524 let exit_event = exit_event.try_clone().map_err(Error::EventFdClone)?;
525 thread::Builder::new()
526 .name("vmm".to_string())
527 .spawn(move || {
528 // Apply seccomp filter for VMM thread.
529 if !vmm_seccomp_filter.is_empty() {
530 apply_filter(&vmm_seccomp_filter).map_err(Error::ApplySeccompFilter)?;
531 }
532
533 let mut vmm = Vmm::new(
534 vmm_version,
535 api_event,
536 #[cfg(feature = "guest_debug")]
537 debug_event,
538 #[cfg(feature = "guest_debug")]
539 vm_debug_event,
540 vmm_seccomp_action,
541 hypervisor,
542 exit_event,
543 )?;
544
545 vmm.setup_signal_handler(landlock_enable)?;
546
547 vmm.control_loop(
548 Rc::new(api_receiver),
549 #[cfg(feature = "guest_debug")]
550 Rc::new(gdb_receiver),
551 )
552 })
553 .map_err(Error::VmmThreadSpawn)?
554 };
555
556 // The VMM thread is started, we can start the dbus thread
557 // and start serving HTTP requests
558 #[cfg(feature = "dbus_api")]
559 let dbus_shutdown_chs = match dbus_options {
560 Some(opts) => {
561 let (_, chs) = api::start_dbus_thread(
562 opts,
563 api_event_clone.try_clone().map_err(Error::EventFdClone)?,
564 api_sender.clone(),
565 seccomp_action,
566 exit_event.try_clone().map_err(Error::EventFdClone)?,
567 hypervisor_type,
568 )?;
569 Some(chs)
570 }
571 None => None,
572 };
573
574 let http_api_handle = if let Some(http_path) = http_path {
575 Some(api::start_http_path_thread(
576 http_path,
577 api_event_clone,
578 api_sender,
579 seccomp_action,
580 exit_event,
581 hypervisor_type,
582 landlock_enable,
583 )?)
584 } else if let Some(http_fd) = http_fd {
585 Some(api::start_http_fd_thread(
586 http_fd,
587 api_event_clone,
588 api_sender,
589 seccomp_action,
590 exit_event,
591 hypervisor_type,
592 landlock_enable,
593 )?)
594 } else {
595 None
596 };
597
598 #[cfg(feature = "guest_debug")]
599 if let Some(debug_path) = debug_path {
600 let target = gdb::GdbStub::new(
601 gdb_sender,
602 gdb_debug_event,
603 gdb_vm_debug_event,
604 gdb_hw_breakpoints,
605 );
606 thread::Builder::new()
607 .name("gdb".to_owned())
608 .spawn(move || gdb::gdb_thread(target, &debug_path))
609 .map_err(Error::GdbThreadSpawn)?;
610 }
611
612 Ok(VmmThreadHandle {
613 thread_handle: thread,
614 #[cfg(feature = "dbus_api")]
615 dbus_shutdown_chs,
616 http_api_handle,
617 })
618 }
619
620 #[derive(Clone, Deserialize, Serialize)]
621 struct VmMigrationConfig {
622 vm_config: Arc<Mutex<VmConfig>>,
623 #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
624 common_cpuid: Vec<hypervisor::arch::x86::CpuIdEntry>,
625 memory_manager_data: MemoryManagerSnapshotData,
626 }
627
628 #[derive(Debug, Clone)]
629 pub struct VmmVersionInfo {
630 pub build_version: String,
631 pub version: String,
632 }
633
634 impl VmmVersionInfo {
new(build_version: &str, version: &str) -> Self635 pub fn new(build_version: &str, version: &str) -> Self {
636 Self {
637 build_version: build_version.to_owned(),
638 version: version.to_owned(),
639 }
640 }
641 }
642
643 pub struct VmmThreadHandle {
644 pub thread_handle: thread::JoinHandle<Result<()>>,
645 #[cfg(feature = "dbus_api")]
646 pub dbus_shutdown_chs: Option<DBusApiShutdownChannels>,
647 pub http_api_handle: Option<HttpApiHandle>,
648 }
649
650 pub struct Vmm {
651 epoll: EpollContext,
652 exit_evt: EventFd,
653 reset_evt: EventFd,
654 api_evt: EventFd,
655 #[cfg(feature = "guest_debug")]
656 debug_evt: EventFd,
657 #[cfg(feature = "guest_debug")]
658 vm_debug_evt: EventFd,
659 version: VmmVersionInfo,
660 vm: Option<Vm>,
661 vm_config: Option<Arc<Mutex<VmConfig>>>,
662 seccomp_action: SeccompAction,
663 hypervisor: Arc<dyn hypervisor::Hypervisor>,
664 activate_evt: EventFd,
665 signals: Option<Handle>,
666 threads: Vec<thread::JoinHandle<()>>,
667 original_termios_opt: Arc<Mutex<Option<termios>>>,
668 console_resize_pipe: Option<Arc<File>>,
669 console_info: Option<ConsoleInfo>,
670 }
671
672 impl Vmm {
673 pub const HANDLED_SIGNALS: [i32; 2] = [SIGTERM, SIGINT];
674
signal_handler( mut signals: Signals, original_termios_opt: Arc<Mutex<Option<termios>>>, exit_evt: &EventFd, )675 fn signal_handler(
676 mut signals: Signals,
677 original_termios_opt: Arc<Mutex<Option<termios>>>,
678 exit_evt: &EventFd,
679 ) {
680 for sig in &Self::HANDLED_SIGNALS {
681 unblock_signal(*sig).unwrap();
682 }
683
684 for signal in signals.forever() {
685 match signal {
686 SIGTERM | SIGINT => {
687 if exit_evt.write(1).is_err() {
688 // Resetting the terminal is usually done as the VMM exits
689 if let Ok(lock) = original_termios_opt.lock() {
690 if let Some(termios) = *lock {
691 // SAFETY: FFI call
692 let _ = unsafe {
693 tcsetattr(stdout().lock().as_raw_fd(), TCSANOW, &termios)
694 };
695 }
696 } else {
697 warn!("Failed to lock original termios");
698 }
699
700 std::process::exit(1);
701 }
702 }
703 _ => (),
704 }
705 }
706 }
707
setup_signal_handler(&mut self, landlock_enable: bool) -> Result<()>708 fn setup_signal_handler(&mut self, landlock_enable: bool) -> Result<()> {
709 let signals = Signals::new(Self::HANDLED_SIGNALS);
710 match signals {
711 Ok(signals) => {
712 self.signals = Some(signals.handle());
713 let exit_evt = self.exit_evt.try_clone().map_err(Error::EventFdClone)?;
714 let original_termios_opt = Arc::clone(&self.original_termios_opt);
715
716 let signal_handler_seccomp_filter = get_seccomp_filter(
717 &self.seccomp_action,
718 Thread::SignalHandler,
719 self.hypervisor.hypervisor_type(),
720 )
721 .map_err(Error::CreateSeccompFilter)?;
722 self.threads.push(
723 thread::Builder::new()
724 .name("vmm_signal_handler".to_string())
725 .spawn(move || {
726 if !signal_handler_seccomp_filter.is_empty() {
727 if let Err(e) = apply_filter(&signal_handler_seccomp_filter)
728 .map_err(Error::ApplySeccompFilter)
729 {
730 error!("Error applying seccomp filter: {:?}", e);
731 exit_evt.write(1).ok();
732 return;
733 }
734 }
735 if landlock_enable{
736 match Landlock::new() {
737 Ok(landlock) => {
738 let _ = landlock.restrict_self().map_err(Error::ApplyLandlock).map_err(|e| {
739 error!("Error applying Landlock to signal handler thread: {:?}", e);
740 exit_evt.write(1).ok();
741 });
742 }
743 Err(e) => {
744 error!("Error creating Landlock object: {:?}", e);
745 exit_evt.write(1).ok();
746 }
747 };
748 }
749
750 std::panic::catch_unwind(AssertUnwindSafe(|| {
751 Vmm::signal_handler(signals, original_termios_opt, &exit_evt);
752 }))
753 .map_err(|_| {
754 error!("vmm signal_handler thread panicked");
755 exit_evt.write(1).ok()
756 })
757 .ok();
758 })
759 .map_err(Error::SignalHandlerSpawn)?,
760 );
761 }
762 Err(e) => error!("Signal not found {}", e),
763 }
764 Ok(())
765 }
766
767 #[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>768 fn new(
769 vmm_version: VmmVersionInfo,
770 api_evt: EventFd,
771 #[cfg(feature = "guest_debug")] debug_evt: EventFd,
772 #[cfg(feature = "guest_debug")] vm_debug_evt: EventFd,
773 seccomp_action: SeccompAction,
774 hypervisor: Arc<dyn hypervisor::Hypervisor>,
775 exit_evt: EventFd,
776 ) -> Result<Self> {
777 let mut epoll = EpollContext::new().map_err(Error::Epoll)?;
778 let reset_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
779 let activate_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
780
781 epoll
782 .add_event(&exit_evt, EpollDispatch::Exit)
783 .map_err(Error::Epoll)?;
784
785 epoll
786 .add_event(&reset_evt, EpollDispatch::Reset)
787 .map_err(Error::Epoll)?;
788
789 epoll
790 .add_event(&activate_evt, EpollDispatch::ActivateVirtioDevices)
791 .map_err(Error::Epoll)?;
792
793 epoll
794 .add_event(&api_evt, EpollDispatch::Api)
795 .map_err(Error::Epoll)?;
796
797 #[cfg(feature = "guest_debug")]
798 epoll
799 .add_event(&debug_evt, EpollDispatch::Debug)
800 .map_err(Error::Epoll)?;
801
802 Ok(Vmm {
803 epoll,
804 exit_evt,
805 reset_evt,
806 api_evt,
807 #[cfg(feature = "guest_debug")]
808 debug_evt,
809 #[cfg(feature = "guest_debug")]
810 vm_debug_evt,
811 version: vmm_version,
812 vm: None,
813 vm_config: None,
814 seccomp_action,
815 hypervisor,
816 activate_evt,
817 signals: None,
818 threads: vec![],
819 original_termios_opt: Arc::new(Mutex::new(None)),
820 console_resize_pipe: None,
821 console_info: None,
822 })
823 }
824
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,825 fn vm_receive_config<T>(
826 &mut self,
827 req: &Request,
828 socket: &mut T,
829 existing_memory_files: Option<HashMap<u32, File>>,
830 ) -> std::result::Result<Arc<Mutex<MemoryManager>>, MigratableError>
831 where
832 T: Read + Write,
833 {
834 // Read in config data along with memory manager data
835 let mut data: Vec<u8> = Vec::new();
836 data.resize_with(req.length() as usize, Default::default);
837 socket
838 .read_exact(&mut data)
839 .map_err(MigratableError::MigrateSocket)?;
840
841 let vm_migration_config: VmMigrationConfig =
842 serde_json::from_slice(&data).map_err(|e| {
843 MigratableError::MigrateReceive(anyhow!("Error deserialising config: {}", e))
844 })?;
845
846 #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
847 self.vm_check_cpuid_compatibility(
848 &vm_migration_config.vm_config,
849 &vm_migration_config.common_cpuid,
850 )?;
851
852 let config = vm_migration_config.vm_config.clone();
853 self.vm_config = Some(vm_migration_config.vm_config);
854 self.console_info = Some(pre_create_console_devices(self).map_err(|e| {
855 MigratableError::MigrateReceive(anyhow!("Error creating console devices: {:?}", e))
856 })?);
857
858 if self
859 .vm_config
860 .as_ref()
861 .unwrap()
862 .lock()
863 .unwrap()
864 .landlock_enable
865 {
866 apply_landlock(self.vm_config.as_ref().unwrap().clone()).map_err(|e| {
867 MigratableError::MigrateReceive(anyhow!("Error applying landlock: {:?}", e))
868 })?;
869 }
870
871 let vm = Vm::create_hypervisor_vm(
872 &self.hypervisor,
873 #[cfg(feature = "tdx")]
874 false,
875 #[cfg(feature = "sev_snp")]
876 false,
877 #[cfg(feature = "sev_snp")]
878 config.lock().unwrap().memory.total_size(),
879 )
880 .map_err(|e| {
881 MigratableError::MigrateReceive(anyhow!(
882 "Error creating hypervisor VM from snapshot: {:?}",
883 e
884 ))
885 })?;
886
887 let phys_bits =
888 vm::physical_bits(&self.hypervisor, config.lock().unwrap().cpus.max_phys_bits);
889
890 let memory_manager = MemoryManager::new(
891 vm,
892 &config.lock().unwrap().memory.clone(),
893 None,
894 phys_bits,
895 #[cfg(feature = "tdx")]
896 false,
897 Some(&vm_migration_config.memory_manager_data),
898 existing_memory_files,
899 #[cfg(target_arch = "x86_64")]
900 None,
901 )
902 .map_err(|e| {
903 MigratableError::MigrateReceive(anyhow!(
904 "Error creating MemoryManager from snapshot: {:?}",
905 e
906 ))
907 })?;
908
909 Response::ok().write_to(socket)?;
910
911 Ok(memory_manager)
912 }
913
vm_receive_state<T>( &mut self, req: &Request, socket: &mut T, mm: Arc<Mutex<MemoryManager>>, ) -> std::result::Result<(), MigratableError> where T: Read + Write,914 fn vm_receive_state<T>(
915 &mut self,
916 req: &Request,
917 socket: &mut T,
918 mm: Arc<Mutex<MemoryManager>>,
919 ) -> std::result::Result<(), MigratableError>
920 where
921 T: Read + Write,
922 {
923 // Read in state data
924 let mut data: Vec<u8> = Vec::new();
925 data.resize_with(req.length() as usize, Default::default);
926 socket
927 .read_exact(&mut data)
928 .map_err(MigratableError::MigrateSocket)?;
929 let snapshot: Snapshot = serde_json::from_slice(&data).map_err(|e| {
930 MigratableError::MigrateReceive(anyhow!("Error deserialising snapshot: {}", e))
931 })?;
932
933 let exit_evt = self.exit_evt.try_clone().map_err(|e| {
934 MigratableError::MigrateReceive(anyhow!("Error cloning exit EventFd: {}", e))
935 })?;
936 let reset_evt = self.reset_evt.try_clone().map_err(|e| {
937 MigratableError::MigrateReceive(anyhow!("Error cloning reset EventFd: {}", e))
938 })?;
939 #[cfg(feature = "guest_debug")]
940 let debug_evt = self.vm_debug_evt.try_clone().map_err(|e| {
941 MigratableError::MigrateReceive(anyhow!("Error cloning debug EventFd: {}", e))
942 })?;
943 let activate_evt = self.activate_evt.try_clone().map_err(|e| {
944 MigratableError::MigrateReceive(anyhow!("Error cloning activate EventFd: {}", e))
945 })?;
946
947 #[cfg(not(target_arch = "riscv64"))]
948 let timestamp = Instant::now();
949 let hypervisor_vm = mm.lock().unwrap().vm.clone();
950 let mut vm = Vm::new_from_memory_manager(
951 self.vm_config.clone().unwrap(),
952 mm,
953 hypervisor_vm,
954 exit_evt,
955 reset_evt,
956 #[cfg(feature = "guest_debug")]
957 debug_evt,
958 &self.seccomp_action,
959 self.hypervisor.clone(),
960 activate_evt,
961 #[cfg(not(target_arch = "riscv64"))]
962 timestamp,
963 self.console_info.clone(),
964 self.console_resize_pipe.clone(),
965 Arc::clone(&self.original_termios_opt),
966 Some(snapshot),
967 )
968 .map_err(|e| {
969 MigratableError::MigrateReceive(anyhow!("Error creating VM from snapshot: {:?}", e))
970 })?;
971
972 // Create VM
973 vm.restore().map_err(|e| {
974 Response::error().write_to(socket).ok();
975 MigratableError::MigrateReceive(anyhow!("Failed restoring the Vm: {}", e))
976 })?;
977 self.vm = Some(vm);
978
979 Response::ok().write_to(socket)?;
980
981 Ok(())
982 }
983
vm_receive_memory<T>( &mut self, req: &Request, socket: &mut T, memory_manager: &mut MemoryManager, ) -> std::result::Result<(), MigratableError> where T: Read + ReadVolatile + Write,984 fn vm_receive_memory<T>(
985 &mut self,
986 req: &Request,
987 socket: &mut T,
988 memory_manager: &mut MemoryManager,
989 ) -> std::result::Result<(), MigratableError>
990 where
991 T: Read + ReadVolatile + Write,
992 {
993 // Read table
994 let table = MemoryRangeTable::read_from(socket, req.length())?;
995
996 // And then read the memory itself
997 memory_manager
998 .receive_memory_regions(&table, socket)
999 .inspect_err(|_| {
1000 Response::error().write_to(socket).ok();
1001 })?;
1002 Response::ok().write_to(socket)?;
1003 Ok(())
1004 }
1005
socket_url_to_path(url: &str) -> result::Result<PathBuf, MigratableError>1006 fn socket_url_to_path(url: &str) -> result::Result<PathBuf, MigratableError> {
1007 url.strip_prefix("unix:")
1008 .ok_or_else(|| {
1009 MigratableError::MigrateSend(anyhow!("Could not extract path from URL: {}", url))
1010 })
1011 .map(|s| s.into())
1012 }
1013
send_migration_socket( destination_url: &str, ) -> std::result::Result<SocketStream, MigratableError>1014 fn send_migration_socket(
1015 destination_url: &str,
1016 ) -> std::result::Result<SocketStream, MigratableError> {
1017 if let Some(address) = destination_url.strip_prefix("tcp:") {
1018 info!("Connecting to TCP socket at {}", address);
1019
1020 let socket = TcpStream::connect(address).map_err(|e| {
1021 MigratableError::MigrateSend(anyhow!("Error connecting to TCP socket: {}", e))
1022 })?;
1023
1024 Ok(SocketStream::Tcp(socket))
1025 } else {
1026 let path = Vmm::socket_url_to_path(destination_url)?;
1027 info!("Connecting to UNIX socket at {:?}", path);
1028
1029 let socket = UnixStream::connect(&path).map_err(|e| {
1030 MigratableError::MigrateSend(anyhow!("Error connecting to UNIX socket: {}", e))
1031 })?;
1032
1033 Ok(SocketStream::Unix(socket))
1034 }
1035 }
1036
receive_migration_socket( receiver_url: &str, ) -> std::result::Result<SocketStream, MigratableError>1037 fn receive_migration_socket(
1038 receiver_url: &str,
1039 ) -> std::result::Result<SocketStream, MigratableError> {
1040 if let Some(address) = receiver_url.strip_prefix("tcp:") {
1041 let listener = TcpListener::bind(address).map_err(|e| {
1042 MigratableError::MigrateReceive(anyhow!("Error binding to TCP socket: {}", e))
1043 })?;
1044
1045 let (socket, _addr) = listener.accept().map_err(|e| {
1046 MigratableError::MigrateReceive(anyhow!(
1047 "Error accepting connection on TCP socket: {}",
1048 e
1049 ))
1050 })?;
1051
1052 Ok(SocketStream::Tcp(socket))
1053 } else {
1054 let path = Vmm::socket_url_to_path(receiver_url)?;
1055 let listener = UnixListener::bind(&path).map_err(|e| {
1056 MigratableError::MigrateReceive(anyhow!("Error binding to UNIX socket: {}", e))
1057 })?;
1058
1059 let (socket, _addr) = listener.accept().map_err(|e| {
1060 MigratableError::MigrateReceive(anyhow!(
1061 "Error accepting connection on UNIX socket: {}",
1062 e
1063 ))
1064 })?;
1065
1066 // Remove the UNIX socket file after accepting the connection
1067 std::fs::remove_file(&path).map_err(|e| {
1068 MigratableError::MigrateReceive(anyhow!("Error removing UNIX socket file: {}", e))
1069 })?;
1070
1071 Ok(SocketStream::Unix(socket))
1072 }
1073 }
1074
1075 // Returns true if there were dirty pages to send
vm_maybe_send_dirty_pages( vm: &mut Vm, socket: &mut SocketStream, ) -> result::Result<bool, MigratableError>1076 fn vm_maybe_send_dirty_pages(
1077 vm: &mut Vm,
1078 socket: &mut SocketStream,
1079 ) -> result::Result<bool, MigratableError> {
1080 // Send (dirty) memory table
1081 let table = vm.dirty_log()?;
1082
1083 // But if there are no regions go straight to pause
1084 if table.regions().is_empty() {
1085 return Ok(false);
1086 }
1087
1088 Request::memory(table.length()).write_to(socket).unwrap();
1089 table.write_to(socket)?;
1090 // And then the memory itself
1091 vm.send_memory_regions(&table, socket)?;
1092 Response::read_from(socket)?.ok_or_abandon(
1093 socket,
1094 MigratableError::MigrateSend(anyhow!("Error during dirty memory migration")),
1095 )?;
1096
1097 Ok(true)
1098 }
1099
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>1100 fn send_migration(
1101 vm: &mut Vm,
1102 #[cfg(all(feature = "kvm", target_arch = "x86_64"))] hypervisor: Arc<
1103 dyn hypervisor::Hypervisor,
1104 >,
1105 send_data_migration: VmSendMigrationData,
1106 ) -> result::Result<(), MigratableError> {
1107 // Set up the socket connection
1108 let mut socket = Self::send_migration_socket(&send_data_migration.destination_url)?;
1109
1110 // Start the migration
1111 Request::start().write_to(&mut socket)?;
1112 Response::read_from(&mut socket)?.ok_or_abandon(
1113 &mut socket,
1114 MigratableError::MigrateSend(anyhow!("Error starting migration")),
1115 )?;
1116
1117 // Send config
1118 let vm_config = vm.get_config();
1119 #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
1120 let common_cpuid = {
1121 #[cfg(feature = "tdx")]
1122 if vm_config.lock().unwrap().is_tdx_enabled() {
1123 return Err(MigratableError::MigrateSend(anyhow!(
1124 "Live Migration is not supported when TDX is enabled"
1125 )));
1126 };
1127
1128 let amx = vm_config.lock().unwrap().cpus.features.amx;
1129 let phys_bits =
1130 vm::physical_bits(&hypervisor, vm_config.lock().unwrap().cpus.max_phys_bits);
1131 arch::generate_common_cpuid(
1132 &hypervisor,
1133 &arch::CpuidConfig {
1134 sgx_epc_sections: None,
1135 phys_bits,
1136 kvm_hyperv: vm_config.lock().unwrap().cpus.kvm_hyperv,
1137 #[cfg(feature = "tdx")]
1138 tdx: false,
1139 amx,
1140 },
1141 )
1142 .map_err(|e| {
1143 MigratableError::MigrateSend(anyhow!("Error generating common cpuid': {:?}", e))
1144 })?
1145 };
1146
1147 if send_data_migration.local {
1148 match &mut socket {
1149 SocketStream::Unix(unix_socket) => {
1150 // Proceed with sending memory file descriptors over UNIX socket
1151 vm.send_memory_fds(unix_socket)?;
1152 }
1153 SocketStream::Tcp(_tcp_socket) => {
1154 return Err(MigratableError::MigrateSend(anyhow!(
1155 "--local option is not supported with TCP sockets",
1156 )));
1157 }
1158 }
1159 }
1160
1161 let vm_migration_config = VmMigrationConfig {
1162 vm_config,
1163 #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
1164 common_cpuid,
1165 memory_manager_data: vm.memory_manager_data(),
1166 };
1167 let config_data = serde_json::to_vec(&vm_migration_config).unwrap();
1168 Request::config(config_data.len() as u64).write_to(&mut socket)?;
1169 socket
1170 .write_all(&config_data)
1171 .map_err(MigratableError::MigrateSocket)?;
1172 Response::read_from(&mut socket)?.ok_or_abandon(
1173 &mut socket,
1174 MigratableError::MigrateSend(anyhow!("Error during config migration")),
1175 )?;
1176
1177 // Let every Migratable object know about the migration being started.
1178 vm.start_migration()?;
1179
1180 if send_data_migration.local {
1181 // Now pause VM
1182 vm.pause()?;
1183 } else {
1184 // Start logging dirty pages
1185 vm.start_dirty_log()?;
1186
1187 // Send memory table
1188 let table = vm.memory_range_table()?;
1189 Request::memory(table.length())
1190 .write_to(&mut socket)
1191 .unwrap();
1192 table.write_to(&mut socket)?;
1193 // And then the memory itself
1194 vm.send_memory_regions(&table, &mut socket)?;
1195 Response::read_from(&mut socket)?.ok_or_abandon(
1196 &mut socket,
1197 MigratableError::MigrateSend(anyhow!("Error during dirty memory migration")),
1198 )?;
1199
1200 // Try at most 5 passes of dirty memory sending
1201 const MAX_DIRTY_MIGRATIONS: usize = 5;
1202 for i in 0..MAX_DIRTY_MIGRATIONS {
1203 info!("Dirty memory migration {} of {}", i, MAX_DIRTY_MIGRATIONS);
1204 if !Self::vm_maybe_send_dirty_pages(vm, &mut socket)? {
1205 break;
1206 }
1207 }
1208
1209 // Now pause VM
1210 vm.pause()?;
1211
1212 // Send last batch of dirty pages
1213 Self::vm_maybe_send_dirty_pages(vm, &mut socket)?;
1214 }
1215
1216 // We release the locks early to enable locking them on the destination host.
1217 // The VM is already stopped.
1218 vm.release_disk_locks()
1219 .map_err(|e| MigratableError::UnlockError(anyhow!("{e}")))?;
1220
1221 // Capture snapshot and send it
1222 let vm_snapshot = vm.snapshot()?;
1223 let snapshot_data = serde_json::to_vec(&vm_snapshot).unwrap();
1224 Request::state(snapshot_data.len() as u64).write_to(&mut socket)?;
1225 socket
1226 .write_all(&snapshot_data)
1227 .map_err(MigratableError::MigrateSocket)?;
1228 Response::read_from(&mut socket)?.ok_or_abandon(
1229 &mut socket,
1230 MigratableError::MigrateSend(anyhow!("Error during state migration")),
1231 )?;
1232 // Complete the migration
1233 // At this step, the receiving VMM will acquire disk locks again.
1234 Request::complete().write_to(&mut socket)?;
1235 Response::read_from(&mut socket)?.ok_or_abandon(
1236 &mut socket,
1237 MigratableError::MigrateSend(anyhow!("Error completing migration")),
1238 )?;
1239
1240 // Stop logging dirty pages
1241 if !send_data_migration.local {
1242 vm.stop_dirty_log()?;
1243 }
1244
1245 info!("Migration complete");
1246
1247 // Let every Migratable object know about the migration being complete
1248 vm.complete_migration()
1249 }
1250
1251 #[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>1252 fn vm_check_cpuid_compatibility(
1253 &self,
1254 src_vm_config: &Arc<Mutex<VmConfig>>,
1255 src_vm_cpuid: &[hypervisor::arch::x86::CpuIdEntry],
1256 ) -> result::Result<(), MigratableError> {
1257 #[cfg(feature = "tdx")]
1258 if src_vm_config.lock().unwrap().is_tdx_enabled() {
1259 return Err(MigratableError::MigrateReceive(anyhow!(
1260 "Live Migration is not supported when TDX is enabled"
1261 )));
1262 };
1263
1264 // We check the `CPUID` compatibility of between the source vm and destination, which is
1265 // mostly about feature compatibility and "topology/sgx" leaves are not relevant.
1266 let dest_cpuid = &{
1267 let vm_config = &src_vm_config.lock().unwrap();
1268
1269 let phys_bits = vm::physical_bits(&self.hypervisor, vm_config.cpus.max_phys_bits);
1270 arch::generate_common_cpuid(
1271 &self.hypervisor.clone(),
1272 &arch::CpuidConfig {
1273 sgx_epc_sections: None,
1274 phys_bits,
1275 kvm_hyperv: vm_config.cpus.kvm_hyperv,
1276 #[cfg(feature = "tdx")]
1277 tdx: false,
1278 amx: vm_config.cpus.features.amx,
1279 },
1280 )
1281 .map_err(|e| {
1282 MigratableError::MigrateReceive(anyhow!("Error generating common cpuid: {:?}", e))
1283 })?
1284 };
1285 arch::CpuidFeatureEntry::check_cpuid_compatibility(src_vm_cpuid, dest_cpuid).map_err(|e| {
1286 MigratableError::MigrateReceive(anyhow!(
1287 "Error checking cpu feature compatibility': {:?}",
1288 e
1289 ))
1290 })
1291 }
1292
vm_restore( &mut self, source_url: &str, vm_config: Arc<Mutex<VmConfig>>, prefault: bool, ) -> std::result::Result<(), VmError>1293 fn vm_restore(
1294 &mut self,
1295 source_url: &str,
1296 vm_config: Arc<Mutex<VmConfig>>,
1297 prefault: bool,
1298 ) -> std::result::Result<(), VmError> {
1299 let snapshot = recv_vm_state(source_url).map_err(VmError::Restore)?;
1300 #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
1301 let vm_snapshot = get_vm_snapshot(&snapshot).map_err(VmError::Restore)?;
1302
1303 #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
1304 self.vm_check_cpuid_compatibility(&vm_config, &vm_snapshot.common_cpuid)
1305 .map_err(VmError::Restore)?;
1306
1307 self.vm_config = Some(Arc::clone(&vm_config));
1308
1309 // Always re-populate the 'console_info' based on the new 'vm_config'
1310 self.console_info =
1311 Some(pre_create_console_devices(self).map_err(VmError::CreateConsoleDevices)?);
1312
1313 let exit_evt = self.exit_evt.try_clone().map_err(VmError::EventFdClone)?;
1314 let reset_evt = self.reset_evt.try_clone().map_err(VmError::EventFdClone)?;
1315 #[cfg(feature = "guest_debug")]
1316 let debug_evt = self
1317 .vm_debug_evt
1318 .try_clone()
1319 .map_err(VmError::EventFdClone)?;
1320 let activate_evt = self
1321 .activate_evt
1322 .try_clone()
1323 .map_err(VmError::EventFdClone)?;
1324
1325 let vm = Vm::new(
1326 vm_config,
1327 exit_evt,
1328 reset_evt,
1329 #[cfg(feature = "guest_debug")]
1330 debug_evt,
1331 &self.seccomp_action,
1332 self.hypervisor.clone(),
1333 activate_evt,
1334 self.console_info.clone(),
1335 self.console_resize_pipe.clone(),
1336 Arc::clone(&self.original_termios_opt),
1337 Some(snapshot),
1338 Some(source_url),
1339 Some(prefault),
1340 )?;
1341 self.vm = Some(vm);
1342
1343 if self
1344 .vm_config
1345 .as_ref()
1346 .unwrap()
1347 .lock()
1348 .unwrap()
1349 .landlock_enable
1350 {
1351 apply_landlock(self.vm_config.as_ref().unwrap().clone())
1352 .map_err(VmError::ApplyLandlock)?;
1353 }
1354
1355 // Now we can restore the rest of the VM.
1356 if let Some(ref mut vm) = self.vm {
1357 vm.restore()
1358 } else {
1359 Err(VmError::VmNotCreated)
1360 }
1361 }
1362
control_loop( &mut self, api_receiver: Rc<Receiver<ApiRequest>>, #[cfg(feature = "guest_debug")] gdb_receiver: Rc<Receiver<gdb::GdbRequest>>, ) -> Result<()>1363 fn control_loop(
1364 &mut self,
1365 api_receiver: Rc<Receiver<ApiRequest>>,
1366 #[cfg(feature = "guest_debug")] gdb_receiver: Rc<Receiver<gdb::GdbRequest>>,
1367 ) -> Result<()> {
1368 const EPOLL_EVENTS_LEN: usize = 100;
1369
1370 let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN];
1371 let epoll_fd = self.epoll.as_raw_fd();
1372
1373 'outer: loop {
1374 let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) {
1375 Ok(res) => res,
1376 Err(e) => {
1377 if e.kind() == io::ErrorKind::Interrupted {
1378 // It's well defined from the epoll_wait() syscall
1379 // documentation that the epoll loop can be interrupted
1380 // before any of the requested events occurred or the
1381 // timeout expired. In both those cases, epoll_wait()
1382 // returns an error of type EINTR, but this should not
1383 // be considered as a regular error. Instead it is more
1384 // appropriate to retry, by calling into epoll_wait().
1385 continue;
1386 }
1387 return Err(Error::Epoll(e));
1388 }
1389 };
1390
1391 for event in events.iter().take(num_events) {
1392 let dispatch_event: EpollDispatch = event.data.into();
1393 match dispatch_event {
1394 EpollDispatch::Unknown => {
1395 let event = event.data;
1396 warn!("Unknown VMM loop event: {}", event);
1397 }
1398 EpollDispatch::Exit => {
1399 info!("VM exit event");
1400 // Consume the event.
1401 self.exit_evt.read().map_err(Error::EventFdRead)?;
1402 self.vmm_shutdown().map_err(Error::VmmShutdown)?;
1403
1404 break 'outer;
1405 }
1406 EpollDispatch::Reset => {
1407 info!("VM reset event");
1408 // Consume the event.
1409 self.reset_evt.read().map_err(Error::EventFdRead)?;
1410 self.vm_reboot().map_err(Error::VmReboot)?;
1411 }
1412 EpollDispatch::ActivateVirtioDevices => {
1413 if let Some(ref vm) = self.vm {
1414 let count = self.activate_evt.read().map_err(Error::EventFdRead)?;
1415 info!(
1416 "Trying to activate pending virtio devices: count = {}",
1417 count
1418 );
1419 vm.activate_virtio_devices()
1420 .map_err(Error::ActivateVirtioDevices)?;
1421 }
1422 }
1423 EpollDispatch::Api => {
1424 // Consume the events.
1425 for _ in 0..self.api_evt.read().map_err(Error::EventFdRead)? {
1426 // Read from the API receiver channel
1427 let api_request = api_receiver.recv().map_err(Error::ApiRequestRecv)?;
1428
1429 if api_request(self)? {
1430 break 'outer;
1431 }
1432 }
1433 }
1434 #[cfg(feature = "guest_debug")]
1435 EpollDispatch::Debug => {
1436 // Consume the events.
1437 for _ in 0..self.debug_evt.read().map_err(Error::EventFdRead)? {
1438 // Read from the API receiver channel
1439 let gdb_request = gdb_receiver.recv().map_err(Error::GdbRequestRecv)?;
1440
1441 let response = if let Some(ref mut vm) = self.vm {
1442 vm.debug_request(&gdb_request.payload, gdb_request.cpu_id)
1443 } else {
1444 Err(VmError::VmNotRunning)
1445 }
1446 .map_err(gdb::Error::Vm);
1447
1448 gdb_request
1449 .sender
1450 .send(response)
1451 .map_err(Error::GdbResponseSend)?;
1452 }
1453 }
1454 #[cfg(not(feature = "guest_debug"))]
1455 EpollDispatch::Debug => {}
1456 }
1457 }
1458 }
1459
1460 // Trigger the termination of the signal_handler thread
1461 if let Some(signals) = self.signals.take() {
1462 signals.close();
1463 }
1464
1465 // Wait for all the threads to finish
1466 for thread in self.threads.drain(..) {
1467 thread.join().map_err(Error::ThreadCleanup)?
1468 }
1469
1470 Ok(())
1471 }
1472 }
1473
apply_landlock(vm_config: Arc<Mutex<VmConfig>>) -> result::Result<(), LandlockError>1474 fn apply_landlock(vm_config: Arc<Mutex<VmConfig>>) -> result::Result<(), LandlockError> {
1475 vm_config.lock().unwrap().apply_landlock()?;
1476 Ok(())
1477 }
1478
1479 impl RequestHandler for Vmm {
vm_create(&mut self, config: Box<VmConfig>) -> result::Result<(), VmError>1480 fn vm_create(&mut self, config: Box<VmConfig>) -> result::Result<(), VmError> {
1481 // We only store the passed VM config.
1482 // The VM will be created when being asked to boot it.
1483 if self.vm_config.is_none() {
1484 self.vm_config = Some(Arc::new(Mutex::new(*config)));
1485 self.console_info =
1486 Some(pre_create_console_devices(self).map_err(VmError::CreateConsoleDevices)?);
1487
1488 if self
1489 .vm_config
1490 .as_ref()
1491 .unwrap()
1492 .lock()
1493 .unwrap()
1494 .landlock_enable
1495 {
1496 apply_landlock(self.vm_config.as_ref().unwrap().clone())
1497 .map_err(VmError::ApplyLandlock)?;
1498 }
1499 Ok(())
1500 } else {
1501 Err(VmError::VmAlreadyCreated)
1502 }
1503 }
1504
vm_boot(&mut self) -> result::Result<(), VmError>1505 fn vm_boot(&mut self) -> result::Result<(), VmError> {
1506 tracer::start();
1507 info!("Booting VM");
1508 event!("vm", "booting");
1509 let r = {
1510 trace_scoped!("vm_boot");
1511 // If we don't have a config, we cannot boot a VM.
1512 if self.vm_config.is_none() {
1513 return Err(VmError::VmMissingConfig);
1514 };
1515
1516 // console_info is set to None in vm_shutdown. re-populate here if empty
1517 if self.console_info.is_none() {
1518 self.console_info =
1519 Some(pre_create_console_devices(self).map_err(VmError::CreateConsoleDevices)?);
1520 }
1521
1522 // Create a new VM if we don't have one yet.
1523 if self.vm.is_none() {
1524 let exit_evt = self.exit_evt.try_clone().map_err(VmError::EventFdClone)?;
1525 let reset_evt = self.reset_evt.try_clone().map_err(VmError::EventFdClone)?;
1526 #[cfg(feature = "guest_debug")]
1527 let vm_debug_evt = self
1528 .vm_debug_evt
1529 .try_clone()
1530 .map_err(VmError::EventFdClone)?;
1531 let activate_evt = self
1532 .activate_evt
1533 .try_clone()
1534 .map_err(VmError::EventFdClone)?;
1535
1536 if let Some(ref vm_config) = self.vm_config {
1537 let vm = Vm::new(
1538 Arc::clone(vm_config),
1539 exit_evt,
1540 reset_evt,
1541 #[cfg(feature = "guest_debug")]
1542 vm_debug_evt,
1543 &self.seccomp_action,
1544 self.hypervisor.clone(),
1545 activate_evt,
1546 self.console_info.clone(),
1547 self.console_resize_pipe.clone(),
1548 Arc::clone(&self.original_termios_opt),
1549 None,
1550 None,
1551 None,
1552 )?;
1553
1554 self.vm = Some(vm);
1555 }
1556 }
1557
1558 // Now we can boot the VM.
1559 if let Some(ref mut vm) = self.vm {
1560 vm.boot()
1561 } else {
1562 Err(VmError::VmNotCreated)
1563 }
1564 };
1565 tracer::end();
1566 if r.is_ok() {
1567 event!("vm", "booted");
1568 }
1569 r
1570 }
1571
vm_pause(&mut self) -> result::Result<(), VmError>1572 fn vm_pause(&mut self) -> result::Result<(), VmError> {
1573 if let Some(ref mut vm) = self.vm {
1574 vm.pause().map_err(VmError::Pause)
1575 } else {
1576 Err(VmError::VmNotRunning)
1577 }
1578 }
1579
vm_resume(&mut self) -> result::Result<(), VmError>1580 fn vm_resume(&mut self) -> result::Result<(), VmError> {
1581 if let Some(ref mut vm) = self.vm {
1582 vm.resume().map_err(VmError::Resume)
1583 } else {
1584 Err(VmError::VmNotRunning)
1585 }
1586 }
1587
vm_snapshot(&mut self, destination_url: &str) -> result::Result<(), VmError>1588 fn vm_snapshot(&mut self, destination_url: &str) -> result::Result<(), VmError> {
1589 if let Some(ref mut vm) = self.vm {
1590 // Drain console_info so that FDs are not reused
1591 let _ = self.console_info.take();
1592 vm.snapshot()
1593 .map_err(VmError::Snapshot)
1594 .and_then(|snapshot| {
1595 vm.send(&snapshot, destination_url)
1596 .map_err(VmError::SnapshotSend)
1597 })
1598 } else {
1599 Err(VmError::VmNotRunning)
1600 }
1601 }
1602
vm_restore(&mut self, restore_cfg: RestoreConfig) -> result::Result<(), VmError>1603 fn vm_restore(&mut self, restore_cfg: RestoreConfig) -> result::Result<(), VmError> {
1604 if self.vm.is_some() || self.vm_config.is_some() {
1605 return Err(VmError::VmAlreadyCreated);
1606 }
1607
1608 let source_url = restore_cfg.source_url.as_path().to_str();
1609 if source_url.is_none() {
1610 return Err(VmError::InvalidRestoreSourceUrl);
1611 }
1612 // Safe to unwrap as we checked it was Some(&str).
1613 let source_url = source_url.unwrap();
1614
1615 let vm_config = Arc::new(Mutex::new(
1616 recv_vm_config(source_url).map_err(VmError::Restore)?,
1617 ));
1618 restore_cfg
1619 .validate(&vm_config.lock().unwrap().clone())
1620 .map_err(VmError::ConfigValidation)?;
1621
1622 // Update VM's net configurations with new fds received for restore operation
1623 if let (Some(restored_nets), Some(vm_net_configs)) =
1624 (restore_cfg.net_fds, &mut vm_config.lock().unwrap().net)
1625 {
1626 for net in restored_nets.iter() {
1627 for net_config in vm_net_configs.iter_mut() {
1628 // update only if the net dev is backed by FDs
1629 if net_config.id == Some(net.id.clone()) && net_config.fds.is_some() {
1630 net_config.fds.clone_from(&net.fds);
1631 }
1632 }
1633 }
1634 }
1635
1636 self.vm_restore(source_url, vm_config, restore_cfg.prefault)
1637 .map_err(|vm_restore_err| {
1638 error!("VM Restore failed: {:?}", vm_restore_err);
1639
1640 // Cleanup the VM being created while vm restore
1641 if let Err(e) = self.vm_delete() {
1642 return e;
1643 }
1644
1645 vm_restore_err
1646 })
1647 }
1648
1649 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
vm_coredump(&mut self, destination_url: &str) -> result::Result<(), VmError>1650 fn vm_coredump(&mut self, destination_url: &str) -> result::Result<(), VmError> {
1651 if let Some(ref mut vm) = self.vm {
1652 vm.coredump(destination_url).map_err(VmError::Coredump)
1653 } else {
1654 Err(VmError::VmNotRunning)
1655 }
1656 }
1657
vm_shutdown(&mut self) -> result::Result<(), VmError>1658 fn vm_shutdown(&mut self) -> result::Result<(), VmError> {
1659 let r = if let Some(ref mut vm) = self.vm.take() {
1660 // Drain console_info so that the FDs are not reused
1661 let _ = self.console_info.take();
1662 vm.shutdown()
1663 } else {
1664 Err(VmError::VmNotRunning)
1665 };
1666
1667 if r.is_ok() {
1668 event!("vm", "shutdown");
1669 }
1670
1671 r
1672 }
1673
vm_reboot(&mut self) -> result::Result<(), VmError>1674 fn vm_reboot(&mut self) -> result::Result<(), VmError> {
1675 event!("vm", "rebooting");
1676
1677 // First we stop the current VM
1678 let config = if let Some(mut vm) = self.vm.take() {
1679 let config = vm.get_config();
1680 vm.shutdown()?;
1681 config
1682 } else {
1683 return Err(VmError::VmNotCreated);
1684 };
1685
1686 // vm.shutdown() closes all the console devices, so set console_info to None
1687 // so that the closed FD #s are not reused.
1688 let _ = self.console_info.take();
1689
1690 let exit_evt = self.exit_evt.try_clone().map_err(VmError::EventFdClone)?;
1691 let reset_evt = self.reset_evt.try_clone().map_err(VmError::EventFdClone)?;
1692 #[cfg(feature = "guest_debug")]
1693 let debug_evt = self
1694 .vm_debug_evt
1695 .try_clone()
1696 .map_err(VmError::EventFdClone)?;
1697 let activate_evt = self
1698 .activate_evt
1699 .try_clone()
1700 .map_err(VmError::EventFdClone)?;
1701
1702 // The Linux kernel fires off an i8042 reset after doing the ACPI reset so there may be
1703 // an event sitting in the shared reset_evt. Without doing this we get very early reboots
1704 // during the boot process.
1705 if self.reset_evt.read().is_ok() {
1706 warn!("Spurious second reset event received. Ignoring.");
1707 }
1708
1709 self.console_info =
1710 Some(pre_create_console_devices(self).map_err(VmError::CreateConsoleDevices)?);
1711
1712 // Then we create the new VM
1713 let mut vm = Vm::new(
1714 config,
1715 exit_evt,
1716 reset_evt,
1717 #[cfg(feature = "guest_debug")]
1718 debug_evt,
1719 &self.seccomp_action,
1720 self.hypervisor.clone(),
1721 activate_evt,
1722 self.console_info.clone(),
1723 self.console_resize_pipe.clone(),
1724 Arc::clone(&self.original_termios_opt),
1725 None,
1726 None,
1727 None,
1728 )?;
1729
1730 // And we boot it
1731 vm.boot()?;
1732
1733 self.vm = Some(vm);
1734
1735 event!("vm", "rebooted");
1736
1737 Ok(())
1738 }
1739
vm_info(&self) -> result::Result<VmInfoResponse, VmError>1740 fn vm_info(&self) -> result::Result<VmInfoResponse, VmError> {
1741 match &self.vm_config {
1742 Some(vm_config) => {
1743 let state = match &self.vm {
1744 Some(vm) => vm.get_state()?,
1745 None => VmState::Created,
1746 };
1747 let config = vm_config.lock().unwrap().clone();
1748
1749 let mut memory_actual_size = config.memory.total_size();
1750 if let Some(vm) = &self.vm {
1751 memory_actual_size -= vm.balloon_size();
1752 }
1753
1754 let device_tree = self
1755 .vm
1756 .as_ref()
1757 .map(|vm| vm.device_tree().lock().unwrap().clone());
1758
1759 Ok(VmInfoResponse {
1760 config: Box::new(config),
1761 state,
1762 memory_actual_size,
1763 device_tree,
1764 })
1765 }
1766 None => Err(VmError::VmNotCreated),
1767 }
1768 }
1769
vmm_ping(&self) -> VmmPingResponse1770 fn vmm_ping(&self) -> VmmPingResponse {
1771 let VmmVersionInfo {
1772 build_version,
1773 version,
1774 } = self.version.clone();
1775
1776 VmmPingResponse {
1777 build_version,
1778 version,
1779 pid: std::process::id() as i64,
1780 features: feature_list(),
1781 }
1782 }
1783
vm_delete(&mut self) -> result::Result<(), VmError>1784 fn vm_delete(&mut self) -> result::Result<(), VmError> {
1785 if self.vm_config.is_none() {
1786 return Ok(());
1787 }
1788
1789 // If a VM is booted, we first try to shut it down.
1790 if self.vm.is_some() {
1791 self.vm_shutdown()?;
1792 }
1793
1794 self.vm_config = None;
1795
1796 event!("vm", "deleted");
1797
1798 Ok(())
1799 }
1800
vmm_shutdown(&mut self) -> result::Result<(), VmError>1801 fn vmm_shutdown(&mut self) -> result::Result<(), VmError> {
1802 self.vm_delete()?;
1803 event!("vmm", "shutdown");
1804 Ok(())
1805 }
1806
vm_resize( &mut self, desired_vcpus: Option<u8>, desired_ram: Option<u64>, desired_balloon: Option<u64>, ) -> result::Result<(), VmError>1807 fn vm_resize(
1808 &mut self,
1809 desired_vcpus: Option<u8>,
1810 desired_ram: Option<u64>,
1811 desired_balloon: Option<u64>,
1812 ) -> result::Result<(), VmError> {
1813 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
1814
1815 if let Some(ref mut vm) = self.vm {
1816 if let Err(e) = vm.resize(desired_vcpus, desired_ram, desired_balloon) {
1817 error!("Error when resizing VM: {:?}", e);
1818 Err(e)
1819 } else {
1820 Ok(())
1821 }
1822 } else {
1823 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
1824 if let Some(desired_vcpus) = desired_vcpus {
1825 config.cpus.boot_vcpus = desired_vcpus;
1826 }
1827 if let Some(desired_ram) = desired_ram {
1828 config.memory.size = desired_ram;
1829 }
1830 if let Some(desired_balloon) = desired_balloon {
1831 if let Some(balloon_config) = &mut config.balloon {
1832 balloon_config.size = desired_balloon;
1833 }
1834 }
1835 Ok(())
1836 }
1837 }
1838
vm_resize_zone(&mut self, id: String, desired_ram: u64) -> result::Result<(), VmError>1839 fn vm_resize_zone(&mut self, id: String, desired_ram: u64) -> result::Result<(), VmError> {
1840 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
1841
1842 if let Some(ref mut vm) = self.vm {
1843 if let Err(e) = vm.resize_zone(id, desired_ram) {
1844 error!("Error when resizing VM: {:?}", e);
1845 Err(e)
1846 } else {
1847 Ok(())
1848 }
1849 } else {
1850 // Update VmConfig by setting the new desired ram.
1851 let memory_config = &mut self.vm_config.as_ref().unwrap().lock().unwrap().memory;
1852
1853 if let Some(zones) = &mut memory_config.zones {
1854 for zone in zones.iter_mut() {
1855 if zone.id == id {
1856 zone.size = desired_ram;
1857 return Ok(());
1858 }
1859 }
1860 }
1861
1862 error!("Could not find the memory zone {} for the resize", id);
1863 Err(VmError::ResizeZone)
1864 }
1865 }
1866
vm_add_device( &mut self, device_cfg: DeviceConfig, ) -> result::Result<Option<Vec<u8>>, VmError>1867 fn vm_add_device(
1868 &mut self,
1869 device_cfg: DeviceConfig,
1870 ) -> result::Result<Option<Vec<u8>>, VmError> {
1871 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
1872
1873 {
1874 // Validate the configuration change in a cloned configuration
1875 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
1876 add_to_config(&mut config.devices, device_cfg.clone());
1877 config.validate().map_err(VmError::ConfigValidation)?;
1878 }
1879
1880 if let Some(ref mut vm) = self.vm {
1881 let info = vm.add_device(device_cfg).map_err(|e| {
1882 error!("Error when adding new device to the VM: {:?}", e);
1883 e
1884 })?;
1885 serde_json::to_vec(&info)
1886 .map(Some)
1887 .map_err(VmError::SerializeJson)
1888 } else {
1889 // Update VmConfig by adding the new device.
1890 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
1891 add_to_config(&mut config.devices, device_cfg);
1892 Ok(None)
1893 }
1894 }
1895
vm_add_user_device( &mut self, device_cfg: UserDeviceConfig, ) -> result::Result<Option<Vec<u8>>, VmError>1896 fn vm_add_user_device(
1897 &mut self,
1898 device_cfg: UserDeviceConfig,
1899 ) -> result::Result<Option<Vec<u8>>, VmError> {
1900 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
1901
1902 {
1903 // Validate the configuration change in a cloned configuration
1904 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
1905 add_to_config(&mut config.user_devices, device_cfg.clone());
1906 config.validate().map_err(VmError::ConfigValidation)?;
1907 }
1908
1909 if let Some(ref mut vm) = self.vm {
1910 let info = vm.add_user_device(device_cfg).map_err(|e| {
1911 error!("Error when adding new user device to the VM: {:?}", e);
1912 e
1913 })?;
1914 serde_json::to_vec(&info)
1915 .map(Some)
1916 .map_err(VmError::SerializeJson)
1917 } else {
1918 // Update VmConfig by adding the new device.
1919 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
1920 add_to_config(&mut config.user_devices, device_cfg);
1921 Ok(None)
1922 }
1923 }
1924
vm_remove_device(&mut self, id: String) -> result::Result<(), VmError>1925 fn vm_remove_device(&mut self, id: String) -> result::Result<(), VmError> {
1926 if let Some(ref mut vm) = self.vm {
1927 if let Err(e) = vm.remove_device(id) {
1928 error!("Error when removing device from the VM: {:?}", e);
1929 Err(e)
1930 } else {
1931 Ok(())
1932 }
1933 } else if let Some(ref config) = self.vm_config {
1934 let mut config = config.lock().unwrap();
1935 if config.remove_device(&id) {
1936 Ok(())
1937 } else {
1938 Err(VmError::NoDeviceToRemove(id))
1939 }
1940 } else {
1941 Err(VmError::VmNotCreated)
1942 }
1943 }
1944
vm_add_disk(&mut self, disk_cfg: DiskConfig) -> result::Result<Option<Vec<u8>>, VmError>1945 fn vm_add_disk(&mut self, disk_cfg: DiskConfig) -> result::Result<Option<Vec<u8>>, VmError> {
1946 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
1947
1948 {
1949 // Validate the configuration change in a cloned configuration
1950 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
1951 add_to_config(&mut config.disks, disk_cfg.clone());
1952 config.validate().map_err(VmError::ConfigValidation)?;
1953 }
1954
1955 if let Some(ref mut vm) = self.vm {
1956 let info = vm.add_disk(disk_cfg).map_err(|e| {
1957 error!("Error when adding new disk to the VM: {:?}", e);
1958 e
1959 })?;
1960 serde_json::to_vec(&info)
1961 .map(Some)
1962 .map_err(VmError::SerializeJson)
1963 } else {
1964 // Update VmConfig by adding the new device.
1965 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
1966 add_to_config(&mut config.disks, disk_cfg);
1967 Ok(None)
1968 }
1969 }
1970
vm_add_fs(&mut self, fs_cfg: FsConfig) -> result::Result<Option<Vec<u8>>, VmError>1971 fn vm_add_fs(&mut self, fs_cfg: FsConfig) -> result::Result<Option<Vec<u8>>, VmError> {
1972 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
1973
1974 {
1975 // Validate the configuration change in a cloned configuration
1976 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
1977 add_to_config(&mut config.fs, fs_cfg.clone());
1978 config.validate().map_err(VmError::ConfigValidation)?;
1979 }
1980
1981 if let Some(ref mut vm) = self.vm {
1982 let info = vm.add_fs(fs_cfg).map_err(|e| {
1983 error!("Error when adding new fs to the VM: {:?}", e);
1984 e
1985 })?;
1986 serde_json::to_vec(&info)
1987 .map(Some)
1988 .map_err(VmError::SerializeJson)
1989 } else {
1990 // Update VmConfig by adding the new device.
1991 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
1992 add_to_config(&mut config.fs, fs_cfg);
1993 Ok(None)
1994 }
1995 }
1996
vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> result::Result<Option<Vec<u8>>, VmError>1997 fn vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> result::Result<Option<Vec<u8>>, VmError> {
1998 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
1999
2000 {
2001 // Validate the configuration change in a cloned configuration
2002 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
2003 add_to_config(&mut config.pmem, pmem_cfg.clone());
2004 config.validate().map_err(VmError::ConfigValidation)?;
2005 }
2006
2007 if let Some(ref mut vm) = self.vm {
2008 let info = vm.add_pmem(pmem_cfg).map_err(|e| {
2009 error!("Error when adding new pmem device to the VM: {:?}", e);
2010 e
2011 })?;
2012 serde_json::to_vec(&info)
2013 .map(Some)
2014 .map_err(VmError::SerializeJson)
2015 } else {
2016 // Update VmConfig by adding the new device.
2017 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
2018 add_to_config(&mut config.pmem, pmem_cfg);
2019 Ok(None)
2020 }
2021 }
2022
vm_add_net(&mut self, net_cfg: NetConfig) -> result::Result<Option<Vec<u8>>, VmError>2023 fn vm_add_net(&mut self, net_cfg: NetConfig) -> result::Result<Option<Vec<u8>>, VmError> {
2024 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
2025
2026 {
2027 // Validate the configuration change in a cloned configuration
2028 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
2029 add_to_config(&mut config.net, net_cfg.clone());
2030 config.validate().map_err(VmError::ConfigValidation)?;
2031 }
2032
2033 if let Some(ref mut vm) = self.vm {
2034 let info = vm.add_net(net_cfg).map_err(|e| {
2035 error!("Error when adding new network device to the VM: {:?}", e);
2036 e
2037 })?;
2038 serde_json::to_vec(&info)
2039 .map(Some)
2040 .map_err(VmError::SerializeJson)
2041 } else {
2042 // Update VmConfig by adding the new device.
2043 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
2044 add_to_config(&mut config.net, net_cfg);
2045 Ok(None)
2046 }
2047 }
2048
vm_add_vdpa(&mut self, vdpa_cfg: VdpaConfig) -> result::Result<Option<Vec<u8>>, VmError>2049 fn vm_add_vdpa(&mut self, vdpa_cfg: VdpaConfig) -> result::Result<Option<Vec<u8>>, VmError> {
2050 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
2051
2052 {
2053 // Validate the configuration change in a cloned configuration
2054 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
2055 add_to_config(&mut config.vdpa, vdpa_cfg.clone());
2056 config.validate().map_err(VmError::ConfigValidation)?;
2057 }
2058
2059 if let Some(ref mut vm) = self.vm {
2060 let info = vm.add_vdpa(vdpa_cfg).map_err(|e| {
2061 error!("Error when adding new vDPA device to the VM: {:?}", e);
2062 e
2063 })?;
2064 serde_json::to_vec(&info)
2065 .map(Some)
2066 .map_err(VmError::SerializeJson)
2067 } else {
2068 // Update VmConfig by adding the new device.
2069 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
2070 add_to_config(&mut config.vdpa, vdpa_cfg);
2071 Ok(None)
2072 }
2073 }
2074
vm_add_vsock(&mut self, vsock_cfg: VsockConfig) -> result::Result<Option<Vec<u8>>, VmError>2075 fn vm_add_vsock(&mut self, vsock_cfg: VsockConfig) -> result::Result<Option<Vec<u8>>, VmError> {
2076 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
2077
2078 {
2079 // Validate the configuration change in a cloned configuration
2080 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
2081
2082 if config.vsock.is_some() {
2083 return Err(VmError::TooManyVsockDevices);
2084 }
2085
2086 config.vsock = Some(vsock_cfg.clone());
2087 config.validate().map_err(VmError::ConfigValidation)?;
2088 }
2089
2090 if let Some(ref mut vm) = self.vm {
2091 let info = vm.add_vsock(vsock_cfg).map_err(|e| {
2092 error!("Error when adding new vsock device to the VM: {:?}", e);
2093 e
2094 })?;
2095 serde_json::to_vec(&info)
2096 .map(Some)
2097 .map_err(VmError::SerializeJson)
2098 } else {
2099 // Update VmConfig by adding the new device.
2100 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
2101 config.vsock = Some(vsock_cfg);
2102 Ok(None)
2103 }
2104 }
2105
vm_counters(&mut self) -> result::Result<Option<Vec<u8>>, VmError>2106 fn vm_counters(&mut self) -> result::Result<Option<Vec<u8>>, VmError> {
2107 if let Some(ref mut vm) = self.vm {
2108 let info = vm.counters().map_err(|e| {
2109 error!("Error when getting counters from the VM: {:?}", e);
2110 e
2111 })?;
2112 serde_json::to_vec(&info)
2113 .map(Some)
2114 .map_err(VmError::SerializeJson)
2115 } else {
2116 Err(VmError::VmNotRunning)
2117 }
2118 }
2119
vm_power_button(&mut self) -> result::Result<(), VmError>2120 fn vm_power_button(&mut self) -> result::Result<(), VmError> {
2121 if let Some(ref mut vm) = self.vm {
2122 vm.power_button()
2123 } else {
2124 Err(VmError::VmNotRunning)
2125 }
2126 }
2127
vm_nmi(&mut self) -> result::Result<(), VmError>2128 fn vm_nmi(&mut self) -> result::Result<(), VmError> {
2129 if let Some(ref mut vm) = self.vm {
2130 vm.nmi()
2131 } else {
2132 Err(VmError::VmNotRunning)
2133 }
2134 }
2135
vm_receive_migration( &mut self, receive_data_migration: VmReceiveMigrationData, ) -> result::Result<(), MigratableError>2136 fn vm_receive_migration(
2137 &mut self,
2138 receive_data_migration: VmReceiveMigrationData,
2139 ) -> result::Result<(), MigratableError> {
2140 info!(
2141 "Receiving migration: receiver_url = {}",
2142 receive_data_migration.receiver_url
2143 );
2144
2145 // Accept the connection and get the socket
2146 let mut socket = Vmm::receive_migration_socket(&receive_data_migration.receiver_url)?;
2147
2148 let mut started = false;
2149 let mut memory_manager: Option<Arc<Mutex<MemoryManager>>> = None;
2150 let mut existing_memory_files = None;
2151 loop {
2152 let req = Request::read_from(&mut socket)?;
2153 match req.command() {
2154 Command::Invalid => info!("Invalid Command Received"),
2155 Command::Start => {
2156 info!("Start Command Received");
2157 started = true;
2158
2159 Response::ok().write_to(&mut socket)?;
2160 }
2161 Command::Config => {
2162 info!("Config Command Received");
2163
2164 if !started {
2165 warn!("Migration not started yet");
2166 Response::error().write_to(&mut socket)?;
2167 continue;
2168 }
2169 memory_manager = Some(self.vm_receive_config(
2170 &req,
2171 &mut socket,
2172 existing_memory_files.take(),
2173 )?);
2174 }
2175 Command::State => {
2176 info!("State Command Received");
2177
2178 if !started {
2179 warn!("Migration not started yet");
2180 Response::error().write_to(&mut socket)?;
2181 continue;
2182 }
2183 if let Some(mm) = memory_manager.take() {
2184 self.vm_receive_state(&req, &mut socket, mm)?;
2185 } else {
2186 warn!("Configuration not sent yet");
2187 Response::error().write_to(&mut socket)?;
2188 }
2189 }
2190 Command::Memory => {
2191 info!("Memory Command Received");
2192
2193 if !started {
2194 warn!("Migration not started yet");
2195 Response::error().write_to(&mut socket)?;
2196 continue;
2197 }
2198 if let Some(mm) = memory_manager.as_ref() {
2199 self.vm_receive_memory(&req, &mut socket, &mut mm.lock().unwrap())?;
2200 } else {
2201 warn!("Configuration not sent yet");
2202 Response::error().write_to(&mut socket)?;
2203 }
2204 }
2205 Command::MemoryFd => {
2206 info!("MemoryFd Command Received");
2207
2208 if !started {
2209 warn!("Migration not started yet");
2210 Response::error().write_to(&mut socket)?;
2211 continue;
2212 }
2213
2214 match &mut socket {
2215 SocketStream::Unix(unix_socket) => {
2216 let mut buf = [0u8; 4];
2217 let (_, file) = unix_socket.recv_with_fd(&mut buf).map_err(|e| {
2218 MigratableError::MigrateReceive(anyhow!(
2219 "Error receiving slot from socket: {}",
2220 e
2221 ))
2222 })?;
2223
2224 if existing_memory_files.is_none() {
2225 existing_memory_files = Some(HashMap::default())
2226 }
2227
2228 if let Some(ref mut existing_memory_files) = existing_memory_files {
2229 let slot = u32::from_le_bytes(buf);
2230 existing_memory_files.insert(slot, file.unwrap());
2231 }
2232
2233 Response::ok().write_to(&mut socket)?;
2234 }
2235 SocketStream::Tcp(_tcp_socket) => {
2236 // For TCP sockets, we cannot transfer file descriptors
2237 warn!(
2238 "MemoryFd command received over TCP socket, which is not supported"
2239 );
2240 Response::error().write_to(&mut socket)?;
2241 }
2242 }
2243 }
2244 Command::Complete => {
2245 info!("Complete Command Received");
2246 if let Some(ref mut vm) = self.vm.as_mut() {
2247 vm.resume()?;
2248 Response::ok().write_to(&mut socket)?;
2249 } else {
2250 warn!("VM not created yet");
2251 Response::error().write_to(&mut socket)?;
2252 }
2253 break;
2254 }
2255 Command::Abandon => {
2256 info!("Abandon Command Received");
2257 self.vm = None;
2258 self.vm_config = None;
2259 Response::ok().write_to(&mut socket).ok();
2260 break;
2261 }
2262 }
2263 }
2264
2265 Ok(())
2266 }
2267
vm_send_migration( &mut self, send_data_migration: VmSendMigrationData, ) -> result::Result<(), MigratableError>2268 fn vm_send_migration(
2269 &mut self,
2270 send_data_migration: VmSendMigrationData,
2271 ) -> result::Result<(), MigratableError> {
2272 info!(
2273 "Sending migration: destination_url = {}, local = {}",
2274 send_data_migration.destination_url, send_data_migration.local
2275 );
2276
2277 if !self
2278 .vm_config
2279 .as_ref()
2280 .unwrap()
2281 .lock()
2282 .unwrap()
2283 .backed_by_shared_memory()
2284 && send_data_migration.local
2285 {
2286 return Err(MigratableError::MigrateSend(anyhow!(
2287 "Local migration requires shared memory or hugepages enabled"
2288 )));
2289 }
2290
2291 if let Some(vm) = self.vm.as_mut() {
2292 Self::send_migration(
2293 vm,
2294 #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
2295 self.hypervisor.clone(),
2296 send_data_migration.clone(),
2297 )
2298 .map_err(|migration_err| {
2299 error!("Migration failed: {:?}", migration_err);
2300
2301 // Stop logging dirty pages only for non-local migrations
2302 if !send_data_migration.local {
2303 if let Err(e) = vm.stop_dirty_log() {
2304 return e;
2305 }
2306 }
2307
2308 if vm.get_state().unwrap() == VmState::Paused {
2309 if let Err(e) = vm.resume() {
2310 return e;
2311 }
2312 }
2313
2314 migration_err
2315 })?;
2316
2317 // Shutdown the VM after the migration succeeded
2318 self.exit_evt.write(1).map_err(|e| {
2319 MigratableError::MigrateSend(anyhow!(
2320 "Failed shutting down the VM after migration: {:?}",
2321 e
2322 ))
2323 })
2324 } else {
2325 Err(MigratableError::MigrateSend(anyhow!("VM is not running")))
2326 }
2327 }
2328 }
2329
2330 const CPU_MANAGER_SNAPSHOT_ID: &str = "cpu-manager";
2331 const MEMORY_MANAGER_SNAPSHOT_ID: &str = "memory-manager";
2332 const DEVICE_MANAGER_SNAPSHOT_ID: &str = "device-manager";
2333
2334 #[cfg(test)]
2335 mod unit_tests {
2336 use super::*;
2337 #[cfg(target_arch = "x86_64")]
2338 use crate::vm_config::DebugConsoleConfig;
2339 use crate::vm_config::{
2340 ConsoleConfig, ConsoleOutputMode, CpuFeatures, CpusConfig, HotplugMethod, MemoryConfig,
2341 PayloadConfig, RngConfig,
2342 };
2343
create_dummy_vmm() -> Vmm2344 fn create_dummy_vmm() -> Vmm {
2345 Vmm::new(
2346 VmmVersionInfo::new("dummy", "dummy"),
2347 EventFd::new(EFD_NONBLOCK).unwrap(),
2348 #[cfg(feature = "guest_debug")]
2349 EventFd::new(EFD_NONBLOCK).unwrap(),
2350 #[cfg(feature = "guest_debug")]
2351 EventFd::new(EFD_NONBLOCK).unwrap(),
2352 SeccompAction::Allow,
2353 hypervisor::new().unwrap(),
2354 EventFd::new(EFD_NONBLOCK).unwrap(),
2355 )
2356 .unwrap()
2357 }
2358
create_dummy_vm_config() -> Box<VmConfig>2359 fn create_dummy_vm_config() -> Box<VmConfig> {
2360 Box::new(VmConfig {
2361 cpus: CpusConfig {
2362 boot_vcpus: 1,
2363 max_vcpus: 1,
2364 topology: None,
2365 kvm_hyperv: false,
2366 max_phys_bits: 46,
2367 affinity: None,
2368 features: CpuFeatures::default(),
2369 },
2370 memory: MemoryConfig {
2371 size: 536_870_912,
2372 mergeable: false,
2373 hotplug_method: HotplugMethod::Acpi,
2374 hotplug_size: None,
2375 hotplugged_size: None,
2376 shared: true,
2377 hugepages: false,
2378 hugepage_size: None,
2379 prefault: false,
2380 zones: None,
2381 thp: true,
2382 },
2383 payload: Some(PayloadConfig {
2384 kernel: Some(PathBuf::from("/path/to/kernel")),
2385 firmware: None,
2386 cmdline: None,
2387 initramfs: None,
2388 #[cfg(feature = "igvm")]
2389 igvm: None,
2390 #[cfg(feature = "sev_snp")]
2391 host_data: None,
2392 }),
2393 rate_limit_groups: None,
2394 disks: None,
2395 net: None,
2396 rng: RngConfig {
2397 src: PathBuf::from("/dev/urandom"),
2398 iommu: false,
2399 },
2400 balloon: None,
2401 fs: None,
2402 pmem: None,
2403 serial: ConsoleConfig {
2404 file: None,
2405 mode: ConsoleOutputMode::Null,
2406 iommu: false,
2407 socket: None,
2408 },
2409 console: ConsoleConfig {
2410 file: None,
2411 mode: ConsoleOutputMode::Tty,
2412 iommu: false,
2413 socket: None,
2414 },
2415 #[cfg(target_arch = "x86_64")]
2416 debug_console: DebugConsoleConfig::default(),
2417 devices: None,
2418 user_devices: None,
2419 vdpa: None,
2420 vsock: None,
2421 #[cfg(feature = "pvmemcontrol")]
2422 pvmemcontrol: None,
2423 pvpanic: false,
2424 iommu: false,
2425 #[cfg(target_arch = "x86_64")]
2426 sgx_epc: None,
2427 numa: None,
2428 watchdog: false,
2429 #[cfg(feature = "guest_debug")]
2430 gdb: false,
2431 pci_segments: None,
2432 platform: None,
2433 tpm: None,
2434 preserved_fds: None,
2435 landlock_enable: false,
2436 landlock_rules: None,
2437 })
2438 }
2439
2440 #[test]
test_vmm_vm_create()2441 fn test_vmm_vm_create() {
2442 let mut vmm = create_dummy_vmm();
2443 let config = create_dummy_vm_config();
2444
2445 assert!(matches!(vmm.vm_create(config.clone()), Ok(())));
2446 assert!(matches!(
2447 vmm.vm_create(config),
2448 Err(VmError::VmAlreadyCreated)
2449 ));
2450 }
2451
2452 #[test]
test_vmm_vm_cold_add_device()2453 fn test_vmm_vm_cold_add_device() {
2454 let mut vmm = create_dummy_vmm();
2455 let device_config = DeviceConfig::parse("path=/path/to/device").unwrap();
2456
2457 assert!(matches!(
2458 vmm.vm_add_device(device_config.clone()),
2459 Err(VmError::VmNotCreated)
2460 ));
2461
2462 let _ = vmm.vm_create(create_dummy_vm_config());
2463 assert!(vmm
2464 .vm_config
2465 .as_ref()
2466 .unwrap()
2467 .lock()
2468 .unwrap()
2469 .devices
2470 .is_none());
2471
2472 assert!(vmm.vm_add_device(device_config.clone()).unwrap().is_none());
2473 assert_eq!(
2474 vmm.vm_config
2475 .as_ref()
2476 .unwrap()
2477 .lock()
2478 .unwrap()
2479 .devices
2480 .clone()
2481 .unwrap()
2482 .len(),
2483 1
2484 );
2485 assert_eq!(
2486 vmm.vm_config
2487 .as_ref()
2488 .unwrap()
2489 .lock()
2490 .unwrap()
2491 .devices
2492 .clone()
2493 .unwrap()[0],
2494 device_config
2495 );
2496 }
2497
2498 #[test]
test_vmm_vm_cold_add_user_device()2499 fn test_vmm_vm_cold_add_user_device() {
2500 let mut vmm = create_dummy_vmm();
2501 let user_device_config =
2502 UserDeviceConfig::parse("socket=/path/to/socket,id=8,pci_segment=2").unwrap();
2503
2504 assert!(matches!(
2505 vmm.vm_add_user_device(user_device_config.clone()),
2506 Err(VmError::VmNotCreated)
2507 ));
2508
2509 let _ = vmm.vm_create(create_dummy_vm_config());
2510 assert!(vmm
2511 .vm_config
2512 .as_ref()
2513 .unwrap()
2514 .lock()
2515 .unwrap()
2516 .user_devices
2517 .is_none());
2518
2519 assert!(vmm
2520 .vm_add_user_device(user_device_config.clone())
2521 .unwrap()
2522 .is_none());
2523 assert_eq!(
2524 vmm.vm_config
2525 .as_ref()
2526 .unwrap()
2527 .lock()
2528 .unwrap()
2529 .user_devices
2530 .clone()
2531 .unwrap()
2532 .len(),
2533 1
2534 );
2535 assert_eq!(
2536 vmm.vm_config
2537 .as_ref()
2538 .unwrap()
2539 .lock()
2540 .unwrap()
2541 .user_devices
2542 .clone()
2543 .unwrap()[0],
2544 user_device_config
2545 );
2546 }
2547
2548 #[test]
test_vmm_vm_cold_add_disk()2549 fn test_vmm_vm_cold_add_disk() {
2550 let mut vmm = create_dummy_vmm();
2551 let disk_config = DiskConfig::parse("path=/path/to_file").unwrap();
2552
2553 assert!(matches!(
2554 vmm.vm_add_disk(disk_config.clone()),
2555 Err(VmError::VmNotCreated)
2556 ));
2557
2558 let _ = vmm.vm_create(create_dummy_vm_config());
2559 assert!(vmm
2560 .vm_config
2561 .as_ref()
2562 .unwrap()
2563 .lock()
2564 .unwrap()
2565 .disks
2566 .is_none());
2567
2568 assert!(vmm.vm_add_disk(disk_config.clone()).unwrap().is_none());
2569 assert_eq!(
2570 vmm.vm_config
2571 .as_ref()
2572 .unwrap()
2573 .lock()
2574 .unwrap()
2575 .disks
2576 .clone()
2577 .unwrap()
2578 .len(),
2579 1
2580 );
2581 assert_eq!(
2582 vmm.vm_config
2583 .as_ref()
2584 .unwrap()
2585 .lock()
2586 .unwrap()
2587 .disks
2588 .clone()
2589 .unwrap()[0],
2590 disk_config
2591 );
2592 }
2593
2594 #[test]
test_vmm_vm_cold_add_fs()2595 fn test_vmm_vm_cold_add_fs() {
2596 let mut vmm = create_dummy_vmm();
2597 let fs_config = FsConfig::parse("tag=mytag,socket=/tmp/sock").unwrap();
2598
2599 assert!(matches!(
2600 vmm.vm_add_fs(fs_config.clone()),
2601 Err(VmError::VmNotCreated)
2602 ));
2603
2604 let _ = vmm.vm_create(create_dummy_vm_config());
2605 assert!(vmm.vm_config.as_ref().unwrap().lock().unwrap().fs.is_none());
2606
2607 assert!(vmm.vm_add_fs(fs_config.clone()).unwrap().is_none());
2608 assert_eq!(
2609 vmm.vm_config
2610 .as_ref()
2611 .unwrap()
2612 .lock()
2613 .unwrap()
2614 .fs
2615 .clone()
2616 .unwrap()
2617 .len(),
2618 1
2619 );
2620 assert_eq!(
2621 vmm.vm_config
2622 .as_ref()
2623 .unwrap()
2624 .lock()
2625 .unwrap()
2626 .fs
2627 .clone()
2628 .unwrap()[0],
2629 fs_config
2630 );
2631 }
2632
2633 #[test]
test_vmm_vm_cold_add_pmem()2634 fn test_vmm_vm_cold_add_pmem() {
2635 let mut vmm = create_dummy_vmm();
2636 let pmem_config = PmemConfig::parse("file=/tmp/pmem,size=128M").unwrap();
2637
2638 assert!(matches!(
2639 vmm.vm_add_pmem(pmem_config.clone()),
2640 Err(VmError::VmNotCreated)
2641 ));
2642
2643 let _ = vmm.vm_create(create_dummy_vm_config());
2644 assert!(vmm
2645 .vm_config
2646 .as_ref()
2647 .unwrap()
2648 .lock()
2649 .unwrap()
2650 .pmem
2651 .is_none());
2652
2653 assert!(vmm.vm_add_pmem(pmem_config.clone()).unwrap().is_none());
2654 assert_eq!(
2655 vmm.vm_config
2656 .as_ref()
2657 .unwrap()
2658 .lock()
2659 .unwrap()
2660 .pmem
2661 .clone()
2662 .unwrap()
2663 .len(),
2664 1
2665 );
2666 assert_eq!(
2667 vmm.vm_config
2668 .as_ref()
2669 .unwrap()
2670 .lock()
2671 .unwrap()
2672 .pmem
2673 .clone()
2674 .unwrap()[0],
2675 pmem_config
2676 );
2677 }
2678
2679 #[test]
test_vmm_vm_cold_add_net()2680 fn test_vmm_vm_cold_add_net() {
2681 let mut vmm = create_dummy_vmm();
2682 let net_config = NetConfig::parse(
2683 "mac=de:ad:be:ef:12:34,host_mac=12:34:de:ad:be:ef,vhost_user=true,socket=/tmp/sock",
2684 )
2685 .unwrap();
2686
2687 assert!(matches!(
2688 vmm.vm_add_net(net_config.clone()),
2689 Err(VmError::VmNotCreated)
2690 ));
2691
2692 let _ = vmm.vm_create(create_dummy_vm_config());
2693 assert!(vmm
2694 .vm_config
2695 .as_ref()
2696 .unwrap()
2697 .lock()
2698 .unwrap()
2699 .net
2700 .is_none());
2701
2702 assert!(vmm.vm_add_net(net_config.clone()).unwrap().is_none());
2703 assert_eq!(
2704 vmm.vm_config
2705 .as_ref()
2706 .unwrap()
2707 .lock()
2708 .unwrap()
2709 .net
2710 .clone()
2711 .unwrap()
2712 .len(),
2713 1
2714 );
2715 assert_eq!(
2716 vmm.vm_config
2717 .as_ref()
2718 .unwrap()
2719 .lock()
2720 .unwrap()
2721 .net
2722 .clone()
2723 .unwrap()[0],
2724 net_config
2725 );
2726 }
2727
2728 #[test]
test_vmm_vm_cold_add_vdpa()2729 fn test_vmm_vm_cold_add_vdpa() {
2730 let mut vmm = create_dummy_vmm();
2731 let vdpa_config = VdpaConfig::parse("path=/dev/vhost-vdpa,num_queues=2").unwrap();
2732
2733 assert!(matches!(
2734 vmm.vm_add_vdpa(vdpa_config.clone()),
2735 Err(VmError::VmNotCreated)
2736 ));
2737
2738 let _ = vmm.vm_create(create_dummy_vm_config());
2739 assert!(vmm
2740 .vm_config
2741 .as_ref()
2742 .unwrap()
2743 .lock()
2744 .unwrap()
2745 .vdpa
2746 .is_none());
2747
2748 assert!(vmm.vm_add_vdpa(vdpa_config.clone()).unwrap().is_none());
2749 assert_eq!(
2750 vmm.vm_config
2751 .as_ref()
2752 .unwrap()
2753 .lock()
2754 .unwrap()
2755 .vdpa
2756 .clone()
2757 .unwrap()
2758 .len(),
2759 1
2760 );
2761 assert_eq!(
2762 vmm.vm_config
2763 .as_ref()
2764 .unwrap()
2765 .lock()
2766 .unwrap()
2767 .vdpa
2768 .clone()
2769 .unwrap()[0],
2770 vdpa_config
2771 );
2772 }
2773
2774 #[test]
test_vmm_vm_cold_add_vsock()2775 fn test_vmm_vm_cold_add_vsock() {
2776 let mut vmm = create_dummy_vmm();
2777 let vsock_config = VsockConfig::parse("socket=/tmp/sock,cid=3,iommu=on").unwrap();
2778
2779 assert!(matches!(
2780 vmm.vm_add_vsock(vsock_config.clone()),
2781 Err(VmError::VmNotCreated)
2782 ));
2783
2784 let _ = vmm.vm_create(create_dummy_vm_config());
2785 assert!(vmm
2786 .vm_config
2787 .as_ref()
2788 .unwrap()
2789 .lock()
2790 .unwrap()
2791 .vsock
2792 .is_none());
2793
2794 assert!(vmm.vm_add_vsock(vsock_config.clone()).unwrap().is_none());
2795 assert_eq!(
2796 vmm.vm_config
2797 .as_ref()
2798 .unwrap()
2799 .lock()
2800 .unwrap()
2801 .vsock
2802 .clone()
2803 .unwrap(),
2804 vsock_config
2805 );
2806 }
2807 }
2808