summary refs log tree commit diff
path: root/devices
diff options
context:
space:
mode:
authorJason D. Clinton <jclinton@chromium.org>2017-09-27 22:04:03 -0600
committerchrome-bot <chrome-bot@chromium.org>2018-02-02 16:32:12 -0800
commit865323d0ed8b6913ed7dfe6e31c3b86eb46775bd (patch)
treebe835e928e8932ab66dc00412d5f96430289e94c /devices
parent19e57b9532f9be830fab7fad685957afc8f5ab78 (diff)
downloadcrosvm-865323d0ed8b6913ed7dfe6e31c3b86eb46775bd.tar
crosvm-865323d0ed8b6913ed7dfe6e31c3b86eb46775bd.tar.gz
crosvm-865323d0ed8b6913ed7dfe6e31c3b86eb46775bd.tar.bz2
crosvm-865323d0ed8b6913ed7dfe6e31c3b86eb46775bd.tar.lz
crosvm-865323d0ed8b6913ed7dfe6e31c3b86eb46775bd.tar.xz
crosvm-865323d0ed8b6913ed7dfe6e31c3b86eb46775bd.tar.zst
crosvm-865323d0ed8b6913ed7dfe6e31c3b86eb46775bd.zip
hw/virtio/vhost: Add simple tests backed by fakes
This slightly advances the use of fakes to test higher level
application logic. The fakes are rudimentary at this point, but I
wanted to get feedback on the addition of generics in order to
facilitate swaping concrete implementations out with fakes in higher
level code.

BUG=none
TEST=./build_test and
cargo test -p crosvm -p data_model -p syscall_defines -p kernel_loader
-p net_util -p x86_64 -p virtio_sys -p kvm_sys -p vhost -p io_jail -p
net_sys -p sys_util -p kvm

Change-Id: Ib64581014391f49cff30ada10677bbbcd0088f20
Reviewed-on: https://chromium-review.googlesource.com/689740
Commit-Ready: Jason Clinton <jclinton@chromium.org>
Tested-by: Jason Clinton <jclinton@chromium.org>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
Diffstat (limited to 'devices')
-rw-r--r--devices/src/virtio/net.rs61
-rw-r--r--devices/src/virtio/vhost/net.rs104
2 files changed, 126 insertions, 39 deletions
diff --git a/devices/src/virtio/net.rs b/devices/src/virtio/net.rs
index a4df8c9..2c15271 100644
--- a/devices/src/virtio/net.rs
+++ b/devices/src/virtio/net.rs
@@ -4,7 +4,6 @@
 
 use std::cmp;
 use std::mem;
-use std::io::{Read, Write};
 use std::net::Ipv4Addr;
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::sync::Arc;
@@ -13,8 +12,8 @@ use std::thread;
 
 use libc::EAGAIN;
 use net_sys;
-use net_util::{Tap, Error as TapError};
-use sys_util::{Error as SysError};
+use net_util::{Error as TapError, TapT};
+use sys_util::Error as SysError;
 use sys_util::{EventFd, GuestMemory, Pollable, Poller};
 use virtio_sys::{vhost, virtio_net};
 use virtio_sys::virtio_net::virtio_net_hdr_v1;
@@ -50,11 +49,11 @@ pub enum NetError {
     PollError(SysError),
 }
 
