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::UserDeviceConfig; 38 use crate::config::{ 39 DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, RestoreConfig, 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 vsock device could not be added to the VM. 138 VmAddVsock(VmError), 139 140 /// Error starting migration receiever 141 VmReceiveMigration(MigratableError), 142 143 /// Error starting migration sender 144 VmSendMigration(MigratableError), 145 146 /// Error triggering power button 147 VmPowerButton(VmError), 148 } 149 pub type ApiResult<T> = std::result::Result<T, ApiError>; 150 151 #[derive(Clone, Deserialize, Serialize)] 152 pub struct VmInfo { 153 pub config: Arc<Mutex<VmConfig>>, 154 pub state: VmState, 155 pub memory_actual_size: u64, 156 pub device_tree: Option<Arc<Mutex<DeviceTree>>>, 157 } 158 159 #[derive(Clone, Deserialize, Serialize)] 160 pub struct VmmPingResponse { 161 pub version: String, 162 } 163 164 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 165 pub struct VmResizeData { 166 pub desired_vcpus: Option<u8>, 167 pub desired_ram: Option<u64>, 168 pub desired_balloon: Option<u64>, 169 } 170 171 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 172 pub struct VmResizeZoneData { 173 pub id: String, 174 pub desired_ram: u64, 175 } 176 177 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 178 pub struct VmRemoveDeviceData { 179 pub id: String, 180 } 181 182 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 183 pub struct VmSnapshotConfig { 184 /// The snapshot destination URL 185 pub destination_url: String, 186 } 187 188 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 189 pub struct VmReceiveMigrationData { 190 /// URL for the reception of migration state 191 pub receiver_url: String, 192 } 193 194 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 195 pub struct VmSendMigrationData { 196 /// URL to migrate the VM to 197 pub destination_url: String, 198 } 199 200 pub enum ApiResponsePayload { 201 /// No data is sent on the channel. 202 Empty, 203 204 /// Virtual machine information 205 VmInfo(VmInfo), 206 207 /// Vmm ping response 208 VmmPing(VmmPingResponse), 209 210 /// Vm action response 211 VmAction(Vec<u8>), 212 } 213 214 /// This is the response sent by the VMM API server through the mpsc channel. 215 pub type ApiResponse = std::result::Result<ApiResponsePayload, ApiError>; 216 217 #[allow(clippy::large_enum_variant)] 218 #[derive(Debug)] 219 pub enum ApiRequest { 220 /// Create the virtual machine. This request payload is a VM configuration 221 /// (VmConfig). 222 /// If the VMM API server could not create the VM, it will send a VmCreate 223 /// error back. 224 VmCreate(Arc<Mutex<VmConfig>>, Sender<ApiResponse>), 225 226 /// Boot the previously created virtual machine. 227 /// If the VM was not previously created, the VMM API server will send a 228 /// VmBoot error back. 229 VmBoot(Sender<ApiResponse>), 230 231 /// Delete the previously created virtual machine. 232 /// If the VM was not previously created, the VMM API server will send a 233 /// VmDelete error back. 234 /// If the VM is booted, we shut it down first. 235 VmDelete(Sender<ApiResponse>), 236 237 /// Request the VM information. 238 VmInfo(Sender<ApiResponse>), 239 240 /// Request the VMM API server status 241 VmmPing(Sender<ApiResponse>), 242 243 /// Pause a VM. 244 VmPause(Sender<ApiResponse>), 245 246 /// Resume a VM. 247 VmResume(Sender<ApiResponse>), 248 249 /// Get counters for a VM. 250 VmCounters(Sender<ApiResponse>), 251 252 /// Shut the previously booted virtual machine down. 253 /// If the VM was not previously booted or created, the VMM API server 254 /// will send a VmShutdown error back. 255 VmShutdown(Sender<ApiResponse>), 256 257 /// Reboot the previously booted virtual machine. 258 /// If the VM was not previously booted or created, the VMM API server 259 /// will send a VmReboot error back. 260 VmReboot(Sender<ApiResponse>), 261 262 /// Shut the VMM down. 263 /// This will shutdown and delete the current VM, if any, and then exit the 264 /// VMM process. 265 VmmShutdown(Sender<ApiResponse>), 266 267 /// Resize the VM. 268 VmResize(Arc<VmResizeData>, Sender<ApiResponse>), 269 270 /// Resize the memory zone. 271 VmResizeZone(Arc<VmResizeZoneData>, Sender<ApiResponse>), 272 273 /// Add a device to the VM. 274 VmAddDevice(Arc<DeviceConfig>, Sender<ApiResponse>), 275 276 /// Add a user device to the VM. 277 VmAddUserDevice(Arc<UserDeviceConfig>, Sender<ApiResponse>), 278 279 /// Remove a device from the VM. 280 VmRemoveDevice(Arc<VmRemoveDeviceData>, Sender<ApiResponse>), 281 282 /// Add a disk to the VM. 283 VmAddDisk(Arc<DiskConfig>, Sender<ApiResponse>), 284 285 /// Add a fs to the VM. 286 VmAddFs(Arc<FsConfig>, Sender<ApiResponse>), 287 288 /// Add a pmem device to the VM. 289 VmAddPmem(Arc<PmemConfig>, Sender<ApiResponse>), 290 291 /// Add a network device to the VM. 292 VmAddNet(Arc<NetConfig>, Sender<ApiResponse>), 293 294 /// Add a vsock device to the VM. 295 VmAddVsock(Arc<VsockConfig>, Sender<ApiResponse>), 296 297 /// Take a VM snapshot 298 VmSnapshot(Arc<VmSnapshotConfig>, Sender<ApiResponse>), 299 300 /// Restore from a VM snapshot 301 VmRestore(Arc<RestoreConfig>, Sender<ApiResponse>), 302 303 /// Incoming migration 304 VmReceiveMigration(Arc<VmReceiveMigrationData>, Sender<ApiResponse>), 305 306 /// Outgoing migration 307 VmSendMigration(Arc<VmSendMigrationData>, Sender<ApiResponse>), 308 309 // Trigger power button 310 VmPowerButton(Sender<ApiResponse>), 311 } 312 313 pub fn vm_create( 314 api_evt: EventFd, 315 api_sender: Sender<ApiRequest>, 316 config: Arc<Mutex<VmConfig>>, 317 ) -> ApiResult<()> { 318 let (response_sender, response_receiver) = channel(); 319 320 // Send the VM creation request. 321 api_sender 322 .send(ApiRequest::VmCreate(config, response_sender)) 323 .map_err(ApiError::RequestSend)?; 324 api_evt.write(1).map_err(ApiError::EventFdWrite)?; 325 326 response_receiver.recv().map_err(ApiError::ResponseRecv)??; 327 328 Ok(()) 329 } 330 331 /// Represents a VM related action. 332 /// This is mostly used to factorize code between VM routines 333 /// that only differ by the IPC command they send. 334 pub enum VmAction { 335 /// Boot a VM 336 Boot, 337 338 /// Delete a VM 339 Delete, 340 341 /// Shut a VM down 342 Shutdown, 343 344 /// Reboot a VM 345 Reboot, 346 347 /// Pause a VM 348 Pause, 349 350 /// Resume a VM 351 Resume, 352 353 /// Return VM counters 354 Counters, 355 356 /// Add VFIO device 357 AddDevice(Arc<DeviceConfig>), 358 359 /// Add disk 360 AddDisk(Arc<DiskConfig>), 361 362 /// Add filesystem 363 AddFs(Arc<FsConfig>), 364 365 /// Add pmem 366 AddPmem(Arc<PmemConfig>), 367 368 /// Add network 369 AddNet(Arc<NetConfig>), 370 371 /// Add vsock 372 AddVsock(Arc<VsockConfig>), 373 374 /// Add user device 375 AddUserDevice(Arc<UserDeviceConfig>), 376 377 /// Remove VFIO device 378 RemoveDevice(Arc<VmRemoveDeviceData>), 379 380 /// Resize VM 381 Resize(Arc<VmResizeData>), 382 383 /// Resize memory zone 384 ResizeZone(Arc<VmResizeZoneData>), 385 386 /// Restore VM 387 Restore(Arc<RestoreConfig>), 388 389 /// Snapshot VM 390 Snapshot(Arc<VmSnapshotConfig>), 391 392 /// Incoming migration 393 ReceiveMigration(Arc<VmReceiveMigrationData>), 394 395 /// Outgoing migration 396 SendMigration(Arc<VmSendMigrationData>), 397 398 /// Power Button for clean shutdown 399 PowerButton, 400 } 401 402 fn vm_action( 403 api_evt: EventFd, 404 api_sender: Sender<ApiRequest>, 405 action: VmAction, 406 ) -> ApiResult<Option<Body>> { 407 let (response_sender, response_receiver) = channel(); 408 409 use VmAction::*; 410 let request = match action { 411 Boot => ApiRequest::VmBoot(response_sender), 412 Delete => ApiRequest::VmDelete(response_sender), 413 Shutdown => ApiRequest::VmShutdown(response_sender), 414 Reboot => ApiRequest::VmReboot(response_sender), 415 Pause => ApiRequest::VmPause(response_sender), 416 Resume => ApiRequest::VmResume(response_sender), 417 Counters => ApiRequest::VmCounters(response_sender), 418 AddDevice(v) => ApiRequest::VmAddDevice(v, response_sender), 419 AddDisk(v) => ApiRequest::VmAddDisk(v, response_sender), 420 AddFs(v) => ApiRequest::VmAddFs(v, response_sender), 421 AddPmem(v) => ApiRequest::VmAddPmem(v, response_sender), 422 AddNet(v) => ApiRequest::VmAddNet(v, response_sender), 423 AddVsock(v) => ApiRequest::VmAddVsock(v, response_sender), 424 AddUserDevice(v) => ApiRequest::VmAddUserDevice(v, response_sender), 425 RemoveDevice(v) => ApiRequest::VmRemoveDevice(v, response_sender), 426 Resize(v) => ApiRequest::VmResize(v, response_sender), 427 ResizeZone(v) => ApiRequest::VmResizeZone(v, response_sender), 428 Restore(v) => ApiRequest::VmRestore(v, response_sender), 429 Snapshot(v) => ApiRequest::VmSnapshot(v, response_sender), 430 ReceiveMigration(v) => ApiRequest::VmReceiveMigration(v, response_sender), 431 SendMigration(v) => ApiRequest::VmSendMigration(v, response_sender), 432 PowerButton => ApiRequest::VmPowerButton(response_sender), 433 }; 434 435 // Send the VM request. 436 api_sender.send(request).map_err(ApiError::RequestSend)?; 437 api_evt.write(1).map_err(ApiError::EventFdWrite)?; 438 439 let body = match response_receiver.recv().map_err(ApiError::ResponseRecv)?? { 440 ApiResponsePayload::VmAction(response) => Some(Body::new(response)), 441 ApiResponsePayload::Empty => None, 442 _ => return Err(ApiError::ResponsePayloadType), 443 }; 444 445 Ok(body) 446 } 447 448 pub fn vm_boot(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 449 vm_action(api_evt, api_sender, VmAction::Boot) 450 } 451 452 pub fn vm_delete(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 453 vm_action(api_evt, api_sender, VmAction::Delete) 454 } 455 456 pub fn vm_shutdown(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 457 vm_action(api_evt, api_sender, VmAction::Shutdown) 458 } 459 460 pub fn vm_reboot(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 461 vm_action(api_evt, api_sender, VmAction::Reboot) 462 } 463 464 pub fn vm_pause(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 465 vm_action(api_evt, api_sender, VmAction::Pause) 466 } 467 468 pub fn vm_resume(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 469 vm_action(api_evt, api_sender, VmAction::Resume) 470 } 471 472 pub fn vm_counters(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> { 473 vm_action(api_evt, api_sender, VmAction::Counters) 474 } 475 476 pub fn vm_power_button( 477 api_evt: EventFd, 478 api_sender: Sender<ApiRequest>, 479 ) -> ApiResult<Option<Body>> { 480 vm_action(api_evt, api_sender, VmAction::PowerButton) 481 } 482 483 pub fn vm_receive_migration( 484 api_evt: EventFd, 485 api_sender: Sender<ApiRequest>, 486 data: Arc<VmReceiveMigrationData>, 487 ) -> ApiResult<Option<Body>> { 488 vm_action(api_evt, api_sender, VmAction::ReceiveMigration(data)) 489 } 490 491 pub fn vm_send_migration( 492 api_evt: EventFd, 493 api_sender: Sender<ApiRequest>, 494 data: Arc<VmSendMigrationData>, 495 ) -> ApiResult<Option<Body>> { 496 vm_action(api_evt, api_sender, VmAction::SendMigration(data)) 497 } 498 499 pub fn vm_snapshot( 500 api_evt: EventFd, 501 api_sender: Sender<ApiRequest>, 502 data: Arc<VmSnapshotConfig>, 503 ) -> ApiResult<Option<Body>> { 504 vm_action(api_evt, api_sender, VmAction::Snapshot(data)) 505 } 506 507 pub fn vm_restore( 508 api_evt: EventFd, 509 api_sender: Sender<ApiRequest>, 510 data: Arc<RestoreConfig>, 511 ) -> ApiResult<Option<Body>> { 512 vm_action(api_evt, api_sender, VmAction::Restore(data)) 513 } 514 515 pub fn vm_info(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<VmInfo> { 516 let (response_sender, response_receiver) = channel(); 517 518 // Send the VM request. 519 api_sender 520 .send(ApiRequest::VmInfo(response_sender)) 521 .map_err(ApiError::RequestSend)?; 522 api_evt.write(1).map_err(ApiError::EventFdWrite)?; 523 524 let vm_info = response_receiver.recv().map_err(ApiError::ResponseRecv)??; 525 526 match vm_info { 527 ApiResponsePayload::VmInfo(info) => Ok(info), 528 _ => Err(ApiError::ResponsePayloadType), 529 } 530 } 531 532 pub fn vmm_ping(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<VmmPingResponse> { 533 let (response_sender, response_receiver) = channel(); 534 535 api_sender 536 .send(ApiRequest::VmmPing(response_sender)) 537 .map_err(ApiError::RequestSend)?; 538 api_evt.write(1).map_err(ApiError::EventFdWrite)?; 539 540 let vmm_pong = response_receiver.recv().map_err(ApiError::ResponseRecv)??; 541 542 match vmm_pong { 543 ApiResponsePayload::VmmPing(pong) => Ok(pong), 544 _ => Err(ApiError::ResponsePayloadType), 545 } 546 } 547 548 pub fn vmm_shutdown(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<()> { 549 let (response_sender, response_receiver) = channel(); 550 551 // Send the VMM shutdown request. 552 api_sender 553 .send(ApiRequest::VmmShutdown(response_sender)) 554 .map_err(ApiError::RequestSend)?; 555 api_evt.write(1).map_err(ApiError::EventFdWrite)?; 556 557 response_receiver.recv().map_err(ApiError::ResponseRecv)??; 558 559 Ok(()) 560 } 561 562 pub fn vm_resize( 563 api_evt: EventFd, 564 api_sender: Sender<ApiRequest>, 565 data: Arc<VmResizeData>, 566 ) -> ApiResult<Option<Body>> { 567 vm_action(api_evt, api_sender, VmAction::Resize(data)) 568 } 569 570 pub fn vm_resize_zone( 571 api_evt: EventFd, 572 api_sender: Sender<ApiRequest>, 573 data: Arc<VmResizeZoneData>, 574 ) -> ApiResult<Option<Body>> { 575 vm_action(api_evt, api_sender, VmAction::ResizeZone(data)) 576 } 577 578 pub fn vm_add_device( 579 api_evt: EventFd, 580 api_sender: Sender<ApiRequest>, 581 data: Arc<DeviceConfig>, 582 ) -> ApiResult<Option<Body>> { 583 vm_action(api_evt, api_sender, VmAction::AddDevice(data)) 584 } 585 586 pub fn vm_add_user_device( 587 api_evt: EventFd, 588 api_sender: Sender<ApiRequest>, 589 data: Arc<UserDeviceConfig>, 590 ) -> ApiResult<Option<Body>> { 591 vm_action(api_evt, api_sender, VmAction::AddUserDevice(data)) 592 } 593 594 pub fn vm_remove_device( 595 api_evt: EventFd, 596 api_sender: Sender<ApiRequest>, 597 data: Arc<VmRemoveDeviceData>, 598 ) -> ApiResult<Option<Body>> { 599 vm_action(api_evt, api_sender, VmAction::RemoveDevice(data)) 600 } 601 602 pub fn vm_add_disk( 603 api_evt: EventFd, 604 api_sender: Sender<ApiRequest>, 605 data: Arc<DiskConfig>, 606 ) -> ApiResult<Option<Body>> { 607 vm_action(api_evt, api_sender, VmAction::AddDisk(data)) 608 } 609 610 pub fn vm_add_fs( 611 api_evt: EventFd, 612 api_sender: Sender<ApiRequest>, 613 data: Arc<FsConfig>, 614 ) -> ApiResult<Option<Body>> { 615 vm_action(api_evt, api_sender, VmAction::AddFs(data)) 616 } 617 618 pub fn vm_add_pmem( 619 api_evt: EventFd, 620 api_sender: Sender<ApiRequest>, 621 data: Arc<PmemConfig>, 622 ) -> ApiResult<Option<Body>> { 623 vm_action(api_evt, api_sender, VmAction::AddPmem(data)) 624 } 625 626 pub fn vm_add_net( 627 api_evt: EventFd, 628 api_sender: Sender<ApiRequest>, 629 data: Arc<NetConfig>, 630 ) -> ApiResult<Option<Body>> { 631 vm_action(api_evt, api_sender, VmAction::AddNet(data)) 632 } 633 634 pub fn vm_add_vsock( 635 api_evt: EventFd, 636 api_sender: Sender<ApiRequest>, 637 data: Arc<VsockConfig>, 638 ) -> ApiResult<Option<Body>> { 639 vm_action(api_evt, api_sender, VmAction::AddVsock(data)) 640 } 641