use std::num::Wrapping;
use std::os::unix::io::OwnedFd;
use super::RxOps;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct VsockConnectionId {
pub host_port: u32,
pub guest_port: u32,
}
pub const TX_BUFFER_SIZE: u32 = 64 * 1024;
pub const CREDIT_UPDATE_THRESHOLD: u32 = 4096;
pub const VSOCK_SHUTDOWN_F_RECEIVE: u32 = 1 << 0;
pub const VSOCK_SHUTDOWN_F_SEND: u32 = 1 << 1;
pub const VSOCK_SHUTDOWN_F_BOTH: u32 = VSOCK_SHUTDOWN_F_RECEIVE | VSOCK_SHUTDOWN_F_SEND;
pub struct VsockConnection {
pub id: VsockConnectionId,
pub internal_fd: OwnedFd,
pub injected_notify: Option<std::sync::mpsc::Sender<()>>,
pub guest_cid: u64,
pub connect: bool,
pub rx_queue: RxOps,
pub fwd_cnt: Wrapping<u32>,
last_fwd_cnt: Wrapping<u32>,
pub peer_buf_alloc: u32,
pub peer_fwd_cnt: Wrapping<u32>,
pub rx_cnt: Wrapping<u32>,
credit_request_pending: bool,
peer_no_recv: bool,
}
impl VsockConnection {
pub fn new_local_init(
id: VsockConnectionId,
guest_cid: u64,
fd: OwnedFd,
injected_notify: std::sync::mpsc::Sender<()>,
) -> Self {
let mut conn = Self {
id,
internal_fd: fd,
guest_cid,
connect: false,
injected_notify: Some(injected_notify),
rx_queue: RxOps::default(),
fwd_cnt: Wrapping(0),
last_fwd_cnt: Wrapping(0),
peer_buf_alloc: 0,
peer_fwd_cnt: Wrapping(0),
rx_cnt: Wrapping(0),
credit_request_pending: false,
peer_no_recv: false,
};
conn.rx_queue.enqueue(RxOps::REQUEST);
conn
}
pub fn peer_avail_credit(&self) -> usize {
(Wrapping(self.peer_buf_alloc) - (self.rx_cnt - self.peer_fwd_cnt)).0 as usize
}
pub fn update_peer_credit(&mut self, buf_alloc: u32, fwd_cnt: u32) {
self.peer_buf_alloc = buf_alloc;
self.peer_fwd_cnt = Wrapping(fwd_cnt);
self.credit_request_pending = false;
}
pub fn maybe_request_credit(&mut self) {
if self.credit_request_pending || self.peer_buf_alloc == 0 {
return;
}
let half = (self.peer_buf_alloc / 2) as usize;
if self.peer_avail_credit() < half {
self.rx_queue.enqueue(RxOps::CREDIT_REQUEST);
self.credit_request_pending = true;
}
}
pub fn note_credit_request_sent(&mut self) {
self.credit_request_pending = true;
}
#[must_use]
pub fn credit_request_pending(&self) -> bool {
self.credit_request_pending
}
pub fn mark_peer_no_recv(&mut self) {
self.peer_no_recv = true;
}
#[must_use]
pub const fn peer_no_recv(&self) -> bool {
self.peer_no_recv
}
#[must_use]
pub const fn accepts_data(&self) -> bool {
self.connect && !self.peer_no_recv
}
pub fn advance_fwd_cnt(&mut self, bytes: u32) {
self.fwd_cnt += Wrapping(bytes);
let consumed = (self.fwd_cnt - self.last_fwd_cnt).0;
if consumed >= CREDIT_UPDATE_THRESHOLD {
self.rx_queue.enqueue(RxOps::CREDIT_UPDATE);
}
}
pub fn record_rx(&mut self, bytes: u32) {
self.rx_cnt += Wrapping(bytes);
}
pub fn mark_credit_sent(&mut self) {
self.last_fwd_cnt = self.fwd_cnt;
}
}