Skip to content
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"lib/flash-rs",
"lib/utils-rs",
"examples/arpresolver-rs",
"examples/firewall-rs",
"examples/helloworld-rs",
Expand Down
3 changes: 2 additions & 1 deletion examples/arpresolver-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ edition = "2024"

[dependencies]
clap = { version = "4.5.35", features = ["derive"] }
core_affinity = "0.8.3"
ctrlc = { version = "3.4.5", optional = true }
flash = { path = "../../lib/flash-rs", features = ["clap"] }
macaddr = "1.0.1"
thiserror = "2.0.17"
tracing = { version = "0.1.41", optional = true }
tracing-subscriber = { version = "0.3.19", optional = true }
utils = { path = "../../lib/utils-rs" }

[features]
default = ["dep:ctrlc"]
Expand Down
31 changes: 10 additions & 21 deletions examples/arpresolver-rs/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#[cfg(feature = "stats")]
use std::str::FromStr as _;

use clap::Parser;
use flash::FlashConfig;
use macaddr::MacAddr6;
use utils::CpuRange;

#[cfg(feature = "stats")]
use flash::tui::GridLayout;
Expand All @@ -13,21 +11,8 @@ pub struct Cli {
#[command(flatten)]
pub flash_config: FlashConfig,

#[arg(
short = 'c',
long,
default_value_t = 0,
help = "Starting CPU core index for socket threads"
)]
pub cpu_start: usize,

#[arg(
short = 'e',
long,
default_value_t = 0,
help = "Ending CPU core index for socket threads (inclusive)"
)]
pub cpu_end: usize,
#[arg(short = 'c', long, help = "CPU core range for socket threads")]
pub cpu_range: Option<CpuRange>,

#[arg(short = 'M', long, help = "NF MAC address")]
pub nf_mac: MacAddr6,
Expand All @@ -46,14 +31,18 @@ pub struct StatsConfig {
#[arg(
short = 's',
long = "stats-cpu",
default_value_t = 1,
help = "CPU core index for stats thread"
)]
pub cpu: usize,
pub cpu: Option<CpuRange>,

#[arg(short = 'F', long, default_value_t = 1, help = "Tui frames per second")]
pub fps: u64,

