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