xref: /cloud-hypervisor/vmm/src/api/dbus/mod.rs (revision 51002f2bae2b97b4700c07c378995a32426f78a8)
1c016a0d4SOmer Faruk Bayram // Copyright © 2023 Sartura Ltd.
2c016a0d4SOmer Faruk Bayram //
3c016a0d4SOmer Faruk Bayram // SPDX-License-Identifier: Apache-2.0
4c016a0d4SOmer Faruk Bayram //
588a9f799SRob Bradford use std::panic::AssertUnwindSafe;
688a9f799SRob Bradford use std::sync::mpsc::Sender;
788a9f799SRob Bradford use std::sync::Arc;
888a9f799SRob Bradford use std::thread;
988a9f799SRob Bradford 
1088a9f799SRob Bradford use futures::channel::oneshot;
1188a9f799SRob Bradford use futures::{executor, FutureExt};
1288a9f799SRob Bradford use hypervisor::HypervisorType;
1388a9f799SRob Bradford use seccompiler::{apply_filter, SeccompAction};
1488a9f799SRob Bradford use vmm_sys_util::eventfd::EventFd;
15*51002f2bSJinank Jain use zbus::connection::Builder;
1688a9f799SRob Bradford use zbus::fdo::{self, Result};
17*51002f2bSJinank Jain use zbus::interface;
1888a9f799SRob Bradford use zbus::zvariant::Optional;
1988a9f799SRob Bradford 
204ca18c08SAlyssa Ross use super::{ApiAction, ApiRequest};
214ca18c08SAlyssa Ross #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
224ca18c08SAlyssa Ross use crate::api::VmCoredump;
234ca18c08SAlyssa Ross use crate::api::{
244ca18c08SAlyssa Ross     AddDisk, Body, VmAddDevice, VmAddFs, VmAddNet, VmAddPmem, VmAddUserDevice, VmAddVdpa,
254ca18c08SAlyssa Ross     VmAddVsock, VmBoot, VmCounters, VmCreate, VmDelete, VmInfo, VmPause, VmPowerButton, VmReboot,
264ca18c08SAlyssa Ross     VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeZone, VmRestore, VmResume,
274ca18c08SAlyssa Ross     VmSendMigration, VmShutdown, VmSnapshot, VmmPing, VmmShutdown,
284ca18c08SAlyssa Ross };
29a92d8528SOmer Faruk Bayram use crate::seccomp_filters::{get_seccomp_filter, Thread};
3061e57e1cSRuoqing He use crate::{Error as VmmError, NetConfig, Result as VmmResult, VmConfig};
31c016a0d4SOmer Faruk Bayram 
32f00df25dSOmer Faruk Bayram pub type DBusApiShutdownChannels = (oneshot::Sender<()>, oneshot::Receiver<()>);
33f00df25dSOmer Faruk Bayram 
347a458d85SOmer Faruk Bayram pub struct DBusApiOptions {
357a458d85SOmer Faruk Bayram     pub service_name: String,
367a458d85SOmer Faruk Bayram     pub object_path: String,
377a458d85SOmer Faruk Bayram     pub system_bus: bool,
382ed96cd3SOmer Faruk Bayram     pub event_monitor_rx: flume::Receiver<Arc<String>>,
397a458d85SOmer Faruk Bayram }
407a458d85SOmer Faruk Bayram 
41c016a0d4SOmer Faruk Bayram pub struct DBusApi {
42c016a0d4SOmer Faruk Bayram     api_notifier: EventFd,
43c016a0d4SOmer Faruk Bayram     api_sender: futures::lock::Mutex<Sender<ApiRequest>>,
44c016a0d4SOmer Faruk Bayram }
45c016a0d4SOmer Faruk Bayram 
api_error(error: impl std::fmt::Debug + std::fmt::Display) -> fdo::Error46895dc12aSRavi kumar Veeramally fn api_error(error: impl std::fmt::Debug + std::fmt::Display) -> fdo::Error {
47895dc12aSRavi kumar Veeramally     fdo::Error::Failed(format!("{error}"))
48c016a0d4SOmer Faruk Bayram }
49c016a0d4SOmer Faruk Bayram 
50f00df25dSOmer Faruk Bayram // This method is intended to ensure that the DBusApi thread has enough time to
51f00df25dSOmer Faruk Bayram // send a response to the VmmShutdown method call before it is terminated. If
52f00df25dSOmer Faruk Bayram // this step is omitted, the thread may be terminated before it can send a
53f00df25dSOmer Faruk Bayram // response, resulting in an error message stating that the message recipient
54f00df25dSOmer Faruk Bayram // disconnected from the message bus without providing a reply.
dbus_api_graceful_shutdown(ch: DBusApiShutdownChannels)55f00df25dSOmer Faruk Bayram pub fn dbus_api_graceful_shutdown(ch: DBusApiShutdownChannels) {
56f00df25dSOmer Faruk Bayram     let (send_shutdown, mut recv_done) = ch;
57f00df25dSOmer Faruk Bayram 
58f00df25dSOmer Faruk Bayram     // send the shutdown signal and return
59f00df25dSOmer Faruk Bayram     // if it errors out
60f00df25dSOmer Faruk Bayram     if send_shutdown.send(()).is_err() {
61f00df25dSOmer Faruk Bayram         return;
62f00df25dSOmer Faruk Bayram     }
63f00df25dSOmer Faruk Bayram 
64f00df25dSOmer Faruk Bayram     // loop until `recv_err` errors out
65f00df25dSOmer Faruk Bayram     // or as long as the return value indicates
66f00df25dSOmer Faruk Bayram     // "immediately stale" (None)
67f00df25dSOmer Faruk Bayram     while let Ok(None) = recv_done.try_recv() {}
68f00df25dSOmer Faruk Bayram }
69f00df25dSOmer Faruk Bayram 
70c016a0d4SOmer Faruk Bayram impl DBusApi {
new(api_notifier: EventFd, api_sender: Sender<ApiRequest>) -> Self71c016a0d4SOmer Faruk Bayram     pub fn new(api_notifier: EventFd, api_sender: Sender<ApiRequest>) -> Self {
72c016a0d4SOmer Faruk Bayram         Self {
73c016a0d4SOmer Faruk Bayram             api_notifier,
74c016a0d4SOmer Faruk Bayram             api_sender: futures::lock::Mutex::new(api_sender),
75c016a0d4SOmer Faruk Bayram         }
76c016a0d4SOmer Faruk Bayram     }
77c016a0d4SOmer Faruk Bayram 
clone_api_sender(&self) -> Sender<ApiRequest>78c016a0d4SOmer Faruk Bayram     async fn clone_api_sender(&self) -> Sender<ApiRequest> {
79c016a0d4SOmer Faruk Bayram         // lock the async mutex, clone the `Sender` and then immediately
80c016a0d4SOmer Faruk Bayram         // drop the MutexGuard so that other tasks can clone the
81c016a0d4SOmer Faruk Bayram         // `Sender` as well
82c016a0d4SOmer Faruk Bayram         self.api_sender.lock().await.clone()
83c016a0d4SOmer Faruk Bayram     }
84c016a0d4SOmer Faruk Bayram 
clone_api_notifier(&self) -> Result<EventFd>85c016a0d4SOmer Faruk Bayram     fn clone_api_notifier(&self) -> Result<EventFd> {
86c016a0d4SOmer Faruk Bayram         self.api_notifier
87c016a0d4SOmer Faruk Bayram             .try_clone()
88c016a0d4SOmer Faruk Bayram             .map_err(|err| fdo::Error::IOError(format!("{err:?}")))
89c016a0d4SOmer Faruk Bayram     }
90c016a0d4SOmer Faruk Bayram 
vm_action<Action: ApiAction<ResponseBody = Option<Body>>>( &self, action: &'static Action, body: Action::RequestBody, ) -> Result<Optional<String>>914ca18c08SAlyssa Ross     async fn vm_action<Action: ApiAction<ResponseBody = Option<Body>>>(
924ca18c08SAlyssa Ross         &self,
934ca18c08SAlyssa Ross         action: &'static Action,
944ca18c08SAlyssa Ross         body: Action::RequestBody,
954ca18c08SAlyssa Ross     ) -> Result<Optional<String>> {
96c016a0d4SOmer Faruk Bayram         let api_sender = self.clone_api_sender().await;
97c016a0d4SOmer Faruk Bayram         let api_notifier = self.clone_api_notifier()?;
98c016a0d4SOmer Faruk Bayram 
994ca18c08SAlyssa Ross         let result = blocking::unblock(move || action.send(api_notifier, api_sender, body))
100c016a0d4SOmer Faruk Bayram             .await
101c016a0d4SOmer Faruk Bayram             .map_err(api_error)?
102c016a0d4SOmer Faruk Bayram             // We're using `from_utf8_lossy` here to not deal with the
103c016a0d4SOmer Faruk Bayram             // error case of `from_utf8` as we know that `b.body` is valid JSON.
104c016a0d4SOmer Faruk Bayram             .map(|b| String::from_utf8_lossy(&b.body).to_string());
105c016a0d4SOmer Faruk Bayram 
106c016a0d4SOmer Faruk Bayram         Ok(result.into())
107c016a0d4SOmer Faruk Bayram     }
108c016a0d4SOmer Faruk Bayram }
109c016a0d4SOmer Faruk Bayram 
110036e7e37SOmer Faruk Bayram #[interface(name = "org.cloudhypervisor.DBusApi1")]
111c016a0d4SOmer Faruk Bayram impl DBusApi {
vmm_ping(&self) -> Result<String>112c016a0d4SOmer Faruk Bayram     async fn vmm_ping(&self) -> Result<String> {
113c016a0d4SOmer Faruk Bayram         let api_sender = self.clone_api_sender().await;
114c016a0d4SOmer Faruk Bayram         let api_notifier = self.clone_api_notifier()?;
115c016a0d4SOmer Faruk Bayram 
1164ca18c08SAlyssa Ross         let result = blocking::unblock(move || VmmPing.send(api_notifier, api_sender, ()))
117c016a0d4SOmer Faruk Bayram             .await
118c016a0d4SOmer Faruk Bayram             .map_err(api_error)?;
119c016a0d4SOmer Faruk Bayram         serde_json::to_string(&result).map_err(api_error)
120c016a0d4SOmer Faruk Bayram     }
121c016a0d4SOmer Faruk Bayram 
vmm_shutdown(&self) -> Result<()>122c016a0d4SOmer Faruk Bayram     async fn vmm_shutdown(&self) -> Result<()> {
123c016a0d4SOmer Faruk Bayram         let api_sender = self.clone_api_sender().await;
124c016a0d4SOmer Faruk Bayram         let api_notifier = self.clone_api_notifier()?;
125c016a0d4SOmer Faruk Bayram 
1264ca18c08SAlyssa Ross         blocking::unblock(move || VmmShutdown.send(api_notifier, api_sender, ()))
127c016a0d4SOmer Faruk Bayram             .await
128c016a0d4SOmer Faruk Bayram             .map_err(api_error)
129c016a0d4SOmer Faruk Bayram     }
130c016a0d4SOmer Faruk Bayram 
vm_add_device(&self, device_config: String) -> Result<Optional<String>>131c016a0d4SOmer Faruk Bayram     async fn vm_add_device(&self, device_config: String) -> Result<Optional<String>> {
13205cc5f59SAlyssa Ross         let device_config = serde_json::from_str(&device_config).map_err(api_error)?;
1334ca18c08SAlyssa Ross         self.vm_action(&VmAddDevice, device_config).await
134c016a0d4SOmer Faruk Bayram     }
135c016a0d4SOmer Faruk Bayram 
vm_add_disk(&self, disk_config: String) -> Result<Optional<String>>136c016a0d4SOmer Faruk Bayram     async fn vm_add_disk(&self, disk_config: String) -> Result<Optional<String>> {
13705cc5f59SAlyssa Ross         let disk_config = serde_json::from_str(&disk_config).map_err(api_error)?;
1384ca18c08SAlyssa Ross         self.vm_action(&AddDisk, disk_config).await
139c016a0d4SOmer Faruk Bayram     }
140c016a0d4SOmer Faruk Bayram 
vm_add_fs(&self, fs_config: String) -> Result<Optional<String>>141c016a0d4SOmer Faruk Bayram     async fn vm_add_fs(&self, fs_config: String) -> Result<Optional<String>> {
14205cc5f59SAlyssa Ross         let fs_config = serde_json::from_str(&fs_config).map_err(api_error)?;
1434ca18c08SAlyssa Ross         self.vm_action(&VmAddFs, fs_config).await
144c016a0d4SOmer Faruk Bayram     }
145c016a0d4SOmer Faruk Bayram 
vm_add_net(&self, net_config: String) -> Result<Optional<String>>146c016a0d4SOmer Faruk Bayram     async fn vm_add_net(&self, net_config: String) -> Result<Optional<String>> {
14705cc5f59SAlyssa Ross         let mut net_config: NetConfig = serde_json::from_str(&net_config).map_err(api_error)?;
14805cc5f59SAlyssa Ross         if net_config.fds.is_some() {
14905cc5f59SAlyssa Ross             warn!("Ignoring FDs sent via the D-Bus request body");
15005cc5f59SAlyssa Ross             net_config.fds = None;
15105cc5f59SAlyssa Ross         }
1524ca18c08SAlyssa Ross         self.vm_action(&VmAddNet, net_config).await
153c016a0d4SOmer Faruk Bayram     }
154c016a0d4SOmer Faruk Bayram 
vm_add_pmem(&self, pmem_config: String) -> Result<Optional<String>>155c016a0d4SOmer Faruk Bayram     async fn vm_add_pmem(&self, pmem_config: String) -> Result<Optional<String>> {
15605cc5f59SAlyssa Ross         let pmem_config = serde_json::from_str(&pmem_config).map_err(api_error)?;
1574ca18c08SAlyssa Ross         self.vm_action(&VmAddPmem, pmem_config).await
158c016a0d4SOmer Faruk Bayram     }
159c016a0d4SOmer Faruk Bayram 
vm_add_user_device(&self, vm_add_user_device: String) -> Result<Optional<String>>160c016a0d4SOmer Faruk Bayram     async fn vm_add_user_device(&self, vm_add_user_device: String) -> Result<Optional<String>> {
16105cc5f59SAlyssa Ross         let vm_add_user_device = serde_json::from_str(&vm_add_user_device).map_err(api_error)?;
1624ca18c08SAlyssa Ross         self.vm_action(&VmAddUserDevice, vm_add_user_device).await
163c016a0d4SOmer Faruk Bayram     }
164c016a0d4SOmer Faruk Bayram 
vm_add_vdpa(&self, vdpa_config: String) -> Result<Optional<String>>165c016a0d4SOmer Faruk Bayram     async fn vm_add_vdpa(&self, vdpa_config: String) -> Result<Optional<String>> {
16605cc5f59SAlyssa Ross         let vdpa_config = serde_json::from_str(&vdpa_config).map_err(api_error)?;
1674ca18c08SAlyssa Ross         self.vm_action(&VmAddVdpa, vdpa_config).await
168c016a0d4SOmer Faruk Bayram     }
169c016a0d4SOmer Faruk Bayram 
vm_add_vsock(&self, vsock_config: String) -> Result<Optional<String>>170c016a0d4SOmer Faruk Bayram     async fn vm_add_vsock(&self, vsock_config: String) -> Result<Optional<String>> {
17105cc5f59SAlyssa Ross         let vsock_config = serde_json::from_str(&vsock_config).map_err(api_error)?;
1724ca18c08SAlyssa Ross         self.vm_action(&VmAddVsock, vsock_config).await
173c016a0d4SOmer Faruk Bayram     }
174c016a0d4SOmer Faruk Bayram 
vm_boot(&self) -> Result<()>175c016a0d4SOmer Faruk Bayram     async fn vm_boot(&self) -> Result<()> {
1764ca18c08SAlyssa Ross         self.vm_action(&VmBoot, ()).await.map(|_| ())
177c016a0d4SOmer Faruk Bayram     }
178c016a0d4SOmer Faruk Bayram 
179c016a0d4SOmer Faruk Bayram     #[allow(unused_variables)]
180c016a0d4SOmer Faruk Bayram     // zbus doesn't support cfg attributes on interface methods
181c016a0d4SOmer Faruk Bayram     // as a workaround, we make the *call to the internal API* conditionally
182c016a0d4SOmer Faruk Bayram     // compile and return an error on unsupported platforms.
vm_coredump(&self, vm_coredump_data: String) -> Result<()>183c016a0d4SOmer Faruk Bayram     async fn vm_coredump(&self, vm_coredump_data: String) -> Result<()> {
184c016a0d4SOmer Faruk Bayram         #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
185c016a0d4SOmer Faruk Bayram         {
18605cc5f59SAlyssa Ross             let vm_coredump_data = serde_json::from_str(&vm_coredump_data).map_err(api_error)?;
1874ca18c08SAlyssa Ross             self.vm_action(&VmCoredump, vm_coredump_data)
188c016a0d4SOmer Faruk Bayram                 .await
189c016a0d4SOmer Faruk Bayram                 .map(|_| ())
190c016a0d4SOmer Faruk Bayram         }
191c016a0d4SOmer Faruk Bayram 
192c016a0d4SOmer Faruk Bayram         #[cfg(not(all(target_arch = "x86_64", feature = "guest_debug")))]
193c016a0d4SOmer Faruk Bayram         Err(api_error(
194c016a0d4SOmer Faruk Bayram             "VmCoredump only works on x86_64 with the `guest_debug` feature enabled",
195c016a0d4SOmer Faruk Bayram         ))
196c016a0d4SOmer Faruk Bayram     }
197c016a0d4SOmer Faruk Bayram 
vm_counters(&self) -> Result<Optional<String>>198c016a0d4SOmer Faruk Bayram     async fn vm_counters(&self) -> Result<Optional<String>> {
1994ca18c08SAlyssa Ross         self.vm_action(&VmCounters, ()).await
200c016a0d4SOmer Faruk Bayram     }
201c016a0d4SOmer Faruk Bayram 
vm_create(&self, vm_config: String) -> Result<()>202c016a0d4SOmer Faruk Bayram     async fn vm_create(&self, vm_config: String) -> Result<()> {
203c016a0d4SOmer Faruk Bayram         let api_sender = self.clone_api_sender().await;
204c016a0d4SOmer Faruk Bayram         let api_notifier = self.clone_api_notifier()?;
205c016a0d4SOmer Faruk Bayram 
206cc9899e0SSongqian Li         let mut vm_config: Box<VmConfig> = serde_json::from_str(&vm_config).map_err(api_error)?;
207fba0b5f9SAlyssa Ross 
208fba0b5f9SAlyssa Ross         if let Some(ref mut nets) = vm_config.net {
209fba0b5f9SAlyssa Ross             if nets.iter().any(|net| net.fds.is_some()) {
210fba0b5f9SAlyssa Ross                 warn!("Ignoring FDs sent via the D-Bus request body");
211fba0b5f9SAlyssa Ross             }
212fba0b5f9SAlyssa Ross             for net in nets {
213fba0b5f9SAlyssa Ross                 net.fds = None;
214fba0b5f9SAlyssa Ross             }
215fba0b5f9SAlyssa Ross         }
216fba0b5f9SAlyssa Ross 
217cc9899e0SSongqian Li         blocking::unblock(move || VmCreate.send(api_notifier, api_sender, vm_config))
218c016a0d4SOmer Faruk Bayram             .await
219c016a0d4SOmer Faruk Bayram             .map_err(api_error)?;
220c016a0d4SOmer Faruk Bayram 
221c016a0d4SOmer Faruk Bayram         Ok(())
222c016a0d4SOmer Faruk Bayram     }
223c016a0d4SOmer Faruk Bayram 
vm_delete(&self) -> Result<()>224c016a0d4SOmer Faruk Bayram     async fn vm_delete(&self) -> Result<()> {
2254ca18c08SAlyssa Ross         self.vm_action(&VmDelete, ()).await.map(|_| ())
226c016a0d4SOmer Faruk Bayram     }
227c016a0d4SOmer Faruk Bayram 
vm_info(&self) -> Result<String>228c016a0d4SOmer Faruk Bayram     async fn vm_info(&self) -> Result<String> {
229c016a0d4SOmer Faruk Bayram         let api_sender = self.clone_api_sender().await;
230c016a0d4SOmer Faruk Bayram         let api_notifier = self.clone_api_notifier()?;
231c016a0d4SOmer Faruk Bayram 
2324ca18c08SAlyssa Ross         let result = blocking::unblock(move || VmInfo.send(api_notifier, api_sender, ()))
233c016a0d4SOmer Faruk Bayram             .await
234c016a0d4SOmer Faruk Bayram             .map_err(api_error)?;
235c016a0d4SOmer Faruk Bayram         serde_json::to_string(&result).map_err(api_error)
236c016a0d4SOmer Faruk Bayram     }
237c016a0d4SOmer Faruk Bayram 
vm_pause(&self) -> Result<()>238c016a0d4SOmer Faruk Bayram     async fn vm_pause(&self) -> Result<()> {
2394ca18c08SAlyssa Ross         self.vm_action(&VmPause, ()).await.map(|_| ())
240c016a0d4SOmer Faruk Bayram     }
241c016a0d4SOmer Faruk Bayram 
vm_power_button(&self) -> Result<()>242c016a0d4SOmer Faruk Bayram     async fn vm_power_button(&self) -> Result<()> {
2434ca18c08SAlyssa Ross         self.vm_action(&VmPowerButton, ()).await.map(|_| ())
244c016a0d4SOmer Faruk Bayram     }
245c016a0d4SOmer Faruk Bayram 
vm_reboot(&self) -> Result<()>246c016a0d4SOmer Faruk Bayram     async fn vm_reboot(&self) -> Result<()> {
2474ca18c08SAlyssa Ross         self.vm_action(&VmReboot, ()).await.map(|_| ())
248c016a0d4SOmer Faruk Bayram     }
249c016a0d4SOmer Faruk Bayram 
vm_remove_device(&self, vm_remove_device: String) -> Result<()>250c016a0d4SOmer Faruk Bayram     async fn vm_remove_device(&self, vm_remove_device: String) -> Result<()> {
25105cc5f59SAlyssa Ross         let vm_remove_device = serde_json::from_str(&vm_remove_device).map_err(api_error)?;
2524ca18c08SAlyssa Ross         self.vm_action(&VmRemoveDevice, vm_remove_device)
253c016a0d4SOmer Faruk Bayram             .await
254c016a0d4SOmer Faruk Bayram             .map(|_| ())
255c016a0d4SOmer Faruk Bayram     }
256c016a0d4SOmer Faruk Bayram 
vm_resize(&self, vm_resize: String) -> Result<()>257c016a0d4SOmer Faruk Bayram     async fn vm_resize(&self, vm_resize: String) -> Result<()> {
25805cc5f59SAlyssa Ross         let vm_resize = serde_json::from_str(&vm_resize).map_err(api_error)?;
2594ca18c08SAlyssa Ross         self.vm_action(&VmResize, vm_resize).await.map(|_| ())
260c016a0d4SOmer Faruk Bayram     }
261c016a0d4SOmer Faruk Bayram 
vm_resize_zone(&self, vm_resize_zone: String) -> Result<()>262c016a0d4SOmer Faruk Bayram     async fn vm_resize_zone(&self, vm_resize_zone: String) -> Result<()> {
26305cc5f59SAlyssa Ross         let vm_resize_zone = serde_json::from_str(&vm_resize_zone).map_err(api_error)?;
2644ca18c08SAlyssa Ross         self.vm_action(&VmResizeZone, vm_resize_zone)
265c016a0d4SOmer Faruk Bayram             .await
266c016a0d4SOmer Faruk Bayram             .map(|_| ())
267c016a0d4SOmer Faruk Bayram     }
268c016a0d4SOmer Faruk Bayram 
vm_restore(&self, restore_config: String) -> Result<()>269c016a0d4SOmer Faruk Bayram     async fn vm_restore(&self, restore_config: String) -> Result<()> {
27005cc5f59SAlyssa Ross         let restore_config = serde_json::from_str(&restore_config).map_err(api_error)?;
2714ca18c08SAlyssa Ross         self.vm_action(&VmRestore, restore_config).await.map(|_| ())
272c016a0d4SOmer Faruk Bayram     }
273c016a0d4SOmer Faruk Bayram 
vm_receive_migration(&self, receive_migration_data: String) -> Result<()>274c016a0d4SOmer Faruk Bayram     async fn vm_receive_migration(&self, receive_migration_data: String) -> Result<()> {
275c016a0d4SOmer Faruk Bayram         let receive_migration_data =
27605cc5f59SAlyssa Ross             serde_json::from_str(&receive_migration_data).map_err(api_error)?;
2774ca18c08SAlyssa Ross         self.vm_action(&VmReceiveMigration, receive_migration_data)
278c016a0d4SOmer Faruk Bayram             .await
279c016a0d4SOmer Faruk Bayram             .map(|_| ())
280c016a0d4SOmer Faruk Bayram     }
281c016a0d4SOmer Faruk Bayram 
vm_send_migration(&self, send_migration_data: String) -> Result<()>282c016a0d4SOmer Faruk Bayram     async fn vm_send_migration(&self, send_migration_data: String) -> Result<()> {
28305cc5f59SAlyssa Ross         let send_migration_data = serde_json::from_str(&send_migration_data).map_err(api_error)?;
2844ca18c08SAlyssa Ross         self.vm_action(&VmSendMigration, send_migration_data)
285c016a0d4SOmer Faruk Bayram             .await
286c016a0d4SOmer Faruk Bayram             .map(|_| ())
287c016a0d4SOmer Faruk Bayram     }
288c016a0d4SOmer Faruk Bayram 
vm_resume(&self) -> Result<()>289c016a0d4SOmer Faruk Bayram     async fn vm_resume(&self) -> Result<()> {
2904ca18c08SAlyssa Ross         self.vm_action(&VmResume, ()).await.map(|_| ())
291c016a0d4SOmer Faruk Bayram     }
292c016a0d4SOmer Faruk Bayram 
vm_shutdown(&self) -> Result<()>293c016a0d4SOmer Faruk Bayram     async fn vm_shutdown(&self) -> Result<()> {
2944ca18c08SAlyssa Ross         self.vm_action(&VmShutdown, ()).await.map(|_| ())
295c016a0d4SOmer Faruk Bayram     }
296c016a0d4SOmer Faruk Bayram 
vm_snapshot(&self, vm_snapshot_config: String) -> Result<()>297c016a0d4SOmer Faruk Bayram     async fn vm_snapshot(&self, vm_snapshot_config: String) -> Result<()> {
29805cc5f59SAlyssa Ross         let vm_snapshot_config = serde_json::from_str(&vm_snapshot_config).map_err(api_error)?;
2994ca18c08SAlyssa Ross         self.vm_action(&VmSnapshot, vm_snapshot_config)
300c016a0d4SOmer Faruk Bayram             .await
301c016a0d4SOmer Faruk Bayram             .map(|_| ())
302c016a0d4SOmer Faruk Bayram     }
3032ed96cd3SOmer Faruk Bayram 
304036e7e37SOmer Faruk Bayram     // implementation of this function is provided by the `#[zbus(signal)]` macro call
305036e7e37SOmer Faruk Bayram     #[zbus(signal)]
event( ctxt: &zbus::object_server::SignalEmitter<'_>, event: Arc<String>, ) -> zbus::Result<()>306*51002f2bSJinank Jain     async fn event(
307*51002f2bSJinank Jain         ctxt: &zbus::object_server::SignalEmitter<'_>,
308*51002f2bSJinank Jain         event: Arc<String>,
309*51002f2bSJinank Jain     ) -> zbus::Result<()>;
310c016a0d4SOmer Faruk Bayram }
311c016a0d4SOmer Faruk Bayram 
start_dbus_thread( dbus_options: DBusApiOptions, api_notifier: EventFd, api_sender: Sender<ApiRequest>, seccomp_action: &SeccompAction, exit_evt: EventFd, hypervisor_type: HypervisorType, ) -> VmmResult<(thread::JoinHandle<VmmResult<()>>, DBusApiShutdownChannels)>312c016a0d4SOmer Faruk Bayram pub fn start_dbus_thread(
3137a458d85SOmer Faruk Bayram     dbus_options: DBusApiOptions,
314c016a0d4SOmer Faruk Bayram     api_notifier: EventFd,
315c016a0d4SOmer Faruk Bayram     api_sender: Sender<ApiRequest>,
316a92d8528SOmer Faruk Bayram     seccomp_action: &SeccompAction,
317a92d8528SOmer Faruk Bayram     exit_evt: EventFd,
318a92d8528SOmer Faruk Bayram     hypervisor_type: HypervisorType,
319a92d8528SOmer Faruk Bayram ) -> VmmResult<(thread::JoinHandle<VmmResult<()>>, DBusApiShutdownChannels)> {
320c016a0d4SOmer Faruk Bayram     let dbus_iface = DBusApi::new(api_notifier, api_sender);
3212ed96cd3SOmer Faruk Bayram     let (connection, iface_ref) = executor::block_on(async move {
3227a458d85SOmer Faruk Bayram         let conn_builder = if dbus_options.system_bus {
323*51002f2bSJinank Jain             Builder::system()?
3247a458d85SOmer Faruk Bayram         } else {
325*51002f2bSJinank Jain             Builder::session()?
3267a458d85SOmer Faruk Bayram         };
3277a458d85SOmer Faruk Bayram 
3282ed96cd3SOmer Faruk Bayram         let conn = conn_builder
329c016a0d4SOmer Faruk Bayram             .internal_executor(false)
3307a458d85SOmer Faruk Bayram             .name(dbus_options.service_name)?
3312ed96cd3SOmer Faruk Bayram             .serve_at(dbus_options.object_path.as_str(), dbus_iface)?
332c016a0d4SOmer Faruk Bayram             .build()
3332ed96cd3SOmer Faruk Bayram             .await?;
3342ed96cd3SOmer Faruk Bayram 
3352ed96cd3SOmer Faruk Bayram         let iface_ref = conn
3362ed96cd3SOmer Faruk Bayram             .object_server()
3372ed96cd3SOmer Faruk Bayram             .interface::<_, DBusApi>(dbus_options.object_path)
3382ed96cd3SOmer Faruk Bayram             .await?;
3392ed96cd3SOmer Faruk Bayram 
3402ed96cd3SOmer Faruk Bayram         Ok((conn, iface_ref))
341c016a0d4SOmer Faruk Bayram     })
342c016a0d4SOmer Faruk Bayram     .map_err(VmmError::CreateDBusSession)?;
343c016a0d4SOmer Faruk Bayram 
344f00df25dSOmer Faruk Bayram     let (send_shutdown, recv_shutdown) = oneshot::channel::<()>();
345f00df25dSOmer Faruk Bayram     let (send_done, recv_done) = oneshot::channel::<()>();
346f00df25dSOmer Faruk Bayram 
347a92d8528SOmer Faruk Bayram     // Retrieve seccomp filter for API thread
348a92d8528SOmer Faruk Bayram     let api_seccomp_filter = get_seccomp_filter(seccomp_action, Thread::DBusApi, hypervisor_type)
349a92d8528SOmer Faruk Bayram         .map_err(VmmError::CreateSeccompFilter)?;
350a92d8528SOmer Faruk Bayram 
351f00df25dSOmer Faruk Bayram     let thread_join_handle = thread::Builder::new()
352c016a0d4SOmer Faruk Bayram         .name("dbus-thread".to_string())
353c016a0d4SOmer Faruk Bayram         .spawn(move || {
354a92d8528SOmer Faruk Bayram             // Apply seccomp filter for API thread.
355a92d8528SOmer Faruk Bayram             if !api_seccomp_filter.is_empty() {
356a92d8528SOmer Faruk Bayram                 apply_filter(&api_seccomp_filter)
357a92d8528SOmer Faruk Bayram                     .map_err(VmmError::ApplySeccompFilter)
358a92d8528SOmer Faruk Bayram                     .map_err(|e| {
359a92d8528SOmer Faruk Bayram                         error!("Error applying seccomp filter: {:?}", e);
360a92d8528SOmer Faruk Bayram                         exit_evt.write(1).ok();
361a92d8528SOmer Faruk Bayram                         e
362a92d8528SOmer Faruk Bayram                     })?;
363a92d8528SOmer Faruk Bayram             }
364a92d8528SOmer Faruk Bayram 
365a92d8528SOmer Faruk Bayram             std::panic::catch_unwind(AssertUnwindSafe(move || {
366c016a0d4SOmer Faruk Bayram                 executor::block_on(async move {
367f00df25dSOmer Faruk Bayram                     let recv_shutdown = recv_shutdown.fuse();
368f00df25dSOmer Faruk Bayram                     let executor_tick = futures::future::Fuse::terminated();
369f00df25dSOmer Faruk Bayram                     futures::pin_mut!(recv_shutdown, executor_tick);
370f00df25dSOmer Faruk Bayram                     executor_tick.set(connection.executor().tick().fuse());
371f00df25dSOmer Faruk Bayram 
372c016a0d4SOmer Faruk Bayram                     loop {
373f00df25dSOmer Faruk Bayram                         futures::select! {
374f00df25dSOmer Faruk Bayram                             _ = executor_tick => executor_tick.set(connection.executor().tick().fuse()),
375f00df25dSOmer Faruk Bayram                             _ = recv_shutdown => {
376f00df25dSOmer Faruk Bayram                                 send_done.send(()).ok();
377f00df25dSOmer Faruk Bayram                                 break;
378f00df25dSOmer Faruk Bayram                             },
3792ed96cd3SOmer Faruk Bayram                             ret = dbus_options.event_monitor_rx.recv_async() => {
3802ed96cd3SOmer Faruk Bayram                                 if let Ok(event) = ret {
381*51002f2bSJinank Jain                                     DBusApi::event(iface_ref.signal_emitter(), event).await.ok();
3822ed96cd3SOmer Faruk Bayram                                 }
3832ed96cd3SOmer Faruk Bayram                             }
384f00df25dSOmer Faruk Bayram                         }
385c016a0d4SOmer Faruk Bayram                     }
386c016a0d4SOmer Faruk Bayram                 })
387a92d8528SOmer Faruk Bayram             }))
388a92d8528SOmer Faruk Bayram             .map_err(|_| {
389a92d8528SOmer Faruk Bayram                 error!("dbus-api thread panicked");
390a92d8528SOmer Faruk Bayram                 exit_evt.write(1).ok()
391a92d8528SOmer Faruk Bayram             })
392a92d8528SOmer Faruk Bayram             .ok();
393a92d8528SOmer Faruk Bayram 
394a92d8528SOmer Faruk Bayram             Ok(())
395c016a0d4SOmer Faruk Bayram         })
396f00df25dSOmer Faruk Bayram         .map_err(VmmError::DBusThreadSpawn)?;
397f00df25dSOmer Faruk Bayram 
398f00df25dSOmer Faruk Bayram     Ok((thread_join_handle, (send_shutdown, recv_done)))
399c016a0d4SOmer Faruk Bayram }
400