use alloc::{boxed::Box, string::String, vec::Vec};
use ax_lazyinit::OnceLock;
use ax_sync::MutexGuard;
use irq_framework::IrqId;
use rdif_vsock::{Interface, VsockAddr, VsockConnId, VsockError, VsockIrqEndpoints};
use crate::{NetError, NetResult, PinnedNetIrqRegistrar};
mod irq_runtime;
use irq_runtime::VsockIrqRuntime;
pub use irq_runtime::VsockRuntimeError;
pub type VsockDevice = Box<dyn Interface>;
pub type VsockDeviceList = Vec<VsockDeviceInput>;
pub struct VsockDeviceInput {
pub name: String,
pub device: VsockDevice,
pub irq: IrqId,
pub endpoints: VsockIrqEndpoints,
}
static VSOCK_RUNTIME: OnceLock<VsockIrqRuntime> = OnceLock::new();
pub fn init_vsock_device(
mut devices: VsockDeviceList,
registrar: &dyn PinnedNetIrqRegistrar,
owner_cpu: usize,
topology_len: usize,
) -> Result<(), VsockRuntimeError> {
if devices.is_empty() {
return Ok(());
}
if devices.len() != 1 || VSOCK_RUNTIME.get().is_some() {
return Err(VsockRuntimeError::InvalidTopology);
}
let input = devices.pop().expect("one validated vsock input must exist");
let runtime = VsockIrqRuntime::start(input, registrar, owner_cpu, topology_len)?;
VSOCK_RUNTIME.call_once(|| runtime);
Ok(())
}
fn device() -> NetResult<MutexGuard<'static, VsockDevice>> {
let runtime = VSOCK_RUNTIME.get().ok_or(NetError::NotFound)?;
Ok(runtime.device().lock())
}
pub(crate) fn request_vsock_work() {
if let Some(runtime) = VSOCK_RUNTIME.get() {
runtime.request_task_work();
}
}
pub fn vsock_listen(addr: VsockAddr) -> NetResult<()> {
device()?.listen(addr.port).map_err(map_vsock_error)
}
fn map_vsock_error(e: VsockError) -> NetError {
match e {
VsockError::AlreadyExists => NetError::AlreadyExists,
VsockError::Retry => NetError::WouldBlock,
VsockError::NotConnected => NetError::NotConnected,
VsockError::NotAvailable => NetError::NotFound,
VsockError::NotSupported => NetError::Unsupported,
VsockError::Other(_) => NetError::BadState,
}
}
pub fn vsock_connect(conn_id: VsockConnId) -> NetResult<()> {
device()?.connect(conn_id).map_err(map_vsock_error)
}
pub fn vsock_send(conn_id: VsockConnId, buf: &[u8]) -> NetResult<usize> {
device()?.send(conn_id, buf).map_err(map_vsock_error)
}
pub fn vsock_send_capacity(conn_id: VsockConnId) -> NetResult<usize> {
device()?.send_capacity(conn_id).map_err(map_vsock_error)
}
pub fn vsock_disconnect(conn_id: VsockConnId) -> NetResult<()> {
device()?.disconnect(conn_id).map_err(map_vsock_error)
}
pub fn vsock_guest_cid() -> NetResult<u64> {
Ok(device()?.guest_cid())
}