diff options
Diffstat (limited to 'devices/src/virtio/vhost_user/vu_common_ctrl.rs')
-rw-r--r-- | devices/src/virtio/vhost_user/vu_common_ctrl.rs | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/devices/src/virtio/vhost_user/vu_common_ctrl.rs b/devices/src/virtio/vhost_user/vu_common_ctrl.rs new file mode 100644 index 0000000..38b7b4f --- /dev/null +++ b/devices/src/virtio/vhost_user/vu_common_ctrl.rs @@ -0,0 +1,115 @@ +// Copyright 2019 Intel Corporation. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use libc; +use libc::EFD_NONBLOCK; +use std::os::unix::io::AsRawFd; +use std::vec::Vec; +use sys_util::{EventFd, GuestMemory}; + +use vm_memory::{Address, Error as MmapError}; + +use super::super::Queue; +use super::{Error, Result}; +use vhost_rs::vhost_user::{Master, VhostUserMaster}; +use vhost_rs::{VhostBackend, VhostUserMemoryRegionInfo, VringConfigData}; + +#[derive(Debug, Copy, Clone)] +pub struct VhostUserConfig<'a> { + pub sock: &'a str, + pub num_queues: usize, + pub queue_size: u16, +} + +pub fn setup_vhost_user_vring( + vu: &mut Master, + mem: &GuestMemory, + queues: Vec<Queue>, + queue_evts: Vec<EventFd>, +) -> Result<Vec<(vmm_sys_util::eventfd::EventFd, Queue)>> { + let mut regions: Vec<VhostUserMemoryRegionInfo> = Vec::new(); + mem.with_regions( + |_index, + region_guest_base, + region_mapping_size, + region_mapping_as_ptr, + region_memfd_offset| { + let vhost_user_net_reg = VhostUserMemoryRegionInfo { + guest_phys_addr: region_guest_base.0, + memory_size: region_mapping_size as u64, + userspace_addr: region_mapping_as_ptr as u64, + mmap_offset: region_memfd_offset as u64, + mmap_handle: mem.as_raw_fd(), + }; + + regions.push(vhost_user_net_reg); + + Ok(()) + }, + ) + .map_err(Error::VhostUserMemoryRegion)?; + + vu.set_mem_table(regions.as_slice()) + .map_err(Error::VhostUserSetMemTable)?; + + let mut vu_interrupt_list = Vec::new(); + + for (queue_index, queue) in queues.into_iter().enumerate() { + vu.set_vring_num(queue_index, queue.max_size) + .map_err(Error::VhostUserSetVringNum)?; + + let config_data = VringConfigData { + queue_max_size: queue.max_size, + queue_size: queue.actual_size(), + flags: 0u32, + desc_table_addr: mem + .get_host_address(queue.desc_table) + .map_err(Error::DescriptorTableAddress)? as u64, + used_ring_addr: mem + .get_host_address(queue.used_ring) + .map_err(Error::UsedAddress)? as u64, + avail_ring_addr: mem + .get_host_address(queue.avail_ring) + .map_err(Error::AvailAddress)? as u64, + log_addr: None, + }; + + vu.set_vring_addr(queue_index, &config_data) + .map_err(Error::VhostUserSetVringAddr)?; + vu.set_vring_base(queue_index, 0u16) + .map_err(Error::VhostUserSetVringBase)?; + + let vhost_user_interrupt = + vmm_sys_util::eventfd::EventFd::new(EFD_NONBLOCK).map_err(Error::VhostIrqCreate)?; + vu.set_vring_call(queue_index, &vhost_user_interrupt) + .map_err(Error::VhostUserSetVringCall)?; + vu_interrupt_list.push((vhost_user_interrupt, queue)); + + vu.set_vring_kick(queue_index, &queue_evts[queue_index]) + .map_err(Error::VhostUserSetVringKick)?; + } + + Ok(vu_interrupt_list) +} + +pub fn setup_vhost_user( + vu: &mut Master, + mem: &GuestMemory, + queues: Vec<Queue>, + queue_evts: Vec<EventFd>, + acked_features: u64, +) -> Result<Vec<(vmm_sys_util::eventfd::EventFd, Queue)>> { + for i in 0..queues.len() { + vu.set_vring_enable(i, true) + .map_err(Error::VhostUserSetVringEnable)?; + } + + let backend_features = vu.get_features().unwrap(); + vu.set_features(acked_features & backend_features) + .map_err(Error::VhostUserSetFeatures)?; + + match setup_vhost_user_vring(vu, mem, queues, queue_evts) { + Ok(vu_interrupt_list) => Ok(vu_interrupt_list), + Err(_) => Err(Error::VhostUserSetupVringFailed), + } +} |