1 // Copyright (C) 2019 Alibaba Cloud. All rights reserved. 2 // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause 3 4 //! Virtio Vhost Backend Drivers 5 //! 6 //! Virtio devices use virtqueues to transport data efficiently. The first generation of virtqueue 7 //! is a set of three different single-producer, single-consumer ring structures designed to store 8 //! generic scatter-gather I/O. The virtio specification 1.1 introduces an alternative compact 9 //! virtqueue layout named "Packed Virtqueue", which is more friendly to memory cache system and 10 //! hardware implemented virtio devices. The packed virtqueue uses read-write memory, that means 11 //! the memory will be both read and written by both host and guest. The new Packed Virtqueue is 12 //! preferred for performance. 13 //! 14 //! Vhost is a mechanism to improve performance of Virtio devices by delegate data plane operations 15 //! to dedicated IO service processes. Only the configuration, I/O submission notification, and I/O 16 //! completion interruption are piped through the hypervisor. 17 //! It uses the same virtqueue layout as Virtio to allow Vhost devices to be mapped directly to 18 //! Virtio devices. This allows a Vhost device to be accessed directly by a guest OS inside a 19 //! hypervisor process with an existing Virtio (PCI) driver. 20 //! 21 //! The initial vhost implementation is a part of the Linux kernel and uses ioctl interface to 22 //! communicate with userspace applications. Dedicated kernel worker threads are created to handle 23 //! IO requests from the guest. 24 //! 25 //! Later Vhost-user protocol is introduced to complement the ioctl interface used to control the 26 //! vhost implementation in the Linux kernel. It implements the control plane needed to establish 27 //! virtqueues sharing with a user space process on the same host. It uses communication over a 28 //! Unix domain socket to share file descriptors in the ancillary data of the message. 29 //! The protocol defines 2 sides of the communication, master and slave. Master is the application 30 //! that shares its virtqueues. Slave is the consumer of the virtqueues. Master and slave can be 31 //! either a client (i.e. connecting) or server (listening) in the socket communication. 32 33 #![deny(missing_docs)] 34 35 #[cfg_attr(feature = "vhost-user", macro_use)] 36 extern crate bitflags; 37 #[cfg_attr(feature = "vhost-kern", macro_use)] 38 extern crate sys_util; 39 40 mod backend; 41 pub use backend::*; 42 43 #[cfg(feature = "vhost-kern")] 44 pub mod vhost_kern; 45 #[cfg(feature = "vhost-user")] 46 pub mod vhost_user; 47 #[cfg(feature = "vhost-vsock")] 48 pub mod vsock; 49 50 /// Error codes for vhost operations 51 #[derive(Debug)] 52 pub enum Error { 53 /// Invalid operations. 54 InvalidOperation, 55 /// Invalid guest memory. 56 InvalidGuestMemory, 57 /// Invalid guest memory region. 58 InvalidGuestMemoryRegion, 59 /// Invalid queue. 60 InvalidQueue, 61 /// Invalid descriptor table address. 62 DescriptorTableAddress, 63 /// Invalid used address. 64 UsedAddress, 65 /// Invalid available address. 66 AvailAddress, 67 /// Invalid log address. 68 LogAddress, 69 #[cfg(feature = "vhost-kern")] 70 /// Error opening the vhost backend driver. 71 VhostOpen(std::io::Error), 72 #[cfg(feature = "vhost-kern")] 73 /// Error while running ioctl. 74 IoctlError(std::io::Error), 75 /// Error from IO subsystem. 76 IOError(std::io::Error), 77 #[cfg(feature = "vhost-user")] 78 /// Error from the vhost-user subsystem. 79 VhostUserProtocol(vhost_user::Error), 80 } 81 82 impl std::fmt::Display for Error { fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result83 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 84 match self { 85 Error::InvalidOperation => write!(f, "invalid vhost operations"), 86 Error::InvalidGuestMemory => write!(f, "invalid guest memory object"), 87 Error::InvalidGuestMemoryRegion => write!(f, "invalid guest memory region"), 88 Error::InvalidQueue => write!(f, "invalid virtque"), 89 Error::DescriptorTableAddress => write!(f, "invalid virtque descriptor talbe address"), 90 Error::UsedAddress => write!(f, "invalid virtque used talbe address"), 91 Error::AvailAddress => write!(f, "invalid virtque available table address"), 92 Error::LogAddress => write!(f, "invalid virtque log address"), 93 Error::IOError(e) => write!(f, "IO error: {}", e), 94 #[cfg(feature = "vhost-kern")] 95 Error::VhostOpen(e) => write!(f, "failure in opening vhost file: {}", e), 96 #[cfg(feature = "vhost-kern")] 97 Error::IoctlError(e) => write!(f, "failure in vhost ioctl: {}", e), 98 #[cfg(feature = "vhost-user")] 99 Error::VhostUserProtocol(e) => write!(f, "vhost-user: {}", e), 100 } 101 } 102 } 103 104 impl std::error::Error for Error {} 105 106 #[cfg(feature = "vhost-user")] 107 impl std::convert::From<vhost_user::Error> for Error { from(err: vhost_user::Error) -> Self108 fn from(err: vhost_user::Error) -> Self { 109 Error::VhostUserProtocol(err) 110 } 111 } 112 113 /// Result of vhost operations 114 pub type Result<T> = std::result::Result<T, Error>; 115 116 #[cfg(test)] 117 mod tests { 118 use super::*; 119 120 #[test] test_error()121 fn test_error() { 122 assert_eq!( 123 format!("{}", Error::AvailAddress), 124 "invalid virtque available table address" 125 ); 126 assert_eq!( 127 format!("{}", Error::InvalidOperation), 128 "invalid vhost operations" 129 ); 130 assert_eq!( 131 format!("{}", Error::InvalidGuestMemory), 132 "invalid guest memory object" 133 ); 134 assert_eq!( 135 format!("{}", Error::InvalidGuestMemoryRegion), 136 "invalid guest memory region" 137 ); 138 assert_eq!(format!("{}", Error::InvalidQueue), "invalid virtque"); 139 assert_eq!( 140 format!("{}", Error::DescriptorTableAddress), 141 "invalid virtque descriptor talbe address" 142 ); 143 assert_eq!( 144 format!("{}", Error::UsedAddress), 145 "invalid virtque used talbe address" 146 ); 147 assert_eq!( 148 format!("{}", Error::LogAddress), 149 "invalid virtque log address" 150 ); 151 152 assert_eq!(format!("{:?}", Error::AvailAddress), "AvailAddress"); 153 } 154 155 #[cfg(feature = "vhost-user")] 156 #[test] test_convert_from_vhost_user_error()157 fn test_convert_from_vhost_user_error() { 158 let e: Error = vhost_user::Error::OversizedMsg.into(); 159 160 assert_eq!(format!("{}", e), "vhost-user: oversized message"); 161 } 162 } 163