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 mod sys;
6
7 use std::collections::BTreeMap;
8 use std::fmt;
9 use std::io;
10 use std::io::Write;
11 use std::net::Ipv4Addr;
12 use std::os::raw::c_uint;
13 use std::path::PathBuf;
14 use std::str::FromStr;
15
16 use anyhow::anyhow;
17 use anyhow::Context;
18 use base::error;
19 #[cfg(windows)]
20 use base::named_pipes::OverlappedWrapper;
21 use base::warn;
22 use base::Error as SysError;
23 use base::Event;
24 use base::EventToken;
25 use base::RawDescriptor;
26 use base::ReadNotifier;
27 use base::WaitContext;
28 use base::WorkerThread;
29 use data_model::Le16;
30 use data_model::Le64;
31 use net_util::Error as TapError;
32 use net_util::MacAddress;
33 use net_util::TapT;
34 use remain::sorted;
35 use serde::Deserialize;
36 use serde::Serialize;
37 use thiserror::Error as ThisError;
38 use virtio_sys::virtio_config::VIRTIO_F_RING_PACKED;
39 use virtio_sys::virtio_net;
40 use virtio_sys::virtio_net::VIRTIO_NET_CTRL_GUEST_OFFLOADS;
41 use virtio_sys::virtio_net::VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET;
42 use virtio_sys::virtio_net::VIRTIO_NET_CTRL_MQ;
43 use virtio_sys::virtio_net::VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET;
44 use virtio_sys::virtio_net::VIRTIO_NET_ERR;
45 use virtio_sys::virtio_net::VIRTIO_NET_OK;
46 use vm_memory::GuestMemory;
47 use zerocopy::AsBytes;
48 use zerocopy::FromBytes;
49 use zerocopy::FromZeroes;
50
51 use super::copy_config;
52 use super::DeviceType;
53 use super::Interrupt;
54 use super::Queue;
55 use super::Reader;
56 use super::VirtioDevice;
57 use crate::PciAddress;
58
59 /// The maximum buffer size when segmentation offload is enabled. This
60 /// includes the 12-byte virtio net header.
61 /// http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html#x1-1740003
62 #[cfg(windows)]
63 pub(crate) const MAX_BUFFER_SIZE: usize = 65562;
64 const QUEUE_SIZE: u16 = 256;
65
66 #[cfg(any(target_os = "android", target_os = "linux"))]
67 pub static VHOST_NET_DEFAULT_PATH: &str = "/dev/vhost-net";
68
69 pub(crate) use sys::process_rx;
70 pub(crate) use sys::process_tx;
71 pub(crate) use sys::validate_and_configure_tap;
72 pub(crate) use sys::virtio_features_to_tap_offload;
73
74 #[sorted]
75 #[derive(ThisError, Debug)]
76 pub enum NetError {
77 /// Cloning kill event failed.
78 #[error("failed to clone kill event: {0}")]
79 CloneKillEvent(SysError),
80 /// Creating kill event failed.
81 #[error("failed to create kill event: {0}")]
82 CreateKillEvent(SysError),
83 /// Creating WaitContext failed.
84 #[error("failed to create wait context: {0}")]
85 CreateWaitContext(SysError),
86 /// Adding the tap descriptor back to the event context failed.
87 #[error("failed to add tap trigger to event context: {0}")]
88 EventAddTap(SysError),
89 /// Removing the tap descriptor from the event context failed.
90 #[error("failed to remove tap trigger from event context: {0}")]
91 EventRemoveTap(SysError),
92 /// Invalid control command
93 #[error("invalid control command")]
94 InvalidCmd,
95 /// Error reading data from control queue.
96 #[error("failed to read control message data: {0}")]
97 ReadCtrlData(io::Error),
98 /// Error reading header from control queue.
99 #[error("failed to read control message header: {0}")]
100 ReadCtrlHeader(io::Error),
101 /// There are no more available descriptors to receive into.
102 #[cfg(any(target_os = "android", target_os = "linux"))]
103 #[error("no rx descriptors available")]
104 RxDescriptorsExhausted,
105 /// Failure creating the Slirp loop.
106 #[cfg(windows)]
107 #[error("error creating Slirp: {0}")]
108 SlirpCreateError(net_util::Error),
109 /// Enabling tap interface failed.
110 #[error("failed to enable tap interface: {0}")]
111 TapEnable(TapError),
112 /// Couldn't get the MTU from the tap device.
113 #[error("failed to get tap interface MTU: {0}")]
114 TapGetMtu(TapError),
115 /// Open tap device failed.
116 #[error("failed to open tap device: {0}")]
117 TapOpen(TapError),
118 /// Setting tap IP failed.
119 #[error("failed to set tap IP: {0}")]
120 TapSetIp(TapError),
121 /// Setting tap mac address failed.
122 #[error("failed to set tap mac address: {0}")]
123 TapSetMacAddress(TapError),
124 /// Setting tap netmask failed.
125 #[error("failed to set tap netmask: {0}")]
126 TapSetNetmask(TapError),
127 /// Setting tap offload failed.
128 #[error("failed to set tap offload: {0}")]
129 TapSetOffload(TapError),
130 /// Setting vnet header size failed.
131 #[error("failed to set vnet header size: {0}")]
132 TapSetVnetHdrSize(TapError),
133 /// Validating tap interface failed.
134 #[error("failed to validate tap interface: {0}")]
135 TapValidate(String),
136 /// Removing read event from the tap fd events failed.
137 #[error("failed to disable EPOLLIN on tap fd: {0}")]
138 WaitContextDisableTap(SysError),
139 /// Adding read event to the tap fd events failed.
140 #[error("failed to enable EPOLLIN on tap fd: {0}")]
141 WaitContextEnableTap(SysError),
142 /// Error while waiting for events.
143 #[error("error while waiting for events: {0}")]
144 WaitError(SysError),
145 /// Failed writing an ack in response to a control message.
146 #[error("failed to write control message ack: {0}")]
147 WriteAck(io::Error),
148 /// Writing to a buffer in the guest failed.
149 #[cfg(any(target_os = "android", target_os = "linux"))]
150 #[error("failed to write to guest buffer: {0}")]
151 WriteBuffer(io::Error),
152 }
153
154 #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
155 #[serde(untagged, deny_unknown_fields)]
156 pub enum NetParametersMode {
157 #[serde(rename_all = "kebab-case")]
158 TapName {
159 tap_name: String,
160 mac: Option<MacAddress>,
161 },
162 #[serde(rename_all = "kebab-case")]
163 TapFd {
164 tap_fd: i32,
165 mac: Option<MacAddress>,
166 },
167 #[serde(rename_all = "kebab-case")]
168 RawConfig {
169 host_ip: Ipv4Addr,
170 netmask: Ipv4Addr,
171 mac: MacAddress,
172 },
173 }
174
175 #[cfg(any(target_os = "android", target_os = "linux"))]
vhost_net_device_path_default() -> PathBuf176 fn vhost_net_device_path_default() -> PathBuf {
177 PathBuf::from(VHOST_NET_DEFAULT_PATH)
178 }
179
180 #[cfg(any(target_os = "android", target_os = "linux"))]
181 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
182 #[serde(rename_all = "kebab-case", deny_unknown_fields)]
183 pub struct VhostNetParameters {
184 #[serde(default = "vhost_net_device_path_default")]
185 pub device: PathBuf,
186 }
187
188 #[cfg(any(target_os = "android", target_os = "linux"))]
189 impl Default for VhostNetParameters {
default() -> Self190 fn default() -> Self {
191 Self {
192 device: vhost_net_device_path_default(),
193 }
194 }
195 }
196
197 #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
198 #[serde(rename_all = "kebab-case")]
199 pub struct NetParameters {
200 #[serde(flatten)]
201 pub mode: NetParametersMode,
202 pub vq_pairs: Option<u16>,
203 // Style-guide asks to refrain against #[cfg] directives in structs, this is an exception due
204 // to the fact this struct is used for argument parsing.
205 #[cfg(any(target_os = "android", target_os = "linux"))]
206 pub vhost_net: Option<VhostNetParameters>,
207 #[serde(default)]
208 pub packed_queue: bool,
209 pub pci_address: Option<PciAddress>,
210 }
211
212 impl FromStr for NetParameters {
213 type Err = String;
from_str(s: &str) -> Result<Self, Self::Err>214 fn from_str(s: &str) -> Result<Self, Self::Err> {
215 serde_keyvalue::from_key_values(s).map_err(|e| e.to_string())
216 }
217 }
218
219 #[repr(C, packed)]
220 #[derive(Debug, Clone, Copy, AsBytes, FromZeroes, FromBytes)]
221 pub struct virtio_net_ctrl_hdr {
222 pub class: u8,
223 pub cmd: u8,
224 }
225
226 #[derive(Debug, Clone, Copy, Default, AsBytes, FromZeroes, FromBytes)]
227 #[repr(C)]
228 pub struct VirtioNetConfig {
229 mac: [u8; 6],
230 status: Le16,
231 max_vq_pairs: Le16,
232 mtu: Le16,
233 }
234
process_ctrl_request<T: TapT>( reader: &mut Reader, tap: &mut T, acked_features: u64, vq_pairs: u16, ) -> Result<(), NetError>235 fn process_ctrl_request<T: TapT>(
236 reader: &mut Reader,
237 tap: &mut T,
238 acked_features: u64,
239 vq_pairs: u16,
240 ) -> Result<(), NetError> {
241 let ctrl_hdr: virtio_net_ctrl_hdr = reader.read_obj().map_err(NetError::ReadCtrlHeader)?;
242
243 match ctrl_hdr.class as c_uint {
244 VIRTIO_NET_CTRL_GUEST_OFFLOADS => {
245 if ctrl_hdr.cmd != VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET as u8 {
246 error!(
247 "invalid cmd for VIRTIO_NET_CTRL_GUEST_OFFLOADS: {}",
248 ctrl_hdr.cmd
249 );
250 return Err(NetError::InvalidCmd);
251 }
252 let offloads: Le64 = reader.read_obj().map_err(NetError::ReadCtrlData)?;
253 let tap_offloads = virtio_features_to_tap_offload(offloads.into());
254 tap.set_offload(tap_offloads)
255 .map_err(NetError::TapSetOffload)?;
256 }
257 VIRTIO_NET_CTRL_MQ => {
258 if ctrl_hdr.cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET as u8 {
259 let pairs: Le16 = reader.read_obj().map_err(NetError::ReadCtrlData)?;
260 // Simple handle it now
261 if acked_features & 1 << virtio_net::VIRTIO_NET_F_MQ == 0
262 || pairs.to_native() != vq_pairs
263 {
264 error!(
265 "Invalid VQ_PAIRS_SET cmd, driver request pairs: {}, device vq pairs: {}",
266 pairs.to_native(),
267 vq_pairs
268 );
269 return Err(NetError::InvalidCmd);
270 }
271 }
272 }
273 _ => {
274 warn!(
275 "unimplemented class for VIRTIO_NET_CTRL_GUEST_OFFLOADS: {}",
276 ctrl_hdr.class
277 );
278 return Err(NetError::InvalidCmd);
279 }
280 }
281
282 Ok(())
283 }
284
process_ctrl<T: TapT>( interrupt: &Interrupt, ctrl_queue: &mut Queue, tap: &mut T, acked_features: u64, vq_pairs: u16, ) -> Result<(), NetError>285 pub fn process_ctrl<T: TapT>(
286 interrupt: &Interrupt,
287 ctrl_queue: &mut Queue,
288 tap: &mut T,
289 acked_features: u64,
290 vq_pairs: u16,
291 ) -> Result<(), NetError> {
292 while let Some(mut desc_chain) = ctrl_queue.pop() {
293 if let Err(e) = process_ctrl_request(&mut desc_chain.reader, tap, acked_features, vq_pairs)
294 {
295 error!("process_ctrl_request failed: {}", e);
296 desc_chain
297 .writer
298 .write_all(&[VIRTIO_NET_ERR as u8])
299 .map_err(NetError::WriteAck)?;
300 } else {
301 desc_chain
302 .writer
303 .write_all(&[VIRTIO_NET_OK as u8])
304 .map_err(NetError::WriteAck)?;
305 }
306 let len = desc_chain.writer.bytes_written() as u32;
307 ctrl_queue.add_used(desc_chain, len);
308 }
309
310 ctrl_queue.trigger_interrupt(interrupt);
311 Ok(())
312 }
313
314 #[derive(EventToken, Debug, Clone)]
315 pub enum Token {
316 // A frame is available for reading from the tap device to receive in the guest.
317 RxTap,
318 // The guest has made a buffer available to receive a frame into.
319 RxQueue,
320 // The transmit queue has a frame that is ready to send from the guest.
321 TxQueue,
322 // The control queue has a message.
323 CtrlQueue,
324 // Check if any interrupts need to be re-asserted.
325 InterruptResample,
326 // crosvm has requested the device to shut down.
327 Kill,
328 }
329
330 pub(super) struct Worker<T: TapT> {
331 pub(super) interrupt: Interrupt,
332 pub(super) rx_queue: Queue,
333 pub(super) tx_queue: Queue,
334 pub(super) ctrl_queue: Option<Queue>,
335 pub(super) tap: T,
336 #[cfg(windows)]
337 pub(super) overlapped_wrapper: OverlappedWrapper,
338 #[cfg(windows)]
339 pub(super) rx_buf: [u8; MAX_BUFFER_SIZE],
340 #[cfg(windows)]
341 pub(super) rx_count: usize,
342 #[cfg(windows)]
343 pub(super) deferred_rx: bool,
344 acked_features: u64,
345 vq_pairs: u16,
346 #[allow(dead_code)]
347 kill_evt: Event,
348 }
349
350 impl<T> Worker<T>
351 where
352 T: TapT + ReadNotifier,
353 {
process_tx(&mut self)354 fn process_tx(&mut self) {
355 process_tx(&self.interrupt, &mut self.tx_queue, &mut self.tap)
356 }
357
process_ctrl(&mut self) -> Result<(), NetError>358 fn process_ctrl(&mut self) -> Result<(), NetError> {
359 let ctrl_queue = match self.ctrl_queue.as_mut() {
360 Some(queue) => queue,
361 None => return Ok(()),
362 };
363
364 process_ctrl(
365 &self.interrupt,
366 ctrl_queue,
367 &mut self.tap,
368 self.acked_features,
369 self.vq_pairs,
370 )
371 }
372
run(&mut self, handle_interrupt_resample: bool) -> Result<(), NetError>373 fn run(&mut self, handle_interrupt_resample: bool) -> Result<(), NetError> {
374 let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
375 // This doesn't use get_read_notifier() because of overlapped io; we
376 // have overlapped wrapper separate from the TAP so that we can pass
377 // the overlapped wrapper into the read function. This overlapped
378 // wrapper's event is where we get the read notification.
379 #[cfg(windows)]
380 (
381 self.overlapped_wrapper.get_h_event_ref().unwrap(),
382 Token::RxTap,
383 ),
384 #[cfg(any(target_os = "android", target_os = "linux"))]
385 (self.tap.get_read_notifier(), Token::RxTap),
386 (self.rx_queue.event(), Token::RxQueue),
387 (self.tx_queue.event(), Token::TxQueue),
388 (&self.kill_evt, Token::Kill),
389 ])
390 .map_err(NetError::CreateWaitContext)?;
391
392 if let Some(ctrl_queue) = &self.ctrl_queue {
393 wait_ctx
394 .add(ctrl_queue.event(), Token::CtrlQueue)
395 .map_err(NetError::CreateWaitContext)?;
396 }
397
398 if handle_interrupt_resample {
399 if let Some(resample_evt) = self.interrupt.get_resample_evt() {
400 wait_ctx
401 .add(resample_evt, Token::InterruptResample)
402 .map_err(NetError::CreateWaitContext)?;
403 }
404 }
405
406 let mut tap_polling_enabled = true;
407 'wait: loop {
408 let events = wait_ctx.wait().map_err(NetError::WaitError)?;
409 for event in events.iter().filter(|e| e.is_readable) {
410 match event.token {
411 Token::RxTap => {
412 let _trace = cros_tracing::trace_event!(VirtioNet, "handle RxTap event");
413 self.handle_rx_token(&wait_ctx)?;
414 tap_polling_enabled = false;
415 }
416 Token::RxQueue => {
417 let _trace = cros_tracing::trace_event!(VirtioNet, "handle RxQueue event");
418 if let Err(e) = self.rx_queue.event().wait() {
419 error!("net: error reading rx queue Event: {}", e);
420 break 'wait;
421 }
422 self.handle_rx_queue(&wait_ctx, tap_polling_enabled)?;
423 tap_polling_enabled = true;
424 }
425 Token::TxQueue => {
426 let _trace = cros_tracing::trace_event!(VirtioNet, "handle TxQueue event");
427 if let Err(e) = self.tx_queue.event().wait() {
428 error!("net: error reading tx queue Event: {}", e);
429 break 'wait;
430 }
431 self.process_tx();
432 }
433 Token::CtrlQueue => {
434 let _trace =
435 cros_tracing::trace_event!(VirtioNet, "handle CtrlQueue event");
436 if let Some(ctrl_evt) = self.ctrl_queue.as_ref().map(|q| q.event()) {
437 if let Err(e) = ctrl_evt.wait() {
438 error!("net: error reading ctrl queue Event: {}", e);
439 break 'wait;
440 }
441 } else {
442 break 'wait;
443 }
444 if let Err(e) = self.process_ctrl() {
445 error!("net: failed to process control message: {}", e);
446 break 'wait;
447 }
448 }
449 Token::InterruptResample => {
450 let _trace =
451 cros_tracing::trace_event!(VirtioNet, "handle InterruptResample event");
452 // We can unwrap safely because interrupt must have the event.
453 let _ = self.interrupt.get_resample_evt().unwrap().wait();
454 self.interrupt.do_interrupt_resample();
455 }
456 Token::Kill => {
457 let _ = self.kill_evt.wait();
458 break 'wait;
459 }
460 }
461 }
462 }
463 Ok(())
464 }
465 }
466
build_config(vq_pairs: u16, mtu: u16, mac: Option<[u8; 6]>) -> VirtioNetConfig467 pub fn build_config(vq_pairs: u16, mtu: u16, mac: Option<[u8; 6]>) -> VirtioNetConfig {
468 VirtioNetConfig {
469 max_vq_pairs: Le16::from(vq_pairs),
470 mtu: Le16::from(mtu),
471 mac: mac.unwrap_or_default(),
472 // Other field has meaningful value when the corresponding feature
473 // is enabled, but all these features aren't supported now.
474 // So set them to default.
475 ..Default::default()
476 }
477 }
478
479 pub struct Net<T: TapT + ReadNotifier + 'static> {
480 guest_mac: Option<[u8; 6]>,
481 queue_sizes: Box<[u16]>,
482 worker_threads: Vec<WorkerThread<Worker<T>>>,
483 taps: Vec<T>,
484 avail_features: u64,
485 acked_features: u64,
486 mtu: u16,
487 pci_address: Option<PciAddress>,
488 #[cfg(windows)]
489 slirp_kill_evt: Option<Event>,
490 }
491
492 #[derive(Serialize, Deserialize)]
493 struct NetSnapshot {
494 avail_features: u64,
495 acked_features: u64,
496 }
497
498 impl<T> Net<T>
499 where
500 T: TapT + ReadNotifier,
501 {
502 /// Creates a new virtio network device from a tap device that has already been
503 /// configured.
new( base_features: u64, tap: T, vq_pairs: u16, mac_addr: Option<MacAddress>, use_packed_queue: bool, pci_address: Option<PciAddress>, ) -> Result<Net<T>, NetError>504 pub fn new(
505 base_features: u64,
506 tap: T,
507 vq_pairs: u16,
508 mac_addr: Option<MacAddress>,
509 use_packed_queue: bool,
510 pci_address: Option<PciAddress>,
511 ) -> Result<Net<T>, NetError> {
512 let taps = tap.into_mq_taps(vq_pairs).map_err(NetError::TapOpen)?;
513
514 let mut mtu = u16::MAX;
515 // This would also validate a tap created by Self::new(), but that's a good thing as it
516 // would ensure that any changes in the creation procedure are matched in the validation.
517 // Plus we still need to set the offload and vnet_hdr_size values.
518 for tap in &taps {
519 validate_and_configure_tap(tap, vq_pairs)?;
520 mtu = std::cmp::min(mtu, tap.mtu().map_err(NetError::TapGetMtu)?);
521 }
522
523 // Indicate that the TAP device supports a number of features, such as:
524 // Partial checksum offload
525 // TSO (TCP segmentation offload)
526 // UFO (UDP fragmentation offload)
527 // See the network device feature bits section for further details:
528 // http://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html#x1-1970003
529 let mut avail_features = base_features
530 | 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
531 | 1 << virtio_net::VIRTIO_NET_F_CSUM
532 | 1 << virtio_net::VIRTIO_NET_F_CTRL_VQ
533 | 1 << virtio_net::VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
534 | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
535 | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
536 | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
537 | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
538 | 1 << virtio_net::VIRTIO_NET_F_MTU;
539
540 if vq_pairs > 1 {
541 avail_features |= 1 << virtio_net::VIRTIO_NET_F_MQ;
542 }
543
544 if use_packed_queue {
545 avail_features |= 1 << VIRTIO_F_RING_PACKED;
546 }
547
548 if mac_addr.is_some() {
549 avail_features |= 1 << virtio_net::VIRTIO_NET_F_MAC;
550 }
551
552 Self::new_internal(
553 taps,
554 avail_features,
555 mtu,
556 mac_addr,
557 pci_address,
558 #[cfg(windows)]
559 None,
560 )
561 }
562
new_internal( taps: Vec<T>, avail_features: u64, mtu: u16, mac_addr: Option<MacAddress>, pci_address: Option<PciAddress>, #[cfg(windows)] slirp_kill_evt: Option<Event>, ) -> Result<Self, NetError>563 pub(crate) fn new_internal(
564 taps: Vec<T>,
565 avail_features: u64,
566 mtu: u16,
567 mac_addr: Option<MacAddress>,
568 pci_address: Option<PciAddress>,
569 #[cfg(windows)] slirp_kill_evt: Option<Event>,
570 ) -> Result<Self, NetError> {
571 let net = Self {
572 guest_mac: mac_addr.map(|mac| mac.octets()),
573 queue_sizes: vec![QUEUE_SIZE; taps.len() * 2 + 1].into_boxed_slice(),
574 worker_threads: Vec::new(),
575 taps,
576 avail_features,
577 acked_features: 0u64,
578 mtu,
579 pci_address,
580 #[cfg(windows)]
581 slirp_kill_evt: None,
582 };
583 cros_tracing::trace_simple_print!("New Net device created: {:?}", net);
584 Ok(net)
585 }
586
587 /// Returns the maximum number of receive/transmit queue pairs for this device.
588 /// Only relevant when multi-queue support is negotiated.
max_virtqueue_pairs(&self) -> usize589 fn max_virtqueue_pairs(&self) -> usize {
590 self.taps.len()
591 }
592 }
593
594 impl<T> Drop for Net<T>
595 where
596 T: TapT + ReadNotifier,
597 {
drop(&mut self)598 fn drop(&mut self) {
599 #[cfg(windows)]
600 {
601 if let Some(slirp_kill_evt) = self.slirp_kill_evt.take() {
602 let _ = slirp_kill_evt.signal();
603 }
604 }
605 }
606 }
607
608 impl<T> VirtioDevice for Net<T>
609 where
610 T: 'static + TapT + ReadNotifier,
611 {
keep_rds(&self) -> Vec<RawDescriptor>612 fn keep_rds(&self) -> Vec<RawDescriptor> {
613 let mut keep_rds = Vec::new();
614
615 for tap in &self.taps {
616 keep_rds.push(tap.as_raw_descriptor());
617 }
618
619 keep_rds
620 }
621
device_type(&self) -> DeviceType622 fn device_type(&self) -> DeviceType {
623 DeviceType::Net
624 }
625
queue_max_sizes(&self) -> &[u16]626 fn queue_max_sizes(&self) -> &[u16] {
627 &self.queue_sizes
628 }
629
features(&self) -> u64630 fn features(&self) -> u64 {
631 self.avail_features
632 }
633
ack_features(&mut self, value: u64)634 fn ack_features(&mut self, value: u64) {
635 let mut v = value;
636
637 // Check if the guest is ACK'ing a feature that we didn't claim to have.
638 let unrequested_features = v & !self.avail_features;
639 if unrequested_features != 0 {
640 warn!("net: virtio net got unknown feature ack: {:x}", v);
641
642 // Don't count these features as acked.
643 v &= !unrequested_features;
644 }
645 self.acked_features |= v;
646
647 // Set offload flags to match acked virtio features.
648 if let Some(tap) = self.taps.first() {
649 if let Err(e) = tap.set_offload(virtio_features_to_tap_offload(self.acked_features)) {
650 warn!(
651 "net: failed to set tap offload to match acked features: {}",
652 e
653 );
654 }
655 }
656 }
657
read_config(&self, offset: u64, data: &mut [u8])658 fn read_config(&self, offset: u64, data: &mut [u8]) {
659 let vq_pairs = self.queue_sizes.len() / 2;
660 let config_space = build_config(vq_pairs as u16, self.mtu, self.guest_mac);
661 copy_config(data, 0, config_space.as_bytes(), offset);
662 }
663
activate( &mut self, _mem: GuestMemory, interrupt: Interrupt, mut queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>664 fn activate(
665 &mut self,
666 _mem: GuestMemory,
667 interrupt: Interrupt,
668 mut queues: BTreeMap<usize, Queue>,
669 ) -> anyhow::Result<()> {
670 let ctrl_vq_enabled = self.acked_features & (1 << virtio_net::VIRTIO_NET_F_CTRL_VQ) != 0;
671 let mq_enabled = self.acked_features & (1 << virtio_net::VIRTIO_NET_F_MQ) != 0;
672
673 let vq_pairs = if mq_enabled {
674 self.max_virtqueue_pairs()
675 } else {
676 1
677 };
678
679 let mut num_queues_expected = vq_pairs * 2;
680 if ctrl_vq_enabled {
681 num_queues_expected += 1;
682 }
683
684 if queues.len() != num_queues_expected {
685 return Err(anyhow!(
686 "net: expected {} queues, got {} queues",
687 self.queue_sizes.len(),
688 queues.len(),
689 ));
690 }
691
692 if self.taps.len() < vq_pairs {
693 return Err(anyhow!(
694 "net: expected {} taps, got {}",
695 vq_pairs,
696 self.taps.len()
697 ));
698 }
699
700 for i in 0..vq_pairs {
701 let tap = self.taps.remove(0);
702 let acked_features = self.acked_features;
703 let interrupt = interrupt.clone();
704 let first_queue = i == 0;
705 // Queues alternate between rx0, tx0, rx1, tx1, ..., rxN, txN, ctrl.
706 let rx_queue = queues.pop_first().unwrap().1;
707 let tx_queue = queues.pop_first().unwrap().1;
708 let ctrl_queue = if first_queue && ctrl_vq_enabled {
709 Some(queues.pop_last().unwrap().1)
710 } else {
711 None
712 };
713 // Handle interrupt resampling on the first queue's thread.
714 let handle_interrupt_resample = first_queue;
715 let pairs = vq_pairs as u16;
716 #[cfg(windows)]
717 let overlapped_wrapper = OverlappedWrapper::new(true).unwrap();
718 self.worker_threads
719 .push(WorkerThread::start(format!("v_net:{i}"), move |kill_evt| {
720 let mut worker = Worker {
721 interrupt,
722 rx_queue,
723 tx_queue,
724 ctrl_queue,
725 tap,
726 #[cfg(windows)]
727 overlapped_wrapper,
728 acked_features,
729 vq_pairs: pairs,
730 #[cfg(windows)]
731 rx_buf: [0u8; MAX_BUFFER_SIZE],
732 #[cfg(windows)]
733 rx_count: 0,
734 #[cfg(windows)]
735 deferred_rx: false,
736 kill_evt,
737 };
738 let result = worker.run(handle_interrupt_resample);
739 if let Err(e) = result {
740 error!("net worker thread exited with error: {}", e);
741 }
742 worker
743 }));
744 }
745 cros_tracing::trace_simple_print!("Net device activated: {:?}", self);
746 Ok(())
747 }
748
pci_address(&self) -> Option<PciAddress>749 fn pci_address(&self) -> Option<PciAddress> {
750 self.pci_address
751 }
752
virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>>753 fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> {
754 if self.worker_threads.is_empty() {
755 return Ok(None);
756 }
757 let mut queues = BTreeMap::new();
758 let mut queue_index = 0;
759 let mut ctrl_queue = None;
760 for worker_thread in self.worker_threads.drain(..) {
761 let mut worker = worker_thread.stop();
762 if worker.ctrl_queue.is_some() {
763 ctrl_queue = worker.ctrl_queue.take();
764 }
765 self.taps.push(worker.tap);
766 queues.insert(queue_index + 0, worker.rx_queue);
767 queues.insert(queue_index + 1, worker.tx_queue);
768 queue_index += 2;
769 }
770 if let Some(ctrl_queue) = ctrl_queue {
771 queues.insert(queue_index, ctrl_queue);
772 }
773 Ok(Some(queues))
774 }
775
virtio_wake( &mut self, device_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>, ) -> anyhow::Result<()>776 fn virtio_wake(
777 &mut self,
778 device_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>,
779 ) -> anyhow::Result<()> {
780 match device_state {
781 None => Ok(()),
782 Some((mem, interrupt, queues)) => {
783 // TODO: activate is just what we want at the moment, but we should probably move
784 // it into a "start workers" function to make it obvious that it isn't strictly
785 // used for activate events.
786 self.activate(mem, interrupt, queues)?;
787 Ok(())
788 }
789 }
790 }
791
virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value>792 fn virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
793 serde_json::to_value(NetSnapshot {
794 acked_features: self.acked_features,
795 avail_features: self.avail_features,
796 })
797 .context("failed to snapshot virtio Net device")
798 }
799
virtio_restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>800 fn virtio_restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
801 let deser: NetSnapshot =
802 serde_json::from_value(data).context("failed to deserialize Net device")?;
803 anyhow::ensure!(
804 self.avail_features == deser.avail_features,
805 "Available features for net device do not match. expected: {}, got: {}",
806 deser.avail_features,
807 self.avail_features
808 );
809 self.acked_features = deser.acked_features;
810 Ok(())
811 }
812
reset(&mut self) -> anyhow::Result<()>813 fn reset(&mut self) -> anyhow::Result<()> {
814 for worker_thread in self.worker_threads.drain(..) {
815 let worker = worker_thread.stop();
816 self.taps.push(worker.tap);
817 }
818
819 Ok(())
820 }
821 }
822
823 impl<T> std::fmt::Debug for Net<T>
824 where
825 T: TapT + ReadNotifier,
826 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result827 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
828 f.debug_struct("Net")
829 .field("guest_mac", &self.guest_mac)
830 .field("queue_sizes", &self.queue_sizes)
831 .field("worker_threads_size", &self.worker_threads.len())
832 .field("taps_size", &self.taps.len())
833 .field("avail_features", &self.avail_features)
834 .field("acked_features", &self.acked_features)
835 .field("mtu", &self.mtu)
836 .finish()
837 }
838 }
839
840 #[cfg(test)]
841 mod tests {
842 use serde_keyvalue::*;
843
844 use super::*;
845
from_net_arg(options: &str) -> Result<NetParameters, ParseError>846 fn from_net_arg(options: &str) -> Result<NetParameters, ParseError> {
847 from_key_values(options)
848 }
849
850 #[test]
params_from_key_values()851 fn params_from_key_values() {
852 let params = from_net_arg("");
853 assert!(params.is_err());
854
855 let params = from_net_arg("tap-name=tap").unwrap();
856 assert_eq!(
857 params,
858 NetParameters {
859 #[cfg(any(target_os = "android", target_os = "linux"))]
860 vhost_net: None,
861 vq_pairs: None,
862 mode: NetParametersMode::TapName {
863 tap_name: "tap".to_string(),
864 mac: None
865 },
866 packed_queue: false,
867 pci_address: None,
868 }
869 );
870
871 let params = from_net_arg("tap-name=tap,mac=\"3d:70:eb:61:1a:91\"").unwrap();
872 assert_eq!(
873 params,
874 NetParameters {
875 #[cfg(any(target_os = "android", target_os = "linux"))]
876 vhost_net: None,
877 vq_pairs: None,
878 mode: NetParametersMode::TapName {
879 tap_name: "tap".to_string(),
880 mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
881 },
882 packed_queue: false,
883 pci_address: None,
884 }
885 );
886
887 let params = from_net_arg("tap-fd=12").unwrap();
888 assert_eq!(
889 params,
890 NetParameters {
891 #[cfg(any(target_os = "android", target_os = "linux"))]
892 vhost_net: None,
893 vq_pairs: None,
894 mode: NetParametersMode::TapFd {
895 tap_fd: 12,
896 mac: None
897 },
898 packed_queue: false,
899 pci_address: None,
900 }
901 );
902
903 let params = from_net_arg("tap-fd=12,mac=\"3d:70:eb:61:1a:91\"").unwrap();
904 assert_eq!(
905 params,
906 NetParameters {
907 #[cfg(any(target_os = "android", target_os = "linux"))]
908 vhost_net: None,
909 vq_pairs: None,
910 mode: NetParametersMode::TapFd {
911 tap_fd: 12,
912 mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
913 },
914 packed_queue: false,
915 pci_address: None,
916 }
917 );
918
919 let params = from_net_arg(
920 "host-ip=\"192.168.10.1\",netmask=\"255.255.255.0\",mac=\"3d:70:eb:61:1a:91\"",
921 )
922 .unwrap();
923 assert_eq!(
924 params,
925 NetParameters {
926 #[cfg(any(target_os = "android", target_os = "linux"))]
927 vhost_net: None,
928 vq_pairs: None,
929 mode: NetParametersMode::RawConfig {
930 host_ip: Ipv4Addr::from_str("192.168.10.1").unwrap(),
931 netmask: Ipv4Addr::from_str("255.255.255.0").unwrap(),
932 mac: MacAddress::from_str("3d:70:eb:61:1a:91").unwrap(),
933 },
934 packed_queue: false,
935 pci_address: None,
936 }
937 );
938
939 let params = from_net_arg("tap-fd=12,pci-address=00:01.1").unwrap();
940 assert_eq!(
941 params,
942 NetParameters {
943 #[cfg(any(target_os = "android", target_os = "linux"))]
944 vhost_net: None,
945 vq_pairs: None,
946 mode: NetParametersMode::TapFd {
947 tap_fd: 12,
948 mac: None,
949 },
950 packed_queue: false,
951 pci_address: Some(PciAddress {
952 bus: 0,
953 dev: 1,
954 func: 1,
955 }),
956 }
957 );
958
959 // wrong pci format
960 assert!(from_net_arg("tap-fd=12,pci-address=hello").is_err());
961
962 // missing netmask
963 assert!(from_net_arg("host-ip=\"192.168.10.1\",mac=\"3d:70:eb:61:1a:91\"").is_err());
964
965 // invalid parameter
966 assert!(from_net_arg("tap-name=tap,foomatic=true").is_err());
967 }
968
969 #[test]
970 #[cfg(any(target_os = "android", target_os = "linux"))]
params_from_key_values_vhost_net()971 fn params_from_key_values_vhost_net() {
972 let params = from_net_arg(
973 "vhost-net=[device=/dev/foo],\
974 host-ip=\"192.168.10.1\",\
975 netmask=\"255.255.255.0\",\
976 mac=\"3d:70:eb:61:1a:91\"",
977 )
978 .unwrap();
979 assert_eq!(
980 params,
981 NetParameters {
982 vhost_net: Some(VhostNetParameters {
983 device: PathBuf::from("/dev/foo")
984 }),
985 vq_pairs: None,
986 mode: NetParametersMode::RawConfig {
987 host_ip: Ipv4Addr::from_str("192.168.10.1").unwrap(),
988 netmask: Ipv4Addr::from_str("255.255.255.0").unwrap(),
989 mac: MacAddress::from_str("3d:70:eb:61:1a:91").unwrap(),
990 },
991 packed_queue: false,
992 pci_address: None,
993 }
994 );
995
996 let params = from_net_arg("tap-fd=3,vhost-net").unwrap();
997 assert_eq!(
998 params,
999 NetParameters {
1000 vhost_net: Some(Default::default()),
1001 vq_pairs: None,
1002 mode: NetParametersMode::TapFd {
1003 tap_fd: 3,
1004 mac: None
1005 },
1006 packed_queue: false,
1007 pci_address: None,
1008 }
1009 );
1010
1011 let params = from_net_arg("vhost-net,tap-name=crosvm_tap").unwrap();
1012 assert_eq!(
1013 params,
1014 NetParameters {
1015 vhost_net: Some(Default::default()),
1016 vq_pairs: None,
1017 mode: NetParametersMode::TapName {
1018 tap_name: "crosvm_tap".to_owned(),
1019 mac: None
1020 },
1021 packed_queue: false,
1022 pci_address: None,
1023 }
1024 );
1025
1026 let params =
1027 from_net_arg("vhost-net,mac=\"3d:70:eb:61:1a:91\",tap-name=crosvm_tap").unwrap();
1028 assert_eq!(
1029 params,
1030 NetParameters {
1031 vhost_net: Some(Default::default()),
1032 vq_pairs: None,
1033 mode: NetParametersMode::TapName {
1034 tap_name: "crosvm_tap".to_owned(),
1035 mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
1036 },
1037 packed_queue: false,
1038 pci_address: None,
1039 }
1040 );
1041
1042 let params = from_net_arg("tap-name=tap,packed-queue=true").unwrap();
1043 assert_eq!(
1044 params,
1045 NetParameters {
1046 #[cfg(any(target_os = "android", target_os = "linux"))]
1047 vhost_net: None,
1048 vq_pairs: None,
1049 mode: NetParametersMode::TapName {
1050 tap_name: "tap".to_string(),
1051 mac: None
1052 },
1053 packed_queue: true,
1054 pci_address: None,
1055 }
1056 );
1057
1058 let params = from_net_arg("tap-name=tap,packed-queue").unwrap();
1059 assert_eq!(
1060 params,
1061 NetParameters {
1062 #[cfg(any(target_os = "android", target_os = "linux"))]
1063 vhost_net: None,
1064 vq_pairs: None,
1065 mode: NetParametersMode::TapName {
1066 tap_name: "tap".to_string(),
1067 mac: None
1068 },
1069 packed_queue: true,
1070 pci_address: None,
1071 }
1072 );
1073
1074 let params = from_net_arg("vhost-net,tap-name=crosvm_tap,pci-address=00:01.1").unwrap();
1075 assert_eq!(
1076 params,
1077 NetParameters {
1078 vhost_net: Some(Default::default()),
1079 vq_pairs: None,
1080 mode: NetParametersMode::TapName {
1081 tap_name: "crosvm_tap".to_owned(),
1082 mac: None,
1083 },
1084 packed_queue: false,
1085 pci_address: Some(PciAddress {
1086 bus: 0,
1087 dev: 1,
1088 func: 1,
1089 }),
1090 }
1091 );
1092
1093 // mixed configs
1094 assert!(from_net_arg(
1095 "tap-name=tap,\
1096 vhost-net,\
1097 host-ip=\"192.168.10.1\",\
1098 netmask=\"255.255.255.0\",\
1099 mac=\"3d:70:eb:61:1a:91\"",
1100 )
1101 .is_err());
1102 }
1103 }
1104