tpt-netctl

Rust

Backend-independent Rust API for Linux dataplane control (filter/NAT/rate-limit) over nftables and eBPF/XDP.

0 stars0 forks0 watchersApache License 2.0

Languages

Rust100.0%
README

tpt-netctl

CI License MSRV

Backend-independent dataplane control for Linux — nftables and eBPF behind a single stable Rust API.

Overview

tpt-netctl lets consumers apply, validate, and read back filter rules, NAT rules, rate limits, interface state, and per-rule counters without knowing which dataplane backend is active.

Crates

CrateDescription
tpt-netctl-coreDataplaneBackend trait and shared types
tpt-netctl-nftablesNftablesBackend — netlink-based nftables implementation

Usage

use tpt_netctl_core::{
    Action, Chain, DataplaneBackend, Matcher, Policy, Rule, Ruleset, RulesetDiff,
};
use tpt_netctl_nftables::NftablesBackend;

fn main() -> Result<(), tpt_netctl_core::NetctlError> {
    // Connect (requires CAP_NET_ADMIN on Linux).
    let backend = NftablesBackend::connect()?;

    // Describe the desired change.
    let diff = RulesetDiff {
        add: vec![Rule {
            id: 1,
            description: Some("allow ssh".into()),
            matcher: Matcher {
                protocol: Some("tcp".into()),
                dst_port: Some("22".into()),
                ..Default::default()
            },
            action: Action::Accept,
        }],
        update: vec![],
        remove: vec![],
    };

    // Dry-run: what would change? (no mutation)
    let report = backend.validate(&diff)?;
    println!("planned: {:?}", report.planned_changes);

    // Atomic apply — all-or-nothing.
    let applied = backend.apply(&diff)?;
    println!("added {} rule(s)", applied.added);

    // Read back state and per-rule counters.
    let state = backend.read_state()?;
    let counters = backend.counters(1)?;
    println!(
        "installed chains: {}, rule 1 counters: {} pkts / {} bytes",
        state.ruleset.chains.len(),
        counters.packets,
        counters.bytes
    );

    Ok(())
}

Architecture

A single trait, two backend implementations:

trait DataplaneBackend {
    fn validate(&self, diff: &RulesetDiff) -> Result<ValidationReport>;
    fn apply(&self, diff: &RulesetDiff) -> Result<ApplyReport>;
    fn read_state(&self) -> Result<DataplaneState>;
    fn counters(&self, rule_id: RuleId) -> Result<Counters>;
    fn interfaces(&self) -> Result<Vec<InterfaceInfo>>;
}
  • NftablesBackend (default): netlink-based, uses nftables' native atomic transaction commits.
  • EbpfBackend (planned, opt-in): aya-based acceleration for specific hot paths — gated behind real performance measurements per the spec's phased approach.

Privilege

All kernel-touching methods require CAP_NET_ADMIN on Linux. This is documented per-method in rustdoc.

Development

See CONTRIBUTING.md.

cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo doc --workspace --no-deps

# Privileged integration tests (Linux, root):
sudo cargo test -p tpt-netctl-nftables --features integration -- --ignored

License

Licensed under either of

at your option.