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