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 let r = { 1220 trace_scoped!("vm_boot"); 1221 // If we don't have a config, we can not boot a VM. 1222 if self.vm_config.is_none() { 1223 return Err(VmError::VmMissingConfig); 1224 }; 1225 1226 // Create a new VM if we don't have one yet. 1227 if self.vm.is_none() { 1228 let exit_evt = self.exit_evt.try_clone().map_err(VmError::EventFdClone)?; 1229 let reset_evt = self.reset_evt.try_clone().map_err(VmError::EventFdClone)?; 1230 #[cfg(feature = "guest_debug")] 1231 let vm_debug_evt = self 1232 .vm_debug_evt 1233 .try_clone() 1234 .map_err(VmError::EventFdClone)?; 1235 let activate_evt = self 1236 .activate_evt 1237 .try_clone() 1238 .map_err(VmError::EventFdClone)?; 1239 1240 if let Some(ref vm_config) = self.vm_config { 1241 let vm = Vm::new( 1242 Arc::clone(vm_config), 1243 exit_evt, 1244 reset_evt, 1245 #[cfg(feature = "guest_debug")] 1246 vm_debug_evt, 1247 &self.seccomp_action, 1248 self.hypervisor.clone(), 1249 activate_evt, 1250 None, 1251 None, 1252 None, 1253 None, 1254 Arc::clone(&self.original_termios_opt), 1255 None, 1256 None, 1257 None, 1258 )?; 1259 1260 self.vm = Some(vm); 1261 } 1262 } 1263 1264 // Now we can boot the VM. 1265 if let Some(ref mut vm) = self.vm { 1266 vm.boot() 1267 } else { 1268 Err(VmError::VmNotCreated) 1269 } 1270 }; 1271 tracer::end(); 1272 r 1273 } 1274 1275 fn vm_pause(&mut self) -> result::Result<(), VmError> { 1276 if let Some(ref mut vm) = self.vm { 1277 vm.pause().map_err(VmError::Pause) 1278 } else { 1279 Err(VmError::VmNotRunning) 1280 } 1281 } 1282 1283 fn vm_resume(&mut self) -> result::Result<(), VmError> { 1284 if let Some(ref mut vm) = self.vm { 1285 vm.resume().map_err(VmError::Resume) 1286 } else { 1287 Err(VmError::VmNotRunning) 1288 } 1289 } 1290 1291 fn vm_snapshot(&mut self, destination_url: &str) -> result::Result<(), VmError> { 1292 if let Some(ref mut vm) = self.vm { 1293 vm.snapshot() 1294 .map_err(VmError::Snapshot) 1295 .and_then(|snapshot| { 1296 vm.send(&snapshot, destination_url) 1297 .map_err(VmError::SnapshotSend) 1298 }) 1299 } else { 1300 Err(VmError::VmNotRunning) 1301 } 1302 } 1303 1304 fn vm_restore(&mut self, restore_cfg: RestoreConfig) -> result::Result<(), VmError> { 1305 if self.vm.is_some() || self.vm_config.is_some() { 1306 return Err(VmError::VmAlreadyCreated); 1307 } 1308 1309 let source_url = restore_cfg.source_url.as_path().to_str(); 1310 if source_url.is_none() { 1311 return Err(VmError::InvalidRestoreSourceUrl); 1312 } 1313 // Safe to unwrap as we checked it was Some(&str). 1314 let source_url = source_url.unwrap(); 1315 1316 let vm_config = Arc::new(Mutex::new( 1317 recv_vm_config(source_url).map_err(VmError::Restore)?, 1318 )); 1319 let snapshot = recv_vm_state(source_url).map_err(VmError::Restore)?; 1320 #[cfg(all(feature = "kvm", target_arch = "x86_64"))] 1321 let vm_snapshot = get_vm_snapshot(&snapshot).map_err(VmError::Restore)?; 1322 1323 #[cfg(all(feature = "kvm", target_arch = "x86_64"))] 1324 self.vm_check_cpuid_compatibility(&vm_config, &vm_snapshot.common_cpuid) 1325 .map_err(VmError::Restore)?; 1326 1327 self.vm_config = Some(Arc::clone(&vm_config)); 1328 1329 let exit_evt = self.exit_evt.try_clone().map_err(VmError::EventFdClone)?; 1330 let reset_evt = self.reset_evt.try_clone().map_err(VmError::EventFdClone)?; 1331 #[cfg(feature = "guest_debug")] 1332 let debug_evt = self 1333 .vm_debug_evt 1334 .try_clone() 1335 .map_err(VmError::EventFdClone)?; 1336 let activate_evt = self 1337 .activate_evt 1338 .try_clone() 1339 .map_err(VmError::EventFdClone)?; 1340 1341 let vm = Vm::new( 1342 vm_config, 1343 exit_evt, 1344 reset_evt, 1345 #[cfg(feature = "guest_debug")] 1346 debug_evt, 1347 &self.seccomp_action, 1348 self.hypervisor.clone(), 1349 activate_evt, 1350 None, 1351 None, 1352 None, 1353 None, 1354 Arc::clone(&self.original_termios_opt), 1355 Some(snapshot), 1356 Some(source_url), 1357 Some(restore_cfg.prefault), 1358 )?; 1359 self.vm = Some(vm); 1360 1361 // Now we can restore the rest of the VM. 1362 if let Some(ref mut vm) = self.vm { 1363 vm.restore() 1364 } else { 1365 Err(VmError::VmNotCreated) 1366 } 1367 } 1368 1369 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] 1370 fn vm_coredump(&mut self, destination_url: &str) -> result::Result<(), VmError> { 1371 if let Some(ref mut vm) = self.vm { 1372 vm.coredump(destination_url).map_err(VmError::Coredump) 1373 } else { 1374 Err(VmError::VmNotRunning) 1375 } 1376 } 1377 1378 fn vm_shutdown(&mut self) -> result::Result<(), VmError> { 1379 if let Some(ref mut vm) = self.vm.take() { 1380 vm.shutdown() 1381 } else { 1382 Err(VmError::VmNotRunning) 1383 } 1384 } 1385 1386 fn vm_reboot(&mut self) -> result::Result<(), VmError> { 1387 // First we stop the current VM 1388 let (config, serial_pty, console_pty, debug_console_pty, console_resize_pipe) = 1389 if let Some(mut vm) = self.vm.take() { 1390 let config = vm.get_config(); 1391 let serial_pty = vm.serial_pty(); 1392 let console_pty = vm.console_pty(); 1393 let debug_console_pty = vm.debug_console_pty(); 1394 let console_resize_pipe = vm 1395 .console_resize_pipe() 1396 .as_ref() 1397 .map(|pipe| pipe.try_clone().unwrap()); 1398 vm.shutdown()?; 1399 ( 1400 config, 1401 serial_pty, 1402 console_pty, 1403 debug_console_pty, 1404 console_resize_pipe, 1405 ) 1406 } else { 1407 return Err(VmError::VmNotCreated); 1408 }; 1409 1410 let exit_evt = self.exit_evt.try_clone().map_err(VmError::EventFdClone)?; 1411 let reset_evt = self.reset_evt.try_clone().map_err(VmError::EventFdClone)?; 1412 #[cfg(feature = "guest_debug")] 1413 let debug_evt = self 1414 .vm_debug_evt 1415 .try_clone() 1416 .map_err(VmError::EventFdClone)?; 1417 let activate_evt = self 1418 .activate_evt 1419 .try_clone() 1420 .map_err(VmError::EventFdClone)?; 1421 1422 // The Linux kernel fires off an i8042 reset after doing the ACPI reset so there may be 1423 // an event sitting in the shared reset_evt. Without doing this we get very early reboots 1424 // during the boot process. 1425 if self.reset_evt.read().is_ok() { 1426 warn!("Spurious second reset event received. Ignoring."); 1427 } 1428 1429 // Then we create the new VM 1430 let mut vm = Vm::new( 1431 config, 1432 exit_evt, 1433 reset_evt, 1434 #[cfg(feature = "guest_debug")] 1435 debug_evt, 1436 &self.seccomp_action, 1437 self.hypervisor.clone(), 1438 activate_evt, 1439 serial_pty, 1440 console_pty, 1441 debug_console_pty, 1442 console_resize_pipe, 1443 Arc::clone(&self.original_termios_opt), 1444 None, 1445 None, 1446 None, 1447 )?; 1448 1449 // And we boot it 1450 vm.boot()?; 1451 1452 self.vm = Some(vm); 1453 1454 Ok(()) 1455 } 1456 1457 fn vm_info(&self) -> result::Result<VmInfoResponse, VmError> { 1458 match &self.vm_config { 1459 Some(config) => { 1460 let state = match &self.vm { 1461 Some(vm) => vm.get_state()?, 1462 None => VmState::Created, 1463 }; 1464 1465 let config = Arc::clone(config); 1466 1467 let mut memory_actual_size = config.lock().unwrap().memory.total_size(); 1468 if let Some(vm) = &self.vm { 1469 memory_actual_size -= vm.balloon_size(); 1470 } 1471 1472 let device_tree = self.vm.as_ref().map(|vm| vm.device_tree()); 1473 1474 Ok(VmInfoResponse { 1475 config, 1476 state, 1477 memory_actual_size, 1478 device_tree, 1479 }) 1480 } 1481 None => Err(VmError::VmNotCreated), 1482 } 1483 } 1484 1485 fn vmm_ping(&self) -> VmmPingResponse { 1486 let VmmVersionInfo { 1487 build_version, 1488 version, 1489 } = self.version.clone(); 1490 1491 VmmPingResponse { 1492 build_version, 1493 version, 1494 pid: std::process::id() as i64, 1495 features: feature_list(), 1496 } 1497 } 1498 1499 fn vm_delete(&mut self) -> result::Result<(), VmError> { 1500 if self.vm_config.is_none() { 1501 return Ok(()); 1502 } 1503 1504 // If a VM is booted, we first try to shut it down. 1505 if self.vm.is_some() { 1506 self.vm_shutdown()?; 1507 } 1508 1509 self.vm_config = None; 1510 1511 event!("vm", "deleted"); 1512 1513 Ok(()) 1514 } 1515 1516 fn vmm_shutdown(&mut self) -> result::Result<(), VmError> { 1517 self.vm_delete()?; 1518 event!("vmm", "shutdown"); 1519 Ok(()) 1520 } 1521 1522 fn vm_resize( 1523 &mut self, 1524 desired_vcpus: Option<u8>, 1525 desired_ram: Option<u64>, 1526 desired_balloon: Option<u64>, 1527 ) -> result::Result<(), VmError> { 1528 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?; 1529 1530 if let Some(ref mut vm) = self.vm { 1531 if let Err(e) = vm.resize(desired_vcpus, desired_ram, desired_balloon) { 1532 error!("Error when resizing VM: {:?}", e); 1533 Err(e) 1534 } else { 1535 Ok(()) 1536 } 1537 } else { 1538 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap(); 1539 if let Some(desired_vcpus) = desired_vcpus { 1540 config.cpus.boot_vcpus = desired_vcpus; 1541 } 1542 if let Some(desired_ram) = desired_ram { 1543 config.memory.size = desired_ram; 1544 } 1545 if let Some(desired_balloon) = desired_balloon { 1546 if let Some(balloon_config) = &mut config.balloon { 1547 balloon_config.size = desired_balloon; 1548 } 1549 } 1550 Ok(()) 1551 } 1552 } 1553 1554 fn vm_resize_zone(&mut self, id: String, desired_ram: u64) -> result::Result<(), VmError> { 1555 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?; 1556 1557 if let Some(ref mut vm) = self.vm { 1558 if let Err(e) = vm.resize_zone(id, desired_ram) { 1559 error!("Error when resizing VM: {:?}", e); 1560 Err(e) 1561 } else { 1562 Ok(()) 1563 } 1564 } else { 1565 // Update VmConfig by setting the new desired ram. 1566 let memory_config = &mut self.vm_config.as_ref().unwrap().lock().unwrap().memory; 1567 1568 if let Some(zones) = &mut memory_config.zones { 1569 for zone in zones.iter_mut() { 1570 if zone.id == id { 1571 zone.size = desired_ram; 1572 return Ok(()); 1573 } 1574 } 1575 } 1576 1577 error!("Could not find the memory zone {} for the resize", id); 1578 Err(VmError::ResizeZone) 1579 } 1580 } 1581 1582 fn vm_add_device( 1583 &mut self, 1584 device_cfg: DeviceConfig, 1585 ) -> result::Result<Option<Vec<u8>>, VmError> { 1586 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?; 1587 1588 { 1589 // Validate the configuration change in a cloned configuration 1590 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone(); 1591 add_to_config(&mut config.devices, device_cfg.clone()); 1592 config.validate().map_err(VmError::ConfigValidation)?; 1593 } 1594 1595 if let Some(ref mut vm) = self.vm { 1596 let info = vm.add_device(device_cfg).map_err(|e| { 1597 error!("Error when adding new device to the VM: {:?}", e); 1598 e 1599 })?; 1600 serde_json::to_vec(&info) 1601 .map(Some) 1602 .map_err(VmError::SerializeJson) 1603 } else { 1604 // Update VmConfig by adding the new device. 1605 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap(); 1606 add_to_config(&mut config.devices, device_cfg); 1607 Ok(None) 1608 } 1609 } 1610 1611 fn vm_add_user_device( 1612 &mut self, 1613 device_cfg: UserDeviceConfig, 1614 ) -> result::Result<Option<Vec<u8>>, VmError> { 1615 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?; 1616 1617 { 1618 // Validate the configuration change in a cloned configuration 1619 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone(); 1620 add_to_config(&mut config.user_devices, device_cfg.clone()); 1621 config.validate().map_err(VmError::ConfigValidation)?; 1622 } 1623 1624 if let Some(ref mut vm) = self.vm { 1625 let info = vm.add_user_device(device_cfg).map_err(|e| { 1626 error!("Error when adding new user device to the VM: {:?}", e); 1627 e 1628 })?; 1629 serde_json::to_vec(&info) 1630 .map(Some) 1631 .map_err(VmError::SerializeJson) 1632 } else { 1633 // Update VmConfig by adding the new device. 1634 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap(); 1635 add_to_config(&mut config.user_devices, device_cfg); 1636 Ok(None) 1637 } 1638 } 1639 1640 fn vm_remove_device(&mut self, id: String) -> result::Result<(), VmError> { 1641 if let Some(ref mut vm) = self.vm { 1642 if let Err(e) = vm.remove_device(id) { 1643 error!("Error when removing device from the VM: {:?}", e); 1644 Err(e) 1645 } else { 1646 Ok(()) 1647 } 1648 } else if let Some(ref config) = self.vm_config { 1649 let mut config = config.lock().unwrap(); 1650 if config.remove_device(&id) { 1651 Ok(()) 1652 } else { 1653 Err(VmError::NoDeviceToRemove(id)) 1654 } 1655 } else { 1656 Err(VmError::VmNotCreated) 1657 } 1658 } 1659 1660 fn vm_add_disk(&mut self, disk_cfg: DiskConfig) -> result::Result<Option<Vec<u8>>, VmError> { 1661 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?; 1662 1663 { 1664 // Validate the configuration change in a cloned configuration 1665 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone(); 1666 add_to_config(&mut config.disks, disk_cfg.clone()); 1667 config.validate().map_err(VmError::ConfigValidation)?; 1668 } 1669 1670 if let Some(ref mut vm) = self.vm { 1671 let info = vm.add_disk(disk_cfg).map_err(|e| { 1672 error!("Error when adding new disk to the VM: {:?}", e); 1673 e 1674 })?; 1675 serde_json::to_vec(&info) 1676 .map(Some) 1677 .map_err(VmError::SerializeJson) 1678 } else { 1679 // Update VmConfig by adding the new device. 1680 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap(); 1681 add_to_config(&mut config.disks, disk_cfg); 1682 Ok(None) 1683 } 1684 } 1685 1686 fn vm_add_fs(&mut self, fs_cfg: FsConfig) -> result::Result<Option<Vec<u8>>, VmError> { 1687 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?; 1688 1689 { 1690 // Validate the configuration change in a cloned configuration 1691 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone(); 1692 add_to_config(&mut config.fs, fs_cfg.clone()); 1693 config.validate().map_err(VmError::ConfigValidation)?; 1694 } 1695 1696 if let Some(ref mut vm) = self.vm { 1697 let info = vm.add_fs(fs_cfg).map_err(|e| { 1698 error!("Error when adding new fs to the VM: {:?}", e); 1699 e 1700 })?; 1701 serde_json::to_vec(&info) 1702 .map(Some) 1703 .map_err(VmError::SerializeJson) 1704 } else { 1705 // Update VmConfig by adding the new device. 1706 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap(); 1707 add_to_config(&mut config.fs, fs_cfg); 1708 Ok(None) 1709 } 1710 } 1711 1712 fn vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> result::Result<Option<Vec<u8>>, VmError> { 1713 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?; 1714 1715 { 1716 // Validate the configuration change in a cloned configuration 1717 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone(); 1718 add_to_config(&mut config.pmem, pmem_cfg.clone()); 1719 config.validate().map_err(VmError::ConfigValidation)?; 1720 } 1721 1722 if let Some(ref mut vm) = self.vm { 1723 let info = vm.add_pmem(pmem_cfg).map_err(|e| { 1724 error!("Error when adding new pmem device to the VM: {:?}", e); 1725 e 1726 })?; 1727 serde_json::to_vec(&info) 1728 .map(Some) 1729 .map_err(VmError::SerializeJson) 1730 } else { 1731 // Update VmConfig by adding the new device. 1732 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap(); 1733 add_to_config(&mut config.pmem, pmem_cfg); 1734 Ok(None) 1735 } 1736 } 1737 1738 fn vm_add_net(&mut self, net_cfg: NetConfig) -> result::Result<Option<Vec<u8>>, VmError> { 1739 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?; 1740 1741 { 1742 // Validate the configuration change in a cloned configuration 1743 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone(); 1744 add_to_config(&mut config.net, net_cfg.clone()); 1745 config.validate().map_err(VmError::ConfigValidation)?; 1746 } 1747 1748 if let Some(ref mut vm) = self.vm { 1749 let info = vm.add_net(net_cfg).map_err(|e| { 1750 error!("Error when adding new network device to the VM: {:?}", e); 1751 e 1752 })?; 1753 serde_json::to_vec(&info) 1754 .map(Some) 1755 .map_err(VmError::SerializeJson) 1756 } else { 1757 // Update VmConfig by adding the new device. 1758 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap(); 1759 add_to_config(&mut config.net, net_cfg); 1760 Ok(None) 1761 } 1762 } 1763 1764 fn vm_add_vdpa(&mut self, vdpa_cfg: VdpaConfig) -> result::Result<Option<Vec<u8>>, VmError> { 1765 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?; 1766 1767 { 1768 // Validate the configuration change in a cloned configuration 1769 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone(); 1770 add_to_config(&mut config.vdpa, vdpa_cfg.clone()); 1771 config.validate().map_err(VmError::ConfigValidation)?; 1772 } 1773 1774 if let Some(ref mut vm) = self.vm { 1775 let info = vm.add_vdpa(vdpa_cfg).map_err(|e| { 1776 error!("Error when adding new vDPA device to the VM: {:?}", e); 1777 e 1778 })?; 1779 serde_json::to_vec(&info) 1780 .map(Some) 1781 .map_err(VmError::SerializeJson) 1782 } else { 1783 // Update VmConfig by adding the new device. 1784 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap(); 1785 add_to_config(&mut config.vdpa, vdpa_cfg); 1786 Ok(None) 1787 } 1788 } 1789 1790 fn vm_add_vsock(&mut self, vsock_cfg: VsockConfig) -> result::Result<Option<Vec<u8>>, VmError> { 1791 self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?; 1792 1793 { 1794 // Validate the configuration change in a cloned configuration 1795 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone(); 1796 1797 if config.vsock.is_some() { 1798 return Err(VmError::TooManyVsockDevices); 1799 } 1800 1801 config.vsock = Some(vsock_cfg.clone()); 1802 config.validate().map_err(VmError::ConfigValidation)?; 1803 } 1804 1805 if let Some(ref mut vm) = self.vm { 1806 let info = vm.add_vsock(vsock_cfg).map_err(|e| { 1807 error!("Error when adding new vsock device to the VM: {:?}", e); 1808 e 1809 })?; 1810 serde_json::to_vec(&info) 1811 .map(Some) 1812 .map_err(VmError::SerializeJson) 1813 } else { 1814 // Update VmConfig by adding the new device. 1815 let mut config = self.vm_config.as_ref().unwrap().lock().unwrap(); 1816 config.vsock = Some(vsock_cfg); 1817 Ok(None) 1818 } 1819 } 1820 1821 fn vm_counters(&mut self) -> result::Result<Option<Vec<u8>>, VmError> { 1822 if let Some(ref mut vm) = self.vm { 1823 let info = vm.counters().map_err(|e| { 1824 error!("Error when getting counters from the VM: {:?}", e); 1825 e 1826 })?; 1827 serde_json::to_vec(&info) 1828 .map(Some) 1829 .map_err(VmError::SerializeJson) 1830 } else { 1831 Err(VmError::VmNotRunning) 1832 } 1833 } 1834 1835 fn vm_power_button(&mut self) -> result::Result<(), VmError> { 1836 if let Some(ref mut vm) = self.vm { 1837 vm.power_button() 1838 } else { 1839 Err(VmError::VmNotRunning) 1840 } 1841 } 1842 1843 fn vm_receive_migration( 1844 &mut self, 1845 receive_data_migration: VmReceiveMigrationData, 1846 ) -> result::Result<(), MigratableError> { 1847 info!( 1848 "Receiving migration: receiver_url = {}", 1849 receive_data_migration.receiver_url 1850 ); 1851 1852 let path = Self::socket_url_to_path(&receive_data_migration.receiver_url)?; 1853 let listener = UnixListener::bind(&path).map_err(|e| { 1854 MigratableError::MigrateReceive(anyhow!("Error binding to UNIX socket: {}", e)) 1855 })?; 1856 let (mut socket, _addr) = listener.accept().map_err(|e| { 1857 MigratableError::MigrateReceive(anyhow!("Error accepting on UNIX socket: {}", e)) 1858 })?; 1859 std::fs::remove_file(&path).map_err(|e| { 1860 MigratableError::MigrateReceive(anyhow!("Error unlinking UNIX socket: {}", e)) 1861 })?; 1862 1863 let mut started = false; 1864 let mut memory_manager: Option<Arc<Mutex<MemoryManager>>> = None; 1865 let mut existing_memory_files = None; 1866 loop { 1867 let req = Request::read_from(&mut socket)?; 1868 match req.command() { 1869 Command::Invalid => info!("Invalid Command Received"), 1870 Command::Start => { 1871 info!("Start Command Received"); 1872 started = true; 1873 1874 Response::ok().write_to(&mut socket)?; 1875 } 1876 Command::Config => { 1877 info!("Config Command Received"); 1878 1879 if !started { 1880 warn!("Migration not started yet"); 1881 Response::error().write_to(&mut socket)?; 1882 continue; 1883 } 1884 memory_manager = Some(self.vm_receive_config( 1885 &req, 1886 &mut socket, 1887 existing_memory_files.take(), 1888 )?); 1889 } 1890 Command::State => { 1891 info!("State Command Received"); 1892 1893 if !started { 1894 warn!("Migration not started yet"); 1895 Response::error().write_to(&mut socket)?; 1896 continue; 1897 } 1898 if let Some(mm) = memory_manager.take() { 1899 self.vm_receive_state(&req, &mut socket, mm)?; 1900 } else { 1901 warn!("Configuration not sent yet"); 1902 Response::error().write_to(&mut socket)?; 1903 } 1904 } 1905 Command::Memory => { 1906 info!("Memory Command Received"); 1907 1908 if !started { 1909 warn!("Migration not started yet"); 1910 Response::error().write_to(&mut socket)?; 1911 continue; 1912 } 1913 if let Some(mm) = memory_manager.as_ref() { 1914 self.vm_receive_memory(&req, &mut socket, &mut mm.lock().unwrap())?; 1915 } else { 1916 warn!("Configuration not sent yet"); 1917 Response::error().write_to(&mut socket)?; 1918 } 1919 } 1920 Command::MemoryFd => { 1921 info!("MemoryFd Command Received"); 1922 1923 if !started { 1924 warn!("Migration not started yet"); 1925 Response::error().write_to(&mut socket)?; 1926 continue; 1927 } 1928 1929 let mut buf = [0u8; 4]; 1930 let (_, file) = socket.recv_with_fd(&mut buf).map_err(|e| { 1931 MigratableError::MigrateReceive(anyhow!( 1932 "Error receiving slot from socket: {}", 1933 e 1934 )) 1935 })?; 1936 1937 if existing_memory_files.is_none() { 1938 existing_memory_files = Some(HashMap::default()) 1939 } 1940 1941 if let Some(ref mut existing_memory_files) = existing_memory_files { 1942 let slot = u32::from_le_bytes(buf); 1943 existing_memory_files.insert(slot, file.unwrap()); 1944 } 1945 1946 Response::ok().write_to(&mut socket)?; 1947 } 1948 Command::Complete => { 1949 info!("Complete Command Received"); 1950 if let Some(ref mut vm) = self.vm.as_mut() { 1951 vm.resume()?; 1952 Response::ok().write_to(&mut socket)?; 1953 } else { 1954 warn!("VM not created yet"); 1955 Response::error().write_to(&mut socket)?; 1956 } 1957 break; 1958 } 1959 Command::Abandon => { 1960 info!("Abandon Command Received"); 1961 self.vm = None; 1962 self.vm_config = None; 1963 Response::ok().write_to(&mut socket).ok(); 1964 break; 1965 } 1966 } 1967 } 1968 1969 Ok(()) 1970 } 1971 1972 fn vm_send_migration( 1973 &mut self, 1974 send_data_migration: VmSendMigrationData, 1975 ) -> result::Result<(), MigratableError> { 1976 info!( 1977 "Sending migration: destination_url = {}, local = {}", 1978 send_data_migration.destination_url, send_data_migration.local 1979 ); 1980 1981 if !self 1982 .vm_config 1983 .as_ref() 1984 .unwrap() 1985 .lock() 1986 .unwrap() 1987 .backed_by_shared_memory() 1988 && send_data_migration.local 1989 { 1990 return Err(MigratableError::MigrateSend(anyhow!( 1991 "Local migration requires shared memory or hugepages enabled" 1992 ))); 1993 } 1994 1995 if let Some(vm) = self.vm.as_mut() { 1996 Self::send_migration( 1997 vm, 1998 #[cfg(all(feature = "kvm", target_arch = "x86_64"))] 1999 self.hypervisor.clone(), 2000 send_data_migration, 2001 ) 2002 .map_err(|migration_err| { 2003 error!("Migration failed: {:?}", migration_err); 2004 2005 // Stop logging dirty pages 2006 if let Err(e) = vm.stop_dirty_log() { 2007 return e; 2008 } 2009 2010 if vm.get_state().unwrap() == VmState::Paused { 2011 if let Err(e) = vm.resume() { 2012 return e; 2013 } 2014 } 2015 2016 migration_err 2017 })?; 2018 2019 // Shutdown the VM after the migration succeeded 2020 self.exit_evt.write(1).map_err(|e| { 2021 MigratableError::MigrateSend(anyhow!( 2022 "Failed shutting down the VM after migration: {:?}", 2023 e 2024 )) 2025 }) 2026 } else { 2027 Err(MigratableError::MigrateSend(anyhow!("VM is not running"))) 2028 } 2029 } 2030 } 2031 2032 const CPU_MANAGER_SNAPSHOT_ID: &str = "cpu-manager"; 2033 const MEMORY_MANAGER_SNAPSHOT_ID: &str = "memory-manager"; 2034 const DEVICE_MANAGER_SNAPSHOT_ID: &str = "device-manager"; 2035 2036 #[cfg(test)] 2037 mod unit_tests { 2038 use super::*; 2039 #[cfg(target_arch = "x86_64")] 2040 use crate::config::DebugConsoleConfig; 2041 use config::{ 2042 ConsoleConfig, ConsoleOutputMode, CpusConfig, HotplugMethod, MemoryConfig, PayloadConfig, 2043 RngConfig, 2044 }; 2045 2046 fn create_dummy_vmm() -> Vmm { 2047 Vmm::new( 2048 VmmVersionInfo::new("dummy", "dummy"), 2049 EventFd::new(EFD_NONBLOCK).unwrap(), 2050 #[cfg(feature = "guest_debug")] 2051 EventFd::new(EFD_NONBLOCK).unwrap(), 2052 #[cfg(feature = "guest_debug")] 2053 EventFd::new(EFD_NONBLOCK).unwrap(), 2054 SeccompAction::Allow, 2055 hypervisor::new().unwrap(), 2056 EventFd::new(EFD_NONBLOCK).unwrap(), 2057 ) 2058 .unwrap() 2059 } 2060 2061 fn create_dummy_vm_config() -> Arc<Mutex<VmConfig>> { 2062 Arc::new(Mutex::new(VmConfig { 2063 cpus: CpusConfig { 2064 boot_vcpus: 1, 2065 max_vcpus: 1, 2066 topology: None, 2067 kvm_hyperv: false, 2068 max_phys_bits: 46, 2069 affinity: None, 2070 features: config::CpuFeatures::default(), 2071 }, 2072 memory: MemoryConfig { 2073 size: 536_870_912, 2074 mergeable: false, 2075 hotplug_method: HotplugMethod::Acpi, 2076 hotplug_size: None, 2077 hotplugged_size: None, 2078 shared: true, 2079 hugepages: false, 2080 hugepage_size: None, 2081 prefault: false, 2082 zones: None, 2083 thp: true, 2084 }, 2085 payload: Some(PayloadConfig { 2086 kernel: Some(PathBuf::from("/path/to/kernel")), 2087 firmware: None, 2088 cmdline: None, 2089 initramfs: None, 2090 #[cfg(feature = "igvm")] 2091 igvm: None, 2092 #[cfg(feature = "sev_snp")] 2093 host_data: None, 2094 }), 2095 rate_limit_groups: None, 2096 disks: None, 2097 net: None, 2098 rng: RngConfig { 2099 src: PathBuf::from("/dev/urandom"), 2100 iommu: false, 2101 }, 2102 balloon: None, 2103 fs: None, 2104 pmem: None, 2105 serial: ConsoleConfig { 2106 file: None, 2107 mode: ConsoleOutputMode::Null, 2108 iommu: false, 2109 socket: None, 2110 }, 2111 console: ConsoleConfig { 2112 file: None, 2113 mode: ConsoleOutputMode::Tty, 2114 iommu: false, 2115 socket: None, 2116 }, 2117 #[cfg(target_arch = "x86_64")] 2118 debug_console: DebugConsoleConfig::default(), 2119 devices: None, 2120 user_devices: None, 2121 vdpa: None, 2122 vsock: None, 2123 pvpanic: false, 2124 iommu: false, 2125 #[cfg(target_arch = "x86_64")] 2126 sgx_epc: None, 2127 numa: None, 2128 watchdog: false, 2129 #[cfg(feature = "guest_debug")] 2130 gdb: false, 2131 platform: None, 2132 tpm: None, 2133 preserved_fds: None, 2134 })) 2135 } 2136 2137 #[test] 2138 fn test_vmm_vm_create() { 2139 let mut vmm = create_dummy_vmm(); 2140 let config = create_dummy_vm_config(); 2141 2142 assert!(matches!(vmm.vm_create(config.clone()), Ok(()))); 2143 assert!(matches!( 2144 vmm.vm_create(config), 2145 Err(VmError::VmAlreadyCreated) 2146 )); 2147 } 2148 2149 #[test] 2150 fn test_vmm_vm_cold_add_device() { 2151 let mut vmm = create_dummy_vmm(); 2152 let device_config = DeviceConfig::parse("path=/path/to/device").unwrap(); 2153 2154 assert!(matches!( 2155 vmm.vm_add_device(device_config.clone()), 2156 Err(VmError::VmNotCreated) 2157 )); 2158 2159 let _ = vmm.vm_create(create_dummy_vm_config()); 2160 assert!(vmm 2161 .vm_config 2162 .as_ref() 2163 .unwrap() 2164 .lock() 2165 .unwrap() 2166 .devices 2167 .is_none()); 2168 2169 let result = vmm.vm_add_device(device_config.clone()); 2170 assert!(result.is_ok()); 2171 assert!(result.unwrap().is_none()); 2172 assert_eq!( 2173 vmm.vm_config 2174 .as_ref() 2175 .unwrap() 2176 .lock() 2177 .unwrap() 2178 .devices 2179 .clone() 2180 .unwrap() 2181 .len(), 2182 1 2183 ); 2184 assert_eq!( 2185 vmm.vm_config 2186 .as_ref() 2187 .unwrap() 2188 .lock() 2189 .unwrap() 2190 .devices 2191 .clone() 2192 .unwrap()[0], 2193 device_config 2194 ); 2195 } 2196 2197 #[test] 2198 fn test_vmm_vm_cold_add_user_device() { 2199 let mut vmm = create_dummy_vmm(); 2200 let user_device_config = 2201 UserDeviceConfig::parse("socket=/path/to/socket,id=8,pci_segment=2").unwrap(); 2202 2203 assert!(matches!( 2204 vmm.vm_add_user_device(user_device_config.clone()), 2205 Err(VmError::VmNotCreated) 2206 )); 2207 2208 let _ = vmm.vm_create(create_dummy_vm_config()); 2209 assert!(vmm 2210 .vm_config 2211 .as_ref() 2212 .unwrap() 2213 .lock() 2214 .unwrap() 2215 .user_devices 2216 .is_none()); 2217 2218 let result = vmm.vm_add_user_device(user_device_config.clone()); 2219 assert!(result.is_ok()); 2220 assert!(result.unwrap().is_none()); 2221 assert_eq!( 2222 vmm.vm_config 2223 .as_ref() 2224 .unwrap() 2225 .lock() 2226 .unwrap() 2227 .user_devices 2228 .clone() 2229 .unwrap() 2230 .len(), 2231 1 2232 ); 2233 assert_eq!( 2234 vmm.vm_config 2235 .as_ref() 2236 .unwrap() 2237 .lock() 2238 .unwrap() 2239 .user_devices 2240 .clone() 2241 .unwrap()[0], 2242 user_device_config 2243 ); 2244 } 2245 2246 #[test] 2247 fn test_vmm_vm_cold_add_disk() { 2248 let mut vmm = create_dummy_vmm(); 2249 let disk_config = DiskConfig::parse("path=/path/to_file").unwrap(); 2250 2251 assert!(matches!( 2252 vmm.vm_add_disk(disk_config.clone()), 2253 Err(VmError::VmNotCreated) 2254 )); 2255 2256 let _ = vmm.vm_create(create_dummy_vm_config()); 2257 assert!(vmm 2258 .vm_config 2259 .as_ref() 2260 .unwrap() 2261 .lock() 2262 .unwrap() 2263 .disks 2264 .is_none()); 2265 2266 let result = vmm.vm_add_disk(disk_config.clone()); 2267 assert!(result.is_ok()); 2268 assert!(result.unwrap().is_none()); 2269 assert_eq!( 2270 vmm.vm_config 2271 .as_ref() 2272 .unwrap() 2273 .lock() 2274 .unwrap() 2275 .disks 2276 .clone() 2277 .unwrap() 2278 .len(), 2279 1 2280 ); 2281 assert_eq!( 2282 vmm.vm_config 2283 .as_ref() 2284 .unwrap() 2285 .lock() 2286 .unwrap() 2287 .disks 2288 .clone() 2289 .unwrap()[0], 2290 disk_config 2291 ); 2292 } 2293 2294 #[test] 2295 fn test_vmm_vm_cold_add_fs() { 2296 let mut vmm = create_dummy_vmm(); 2297 let fs_config = FsConfig::parse("tag=mytag,socket=/tmp/sock").unwrap(); 2298 2299 assert!(matches!( 2300 vmm.vm_add_fs(fs_config.clone()), 2301 Err(VmError::VmNotCreated) 2302 )); 2303 2304 let _ = vmm.vm_create(create_dummy_vm_config()); 2305 assert!(vmm.vm_config.as_ref().unwrap().lock().unwrap().fs.is_none()); 2306 2307 let result = vmm.vm_add_fs(fs_config.clone()); 2308 assert!(result.is_ok()); 2309 assert!(result.unwrap().is_none()); 2310 assert_eq!( 2311 vmm.vm_config 2312 .as_ref() 2313 .unwrap() 2314 .lock() 2315 .unwrap() 2316 .fs 2317 .clone() 2318 .unwrap() 2319 .len(), 2320 1 2321 ); 2322 assert_eq!( 2323 vmm.vm_config 2324 .as_ref() 2325 .unwrap() 2326 .lock() 2327 .unwrap() 2328 .fs 2329 .clone() 2330 .unwrap()[0], 2331 fs_config 2332 ); 2333 } 2334 2335 #[test] 2336 fn test_vmm_vm_cold_add_pmem() { 2337 let mut vmm = create_dummy_vmm(); 2338 let pmem_config = PmemConfig::parse("file=/tmp/pmem,size=128M").unwrap(); 2339 2340 assert!(matches!( 2341 vmm.vm_add_pmem(pmem_config.clone()), 2342 Err(VmError::VmNotCreated) 2343 )); 2344 2345 let _ = vmm.vm_create(create_dummy_vm_config()); 2346 assert!(vmm 2347 .vm_config 2348 .as_ref() 2349 .unwrap() 2350 .lock() 2351 .unwrap() 2352 .pmem 2353 .is_none()); 2354 2355 let result = vmm.vm_add_pmem(pmem_config.clone()); 2356 assert!(result.is_ok()); 2357 assert!(result.unwrap().is_none()); 2358 assert_eq!( 2359 vmm.vm_config 2360 .as_ref() 2361 .unwrap() 2362 .lock() 2363 .unwrap() 2364 .pmem 2365 .clone() 2366 .unwrap() 2367 .len(), 2368 1 2369 ); 2370 assert_eq!( 2371 vmm.vm_config 2372 .as_ref() 2373 .unwrap() 2374 .lock() 2375 .unwrap() 2376 .pmem 2377 .clone() 2378 .unwrap()[0], 2379 pmem_config 2380 ); 2381 } 2382 2383 #[test] 2384 fn test_vmm_vm_cold_add_net() { 2385 let mut vmm = create_dummy_vmm(); 2386 let net_config = NetConfig::parse( 2387 "mac=de:ad:be:ef:12:34,host_mac=12:34:de:ad:be:ef,vhost_user=true,socket=/tmp/sock", 2388 ) 2389 .unwrap(); 2390 2391 assert!(matches!( 2392 vmm.vm_add_net(net_config.clone()), 2393 Err(VmError::VmNotCreated) 2394 )); 2395 2396 let _ = vmm.vm_create(create_dummy_vm_config()); 2397 assert!(vmm 2398 .vm_config 2399 .as_ref() 2400 .unwrap() 2401 .lock() 2402 .unwrap() 2403 .net 2404 .is_none()); 2405 2406 let result = vmm.vm_add_net(net_config.clone()); 2407 assert!(result.is_ok()); 2408 assert!(result.unwrap().is_none()); 2409 assert_eq!( 2410 vmm.vm_config 2411 .as_ref() 2412 .unwrap() 2413 .lock() 2414 .unwrap() 2415 .net 2416 .clone() 2417 .unwrap() 2418 .len(), 2419 1 2420 ); 2421 assert_eq!( 2422 vmm.vm_config 2423 .as_ref() 2424 .unwrap() 2425 .lock() 2426 .unwrap() 2427 .net 2428 .clone() 2429 .unwrap()[0], 2430 net_config 2431 ); 2432 } 2433 2434 #[test] 2435 fn test_vmm_vm_cold_add_vdpa() { 2436 let mut vmm = create_dummy_vmm(); 2437 let vdpa_config = VdpaConfig::parse("path=/dev/vhost-vdpa,num_queues=2").unwrap(); 2438 2439 assert!(matches!( 2440 vmm.vm_add_vdpa(vdpa_config.clone()), 2441 Err(VmError::VmNotCreated) 2442 )); 2443 2444 let _ = vmm.vm_create(create_dummy_vm_config()); 2445 assert!(vmm 2446 .vm_config 2447 .as_ref() 2448 .unwrap() 2449 .lock() 2450 .unwrap() 2451 .vdpa 2452 .is_none()); 2453 2454 let result = vmm.vm_add_vdpa(vdpa_config.clone()); 2455 assert!(result.is_ok()); 2456 assert!(result.unwrap().is_none()); 2457 assert_eq!( 2458 vmm.vm_config 2459 .as_ref() 2460 .unwrap() 2461 .lock() 2462 .unwrap() 2463 .vdpa 2464 .clone() 2465 .unwrap() 2466 .len(), 2467 1 2468 ); 2469 assert_eq!( 2470 vmm.vm_config 2471 .as_ref() 2472 .unwrap() 2473 .lock() 2474 .unwrap() 2475 .vdpa 2476 .clone() 2477 .unwrap()[0], 2478 vdpa_config 2479 ); 2480 } 2481 2482 #[test] 2483 fn test_vmm_vm_cold_add_vsock() { 2484 let mut vmm = create_dummy_vmm(); 2485 let vsock_config = VsockConfig::parse("socket=/tmp/sock,cid=3,iommu=on").unwrap(); 2486 2487 assert!(matches!( 2488 vmm.vm_add_vsock(vsock_config.clone()), 2489 Err(VmError::VmNotCreated) 2490 )); 2491 2492 let _ = vmm.vm_create(create_dummy_vm_config()); 2493 assert!(vmm 2494 .vm_config 2495 .as_ref() 2496 .unwrap() 2497 .lock() 2498 .unwrap() 2499 .vsock 2500 .is_none()); 2501 2502 let result = vmm.vm_add_vsock(vsock_config.clone()); 2503 assert!(result.is_ok()); 2504 assert!(result.unwrap().is_none()); 2505 assert_eq!( 2506 vmm.vm_config 2507 .as_ref() 2508 .unwrap() 2509 .lock() 2510 .unwrap() 2511 .vsock 2512 .clone() 2513 .unwrap(), 2514 vsock_config 2515 ); 2516 } 2517 } 2518