diff options
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | Android.bp | 6 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | Cargo.toml.orig | 2 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | src/device/socket/connectionmanager.rs (renamed from src/device/socket/multiconnectionmanager.rs) | 12 | ||||
-rw-r--r-- | src/device/socket/mod.rs | 16 | ||||
-rw-r--r-- | src/device/socket/singleconnectionmanager.rs | 444 | ||||
-rw-r--r-- | src/queue.rs | 2 |
9 files changed, 28 insertions, 466 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index b5546f9..c6e71f9 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "94e013fd4cfb8ff5061e9fa9a4f43521b49679bb" + "sha1": "fd54a1b1c3d7c8bfe59c5a4f0dbe1ea981328116" }, "path_in_vcs": "" }
\ No newline at end of file @@ -22,10 +22,9 @@ license { rust_library_rlib { name: "libvirtio_drivers", - // has rustc warnings crate_name: "virtio_drivers", cargo_env_compat: true, - cargo_pkg_version: "0.6.0", + cargo_pkg_version: "0.7.0", srcs: ["src/lib.rs"], edition: "2018", features: ["alloc"], @@ -48,10 +47,9 @@ rust_library_rlib { rust_test { name: "virtio-drivers_test_src_lib", - // has rustc warnings crate_name: "virtio_drivers", cargo_env_compat: true, - cargo_pkg_version: "0.6.0", + cargo_pkg_version: "0.7.0", srcs: ["src/lib.rs"], test_suites: ["general-tests"], auto_gen_config: true, @@ -12,7 +12,7 @@ [package] edition = "2018" name = "virtio-drivers" -version = "0.6.0" +version = "0.7.0" authors = [ "Jiajie Chen <noc@jiegec.ac.cn>", "Runji Wang <wangrunji0408@163.com>", diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 8709240..9b216f6 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "virtio-drivers" -version = "0.6.0" +version = "0.7.0" license = "MIT" authors = [ "Jiajie Chen <noc@jiegec.ac.cn>", @@ -11,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/virtio-drivers/virtio-drivers-0.6.0.crate" + value: "https://static.crates.io/crates/virtio-drivers/virtio-drivers-0.7.0.crate" } - version: "0.6.0" + version: "0.7.0" license_type: NOTICE last_upgrade_date { year: 2023 - month: 7 - day: 27 + month: 10 + day: 6 } } diff --git a/src/device/socket/multiconnectionmanager.rs b/src/device/socket/connectionmanager.rs index 430f5e8..1a6915f 100644 --- a/src/device/socket/multiconnectionmanager.rs +++ b/src/device/socket/connectionmanager.rs @@ -226,6 +226,18 @@ impl<H: Hal, T: Transport> VsockConnectionManager<H, T> { Ok(bytes_read) } + /// Returns the number of bytes currently available in the recv buffer. + pub fn recv_buffer_available_bytes(&mut self, peer: VsockAddr, src_port: u32) -> Result<usize> { + let (_, connection) = get_connection(&mut self.connections, peer, src_port)?; + Ok(connection.buffer.available()) + } + + /// Sends a credit update to the given peer. + pub fn update_credit(&mut self, peer: VsockAddr, src_port: u32) -> Result { + let (_, connection) = get_connection(&mut self.connections, peer, src_port)?; + self.driver.credit_update(&connection.info) + } + /// Blocks until we get some event from the vsock device. pub fn wait_for_event(&mut self) -> Result<VsockEvent> { loop { diff --git a/src/device/socket/mod.rs b/src/device/socket/mod.rs index acc7def..8d2de2b 100644 --- a/src/device/socket/mod.rs +++ b/src/device/socket/mod.rs @@ -2,25 +2,21 @@ //! //! To use the driver, you should first create a [`VirtIOSocket`] instance with your VirtIO //! transport, and then create a [`VsockConnectionManager`] wrapping it to keep track of -//! connections. If you only want to have a single outgoing vsock connection at once, you can use -//! [`SingleConnectionManager`] for a slightly simpler interface. +//! connections. If you want to manage connections yourself you can use the `VirtIOSocket` directly +//! for a lower-level interface. //! //! See [`VsockConnectionManager`] for a usage example. -mod error; #[cfg(feature = "alloc")] -mod multiconnectionmanager; +mod connectionmanager; +mod error; mod protocol; #[cfg(feature = "alloc")] -mod singleconnectionmanager; -#[cfg(feature = "alloc")] mod vsock; -pub use error::SocketError; #[cfg(feature = "alloc")] -pub use multiconnectionmanager::VsockConnectionManager; +pub use connectionmanager::VsockConnectionManager; +pub use error::SocketError; pub use protocol::{VsockAddr, VMADDR_CID_HOST}; #[cfg(feature = "alloc")] -pub use singleconnectionmanager::SingleConnectionManager; -#[cfg(feature = "alloc")] pub use vsock::{DisconnectReason, VirtIOSocket, VsockEvent, VsockEventType}; diff --git a/src/device/socket/singleconnectionmanager.rs b/src/device/socket/singleconnectionmanager.rs deleted file mode 100644 index b5b21e4..0000000 --- a/src/device/socket/singleconnectionmanager.rs +++ /dev/null @@ -1,444 +0,0 @@ -use super::{ - protocol::VsockAddr, vsock::ConnectionInfo, SocketError, VirtIOSocket, VsockEvent, - VsockEventType, -}; -use crate::{transport::Transport, Hal, Result}; -use core::hint::spin_loop; -use log::debug; - -/// A higher level interface for VirtIO socket (vsock) devices. -/// -/// This can only keep track of a single vsock connection. If you want to support multiple -/// simultaneous connections, try [`VsockConnectionManager`](super::VsockConnectionManager). -pub struct SingleConnectionManager<H: Hal, T: Transport> { - driver: VirtIOSocket<H, T>, - connection_info: Option<ConnectionInfo>, -} - -impl<H: Hal, T: Transport> SingleConnectionManager<H, T> { - /// Construct a new connection manager wrapping the given low-level VirtIO socket driver. - pub fn new(driver: VirtIOSocket<H, T>) -> Self { - Self { - driver, - connection_info: None, - } - } - - /// Returns the CID which has been assigned to this guest. - pub fn guest_cid(&self) -> u64 { - self.driver.guest_cid() - } - - /// Sends a request to connect to the given destination. - /// - /// This returns as soon as the request is sent; you should wait until `poll_recv` returns a - /// `VsockEventType::Connected` event indicating that the peer has accepted the connection - /// before sending data. - pub fn connect(&mut self, destination: VsockAddr, src_port: u32) -> Result { - if self.connection_info.is_some() { - return Err(SocketError::ConnectionExists.into()); - } - - let new_connection_info = ConnectionInfo::new(destination, src_port); - - self.driver.connect(&new_connection_info)?; - debug!("Connection requested: {:?}", new_connection_info); - self.connection_info = Some(new_connection_info); - Ok(()) - } - - /// Sends the buffer to the destination. - pub fn send(&mut self, buffer: &[u8]) -> Result { - let connection_info = self - .connection_info - .as_mut() - .ok_or(SocketError::NotConnected)?; - connection_info.buf_alloc = 0; - self.driver.send(buffer, connection_info) - } - - /// Polls the vsock device to receive data or other updates. - /// - /// A buffer must be provided to put the data in if there is some to - /// receive. - pub fn poll_recv(&mut self, buffer: &mut [u8]) -> Result<Option<VsockEvent>> { - let Some(connection_info) = &mut self.connection_info else { - return Err(SocketError::NotConnected.into()); - }; - - // Tell the peer that we have space to receive some data. - connection_info.buf_alloc = buffer.len() as u32; - self.driver.credit_update(connection_info)?; - - self.poll_rx_queue(buffer) - } - - /// Blocks until we get some event from the vsock device. - /// - /// A buffer must be provided to put the data in if there is some to - /// receive. - pub fn wait_for_recv(&mut self, buffer: &mut [u8]) -> Result<VsockEvent> { - loop { - if let Some(event) = self.poll_recv(buffer)? { - return Ok(event); - } else { - spin_loop(); - } - } - } - - fn poll_rx_queue(&mut self, body: &mut [u8]) -> Result<Option<VsockEvent>> { - let guest_cid = self.driver.guest_cid(); - let self_connection_info = &mut self.connection_info; - - self.driver.poll(|event, borrowed_body| { - let Some(connection_info) = self_connection_info else { - return Ok(None); - }; - - // Skip packets which don't match our current connection. - if !event.matches_connection(connection_info, guest_cid) { - debug!( - "Skipping {:?} as connection is {:?}", - event, connection_info - ); - return Ok(None); - } - - // Update stored connection info. - connection_info.update_for_event(&event); - - match event.event_type { - VsockEventType::ConnectionRequest => { - // TODO: Send Rst or handle incoming connections. - } - VsockEventType::Connected => {} - VsockEventType::Disconnected { .. } => { - *self_connection_info = None; - } - VsockEventType::Received { length } => { - body.get_mut(0..length) - .ok_or(SocketError::OutputBufferTooShort(length))? - .copy_from_slice(borrowed_body); - connection_info.done_forwarding(length); - } - VsockEventType::CreditRequest => { - // No point sending a credit update until `poll_recv` is called with a buffer, - // as otherwise buf_alloc would just be 0 anyway. - } - VsockEventType::CreditUpdate => {} - } - - Ok(Some(event)) - }) - } - - /// Requests to shut down the connection cleanly. - /// - /// This returns as soon as the request is sent; you should wait until `poll_recv` returns a - /// `VsockEventType::Disconnected` event if you want to know that the peer has acknowledged the - /// shutdown. - pub fn shutdown(&mut self) -> Result { - let connection_info = self - .connection_info - .as_mut() - .ok_or(SocketError::NotConnected)?; - connection_info.buf_alloc = 0; - - self.driver.shutdown(connection_info) - } - - /// Forcibly closes the connection without waiting for the peer. - pub fn force_close(&mut self) -> Result { - let connection_info = self - .connection_info - .as_mut() - .ok_or(SocketError::NotConnected)?; - connection_info.buf_alloc = 0; - - self.driver.force_close(connection_info)?; - self.connection_info = None; - Ok(()) - } - - /// Blocks until the peer either accepts our connection request (with a - /// `VIRTIO_VSOCK_OP_RESPONSE`) or rejects it (with a - /// `VIRTIO_VSOCK_OP_RST`). - pub fn wait_for_connect(&mut self) -> Result { - loop { - match self.wait_for_recv(&mut [])?.event_type { - VsockEventType::Connected => return Ok(()), - VsockEventType::Disconnected { .. } => { - return Err(SocketError::ConnectionFailed.into()) - } - VsockEventType::Received { .. } => return Err(SocketError::InvalidOperation.into()), - VsockEventType::ConnectionRequest - | VsockEventType::CreditRequest - | VsockEventType::CreditUpdate => {} - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - device::socket::{ - protocol::{SocketType, VirtioVsockConfig, VirtioVsockHdr, VirtioVsockOp}, - vsock::{VsockBufferStatus, QUEUE_SIZE, RX_QUEUE_IDX, TX_QUEUE_IDX}, - }, - hal::fake::FakeHal, - transport::{ - fake::{FakeTransport, QueueStatus, State}, - DeviceType, - }, - volatile::ReadOnly, - }; - use alloc::{sync::Arc, vec}; - use core::{mem::size_of, ptr::NonNull}; - use std::{sync::Mutex, thread}; - use zerocopy::{AsBytes, FromBytes}; - - #[test] - fn send_recv() { - let host_cid = 2; - let guest_cid = 66; - let host_port = 1234; - let guest_port = 4321; - let host_address = VsockAddr { - cid: host_cid, - port: host_port, - }; - let hello_from_guest = "Hello from guest"; - let hello_from_host = "Hello from host"; - - let mut config_space = VirtioVsockConfig { - guest_cid_low: ReadOnly::new(66), - guest_cid_high: ReadOnly::new(0), - }; - let state = Arc::new(Mutex::new(State { - queues: vec![ - QueueStatus::default(), - QueueStatus::default(), - QueueStatus::default(), - ], - ..Default::default() - })); - let transport = FakeTransport { - device_type: DeviceType::Socket, - max_queue_size: 32, - device_features: 0, - config_space: NonNull::from(&mut config_space), - state: state.clone(), - }; - let mut socket = SingleConnectionManager::new( - VirtIOSocket::<FakeHal, FakeTransport<VirtioVsockConfig>>::new(transport).unwrap(), - ); - - // Start a thread to simulate the device. - let handle = thread::spawn(move || { - // Wait for connection request. - State::wait_until_queue_notified(&state, TX_QUEUE_IDX); - assert_eq!( - VirtioVsockHdr::read_from( - state - .lock() - .unwrap() - .read_from_queue::<QUEUE_SIZE>(TX_QUEUE_IDX) - .as_slice() - ) - .unwrap(), - VirtioVsockHdr { - op: VirtioVsockOp::Request.into(), - src_cid: guest_cid.into(), - dst_cid: host_cid.into(), - src_port: guest_port.into(), - dst_port: host_port.into(), - len: 0.into(), - socket_type: SocketType::Stream.into(), - flags: 0.into(), - buf_alloc: 0.into(), - fwd_cnt: 0.into(), - } - ); - - // Accept connection and give the peer enough credit to send the message. - state.lock().unwrap().write_to_queue::<QUEUE_SIZE>( - RX_QUEUE_IDX, - VirtioVsockHdr { - op: VirtioVsockOp::Response.into(), - src_cid: host_cid.into(), - dst_cid: guest_cid.into(), - src_port: host_port.into(), - dst_port: guest_port.into(), - len: 0.into(), - socket_type: SocketType::Stream.into(), - flags: 0.into(), - buf_alloc: 50.into(), - fwd_cnt: 0.into(), - } - .as_bytes(), - ); - - // Expect a credit update. - State::wait_until_queue_notified(&state, TX_QUEUE_IDX); - assert_eq!( - VirtioVsockHdr::read_from( - state - .lock() - .unwrap() - .read_from_queue::<QUEUE_SIZE>(TX_QUEUE_IDX) - .as_slice() - ) - .unwrap(), - VirtioVsockHdr { - op: VirtioVsockOp::CreditUpdate.into(), - src_cid: guest_cid.into(), - dst_cid: host_cid.into(), - src_port: guest_port.into(), - dst_port: host_port.into(), - len: 0.into(), - socket_type: SocketType::Stream.into(), - flags: 0.into(), - buf_alloc: 0.into(), - fwd_cnt: 0.into(), - } - ); - - // Expect the guest to send some data. - State::wait_until_queue_notified(&state, TX_QUEUE_IDX); - let request = state - .lock() - .unwrap() - .read_from_queue::<QUEUE_SIZE>(TX_QUEUE_IDX); - assert_eq!( - request.len(), - size_of::<VirtioVsockHdr>() + hello_from_guest.len() - ); - assert_eq!( - VirtioVsockHdr::read_from_prefix(request.as_slice()).unwrap(), - VirtioVsockHdr { - op: VirtioVsockOp::Rw.into(), - src_cid: guest_cid.into(), - dst_cid: host_cid.into(), - src_port: guest_port.into(), - dst_port: host_port.into(), - len: (hello_from_guest.len() as u32).into(), - socket_type: SocketType::Stream.into(), - flags: 0.into(), - buf_alloc: 0.into(), - fwd_cnt: 0.into(), - } - ); - assert_eq!( - &request[size_of::<VirtioVsockHdr>()..], - hello_from_guest.as_bytes() - ); - - // Send a response. - let mut response = vec![0; size_of::<VirtioVsockHdr>() + hello_from_host.len()]; - VirtioVsockHdr { - op: VirtioVsockOp::Rw.into(), - src_cid: host_cid.into(), - dst_cid: guest_cid.into(), - src_port: host_port.into(), - dst_port: guest_port.into(), - len: (hello_from_host.len() as u32).into(), - socket_type: SocketType::Stream.into(), - flags: 0.into(), - buf_alloc: 50.into(), - fwd_cnt: (hello_from_guest.len() as u32).into(), - } - .write_to_prefix(response.as_mut_slice()); - response[size_of::<VirtioVsockHdr>()..].copy_from_slice(hello_from_host.as_bytes()); - state - .lock() - .unwrap() - .write_to_queue::<QUEUE_SIZE>(RX_QUEUE_IDX, &response); - - // Expect a credit update. - State::wait_until_queue_notified(&state, TX_QUEUE_IDX); - assert_eq!( - VirtioVsockHdr::read_from( - state - .lock() - .unwrap() - .read_from_queue::<QUEUE_SIZE>(TX_QUEUE_IDX) - .as_slice() - ) - .unwrap(), - VirtioVsockHdr { - op: VirtioVsockOp::CreditUpdate.into(), - src_cid: guest_cid.into(), - dst_cid: host_cid.into(), - src_port: guest_port.into(), - dst_port: host_port.into(), - len: 0.into(), - socket_type: SocketType::Stream.into(), - flags: 0.into(), - buf_alloc: 64.into(), - fwd_cnt: 0.into(), - } - ); - - // Expect a shutdown. - State::wait_until_queue_notified(&state, TX_QUEUE_IDX); - assert_eq!( - VirtioVsockHdr::read_from( - state - .lock() - .unwrap() - .read_from_queue::<QUEUE_SIZE>(TX_QUEUE_IDX) - .as_slice() - ) - .unwrap(), - VirtioVsockHdr { - op: VirtioVsockOp::Shutdown.into(), - src_cid: guest_cid.into(), - dst_cid: host_cid.into(), - src_port: guest_port.into(), - dst_port: host_port.into(), - len: 0.into(), - socket_type: SocketType::Stream.into(), - flags: 0.into(), - buf_alloc: 0.into(), - fwd_cnt: (hello_from_host.len() as u32).into(), - } - ); - }); - - socket.connect(host_address, guest_port).unwrap(); - socket.wait_for_connect().unwrap(); - socket.send(hello_from_guest.as_bytes()).unwrap(); - let mut buffer = [0u8; 64]; - let event = socket.wait_for_recv(&mut buffer).unwrap(); - assert_eq!( - event, - VsockEvent { - source: VsockAddr { - cid: host_cid, - port: host_port, - }, - destination: VsockAddr { - cid: guest_cid, - port: guest_port, - }, - event_type: VsockEventType::Received { - length: hello_from_host.len() - }, - buffer_status: VsockBufferStatus { - buffer_allocation: 50, - forward_count: hello_from_guest.len() as u32, - }, - } - ); - assert_eq!( - &buffer[0..hello_from_host.len()], - hello_from_host.as_bytes() - ); - socket.shutdown().unwrap(); - - handle.join().unwrap(); - } -} diff --git a/src/queue.rs b/src/queue.rs index dcafcbc..3257b35 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -944,7 +944,7 @@ mod tests { transport::{ fake::{FakeTransport, QueueStatus, State}, mmio::{MmioTransport, VirtIOHeader, MODERN_VERSION}, - DeviceStatus, DeviceType, + DeviceType, }, }; use core::ptr::NonNull; |