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 {
vm_create(&mut self, config: Box<VmConfig>) -> Result<(), VmError>281 fn vm_create(&mut self, config: Box<VmConfig>) -> Result<(), VmError>;
282
vm_boot(&mut self) -> Result<(), VmError>283 fn vm_boot(&mut self) -> Result<(), VmError>;
284
vm_pause(&mut self) -> Result<(), VmError>285 fn vm_pause(&mut self) -> Result<(), VmError>;
286
vm_resume(&mut self) -> Result<(), VmError>287 fn vm_resume(&mut self) -> Result<(), VmError>;
288
vm_snapshot(&mut self, destination_url: &str) -> Result<(), VmError>289 fn vm_snapshot(&mut self, destination_url: &str) -> Result<(), VmError>;
290
vm_restore(&mut self, restore_cfg: RestoreConfig) -> Result<(), VmError>291 fn vm_restore(&mut self, restore_cfg: RestoreConfig) -> Result<(), VmError>;
292
293 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
vm_coredump(&mut self, destination_url: &str) -> Result<(), VmError>294 fn vm_coredump(&mut self, destination_url: &str) -> Result<(), VmError>;
295
vm_shutdown(&mut self) -> Result<(), VmError>296 fn vm_shutdown(&mut self) -> Result<(), VmError>;
297
vm_reboot(&mut self) -> Result<(), VmError>298 fn vm_reboot(&mut self) -> Result<(), VmError>;
299
vm_info(&self) -> Result<VmInfoResponse, VmError>300 fn vm_info(&self) -> Result<VmInfoResponse, VmError>;
301
vmm_ping(&self) -> VmmPingResponse302 fn vmm_ping(&self) -> VmmPingResponse;
303
vm_delete(&mut self) -> Result<(), VmError>304 fn vm_delete(&mut self) -> Result<(), VmError>;
305
vmm_shutdown(&mut self) -> Result<(), VmError>306 fn vmm_shutdown(&mut self) -> Result<(), VmError>;
307
vm_resize( &mut self, desired_vcpus: Option<u8>, desired_ram: Option<u64>, desired_balloon: Option<u64>, ) -> Result<(), VmError>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
vm_resize_zone(&mut self, id: String, desired_ram: u64) -> Result<(), VmError>315 fn vm_resize_zone(&mut self, id: String, desired_ram: u64) -> Result<(), VmError>;
316
vm_add_device(&mut self, device_cfg: DeviceConfig) -> Result<Option<Vec<u8>>, VmError>317 fn vm_add_device(&mut self, device_cfg: DeviceConfig) -> Result<Option<Vec<u8>>, VmError>;
318
vm_add_user_device( &mut self, device_cfg: UserDeviceConfig, ) -> Result<Option<Vec<u8>>, VmError>319 fn vm_add_user_device(
320 &mut self,
321 device_cfg: UserDeviceConfig,
322 ) -> Result<Option<Vec<u8>>, VmError>;
323
vm_remove_device(&mut self, id: String) -> Result<(), VmError>324 fn vm_remove_device(&mut self, id: String) -> Result<(), VmError>;
325
vm_add_disk(&mut self, disk_cfg: DiskConfig) -> Result<Option<Vec<u8>>, VmError>326 fn vm_add_disk(&mut self, disk_cfg: DiskConfig) -> Result<Option<Vec<u8>>, VmError>;
327
vm_add_fs(&mut self, fs_cfg: FsConfig) -> Result<Option<Vec<u8>>, VmError>328 fn vm_add_fs(&mut self, fs_cfg: FsConfig) -> Result<Option<Vec<u8>>, VmError>;
329
vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> Result<Option<Vec<u8>>, VmError>330 fn vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> Result<Option<Vec<u8>>, VmError>;
331
vm_add_net(&mut self, net_cfg: NetConfig) -> Result<Option<Vec<u8>>, VmError>332 fn vm_add_net(&mut self, net_cfg: NetConfig) -> Result<Option<Vec<u8>>, VmError>;
333
vm_add_vdpa(&mut self, vdpa_cfg: VdpaConfig) -> Result<Option<Vec<u8>>, VmError>334 fn vm_add_vdpa(&mut self, vdpa_cfg: VdpaConfig) -> Result<Option<Vec<u8>>, VmError>;
335
vm_add_vsock(&mut self, vsock_cfg: VsockConfig) -> Result<Option<Vec<u8>>, VmError>336 fn vm_add_vsock(&mut self, vsock_cfg: VsockConfig) -> Result<Option<Vec<u8>>, VmError>;
337
vm_counters(&mut self) -> Result<Option<Vec<u8>>, VmError>338 fn vm_counters(&mut self) -> Result<Option<Vec<u8>>, VmError>;
339
vm_power_button(&mut self) -> Result<(), VmError>340 fn vm_power_button(&mut self) -> Result<(), VmError>;
341
vm_receive_migration( &mut self, receive_data_migration: VmReceiveMigrationData, ) -> Result<(), MigratableError>342 fn vm_receive_migration(
343 &mut self,
344 receive_data_migration: VmReceiveMigrationData,
345 ) -> Result<(), MigratableError>;
346
vm_send_migration( &mut self, send_data_migration: VmSendMigrationData, ) -> Result<(), MigratableError>347 fn vm_send_migration(
348 &mut self,
349 send_data_migration: VmSendMigrationData,
350 ) -> Result<(), MigratableError>;
351
vm_nmi(&mut self) -> Result<(), VmError>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
get_response<Action: ApiAction>( action: &Action, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Action::RequestBody, ) -> ApiResult<ApiResponsePayload>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
get_response_body<Action: ApiAction<ResponseBody = Option<Body>>>( action: &Action, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Action::RequestBody, ) -> ApiResult<Option<Body>>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
request(&self, body: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest407 fn request(&self, body: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest;
408
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, config: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest423 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, config: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest460 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, config: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest497 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, config: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest534 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, config: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest571 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, config: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest608 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, config: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest645 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, config: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest682 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest719 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, coredump_data: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest754 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest791 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, config: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest824 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<()>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
request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest863 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest896 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: (), ) -> ApiResult<VmInfoResponse>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
request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest934 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest967 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest1000 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request(&self, data: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest1033 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, remove_device_data: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest1066 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, resize_data: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest1103 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, resize_zone_data: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest1144 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, config: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest1181 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest1218 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request(&self, data: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest1251 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, config: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest1284 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request( &self, config: Self::RequestBody, response_sender: Sender<ApiResponse>, ) -> ApiRequest1321 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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
request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest1358 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: (), ) -> ApiResult<VmmPingResponse>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
request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest1393 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
send(&self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: ()) -> ApiResult<()>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
request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest1423 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
send( &self, api_evt: EventFd, api_sender: Sender<ApiRequest>, data: Self::RequestBody, ) -> ApiResult<Self::ResponseBody>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