From 58680d58262fbb0086ba7b320cbbf9cf7bcf5293 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 23 Mar 2021 16:26:25 +0100 Subject: [PATCH] vhost_kern: add IOTLB message support Implement VhostIotlbBackend trait for vhost_kern handling both vhost_msg and vhost_msg_v2 messages according to acked backend features. Signed-off-by: Stefano Garzarella --- src/vhost_kern/mod.rs | 128 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 3 deletions(-) diff --git a/src/vhost_kern/mod.rs b/src/vhost_kern/mod.rs index 7f87920..7f9a079 100644 --- a/src/vhost_kern/mod.rs +++ b/src/vhost_kern/mod.rs @@ -11,15 +11,18 @@ //! communicate with userspace applications. This sub module provides ioctl based interfaces to //! control the in-kernel net, scsi, vsock vhost drivers. +use std::mem; use std::os::unix::io::{AsRawFd, RawFd}; +use libc::{c_void, ssize_t, write}; + use vm_memory::{Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestUsize}; use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::ioctl::{ioctl, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref}; use super::{ - Error, Result, VhostBackend, VhostUserDirtyLogRegion, VhostUserMemoryRegionInfo, - VringConfigData, VHOST_MAX_MEMORY_REGIONS, + Error, Result, VhostBackend, VhostIotlbBackend, VhostIotlbMsg, VhostIotlbMsgParser, + VhostUserDirtyLogRegion, VhostUserMemoryRegionInfo, VringConfigData, VHOST_MAX_MEMORY_REGIONS, }; pub mod vhost_binding; @@ -37,6 +40,15 @@ fn ioctl_result(rc: i32, res: T) -> Result { } } +#[inline] +fn io_result(rc: isize, res: T) -> Result { + if rc < 0 { + Err(Error::IOError(std::io::Error::last_os_error())) + } else { + Ok(res) + } +} + /// Represent an in-kernel vhost device backend. pub trait VhostKernBackend: AsRawFd { /// Associated type to access guest memory. @@ -314,4 +326,114 @@ pub trait VhostKernFeatures: Sized + AsRawFd { ioctl_result(ret, ()) } -} \ No newline at end of file +} + +/// Handle IOTLB messeges for in-kernel vhost device backend. +impl VhostIotlbBackend for I { + /// Send an IOTLB message to the in-kernel vhost backend. + /// + /// # Arguments + /// * `msg` - IOTLB message to send. + fn send_iotlb_msg(&self, msg: &VhostIotlbMsg) -> Result<()> { + let ret: ssize_t; + + if self.get_backend_features_acked() & (1 << VHOST_BACKEND_F_IOTLB_MSG_V2) != 0 { + let mut msg_v2 = vhost_msg_v2 { + type_: VHOST_IOTLB_MSG_V2, + ..Default::default() + }; + + msg_v2.__bindgen_anon_1.iotlb.iova = msg.iova; + msg_v2.__bindgen_anon_1.iotlb.size = msg.size; + msg_v2.__bindgen_anon_1.iotlb.uaddr = msg.userspace_addr; + msg_v2.__bindgen_anon_1.iotlb.perm = msg.perm as u8; + msg_v2.__bindgen_anon_1.iotlb.type_ = msg.msg_type as u8; + + ret = unsafe { + write( + self.as_raw_fd(), + &msg_v2 as *const vhost_msg_v2 as *const c_void, + mem::size_of::(), + ) + }; + } else { + let mut msg_v1 = vhost_msg { + type_: VHOST_IOTLB_MSG, + ..Default::default() + }; + + msg_v1.__bindgen_anon_1.iotlb.iova = msg.iova; + msg_v1.__bindgen_anon_1.iotlb.size = msg.size; + msg_v1.__bindgen_anon_1.iotlb.uaddr = msg.userspace_addr; + msg_v1.__bindgen_anon_1.iotlb.perm = msg.perm as u8; + msg_v1.__bindgen_anon_1.iotlb.type_ = msg.msg_type as u8; + + ret = unsafe { + write( + self.as_raw_fd(), + &msg_v1 as *const vhost_msg as *const c_void, + mem::size_of::(), + ) + }; + } + + io_result(ret, ()) + } + + /// Parse a buffer received from the in-kernel vhost backend and fill a VhostIotlbMsg. + /// + /// # Arguments + /// * `buffer` - Buffer containing the raw data received from the in-kernel vhost backend. + /// * `msg` - IOTLB message parsed. + fn parse_iotlb_msg( + &self, + buffer: &T, + msg: &mut VhostIotlbMsg, + ) -> Result<()> { + buffer.parse(msg) + } +} + +impl VhostIotlbMsgParser for vhost_msg { + fn parse(&self, msg: &mut VhostIotlbMsg) -> Result<()> { + if self.type_ != VHOST_IOTLB_MSG { + return Err(Error::InvalidIotlbMsg); + } + + unsafe { + if self.__bindgen_anon_1.iotlb.type_ == 0 { + return Err(Error::InvalidIotlbMsg); + } + + msg.iova = self.__bindgen_anon_1.iotlb.iova; + msg.size = self.__bindgen_anon_1.iotlb.size; + msg.userspace_addr = self.__bindgen_anon_1.iotlb.uaddr; + msg.perm = mem::transmute(self.__bindgen_anon_1.iotlb.perm); + msg.msg_type = mem::transmute(self.__bindgen_anon_1.iotlb.type_); + } + + Ok(()) + } +} + +impl VhostIotlbMsgParser for vhost_msg_v2 { + fn parse(&self, msg: &mut VhostIotlbMsg) -> Result<()> { + if self.type_ != VHOST_IOTLB_MSG_V2 { + return Err(Error::InvalidIotlbMsg); + } + + unsafe { + if self.__bindgen_anon_1.iotlb.type_ == 0 { + return Err(Error::InvalidIotlbMsg); + } + + msg.iova = self.__bindgen_anon_1.iotlb.iova; + msg.size = self.__bindgen_anon_1.iotlb.size; + msg.userspace_addr = self.__bindgen_anon_1.iotlb.uaddr; + msg.perm = mem::transmute(self.__bindgen_anon_1.iotlb.perm); + msg.msg_type = mem::transmute(self.__bindgen_anon_1.iotlb.type_); + } + + Ok(()) + } +}