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