diff options
author | Jason D. Clinton <jclinton@chromium.org> | 2017-09-27 22:04:03 -0600 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-02-02 16:32:12 -0800 |
commit | 865323d0ed8b6913ed7dfe6e31c3b86eb46775bd (patch) | |
tree | be835e928e8932ab66dc00412d5f96430289e94c /devices | |
parent | 19e57b9532f9be830fab7fad685957afc8f5ab78 (diff) | |
download | crosvm-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.rs | 61 | ||||
-rw-r--r-- | devices/src/virtio/vhost/net.rs | 104 |
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()], + ); + } +} |