No description
  • Rust 97.3%
  • Shell 2.7%
Find a file
Jan De Landtsheer a648bb8d7d
perf(dataplane): drop steady-state block_in_place from run loop (ADR-0023 Step 1)
The run loop wrapped every handle_packet call in block_in_place. On the
established-flow path translation is pure CPU over wait-free left-right
lookups (ADR-0002) and never blocks, so the wrap taxed every packet for
nothing. The only blocking op, get_or_insert on a new flow, already
self-manages via block_in_place internally
(binding::{pool_mode,kernel_mode}::WriterHandle::get_or_insert), so the
outer wrap is redundant.

Removing it also unblocks the thread-per-core worker model (ADR-0023
Step 4): block_in_place panics on a current_thread runtime, so it could
not have wrapped the per-queue loops.

netns iperf3, daemon NAPT, 10s, single queue (avg of clean runs):
  v6->v4: parent ~2233 Mbps -> Step 1 ~2250 Mbps
  v4->v6: parent ~3384 Mbps -> Step 1 ~3410 Mbps
At parity within run-to-run noise (~3%), as expected single-queue;
no regression.

build/test/clippy/fmt --workspace all green.
2026-06-06 20:11:41 +02:00
contrib feat: ADR-0020 wire kernel NAPT into daemon + stress + bench (commit 3/4) 2026-04-21 13:28:17 +02:00
crates perf(dataplane): drop steady-state block_in_place from run loop (ADR-0023 Step 1) 2026-06-06 20:11:41 +02:00
docs docs: ADR-0023 plan Step 8 adds version bump 0.4.0 -> 0.5.0 2026-06-06 20:02:51 +02:00
examples feat: make reaper sweep interval configurable via reap-interval-secs 2026-05-20 14:25:49 +02:00
fuzz feat: make reaper sweep interval configurable via reap-interval-secs 2026-05-20 14:25:49 +02:00
.gitignore feat: make reaper sweep interval configurable via reap-interval-secs 2026-05-20 14:25:49 +02:00
AGENTS.md feat: make reaper sweep interval configurable via reap-interval-secs 2026-05-20 14:25:49 +02:00
Cargo.lock feat(tun): adopt tun-rs for the TUN edge (ADR-0022) 2026-05-26 15:25:33 +02:00
Cargo.toml feat(tun): adopt tun-rs for the TUN edge (ADR-0022) 2026-05-26 15:25:33 +02:00
CHANGELOG.md feat(tun): adopt tun-rs for the TUN edge (ADR-0022) 2026-05-26 15:25:33 +02:00
CODE_STRUCTURE.md feat: make reaper sweep interval configurable via reap-interval-secs 2026-05-20 14:25:49 +02:00
nat64.toml nat64 v0.1: stateless RFC 7915 translator 2026-04-15 15:11:52 +02:00
README.md docs: reflect ADR-0020 in README, operator notes, and examples 2026-04-21 13:40:07 +02:00

nat64

Stateful NAT64 daemon (RFC 6146 + RFC 7915) in Rust. Replaces Tayga at the routing level for Mycelium-overlay workloads that need to reach the IPv4 internet.

Build

cargo build --release

Binary is target/release/nat64. Run nat64 --help for subcommands.

Prefix selection

NAT64 can use either the RFC 6052 Well-Known Prefix (64:ff9b::/96) or an operator-chosen Network-Specific Prefix (NSP). Pick based on where your v6 clients live:

  • Global IPv6 → public v4 internet: use 64:ff9b::/96. RFC 6052 §3.1 forbids combining it with RFC1918 / loopback pools; the daemon enforces that check at startup.
  • Overlay networks with a constrained range (e.g. Mycelium, which only carries 400::/7): carve a /96 out of the overlay's routable range and use that as your NSP. Example: prefix = "400:dead:beef::/96". No RFC 6052 §3.1 restriction applies to NSPs, so RFC1918 pools are fine.
  • Corporate / lab IPv6: any /96 out of your own space works.

Side-effect worth knowing: daemon-originated ICMP (TTL-exceeded, and PTB in v0.2) uses prefix || gateway_v4 as its v6 source per ADR-0011. When the prefix sits inside your overlay's routable range, replies from the translator are automatically reachable over the overlay — no extra route needed.

NAPT modes (ADR-0020)

Two backends, selected by the napt config key:

  • napt = "daemon" (default, v0.2). Userspace NAPT over a provider-allocated v4 pool. Each v6 source gets per-flow port allocation; distinct clients take distinct pool v4s. Right choice when a provider gives you a /28 (or similar) of routable v4.

  • napt = "kernel" (ADR-0020). 1:1 v6 -> inner-v4 mapping; the host kernel's MASQUERADE hook owns port allocation and conntrack. The daemon never binds any v4 address on any interface, so the F-001 local-table collision class cannot occur. --config geomind auto-selects this mode.

See docs/operator.md "NAPT mode selection" for the per-mode plumbing.

Status

v0.1 scope: /96 prefix only, TCP/UDP/ICMP, stateless per-fragment translation, 1:1 v6→v4 mapping, in-memory bindings with a 5-minute reaper. v0.2 (PRD-0002) adds NAPT, Prometheus metrics, UDS show, and pool affinity. ADR-0020 layers a kernel-delegated NAPT option on top without changing the v0.2 default.

Workspace layout

  • crates/nat64-core — library (translation core, binding table, pool)
  • crates/nat64 — daemon binary (CLI, TUN I/O, reaper, ICMP rate limiter)