• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 use std::io;
6 use std::io::Write;
7 use std::mem;
8 use std::net::Ipv4Addr;
9 use std::os::raw::c_uint;
10 use std::str::FromStr;
11 
12 use anyhow::anyhow;
13 use base::error;
14 #[cfg(windows)]
15 use base::named_pipes::OverlappedWrapper;
16 use base::warn;
17 use base::Error as SysError;
18 use base::Event;
19 use base::EventToken;
20 use base::RawDescriptor;
21 use base::ReadNotifier;
22 use base::WaitContext;
23 use base::WorkerThread;
24 use data_model::Le16;
25 use data_model::Le64;
26 use net_util::Error as TapError;
27 use net_util::MacAddress;
28 use net_util::TapT;
29 use remain::sorted;
30 use serde::Deserialize;
31 use serde::Serialize;
32 use thiserror::Error as ThisError;
33 use virtio_sys::virtio_net;
34 use virtio_sys::virtio_net::virtio_net_hdr_v1;
35 use virtio_sys::virtio_net::VIRTIO_NET_CTRL_GUEST_OFFLOADS;
36 use virtio_sys::virtio_net::VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET;
37 use virtio_sys::virtio_net::VIRTIO_NET_CTRL_MQ;
38 use virtio_sys::virtio_net::VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET;
39 use virtio_sys::virtio_net::VIRTIO_NET_ERR;
40 use virtio_sys::virtio_net::VIRTIO_NET_OK;
41 use vm_memory::GuestMemory;
42 use zerocopy::AsBytes;
43 use zerocopy::FromBytes;
44 
45 use super::copy_config;
46 use super::DescriptorError;
47 use super::DeviceType;
48 use super::Interrupt;
49 use super::Queue;
50 use super::Reader;
51 use super::SignalableInterrupt;
52 use super::VirtioDevice;
53 use super::Writer;
54 use crate::Suspendable;
55 
56 /// The maximum buffer size when segmentation offload is enabled. This
57 /// includes the 12-byte virtio net header.
58 /// http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html#x1-1740003
59 #[cfg(windows)]
60 pub(crate) const MAX_BUFFER_SIZE: usize = 65562;
61 const QUEUE_SIZE: u16 = 256;
62 
63 pub(crate) use super::sys::process_rx;
64 pub(crate) use super::sys::process_tx;
65 
66 #[sorted]
67 #[derive(ThisError, Debug)]
68 pub enum NetError {
69     /// Cloning kill event failed.
70     #[error("failed to clone kill event: {0}")]
71     CloneKillEvent(SysError),
72     /// Creating kill event failed.
73     #[error("failed to create kill event: {0}")]
74     CreateKillEvent(SysError),
75     /// Creating WaitContext failed.
76     #[error("failed to create wait context: {0}")]
77     CreateWaitContext(SysError),
78     /// Descriptor chain was invalid.
79     #[error("failed to valildate descriptor chain: {0}")]
80     DescriptorChain(DescriptorError),
81     /// Adding the tap descriptor back to the event context failed.
82     #[error("failed to add tap trigger to event context: {0}")]
83     EventAddTap(SysError),
84     /// Removing the tap descriptor from the event context failed.
85     #[error("failed to remove tap trigger from event context: {0}")]
86     EventRemoveTap(SysError),
87     /// Error reading data from control queue.
88     #[error("failed to read control message data: {0}")]
89     ReadCtrlData(io::Error),
90     /// Error reading header from control queue.
91     #[error("failed to read control message header: {0}")]
92     ReadCtrlHeader(io::Error),
93     /// There are no more available descriptors to receive into.
94     #[cfg(unix)]
95     #[error("no rx descriptors available")]
96     RxDescriptorsExhausted,
97     /// Failure creating the Slirp loop.
98     #[cfg(windows)]
99     #[error("error creating Slirp: {0}")]
100     SlirpCreateError(net_util::Error),
101     /// Enabling tap interface failed.
102     #[error("failed to enable tap interface: {0}")]
103     TapEnable(TapError),
104     /// Couldn't get the MTU from the tap device.
105     #[error("failed to get tap interface MTU: {0}")]
106     TapGetMtu(TapError),
107     /// Open tap device failed.
108     #[error("failed to open tap device: {0}")]
109     TapOpen(TapError),
110     /// Setting tap IP failed.
111     #[error("failed to set tap IP: {0}")]
112     TapSetIp(TapError),
113     /// Setting tap mac address failed.
114     #[error("failed to set tap mac address: {0}")]
115     TapSetMacAddress(TapError),
116     /// Setting tap netmask failed.
117     #[error("failed to set tap netmask: {0}")]
118     TapSetNetmask(TapError),
119     /// Setting vnet header size failed.
120     #[error("failed to set vnet header size: {0}")]
121     TapSetVnetHdrSize(TapError),
122     /// Validating tap interface failed.
123     #[error("failed to validate tap interface: {0}")]
124     TapValidate(String),
125     /// Removing read event from the tap fd events failed.
126     #[error("failed to disable EPOLLIN on tap fd: {0}")]
127     WaitContextDisableTap(SysError),
128     /// Adding read event to the tap fd events failed.
129     #[error("failed to enable EPOLLIN on tap fd: {0}")]
130     WaitContextEnableTap(SysError),
131     /// Error while waiting for events.
132     #[error("error while waiting for events: {0}")]
133     WaitError(SysError),
134     /// Failed writing an ack in response to a control message.
135     #[error("failed to write control message ack: {0}")]
136     WriteAck(io::Error),
137     /// Writing to a buffer in the guest failed.
138     #[cfg(unix)]
139     #[error("failed to write to guest buffer: {0}")]
140     WriteBuffer(io::Error),
141 }
142 
143 #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
144 #[serde(untagged, deny_unknown_fields)]
145 pub enum NetParametersMode {
146     #[serde(rename_all = "kebab-case")]
147     TapName {
148         tap_name: String,
149         mac: Option<MacAddress>,
150     },
151     #[serde(rename_all = "kebab-case")]
152     TapFd {
153         tap_fd: i32,
154         mac: Option<MacAddress>,
155     },
156     #[serde(rename_all = "kebab-case")]
157     RawConfig {
158         host_ip: Ipv4Addr,
159         netmask: Ipv4Addr,
160         mac: MacAddress,
161     },
162 }
163 
164 #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
165 #[serde(rename_all = "kebab-case")]
166 pub struct NetParameters {
167     #[serde(flatten)]
168     pub mode: NetParametersMode,
169     #[serde(default)]
170     pub vhost_net: bool,
171     pub vq_pairs: Option<u16>,
172 }
173 
174 impl FromStr for NetParameters {
175     type Err = String;
from_str(s: &str) -> Result<Self, Self::Err>176     fn from_str(s: &str) -> Result<Self, Self::Err> {
177         serde_keyvalue::from_key_values(s).map_err(|e| e.to_string())
178     }
179 }
180 
181 #[repr(C, packed)]
182 #[derive(Debug, Clone, Copy, AsBytes, FromBytes)]
183 pub struct virtio_net_ctrl_hdr {
184     pub class: u8,
185     pub cmd: u8,
186 }
187 
188 /// Converts virtio-net feature bits to tap's offload bits.
virtio_features_to_tap_offload(features: u64) -> c_uint189 pub fn virtio_features_to_tap_offload(features: u64) -> c_uint {
190     let mut tap_offloads: c_uint = 0;
191     if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM) != 0 {
192         tap_offloads |= net_sys::TUN_F_CSUM;
193     }
194     if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4) != 0 {
195         tap_offloads |= net_sys::TUN_F_TSO4;
196     }
197     if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_TSO6) != 0 {
198         tap_offloads |= net_sys::TUN_F_TSO6;
199     }
200     if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_ECN) != 0 {
201         tap_offloads |= net_sys::TUN_F_TSO_ECN;
202     }
203     if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_UFO) != 0 {
204         tap_offloads |= net_sys::TUN_F_UFO;
205     }
206 
207     tap_offloads
208 }
209 
210 #[derive(Debug, Clone, Copy, Default, AsBytes, FromBytes)]
211 #[repr(C)]
212 pub struct VirtioNetConfig {
213     mac: [u8; 6],
214     status: Le16,
215     max_vq_pairs: Le16,
216     mtu: Le16,
217 }
218 
process_ctrl<I: SignalableInterrupt, T: TapT>( interrupt: &I, ctrl_queue: &mut Queue, mem: &GuestMemory, tap: &mut T, acked_features: u64, vq_pairs: u16, ) -> Result<(), NetError>219 pub fn process_ctrl<I: SignalableInterrupt, T: TapT>(
220     interrupt: &I,
221     ctrl_queue: &mut Queue,
222     mem: &GuestMemory,
223     tap: &mut T,
224     acked_features: u64,
225     vq_pairs: u16,
226 ) -> Result<(), NetError> {
227     while let Some(desc_chain) = ctrl_queue.pop(mem) {
228         let index = desc_chain.index;
229 
230         let mut reader =
231             Reader::new(mem.clone(), desc_chain.clone()).map_err(NetError::DescriptorChain)?;
232         let mut writer = Writer::new(mem.clone(), desc_chain).map_err(NetError::DescriptorChain)?;
233         let ctrl_hdr: virtio_net_ctrl_hdr = reader.read_obj().map_err(NetError::ReadCtrlHeader)?;
234 
235         let mut write_error = || {
236             writer
237                 .write_all(&[VIRTIO_NET_ERR as u8])
238                 .map_err(NetError::WriteAck)?;
239             ctrl_queue.add_used(mem, index, writer.bytes_written() as u32);
240             Ok(())
241         };
242 
243         match ctrl_hdr.class as c_uint {
244             VIRTIO_NET_CTRL_GUEST_OFFLOADS => {
245                 if ctrl_hdr.cmd != VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET as u8 {
246                     error!(
247                         "invalid cmd for VIRTIO_NET_CTRL_GUEST_OFFLOADS: {}",
248                         ctrl_hdr.cmd
249                     );
250                     write_error()?;
251                     continue;
252                 }
253                 let offloads: Le64 = reader.read_obj().map_err(NetError::ReadCtrlData)?;
254                 let tap_offloads = virtio_features_to_tap_offload(offloads.into());
255                 if let Err(e) = tap.set_offload(tap_offloads) {
256                     error!("Failed to set tap itnerface offload flags: {}", e);
257                     write_error()?;
258                     continue;
259                 }
260 
261                 let ack = VIRTIO_NET_OK as u8;
262                 writer.write_all(&[ack]).map_err(NetError::WriteAck)?;
263             }
264             VIRTIO_NET_CTRL_MQ => {
265                 if ctrl_hdr.cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET as u8 {
266                     let pairs: Le16 = reader.read_obj().map_err(NetError::ReadCtrlData)?;
267                     // Simple handle it now
268                     if acked_features & 1 << virtio_net::VIRTIO_NET_F_MQ == 0
269                         || pairs.to_native() != vq_pairs
270                     {
271                         error!("Invalid VQ_PAIRS_SET cmd, driver request pairs: {}, device vq pairs: {}",
272                                    pairs.to_native(), vq_pairs);
273                         write_error()?;
274                         continue;
275                     }
276                     let ack = VIRTIO_NET_OK as u8;
277                     writer.write_all(&[ack]).map_err(NetError::WriteAck)?;
278                 }
279             }
280             _ => warn!(
281                 "unimplemented class for VIRTIO_NET_CTRL_GUEST_OFFLOADS: {}",
282                 ctrl_hdr.class
283             ),
284         }
285 
286         ctrl_queue.add_used(mem, index, writer.bytes_written() as u32);
287     }
288 
289     ctrl_queue.trigger_interrupt(mem, interrupt);
290     Ok(())
291 }
292 
293 #[derive(EventToken, Debug, Clone)]
294 pub enum Token {
295     // A frame is available for reading from the tap device to receive in the guest.
296     RxTap,
297     // The guest has made a buffer available to receive a frame into.
298     RxQueue,
299     // The transmit queue has a frame that is ready to send from the guest.
300     TxQueue,
301     // The control queue has a message.
302     CtrlQueue,
303     // Check if any interrupts need to be re-asserted.
304     InterruptResample,
305     // crosvm has requested the device to shut down.
306     Kill,
307 }
308 
309 pub(super) struct Worker<T: TapT> {
310     pub(super) interrupt: Interrupt,
311     pub(super) mem: GuestMemory,
312     pub(super) rx_queue: Queue,
313     pub(super) tx_queue: Queue,
314     pub(super) ctrl_queue: Option<Queue>,
315     pub(super) tap: T,
316     #[cfg(windows)]
317     pub(super) overlapped_wrapper: OverlappedWrapper,
318     #[cfg(windows)]
319     pub(super) rx_buf: [u8; MAX_BUFFER_SIZE],
320     #[cfg(windows)]
321     pub(super) rx_count: usize,
322     #[cfg(windows)]
323     pub(super) deferred_rx: bool,
324     acked_features: u64,
325     vq_pairs: u16,
326     #[allow(dead_code)]
327     kill_evt: Event,
328 }
329 
330 impl<T> Worker<T>
331 where
332     T: TapT + ReadNotifier,
333 {
process_tx(&mut self)334     fn process_tx(&mut self) {
335         process_tx(
336             &self.interrupt,
337             &mut self.tx_queue,
338             &self.mem,
339             &mut self.tap,
340         )
341     }
342 
process_ctrl(&mut self) -> Result<(), NetError>343     fn process_ctrl(&mut self) -> Result<(), NetError> {
344         let ctrl_queue = match self.ctrl_queue.as_mut() {
345             Some(queue) => queue,
346             None => return Ok(()),
347         };
348 
349         process_ctrl(
350             &self.interrupt,
351             ctrl_queue,
352             &self.mem,
353             &mut self.tap,
354             self.acked_features,
355             self.vq_pairs,
356         )
357     }
358 
run( &mut self, rx_queue_evt: Event, tx_queue_evt: Event, ctrl_queue_evt: Option<Event>, handle_interrupt_resample: bool, ) -> Result<(), NetError>359     fn run(
360         &mut self,
361         rx_queue_evt: Event,
362         tx_queue_evt: Event,
363         ctrl_queue_evt: Option<Event>,
364         handle_interrupt_resample: bool,
365     ) -> Result<(), NetError> {
366         let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
367             // This doesn't use get_read_notifier() because of overlapped io; we
368             // have overlapped wrapper separate from the TAP so that we can pass
369             // the overlapped wrapper into the read function. This overlapped
370             // wrapper's event is where we get the read notification.
371             #[cfg(windows)]
372             (
373                 self.overlapped_wrapper.get_h_event_ref().unwrap(),
374                 Token::RxTap,
375             ),
376             #[cfg(unix)]
377             (self.tap.get_read_notifier(), Token::RxTap),
378             (&rx_queue_evt, Token::RxQueue),
379             (&tx_queue_evt, Token::TxQueue),
380             (&self.kill_evt, Token::Kill),
381         ])
382         .map_err(NetError::CreateWaitContext)?;
383 
384         if let Some(ctrl_evt) = &ctrl_queue_evt {
385             wait_ctx
386                 .add(ctrl_evt, Token::CtrlQueue)
387                 .map_err(NetError::CreateWaitContext)?;
388         }
389 
390         if handle_interrupt_resample {
391             if let Some(resample_evt) = self.interrupt.get_resample_evt() {
392                 wait_ctx
393                     .add(resample_evt, Token::InterruptResample)
394                     .map_err(NetError::CreateWaitContext)?;
395             }
396         }
397 
398         let mut tap_polling_enabled = true;
399         'wait: loop {
400             let events = wait_ctx.wait().map_err(NetError::WaitError)?;
401             for event in events.iter().filter(|e| e.is_readable) {
402                 match event.token {
403                     Token::RxTap => {
404                         self.handle_rx_token(&wait_ctx)?;
405                         tap_polling_enabled = false;
406                     }
407                     Token::RxQueue => {
408                         if let Err(e) = rx_queue_evt.wait() {
409                             error!("net: error reading rx queue Event: {}", e);
410                             break 'wait;
411                         }
412                         self.handle_rx_queue(&wait_ctx, tap_polling_enabled)?;
413                         tap_polling_enabled = true;
414                     }
415                     Token::TxQueue => {
416                         if let Err(e) = tx_queue_evt.wait() {
417                             error!("net: error reading tx queue Event: {}", e);
418                             break 'wait;
419                         }
420                         self.process_tx();
421                     }
422                     Token::CtrlQueue => {
423                         if let Some(ctrl_evt) = &ctrl_queue_evt {
424                             if let Err(e) = ctrl_evt.wait() {
425                                 error!("net: error reading ctrl queue Event: {}", e);
426                                 break 'wait;
427                             }
428                         } else {
429                             break 'wait;
430                         }
431                         if let Err(e) = self.process_ctrl() {
432                             error!("net: failed to process control message: {}", e);
433                             break 'wait;
434                         }
435                     }
436                     Token::InterruptResample => {
437                         // We can unwrap safely because interrupt must have the event.
438                         let _ = self.interrupt.get_resample_evt().unwrap().wait();
439                         self.interrupt.do_interrupt_resample();
440                     }
441                     Token::Kill => {
442                         let _ = self.kill_evt.wait();
443                         break 'wait;
444                     }
445                 }
446             }
447         }
448         Ok(())
449     }
450 }
451 
build_config(vq_pairs: u16, mtu: u16, mac: Option<[u8; 6]>) -> VirtioNetConfig452 pub fn build_config(vq_pairs: u16, mtu: u16, mac: Option<[u8; 6]>) -> VirtioNetConfig {
453     VirtioNetConfig {
454         max_vq_pairs: Le16::from(vq_pairs),
455         mtu: Le16::from(mtu),
456         mac: mac.unwrap_or_default(),
457         // Other field has meaningful value when the corresponding feature
458         // is enabled, but all these features aren't supported now.
459         // So set them to default.
460         ..Default::default()
461     }
462 }
463 
464 pub struct Net<T: TapT + ReadNotifier + 'static> {
465     guest_mac: Option<[u8; 6]>,
466     queue_sizes: Box<[u16]>,
467     worker_threads: Vec<WorkerThread<Worker<T>>>,
468     taps: Vec<T>,
469     avail_features: u64,
470     acked_features: u64,
471     mtu: u16,
472     #[cfg(windows)]
473     slirp_kill_evt: Option<Event>,
474 }
475 
476 impl<T> Net<T>
477 where
478     T: TapT + ReadNotifier,
479 {
480     /// Creates a new virtio network device from a tap device that has already been
481     /// configured.
new( base_features: u64, tap: T, vq_pairs: u16, mac_addr: Option<MacAddress>, ) -> Result<Net<T>, NetError>482     pub fn new(
483         base_features: u64,
484         tap: T,
485         vq_pairs: u16,
486         mac_addr: Option<MacAddress>,
487     ) -> Result<Net<T>, NetError> {
488         let taps = tap.into_mq_taps(vq_pairs).map_err(NetError::TapOpen)?;
489 
490         let mut mtu = u16::MAX;
491         // This would also validate a tap created by Self::new(), but that's a good thing as it
492         // would ensure that any changes in the creation procedure are matched in the validation.
493         // Plus we still need to set the offload and vnet_hdr_size values.
494         for tap in &taps {
495             validate_and_configure_tap(tap, vq_pairs)?;
496             mtu = std::cmp::min(mtu, tap.mtu().map_err(NetError::TapGetMtu)?);
497         }
498 
499         // Indicate that the TAP device supports a number of features, such as:
500         // Partial checksum offload
501         // TSO (TCP segmentation offload)
502         // UFO (UDP fragmentation offload)
503         // See the network device feature bits section for further details:
504         //     http://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html#x1-1970003
505         let mut avail_features = base_features
506             | 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
507             | 1 << virtio_net::VIRTIO_NET_F_CSUM
508             | 1 << virtio_net::VIRTIO_NET_F_CTRL_VQ
509             | 1 << virtio_net::VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
510             | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
511             | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
512             | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
513             | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
514             | 1 << virtio_net::VIRTIO_NET_F_MTU;
515 
516         if vq_pairs > 1 {
517             avail_features |= 1 << virtio_net::VIRTIO_NET_F_MQ;
518         }
519 
520         if mac_addr.is_some() {
521             avail_features |= 1 << virtio_net::VIRTIO_NET_F_MAC;
522         }
523 
524         Self::new_internal(
525             taps,
526             avail_features,
527             mtu,
528             mac_addr,
529             #[cfg(windows)]
530             None,
531         )
532     }
533 
new_internal( taps: Vec<T>, avail_features: u64, mtu: u16, mac_addr: Option<MacAddress>, #[cfg(windows)] slirp_kill_evt: Option<Event>, ) -> Result<Self, NetError>534     pub(crate) fn new_internal(
535         taps: Vec<T>,
536         avail_features: u64,
537         mtu: u16,
538         mac_addr: Option<MacAddress>,
539         #[cfg(windows)] slirp_kill_evt: Option<Event>,
540     ) -> Result<Self, NetError> {
541         Ok(Self {
542             guest_mac: mac_addr.map(|mac| mac.octets()),
543             queue_sizes: vec![QUEUE_SIZE; (taps.len() * 2 + 1) as usize].into_boxed_slice(),
544             worker_threads: Vec::new(),
545             taps,
546             avail_features,
547             acked_features: 0u64,
548             mtu,
549             #[cfg(windows)]
550             slirp_kill_evt: None,
551         })
552     }
553 
554     /// Returns the maximum number of receive/transmit queue pairs for this device.
555     /// Only relevant when multi-queue support is negotiated.
max_virtqueue_pairs(&self) -> usize556     fn max_virtqueue_pairs(&self) -> usize {
557         self.taps.len()
558     }
559 }
560 
561 // Ensure that the tap interface has the correct flags and sets the offload and VNET header size
562 // to the appropriate values.
validate_and_configure_tap<T: TapT>(tap: &T, vq_pairs: u16) -> Result<(), NetError>563 pub fn validate_and_configure_tap<T: TapT>(tap: &T, vq_pairs: u16) -> Result<(), NetError> {
564     let flags = tap.if_flags();
565     let mut required_flags = vec![
566         (net_sys::IFF_TAP, "IFF_TAP"),
567         (net_sys::IFF_NO_PI, "IFF_NO_PI"),
568         (net_sys::IFF_VNET_HDR, "IFF_VNET_HDR"),
569     ];
570     if vq_pairs > 1 {
571         required_flags.push((net_sys::IFF_MULTI_QUEUE, "IFF_MULTI_QUEUE"));
572     }
573     let missing_flags = required_flags
574         .iter()
575         .filter_map(
576             |(value, name)| {
577                 if value & flags == 0 {
578                     Some(name)
579                 } else {
580                     None
581                 }
582             },
583         )
584         .collect::<Vec<_>>();
585 
586     if !missing_flags.is_empty() {
587         return Err(NetError::TapValidate(format!(
588             "Missing flags: {:?}",
589             missing_flags
590         )));
591     }
592 
593     let vnet_hdr_size = mem::size_of::<virtio_net_hdr_v1>() as i32;
594     tap.set_vnet_hdr_size(vnet_hdr_size)
595         .map_err(NetError::TapSetVnetHdrSize)?;
596 
597     Ok(())
598 }
599 
600 impl<T> Drop for Net<T>
601 where
602     T: TapT + ReadNotifier,
603 {
drop(&mut self)604     fn drop(&mut self) {
605         #[cfg(windows)]
606         {
607             if let Some(slirp_kill_evt) = self.slirp_kill_evt.take() {
608                 let _ = slirp_kill_evt.signal();
609             }
610         }
611     }
612 }
613 
614 impl<T> VirtioDevice for Net<T>
615 where
616     T: 'static + TapT + ReadNotifier,
617 {
keep_rds(&self) -> Vec<RawDescriptor>618     fn keep_rds(&self) -> Vec<RawDescriptor> {
619         let mut keep_rds = Vec::new();
620 
621         for tap in &self.taps {
622             keep_rds.push(tap.as_raw_descriptor());
623         }
624 
625         keep_rds
626     }
627 
device_type(&self) -> DeviceType628     fn device_type(&self) -> DeviceType {
629         DeviceType::Net
630     }
631 
queue_max_sizes(&self) -> &[u16]632     fn queue_max_sizes(&self) -> &[u16] {
633         &self.queue_sizes
634     }
635 
features(&self) -> u64636     fn features(&self) -> u64 {
637         self.avail_features
638     }
639 
ack_features(&mut self, value: u64)640     fn ack_features(&mut self, value: u64) {
641         let mut v = value;
642 
643         // Check if the guest is ACK'ing a feature that we didn't claim to have.
644         let unrequested_features = v & !self.avail_features;
645         if unrequested_features != 0 {
646             warn!("net: virtio net got unknown feature ack: {:x}", v);
647 
648             // Don't count these features as acked.
649             v &= !unrequested_features;
650         }
651         self.acked_features |= v;
652 
653         // Set offload flags to match acked virtio features.
654         if let Some(tap) = self.taps.first() {
655             if let Err(e) = tap.set_offload(virtio_features_to_tap_offload(self.acked_features)) {
656                 warn!(
657                     "net: failed to set tap offload to match acked features: {}",
658                     e
659                 );
660             }
661         }
662     }
663 
read_config(&self, offset: u64, data: &mut [u8])664     fn read_config(&self, offset: u64, data: &mut [u8]) {
665         let vq_pairs = self.queue_sizes.len() / 2;
666         let config_space = build_config(vq_pairs as u16, self.mtu, self.guest_mac);
667         copy_config(data, 0, config_space.as_bytes(), offset);
668     }
669 
activate( &mut self, mem: GuestMemory, interrupt: Interrupt, mut queues: Vec<(Queue, Event)>, ) -> anyhow::Result<()>670     fn activate(
671         &mut self,
672         mem: GuestMemory,
673         interrupt: Interrupt,
674         mut queues: Vec<(Queue, Event)>,
675     ) -> anyhow::Result<()> {
676         let ctrl_vq_enabled = self.acked_features & (1 << virtio_net::VIRTIO_NET_F_CTRL_VQ) != 0;
677         let mq_enabled = self.acked_features & (1 << virtio_net::VIRTIO_NET_F_MQ) != 0;
678 
679         let vq_pairs = if mq_enabled {
680             self.max_virtqueue_pairs()
681         } else {
682             1
683         };
684 
685         let mut num_queues_expected = vq_pairs * 2;
686         if ctrl_vq_enabled {
687             num_queues_expected += 1;
688         }
689 
690         if queues.len() != num_queues_expected {
691             return Err(anyhow!(
692                 "net: expected {} queues, got {} queues",
693                 self.queue_sizes.len(),
694                 queues.len(),
695             ));
696         }
697 
698         if self.taps.len() < vq_pairs {
699             return Err(anyhow!(
700                 "net: expected {} taps, got {}",
701                 vq_pairs,
702                 self.taps.len()
703             ));
704         }
705 
706         for i in 0..vq_pairs {
707             let tap = self.taps.remove(0);
708             let acked_features = self.acked_features;
709             let interrupt = interrupt.clone();
710             let memory = mem.clone();
711             let first_queue = i == 0;
712             // Queues alternate between rx0, tx0, rx1, tx1, ..., rxN, txN, ctrl.
713             let (rx_queue, rx_queue_evt) = queues.remove(0);
714             let (tx_queue, tx_queue_evt) = queues.remove(0);
715             let (ctrl_queue, ctrl_queue_evt) = if first_queue && ctrl_vq_enabled {
716                 let (queue, evt) = queues.remove(queues.len() - 1);
717                 (Some(queue), Some(evt))
718             } else {
719                 (None, None)
720             };
721             // Handle interrupt resampling on the first queue's thread.
722             let handle_interrupt_resample = first_queue;
723             let pairs = vq_pairs as u16;
724             #[cfg(windows)]
725             let overlapped_wrapper = OverlappedWrapper::new(true).unwrap();
726             self.worker_threads
727                 .push(WorkerThread::start(format!("v_net:{i}"), move |kill_evt| {
728                     let mut worker = Worker {
729                         interrupt,
730                         mem: memory,
731                         rx_queue,
732                         tx_queue,
733                         ctrl_queue,
734                         tap,
735                         #[cfg(windows)]
736                         overlapped_wrapper,
737                         acked_features,
738                         vq_pairs: pairs,
739                         #[cfg(windows)]
740                         rx_buf: [0u8; MAX_BUFFER_SIZE],
741                         #[cfg(windows)]
742                         rx_count: 0,
743                         #[cfg(windows)]
744                         deferred_rx: false,
745                         kill_evt,
746                     };
747                     let result = worker.run(
748                         rx_queue_evt,
749                         tx_queue_evt,
750                         ctrl_queue_evt,
751                         handle_interrupt_resample,
752                     );
753                     if let Err(e) = result {
754                         error!("net worker thread exited with error: {}", e);
755                     }
756                     worker
757                 }));
758         }
759         Ok(())
760     }
761 
reset(&mut self) -> bool762     fn reset(&mut self) -> bool {
763         for worker_thread in self.worker_threads.drain(..) {
764             let worker = worker_thread.stop();
765             self.taps.push(worker.tap);
766         }
767 
768         true
769     }
770 }
771 
772 impl<T> Suspendable for Net<T> where T: 'static + TapT + ReadNotifier {}
773 
774 #[cfg(test)]
775 mod tests {
776     use serde_keyvalue::*;
777 
778     use super::*;
779 
from_net_arg(options: &str) -> Result<NetParameters, ParseError>780     fn from_net_arg(options: &str) -> Result<NetParameters, ParseError> {
781         from_key_values(options)
782     }
783 
784     #[test]
params_from_key_values()785     fn params_from_key_values() {
786         let params = from_net_arg("");
787         assert!(params.is_err());
788 
789         let params = from_net_arg("tap-name=tap").unwrap();
790         assert_eq!(
791             params,
792             NetParameters {
793                 vhost_net: false,
794                 vq_pairs: None,
795                 mode: NetParametersMode::TapName {
796                     tap_name: "tap".to_string(),
797                     mac: None
798                 }
799             }
800         );
801 
802         let params = from_net_arg("tap-name=tap,mac=\"3d:70:eb:61:1a:91\"").unwrap();
803         assert_eq!(
804             params,
805             NetParameters {
806                 vhost_net: false,
807                 vq_pairs: None,
808                 mode: NetParametersMode::TapName {
809                     tap_name: "tap".to_string(),
810                     mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
811                 }
812             }
813         );
814 
815         let params = from_net_arg("tap-fd=12").unwrap();
816         assert_eq!(
817             params,
818             NetParameters {
819                 vhost_net: false,
820                 vq_pairs: None,
821                 mode: NetParametersMode::TapFd {
822                     tap_fd: 12,
823                     mac: None
824                 }
825             }
826         );
827 
828         let params = from_net_arg("tap-fd=12,mac=\"3d:70:eb:61:1a:91\"").unwrap();
829         assert_eq!(
830             params,
831             NetParameters {
832                 vhost_net: false,
833                 vq_pairs: None,
834                 mode: NetParametersMode::TapFd {
835                     tap_fd: 12,
836                     mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
837                 }
838             }
839         );
840 
841         let params = from_net_arg(
842             "host-ip=\"192.168.10.1\",netmask=\"255.255.255.0\",mac=\"3d:70:eb:61:1a:91\"",
843         )
844         .unwrap();
845         assert_eq!(
846             params,
847             NetParameters {
848                 vhost_net: false,
849                 vq_pairs: None,
850                 mode: NetParametersMode::RawConfig {
851                     host_ip: Ipv4Addr::from_str("192.168.10.1").unwrap(),
852                     netmask: Ipv4Addr::from_str("255.255.255.0").unwrap(),
853                     mac: MacAddress::from_str("3d:70:eb:61:1a:91").unwrap(),
854                 }
855             }
856         );
857 
858         let params = from_net_arg(
859             "vhost-net=true,\
860                 host-ip=\"192.168.10.1\",\
861                 netmask=\"255.255.255.0\",\
862                 mac=\"3d:70:eb:61:1a:91\"",
863         )
864         .unwrap();
865         assert_eq!(
866             params,
867             NetParameters {
868                 vhost_net: true,
869                 vq_pairs: None,
870                 mode: NetParametersMode::RawConfig {
871                     host_ip: Ipv4Addr::from_str("192.168.10.1").unwrap(),
872                     netmask: Ipv4Addr::from_str("255.255.255.0").unwrap(),
873                     mac: MacAddress::from_str("3d:70:eb:61:1a:91").unwrap(),
874                 }
875             }
876         );
877 
878         let params = from_net_arg("tap-fd=3,vhost-net=true").unwrap();
879         assert_eq!(
880             params,
881             NetParameters {
882                 vhost_net: true,
883                 vq_pairs: None,
884                 mode: NetParametersMode::TapFd {
885                     tap_fd: 3,
886                     mac: None
887                 }
888             }
889         );
890 
891         let params = from_net_arg("tap-fd=4,vhost-net=false,mac=\"3d:70:eb:61:1a:91\"").unwrap();
892         assert_eq!(
893             params,
894             NetParameters {
895                 vhost_net: false,
896                 vq_pairs: None,
897                 mode: NetParametersMode::TapFd {
898                     tap_fd: 4,
899                     mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
900                 }
901             }
902         );
903 
904         let params =
905             from_net_arg("tap-fd=4,vhost-net=false,mac=\"3d:70:eb:61:1a:91\",vq-pairs=16").unwrap();
906         assert_eq!(
907             params,
908             NetParameters {
909                 vhost_net: false,
910                 vq_pairs: Some(16),
911                 mode: NetParametersMode::TapFd {
912                     tap_fd: 4,
913                     mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
914                 }
915             }
916         );
917 
918         let params = from_net_arg("vhost-net=true,tap-name=crosvm_tap").unwrap();
919         assert_eq!(
920             params,
921             NetParameters {
922                 vhost_net: true,
923                 vq_pairs: None,
924                 mode: NetParametersMode::TapName {
925                     tap_name: "crosvm_tap".to_owned(),
926                     mac: None
927                 }
928             }
929         );
930 
931         let params =
932             from_net_arg("vhost-net=true,mac=\"3d:70:eb:61:1a:91\",tap-name=crosvm_tap").unwrap();
933         assert_eq!(
934             params,
935             NetParameters {
936                 vhost_net: true,
937                 vq_pairs: None,
938                 mode: NetParametersMode::TapName {
939                     tap_name: "crosvm_tap".to_owned(),
940                     mac: Some(MacAddress::from_str("3d:70:eb:61:1a:91").unwrap())
941                 }
942             }
943         );
944 
945         // mixed configs
946         assert!(from_net_arg(
947             "tap-name=tap,\
948             vhost-net=true,\
949             host-ip=\"192.168.10.1\",\
950             netmask=\"255.255.255.0\",\
951             mac=\"3d:70:eb:61:1a:91\"",
952         )
953         .is_err());
954 
955         // missing netmask
956         assert!(from_net_arg("host-ip=\"192.168.10.1\",mac=\"3d:70:eb:61:1a:91\"").is_err());
957 
958         // invalid parameter
959         assert!(from_net_arg("tap-name=tap,foomatic=true").is_err());
960     }
961 }
962