vmm_vhost/
frontend_server.rs1use std::fs::File;
5use std::mem;
6
7use base::AsRawDescriptor;
8use zerocopy::FromBytes;
9
10use crate::message::*;
11use crate::BackendReq;
12use crate::Connection;
13use crate::Error;
14use crate::HandlerResult;
15use crate::Result;
16
17pub trait Frontend {
21 fn handle_config_change(&mut self) -> HandlerResult<u64> {
23 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
24 }
25
26 fn shmem_map(
28 &mut self,
29 _req: &VhostUserShmemMapMsg,
30 _fd: &dyn AsRawDescriptor,
31 ) -> HandlerResult<u64> {
32 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
33 }
34
35 fn shmem_unmap(&mut self, _req: &VhostUserShmemUnmapMsg) -> HandlerResult<u64> {
37 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
38 }
39
40 fn gpu_map(
45 &mut self,
46 _req: &VhostUserGpuMapMsg,
47 _descriptor: &dyn AsRawDescriptor,
48 ) -> HandlerResult<u64> {
49 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
50 }
51
52 fn external_map(&mut self, _req: &VhostUserExternalMapMsg) -> HandlerResult<u64> {
54 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
55 }
56}
57
58pub struct FrontendServer<S: Frontend> {
61 pub(crate) sub_sock: Connection<BackendReq>,
63 reply_ack_negotiated: bool,
65
66 frontend: S,
67}
68
69impl<S: Frontend> FrontendServer<S> {
70 pub(crate) fn new(frontend: S, connection: Connection<BackendReq>) -> Result<Self> {
72 Ok(FrontendServer {
73 sub_sock: connection,
74 reply_ack_negotiated: false,
75 frontend,
76 })
77 }
78
79 pub fn set_reply_ack_flag(&mut self, enable: bool) {
84 self.reply_ack_negotiated = enable;
85 }
86
87 pub fn frontend_mut(&mut self) -> &mut S {
89 &mut self.frontend
90 }
91
92 pub fn handle_request(&mut self) -> Result<u64> {
99 let (hdr, files) = self.sub_sock.recv_header()?;
109 if !hdr.is_valid() || hdr.is_reply() {
110 return Err(Error::InvalidMessage);
111 }
112 self.check_attached_files(&hdr, &files)?;
113 let (buf, extra_files) = self.sub_sock.recv_body_bytes(&hdr)?;
114 if !extra_files.is_empty() {
115 return Err(Error::InvalidMessage);
116 }
117
118 let res = match hdr.get_code() {
119 Ok(BackendReq::CONFIG_CHANGE_MSG) => {
120 self.check_msg_size(&hdr, 0)?;
121 self.frontend
122 .handle_config_change()
123 .map_err(Error::ReqHandlerError)
124 }
125 Ok(BackendReq::SHMEM_MAP) => {
126 let msg = self.extract_msg_body::<VhostUserShmemMapMsg>(&hdr, &buf)?;
127 self.frontend
129 .shmem_map(&msg, &files[0])
130 .map_err(Error::ReqHandlerError)
131 }
132 Ok(BackendReq::SHMEM_UNMAP) => {
133 let msg = self.extract_msg_body::<VhostUserShmemUnmapMsg>(&hdr, &buf)?;
134 self.frontend
135 .shmem_unmap(&msg)
136 .map_err(Error::ReqHandlerError)
137 }
138 Ok(BackendReq::GPU_MAP) => {
139 let msg = self.extract_msg_body::<VhostUserGpuMapMsg>(&hdr, &buf)?;
140 self.frontend
142 .gpu_map(&msg, &files[0])
143 .map_err(Error::ReqHandlerError)
144 }
145 Ok(BackendReq::EXTERNAL_MAP) => {
146 let msg = self.extract_msg_body::<VhostUserExternalMapMsg>(&hdr, &buf)?;
147 self.frontend
148 .external_map(&msg)
149 .map_err(Error::ReqHandlerError)
150 }
151 _ => Err(Error::InvalidMessage),
152 };
153
154 self.send_reply(&hdr, &res)?;
155
156 res
157 }
158
159 fn check_msg_size(&self, hdr: &VhostUserMsgHeader<BackendReq>, expected: usize) -> Result<()> {
160 if hdr.get_size() as usize != expected {
161 return Err(Error::InvalidMessage);
162 }
163 Ok(())
164 }
165
166 fn check_attached_files(
167 &self,
168 hdr: &VhostUserMsgHeader<BackendReq>,
169 files: &[File],
170 ) -> Result<()> {
171 let expected_num_files = match hdr.get_code().map_err(|_| Error::InvalidMessage)? {
172 BackendReq::SHMEM_MAP | BackendReq::GPU_MAP => 1,
174 _ => 0,
175 };
176
177 if files.len() == expected_num_files {
178 Ok(())
179 } else {
180 Err(Error::InvalidMessage)
181 }
182 }
183
184 fn extract_msg_body<T: FromBytes + VhostUserMsgValidator>(
185 &self,
186 hdr: &VhostUserMsgHeader<BackendReq>,
187 buf: &[u8],
188 ) -> Result<T> {
189 self.check_msg_size(hdr, mem::size_of::<T>())?;
190 let msg = T::read_from_bytes(buf).map_err(|_| Error::InvalidMessage)?;
191 if !msg.is_valid() {
192 return Err(Error::InvalidMessage);
193 }
194 Ok(msg)
195 }
196
197 fn new_reply_header<T: Sized>(
198 &self,
199 req: &VhostUserMsgHeader<BackendReq>,
200 ) -> Result<VhostUserMsgHeader<BackendReq>> {
201 Ok(VhostUserMsgHeader::new(
202 req.get_code().map_err(|_| Error::InvalidMessage)?,
203 VhostUserHeaderFlag::REPLY.bits(),
204 mem::size_of::<T>() as u32,
205 ))
206 }
207
208 fn send_reply(
209 &mut self,
210 req: &VhostUserMsgHeader<BackendReq>,
211 res: &Result<u64>,
212 ) -> Result<()> {
213 let code = req.get_code().map_err(|_| Error::InvalidMessage)?;
214 if code == BackendReq::SHMEM_MAP
215 || code == BackendReq::SHMEM_UNMAP
216 || code == BackendReq::GPU_MAP
217 || code == BackendReq::EXTERNAL_MAP
218 || (self.reply_ack_negotiated && req.is_need_reply())
219 {
220 let hdr = self.new_reply_header::<VhostUserU64>(req)?;
221 let def_err = libc::EINVAL;
222 let val = match res {
223 Ok(n) => *n,
224 Err(e) => match e {
225 Error::ReqHandlerError(ioerr) => match ioerr.raw_os_error() {
226 Some(rawerr) => -rawerr as u64,
227 None => -def_err as u64,
228 },
229 _ => -def_err as u64,
230 },
231 };
232 let msg = VhostUserU64::new(val);
233 self.sub_sock.send_message(&hdr, &msg, None)?;
234 }
235 Ok(())
236 }
237}