• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 pub mod sys;
6 use std::any::Any;
7 use std::pin::Pin;
8 use std::sync::Mutex;
9 
10 use base::RawDescriptor;
11 use cros_async::Executor;
12 use futures::Future;
13 pub use sys::VhostUserListener;
14 use vmm_vhost::VhostUserSlaveReqHandler;
15 
16 use crate::virtio::vhost::user::device::handler::DeviceRequestHandler;
17 use crate::virtio::vhost::user::device::handler::VhostUserBackend;
18 use crate::virtio::vhost::user::device::handler::VhostUserPlatformOps;
19 use crate::virtio::vhost::user::VhostUserDevice;
20 
21 /// Trait that the platform-specific type `VhostUserListener` needs to implement. It contains all
22 /// the methods that are ok to call from non-platform specific code.
23 pub trait VhostUserListenerTrait {
24     /// Creates a VhostUserListener from `path`, which is a platform-specific string describing how
25     /// to establish the vhost-user channel. For instance, it can be a path to a socket.
26     ///
27     /// `max_num_queues` is the maximum number of queues we will supports through this channel.
28     /// `keep_rds` is a vector of `RawDescriptor`s to which the descriptors needed for this listener
29     /// to operate properly will be added if it is `Some()`.
new( path: &str, max_num_queues: usize, keep_rds: Option<&mut Vec<RawDescriptor>>, ) -> anyhow::Result<VhostUserListener>30     fn new(
31         path: &str,
32         max_num_queues: usize,
33         keep_rds: Option<&mut Vec<RawDescriptor>>,
34     ) -> anyhow::Result<VhostUserListener>;
35 
36     /// Take and return resources owned by the parent process in case of a incoming fork.
37     ///
38     /// This method needs to be called only if you are going to use the listener in a jailed child
39     /// process. In this case, the listener will belong to the child and the parent will drop it,
40     /// but the child may lack the rights to drop some resources created at construction time. One
41     /// such example is the socket file of a regular vhost-user device, that cannot be dropped by
42     /// the child unless it gets extra permissions.
43     ///
44     /// This method returns an opaque object that, upon being dropped, will free these resources.
45     /// That way, the child process does not need extra rights to clear them, and the parent can
46     /// drop the listener after forking and just need to keep that object alive until the child
47     /// exits to do housekeeping properly.
48     ///
49     /// The default implementation returns nothing as that's what most listeners would need anyway.
take_parent_process_resources(&mut self) -> Option<Box<dyn Any>>50     fn take_parent_process_resources(&mut self) -> Option<Box<dyn Any>> {
51         None
52     }
53 
54     /// Returns a `Future` that processes requests for a `VhostUserSlaveReqHandler`. The future
55     /// exits when the front-end side disconnects or an error occurs.
56     ///
57     /// The `VhostUserSlaveReqHandler` is built from `handler_builder` after being passed the ops
58     /// that correspond to the kind of transport used for vhost-user.
run_req_handler<'e, F>( self, handler_builder: F, ex: &'e Executor, ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>> where F: FnOnce(Box<dyn VhostUserPlatformOps>) -> Box<dyn VhostUserSlaveReqHandler> + 'e59     fn run_req_handler<'e, F>(
60         self,
61         handler_builder: F,
62         ex: &'e Executor,
63     ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>>
64     where
65         F: FnOnce(Box<dyn VhostUserPlatformOps>) -> Box<dyn VhostUserSlaveReqHandler> + 'e;
66 
67     /// Returns a `Future` that will process requests from `backend` when polled. The future exits
68     /// when the front-end side disconnects or an error occurs.
69     ///
70     /// This is a legacy way to run devices - prefer `run_device`.
run_backend<'e>( self, backend: Box<dyn VhostUserBackend>, ex: &'e Executor, ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>> where Self: Sized,71     fn run_backend<'e>(
72         self,
73         backend: Box<dyn VhostUserBackend>,
74         ex: &'e Executor,
75     ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>>
76     where
77         Self: Sized,
78     {
79         self.run_req_handler(
80             |ops| {
81                 Box::new(Mutex::new(DeviceRequestHandler::new(backend, ops)))
82                     as Box<dyn VhostUserSlaveReqHandler>
83             },
84             ex,
85         )
86     }
87 
88     /// Start processing requests for a `VhostUserDevice` on `listener`. Returns when the front-end
89     /// side disconnects or an error occurs.
run_device(self, ex: Executor, device: Box<dyn VhostUserDevice>) -> anyhow::Result<()> where Self: Sized,90     fn run_device(self, ex: Executor, device: Box<dyn VhostUserDevice>) -> anyhow::Result<()>
91     where
92         Self: Sized,
93     {
94         ex.run_until(self.run_req_handler(|ops| device.into_req_handler(ops, &ex).unwrap(), &ex))?
95     }
96 }
97