• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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