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