Skip to main content

arcbox_virtio_vsock/
addr.rs

1//! Vsock address type + host-side connection-manager trait.
2
3use std::os::unix::io::RawFd;
4
5/// Well-known CID for the host.
6pub const HOST_CID: u64 = 2;
7
8/// Reserved CID — must not be used by guests.
9pub const RESERVED_CID: u64 = 1;
10
11/// Vsock address.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub struct VsockAddr {
14    /// Context Identifier.
15    pub cid: u64,
16    /// Port number.
17    pub port: u32,
18}
19
20impl VsockAddr {
21    /// Creates a new vsock address.
22    #[must_use]
23    pub const fn new(cid: u64, port: u32) -> Self {
24        Self { cid, port }
25    }
26
27    /// Returns the host address for a given port.
28    #[must_use]
29    pub const fn host(port: u32) -> Self {
30        Self::new(HOST_CID, port)
31    }
32}
33
34/// Abstracts host-side vsock connection tracking for the HV backend.
35///
36/// The VZ backend handles connections natively via Virtualization.framework.
37/// For the HV backend, a concrete `VsockConnectionManager` (in arcbox-vmm)
38/// implements this trait and is shared with `VirtioVsock` via `bind_connections`.
39pub trait VsockHostConnections: Send + Sync {
40    /// Returns the host fd for a connection identified by (`guest_port`, `host_port`).
41    fn fd_for(&self, guest_port: u32, host_port: u32) -> Option<RawFd>;
42
43    /// Marks a connection as established (called when `OP_RESPONSE` is received).
44    fn mark_connected(&mut self, guest_port: u32, host_port: u32);
45
46    /// Removes a connection and closes the associated fd (called on `OP_RST`).
47    fn remove_connection(&mut self, guest_port: u32, host_port: u32);
48
49    /// Updates peer credit state from an incoming guest packet.
50    /// Called for every TX packet to keep credit info in sync.
51    fn update_peer_credit(
52        &mut self,
53        _guest_port: u32,
54        _host_port: u32,
55        _buf_alloc: u32,
56        _fwd_cnt: u32,
57    ) {
58    }
59
60    /// Advances `fwd_cnt` after writing guest data to the host stream.
61    /// Returns `true` if the host has pending RX data as a result (`CreditUpdate`).
62    fn advance_fwd_cnt(&mut self, _guest_port: u32, _host_port: u32, _bytes: u32) -> bool {
63        false
64    }
65
66    /// Enqueues a `CreditUpdate` to be sent on the next RX fill.
67    fn enqueue_credit_update(&mut self, _guest_port: u32, _host_port: u32) {}
68
69    /// Handles a guest-originated `OP_SHUTDOWN` with its flags bitmask.
70    ///
71    /// Per the vsock spec, `flags` carries two bits:
72    /// - `VSOCK_SHUTDOWN_F_RECEIVE` (bit 0) — peer won't receive more data.
73    /// - `VSOCK_SHUTDOWN_F_SEND` (bit 1) — peer won't send more data.
74    ///
75    /// The default behaviour mirrors `RST` (full teardown), which is correct
76    /// when both bits are set; concrete managers override to handle half-close
77    /// cases that should preserve the connection.
78    fn handle_shutdown(&mut self, guest_port: u32, host_port: u32, _flags: u32) {
79        self.remove_connection(guest_port, host_port);
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_vsock_addr_new() {
89        let addr = VsockAddr::new(3, 1234);
90        assert_eq!(addr.cid, 3);
91        assert_eq!(addr.port, 1234);
92    }
93
94    #[test]
95    fn test_vsock_addr_host() {
96        let addr = VsockAddr::host(8080);
97        assert_eq!(addr.cid, HOST_CID);
98        assert_eq!(addr.cid, 2);
99        assert_eq!(addr.port, 8080);
100    }
101
102    #[test]
103    #[allow(clippy::clone_on_copy)]
104    fn test_vsock_addr_clone_copy() {
105        let addr = VsockAddr::new(10, 5000);
106        let cloned = addr.clone();
107        let copied = addr;
108
109        assert_eq!(cloned.cid, 10);
110        assert_eq!(copied.port, 5000);
111    }
112
113    #[test]
114    fn test_vsock_addr_eq() {
115        let addr1 = VsockAddr::new(3, 1234);
116        let addr2 = VsockAddr::new(3, 1234);
117        let addr3 = VsockAddr::new(3, 5678);
118
119        assert_eq!(addr1, addr2);
120        assert_ne!(addr1, addr3);
121    }
122
123    #[test]
124    fn test_vsock_addr_hash() {
125        use std::collections::HashSet;
126
127        let mut set = HashSet::new();
128        set.insert(VsockAddr::new(3, 1234));
129        set.insert(VsockAddr::new(3, 1234)); // Duplicate
130        set.insert(VsockAddr::new(4, 1234));
131
132        assert_eq!(set.len(), 2);
133    }
134
135    #[test]
136    fn test_vsock_constants() {
137        assert_eq!(HOST_CID, 2);
138        assert_eq!(RESERVED_CID, 1);
139    }
140}