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