• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::io;
6 use std::result;
7 
8 use base::error;
9 use base::warn;
10 use base::EventType;
11 use base::ReadNotifier;
12 use base::WaitContext;
13 use net_util::TapT;
14 use virtio_sys::virtio_net;
15 use virtio_sys::virtio_net::virtio_net_hdr_v1;
16 
17 use super::super::super::net::NetError;
18 use super::super::super::net::Token;
19 use super::super::super::net::Worker;
20 use super::super::super::Interrupt;
21 use super::super::super::Queue;
22 
23 // Ensure that the tap interface has the correct flags and sets the offload and VNET header size
24 // to the appropriate values.
validate_and_configure_tap<T: TapT>(tap: &T, vq_pairs: u16) -> Result<(), NetError>25 pub fn validate_and_configure_tap<T: TapT>(tap: &T, vq_pairs: u16) -> Result<(), NetError> {
26     let flags = tap.if_flags();
27     let mut required_flags = vec![
28         (net_sys::IFF_TAP, "IFF_TAP"),
29         (net_sys::IFF_NO_PI, "IFF_NO_PI"),
30         (net_sys::IFF_VNET_HDR, "IFF_VNET_HDR"),
31     ];
32     if vq_pairs > 1 {
33         required_flags.push((net_sys::IFF_MULTI_QUEUE, "IFF_MULTI_QUEUE"));
34     }
35     let missing_flags = required_flags
36         .iter()
37         .filter_map(
38             |(value, name)| {
39                 if value & flags == 0 {
40                     Some(name)
41                 } else {
42                     None
43                 }
44             },
45         )
46         .collect::<Vec<_>>();
47 
48     if !missing_flags.is_empty() {
49         return Err(NetError::TapValidate(format!(
50             "Missing flags: {:?}",
51             missing_flags
52         )));
53     }
54 
55     let vnet_hdr_size = std::mem::size_of::<virtio_net_hdr_v1>();
56     tap.set_vnet_hdr_size(vnet_hdr_size)
57         .map_err(NetError::TapSetVnetHdrSize)?;
58 
59     Ok(())
60 }
61 
62 /// Converts virtio-net feature bits to tap's offload bits.
virtio_features_to_tap_offload(features: u64) -> u3263 pub fn virtio_features_to_tap_offload(features: u64) -> u32 {
64     let mut tap_offloads: u32 = 0;
65     if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM) != 0 {
66         tap_offloads |= net_sys::TUN_F_CSUM;
67     }
68     if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4) != 0 {
69         tap_offloads |= net_sys::TUN_F_TSO4;
70     }
71     if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_TSO6) != 0 {
72         tap_offloads |= net_sys::TUN_F_TSO6;
73     }
74     if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_ECN) != 0 {
75         tap_offloads |= net_sys::TUN_F_TSO_ECN;
76     }
77     if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_UFO) != 0 {
78         tap_offloads |= net_sys::TUN_F_UFO;
79     }
80 
81     tap_offloads
82 }
83 
process_rx<T: TapT>( interrupt: &Interrupt, rx_queue: &mut Queue, mut tap: &mut T, ) -> result::Result<(), NetError>84 pub fn process_rx<T: TapT>(
85     interrupt: &Interrupt,
86     rx_queue: &mut Queue,
87     mut tap: &mut T,
88 ) -> result::Result<(), NetError> {
89     let mut needs_interrupt = false;
90     let mut exhausted_queue = false;
91 
92     // Read as many frames as possible.
93     loop {
94         let mut desc_chain = match rx_queue.peek() {
95             Some(desc) => desc,
96             None => {
97                 exhausted_queue = true;
98                 break;
99             }
100         };
101 
102         let writer = &mut desc_chain.writer;
103 
104         match writer.write_from(&mut tap, writer.available_bytes()) {
105             Ok(_) => {}
106             Err(ref e) if e.kind() == io::ErrorKind::WriteZero => {
107                 warn!("net: rx: buffer is too small to hold frame");
108                 break;
109             }
110             Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
111                 // No more to read from the tap.
112                 break;
113             }
114             Err(e) => {
115                 warn!("net: rx: failed to write slice: {}", e);
116                 return Err(NetError::WriteBuffer(e));
117             }
118         };
119 
120         let bytes_written = writer.bytes_written() as u32;
121         cros_tracing::trace_simple_print!("{bytes_written} bytes read from tap");
122 
123         if bytes_written > 0 {
124             let desc_chain = desc_chain.pop();
125             rx_queue.add_used(desc_chain, bytes_written);
126             needs_interrupt = true;
127         }
128     }
129 
130     if needs_interrupt {
131         rx_queue.trigger_interrupt(interrupt);
132     }
133 
134     if exhausted_queue {
135         Err(NetError::RxDescriptorsExhausted)
136     } else {
137         Ok(())
138     }
139 }
140 
process_tx<T: TapT>(interrupt: &Interrupt, tx_queue: &mut Queue, mut tap: &mut T)141 pub fn process_tx<T: TapT>(interrupt: &Interrupt, tx_queue: &mut Queue, mut tap: &mut T) {
142     while let Some(mut desc_chain) = tx_queue.pop() {
143         let reader = &mut desc_chain.reader;
144         let expected_count = reader.available_bytes();
145         match reader.read_to(&mut tap, expected_count) {
146             Ok(count) => {
147                 // Tap writes must be done in one call. If the entire frame was not
148                 // written, it's an error.
149                 if count != expected_count {
150                     error!(
151                         "net: tx: wrote only {} bytes of {} byte frame",
152                         count, expected_count
153                     );
154                 }
155                 cros_tracing::trace_simple_print!("{count} bytes write to tap");
156             }
157             Err(e) => error!("net: tx: failed to write frame to tap: {}", e),
158         }
159 
160         tx_queue.add_used(desc_chain, 0);
161     }
162 
163     tx_queue.trigger_interrupt(interrupt);
164 }
165 
166 impl<T> Worker<T>
167 where
168     T: TapT + ReadNotifier,
169 {
handle_rx_token( &mut self, wait_ctx: &WaitContext<Token>, ) -> result::Result<(), NetError>170     pub(in crate::virtio) fn handle_rx_token(
171         &mut self,
172         wait_ctx: &WaitContext<Token>,
173     ) -> result::Result<(), NetError> {
174         match self.process_rx() {
175             Ok(()) => Ok(()),
176             Err(NetError::RxDescriptorsExhausted) => {
177                 wait_ctx
178                     .modify(&self.tap, EventType::None, Token::RxTap)
179                     .map_err(NetError::WaitContextDisableTap)?;
180                 Ok(())
181             }
182             Err(e) => Err(e),
183         }
184     }
handle_rx_queue( &mut self, wait_ctx: &WaitContext<Token>, tap_polling_enabled: bool, ) -> result::Result<(), NetError>185     pub(in crate::virtio) fn handle_rx_queue(
186         &mut self,
187         wait_ctx: &WaitContext<Token>,
188         tap_polling_enabled: bool,
189     ) -> result::Result<(), NetError> {
190         if !tap_polling_enabled {
191             wait_ctx
192                 .modify(&self.tap, EventType::Read, Token::RxTap)
193                 .map_err(NetError::WaitContextEnableTap)?;
194         }
195         Ok(())
196     }
process_rx(&mut self) -> result::Result<(), NetError>197     pub(super) fn process_rx(&mut self) -> result::Result<(), NetError> {
198         process_rx(&self.interrupt, &mut self.rx_queue, &mut self.tap)
199     }
200 }
201