device_virtio_net/sys/
linux.rs

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
5use 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            // SAFETY:
45            // Safe because we ensure that we get a unique handle to the fd.
46            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
71// Ensure that the tap interface has the correct flags and sets the offload and VNET header size
72// to the appropriate values.
73pub 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
109/// Converts virtio-net feature bits to tap's offload bits.
110pub 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
131/// If avail_feature has mrg_rxbuf, use this function to process rx flow.
132pub 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        // Refill `pending` if it is empty.
142        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                    // No more to read from the tap.
149                    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            // If vq is exhausted, pending buffer should be used firstly
163            // instead of reading from tap in next loop.
164            exhausted_queue = true;
165            break;
166        };
167        let num_buffers = desc_list.len() as u16;
168
169        // Copy the num_buffers value to specified address
170        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    // Read as many frames as possible.
211    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                // No more to read from the tap.
230                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                // Tap writes must be done in one call. If the entire frame was not
266                // written, it's an error.
267                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}