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