Skip to content
Open
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
17 changes: 17 additions & 0 deletions architecture/sandbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -612,3 +612,20 @@ broker as its sender, not the original calling agent's `SI_USER` identity.
Queued signals preserve permitted application siginfo payloads; they cannot
forge kernel-generated or `SI_TKILL` codes. Programs requiring original sender
identity must account for this mediation boundary.

## Performance Measurement

The optional `perf-harness` feature provides a local TCP microbenchmark, not a
full sandbox benchmark. It separates connection establishment from established
stream I/O. Connections and warmup complete before measurement starts;
connection-only results have no payload-throughput value. Worker preparation
fails with an error rather than leaving peers blocked at a barrier.

The opt-in E2E benchmarks exercise DNS and TCP through both sandbox and
supervisor to Internet destinations. The live-traffic benchmark alternates a
direct **host-process** baseline with sandbox traffic for ten rounds by default;
this baseline is not raw Docker. Its typed reports distinguish successful,
failed, and skipped samples. Only successful samples are performance results:
every comparable scenario needs successful coverage, and every sandbox denial
round must report an explicit permission error. HTTP error responses, truncated
downloads, and failed DNS queries cannot count as fast successful requests.
5 changes: 5 additions & 0 deletions crates/openshell-sandbox/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ repository.workspace = true
name = "openshell-sandbox"
path = "src/main.rs"

[[bin]]
name = "openshell-seccomp-perf"
path = "src/bin/seccomp-perf.rs"
required-features = ["perf-harness"]

[features]
perf-harness = []

Expand Down
134 changes: 134 additions & 0 deletions crates/openshell-sandbox/src/bin/seccomp-perf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

//! Microbenchmark entry point for the production seccomp network broker.

use std::net::SocketAddr;

use clap::{Parser, Subcommand, ValueEnum};
use openshell_sandbox::perf::{BenchmarkOptions, Layer, Protocol};

#[derive(Debug, Parser)]
#[command(
about = "Measure native and seccomp-filtered socket performance",
long_about = "Measure native and seccomp-filtered TCP connection establishment and established-stream performance. Full supervisor-mediated DNS and Internet traffic are measured by the separate E2E harness."
)]
struct Cli {
/// Benchmark layer: native, filtered, or all.
#[arg(long, default_value = "all", value_enum)]
layer: LayerSelection,
/// TCP scenario to measure.
#[arg(long, default_value = "all", value_enum)]
protocol: ProtocolSelection,
#[arg(long, default_value_t = 10_000)]
iterations: u64,
#[arg(long, default_value_t = 1_000)]
warmup: u64,
#[arg(long, default_value_t = 1)]
concurrency: usize,
#[arg(long, default_value_t = 64)]
payload_bytes: usize,
#[command(subcommand)]
command: Option<Command>,
}

#[derive(Debug, Subcommand)]
enum Command {
#[command(hide = true)]
Worker {
#[arg(long)]
protocol: Protocol,
#[arg(long)]
target: SocketAddr,
#[arg(long)]
iterations: u64,
#[arg(long)]
warmup: u64,
#[arg(long)]
concurrency: usize,
#[arg(long)]
payload_bytes: usize,
},
}

fn main() -> anyhow::Result<()> {
let cli = Cli::parse();
if let Some(Command::Worker {
protocol,
target,
iterations,
warmup,
concurrency,
payload_bytes,
}) = cli.command
{
let report = openshell_sandbox::perf::run_worker(
protocol,
target,
iterations,
warmup,
concurrency,
payload_bytes,
)?;
println!("{}", serde_json::to_string(&report)?);
return Ok(());
}

let options = BenchmarkOptions {
layers: cli.layer.values(),
protocols: cli.protocol.values(),
iterations: cli.iterations,
warmup: cli.warmup,
concurrency: cli.concurrency,
payload_bytes: cli.payload_bytes,
};
for report in openshell_sandbox::perf::run(options)? {
println!("{}", serde_json::to_string(&report)?);
}
Ok(())
}

#[derive(Clone, Copy, Debug, ValueEnum)]
enum LayerSelection {
Native,
Filtered,
All,
}

impl LayerSelection {
fn values(self) -> Vec<Layer> {
match self {
Self::Native => vec![Layer::Native],
Self::Filtered => vec![Layer::Filtered],
Self::All => vec![Layer::Native, Layer::Filtered],
}
}
}

#[derive(Clone, Copy, Debug, ValueEnum)]
enum ProtocolSelection {
TcpConnect,
TcpStream,
All,
}

impl ProtocolSelection {
fn values(self) -> Vec<Protocol> {
match self {
Self::TcpConnect => vec![Protocol::TcpConnect],
Self::TcpStream => vec![Protocol::TcpStream],
Self::All => vec![Protocol::TcpConnect, Protocol::TcpStream],
}
}
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unsupported_udp_is_rejected_by_cli() {
for value in ["udp-connected", "udp-unconnected"] {
assert!(Cli::try_parse_from(["seccomp-perf", "--protocol", value]).is_err());
}
}
}
2 changes: 2 additions & 0 deletions crates/openshell-sandbox/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ pub mod main_session;
pub mod managed_children;
#[cfg(target_os = "linux")]
mod network_broker;
#[cfg(all(target_os = "linux", feature = "perf-harness"))]
pub mod perf;
#[cfg(unix)]
pub mod process;
mod pty;
Expand Down
Loading
Loading