summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLiu Jiang <gerry@linux.alibaba.com>2021-02-21 22:56:35 +0800
committerSergio Lopez <slp@sinrega.org>2021-03-01 12:50:56 +0100
commitec6eae722ef7c6fcecbb8acddf1d9905083dc3de (patch)
treede3776314e023cb30b9b5e631f49f84fad57fbdf /src
parent56b823482b1f47392aeec9051ed3bcf526926864 (diff)
downloadvmm_vhost-ec6eae722ef7c6fcecbb8acddf1d9905083dc3de.tar.gz
vhost_user: add more unit test cases
Add more unit test cases for vhost-user protocol. Signed-off-by: Liu Jiang <gerry@linux.alibaba.com>
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs12
-rw-r--r--src/vhost_user/connection.rs34
-rw-r--r--src/vhost_user/dummy_slave.rs48
-rw-r--r--src/vhost_user/master.rs62
-rw-r--r--src/vhost_user/master_req_handler.rs99
-rw-r--r--src/vhost_user/mod.rs180
-rw-r--r--src/vhost_user/slave.rs40
-rw-r--r--src/vhost_user/slave_req_handler.rs21
8 files changed, 416 insertions, 80 deletions
diff --git a/src/lib.rs b/src/lib.rs
index a3852a6..b7ed15c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -74,7 +74,7 @@ pub enum Error {
IoctlError(std::io::Error),
/// Error from IO subsystem.
IOError(std::io::Error),
- #[cfg(feature = "vhost-user-master")]
+ #[cfg(feature = "vhost-user")]
/// Error from the vhost-user subsystem.
VhostUserProtocol(vhost_user::Error),
}
@@ -95,7 +95,7 @@ impl std::fmt::Display for Error {
Error::VhostOpen(e) => write!(f, "failure in opening vhost file: {}", e),
#[cfg(feature = "vhost-kern")]
Error::IoctlError(e) => write!(f, "failure in vhost ioctl: {}", e),
- #[cfg(feature = "vhost-user-master")]
+ #[cfg(feature = "vhost-user")]
Error::VhostUserProtocol(e) => write!(f, "vhost-user: {}", e),
}
}
@@ -151,4 +151,12 @@ mod tests {
assert_eq!(format!("{:?}", Error::AvailAddress), "AvailAddress");
}
+
+ #[cfg(feature = "vhost-user")]
+ #[test]
+ fn test_convert_from_vhost_user_error() {
+ let e: Error = vhost_user::Error::OversizedMsg.into();
+
+ assert_eq!(format!("{}", e), "vhost-user: oversized message");
+ }
}
diff --git a/src/vhost_user/connection.rs b/src/vhost_user/connection.rs
index d89f9c7..01bf124 100644
--- a/src/vhost_user/connection.rs
+++ b/src/vhost_user/connection.rs
@@ -606,29 +606,32 @@ fn get_sub_iovs_offset(iov_lens: &[usize], skip_size: usize) -> (usize, usize) {
#[cfg(test)]
mod tests {
-
use super::*;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom, Write};
use std::os::unix::io::FromRawFd;
+ use vmm_sys_util::rand::rand_alphanumerics;
use vmm_sys_util::tempfile::TempFile;
- const UNIX_SOCKET_LISTENER: &'static str = "/tmp/vhost_user_test_rust_listener";
- const UNIX_SOCKET_CONNECTION: &'static str = "/tmp/vhost_user_test_rust_connection";
- const UNIX_SOCKET_DATA: &'static str = "/tmp/vhost_user_test_rust_data";
- const UNIX_SOCKET_FD: &'static str = "/tmp/vhost_user_test_rust_fd";
- const UNIX_SOCKET_SEND: &'static str = "/tmp/vhost_user_test_rust_send";
+ fn temp_path() -> String {
+ format!(
+ "/tmp/vhost_test_{}",
+ rand_alphanumerics(8).to_str().unwrap()
+ )
+ }
#[test]
fn create_listener() {
- let listener = Listener::new(UNIX_SOCKET_LISTENER, true).unwrap();
+ let path = temp_path();
+ let listener = Listener::new(&path, true).unwrap();
assert!(listener.as_raw_fd() > 0);
}
#[test]
fn accept_connection() {
- let listener = Listener::new(UNIX_SOCKET_CONNECTION, true).unwrap();
+ let path = temp_path();
+ let listener = Listener::new(&path, true).unwrap();
listener.set_nonblocking(true).unwrap();
// accept on a fd without incoming connection
@@ -638,9 +641,10 @@ mod tests {
#[test]
fn send_data() {
- let listener = Listener::new(UNIX_SOCKET_DATA, true).unwrap();
+ let path = temp_path();
+ let listener = Listener::new(&path, true).unwrap();
listener.set_nonblocking(true).unwrap();
- let mut master = Endpoint::<MasterReq>::connect(UNIX_SOCKET_DATA).unwrap();
+ let mut master = Endpoint::<MasterReq>::connect(&path).unwrap();
let sock = listener.accept().unwrap().unwrap();
let mut slave = Endpoint::<MasterReq>::from_stream(sock);
@@ -663,9 +667,10 @@ mod tests {
#[test]
fn send_fd() {
- let listener = Listener::new(UNIX_SOCKET_FD, true).unwrap();
+ let path = temp_path();
+ let listener = Listener::new(&path, true).unwrap();
listener.set_nonblocking(true).unwrap();
- let mut master = Endpoint::<MasterReq>::connect(UNIX_SOCKET_FD).unwrap();
+ let mut master = Endpoint::<MasterReq>::connect(&path).unwrap();
let sock = listener.accept().unwrap().unwrap();
let mut slave = Endpoint::<MasterReq>::from_stream(sock);
@@ -816,9 +821,10 @@ mod tests {
#[test]
fn send_recv() {
- let listener = Listener::new(UNIX_SOCKET_SEND, true).unwrap();
+ let path = temp_path();
+ let listener = Listener::new(&path, true).unwrap();
listener.set_nonblocking(true).unwrap();
- let mut master = Endpoint::<MasterReq>::connect(UNIX_SOCKET_SEND).unwrap();
+ let mut master = Endpoint::<MasterReq>::connect(&path).unwrap();
let sock = listener.accept().unwrap().unwrap();
let mut slave = Endpoint::<MasterReq>::from_stream(sock);
diff --git a/src/vhost_user/dummy_slave.rs b/src/vhost_user/dummy_slave.rs
index 53887e2..99f08e7 100644
--- a/src/vhost_user/dummy_slave.rs
+++ b/src/vhost_user/dummy_slave.rs
@@ -1,9 +1,10 @@
// Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
+use std::os::unix::io::RawFd;
+
use super::message::*;
use super::*;
-use std::os::unix::io::RawFd;
pub const MAX_QUEUE_NUM: usize = 2;
pub const MAX_VRING_NUM: usize = 256;
@@ -34,7 +35,7 @@ impl DummySlaveReqHandler {
}
}
-impl VhostUserSlaveReqHandler for DummySlaveReqHandler {
+impl VhostUserSlaveReqHandlerMut for DummySlaveReqHandler {
fn set_owner(&mut self) -> Result<()> {
if self.owned {
return Err(Error::InvalidOperation);
@@ -83,30 +84,10 @@ impl VhostUserSlaveReqHandler for DummySlaveReqHandler {
Ok(())
}
- fn get_protocol_features(&mut self) -> Result<VhostUserProtocolFeatures> {
- Ok(VhostUserProtocolFeatures::all())
- }
-
- fn set_protocol_features(&mut self, features: u64) -> Result<()> {
- // Note: slave that reported VHOST_USER_F_PROTOCOL_FEATURES must
- // support this message even before VHOST_USER_SET_FEATURES was
- // called.
- // What happens if the master calls set_features() with
- // VHOST_USER_F_PROTOCOL_FEATURES cleared after calling this
- // interface?
- self.acked_protocol_features = features;
- Ok(())
- }
-
fn set_mem_table(&mut self, _ctx: &[VhostUserMemoryRegion], _fds: &[RawFd]) -> Result<()> {
- // TODO
Ok(())
}
- fn get_queue_num(&mut self) -> Result<u64> {
- Ok(MAX_QUEUE_NUM as u64)
- }
-
fn set_vring_num(&mut self, index: u32, num: u32) -> Result<()> {
if index as usize >= self.queue_num || num == 0 || num as usize > MAX_VRING_NUM {
return Err(Error::InvalidParam);
@@ -199,6 +180,25 @@ impl VhostUserSlaveReqHandler for DummySlaveReqHandler {
Ok(())
}
+ fn get_protocol_features(&mut self) -> Result<VhostUserProtocolFeatures> {
+ Ok(VhostUserProtocolFeatures::all())
+ }
+
+ fn set_protocol_features(&mut self, features: u64) -> Result<()> {
+ // Note: slave that reported VHOST_USER_F_PROTOCOL_FEATURES must
+ // support this message even before VHOST_USER_SET_FEATURES was
+ // called.
+ // What happens if the master calls set_features() with
+ // VHOST_USER_F_PROTOCOL_FEATURES cleared after calling this
+ // interface?
+ self.acked_protocol_features = features;
+ Ok(())
+ }
+
+ fn get_queue_num(&mut self) -> Result<u64> {
+ Ok(MAX_QUEUE_NUM as u64)
+ }
+
fn set_vring_enable(&mut self, index: u32, enable: bool) -> Result<()> {
// This request should be handled only when VHOST_USER_F_PROTOCOL_FEATURES
// has been negotiated.
@@ -222,7 +222,7 @@ impl VhostUserSlaveReqHandler for DummySlaveReqHandler {
size: u32,
_flags: VhostUserConfigFlags,
) -> Result<Vec<u8>> {
- if self.acked_features & VhostUserProtocolFeatures::CONFIG.bits() == 0 {
+ if self.acked_protocol_features & VhostUserProtocolFeatures::CONFIG.bits() == 0 {
return Err(Error::InvalidOperation);
} else if offset < VHOST_USER_CONFIG_OFFSET
|| offset >= VHOST_USER_CONFIG_SIZE
@@ -236,7 +236,7 @@ impl VhostUserSlaveReqHandler for DummySlaveReqHandler {
fn set_config(&mut self, offset: u32, buf: &[u8], _flags: VhostUserConfigFlags) -> Result<()> {
let size = buf.len() as u32;
- if self.acked_features & VhostUserProtocolFeatures::CONFIG.bits() == 0 {
+ if self.acked_protocol_features & VhostUserProtocolFeatures::CONFIG.bits() == 0 {
return Err(Error::InvalidOperation);
} else if offset < VHOST_USER_CONFIG_OFFSET
|| offset >= VHOST_USER_CONFIG_SIZE
diff --git a/src/vhost_user/master.rs b/src/vhost_user/master.rs
index 65c7960..cc754b5 100644
--- a/src/vhost_user/master.rs
+++ b/src/vhost_user/master.rs
@@ -393,7 +393,10 @@ impl VhostUserMaster for Master {
return error_code(VhostUserError::SlaveInternalError);
} else if body_reply.size != body.size || body_reply.size as usize != buf.len() {
return error_code(VhostUserError::InvalidMessage);
+ } else if body_reply.offset != body.offset {
+ return error_code(VhostUserError::InvalidMessage);
}
+
Ok((body_reply, buf_reply))
}
@@ -571,6 +574,7 @@ impl MasterInternal {
) -> VhostUserResult<(T, Vec<u8>, Option<Vec<RawFd>>)> {
if mem::size_of::<T>() > MAX_MSG_SIZE
|| hdr.get_size() as usize <= mem::size_of::<T>()
+ || hdr.get_size() as usize > MAX_MSG_SIZE
|| hdr.is_reply()
{
return Err(VhostUserError::InvalidParam);
@@ -586,11 +590,8 @@ impl MasterInternal {
{
Endpoint::<MasterReq>::close_rfds(rfds);
return Err(VhostUserError::InvalidMessage);
- } else if bytes > MAX_MSG_SIZE - mem::size_of::<T>() {
+ } else if bytes != buf.len() {
return Err(VhostUserError::InvalidMessage);
- } else if bytes < buf.len() {
- // It's safe because we have checked the buffer size
- unsafe { buf.set_len(bytes) };
}
Ok((body, buf, rfds))
}
@@ -638,11 +639,14 @@ impl MasterInternal {
mod tests {
use super::super::connection::Listener;
use super::*;
+ use vmm_sys_util::rand::rand_alphanumerics;
- const UNIX_SOCKET_MASTER: &'static str = "/tmp/vhost_user_test_rust_master";
- const UNIX_SOCKET_MASTER2: &'static str = "/tmp/vhost_user_test_rust_master2";
- const UNIX_SOCKET_MASTER3: &'static str = "/tmp/vhost_user_test_rust_master3";
- const UNIX_SOCKET_MASTER4: &'static str = "/tmp/vhost_user_test_rust_master4";
+ fn temp_path() -> String {
+ format!(
+ "/tmp/vhost_test_{}",
+ rand_alphanumerics(8).to_str().unwrap()
+ )
+ }
fn create_pair(path: &str) -> (Master, Endpoint<MasterReq>) {
let listener = Listener::new(path, true).unwrap();
@@ -653,14 +657,15 @@ mod tests {
}
#[test]
- #[ignore]
fn create_master() {
- let listener = Listener::new(UNIX_SOCKET_MASTER, true).unwrap();
+ let path = temp_path();
+ let listener = Listener::new(&path, true).unwrap();
listener.set_nonblocking(true).unwrap();
- let master = Master::connect(UNIX_SOCKET_MASTER, 1).unwrap();
+ let master = Master::connect(&path, 1).unwrap();
let mut slave = Endpoint::<MasterReq>::from_stream(listener.accept().unwrap().unwrap());
+ assert!(master.as_raw_fd() > 0);
// Send two messages continuously
master.set_owner().unwrap();
master.reset_owner().unwrap();
@@ -679,24 +684,24 @@ mod tests {
}
#[test]
- #[ignore]
fn test_create_failure() {
- let _ = Listener::new(UNIX_SOCKET_MASTER2, true).unwrap();
- let _ = Listener::new(UNIX_SOCKET_MASTER2, false).is_err();
- assert!(Master::connect(UNIX_SOCKET_MASTER2, 1).is_err());
+ let path = temp_path();
+ let _ = Listener::new(&path, true).unwrap();
+ let _ = Listener::new(&path, false).is_err();
+ assert!(Master::connect(&path, 1).is_err());
- let listener = Listener::new(UNIX_SOCKET_MASTER2, true).unwrap();
- assert!(Listener::new(UNIX_SOCKET_MASTER2, false).is_err());
+ let listener = Listener::new(&path, true).unwrap();
+ assert!(Listener::new(&path, false).is_err());
listener.set_nonblocking(true).unwrap();
- let _master = Master::connect(UNIX_SOCKET_MASTER2, 1).unwrap();
+ let _master = Master::connect(&path, 1).unwrap();
let _slave = listener.accept().unwrap().unwrap();
}
#[test]
- #[ignore]
fn test_features() {
- let (master, mut peer) = create_pair(UNIX_SOCKET_MASTER3);
+ let path = temp_path();
+ let (master, mut peer) = create_pair(&path);
master.set_owner().unwrap();
let (hdr, rfds) = peer.recv_header().unwrap();
@@ -713,6 +718,9 @@ mod tests {
let (_hdr, rfds) = peer.recv_header().unwrap();
assert!(rfds.is_none());
+ let hdr = VhostUserMsgHeader::new(MasterReq::SET_FEATURES, 0x4, 8);
+ let msg = VhostUserU64::new(0x15);
+ peer.send_message(&hdr, &msg, None).unwrap();
master.set_features(0x15).unwrap();
let (_hdr, msg, rfds) = peer.recv_body::<VhostUserU64>().unwrap();
assert!(rfds.is_none());
@@ -726,9 +734,9 @@ mod tests {
}
#[test]
- #[ignore]
fn test_protocol_features() {
- let (mut master, mut peer) = create_pair(UNIX_SOCKET_MASTER4);
+ let path = temp_path();
+ let (mut master, mut peer) = create_pair(&path);
master.set_owner().unwrap();
let (hdr, rfds) = peer.recv_header().unwrap();
@@ -775,14 +783,4 @@ mod tests {
peer.send_message(&hdr, &msg, None).unwrap();
assert!(master.get_protocol_features().is_err());
}
-
- #[test]
- fn test_set_mem_table() {
- // TODO
- }
-
- #[test]
- fn test_get_ring_num() {
- // TODO
- }
}
diff --git a/src/vhost_user/master_req_handler.rs b/src/vhost_user/master_req_handler.rs
index 02c2bb7..fb33f15 100644
--- a/src/vhost_user/master_req_handler.rs
+++ b/src/vhost_user/master_req_handler.rs
@@ -377,3 +377,102 @@ impl<S: VhostUserMasterReqHandler> AsRawFd for MasterReqHandler<S> {
self.sub_sock.as_raw_fd()
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[cfg(feature = "vhost-user-slave")]
+ use crate::vhost_user::SlaveFsCacheReq;
+ #[cfg(feature = "vhost-user-slave")]
+ use std::os::unix::io::FromRawFd;
+
+ struct MockMasterReqHandler {}
+
+ impl VhostUserMasterReqHandlerMut for MockMasterReqHandler {
+ /// Handle virtio-fs map file requests from the slave.
+ fn fs_slave_map(&mut self, _fs: &VhostUserFSSlaveMsg, fd: RawFd) -> HandlerResult<u64> {
+ // Safe because we have just received the rawfd from kernel.
+ unsafe { libc::close(fd) };
+ Ok(0)
+ }
+
+ /// Handle virtio-fs unmap file requests from the slave.
+ fn fs_slave_unmap(&mut self, _fs: &VhostUserFSSlaveMsg) -> HandlerResult<u64> {
+ Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
+ }
+ }
+
+ #[test]
+ fn test_new_master_req_handler() {
+ let backend = Arc::new(Mutex::new(MockMasterReqHandler {}));
+ let mut handler = MasterReqHandler::new(backend).unwrap();
+
+ assert!(handler.get_tx_raw_fd() >= 0);
+ assert!(handler.as_raw_fd() >= 0);
+ handler.check_state().unwrap();
+
+ assert_eq!(handler.error, None);
+ handler.set_failed(libc::EAGAIN);
+ assert_eq!(handler.error, Some(libc::EAGAIN));
+ handler.check_state().unwrap_err();
+ }
+
+ #[cfg(feature = "vhost-user-slave")]
+ #[test]
+ fn test_master_slave_req_handler() {
+ let backend = Arc::new(Mutex::new(MockMasterReqHandler {}));
+ let mut handler = MasterReqHandler::new(backend).unwrap();
+
+ let fd = unsafe { libc::dup(handler.get_tx_raw_fd()) };
+ if fd < 0 {
+ panic!("failed to duplicated tx fd!");
+ }
+ let stream = unsafe { UnixStream::from_raw_fd(fd) };
+ let fs_cache = SlaveFsCacheReq::from_stream(stream);
+
+ std::thread::spawn(move || {
+ let res = handler.handle_request().unwrap();
+ assert_eq!(res, 0);
+ handler.handle_request().unwrap_err();
+ });
+
+ fs_cache
+ .fs_slave_map(&VhostUserFSSlaveMsg::default(), fd)
+ .unwrap();
+ // When REPLY_ACK has not been negotiated, the master has no way to detect failure from
+ // slave side.
+ fs_cache
+ .fs_slave_unmap(&VhostUserFSSlaveMsg::default())
+ .unwrap();
+ }
+
+ #[cfg(feature = "vhost-user-slave")]
+ #[test]
+ fn test_master_slave_req_handler_with_ack() {
+ let backend = Arc::new(Mutex::new(MockMasterReqHandler {}));
+ let mut handler = MasterReqHandler::new(backend).unwrap();
+ handler.set_reply_ack_flag(true);
+
+ let fd = unsafe { libc::dup(handler.get_tx_raw_fd()) };
+ if fd < 0 {
+ panic!("failed to duplicated tx fd!");
+ }
+ let stream = unsafe { UnixStream::from_raw_fd(fd) };
+ let fs_cache = SlaveFsCacheReq::from_stream(stream);
+
+ std::thread::spawn(move || {
+ let res = handler.handle_request().unwrap();
+ assert_eq!(res, 0);
+ handler.handle_request().unwrap_err();
+ });
+
+ fs_cache.set_reply_ack_flag(true);
+ fs_cache
+ .fs_slave_map(&VhostUserFSSlaveMsg::default(), fd)
+ .unwrap();
+ fs_cache
+ .fs_slave_unmap(&VhostUserFSSlaveMsg::default())
+ .unwrap_err();
+ }
+}
diff --git a/src/vhost_user/mod.rs b/src/vhost_user/mod.rs
index 91e4203..bf0a261 100644
--- a/src/vhost_user/mod.rs
+++ b/src/vhost_user/mod.rs
@@ -175,21 +175,32 @@ pub type Result<T> = std::result::Result<T, Error>;
/// Result of request handler.
pub type HandlerResult<T> = std::result::Result<T, IOError>;
-#[cfg(all(test, feature = "vhost-user-master", feature = "vhost-user-slave"))]
+#[cfg(all(test, feature = "vhost-user-slave"))]
mod dummy_slave;
#[cfg(all(test, feature = "vhost-user-master", feature = "vhost-user-slave"))]
mod tests {
+ use std::os::unix::io::AsRawFd;
+ use std::sync::{Arc, Barrier, Mutex};
+ use std::thread;
+ use vmm_sys_util::rand::rand_alphanumerics;
+
use super::dummy_slave::{DummySlaveReqHandler, VIRTIO_FEATURES};
use super::message::*;
use super::*;
use crate::backend::VhostBackend;
- use std::sync::{Arc, Barrier, Mutex};
- use std::thread;
+ use crate::{VhostUserMemoryRegionInfo, VringConfigData};
+
+ fn temp_path() -> String {
+ format!(
+ "/tmp/vhost_test_{}",
+ rand_alphanumerics(8).to_str().unwrap()
+ )
+ }
fn create_slave<S: VhostUserSlaveReqHandler>(
path: &str,
- backend: Arc<Mutex<S>>,
+ backend: Arc<S>,
) -> (Master, SlaveReqHandler<S>) {
let listener = Listener::new(path, true).unwrap();
let mut slave_listener = SlaveListener::new(listener, backend).unwrap();
@@ -208,8 +219,8 @@ mod tests {
#[test]
fn test_set_owner() {
let slave_be = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
- let (master, mut slave) =
- create_slave("/tmp/vhost_user_lib_unit_test_owner", slave_be.clone());
+ let path = temp_path();
+ let (master, mut slave) = create_slave(&path, slave_be.clone());
assert_eq!(slave_be.lock().unwrap().owned, false);
master.set_owner().unwrap();
@@ -224,14 +235,60 @@ mod tests {
fn test_set_features() {
let mbar = Arc::new(Barrier::new(2));
let sbar = mbar.clone();
+ let path = temp_path();
+ let slave_be = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
+ let (mut master, mut slave) = create_slave(&path, slave_be.clone());
+
+ thread::spawn(move || {
+ slave.handle_request().unwrap();
+ assert_eq!(slave_be.lock().unwrap().owned, true);
+
+ slave.handle_request().unwrap();
+ slave.handle_request().unwrap();
+ assert_eq!(
+ slave_be.lock().unwrap().acked_features,
+ VIRTIO_FEATURES & !0x1
+ );
+
+ slave.handle_request().unwrap();
+ slave.handle_request().unwrap();
+ assert_eq!(
+ slave_be.lock().unwrap().acked_protocol_features,
+ VhostUserProtocolFeatures::all().bits()
+ );
+
+ sbar.wait();
+ });
+
+ master.set_owner().unwrap();
+
+ // set virtio features
+ let features = master.get_features().unwrap();
+ assert_eq!(features, VIRTIO_FEATURES);
+ master.set_features(VIRTIO_FEATURES & !0x1).unwrap();
+
+ // set vhost protocol features
+ let features = master.get_protocol_features().unwrap();
+ assert_eq!(features.bits(), VhostUserProtocolFeatures::all().bits());
+ master.set_protocol_features(features).unwrap();
+
+ mbar.wait();
+ }
+
+ #[test]
+ fn test_master_slave_process() {
+ let mbar = Arc::new(Barrier::new(2));
+ let sbar = mbar.clone();
+ let path = temp_path();
let slave_be = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
- let (mut master, mut slave) =
- create_slave("/tmp/vhost_user_lib_unit_test_feature", slave_be.clone());
+ let (mut master, mut slave) = create_slave(&path, slave_be.clone());
thread::spawn(move || {
+ // set_own()
slave.handle_request().unwrap();
assert_eq!(slave_be.lock().unwrap().owned, true);
+ // get/set_features()
slave.handle_request().unwrap();
slave.handle_request().unwrap();
assert_eq!(
@@ -246,6 +303,36 @@ mod tests {
VhostUserProtocolFeatures::all().bits()
);
+ // get_queue_num()
+ slave.handle_request().unwrap();
+
+ // set_mem_table()
+ slave.handle_request().unwrap();
+
+ // get/set_config()
+ slave.handle_request().unwrap();
+ slave.handle_request().unwrap();
+
+ // set_slave_request_fd
+ slave.handle_request().unwrap();
+
+ // set_vring_enable
+ slave.handle_request().unwrap();
+
+ /*
+ // set_log_base,set_log_fd()
+ slave.handle_request().unwrap();
+ slave.handle_request().unwrap();
+ */
+
+ // set_vring_xxx
+ slave.handle_request().unwrap();
+ slave.handle_request().unwrap();
+ slave.handle_request().unwrap();
+ slave.handle_request().unwrap();
+ slave.handle_request().unwrap();
+ slave.handle_request().unwrap();
+
sbar.wait();
});
@@ -261,6 +348,83 @@ mod tests {
assert_eq!(features.bits(), VhostUserProtocolFeatures::all().bits());
master.set_protocol_features(features).unwrap();
+ let num = master.get_queue_num().unwrap();
+ assert_eq!(num, 2);
+
+ let eventfd = vmm_sys_util::eventfd::EventFd::new(0).unwrap();
+ let mem = [VhostUserMemoryRegionInfo {
+ guest_phys_addr: 0,
+ memory_size: 0x10_0000,
+ userspace_addr: 0,
+ mmap_offset: 0,
+ mmap_handle: eventfd.as_raw_fd(),
+ }];
+ master.set_mem_table(&mem).unwrap();
+
+ master
+ .set_config(0x100, VhostUserConfigFlags::WRITABLE, &[0xa5u8])
+ .unwrap();
+ let buf = [0x0u8; 4];
+ let (reply_body, reply_payload) = master
+ .get_config(0x100, 4, VhostUserConfigFlags::empty(), &buf)
+ .unwrap();
+ let offset = reply_body.offset;
+ assert_eq!(offset, 0x100);
+ assert_eq!(reply_payload[0], 0xa5);
+
+ master.set_slave_request_fd(eventfd.as_raw_fd()).unwrap();
+ master.set_vring_enable(0, true).unwrap();
+
+ /*
+ master.set_log_base(0, Some(eventfd.as_raw_fd())).unwrap();
+ master.set_log_fd(eventfd.as_raw_fd()).unwrap();
+ */
+
+ master.set_vring_num(0, 256).unwrap();
+ master.set_vring_base(0, 0).unwrap();
+ let config = VringConfigData {
+ queue_max_size: 256,
+ queue_size: 128,
+ flags: VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits(),
+ desc_table_addr: 0x1000,
+ used_ring_addr: 0x2000,
+ avail_ring_addr: 0x3000,
+ log_addr: Some(0x4000),
+ };
+ master.set_vring_addr(0, &config).unwrap();
+ master.set_vring_call(0, &eventfd).unwrap();
+ master.set_vring_kick(0, &eventfd).unwrap();
+ master.set_vring_err(0, &eventfd).unwrap();
+
mbar.wait();
}
+
+ #[test]
+ fn test_error_display() {
+ assert_eq!(format!("{}", Error::InvalidParam), "invalid parameters");
+ assert_eq!(format!("{}", Error::InvalidOperation), "invalid operation");
+ }
+
+ #[test]
+ fn test_should_reconnect() {
+ assert_eq!(Error::PartialMessage.should_reconnect(), true);
+ assert_eq!(Error::SlaveInternalError.should_reconnect(), true);
+ assert_eq!(Error::MasterInternalError.should_reconnect(), true);
+ assert_eq!(Error::InvalidParam.should_reconnect(), false);
+ assert_eq!(Error::InvalidOperation.should_reconnect(), false);
+ assert_eq!(Error::InvalidMessage.should_reconnect(), false);
+ assert_eq!(Error::IncorrectFds.should_reconnect(), false);
+ assert_eq!(Error::OversizedMsg.should_reconnect(), false);
+ assert_eq!(Error::FeatureMismatch.should_reconnect(), false);
+ }
+
+ #[test]
+ fn test_error_from_sys_util_error() {
+ let e: Error = vmm_sys_util::errno::Error::new(libc::EAGAIN.into()).into();
+ if let Error::SocketRetry(e1) = e {
+ assert_eq!(e1.raw_os_error().unwrap(), libc::EAGAIN);
+ } else {
+ panic!("invalid error code conversion!");
+ }
+ }
}
diff --git a/src/vhost_user/slave.rs b/src/vhost_user/slave.rs
index c167dce..fb65c41 100644
--- a/src/vhost_user/slave.rs
+++ b/src/vhost_user/slave.rs
@@ -44,3 +44,43 @@ impl<S: VhostUserSlaveReqHandler> SlaveListener<S> {
self.listener.set_nonblocking(block)
}
}
+
+#[cfg(test)]
+mod tests {
+ use std::sync::Mutex;
+
+ use super::*;
+ use crate::vhost_user::dummy_slave::DummySlaveReqHandler;
+
+ #[test]
+ fn test_slave_listener_set_nonblocking() {
+ let backend = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
+ let listener =
+ Listener::new("/tmp/vhost_user_lib_unit_test_slave_nonblocking", true).unwrap();
+ let slave_listener = SlaveListener::new(listener, backend).unwrap();
+
+ slave_listener.set_nonblocking(true).unwrap();
+ slave_listener.set_nonblocking(false).unwrap();
+ slave_listener.set_nonblocking(false).unwrap();
+ slave_listener.set_nonblocking(true).unwrap();
+ slave_listener.set_nonblocking(true).unwrap();
+ }
+
+ #[cfg(feature = "vhost-user-master")]
+ #[test]
+ fn test_slave_listener_accept() {
+ use super::super::Master;
+
+ let path = "/tmp/vhost_user_lib_unit_test_slave_accept";
+ let backend = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
+ let listener = Listener::new(path, true).unwrap();
+ let mut slave_listener = SlaveListener::new(listener, backend).unwrap();
+
+ slave_listener.set_nonblocking(true).unwrap();
+ assert!(slave_listener.accept().unwrap().is_none());
+ assert!(slave_listener.accept().unwrap().is_none());
+
+ let _master = Master::connect(path, 1).unwrap();
+ let _slave = slave_listener.accept().unwrap().unwrap();
+ }
+}
diff --git a/src/vhost_user/slave_req_handler.rs b/src/vhost_user/slave_req_handler.rs
index 344afff..ff07304 100644
--- a/src/vhost_user/slave_req_handler.rs
+++ b/src/vhost_user/slave_req_handler.rs
@@ -743,3 +743,24 @@ impl<S: VhostUserSlaveReqHandler> AsRawFd for SlaveReqHandler<S> {
self.main_sock.as_raw_fd()
}
}
+
+#[cfg(test)]
+mod tests {
+ use std::os::unix::io::AsRawFd;
+
+ use super::*;
+ use crate::vhost_user::dummy_slave::DummySlaveReqHandler;
+
+ #[test]
+ fn test_slave_req_handler_new() {
+ let (p1, _p2) = UnixStream::pair().unwrap();
+ let endpoint = Endpoint::<MasterReq>::from_stream(p1);
+ let backend = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
+ let mut handler = SlaveReqHandler::new(endpoint, backend);
+
+ handler.check_state().unwrap();
+ handler.set_failed(libc::EAGAIN);
+ handler.check_state().unwrap_err();
+ assert!(handler.as_raw_fd() >= 0);
+ }
+}