Skip to content
This repository was archived by the owner on Nov 20, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 13 additions & 34 deletions src/rings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ struct XskRing<T: 'static> {
cached_consumed: u32,
/// Total number of entries in the ring
count: u32,
/// Mask for indexing ops, since rings are required to be power of 2 this
/// lets us get away with a simple `&` instead of `%`
mask: usize,
}

/// Creates a memory map for a ring
Expand Down Expand Up @@ -196,6 +199,7 @@ fn map_ring<T>(
producer,
consumer,
count,
mask: count as usize - 1,
ring,
cached_produced: 0,
cached_consumed: 0,
Expand All @@ -210,8 +214,11 @@ struct XskProducer<T: 'static>(XskRing<T>);

impl<T> XskProducer<T> {
#[inline]
fn mask(&self) -> usize {
self.0.count as usize - 1
fn set(&mut self, i: usize, item: T) {
// SAFETY: The mask ensures the index is always within range
unsafe {
*self.0.ring.get_unchecked_mut(i & self.0.mask) = item;
}
}

/// The equivalent of [`xsk_ring_prod__reserve`](https://docs.ebpf.io/ebpf-library/libxdp/functions/xsk_ring_prod__reserve/)
Expand Down Expand Up @@ -255,31 +262,14 @@ impl<T> XskProducer<T> {
}
}

impl<T> std::ops::Index<usize> for XskProducer<T> {
type Output = T;

#[inline]
fn index(&self, index: usize) -> &Self::Output {
// SAFETY: each ring impl ensures the index is valid
unsafe { self.0.ring.get_unchecked(index) }
}
}

impl<T> std::ops::IndexMut<usize> for XskProducer<T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
// SAFETY: each ring impl ensures the index is valid
unsafe { self.0.ring.get_unchecked_mut(index) }
}
}

/// Used for rx and completion rings where userspace is the consumer
struct XskConsumer<T: 'static>(XskRing<T>);

impl<T> XskConsumer<T> {
impl<T: Copy> XskConsumer<T> {
#[inline]
fn mask(&self) -> usize {
self.0.count as usize - 1
fn get(&self, i: usize) -> T {
// SAFETY: The mask ensures the index is always within range
unsafe { *self.0.ring.get_unchecked(i & self.0.mask) }
}

/// The equivalent of [`xsk_ring_cons__peek`](https://docs.ebpf.io/ebpf-library/libxdp/functions/xsk_ring_cons__peek/)
Expand Down Expand Up @@ -316,14 +306,3 @@ impl<T> XskConsumer<T> {
self.0.consumer.fetch_add(nb, Ordering::Release);
}
}

impl<T> std::ops::Index<usize> for XskConsumer<T> {
type Output = T;

#[inline]
fn index(&self, index: usize) -> &Self::Output {
// SAFETY: Since we force power of 2 the same as libxdp, we know
// it will always be within bounds
unsafe { self.0.ring.get_unchecked(index) }
}
}
7 changes: 3 additions & 4 deletions src/rings/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ impl CompletionRing {
let (actual, idx) = self.ring.peek(requested as _);

if actual > 0 {
let mask = self.ring.mask();
for i in idx..idx + actual {
let addr = self.ring[i & mask];
// SAFETY: The mask ensures the index is always within range
let addr = self.ring.get(i);
umem.free_addr(addr);
}

Expand All @@ -74,9 +74,8 @@ impl CompletionRing {
let (actual, idx) = self.ring.peek(requested as _);

if actual > 0 {
let mask = self.ring.mask();
for (ts, i) in timestamps.iter_mut().zip(idx..idx + actual) {
let addr = self.ring[i & mask];
let addr = self.ring.get(i);
*ts = umem.free_get_timestamp(addr);
}

Expand Down
3 changes: 1 addition & 2 deletions src/rings/fill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@ impl FillRing {
let (actual, idx) = self.ring.reserve(requested as _);

if actual > 0 {
let mask = self.ring.mask();
for i in idx..idx + actual {
self.ring[i & mask] = available.pop_front().unwrap();
self.ring.set(i, available.pop_front().unwrap());
}

self.ring.submit(actual as _);
Expand Down
3 changes: 1 addition & 2 deletions src/rings/rx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@ impl RxRing {
let (actual, idx) = self.ring.peek(nb as _);

if actual > 0 {
let mask = self.ring.mask();
for i in idx..idx + actual {
let desc = self.ring[i & mask];
let desc = self.ring.get(i);
packets.push_front(
// SAFETY: The user is responsible for the lifetime of the
// packets we are returning
Expand Down
3 changes: 1 addition & 2 deletions src/rings/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,12 @@ impl TxRing {
let (actual, idx) = self.ring.reserve(requested as _);

if actual > 0 {
let mask = self.ring.mask();
for i in idx..idx + actual {
let Some(packet) = packets.pop_back() else {
unreachable!()
};

self.ring[i & mask] = packet.into();
self.ring.set(i, packet.into());
}

self.ring.submit(actual as _);
Expand Down