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