1use std::fs::File;
6use std::fs::OpenOptions;
7use std::marker::PhantomData;
8use std::os::unix::fs::OpenOptionsExt;
9use std::path::Path;
10
11use base::ioctl_with_ref;
12use base::AsRawDescriptor;
13use base::RawDescriptor;
14use net_util::TapT;
15
16use super::ioctl_result;
17use super::Error;
18use super::Result;
19use super::Vhost;
20
21pub struct Net<T> {
26 descriptor: File,
29 phantom: PhantomData<T>,
30}
31
32pub trait NetT<T: TapT>: Vhost + AsRawDescriptor + Send + Sized {
33 fn new(vhost_net_device_path: &Path) -> Result<Self>;
35
36 fn set_backend(&self, queue_index: usize, descriptor: Option<&T>) -> Result<()>;
43}
44
45impl<T> NetT<T> for Net<T>
46where
47 T: TapT,
48{
49 fn new(vhost_net_device_path: &Path) -> Result<Net<T>> {
54 Ok(Net::<T> {
55 descriptor: OpenOptions::new()
56 .read(true)
57 .write(true)
58 .custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK)
59 .open(vhost_net_device_path)
60 .map_err(Error::VhostOpen)?,
61 phantom: PhantomData,
62 })
63 }
64
65 fn set_backend(&self, queue_index: usize, event: Option<&T>) -> Result<()> {
66 let vring_file = virtio_sys::vhost::vhost_vring_file {
67 index: queue_index as u32,
68 fd: event.map_or(-1, |event| event.as_raw_descriptor()),
69 };
70
71 let ret = unsafe {
75 ioctl_with_ref(
76 &self.descriptor,
77 virtio_sys::VHOST_NET_SET_BACKEND,
78 &vring_file,
79 )
80 };
81 if ret < 0 {
82 return ioctl_result();
83 }
84 Ok(())
85 }
86}
87
88impl<T> Vhost for Net<T> {}
89
90impl<T> AsRawDescriptor for Net<T> {
91 fn as_raw_descriptor(&self) -> RawDescriptor {
92 self.descriptor.as_raw_descriptor()
93 }
94}
95
96pub mod fakes {
97 use std::fs::remove_file;
98 use std::fs::OpenOptions;
99
100 use super::*;
101
102 const TMP_FILE: &str = "/tmp/crosvm_vhost_test_file";
103
104 pub struct FakeNet<T> {
105 descriptor: File,
106 phantom: PhantomData<T>,
107 }
108
109 impl<T> Drop for FakeNet<T> {
110 fn drop(&mut self) {
111 let _ = remove_file(TMP_FILE);
112 }
113 }
114
115 impl<T> NetT<T> for FakeNet<T>
116 where
117 T: TapT,
118 {
119 fn new(_vhost_net_device_path: &Path) -> Result<FakeNet<T>> {
120 Ok(FakeNet::<T> {
121 descriptor: OpenOptions::new()
122 .read(true)
123 .append(true)
124 .create(true)
125 .open(TMP_FILE)
126 .unwrap(),
127 phantom: PhantomData,
128 })
129 }
130
131 fn set_backend(&self, _queue_index: usize, _fd: Option<&T>) -> Result<()> {
132 Ok(())
133 }
134 }
135
136 impl<T> Vhost for FakeNet<T> {}
137
138 impl<T> AsRawDescriptor for FakeNet<T> {
139 fn as_raw_descriptor(&self) -> RawDescriptor {
140 self.descriptor.as_raw_descriptor()
141 }
142 }
143}