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