• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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