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