summaryrefslogtreecommitdiffhomepage
path: root/src/platform/linux
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/linux')
-rw-r--r--src/platform/linux/libc_s.rs95
-rw-r--r--src/platform/linux/rxring.rs111
2 files changed, 132 insertions, 74 deletions
diff --git a/src/platform/linux/libc_s.rs b/src/platform/linux/libc_s.rs
new file mode 100644
index 0000000..f599ed0
--- /dev/null
+++ b/src/platform/linux/libc_s.rs
@@ -0,0 +1,95 @@
+// SPDX-FileCopyrightText: 2026 Dilluti0n <[email protected]>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+use std::os::fd::{OwnedFd, RawFd, FromRawFd};
+use std::io::Error;
+
+use std::ffi::{c_int, c_void};
+use std::mem;
+
+macro_rules! syscall {
+ ($call:expr) => {
+ match $call {
+ -1 => Err(::std::io::Error::last_os_error()),
+ res => Ok(res),
+ }
+ };
+}
+
+#[allow(non_camel_case_types)]
+pub enum FcntlArg {
+ F_GETFL,
+ F_SETFL(c_int),
+}
+
+pub fn fcntl(fd: RawFd, op: FcntlArg) -> Result<c_int, Error> {
+ use libc::fcntl;
+
+ syscall!(match op {
+ FcntlArg::F_GETFL => unsafe { fcntl(fd, libc::F_GETFL) },
+ FcntlArg::F_SETFL(flags) => unsafe { fcntl(fd, libc::F_SETFL, flags) }
+ })
+}
+
+pub fn flock(fd: RawFd, op: c_int) -> Result<(), Error> {
+ syscall!(unsafe { libc::flock(fd, op) }).map(drop)
+}
+
+pub fn geteuid() -> libc::uid_t {
+ unsafe { libc::geteuid() }
+}
+
+pub fn poll(fds: &mut [libc::pollfd], timeout: c_int) -> Result<(), Error> {
+ syscall!(unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as _, timeout) }).map(drop)
+}
+
+unsafe fn setsockopt_1<T>(sockfd: RawFd, level: c_int, optname: c_int, optval: &T) -> c_int {
+ unsafe {
+ libc::setsockopt(sockfd, level, optname,
+ (optval as *const T).cast() as *const c_void,
+ mem::size_of::<T>() as libc::socklen_t)
+ }
+}
+
+#[allow(non_camel_case_types)]
+pub enum SockOpt<'a> {
+ SO_ATTACH_FILTER(&'a [libc::sock_filter]),
+ PACKET_RX_RING(&'a libc::tpacket_req),
+}
+
+pub fn setsockopt(sockfd: RawFd, opt: SockOpt) -> Result<(), Error> {
+ syscall!(match opt {
+ SockOpt::SO_ATTACH_FILTER(val) => {
+ let prog = libc::sock_fprog {
+ len: val.len() as u16,
+ filter: val.as_ptr() as *mut libc::sock_filter
+ };
+
+ unsafe {setsockopt_1(sockfd, libc::SOL_SOCKET, libc::SO_ATTACH_FILTER, &prog)}
+ },
+ SockOpt::PACKET_RX_RING(optval) => unsafe {
+ setsockopt_1(sockfd, libc::SOL_PACKET, libc::PACKET_RX_RING, optval)
+ }
+ }).map(drop)
+}
+
+pub fn socket(domain: c_int, so_type: c_int, protocol: c_int) -> Result<OwnedFd, Error> {
+ unsafe {
+ let raw = syscall!(libc::socket(domain, so_type, protocol))?;
+ Ok(OwnedFd::from_raw_fd(raw))
+ }
+}
+
+pub unsafe fn mmap(
+ addr: *mut c_void, length: usize, prot: c_int,
+ flags: c_int, fd: RawFd, offset: libc::off_t
+) -> Result<*mut c_void, Error> {
+ match unsafe {libc::mmap(addr, length, prot, flags, fd, offset)} {
+ libc::MAP_FAILED => Err(Error::last_os_error()),
+ res => Ok(res),
+ }
+}
+
+pub unsafe fn munmap(addr: *mut c_void, length: usize) -> Result<(), Error> {
+ syscall!(unsafe { libc::munmap(addr, length) }).map(drop)
+}
diff --git a/src/platform/linux/rxring.rs b/src/platform/linux/rxring.rs
index e5066dd..0249b9f 100644
--- a/src/platform/linux/rxring.rs
+++ b/src/platform/linux/rxring.rs
@@ -1,10 +1,14 @@
// SPDX-FileCopyrightText: 2026 Dilluti0n <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later
-use std::os::fd::{RawFd, BorrowedFd, AsFd, OwnedFd, FromRawFd, AsRawFd};
+use std::os::fd::{RawFd, BorrowedFd, AsFd, OwnedFd, AsRawFd};
use std::io::Error;
use libc::*;
+use super::libc_s;
+
+use libc_s::{setsockopt, SockOpt};
+
pub struct RxRing {
fd: OwnedFd,
ring: *mut u8,
@@ -17,85 +21,45 @@ pub struct RxRing {
current: usize
}
-fn attach_filter(sockfd: RawFd, filter: &[sock_filter]) -> Result<(), Error> {
- let prog = sock_fprog {
- len: filter.len() as u16,
- filter: filter.as_ptr() as *mut sock_filter,
- };
-
- let ret = unsafe {
- setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER,
- &prog as *const _ as *const _,
- std::mem::size_of::<sock_fprog>() as socklen_t)
- };
-
- if ret < 0 {
- return Err(Error::last_os_error());
- }
-
- Ok(())
-}
-
-/// Make [`sockfd`] as mmapable rxring with size of [`BLOCK_SIZE`] * [`BLOCK_NR`]
-/// and single frame [`FRAME_SIZE`] (each packet goes to frame).
-/// Since we only need to seek ip header here, 128 bytes are
-/// enough.
-fn setup_rxring(sockfd: RawFd) -> Result<tpacket_req, Error> {
- const BLOCK_SIZE: u32 = 4096 * 4; // 16 KB
- const BLOCK_NR: u32 = 4;
-
- // tpacket_hdr (~66) + eth(14) + ipv6(40) + tcp with options(60) = ~180
- const FRAME_SIZE: u32 = 256;
+/// Make [`sockfd`] as mmapable rxring with size of [`tp_block_size`] * [`tp_block_nr`]
+/// and single frame [`tp_frame_size`] (each packet goes to frame).
+fn setup_rxring(sockfd: RawFd,
+ tp_block_size: u32, tp_block_nr: u32, tp_frame_size: u32
+) -> Result<tpacket_req, Error> {
let req = tpacket_req {
- tp_block_size: BLOCK_SIZE,
- tp_block_nr: BLOCK_NR,
- tp_frame_size: FRAME_SIZE,
- tp_frame_nr: BLOCK_SIZE / FRAME_SIZE * BLOCK_NR,
+ tp_block_size,
+ tp_block_nr,
+ tp_frame_size,
+ tp_frame_nr: tp_block_size / tp_frame_size * tp_block_nr,
};
- let ret = unsafe {
- setsockopt(sockfd, SOL_PACKET, PACKET_RX_RING,
- &req as *const _ as *const _,
- std::mem::size_of::<tpacket_req>() as socklen_t)
- };
-
- if ret < 0 {
- return Err(Error::last_os_error());
- }
+ setsockopt(sockfd, SockOpt::PACKET_RX_RING(&req))?;
Ok(req)
}
impl RxRing {
- pub fn new(filter: &[libc::sock_filter]) -> Result<Self, Error> {
- let raw = unsafe {
- socket(
- AF_PACKET,
- SOCK_RAW,
- (ETH_P_ALL as u16).to_be() as i32 // big-endian
- )
- };
- if raw < 0 { return Err(Error::last_os_error()); }
-
- // SAFETY: we just opened raw.
- let fd = unsafe { OwnedFd::from_raw_fd(raw) };
-
- attach_filter(fd.as_raw_fd(), filter)?;
- let req = setup_rxring(fd.as_raw_fd())?;
+ pub fn new(
+ filter: &[libc::sock_filter],
+ tp_block_size: u32, tp_block_nr: u32, tp_frame_size: u32
+ ) -> Result<Self, Error> {
+ let fd = libc_s::socket(AF_PACKET, SOCK_RAW, (ETH_P_ALL as u16).to_be() as i32)?;
+ let raw = fd.as_raw_fd();
+
+ setsockopt(raw, SockOpt::SO_ATTACH_FILTER(&filter))?;
+ let req = setup_rxring(raw, tp_block_size, tp_block_nr, tp_frame_size)?;
let ring_size = (req.tp_block_size * req.tp_block_nr) as usize;
- let ring = unsafe {
- mmap(
- std::ptr::null_mut(),
- ring_size,
- PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_LOCKED,
- fd.as_raw_fd(),
- 0
- )
- };
- if ring == MAP_FAILED { return Err(Error::last_os_error()); }
+ // SAFETY: we munmap this segment when RxRing is dropped.
+ let ring = unsafe {libc_s::mmap(
+ std::ptr::null_mut(),
+ ring_size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_LOCKED,
+ raw,
+ 0
+ )}?;
Ok(RxRing {
fd,
@@ -110,7 +74,6 @@ impl RxRing {
let frame_size = self.req.tp_frame_size as usize;
// SAFETY: current < frame_nr guaranteed by modular increment on advance.
- // ring is valid mmap'd memory from new(), munmapped by Drop.
unsafe { self.ring.add(self.current * frame_size) as *mut tpacket_hdr }
}
@@ -151,12 +114,12 @@ impl AsRawFd for RxRing {
}
}
-// SAFETY: ring was mmap'd with ring_size bytes.
-// This guarantees munmap() happens before OwnedFd closes the fd.
impl Drop for RxRing {
fn drop(&mut self) {
- unsafe {
- libc::munmap(self.ring as *mut _, self.ring_size);
+ // SAFETY: ring was mmap'd with ring_size bytes.
+ match unsafe { libc_s::munmap(self.ring as *mut _, self.ring_size) } {
+ Err(e) => crate::warn!("rxring: cannot munmap: {}", e.kind()),
+ Ok(_) => {}
}
}
}