Skip to content

Commit

Permalink
vhost: promote get/set_status from vdpa to vhost
Browse files Browse the repository at this point in the history
Although originally introduced for VDPA we also have support for
get/set status messages for vhost-user. So lets promote the trait
functions to the main VhostBackend traits while providing a default
implementation which responds for errors (which the Kernel variant
would inherit).

As the status bits are common between backends most of the
implementation details can be handled within the vhost-user traits.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
  • Loading branch information
stsquad committed Jul 10, 2023
1 parent 900b9a5 commit 3c6b1f1
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 13 deletions.
12 changes: 12 additions & 0 deletions crates/vhost-user-backend/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ pub struct VhostUserHandler<S, V, B: Bitmap + 'static> {
atomic_mem: GM<B>,
vrings: Vec<V>,
worker_threads: Vec<thread::JoinHandle<VringEpollResult<()>>>,
/// VirtIO Device Status field, when using get/set status
status: u8,
}

// Ensure VhostUserHandler: Clone + Send + Sync + 'static.
Expand Down Expand Up @@ -147,6 +149,7 @@ where
atomic_mem,
vrings,
worker_threads,
status: 0,
})
}
}
Expand Down Expand Up @@ -586,6 +589,15 @@ where

Ok(())
}

fn get_status(&self) -> VhostUserResult<u8> {
Ok(self.status)
}

fn set_status(&mut self, status: u8) -> VhostUserResult<()> {
self.status = status;
Ok(())
}
}

