Skip to content
Closed
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
5 changes: 4 additions & 1 deletion dist/setup.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#!/bin/bash

sudo apt update
sudo apt upgrade -y
sudo apt install -y \
build-essential \
clang \
llvm \
m4 \
pkg-config \
gnupg \
git \
libbpf-dev \
libxdp-dev \
Expand All @@ -16,7 +18,8 @@ sudo apt install -y \
unzip \
jq \
wget \
zsh
zsh \
htop

wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
Expand Down
99 changes: 99 additions & 0 deletions examples/raw-receiver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use std::{
ops::{Deref, DerefMut},
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
};

use clap::Parser;

use libvoid::{
raw::RawReceiver,
xdp::{context::XdpContext, frame::BasicFrameBuffer},
};

mod common;
use common::{BaseArgs, Stats};

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Args {
#[command(flatten)]
base: BaseArgs,
}

impl Deref for Args {
type Target = BaseArgs;

fn deref(&self) -> &Self::Target {
&self.base
}
}

impl DerefMut for Args {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}

fn main() {
let mut stats = Stats::new();
let args = Args::parse();

// Every application starts with setting up an XdpContext, this loads the XDP kernel program and attaches it to the named
// interface.
let mut xdp_ctx = XdpContext::builder(&args.if_name)
.attach_mode(args.attach_mode)
.enable_fragmentation(args.enable_fragmentation)
.build()
.expect("Failed to create xdp context");

let mut reciever = RawReceiver::<BasicFrameBuffer>::builder(&args.if_name, args.queue)
.frame_size(args.frame_size)
.num_frames(args.busy_poll_batch_size)
.huge_tables(args.huge_tables)
.unaligned(args.unaligned)
.busy_poll(args.busy_poll)
.busy_poll_batch_size(args.busy_poll_batch_size)
.busy_poll_timeout_us(args.busy_poll_timeout_us)
.copy_mode(args.copy_mode)
.enable_fragmentation(args.enable_fragmentation)
.build::<BasicFrameBuffer>(&mut xdp_ctx)
.expect("Failed to create receiver");

// Always catch SIGINT/SIGTERM to ensure we clean up properly, we have a running XDP program attached to the interface.
//
// Note: In other words its very important to ensure that the Drop impl for XdpContext is run to detach the XDP program from
// the interface, OR manually call detach().
let exit = Arc::new(AtomicBool::new(false));
ctrlc::set_handler({
let exit = exit.clone();
move || {
exit.store(true, Ordering::Relaxed);
}
})
.expect("Error setting Ctrl-C handler");

println!("Socket created, listening for packets...");

// Loop forever reading packets from the socket.
while !exit.load(Ordering::Relaxed) {
// Read some frames from the socket.
//
// This will return with 1 > N frames in the success case, as soon as possible. If there are no frames it will return an error,
// at this point we would have blocked so a retry is necessary this is left for the caller to handle.
match reciever.recv() {
Ok(frames) => {
for frame in frames {
stats.update(frame.len(), frame.is_fragment());
}
}
Err(_) => {
continue;
}
}

stats.maybe_print();
}
}
106 changes: 106 additions & 0 deletions examples/raw-sender.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use std::{
ops::{Deref, DerefMut},
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
};

use clap::Parser;

use libvoid::{
raw::RawSender,
xdp::{
context::XdpContext,
frame::{BasicFrameBuffer, FrameBuffer},
},
};

mod common;
use common::{BaseArgs, GeneratorArgs, Stats, build_frame};

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Args {
#[command(flatten)]
base: BaseArgs,
#[command(flatten)]
generator: GeneratorArgs,
}

impl Deref for Args {
type Target = BaseArgs;

fn deref(&self) -> &Self::Target {
&self.base
}
}

impl DerefMut for Args {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}

