• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #[cfg_attr(windows, path = "windows/net.rs")]
6 #[cfg_attr(not(windows), path = "unix/net.rs")]
7 mod net;
8 
9 // Only Windows exposes public symbols, but the module level use is used on both platforms.
10 #[allow(unused_imports)]
11 pub use net::*;
12 
13 use std::sync::Arc;
14 
15 use anyhow::{anyhow, bail, Context};
16 use base::{error, Event};
17 use cros_async::{EventAsync, Executor, IntoAsync};
18 use data_model::DataInit;
19 use futures::future::AbortHandle;
20 use net_util::TapT;
21 use once_cell::sync::OnceCell;
22 use sync::Mutex;
23 use vm_memory::GuestMemory;
24 use vmm_vhost::message::VhostUserProtocolFeatures;
25 
26 use crate::virtio;
27 use crate::virtio::net::{build_config, process_ctrl, process_tx, virtio_features_to_tap_offload};
28 use crate::virtio::vhost::user::device::handler::{Doorbell, VhostUserBackend};
29 
30 thread_local! {
31     pub(crate) static NET_EXECUTOR: OnceCell<Executor> = OnceCell::new();
32 }
33 
34 // TODO(b/188947559): Come up with better way to include these constants. Compiler errors happen
35 // if they are kept in the trait.
36 const MAX_QUEUE_NUM: usize = 3; /* rx, tx, ctrl */
37 const MAX_VRING_LEN: u16 = 256;
38 
run_tx_queue<T: TapT>( mut queue: virtio::Queue, mem: GuestMemory, mut tap: T, doorbell: Arc<Mutex<Doorbell>>, kick_evt: EventAsync, )39 async fn run_tx_queue<T: TapT>(
40     mut queue: virtio::Queue,
41     mem: GuestMemory,
42     mut tap: T,
43     doorbell: Arc<Mutex<Doorbell>>,
44     kick_evt: EventAsync,
45 ) {
46     loop {
47         if let Err(e) = kick_evt.next_val().await {
48             error!("Failed to read kick event for tx queue: {}", e);
49             break;
50         }
51 
52         process_tx(&doorbell, &mut queue, &mem, &mut tap);
53     }
54 }
55 
run_ctrl_queue<T: TapT>( mut queue: virtio::Queue, mem: GuestMemory, mut tap: T, doorbell: Arc<Mutex<Doorbell>>, kick_evt: EventAsync, acked_features: u64, vq_pairs: u16, )56 async fn run_ctrl_queue<T: TapT>(
57     mut queue: virtio::Queue,
58     mem: GuestMemory,
59     mut tap: T,
60     doorbell: Arc<Mutex<Doorbell>>,
61     kick_evt: EventAsync,
62     acked_features: u64,
63     vq_pairs: u16,
64 ) {
65     loop {
66         if let Err(e) = kick_evt.next_val().await {
67             error!("Failed to read kick event for tx queue: {}", e);
68             break;
69         }
70 
71         if let Err(e) = process_ctrl(
72             &doorbell,
73             &mut queue,
74             &mem,
75             &mut tap,
76             acked_features,
77             vq_pairs,
78         ) {
79             error!("Failed to process ctrl queue: {}", e);
80             break;
81         }
82     }
83 }
84 
85 pub(crate) struct NetBackend<T: TapT + IntoAsync> {
86     tap: T,
87     avail_features: u64,
88     acked_features: u64,
89     acked_protocol_features: VhostUserProtocolFeatures,
90     workers: [Option<AbortHandle>; MAX_QUEUE_NUM],
91     mtu: u16,
92     #[cfg(all(windows, feature = "slirp"))]
93     slirp_kill_event: Event,
94 }
95 
96 impl<T: 'static> NetBackend<T>
97 where
98     T: TapT + IntoAsync,
99 {
max_vq_pairs() -> usize100     fn max_vq_pairs() -> usize {
101         Self::MAX_QUEUE_NUM / 2
102     }
103 }
104 
105 impl<T: 'static> VhostUserBackend for NetBackend<T>
106 where
107     T: TapT + IntoAsync,
108 {
109     const MAX_QUEUE_NUM: usize = MAX_QUEUE_NUM; /* rx, tx, ctrl */
110     const MAX_VRING_LEN: u16 = MAX_VRING_LEN;
111 
112     type Error = anyhow::Error;
113 
features(&self) -> u64114     fn features(&self) -> u64 {
115         self.avail_features
116     }
117 
ack_features(&mut self, value: u64) -> anyhow::Result<()>118     fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
119         let unrequested_features = value & !self.avail_features;
120         if unrequested_features != 0 {
121             bail!("invalid features are given: {:#x}", unrequested_features);
122         }
123 
124         self.acked_features |= value;
125 
126         self.tap
127             .set_offload(virtio_features_to_tap_offload(self.acked_features))
128             .context("failed to set tap offload to match features")?;
129 
130         Ok(())
131     }
132 
acked_features(&self) -> u64133     fn acked_features(&self) -> u64 {
134         self.acked_features
135     }
136 
protocol_features(&self) -> VhostUserProtocolFeatures137     fn protocol_features(&self) -> VhostUserProtocolFeatures {
138         VhostUserProtocolFeatures::CONFIG
139     }
140 
ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()>141     fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> {
142         let features = VhostUserProtocolFeatures::from_bits(features)
143             .ok_or_else(|| anyhow!("invalid protocol features are given: {:#x}", features))?;
144         let supported = self.protocol_features();
145         self.acked_protocol_features = features & supported;
146         Ok(())
147     }
148 
acked_protocol_features(&self) -> u64149     fn acked_protocol_features(&self) -> u64 {
150         self.acked_protocol_features.bits()
151     }
152 
read_config(&self, offset: u64, data: &mut [u8])153     fn read_config(&self, offset: u64, data: &mut [u8]) {
154         let config_space = build_config(Self::max_vq_pairs() as u16, self.mtu);
155         virtio::copy_config(data, 0, config_space.as_slice(), offset);
156     }
157 
reset(&mut self)158     fn reset(&mut self) {}
159 
start_queue( &mut self, idx: usize, queue: virtio::Queue, mem: GuestMemory, doorbell: Arc<Mutex<Doorbell>>, kick_evt: Event, ) -> anyhow::Result<()>160     fn start_queue(
161         &mut self,
162         idx: usize,
163         queue: virtio::Queue,
164         mem: GuestMemory,
165         doorbell: Arc<Mutex<Doorbell>>,
166         kick_evt: Event,
167     ) -> anyhow::Result<()> {
168         net::start_queue(self, idx, queue, mem, doorbell, kick_evt)
169     }
170 
stop_queue(&mut self, idx: usize)171     fn stop_queue(&mut self, idx: usize) {
172         if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
173             handle.abort();
174         }
175     }
176 }
177 
178 /// Starts a vhost-user net device.
run_net_device(program_name: &str, args: &[&str]) -> anyhow::Result<()>179 pub fn run_net_device(program_name: &str, args: &[&str]) -> anyhow::Result<()> {
180     start_device(program_name, args)
181 }
182