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