fn main() {
let mut stats = Stats::new();
let args = Args::parse();

// Every application starts with setting up an XdpContext, this loads the XDP kernel program and attaches it to the named
// interface.
let mut xdp_ctx = XdpContext::builder(&args.if_name)
.attach_mode(args.attach_mode)
.enable_fragmentation(args.enable_fragmentation)
.build()
.expect("Failed to create xdp context");

let (mut sender, mut buffer) = RawSender::builder(&args.if_name, args.queue)
.frame_size(args.frame_size)
.num_frames(args.busy_poll_batch_size)
.huge_tables(args.huge_tables)
.unaligned(args.unaligned)
.busy_poll(args.busy_poll)
.busy_poll_batch_size(args.busy_poll_batch_size)
.busy_poll_timeout_us(args.busy_poll_timeout_us)
.build::<BasicFrameBuffer>(&mut xdp_ctx)
.expect("Failed to create receiver");

// Always catch SIGINT/SIGTERM to ensure we clean up properly, we have a running XDP program attached to the interface.
//
// Note: In other words its very important to ensure that the Drop impl for XdpContext is run to detach the XDP program from
// the interface, OR manually call detach().
let exit = Arc::new(AtomicBool::new(false));
ctrlc::set_handler({
let exit = exit.clone();
move || {
exit.store(true, Ordering::Relaxed);
}
})
.expect("Error setting Ctrl-C handler");

println!("Socket created, listening for packets...");
// Generate our mock UDP packet to send.
let packet_data = build_frame(&args.generator);

for frame in buffer.iter_frames_mut() {
frame.copy_from(&packet_data);
}

// Loop forever reading packets from the socket.
while !exit.load(Ordering::Relaxed) {
for frame in buffer.iter_frames_mut() {
unsafe { frame.set_len(packet_data.len()) };
}

match sender.send(&mut buffer) {
Ok(sent) => {
stats.update_batch(sent as usize, packet_data.len());
}
Err(_) => {
continue;
}
}

stats.maybe_print();
}
}
101 changes: 101 additions & 0 deletions examples/raw-transceiver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use std::{
ops::{Deref, DerefMut},
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
};

use clap::Parser;

use libvoid::{
raw::RawTransceiver,
xdp::{
context::XdpContext,
frame::{BasicFrameBuffer, FrameBuffer},
},
};

mod common;
use common::{BaseArgs, Stats};

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Args {
#[command(flatten)]
base: BaseArgs,
}

impl Deref for Args {
type Target = BaseArgs;

fn deref(&self) -> &Self::Target {
&self.base
}
}

impl DerefMut for Args {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}

#[inline(always)]
fn handler<'umem, 'buffer, T: FrameBuffer<'umem>>(frames: T::IterMut<'buffer>, stats: &mut Stats) {
for frame in frames {
stats.update(frame.len(), frame.is_fragment());
}
}

fn main() {
let mut stats = Stats::new();
let args = Args::parse();

// Every application starts with setting up an XdpContext, this loads the XDP kernel program and attaches it to the named
// interface.
let mut xdp_ctx = XdpContext::builder(&args.if_name)
.attach_mode(args.attach_mode)
.enable_fragmentation(args.enable_fragmentation)
.build()
.expect("Failed to create xdp context");

let mut reciever = RawTransceiver::<BasicFrameBuffer>::builder(&args.if_name, args.queue)
.rx_ring_size(args.rx_ring_size)
.tx_ring_size(args.tx_ring_size)
.busy_poll(args.busy_poll)
.busy_poll_batch_size(args.busy_poll_batch_size)
.busy_poll_timeout_us(args.busy_poll_timeout_us)
.copy_mode(args.copy_mode)
.enable_fragmentation(args.enable_fragmentation)
.completion_ring_size(args.completion_ring_size)
.fill_ring_size(args.fill_ring_size)
.frame_size(args.frame_size)
.busy_poll(args.busy_poll)
.num_frames(args.busy_poll_batch_size)
.huge_tables(args.huge_tables)
.unaligned(args.unaligned)
.build::<BasicFrameBuffer>(&mut xdp_ctx)
.expect("Failed to create receiver");

// Always catch SIGINT/SIGTERM to ensure we clean up properly, we have a running XDP program attached to the interface.
//
// Note: In other words its very important to ensure that the Drop impl for XdpContext is run to detach the XDP program from
// the interface, OR manually call detach().
let exit = Arc::new(AtomicBool::new(false));
ctrlc::set_handler({
let exit = exit.clone();
move || {
exit.store(true, Ordering::Relaxed);
}
})
.expect("Error setting Ctrl-C handler");

println!("Socket created, listening for packets...");

// Loop forever reading packets from the socket.
while !exit.load(Ordering::Relaxed) {
if let Ok(_) = reciever.echo(|frames| handler::<BasicFrameBuffer>(frames, &mut stats)) {
stats.maybe_print();
}
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod raw;
pub mod xdp;
7 changes: 7 additions & 0 deletions src/raw/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mod receiver;
mod sender;
mod transceiver;

pub use receiver::{RawReceiver, RawReceiverBuilder};
pub use sender::{RawSender, RawSenderBuilder};
pub use transceiver::{RawTransceiver, RawTransceiverBuilder};
Loading
Loading