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