devices/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 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
27// Ensure that the tap interface has the correct flags and sets the offload and VNET header size
28// to the appropriate values.
29pub 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
65/// Converts virtio-net feature bits to tap's offload bits.
66pub 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
87/// If avail_feature has mrg_rxbuf, use this function to process rx flow.
88pub 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        // Refill `pending` if it is empty.
98        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                    // No more to read from the tap.
105                    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            // If vq is exhausted, pending buffer should be used firstly
119            // instead of reading from tap in next loop.
120            exhausted_queue = true;
121            break;
122        };
123        let num_buffers = desc_list.len() as u16;
124
125        // Copy the num_buffers value to specified address
126        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    // Read as many frames as possible.
167    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                // No more to read from the tap.
186                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                // Tap writes must be done in one call. If the entire frame was not
222                // written, it's an error.
223                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}