devices/virtio/vhost_user_backend/
connection.rs

1// Copyright 2022 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5pub mod sys;
6use std::any::Any;
7use std::pin::Pin;
8
9use cros_async::Executor;
10use futures::Future;
11use futures::FutureExt;
12
13use crate::virtio::vhost_user_backend::handler::DeviceRequestHandler;
14use crate::virtio::vhost_user_backend::handler::VhostUserDevice;
15use crate::virtio::vhost_user_backend::VhostUserDeviceBuilder;
16use crate::virtio::vhost_user_backend::VhostUserListener;
17use crate::virtio::vhost_user_backend::VhostUserStream;
18
19pub enum BackendConnection {
20    Listener(VhostUserListener),
21    Stream(VhostUserStream),
22}
23
24/// Trait that the platform-specific type `VhostUserConnection` needs to implement. It contains all
25/// the methods that are ok to call from non-platform specific code.
26pub trait VhostUserConnectionTrait {
27    /// Take and return resources owned by the parent process in case of a incoming fork.
28    ///
29    /// This method needs to be called only if you are going to use the connection in a jailed child
30    /// process. In this case, the connection will belong to the child and the parent will drop it,
31    /// but the child may lack the rights to drop some resources created at construction time. One
32    /// such example is the socket file of a regular vhost-user device, that cannot be dropped by
33    /// the child unless it gets extra permissions.
34    ///
35    /// This method returns an opaque object that, upon being dropped, will free these resources.
36    /// That way, the child process does not need extra rights to clear them, and the parent can
37    /// drop the connection after forking and just need to keep that object alive until the child
38    /// exits to do housekeeping properly.
39    ///
40    /// The default implementation returns nothing as that's what most connection would need anyway.
41    fn take_parent_process_resources(&mut self) -> Option<Box<dyn Any>> {
42        None
43    }
44
45    /// Returns a `Future` that processes requests for `handler`. The future exits when the
46    /// front-end side disconnects or an error occurs.
47    fn run_req_handler<'e>(
48        self,
49        handler: &'e mut (dyn vmm_vhost::Backend + 'e),
50        ex: &'e Executor,
51    ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>>;
52
53    /// Returns a `Future` that will process requests from `backend` when polled. The future exits
54    /// when the front-end side disconnects or an error occurs.
55    ///
56    /// This is a legacy way to run devices - prefer `run_device`.
57    fn run_backend<'e>(
58        self,
59        backend: impl VhostUserDevice + 'e,
60        ex: &'e Executor,
61    ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>>
62    where
63        Self: Sized + 'e,
64    {
65        async move {
66            let mut handler = DeviceRequestHandler::new(backend);
67            self.run_req_handler(&mut handler, ex).await
68        }
69        .boxed_local()
70    }
71
72    /// Start processing requests for a `VhostUserDevice` on `connection`. Returns when the
73    /// front-end side disconnects or an error occurs.
74    fn run_device(self, ex: Executor, device: Box<dyn VhostUserDeviceBuilder>) -> anyhow::Result<()>
75    where
76        Self: Sized,
77    {
78        let mut handler = device.build(&ex).unwrap();
79        ex.run_until(self.run_req_handler(handler.as_mut(), &ex))?
80    }
81}