1 // Copyright 2017 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 //! Implements vhost-based virtio devices.
6
7 use anyhow::anyhow;
8 use anyhow::Context;
9 use base::Error as SysError;
10 use base::TubeError;
11 use data_model::DataInit;
12 use net_util::Error as TapError;
13 use remain::sorted;
14 use thiserror::Error;
15 use vhost::Error as VhostError;
16 use vmm_vhost::message::MasterReq;
17 use vmm_vhost::message::Req;
18 use vmm_vhost::message::VhostUserMsgHeader;
19 use zerocopy::LayoutVerified;
20
21 mod control_socket;
22 pub mod user;
23
24 pub use self::control_socket::*;
25
26 cfg_if::cfg_if! {
27 if #[cfg(unix)] {
28 mod net;
29 pub mod vsock;
30 mod worker;
31
32 pub use self::net::Net;
33 pub use self::vsock::Vsock;
34 } else if #[cfg(windows)] {}
35 }
36
37 #[sorted]
38 #[derive(Error, Debug)]
39 pub enum Error {
40 /// Cloning kill event failed.
41 #[error("failed to clone kill event: {0}")]
42 CloneKillEvent(SysError),
43 /// Creating kill event failed.
44 #[error("failed to create kill event: {0}")]
45 CreateKillEvent(SysError),
46 /// Creating tube failed.
47 #[error("failed to create tube: {0}")]
48 CreateTube(TubeError),
49 /// Creating wait context failed.
50 #[error("failed to create poll context: {0}")]
51 CreateWaitContext(SysError),
52 /// Enabling tap interface failed.
53 #[error("failed to enable tap interface: {0}")]
54 TapEnable(TapError),
55 /// Open tap device failed.
56 #[error("failed to open tap device: {0}")]
57 TapOpen(TapError),
58 /// Setting tap IP failed.
59 #[error("failed to set tap IP: {0}")]
60 TapSetIp(TapError),
61 /// Setting tap mac address failed.
62 #[error("failed to set tap mac address: {0}")]
63 TapSetMacAddress(TapError),
64 /// Setting tap netmask failed.
65 #[error("failed to set tap netmask: {0}")]
66 TapSetNetmask(TapError),
67 /// Setting tap interface offload flags failed.
68 #[error("failed to set tap interface offload flags: {0}")]
69 TapSetOffload(TapError),
70 /// Setting vnet header size failed.
71 #[error("failed to set vnet header size: {0}")]
72 TapSetVnetHdrSize(TapError),
73 /// Get features failed.
74 #[error("failed to get features: {0}")]
75 VhostGetFeatures(VhostError),
76 /// Vhost IOTLB required but not supported.
77 #[error("Vhost IOTLB required but not supported")]
78 VhostIotlbUnsupported,
79 /// Failed to create vhost event.
80 #[error("failed to create vhost event: {0}")]
81 VhostIrqCreate(SysError),
82 /// Failed to read vhost event.
83 #[error("failed to read vhost event: {0}")]
84 VhostIrqRead(SysError),
85 /// Net set backend failed.
86 #[error("net set backend failed: {0}")]
87 VhostNetSetBackend(VhostError),
88 /// Failed to open vhost device.
89 #[error("failed to open vhost device: {0}")]
90 VhostOpen(VhostError),
91 /// Set features failed.
92 #[error("failed to set features: {0}")]
93 VhostSetFeatures(VhostError),
94 /// Set mem table failed.
95 #[error("failed to set mem table: {0}")]
96 VhostSetMemTable(VhostError),
97 /// Set owner failed.
98 #[error("failed to set owner: {0}")]
99 VhostSetOwner(VhostError),
100 /// Set vring addr failed.
101 #[error("failed to set vring addr: {0}")]
102 VhostSetVringAddr(VhostError),
103 /// Set vring base failed.
104 #[error("failed to set vring base: {0}")]
105 VhostSetVringBase(VhostError),
106 /// Set vring call failed.
107 #[error("failed to set vring call: {0}")]
108 VhostSetVringCall(VhostError),
109 /// Set vring kick failed.
110 #[error("failed to set vring kick: {0}")]
111 VhostSetVringKick(VhostError),
112 /// Set vring num failed.
113 #[error("failed to set vring num: {0}")]
114 VhostSetVringNum(VhostError),
115 /// Failed to set CID for guest.
116 #[error("failed to set CID for guest: {0}")]
117 VhostVsockSetCid(VhostError),
118 /// Failed to start vhost-vsock driver.
119 #[error("failed to start vhost-vsock driver: {0}")]
120 VhostVsockStart(VhostError),
121 /// Error while waiting for events.
122 #[error("failed waiting for events: {0}")]
123 WaitError(SysError),
124 }
125
126 pub type Result<T> = std::result::Result<T, Error>;
127
128 pub const HEADER_LEN: usize = std::mem::size_of::<VhostUserMsgHeader<MasterReq>>();
129
vhost_header_from_bytes<R: Req>(bytes: &[u8]) -> Option<&VhostUserMsgHeader<R>>130 pub fn vhost_header_from_bytes<R: Req>(bytes: &[u8]) -> Option<&VhostUserMsgHeader<R>> {
131 if bytes.len() < HEADER_LEN {
132 return None;
133 }
134 // This can't fail because we already checked the size and because packed alignment is 1.
135 Some(
136 LayoutVerified::<_, VhostUserMsgHeader<R>>::new(&bytes[0..HEADER_LEN])
137 .unwrap()
138 .into_ref(),
139 )
140 }
141
vhost_body_from_message_bytes<T: DataInit>(bytes: &mut [u8]) -> anyhow::Result<&mut T>142 pub fn vhost_body_from_message_bytes<T: DataInit>(bytes: &mut [u8]) -> anyhow::Result<&mut T> {
143 let body_len = std::mem::size_of::<T>();
144 let hdr = vhost_header_from_bytes::<MasterReq>(bytes).context("failed to parse header")?;
145
146 if body_len != hdr.get_size() as usize || bytes.len() != body_len + HEADER_LEN {
147 return Err(anyhow!(
148 "parse error: body_len={} hdr_size={} msg_size={}",
149 body_len,
150 hdr.get_size(),
151 bytes.len()
152 ));
153 }
154
155 // We already checked the size. This can only fail due to alignment, but all valid
156 // message types are packed (i.e. alignment=1).
157 Ok(T::from_mut_slice(&mut bytes[HEADER_LEN..]).expect("bad alignment"))
158 }
159