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