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