summary refs log tree commit diff
diff options
context:
space:
mode:
authorJakub Staron <jstaron@google.com>2019-06-11 15:17:49 -0700
committerCommit Bot <commit-bot@chromium.org>2019-06-24 07:53:29 +0000
commit4aaefc377f37a14ecad2725946d8385b92ceb1e4 (patch)
tree3b5ae801832958b27df09db6150e44a43872bda5
parentdd11d434730a5dea56106d0533bf42c6b7206ed0 (diff)
downloadcrosvm-4aaefc377f37a14ecad2725946d8385b92ceb1e4.tar
crosvm-4aaefc377f37a14ecad2725946d8385b92ceb1e4.tar.gz
crosvm-4aaefc377f37a14ecad2725946d8385b92ceb1e4.tar.bz2
crosvm-4aaefc377f37a14ecad2725946d8385b92ceb1e4.tar.lz
crosvm-4aaefc377f37a14ecad2725946d8385b92ceb1e4.tar.xz
crosvm-4aaefc377f37a14ecad2725946d8385b92ceb1e4.tar.zst
crosvm-4aaefc377f37a14ecad2725946d8385b92ceb1e4.zip
devices: Use Reader/Writer interfaces in virtio-net.
BUG=chromium:966258
TEST=tast run ${IP} vm.CrostiniStartEverything
TEST=tast run ${IP} vm.CrostiniNetworkPerf

Change-Id: I99c5b9e564c219b76593d729fb934722fc8a3431
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1658980
Reviewed-by: Stephen Barber <smbarber@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Stephen Barber <smbarber@chromium.org>
-rw-r--r--devices/src/virtio/net.rs110
1 files changed, 34 insertions, 76 deletions
diff --git a/devices/src/virtio/net.rs b/devices/src/virtio/net.rs
index 61a82cc..cfb43b9 100644
--- a/devices/src/virtio/net.rs
+++ b/devices/src/virtio/net.rs
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use std::cmp;
 use std::fmt::{self, Display};
 use std::mem;
 use std::net::Ipv4Addr;
@@ -14,12 +13,13 @@ use std::thread;
 use libc::EAGAIN;
 use net_sys;
 use net_util::{Error as TapError, MacAddress, TapT};
+use sys_util::guest_memory::Error as MemoryError;
 use sys_util::Error as SysError;
 use sys_util::{error, warn, EventFd, GuestMemory, PollContext, PollToken};
 use virtio_sys::virtio_net::virtio_net_hdr_v1;
 use virtio_sys::{vhost, virtio_net};
 
-use super::{Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TYPE_NET};
+use super::{Queue, Reader, VirtioDevice, Writer, INTERRUPT_STATUS_USED_RING, TYPE_NET};
 
 /// The maximum buffer size when segmentation offload is enabled. This
 /// includes the 12-byte virtio net header.
@@ -108,54 +108,29 @@ where
     // if a buffer was used, and false if the frame must be deferred until a buffer
     // is made available by the driver.
     fn rx_single_frame(&mut self) -> bool {
-        let mut next_desc = self.rx_queue.pop(&self.mem);
-
-        if next_desc.is_none() {
-            return false;
-        }
-
-        // We just checked that the head descriptor exists.
-        let head_index = next_desc.as_ref().unwrap().index;
-        let mut write_count = 0;
-
-        // Copy from frame into buffer, which may span multiple descriptors.
-        loop {
-            match next_desc {
-                Some(desc) => {
-                    if !desc.is_write_only() {
-                        break;
-                    }
-                    let limit = cmp::min(write_count + desc.len as usize, self.rx_count);
-                    let source_slice = &self.rx_buf[write_count..limit];
-                    let write_result = self.mem.write_at_addr(source_slice, desc.addr);
-
-                    match write_result {
-                        Ok(sz) => {
-                            write_count += sz;
-                        }
-                        Err(e) => {
-                            warn!("net: rx: failed to write slice: {}", e);
-                            break;
-                        }
-                    };
-
-                    if write_count >= self.rx_count {
-                        break;
-                    }
-                    next_desc = desc.next_descriptor();
-                }
-                None => {
-                    warn!(
-                        "net: rx: buffer is too small to hold frame of size {}",
-                        self.rx_count
-                    );
-                    break;
-                }
+        let desc_chain = match self.rx_queue.pop(&self.mem) {
+            Some(desc) => desc,
+            None => return false,
+        };
+
+        let index = desc_chain.index;
+        let mut writer = Writer::new(&self.mem, desc_chain);
+
+        match writer.write_all(&self.rx_buf[0..self.rx_count]) {
+            Ok(()) => (),
+            Err(MemoryError::ShortWrite { .. }) => {
+                warn!(
+                    "net: rx: buffer is too small to hold frame of size {}",
+                    self.rx_count
+                );
+            }
+            Err(e) => {
+                warn!("net: rx: failed to write slice: {}", e);
             }
         }
 
         self.rx_queue
-            .add_used(&self.mem, head_index, write_count as u32);
+            .add_used(&self.mem, index, writer.bytes_written() as u32);
 
         // Interrupt the guest immediately for received frames to
         // reduce latency.
@@ -191,41 +166,24 @@ where
     fn process_tx(&mut self) {
         let mut frame = [0u8; MAX_BUFFER_SIZE];
 
-        while let Some(avail_desc) = self.tx_queue.pop(&self.mem) {
-            let head_index = avail_desc.index;
-            let mut next_desc = Some(avail_desc);
-            let mut read_count = 0;
+        while let Some(desc_chain) = self.tx_queue.pop(&self.mem) {
+            let index = desc_chain.index;
+            let mut reader = Reader::new(&self.mem, desc_chain);
 
-            // Copy buffer from across multiple descriptors.
-            while let Some(desc) = next_desc {
-                if desc.is_write_only() {
-                    break;
-                }
-                let limit = cmp::min(read_count + desc.len as usize, frame.len());
-                let read_result = self
-                    .mem
-                    .read_at_addr(&mut frame[read_count..limit as usize], desc.addr);
-                match read_result {
-                    Ok(sz) => {
-                        read_count += sz;
-                    }
-                    Err(e) => {
-                        warn!("net: tx: failed to read slice: {}", e);
-                        break;
+            match reader.read(&mut frame) {
+                // We need to copy frame into continuous buffer before writing it to tap
+                // because tap requires frame to complete in a single write.
+                Ok(read_count) => {
+                    if let Err(err) = self.tap.write_all(&frame[..read_count]) {
+                        error!("net: tx: failed to write to tap: {}", err);
                     }
                 }
-                next_desc = desc.next_descriptor();
-            }
-
-            let write_result = self.tap.write(&frame[..read_count as usize]);
-            match write_result {
-                Ok(_) => {}
-                Err(e) => {
-                    warn!("net: tx: error failed to write to tap: {}", e);
+                Err(err) => {
+                    error!("net: tx: failed to read frame into buffer: {}", err);
                 }
-            };
+            }
 
-            self.tx_queue.add_used(&self.mem, head_index, 0);
+            self.tx_queue.add_used(&self.mem, index, 0);
         }
 
         self.signal_used_queue();