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,
23
24 reply_ack_negotiated: bool,
29}
30
31impl FrontendClient {
32 pub fn new(ep: Connection, reply_ack_negotiated: bool) -> Self {
34 FrontendClient {
35 sock: ep,
36 reply_ack_negotiated,
37 }
38 }
39
40 fn send_message<T>(
41 &mut self,
42 request: BackendReq,
43 msg: &T,
44 fds: Option<&[RawDescriptor]>,
45 want_reply: bool,
46 ) -> HandlerResult<()>
47 where
48 T: IntoBytes + Immutable,
49 {
50 let need_reply = want_reply && self.reply_ack_negotiated;
51
52 let len = mem::size_of::<T>();
53 let hdr = VhostUserMsgHeader::new_request_header(request, len as u32, need_reply);
54 self.sock
55 .send_message(&hdr, msg, fds)
56 .map_err(|e| std::io::Error::other(e.to_string()))?;
57
58 let non_standard_forced_reply =
59 [BackendReq::GPU_MAP, BackendReq::EXTERNAL_MAP].contains(&request);
60 if need_reply || non_standard_forced_reply {
61 self.wait_for_reply(&hdr)
62 .map_err(|e| std::io::Error::other(e.to_string()))?;
63 }
64 Ok(())
65 }
66
67 fn wait_for_reply(&mut self, hdr: &VhostUserMsgHeader) -> Result<()> {
68 let (reply, body, rfds) = self.sock.recv_message::<VhostUserU64>()?;
69 if !reply.is_valid() || !reply.is_reply_for(hdr) || !rfds.is_empty() || !body.is_valid() {
70 return Err(Error::InvalidMessage);
71 }
72 if body.value != 0 {
73 return Err(Error::FrontendInternalError);
74 }
75
76 Ok(())
77 }
78}
79
80impl Frontend for FrontendClient {
81 fn shmem_map(&mut self, req: &VhostUserMMap, fd: &dyn AsRawDescriptor) -> HandlerResult<()> {
83 if !self.reply_ack_negotiated {
84 base::warn!("SHMEM_MAP without REPLY_ACK is prone to race conditions");
85 }
86 self.send_message(
87 BackendReq::SHMEM_MAP,
88 req,
89 Some(&[fd.as_raw_descriptor()]),
90 true,
91 )
92 }
93
94 fn shmem_unmap(&mut self, req: &VhostUserMMap) -> HandlerResult<()> {
96 self.send_message(
97 BackendReq::SHMEM_UNMAP,
98 req,
99 None,
100 true,
101 )
102 }
103
104 fn handle_config_change(&mut self) -> HandlerResult<()> {
106 self.send_message(
107 BackendReq::CONFIG_CHANGE_MSG,
108 &VhostUserEmptyMessage,
109 None,
110 false,
111 )
112 }
113
114 fn gpu_map(
116 &mut self,
117 req: &VhostUserGpuMapMsg,
118 descriptor: &dyn AsRawDescriptor,
119 ) -> HandlerResult<()> {
120 self.send_message(
121 BackendReq::GPU_MAP,
122 req,
123 Some(&[descriptor.as_raw_descriptor()]),
124 false,
125 )
126 }
127
128 fn external_map(&mut self, req: &VhostUserExternalMapMsg) -> HandlerResult<()> {
130 self.send_message(
131 BackendReq::EXTERNAL_MAP,
132 req,
133 None,
134 false,
135 )
136 }
137}