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