diff --git a/vm-virtio/src/vsock/csm/connection.rs b/vm-virtio/src/vsock/csm/connection.rs index a42794c6a..6770870b2 100644 --- a/vm-virtio/src/vsock/csm/connection.rs +++ b/vm-virtio/src/vsock/csm/connection.rs @@ -557,7 +557,7 @@ where /// Raw data can either be sent straight to the host stream, or to our TX buffer, if the /// former fails. /// - fn send_bytes(&mut self, buf: &[u8]) -> Result<()> { + pub fn send_bytes(&mut self, buf: &[u8]) -> Result<()> { // If there is data in the TX buffer, that means we're already registered for EPOLLOUT // events on the underlying stream. Therefore, there's no point in attempting a write // at this point. `self.notify()` will get called when EPOLLOUT arrives, and it will @@ -592,6 +592,11 @@ where Ok(()) } + /// Return the connections state. + pub fn state(&self) -> ConnState { + self.state + } + /// Check if the credit information the peer has last received from us is outdated. /// fn peer_needs_credit_update(&self) -> bool { diff --git a/vm-virtio/src/vsock/csm/mod.rs b/vm-virtio/src/vsock/csm/mod.rs index a6bd7071a..635b7931b 100644 --- a/vm-virtio/src/vsock/csm/mod.rs +++ b/vm-virtio/src/vsock/csm/mod.rs @@ -38,7 +38,7 @@ type Result = std::result::Result; /// A vsock connection state. /// -#[derive(Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum ConnState { /// The connection has been initiated by the host end, but is yet to be confirmed by the guest. LocalInit, diff --git a/vm-virtio/src/vsock/unix/muxer.rs b/vm-virtio/src/vsock/unix/muxer.rs index 2e6f8943b..88af69d45 100644 --- a/vm-virtio/src/vsock/unix/muxer.rs +++ b/vm-virtio/src/vsock/unix/muxer.rs @@ -36,6 +36,7 @@ use std::io::Read; use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::net::{UnixListener, UnixStream}; +use super::super::csm::ConnState; use super::super::defs::uapi; use super::super::packet::VsockPacket; use super::super::{ @@ -652,9 +653,20 @@ impl VsockMuxer { if let Some(conn) = self.conn_map.get_mut(&key) { let had_rx = conn.has_pending_rx(); let was_expiring = conn.will_expire(); + let prev_state = conn.state(); mut_fn(conn); + // If this is a host-initiated connection that has just become established, we'll have + // to send an ack message to the host end. + if prev_state == ConnState::LocalInit && conn.state() == ConnState::Established { + conn.send_bytes(format!("OK {}\n", key.local_port).as_bytes()) + .unwrap_or_else(|err| { + conn.kill(); + warn!("vsock: unable to ack host connection: {:?}", err); + }); + } + // If the connection wasn't previously scheduled for RX, add it to our RX queue. if !had_rx && conn.has_pending_rx() { self.rxq.push(MuxerRx::ConnRx(key)); @@ -917,6 +929,10 @@ mod tests { self.init_pkt(local_port, peer_port, uapi::VSOCK_OP_RESPONSE); self.send(); + let mut buf = vec![0u8; 32]; + let len = stream.read(&mut buf[..]).unwrap(); + assert_eq!(&buf[..len], format!("OK {}\n", local_port).as_bytes()); + (stream, local_port) } }