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