-struct Worker {
+struct Worker<T: TapT> {
     mem: GuestMemory,
     rx_queue: Queue,
     tx_queue: Queue,
-    tap: Tap,
+    tap: T,
     interrupt_status: Arc<AtomicUsize>,
     interrupt_evt: EventFd,
     rx_buf: [u8; MAX_BUFFER_SIZE],
@@ -66,7 +65,10 @@ struct Worker {
     acked_features: u64,
 }
 
-impl Worker {
+impl<T> Worker<T>
+where
+    T: TapT,
+{
     fn signal_used_queue(&self) {
         self.interrupt_status
             .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
@@ -226,7 +228,7 @@ impl Worker {
         const KILL: u32 = 4;
 
         'poll: loop {
-            let tokens = match poller.poll(&[(RX_TAP, &self.tap as &Pollable),
+            let tokens = match poller.poll(&[(RX_TAP, &self.tap),
                                              (RX_QUEUE, &rx_queue_evt as &Pollable),
                                              (TX_QUEUE, &tx_queue_evt as &Pollable),
                                              (KILL, &kill_evt as &Pollable)]) {
@@ -274,21 +276,24 @@ impl Worker {
     }
 }
 
-pub struct Net {
+pub struct Net<T: TapT> {
     workers_kill_evt: Option<EventFd>,
     kill_evt: EventFd,
-    tap: Option<Tap>,
+    tap: Option<T>,
     avail_features: u64,
     acked_features: u64,
 }
 
-impl Net {
+impl<T> Net<T>
+where
+    T: TapT,
+{
     /// Create a new virtio network device with the given IP address and
     /// netmask.
-    pub fn new(ip_addr: Ipv4Addr, netmask: Ipv4Addr) -> Result<Net, NetError> {
+    pub fn new(ip_addr: Ipv4Addr, netmask: Ipv4Addr) -> Result<Net<T>, NetError> {
         let kill_evt = EventFd::new().map_err(NetError::CreateKillEventFd)?;
 
-        let tap = Tap::new().map_err(NetError::TapOpen)?;
+        let tap: T = T::new().map_err(NetError::TapOpen)?;
         tap.set_ip_addr(ip_addr).map_err(NetError::TapSetIp)?;
         tap.set_netmask(netmask)
             .map_err(NetError::TapSetNetmask)?;
@@ -306,24 +311,25 @@ impl Net {
 
         let avail_features =
             1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM | 1 << virtio_net::VIRTIO_NET_F_CSUM |
-            1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4 |
-            1 << virtio_net::VIRTIO_NET_F_GUEST_UFO |
-            1 << virtio_net::VIRTIO_NET_F_HOST_TSO4 |
-            1 << virtio_net::VIRTIO_NET_F_HOST_UFO | 1 << vhost::VIRTIO_F_VERSION_1;
+                1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4 |
+                1 << virtio_net::VIRTIO_NET_F_GUEST_UFO |
+                1 << virtio_net::VIRTIO_NET_F_HOST_TSO4 |
+                1 << virtio_net::VIRTIO_NET_F_HOST_UFO | 1 << vhost::VIRTIO_F_VERSION_1;
 
         Ok(Net {
-               workers_kill_evt: Some(kill_evt
-                                          .try_clone()
-                                          .map_err(NetError::CloneKillEventFd)?),
-               kill_evt: kill_evt,
-               tap: Some(tap),
-               avail_features: avail_features,
-               acked_features: 0u64,
-           })
+            workers_kill_evt: Some(kill_evt.try_clone().map_err(NetError::CloneKillEventFd)?),
+            kill_evt: kill_evt,
+            tap: Some(tap),
+            avail_features: avail_features,
+            acked_features: 0u64,
+        })
     }
 }
 
-impl Drop for Net {
+impl<T> Drop for Net<T>
+where
+    T: TapT,
+{
     fn drop(&mut self) {
         // Only kill the child if it claimed its eventfd.
         if self.workers_kill_evt.is_none() {
@@ -333,7 +339,10 @@ impl Drop for Net {
     }
 }
 
-impl VirtioDevice for Net {
+impl<T> VirtioDevice for Net<T>
+where
+    T: 'static + TapT,
+{
     fn keep_fds(&self) -> Vec<RawFd> {
         let mut keep_fds = Vec::new();
 
diff --git a/devices/src/virtio/vhost/net.rs b/devices/src/virtio/vhost/net.rs
index 473c7e8..fa8df76 100644
--- a/devices/src/virtio/vhost/net.rs
+++ b/devices/src/virtio/vhost/net.rs
@@ -10,10 +10,10 @@ use std::sync::atomic::AtomicUsize;
 use std::thread;
 
 use net_sys;
-use net_util::Tap;
+use net_util::TapT;
+
 use sys_util::{EventFd, GuestMemory};
-use vhost::Net as VhostNetHandle;
-use vhost::net::NetT;
+use vhost::NetT as VhostNetT;
 use virtio_sys::{vhost, virtio_net};
 
 use super::{Error, Result};
@@ -24,23 +24,27 @@ const QUEUE_SIZE: u16 = 256;
 const NUM_QUEUES: usize = 2;
 const QUEUE_SIZES: &'static [u16] = &[QUEUE_SIZE; NUM_QUEUES];
 
-pub struct Net {
+pub struct Net<T: TapT, U: VhostNetT<T>> {
     workers_kill_evt: Option<EventFd>,
     kill_evt: EventFd,
-    tap: Option<Tap>,
-    vhost_net_handle: Option<VhostNetHandle>,
+    tap: Option<T>,
+    vhost_net_handle: Option<U>,
     vhost_interrupt: Option<EventFd>,
     avail_features: u64,
     acked_features: u64,
 }
 
-impl Net {
+impl<T, U> Net<T, U>
+where
+    T: TapT,
+    U: VhostNetT<T>,
+{
     /// Create a new virtio network device with the given IP address and
     /// netmask.
-    pub fn new(ip_addr: Ipv4Addr, netmask: Ipv4Addr, mem: &GuestMemory) -> Result<Net> {
+    pub fn new(ip_addr: Ipv4Addr, netmask: Ipv4Addr, mem: &GuestMemory) -> Result<Net<T, U>> {
         let kill_evt = EventFd::new().map_err(Error::CreateKillEventFd)?;
 
-        let tap = Tap::new().map_err(Error::TapOpen)?;
+        let tap: T = T::new().map_err(Error::TapOpen)?;
         tap.set_ip_addr(ip_addr).map_err(Error::TapSetIp)?;
         tap.set_netmask(netmask).map_err(Error::TapSetNetmask)?;
 
@@ -54,7 +58,7 @@ impl Net {
         tap.set_vnet_hdr_size(vnet_hdr_size).map_err(Error::TapSetVnetHdrSize)?;
 
         tap.enable().map_err(Error::TapEnable)?;
-        let vhost_net_handle = VhostNetHandle::new(mem).map_err(Error::VhostOpen)?;
+        let vhost_net_handle = U::new(mem).map_err(Error::VhostOpen)?;
 
         let avail_features =
             1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM | 1 << virtio_net::VIRTIO_NET_F_CSUM |
@@ -79,7 +83,11 @@ impl Net {
     }
 }
 
-impl Drop for Net {
+impl<T, U> Drop for Net<T, U>
+where
+    T: TapT,
+    U: VhostNetT<T>,
+{
     fn drop(&mut self) {
         // Only kill the child if it claimed its eventfd.
         if self.workers_kill_evt.is_none() {
@@ -89,7 +97,11 @@ impl Drop for Net {
     }
 }
 
-impl VirtioDevice for Net {
+impl<T, U> VirtioDevice for Net<T, U>
+where
+    T: TapT + 'static,
+    U: VhostNetT<T> + 'static,
+{
     fn keep_fds(&self) -> Vec<RawFd> {
         let mut keep_fds = Vec::new();
 
@@ -182,7 +194,7 @@ impl VirtioDevice for Net {
                                                              status,
                                                              interrupt_evt,
                                                              acked_features);
-                                let activate_vqs = |handle: &VhostNetHandle| -> Result<()> {
+                                let activate_vqs = |handle: &U| -> Result<()> {
                                     for idx in 0..NUM_QUEUES {
                                         handle
                                             .set_backend(idx, &tap)
@@ -207,3 +219,69 @@ impl VirtioDevice for Net {
         }
     }
 }
+
+#[cfg(test)]
+pub mod tests {
+    use super::*;
+    use std::result;
+    use net_util::fakes::FakeTap;
+    use sys_util::{GuestAddress, GuestMemory, GuestMemoryError};
+    use vhost::net::fakes::FakeNet;
+
+    fn create_guest_memory() -> result::Result<GuestMemory, GuestMemoryError> {
+        let start_addr1 = GuestAddress(0x0);
+        let start_addr2 = GuestAddress(0x100);
+        GuestMemory::new(&vec![(start_addr1, 0x100), (start_addr2, 0x400)])
+    }
+
+    fn create_net_common() -> Net<FakeTap, FakeNet<FakeTap>> {
+        let guest_memory = create_guest_memory().unwrap();
+        Net::<FakeTap, FakeNet<FakeTap>>::new(
+            Ipv4Addr::new(127, 0, 0, 1),
+            Ipv4Addr::new(255, 255, 255, 0),
+            &guest_memory,
+        ).unwrap()
+    }
+
+    #[test]
+    fn create_net() {
+        create_net_common();
+    }
+
+    #[test]
+    fn keep_fds() {
+        let net = create_net_common();
+        let fds = net.keep_fds();
+        assert!(fds.len() >= 1, "We should have gotten at least one fd");
+    }
+
+    #[test]
+    fn features() {
+        let net = create_net_common();
+        assert_eq!(net.features(0), 822135939);
+        assert_eq!(net.features(1), 1);
+        assert_eq!(net.features(2), 0);
+    }
+
+    #[test]
+    fn ack_features() {
+        let mut net = create_net_common();
+        // Just testing that we don't panic, for now
+        net.ack_features(0, 1);
+        net.ack_features(1, 1);
+    }
+
+    #[test]
+    fn activate() {
+        let mut net = create_net_common();
+        let guest_memory = create_guest_memory().unwrap();
+        // Just testing that we don't panic, for now
+        net.activate(
+            guest_memory,
+            EventFd::new().unwrap(),
+            Arc::new(AtomicUsize::new(0)),
+            vec![Queue::new(1)],
+            vec![EventFd::new().unwrap()],
+        );
+    }
+}