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<()> {
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<()> {
28 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
29 }
30
31 fn shmem_unmap(&mut self, _req: &VhostUserMMap) -> HandlerResult<()> {
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<()> {
45 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
46 }
47
48 fn external_map(&mut self, _req: &VhostUserExternalMapMsg) -> HandlerResult<()> {
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,
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) -> 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) {
77 self.reply_ack_negotiated = enable;
78 }
79
80 pub fn frontend_mut(&mut self) -> &mut S {
82 &mut self.frontend
83 }
84
85 pub fn handle_request(&mut self) -> Result<()> {
92 let (hdr, files) = self.sub_sock.recv_header()?;
102 if !hdr.is_valid() || hdr.is_reply() {
103 return Err(Error::InvalidMessage);
104 }
105 self.check_attached_files(&hdr, &files)?;
106 let (buf, extra_files) = self.sub_sock.recv_body_bytes(&hdr)?;
107 if !extra_files.is_empty() {
108 return Err(Error::InvalidMessage);
109 }
110
111 let res = match hdr.get_code() {
112 Ok(BackendReq::CONFIG_CHANGE_MSG) => {
113 self.check_msg_size(&hdr, 0)?;
114 self.frontend
115 .handle_config_change()
116 .map_err(Error::ReqHandlerError)
117 }
118 Ok(BackendReq::SHMEM_MAP) => {
119 let msg = self.extract_msg_body::<VhostUserMMap>(&hdr, &buf)?;
120 self.frontend
122 .shmem_map(&msg, &files[0])
123 .map_err(Error::ReqHandlerError)
124 }
125 Ok(BackendReq::SHMEM_UNMAP) => {
126 let msg = self.extract_msg_body::<VhostUserMMap>(&hdr, &buf)?;
127 self.frontend
128 .shmem_unmap(&msg)
129 .map_err(Error::ReqHandlerError)
130 }
131 Ok(BackendReq::GPU_MAP) => {
132 let msg = self.extract_msg_body::<VhostUserGpuMapMsg>(&hdr, &buf)?;
133 self.frontend
135 .gpu_map(&msg, &files[0])
136 .map_err(Error::ReqHandlerError)
137 }
138 Ok(BackendReq::EXTERNAL_MAP) => {
139 let msg = self.extract_msg_body::<VhostUserExternalMapMsg>(&hdr, &buf)?;
140 self.frontend
141 .external_map(&msg)
142 .map_err(Error::ReqHandlerError)
143 }
144 _ => Err(Error::InvalidMessage),
145 };
146
147 self.send_reply(&hdr, &res)?;
148
149 res
150 }
151
152 fn check_msg_size(&self, hdr: &VhostUserMsgHeader, expected: usize) -> Result<()> {
153 if hdr.get_size() as usize != expected {
154 return Err(Error::InvalidMessage);
155 }
156 Ok(())
157 }
158
159 fn check_attached_files(&self, hdr: &VhostUserMsgHeader, files: &[File]) -> Result<()> {
160 let expected_num_files = match hdr.get_code().map_err(|_| Error::InvalidMessage)? {
161 BackendReq::SHMEM_MAP | BackendReq::GPU_MAP => 1,
163 _ => 0,
164 };
165
166 if files.len() == expected_num_files {
167 Ok(())
168 } else {
169 Err(Error::InvalidMessage)
170 }
171 }
172
173 fn extract_msg_body<T: FromBytes + VhostUserMsgValidator>(
174 &self,
175 hdr: &VhostUserMsgHeader,
176 buf: &[u8],
177 ) -> Result<T> {
178 self.check_msg_size(hdr, mem::size_of::<T>())?;
179 let msg = T::read_from_bytes(buf).map_err(|_| Error::InvalidMessage)?;
180 if !msg.is_valid() {
181 return Err(Error::InvalidMessage);
182 }
183 Ok(msg)
184 }
185
186 fn new_reply_header<T: Sized>(&self, req: &VhostUserMsgHeader) -> Result<VhostUserMsgHeader> {
187 Ok(VhostUserMsgHeader::new_reply_header(
188 req.get_code::<BackendReq>()
189 .map_err(|_| Error::InvalidMessage)?,
190 mem::size_of::<T>() as u32,
191 ))
192 }
193
194 fn send_reply(&mut self, req: &VhostUserMsgHeader, res: &Result<()>) -> Result<()> {
195 let code = req
196 .get_code::<BackendReq>()
197 .map_err(|_| Error::InvalidMessage)?;
198 if code == BackendReq::GPU_MAP
199 || code == BackendReq::EXTERNAL_MAP
200 || (self.reply_ack_negotiated && req.is_need_reply())
201 {
202 let hdr = self.new_reply_header::<VhostUserU64>(req)?;
203 let def_err = libc::EINVAL;
204 let val = match res {
205 Ok(()) => 0,
206 Err(e) => match e {
207 Error::ReqHandlerError(ioerr) => match ioerr.raw_os_error() {
208 Some(rawerr) => -rawerr as u64,
209 None => -def_err as u64,
210 },
211 _ => -def_err as u64,
212 },
213 };
214 let msg = VhostUserU64::new(val);
215 self.sub_sock.send_message(&hdr, &msg, None)?;
216 }
217 Ok(())
218 }
219}