xref: /aosp_15_r20/external/crosvm/vhost/src/net.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2017 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::OpenOptions;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::marker::PhantomData;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::fs::OpenOptionsExt;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
10*bb4ee6a4SAndroid Build Coastguard Worker 
11*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_with_ref;
12*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
13*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
14*bb4ee6a4SAndroid Build Coastguard Worker use net_util::TapT;
15*bb4ee6a4SAndroid Build Coastguard Worker 
16*bb4ee6a4SAndroid Build Coastguard Worker use super::ioctl_result;
17*bb4ee6a4SAndroid Build Coastguard Worker use super::Error;
18*bb4ee6a4SAndroid Build Coastguard Worker use super::Result;
19*bb4ee6a4SAndroid Build Coastguard Worker use super::Vhost;
20*bb4ee6a4SAndroid Build Coastguard Worker 
21*bb4ee6a4SAndroid Build Coastguard Worker /// Handle to run VHOST_NET ioctls.
22*bb4ee6a4SAndroid Build Coastguard Worker ///
23*bb4ee6a4SAndroid Build Coastguard Worker /// This provides a simple wrapper around a VHOST_NET file descriptor and
24*bb4ee6a4SAndroid Build Coastguard Worker /// methods that safely run ioctls on that file descriptor.
25*bb4ee6a4SAndroid Build Coastguard Worker pub struct Net<T> {
26*bb4ee6a4SAndroid Build Coastguard Worker     // descriptor must be dropped first, which will stop and tear down the
27*bb4ee6a4SAndroid Build Coastguard Worker     // vhost-net worker before GuestMemory can potentially be unmapped.
28*bb4ee6a4SAndroid Build Coastguard Worker     descriptor: File,
29*bb4ee6a4SAndroid Build Coastguard Worker     phantom: PhantomData<T>,
30*bb4ee6a4SAndroid Build Coastguard Worker }
31*bb4ee6a4SAndroid Build Coastguard Worker 
32*bb4ee6a4SAndroid Build Coastguard Worker pub trait NetT<T: TapT>: Vhost + AsRawDescriptor + Send + Sized {
33*bb4ee6a4SAndroid Build Coastguard Worker     /// Create a new NetT instance
new(vhost_net_device_path: &Path) -> Result<Self>34*bb4ee6a4SAndroid Build Coastguard Worker     fn new(vhost_net_device_path: &Path) -> Result<Self>;
35*bb4ee6a4SAndroid Build Coastguard Worker 
36*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the tap file descriptor that will serve as the VHOST_NET backend.
37*bb4ee6a4SAndroid Build Coastguard Worker     /// This will start the vhost worker for the given queue.
38*bb4ee6a4SAndroid Build Coastguard Worker     ///
39*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
40*bb4ee6a4SAndroid Build Coastguard Worker     /// * `queue_index` - Index of the queue to modify.
41*bb4ee6a4SAndroid Build Coastguard Worker     /// * `descriptor` - Tap interface that will be used as the backend.
set_backend(&self, queue_index: usize, descriptor: Option<&T>) -> Result<()>42*bb4ee6a4SAndroid Build Coastguard Worker     fn set_backend(&self, queue_index: usize, descriptor: Option<&T>) -> Result<()>;
43*bb4ee6a4SAndroid Build Coastguard Worker }
44*bb4ee6a4SAndroid Build Coastguard Worker 
45*bb4ee6a4SAndroid Build Coastguard Worker impl<T> NetT<T> for Net<T>
46*bb4ee6a4SAndroid Build Coastguard Worker where
47*bb4ee6a4SAndroid Build Coastguard Worker     T: TapT,
48*bb4ee6a4SAndroid Build Coastguard Worker {
49*bb4ee6a4SAndroid Build Coastguard Worker     /// Opens /dev/vhost-net and holds a file descriptor open for it.
50*bb4ee6a4SAndroid Build Coastguard Worker     ///
51*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
52*bb4ee6a4SAndroid Build Coastguard Worker     /// * `mem` - Guest memory mapping.
new(vhost_net_device_path: &Path) -> Result<Net<T>>53*bb4ee6a4SAndroid Build Coastguard Worker     fn new(vhost_net_device_path: &Path) -> Result<Net<T>> {
54*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Net::<T> {
55*bb4ee6a4SAndroid Build Coastguard Worker             descriptor: OpenOptions::new()
56*bb4ee6a4SAndroid Build Coastguard Worker                 .read(true)
57*bb4ee6a4SAndroid Build Coastguard Worker                 .write(true)
58*bb4ee6a4SAndroid Build Coastguard Worker                 .custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK)
59*bb4ee6a4SAndroid Build Coastguard Worker                 .open(vhost_net_device_path)
60*bb4ee6a4SAndroid Build Coastguard Worker                 .map_err(Error::VhostOpen)?,
61*bb4ee6a4SAndroid Build Coastguard Worker             phantom: PhantomData,
62*bb4ee6a4SAndroid Build Coastguard Worker         })
63*bb4ee6a4SAndroid Build Coastguard Worker     }
64*bb4ee6a4SAndroid Build Coastguard Worker 
set_backend(&self, queue_index: usize, event: Option<&T>) -> Result<()>65*bb4ee6a4SAndroid Build Coastguard Worker     fn set_backend(&self, queue_index: usize, event: Option<&T>) -> Result<()> {
66*bb4ee6a4SAndroid Build Coastguard Worker         let vring_file = virtio_sys::vhost::vhost_vring_file {
67*bb4ee6a4SAndroid Build Coastguard Worker             index: queue_index as u32,
68*bb4ee6a4SAndroid Build Coastguard Worker             fd: event.map_or(-1, |event| event.as_raw_descriptor()),
69*bb4ee6a4SAndroid Build Coastguard Worker         };
70*bb4ee6a4SAndroid Build Coastguard Worker 
71*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
72*bb4ee6a4SAndroid Build Coastguard Worker         // This ioctl is called on a valid vhost_net descriptor and has its
73*bb4ee6a4SAndroid Build Coastguard Worker         // return value checked.
74*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe {
75*bb4ee6a4SAndroid Build Coastguard Worker             ioctl_with_ref(
76*bb4ee6a4SAndroid Build Coastguard Worker                 &self.descriptor,
77*bb4ee6a4SAndroid Build Coastguard Worker                 virtio_sys::VHOST_NET_SET_BACKEND,
78*bb4ee6a4SAndroid Build Coastguard Worker                 &vring_file,
79*bb4ee6a4SAndroid Build Coastguard Worker             )
80*bb4ee6a4SAndroid Build Coastguard Worker         };
81*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
82*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
83*bb4ee6a4SAndroid Build Coastguard Worker         }
84*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
85*bb4ee6a4SAndroid Build Coastguard Worker     }
86*bb4ee6a4SAndroid Build Coastguard Worker }
87*bb4ee6a4SAndroid Build Coastguard Worker 
88*bb4ee6a4SAndroid Build Coastguard Worker impl<T> Vhost for Net<T> {}
89*bb4ee6a4SAndroid Build Coastguard Worker 
90*bb4ee6a4SAndroid Build Coastguard Worker impl<T> AsRawDescriptor for Net<T> {
as_raw_descriptor(&self) -> RawDescriptor91*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptor(&self) -> RawDescriptor {
92*bb4ee6a4SAndroid Build Coastguard Worker         self.descriptor.as_raw_descriptor()
93*bb4ee6a4SAndroid Build Coastguard Worker     }
94*bb4ee6a4SAndroid Build Coastguard Worker }
95*bb4ee6a4SAndroid Build Coastguard Worker 
96*bb4ee6a4SAndroid Build Coastguard Worker pub mod fakes {
97*bb4ee6a4SAndroid Build Coastguard Worker     use std::fs::remove_file;
98*bb4ee6a4SAndroid Build Coastguard Worker     use std::fs::OpenOptions;
99*bb4ee6a4SAndroid Build Coastguard Worker 
100*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
101*bb4ee6a4SAndroid Build Coastguard Worker 
102*bb4ee6a4SAndroid Build Coastguard Worker     const TMP_FILE: &str = "/tmp/crosvm_vhost_test_file";
103*bb4ee6a4SAndroid Build Coastguard Worker 
104*bb4ee6a4SAndroid Build Coastguard Worker     pub struct FakeNet<T> {
105*bb4ee6a4SAndroid Build Coastguard Worker         descriptor: File,
106*bb4ee6a4SAndroid Build Coastguard Worker         phantom: PhantomData<T>,
107*bb4ee6a4SAndroid Build Coastguard Worker     }
108*bb4ee6a4SAndroid Build Coastguard Worker 
109*bb4ee6a4SAndroid Build Coastguard Worker     impl<T> Drop for FakeNet<T> {
drop(&mut self)110*bb4ee6a4SAndroid Build Coastguard Worker         fn drop(&mut self) {
111*bb4ee6a4SAndroid Build Coastguard Worker             let _ = remove_file(TMP_FILE);
112*bb4ee6a4SAndroid Build Coastguard Worker         }
113*bb4ee6a4SAndroid Build Coastguard Worker     }
114*bb4ee6a4SAndroid Build Coastguard Worker 
115*bb4ee6a4SAndroid Build Coastguard Worker     impl<T> NetT<T> for FakeNet<T>
116*bb4ee6a4SAndroid Build Coastguard Worker     where
117*bb4ee6a4SAndroid Build Coastguard Worker         T: TapT,
118*bb4ee6a4SAndroid Build Coastguard Worker     {
new(_vhost_net_device_path: &Path) -> Result<FakeNet<T>>119*bb4ee6a4SAndroid Build Coastguard Worker         fn new(_vhost_net_device_path: &Path) -> Result<FakeNet<T>> {
120*bb4ee6a4SAndroid Build Coastguard Worker             Ok(FakeNet::<T> {
121*bb4ee6a4SAndroid Build Coastguard Worker                 descriptor: OpenOptions::new()
122*bb4ee6a4SAndroid Build Coastguard Worker                     .read(true)
123*bb4ee6a4SAndroid Build Coastguard Worker                     .append(true)
124*bb4ee6a4SAndroid Build Coastguard Worker                     .create(true)
125*bb4ee6a4SAndroid Build Coastguard Worker                     .open(TMP_FILE)
126*bb4ee6a4SAndroid Build Coastguard Worker                     .unwrap(),
127*bb4ee6a4SAndroid Build Coastguard Worker                 phantom: PhantomData,
128*bb4ee6a4SAndroid Build Coastguard Worker             })
129*bb4ee6a4SAndroid Build Coastguard Worker         }
130*bb4ee6a4SAndroid Build Coastguard Worker 
set_backend(&self, _queue_index: usize, _fd: Option<&T>) -> Result<()>131*bb4ee6a4SAndroid Build Coastguard Worker         fn set_backend(&self, _queue_index: usize, _fd: Option<&T>) -> Result<()> {
132*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
133*bb4ee6a4SAndroid Build Coastguard Worker         }
134*bb4ee6a4SAndroid Build Coastguard Worker     }
135*bb4ee6a4SAndroid Build Coastguard Worker 
136*bb4ee6a4SAndroid Build Coastguard Worker     impl<T> Vhost for FakeNet<T> {}
137*bb4ee6a4SAndroid Build Coastguard Worker 
138*bb4ee6a4SAndroid Build Coastguard Worker     impl<T> AsRawDescriptor for FakeNet<T> {
as_raw_descriptor(&self) -> RawDescriptor139*bb4ee6a4SAndroid Build Coastguard Worker         fn as_raw_descriptor(&self) -> RawDescriptor {
140*bb4ee6a4SAndroid Build Coastguard Worker             self.descriptor.as_raw_descriptor()
141*bb4ee6a4SAndroid Build Coastguard Worker         }
142*bb4ee6a4SAndroid Build Coastguard Worker     }
143*bb4ee6a4SAndroid Build Coastguard Worker }
144