summary refs log tree commit diff
path: root/vhost_rs/src/vhost_kern
diff options
context:
space:
mode:
Diffstat (limited to 'vhost_rs/src/vhost_kern')
-rw-r--r--vhost_rs/src/vhost_kern/mod.rs320
-rw-r--r--vhost_rs/src/vhost_kern/vhost_binding.rs405
-rw-r--r--vhost_rs/src/vhost_kern/vsock.rs84
3 files changed, 809 insertions, 0 deletions
diff --git a/vhost_rs/src/vhost_kern/mod.rs b/vhost_rs/src/vhost_kern/mod.rs
new file mode 100644
index 0000000..fde50fb
--- /dev/null
+++ b/vhost_rs/src/vhost_kern/mod.rs
@@ -0,0 +1,320 @@
+// Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
+//
+// 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 file.
+
+//! Traits and structs to control Linux in-kernel vhost drivers.
+//!
+//! The initial vhost implementation is a part of the Linux kernel and uses ioctl interface to
+//! communicate with userspace applications. This sub module provides ioctl based interfaces to
+//! control the in-kernel net, scsi, vsock vhost drivers.
+
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::ptr::null;
+
+use vm_memory::{Address, GuestAddress, 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, VhostUserMemoryRegionInfo, VringConfigData,
+    VHOST_MAX_MEMORY_REGIONS,
+};
+
+pub mod vhost_binding;
+use self::vhost_binding::*;
+
+#[cfg(feature = "vhost-vsock")]
+pub mod vsock;
+
+#[inline]
+fn ioctl_result<T>(rc: i32, res: T) -> Result<T> {
+    if rc < 0 {
+        Err(Error::IoctlError(std::io::Error::last_os_error()))
+    } else {
+        Ok(res)
+    }
+}
+
+fn guest_addr(addr: u64) -> GuestAddress {
+    GuestAddress::new(addr)
+}
+
+/// Represent an in-kernel vhost device backend.
+pub trait VhostKernBackend<'a>: AsRawFd {
+    /// Associated type to access the guest's memory.
+    type M: GuestMemory<'a>;
+
+    /// Get the object to access the guest's memory.
+    fn mem(&self) -> &Self::M;
+
+    /// Check whether the ring configuration is valid.
+    #[allow(clippy::if_same_then_else)]
+    #[allow(clippy::needless_bool)]
+    fn is_valid(
+        &self,
+        queue_max_size: u16,
+        queue_size: u16,
+        desc_addr: GuestAddress,
+        avail_addr: GuestAddress,
+        used_addr: GuestAddress,
+    ) -> bool {
+        let desc_table_size = 16 * u64::from(queue_size) as GuestUsize;
+        let avail_ring_size = 6 + 2 * u64::from(queue_size) as GuestUsize;
+        let used_ring_size = 6 + 8 * u64::from(queue_size) as GuestUsize;
+        if queue_size > queue_max_size || queue_size == 0 || (queue_size & (queue_size - 1)) != 0 {
+            false
+        } else if desc_addr
+            .checked_add(desc_table_size)
+            .map_or(true, |v| !self.mem().address_in_range(v))
+        {
+            false
+        } else if avail_addr
+            .checked_add(avail_ring_size)
+            .map_or(true, |v| !self.mem().address_in_range(v))
+        {
+            false
+        } else if used_addr
+            .checked_add(used_ring_size)
+            .map_or(true, |v| !self.mem().address_in_range(v))
+        {
+            false
+        } else {
+            true
+        }
+    }
+}
+
+impl<'a, T: VhostKernBackend<'a>> VhostBackend for T {
+    /// Set the current process as the owner of this file descriptor.
+    /// This must be run before any other vhost ioctls.
+    fn set_owner(&mut self) -> Result<()> {
+        // This ioctl is called on a valid vhost fd and has its return value checked.
+        let ret = unsafe { ioctl(self, VHOST_SET_OWNER()) };
+        ioctl_result(ret, ())
+    }
+
+    fn reset_owner(&mut self) -> Result<()> {
+        // This ioctl is called on a valid vhost fd and has its return value checked.
+        let ret = unsafe { ioctl(self, VHOST_RESET_OWNER()) };
+        ioctl_result(ret, ())
+    }
+
+    /// Get a bitmask of supported virtio/vhost features.
+    fn get_features(&mut self) -> Result<u64> {
+        let mut avail_features: u64 = 0;
+        // This ioctl is called on a valid vhost fd and has its return value checked.
+        let ret = unsafe { ioctl_with_mut_ref(self, VHOST_GET_FEATURES(), &mut avail_features) };
+        ioctl_result(ret, avail_features)
+    }
+
+    /// Inform the vhost subsystem which features to enable. This should be a subset of
+    /// supported features from VHOST_GET_FEATURES.
+    ///
+    /// # Arguments
+    /// * `features` - Bitmask of features to set.
+    fn set_features(&mut self, features: u64) -> Result<()> {
+        // This ioctl is called on a valid vhost fd and has its return value checked.
+        let ret = unsafe { ioctl_with_ref(self, VHOST_SET_FEATURES(), &features) };
+        ioctl_result(ret, ())
+    }
+
+    /// Set the guest memory mappings for vhost to use.
+    fn set_mem_table(&mut self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()> {
+        if regions.is_empty() || regions.len() > VHOST_MAX_MEMORY_REGIONS {
+            return Err(Error::InvalidGuestMemory);
+        }
+
+        let mut vhost_memory = VhostMemory::new(regions.len() as u16);
+        for (index, region) in regions.iter().enumerate() {
+            vhost_memory.set_region(
+                index as u32,
+                &vhost_memory_region {
+                    guest_phys_addr: region.guest_phys_addr,
+                    memory_size: region.memory_size,
+                    userspace_addr: region.userspace_addr,
+                    flags_padding: 0u64,
+                },
+            )?;
+        }
+
+        // This ioctl is called with a pointer that is valid for the lifetime
+        // of this function. The kernel will make its own copy of the memory
+        // tables. As always, check the return value.
+        let ret = unsafe { ioctl_with_ptr(self, VHOST_SET_MEM_TABLE(), vhost_memory.as_ptr()) };
+        ioctl_result(ret, ())
+    }
+
+    /// Set base address for page modification logging.
+    ///
+    /// # Arguments
+    /// * `base` - Base address for page modification logging.
+    fn set_log_base(&mut self, base: u64, fd: Option<RawFd>) -> Result<()> {
+        if fd.is_some() {
+            return Err(Error::LogAddress);
+        }
+
+        // This ioctl is called on a valid vhost fd and has its return value checked.
+        let ret = unsafe { ioctl_with_ref(self, VHOST_SET_LOG_BASE(), &base) };
+        ioctl_result(ret, ())
+    }
+
+    /// Specify an eventfd file descriptor to signal on log write.
+    fn set_log_fd(&mut self, fd: RawFd) -> Result<()> {
+        // This ioctl is called on a valid vhost fd and has its return value checked.
+        let val: i32 = fd;
+        let ret = unsafe { ioctl_with_ref(self, VHOST_SET_LOG_FD(), &val) };
+        ioctl_result(ret, ())
+    }
+
+    /// 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<()> {
+        let vring_state = vhost_vring_state {
+            index: queue_index as u32,
+            num: u32::from(num),
+        };
+
+        // This ioctl is called on a valid vhost fd and has its return value checked.
+        let ret = unsafe { ioctl_with_ref(self, VHOST_SET_VRING_NUM(), &vring_state) };
+        ioctl_result(ret, ())
+    }
+
+    /// Set the addresses for a given vring.
+    ///
+    /// # Arguments
+    /// * `queue_max_size` - Maximum queue size supported by the device.
+    /// * `queue_size` - Actual queue size negotiated by the driver.
+    /// * `queue_index` - Index of the queue to set addresses for.
+    /// * `flags` - Bitmask of vring flags.
+    /// * `desc_table_addr` - Descriptor table address.
+    /// * `used_ring_addr` - Used ring buffer address.
+    /// * `avail_ring_addr` - Available ring buffer address.
+    /// * `log_addr` - Optional address for logging.
+    fn set_vring_addr(&mut self, queue_index: usize, config_data: &VringConfigData) -> Result<()> {
+        if !self.is_valid(
+            config_data.queue_max_size,
+            config_data.queue_size,
+            guest_addr(config_data.desc_table_addr),
+            guest_addr(config_data.used_ring_addr),
+            guest_addr(config_data.avail_ring_addr),
+        ) {
+            return Err(Error::InvalidQueue);
+        }
+
+        let desc_addr = self
+            .mem()
+            .get_host_address(guest_addr(config_data.desc_table_addr))
+            .ok_or(Error::DescriptorTableAddress)?;
+        let used_addr = self
+            .mem()
+            .get_host_address(guest_addr(config_data.used_ring_addr))
+            .ok_or(Error::UsedAddress)?;
+        let avail_addr = self
+            .mem()
+            .get_host_address(guest_addr(config_data.avail_ring_addr))
+            .ok_or(Error::AvailAddress)?;
+        let log_addr = match config_data.log_addr {
+            None => null(),
+            Some(a) => self
+                .mem()
+                .get_host_address(guest_addr(a))
+                .ok_or(Error::LogAddress)?,
+        };
+
+        let vring_addr = vhost_vring_addr {
+            index: queue_index as u32,
+            flags: config_data.flags,
+            desc_user_addr: desc_addr as u64,
+            used_user_addr: used_addr as u64,
+            avail_user_addr: avail_addr as u64,
+            log_guest_addr: log_addr as u64,
+        };
+
+        // This ioctl is called on a valid vhost fd and has its
+        // return value checked.
+        let ret = unsafe { ioctl_with_ref(self, VHOST_SET_VRING_ADDR(), &vring_addr) };
+        ioctl_result(ret, ())
+    }
+
+    /// 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<()> {
+        let vring_state = vhost_vring_state {
+            index: queue_index as u32,
+            num: u32::from(base),
+        };
+
+        // This ioctl is called on a valid vhost fd and has its return value checked.
+        let ret = unsafe { ioctl_with_ref(self, VHOST_SET_VRING_BASE(), &vring_state) };
+        ioctl_result(ret, ())
+    }
+
+    /// Get a bitmask of supported virtio/vhost features.
+    fn get_vring_base(&mut self, queue_index: usize) -> Result<u32> {
+        let vring_state = vhost_vring_state {
+            index: queue_index as u32,
+            num: 0,
+        };
+        // This ioctl is called on a valid vhost fd and has its return value checked.
+        let ret = unsafe { ioctl_with_ref(self, VHOST_GET_VRING_BASE(), &vring_state) };
+        ioctl_result(ret, vring_state.num)
+    }
+
+    /// 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<()> {
+        let vring_file = vhost_vring_file {
+            index: queue_index as u32,
+            fd: fd.as_raw_fd(),
+        };
+
+        // This ioctl is called on a valid vhost fd and has its return value checked.
+        let ret = unsafe { ioctl_with_ref(self, VHOST_SET_VRING_CALL(), &vring_file) };
+        ioctl_result(ret, ())
+    }
+
+    /// 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<()> {
+        let vring_file = vhost_vring_file {
+            index: queue_index as u32,
+            fd: fd.as_raw_fd(),
+        };
+
+        // This ioctl is called on a valid vhost fd and has its return value checked.
+        let ret = unsafe { ioctl_with_ref(self, VHOST_SET_VRING_KICK(), &vring_file) };
+        ioctl_result(ret, ())
+    }
+
+    /// Set the eventfd to signal an error from the vhost backend.
+    ///
+    /// # Arguments
+    /// * `queue_index` - Index of the queue to modify.
+    /// * `fd` - EventFd that will be signaled from the backend.
+    fn set_vring_err(&mut self, queue_index: usize, fd: &EventFd) -> Result<()> {
+        let vring_file = vhost_vring_file {
+            index: queue_index as u32,
+            fd: fd.as_raw_fd(),
+        };
+
+        // This ioctl is called on a valid vhost fd and has its return value checked.
+        let ret = unsafe { ioctl_with_ref(self, VHOST_SET_VRING_ERR(), &vring_file) };
+        ioctl_result(ret, ())
+    }
+}
diff --git a/vhost_rs/src/vhost_kern/vhost_binding.rs b/vhost_rs/src/vhost_kern/vhost_binding.rs
new file mode 100644
index 0000000..21fd82c
--- /dev/null
+++ b/vhost_rs/src/vhost_kern/vhost_binding.rs
@@ -0,0 +1,405 @@
+// Copyright (C) 2019 Alibaba Cloud Computing. 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 file.
+
+/* Auto-generated by bindgen then manually edited for simplicity */
+
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(missing_docs)]
+
+use std::os::raw;
+use {Error, Result};
+
+pub const VHOST: raw::c_uint = 0xaf;
+pub const VHOST_VRING_F_LOG: raw::c_uint = 0;
+pub const VHOST_ACCESS_RO: raw::c_uint = 1;
+pub const VHOST_ACCESS_WO: raw::c_uint = 2;
+pub const VHOST_ACCESS_RW: raw::c_uint = 3;
+pub const VHOST_IOTLB_MISS: raw::c_uint = 1;
+pub const VHOST_IOTLB_UPDATE: raw::c_uint = 2;
+pub const VHOST_IOTLB_INVALIDATE: raw::c_uint = 3;
+pub const VHOST_IOTLB_ACCESS_FAIL: raw::c_uint = 4;
+pub const VHOST_IOTLB_MSG: raw::c_uint = 1;
+pub const VHOST_PAGE_SIZE: raw::c_uint = 4096;
+pub const VHOST_VIRTIO: raw::c_uint = 175;
+pub const VHOST_VRING_LITTLE_ENDIAN: raw::c_uint = 0;
+pub const VHOST_VRING_BIG_ENDIAN: raw::c_uint = 1;
+pub const VHOST_F_LOG_ALL: raw::c_uint = 26;
+pub const VHOST_NET_F_VIRTIO_NET_HDR: raw::c_uint = 27;
+pub const VHOST_SCSI_ABI_VERSION: raw::c_uint = 1;
+
+ioctl_ior_nr!(VHOST_GET_FEATURES, VHOST, 0x00, raw::c_ulonglong);
+ioctl_iow_nr!(VHOST_SET_FEATURES, VHOST, 0x00, raw::c_ulonglong);
+ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01);
+ioctl_io_nr!(VHOST_RESET_OWNER, VHOST, 0x02);
+ioctl_iow_nr!(VHOST_SET_MEM_TABLE, VHOST, 0x03, vhost_memory);
+ioctl_iow_nr!(VHOST_SET_LOG_BASE, VHOST, 0x04, raw::c_ulonglong);
+ioctl_iow_nr!(VHOST_SET_LOG_FD, VHOST, 0x07, raw::c_int);
+ioctl_iow_nr!(VHOST_SET_VRING_NUM, VHOST, 0x10, vhost_vring_state);
+ioctl_iow_nr!(VHOST_SET_VRING_ADDR, VHOST, 0x11, vhost_vring_addr);
+ioctl_iow_nr!(VHOST_SET_VRING_BASE, VHOST, 0x12, vhost_vring_state);
+ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, vhost_vring_state);
+ioctl_iow_nr!(VHOST_SET_VRING_KICK, VHOST, 0x20, vhost_vring_file);
+ioctl_iow_nr!(VHOST_SET_VRING_CALL, VHOST, 0x21, vhost_vring_file);
+ioctl_iow_nr!(VHOST_SET_VRING_ERR, VHOST, 0x22, vhost_vring_file);
+ioctl_iow_nr!(vhost_SET_BACKEND, VHOST, 0x30, vhost_vring_file);
+ioctl_iow_nr!(VHOST_SCSI_SET_ENDPOINT, VHOST, 0x40, vhost_scsi_target);
+ioctl_iow_nr!(VHOST_SCSI_CLEAR_ENDPOINT, VHOST, 0x41, vhost_scsi_target);
+ioctl_iow_nr!(VHOST_SCSI_GET_ABI_VERSION, VHOST, 0x42, raw::c_int);
+ioctl_iow_nr!(VHOST_SCSI_SET_EVENTS_MISSED, VHOST, 0x43, raw::c_uint);
+ioctl_iow_nr!(VHOST_SCSI_GET_EVENTS_MISSED, VHOST, 0x44, raw::c_uint);
+ioctl_iow_nr!(VHOST_VSOCK_SET_GUEST_CID, VHOST, 0x60, raw::c_ulonglong);
+ioctl_iow_nr!(VHOST_VSOCK_SET_RUNNING, VHOST, 0x61, raw::c_int);
+
+#[repr(C)]
+#[derive(Default)]
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+
+impl<T> __IncompleteArrayField<T> {
+    #[inline]
+    pub fn new() -> Self {
+        __IncompleteArrayField(::std::marker::PhantomData)
+    }
+
+    #[inline]
+    #[allow(clippy::trivially_copy_pass_by_ref)]
+    #[allow(clippy::useless_transmute)]
+    pub unsafe fn as_ptr(&self) -> *const T {
+        ::std::mem::transmute(self)
+    }
+
+    #[inline]
+    #[allow(clippy::useless_transmute)]
+    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
+        ::std::mem::transmute(self)
+    }
+
+    #[inline]
+    pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+        ::std::slice::from_raw_parts(self.as_ptr(), len)
+    }
+
+    #[inline]
+    pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
+        ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+    }
+}
+
+impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        fmt.write_str("__IncompleteArrayField")
+    }
+}
+
+impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::new()
+    }
+}
+
+impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vhost_vring_state {
+    pub index: raw::c_uint,
+    pub num: raw::c_uint,
+}
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vhost_vring_file {
+    pub index: raw::c_uint,
+    pub fd: raw::c_int,
+}
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vhost_vring_addr {
+    pub index: raw::c_uint,
+    pub flags: raw::c_uint,
+    pub desc_user_addr: raw::c_ulonglong,
+    pub used_user_addr: raw::c_ulonglong,
+    pub avail_user_addr: raw::c_ulonglong,
+    pub log_guest_addr: raw::c_ulonglong,
+}
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vhost_iotlb_msg {
+    pub iova: raw::c_ulonglong,
+    pub size: raw::c_ulonglong,
+    pub uaddr: raw::c_ulonglong,
+    pub perm: raw::c_uchar,
+    pub type_: raw::c_uchar,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct vhost_msg {
+    pub type_: raw::c_int,
+    pub __bindgen_anon_1: vhost_msg__bindgen_ty_1,
+}
+
+impl Default for vhost_msg {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union vhost_msg__bindgen_ty_1 {
+    pub iotlb: vhost_iotlb_msg,
+    pub padding: [raw::c_uchar; 64usize],
+    _bindgen_union_align: [u64; 8usize],
+}
+
+impl Default for vhost_msg__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct vhost_memory_region {
+    pub guest_phys_addr: raw::c_ulonglong,
+    pub memory_size: raw::c_ulonglong,
+    pub userspace_addr: raw::c_ulonglong,
+    pub flags_padding: raw::c_ulonglong,
+}
+
+#[repr(C)]
+#[derive(Debug, Default, Clone)]
+pub struct vhost_memory {
+    pub nregions: raw::c_uint,
+    pub padding: raw::c_uint,
+    pub regions: __IncompleteArrayField<vhost_memory_region>,
+    __force_alignment: [u64; 0],
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct vhost_scsi_target {
+    pub abi_version: raw::c_int,
+    pub vhost_wwpn: [raw::c_char; 224usize],
+    pub vhost_tpgt: raw::c_ushort,
+    pub reserved: raw::c_ushort,
+}
+
+impl Default for vhost_scsi_target {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+
+/// Helper to support vhost::set_mem_table()
+pub struct VhostMemory {
+    buf: Vec<vhost_memory>,
+}
+
+impl VhostMemory {
+    // Limit number of regions to u16 to simplify error handling
+    pub fn new(entries: u16) -> Self {
+        let size = std::mem::size_of::<vhost_memory_region>() * entries as usize;
+        let count = (size + 2 * std::mem::size_of::<vhost_memory>() - 1)
+            / std::mem::size_of::<vhost_memory>();
+        let mut buf: Vec<vhost_memory> = vec![Default::default(); count];
+        buf[0].nregions = u32::from(entries);
+        VhostMemory { buf }
+    }
+
+    pub fn as_ptr(&self) -> *const char {
+        &self.buf[0] as *const vhost_memory as *const char
+    }
+
+    pub fn get_header(&self) -> &vhost_memory {
+        &self.buf[0]
+    }
+
+    pub fn get_region(&self, index: u32) -> Option<&vhost_memory_region> {
+        if index >= self.buf[0].nregions {
+            return None;
+        }
+        // Safe because we have allocated enough space nregions
+        let regions = unsafe { self.buf[0].regions.as_slice(self.buf[0].nregions as usize) };
+        Some(&regions[index as usize])
+    }
+
+    pub fn set_region(&mut self, index: u32, region: &vhost_memory_region) -> Result<()> {
+        if index >= self.buf[0].nregions {
+            return Err(Error::InvalidGuestMemory);
+        }
+        // Safe because we have allocated enough space nregions and checked the index.
+        let regions = unsafe { self.buf[0].regions.as_mut_slice(index as usize + 1) };
+        regions[index as usize] = *region;
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn bindgen_test_layout_vhost_vring_state() {
+        assert_eq!(
+            ::std::mem::size_of::<vhost_vring_state>(),
+            8usize,
+            concat!("Size of: ", stringify!(vhost_vring_state))
+        );
+        assert_eq!(
+            ::std::mem::align_of::<vhost_vring_state>(),
+            4usize,
+            concat!("Alignment of ", stringify!(vhost_vring_state))
+        );
+    }
+
+    #[test]
+    fn bindgen_test_layout_vhost_vring_file() {
+        assert_eq!(
+            ::std::mem::size_of::<vhost_vring_file>(),
+            8usize,
+            concat!("Size of: ", stringify!(vhost_vring_file))
+        );
+        assert_eq!(
+            ::std::mem::align_of::<vhost_vring_file>(),
+            4usize,
+            concat!("Alignment of ", stringify!(vhost_vring_file))
+        );
+    }
+
+    #[test]
+    fn bindgen_test_layout_vhost_vring_addr() {
+        assert_eq!(
+            ::std::mem::size_of::<vhost_vring_addr>(),
+            40usize,
+            concat!("Size of: ", stringify!(vhost_vring_addr))
+        );
+        assert_eq!(
+            ::std::mem::align_of::<vhost_vring_addr>(),
+            8usize,
+            concat!("Alignment of ", stringify!(vhost_vring_addr))
+        );
+    }
+
+    #[test]
+    fn bindgen_test_layout_vhost_msg__bindgen_ty_1() {
+        assert_eq!(
+            ::std::mem::size_of::<vhost_msg__bindgen_ty_1>(),
+            64usize,
+            concat!("Size of: ", stringify!(vhost_msg__bindgen_ty_1))
+        );
+        assert_eq!(
+            ::std::mem::align_of::<vhost_msg__bindgen_ty_1>(),
+            8usize,
+            concat!("Alignment of ", stringify!(vhost_msg__bindgen_ty_1))
+        );
+    }
+
+    #[test]
+    fn bindgen_test_layout_vhost_msg() {
+        assert_eq!(
+            ::std::mem::size_of::<vhost_msg>(),
+            72usize,
+            concat!("Size of: ", stringify!(vhost_msg))
+        );
+        assert_eq!(
+            ::std::mem::align_of::<vhost_msg>(),
+            8usize,
+            concat!("Alignment of ", stringify!(vhost_msg))
+        );
+    }
+
+    #[test]
+    fn bindgen_test_layout_vhost_memory_region() {
+        assert_eq!(
+            ::std::mem::size_of::<vhost_memory_region>(),
+            32usize,
+            concat!("Size of: ", stringify!(vhost_memory_region))
+        );
+        assert_eq!(
+            ::std::mem::align_of::<vhost_memory_region>(),
+            8usize,
+            concat!("Alignment of ", stringify!(vhost_memory_region))
+        );
+    }
+
+    #[test]
+    fn bindgen_test_layout_vhost_memory() {
+        assert_eq!(
+            ::std::mem::size_of::<vhost_memory>(),
+            8usize,
+            concat!("Size of: ", stringify!(vhost_memory))
+        );
+        assert_eq!(
+            ::std::mem::align_of::<vhost_memory>(),
+            8usize,
+            concat!("Alignment of ", stringify!(vhost_memory))
+        );
+    }
+
+    #[test]
+    fn bindgen_test_layout_vhost_iotlb_msg() {
+        assert_eq!(
+            ::std::mem::size_of::<vhost_iotlb_msg>(),
+            32usize,
+            concat!("Size of: ", stringify!(vhost_iotlb_msg))
+        );
+        assert_eq!(
+            ::std::mem::align_of::<vhost_iotlb_msg>(),
+            8usize,
+            concat!("Alignment of ", stringify!(vhost_iotlb_msg))
+        );
+    }
+
+    #[test]
+    fn bindgen_test_layout_vhost_scsi_target() {
+        assert_eq!(
+            ::std::mem::size_of::<vhost_scsi_target>(),
+            232usize,
+            concat!("Size of: ", stringify!(vhost_scsi_target))
+        );
+        assert_eq!(
+            ::std::mem::align_of::<vhost_scsi_target>(),
+            4usize,
+            concat!("Alignment of ", stringify!(vhost_scsi_target))
+        );
+    }
+
+    #[test]
+    fn test_vhostmemory() {
+        let mut obj = VhostMemory::new(2);
+        let region = vhost_memory_region {
+            guest_phys_addr: 0x1000u64,
+            memory_size: 0x2000u64,
+            userspace_addr: 0x300000u64,
+            flags_padding: 0u64,
+        };
+        assert!(obj.get_region(2).is_none());
+
+        {
+            let header = obj.get_header();
+            assert_eq!(header.nregions, 2u32);
+        }
+        {
+            assert!(obj.set_region(0, &region).is_ok());
+            assert!(obj.set_region(1, &region).is_ok());
+            assert!(obj.set_region(2, &region).is_err());
+        }
+
+        let region1 = obj.get_region(1).unwrap();
+        assert_eq!(region1.guest_phys_addr, 0x1000u64);
+        assert_eq!(region1.memory_size, 0x2000u64);
+        assert_eq!(region1.userspace_addr, 0x300000u64);
+    }
+}
diff --git a/vhost_rs/src/vhost_kern/vsock.rs b/vhost_rs/src/vhost_kern/vsock.rs
new file mode 100644
index 0000000..187dc2f
--- /dev/null
+++ b/vhost_rs/src/vhost_kern/vsock.rs
@@ -0,0 +1,84 @@
+// Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0 or MIT
+//
+// 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 THIRD-PARTY file.
+
+//! Kernel-based vsock vhost backend.
+
+use std::fs::{File, OpenOptions};
+use std::marker::PhantomData;
+use std::os::unix::fs::OpenOptionsExt;
+use std::os::unix::io::{AsRawFd, RawFd};
+
+use super::vhost_binding::{VHOST_VSOCK_SET_GUEST_CID, VHOST_VSOCK_SET_RUNNING};
+use super::{ioctl_result, Error, Result, VhostKernBackend};
+use libc;
+use vm_memory::GuestMemory;
+use vmm_sys_util::ioctl::ioctl_with_ref;
+
+const VHOST_PATH: &str = "/dev/vhost-vsock";
+
+/// Handle for running VHOST_VSOCK ioctls.
+pub struct Vsock<'a, M: GuestMemory<'a>> {
+    fd: File,
+    mem: M,
+    _phatomdata: PhantomData<&'a M>, // Get rid of unused type parameter `a
+}
+
+impl<'a, M: GuestMemory<'a>> Vsock<'a, M> {
+    /// Open a handle to a new VHOST-VSOCK instance.
+    pub fn new(mem: &M) -> Result<Self> {
+        Ok(Vsock {
+            fd: OpenOptions::new()
+                .read(true)
+                .write(true)
+                .custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK)
+                .open(VHOST_PATH)
+                .map_err(Error::VhostOpen)?,
+            mem: mem.clone(),
+            _phatomdata: PhantomData,
+        })
+    }
+
+    /// Set the CID for the guest.  This number is used for routing all data destined for
+    /// running in the guest. Each guest on a hypervisor must have an unique CID
+    ///
+    /// # Arguments
+    /// * `cid` - CID to assign to the guest
+    pub fn set_guest_cid(&self, cid: u64) -> Result<()> {
+        let ret = unsafe { ioctl_with_ref(&self.fd, VHOST_VSOCK_SET_GUEST_CID(), &cid) };
+        ioctl_result(ret, ())
+    }
+
+    /// Tell the VHOST driver to start performing data transfer.
+    pub fn start(&self) -> Result<()> {
+        self.set_running(true)
+    }
+
+    /// Tell the VHOST driver to stop performing data transfer.
+    pub fn stop(&self) -> Result<()> {
+        self.set_running(false)
+    }
+
+    fn set_running(&self, running: bool) -> Result<()> {
+        let on: ::std::os::raw::c_int = if running { 1 } else { 0 };
+        let ret = unsafe { ioctl_with_ref(&self.fd, VHOST_VSOCK_SET_RUNNING(), &on) };
+        ioctl_result(ret, ())
+    }
+}
+
+impl<'a, M: GuestMemory<'a>> VhostKernBackend<'a> for Vsock<'a, M> {
+    type M = M;
+
+    fn mem(&self) -> &Self::M {
+        &self.mem
+    }
+}
+
+impl<'a, M: GuestMemory<'a>> AsRawFd for Vsock<'a, M> {
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd.as_raw_fd()
+    }
+}