diff --git a/vm-virtio/src/vsock/csm/connection.rs b/vm-virtio/src/vsock/csm/connection.rs index 4735b4b27..bbcc06e4d 100644 --- a/vm-virtio/src/vsock/csm/connection.rs +++ b/vm-virtio/src/vsock/csm/connection.rs @@ -571,12 +571,29 @@ where self.pending_rx.insert(PendingRx::Rst); } + /// Return the connections state. + /// + pub fn state(&self) -> ConnState { + self.state + } + + /// Send some raw, untracked, data straight to the underlying connected stream. + /// Returns: number of bytes written, or the error describing the write failure. + /// + /// Warning: this will bypass the connection state machine and write directly to the + /// underlying stream. No account of this write is kept, which includes bypassing + /// vsock flow control. + /// + pub fn send_bytes_raw(&mut self, buf: &[u8]) -> Result { + self.stream.write(buf).map_err(Error::StreamWrite) + } + /// Send some raw data (a byte-slice) to the host stream. /// /// Raw data can either be sent straight to the host stream, or to our TX buffer, if the /// former fails. /// - pub fn send_bytes(&mut self, buf: &[u8]) -> Result<()> { + 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 @@ -611,11 +628,6 @@ 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/unix/muxer.rs b/vm-virtio/src/vsock/unix/muxer.rs index b2f57c285..e1aec2d8c 100644 --- a/vm-virtio/src/vsock/unix/muxer.rs +++ b/vm-virtio/src/vsock/unix/muxer.rs @@ -682,11 +682,20 @@ impl VsockMuxer { // 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| { + let msg = format!("OK {}\n", key.local_port); + match conn.send_bytes_raw(msg.as_bytes()) { + Ok(written) if written == msg.len() => (), + Ok(_) => { + // If we can't write a dozen bytes to a pristine connection something + // must be really wrong. Killing it. + conn.kill(); + warn!("vsock: unable to fully write connection ack msg."); + } + Err(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.