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