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().filter(|e| e.is_readable) {
403                match event.token {
404                    Token::RxTap => {
405                        let _trace = cros_tracing::trace_event!(VirtioNet, "handle RxTap event");
406                        self.handle_rx_token(&wait_ctx, &mut pending_buffer_for_mrg_rx)?;
407                        tap_polling_enabled = false;
408                    }
409                    Token::RxQueue => {
410                        let _trace = cros_tracing::trace_event!(VirtioNet, "handle RxQueue event");
411                        if let Err(e) = self.rx_queue.event().wait() {
412                            error!("net: error reading rx queue Event: {}", e);
413                            break 'wait;
414                        }
415                        self.handle_rx_queue(&wait_ctx, tap_polling_enabled)?;
416                        tap_polling_enabled = true;
417                    }
418                    Token::TxQueue => {
419                        let _trace = cros_tracing::trace_event!(VirtioNet, "handle TxQueue event");
420                        if let Err(e) = self.tx_queue.event().wait() {
421                            error!("net: error reading tx queue Event: {}", e);
422                            break 'wait;
423                        }
424                        self.process_tx();
425                    }
426                    Token::CtrlQueue => {
427                        let _trace =
428                            cros_tracing::trace_event!(VirtioNet, "handle CtrlQueue event");
429                        if let Some(ctrl_evt) = self.ctrl_queue.as_ref().map(|q| q.event()) {
430                            if let Err(e) = ctrl_evt.wait() {
431                                error!("net: error reading ctrl queue Event: {}", e);
432                                break 'wait;
433                            }
434                        } else {
435                            break 'wait;
436                        }
437                        if let Err(e) = self.process_ctrl() {
438                            error!("net: failed to process control message: {}", e);
439                            break 'wait;
440                        }
441                    }
442                    Token::Kill => {
443                        let _ = self.kill_evt.wait();
444                        break 'wait;
445                    }
446                }
447            }
448        }
449        Ok(())
450    }
451}
452
453pub fn build_config(vq_pairs: u16, mtu: u16, mac: Option<[u8; 6]>) -> VirtioNetConfig {
454    VirtioNetConfig {
455        max_vq_pairs: Le16::from(vq_pairs),
456        mtu: Le16::from(mtu),
457        mac: mac.unwrap_or_default(),
458        // Other field has meaningful value when the corresponding feature
459        // is enabled, but all these features aren't supported now.
460        // So set them to default.
461        ..Default::default()
462    }
463}
464
465pub struct Net<T: TapT + ReadNotifier + 'static> {
466    guest_mac: Option<[u8; 6]>,
467    queue_sizes: Box<[u16]>,
468    worker_threads: Vec<WorkerThread<Worker<T>>>,
469    taps: Vec<T>,
470    avail_features: u64,
471    acked_features: u64,
472    mtu: u16,
473    pci_address: Option<PciAddress>,
474    #[cfg(windows)]
475    slirp_kill_evt: Option<Event>,
476}
477
478#[derive(Serialize, Deserialize)]
479struct NetSnapshot {
480    avail_features: u64,
481    acked_features: u64,
482}
483
484impl<T> Net<T>
485where
486    T: TapT + ReadNotifier,
487{
488    /// Creates a new virtio network device from a tap device that has already been
489    /// configured.
490    pub fn new(
491        base_features: u64,
492        tap: T,
493        vq_pairs: u16,
494        mac_addr: Option<MacAddress>,
495        use_packed_queue: bool,
496        pci_address: Option<PciAddress>,
497        mrg_rxbuf: bool,
498    ) -> Result<Net<T>, NetError> {
499        let taps = tap.into_mq_taps(vq_pairs).map_err(NetError::TapOpen)?;
500
501        let mut mtu = u16::MAX;
502        // This would also validate a tap created by Self::new(), but that's a good thing as it
503        // would ensure that any changes in the creation procedure are matched in the validation.
504        // Plus we still need to set the offload and vnet_hdr_size values.
505        for tap in &taps {
506            validate_and_configure_tap(tap, vq_pairs)?;
507            mtu = std::cmp::min(mtu, tap.mtu().map_err(NetError::TapGetMtu)?);
508        }
509
510        // Indicate that the TAP device supports a number of features, such as:
511        // Partial checksum offload
512        // TSO (TCP segmentation offload)
513        // UFO (UDP fragmentation offload)
514        // See the network device feature bits section for further details:
515        //     http://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html#x1-1970003
516        let mut avail_features = base_features
517            | 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
518            | 1 << virtio_net::VIRTIO_NET_F_CSUM
519            | 1 << virtio_net::VIRTIO_NET_F_CTRL_VQ
520            | 1 << virtio_net::VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
521            | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
522            | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
523            | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
524            | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
525            | 1 << virtio_net::VIRTIO_NET_F_MTU;
526
527        if vq_pairs > 1 {
528            avail_features |= 1 << virtio_net::VIRTIO_NET_F_MQ;
529        }
530
531        if use_packed_queue {
532            avail_features |= 1 << VIRTIO_F_RING_PACKED;
533        }
534
535        if mac_addr.is_some() {
536            avail_features |= 1 << virtio_net::VIRTIO_NET_F_MAC;
537        }
538
539        if mrg_rxbuf {
540            avail_features |= 1 << virtio_net::VIRTIO_NET_F_MRG_RXBUF;
541        }
542
543        Self::new_internal(
544            taps,
545            avail_features,
546            mtu,
547            mac_addr,
548            pci_address,
549            #[cfg(windows)]
550            None,
551        )
552    }
553
554    pub(crate) fn new_internal(
555        taps: Vec<T>,
556        avail_features: u64,
557        mtu: u16,
558        mac_addr: Option<MacAddress>,
559        pci_address: Option<PciAddress>,
560        #[cfg(windows)] slirp_kill_evt: Option<Event>,
561    ) -> Result<Self, NetError> {
562        let net = Self {
563            guest_mac: mac_addr.map(|mac| mac.octets()),
564            queue_sizes: vec![QUEUE_SIZE; taps.len() * 2 + 1].into_boxed_slice(),
565            worker_threads: Vec::new(),
566            taps,
567            avail_features,
568            acked_features: 0u64,
569            mtu,
570            pci_address,
571            #[cfg(windows)]
572            slirp_kill_evt: None,
573        };
574        cros_tracing::trace_simple_print!("New Net device created: {:?}", net);
575        Ok(net)
576    }
577
578    /// Returns the maximum number of receive/transmit queue pairs for this device.
579    /// Only relevant when multi-queue support is negotiated.
580    fn max_virtqueue_pairs(&self) -> usize {
581        self.taps.len()
582    }
583}
584
585impl<T> Drop for Net<T>
586where
587    T: TapT + ReadNotifier,
588{
589    fn drop(&mut self) {
590        #[cfg(windows)]
591        {
592            if let Some(slirp_kill_evt) = self.slirp_kill_evt.take() {
593                let _ = slirp_kill_evt.signal();
594            }
595        }
596    }
597}
598
599impl<T> VirtioDevice for Net<T>
600where
601    T: 'static + TapT + ReadNotifier,
602{
603    fn keep_rds(&self) -> Vec<RawDescriptor> {
604        let mut keep_rds = Vec::new();
605
606        for tap in &self.taps {
607            keep_rds.push(tap.as_raw_descriptor());
608        }
609
610        keep_rds
611    }
612
613    fn device_type(&self) -> DeviceType {
614        DeviceType::Net
615    }
616
617    fn queue_max_sizes(&self) -> &[u16] {
618        &self.queue_sizes
619    }
620
621    fn features(&self) -> u64 {
622        self.avail_features
623    }
624
625    fn ack_features(&mut self, value: u64) {
626        let mut v = value;
627
628        // Check if the guest is ACK'ing a feature that we didn't claim to have.
629        let unrequested_features = v & !self.avail_features;
630        if unrequested_features != 0 {
631            warn!("net: virtio net got unknown feature ack: {:x}", v);
632
633            // Don't count these features as acked.
634            v &= !unrequested_features;
635        }
636        self.acked_features |= v;
637
638        // Set offload flags to match acked virtio features.
639        if let Some(tap) = self.taps.first() {
640            if let Err(e) = tap.set_offload(virtio_features_to_tap_offload(self.acked_features)) {
641                warn!(
642                    "net: failed to set tap offload to match acked features: {}",
643                    e
644                );
645            }
646        }
647    }
648
649    fn read_config(&self, offset: u64, data: &mut [u8]) {
650        let vq_pairs = self.queue_sizes.len() / 2;
651        let config_space = build_config(vq_pairs as u16, self.mtu, self.guest_mac);
652        copy_config(data, 0, config_space.as_bytes(), offset);
653    }
654
655    fn activate(
656        &mut self,
657        _mem: GuestMemory,
658        _interrupt: Interrupt,
659        mut queues: BTreeMap<usize, Queue>,
660    ) -> anyhow::Result<()> {
661        let ctrl_vq_enabled = self.acked_features & (1 << virtio_net::VIRTIO_NET_F_CTRL_VQ) != 0;
662        let mq_enabled = self.acked_features & (1 << virtio_net::VIRTIO_NET_F_MQ) != 0;
663
664        let vq_pairs = if mq_enabled {
665            self.max_virtqueue_pairs()
666        } else {
667            1
668        };
669
670        let mut num_queues_expected = vq_pairs * 2;
671        if ctrl_vq_enabled {
672            num_queues_expected += 1;
673        }
674
675        if queues.len() != num_queues_expected {
676            return Err(anyhow!(
677                "net: expected {} queues, got {} queues",
678                self.queue_sizes.len(),
679                queues.len(),
680            ));
681        }
682
683        if self.taps.len() < vq_pairs {
684            return Err(anyhow!(
685                "net: expected {} taps, got {}",
686                vq_pairs,
687                self.taps.len()
688            ));
689        }
690
691        for i in 0..vq_pairs {
692            let tap = self.taps.remove(0);
693            let acked_features = self.acked_features;
694            let first_queue = i == 0;
695            // Queues alternate between rx0, tx0, rx1, tx1, ..., rxN, txN, ctrl.
696            let rx_queue = queues.pop_first().unwrap().1;
697            let tx_queue = queues.pop_first().unwrap().1;
698            let ctrl_queue = if first_queue && ctrl_vq_enabled {
699                Some(queues.pop_last().unwrap().1)
700            } else {
701                None
702            };
703            let pairs = vq_pairs as u16;
704            #[cfg(windows)]
705            let overlapped_wrapper = OverlappedWrapper::new(true).unwrap();
706            self.worker_threads
707                .push(WorkerThread::start(format!("v_net:{i}"), move |kill_evt| {
708                    let mut worker = Worker {
709                        rx_queue,
710                        tx_queue,
711                        ctrl_queue,
712                        tap,
713                        #[cfg(windows)]
714                        overlapped_wrapper,
715                        acked_features,
716                        vq_pairs: pairs,
717                        #[cfg(windows)]
718                        rx_buf: [0u8; MAX_BUFFER_SIZE],
719                        #[cfg(windows)]
720                        rx_count: 0,
721                        #[cfg(windows)]
722                        deferred_rx: false,
723                        kill_evt,
724                    };
725                    let result = worker.run();
726                    if let Err(e) = result {
727                        error!("net worker thread exited with error: {}", e);
728                    }
729                    worker
730                }));
731        }
732        cros_tracing::trace_simple_print!("Net device activated: {:?}", self);
733        Ok(())
734    }
735
736    fn pci_address(&self) -> Option<PciAddress> {
737        self.pci_address
738    }
739
740    fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> {
741        if self.worker_threads.is_empty() {
742            return Ok(None);
743        }
744        let mut queues = BTreeMap::new();
745        let mut queue_index = 0;
746        let mut ctrl_queue = None;
747        for worker_thread in self.worker_threads.drain(..) {
748            let mut worker = worker_thread.stop();
749            if worker.ctrl_queue.is_some() {
750                ctrl_queue = worker.ctrl_queue.take();
751            }
752            self.taps.push(worker.tap);
753            queues.insert(queue_index + 0, worker.rx_queue);
754            queues.insert(queue_index + 1, worker.tx_queue);
755            queue_index += 2;
756        }
757        if let Some(ctrl_queue) = ctrl_queue {
758            queues.insert(queue_index, ctrl_queue);
759        }
760        Ok(Some(queues))
761    }
762
763    fn virtio_wake(
764        &mut self,
765        device_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>,
766    ) -> anyhow::Result<()> {
767        match device_state {
768            None => Ok(()),
769            Some((mem, interrupt, queues)) => {
770                // TODO: activate is just what we want at the moment, but we should probably move
771                // it into a "start workers" function to make it obvious that it isn't strictly
772                // used for activate events.
773                self.activate(mem, interrupt, queues)?;
774                Ok(())
775            }
776        }
777    }
778
779    fn virtio_snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
780        AnySnapshot::to_any(NetSnapshot {
781            acked_features: self.acked_features,
782            avail_features: self.avail_features,
783        })
784        .context("failed to snapshot virtio Net device")
785    }
786
787    fn virtio_restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
788        let deser: NetSnapshot =
789            AnySnapshot::from_any(data).context("failed to deserialize Net device")?;
790        anyhow::ensure!(
791            self.avail_features == deser.avail_features,
792            "Available features for net device do not match. expected: {},  got: {}",
793            deser.avail_features,
794            self.avail_features
795        );
796        self.acked_features = deser.acked_features;
797        Ok(())
798    }
799
800    fn reset(&mut self) -> anyhow::Result<()> {
801        for worker_thread in self.worker_threads.drain(..) {
802            let worker = worker_thread.stop();
803            self.taps.push(worker.tap);
804        }
805
806        Ok(())
807    }
808}
809
810impl<T> std::fmt::Debug for Net<T>
811where
812    T: TapT + ReadNotifier,
813{
814    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
815        f.debug_struct("Net")
816            .field("guest_mac", &self.guest_mac)
817            .field("queue_sizes", &self.queue_sizes)
818            .field("worker_threads_size", &self.worker_threads.len())
819            .field("taps_size", &self.taps.len())
820            .field("avail_features", &self.avail_features)
821            .field("acked_features", &self.acked_features)
822            .field("mtu", &self.mtu)
823            .finish()
824    }
825}
826
827#[cfg(test)]
828mod tests {
829    use serde_keyvalue::*;
830
831    use super::*;
832
833    fn from_net_arg(options: &str) -> Result<NetParameters, ParseError> {
834        from_key_values(options)
835    }
836
837    #[test]
838    fn params_from_key_values() {
839        let params = from_net_arg("");
840        assert!(params.is_err());
841
842        let params = from_net_arg("tap-name=tap").unwrap();
843        assert_eq!(
844            params,
845            NetParameters {
846                #[cfg(any(target_os = "android", target_os = "linux"))]
847                vhost_net: None,
848                vq_pairs: None,
849                mode: NetParametersMode::TapName {
850                    tap_name: "tap".to_string(),
851                    mac: None
852                },
853                packed_queue: false,
854                pci_address: None,
855                mrg_rxbuf: false,
856            }
857        );
858
859        let params = from_net_arg("tap-name=tap,mrg-rxbuf=true").unwrap();
860        assert_eq!(
861            params,
862            NetParameters {
863                #[cfg(any(target_os = "android", target_os = "linux"))]
864                vhost_net: None,
865                vq_pairs: None,
866                mode: NetParametersMode::TapName {
867                    tap_name: "tap".to_string(),
868                    mac: None
869                },
870                packed_queue: false,
871                pci_address: None,
872                mrg_rxbuf: true,
873            }
874        );
875
876        let params = from_net_arg("tap-name=tap,mac=\"3d:70:eb:61:1a:91\"").unwrap();
877        assert_eq!(
878            params,
879            NetParameters {
880                #[cfg(any(target_os = "android", target_os = "linux"))]
881                vhost_net: None,
882                vq_pairs: None,
883                mode: NetParametersMode::TapName {
884                    tap_name: "tap".to_string(),
885                    mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
886                },
887                packed_queue: false,
888                pci_address: None,
889                mrg_rxbuf: false,
890            }
891        );
892
893        let params = from_net_arg("tap-fd=12").unwrap();
894        assert_eq!(
895            params,
896            NetParameters {
897                #[cfg(any(target_os = "android", target_os = "linux"))]
898                vhost_net: None,
899                vq_pairs: None,
900                mode: NetParametersMode::TapFd {
901                    tap_fd: 12,
902                    mac: None
903                },
904                packed_queue: false,
905                pci_address: None,
906                mrg_rxbuf: false,
907            }
908        );
909
910        let params = from_net_arg("tap-fd=12,mac=\"3d:70:eb:61:1a:91\"").unwrap();
911        assert_eq!(
912            params,
913            NetParameters {
914                #[cfg(any(target_os = "android", target_os = "linux"))]
915                vhost_net: None,
916                vq_pairs: None,
917                mode: NetParametersMode::TapFd {
918                    tap_fd: 12,
919                    mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
920                },
921                packed_queue: false,
922                pci_address: None,
923                mrg_rxbuf: false,
924            }
925        );
926
927        let params = from_net_arg(
928            "host-ip=\"192.168.10.1\",netmask=\"255.255.255.0\",mac=\"3d:70:eb:61:1a:91\"",
929        )
930        .unwrap();
931        assert_eq!(
932            params,
933            NetParameters {
934                #[cfg(any(target_os = "android", target_os = "linux"))]
935                vhost_net: None,
936                vq_pairs: None,
937                mode: NetParametersMode::RawConfig {
938                    host_ip: Ipv4Addr::from_str("192.168.10.1").unwrap(),
939                    netmask: Ipv4Addr::from_str("255.255.255.0").unwrap(),
940                    mac: MacAddress::from_str("3d:70:eb:61:1a:91").unwrap(),
941                },
942                packed_queue: false,
943                pci_address: None,
944                mrg_rxbuf: false,
945            }
946        );
947
948        let params = from_net_arg("tap-fd=12,pci-address=00:01.1").unwrap();
949        assert_eq!(
950            params,
951            NetParameters {
952                #[cfg(any(target_os = "android", target_os = "linux"))]
953                vhost_net: None,
954                vq_pairs: None,
955                mode: NetParametersMode::TapFd {
956                    tap_fd: 12,
957                    mac: None,
958                },
959                packed_queue: false,
960                pci_address: Some(PciAddress {
961                    bus: 0,
962                    dev: 1,
963                    func: 1,
964                }),
965                mrg_rxbuf: false,
966            }
967        );
968
969        // wrong pci format
970        assert!(from_net_arg("tap-fd=12,pci-address=hello").is_err());
971
972        // missing netmask
973        assert!(from_net_arg("host-ip=\"192.168.10.1\",mac=\"3d:70:eb:61:1a:91\"").is_err());
974
975        // invalid parameter
976        assert!(from_net_arg("tap-name=tap,foomatic=true").is_err());
977    }
978
979    #[test]
980    #[cfg(any(target_os = "android", target_os = "linux"))]
981    fn params_from_key_values_vhost_net() {
982        let params = from_net_arg(
983            "vhost-net=[device=/dev/foo],\
984                host-ip=\"192.168.10.1\",\
985                netmask=\"255.255.255.0\",\
986                mac=\"3d:70:eb:61:1a:91\"",
987        )
988        .unwrap();
989        assert_eq!(
990            params,
991            NetParameters {
992                vhost_net: Some(VhostNetParameters {
993                    device: PathBuf::from("/dev/foo")
994                }),
995                vq_pairs: None,
996                mode: NetParametersMode::RawConfig {
997                    host_ip: Ipv4Addr::from_str("192.168.10.1").unwrap(),
998                    netmask: Ipv4Addr::from_str("255.255.255.0").unwrap(),
999                    mac: MacAddress::from_str("3d:70:eb:61:1a:91").unwrap(),
1000                },
1001                packed_queue: false,
1002                pci_address: None,
1003                mrg_rxbuf: false,
1004            }
1005        );
1006
1007        let params = from_net_arg("tap-fd=3,vhost-net").unwrap();
1008        assert_eq!(
1009            params,
1010            NetParameters {
1011                vhost_net: Some(Default::default()),
1012                vq_pairs: None,
1013                mode: NetParametersMode::TapFd {
1014                    tap_fd: 3,
1015                    mac: None
1016                },
1017                packed_queue: false,
1018                pci_address: None,
1019                mrg_rxbuf: false,
1020            }
1021        );
1022
1023        let params = from_net_arg("vhost-net,tap-name=crosvm_tap").unwrap();
1024        assert_eq!(
1025            params,
1026            NetParameters {
1027                vhost_net: Some(Default::default()),
1028                vq_pairs: None,
1029                mode: NetParametersMode::TapName {
1030                    tap_name: "crosvm_tap".to_owned(),
1031                    mac: None
1032                },
1033                packed_queue: false,
1034                pci_address: None,
1035                mrg_rxbuf: false,
1036            }
1037        );
1038
1039        let params =
1040            from_net_arg("vhost-net,mac=\"3d:70:eb:61:1a:91\",tap-name=crosvm_tap").unwrap();
1041        assert_eq!(
1042            params,
1043            NetParameters {
1044                vhost_net: Some(Default::default()),
1045                vq_pairs: None,
1046                mode: NetParametersMode::TapName {
1047                    tap_name: "crosvm_tap".to_owned(),
1048                    mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
1049                },
1050                packed_queue: false,
1051                pci_address: None,
1052                mrg_rxbuf: false,
1053            }
1054        );
1055
1056        let params = from_net_arg("tap-name=tap,packed-queue=true").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                mrg_rxbuf: false,
1070            }
1071        );
1072
1073        let params = from_net_arg("tap-name=tap,packed-queue").unwrap();
1074        assert_eq!(
1075            params,
1076            NetParameters {
1077                #[cfg(any(target_os = "android", target_os = "linux"))]
1078                vhost_net: None,
1079                vq_pairs: None,
1080                mode: NetParametersMode::TapName {
1081                    tap_name: "tap".to_string(),
1082                    mac: None
1083                },
1084                packed_queue: true,
1085                pci_address: None,
1086                mrg_rxbuf: false,
1087            }
1088        );
1089
1090        let params = from_net_arg("vhost-net,tap-name=crosvm_tap,pci-address=00:01.1").unwrap();
1091        assert_eq!(
1092            params,
1093            NetParameters {
1094                vhost_net: Some(Default::default()),
1095                vq_pairs: None,
1096                mode: NetParametersMode::TapName {
1097                    tap_name: "crosvm_tap".to_owned(),
1098                    mac: None,
1099                },
1100                packed_queue: false,
1101                pci_address: Some(PciAddress {
1102                    bus: 0,
1103                    dev: 1,
1104                    func: 1,
1105                }),
1106                mrg_rxbuf: false,
1107            }
1108        );
1109
1110        let params = from_net_arg("vhost-net,tap-name=crosvm_tap,mrg-rxbuf=true").unwrap();
1111        assert_eq!(
1112            params,
1113            NetParameters {
1114                vhost_net: Some(Default::default()),
1115                vq_pairs: None,
1116                mode: NetParametersMode::TapName {
1117                    tap_name: "crosvm_tap".to_owned(),
1118                    mac: None,
1119                },
1120                packed_queue: false,
1121                pci_address: None,
1122                mrg_rxbuf: true,
1123            }
1124        );
1125
1126        let params = from_net_arg("vhost-net,tap-name=crosvm_tap,mrg-rxbuf").unwrap();
1127        assert_eq!(
1128            params,
1129            NetParameters {
1130                vhost_net: Some(Default::default()),
1131                vq_pairs: None,
1132                mode: NetParametersMode::TapName {
1133                    tap_name: "crosvm_tap".to_owned(),
1134                    mac: None,
1135                },
1136                packed_queue: false,
1137                pci_address: None,
1138                mrg_rxbuf: true,
1139            }
1140        );
1141
1142        // mixed configs
1143        assert!(from_net_arg(
1144            "tap-name=tap,\
1145            vhost-net,\
1146            host-ip=\"192.168.10.1\",\
1147            netmask=\"255.255.255.0\",\
1148            mac=\"3d:70:eb:61:1a:91\"",
1149        )
1150        .is_err());
1151    }
1152}