xref: /cloud-hypervisor/vmm/src/api/mod.rs (revision 7d7bfb2034001d4cb15df2ddc56d2d350c8da30f)
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::{
38     DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, RestoreConfig, UserDeviceConfig,
39     VdpaConfig, 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 vDPA device could not be added to the VM.
138     VmAddVdpa(VmError),
139 
140     /// The vsock device could not be added to the VM.
141     VmAddVsock(VmError),
142 
143     /// Error starting migration receiever
144     VmReceiveMigration(MigratableError),
145 
146     /// Error starting migration sender
147     VmSendMigration(MigratableError),
148 
149     /// Error triggering power button
150     VmPowerButton(VmError),
151 }
152 pub type ApiResult<T> = std::result::Result<T, ApiError>;
153 
154 #[derive(Clone, Deserialize, Serialize)]
155 pub struct VmInfo {
156     pub config: Arc<Mutex<VmConfig>>,
157     pub state: VmState,
158     pub memory_actual_size: u64,
159     pub device_tree: Option<Arc<Mutex<DeviceTree>>>,
160 }
161 
162 #[derive(Clone, Deserialize, Serialize)]
163 pub struct VmmPingResponse {
164     pub version: String,
165 }
166 
167 #[derive(Clone, Deserialize, Serialize, Default, Debug)]
168 pub struct VmResizeData {
169     pub desired_vcpus: Option<u8>,
170     pub desired_ram: Option<u64>,
171     pub desired_balloon: Option<u64>,
172 }
173 
174 #[derive(Clone, Deserialize, Serialize, Default, Debug)]
175 pub struct VmResizeZoneData {
176     pub id: String,
177     pub desired_ram: u64,
178 }
179 
180 #[derive(Clone, Deserialize, Serialize, Default, Debug)]
181 pub struct VmRemoveDeviceData {
182     pub id: String,
183 }
184 
185 #[derive(Clone, Deserialize, Serialize, Default, Debug)]
186 pub struct VmSnapshotConfig {
187     /// The snapshot destination URL
188     pub destination_url: String,
189 }
190 
191 #[derive(Clone, Deserialize, Serialize, Default, Debug)]
192 pub struct VmReceiveMigrationData {
193     /// URL for the reception of migration state
194     pub receiver_url: String,
195 }
196 
197 #[derive(Clone, Deserialize, Serialize, Default, Debug)]
198 pub struct VmSendMigrationData {
199     /// URL to migrate the VM to
200     pub destination_url: String,
201     /// Send memory across socket without copying
202     #[serde(default)]
203     pub local: bool,
204 }
205 
206 pub enum ApiResponsePayload {
207     /// No data is sent on the channel.
208     Empty,
209 
210     /// Virtual machine information
211     VmInfo(VmInfo),
212 
213     /// Vmm ping response
214     VmmPing(VmmPingResponse),
215 
216     /// Vm action response
217     VmAction(Option<Vec<u8>>),
218 }
219 
220 /// This is the response sent by the VMM API server through the mpsc channel.
221 pub type ApiResponse = std::result::Result<ApiResponsePayload, ApiError>;
222 
223 #[allow(clippy::large_enum_variant)]
224 #[derive(Debug)]
225 pub enum ApiRequest {
226     /// Create the virtual machine. This request payload is a VM configuration
227     /// (VmConfig).
228     /// If the VMM API server could not create the VM, it will send a VmCreate
229     /// error back.
230     VmCreate(Arc<Mutex<VmConfig>>, Sender<ApiResponse>),
231 
232     /// Boot the previously created virtual machine.
233     /// If the VM was not previously created, the VMM API server will send a
234     /// VmBoot error back.
235     VmBoot(Sender<ApiResponse>),
236 
237     /// Delete the previously created virtual machine.
238     /// If the VM was not previously created, the VMM API server will send a
239     /// VmDelete error back.
240     /// If the VM is booted, we shut it down first.
241     VmDelete(Sender<ApiResponse>),
242 
243     /// Request the VM information.
244     VmInfo(Sender<ApiResponse>),
245 
246     /// Request the VMM API server status
247     VmmPing(Sender<ApiResponse>),
248 
249     /// Pause a VM.
250     VmPause(Sender<ApiResponse>),
251 
252     /// Resume a VM.
253     VmResume(Sender<ApiResponse>),
254 
255     /// Get counters for a VM.
256     VmCounters(Sender<ApiResponse>),
257 
258     /// Shut the previously booted virtual machine down.
259     /// If the VM was not previously booted or created, the VMM API server
260     /// will send a VmShutdown error back.
261     VmShutdown(Sender<ApiResponse>),
262 
263     /// Reboot the previously booted virtual machine.
264     /// If the VM was not previously booted or created, the VMM API server
265     /// will send a VmReboot error back.
266     VmReboot(Sender<ApiResponse>),
267 
268     /// Shut the VMM down.
269     /// This will shutdown and delete the current VM, if any, and then exit the
270     /// VMM process.
271     VmmShutdown(Sender<ApiResponse>),
272 
273     /// Resize the VM.
274     VmResize(Arc<VmResizeData>, Sender<ApiResponse>),
275 
276     /// Resize the memory zone.
277     VmResizeZone(Arc<VmResizeZoneData>, Sender<ApiResponse>),
278 
279     /// Add a device to the VM.
280     VmAddDevice(Arc<DeviceConfig>, Sender<ApiResponse>),
281 
282     /// Add a user device to the VM.
283     VmAddUserDevice(Arc<UserDeviceConfig>, Sender<ApiResponse>),
284 
285     /// Remove a device from the VM.
286     VmRemoveDevice(Arc<VmRemoveDeviceData>, Sender<ApiResponse>),
287 
288     /// Add a disk to the VM.
289     VmAddDisk(Arc<DiskConfig>, Sender<ApiResponse>),
290 
291     /// Add a fs to the VM.
292     VmAddFs(Arc<FsConfig>, Sender<ApiResponse>),
293 
294     /// Add a pmem device to the VM.
295     VmAddPmem(Arc<PmemConfig>, Sender<ApiResponse>),
296 
297     /// Add a network device to the VM.
298     VmAddNet(Arc<NetConfig>, Sender<ApiResponse>),
299 
300     /// Add a vDPA device to the VM.
301     VmAddVdpa(Arc<VdpaConfig>, Sender<ApiResponse>),
302 
303     /// Add a vsock device to the VM.
304     VmAddVsock(Arc<VsockConfig>, Sender<ApiResponse>),
305 
306     /// Take a VM snapshot
307     VmSnapshot(Arc<VmSnapshotConfig>, Sender<ApiResponse>),
308 
309     /// Restore from a VM snapshot
310     VmRestore(Arc<RestoreConfig>, Sender<ApiResponse>),
311 
312     /// Incoming migration
313     VmReceiveMigration(Arc<VmReceiveMigrationData>, Sender<ApiResponse>),
314 
315     /// Outgoing migration
316     VmSendMigration(Arc<VmSendMigrationData>, Sender<ApiResponse>),
317 
318     // Trigger power button
319     VmPowerButton(Sender<ApiResponse>),
320 }
321 
322 pub fn vm_create(
323     api_evt: EventFd,
324     api_sender: Sender<ApiRequest>,
325     config: Arc<Mutex<VmConfig>>,
326 ) -> ApiResult<()> {
327     let (response_sender, response_receiver) = channel();
328 
329     // Send the VM creation request.
330     api_sender
331         .send(ApiRequest::VmCreate(config, response_sender))
332         .map_err(ApiError::RequestSend)?;
333     api_evt.write(1).map_err(ApiError::EventFdWrite)?;
334 
335     response_receiver.recv().map_err(ApiError::ResponseRecv)??;
336 
337     Ok(())
338 }
339 
340 /// Represents a VM related action.
341 /// This is mostly used to factorize code between VM routines
342 /// that only differ by the IPC command they send.
343 pub enum VmAction {
344     /// Boot a VM
345     Boot,
346 
347     /// Delete a VM
348     Delete,
349 
350     /// Shut a VM down
351     Shutdown,
352 
353     /// Reboot a VM
354     Reboot,
355 
356     /// Pause a VM
357     Pause,
358 
359     /// Resume a VM
360     Resume,
361 
362     /// Return VM counters
363     Counters,
364 
365     /// Add VFIO device
366     AddDevice(Arc<DeviceConfig>),
367 
368     /// Add disk
369     AddDisk(Arc<DiskConfig>),
370 
371     /// Add filesystem
372     AddFs(Arc<FsConfig>),
373 
374     /// Add pmem
375     AddPmem(Arc<PmemConfig>),
376 
377     /// Add network
378     AddNet(Arc<NetConfig>),
379 
380     /// Add vdpa
381     AddVdpa(Arc<VdpaConfig>),
382 
383     /// Add vsock
384     AddVsock(Arc<VsockConfig>),
385 
386     /// Add user  device
387     AddUserDevice(Arc<UserDeviceConfig>),
388 
389     /// Remove VFIO device
390     RemoveDevice(Arc<VmRemoveDeviceData>),
391 
392     /// Resize VM
393     Resize(Arc<VmResizeData>),
394 
395     /// Resize memory zone
396     ResizeZone(Arc<VmResizeZoneData>),
397 
398     /// Restore VM
399     Restore(Arc<RestoreConfig>),
400 
401     /// Snapshot VM
402     Snapshot(Arc<VmSnapshotConfig>),
403 
404     /// Incoming migration
405     ReceiveMigration(Arc<VmReceiveMigrationData>),
406 
407     /// Outgoing migration
408     SendMigration(Arc<VmSendMigrationData>),
409 
410     /// Power Button for clean shutdown
411     PowerButton,
412 }
413 
414 fn vm_action(
415     api_evt: EventFd,
416     api_sender: Sender<ApiRequest>,
417     action: VmAction,
418 ) -> ApiResult<Option<Body>> {
419     let (response_sender, response_receiver) = channel();
420 
421     use VmAction::*;
422     let request = match action {
423         Boot => ApiRequest::VmBoot(response_sender),
424         Delete => ApiRequest::VmDelete(response_sender),
425         Shutdown => ApiRequest::VmShutdown(response_sender),
426         Reboot => ApiRequest::VmReboot(response_sender),
427         Pause => ApiRequest::VmPause(response_sender),
428         Resume => ApiRequest::VmResume(response_sender),
429         Counters => ApiRequest::VmCounters(response_sender),
430         AddDevice(v) => ApiRequest::VmAddDevice(v, response_sender),
431         AddDisk(v) => ApiRequest::VmAddDisk(v, response_sender),
432         AddFs(v) => ApiRequest::VmAddFs(v, response_sender),
433         AddPmem(v) => ApiRequest::VmAddPmem(v, response_sender),
434         AddNet(v) => ApiRequest::VmAddNet(v, response_sender),
435         AddVdpa(v) => ApiRequest::VmAddVdpa(v, response_sender),
436         AddVsock(v) => ApiRequest::VmAddVsock(v, response_sender),
437         AddUserDevice(v) => ApiRequest::VmAddUserDevice(v, response_sender),
438         RemoveDevice(v) => ApiRequest::VmRemoveDevice(v, response_sender),
439         Resize(v) => ApiRequest::VmResize(v, response_sender),
440         ResizeZone(v) => ApiRequest::VmResizeZone(v, response_sender),
441         Restore(v) => ApiRequest::VmRestore(v, response_sender),
442         Snapshot(v) => ApiRequest::VmSnapshot(v, response_sender),
443         ReceiveMigration(v) => ApiRequest::VmReceiveMigration(v, response_sender),
444         SendMigration(v) => ApiRequest::VmSendMigration(v, response_sender),
445         PowerButton => ApiRequest::VmPowerButton(response_sender),
446     };
447 
448     // Send the VM request.
449     api_sender.send(request).map_err(ApiError::RequestSend)?;
450     api_evt.write(1).map_err(ApiError::EventFdWrite)?;
451 
452     let body = match response_receiver.recv().map_err(ApiError::ResponseRecv)?? {
453         ApiResponsePayload::VmAction(response) => response.map(Body::new),
454         ApiResponsePayload::Empty => None,
455         _ => return Err(ApiError::ResponsePayloadType),
456     };
457 
458     Ok(body)
459 }
460 
461 pub fn vm_boot(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> {
462     vm_action(api_evt, api_sender, VmAction::Boot)
463 }
464 
465 pub fn vm_delete(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> {
466     vm_action(api_evt, api_sender, VmAction::Delete)
467 }
468 
469 pub fn vm_shutdown(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> {
470     vm_action(api_evt, api_sender, VmAction::Shutdown)
471 }
472 
473 pub fn vm_reboot(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> {
474     vm_action(api_evt, api_sender, VmAction::Reboot)
475 }
476 
477 pub fn vm_pause(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> {
478     vm_action(api_evt, api_sender, VmAction::Pause)
479 }
480 
481 pub fn vm_resume(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> {
482     vm_action(api_evt, api_sender, VmAction::Resume)
483 }
484 
485 pub fn vm_counters(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<Option<Body>> {
486     vm_action(api_evt, api_sender, VmAction::Counters)
487 }
488 
489 pub fn vm_power_button(
490     api_evt: EventFd,
491     api_sender: Sender<ApiRequest>,
492 ) -> ApiResult<Option<Body>> {
493     vm_action(api_evt, api_sender, VmAction::PowerButton)
494 }
495 
496 pub fn vm_receive_migration(
497     api_evt: EventFd,
498     api_sender: Sender<ApiRequest>,
499     data: Arc<VmReceiveMigrationData>,
500 ) -> ApiResult<Option<Body>> {
501     vm_action(api_evt, api_sender, VmAction::ReceiveMigration(data))
502 }
503 
504 pub fn vm_send_migration(
505     api_evt: EventFd,
506     api_sender: Sender<ApiRequest>,
507     data: Arc<VmSendMigrationData>,
508 ) -> ApiResult<Option<Body>> {
509     vm_action(api_evt, api_sender, VmAction::SendMigration(data))
510 }
511 
512 pub fn vm_snapshot(
513     api_evt: EventFd,
514     api_sender: Sender<ApiRequest>,
515     data: Arc<VmSnapshotConfig>,
516 ) -> ApiResult<Option<Body>> {
517     vm_action(api_evt, api_sender, VmAction::Snapshot(data))
518 }
519 
520 pub fn vm_restore(
521     api_evt: EventFd,
522     api_sender: Sender<ApiRequest>,
523     data: Arc<RestoreConfig>,
524 ) -> ApiResult<Option<Body>> {
525     vm_action(api_evt, api_sender, VmAction::Restore(data))
526 }
527 
528 pub fn vm_info(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<VmInfo> {
529     let (response_sender, response_receiver) = channel();
530 
531     // Send the VM request.
532     api_sender
533         .send(ApiRequest::VmInfo(response_sender))
534         .map_err(ApiError::RequestSend)?;
535     api_evt.write(1).map_err(ApiError::EventFdWrite)?;
536 
537     let vm_info = response_receiver.recv().map_err(ApiError::ResponseRecv)??;
538 
539     match vm_info {
540         ApiResponsePayload::VmInfo(info) => Ok(info),
541         _ => Err(ApiError::ResponsePayloadType),
542     }
543 }
544 
545 pub fn vmm_ping(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<VmmPingResponse> {
546     let (response_sender, response_receiver) = channel();
547 
548     api_sender
549         .send(ApiRequest::VmmPing(response_sender))
550         .map_err(ApiError::RequestSend)?;
551     api_evt.write(1).map_err(ApiError::EventFdWrite)?;
552 
553     let vmm_pong = response_receiver.recv().map_err(ApiError::ResponseRecv)??;
554 
555     match vmm_pong {
556         ApiResponsePayload::VmmPing(pong) => Ok(pong),
557         _ => Err(ApiError::ResponsePayloadType),
558     }
559 }
560 
561 pub fn vmm_shutdown(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<()> {
562     let (response_sender, response_receiver) = channel();
563 
564     // Send the VMM shutdown request.
565     api_sender
566         .send(ApiRequest::VmmShutdown(response_sender))
567         .map_err(ApiError::RequestSend)?;
568     api_evt.write(1).map_err(ApiError::EventFdWrite)?;
569 
570     response_receiver.recv().map_err(ApiError::ResponseRecv)??;
571 
572     Ok(())
573 }
574 
575 pub fn vm_resize(
576     api_evt: EventFd,
577     api_sender: Sender<ApiRequest>,
578     data: Arc<VmResizeData>,
579 ) -> ApiResult<Option<Body>> {
580     vm_action(api_evt, api_sender, VmAction::Resize(data))
581 }
582 
583 pub fn vm_resize_zone(
584     api_evt: EventFd,
585     api_sender: Sender<ApiRequest>,
586     data: Arc<VmResizeZoneData>,
587 ) -> ApiResult<Option<Body>> {
588     vm_action(api_evt, api_sender, VmAction::ResizeZone(data))
589 }
590 
591 pub fn vm_add_device(
592     api_evt: EventFd,
593     api_sender: Sender<ApiRequest>,
594     data: Arc<DeviceConfig>,
595 ) -> ApiResult<Option<Body>> {
596     vm_action(api_evt, api_sender, VmAction::AddDevice(data))
597 }
598 
599 pub fn vm_add_user_device(
600     api_evt: EventFd,
601     api_sender: Sender<ApiRequest>,
602     data: Arc<UserDeviceConfig>,
603 ) -> ApiResult<Option<Body>> {
604     vm_action(api_evt, api_sender, VmAction::AddUserDevice(data))
605 }
606 
607 pub fn vm_remove_device(
608     api_evt: EventFd,
609     api_sender: Sender<ApiRequest>,
610     data: Arc<VmRemoveDeviceData>,
611 ) -> ApiResult<Option<Body>> {
612     vm_action(api_evt, api_sender, VmAction::RemoveDevice(data))
613 }
614 
615 pub fn vm_add_disk(
616     api_evt: EventFd,
617     api_sender: Sender<ApiRequest>,
618     data: Arc<DiskConfig>,
619 ) -> ApiResult<Option<Body>> {
620     vm_action(api_evt, api_sender, VmAction::AddDisk(data))
621 }
622 
623 pub fn vm_add_fs(
624     api_evt: EventFd,
625     api_sender: Sender<ApiRequest>,
626     data: Arc<FsConfig>,
627 ) -> ApiResult<Option<Body>> {
628     vm_action(api_evt, api_sender, VmAction::AddFs(data))
629 }
630 
631 pub fn vm_add_pmem(
632     api_evt: EventFd,
633     api_sender: Sender<ApiRequest>,
634     data: Arc<PmemConfig>,
635 ) -> ApiResult<Option<Body>> {
636     vm_action(api_evt, api_sender, VmAction::AddPmem(data))
637 }
638 
639 pub fn vm_add_net(
640     api_evt: EventFd,
641     api_sender: Sender<ApiRequest>,
642     data: Arc<NetConfig>,
643 ) -> ApiResult<Option<Body>> {
644     vm_action(api_evt, api_sender, VmAction::AddNet(data))
645 }
646 
647 pub fn vm_add_vdpa(
648     api_evt: EventFd,
649     api_sender: Sender<ApiRequest>,
650     data: Arc<VdpaConfig>,
651 ) -> ApiResult<Option<Body>> {
652     vm_action(api_evt, api_sender, VmAction::AddVdpa(data))
653 }
654 
655 pub fn vm_add_vsock(
656     api_evt: EventFd,
657     api_sender: Sender<ApiRequest>,
658     data: Arc<VsockConfig>,
659 ) -> ApiResult<Option<Body>> {
660     vm_action(api_evt, api_sender, VmAction::AddVsock(data))
661 }
662