• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 
7 use anyhow::anyhow;
8 use anyhow::Context;
9 use base::error;
10 use base::AsRawDescriptors;
11 use cros_async::EventAsync;
12 use cros_async::Executor;
13 use cros_async::IntoAsync;
14 use cros_async::TaskHandle;
15 use futures::channel::oneshot;
16 use futures::pin_mut;
17 use futures::select_biased;
18 use futures::FutureExt;
19 use net_util::TapT;
20 use once_cell::sync::OnceCell;
21 use serde::Deserialize;
22 use serde::Serialize;
23 use snapshot::AnySnapshot;
24 pub use sys::start_device as run_net_device;
25 pub use sys::Options;
26 use vm_memory::GuestMemory;
27 use vmm_vhost::message::VhostUserProtocolFeatures;
28 use zerocopy::IntoBytes;
29 
30 use crate::virtio;
31 use crate::virtio::net::build_config;
32 use crate::virtio::net::process_ctrl;
33 use crate::virtio::net::process_tx;
34 use crate::virtio::net::virtio_features_to_tap_offload;
35 use crate::virtio::vhost::user::device::handler::DeviceRequestHandler;
36 use crate::virtio::vhost::user::device::handler::Error as DeviceError;
37 use crate::virtio::vhost::user::device::handler::VhostUserDevice;
38 use crate::virtio::vhost::user::VhostUserDeviceBuilder;
39 use crate::virtio::Queue;
40 
41 thread_local! {
42     pub(crate) static NET_EXECUTOR: OnceCell<Executor> = const { OnceCell::new() };
43 }
44 
45 // TODO(b/188947559): Come up with better way to include these constants. Compiler errors happen
46 // if they are kept in the trait.
47 const MAX_QUEUE_NUM: usize = 3; /* rx, tx, ctrl */
48 
run_tx_queue<T: TapT>( mut queue: Queue, mut tap: T, kick_evt: EventAsync, mut stop_rx: oneshot::Receiver<()>, ) -> Queue49 async fn run_tx_queue<T: TapT>(
50     mut queue: Queue,
51     mut tap: T,
52     kick_evt: EventAsync,
53     mut stop_rx: oneshot::Receiver<()>,
54 ) -> Queue {
55     let kick_evt_future = kick_evt.next_val().fuse();
56     pin_mut!(kick_evt_future);
57     loop {
58         select_biased! {
59             kick = kick_evt_future => {
60                 kick_evt_future.set(kick_evt.next_val().fuse());
61                 if let Err(e) = kick {
62                     error!("Failed to read kick event for tx queue: {}", e);
63                     break;
64                 }
65             }
66             _ = stop_rx => {
67                 break;
68             }
69         }
70 
71         process_tx(&mut queue, &mut tap);
72     }
73     queue
74 }
75 
run_ctrl_queue<T: TapT>( mut queue: Queue, mut tap: T, kick_evt: EventAsync, acked_features: u64, vq_pairs: u16, mut stop_rx: oneshot::Receiver<()>, ) -> Queue76 async fn run_ctrl_queue<T: TapT>(
77     mut queue: Queue,
78     mut tap: T,
79     kick_evt: EventAsync,
80     acked_features: u64,
81     vq_pairs: u16,
82     mut stop_rx: oneshot::Receiver<()>,
83 ) -> Queue {
84     let kick_evt_future = kick_evt.next_val().fuse();
85     pin_mut!(kick_evt_future);
86     loop {
87         select_biased! {
88             kick = kick_evt_future => {
89                 kick_evt_future.set(kick_evt.next_val().fuse());
90                 if let Err(e) = kick {
91                     error!("Failed to read kick event for tx queue: {}", e);
92                     break;
93                 }
94             }
95             _ = stop_rx => {
96                 break;
97             }
98         }
99 
100         if let Err(e) = process_ctrl(&mut queue, &mut tap, acked_features, vq_pairs) {
101             error!("Failed to process ctrl queue: {}", e);
102             break;
103         }
104     }
105     queue
106 }
107 
108 pub struct NetBackend<T: TapT + IntoAsync> {
109     tap: T,
110     avail_features: u64,
111     acked_features: u64,
112     mtu: u16,
113     #[cfg(all(windows, feature = "slirp"))]
114     slirp_kill_event: base::Event,
115     workers: [Option<(TaskHandle<Queue>, oneshot::Sender<()>)>; MAX_QUEUE_NUM],
116 }
117 
118 #[derive(Serialize, Deserialize)]
119 pub struct NetBackendSnapshot {
120     acked_feature: u64,
121 }
122 
123 impl<T: 'static> NetBackend<T>
124 where
125     T: TapT + IntoAsync,
126 {
max_vq_pairs() -> usize127     fn max_vq_pairs() -> usize {
128         MAX_QUEUE_NUM / 2
129     }
130 }
131 
132 impl<T: 'static> AsRawDescriptors for NetBackend<T>
133 where
134     T: TapT + IntoAsync + AsRawDescriptors,
135 {
as_raw_descriptors(&self) -> Vec<base::RawDescriptor>136     fn as_raw_descriptors(&self) -> Vec<base::RawDescriptor> {
137         self.tap.as_raw_descriptors()
138     }
139 }
140 
141 impl<T: 'static> VhostUserDevice for NetBackend<T>
142 where
143     T: TapT + IntoAsync,
144 {
max_queue_num(&self) -> usize145     fn max_queue_num(&self) -> usize {
146         MAX_QUEUE_NUM
147     }
148 
features(&self) -> u64149     fn features(&self) -> u64 {
150         self.avail_features
151     }
152 
ack_features(&mut self, value: u64) -> anyhow::Result<()>153     fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
154         self.acked_features |= value;
155 
156         self.tap
157             .set_offload(virtio_features_to_tap_offload(self.acked_features))
158             .context("failed to set tap offload to match features")?;
159 
160         Ok(())
161     }
162 
protocol_features(&self) -> VhostUserProtocolFeatures163     fn protocol_features(&self) -> VhostUserProtocolFeatures {
164         VhostUserProtocolFeatures::CONFIG | VhostUserProtocolFeatures::DEVICE_STATE
165     }
166 
read_config(&self, offset: u64, data: &mut [u8])167     fn read_config(&self, offset: u64, data: &mut [u8]) {
168         let config_space = build_config(Self::max_vq_pairs() as u16, self.mtu, None);
169         virtio::copy_config(data, 0, config_space.as_bytes(), offset);
170     }
171 
reset(&mut self)172     fn reset(&mut self) {}
173 
start_queue( &mut self, idx: usize, queue: virtio::Queue, mem: GuestMemory, ) -> anyhow::Result<()>174     fn start_queue(
175         &mut self,
176         idx: usize,
177         queue: virtio::Queue,
178         mem: GuestMemory,
179     ) -> anyhow::Result<()> {
180         sys::start_queue(self, idx, queue, mem)
181     }
182 
stop_queue(&mut self, idx: usize) -> anyhow::Result<virtio::Queue>183     fn stop_queue(&mut self, idx: usize) -> anyhow::Result<virtio::Queue> {
184         if let Some((task, stop_tx)) = self.workers.get_mut(idx).and_then(Option::take) {
185             if stop_tx.send(()).is_err() {
186                 return Err(anyhow!("Failed to request stop for net queue future"));
187             }
188 
189             // Wait for queue_task to be aborted.
190             let queue = NET_EXECUTOR
191                 .with(|ex| {
192                     let ex = ex.get().expect("Executor not initialized");
193                     ex.run_until(task)
194                 })
195                 .context("Failed to resolve queue worker future")?;
196 
197             Ok(queue)
198         } else {
199             Err(anyhow::Error::new(DeviceError::WorkerNotFound))
200         }
201     }
202 
enter_suspended_state(&mut self) -> anyhow::Result<()>203     fn enter_suspended_state(&mut self) -> anyhow::Result<()> {
204         // No non-queue workers.
205         Ok(())
206     }
207 
snapshot(&mut self) -> anyhow::Result<AnySnapshot>208     fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
209         AnySnapshot::to_any(NetBackendSnapshot {
210             acked_feature: self.acked_features,
211         })
212         .context("Failed to serialize NetBackendSnapshot")
213     }
214 
restore(&mut self, data: AnySnapshot) -> anyhow::Result<()>215     fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
216         let net_backend_snapshot: NetBackendSnapshot =
217             AnySnapshot::from_any(data).context("Failed to deserialize NetBackendSnapshot")?;
218         self.acked_features = net_backend_snapshot.acked_feature;
219         Ok(())
220     }
221 }
222 
223 impl<T> VhostUserDeviceBuilder for NetBackend<T>
224 where
225     T: TapT + IntoAsync + 'static,
226 {
build(self: Box<Self>, ex: &Executor) -> anyhow::Result<Box<dyn vmm_vhost::Backend>>227     fn build(self: Box<Self>, ex: &Executor) -> anyhow::Result<Box<dyn vmm_vhost::Backend>> {
228         NET_EXECUTOR.with(|thread_ex| {
229             let _ = thread_ex.set(ex.clone());
230         });
231         let handler = DeviceRequestHandler::new(*self);
232 
233         Ok(Box::new(handler))
234     }
235 }
236