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