xref: /aosp_15_r20/external/crosvm/devices/src/virtio/vhost/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::collections::BTreeMap;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
8*bb4ee6a4SAndroid Build Coastguard Worker 
9*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
10*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
11*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
12*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
13*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
14*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
16*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread;
18*bb4ee6a4SAndroid Build Coastguard Worker use net_util::MacAddress;
19*bb4ee6a4SAndroid Build Coastguard Worker use net_util::TapT;
20*bb4ee6a4SAndroid Build Coastguard Worker use vhost::NetT as VhostNetT;
21*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_config::VIRTIO_F_RING_PACKED;
22*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_net;
23*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
24*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
25*bb4ee6a4SAndroid Build Coastguard Worker 
26*bb4ee6a4SAndroid Build Coastguard Worker use super::control_socket::*;
27*bb4ee6a4SAndroid Build Coastguard Worker use super::worker::Worker;
28*bb4ee6a4SAndroid Build Coastguard Worker use super::Error;
29*bb4ee6a4SAndroid Build Coastguard Worker use super::Result;
30*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::MsixStatus;
31*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::copy_config;
32*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::net::build_config;
33*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::DeviceType;
34*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::Interrupt;
35*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::Queue;
36*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::VirtioDevice;
37*bb4ee6a4SAndroid Build Coastguard Worker use crate::PciAddress;
38*bb4ee6a4SAndroid Build Coastguard Worker 
39*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZE: u16 = 256;
40*bb4ee6a4SAndroid Build Coastguard Worker const NUM_QUEUES: usize = 2;
41*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES];
42*bb4ee6a4SAndroid Build Coastguard Worker 
43*bb4ee6a4SAndroid Build Coastguard Worker pub struct Net<T: TapT + 'static, U: VhostNetT<T> + 'static> {
44*bb4ee6a4SAndroid Build Coastguard Worker     worker_thread: Option<WorkerThread<(Worker<U>, T)>>,
45*bb4ee6a4SAndroid Build Coastguard Worker     tap: Option<T>,
46*bb4ee6a4SAndroid Build Coastguard Worker     guest_mac: Option<[u8; 6]>,
47*bb4ee6a4SAndroid Build Coastguard Worker     vhost_net_handle: Option<U>,
48*bb4ee6a4SAndroid Build Coastguard Worker     vhost_interrupt: Option<Vec<Event>>,
49*bb4ee6a4SAndroid Build Coastguard Worker     avail_features: u64,
50*bb4ee6a4SAndroid Build Coastguard Worker     acked_features: u64,
51*bb4ee6a4SAndroid Build Coastguard Worker     request_tube: Tube,
52*bb4ee6a4SAndroid Build Coastguard Worker     response_tube: Option<Tube>,
53*bb4ee6a4SAndroid Build Coastguard Worker     pci_address: Option<PciAddress>,
54*bb4ee6a4SAndroid Build Coastguard Worker }
55*bb4ee6a4SAndroid Build Coastguard Worker 
56*bb4ee6a4SAndroid Build Coastguard Worker impl<T, U> Net<T, U>
57*bb4ee6a4SAndroid Build Coastguard Worker where
58*bb4ee6a4SAndroid Build Coastguard Worker     T: TapT,
59*bb4ee6a4SAndroid Build Coastguard Worker     U: VhostNetT<T>,
60*bb4ee6a4SAndroid Build Coastguard Worker {
61*bb4ee6a4SAndroid Build Coastguard Worker     /// Creates a new virtio network device from a tap device that has already been
62*bb4ee6a4SAndroid Build Coastguard Worker     /// configured.
new( vhost_net_device_path: &Path, base_features: u64, tap: T, mac_addr: Option<MacAddress>, use_packed_queue: bool, pci_address: Option<PciAddress>, ) -> Result<Net<T, U>>63*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(
64*bb4ee6a4SAndroid Build Coastguard Worker         vhost_net_device_path: &Path,
65*bb4ee6a4SAndroid Build Coastguard Worker         base_features: u64,
66*bb4ee6a4SAndroid Build Coastguard Worker         tap: T,
67*bb4ee6a4SAndroid Build Coastguard Worker         mac_addr: Option<MacAddress>,
68*bb4ee6a4SAndroid Build Coastguard Worker         use_packed_queue: bool,
69*bb4ee6a4SAndroid Build Coastguard Worker         pci_address: Option<PciAddress>,
70*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Net<T, U>> {
71*bb4ee6a4SAndroid Build Coastguard Worker         // Set offload flags to match the virtio features below.
72*bb4ee6a4SAndroid Build Coastguard Worker         tap.set_offload(
73*bb4ee6a4SAndroid Build Coastguard Worker             net_sys::TUN_F_CSUM | net_sys::TUN_F_UFO | net_sys::TUN_F_TSO4 | net_sys::TUN_F_TSO6,
74*bb4ee6a4SAndroid Build Coastguard Worker         )
75*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(Error::TapSetOffload)?;
76*bb4ee6a4SAndroid Build Coastguard Worker 
77*bb4ee6a4SAndroid Build Coastguard Worker         // We declare VIRTIO_NET_F_MRG_RXBUF, so set the vnet hdr size to match.
78*bb4ee6a4SAndroid Build Coastguard Worker         let vnet_hdr_size = mem::size_of::<virtio_net::virtio_net_hdr_mrg_rxbuf>();
79*bb4ee6a4SAndroid Build Coastguard Worker         tap.set_vnet_hdr_size(vnet_hdr_size)
80*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::TapSetVnetHdrSize)?;
81*bb4ee6a4SAndroid Build Coastguard Worker 
82*bb4ee6a4SAndroid Build Coastguard Worker         let vhost_net_handle = U::new(vhost_net_device_path).map_err(Error::VhostOpen)?;
83*bb4ee6a4SAndroid Build Coastguard Worker 
84*bb4ee6a4SAndroid Build Coastguard Worker         let mut avail_features = base_features
85*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
86*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << virtio_net::VIRTIO_NET_F_CSUM
87*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
88*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
89*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
90*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
91*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << virtio_net::VIRTIO_NET_F_MRG_RXBUF;
92*bb4ee6a4SAndroid Build Coastguard Worker 
93*bb4ee6a4SAndroid Build Coastguard Worker         if use_packed_queue {
94*bb4ee6a4SAndroid Build Coastguard Worker             avail_features |= 1 << VIRTIO_F_RING_PACKED;
95*bb4ee6a4SAndroid Build Coastguard Worker         }
96*bb4ee6a4SAndroid Build Coastguard Worker 
97*bb4ee6a4SAndroid Build Coastguard Worker         if mac_addr.is_some() {
98*bb4ee6a4SAndroid Build Coastguard Worker             avail_features |= 1 << virtio_net::VIRTIO_NET_F_MAC;
99*bb4ee6a4SAndroid Build Coastguard Worker         }
100*bb4ee6a4SAndroid Build Coastguard Worker 
101*bb4ee6a4SAndroid Build Coastguard Worker         let mut vhost_interrupt = Vec::new();
102*bb4ee6a4SAndroid Build Coastguard Worker         for _ in 0..NUM_QUEUES {
103*bb4ee6a4SAndroid Build Coastguard Worker             vhost_interrupt.push(Event::new().map_err(Error::VhostIrqCreate)?);
104*bb4ee6a4SAndroid Build Coastguard Worker         }
105*bb4ee6a4SAndroid Build Coastguard Worker 
106*bb4ee6a4SAndroid Build Coastguard Worker         let (request_tube, response_tube) = Tube::pair().map_err(Error::CreateTube)?;
107*bb4ee6a4SAndroid Build Coastguard Worker 
108*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Net {
109*bb4ee6a4SAndroid Build Coastguard Worker             worker_thread: None,
110*bb4ee6a4SAndroid Build Coastguard Worker             tap: Some(tap),
111*bb4ee6a4SAndroid Build Coastguard Worker             guest_mac: mac_addr.map(|mac| mac.octets()),
112*bb4ee6a4SAndroid Build Coastguard Worker             vhost_net_handle: Some(vhost_net_handle),
113*bb4ee6a4SAndroid Build Coastguard Worker             vhost_interrupt: Some(vhost_interrupt),
114*bb4ee6a4SAndroid Build Coastguard Worker             avail_features,
115*bb4ee6a4SAndroid Build Coastguard Worker             acked_features: 0u64,
116*bb4ee6a4SAndroid Build Coastguard Worker             request_tube,
117*bb4ee6a4SAndroid Build Coastguard Worker             response_tube: Some(response_tube),
118*bb4ee6a4SAndroid Build Coastguard Worker             pci_address,
119*bb4ee6a4SAndroid Build Coastguard Worker         })
120*bb4ee6a4SAndroid Build Coastguard Worker     }
121*bb4ee6a4SAndroid Build Coastguard Worker }
122*bb4ee6a4SAndroid Build Coastguard Worker 
123*bb4ee6a4SAndroid Build Coastguard Worker impl<T, U> VirtioDevice for Net<T, U>
124*bb4ee6a4SAndroid Build Coastguard Worker where
125*bb4ee6a4SAndroid Build Coastguard Worker     T: TapT + 'static,
126*bb4ee6a4SAndroid Build Coastguard Worker     U: VhostNetT<T> + 'static,
127*bb4ee6a4SAndroid Build Coastguard Worker {
keep_rds(&self) -> Vec<RawDescriptor>128*bb4ee6a4SAndroid Build Coastguard Worker     fn keep_rds(&self) -> Vec<RawDescriptor> {
129*bb4ee6a4SAndroid Build Coastguard Worker         let mut keep_rds = Vec::new();
130*bb4ee6a4SAndroid Build Coastguard Worker 
131*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(tap) = &self.tap {
132*bb4ee6a4SAndroid Build Coastguard Worker             keep_rds.push(tap.as_raw_descriptor());
133*bb4ee6a4SAndroid Build Coastguard Worker         }
134*bb4ee6a4SAndroid Build Coastguard Worker 
135*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(vhost_net_handle) = &self.vhost_net_handle {
136*bb4ee6a4SAndroid Build Coastguard Worker             keep_rds.push(vhost_net_handle.as_raw_descriptor());
137*bb4ee6a4SAndroid Build Coastguard Worker         }
138*bb4ee6a4SAndroid Build Coastguard Worker 
139*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(vhost_interrupt) = &self.vhost_interrupt {
140*bb4ee6a4SAndroid Build Coastguard Worker             for vhost_int in vhost_interrupt.iter() {
141*bb4ee6a4SAndroid Build Coastguard Worker                 keep_rds.push(vhost_int.as_raw_descriptor());
142*bb4ee6a4SAndroid Build Coastguard Worker             }
143*bb4ee6a4SAndroid Build Coastguard Worker         }
144*bb4ee6a4SAndroid Build Coastguard Worker 
145*bb4ee6a4SAndroid Build Coastguard Worker         keep_rds.push(self.request_tube.as_raw_descriptor());
146*bb4ee6a4SAndroid Build Coastguard Worker 
147*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(response_tube) = &self.response_tube {
148*bb4ee6a4SAndroid Build Coastguard Worker             keep_rds.push(response_tube.as_raw_descriptor());
149*bb4ee6a4SAndroid Build Coastguard Worker         }
150*bb4ee6a4SAndroid Build Coastguard Worker 
151*bb4ee6a4SAndroid Build Coastguard Worker         keep_rds
152*bb4ee6a4SAndroid Build Coastguard Worker     }
153*bb4ee6a4SAndroid Build Coastguard Worker 
device_type(&self) -> DeviceType154*bb4ee6a4SAndroid Build Coastguard Worker     fn device_type(&self) -> DeviceType {
155*bb4ee6a4SAndroid Build Coastguard Worker         DeviceType::Net
156*bb4ee6a4SAndroid Build Coastguard Worker     }
157*bb4ee6a4SAndroid Build Coastguard Worker 
queue_max_sizes(&self) -> &[u16]158*bb4ee6a4SAndroid Build Coastguard Worker     fn queue_max_sizes(&self) -> &[u16] {
159*bb4ee6a4SAndroid Build Coastguard Worker         QUEUE_SIZES
160*bb4ee6a4SAndroid Build Coastguard Worker     }
161*bb4ee6a4SAndroid Build Coastguard Worker 
features(&self) -> u64162*bb4ee6a4SAndroid Build Coastguard Worker     fn features(&self) -> u64 {
163*bb4ee6a4SAndroid Build Coastguard Worker         self.avail_features
164*bb4ee6a4SAndroid Build Coastguard Worker     }
165*bb4ee6a4SAndroid Build Coastguard Worker 
ack_features(&mut self, value: u64)166*bb4ee6a4SAndroid Build Coastguard Worker     fn ack_features(&mut self, value: u64) {
167*bb4ee6a4SAndroid Build Coastguard Worker         let mut v = value;
168*bb4ee6a4SAndroid Build Coastguard Worker 
169*bb4ee6a4SAndroid Build Coastguard Worker         // Check if the guest is ACK'ing a feature that we didn't claim to have.
170*bb4ee6a4SAndroid Build Coastguard Worker         let unrequested_features = v & !self.avail_features;
171*bb4ee6a4SAndroid Build Coastguard Worker         if unrequested_features != 0 {
172*bb4ee6a4SAndroid Build Coastguard Worker             warn!("net: virtio net got unknown feature ack: {:x}", v);
173*bb4ee6a4SAndroid Build Coastguard Worker 
174*bb4ee6a4SAndroid Build Coastguard Worker             // Don't count these features as acked.
175*bb4ee6a4SAndroid Build Coastguard Worker             v &= !unrequested_features;
176*bb4ee6a4SAndroid Build Coastguard Worker         }
177*bb4ee6a4SAndroid Build Coastguard Worker         self.acked_features |= v;
178*bb4ee6a4SAndroid Build Coastguard Worker     }
179*bb4ee6a4SAndroid Build Coastguard Worker 
read_config(&self, offset: u64, data: &mut [u8])180*bb4ee6a4SAndroid Build Coastguard Worker     fn read_config(&self, offset: u64, data: &mut [u8]) {
181*bb4ee6a4SAndroid Build Coastguard Worker         let vq_pairs = QUEUE_SIZES.len() / 2;
182*bb4ee6a4SAndroid Build Coastguard Worker         // VIRTIO_NET_F_MTU is not set.
183*bb4ee6a4SAndroid Build Coastguard Worker         let config_space = build_config(vq_pairs as u16, /* mtu= */ 0, self.guest_mac);
184*bb4ee6a4SAndroid Build Coastguard Worker         copy_config(data, 0, config_space.as_bytes(), offset);
185*bb4ee6a4SAndroid Build Coastguard Worker     }
186*bb4ee6a4SAndroid Build Coastguard Worker 
activate( &mut self, mem: GuestMemory, interrupt: Interrupt, queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>187*bb4ee6a4SAndroid Build Coastguard Worker     fn activate(
188*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
189*bb4ee6a4SAndroid Build Coastguard Worker         mem: GuestMemory,
190*bb4ee6a4SAndroid Build Coastguard Worker         interrupt: Interrupt,
191*bb4ee6a4SAndroid Build Coastguard Worker         queues: BTreeMap<usize, Queue>,
192*bb4ee6a4SAndroid Build Coastguard Worker     ) -> anyhow::Result<()> {
193*bb4ee6a4SAndroid Build Coastguard Worker         if queues.len() != NUM_QUEUES {
194*bb4ee6a4SAndroid Build Coastguard Worker             return Err(anyhow!(
195*bb4ee6a4SAndroid Build Coastguard Worker                 "net: expected {} queues, got {}",
196*bb4ee6a4SAndroid Build Coastguard Worker                 NUM_QUEUES,
197*bb4ee6a4SAndroid Build Coastguard Worker                 queues.len()
198*bb4ee6a4SAndroid Build Coastguard Worker             ));
199*bb4ee6a4SAndroid Build Coastguard Worker         }
200*bb4ee6a4SAndroid Build Coastguard Worker 
201*bb4ee6a4SAndroid Build Coastguard Worker         let vhost_net_handle = self
202*bb4ee6a4SAndroid Build Coastguard Worker             .vhost_net_handle
203*bb4ee6a4SAndroid Build Coastguard Worker             .take()
204*bb4ee6a4SAndroid Build Coastguard Worker             .context("missing vhost_net_handle")?;
205*bb4ee6a4SAndroid Build Coastguard Worker         let tap = self.tap.take().context("missing tap")?;
206*bb4ee6a4SAndroid Build Coastguard Worker         let vhost_interrupt = self
207*bb4ee6a4SAndroid Build Coastguard Worker             .vhost_interrupt
208*bb4ee6a4SAndroid Build Coastguard Worker             .take()
209*bb4ee6a4SAndroid Build Coastguard Worker             .context("missing vhost_interrupt")?;
210*bb4ee6a4SAndroid Build Coastguard Worker         let acked_features = self.acked_features;
211*bb4ee6a4SAndroid Build Coastguard Worker         let socket = if self.response_tube.is_some() {
212*bb4ee6a4SAndroid Build Coastguard Worker             self.response_tube.take()
213*bb4ee6a4SAndroid Build Coastguard Worker         } else {
214*bb4ee6a4SAndroid Build Coastguard Worker             None
215*bb4ee6a4SAndroid Build Coastguard Worker         };
216*bb4ee6a4SAndroid Build Coastguard Worker         let mut worker = Worker::new(
217*bb4ee6a4SAndroid Build Coastguard Worker             queues,
218*bb4ee6a4SAndroid Build Coastguard Worker             vhost_net_handle,
219*bb4ee6a4SAndroid Build Coastguard Worker             vhost_interrupt,
220*bb4ee6a4SAndroid Build Coastguard Worker             interrupt,
221*bb4ee6a4SAndroid Build Coastguard Worker             acked_features,
222*bb4ee6a4SAndroid Build Coastguard Worker             socket,
223*bb4ee6a4SAndroid Build Coastguard Worker         );
224*bb4ee6a4SAndroid Build Coastguard Worker         let activate_vqs = |handle: &U| -> Result<()> {
225*bb4ee6a4SAndroid Build Coastguard Worker             for idx in 0..NUM_QUEUES {
226*bb4ee6a4SAndroid Build Coastguard Worker                 handle
227*bb4ee6a4SAndroid Build Coastguard Worker                     .set_backend(idx, Some(&tap))
228*bb4ee6a4SAndroid Build Coastguard Worker                     .map_err(Error::VhostNetSetBackend)?;
229*bb4ee6a4SAndroid Build Coastguard Worker             }
230*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
231*bb4ee6a4SAndroid Build Coastguard Worker         };
232*bb4ee6a4SAndroid Build Coastguard Worker         worker
233*bb4ee6a4SAndroid Build Coastguard Worker             .init(mem, QUEUE_SIZES, activate_vqs, None)
234*bb4ee6a4SAndroid Build Coastguard Worker             .context("net worker init exited with error")?;
235*bb4ee6a4SAndroid Build Coastguard Worker         self.worker_thread = Some(WorkerThread::start("vhost_net", move |kill_evt| {
236*bb4ee6a4SAndroid Build Coastguard Worker             let cleanup_vqs = |handle: &U| -> Result<()> {
237*bb4ee6a4SAndroid Build Coastguard Worker                 for idx in 0..NUM_QUEUES {
238*bb4ee6a4SAndroid Build Coastguard Worker                     handle
239*bb4ee6a4SAndroid Build Coastguard Worker                         .set_backend(idx, None)
240*bb4ee6a4SAndroid Build Coastguard Worker                         .map_err(Error::VhostNetSetBackend)?;
241*bb4ee6a4SAndroid Build Coastguard Worker                 }
242*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(())
243*bb4ee6a4SAndroid Build Coastguard Worker             };
244*bb4ee6a4SAndroid Build Coastguard Worker             let result = worker.run(cleanup_vqs, kill_evt);
245*bb4ee6a4SAndroid Build Coastguard Worker             if let Err(e) = result {
246*bb4ee6a4SAndroid Build Coastguard Worker                 error!("net worker thread exited with error: {}", e);
247*bb4ee6a4SAndroid Build Coastguard Worker             }
248*bb4ee6a4SAndroid Build Coastguard Worker             (worker, tap)
249*bb4ee6a4SAndroid Build Coastguard Worker         }));
250*bb4ee6a4SAndroid Build Coastguard Worker 
251*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
252*bb4ee6a4SAndroid Build Coastguard Worker     }
253*bb4ee6a4SAndroid Build Coastguard Worker 
pci_address(&self) -> Option<PciAddress>254*bb4ee6a4SAndroid Build Coastguard Worker     fn pci_address(&self) -> Option<PciAddress> {
255*bb4ee6a4SAndroid Build Coastguard Worker         self.pci_address
256*bb4ee6a4SAndroid Build Coastguard Worker     }
257*bb4ee6a4SAndroid Build Coastguard Worker 
on_device_sandboxed(&mut self)258*bb4ee6a4SAndroid Build Coastguard Worker     fn on_device_sandboxed(&mut self) {
259*bb4ee6a4SAndroid Build Coastguard Worker         // ignore the error but to log the error. We don't need to do
260*bb4ee6a4SAndroid Build Coastguard Worker         // anything here because when activate, the other vhost set up
261*bb4ee6a4SAndroid Build Coastguard Worker         // will be failed to stop the activate thread.
262*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(vhost_net_handle) = &self.vhost_net_handle {
263*bb4ee6a4SAndroid Build Coastguard Worker             match vhost_net_handle.set_owner() {
264*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(_) => {}
265*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => error!("{}: failed to set owner: {:?}", self.debug_label(), e),
266*bb4ee6a4SAndroid Build Coastguard Worker             }
267*bb4ee6a4SAndroid Build Coastguard Worker         }
268*bb4ee6a4SAndroid Build Coastguard Worker     }
269*bb4ee6a4SAndroid Build Coastguard Worker 
control_notify(&self, behavior: MsixStatus)270*bb4ee6a4SAndroid Build Coastguard Worker     fn control_notify(&self, behavior: MsixStatus) {
271*bb4ee6a4SAndroid Build Coastguard Worker         if self.worker_thread.is_none() {
272*bb4ee6a4SAndroid Build Coastguard Worker             return;
273*bb4ee6a4SAndroid Build Coastguard Worker         }
274*bb4ee6a4SAndroid Build Coastguard Worker         match behavior {
275*bb4ee6a4SAndroid Build Coastguard Worker             MsixStatus::EntryChanged(index) => {
276*bb4ee6a4SAndroid Build Coastguard Worker                 if let Err(e) = self
277*bb4ee6a4SAndroid Build Coastguard Worker                     .request_tube
278*bb4ee6a4SAndroid Build Coastguard Worker                     .send(&VhostDevRequest::MsixEntryChanged(index))
279*bb4ee6a4SAndroid Build Coastguard Worker                 {
280*bb4ee6a4SAndroid Build Coastguard Worker                     error!(
281*bb4ee6a4SAndroid Build Coastguard Worker                         "{} failed to send VhostMsixEntryChanged request for entry {}: {:?}",
282*bb4ee6a4SAndroid Build Coastguard Worker                         self.debug_label(),
283*bb4ee6a4SAndroid Build Coastguard Worker                         index,
284*bb4ee6a4SAndroid Build Coastguard Worker                         e
285*bb4ee6a4SAndroid Build Coastguard Worker                     );
286*bb4ee6a4SAndroid Build Coastguard Worker                     return;
287*bb4ee6a4SAndroid Build Coastguard Worker                 }
288*bb4ee6a4SAndroid Build Coastguard Worker                 if let Err(e) = self.request_tube.recv::<VhostDevResponse>() {
289*bb4ee6a4SAndroid Build Coastguard Worker                     error!(
290*bb4ee6a4SAndroid Build Coastguard Worker                         "{} failed to receive VhostMsixEntryChanged response for entry {}: {:?}",
291*bb4ee6a4SAndroid Build Coastguard Worker                         self.debug_label(),
292*bb4ee6a4SAndroid Build Coastguard Worker                         index,
293*bb4ee6a4SAndroid Build Coastguard Worker                         e
294*bb4ee6a4SAndroid Build Coastguard Worker                     );
295*bb4ee6a4SAndroid Build Coastguard Worker                 }
296*bb4ee6a4SAndroid Build Coastguard Worker             }
297*bb4ee6a4SAndroid Build Coastguard Worker             MsixStatus::Changed => {
298*bb4ee6a4SAndroid Build Coastguard Worker                 if let Err(e) = self.request_tube.send(&VhostDevRequest::MsixChanged) {
299*bb4ee6a4SAndroid Build Coastguard Worker                     error!(
300*bb4ee6a4SAndroid Build Coastguard Worker                         "{} failed to send VhostMsixChanged request: {:?}",
301*bb4ee6a4SAndroid Build Coastguard Worker                         self.debug_label(),
302*bb4ee6a4SAndroid Build Coastguard Worker                         e
303*bb4ee6a4SAndroid Build Coastguard Worker                     );
304*bb4ee6a4SAndroid Build Coastguard Worker                     return;
305*bb4ee6a4SAndroid Build Coastguard Worker                 }
306*bb4ee6a4SAndroid Build Coastguard Worker                 if let Err(e) = self.request_tube.recv::<VhostDevResponse>() {
307*bb4ee6a4SAndroid Build Coastguard Worker                     error!(
308*bb4ee6a4SAndroid Build Coastguard Worker                         "{} failed to receive VhostMsixChanged response {:?}",
309*bb4ee6a4SAndroid Build Coastguard Worker                         self.debug_label(),
310*bb4ee6a4SAndroid Build Coastguard Worker                         e
311*bb4ee6a4SAndroid Build Coastguard Worker                     );
312*bb4ee6a4SAndroid Build Coastguard Worker                 }
313*bb4ee6a4SAndroid Build Coastguard Worker             }
314*bb4ee6a4SAndroid Build Coastguard Worker             _ => {}
315*bb4ee6a4SAndroid Build Coastguard Worker         }
316*bb4ee6a4SAndroid Build Coastguard Worker     }
317*bb4ee6a4SAndroid Build Coastguard Worker 
reset(&mut self) -> anyhow::Result<()>318*bb4ee6a4SAndroid Build Coastguard Worker     fn reset(&mut self) -> anyhow::Result<()> {
319*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(worker_thread) = self.worker_thread.take() {
320*bb4ee6a4SAndroid Build Coastguard Worker             let (worker, tap) = worker_thread.stop();
321*bb4ee6a4SAndroid Build Coastguard Worker             self.vhost_net_handle = Some(worker.vhost_handle);
322*bb4ee6a4SAndroid Build Coastguard Worker             self.tap = Some(tap);
323*bb4ee6a4SAndroid Build Coastguard Worker             self.vhost_interrupt = Some(worker.vhost_interrupt);
324*bb4ee6a4SAndroid Build Coastguard Worker             self.response_tube = worker.response_tube;
325*bb4ee6a4SAndroid Build Coastguard Worker         }
326*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
327*bb4ee6a4SAndroid Build Coastguard Worker     }
328*bb4ee6a4SAndroid Build Coastguard Worker }
329*bb4ee6a4SAndroid Build Coastguard Worker 
330*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
331*bb4ee6a4SAndroid Build Coastguard Worker pub mod tests {
332*bb4ee6a4SAndroid Build Coastguard Worker     use std::net::Ipv4Addr;
333*bb4ee6a4SAndroid Build Coastguard Worker     use std::path::PathBuf;
334*bb4ee6a4SAndroid Build Coastguard Worker     use std::result;
335*bb4ee6a4SAndroid Build Coastguard Worker 
336*bb4ee6a4SAndroid Build Coastguard Worker     use base::pagesize;
337*bb4ee6a4SAndroid Build Coastguard Worker     use hypervisor::ProtectionType;
338*bb4ee6a4SAndroid Build Coastguard Worker     use net_util::sys::linux::fakes::FakeTap;
339*bb4ee6a4SAndroid Build Coastguard Worker     use net_util::TapTCommon;
340*bb4ee6a4SAndroid Build Coastguard Worker     use vhost::net::fakes::FakeNet;
341*bb4ee6a4SAndroid Build Coastguard Worker     use vm_memory::GuestAddress;
342*bb4ee6a4SAndroid Build Coastguard Worker     use vm_memory::GuestMemory;
343*bb4ee6a4SAndroid Build Coastguard Worker     use vm_memory::GuestMemoryError;
344*bb4ee6a4SAndroid Build Coastguard Worker 
345*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
346*bb4ee6a4SAndroid Build Coastguard Worker     use crate::virtio::base_features;
347*bb4ee6a4SAndroid Build Coastguard Worker     use crate::virtio::QueueConfig;
348*bb4ee6a4SAndroid Build Coastguard Worker 
create_guest_memory() -> result::Result<GuestMemory, GuestMemoryError>349*bb4ee6a4SAndroid Build Coastguard Worker     fn create_guest_memory() -> result::Result<GuestMemory, GuestMemoryError> {
350*bb4ee6a4SAndroid Build Coastguard Worker         let start_addr1 = GuestAddress(0x0);
351*bb4ee6a4SAndroid Build Coastguard Worker         let start_addr2 = GuestAddress(pagesize() as u64);
352*bb4ee6a4SAndroid Build Coastguard Worker         GuestMemory::new(&[
353*bb4ee6a4SAndroid Build Coastguard Worker             (start_addr1, pagesize() as u64),
354*bb4ee6a4SAndroid Build Coastguard Worker             (start_addr2, 4 * pagesize() as u64),
355*bb4ee6a4SAndroid Build Coastguard Worker         ])
356*bb4ee6a4SAndroid Build Coastguard Worker     }
357*bb4ee6a4SAndroid Build Coastguard Worker 
create_net_common() -> Net<FakeTap, FakeNet<FakeTap>>358*bb4ee6a4SAndroid Build Coastguard Worker     fn create_net_common() -> Net<FakeTap, FakeNet<FakeTap>> {
359*bb4ee6a4SAndroid Build Coastguard Worker         let tap = FakeTap::new(true, false).unwrap();
360*bb4ee6a4SAndroid Build Coastguard Worker         tap.set_ip_addr(Ipv4Addr::new(127, 0, 0, 1))
361*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::TapSetIp)
362*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
363*bb4ee6a4SAndroid Build Coastguard Worker         tap.set_netmask(Ipv4Addr::new(255, 255, 255, 0))
364*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::TapSetNetmask)
365*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
366*bb4ee6a4SAndroid Build Coastguard Worker         let mac = "de:21:e8:47:6b:6a".parse().unwrap();
367*bb4ee6a4SAndroid Build Coastguard Worker         tap.set_mac_address(mac).unwrap();
368*bb4ee6a4SAndroid Build Coastguard Worker         tap.enable().unwrap();
369*bb4ee6a4SAndroid Build Coastguard Worker 
370*bb4ee6a4SAndroid Build Coastguard Worker         let features = base_features(ProtectionType::Unprotected);
371*bb4ee6a4SAndroid Build Coastguard Worker         Net::<FakeTap, FakeNet<FakeTap>>::new(
372*bb4ee6a4SAndroid Build Coastguard Worker             &PathBuf::from(""),
373*bb4ee6a4SAndroid Build Coastguard Worker             features,
374*bb4ee6a4SAndroid Build Coastguard Worker             tap,
375*bb4ee6a4SAndroid Build Coastguard Worker             Some(mac),
376*bb4ee6a4SAndroid Build Coastguard Worker             false,
377*bb4ee6a4SAndroid Build Coastguard Worker             None,
378*bb4ee6a4SAndroid Build Coastguard Worker         )
379*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap()
380*bb4ee6a4SAndroid Build Coastguard Worker     }
381*bb4ee6a4SAndroid Build Coastguard Worker 
382*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
create_net()383*bb4ee6a4SAndroid Build Coastguard Worker     fn create_net() {
384*bb4ee6a4SAndroid Build Coastguard Worker         create_net_common();
385*bb4ee6a4SAndroid Build Coastguard Worker     }
386*bb4ee6a4SAndroid Build Coastguard Worker 
387*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
keep_rds()388*bb4ee6a4SAndroid Build Coastguard Worker     fn keep_rds() {
389*bb4ee6a4SAndroid Build Coastguard Worker         let net = create_net_common();
390*bb4ee6a4SAndroid Build Coastguard Worker         let fds = net.keep_rds();
391*bb4ee6a4SAndroid Build Coastguard Worker         assert!(
392*bb4ee6a4SAndroid Build Coastguard Worker             !fds.is_empty(),
393*bb4ee6a4SAndroid Build Coastguard Worker             "We should have gotten at least one descriptor"
394*bb4ee6a4SAndroid Build Coastguard Worker         );
395*bb4ee6a4SAndroid Build Coastguard Worker     }
396*bb4ee6a4SAndroid Build Coastguard Worker 
397*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
features()398*bb4ee6a4SAndroid Build Coastguard Worker     fn features() {
399*bb4ee6a4SAndroid Build Coastguard Worker         let net = create_net_common();
400*bb4ee6a4SAndroid Build Coastguard Worker         // Feature bits 0-23 and 50-127 are specific for the device type, but
401*bb4ee6a4SAndroid Build Coastguard Worker         // at the moment crosvm only supports 64 bits of feature bits.
402*bb4ee6a4SAndroid Build Coastguard Worker         const DEVICE_FEATURE_BITS: u64 = 0xffffff;
403*bb4ee6a4SAndroid Build Coastguard Worker         let expected_features = 1 << 0 // VIRTIO_NET_F_CSUM
404*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << 1 // VIRTIO_NET_F_GUEST_CSUM
405*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << 5 // VIRTIO_NET_F_MAC
406*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << 7 // VIRTIO_NET_F_GUEST_TSO4
407*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << 10 // VIRTIO_NET_F_GUEST_UFO
408*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << 11 // VIRTIO_NET_F_HOST_TSO4
409*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << 14 // VIRTIO_NET_F_HOST_UFO
410*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << 15; // VIRTIO_NET_F_MRG_RXBUF
411*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(net.features() & DEVICE_FEATURE_BITS, expected_features);
412*bb4ee6a4SAndroid Build Coastguard Worker     }
413*bb4ee6a4SAndroid Build Coastguard Worker 
414*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
ack_features()415*bb4ee6a4SAndroid Build Coastguard Worker     fn ack_features() {
416*bb4ee6a4SAndroid Build Coastguard Worker         let mut net = create_net_common();
417*bb4ee6a4SAndroid Build Coastguard Worker         // Just testing that we don't panic, for now
418*bb4ee6a4SAndroid Build Coastguard Worker         net.ack_features(1);
419*bb4ee6a4SAndroid Build Coastguard Worker         net.ack_features(1 << 32);
420*bb4ee6a4SAndroid Build Coastguard Worker     }
421*bb4ee6a4SAndroid Build Coastguard Worker 
422*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
activate()423*bb4ee6a4SAndroid Build Coastguard Worker     fn activate() {
424*bb4ee6a4SAndroid Build Coastguard Worker         let mut net = create_net_common();
425*bb4ee6a4SAndroid Build Coastguard Worker         let guest_memory = create_guest_memory().unwrap();
426*bb4ee6a4SAndroid Build Coastguard Worker         let interrupt = Interrupt::new_for_test();
427*bb4ee6a4SAndroid Build Coastguard Worker 
428*bb4ee6a4SAndroid Build Coastguard Worker         let mut q0 = QueueConfig::new(1, 0);
429*bb4ee6a4SAndroid Build Coastguard Worker         q0.set_ready(true);
430*bb4ee6a4SAndroid Build Coastguard Worker         let q0 = q0
431*bb4ee6a4SAndroid Build Coastguard Worker             .activate(&guest_memory, Event::new().unwrap(), interrupt.clone())
432*bb4ee6a4SAndroid Build Coastguard Worker             .expect("QueueConfig::activate");
433*bb4ee6a4SAndroid Build Coastguard Worker 
434*bb4ee6a4SAndroid Build Coastguard Worker         let mut q1 = QueueConfig::new(1, 0);
435*bb4ee6a4SAndroid Build Coastguard Worker         q1.set_ready(true);
436*bb4ee6a4SAndroid Build Coastguard Worker         let q1 = q1
437*bb4ee6a4SAndroid Build Coastguard Worker             .activate(&guest_memory, Event::new().unwrap(), interrupt.clone())
438*bb4ee6a4SAndroid Build Coastguard Worker             .expect("QueueConfig::activate");
439*bb4ee6a4SAndroid Build Coastguard Worker 
440*bb4ee6a4SAndroid Build Coastguard Worker         // Just testing that we don't panic, for now
441*bb4ee6a4SAndroid Build Coastguard Worker         let _ = net.activate(guest_memory, interrupt, BTreeMap::from([(0, q0), (1, q1)]));
442*bb4ee6a4SAndroid Build Coastguard Worker     }
443*bb4ee6a4SAndroid Build Coastguard Worker }
444