virtio: Port codebase to the latest virtio-queue version

The new virtio-queue version introduced some breaking changes which need
to be addressed so that Cloud Hypervisor can still work with this
version.

The most important change is about removing a handle to the guest memory
from the Queue, meaning the caller has to provide the guest memory
handle for multiple methods from the QueueT trait.

One interesting aspect is that QueueT has been widely extended to
provide every getter and setter we need to access and update the Queue
structure without having direct access to its internal fields.

This patch ports all the virtio and vhost-user devices to this new crate
definition. It also updates both vhost-user-block and vhost-user-net
backends based on the updated vhost-user-backend crate. It also updates
the fuzz directory.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf
2022-07-06 16:08:08 +02:00
committed by Rob Bradford
parent 7199119bb2
commit a423bf13ad
41 changed files with 414 additions and 354 deletions

View File

@@ -673,6 +673,7 @@ where
#[cfg(test)]
mod tests {
use libc::EFD_NONBLOCK;
use virtio_queue::QueueOwnedT;
use std::io::{Error as IoError, ErrorKind, Read, Result as IoResult, Write};
use std::os::unix::io::RawFd;
@@ -819,7 +820,7 @@ mod tests {
let stream = TestStream::new();
let mut pkt = VsockPacket::from_rx_virtq_head(
&mut handler_ctx.handler.queues[0]
.iter()
.iter(&vsock_test_ctx.mem)
.unwrap()
.next()
.unwrap(),

View File

@@ -40,6 +40,7 @@ use crate::{
use byteorder::{ByteOrder, LittleEndian};
use seccompiler::SeccompAction;
use std::io;
use std::ops::Deref;
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::result;
@@ -48,6 +49,9 @@ use std::sync::{Arc, Barrier, RwLock};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use virtio_queue::Queue;
use virtio_queue::QueueOwnedT;
use virtio_queue::QueueT;
use vm_memory::GuestAddressSpace;
use vm_memory::GuestMemoryAtomic;
use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
@@ -88,7 +92,7 @@ pub const BACKEND_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 4;
///
pub struct VsockEpollHandler<B: VsockBackend> {
pub mem: GuestMemoryAtomic<GuestMemoryMmap>,
pub queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
pub queues: Vec<Queue>,
pub queue_evts: Vec<EventFd>,
pub kill_evt: EventFd,
pub pause_evt: EventFd,
@@ -124,7 +128,9 @@ where
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
let mut used_count = 0;
let mut avail_iter = self.queues[0].iter().map_err(DeviceError::QueueIterator)?;
let mut avail_iter = self.queues[0]
.iter(self.mem.memory())
.map_err(DeviceError::QueueIterator)?;
for mut desc_chain in &mut avail_iter {
let used_len = match VsockPacket::from_rx_virtq_head(
&mut desc_chain,
@@ -150,9 +156,10 @@ where
used_count += 1;
}
let mem = self.mem.memory();
for &(desc_index, len) in &used_desc_heads[..used_count] {
self.queues[0]
.add_used(desc_index, len)
.add_used(mem.deref(), desc_index, len)
.map_err(DeviceError::QueueAddUsed)?;
}
@@ -172,7 +179,9 @@ where
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
let mut used_count = 0;
let mut avail_iter = self.queues[1].iter().map_err(DeviceError::QueueIterator)?;
let mut avail_iter = self.queues[1]
.iter(self.mem.memory())
.map_err(DeviceError::QueueIterator)?;
for mut desc_chain in &mut avail_iter {
let pkt = match VsockPacket::from_tx_virtq_head(
&mut desc_chain,
@@ -196,9 +205,10 @@ where
used_count += 1;
}
let mem = self.mem.memory();
for &(desc_index, len) in &used_desc_heads[..used_count] {
self.queues[1]
.add_used(desc_index, len)
.add_used(mem.deref(), desc_index, len)
.map_err(DeviceError::QueueAddUsed)?;
}
@@ -432,7 +442,7 @@ where
&mut self,
mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>,
queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
queues: Vec<(usize, Queue, EventFd)>,
) -> ActivateResult {
self.common.activate(&queues, &interrupt_cb)?;
let (kill_evt, pause_evt) = self.common.dup_eventfds();
@@ -592,38 +602,36 @@ mod tests {
// A warning is, however, logged, if the guest driver attempts to write any config data.
ctx.device.write_config(0, &data[..4]);
let memory = GuestMemoryAtomic::new(ctx.mem.clone());
// Test a bad activation.
let bad_activate = ctx.device.activate(
GuestMemoryAtomic::new(ctx.mem.clone()),
Arc::new(NoopVirtioInterrupt {}),
Vec::new(),
);
let bad_activate =
ctx.device
.activate(memory.clone(), Arc::new(NoopVirtioInterrupt {}), Vec::new());
match bad_activate {
Err(ActivateError::BadActivate) => (),
other => panic!("{:?}", other),
}
let memory = GuestMemoryAtomic::new(ctx.mem.clone());
// Test a correct activation.
ctx.device
.activate(
memory.clone(),
memory,
Arc::new(NoopVirtioInterrupt {}),
vec![
(
0,
Queue::new(memory.clone(), 256),
Queue::new(256).unwrap(),
EventFd::new(EFD_NONBLOCK).unwrap(),
),
(
1,
Queue::new(memory.clone(), 256),
Queue::new(256).unwrap(),
EventFd::new(EFD_NONBLOCK).unwrap(),
),
(
2,
Queue::new(memory, 256),
Queue::new(256).unwrap(),
EventFd::new(EFD_NONBLOCK).unwrap(),
),
],
@@ -637,9 +645,8 @@ 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<GuestMemoryAtomic<GuestMemoryMmap>> = Queue::new(memory, 256);
let _queue: Queue = Queue::new(256).unwrap();
assert!(ctx.handler.signal_used_queue(0).is_ok());
}
}

View File

@@ -170,7 +170,7 @@ 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};
use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE};
use vm_memory::{GuestAddress, GuestMemoryAtomic};
use vm_virtio::queue::testing::VirtQueue as GuestQ;
use vmm_sys_util::eventfd::EventFd;
@@ -295,15 +295,20 @@ mod tests {
guest_rxvq.dtable[0].set(
0x0040_0000,
VSOCK_PKT_HDR_SIZE as u32,
VIRTQ_DESC_F_WRITE | VIRTQ_DESC_F_NEXT,
(VRING_DESC_F_WRITE | VRING_DESC_F_NEXT).try_into().unwrap(),
1,
);
guest_rxvq.dtable[1].set(0x0040_1000, 4096, VIRTQ_DESC_F_WRITE, 0);
guest_rxvq.dtable[1].set(0x0040_1000, 4096, VRING_DESC_F_WRITE.try_into().unwrap(), 0);
guest_rxvq.avail.ring[0].set(0);
guest_rxvq.avail.idx.set(1);
// Set up one available descriptor in the TX queue.
guest_txvq.dtable[0].set(0x0050_0000, VSOCK_PKT_HDR_SIZE as u32, VIRTQ_DESC_F_NEXT, 1);
guest_txvq.dtable[0].set(
0x0050_0000,
VSOCK_PKT_HDR_SIZE as u32,
VRING_DESC_F_NEXT.try_into().unwrap(),
1,
);
guest_txvq.dtable[1].set(0x0050_1000, 4096, 0, 0);
guest_txvq.avail.ring[0].set(0);
guest_txvq.avail.idx.set(1);

View File

@@ -16,13 +16,14 @@
/// to temporary buffers, before passing it on to the vsock backend.
///
use byteorder::{ByteOrder, LittleEndian};
use std::ops::Deref;
use std::sync::Arc;
use super::defs;
use super::{Result, VsockError};
use crate::{get_host_address_range, GuestMemoryMmap};
use crate::get_host_address_range;
use virtio_queue::DescriptorChain;
use vm_memory::GuestMemoryLoadGuard;
use vm_memory::GuestMemory;
use vm_virtio::{AccessPlatform, Translatable};
// The vsock packet header is defined by the C struct:
@@ -107,10 +108,14 @@ impl VsockPacket {
/// descriptor can optionally end the chain. Bounds and pointer checks are performed when
/// creating the wrapper.
///
pub fn from_tx_virtq_head(
desc_chain: &mut DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap>>,
pub fn from_tx_virtq_head<M>(
desc_chain: &mut DescriptorChain<M>,
access_platform: Option<&Arc<dyn AccessPlatform>>,
) -> Result<Self> {
) -> Result<Self>
where
M: Clone + Deref,
M::Target: GuestMemory,
{
let head = desc_chain.next().ok_or(VsockError::HdrDescMissing)?;
// All buffers in the TX queue must be readable.
@@ -181,10 +186,14 @@ 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(
desc_chain: &mut DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap>>,
pub fn from_rx_virtq_head<M>(
desc_chain: &mut DescriptorChain<M>,
access_platform: Option<&Arc<dyn AccessPlatform>>,
) -> Result<Self> {
) -> Result<Self>
where
M: Clone + Deref,
M::Target: GuestMemory,
{
let head = desc_chain.next().ok_or(VsockError::HdrDescMissing)?;
// All RX buffers must be writable.
@@ -379,7 +388,8 @@ mod tests {
use super::*;
use crate::vsock::defs::MAX_PKT_BUF_SIZE;
use crate::GuestMemoryMmap;
use virtio_queue::defs::VIRTQ_DESC_F_WRITE;
use virtio_bindings::bindings::virtio_ring::VRING_DESC_F_WRITE;
use virtio_queue::QueueOwnedT;
use vm_memory::GuestAddress;
use vm_virtio::queue::testing::VirtqDesc as GuestQDesc;
@@ -402,7 +412,7 @@ mod tests {
($test_ctx:expr, $handler_ctx:expr, $err:pat, $ctor:ident, $vq:expr) => {
match VsockPacket::$ctor(
&mut $handler_ctx.handler.queues[$vq]
.iter()
.iter(&$test_ctx.mem)
.unwrap()
.next()
.unwrap(),
@@ -433,7 +443,7 @@ mod tests {
let pkt = VsockPacket::from_tx_virtq_head(
&mut handler_ctx.handler.queues[1]
.iter()
.iter(&test_ctx.mem)
.unwrap()
.next()
.unwrap(),
@@ -452,7 +462,7 @@ mod tests {
create_context!(test_ctx, handler_ctx);
handler_ctx.guest_txvq.dtable[0]
.flags
.set(VIRTQ_DESC_F_WRITE);
.set(VRING_DESC_F_WRITE.try_into().unwrap());
expect_asm_error!(tx, test_ctx, handler_ctx, VsockError::UnreadableDescriptor);
}
@@ -471,7 +481,7 @@ mod tests {
set_pkt_len(0, &handler_ctx.guest_txvq.dtable[0], &test_ctx.mem);
let mut pkt = VsockPacket::from_tx_virtq_head(
&mut handler_ctx.handler.queues[1]
.iter()
.iter(&test_ctx.mem)
.unwrap()
.next()
.unwrap(),
@@ -508,7 +518,7 @@ mod tests {
create_context!(test_ctx, handler_ctx);
handler_ctx.guest_txvq.dtable[1]
.flags
.set(VIRTQ_DESC_F_WRITE);
.set(VRING_DESC_F_WRITE.try_into().unwrap());
expect_asm_error!(tx, test_ctx, handler_ctx, VsockError::UnreadableDescriptor);
}
@@ -529,7 +539,7 @@ mod tests {
create_context!(test_ctx, handler_ctx);
let pkt = VsockPacket::from_rx_virtq_head(
&mut handler_ctx.handler.queues[0]
.iter()
.iter(&test_ctx.mem)
.unwrap()
.next()
.unwrap(),
@@ -564,7 +574,7 @@ mod tests {
create_context!(test_ctx, handler_ctx);
handler_ctx.guest_rxvq.dtable[0]
.flags
.set(VIRTQ_DESC_F_WRITE);
.set(VRING_DESC_F_WRITE.try_into().unwrap());
expect_asm_error!(rx, test_ctx, handler_ctx, VsockError::BufDescMissing);
}
}
@@ -586,7 +596,7 @@ mod tests {
create_context!(test_ctx, handler_ctx);
let mut pkt = VsockPacket::from_rx_virtq_head(
&mut handler_ctx.handler.queues[0]
.iter()
.iter(&test_ctx.mem)
.unwrap()
.next()
.unwrap(),
@@ -677,7 +687,7 @@ mod tests {
create_context!(test_ctx, handler_ctx);
let mut pkt = VsockPacket::from_rx_virtq_head(
&mut handler_ctx.handler.queues[0]
.iter()
.iter(&test_ctx.mem)
.unwrap()
.next()
.unwrap(),

View File

@@ -817,6 +817,8 @@ mod tests {
use std::os::unix::net::{UnixListener, UnixStream};
use std::path::{Path, PathBuf};
use virtio_queue::QueueOwnedT;
use super::super::super::csm::defs as csm_defs;
use super::super::super::tests::TestContext as VsockTestContext;
use super::*;
@@ -842,7 +844,7 @@ mod tests {
let mut handler_ctx = vsock_test_ctx.create_epoll_handler_context();
let pkt = VsockPacket::from_rx_virtq_head(
&mut handler_ctx.handler.queues[0]
.iter()
.iter(&vsock_test_ctx.mem)
.unwrap()
.next()
.unwrap(),