vmm_vhost/
frontend_client.rs1use std::mem;
5use std::string::ToString;
6
7use base::AsRawDescriptor;
8use base::RawDescriptor;
9use zerocopy::Immutable;
10use zerocopy::IntoBytes;
11
12use crate::message::*;
13use crate::BackendReq;
14use crate::Connection;
15use crate::Error;
16use crate::Frontend;
17use crate::HandlerResult;
18use crate::Result;
19
20pub struct FrontendClient {
22 sock: Connection<BackendReq>,
23
24 reply_ack_negotiated: bool,
26}
27
28impl FrontendClient {
29 pub fn new(ep: Connection<BackendReq>) -> Self {
31 FrontendClient {
32 sock: ep,
33 reply_ack_negotiated: false,
34 }
35 }
36
37 fn send_message<T>(
38 &mut self,
39 request: BackendReq,
40 msg: &T,
41 fds: Option<&[RawDescriptor]>,
42 ) -> HandlerResult<u64>
43 where
44 T: IntoBytes + Immutable,
45 {
46 let len = mem::size_of::<T>();
47 let mut hdr = VhostUserMsgHeader::new(request, 0, len as u32);
48 if self.reply_ack_negotiated {
49 hdr.set_need_reply(true);
50 }
51 self.sock
52 .send_message(&hdr, msg, fds)
53 .map_err(|e| std::io::Error::other(e.to_string()))?;
54
55 self.wait_for_reply(&hdr)
56 .map_err(|e| std::io::Error::other(e.to_string()))
57 }
58
59 fn wait_for_reply(&mut self, hdr: &VhostUserMsgHeader<BackendReq>) -> Result<u64> {
60 let code = hdr.get_code().map_err(|_| Error::InvalidMessage)?;
61 if code != BackendReq::GPU_MAP
62 && code != BackendReq::EXTERNAL_MAP
63 && code != BackendReq::SHMEM_MAP
65 && code != BackendReq::SHMEM_UNMAP
66 && !self.reply_ack_negotiated
67 {
68 return Ok(0);
69 }
70
71 let (reply, body, rfds) = self.sock.recv_message::<VhostUserU64>()?;
72 if !reply.is_valid() || !reply.is_reply_for(hdr) || !rfds.is_empty() || !body.is_valid() {
73 return Err(Error::InvalidMessage);
74 }
75 if body.value != 0 {
76 return Err(Error::FrontendInternalError);
77 }
78
79 Ok(body.value)
80 }
81
82 pub fn set_reply_ack_flag(&mut self, enable: bool) {
88 self.reply_ack_negotiated = enable;
89 }
90}
91
92impl Frontend for FrontendClient {
93 fn shmem_map(&mut self, req: &VhostUserMMap, fd: &dyn AsRawDescriptor) -> HandlerResult<u64> {
95 self.send_message(BackendReq::SHMEM_MAP, req, Some(&[fd.as_raw_descriptor()]))
96 }
97
98 fn shmem_unmap(&mut self, req: &VhostUserMMap) -> HandlerResult<u64> {
100 self.send_message(BackendReq::SHMEM_UNMAP, req, None)
101 }
102
103 fn handle_config_change(&mut self) -> HandlerResult<u64> {
105 self.send_message(BackendReq::CONFIG_CHANGE_MSG, &VhostUserEmptyMessage, None)
106 }
107
108 fn gpu_map(
110 &mut self,
111 req: &VhostUserGpuMapMsg,
112 descriptor: &dyn AsRawDescriptor,
113 ) -> HandlerResult<u64> {
114 self.send_message(
115 BackendReq::GPU_MAP,
116 req,
117 Some(&[descriptor.as_raw_descriptor()]),
118 )
119 }
120
121 fn external_map(&mut self, req: &VhostUserExternalMapMsg) -> HandlerResult<u64> {
123 self.send_message(BackendReq::EXTERNAL_MAP, req, None)
124 }
125}