wireshift-uring 0.1.1

Native Linux io_uring backend for wireshift
Documentation
#![allow(clippy::unnecessary_wraps)]
use std::os::fd::AsRawFd;

use io_uring::{opcode, types};
use wireshift_core::op::OpDescriptor;
use wireshift_core::{Error, Result};

use super::PreparedEntry;
use crate::file_registry::FileRegistryTable;
use crate::types::InflightData;

pub(crate) fn build_read(
    descriptor: &OpDescriptor,
    id: u64,
    fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
    let OpDescriptor::Read {
        file,
        offset,
        buffer,
        len,
    } = descriptor
    else {
        unreachable!()
    };
    let read_len = len.unwrap_or_else(|| buffer.capacity());
    let len_u32 = u32::try_from(read_len).map_err(|_| {
        Error::validation(
            "read buffer length exceeds io_uring's u32 limit",
            "use smaller buffers for native io_uring reads",
        )
    })?;
    let entry = if let Some(slot) = fixed_files.lookup(file.as_raw_fd()) {
        opcode::Read::new(
            types::Fixed(slot),
            buffer.backend_ref().as_ptr().cast_mut(),
            len_u32,
        )
    } else {
        opcode::Read::new(
            types::Fd(file.as_raw_fd()),
            buffer.backend_ref().as_ptr().cast_mut(),
            len_u32,
        )
    }
    .offset(*offset)
    .build()
    .user_data(id);
    Ok(vec![PreparedEntry {
        entry,
        pinned: InflightData::None,
        link_to_next: None,
    }])
}

pub(crate) fn build_read_fixed(
    descriptor: &OpDescriptor,
    id: u64,
    _fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
    let OpDescriptor::ReadFixed {
        slot,
        offset,
        buffer,
    } = descriptor
    else {
        unreachable!()
    };
    let len = u32::try_from(buffer.capacity()).map_err(|_| {
        Error::validation(
            "read buffer length exceeds io_uring's u32 limit",
            "use smaller buffers for native io_uring reads",
        )
    })?;
    let entry = opcode::Read::new(
        types::Fixed(*slot),
        buffer.backend_ref().as_ptr().cast_mut(),
        len,
    )
    .offset(*offset)
    .build()
    .user_data(id);
    Ok(vec![PreparedEntry {
        entry,
        pinned: InflightData::None,
        link_to_next: None,
    }])
}

pub(crate) fn build_read_gpu(
    descriptor: &OpDescriptor,
    id: u64,
    fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
    let OpDescriptor::ReadGpu {
        file,
        offset,
        buffer,
    } = descriptor
    else {
        unreachable!()
    };
    let len = u32::try_from(buffer.capacity()).map_err(|_| {
        Error::validation(
            "gpu staging buffer length exceeds io_uring's u32 limit",
            "use smaller buffers for native GPU-staged reads",
        )
    })?;
    let entry = if let Some(slot) = fixed_files.lookup(file.as_raw_fd()) {
        opcode::Read::new(
            types::Fixed(slot),
            buffer.as_slice().as_ptr().cast_mut(),
            len,
        )
    } else {
        opcode::Read::new(
            types::Fd(file.as_raw_fd()),
            buffer.as_slice().as_ptr().cast_mut(),
            len,
        )
    }
    .offset(*offset)
    .build()
    .user_data(id);
    Ok(vec![PreparedEntry {
        entry,
        pinned: InflightData::None,
        link_to_next: None,
    }])
}

pub(crate) fn build_write(
    descriptor: &OpDescriptor,
    id: u64,
    fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
    let OpDescriptor::Write {
        file,
        offset,
        buffer,
    } = descriptor
    else {
        unreachable!()
    };
    let len = u32::try_from(buffer.filled_len()).map_err(|_| {
        Error::validation(
            "write buffer length exceeds io_uring's u32 limit",
            "use smaller buffers for native io_uring writes",
        )
    })?;
    let entry = if let Some(slot) = fixed_files.lookup(file.as_raw_fd()) {
        opcode::Write::new(types::Fixed(slot), buffer.backend_ref().as_ptr(), len)
    } else {
        opcode::Write::new(
            types::Fd(file.as_raw_fd()),
            buffer.backend_ref().as_ptr(),
            len,
        )
    }
    .offset(*offset)
    .build()
    .user_data(id);
    Ok(vec![PreparedEntry {
        entry,
        pinned: InflightData::None,
        link_to_next: None,
    }])
}

pub(crate) fn build_read_vectored(
    descriptor: &OpDescriptor,
    id: u64,
    fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
    let OpDescriptor::ReadVectored {
        file,
        offset,
        buffers,
    } = descriptor
    else {
        unreachable!()
    };
    let iovecs: Vec<libc::iovec> = buffers
        .iter()
        .map(|buf| libc::iovec {
            iov_base: buf.backend_ref().as_ptr().cast_mut().cast::<libc::c_void>(),
            iov_len: buf.capacity(),
        })
        .collect();
    let entry = if let Some(slot) = fixed_files.lookup(file.as_raw_fd()) {
        opcode::Readv::new(
            types::Fixed(slot),
            iovecs.as_ptr().cast(),
            iovecs.len() as u32,
        )
    } else {
        opcode::Readv::new(
            types::Fd(file.as_raw_fd()),
            iovecs.as_ptr().cast(),
            iovecs.len() as u32,
        )
    }
    .offset(*offset)
    .build()
    .user_data(id);
    Ok(vec![PreparedEntry {
        entry,
        pinned: InflightData::Iovec(iovecs),
        link_to_next: None,
    }])
}

pub(crate) fn build_write_vectored(
    descriptor: &OpDescriptor,
    id: u64,
    fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
    let OpDescriptor::WriteVectored {
        file,
        offset,
        buffers,
    } = descriptor
    else {
        unreachable!()
    };
    let iovecs: Vec<libc::iovec> = buffers
        .iter()
        .map(|buf| libc::iovec {
            iov_base: buf.backend_ref().as_ptr().cast_mut().cast::<libc::c_void>(),
            iov_len: buf.filled_len(),
        })
        .collect();
    let entry = if let Some(slot) = fixed_files.lookup(file.as_raw_fd()) {
        opcode::Writev::new(
            types::Fixed(slot),
            iovecs.as_ptr().cast(),
            iovecs.len() as u32,
        )
    } else {
        opcode::Writev::new(
            types::Fd(file.as_raw_fd()),
            iovecs.as_ptr().cast(),
            iovecs.len() as u32,
        )
    }
    .offset(*offset)
    .build()
    .user_data(id);
    Ok(vec![PreparedEntry {
        entry,
        pinned: InflightData::Iovec(iovecs),
        link_to_next: None,
    }])
}