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