Move Cloud Hypervisor to virtio-queue crate

Relying on the vm-virtio/virtio-queue crate from rust-vmm which has been
copied inside the Cloud Hypervisor tree, the entire codebase is moved to
the new definition of a Queue and other related structures.

The reason for this move is to follow the upstream until we get some
agreement for the patches that we need on top of that to make it
properly work with Cloud Hypervisor.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf
2021-10-21 12:41:16 +02:00
parent 7c19ae92b8
commit 0249e8641a
44 changed files with 936 additions and 1652 deletions
+3 -2
View File
@@ -818,8 +818,9 @@ mod tests {
let mut handler_ctx = vsock_test_ctx.create_epoll_handler_context();
let stream = TestStream::new();
let mut pkt = VsockPacket::from_rx_virtq_head(
&handler_ctx.handler.queues[0]
.iter(&vsock_test_ctx.mem)
&mut handler_ctx.handler.queues[0]
.iter()
.unwrap()
.next()
.unwrap(),
)
+38 -21
View File
@@ -34,7 +34,7 @@ use crate::GuestMemoryMmap;
use crate::VirtioInterrupt;
use crate::{
thread_helper::spawn_virtio_thread, ActivateResult, EpollHelper, EpollHelperError,
EpollHelperHandler, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType,
EpollHelperHandler, VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType,
EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IN_ORDER, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1,
};
use byteorder::{ByteOrder, LittleEndian};
@@ -47,7 +47,8 @@ use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Barrier, RwLock};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_memory::{GuestAddressSpace, GuestMemoryAtomic};
use virtio_queue::Queue;
use vm_memory::GuestMemoryAtomic;
use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
};
@@ -86,7 +87,7 @@ pub const BACKEND_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 4;
///
pub struct VsockEpollHandler<B: VsockBackend> {
pub mem: GuestMemoryAtomic<GuestMemoryMmap>,
pub queues: Vec<Queue>,
pub queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
pub queue_evts: Vec<EventFd>,
pub kill_evt: EventFd,
pub pause_evt: EventFd,
@@ -101,7 +102,10 @@ where
/// Signal the guest driver that we've used some virtio buffers that it had previously made
/// available.
///
fn signal_used_queue(&self, queue: &Queue) -> result::Result<(), DeviceError> {
fn signal_used_queue(
&self,
queue: &Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
) -> result::Result<(), DeviceError> {
debug!("vsock: raising IRQ");
self.interrupt_cb
@@ -120,16 +124,17 @@ where
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
let mut used_count = 0;
let mem = self.mem.memory();
for avail_desc in self.queues[0].iter(&mem) {
let used_len = match VsockPacket::from_rx_virtq_head(&avail_desc) {
let mut avail_iter = self.queues[0].iter().map_err(DeviceError::QueueIterator)?;
for mut desc_chain in &mut avail_iter {
let used_len = match VsockPacket::from_rx_virtq_head(&mut desc_chain) {
Ok(mut pkt) => {
if self.backend.write().unwrap().recv_pkt(&mut pkt).is_ok() {
pkt.hdr().len() as u32 + pkt.len()
} else {
// We are using a consuming iterator over the virtio buffers, so, if we can't
// fill in this buffer, we'll need to undo the last iterator step.
self.queues[0].go_to_previous_position();
avail_iter.go_to_previous_position();
break;
}
}
@@ -139,12 +144,14 @@ where
}
};
used_desc_heads[used_count] = (avail_desc.index, used_len);
used_desc_heads[used_count] = (desc_chain.head_index(), used_len);
used_count += 1;
}
for &(desc_index, len) in &used_desc_heads[..used_count] {
self.queues[0].add_used(&mem, desc_index, len);
self.queues[0]
.add_used(desc_index, len)
.map_err(DeviceError::QueueAddUsed)?;
}
if used_count > 0 {
@@ -162,29 +169,32 @@ where
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
let mut used_count = 0;
let mem = self.mem.memory();
for avail_desc in self.queues[1].iter(&mem) {
let pkt = match VsockPacket::from_tx_virtq_head(&avail_desc) {
let mut avail_iter = self.queues[1].iter().map_err(DeviceError::QueueIterator)?;
for mut desc_chain in &mut avail_iter {
let pkt = match VsockPacket::from_tx_virtq_head(&mut desc_chain) {
Ok(pkt) => pkt,
Err(e) => {
error!("vsock: error reading TX packet: {:?}", e);
used_desc_heads[used_count] = (avail_desc.index, 0);
used_desc_heads[used_count] = (desc_chain.head_index(), 0);
used_count += 1;
continue;
}
};
if self.backend.write().unwrap().send_pkt(&pkt).is_err() {
self.queues[1].go_to_previous_position();
avail_iter.go_to_previous_position();
break;
}
used_desc_heads[used_count] = (avail_desc.index, 0);
used_desc_heads[used_count] = (desc_chain.head_index(), 0);
used_count += 1;
}
for &(desc_index, len) in &used_desc_heads[..used_count] {
self.queues[1].add_used(&mem, desc_index, len);
self.queues[1]
.add_used(desc_index, len)
.map_err(DeviceError::QueueAddUsed)?;
}
if used_count > 0 {
@@ -417,7 +427,7 @@ where
&mut self,
mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>,
queues: Vec<Queue>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
queue_evts: Vec<EventFd>,
) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
@@ -578,12 +588,18 @@ mod tests {
other => panic!("{:?}", other),
}
let memory = GuestMemoryAtomic::new(ctx.mem.clone());
// Test a correct activation.
ctx.device
.activate(
GuestMemoryAtomic::new(ctx.mem.clone()),
memory.clone(),
Arc::new(NoopVirtioInterrupt {}),
vec![Queue::new(256), Queue::new(256), Queue::new(256)],
vec![
Queue::new(memory.clone(), 256),
Queue::new(memory.clone(), 256),
Queue::new(memory, 256),
],
vec![
EventFd::new(EFD_NONBLOCK).unwrap(),
EventFd::new(EFD_NONBLOCK).unwrap(),
@@ -599,8 +615,9 @@ mod tests {
{
let test_ctx = TestContext::new();
let ctx = test_ctx.create_epoll_handler_context();
let memory = GuestMemoryAtomic::new(test_ctx.mem.clone());
let queue = Queue::new(256);
let queue = Queue::new(memory, 256);
assert!(ctx.handler.signal_used_queue(&queue).is_ok());
}
}
+4 -3
View File
@@ -75,6 +75,8 @@ pub enum VsockError {
GuestMemoryBounds,
/// The vsock header descriptor length is too small.
HdrDescTooSmall(u32),
/// The vsock header descriptor is expected, but missing.
HdrDescMissing,
/// The vsock header `len` field holds an invalid value.
InvalidPktLen(u32),
/// A data fetch was attempted when no data was available.
@@ -168,10 +170,9 @@ mod tests {
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::sync::{Arc, RwLock};
use virtio_queue::{defs::VIRTQ_DESC_F_NEXT, defs::VIRTQ_DESC_F_WRITE, Queue};
use vm_memory::{GuestAddress, GuestMemoryAtomic};
use vm_virtio::queue::testing::VirtQueue as GuestQ;
use vm_virtio::queue::Queue;
use vm_virtio::queue::{VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE};
use vmm_sys_util::eventfd::EventFd;
pub struct NoopVirtioInterrupt {}
@@ -180,7 +181,7 @@ mod tests {
fn trigger(
&self,
_int_type: &VirtioInterruptType,
_queue: Option<&Queue>,
_queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
) -> std::result::Result<(), std::io::Error> {
Ok(())
}
+45 -29
View File
@@ -19,7 +19,9 @@ use byteorder::{ByteOrder, LittleEndian};
use super::defs;
use super::{Result, VsockError};
use crate::{get_host_address_range, DescriptorChain};
use crate::{get_host_address_range, GuestMemoryMmap};
use virtio_queue::DescriptorChain;
use vm_memory::GuestMemoryAtomic;
// The vsock packet header is defined by the C struct:
//
@@ -103,7 +105,11 @@ impl VsockPacket {
/// descriptor can optionally end the chain. Bounds and pointer checks are performed when
/// creating the wrapper.
///
pub fn from_tx_virtq_head(head: &DescriptorChain) -> Result<Self> {
pub fn from_tx_virtq_head(
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
) -> Result<Self> {
let head = desc_chain.next().ok_or(VsockError::HdrDescMissing)?;
// All buffers in the TX queue must be readable.
//
if head.is_write_only() {
@@ -111,12 +117,12 @@ impl VsockPacket {
}
// The packet header should fit inside the head descriptor.
if head.len < VSOCK_PKT_HDR_SIZE as u32 {
return Err(VsockError::HdrDescTooSmall(head.len));
if head.len() < VSOCK_PKT_HDR_SIZE as u32 {
return Err(VsockError::HdrDescTooSmall(head.len()));
}
let mut pkt = Self {
hdr: get_host_address_range(head.mem, head.addr, VSOCK_PKT_HDR_SIZE)
hdr: get_host_address_range(desc_chain.memory(), head.addr(), VSOCK_PKT_HDR_SIZE)
.ok_or(VsockError::GuestMemory)? as *mut u8,
buf: None,
buf_size: 0,
@@ -134,7 +140,7 @@ impl VsockPacket {
}
// If the packet header showed a non-zero length, there should be a data descriptor here.
let buf_desc = head.next_descriptor().ok_or(VsockError::BufDescMissing)?;
let buf_desc = desc_chain.next().ok_or(VsockError::BufDescMissing)?;
// TX data should be read-only.
if buf_desc.is_write_only() {
@@ -143,13 +149,13 @@ impl VsockPacket {
// The data buffer should be large enough to fit the size of the data, as described by
// the header descriptor.
if buf_desc.len < pkt.len() {
if buf_desc.len() < pkt.len() {
return Err(VsockError::BufDescTooSmall);
}
pkt.buf_size = buf_desc.len as usize;
pkt.buf_size = buf_desc.len() as usize;
pkt.buf = Some(
get_host_address_range(buf_desc.mem, buf_desc.addr, pkt.buf_size)
get_host_address_range(desc_chain.memory(), buf_desc.addr(), pkt.buf_size)
.ok_or(VsockError::GuestMemory)? as *mut u8,
);
@@ -161,7 +167,11 @@ impl VsockPacket {
/// There must be two descriptors in the chain, both writable: a header descriptor and a data
/// descriptor. Bounds and pointer checks are performed when creating the wrapper.
///
pub fn from_rx_virtq_head(head: &DescriptorChain) -> Result<Self> {
pub fn from_rx_virtq_head(
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
) -> Result<Self> {
let head = desc_chain.next().ok_or(VsockError::HdrDescMissing)?;
// All RX buffers must be writable.
//
if !head.is_write_only() {
@@ -169,22 +179,22 @@ impl VsockPacket {
}
// The packet header should fit inside the head descriptor.
if head.len < VSOCK_PKT_HDR_SIZE as u32 {
return Err(VsockError::HdrDescTooSmall(head.len));
if head.len() < VSOCK_PKT_HDR_SIZE as u32 {
return Err(VsockError::HdrDescTooSmall(head.len()));
}
// All RX descriptor chains should have a header and a data descriptor.
if !head.has_next() {
return Err(VsockError::BufDescMissing);
}
let buf_desc = head.next_descriptor().ok_or(VsockError::BufDescMissing)?;
let buf_size = buf_desc.len as usize;
let buf_desc = desc_chain.next().ok_or(VsockError::BufDescMissing)?;
let buf_size = buf_desc.len() as usize;
Ok(Self {
hdr: get_host_address_range(head.mem, head.addr, VSOCK_PKT_HDR_SIZE)
hdr: get_host_address_range(desc_chain.memory(), head.addr(), VSOCK_PKT_HDR_SIZE)
.ok_or(VsockError::GuestMemory)? as *mut u8,
buf: Some(
get_host_address_range(buf_desc.mem, buf_desc.addr, buf_size)
get_host_address_range(desc_chain.memory(), buf_desc.addr(), buf_size)
.ok_or(VsockError::GuestMemory)? as *mut u8,
),
buf_size,
@@ -343,9 +353,9 @@ mod tests {
use super::*;
use crate::vsock::defs::MAX_PKT_BUF_SIZE;
use crate::GuestMemoryMmap;
use virtio_queue::defs::VIRTQ_DESC_F_WRITE;
use vm_memory::GuestAddress;
use vm_virtio::queue::testing::VirtqDesc as GuestQDesc;
use vm_virtio::queue::VIRTQ_DESC_F_WRITE;
macro_rules! create_context {
($test_ctx:ident, $handler_ctx:ident) => {
@@ -365,8 +375,9 @@ mod tests {
};
($test_ctx:expr, $handler_ctx:expr, $err:pat, $ctor:ident, $vq:expr) => {
match VsockPacket::$ctor(
&$handler_ctx.handler.queues[$vq]
.iter(&$test_ctx.mem)
&mut $handler_ctx.handler.queues[$vq]
.iter()
.unwrap()
.next()
.unwrap(),
) {
@@ -394,8 +405,9 @@ mod tests {
create_context!(test_ctx, handler_ctx);
let pkt = VsockPacket::from_tx_virtq_head(
&handler_ctx.handler.queues[1]
.iter(&test_ctx.mem)
&mut handler_ctx.handler.queues[1]
.iter()
.unwrap()
.next()
.unwrap(),
)
@@ -430,8 +442,9 @@ mod tests {
create_context!(test_ctx, handler_ctx);
set_pkt_len(0, &handler_ctx.guest_txvq.dtable[0], &test_ctx.mem);
let mut pkt = VsockPacket::from_tx_virtq_head(
&handler_ctx.handler.queues[1]
.iter(&test_ctx.mem)
&mut handler_ctx.handler.queues[1]
.iter()
.unwrap()
.next()
.unwrap(),
)
@@ -486,8 +499,9 @@ mod tests {
{
create_context!(test_ctx, handler_ctx);
let pkt = VsockPacket::from_rx_virtq_head(
&handler_ctx.handler.queues[0]
.iter(&test_ctx.mem)
&mut handler_ctx.handler.queues[0]
.iter()
.unwrap()
.next()
.unwrap(),
)
@@ -541,8 +555,9 @@ mod tests {
create_context!(test_ctx, handler_ctx);
let mut pkt = VsockPacket::from_rx_virtq_head(
&handler_ctx.handler.queues[0]
.iter(&test_ctx.mem)
&mut handler_ctx.handler.queues[0]
.iter()
.unwrap()
.next()
.unwrap(),
)
@@ -630,8 +645,9 @@ mod tests {
fn test_packet_buf() {
create_context!(test_ctx, handler_ctx);
let mut pkt = VsockPacket::from_rx_virtq_head(
&handler_ctx.handler.queues[0]
.iter(&test_ctx.mem)
&mut handler_ctx.handler.queues[0]
.iter()
.unwrap()
.next()
.unwrap(),
)
+3 -2
View File
@@ -840,8 +840,9 @@ mod tests {
let vsock_test_ctx = VsockTestContext::new();
let mut handler_ctx = vsock_test_ctx.create_epoll_handler_context();
let pkt = VsockPacket::from_rx_virtq_head(
&handler_ctx.handler.queues[0]
.iter(&vsock_test_ctx.mem)
&mut handler_ctx.handler.queues[0]
.iter()
.unwrap()
.next()
.unwrap(),
)