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(&mut self, _req: &VhostUserMMap, _fd: &dyn AsRawDescriptor) -> HandlerResult<u64> {
28 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
29 }
30
31 fn shmem_unmap(&mut self, _req: &VhostUserMMap) -> HandlerResult<u64> {
33 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
34 }
35
36 fn gpu_map(
41 &mut self,
42 _req: &VhostUserGpuMapMsg,
43 _descriptor: &dyn AsRawDescriptor,
44 ) -> HandlerResult<u64> {
45 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
46 }
47
48 fn external_map(&mut self, _req: &VhostUserExternalMapMsg) -> HandlerResult<u64> {
50 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
51 }
52}
53
54pub struct FrontendServer<S: Frontend> {
57 pub(crate) sub_sock: Connection<BackendReq>,
59 reply_ack_negotiated: bool,
61
62 frontend: S,
63}
64
65impl<S: Frontend> FrontendServer<S> {
66 pub(crate) fn new(frontend: S, connection: Connection<BackendReq>) -> Result<Self> {
68 Ok(FrontendServer {
69 sub_sock: connection,
70 reply_ack_negotiated: false,
71 frontend,
72 })
73 }
74
75 pub fn set_reply_ack_flag(&mut self, enable: bool) {
80 self.reply_ack_negotiated = enable;
81 }
82
83 pub fn frontend_mut(&mut self) -> &mut S {
85 &mut self.frontend
86 }
87
88 pub fn handle_request(&mut self) -> Result<u64> {
95 let (hdr, files) = self.sub_sock.recv_header()?;
105 if !hdr.is_valid() || hdr.is_reply() {
106 return Err(Error::InvalidMessage);
107 }
108 self.check_attached_files(&hdr, &files)?;
109 let (buf, extra_files) = self.sub_sock.recv_body_bytes(&hdr)?;
110 if !extra_files.is_empty() {
111 return Err(Error::InvalidMessage);
112 }
113
114 let res = match hdr.get_code() {
115 Ok(BackendReq::CONFIG_CHANGE_MSG) => {
116 self.check_msg_size(&hdr, 0)?;
117 self.frontend
118 .handle_config_change()
119 .map_err(Error::ReqHandlerError)
120 }
121 Ok(BackendReq::SHMEM_MAP) => {
122 let msg = self.extract_msg_body::<VhostUserMMap>(&hdr, &buf)?;
123 self.frontend
125 .shmem_map(&msg, &files[0])
126 .map_err(Error::ReqHandlerError)
127 }
128 Ok(BackendReq::SHMEM_UNMAP) => {
129 let msg = self.extract_msg_body::<VhostUserMMap>(&hdr, &buf)?;
130 self.frontend
131 .shmem_unmap(&msg)
132 .map_err(Error::ReqHandlerError)
133 }
134 Ok(BackendReq::GPU_MAP) => {
135 let msg = self.extract_msg_body::<VhostUserGpuMapMsg>(&hdr, &buf)?;
136 self.frontend
138 .gpu_map(&msg, &files[0])
139 .map_err(Error::ReqHandlerError)
140 }
141 Ok(BackendReq::EXTERNAL_MAP) => {
142 let msg = self.extract_msg_body::<VhostUserExternalMapMsg>(&hdr, &buf)?;
143 self.frontend
144 .external_map(&msg)
145 .map_err(Error::ReqHandlerError)
146 }
147 _ => Err(Error::InvalidMessage),
148 };
149
150 self.send_reply(&hdr, &res)?;
151
152 res
153 }
154
155 fn check_msg_size(&self, hdr: &VhostUserMsgHeader<BackendReq>, expected: usize) -> Result<()> {
156 if hdr.get_size() as usize != expected {
157 return Err(Error::InvalidMessage);
158 }
159 Ok(())
160 }
161
162 fn check_attached_files(
163 &self,
164 hdr: &VhostUserMsgHeader<BackendReq>,
165 files: &[File],
166 ) -> Result<()> {
167 let expected_num_files = match hdr.get_code().map_err(|_| Error::InvalidMessage)? {
168 BackendReq::SHMEM_MAP | BackendReq::GPU_MAP => 1,
170 _ => 0,
171 };
172
173 if files.len() == expected_num_files {
174 Ok(())
175 } else {
176 Err(Error::InvalidMessage)
177 }
178 }
179
180 fn extract_msg_body<T: FromBytes + VhostUserMsgValidator>(
181 &self,
182 hdr: &VhostUserMsgHeader<BackendReq>,
183 buf: &[u8],
184 ) -> Result<T> {
185 self.check_msg_size(hdr, mem::size_of::<T>())?;
186 let msg = T::read_from_bytes(buf).map_err(|_| Error::InvalidMessage)?;
187 if !msg.is_valid() {
188 return Err(Error::InvalidMessage);
189 }
190 Ok(msg)
191 }
192
193 fn new_reply_header<T: Sized>(
194 &self,
195 req: &VhostUserMsgHeader<BackendReq>,
196 ) -> Result<VhostUserMsgHeader<BackendReq>> {
197 Ok(VhostUserMsgHeader::new(
198 req.get_code().map_err(|_| Error::InvalidMessage)?,
199 VhostUserHeaderFlag::REPLY.bits(),
200 mem::size_of::<T>() as u32,
201 ))
202 }
203
204 fn send_reply(
205 &mut self,
206 req: &VhostUserMsgHeader<BackendReq>,
207 res: &Result<u64>,
208 ) -> Result<()> {
209 let code = req.get_code().map_err(|_| Error::InvalidMessage)?;
210 if code == BackendReq::GPU_MAP
211 || code == BackendReq::EXTERNAL_MAP
212 || code == BackendReq::SHMEM_MAP
214 || code == BackendReq::SHMEM_UNMAP
215 || (self.reply_ack_negotiated && req.is_need_reply())
216 {
217 let hdr = self.new_reply_header::<VhostUserU64>(req)?;
218 let def_err = libc::EINVAL;
219 let val = match res {
220 Ok(n) => *n,
221 Err(e) => match e {
222 Error::ReqHandlerError(ioerr) => match ioerr.raw_os_error() {
223 Some(rawerr) => -rawerr as u64,
224 None => -def_err as u64,
225 },
226 _ => -def_err as u64,
227 },
228 };
229 let msg = VhostUserU64::new(val);
230 self.sub_sock.send_message(&hdr, &msg, None)?;
231 }
232 Ok(())
233 }
234}