#[arg(short = 'l', long, default_value_t = GridLayout::default(), value_parser = GridLayout::from_str, help = "Tui layout")]
#[arg(
short = 'l',
long,
default_value_t = GridLayout::default(),
help = "Tui layout"
)]
pub layout: GridLayout,
}
12 changes: 12 additions & 0 deletions examples/arpresolver-rs/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#[derive(Debug, thiserror::Error)]
#[error("app error: {0}")]
pub enum AppError {
Flash(#[from] flash::FlashError),

#[cfg(feature = "stats")]
Tui(#[from] flash::tui::TuiError),

#[cfg(not(feature = "stats"))]
#[error("app error: error setting Ctrl-C handler: {0}")]
Ctrl(#[from] ctrlc::Error),
}
140 changes: 55 additions & 85 deletions examples/arpresolver-rs/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
mod cli;
mod error;
mod nf;

use std::{
net::Ipv4Addr,
process::ExitCode,
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
thread,
};

use clap::Parser;
Expand All @@ -17,16 +18,16 @@ use macaddr::MacAddr6;
#[cfg(feature = "stats")]
use flash::tui::StatsDashboard;

use crate::cli::Cli;
use crate::{cli::Cli, error::AppError};

fn socket_thread(
mut socket: Socket,
nf_mac: MacAddr6,
nf_ip: Ipv4Addr,
mac_addr: Option<MacAddr6>,
run: &Arc<AtomicBool>,
stop: &Arc<AtomicBool>,
) {
while run.load(Ordering::SeqCst) {
while !stop.load(Ordering::Relaxed) {
if !socket.poll().is_ok_and(|val| val) {
continue;
}
Expand Down Expand Up @@ -60,108 +61,77 @@ fn socket_thread(
}
}

fn main() {
#[cfg(feature = "tracing")]
tracing_subscriber::fmt::init();

let cli = Cli::parse();

let (sockets, route) = match flash::connect(&cli.flash_config) {
Ok(t) => t,
Err(err) => {
eprintln!("{err}");
return;
}
};

if sockets.is_empty() {
eprintln!("no sockets received");
return;
}

#[cfg(feature = "tracing")]
tracing::debug!("Sockets: {:?}", sockets);
fn run(cli: Cli) -> Result<(), AppError> {
let (sockets, mut monitor) = flash::connect(&cli.flash_config)?;
let nf_ip_addr = monitor.get_nf_ip_addr()?;
let stop = Arc::new(AtomicBool::new(true));

#[cfg(feature = "stats")]
let mut tui = match StatsDashboard::new(
let mut tui = StatsDashboard::new(
sockets.iter().map(Socket::stats),
cli.stats.fps,
cli.stats.layout,
) {
Ok(t) => t,
Err(err) => {
eprintln!("error creating tui: {err}");
return;
}
};

let cores = core_affinity::get_core_ids()
.unwrap_or_default()
.into_iter()
.filter(|core_id| core_id.id >= cli.cpu_start && core_id.id <= cli.cpu_end)
.collect::<Vec<_>>();

if cores.is_empty() {
eprintln!("no cores found in range {}-{}", cli.cpu_start, cli.cpu_end);
return;
}

#[cfg(feature = "tracing")]
tracing::debug!("Cores: {:?}", cores);
Some(stop.clone()),
)?;

#[cfg(feature = "stats")]
let Some(stats_core) = core_affinity::get_core_ids()
.unwrap_or_default()
.into_iter()
.find(|core_id| core_id.id == cli.stats.cpu)
else {
eprintln!("no core found for stats thread {}", cli.stats.cpu);
return;
};

let run = Arc::new(AtomicBool::new(true));
let stats_thread = cli.stats.cpu.unwrap_or_default().spawn(move || {
if let Err(err) = tui.run() {
eprintln!("error dumping stats: {err}");
}
});

#[cfg(not(feature = "stats"))]
if let Err(err) = {
let r = run.clone();
{
let stop = stop.clone();
ctrlc::set_handler(move || {
r.store(false, Ordering::SeqCst);
stop.store(true, Ordering::Release);
})
} {
eprintln!("error setting Ctrl-C handler: {err}");
return;
}
}?;

let handles = sockets
.into_iter()
.zip(cores.into_iter().cycle())
.map(|(socket, core_id)| {
let r = run.clone();
thread::spawn(move || {
core_affinity::set_for_current(core_id);
socket_thread(socket, cli.nf_mac, route.ip_addr, cli.mac_addr, &r);
})
let _ = {
let stop = stop.clone();
monitor.spawn_disconnect_handler(move || {
stop.store(true, Ordering::Release);
})
.collect::<Vec<_>>();
};

let socket_threads = cli
.cpu_range
.unwrap_or_default()
.spawn_multiple(sockets.into_iter().map(|socket| {
let stop = stop.clone();
move || socket_thread(socket, cli.nf_mac, nf_ip_addr, cli.mac_addr, &stop)
}));

#[cfg(feature = "stats")]
if let Err(err) = thread::spawn(move || {
core_affinity::set_for_current(stats_core);
if let Err(err) = tui.run() {
eprintln!("error dumping stats: {err}");
}
})
.join()
{
if let Err(err) = stats_thread.join() {
eprintln!("error in stats thread: {err:?}");
}

#[cfg(feature = "stats")]
run.store(false, Ordering::SeqCst);
stop.store(true, Ordering::Release);

for handle in handles {
for handle in socket_threads {
if let Err(err) = handle.join() {
eprintln!("error in thread: {err:?}");
eprintln!("error in socket thread: {err:?}");
}
}

Ok(())
}

fn main() -> ExitCode {
#[cfg(feature = "tracing")]
tracing_subscriber::fmt::init();

let cli = Cli::parse();

match run(cli) {
Ok(()) => ExitCode::SUCCESS,
Err(err) => {
eprintln!("{err}");
ExitCode::FAILURE
}
}
}
3 changes: 2 additions & 1 deletion examples/firewall-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ edition = "2024"

[dependencies]
clap = { version = "4.5.35", features = ["derive"] }
core_affinity = "0.8.3"
csv = "1.3.1"
ctrlc = { version = "3.4.5", optional = true }
flash = { path = "../../lib/flash-rs", features = ["clap"] }
macaddr = "1.0.1"
serde = { version = "1.0.219", features = ["derive"] }
thiserror = "2.0.17"
tracing = { version = "0.1.41", optional = true }
tracing-subscriber = { version = "0.3.19", optional = true }
utils = { path = "../../lib/utils-rs" }

[features]
default = ["dep:ctrlc"]
Expand Down
31 changes: 10 additions & 21 deletions examples/firewall-rs/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
use std::path::PathBuf;

#[cfg(feature = "stats")]
use std::str::FromStr as _;

use clap::Parser;
use flash::FlashConfig;
use macaddr::MacAddr6;
use utils::CpuRange;

#[cfg(feature = "stats")]
use flash::tui::GridLayout;
Expand All @@ -15,21 +13,8 @@ pub struct Cli {
#[command(flatten)]
pub flash_config: FlashConfig,

#[arg(
short = 'c',
long,
default_value_t = 0,
help = "Starting CPU core index for socket threads"
)]
pub cpu_start: usize,

#[arg(
short = 'e',
long,
default_value_t = 0,
help = "Ending CPU core index for socket threads (inclusive)"
)]
pub cpu_end: usize,
#[arg(short = 'c', long, help = "CPU core range for socket threads")]
pub cpu_range: Option<CpuRange>,

#[arg(short, long, help = "Path to denylist csv file")]
pub denylist: PathBuf,
Expand All @@ -48,14 +33,18 @@ pub struct StatsConfig {
#[arg(
short = 's',
long = "stats-cpu",
default_value_t = 1,
help = "CPU core index for stats thread"
)]
pub cpu: usize,
pub cpu: Option<CpuRange>,

#[arg(short = 'F', long, default_value_t = 1, help = "Tui frames per second")]
pub fps: u64,

#[arg(short = 'l', long, default_value_t = GridLayout::default(), value_parser = GridLayout::from_str, help = "Tui layout")]
#[arg(
short = 'l',
long,
default_value_t = GridLayout::default(),
help = "Tui layout"
)]
pub layout: GridLayout,
}
13 changes: 13 additions & 0 deletions examples/firewall-rs/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#[derive(Debug, thiserror::Error)]
#[error("app error: {0}")]
pub enum AppError {
Flash(#[from] flash::FlashError),
Csv(#[from] csv::Error),

#[cfg(feature = "stats")]
Tui(#[from] flash::tui::TuiError),

#[cfg(not(feature = "stats"))]
#[error("app error: error setting Ctrl-C handler: {0}")]
Ctrl(#[from] ctrlc::Error),
}
Loading