1 // Copyright © 2019 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 //! The internal VMM API for Cloud Hypervisor. 7 //! 8 //! This API is a synchronous, [mpsc](https://doc.rust-lang.org/std/sync/mpsc/) 9 //! based IPC for sending commands to the VMM thread, from other 10 //! Cloud Hypervisor threads. The IPC follows a command-response protocol, i.e. 11 //! each command will receive a response back. 12 //! 13 //! The main Cloud Hypervisor thread creates an API event file descriptor 14 //! to notify the VMM thread about pending API commands, together with an 15 //! API mpsc channel. The former is the IPC control plane, the latter is the 16 //! IPC data plane. 17 //! In order to use the IPC, a Cloud Hypervisor thread needs to have a clone 18 //! of both the API event file descriptor and the channel Sender. Then it must 19 //! go through the following steps: 20 //! 21 //! 1. The thread creates an mpsc channel for receiving the command response. 22 //! 2. The thread sends an ApiRequest to the Sender endpoint. The ApiRequest 23 //! contains the response channel Sender, for the VMM API server to be able 24 //! to send the response back. 25 //! 3. The thread writes to the API event file descriptor to notify the VMM 26 //! API server about a pending command. 27 //! 4. The thread reads the response back from the VMM API server, from the 28 //! response channel Receiver. 29 //! 5. The thread handles the response and forwards potential errors. 30 31 pub use self::http::start_http_fd_thread; 32 pub use self::http::start_http_path_thread; 33 34 pub mod http; 35 pub mod http_endpoint; 36 37 use crate::config::{ 38 DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, RestoreConfig, UserDeviceConfig, 39 VdpaConfig, VmConfig, VsockConfig, 40 }; 41 use crate::device_tree::DeviceTree; 42 use crate::vm::{Error as VmError, VmState}; 43 use micro_http::Body; 44 use std::io; 45 use std::sync::mpsc::{channel, RecvError, SendError, Sender}; 46 use std::sync::{Arc, Mutex}; 47 use vm_migration::MigratableError; 48 use vmm_sys_util::eventfd::EventFd; 49 50 /// API errors are sent back from the VMM API server through the ApiResponse. 51 #[derive(Debug)] 52 pub enum ApiError { 53 /// Cannot write to EventFd. 54 EventFdWrite(io::Error), 55 56 /// API request send error 57 RequestSend(SendError<ApiRequest>), 58 59 /// Wrong response payload type 60 ResponsePayloadType, 61 62 /// API response receive error 63 ResponseRecv(RecvError), 64 65 /// The VM could not boot. 66 VmBoot(VmError), 67 68 /// The VM could not be created. 69 VmCreate(VmError), 70 71 /// The VM could not be deleted. 72 VmDelete(VmError), 73 74 /// The VM info is not available. 75 VmInfo(VmError), 76 77 /// The VM could not be paused. 78 VmPause(VmError), 79 80 /// The VM could not resume. 81 VmResume(VmError), 82 83 /// The VM is not booted. 84 VmNotBooted, 85 86 /// The VM is not created. 87 VmNotCreated, 88 89 /// The VM could not shutdown. 90 VmShutdown(VmError), 91 92 /// The VM could not reboot. 93 VmReboot(VmError), 94 95 /// The VM could not be snapshotted. 96 VmSnapshot(VmError), 97 98 /// The VM could not restored. 99 VmRestore(VmError), 100 101 /// The VMM could not shutdown. 102 VmmShutdown(VmError), 103 104 /// The VM could not be resized 105 VmResize(VmError), 106 107 /// The memory zone could not be resized. 108 VmResizeZone(VmError), 109 110 /// The device could not be added to the VM. 111 VmAddDevice(VmError), 112 113 /// The user device could not be added to the VM. 114 VmAddUserDevice(VmError), 115 116 /// The device could not be removed from the VM. 117 VmRemoveDevice(VmError), 118 119 /// Cannot create seccomp filter 120 CreateSeccompFilter(seccompiler::Error), 121 122 /// Cannot apply seccomp filter 123 ApplySeccompFilter(seccompiler::Error), 124 125 /// The disk could not be added to the VM. 126 VmAddDisk(VmError), 127 128 /// The fs could not be added to the VM. 129 VmAddFs(VmError), 130 131 /// The pmem device could not be added to the VM. 132 VmAddPmem(VmError), 133 134 /// The network device could not be added to the VM. 135 VmAddNet(VmError), 136 137 /// The vDPA device could not be added to the VM. 138 VmAddVdpa(VmError), 139 140 /// The vsock device could not be added to the VM. 141 VmAddVsock(VmError), 142 143 /// Error starting migration receiever 144 VmReceiveMigration(MigratableError), 145 146 /// Error starting migration sender 147 VmSendMigration(MigratableError), 148 149 /// Error triggering power button 150 VmPowerButton(VmError), 151 } 152 pub type ApiResult<T> = std::result::Result<T, ApiError>; 153 154 #[derive(Clone, Deserialize, Serialize)] 155 pub struct VmInfo { 156 pub config: Arc<Mutex<VmConfig>>, 157 pub state: VmState, 158 pub memory_actual_size: u64, 159 pub device_tree: Option<Arc<Mutex<DeviceTree>>>, 160 } 161 162 #[derive(Clone, Deserialize, Serialize)] 163 pub struct VmmPingResponse { 164 pub version: String, 165 } 166 167 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 168 pub struct VmResizeData { 169 pub desired_vcpus: Option<u8>, 170 pub desired_ram: Option<u64>, 171 pub desired_balloon: Option<u64>, 172 } 173 174 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 175 pub struct VmResizeZoneData { 176 pub id: String, 177 pub desired_ram: u64, 178 } 179 180 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 181 pub struct VmRemoveDeviceData { 182 pub id: String, 183 } 184 185 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 186 pub struct VmSnapshotConfig { 187 /// The snapshot destination URL 188 pub destination_url: String, 189 } 190 191 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 192 pub struct VmReceiveMigrationData { 193 /// URL for the reception of migration state 194 pub receiver_url: String, 195 } 196 197 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 198 pub struct VmSendMigrationData { 199 /// URL to migrate the VM to 200 pub destination_url: String, 201 /// Send memory across socket without copying 202 #[serde(default)] 203 pub local: bool, 204 } 205 206 pub enum ApiResponsePayload { 207 /// No data is sent on the channel. 208 Empty, 209 210 /// Virtual machine information 211 VmInfo(VmInfo), 212 213 /// Vmm ping response 214 VmmPing(VmmPingResponse), 215 216 /// Vm action response 217 VmAction(Option<Vec<u8>>), 218 } 219 220 /// This is the response sent by the VMM API server through the mpsc channel. 221 pub type ApiResponse = std::result::Result<ApiResponsePayload, ApiError>; 222 223 #[allow(clippy::large_enum_variant)] 224 #[derive(Debug)] 225 pub enum ApiRequest { 226 /// Create the virtual machine. This request payload is a VM configuration 227 /// (VmConfig). 228 /// If the VMM API server could not create the VM, it will send a VmCreate 229 /// error back. 230 VmCreate(Arc<Mutex<VmConfig>>, Sender<ApiResponse>), 231 232 /// Boot the previously created virtual machine. 233 /// If the VM was not previously created, the VMM API server will send a 234 /// VmBoot error back. 235 VmBoot(Sender<ApiResponse>), 236 237 /// Delete the previously created virtual machine. 238 /// If the VM was not previously created, the VMM API server will send a 239 /// VmDelete error back. 240 /// If the VM is booted, we shut it down first. 241 VmDelete(Sender<ApiResponse>), 242 243 /// Request the VM information. 244 VmInfo(Sender<ApiResponse>), 245 246 /// Request the VMM API server status 247 VmmPing(Sender<ApiResponse>), 248 249 /// Pause a VM. 250 VmPause(Sender<ApiResponse>), 251 252 /// Resume a VM. 253 VmResume(Sender<ApiResponse>), 254 255 /// Get counters for a VM. 256 VmCounters(Sender<ApiResponse>), 257 258 /// Shut the previously booted virtual machine down. 259 /// If the VM was not previously booted or created, the VMM API server 260 /// will send a VmShutdown error back. 261 VmShutdown(Sender<ApiResponse>), 262 263 /// Reboot the previously booted virtual machine. 264 /// If the VM was not previously booted or created, the VMM API server 265 /// will send a VmReboot error back. 266 VmReboot(Sender<ApiResponse>), 267 268 /// Shut the VMM down. 269 /// This will shutdown and delete the current VM, if any, and then exit the 270 /// VMM process. 271 VmmShutdown(Sender<ApiResponse>), 272 273 /// Resize the VM. 274 VmResize(Arc<VmResizeData>, Sender<ApiResponse>), 275 276 /// Resize the memory zone. 277 VmResizeZone(Arc<VmResizeZoneData>, Sender<ApiResponse>), 278 279 /// Add a device to the VM. 280 VmAddDevice(Arc<DeviceConfig>, Sender<ApiResponse>), 281 282 /// Add a user device to the VM. 283 VmAddUserDevice(Arc<UserDeviceConfig>, Sender<ApiResponse>), 284 285 /// Remove a device from the VM. 286 VmRemoveDevice(Arc<VmRemoveDeviceData>, Sender<ApiResponse>), 287 288 /// Add a disk to the VM. 289 VmAddDisk(Arc<DiskConfig>, Sender<ApiResponse>), 290 291 /// Add a fs to the VM. 292 VmAddFs(Arc<FsConfig>, Sender<ApiResponse>), 293 294 /// Add a pmem device to the VM. 295 VmAddPmem(Arc<PmemConfig>, Sender<ApiResponse>), 296 297 /// Add a network device to the VM. 298 VmAddNet(Arc<NetConfig>, Sender<ApiResponse>), 299 300 /// Add a vDPA device to the VM. 301 VmAddVdpa(Arc<VdpaConfig>, Sender<ApiResponse>), 302 303 /// Add a vsock device to the VM. 304 VmAddVsock(Arc<VsockConfig>, Sender<ApiResponse>), 305 306 /// Take a VM snapshot 307 VmSnapshot(Arc<VmSnapshotConfig>, Sender<ApiResponse>), 308 309 /// Restore from a VM snapshot 310 VmRestore(Arc<RestoreConfig>, Sender<ApiResponse>), 311 312 /// Incoming migration 313 VmReceiveMigration(Arc<VmReceiveMigrationData>, Sender<ApiResponse>), 314 315 /// Outgoing migration 316 VmSendMigration(Arc<VmSendMigrationData>, Sender<ApiResponse>), 317 318 // Trigger power button 319 VmPowerButton(Sender<ApiResponse>), 320 } 321 322 pub fn vm_create( 323 api_evt: EventFd, 324 api_sender: Sender<ApiRequest>, 325 config: Arc<Mutex<VmConfig>>, 326 ) -> ApiResult<()> { 327 let (response_sender, response_receiver) = channel(); 328 329 // Send the VM creation request. 330 api_sender 331 .send(ApiRequest::VmCreate(config, response_sender)) 332 .map_err(ApiError::RequestSend)?; 333 api_evt.write(1).map_err(ApiError::EventFdWrite)?; 334 335 response_receiver.recv().map_err(ApiError::ResponseRecv)??; 336 337 Ok(()) 338 } 339 340 /// Represents a VM related action. 341 /// This is mostly used to factorize code between VM routines 342 /// that only differ by the IPC command they send. 343 pub enum VmAction { 344 /// Boot a VM 345 Boot, 346 347 /// Delete a VM 348 Delete, 349 350 /// Shut a VM down 351 Shutdown, 352 353 /// Reboot a VM 354 Reboot, 355 356 /// Pause a VM 357 Pause, 358 359 /// Resume a VM 360 Resume, 361 362 /// Return VM counters 363 Counters, 364 365 /// Add VFIO device 366 AddDevice(Arc<DeviceConfig>), 367 368 /// Add disk 369 AddDisk(Arc<DiskConfig>), 370 371 /// Add filesystem 372 AddFs(Arc<FsConfig>), 373 374 /// Add pmem 375 AddPmem(Arc<PmemConfig>), 376 377 /// Add network 378 AddNet(Arc<NetConfig>), 379 380 /// Add vdpa 381 AddVdpa(Arc<VdpaConfig>), 382 383 /// Add vsock 384 AddVsock(Arc<VsockConfig>), 385 386 /// Add user device 387 AddUserDevice(Arc<UserDeviceConfig>), 388 389 /// Remove VFIO device 390 RemoveDevice(Arc<VmRemoveDeviceData>), 391 392 /// Resize VM 393 Resize(Arc<VmResizeData>), 394 395 /// Resize memory zone 396 ResizeZone(Arc<VmResizeZoneData>), 397 398 /// Restore VM 399 Restore(Arc<RestoreConfig>), 400 401 /// Snapshot VM 402 Snapshot(Arc<VmSnapshotConfig>), 403 404 /// Incoming migration 405 ReceiveMigration(Arc<VmReceiveMigrationData>), 406 407 /// Outgoing migration 408 SendMigration(Arc<VmSendMigrationData>), 409 410 /// Power Button for clean shutdown 411 PowerButton, 412 } 413 414 fn vm_action( 415 api_evt: EventFd, 416 api_sender: Sender<ApiRequest>, 417 action: VmAction, 418 ) -> ApiResult<Option<Body>> { 419 let (response_sender, response_receiver) = channel(); 420 421 use VmAction::*; 422 let request = match action { 423 Boot => ApiRequest::VmBoot(response_sender), 424 Delete => ApiRequest::VmDelete(response_sender), 425 Shutdown => ApiRequest::VmShutdown(response_sender), 426 Reboot => ApiRequest::VmReboot(response_sender), 427 Pause => ApiRequest::VmPause(response_sender), 428 Resume => ApiRequest::VmResume(response_sender), 429 Counters => ApiRequest::VmCounters(response_sender), 430 AddDevice(v) => ApiRequest::VmAddDevice(v, response_sender), 431 AddDisk(v) => ApiRequest::VmAddDisk(v, response_sender), 432 AddFs(v) => ApiRequest::VmAddFs(v, response_sender), 433 AddPmem(v) => ApiRequest::VmAddPmem(v, response_sender), 434 AddNet(v) => ApiRequest::VmAddNet(v, response_sender), 435 AddVdpa(v) => ApiRequest::VmAddVdpa(v, response_sender), 436 AddVsock(v) => ApiRequest::VmAddVsock(v, response_sender), 437 AddUserDevice(v) => ApiRequest::VmAddUserDevice(v, response_sender), 438 RemoveDevice(v) => ApiRequest::VmRemoveDevice(v, response_sender), 439 Resize(v) => ApiRequest::VmResize(v, response_sender), 440 ResizeZone(v) => ApiRequest::VmResizeZone(v, response_sender), 441 Restore(v) => ApiRequest::VmRestore(v, response_sender), 442 Snapshot(v) => ApiRequest::VmSnapshot(v, response_sender), 443 ReceiveMigration(v) => ApiRequest::VmReceiveMigration(v, response_sender), 444 SendMigration(v) => ApiRequest::VmSendMigration(v, response_sender), 445 PowerButton => ApiRequest::VmPowerButton(response_sender), 446 }; 447 448 // Send the VM request. 449 api_sender.send(request).map_err(ApiError::RequestSend)?; 450 api_evt.write(1).map_err(ApiError::EventFdWrite)?; 451 452 let body = match response_receiver.recv().map_err(ApiError::ResponseRecv)?? { 453 ApiResponsePayload::VmAction(response) => response.map(Body::new), 454 ApiResponsePayload::Empty => None, 455 _ => return Err(ApiError::ResponsePayloadType), 456 }; 457 458 Ok(body) 459 } 460 461 pub fn vm_boot(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 462 vm_action(api_evt, api_sender, VmAction::Boot) 463 } 464 465 pub fn vm_delete(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 466 vm_action(api_evt, api_sender, VmAction::Delete) 467 } 468 469 pub fn vm_shutdown(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 470 vm_action(api_evt, api_sender, VmAction::Shutdown) 471 } 472 473 pub fn vm_reboot(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 474 vm_action(api_evt, api_sender, VmAction::Reboot) 475 } 476 477 pub fn vm_pause(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 478 vm_action(api_evt, api_sender, VmAction::Pause) 479 } 480 481 pub fn vm_resume(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 482 vm_action(api_evt, api_sender, VmAction::Resume) 483 } 484 485 pub fn vm_counters(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 486 vm_action(api_evt, api_sender, VmAction::Counters) 487 } 488 489 pub fn vm_power_button( 490 api_evt: EventFd, 491 api_sender: Sender<ApiRequest>, 492 ) -> ApiResult<Option<Body>> { 493 vm_action(api_evt, api_sender, VmAction::PowerButton) 494 } 495 496 pub fn vm_receive_migration( 497 api_evt: EventFd, 498 api_sender: Sender<ApiRequest>, 499 data: Arc<VmReceiveMigrationData>, 500 ) -> ApiResult<Option<Body>> { 501 vm_action(api_evt, api_sender, VmAction::ReceiveMigration(data)) 502 } 503 504 pub fn vm_send_migration( 505 api_evt: EventFd, 506 api_sender: Sender<ApiRequest>, 507 data: Arc<VmSendMigrationData>, 508 ) -> ApiResult<Option<Body>> { 509 vm_action(api_evt, api_sender, VmAction::SendMigration(data)) 510 } 511 512 pub fn vm_snapshot( 513 api_evt: EventFd, 514 api_sender: Sender<ApiRequest>, 515 data: Arc<VmSnapshotConfig>, 516 ) -> ApiResult<Option<Body>> { 517 vm_action(api_evt, api_sender, VmAction::Snapshot(data)) 518 } 519 520 pub fn vm_restore( 521 api_evt: EventFd, 522 api_sender: Sender<ApiRequest>, 523 data: Arc<RestoreConfig>, 524 ) -> ApiResult<Option<Body>> { 525 vm_action(api_evt, api_sender, VmAction::Restore(data)) 526 } 527 528 pub fn vm_info(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<VmInfo> { 529 let (response_sender, response_receiver) = channel(); 530 531 // Send the VM request. 532 api_sender 533 .send(ApiRequest::VmInfo(response_sender)) 534 .map_err(ApiError::RequestSend)?; 535 api_evt.write(1).map_err(ApiError::EventFdWrite)?; 536 537 let vm_info = response_receiver.recv().map_err(ApiError::ResponseRecv)??; 538 539 match vm_info { 540 ApiResponsePayload::VmInfo(info) => Ok(info), 541 _ => Err(ApiError::ResponsePayloadType), 542 } 543 } 544 545 pub fn vmm_ping(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<VmmPingResponse> { 546 let (response_sender, response_receiver) = channel(); 547 548 api_sender 549 .send(ApiRequest::VmmPing(response_sender)) 550 .map_err(ApiError::RequestSend)?; 551 api_evt.write(1).map_err(ApiError::EventFdWrite)?; 552 553 let vmm_pong = response_receiver.recv().map_err(ApiError::ResponseRecv)??; 554 555 match vmm_pong { 556 ApiResponsePayload::VmmPing(pong) => Ok(pong), 557 _ => Err(ApiError::ResponsePayloadType), 558 } 559 } 560 561 pub fn vmm_shutdown(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<()> { 562 let (response_sender, response_receiver) = channel(); 563 564 // Send the VMM shutdown request. 565 api_sender 566 .send(ApiRequest::VmmShutdown(response_sender)) 567 .map_err(ApiError::RequestSend)?; 568 api_evt.write(1).map_err(ApiError::EventFdWrite)?; 569 570 response_receiver.recv().map_err(ApiError::ResponseRecv)??; 571 572 Ok(()) 573 } 574 575 pub fn vm_resize( 576 api_evt: EventFd, 577 api_sender: Sender<ApiRequest>, 578 data: Arc<VmResizeData>, 579 ) -> ApiResult<Option<Body>> { 580 vm_action(api_evt, api_sender, VmAction::Resize(data)) 581 } 582 583 pub fn vm_resize_zone( 584 api_evt: EventFd, 585 api_sender: Sender<ApiRequest>, 586 data: Arc<VmResizeZoneData>, 587 ) -> ApiResult<Option<Body>> { 588 vm_action(api_evt, api_sender, VmAction::ResizeZone(data)) 589 } 590 591 pub fn vm_add_device( 592 api_evt: EventFd, 593 api_sender: Sender<ApiRequest>, 594 data: Arc<DeviceConfig>, 595 ) -> ApiResult<Option<Body>> { 596 vm_action(api_evt, api_sender, VmAction::AddDevice(data)) 597 } 598 599 pub fn vm_add_user_device( 600 api_evt: EventFd, 601 api_sender: Sender<ApiRequest>, 602 data: Arc<UserDeviceConfig>, 603 ) -> ApiResult<Option<Body>> { 604 vm_action(api_evt, api_sender, VmAction::AddUserDevice(data)) 605 } 606 607 pub fn vm_remove_device( 608 api_evt: EventFd, 609 api_sender: Sender<ApiRequest>, 610 data: Arc<VmRemoveDeviceData>, 611 ) -> ApiResult<Option<Body>> { 612 vm_action(api_evt, api_sender, VmAction::RemoveDevice(data)) 613 } 614 615 pub fn vm_add_disk( 616 api_evt: EventFd, 617 api_sender: Sender<ApiRequest>, 618 data: Arc<DiskConfig>, 619 ) -> ApiResult<Option<Body>> { 620 vm_action(api_evt, api_sender, VmAction::AddDisk(data)) 621 } 622 623 pub fn vm_add_fs( 624 api_evt: EventFd, 625 api_sender: Sender<ApiRequest>, 626 data: Arc<FsConfig>, 627 ) -> ApiResult<Option<Body>> { 628 vm_action(api_evt, api_sender, VmAction::AddFs(data)) 629 } 630 631 pub fn vm_add_pmem( 632 api_evt: EventFd, 633 api_sender: Sender<ApiRequest>, 634 data: Arc<PmemConfig>, 635 ) -> ApiResult<Option<Body>> { 636 vm_action(api_evt, api_sender, VmAction::AddPmem(data)) 637 } 638 639 pub fn vm_add_net( 640 api_evt: EventFd, 641 api_sender: Sender<ApiRequest>, 642 data: Arc<NetConfig>, 643 ) -> ApiResult<Option<Body>> { 644 vm_action(api_evt, api_sender, VmAction::AddNet(data)) 645 } 646 647 pub fn vm_add_vdpa( 648 api_evt: EventFd, 649 api_sender: Sender<ApiRequest>, 650 data: Arc<VdpaConfig>, 651 ) -> ApiResult<Option<Body>> { 652 vm_action(api_evt, api_sender, VmAction::AddVdpa(data)) 653 } 654 655 pub fn vm_add_vsock( 656 api_evt: EventFd, 657 api_sender: Sender<ApiRequest>, 658 data: Arc<VsockConfig>, 659 ) -> ApiResult<Option<Body>> { 660 vm_action(api_evt, api_sender, VmAction::AddVsock(data)) 661 } 662