devices/virtio/net/sys/
linux.rs1use std::io;
6use std::io::Write;
7use std::mem;
8use std::result;
9
10use base::error;
11use base::warn;
12use base::EventType;
13use base::ReadNotifier;
14use base::WaitContext;
15use net_util::TapT;
16use virtio_sys::virtio_net;
17use virtio_sys::virtio_net::virtio_net_hdr;
18use virtio_sys::virtio_net::virtio_net_hdr_v1;
19use zerocopy::IntoBytes;
20
21use super::super::super::net::NetError;
22use super::super::super::net::Token;
23use super::super::super::net::Worker;
24use super::super::super::Queue;
25use super::PendingBuffer;
26
27pub fn validate_and_configure_tap<T: TapT>(tap: &T, vq_pairs: u16) -> Result<(), NetError> {
30 let flags = tap.if_flags();
31 let mut required_flags = vec![
32 (net_sys::IFF_TAP, "IFF_TAP"),
33 (net_sys::IFF_NO_PI, "IFF_NO_PI"),
34 (net_sys::IFF_VNET_HDR, "IFF_VNET_HDR"),
35 ];
36 if vq_pairs > 1 {
37 required_flags.push((net_sys::IFF_MULTI_QUEUE, "IFF_MULTI_QUEUE"));
38 }
39 let missing_flags = required_flags
40 .iter()
41 .filter_map(
42 |(value, name)| {
43 if value & flags == 0 {
44 Some(name)
45 } else {
46 None
47 }
48 },
49 )
50 .collect::<Vec<_>>();
51
52 if !missing_flags.is_empty() {
53 return Err(NetError::TapValidate(format!(
54 "Missing flags: {missing_flags:?}"
55 )));
56 }
57
58 let vnet_hdr_size = std::mem::size_of::<virtio_net_hdr_v1>();
59 tap.set_vnet_hdr_size(vnet_hdr_size)
60 .map_err(NetError::TapSetVnetHdrSize)?;
61
62 Ok(())
63}
64
65pub fn virtio_features_to_tap_offload(features: u64) -> u32 {
67 let mut tap_offloads: u32 = 0;
68 if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM) != 0 {
69 tap_offloads |= net_sys::TUN_F_CSUM;
70 }
71 if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4) != 0 {
72 tap_offloads |= net_sys::TUN_F_TSO4;
73 }
74 if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_TSO6) != 0 {
75 tap_offloads |= net_sys::TUN_F_TSO6;
76 }
77 if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_ECN) != 0 {
78 tap_offloads |= net_sys::TUN_F_TSO_ECN;
79 }
80 if features & (1 << virtio_net::VIRTIO_NET_F_GUEST_UFO) != 0 {
81 tap_offloads |= net_sys::TUN_F_UFO;
82 }
83
84 tap_offloads
85}
86
87pub fn process_mrg_rx<T: TapT>(
89 rx_queue: &mut Queue,
90 tap: &mut T,
91 pending: &mut PendingBuffer,
92) -> result::Result<(), NetError> {
93 let mut needs_interrupt = false;
94 let mut exhausted_queue = false;
95
96 loop {
97 if pending.length == 0 {
99 match tap.read(&mut *pending.buffer) {
100 Ok(length) => {
101 pending.length = length as u32;
102 }
103 Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
104 break;
106 }
107 Err(e) => {
108 warn!("net: rx: failed to write slice: {}", e);
109 return Err(NetError::WriteBuffer(e));
110 }
111 }
112 }
113 if pending.length == 0 {
114 break;
115 }
116 let packet_len = pending.length;
117 let Some(mut desc_list) = rx_queue.try_pop_length(packet_len as usize) else {
118 exhausted_queue = true;
121 break;
122 };
123 let num_buffers = desc_list.len() as u16;
124
125 let num_buffers_offset = mem::size_of::<virtio_net_hdr>();
127 pending.buffer[num_buffers_offset..num_buffers_offset + 2]
128 .copy_from_slice(num_buffers.as_bytes());
129 let mut offset = 0;
130 let end = packet_len as usize;
131 for desc in desc_list.iter_mut() {
132 let writer = &mut desc.writer;
133 let bytes_written = match writer.write(&pending.buffer[offset..end]) {
134 Ok(n) => n,
135 Err(e) => {
136 warn!(
137 "net: mrg_rx: failed to write slice from pending buffer: {}",
138 e
139 );
140 return Err(NetError::WriteBuffer(e));
141 }
142 };
143 offset += bytes_written;
144 }
145 rx_queue.add_used_batch(desc_list);
146
147 needs_interrupt = true;
148 pending.length = 0;
149 }
150
151 if needs_interrupt {
152 rx_queue.trigger_interrupt();
153 }
154
155 if exhausted_queue {
156 Err(NetError::RxDescriptorsExhausted)
157 } else {
158 Ok(())
159 }
160}
161
162pub fn process_rx<T: TapT>(rx_queue: &mut Queue, mut tap: &mut T) -> result::Result<(), NetError> {
163 let mut needs_interrupt = false;
164 let mut exhausted_queue = false;
165
166 loop {
168 let mut desc_chain = match rx_queue.peek() {
169 Some(desc) => desc,
170 None => {
171 exhausted_queue = true;
172 break;
173 }
174 };
175
176 let writer = &mut desc_chain.writer;
177
178 match writer.write_from(&mut tap, writer.available_bytes()) {
179 Ok(_) => {}
180 Err(ref e) if e.kind() == io::ErrorKind::WriteZero => {
181 warn!("net: rx: buffer is too small to hold frame");
182 break;
183 }
184 Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
185 break;
187 }
188 Err(e) => {
189 warn!("net: rx: failed to write slice: {}", e);
190 return Err(NetError::WriteBuffer(e));
191 }
192 };
193
194 let bytes_written = writer.bytes_written() as u32;
195 cros_tracing::trace_simple_print!("{bytes_written} bytes read from tap");
196
197 if bytes_written > 0 {
198 let desc_chain = desc_chain.pop();
199 rx_queue.add_used(desc_chain);
200 needs_interrupt = true;
201 }
202 }
203
204 if needs_interrupt {
205 rx_queue.trigger_interrupt();
206 }
207
208 if exhausted_queue {
209 Err(NetError::RxDescriptorsExhausted)
210 } else {
211 Ok(())
212 }
213}
214
215pub fn process_tx<T: TapT>(tx_queue: &mut Queue, mut tap: &mut T) {
216 while let Some(mut desc_chain) = tx_queue.pop() {
217 let reader = &mut desc_chain.reader;
218 let expected_count = reader.available_bytes();
219 match reader.read_to(&mut tap, expected_count) {
220 Ok(count) => {
221 if count != expected_count {
224 error!(
225 "net: tx: wrote only {} bytes of {} byte frame",
226 count, expected_count
227 );
228 }
229 cros_tracing::trace_simple_print!("{count} bytes write to tap");
230 }
231 Err(e) => error!("net: tx: failed to write frame to tap: {}", e),
232 }
233
234 tx_queue.add_used(desc_chain);
235 }
236
237 tx_queue.trigger_interrupt();
238}
239
240impl<T> Worker<T>
241where
242 T: TapT + ReadNotifier,
243{
244 pub(in crate::virtio) fn handle_rx_token(
245 &mut self,
246 wait_ctx: &WaitContext<Token>,
247 pending_buffer: &mut PendingBuffer,
248 ) -> result::Result<(), NetError> {
249 match self.process_rx(pending_buffer) {
250 Ok(()) => Ok(()),
251 Err(NetError::RxDescriptorsExhausted) => {
252 wait_ctx
253 .modify(&self.tap, EventType::None, Token::RxTap)
254 .map_err(NetError::WaitContextDisableTap)?;
255 Ok(())
256 }
257 Err(e) => Err(e),
258 }
259 }
260 pub(in crate::virtio) fn handle_rx_queue(
261 &mut self,
262 wait_ctx: &WaitContext<Token>,
263 tap_polling_enabled: bool,
264 ) -> result::Result<(), NetError> {
265 if !tap_polling_enabled {
266 wait_ctx
267 .modify(&self.tap, EventType::Read, Token::RxTap)
268 .map_err(NetError::WaitContextEnableTap)?;
269 }
270 Ok(())
271 }
272 pub(super) fn process_rx(
273 &mut self,
274 pending_buffer: &mut PendingBuffer,
275 ) -> result::Result<(), NetError> {
276 if self.acked_features & 1 << virtio_net::VIRTIO_NET_F_MRG_RXBUF == 0 {
277 process_rx(&mut self.rx_queue, &mut self.tap)
278 } else {
279 process_mrg_rx(&mut self.rx_queue, &mut self.tap, pending_buffer)
280 }
281 }
282}