devices/virtio/
net.rs

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
5mod sys;
6
7use std::collections::BTreeMap;
8use std::fmt;
9use std::io;
10use std::io::Write;
11use std::net::Ipv4Addr;
12use std::os::raw::c_uint;
13use std::path::PathBuf;
14use std::str::FromStr;
15
16use anyhow::anyhow;
17use anyhow::Context;
18use base::error;
19#[cfg(windows)]
20use base::named_pipes::OverlappedWrapper;
21use base::warn;
22use base::Error as SysError;
23use base::Event;
24use base::EventToken;
25use base::RawDescriptor;
26use base::ReadNotifier;
27use base::WaitContext;
28use base::WorkerThread;
29use data_model::Le16;
30use data_model::Le64;
31use net_util::Error as TapError;
32use net_util::MacAddress;
33use net_util::TapT;
34use remain::sorted;
35use serde::Deserialize;
36use serde::Serialize;
37use snapshot::AnySnapshot;
38use thiserror::Error as ThisError;
39use virtio_sys::virtio_config::VIRTIO_F_RING_PACKED;
40use virtio_sys::virtio_net;
41use virtio_sys::virtio_net::VIRTIO_NET_CTRL_GUEST_OFFLOADS;
42use virtio_sys::virtio_net::VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET;
43use virtio_sys::virtio_net::VIRTIO_NET_CTRL_MQ;
44use virtio_sys::virtio_net::VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET;
45use virtio_sys::virtio_net::VIRTIO_NET_ERR;
46use virtio_sys::virtio_net::VIRTIO_NET_OK;
47use vm_memory::GuestMemory;
48use zerocopy::FromBytes;
49use zerocopy::Immutable;
50use zerocopy::IntoBytes;
51use zerocopy::KnownLayout;
52
53use super::copy_config;
54use super::DeviceType;
55use super::Interrupt;
56use super::Queue;
57use super::Reader;
58use super::VirtioDevice;
59use 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)]
65pub(crate) const MAX_BUFFER_SIZE: usize = 65562;
66const QUEUE_SIZE: u16 = 256;
67
68#[cfg(any(target_os = "android", target_os = "linux"))]
69pub static VHOST_NET_DEFAULT_PATH: &str = "/dev/vhost-net";
70
71pub(crate) use sys::process_mrg_rx;
72pub(crate) use sys::process_rx;
73pub(crate) use sys::process_tx;
74pub(crate) use sys::validate_and_configure_tap;
75pub(crate) use sys::virtio_features_to_tap_offload;
76pub(crate) use sys::PendingBuffer;
77
78#[sorted]
79#[derive(ThisError, Debug)]
80pub enum NetError {
81    /// Cloning kill event failed.
82    #[error("failed to clone kill event: {0}")]
83    CloneKillEvent(SysError),
84    /// Creating kill event failed.
85    #[error("failed to create kill event: {0}")]
86    CreateKillEvent(SysError),
87    /// Creating WaitContext failed.
88    #[error("failed to create wait context: {0}")]
89    CreateWaitContext(SysError),
90    /// Adding the tap descriptor back to the event context failed.
91    #[error("failed to add tap trigger to event context: {0}")]
92    EventAddTap(SysError),
93    /// Removing the tap descriptor from the event context failed.
94    #[error("failed to remove tap trigger from event context: {0}")]
95    EventRemoveTap(SysError),
96    /// Invalid control command
97    #[error("invalid control command")]
98    InvalidCmd,
99    /// Error reading data from control queue.
100    #[error("failed to read control message data: {0}")]
101    ReadCtrlData(io::Error),
102    /// Error reading header from control queue.
103    #[error("failed to read control message header: {0}")]
104    ReadCtrlHeader(io::Error),
105    /// There are no more available descriptors to receive into.
106    #[cfg(any(target_os = "android", target_os = "linux"))]
107    #[error("no rx descriptors available")]
108    RxDescriptorsExhausted,
109    /// Failure creating the Slirp loop.
110    #[cfg(windows)]
111    #[error("error creating Slirp: {0}")]
112    SlirpCreateError(net_util::Error),
113    /// Enabling tap interface failed.
114    #[error("failed to enable tap interface: {0}")]
115    TapEnable(TapError),
116    /// Couldn't get the MTU from the tap device.
117    #[error("failed to get tap interface MTU: {0}")]
118    TapGetMtu(TapError),
119    /// Open tap device failed.
120    #[error("failed to open tap device: {0}")]
121    TapOpen(TapError),
122    /// Setting tap IP failed.
123    #[error("failed to set tap IP: {0}")]
124    TapSetIp(TapError),
125    /// Setting tap mac address failed.
126    #[error("failed to set tap mac address: {0}")]
127    TapSetMacAddress(TapError),
128    /// Setting tap netmask failed.
129    #[error("failed to set tap netmask: {0}")]
130    TapSetNetmask(TapError),
131    /// Setting tap offload failed.
132    #[error("failed to set tap offload: {0}")]
133    TapSetOffload(TapError),
134    /// Setting vnet header size failed.
135    #[error("failed to set vnet header size: {0}")]
136    TapSetVnetHdrSize(TapError),
137    /// Validating tap interface failed.
138    #[error("failed to validate tap interface: {0}")]
139    TapValidate(String),
140    /// Removing read event from the tap fd events failed.
141    #[error("failed to disable EPOLLIN on tap fd: {0}")]
142    WaitContextDisableTap(SysError),
143    /// Adding read event to the tap fd events failed.
144    #[error("failed to enable EPOLLIN on tap fd: {0}")]
145    WaitContextEnableTap(SysError),
146    /// Error while waiting for events.
147    #[error("error while waiting for events: {0}")]
148    WaitError(SysError),
149    /// Failed writing an ack in response to a control message.
150    #[error("failed to write control message ack: {0}")]
151    WriteAck(io::Error),
152    /// Writing to a buffer in the guest failed.
153    #[cfg(any(target_os = "android", target_os = "linux"))]
154    #[error("failed to write to guest buffer: {0}")]
155    WriteBuffer(io::Error),
156}
157
158#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
159#[serde(untagged, deny_unknown_fields)]
160pub enum NetParametersMode {
161    #[serde(rename_all = "kebab-case")]
162    TapName {
163        tap_name: String,
164        mac: Option<MacAddress>,
165    },
166    #[serde(rename_all = "kebab-case")]
167    TapFd {
168        tap_fd: i32,
169        mac: Option<MacAddress>,
170    },
171    #[serde(rename_all = "kebab-case")]
172    RawConfig {
173        host_ip: Ipv4Addr,
174        netmask: Ipv4Addr,
175        mac: MacAddress,
176    },
177}
178
179#[cfg(any(target_os = "android", target_os = "linux"))]
180fn vhost_net_device_path_default() -> PathBuf {
181    PathBuf::from(VHOST_NET_DEFAULT_PATH)
182}
183
184#[cfg(any(target_os = "android", target_os = "linux"))]
185#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
186#[serde(rename_all = "kebab-case", deny_unknown_fields)]
187pub struct VhostNetParameters {
188    #[serde(default = "vhost_net_device_path_default")]
189    pub device: PathBuf,
190}
191
192#[cfg(any(target_os = "android", target_os = "linux"))]
193impl Default for VhostNetParameters {
194    fn default() -> Self {
195        Self {
196            device: vhost_net_device_path_default(),
197        }
198    }
199}
200
201#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
202#[serde(rename_all = "kebab-case")]
203pub struct NetParameters {
204    #[serde(flatten)]
205    pub mode: NetParametersMode,
206    pub vq_pairs: Option<u16>,
207    // Style-guide asks to refrain against #[cfg] directives in structs, this is an exception due
208    // to the fact this struct is used for argument parsing.
209    #[cfg(any(target_os = "android", target_os = "linux"))]
210    pub vhost_net: Option<VhostNetParameters>,
211    #[serde(default)]
212    pub packed_queue: bool,
213    pub pci_address: Option<PciAddress>,
214    #[serde(default)]
215    pub mrg_rxbuf: bool,
216}
217
218impl FromStr for NetParameters {
219    type Err = String;
220    fn from_str(s: &str) -> Result<Self, Self::Err> {
221        serde_keyvalue::from_key_values(s).map_err(|e| e.to_string())
222    }
223}
224
225#[repr(C, packed)]
226#[derive(Debug, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
227pub struct virtio_net_ctrl_hdr {
228    pub class: u8,
229    pub cmd: u8,
230}
231
232#[derive(Debug, Clone, Copy, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
233#[repr(C)]
234pub struct VirtioNetConfig {
235    mac: [u8; 6],
236    status: Le16,
237    max_vq_pairs: Le16,
238    mtu: Le16,
239}
240
241fn process_ctrl_request<T: TapT>(
242    reader: &mut Reader,
243    tap: &mut T,
244    acked_features: u64,
245    vq_pairs: u16,
246) -> Result<(), NetError> {
247    let ctrl_hdr: virtio_net_ctrl_hdr = reader.read_obj().map_err(NetError::ReadCtrlHeader)?;
248
249    match ctrl_hdr.class as c_uint {
250        VIRTIO_NET_CTRL_GUEST_OFFLOADS => {
251            if ctrl_hdr.cmd != VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET as u8 {
252                error!(
253                    "invalid cmd for VIRTIO_NET_CTRL_GUEST_OFFLOADS: {}",
254                    ctrl_hdr.cmd
255                );
256                return Err(NetError::InvalidCmd);
257            }
258            let offloads: Le64 = reader.read_obj().map_err(NetError::ReadCtrlData)?;
259            let tap_offloads = virtio_features_to_tap_offload(offloads.into());
260            tap.set_offload(tap_offloads)
261                .map_err(NetError::TapSetOffload)?;
262        }
263        VIRTIO_NET_CTRL_MQ => {
264            if ctrl_hdr.cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET as u8 {
265                let pairs: Le16 = reader.read_obj().map_err(NetError::ReadCtrlData)?;
266                // Simple handle it now
267                if acked_features & 1 << virtio_net::VIRTIO_NET_F_MQ == 0
268                    || pairs.to_native() != vq_pairs
269                {
270                    error!(
271                        "Invalid VQ_PAIRS_SET cmd, driver request pairs: {}, device vq pairs: {}",
272                        pairs.to_native(),
273                        vq_pairs
274                    );
275                    return Err(NetError::InvalidCmd);
276                }
277            }
278        }
279        _ => {
280            warn!(
281                "unimplemented class for VIRTIO_NET_CTRL_GUEST_OFFLOADS: {}",
282                ctrl_hdr.class
283            );
284            return Err(NetError::InvalidCmd);
285        }
286    }
287
288    Ok(())
289}
290
291pub fn process_ctrl<T: TapT>(
292    ctrl_queue: &mut Queue,
293    tap: &mut T,
294    acked_features: u64,
295    vq_pairs: u16,
296) -> Result<(), NetError> {
297    while let Some(mut desc_chain) = ctrl_queue.pop() {
298        if let Err(e) = process_ctrl_request(&mut desc_chain.reader, tap, acked_features, vq_pairs)
299        {
300            error!("process_ctrl_request failed: {}", e);
301            desc_chain
302                .writer
303                .write_all(&[VIRTIO_NET_ERR as u8])
304                .map_err(NetError::WriteAck)?;
305        } else {
306            desc_chain
307                .writer
308                .write_all(&[VIRTIO_NET_OK as u8])
309                .map_err(NetError::WriteAck)?;
310        }
311        ctrl_queue.add_used(desc_chain);
312    }
313
314    ctrl_queue.trigger_interrupt();
315    Ok(())
316}
317
318#[derive(EventToken, Debug, Clone)]
319pub enum Token {
320    // A frame is available for reading from the tap device to receive in the guest.
321    RxTap,
322    // The guest has made a buffer available to receive a frame into.
323    RxQueue,
324    // The transmit queue has a frame that is ready to send from the guest.
325    TxQueue,
326    // The control queue has a message.
327    CtrlQueue,
328    // crosvm has requested the device to shut down.
329    Kill,
330}
331
332pub(super) struct Worker<T: TapT> {
333    pub(super) rx_queue: Queue,
334    pub(super) tx_queue: Queue,
335    pub(super) ctrl_queue: Option<Queue>,
336    pub(super) tap: T,
337    #[cfg(windows)]
338    pub(super) overlapped_wrapper: OverlappedWrapper,
339    #[cfg(windows)]
340    pub(super) rx_buf: [u8; MAX_BUFFER_SIZE],
341    #[cfg(windows)]
342    pub(super) rx_count: usize,
343    #[cfg(windows)]
344    pub(super) deferred_rx: bool,
345    acked_features: u64,
346    vq_pairs: u16,
347    #[allow(dead_code)]
348    kill_evt: Event,
349}
350
351impl<T> Worker<T>
352where
353    T: TapT + ReadNotifier,
354{
355    fn process_tx(&mut self) {
356        process_tx(&mut self.tx_queue, &mut self.tap)
357    }
358
359    fn process_ctrl(&mut self) -> Result<(), NetError> {
360        let ctrl_queue = match self.ctrl_queue.as_mut() {
361            Some(queue) => queue,
362            None => return Ok(()),
363        };
364
365        process_ctrl(
366            ctrl_queue,
367            &mut self.tap,
368            self.acked_features,
369            self.vq_pairs,
370        )
371    }
372
373    fn run(&mut self) -> 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        let mut tap_polling_enabled = true;
399        let mut pending_buffer_for_mrg_rx = PendingBuffer::new();
400        'wait: loop {
401            let events = wait_ctx.wait().map_err(NetError::WaitError)?;
402            for event in events.iter() {
403                if event.is_hungup && matches!(event.token, Token::RxTap) {
404                    warn!("net: TAP fd hung up, exiting worker");
405                    break 'wait;
406                }
407                if !event.is_readable {
408                    continue;
409                }
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, &mut pending_buffer_for_mrg_rx)?;
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::Kill => {
450                        let _ = self.kill_evt.wait();
451                        break 'wait;
452                    }
453                }
454            }
455        }
456        Ok(())
457    }
458}
459
460pub fn build_config(vq_pairs: u16, mtu: u16, mac: Option<[u8; 6]>) -> VirtioNetConfig {
461    VirtioNetConfig {
462        max_vq_pairs: Le16::from(vq_pairs),
463        mtu: Le16::from(mtu),
464        mac: mac.unwrap_or_default(),
465        // Other field has meaningful value when the corresponding feature
466        // is enabled, but all these features aren't supported now.
467        // So set them to default.
468        ..Default::default()
469    }
470}
471
472pub struct Net<T: TapT + ReadNotifier + 'static> {
473    guest_mac: Option<[u8; 6]>,
474    queue_sizes: Box<[u16]>,
475    worker_threads: Vec<WorkerThread<Worker<T>>>,
476    taps: Vec<T>,
477    avail_features: u64,
478    acked_features: u64,
479    mtu: u16,
480    pci_address: Option<PciAddress>,
481    #[cfg(windows)]
482    slirp_kill_evt: Option<Event>,
483}
484
485#[derive(Serialize, Deserialize)]
486struct NetSnapshot {
487    avail_features: u64,
488    acked_features: u64,
489}
490
491impl<T> Net<T>
492where
493    T: TapT + ReadNotifier,
494{
495    /// Creates a new virtio network device from a tap device that has already been
496    /// configured.
497    pub fn new(
498        base_features: u64,
499        tap: T,
500        vq_pairs: u16,
501        mac_addr: Option<MacAddress>,
502        use_packed_queue: bool,
503        pci_address: Option<PciAddress>,
504        mrg_rxbuf: bool,
505    ) -> Result<Net<T>, NetError> {
506        let taps = tap.into_mq_taps(vq_pairs).map_err(NetError::TapOpen)?;
507
508        let mut mtu = u16::MAX;
509        // This would also validate a tap created by Self::new(), but that's a good thing as it
510        // would ensure that any changes in the creation procedure are matched in the validation.
511        // Plus we still need to set the offload and vnet_hdr_size values.
512        for tap in &taps {
513            validate_and_configure_tap(tap, vq_pairs)?;
514            mtu = std::cmp::min(mtu, tap.mtu().map_err(NetError::TapGetMtu)?);
515        }
516
517        // Indicate that the TAP device supports a number of features, such as:
518        // Partial checksum offload
519        // TSO (TCP segmentation offload)
520        // UFO (UDP fragmentation offload)
521        // See the network device feature bits section for further details:
522        //     http://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html#x1-1970003
523        let mut avail_features = base_features
524            | 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
525            | 1 << virtio_net::VIRTIO_NET_F_CSUM
526            | 1 << virtio_net::VIRTIO_NET_F_CTRL_VQ
527            | 1 << virtio_net::VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
528            | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
529            | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
530            | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
531            | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
532            | 1 << virtio_net::VIRTIO_NET_F_MTU;
533
534        if vq_pairs > 1 {
535            avail_features |= 1 << virtio_net::VIRTIO_NET_F_MQ;
536        }
537
538        if use_packed_queue {
539            avail_features |= 1 << VIRTIO_F_RING_PACKED;
540        }
541
542        if mac_addr.is_some() {
543            avail_features |= 1 << virtio_net::VIRTIO_NET_F_MAC;
544        }
545
546        if mrg_rxbuf {
547            avail_features |= 1 << virtio_net::VIRTIO_NET_F_MRG_RXBUF;
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
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.
587    fn max_virtqueue_pairs(&self) -> usize {
588        self.taps.len()
589    }
590}
591
592impl<T> Drop for Net<T>
593where
594    T: TapT + ReadNotifier,
595{
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
606impl<T> VirtioDevice for Net<T>
607where
608    T: 'static + TapT + ReadNotifier,
609{
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
620    fn device_type(&self) -> DeviceType {
621        DeviceType::Net
622    }
623
624    fn queue_max_sizes(&self) -> &[u16] {
625        &self.queue_sizes
626    }
627
628    fn features(&self) -> u64 {
629        self.avail_features
630    }
631
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
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
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 first_queue = i == 0;
702            // Queues alternate between rx0, tx0, rx1, tx1, ..., rxN, txN, ctrl.
703            let rx_queue = queues.pop_first().unwrap().1;
704            let tx_queue = queues.pop_first().unwrap().1;
705            let ctrl_queue = if first_queue && ctrl_vq_enabled {
706                Some(queues.pop_last().unwrap().1)
707            } else {
708                None
709            };
710            let pairs = vq_pairs as u16;
711            #[cfg(windows)]
712            let overlapped_wrapper = OverlappedWrapper::new(true).unwrap();
713            self.worker_threads
714                .push(WorkerThread::start(format!("v_net:{i}"), move |kill_evt| {
715                    let mut worker = Worker {
716                        rx_queue,
717                        tx_queue,
718                        ctrl_queue,
719                        tap,
720                        #[cfg(windows)]
721                        overlapped_wrapper,
722                        acked_features,
723                        vq_pairs: pairs,
724                        #[cfg(windows)]
725                        rx_buf: [0u8; MAX_BUFFER_SIZE],
726                        #[cfg(windows)]
727                        rx_count: 0,
728                        #[cfg(windows)]
729                        deferred_rx: false,
730                        kill_evt,
731                    };
732                    let result = worker.run();
733                    if let Err(e) = result {
734                        error!("net worker thread exited with error: {}", e);
735                    }
736                    worker
737                }));
738        }
739        cros_tracing::trace_simple_print!("Net device activated: {:?}", self);
740        Ok(())
741    }
742
743    fn pci_address(&self) -> Option<PciAddress> {
744        self.pci_address
745    }
746
747    fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> {
748        if self.worker_threads.is_empty() {
749            return Ok(None);
750        }
751        let mut queues = BTreeMap::new();
752        let mut queue_index = 0;
753        let mut ctrl_queue = None;
754        for worker_thread in self.worker_threads.drain(..) {
755            let mut worker = worker_thread.stop();
756            if worker.ctrl_queue.is_some() {
757                ctrl_queue = worker.ctrl_queue.take();
758            }
759            self.taps.push(worker.tap);
760            queues.insert(queue_index + 0, worker.rx_queue);
761            queues.insert(queue_index + 1, worker.tx_queue);
762            queue_index += 2;
763        }
764        if let Some(ctrl_queue) = ctrl_queue {
765            queues.insert(queue_index, ctrl_queue);
766        }
767        Ok(Some(queues))
768    }
769
770    fn virtio_wake(
771        &mut self,
772        device_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>,
773    ) -> anyhow::Result<()> {
774        match device_state {
775            None => Ok(()),
776            Some((mem, interrupt, queues)) => {
777                // TODO: activate is just what we want at the moment, but we should probably move
778                // it into a "start workers" function to make it obvious that it isn't strictly
779                // used for activate events.
780                self.activate(mem, interrupt, queues)?;
781                Ok(())
782            }
783        }
784    }
785
786    fn virtio_snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
787        AnySnapshot::to_any(NetSnapshot {
788            acked_features: self.acked_features,
789            avail_features: self.avail_features,
790        })
791        .context("failed to snapshot virtio Net device")
792    }
793
794    fn virtio_restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
795        let deser: NetSnapshot =
796            AnySnapshot::from_any(data).context("failed to deserialize Net device")?;
797        anyhow::ensure!(
798            self.avail_features == deser.avail_features,
799            "Available features for net device do not match. expected: {},  got: {}",
800            deser.avail_features,
801            self.avail_features
802        );
803        self.acked_features = deser.acked_features;
804        Ok(())
805    }
806
807    fn reset(&mut self) -> anyhow::Result<()> {
808        for worker_thread in self.worker_threads.drain(..) {
809            let worker = worker_thread.stop();
810            self.taps.push(worker.tap);
811        }
812
813        Ok(())
814    }
815}
816
817impl<T> std::fmt::Debug for Net<T>
818where
819    T: TapT + ReadNotifier,
820{
821    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
822        f.debug_struct("Net")
823            .field("guest_mac", &self.guest_mac)
824            .field("queue_sizes", &self.queue_sizes)
825            .field("worker_threads_size", &self.worker_threads.len())
826            .field("taps_size", &self.taps.len())
827            .field("avail_features", &self.avail_features)
828            .field("acked_features", &self.acked_features)
829            .field("mtu", &self.mtu)
830            .finish()
831    }
832}
833
834#[cfg(test)]
835mod tests {
836    use serde_keyvalue::*;
837
838    use super::*;
839
840    fn from_net_arg(options: &str) -> Result<NetParameters, ParseError> {
841        from_key_values(options)
842    }
843
844    #[test]
845    fn params_from_key_values() {
846        let params = from_net_arg("");
847        assert!(params.is_err());
848
849        let params = from_net_arg("tap-name=tap").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: None
859                },
860                packed_queue: false,
861                pci_address: None,
862                mrg_rxbuf: false,
863            }
864        );
865
866        let params = from_net_arg("tap-name=tap,mrg-rxbuf=true").unwrap();
867        assert_eq!(
868            params,
869            NetParameters {
870                #[cfg(any(target_os = "android", target_os = "linux"))]
871                vhost_net: None,
872                vq_pairs: None,
873                mode: NetParametersMode::TapName {
874                    tap_name: "tap".to_string(),
875                    mac: None
876                },
877                packed_queue: false,
878                pci_address: None,
879                mrg_rxbuf: true,
880            }
881        );
882
883        let params = from_net_arg("tap-name=tap,mac=\"3d:70:eb:61:1a:91\"").unwrap();
884        assert_eq!(
885            params,
886            NetParameters {
887                #[cfg(any(target_os = "android", target_os = "linux"))]
888                vhost_net: None,
889                vq_pairs: None,
890                mode: NetParametersMode::TapName {
891                    tap_name: "tap".to_string(),
892                    mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
893                },
894                packed_queue: false,
895                pci_address: None,
896                mrg_rxbuf: false,
897            }
898        );
899
900        let params = from_net_arg("tap-fd=12").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::TapFd {
908                    tap_fd: 12,
909                    mac: None
910                },
911                packed_queue: false,
912                pci_address: None,
913                mrg_rxbuf: false,
914            }
915        );
916
917        let params = from_net_arg("tap-fd=12,mac=\"3d:70:eb:61:1a:91\"").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: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
927                },
928                packed_queue: false,
929                pci_address: None,
930                mrg_rxbuf: false,
931            }
932        );
933
934        let params = from_net_arg(
935            "host-ip=\"192.168.10.1\",netmask=\"255.255.255.0\",mac=\"3d:70:eb:61:1a:91\"",
936        )
937        .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::RawConfig {
945                    host_ip: Ipv4Addr::from_str("192.168.10.1").unwrap(),
946                    netmask: Ipv4Addr::from_str("255.255.255.0").unwrap(),
947                    mac: MacAddress::from_str("3d:70:eb:61:1a:91").unwrap(),
948                },
949                packed_queue: false,
950                pci_address: None,
951                mrg_rxbuf: false,
952            }
953        );
954
955        let params = from_net_arg("tap-fd=12,pci-address=00:01.1").unwrap();
956        assert_eq!(
957            params,
958            NetParameters {
959                #[cfg(any(target_os = "android", target_os = "linux"))]
960                vhost_net: None,
961                vq_pairs: None,
962                mode: NetParametersMode::TapFd {
963                    tap_fd: 12,
964                    mac: None,
965                },
966                packed_queue: false,
967                pci_address: Some(PciAddress {
968                    bus: 0,
969                    dev: 1,
970                    func: 1,
971                }),
972                mrg_rxbuf: false,
973            }
974        );
975
976        // wrong pci format
977        assert!(from_net_arg("tap-fd=12,pci-address=hello").is_err());
978
979        // missing netmask
980        assert!(from_net_arg("host-ip=\"192.168.10.1\",mac=\"3d:70:eb:61:1a:91\"").is_err());
981
982        // invalid parameter
983        assert!(from_net_arg("tap-name=tap,foomatic=true").is_err());
984    }
985
986    #[test]
987    #[cfg(any(target_os = "android", target_os = "linux"))]
988    fn params_from_key_values_vhost_net() {
989        let params = from_net_arg(
990            "vhost-net=[device=/dev/foo],\
991                host-ip=\"192.168.10.1\",\
992                netmask=\"255.255.255.0\",\
993                mac=\"3d:70:eb:61:1a:91\"",
994        )
995        .unwrap();
996        assert_eq!(
997            params,
998            NetParameters {
999                vhost_net: Some(VhostNetParameters {
1000                    device: PathBuf::from("/dev/foo")
1001                }),
1002                vq_pairs: None,
1003                mode: NetParametersMode::RawConfig {
1004                    host_ip: Ipv4Addr::from_str("192.168.10.1").unwrap(),
1005                    netmask: Ipv4Addr::from_str("255.255.255.0").unwrap(),
1006                    mac: MacAddress::from_str("3d:70:eb:61:1a:91").unwrap(),
1007                },
1008                packed_queue: false,
1009                pci_address: None,
1010                mrg_rxbuf: false,
1011            }
1012        );
1013
1014        let params = from_net_arg("tap-fd=3,vhost-net").unwrap();
1015        assert_eq!(
1016            params,
1017            NetParameters {
1018                vhost_net: Some(Default::default()),
1019                vq_pairs: None,
1020                mode: NetParametersMode::TapFd {
1021                    tap_fd: 3,
1022                    mac: None
1023                },
1024                packed_queue: false,
1025                pci_address: None,
1026                mrg_rxbuf: false,
1027            }
1028        );
1029
1030        let params = from_net_arg("vhost-net,tap-name=crosvm_tap").unwrap();
1031        assert_eq!(
1032            params,
1033            NetParameters {
1034                vhost_net: Some(Default::default()),
1035                vq_pairs: None,
1036                mode: NetParametersMode::TapName {
1037                    tap_name: "crosvm_tap".to_owned(),
1038                    mac: None
1039                },
1040                packed_queue: false,
1041                pci_address: None,
1042                mrg_rxbuf: false,
1043            }
1044        );
1045
1046        let params =
1047            from_net_arg("vhost-net,mac=\"3d:70:eb:61:1a:91\",tap-name=crosvm_tap").unwrap();
1048        assert_eq!(
1049            params,
1050            NetParameters {
1051                vhost_net: Some(Default::default()),
1052                vq_pairs: None,
1053                mode: NetParametersMode::TapName {
1054                    tap_name: "crosvm_tap".to_owned(),
1055                    mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
1056                },
1057                packed_queue: false,
1058                pci_address: None,
1059                mrg_rxbuf: false,
1060            }
1061        );
1062
1063        let params = from_net_arg("tap-name=tap,packed-queue=true").unwrap();
1064        assert_eq!(
1065            params,
1066            NetParameters {
1067                #[cfg(any(target_os = "android", target_os = "linux"))]
1068                vhost_net: None,
1069                vq_pairs: None,
1070                mode: NetParametersMode::TapName {
1071                    tap_name: "tap".to_string(),
1072                    mac: None
1073                },
1074                packed_queue: true,
1075                pci_address: None,
1076                mrg_rxbuf: false,
1077            }
1078        );
1079
1080        let params = from_net_arg("tap-name=tap,packed-queue").unwrap();
1081        assert_eq!(
1082            params,
1083            NetParameters {
1084                #[cfg(any(target_os = "android", target_os = "linux"))]
1085                vhost_net: None,
1086                vq_pairs: None,
1087                mode: NetParametersMode::TapName {
1088                    tap_name: "tap".to_string(),
1089                    mac: None
1090                },
1091                packed_queue: true,
1092                pci_address: None,
1093                mrg_rxbuf: false,
1094            }
1095        );
1096
1097        let params = from_net_arg("vhost-net,tap-name=crosvm_tap,pci-address=00:01.1").unwrap();
1098        assert_eq!(
1099            params,
1100            NetParameters {
1101                vhost_net: Some(Default::default()),
1102                vq_pairs: None,
1103                mode: NetParametersMode::TapName {
1104                    tap_name: "crosvm_tap".to_owned(),
1105                    mac: None,
1106                },
1107                packed_queue: false,
1108                pci_address: Some(PciAddress {
1109                    bus: 0,
1110                    dev: 1,
1111                    func: 1,
1112                }),
1113                mrg_rxbuf: false,
1114            }
1115        );
1116
1117        let params = from_net_arg("vhost-net,tap-name=crosvm_tap,mrg-rxbuf=true").unwrap();
1118        assert_eq!(
1119            params,
1120            NetParameters {
1121                vhost_net: Some(Default::default()),
1122                vq_pairs: None,
1123                mode: NetParametersMode::TapName {
1124                    tap_name: "crosvm_tap".to_owned(),
1125                    mac: None,
1126                },
1127                packed_queue: false,
1128                pci_address: None,
1129                mrg_rxbuf: true,
1130            }
1131        );
1132
1133        let params = from_net_arg("vhost-net,tap-name=crosvm_tap,mrg-rxbuf").unwrap();
1134        assert_eq!(
1135            params,
1136            NetParameters {
1137                vhost_net: Some(Default::default()),
1138                vq_pairs: None,
1139                mode: NetParametersMode::TapName {
1140                    tap_name: "crosvm_tap".to_owned(),
1141                    mac: None,
1142                },
1143                packed_queue: false,
1144                pci_address: None,
1145                mrg_rxbuf: true,
1146            }
1147        );
1148
1149        // mixed configs
1150        assert!(from_net_arg(
1151            "tap-name=tap,\
1152            vhost-net,\
1153            host-ip=\"192.168.10.1\",\
1154            netmask=\"255.255.255.0\",\
1155            mac=\"3d:70:eb:61:1a:91\"",
1156        )
1157        .is_err());
1158    }
1159}