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