1 // Copyright © 2019 Intel Corporation 2 // Copyright 2024 Alyssa Ross <hi@alyssa.is> 3 // 4 // SPDX-License-Identifier: Apache-2.0 5 // 6 7 //! The internal VMM API for Cloud Hypervisor. 8 //! 9 //! This API is a synchronous, [mpsc](https://doc.rust-lang.org/std/sync/mpsc/) 10 //! based IPC for sending commands to the VMM thread, from other 11 //! Cloud Hypervisor threads. The IPC follows a command-response protocol, i.e. 12 //! each command will receive a response back. 13 //! 14 //! The main Cloud Hypervisor thread creates an API event file descriptor 15 //! to notify the VMM thread about pending API commands, together with an 16 //! API mpsc channel. The former is the IPC control plane, the latter is the 17 //! IPC data plane. 18 //! In order to use the IPC, a Cloud Hypervisor thread needs to have a clone 19 //! of both the API event file descriptor and the channel Sender. Then it must 20 //! go through the following steps: 21 //! 22 //! 1. The thread creates an mpsc channel for receiving the command response. 23 //! 2. The thread sends an ApiRequest to the Sender endpoint. The ApiRequest 24 //! encapsulates the response channel Sender, for the VMM API server to be 25 //! able to send the response back. 26 //! 3. The thread writes to the API event file descriptor to notify the VMM 27 //! API server about a pending command. 28 //! 4. The thread reads the response back from the VMM API server, from the 29 //! response channel Receiver. 30 //! 5. The thread handles the response and forwards potential errors. 31 32 #[cfg(feature = "dbus_api")] 33 pub mod dbus; 34 pub mod http; 35 36 use std::io; 37 use std::sync::mpsc::{channel, RecvError, SendError, Sender}; 38 39 use micro_http::Body; 40 use serde::{Deserialize, Serialize}; 41 use thiserror::Error; 42 use vm_migration::MigratableError; 43 use vmm_sys_util::eventfd::EventFd; 44 45 #[cfg(feature = "dbus_api")] 46 pub use self::dbus::start_dbus_thread; 47 pub use self::http::{start_http_fd_thread, start_http_path_thread}; 48 use crate::config::RestoreConfig; 49 use crate::device_tree::DeviceTree; 50 use crate::vm::{Error as VmError, VmState}; 51 use crate::vm_config::{ 52 DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, UserDeviceConfig, VdpaConfig, 53 VmConfig, VsockConfig, 54 }; 55 use crate::Error as VmmError; 56 57 /// API errors are sent back from the VMM API server through the ApiResponse. 58 #[derive(Error, Debug)] 59 pub enum ApiError { 60 /// Cannot write to EventFd. 61 #[error("Cannot write to EventFd")] 62 EventFdWrite(#[source] io::Error), 63 64 /// API request send error 65 #[error("API request send error")] 66 RequestSend(#[source] SendError<ApiRequest>), 67 68 /// Wrong response payload type 69 #[error("Wrong response payload type")] 70 ResponsePayloadType, 71 72 /// API response receive error 73 #[error("API response receive error")] 74 ResponseRecv(#[source] RecvError), 75 76 /// The VM could not boot. 77 #[error("The VM could not boot")] 78 VmBoot(#[source] VmError), 79 80 /// The VM could not be created. 81 #[error("The VM could not be created")] 82 VmCreate(#[source] VmError), 83 84 /// The VM could not be deleted. 85 #[error("The VM could not be deleted")] 86 VmDelete(#[source] VmError), 87 88 /// The VM info is not available. 89 #[error("The VM info is not available")] 90 VmInfo(#[source] VmError), 91 92 /// The VM could not be paused. 93 #[error("The VM could not be paused")] 94 VmPause(#[source] VmError), 95 96 /// The VM could not resume. 97 #[error("The VM could not resume")] 98 VmResume(#[source] VmError), 99 100 /// The VM is not booted. 101 #[error("The VM is not booted")] 102 VmNotBooted, 103 104 /// The VM is not created. 105 #[error("The VM is not created")] 106 VmNotCreated, 107 108 /// The VM could not shutdown. 109 #[error("The VM could not shutdown")] 110 VmShutdown(#[source] VmError), 111 112 /// The VM could not reboot. 113 #[error("The VM could not reboot")] 114 VmReboot(#[source] VmError), 115 116 /// The VM could not be snapshotted. 117 #[error("The VM could not be snapshotted")] 118 VmSnapshot(#[source] VmError), 119 120 /// The VM could not restored. 121 #[error("The VM could not restored")] 122 VmRestore(#[source] VmError), 123 124 /// The VM could not be coredumped. 125 #[error("The VM could not be coredumped")] 126 VmCoredump(#[source] VmError), 127 128 /// The VMM could not shutdown. 129 #[error("The VMM could not shutdown")] 130 VmmShutdown(#[source] VmError), 131 132 /// The VM could not be resized 133 #[error("The VM could not be resized")] 134 VmResize(#[source] VmError), 135 136 /// The memory zone could not be resized. 137 #[error("The memory zone could not be resized")] 138 VmResizeZone(#[source] VmError), 139 140 /// The device could not be added to the VM. 141 #[error("The device could not be added to the VM")] 142 VmAddDevice(#[source] VmError), 143 144 /// The user device could not be added to the VM. 145 #[error("The user device could not be added to the VM")] 146 VmAddUserDevice(#[source] VmError), 147 148 /// The device could not be removed from the VM. 149 #[error("The device could not be removed from the VM")] 150 VmRemoveDevice(#[source] VmError), 151 152 /// Cannot create seccomp filter 153 #[error("Cannot create seccomp filter")] 154 CreateSeccompFilter(#[source] seccompiler::Error), 155 156 /// Cannot apply seccomp filter 157 #[error("Cannot apply seccomp filter")] 158 ApplySeccompFilter(#[source] seccompiler::Error), 159 160 /// The disk could not be added to the VM. 161 #[error("The disk could not be added to the VM")] 162 VmAddDisk(#[source] VmError), 163 164 /// The fs could not be added to the VM. 165 #[error("The fs could not be added to the VM")] 166 VmAddFs(#[source] VmError), 167 168 /// The pmem device could not be added to the VM. 169 #[error("The pmem device could not be added to the VM")] 170 VmAddPmem(#[source] VmError), 171 172 /// The network device could not be added to the VM. 173 #[error("The network device could not be added to the VM")] 174 VmAddNet(#[source] VmError), 175 176 /// The vDPA device could not be added to the VM. 177 #[error("The vDPA device could not be added to the VM")] 178 VmAddVdpa(#[source] VmError), 179 180 /// The vsock device could not be added to the VM. 181 #[error("The vsock device could not be added to the VM")] 182 VmAddVsock(#[source] VmError), 183 184 /// Error starting migration receiver 185 #[error("Error starting migration receiver")] 186 VmReceiveMigration(#[source] MigratableError), 187 188 /// Error starting migration sender 189 #[error("Error starting migration sender")] 190 VmSendMigration(#[source] MigratableError), 191 192 /// Error triggering power button 193 #[error("Error triggering power button")] 194 VmPowerButton(#[source] VmError), 195 196 /// Error triggering NMI 197 #[error("Error triggering NMI")] 198 VmNmi(#[source] VmError), 199 } 200 pub type ApiResult<T> = Result<T, ApiError>; 201 202 #[derive(Clone, Deserialize, Serialize)] 203 pub struct VmInfoResponse { 204 pub config: Box<VmConfig>, 205 pub state: VmState, 206 pub memory_actual_size: u64, 207 pub device_tree: Option<DeviceTree>, 208 } 209 210 #[derive(Clone, Deserialize, Serialize)] 211 pub struct VmmPingResponse { 212 pub build_version: String, 213 pub version: String, 214 pub pid: i64, 215 pub features: Vec<String>, 216 } 217 218 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 219 pub struct VmResizeData { 220 pub desired_vcpus: Option<u8>, 221 pub desired_ram: Option<u64>, 222 pub desired_balloon: Option<u64>, 223 } 224 225 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 226 pub struct VmResizeZoneData { 227 pub id: String, 228 pub desired_ram: u64, 229 } 230 231 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 232 pub struct VmRemoveDeviceData { 233 pub id: String, 234 } 235 236 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 237 pub struct VmSnapshotConfig { 238 /// The snapshot destination URL 239 pub destination_url: String, 240 } 241 242 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 243 pub struct VmCoredumpData { 244 /// The coredump destination file 245 pub destination_url: String, 246 } 247 248 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 249 pub struct VmReceiveMigrationData { 250 /// URL for the reception of migration state 251 pub receiver_url: String, 252 } 253 254 #[derive(Clone, Deserialize, Serialize, Default, Debug)] 255 pub struct VmSendMigrationData { 256 /// URL to migrate the VM to 257 pub destination_url: String, 258 /// Send memory across socket without copying 259 #[serde(default)] 260 pub local: bool, 261 } 262 263 pub enum ApiResponsePayload { 264 /// No data is sent on the channel. 265 Empty, 266 267 /// Virtual machine information 268 VmInfo(VmInfoResponse), 269 270 /// Vmm ping response 271 VmmPing(VmmPingResponse), 272 273 /// Vm action response 274 VmAction(Option<Vec<u8>>), 275 } 276 277 /// This is the response sent by the VMM API server through the mpsc channel. 278 pub type ApiResponse = Result<ApiResponsePayload, ApiError>; 279 280 pub trait RequestHandler { 281 fn vm_create(&mut self, config: Box<VmConfig>) -> Result<(), VmError>; 282 283 fn vm_boot(&mut self) -> Result<(), VmError>; 284 285 fn vm_pause(&mut self) -> Result<(), VmError>; 286 287 fn vm_resume(&mut self) -> Result<(), VmError>; 288 289 fn vm_snapshot(&mut self, destination_url: &str) -> Result<(), VmError>; 290 291 fn vm_restore(&mut self, restore_cfg: RestoreConfig) -> Result<(), VmError>; 292 293 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] 294 fn vm_coredump(&mut self, destination_url: &str) -> Result<(), VmError>; 295 296 fn vm_shutdown(&mut self) -> Result<(), VmError>; 297 298 fn vm_reboot(&mut self) -> Result<(), VmError>; 299 300 fn vm_info(&self) -> Result<VmInfoResponse, VmError>; 301 302 fn vmm_ping(&self) -> VmmPingResponse; 303 304 fn vm_delete(&mut self) -> Result<(), VmError>; 305 306 fn vmm_shutdown(&mut self) -> Result<(), VmError>; 307 308 fn vm_resize( 309 &mut self, 310 desired_vcpus: Option<u8>, 311 desired_ram: Option<u64>, 312 desired_balloon: Option<u64>, 313 ) -> Result<(), VmError>; 314 315 fn vm_resize_zone(&mut self, id: String, desired_ram: u64) -> Result<(), VmError>; 316 317 fn vm_add_device(&mut self, device_cfg: DeviceConfig) -> Result<Option<Vec<u8>>, VmError>; 318 319 fn vm_add_user_device( 320 &mut self, 321 device_cfg: UserDeviceConfig, 322 ) -> Result<Option<Vec<u8>>, VmError>; 323 324 fn vm_remove_device(&mut self, id: String) -> Result<(), VmError>; 325 326 fn vm_add_disk(&mut self, disk_cfg: DiskConfig) -> Result<Option<Vec<u8>>, VmError>; 327 328 fn vm_add_fs(&mut self, fs_cfg: FsConfig) -> Result<Option<Vec<u8>>, VmError>; 329 330 fn vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> Result<Option<Vec<u8>>, VmError>; 331 332 fn vm_add_net(&mut self, net_cfg: NetConfig) -> Result<Option<Vec<u8>>, VmError>; 333 334 fn vm_add_vdpa(&mut self, vdpa_cfg: VdpaConfig) -> Result<Option<Vec<u8>>, VmError>; 335 336 fn vm_add_vsock(&mut self, vsock_cfg: VsockConfig) -> Result<Option<Vec<u8>>, VmError>; 337 338 fn vm_counters(&mut self) -> Result<Option<Vec<u8>>, VmError>; 339 340 fn vm_power_button(&mut self) -> Result<(), VmError>; 341 342 fn vm_receive_migration( 343 &mut self, 344 receive_data_migration: VmReceiveMigrationData, 345 ) -> Result<(), MigratableError>; 346 347 fn vm_send_migration( 348 &mut self, 349 send_data_migration: VmSendMigrationData, 350 ) -> Result<(), MigratableError>; 351 352 fn vm_nmi(&mut self) -> Result<(), VmError>; 353 } 354 355 /// It would be nice if we could pass around an object like this: 356 /// 357 /// ``` 358 /// # use vmm::api::ApiAction; 359 /// struct ApiRequest<Action: ApiAction + 'static> { 360 /// action: &'static Action, 361 /// body: Action::RequestBody, 362 /// } 363 /// ``` 364 /// 365 /// Unfortunately, it's not possible to use such a type in a trait object, 366 /// so as a workaround, we instead encapsulate that data in a closure, and have 367 /// the event loop call that closure to process a request. 368 pub type ApiRequest = 369 Box<dyn FnOnce(&mut dyn RequestHandler) -> Result<bool, VmmError> + Send + 'static>; 370 371 fn get_response<Action: ApiAction>( 372 action: &Action, 373 api_evt: EventFd, 374 api_sender: Sender<ApiRequest>, 375 data: Action::RequestBody, 376 ) -> ApiResult<ApiResponsePayload> { 377 let (response_sender, response_receiver) = channel(); 378 379 let request = action.request(data, response_sender); 380 381 // Send the VM request. 382 api_sender.send(request).map_err(ApiError::RequestSend)?; 383 api_evt.write(1).map_err(ApiError::EventFdWrite)?; 384 385 response_receiver.recv().map_err(ApiError::ResponseRecv)? 386 } 387 388 fn get_response_body<Action: ApiAction<ResponseBody = Option<Body>>>( 389 action: &Action, 390 api_evt: EventFd, 391 api_sender: Sender<ApiRequest>, 392 data: Action::RequestBody, 393 ) -> ApiResult<Option<Body>> { 394 let body = match get_response(action, api_evt, api_sender, data)? { 395 ApiResponsePayload::VmAction(response) => response.map(Body::new), 396 ApiResponsePayload::Empty => None, 397 _ => return Err(ApiError::ResponsePayloadType), 398 }; 399 400 Ok(body) 401 } 402 403 pub trait ApiAction: Send + Sync { 404 type RequestBody: Send + Sync + Sized; 405 type ResponseBody: Send + Sized; 406 407 fn request(&self, body: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest; 408 409 fn send( 410 &self, 411 api_evt: EventFd, 412 api_sender: Sender<ApiRequest>, 413 data: Self::RequestBody, 414 ) -> ApiResult<Self::ResponseBody>; 415 } 416 417 pub struct VmAddDevice; 418 419 impl ApiAction for VmAddDevice { 420 type RequestBody = DeviceConfig; 421 type ResponseBody = Option<Body>; 422 423 fn request( 424 &self, 425 config: Self::RequestBody, 426 response_sender: Sender<ApiResponse>, 427 ) -> ApiRequest { 428 Box::new(move |vmm| { 429 info!("API request event: VmAddDevice {:?}", config); 430 431 let response = vmm 432 .vm_add_device(config) 433 .map_err(ApiError::VmAddDevice) 434 .map(ApiResponsePayload::VmAction); 435 436 response_sender 437 .send(response) 438 .map_err(VmmError::ApiResponseSend)?; 439 440 Ok(false) 441 }) 442 } 443 444 fn send( 445 &self, 446 api_evt: EventFd, 447 api_sender: Sender<ApiRequest>, 448 data: Self::RequestBody, 449 ) -> ApiResult<Self::ResponseBody> { 450 get_response_body(self, api_evt, api_sender, data) 451 } 452 } 453 454 pub struct AddDisk; 455 456 impl ApiAction for AddDisk { 457 type RequestBody = DiskConfig; 458 type ResponseBody = Option<Body>; 459 460 fn request( 461 &self, 462 config: Self::RequestBody, 463 response_sender: Sender<ApiResponse>, 464 ) -> ApiRequest { 465 Box::new(move |vmm| { 466 info!("API request event: AddDisk {:?}", config); 467 468 let response = vmm 469 .vm_add_disk(config) 470 .map_err(ApiError::VmAddDisk) 471 .map(ApiResponsePayload::VmAction); 472 473 response_sender 474 .send(response) 475 .map_err(VmmError::ApiResponseSend)?; 476 477 Ok(false) 478 }) 479 } 480 481 fn send( 482 &self, 483 api_evt: EventFd, 484 api_sender: Sender<ApiRequest>, 485 data: Self::RequestBody, 486 ) -> ApiResult<Self::ResponseBody> { 487 get_response_body(self, api_evt, api_sender, data) 488 } 489 } 490 491 pub struct VmAddFs; 492 493 impl ApiAction for VmAddFs { 494 type RequestBody = FsConfig; 495 type ResponseBody = Option<Body>; 496 497 fn request( 498 &self, 499 config: Self::RequestBody, 500 response_sender: Sender<ApiResponse>, 501 ) -> ApiRequest { 502 Box::new(move |vmm| { 503 info!("API request event: VmAddFs {:?}", config); 504 505 let response = vmm 506 .vm_add_fs(config) 507 .map_err(ApiError::VmAddFs) 508 .map(ApiResponsePayload::VmAction); 509 510 response_sender 511 .send(response) 512 .map_err(VmmError::ApiResponseSend)?; 513 514 Ok(false) 515 }) 516 } 517 518 fn send( 519 &self, 520 api_evt: EventFd, 521 api_sender: Sender<ApiRequest>, 522 data: Self::RequestBody, 523 ) -> ApiResult<Self::ResponseBody> { 524 get_response_body(self, api_evt, api_sender, data) 525 } 526 } 527 528 pub struct VmAddPmem; 529 530 impl ApiAction for VmAddPmem { 531 type RequestBody = PmemConfig; 532 type ResponseBody = Option<Body>; 533 534 fn request( 535 &self, 536 config: Self::RequestBody, 537 response_sender: Sender<ApiResponse>, 538 ) -> ApiRequest { 539 Box::new(move |vmm| { 540 info!("API request event: VmAddPmem {:?}", config); 541 542 let response = vmm 543 .vm_add_pmem(config) 544 .map_err(ApiError::VmAddPmem) 545 .map(ApiResponsePayload::VmAction); 546 547 response_sender 548 .send(response) 549 .map_err(VmmError::ApiResponseSend)?; 550 551 Ok(false) 552 }) 553 } 554 555 fn send( 556 &self, 557 api_evt: EventFd, 558 api_sender: Sender<ApiRequest>, 559 data: Self::RequestBody, 560 ) -> ApiResult<Self::ResponseBody> { 561 get_response_body(self, api_evt, api_sender, data) 562 } 563 } 564 565 pub struct VmAddNet; 566 567 impl ApiAction for VmAddNet { 568 type RequestBody = NetConfig; 569 type ResponseBody = Option<Body>; 570 571 fn request( 572 &self, 573 config: Self::RequestBody, 574 response_sender: Sender<ApiResponse>, 575 ) -> ApiRequest { 576 Box::new(move |vmm| { 577 info!("API request event: VmAddNet {:?}", config); 578 579 let response = vmm 580 .vm_add_net(config) 581 .map_err(ApiError::VmAddNet) 582 .map(ApiResponsePayload::VmAction); 583 584 response_sender 585 .send(response) 586 .map_err(VmmError::ApiResponseSend)?; 587 588 Ok(false) 589 }) 590 } 591 592 fn send( 593 &self, 594 api_evt: EventFd, 595 api_sender: Sender<ApiRequest>, 596 data: Self::RequestBody, 597 ) -> ApiResult<Self::ResponseBody> { 598 get_response_body(self, api_evt, api_sender, data) 599 } 600 } 601 602 pub struct VmAddVdpa; 603 604 impl ApiAction for VmAddVdpa { 605 type RequestBody = VdpaConfig; 606 type ResponseBody = Option<Body>; 607 608 fn request( 609 &self, 610 config: Self::RequestBody, 611 response_sender: Sender<ApiResponse>, 612 ) -> ApiRequest { 613 Box::new(move |vmm| { 614 info!("API request event: VmAddVdpa {:?}", config); 615 616 let response = vmm 617 .vm_add_vdpa(config) 618 .map_err(ApiError::VmAddVdpa) 619 .map(ApiResponsePayload::VmAction); 620 621 response_sender 622 .send(response) 623 .map_err(VmmError::ApiResponseSend)?; 624 625 Ok(false) 626 }) 627 } 628 629 fn send( 630 &self, 631 api_evt: EventFd, 632 api_sender: Sender<ApiRequest>, 633 data: Self::RequestBody, 634 ) -> ApiResult<Self::ResponseBody> { 635 get_response_body(self, api_evt, api_sender, data) 636 } 637 } 638 639 pub struct VmAddVsock; 640 641 impl ApiAction for VmAddVsock { 642 type RequestBody = VsockConfig; 643 type ResponseBody = Option<Body>; 644 645 fn request( 646 &self, 647 config: Self::RequestBody, 648 response_sender: Sender<ApiResponse>, 649 ) -> ApiRequest { 650 Box::new(move |vmm| { 651 info!("API request event: VmAddVsock {:?}", config); 652 653 let response = vmm 654 .vm_add_vsock(config) 655 .map_err(ApiError::VmAddVsock) 656 .map(ApiResponsePayload::VmAction); 657 658 response_sender 659 .send(response) 660 .map_err(VmmError::ApiResponseSend)?; 661 662 Ok(false) 663 }) 664 } 665 666 fn send( 667 &self, 668 api_evt: EventFd, 669 api_sender: Sender<ApiRequest>, 670 data: Self::RequestBody, 671 ) -> ApiResult<Self::ResponseBody> { 672 get_response_body(self, api_evt, api_sender, data) 673 } 674 } 675 676 pub struct VmAddUserDevice; 677 678 impl ApiAction for VmAddUserDevice { 679 type RequestBody = UserDeviceConfig; 680 type ResponseBody = Option<Body>; 681 682 fn request( 683 &self, 684 config: Self::RequestBody, 685 response_sender: Sender<ApiResponse>, 686 ) -> ApiRequest { 687 Box::new(move |vmm| { 688 info!("API request event: VmAddUserDevice {:?}", config); 689 690 let response = vmm 691 .vm_add_user_device(config) 692 .map_err(ApiError::VmAddUserDevice) 693 .map(ApiResponsePayload::VmAction); 694 695 response_sender 696 .send(response) 697 .map_err(VmmError::ApiResponseSend)?; 698 699 Ok(false) 700 }) 701 } 702 703 fn send( 704 &self, 705 api_evt: EventFd, 706 api_sender: Sender<ApiRequest>, 707 data: Self::RequestBody, 708 ) -> ApiResult<Self::ResponseBody> { 709 get_response_body(self, api_evt, api_sender, data) 710 } 711 } 712 713 pub struct VmBoot; 714 715 impl ApiAction for VmBoot { 716 type RequestBody = (); 717 type ResponseBody = Option<Body>; 718 719 fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 720 Box::new(move |vmm| { 721 info!("API request event: VmBoot"); 722 723 let response = vmm 724 .vm_boot() 725 .map_err(ApiError::VmBoot) 726 .map(|_| ApiResponsePayload::Empty); 727 728 response_sender 729 .send(response) 730 .map_err(VmmError::ApiResponseSend)?; 731 732 Ok(false) 733 }) 734 } 735 736 fn send( 737 &self, 738 api_evt: EventFd, 739 api_sender: Sender<ApiRequest>, 740 data: Self::RequestBody, 741 ) -> ApiResult<Self::ResponseBody> { 742 get_response_body(self, api_evt, api_sender, data) 743 } 744 } 745 746 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] 747 pub struct VmCoredump; 748 749 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] 750 impl ApiAction for VmCoredump { 751 type RequestBody = VmCoredumpData; 752 type ResponseBody = Option<Body>; 753 754 fn request( 755 &self, 756 coredump_data: Self::RequestBody, 757 response_sender: Sender<ApiResponse>, 758 ) -> ApiRequest { 759 Box::new(move |vmm| { 760 info!("API request event: VmCoredump {:?}", coredump_data); 761 762 let response = vmm 763 .vm_coredump(&coredump_data.destination_url) 764 .map_err(ApiError::VmCoredump) 765 .map(|_| ApiResponsePayload::Empty); 766 767 response_sender 768 .send(response) 769 .map_err(VmmError::ApiResponseSend)?; 770 771 Ok(false) 772 }) 773 } 774 775 fn send( 776 &self, 777 api_evt: EventFd, 778 api_sender: Sender<ApiRequest>, 779 data: Self::RequestBody, 780 ) -> ApiResult<Self::ResponseBody> { 781 get_response_body(self, api_evt, api_sender, data) 782 } 783 } 784 785 pub struct VmCounters; 786 787 impl ApiAction for VmCounters { 788 type RequestBody = (); 789 type ResponseBody = Option<Body>; 790 791 fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 792 Box::new(move |vmm| { 793 info!("API request event: VmCounters"); 794 795 let response = vmm 796 .vm_counters() 797 .map_err(ApiError::VmInfo) 798 .map(ApiResponsePayload::VmAction); 799 800 response_sender 801 .send(response) 802 .map_err(VmmError::ApiResponseSend)?; 803 804 Ok(false) 805 }) 806 } 807 808 fn send( 809 &self, 810 api_evt: EventFd, 811 api_sender: Sender<ApiRequest>, 812 data: Self::RequestBody, 813 ) -> ApiResult<Self::ResponseBody> { 814 get_response_body(self, api_evt, api_sender, data) 815 } 816 } 817 818 pub struct VmCreate; 819 820 impl ApiAction for VmCreate { 821 type RequestBody = Box<VmConfig>; 822 type ResponseBody = (); 823 824 fn request( 825 &self, 826 config: Self::RequestBody, 827 response_sender: Sender<ApiResponse>, 828 ) -> ApiRequest { 829 Box::new(move |vmm| { 830 info!("API request event: VmCreate {:?}", config); 831 832 let response = vmm 833 .vm_create(config) 834 .map_err(ApiError::VmCreate) 835 .map(|_| ApiResponsePayload::Empty); 836 837 response_sender 838 .send(response) 839 .map_err(VmmError::ApiResponseSend)?; 840 841 Ok(false) 842 }) 843 } 844 845 fn send( 846 &self, 847 api_evt: EventFd, 848 api_sender: Sender<ApiRequest>, 849 data: Self::RequestBody, 850 ) -> ApiResult<()> { 851 get_response(self, api_evt, api_sender, data)?; 852 853 Ok(()) 854 } 855 } 856 857 pub struct VmDelete; 858 859 impl ApiAction for VmDelete { 860 type RequestBody = (); 861 type ResponseBody = Option<Body>; 862 863 fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 864 Box::new(move |vmm| { 865 info!("API request event: VmDelete"); 866 867 let response = vmm 868 .vm_delete() 869 .map_err(ApiError::VmDelete) 870 .map(|_| ApiResponsePayload::Empty); 871 872 response_sender 873 .send(response) 874 .map_err(VmmError::ApiResponseSend)?; 875 876 Ok(false) 877 }) 878 } 879 880 fn send( 881 &self, 882 api_evt: EventFd, 883 api_sender: Sender<ApiRequest>, 884 data: Self::RequestBody, 885 ) -> ApiResult<Self::ResponseBody> { 886 get_response_body(self, api_evt, api_sender, data) 887 } 888 } 889 890 pub struct VmInfo; 891 892 impl ApiAction for VmInfo { 893 type RequestBody = (); 894 type ResponseBody = VmInfoResponse; 895 896 fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 897 Box::new(move |vmm| { 898 info!("API request event: VmInfo"); 899 900 let response = vmm 901 .vm_info() 902 .map_err(ApiError::VmInfo) 903 .map(ApiResponsePayload::VmInfo); 904 905 response_sender 906 .send(response) 907 .map_err(VmmError::ApiResponseSend)?; 908 909 Ok(false) 910 }) 911 } 912 913 fn send( 914 &self, 915 api_evt: EventFd, 916 api_sender: Sender<ApiRequest>, 917 data: (), 918 ) -> ApiResult<VmInfoResponse> { 919 let vm_info = get_response(self, api_evt, api_sender, data)?; 920 921 match vm_info { 922 ApiResponsePayload::VmInfo(info) => Ok(info), 923 _ => Err(ApiError::ResponsePayloadType), 924 } 925 } 926 } 927 928 pub struct VmPause; 929 930 impl ApiAction for VmPause { 931 type RequestBody = (); 932 type ResponseBody = Option<Body>; 933 934 fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 935 Box::new(move |vmm| { 936 info!("API request event: VmPause"); 937 938 let response = vmm 939 .vm_pause() 940 .map_err(ApiError::VmPause) 941 .map(|_| ApiResponsePayload::Empty); 942 943 response_sender 944 .send(response) 945 .map_err(VmmError::ApiResponseSend)?; 946 947 Ok(false) 948 }) 949 } 950 951 fn send( 952 &self, 953 api_evt: EventFd, 954 api_sender: Sender<ApiRequest>, 955 data: Self::RequestBody, 956 ) -> ApiResult<Self::ResponseBody> { 957 get_response_body(self, api_evt, api_sender, data) 958 } 959 } 960 961 pub struct VmPowerButton; 962 963 impl ApiAction for VmPowerButton { 964 type RequestBody = (); 965 type ResponseBody = Option<Body>; 966 967 fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 968 Box::new(move |vmm| { 969 info!("API request event: VmPowerButton"); 970 971 let response = vmm 972 .vm_power_button() 973 .map_err(ApiError::VmPowerButton) 974 .map(|_| ApiResponsePayload::Empty); 975 976 response_sender 977 .send(response) 978 .map_err(VmmError::ApiResponseSend)?; 979 980 Ok(false) 981 }) 982 } 983 984 fn send( 985 &self, 986 api_evt: EventFd, 987 api_sender: Sender<ApiRequest>, 988 data: Self::RequestBody, 989 ) -> ApiResult<Self::ResponseBody> { 990 get_response_body(self, api_evt, api_sender, data) 991 } 992 } 993 994 pub struct VmReboot; 995 996 impl ApiAction for VmReboot { 997 type RequestBody = (); 998 type ResponseBody = Option<Body>; 999 1000 fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 1001 Box::new(move |vmm| { 1002 info!("API request event: VmReboot"); 1003 1004 let response = vmm 1005 .vm_reboot() 1006 .map_err(ApiError::VmReboot) 1007 .map(|_| ApiResponsePayload::Empty); 1008 1009 response_sender 1010 .send(response) 1011 .map_err(VmmError::ApiResponseSend)?; 1012 1013 Ok(false) 1014 }) 1015 } 1016 1017 fn send( 1018 &self, 1019 api_evt: EventFd, 1020 api_sender: Sender<ApiRequest>, 1021 data: Self::RequestBody, 1022 ) -> ApiResult<Self::ResponseBody> { 1023 get_response_body(self, api_evt, api_sender, data) 1024 } 1025 } 1026 1027 pub struct VmReceiveMigration; 1028 1029 impl ApiAction for VmReceiveMigration { 1030 type RequestBody = VmReceiveMigrationData; 1031 type ResponseBody = Option<Body>; 1032 1033 fn request(&self, data: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 1034 Box::new(move |vmm| { 1035 info!("API request event: VmReceiveMigration {:?}", data); 1036 1037 let response = vmm 1038 .vm_receive_migration(data) 1039 .map_err(ApiError::VmReceiveMigration) 1040 .map(|_| ApiResponsePayload::Empty); 1041 1042 response_sender 1043 .send(response) 1044 .map_err(VmmError::ApiResponseSend)?; 1045 1046 Ok(false) 1047 }) 1048 } 1049 1050 fn send( 1051 &self, 1052 api_evt: EventFd, 1053 api_sender: Sender<ApiRequest>, 1054 data: Self::RequestBody, 1055 ) -> ApiResult<Self::ResponseBody> { 1056 get_response_body(self, api_evt, api_sender, data) 1057 } 1058 } 1059 1060 pub struct VmRemoveDevice; 1061 1062 impl ApiAction for VmRemoveDevice { 1063 type RequestBody = VmRemoveDeviceData; 1064 type ResponseBody = Option<Body>; 1065 1066 fn request( 1067 &self, 1068 remove_device_data: Self::RequestBody, 1069 response_sender: Sender<ApiResponse>, 1070 ) -> ApiRequest { 1071 Box::new(move |vmm| { 1072 info!("API request event: VmRemoveDevice {:?}", remove_device_data); 1073 1074 let response = vmm 1075 .vm_remove_device(remove_device_data.id) 1076 .map_err(ApiError::VmRemoveDevice) 1077 .map(|_| ApiResponsePayload::Empty); 1078 1079 response_sender 1080 .send(response) 1081 .map_err(VmmError::ApiResponseSend)?; 1082 1083 Ok(false) 1084 }) 1085 } 1086 1087 fn send( 1088 &self, 1089 api_evt: EventFd, 1090 api_sender: Sender<ApiRequest>, 1091 data: Self::RequestBody, 1092 ) -> ApiResult<Self::ResponseBody> { 1093 get_response_body(self, api_evt, api_sender, data) 1094 } 1095 } 1096 1097 pub struct VmResize; 1098 1099 impl ApiAction for VmResize { 1100 type RequestBody = VmResizeData; 1101 type ResponseBody = Option<Body>; 1102 1103 fn request( 1104 &self, 1105 resize_data: Self::RequestBody, 1106 response_sender: Sender<ApiResponse>, 1107 ) -> ApiRequest { 1108 Box::new(move |vmm| { 1109 info!("API request event: VmResize {:?}", resize_data); 1110 1111 let response = vmm 1112 .vm_resize( 1113 resize_data.desired_vcpus, 1114 resize_data.desired_ram, 1115 resize_data.desired_balloon, 1116 ) 1117 .map_err(ApiError::VmResize) 1118 .map(|_| ApiResponsePayload::Empty); 1119 1120 response_sender 1121 .send(response) 1122 .map_err(VmmError::ApiResponseSend)?; 1123 1124 Ok(false) 1125 }) 1126 } 1127 1128 fn send( 1129 &self, 1130 api_evt: EventFd, 1131 api_sender: Sender<ApiRequest>, 1132 data: Self::RequestBody, 1133 ) -> ApiResult<Self::ResponseBody> { 1134 get_response_body(self, api_evt, api_sender, data) 1135 } 1136 } 1137 1138 pub struct VmResizeZone; 1139 1140 impl ApiAction for VmResizeZone { 1141 type RequestBody = VmResizeZoneData; 1142 type ResponseBody = Option<Body>; 1143 1144 fn request( 1145 &self, 1146 resize_zone_data: Self::RequestBody, 1147 response_sender: Sender<ApiResponse>, 1148 ) -> ApiRequest { 1149 Box::new(move |vmm| { 1150 info!("API request event: VmResizeZone {:?}", resize_zone_data); 1151 1152 let response = vmm 1153 .vm_resize_zone(resize_zone_data.id, resize_zone_data.desired_ram) 1154 .map_err(ApiError::VmResizeZone) 1155 .map(|_| ApiResponsePayload::Empty); 1156 1157 response_sender 1158 .send(response) 1159 .map_err(VmmError::ApiResponseSend)?; 1160 1161 Ok(false) 1162 }) 1163 } 1164 1165 fn send( 1166 &self, 1167 api_evt: EventFd, 1168 api_sender: Sender<ApiRequest>, 1169 data: Self::RequestBody, 1170 ) -> ApiResult<Self::ResponseBody> { 1171 get_response_body(self, api_evt, api_sender, data) 1172 } 1173 } 1174 1175 pub struct VmRestore; 1176 1177 impl ApiAction for VmRestore { 1178 type RequestBody = RestoreConfig; 1179 type ResponseBody = Option<Body>; 1180 1181 fn request( 1182 &self, 1183 config: Self::RequestBody, 1184 response_sender: Sender<ApiResponse>, 1185 ) -> ApiRequest { 1186 Box::new(move |vmm| { 1187 info!("API request event: VmRestore {:?}", config); 1188 1189 let response = vmm 1190 .vm_restore(config) 1191 .map_err(ApiError::VmRestore) 1192 .map(|_| ApiResponsePayload::Empty); 1193 1194 response_sender 1195 .send(response) 1196 .map_err(VmmError::ApiResponseSend)?; 1197 1198 Ok(false) 1199 }) 1200 } 1201 1202 fn send( 1203 &self, 1204 api_evt: EventFd, 1205 api_sender: Sender<ApiRequest>, 1206 data: Self::RequestBody, 1207 ) -> ApiResult<Self::ResponseBody> { 1208 get_response_body(self, api_evt, api_sender, data) 1209 } 1210 } 1211 1212 pub struct VmResume; 1213 1214 impl ApiAction for VmResume { 1215 type RequestBody = (); 1216 type ResponseBody = Option<Body>; 1217 1218 fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 1219 Box::new(move |vmm| { 1220 info!("API request event: VmResume"); 1221 1222 let response = vmm 1223 .vm_resume() 1224 .map_err(ApiError::VmResume) 1225 .map(|_| ApiResponsePayload::Empty); 1226 1227 response_sender 1228 .send(response) 1229 .map_err(VmmError::ApiResponseSend)?; 1230 1231 Ok(false) 1232 }) 1233 } 1234 1235 fn send( 1236 &self, 1237 api_evt: EventFd, 1238 api_sender: Sender<ApiRequest>, 1239 data: Self::RequestBody, 1240 ) -> ApiResult<Self::ResponseBody> { 1241 get_response_body(self, api_evt, api_sender, data) 1242 } 1243 } 1244 1245 pub struct VmSendMigration; 1246 1247 impl ApiAction for VmSendMigration { 1248 type RequestBody = VmSendMigrationData; 1249 type ResponseBody = Option<Body>; 1250 1251 fn request(&self, data: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 1252 Box::new(move |vmm| { 1253 info!("API request event: VmSendMigration {:?}", data); 1254 1255 let response = vmm 1256 .vm_send_migration(data) 1257 .map_err(ApiError::VmSendMigration) 1258 .map(|_| ApiResponsePayload::Empty); 1259 1260 response_sender 1261 .send(response) 1262 .map_err(VmmError::ApiResponseSend)?; 1263 1264 Ok(false) 1265 }) 1266 } 1267 1268 fn send( 1269 &self, 1270 api_evt: EventFd, 1271 api_sender: Sender<ApiRequest>, 1272 data: Self::RequestBody, 1273 ) -> ApiResult<Self::ResponseBody> { 1274 get_response_body(self, api_evt, api_sender, data) 1275 } 1276 } 1277 1278 pub struct VmShutdown; 1279 1280 impl ApiAction for VmShutdown { 1281 type RequestBody = (); 1282 type ResponseBody = Option<Body>; 1283 1284 fn request( 1285 &self, 1286 config: Self::RequestBody, 1287 response_sender: Sender<ApiResponse>, 1288 ) -> ApiRequest { 1289 Box::new(move |vmm| { 1290 info!("API request event: VmShutdown {:?}", config); 1291 1292 let response = vmm 1293 .vm_shutdown() 1294 .map_err(ApiError::VmShutdown) 1295 .map(|_| ApiResponsePayload::Empty); 1296 1297 response_sender 1298 .send(response) 1299 .map_err(VmmError::ApiResponseSend)?; 1300 1301 Ok(false) 1302 }) 1303 } 1304 1305 fn send( 1306 &self, 1307 api_evt: EventFd, 1308 api_sender: Sender<ApiRequest>, 1309 data: Self::RequestBody, 1310 ) -> ApiResult<Self::ResponseBody> { 1311 get_response_body(self, api_evt, api_sender, data) 1312 } 1313 } 1314 1315 pub struct VmSnapshot; 1316 1317 impl ApiAction for VmSnapshot { 1318 type RequestBody = VmSnapshotConfig; 1319 type ResponseBody = Option<Body>; 1320 1321 fn request( 1322 &self, 1323 config: Self::RequestBody, 1324 response_sender: Sender<ApiResponse>, 1325 ) -> ApiRequest { 1326 Box::new(move |vmm| { 1327 info!("API request event: VmSnapshot {:?}", config); 1328 1329 let response = vmm 1330 .vm_snapshot(&config.destination_url) 1331 .map_err(ApiError::VmSnapshot) 1332 .map(|_| ApiResponsePayload::Empty); 1333 1334 response_sender 1335 .send(response) 1336 .map_err(VmmError::ApiResponseSend)?; 1337 1338 Ok(false) 1339 }) 1340 } 1341 1342 fn send( 1343 &self, 1344 api_evt: EventFd, 1345 api_sender: Sender<ApiRequest>, 1346 data: Self::RequestBody, 1347 ) -> ApiResult<Self::ResponseBody> { 1348 get_response_body(self, api_evt, api_sender, data) 1349 } 1350 } 1351 1352 pub struct VmmPing; 1353 1354 impl ApiAction for VmmPing { 1355 type RequestBody = (); 1356 type ResponseBody = VmmPingResponse; 1357 1358 fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 1359 Box::new(move |vmm| { 1360 info!("API request event: VmmPing"); 1361 1362 let response = ApiResponsePayload::VmmPing(vmm.vmm_ping()); 1363 1364 response_sender 1365 .send(Ok(response)) 1366 .map_err(VmmError::ApiResponseSend)?; 1367 1368 Ok(false) 1369 }) 1370 } 1371 1372 fn send( 1373 &self, 1374 api_evt: EventFd, 1375 api_sender: Sender<ApiRequest>, 1376 data: (), 1377 ) -> ApiResult<VmmPingResponse> { 1378 let vmm_pong = get_response(self, api_evt, api_sender, data)?; 1379 1380 match vmm_pong { 1381 ApiResponsePayload::VmmPing(pong) => Ok(pong), 1382 _ => Err(ApiError::ResponsePayloadType), 1383 } 1384 } 1385 } 1386 1387 pub struct VmmShutdown; 1388 1389 impl ApiAction for VmmShutdown { 1390 type RequestBody = (); 1391 type ResponseBody = (); 1392 1393 fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 1394 Box::new(move |vmm| { 1395 info!("API request event: VmmShutdown"); 1396 1397 let response = vmm 1398 .vmm_shutdown() 1399 .map_err(ApiError::VmmShutdown) 1400 .map(|_| ApiResponsePayload::Empty); 1401 1402 response_sender 1403 .send(response) 1404 .map_err(VmmError::ApiResponseSend)?; 1405 1406 Ok(true) 1407 }) 1408 } 1409 1410 fn send(&self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: ()) -> ApiResult<()> { 1411 get_response(self, api_evt, api_sender, data)?; 1412 1413 Ok(()) 1414 } 1415 } 1416 1417 pub struct VmNmi; 1418 1419 impl ApiAction for VmNmi { 1420 type RequestBody = (); 1421 type ResponseBody = Option<Body>; 1422 1423 fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest { 1424 Box::new(move |vmm| { 1425 info!("API request event: VmNmi"); 1426 1427 let response = vmm 1428 .vm_nmi() 1429 .map_err(ApiError::VmNmi) 1430 .map(|_| ApiResponsePayload::Empty); 1431 1432 response_sender 1433 .send(response) 1434 .map_err(VmmError::ApiResponseSend)?; 1435 1436 Ok(false) 1437 }) 1438 } 1439 1440 fn send( 1441 &self, 1442 api_evt: EventFd, 1443 api_sender: Sender<ApiRequest>, 1444 data: Self::RequestBody, 1445 ) -> ApiResult<Self::ResponseBody> { 1446 get_response_body(self, api_evt, api_sender, data) 1447 } 1448 } 1449