use std::os::fd::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd};
use super::ffi;
use crate::error::Error;
use crate::sockopt::raw_setsockopt;
pub(crate) fn create_xdp_socket() -> Result<OwnedFd, Error> {
let fd = unsafe {
libc::socket(ffi::AF_XDP, libc::SOCK_RAW | libc::SOCK_CLOEXEC, 0)
};
if fd == -1 {
let err = std::io::Error::last_os_error();
return match err.raw_os_error() {
Some(libc::EPERM | libc::EACCES) => Err(Error::PermissionDenied),
_ => Err(Error::Socket(err)),
};
}
Ok(unsafe { OwnedFd::from_raw_fd(fd) })
}
pub(crate) fn register_umem(fd: BorrowedFd<'_>, reg: &ffi::xdp_umem_reg) -> Result<(), Error> {
raw_setsockopt(fd, ffi::SOL_XDP, ffi::XDP_UMEM_REG, reg, "XDP_UMEM_REG")
}
pub(crate) fn set_ring_size(
fd: BorrowedFd<'_>,
opt: libc::c_int,
size: u32,
option_name: &'static str,
) -> Result<(), Error> {
raw_setsockopt(fd, ffi::SOL_XDP, opt, &size, option_name)
}
pub(crate) fn get_mmap_offsets(fd: BorrowedFd<'_>) -> Result<ffi::xdp_mmap_offsets, Error> {
let mut offsets: ffi::xdp_mmap_offsets = unsafe { std::mem::zeroed() };
let mut len = std::mem::size_of::<ffi::xdp_mmap_offsets>() as libc::socklen_t;
let ret = unsafe {
libc::getsockopt(
fd.as_raw_fd(),
ffi::SOL_XDP,
ffi::XDP_MMAP_OFFSETS,
(&mut offsets as *mut ffi::xdp_mmap_offsets).cast(),
&mut len,
)
};
if ret == -1 {
Err(Error::SockOpt {
option: "XDP_MMAP_OFFSETS",
source: std::io::Error::last_os_error(),
})
} else {
Ok(offsets)
}
}
pub(crate) fn bind_xdp(
fd: BorrowedFd<'_>,
ifindex: u32,
queue_id: u32,
flags: u16,
) -> Result<(), Error> {
let sxdp = ffi::sockaddr_xdp {
sxdp_family: ffi::AF_XDP as u16,
sxdp_flags: flags,
sxdp_ifindex: ifindex,
sxdp_queue_id: queue_id,
sxdp_shared_umem_fd: 0,
};
let ret = unsafe {
libc::bind(
fd.as_raw_fd(),
(&sxdp as *const ffi::sockaddr_xdp).cast(),
std::mem::size_of::<ffi::sockaddr_xdp>() as libc::socklen_t,
)
};
if ret == -1 {
Err(Error::Bind(std::io::Error::last_os_error()))
} else {
Ok(())
}
}
pub(crate) fn get_statistics(fd: BorrowedFd<'_>) -> Result<ffi::xdp_statistics, Error> {
let mut stats: ffi::xdp_statistics = unsafe { std::mem::zeroed() };
let mut len = std::mem::size_of::<ffi::xdp_statistics>() as libc::socklen_t;
let ret = unsafe {
libc::getsockopt(
fd.as_raw_fd(),
ffi::SOL_XDP,
ffi::XDP_STATISTICS,
(&mut stats as *mut ffi::xdp_statistics).cast(),
&mut len,
)
};
if ret == -1 {
Err(Error::SockOpt {
option: "XDP_STATISTICS",
source: std::io::Error::last_os_error(),
})
} else {
Ok(stats)
}
}