| // Copyright (C) 2019-2021 Alibaba Cloud. All rights reserved. | |
| // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause | |
| // | |
| // Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. | |
| // | |
| // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE-BSD-Google file. | |
| //! Common traits and structs for vhost-kern and vhost-user backend drivers. | |
| use std::cell::RefCell; | |
| use std::os::unix::io::AsRawFd; | |
| use std::os::unix::io::RawFd; | |
| use std::sync::RwLock; | |
| use vm_memory::{bitmap::Bitmap, Address, GuestMemoryRegion, GuestRegionMmap}; | |
| use vmm_sys_util::eventfd::EventFd; | |
| #[cfg(feature = "vhost-user")] | |
| use super::vhost_user::message::{VhostUserMemoryRegion, VhostUserSingleMemoryRegion}; | |
| use super::{Error, Result}; | |
| /// Maximum number of memory regions supported. | |
| pub const VHOST_MAX_MEMORY_REGIONS: usize = 255; | |
| /// Vring configuration data. | |
| #[derive(Default, Clone, Copy)] | |
| pub struct VringConfigData { | |
| /// Maximum queue size supported by the driver. | |
| pub queue_max_size: u16, | |
| /// Actual queue size negotiated by the driver. | |
| pub queue_size: u16, | |
| /// Bitmask of vring flags. | |
| pub flags: u32, | |
| /// Descriptor table address. | |
| pub desc_table_addr: u64, | |
| /// Used ring buffer address. | |
| pub used_ring_addr: u64, | |
| /// Available ring buffer address. | |
| pub avail_ring_addr: u64, | |
| /// Optional address for logging. | |
| pub log_addr: Option<u64>, | |
| } | |
| impl VringConfigData { | |
| /// Check whether the log (flag, address) pair is valid. | |
| pub fn is_log_addr_valid(&self) -> bool { | |
| if self.flags & 0x1 != 0 && self.log_addr.is_none() { | |
| return false; | |
| } | |
| true | |
| } | |
| /// Get the log address, default to zero if not available. | |
| pub fn get_log_addr(&self) -> u64 { | |
| if self.flags & 0x1 != 0 && self.log_addr.is_some() { | |
| self.log_addr.unwrap() | |
| } else { | |
| 0 | |
| } | |
| } | |
| } | |
| /// Memory region configuration data. | |
| #[derive(Default, Clone, Copy)] | |
| pub struct VhostUserMemoryRegionInfo { | |
| /// Guest physical address of the memory region. | |
| pub guest_phys_addr: u64, | |
| /// Size of the memory region. | |
| pub memory_size: u64, | |
| /// Virtual address in the current process. | |
| pub userspace_addr: u64, | |
| /// Optional offset where region starts in the mapped memory. | |
| pub mmap_offset: u64, | |
| /// Optional file descriptor for mmap. | |
| pub mmap_handle: RawFd, | |
| #[cfg(feature = "xen")] | |
| /// Xen specific flags. | |
| pub xen_mmap_flags: u32, | |
| #[cfg(feature = "xen")] | |
| /// Xen specific data. | |
| pub xen_mmap_data: u32, | |
| } | |
| impl VhostUserMemoryRegionInfo { | |
| /// Creates Self from GuestRegionMmap. | |
| pub fn from_guest_region<B: Bitmap>(region: &GuestRegionMmap<B>) -> Result<Self> { | |
| let file_offset = region | |
| .file_offset() | |
| .ok_or(Error::InvalidGuestMemoryRegion)?; | |
| Ok(Self { | |
| guest_phys_addr: region.start_addr().raw_value(), | |
| memory_size: region.len(), | |
| userspace_addr: region.as_ptr() as u64, | |
| mmap_offset: file_offset.start(), | |
| mmap_handle: file_offset.file().as_raw_fd(), | |
| #[cfg(feature = "xen")] | |
| xen_mmap_flags: region.xen_mmap_flags(), | |
| #[cfg(feature = "xen")] | |
| xen_mmap_data: region.xen_mmap_data(), | |
| }) | |
| } | |
| /// Creates VhostUserMemoryRegion from Self. | |
| #[cfg(feature = "vhost-user")] | |
| pub fn to_region(&self) -> VhostUserMemoryRegion { | |
| #[cfg(not(feature = "xen"))] | |
| return VhostUserMemoryRegion::new( | |
| self.guest_phys_addr, | |
| self.memory_size, | |
| self.userspace_addr, | |
| self.mmap_offset, | |
| ); | |
| #[cfg(feature = "xen")] | |
| VhostUserMemoryRegion::with_xen( | |
| self.guest_phys_addr, | |
| self.memory_size, | |
| self.userspace_addr, | |
| self.mmap_offset, | |
| self.xen_mmap_flags, | |
| self.xen_mmap_data, | |
| ) | |
| } | |
| /// Creates VhostUserSingleMemoryRegion from Self. | |
| #[cfg(feature = "vhost-user")] | |
| pub fn to_single_region(&self) -> VhostUserSingleMemoryRegion { | |
| VhostUserSingleMemoryRegion::new( | |
| self.guest_phys_addr, | |
| self.memory_size, | |
| self.userspace_addr, | |
| self.mmap_offset, | |
| #[cfg(feature = "xen")] | |
| self.xen_mmap_flags, | |
| #[cfg(feature = "xen")] | |
| self.xen_mmap_data, | |
| ) | |
| } | |
| } | |
| /// Shared memory region data for logging dirty pages | |
| #[derive(Default, Clone, Copy)] | |
| pub struct VhostUserDirtyLogRegion { | |
| /// Size of the shared memory region for logging dirty pages | |
| pub mmap_size: u64, | |
| /// Offset where region starts | |
| pub mmap_offset: u64, | |
| /// File descriptor for mmap | |
| pub mmap_handle: RawFd, | |
| } | |
| /// Vhost memory access permission (VHOST_ACCESS_* mapping) | |
| #[repr(u8)] | |
| #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] | |
| pub enum VhostAccess { | |
| /// No access. | |
| #[default] | |
| No = 0, | |
| /// Read-Only access. | |
| ReadOnly = 1, | |
| /// Write-Only access. | |
| WriteOnly = 2, | |
| /// Read and Write access. | |
| ReadWrite = 3, | |
| } | |
| /// Vhost IOTLB message type (VHOST_IOTLB_* mapping) | |
| #[repr(u8)] | |
| #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] | |
| pub enum VhostIotlbType { | |
| /// Empty message (not valid). | |
| #[default] | |
| Empty = 0, | |
| /// I/O virtual address mapping is missing or invalidated. | |
| Miss = 1, | |
| /// Update the I/O virtual address mapping. | |
| Update = 2, | |
| /// Invalidate the I/O virtual address mapping. | |
| Invalidate = 3, | |
| /// Access failed to an I/O virtual address. | |
| AccessFail = 4, | |
| /// Batch of multiple `Update` messages begins. | |
| BatchBegin = 5, | |
| /// Batch of multiple `Update` messages ends. | |
| BatchEnd = 6, | |
| } | |
| /// Vhost IOTLB message structure. | |
| #[derive(Default, Clone, Copy)] | |
| pub struct VhostIotlbMsg { | |
| /// I/O virtual address. | |
| pub iova: u64, | |
| /// Size of the I/O mapping. | |
| pub size: u64, | |
| /// Virtual address in the current process. | |
| pub userspace_addr: u64, | |
| /// Access permissions. | |
| pub perm: VhostAccess, | |
| /// Type of the message. | |
| pub msg_type: VhostIotlbType, | |
| } | |
| /// Vhost IOTLB message parser. | |
| pub trait VhostIotlbMsgParser { | |
| /// Parse the IOTLB message and fill a VhostIotlbMsg. | |
| /// | |
| /// # Arguments | |
| /// * `msg` - IOTLB message parsed. | |
| fn parse(&self, msg: &mut VhostIotlbMsg) -> Result<()>; | |
| } | |
| /// An interface for IOTLB messages support for vhost-based backend | |
| pub trait VhostIotlbBackend: std::marker::Sized { | |
| /// Send an IOTLB message to the vhost-based backend. | |
| /// | |
| /// # Arguments | |
| /// * `msg` - IOTLB message to send. | |
| fn send_iotlb_msg(&self, msg: &VhostIotlbMsg) -> Result<()>; | |
| } | |
| /// An interface for setting up vhost-based backend drivers with interior mutability. | |
| /// | |
| /// Vhost devices are subset of virtio devices, which improve virtio device's performance by | |
| /// delegating data plane operations to dedicated IO service processes. Vhost devices use the | |
| /// same virtqueue layout as virtio devices to allow vhost devices to be mapped directly to | |
| /// virtio devices. | |
| /// | |
| /// The purpose of vhost is to implement a subset of a virtio device's functionality outside the | |
| /// VMM process. Typically fast paths for IO operations are delegated to the dedicated IO service | |
| /// processes, and slow path for device configuration are still handled by the VMM process. It may | |
| /// also be used to control access permissions of virtio backend devices. | |
| pub trait VhostBackend: std::marker::Sized { | |
| /// Get a bitmask of supported virtio/vhost features. | |
| fn get_features(&self) -> Result<u64>; | |
| /// Inform the vhost subsystem which features to enable. | |
| /// This should be a subset of supported features from get_features(). | |
| /// | |
| /// # Arguments | |
| /// * `features` - Bitmask of features to set. | |
| fn set_features(&self, features: u64) -> Result<()>; | |
| /// Set the current process as the owner of the vhost backend. | |
| /// This must be run before any other vhost commands. | |
| fn set_owner(&self) -> Result<()>; | |
| /// Used to be sent to request disabling all rings | |
| /// This is no longer used. | |
| fn reset_owner(&self) -> Result<()>; | |
| /// Set the guest memory mappings for vhost to use. | |
| fn set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>; | |
| /// Set base address for page modification logging. | |
| fn set_log_base(&self, base: u64, region: Option<VhostUserDirtyLogRegion>) -> Result<()>; | |
| /// Specify an eventfd file descriptor to signal on log write. | |
| fn set_log_fd(&self, fd: RawFd) -> Result<()>; | |
| /// Set the number of descriptors in the vring. | |
| /// | |
| /// # Arguments | |
| /// * `queue_index` - Index of the queue to set descriptor count for. | |
| /// * `num` - Number of descriptors in the queue. | |
| fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()>; | |
| /// Set the addresses for a given vring. | |
| /// | |
| /// # Arguments | |
| /// * `queue_index` - Index of the queue to set addresses for. | |
| /// * `config_data` - Configuration data for a vring. | |
| fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()>; | |
| /// Set the first index to look for available descriptors. | |
| /// | |
| /// # Arguments | |
| /// * `queue_index` - Index of the queue to modify. | |
| /// * `num` - Index where available descriptors start. | |
| fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()>; | |
| /// Get the available vring base offset. | |
| fn get_vring_base(&self, queue_index: usize) -> Result<u32>; | |
| /// Set the eventfd to trigger when buffers have been used by the host. | |
| /// | |
| /// # Arguments | |
| /// * `queue_index` - Index of the queue to modify. | |
| /// * `fd` - EventFd to trigger. | |
| fn set_vring_call(&self, queue_index: usize, fd: &EventFd) -> Result<()>; | |
| /// Set the eventfd that will be signaled by the guest when buffers are | |
| /// available for the host to process. | |
| /// | |
| /// # Arguments | |
| /// * `queue_index` - Index of the queue to modify. | |
| /// * `fd` - EventFd that will be signaled from guest. | |
| fn set_vring_kick(&self, queue_index: usize, fd: &EventFd) -> Result<()>; | |
| /// Set the eventfd that will be signaled by the guest when error happens. | |
| /// | |
| /// # Arguments | |
| /// * `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<()>; | |
| } | |
| /// An interface for setting up vhost-based backend drivers. | |
| /// | |
| /// Vhost devices are subset of virtio devices, which improve virtio device's performance by | |
| /// delegating data plane operations to dedicated IO service processes. Vhost devices use the | |
| /// same virtqueue layout as virtio devices to allow vhost devices to be mapped directly to | |
| /// virtio devices. | |
| /// | |
| /// The purpose of vhost is to implement a subset of a virtio device's functionality outside the | |
| /// VMM process. Typically fast paths for IO operations are delegated to the dedicated IO service | |
| /// processes, and slow path for device configuration are still handled by the VMM process. It may | |
| /// also be used to control access permissions of virtio backend devices. | |
| pub trait VhostBackendMut: std::marker::Sized { | |
| /// Get a bitmask of supported virtio/vhost features. | |
| fn get_features(&mut self) -> Result<u64>; | |
| /// Inform the vhost subsystem which features to enable. | |
| /// This should be a subset of supported features from get_features(). | |
| /// | |
| /// # Arguments | |
| /// * `features` - Bitmask of features to set. | |
| fn set_features(&mut self, features: u64) -> Result<()>; | |
| /// Set the current process as the owner of the vhost backend. | |
| /// This must be run before any other vhost commands. | |
| fn set_owner(&mut self) -> Result<()>; | |
| /// Used to be sent to request disabling all rings | |
| /// This is no longer used. | |
| fn reset_owner(&mut self) -> Result<()>; | |
| /// Set the guest memory mappings for vhost to use. | |
| fn set_mem_table(&mut self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>; | |
| /// Set base address for page modification logging. | |
| fn set_log_base(&mut self, base: u64, region: Option<VhostUserDirtyLogRegion>) -> Result<()>; | |
| /// Specify an eventfd file descriptor to signal on log write. | |
| fn set_log_fd(&mut self, fd: RawFd) -> Result<()>; | |
| /// Set the number of descriptors in the vring. | |
| /// | |
| /// # Arguments | |
| /// * `queue_index` - Index of the queue to set descriptor count for. | |
| /// * `num` - Number of descriptors in the queue. | |
| fn set_vring_num(&mut self, queue_index: usize, num: u16) -> Result<()>; | |
| /// Set the addresses for a given vring. | |
| /// | |
| /// # Arguments | |
| /// * `queue_index` - Index of the queue to set addresses for. | |
| /// * `config_data` - Configuration data for a vring. | |
| fn set_vring_addr(&mut self, queue_index: usize, config_data: &VringConfigData) -> Result<()>; | |
| /// Set the first index to look for available descriptors. | |
| /// | |
| /// # Arguments | |
| /// * `queue_index` - Index of the queue to modify. | |
| /// * `num` - Index where available descriptors start. | |
| fn set_vring_base(&mut self, queue_index: usize, base: u16) -> Result<()>; | |
| /// Get the available vring base offset. | |
| fn get_vring_base(&mut self, queue_index: usize) -> Result<u32>; | |
| /// Set the eventfd to trigger when buffers have been used by the host. | |
| /// | |
| /// # Arguments | |
| /// * `queue_index` - Index of the queue to modify. | |
| /// * `fd` - EventFd to trigger. | |
| fn set_vring_call(&mut self, queue_index: usize, fd: &EventFd) -> Result<()>; | |
| /// Set the eventfd that will be signaled by the guest when buffers are | |
| /// available for the host to process. | |
| /// | |
| /// # Arguments | |
| /// * `queue_index` - Index of the queue to modify. | |
| /// * `fd` - EventFd that will be signaled from guest. | |
| fn set_vring_kick(&mut self, queue_index: usize, fd: &EventFd) -> Result<()>; | |
| /// Set the eventfd that will be signaled by the guest when error happens. | |
| /// | |
| /// # Arguments | |
| /// * `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<()>; | |
| } | |
| impl<T: VhostBackendMut> VhostBackend for RwLock<T> { | |
| fn get_features(&self) -> Result<u64> { | |
| self.write().unwrap().get_features() | |
| } | |
| fn set_features(&self, features: u64) -> Result<()> { | |
| self.write().unwrap().set_features(features) | |
| } | |
| fn set_owner(&self) -> Result<()> { | |
| self.write().unwrap().set_owner() | |
| } | |
| fn reset_owner(&self) -> Result<()> { | |
| self.write().unwrap().reset_owner() | |
| } | |
| fn set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()> { | |
| self.write().unwrap().set_mem_table(regions) | |
| } | |
| fn set_log_base(&self, base: u64, region: Option<VhostUserDirtyLogRegion>) -> Result<()> { | |
| self.write().unwrap().set_log_base(base, region) | |
| } | |
| fn set_log_fd(&self, fd: RawFd) -> Result<()> { | |
| self.write().unwrap().set_log_fd(fd) | |
| } | |
| fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()> { | |
| self.write().unwrap().set_vring_num(queue_index, num) | |
| } | |
| fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()> { | |
| self.write() | |
| .unwrap() | |
| .set_vring_addr(queue_index, config_data) | |
| } | |
| fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()> { | |
| self.write().unwrap().set_vring_base(queue_index, base) | |
| } | |
| fn get_vring_base(&self, queue_index: usize) -> Result<u32> { | |
| self.write().unwrap().get_vring_base(queue_index) | |
| } | |
| fn set_vring_call(&self, queue_index: usize, fd: &EventFd) -> Result<()> { | |
| self.write().unwrap().set_vring_call(queue_index, fd) | |
| } | |
| fn set_vring_kick(&self, queue_index: usize, fd: &EventFd) -> Result<()> { | |
| self.write().unwrap().set_vring_kick(queue_index, fd) | |
| } | |
| fn set_vring_err(&self, queue_index: usize, fd: &EventFd) -> Result<()> { | |
| self.write().unwrap().set_vring_err(queue_index, fd) | |
| } | |
| } | |
| impl<T: VhostBackendMut> VhostBackend for RefCell<T> { | |
| fn get_features(&self) -> Result<u64> { | |
| self.borrow_mut().get_features() | |
| } | |
| fn set_features(&self, features: u64) -> Result<()> { | |
| self.borrow_mut().set_features(features) | |
| } | |
| fn set_owner(&self) -> Result<()> { | |
| self.borrow_mut().set_owner() | |
| } | |
| fn reset_owner(&self) -> Result<()> { | |
| self.borrow_mut().reset_owner() | |
| } | |
| fn set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()> { | |
| self.borrow_mut().set_mem_table(regions) | |
| } | |
| fn set_log_base(&self, base: u64, region: Option<VhostUserDirtyLogRegion>) -> Result<()> { | |
| self.borrow_mut().set_log_base(base, region) | |
| } | |
| fn set_log_fd(&self, fd: RawFd) -> Result<()> { | |
| self.borrow_mut().set_log_fd(fd) | |
| } | |
| fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()> { | |
| self.borrow_mut().set_vring_num(queue_index, num) | |
| } | |
| fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()> { | |
| self.borrow_mut().set_vring_addr(queue_index, config_data) | |
| } | |
| fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()> { | |
| self.borrow_mut().set_vring_base(queue_index, base) | |
| } | |
| fn get_vring_base(&self, queue_index: usize) -> Result<u32> { | |
| self.borrow_mut().get_vring_base(queue_index) | |
| } | |
| fn set_vring_call(&self, queue_index: usize, fd: &EventFd) -> Result<()> { | |
| self.borrow_mut().set_vring_call(queue_index, fd) | |
| } | |
| fn set_vring_kick(&self, queue_index: usize, fd: &EventFd) -> Result<()> { | |
| self.borrow_mut().set_vring_kick(queue_index, fd) | |
| } | |
| fn set_vring_err(&self, queue_index: usize, fd: &EventFd) -> Result<()> { | |
| self.borrow_mut().set_vring_err(queue_index, fd) | |
| } | |
| } | |
| #[cfg(any(test, feature = "test-utils"))] | |
| impl VhostUserMemoryRegionInfo { | |
| /// creates instance of `VhostUserMemoryRegionInfo`. | |
| pub fn new( | |
| guest_phys_addr: u64, | |
| memory_size: u64, | |
| userspace_addr: u64, | |
| mmap_offset: u64, | |
| mmap_handle: RawFd, | |
| ) -> Self { | |
| Self { | |
| guest_phys_addr, | |
| memory_size, | |
| userspace_addr, | |
| mmap_offset, | |
| mmap_handle, | |
| #[cfg(feature = "xen")] | |
| xen_mmap_flags: vm_memory::MmapXenFlags::UNIX.bits(), | |
| #[cfg(feature = "xen")] | |
| xen_mmap_data: 0, | |
| } | |
| } | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| struct MockBackend {} | |
| impl VhostBackendMut for MockBackend { | |
| fn get_features(&mut self) -> Result<u64> { | |
| Ok(0x1) | |
| } | |
| fn set_features(&mut self, features: u64) -> Result<()> { | |
| assert_eq!(features, 0x1); | |
| Ok(()) | |
| } | |
| fn set_owner(&mut self) -> Result<()> { | |
| Ok(()) | |
| } | |
| fn reset_owner(&mut self) -> Result<()> { | |
| Ok(()) | |
| } | |
| fn set_mem_table(&mut self, _regions: &[VhostUserMemoryRegionInfo]) -> Result<()> { | |
| Ok(()) | |
| } | |
| fn set_log_base( | |
| &mut self, | |
| base: u64, | |
| region: Option<VhostUserDirtyLogRegion>, | |
| ) -> Result<()> { | |
| assert_eq!(base, 0x100); | |
| let region = region.unwrap(); | |
| assert_eq!(region.mmap_size, 0x1000); | |
| assert_eq!(region.mmap_offset, 0x10); | |
| assert_eq!(region.mmap_handle, 100); | |
| Ok(()) | |
| } | |
| fn set_log_fd(&mut self, fd: RawFd) -> Result<()> { | |
| assert_eq!(fd, 100); | |
| Ok(()) | |
| } | |
| fn set_vring_num(&mut self, queue_index: usize, num: u16) -> Result<()> { | |
| assert_eq!(queue_index, 1); | |
| assert_eq!(num, 256); | |
| Ok(()) | |
| } | |
| fn set_vring_addr( | |
| &mut self, | |
| queue_index: usize, | |
| _config_data: &VringConfigData, | |
| ) -> Result<()> { | |
| assert_eq!(queue_index, 1); | |
| Ok(()) | |
| } | |
| fn set_vring_base(&mut self, queue_index: usize, base: u16) -> Result<()> { | |
| assert_eq!(queue_index, 1); | |
| assert_eq!(base, 2); | |
| Ok(()) | |
| } | |
| fn get_vring_base(&mut self, queue_index: usize) -> Result<u32> { | |
| assert_eq!(queue_index, 1); | |
| Ok(2) | |
| } | |
| fn set_vring_call(&mut self, queue_index: usize, _fd: &EventFd) -> Result<()> { | |
| assert_eq!(queue_index, 1); | |
| Ok(()) | |
| } | |
| fn set_vring_kick(&mut self, queue_index: usize, _fd: &EventFd) -> Result<()> { | |
| assert_eq!(queue_index, 1); | |
| Ok(()) | |
| } | |
| fn set_vring_err(&mut self, queue_index: usize, _fd: &EventFd) -> Result<()> { | |
| assert_eq!(queue_index, 1); | |
| Ok(()) | |
| } | |
| } | |
| #[test] | |
| fn test_vring_backend_mut() { | |
| let b = RwLock::new(MockBackend {}); | |
| assert_eq!(b.get_features().unwrap(), 0x1); | |
| b.set_features(0x1).unwrap(); | |
| b.set_owner().unwrap(); | |
| b.reset_owner().unwrap(); | |
| b.set_mem_table(&[]).unwrap(); | |
| b.set_log_base( | |
| 0x100, | |
| Some(VhostUserDirtyLogRegion { | |
| mmap_size: 0x1000, | |
| mmap_offset: 0x10, | |
| mmap_handle: 100, | |
| }), | |
| ) | |
| .unwrap(); | |
| b.set_log_fd(100).unwrap(); | |
| b.set_vring_num(1, 256).unwrap(); | |
| let config = VringConfigData { | |
| queue_max_size: 0x1000, | |
| queue_size: 0x2000, | |
| flags: 0x0, | |
| desc_table_addr: 0x4000, | |
| used_ring_addr: 0x5000, | |
| avail_ring_addr: 0x6000, | |
| log_addr: None, | |
| }; | |
| b.set_vring_addr(1, &config).unwrap(); | |
| b.set_vring_base(1, 2).unwrap(); | |
| assert_eq!(b.get_vring_base(1).unwrap(), 2); | |
| let eventfd = EventFd::new(0).unwrap(); | |
| b.set_vring_call(1, &eventfd).unwrap(); | |
| b.set_vring_kick(1, &eventfd).unwrap(); | |
| b.set_vring_err(1, &eventfd).unwrap(); | |
| } | |
| #[test] | |
| fn test_vring_config_data() { | |
| let mut config = VringConfigData { | |
| queue_max_size: 0x1000, | |
| queue_size: 0x2000, | |
| flags: 0x0, | |
| desc_table_addr: 0x4000, | |
| used_ring_addr: 0x5000, | |
| avail_ring_addr: 0x6000, | |
| log_addr: None, | |
| }; | |
| assert!(config.is_log_addr_valid()); | |
| assert_eq!(config.get_log_addr(), 0); | |
| config.flags = 0x1; | |
| assert!(!config.is_log_addr_valid()); | |
| assert_eq!(config.get_log_addr(), 0); | |
| config.log_addr = Some(0x7000); | |
| assert!(config.is_log_addr_valid()); | |
| assert_eq!(config.get_log_addr(), 0x7000); | |
| config.flags = 0x0; | |
| assert!(config.is_log_addr_valid()); | |
| assert_eq!(config.get_log_addr(), 0); | |
| } | |
| } |