// 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_evts: Vec, ) -> Result> { let mut regions: Vec = 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)?; vu.set_vring_enable(queue_index, true) .map_err(Error::VhostUserSetVringEnable)?; } Ok(vu_interrupt_list) } pub fn setup_vhost_user( vu: &mut Master, mem: &GuestMemory, queues: Vec, queue_evts: Vec, acked_features: u64, ) -> Result> { let backend_features = vu.get_features().unwrap(); vu.set_features(acked_features & backend_features) .map_err(Error::VhostUserSetFeatures)?; setup_vhost_user_vring(vu, mem, queues, queue_evts) }