From 3e99098bf34fe77b7f6d296adacfe07ca16c4f1b Mon Sep 17 00:00:00 2001 From: Yang Zhong Date: Fri, 19 Jul 2019 20:28:06 +0800 Subject: [PATCH] vhost_rs: add config messge support The previous definitions does not cover config space read/write and only cover general message as below: A vhost-user message consists of 3 header fields and a payload. +---------+-------+------+---------+ | request | flags | size | payload | +---------+-------+------+---------+ but for config space, the payload include: Virtio device config space ^^^^^^^^^^^^^^^^^^^^^^^^^^ +--------+------+-------+---------+ | offset | size | flags | payload | +--------+------+-------+---------+ :offset: a 32-bit offset of virtio device's configuration space :size: a 32-bit configuration space access size in bytes :flags: a 32-bit value: - 0: Vhost master messages used for writeable fields - 1: Vhost master messages used for live migration :payload: Size bytes array holding the contents of the virtio device's configuration space This patch add specific functions for config message, which can get/set config space from/to backend. Signed-off-by: Yang Zhong --- vhost_rs/src/vhost_user/connection.rs | 39 +++++++++++++++++++++++++++ vhost_rs/src/vhost_user/master.rs | 25 +++++++++++++++-- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/vhost_rs/src/vhost_user/connection.rs b/vhost_rs/src/vhost_user/connection.rs index 69439dd70..f0f28c98c 100644 --- a/vhost_rs/src/vhost_user/connection.rs +++ b/vhost_rs/src/vhost_user/connection.rs @@ -197,6 +197,45 @@ impl Endpoint { Ok(()) } + /// Send a message with header, body and config info. Optional file descriptors may be attached to + /// the message. + /// + /// # Return: + /// * - number of bytes sent on success + /// * - SocketRetry: temporary error caused by signals or short of resources. + /// * - SocketBroken: the underline socket is broken. + /// * - SocketError: other socket related errors. + /// * - PartialMessage: received a partial message. + pub fn send_config_message( + &mut self, + hdr: &VhostUserMsgHeader, + user_config: &VhostUserConfig, + buf: &mut [u8], + fds: Option<&[RawFd]>, + ) -> Result<()> { + // Safe because there can't be other mutable referance to hdr and body. + let iovs = unsafe { + [ + slice::from_raw_parts( + hdr as *const VhostUserMsgHeader as *const u8, + mem::size_of::>(), + ), + slice::from_raw_parts( + user_config as *const VhostUserConfig as *const u8, + mem::size_of::(), + ), + slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len()), + ] + }; + let bytes = self.send_iovec(&iovs[..], fds)?; + let total = + mem::size_of::>() + mem::size_of::() + buf.len(); + if bytes != total { + return Err(Error::PartialMessage); + } + Ok(()) + } + /// Send a message with header, body and payload. Optional file descriptors /// may also be attached to the message. /// diff --git a/vhost_rs/src/vhost_user/master.rs b/vhost_rs/src/vhost_user/master.rs index a7129a18d..28b6e99fd 100644 --- a/vhost_rs/src/vhost_user/master.rs +++ b/vhost_rs/src/vhost_user/master.rs @@ -360,7 +360,7 @@ impl VhostUserMaster for Master { // "Master payload: virtio device config space" // But what content should the payload contains for a get_config() request? // So current implementation doesn't conform to the spec. - let hdr = node.send_request_with_body(MasterReq::GET_CONFIG, &body, None)?; + let hdr = node.send_request_with_config_body(MasterReq::GET_CONFIG, &body, None)?; let (reply, buf, rfds) = node.recv_reply_with_payload::(&hdr)?; if rfds.is_some() { Endpoint::::close_rfds(rfds); @@ -480,6 +480,27 @@ impl MasterInternal { Ok(hdr) } + fn send_request_with_config_body( + &mut self, + code: MasterReq, + user_config: &VhostUserConfig, + fds: Option<&[RawFd]>, + ) -> VhostUserResult> { + if mem::size_of::() + user_config.size as usize > MAX_MSG_SIZE { + return Err(VhostUserError::InvalidParam); + } + self.check_state()?; + + let hdr = Self::new_request_header( + code, + mem::size_of::() as u32 + user_config.size, + ); + let mut buf = vec![0; user_config.size as usize]; + self.main_sock + .send_config_message(&hdr, user_config, &mut buf, fds)?; + Ok(hdr) + } + fn send_request_with_payload( &mut self, code: MasterReq, @@ -555,7 +576,7 @@ impl MasterInternal { if !reply.is_reply_for(hdr) || reply.get_size() as usize != mem::size_of::() + bytes || rfds.is_some() - || body.is_valid() + || !body.is_valid() { Endpoint::::close_rfds(rfds); return Err(VhostUserError::InvalidMessage);