impl<S, V, B: Bitmap> Drop for VhostUserHandler<S, V, B> {
Expand Down
68 changes: 66 additions & 2 deletions crates/vhost/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,32 @@ pub trait VhostBackend: std::marker::Sized {
/// * `queue_index` - Index of the queue to modify.
/// * `fd` - EventFd that will be signaled from guest.
fn set_vring_err(&self, queue_index: usize, fd: &EventFd) -> Result<()>;

/// Set the status.
/// The status bits follow the same definition of the device
/// status defined in virtio-spec.
///
/// As not all backends can implement this we provide a default
/// implementation that returns an Error.
///
/// # Arguments
/// * `status` - Status bits to set
fn set_status(&self, _status: u8) -> Result<()>
{
Err(Error::InvalidOperation)
}

/// Get the status.
///
/// The status bits follow the same definition of the device
/// status defined in virtio-spec.
///
/// As not all backends can implement this we provide a default
/// implementation that returns an Error.
fn get_status(&self) -> Result<u8>
{
Err(Error::InvalidOperation)
}
}

/// An interface for setting up vhost-based backend drivers.
Expand Down Expand Up @@ -394,6 +420,17 @@ pub trait VhostBackendMut: std::marker::Sized {
/// * `queue_index` - Index of the queue to modify.
/// * `fd` - EventFd that will be signaled from guest.
fn set_vring_err(&mut self, queue_index: usize, fd: &EventFd) -> Result<()>;

/// Set the status.
/// The status bits follow the same definition of the device status defined in virtio-spec.
///
/// # Arguments
/// * `status` - Status bits to set
fn set_status(&mut self, status: u8) -> Result<()>;

/// Get the status.
/// The status bits follow the same definition of the device status defined in virtio-spec.
fn get_status(&self) -> Result<u8>;
}

impl<T: VhostBackendMut> VhostBackend for RwLock<T> {
Expand Down Expand Up @@ -454,6 +491,14 @@ impl<T: VhostBackendMut> VhostBackend for RwLock<T> {
fn set_vring_err(&self, queue_index: usize, fd: &EventFd) -> Result<()> {
self.write().unwrap().set_vring_err(queue_index, fd)
}

fn set_status(&self, status: u8) -> Result<()> {
self.write().unwrap().set_status(status)
}

fn get_status(&self) -> Result<u8> {
self.write().unwrap().get_status()
}
}

impl<T: VhostBackendMut> VhostBackend for RefCell<T> {
Expand Down Expand Up @@ -512,6 +557,14 @@ impl<T: VhostBackendMut> VhostBackend for RefCell<T> {
fn set_vring_err(&self, queue_index: usize, fd: &EventFd) -> Result<()> {
self.borrow_mut().set_vring_err(queue_index, fd)
}

fn set_status(&self, status: u8) -> Result<()> {
self.borrow_mut().set_status(status)
}

fn get_status(&self) -> Result<u8> {
self.borrow_mut().get_status()
}
}

#[cfg(any(test, feature = "test-utils"))]
Expand Down Expand Up @@ -543,7 +596,9 @@ impl VhostUserMemoryRegionInfo {
mod tests {
use super::*;

struct MockBackend {}
struct MockBackend {
status:u8,
}

impl VhostBackendMut for MockBackend {
fn get_features(&mut self) -> Result<u64> {
Expand Down Expand Up @@ -625,11 +680,20 @@ mod tests {
assert_eq!(queue_index, 1);
Ok(())
}

fn set_status(&mut self, status: u8) -> Result<()> {
self.status = status;
Ok(())
}

fn get_status(&self) -> Result<u8> {
Ok(self.status)
}
}

#[test]
fn test_vring_backend_mut() {
let b = RwLock::new(MockBackend {});
let b = RwLock::new(MockBackend { status: 0 });

assert_eq!(b.get_features().unwrap(), 0x1);
b.set_features(0x1).unwrap();
Expand Down
11 changes: 0 additions & 11 deletions crates/vhost/src/vdpa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,6 @@ pub trait VhostVdpa: VhostBackend {
/// The device ids follow the same definition of the device id defined in virtio-spec.
fn get_device_id(&self) -> Result<u32>;

/// Get the status.
/// The status bits follow the same definition of the device status defined in virtio-spec.
fn get_status(&self) -> Result<u8>;

/// Set the status.
/// The status bits follow the same definition of the device status defined in virtio-spec.
///
/// # Arguments
/// * `status` - Status bits to set
fn set_status(&self, status: u8) -> Result<()>;

/// Get the device configuration.
///
/// # Arguments
Expand Down
21 changes: 21 additions & 0 deletions crates/vhost/src/vhost_user/master.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
use std::os::unix::net::UnixStream;
use std::path::Path;
use std::sync::{Arc, Mutex, MutexGuard};
use std::convert::TryFrom;

use vm_memory::ByteValued;
use vmm_sys_util::eventfd::EventFd;
Expand Down Expand Up @@ -330,6 +331,26 @@ impl VhostBackend for Master {
let hdr = node.send_fd_for_vring(MasterReq::SET_VRING_ERR, queue_index, fd.as_raw_fd())?;
node.wait_for_ack(&hdr).map_err(|e| e.into())
}

/// Set the status at the remote end (if supported)
fn set_status(&self, status: u8) -> Result<()> {
let mut node = self.node();
// depends on VhostUserProtocolFeatures::STATUS
node.check_proto_feature(VhostUserProtocolFeatures::STATUS)?;
let val = VhostUserU64::new(status.into());
node.send_request_with_body(MasterReq::SET_STATUS, &val, None)?;
Ok(())
}

/// Get the status from the remote end (if supported)
fn get_status(&self) -> Result<u8> {
let mut node = self.node();
// depends on VhostUserProtocolFeatures::STATUS
node.check_proto_feature(VhostUserProtocolFeatures::STATUS)?;
let hdr = node.send_request_header(MasterReq::GET_STATUS, None)?;
let reply = node.recv_reply::<VhostUserU64>(&hdr)?;
u8::try_from(reply.value).or(error_code(VhostUserError::InvalidParam))
}
}

impl VhostUserMaster for Master {
Expand Down
26 changes: 26 additions & 0 deletions crates/vhost/src/vhost_user/slave_req_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::os::unix::net::UnixStream;
use std::slice;
use std::sync::{Arc, Mutex};
use std::convert::{TryFrom};

use vm_memory::ByteValued;

Expand Down Expand Up @@ -70,6 +71,8 @@ pub trait VhostUserSlaveReqHandler {
fn get_max_mem_slots(&self) -> Result<u64>;
fn add_mem_region(&self, region: &VhostUserSingleMemoryRegion, fd: File) -> Result<()>;
fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()>;
fn get_status(&self) -> Result<u8>;
fn set_status(&self, status: u8) -> Result<()>;
}

/// Services provided to the master by the slave without interior mutability.
Expand Down Expand Up @@ -118,6 +121,8 @@ pub trait VhostUserSlaveReqHandlerMut {
fn get_max_mem_slots(&mut self) -> Result<u64>;
fn add_mem_region(&mut self, region: &VhostUserSingleMemoryRegion, fd: File) -> Result<()>;
fn remove_mem_region(&mut self, region: &VhostUserSingleMemoryRegion) -> Result<()>;
fn get_status(&self) -> Result<u8>;
fn set_status(&mut self, status: u8) -> Result<()>;
}

impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> {
Expand Down Expand Up @@ -226,6 +231,14 @@ impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> {
fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()> {
self.lock().unwrap().remove_mem_region(region)
}

fn get_status(&self) -> Result<u8> {
self.lock().unwrap().get_status()
}

fn set_status(&self, status: u8) -> Result<()> {
self.lock().unwrap().set_status(status)
}
}

/// Server to handle service requests from masters from the master communication channel.
Expand Down Expand Up @@ -519,6 +532,19 @@ impl<S: VhostUserSlaveReqHandler> SlaveReqHandler<S> {
let res = self.backend.remove_mem_region(&msg);
self.send_ack_message(&hdr, res)?;
}
Ok(MasterReq::SET_STATUS) => {
self.check_proto_feature(VhostUserProtocolFeatures::STATUS)?;
self.check_request_size(&hdr, size, hdr.get_size() as usize)?;
let msg = self.extract_request_body::<VhostUserU64>(&hdr, size, &buf)?;
let status = u8::try_from(msg.value).or(Err(Error::InvalidParam))?;
self.backend.set_status(status)?;
}
Ok(MasterReq::GET_STATUS) => {
self.check_proto_feature(VhostUserProtocolFeatures::STATUS)?;
let num = self.backend.get_status()?;
let msg = VhostUserU64::new(num.into());
self.send_reply_message(&hdr, &msg)?;
}
_ => {
return Err(Error::InvalidMessage);
}
Expand Down

0 comments on commit 3c6b1f1

Please sign in to comment.