xref: /aosp_15_r20/external/crosvm/devices/src/virtio/net.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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>( ctrl_queue: &mut Queue, tap: &mut T, acked_features: u64, vq_pairs: u16, ) -> Result<(), NetError>285 pub fn process_ctrl<T: TapT>(
286     ctrl_queue: &mut Queue,
287     tap: &mut T,
288     acked_features: u64,
289     vq_pairs: u16,
290 ) -> Result<(), NetError> {
291     while let Some(mut desc_chain) = ctrl_queue.pop() {
292         if let Err(e) = process_ctrl_request(&mut desc_chain.reader, tap, acked_features, vq_pairs)
293         {
294             error!("process_ctrl_request failed: {}", e);
295             desc_chain
296                 .writer
297                 .write_all(&[VIRTIO_NET_ERR as u8])
298                 .map_err(NetError::WriteAck)?;
299         } else {
300             desc_chain
301                 .writer
302                 .write_all(&[VIRTIO_NET_OK as u8])
303                 .map_err(NetError::WriteAck)?;
304         }
305         let len = desc_chain.writer.bytes_written() as u32;
306         ctrl_queue.add_used(desc_chain, len);
307     }
308 
309     ctrl_queue.trigger_interrupt();
310     Ok(())
311 }
312 
313 #[derive(EventToken, Debug, Clone)]
314 pub enum Token {
315     // A frame is available for reading from the tap device to receive in the guest.
316     RxTap,
317     // The guest has made a buffer available to receive a frame into.
318     RxQueue,
319     // The transmit queue has a frame that is ready to send from the guest.
320     TxQueue,
321     // The control queue has a message.
322     CtrlQueue,
323     // Check if any interrupts need to be re-asserted.
324     InterruptResample,
325     // crosvm has requested the device to shut down.
326     Kill,
327 }
328 
329 pub(super) struct Worker<T: TapT> {
330     pub(super) interrupt: Interrupt,
331     pub(super) rx_queue: Queue,
332     pub(super) tx_queue: Queue,
333     pub(super) ctrl_queue: Option<Queue>,
334     pub(super) tap: T,
335     #[cfg(windows)]
336     pub(super) overlapped_wrapper: OverlappedWrapper,
337     #[cfg(windows)]
338     pub(super) rx_buf: [u8; MAX_BUFFER_SIZE],
339     #[cfg(windows)]
340     pub(super) rx_count: usize,
341     #[cfg(windows)]
342     pub(super) deferred_rx: bool,
343     acked_features: u64,
344     vq_pairs: u16,
345     #[allow(dead_code)]
346     kill_evt: Event,
347 }
348 
349 impl<T> Worker<T>
350 where
351     T: TapT + ReadNotifier,
352 {
process_tx(&mut self)353     fn process_tx(&mut self) {
354         process_tx(&mut self.tx_queue, &mut self.tap)
355     }
356 
process_ctrl(&mut self) -> Result<(), NetError>357     fn process_ctrl(&mut self) -> Result<(), NetError> {
358         let ctrl_queue = match self.ctrl_queue.as_mut() {
359             Some(queue) => queue,
360             None => return Ok(()),
361         };
362 
363         process_ctrl(
364             ctrl_queue,
365             &mut self.tap,
366             self.acked_features,
367             self.vq_pairs,
368         )
369     }
370 
run(&mut self, handle_interrupt_resample: bool) -> Result<(), NetError>371     fn run(&mut self, handle_interrupt_resample: bool) -> Result<(), NetError> {
372         let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
373             // This doesn't use get_read_notifier() because of overlapped io; we
374             // have overlapped wrapper separate from the TAP so that we can pass
375             // the overlapped wrapper into the read function. This overlapped
376             // wrapper's event is where we get the read notification.
377             #[cfg(windows)]
378             (
379                 self.overlapped_wrapper.get_h_event_ref().unwrap(),
380                 Token::RxTap,
381             ),
382             #[cfg(any(target_os = "android", target_os = "linux"))]
383             (self.tap.get_read_notifier(), Token::RxTap),
384             (self.rx_queue.event(), Token::RxQueue),
385             (self.tx_queue.event(), Token::TxQueue),
386             (&self.kill_evt, Token::Kill),
387         ])
388         .map_err(NetError::CreateWaitContext)?;
389 
390         if let Some(ctrl_queue) = &self.ctrl_queue {
391             wait_ctx
392                 .add(ctrl_queue.event(), Token::CtrlQueue)
393                 .map_err(NetError::CreateWaitContext)?;
394         }
395 
396         if handle_interrupt_resample {
397             if let Some(resample_evt) = self.interrupt.get_resample_evt() {
398                 wait_ctx
399                     .add(resample_evt, Token::InterruptResample)
400                     .map_err(NetError::CreateWaitContext)?;
401             }
402         }
403 
404         let mut tap_polling_enabled = true;
405         'wait: loop {
406             let events = wait_ctx.wait().map_err(NetError::WaitError)?;
407             for event in events.iter().filter(|e| e.is_readable) {
408                 match event.token {
409                     Token::RxTap => {
410                         let _trace = cros_tracing::trace_event!(VirtioNet, "handle RxTap event");
411                         self.handle_rx_token(&wait_ctx)?;
412                         tap_polling_enabled = false;
413                     }
414                     Token::RxQueue => {
415                         let _trace = cros_tracing::trace_event!(VirtioNet, "handle RxQueue event");
416                         if let Err(e) = self.rx_queue.event().wait() {
417                             error!("net: error reading rx queue Event: {}", e);
418                             break 'wait;
419                         }
420                         self.handle_rx_queue(&wait_ctx, tap_polling_enabled)?;
421                         tap_polling_enabled = true;
422                     }
423                     Token::TxQueue => {
424                         let _trace = cros_tracing::trace_event!(VirtioNet, "handle TxQueue event");
425                         if let Err(e) = self.tx_queue.event().wait() {
426                             error!("net: error reading tx queue Event: {}", e);
427                             break 'wait;
428                         }
429                         self.process_tx();
430                     }
431                     Token::CtrlQueue => {
432                         let _trace =
433                             cros_tracing::trace_event!(VirtioNet, "handle CtrlQueue event");
434                         if let Some(ctrl_evt) = self.ctrl_queue.as_ref().map(|q| q.event()) {
435                             if let Err(e) = ctrl_evt.wait() {
436                                 error!("net: error reading ctrl queue Event: {}", e);
437                                 break 'wait;
438                             }
439                         } else {
440                             break 'wait;
441                         }
442                         if let Err(e) = self.process_ctrl() {
443                             error!("net: failed to process control message: {}", e);
444                             break 'wait;
445                         }
446                     }
447                     Token::InterruptResample => {
448                         let _trace =
449                             cros_tracing::trace_event!(VirtioNet, "handle InterruptResample event");
450                         // We can unwrap safely because interrupt must have the event.
451                         let _ = self.interrupt.get_resample_evt().unwrap().wait();
452                         self.interrupt.do_interrupt_resample();
453                     }
454                     Token::Kill => {
455                         let _ = self.kill_evt.wait();
456                         break 'wait;
457                     }
458                 }
459             }
460         }
461         Ok(())
462     }
463 }
464 
build_config(vq_pairs: u16, mtu: u16, mac: Option<[u8; 6]>) -> VirtioNetConfig465 pub fn build_config(vq_pairs: u16, mtu: u16, mac: Option<[u8; 6]>) -> VirtioNetConfig {
466     VirtioNetConfig {
467         max_vq_pairs: Le16::from(vq_pairs),
468         mtu: Le16::from(mtu),
469         mac: mac.unwrap_or_default(),
470         // Other field has meaningful value when the corresponding feature
471         // is enabled, but all these features aren't supported now.
472         // So set them to default.
473         ..Default::default()
474     }
475 }
476 
477 pub struct Net<T: TapT + ReadNotifier + 'static> {
478     guest_mac: Option<[u8; 6]>,
479     queue_sizes: Box<[u16]>,
480     worker_threads: Vec<WorkerThread<Worker<T>>>,
481     taps: Vec<T>,
482     avail_features: u64,
483     acked_features: u64,
484     mtu: u16,
485     pci_address: Option<PciAddress>,
486     #[cfg(windows)]
487     slirp_kill_evt: Option<Event>,
488 }
489 
490 #[derive(Serialize, Deserialize)]
491 struct NetSnapshot {
492     avail_features: u64,
493     acked_features: u64,
494 }
495 
496 impl<T> Net<T>
497 where
498     T: TapT + ReadNotifier,
499 {
500     /// Creates a new virtio network device from a tap device that has already been
501     /// 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>502     pub fn new(
503         base_features: u64,
504         tap: T,
505         vq_pairs: u16,
506         mac_addr: Option<MacAddress>,
507         use_packed_queue: bool,
508         pci_address: Option<PciAddress>,
509     ) -> Result<Net<T>, NetError> {
510         let taps = tap.into_mq_taps(vq_pairs).map_err(NetError::TapOpen)?;
511 
512         let mut mtu = u16::MAX;
513         // This would also validate a tap created by Self::new(), but that's a good thing as it
514         // would ensure that any changes in the creation procedure are matched in the validation.
515         // Plus we still need to set the offload and vnet_hdr_size values.
516         for tap in &taps {
517             validate_and_configure_tap(tap, vq_pairs)?;
518             mtu = std::cmp::min(mtu, tap.mtu().map_err(NetError::TapGetMtu)?);
519         }
520 
521         // Indicate that the TAP device supports a number of features, such as:
522         // Partial checksum offload
523         // TSO (TCP segmentation offload)
524         // UFO (UDP fragmentation offload)
525         // See the network device feature bits section for further details:
526         //     http://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html#x1-1970003
527         let mut avail_features = base_features
528             | 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
529             | 1 << virtio_net::VIRTIO_NET_F_CSUM
530             | 1 << virtio_net::VIRTIO_NET_F_CTRL_VQ
531             | 1 << virtio_net::VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
532             | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
533             | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
534             | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
535             | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
536             | 1 << virtio_net::VIRTIO_NET_F_MTU;
537 
538         if vq_pairs > 1 {
539             avail_features |= 1 << virtio_net::VIRTIO_NET_F_MQ;
540         }
541 
542         if use_packed_queue {
543             avail_features |= 1 << VIRTIO_F_RING_PACKED;
544         }
545 
546         if mac_addr.is_some() {
547             avail_features |= 1 << virtio_net::VIRTIO_NET_F_MAC;
548         }
549 
550         Self::new_internal(
551             taps,
552             avail_features,
553             mtu,
554             mac_addr,
555             pci_address,
556             #[cfg(windows)]
557             None,
558         )
559     }
560 
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>561     pub(crate) fn new_internal(
562         taps: Vec<T>,
563         avail_features: u64,
564         mtu: u16,
565         mac_addr: Option<MacAddress>,
566         pci_address: Option<PciAddress>,
567         #[cfg(windows)] slirp_kill_evt: Option<Event>,
568     ) -> Result<Self, NetError> {
569         let net = Self {
570             guest_mac: mac_addr.map(|mac| mac.octets()),
571             queue_sizes: vec![QUEUE_SIZE; taps.len() * 2 + 1].into_boxed_slice(),
572             worker_threads: Vec::new(),
573             taps,
574             avail_features,
575             acked_features: 0u64,
576             mtu,
577             pci_address,
578             #[cfg(windows)]
579             slirp_kill_evt: None,
580         };
581         cros_tracing::trace_simple_print!("New Net device created: {:?}", net);
582         Ok(net)
583     }
584 
585     /// Returns the maximum number of receive/transmit queue pairs for this device.
586     /// Only relevant when multi-queue support is negotiated.
max_virtqueue_pairs(&self) -> usize587     fn max_virtqueue_pairs(&self) -> usize {
588         self.taps.len()
589     }
590 }
591 
592 impl<T> Drop for Net<T>
593 where
594     T: TapT + ReadNotifier,
595 {
drop(&mut self)596     fn drop(&mut self) {
597         #[cfg(windows)]
598         {
599             if let Some(slirp_kill_evt) = self.slirp_kill_evt.take() {
600                 let _ = slirp_kill_evt.signal();
601             }
602         }
603     }
604 }
605 
606 impl<T> VirtioDevice for Net<T>
607 where
608     T: 'static + TapT + ReadNotifier,
609 {
keep_rds(&self) -> Vec<RawDescriptor>610     fn keep_rds(&self) -> Vec<RawDescriptor> {
611         let mut keep_rds = Vec::new();
612 
613         for tap in &self.taps {
614             keep_rds.push(tap.as_raw_descriptor());
615         }
616 
617         keep_rds
618     }
619 
device_type(&self) -> DeviceType620     fn device_type(&self) -> DeviceType {
621         DeviceType::Net
622     }
623 
queue_max_sizes(&self) -> &[u16]624     fn queue_max_sizes(&self) -> &[u16] {
625         &self.queue_sizes
626     }
627 
features(&self) -> u64628     fn features(&self) -> u64 {
629         self.avail_features
630     }
631 
ack_features(&mut self, value: u64)632     fn ack_features(&mut self, value: u64) {
633         let mut v = value;
634 
635         // Check if the guest is ACK'ing a feature that we didn't claim to have.
636         let unrequested_features = v & !self.avail_features;
637         if unrequested_features != 0 {
638             warn!("net: virtio net got unknown feature ack: {:x}", v);
639 
640             // Don't count these features as acked.
641             v &= !unrequested_features;
642         }
643         self.acked_features |= v;
644 
645         // Set offload flags to match acked virtio features.
646         if let Some(tap) = self.taps.first() {
647             if let Err(e) = tap.set_offload(virtio_features_to_tap_offload(self.acked_features)) {
648                 warn!(
649                     "net: failed to set tap offload to match acked features: {}",
650                     e
651                 );
652             }
653         }
654     }
655 
read_config(&self, offset: u64, data: &mut [u8])656     fn read_config(&self, offset: u64, data: &mut [u8]) {
657         let vq_pairs = self.queue_sizes.len() / 2;
658         let config_space = build_config(vq_pairs as u16, self.mtu, self.guest_mac);
659         copy_config(data, 0, config_space.as_bytes(), offset);
660     }
661 
activate( &mut self, _mem: GuestMemory, interrupt: Interrupt, mut queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>662     fn activate(
663         &mut self,
664         _mem: GuestMemory,
665         interrupt: Interrupt,
666         mut queues: BTreeMap<usize, Queue>,
667     ) -> anyhow::Result<()> {
668         let ctrl_vq_enabled = self.acked_features & (1 << virtio_net::VIRTIO_NET_F_CTRL_VQ) != 0;
669         let mq_enabled = self.acked_features & (1 << virtio_net::VIRTIO_NET_F_MQ) != 0;
670 
671         let vq_pairs = if mq_enabled {
672             self.max_virtqueue_pairs()
673         } else {
674             1
675         };
676 
677         let mut num_queues_expected = vq_pairs * 2;
678         if ctrl_vq_enabled {
679             num_queues_expected += 1;
680         }
681 
682         if queues.len() != num_queues_expected {
683             return Err(anyhow!(
684                 "net: expected {} queues, got {} queues",
685                 self.queue_sizes.len(),
686                 queues.len(),
687             ));
688         }
689 
690         if self.taps.len() < vq_pairs {
691             return Err(anyhow!(
692                 "net: expected {} taps, got {}",
693                 vq_pairs,
694                 self.taps.len()
695             ));
696         }
697 
698         for i in 0..vq_pairs {
699             let tap = self.taps.remove(0);
700             let acked_features = self.acked_features;
701             let interrupt = interrupt.clone();
702             let first_queue = i == 0;
703             // Queues alternate between rx0, tx0, rx1, tx1, ..., rxN, txN, ctrl.
704             let rx_queue = queues.pop_first().unwrap().1;
705             let tx_queue = queues.pop_first().unwrap().1;
706             let ctrl_queue = if first_queue && ctrl_vq_enabled {
707                 Some(queues.pop_last().unwrap().1)
708             } else {
709                 None
710             };
711             // Handle interrupt resampling on the first queue's thread.
712             let handle_interrupt_resample = first_queue;
713             let pairs = vq_pairs as u16;
714             #[cfg(windows)]
715             let overlapped_wrapper = OverlappedWrapper::new(true).unwrap();
716             self.worker_threads
717                 .push(WorkerThread::start(format!("v_net:{i}"), move |kill_evt| {
718                     let mut worker = Worker {
719                         interrupt,
720                         rx_queue,
721                         tx_queue,
722                         ctrl_queue,
723                         tap,
724                         #[cfg(windows)]
725                         overlapped_wrapper,
726                         acked_features,
727                         vq_pairs: pairs,
728                         #[cfg(windows)]
729                         rx_buf: [0u8; MAX_BUFFER_SIZE],
730                         #[cfg(windows)]
731                         rx_count: 0,
732                         #[cfg(windows)]
733                         deferred_rx: false,
734                         kill_evt,
735                     };
736                     let result = worker.run(handle_interrupt_resample);
737                     if let Err(e) = result {
738                         error!("net worker thread exited with error: {}", e);
739                     }
740                     worker
741                 }));
742         }
743         cros_tracing::trace_simple_print!("Net device activated: {:?}", self);
744         Ok(())
745     }
746 
pci_address(&self) -> Option<PciAddress>747     fn pci_address(&self) -> Option<PciAddress> {
748         self.pci_address
749     }
750 
virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>>751     fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> {
752         if self.worker_threads.is_empty() {
753             return Ok(None);
754         }
755         let mut queues = BTreeMap::new();
756         let mut queue_index = 0;
757         let mut ctrl_queue = None;
758         for worker_thread in self.worker_threads.drain(..) {
759             let mut worker = worker_thread.stop();
760             if worker.ctrl_queue.is_some() {
761                 ctrl_queue = worker.ctrl_queue.take();
762             }
763             self.taps.push(worker.tap);
764             queues.insert(queue_index + 0, worker.rx_queue);
765             queues.insert(queue_index + 1, worker.tx_queue);
766             queue_index += 2;
767         }
768         if let Some(ctrl_queue) = ctrl_queue {
769             queues.insert(queue_index, ctrl_queue);
770         }
771         Ok(Some(queues))
772     }
773 
virtio_wake( &mut self, device_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>, ) -> anyhow::Result<()>774     fn virtio_wake(
775         &mut self,
776         device_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>,
777     ) -> anyhow::Result<()> {
778         match device_state {
779             None => Ok(()),
780             Some((mem, interrupt, queues)) => {
781                 // TODO: activate is just what we want at the moment, but we should probably move
782                 // it into a "start workers" function to make it obvious that it isn't strictly
783                 // used for activate events.
784                 self.activate(mem, interrupt, queues)?;
785                 Ok(())
786             }
787         }
788     }
789 
virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value>790     fn virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
791         serde_json::to_value(NetSnapshot {
792             acked_features: self.acked_features,
793             avail_features: self.avail_features,
794         })
795         .context("failed to snapshot virtio Net device")
796     }
797 
virtio_restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>798     fn virtio_restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
799         let deser: NetSnapshot =
800             serde_json::from_value(data).context("failed to deserialize Net device")?;
801         anyhow::ensure!(
802             self.avail_features == deser.avail_features,
803             "Available features for net device do not match. expected: {},  got: {}",
804             deser.avail_features,
805             self.avail_features
806         );
807         self.acked_features = deser.acked_features;
808         Ok(())
809     }
810 
reset(&mut self) -> anyhow::Result<()>811     fn reset(&mut self) -> anyhow::Result<()> {
812         for worker_thread in self.worker_threads.drain(..) {
813             let worker = worker_thread.stop();
814             self.taps.push(worker.tap);
815         }
816 
817         Ok(())
818     }
819 }
820 
821 impl<T> std::fmt::Debug for Net<T>
822 where
823     T: TapT + ReadNotifier,
824 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result825     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
826         f.debug_struct("Net")
827             .field("guest_mac", &self.guest_mac)
828             .field("queue_sizes", &self.queue_sizes)
829             .field("worker_threads_size", &self.worker_threads.len())
830             .field("taps_size", &self.taps.len())
831             .field("avail_features", &self.avail_features)
832             .field("acked_features", &self.acked_features)
833             .field("mtu", &self.mtu)
834             .finish()
835     }
836 }
837 
838 #[cfg(test)]
839 mod tests {
840     use serde_keyvalue::*;
841 
842     use super::*;
843 
from_net_arg(options: &str) -> Result<NetParameters, ParseError>844     fn from_net_arg(options: &str) -> Result<NetParameters, ParseError> {
845         from_key_values(options)
846     }
847 
848     #[test]
params_from_key_values()849     fn params_from_key_values() {
850         let params = from_net_arg("");
851         assert!(params.is_err());
852 
853         let params = from_net_arg("tap-name=tap").unwrap();
854         assert_eq!(
855             params,
856             NetParameters {
857                 #[cfg(any(target_os = "android", target_os = "linux"))]
858                 vhost_net: None,
859                 vq_pairs: None,
860                 mode: NetParametersMode::TapName {
861                     tap_name: "tap".to_string(),
862                     mac: None
863                 },
864                 packed_queue: false,
865                 pci_address: None,
866             }
867         );
868 
869         let params = from_net_arg("tap-name=tap,mac=\"3d:70:eb:61:1a:91\"").unwrap();
870         assert_eq!(
871             params,
872             NetParameters {
873                 #[cfg(any(target_os = "android", target_os = "linux"))]
874                 vhost_net: None,
875                 vq_pairs: None,
876                 mode: NetParametersMode::TapName {
877                     tap_name: "tap".to_string(),
878                     mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
879                 },
880                 packed_queue: false,
881                 pci_address: None,
882             }
883         );
884 
885         let params = from_net_arg("tap-fd=12").unwrap();
886         assert_eq!(
887             params,
888             NetParameters {
889                 #[cfg(any(target_os = "android", target_os = "linux"))]
890                 vhost_net: None,
891                 vq_pairs: None,
892                 mode: NetParametersMode::TapFd {
893                     tap_fd: 12,
894                     mac: None
895                 },
896                 packed_queue: false,
897                 pci_address: None,
898             }
899         );
900 
901         let params = from_net_arg("tap-fd=12,mac=\"3d:70:eb:61:1a:91\"").unwrap();
902         assert_eq!(
903             params,
904             NetParameters {
905                 #[cfg(any(target_os = "android", target_os = "linux"))]
906                 vhost_net: None,
907                 vq_pairs: None,
908                 mode: NetParametersMode::TapFd {
909                     tap_fd: 12,
910                     mac: Some(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(
918             "host-ip=\"192.168.10.1\",netmask=\"255.255.255.0\",mac=\"3d:70:eb:61:1a:91\"",
919         )
920         .unwrap();
921         assert_eq!(
922             params,
923             NetParameters {
924                 #[cfg(any(target_os = "android", target_os = "linux"))]
925                 vhost_net: None,
926                 vq_pairs: None,
927                 mode: NetParametersMode::RawConfig {
928                     host_ip: Ipv4Addr::from_str("192.168.10.1").unwrap(),
929                     netmask: Ipv4Addr::from_str("255.255.255.0").unwrap(),
930                     mac: MacAddress::from_str("3d:70:eb:61:1a:91").unwrap(),
931                 },
932                 packed_queue: false,
933                 pci_address: None,
934             }
935         );
936 
937         let params = from_net_arg("tap-fd=12,pci-address=00:01.1").unwrap();
938         assert_eq!(
939             params,
940             NetParameters {
941                 #[cfg(any(target_os = "android", target_os = "linux"))]
942                 vhost_net: None,
943                 vq_pairs: None,
944                 mode: NetParametersMode::TapFd {
945                     tap_fd: 12,
946                     mac: None,
947                 },
948                 packed_queue: false,
949                 pci_address: Some(PciAddress {
950                     bus: 0,
951                     dev: 1,
952                     func: 1,
953                 }),
954             }
955         );
956 
957         // wrong pci format
958         assert!(from_net_arg("tap-fd=12,pci-address=hello").is_err());
959 
960         // missing netmask
961         assert!(from_net_arg("host-ip=\"192.168.10.1\",mac=\"3d:70:eb:61:1a:91\"").is_err());
962 
963         // invalid parameter
964         assert!(from_net_arg("tap-name=tap,foomatic=true").is_err());
965     }
966 
967     #[test]
968     #[cfg(any(target_os = "android", target_os = "linux"))]
params_from_key_values_vhost_net()969     fn params_from_key_values_vhost_net() {
970         let params = from_net_arg(
971             "vhost-net=[device=/dev/foo],\
972                 host-ip=\"192.168.10.1\",\
973                 netmask=\"255.255.255.0\",\
974                 mac=\"3d:70:eb:61:1a:91\"",
975         )
976         .unwrap();
977         assert_eq!(
978             params,
979             NetParameters {
980                 vhost_net: Some(VhostNetParameters {
981                     device: PathBuf::from("/dev/foo")
982                 }),
983                 vq_pairs: None,
984                 mode: NetParametersMode::RawConfig {
985                     host_ip: Ipv4Addr::from_str("192.168.10.1").unwrap(),
986                     netmask: Ipv4Addr::from_str("255.255.255.0").unwrap(),
987                     mac: MacAddress::from_str("3d:70:eb:61:1a:91").unwrap(),
988                 },
989                 packed_queue: false,
990                 pci_address: None,
991             }
992         );
993 
994         let params = from_net_arg("tap-fd=3,vhost-net").unwrap();
995         assert_eq!(
996             params,
997             NetParameters {
998                 vhost_net: Some(Default::default()),
999                 vq_pairs: None,
1000                 mode: NetParametersMode::TapFd {
1001                     tap_fd: 3,
1002                     mac: None
1003                 },
1004                 packed_queue: false,
1005                 pci_address: None,
1006             }
1007         );
1008 
1009         let params = from_net_arg("vhost-net,tap-name=crosvm_tap").unwrap();
1010         assert_eq!(
1011             params,
1012             NetParameters {
1013                 vhost_net: Some(Default::default()),
1014                 vq_pairs: None,
1015                 mode: NetParametersMode::TapName {
1016                     tap_name: "crosvm_tap".to_owned(),
1017                     mac: None
1018                 },
1019                 packed_queue: false,
1020                 pci_address: None,
1021             }
1022         );
1023 
1024         let params =
1025             from_net_arg("vhost-net,mac=\"3d:70:eb:61:1a:91\",tap-name=crosvm_tap").unwrap();
1026         assert_eq!(
1027             params,
1028             NetParameters {
1029                 vhost_net: Some(Default::default()),
1030                 vq_pairs: None,
1031                 mode: NetParametersMode::TapName {
1032                     tap_name: "crosvm_tap".to_owned(),
1033                     mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
1034                 },
1035                 packed_queue: false,
1036                 pci_address: None,
1037             }
1038         );
1039 
1040         let params = from_net_arg("tap-name=tap,packed-queue=true").unwrap();
1041         assert_eq!(
1042             params,
1043             NetParameters {
1044                 #[cfg(any(target_os = "android", target_os = "linux"))]
1045                 vhost_net: None,
1046                 vq_pairs: None,
1047                 mode: NetParametersMode::TapName {
1048                     tap_name: "tap".to_string(),
1049                     mac: None
1050                 },
1051                 packed_queue: true,
1052                 pci_address: None,
1053             }
1054         );
1055 
1056         let params = from_net_arg("tap-name=tap,packed-queue").unwrap();
1057         assert_eq!(
1058             params,
1059             NetParameters {
1060                 #[cfg(any(target_os = "android", target_os = "linux"))]
1061                 vhost_net: None,
1062                 vq_pairs: None,
1063                 mode: NetParametersMode::TapName {
1064                     tap_name: "tap".to_string(),
1065                     mac: None
1066                 },
1067                 packed_queue: true,
1068                 pci_address: None,
1069             }
1070         );
1071 
1072         let params = from_net_arg("vhost-net,tap-name=crosvm_tap,pci-address=00:01.1").unwrap();
1073         assert_eq!(
1074             params,
1075             NetParameters {
1076                 vhost_net: Some(Default::default()),
1077                 vq_pairs: None,
1078                 mode: NetParametersMode::TapName {
1079                     tap_name: "crosvm_tap".to_owned(),
1080                     mac: None,
1081                 },
1082                 packed_queue: false,
1083                 pci_address: Some(PciAddress {
1084                     bus: 0,
1085                     dev: 1,
1086                     func: 1,
1087                 }),
1088             }
1089         );
1090 
1091         // mixed configs
1092         assert!(from_net_arg(
1093             "tap-name=tap,\
1094             vhost-net,\
1095             host-ip=\"192.168.10.1\",\
1096             netmask=\"255.255.255.0\",\
1097             mac=\"3d:70:eb:61:1a:91\"",
1098         )
1099         .is_err());
1100     }
1101 }
1102