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