From b4313a1fcfe5aaba69efedbc7142b54891db2215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 6 Jul 2023 16:51:15 +0100 Subject: [PATCH] vhost: add vhost-user GET_BACKEND_SPECS handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This seems like an awful lot of boilerplate (without even any test) to implement a single message. Signed-off-by: Alex Bennée --- crates/vhost-user-backend/src/backend.rs | 24 ++++++++++++- crates/vhost-user-backend/src/handler.rs | 4 +++ .../tests/vhost-user-server.rs | 6 +++- crates/vhost/src/vhost_user/dummy_slave.rs | 5 +++ crates/vhost/src/vhost_user/message.rs | 36 ++++++++++++++++++- .../vhost/src/vhost_user/slave_req_handler.rs | 11 ++++++ 6 files changed, 83 insertions(+), 3 deletions(-) diff --git a/crates/vhost-user-backend/src/backend.rs b/crates/vhost-user-backend/src/backend.rs index 43ab7b95..ba10723d 100644 --- a/crates/vhost-user-backend/src/backend.rs +++ b/crates/vhost-user-backend/src/backend.rs @@ -22,7 +22,7 @@ use std::io::Result; use std::ops::Deref; use std::sync::{Arc, Mutex, RwLock}; -use vhost::vhost_user::message::VhostUserProtocolFeatures; +use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserBackendSpecs}; use vhost::vhost_user::Slave; use vm_memory::bitmap::Bitmap; use vmm_sys_util::epoll::EventSet; @@ -54,6 +54,9 @@ where /// Get available vhost protocol features. fn protocol_features(&self) -> VhostUserProtocolFeatures; + /// Get the backends specs + fn specs(&self) -> VhostUserBackendSpecs; + /// Enable or disable the virtio EVENT_IDX feature fn set_event_idx(&self, enabled: bool); @@ -135,6 +138,9 @@ where /// Get available vhost protocol features. fn protocol_features(&self) -> VhostUserProtocolFeatures; + /// Get specs + fn specs(&self) -> VhostUserBackendSpecs; + /// Enable or disable the virtio EVENT_IDX feature fn set_event_idx(&mut self, enabled: bool); @@ -220,6 +226,10 @@ where self.deref().protocol_features() } + fn specs(&self) -> VhostUserBackendSpecs { + self.deref().specs() + } + fn set_event_idx(&self, enabled: bool) { self.deref().set_event_idx(enabled) } @@ -285,6 +295,10 @@ where self.lock().unwrap().protocol_features() } + fn specs(&self) -> VhostUserBackendSpecs { + self.lock().unwrap().specs() + } + fn set_event_idx(&self, enabled: bool) { self.lock().unwrap().set_event_idx(enabled) } @@ -351,6 +365,10 @@ where self.read().unwrap().protocol_features() } + fn specs(&self) -> VhostUserBackendSpecs { + self.read().unwrap().specs() + } + fn set_event_idx(&self, enabled: bool) { self.write().unwrap().set_event_idx(enabled) } @@ -436,6 +454,10 @@ pub mod tests { VhostUserProtocolFeatures::all() } + fn specs(&self) -> VhostUserBackendSpecs { + VhostUserBackendSpecs::new(2, 32, 4, 8) + } + fn set_event_idx(&mut self, enabled: bool) { self.event_idx = enabled; } diff --git a/crates/vhost-user-backend/src/handler.rs b/crates/vhost-user-backend/src/handler.rs index 3761633a..b330d764 100644 --- a/crates/vhost-user-backend/src/handler.rs +++ b/crates/vhost-user-backend/src/handler.rs @@ -455,6 +455,10 @@ where Ok(()) } + fn specs(&self) -> VhostUserResult { + Ok(self.backend.specs()) + } + fn get_queue_num(&mut self) -> VhostUserResult { Ok(self.num_queues as u64) } diff --git a/crates/vhost-user-backend/tests/vhost-user-server.rs b/crates/vhost-user-backend/tests/vhost-user-server.rs index f6fdea7f..a1f03959 100644 --- a/crates/vhost-user-backend/tests/vhost-user-server.rs +++ b/crates/vhost-user-backend/tests/vhost-user-server.rs @@ -8,7 +8,7 @@ use std::sync::{Arc, Barrier, Mutex}; use std::thread; use vhost::vhost_user::message::{ - VhostUserConfigFlags, VhostUserHeaderFlag, VhostUserInflight, VhostUserProtocolFeatures, + VhostUserConfigFlags, VhostUserHeaderFlag, VhostUserInflight, VhostUserProtocolFeatures, VhostUserBackendSpecs, }; use vhost::vhost_user::{Listener, Master, Slave, VhostUserMaster}; use vhost::{VhostBackend, VhostUserMemoryRegionInfo, VringConfigData}; @@ -56,6 +56,10 @@ impl VhostUserBackendMut for MockVhostBackend { VhostUserProtocolFeatures::all() } + fn specs(&self) -> VhostUserBackendSpecs { + VhostUserBackendSpecs::new(1, 32, 4, 8) + } + fn set_event_idx(&mut self, enabled: bool) { self.event_idx = enabled; } diff --git a/crates/vhost/src/vhost_user/dummy_slave.rs b/crates/vhost/src/vhost_user/dummy_slave.rs index ae728a02..ec626450 100644 --- a/crates/vhost/src/vhost_user/dummy_slave.rs +++ b/crates/vhost/src/vhost_user/dummy_slave.rs @@ -203,6 +203,11 @@ impl VhostUserSlaveReqHandlerMut for DummySlaveReqHandler { Ok(()) } + fn specs(&self) -> Result { + Ok(VhostUserBackendSpecs::new( + 1, 2, 3, 4)) + } + fn get_queue_num(&mut self) -> Result { Ok(MAX_QUEUE_NUM as u64) } diff --git a/crates/vhost/src/vhost_user/message.rs b/crates/vhost/src/vhost_user/message.rs index bbd8eb9e..d489e752 100644 --- a/crates/vhost/src/vhost_user/message.rs +++ b/crates/vhost/src/vhost_user/message.rs @@ -146,8 +146,10 @@ pub enum MasterReq { /// Query the backend for its device status as defined in the VIRTIO /// specification. GET_STATUS = 40, + /// Query the backend for its emulation specification + GET_BACKEND_SPECS = 41, /// Upper bound of valid commands. - MAX_CMD = 41, + MAX_CMD = 42, } impl From for u32 { @@ -429,6 +431,8 @@ bitflags! { const STATUS = 0x0001_0000; /// Support Xen mmap. const XEN_MMAP = 0x0002_0000; + /// Support GET_BACKEND_SPECS; + const STANDALONE = 0x0004_0000; } } @@ -667,6 +671,36 @@ impl VhostUserSingleMemoryRegion { unsafe impl ByteValued for VhostUserSingleMemoryRegion {} impl VhostUserMsgValidator for VhostUserSingleMemoryRegion {} +/// Supported specs of the backend. +#[repr(C)] +#[derive(Default, Clone, Copy)] +pub struct VhostUserBackendSpecs { + /// VirtIO device ID + device_id: u32, + /// Size of config space + config_size: u32, + /// Minimum number of VQs + min_vqs: u32, + /// Maximum number of VQs + max_vqs: u32, +} + +impl VhostUserBackendSpecs { + /// Create a new instance. + pub fn new(device_id: u32, config_size: u32, + min_vqs: u32, max_vqs: u32) -> Self { + VhostUserBackendSpecs { + device_id, + config_size, + min_vqs, + max_vqs, + } + } +} + +// SAFETY: Safe because all fields of VhostUserBackendSpecs are POD +unsafe impl ByteValued for VhostUserBackendSpecs {} + /// Vring state descriptor. #[repr(packed)] #[derive(Copy, Clone, Default)] diff --git a/crates/vhost/src/vhost_user/slave_req_handler.rs b/crates/vhost/src/vhost_user/slave_req_handler.rs index d0374206..748688bf 100644 --- a/crates/vhost/src/vhost_user/slave_req_handler.rs +++ b/crates/vhost/src/vhost_user/slave_req_handler.rs @@ -61,6 +61,7 @@ pub trait VhostUserSlaveReqHandler { fn get_protocol_features(&self) -> Result; fn set_protocol_features(&self, features: u64) -> Result<()>; + fn specs(&self) -> Result; fn get_queue_num(&self) -> Result; fn set_vring_enable(&self, index: u32, enable: bool) -> Result<()>; fn get_config(&self, offset: u32, size: u32, flags: VhostUserConfigFlags) -> Result>; @@ -103,6 +104,7 @@ pub trait VhostUserSlaveReqHandlerMut { fn get_protocol_features(&mut self) -> Result; fn set_protocol_features(&mut self, features: u64) -> Result<()>; + fn specs(&self) -> Result; fn get_queue_num(&mut self) -> Result; fn set_vring_enable(&mut self, index: u32, enable: bool) -> Result<()>; fn get_config( @@ -192,6 +194,10 @@ impl VhostUserSlaveReqHandler for Mutex { self.lock().unwrap().set_protocol_features(features) } + fn specs(&self) -> Result { + self.lock().unwrap().specs() + } + fn get_queue_num(&self) -> Result { self.lock().unwrap().get_queue_num() } @@ -545,6 +551,11 @@ impl SlaveReqHandler { let msg = VhostUserU64::new(num.into()); self.send_reply_message(&hdr, &msg)?; } + Ok(MasterReq::GET_BACKEND_SPECS) => { + self.check_proto_feature(VhostUserProtocolFeatures::STANDALONE)?; + let msg = self.backend.specs()?; + self.send_reply_message(&hdr, &msg)?; + } _ => { return Err(Error::InvalidMessage); }