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