/rust/registry/src/index.crates.io-1949cf8c6b5b557f/vhost-0.14.0/src/lib.rs
Line | Count | Source |
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, frontend and backend. Frontend is the application |
30 | | //! that shares its virtqueues. Backend is the consumer of the virtqueues. Frontend and backend 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 vmm_sys_util; |
39 | | |
40 | | mod backend; |
41 | | pub use backend::*; |
42 | | |
43 | | #[cfg(feature = "vhost-net")] |
44 | | pub mod net; |
45 | | #[cfg(feature = "vhost-vdpa")] |
46 | | pub mod vdpa; |
47 | | #[cfg(feature = "vhost-kern")] |
48 | | pub mod vhost_kern; |
49 | | #[cfg(feature = "vhost-user")] |
50 | | pub mod vhost_user; |
51 | | #[cfg(feature = "vhost-vsock")] |
52 | | pub mod vsock; |
53 | | |
54 | | /// Due to the way `xen` handles memory mappings we can not combine it with |
55 | | /// `postcopy` feature which relies on persistent memory mappings. Thus we |
56 | | /// disallow enabling both features at the same time. |
57 | | #[cfg(all(feature = "postcopy", feature = "xen"))] |
58 | | compile_error!("Both `postcopy` and `xen` features can not be enabled at the same time."); |
59 | | |
60 | | /// Error codes for vhost operations |
61 | | #[derive(Debug)] |
62 | | pub enum Error { |
63 | | /// Invalid operations. |
64 | | InvalidOperation, |
65 | | /// Invalid guest memory. |
66 | | InvalidGuestMemory, |
67 | | /// Invalid guest memory region. |
68 | | InvalidGuestMemoryRegion, |
69 | | /// Invalid IOTLB message. |
70 | | InvalidIotlbMsg, |
71 | | /// Invalid queue. |
72 | | InvalidQueue, |
73 | | /// Invalid descriptor table address. |
74 | | DescriptorTableAddress, |
75 | | /// Invalid used address. |
76 | | UsedAddress, |
77 | | /// Invalid available address. |
78 | | AvailAddress, |
79 | | /// Invalid log address. |
80 | | LogAddress, |
81 | | #[cfg(feature = "vhost-kern")] |
82 | | /// Error opening the vhost backend driver. |
83 | | VhostOpen(std::io::Error), |
84 | | #[cfg(feature = "vhost-kern")] |
85 | | /// Error while running ioctl. |
86 | | IoctlError(std::io::Error), |
87 | | /// Error from IO subsystem. |
88 | | IOError(std::io::Error), |
89 | | #[cfg(feature = "vhost-user")] |
90 | | /// Error from the vhost-user subsystem. |
91 | | VhostUserProtocol(vhost_user::Error), |
92 | | } |
93 | | |
94 | | impl std::fmt::Display for Error { |
95 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
96 | 0 | match self { |
97 | 0 | Error::InvalidOperation => write!(f, "invalid vhost operations"), |
98 | 0 | Error::InvalidGuestMemory => write!(f, "invalid guest memory object"), |
99 | 0 | Error::InvalidGuestMemoryRegion => write!(f, "invalid guest memory region"), |
100 | 0 | Error::InvalidIotlbMsg => write!(f, "invalid IOTLB message"), |
101 | 0 | Error::InvalidQueue => write!(f, "invalid virtqueue"), |
102 | | Error::DescriptorTableAddress => { |
103 | 0 | write!(f, "invalid virtqueue descriptor table address") |
104 | | } |
105 | 0 | Error::UsedAddress => write!(f, "invalid virtqueue used table address"), |
106 | 0 | Error::AvailAddress => write!(f, "invalid virtqueue available table address"), |
107 | 0 | Error::LogAddress => write!(f, "invalid virtqueue log address"), |
108 | 0 | Error::IOError(e) => write!(f, "IO error: {}", e), |
109 | | #[cfg(feature = "vhost-kern")] |
110 | 0 | Error::VhostOpen(e) => write!(f, "failure in opening vhost file: {}", e), |
111 | | #[cfg(feature = "vhost-kern")] |
112 | 0 | Error::IoctlError(e) => write!(f, "failure in vhost ioctl: {}", e), |
113 | | #[cfg(feature = "vhost-user")] |
114 | 0 | Error::VhostUserProtocol(e) => write!(f, "vhost-user: {}", e), |
115 | | } |
116 | 0 | } |
117 | | } |
118 | | |
119 | | impl std::error::Error for Error {} |
120 | | |
121 | | #[cfg(feature = "vhost-user")] |
122 | | impl std::convert::From<vhost_user::Error> for Error { |
123 | 0 | fn from(err: vhost_user::Error) -> Self { |
124 | 0 | Error::VhostUserProtocol(err) |
125 | 0 | } |
126 | | } |
127 | | |
128 | | /// Result of vhost operations |
129 | | pub type Result<T> = std::result::Result<T, Error>; |
130 | | |
131 | | #[cfg(test)] |
132 | | mod tests { |
133 | | use super::*; |
134 | | |
135 | | #[test] |
136 | | fn test_error() { |
137 | | assert_eq!( |
138 | | format!("{}", Error::AvailAddress), |
139 | | "invalid virtqueue available table address" |
140 | | ); |
141 | | assert_eq!( |
142 | | format!("{}", Error::InvalidOperation), |
143 | | "invalid vhost operations" |
144 | | ); |
145 | | assert_eq!( |
146 | | format!("{}", Error::InvalidGuestMemory), |
147 | | "invalid guest memory object" |
148 | | ); |
149 | | assert_eq!( |
150 | | format!("{}", Error::InvalidGuestMemoryRegion), |
151 | | "invalid guest memory region" |
152 | | ); |
153 | | assert_eq!( |
154 | | format!("{}", Error::InvalidIotlbMsg), |
155 | | "invalid IOTLB message" |
156 | | ); |
157 | | assert_eq!(format!("{}", Error::InvalidQueue), "invalid virtqueue"); |
158 | | assert_eq!( |
159 | | format!("{}", Error::DescriptorTableAddress), |
160 | | "invalid virtqueue descriptor table address" |
161 | | ); |
162 | | assert_eq!( |
163 | | format!("{}", Error::UsedAddress), |
164 | | "invalid virtqueue used table address" |
165 | | ); |
166 | | assert_eq!( |
167 | | format!("{}", Error::LogAddress), |
168 | | "invalid virtqueue log address" |
169 | | ); |
170 | | |
171 | | assert_eq!(format!("{:?}", Error::AvailAddress), "AvailAddress"); |
172 | | } |
173 | | |
174 | | #[cfg(feature = "vhost-user")] |
175 | | #[test] |
176 | | fn test_convert_from_vhost_user_error() { |
177 | | let e: Error = vhost_user::Error::OversizedMsg.into(); |
178 | | |
179 | | assert_eq!(format!("{}", e), "vhost-user: oversized message"); |
180 | | } |
181 | | } |