Skip to content

Add -nat64 bpf, a translator of sixup's own that needs no module - #6

Merged
lqs merged 2 commits into
mainfrom
nat64-bpf
Oct 11, 2026
Merged

lqs merged 2 commits into
mainfrom
nat64-bpf

Conversation

@lqs

@lqs lqs commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • -nat64 bpf: a stateless RFC 7915 translator in a tc BPF program on the egress of the dummy device sixup-nat64. Each IPv6 source gets an address of its own from 198.18.0.0/15; conntrack and the source NAT on the way out do the stateful part, so a MAP-E line's ports keep one allocator. Translated packets go back to the device's ingress.
  • Translates TCP, UDP (GSO included), ICMP, and ICMP errors with their quotes (RFC 7915 type/code tables, PTB and Fragmentation Needed MTUs, Parameter Problem pointers, quoted fragments), fragments one by one, behind a prefix of any length RFC 6052 allows.
  • A slow path in sixup handles what needs the whole datagram: fragmented ICMP and IPv4 UDP without a checksum. The program hands them over through a BPF ring buffer; sixup reassembles, translates and sends them back through the device, marked.
  • Mappings conntrack has no flow for over two sweeps are removed. sixup refuses to start when the pool overlaps an address or route of the host.
  • No cilium/ebpf: tools/bpfgen (stdlib only) compiles bpf/nat64.c for either byte order at go generate time and writes the instructions, maps, read-only data and relocations; bpf.go loads them with the bpf() system call alone. The amd64 binary is 98 KB larger than main's, within the 6 MiB limit, and 32-bit big-endian MIPS builds.
  • The recipes (en/ja/zh) and the standards document recommend -nat64 bpf, with -nat64 jool for kernels older than 6.6.
  • Needs Linux 6.6 or later (tcx).

Test plan

  • go build ./... && go vet ./... && go test ./..., and go build ./... for linux, darwin and freebsd
  • GOOS=linux golangci-lint run, with and without -tags integration
  • ./build.sh for amd64, arm64, mips and mipsle; amd64 at 5,886,112 bytes
  • go generate reproduces the committed files byte for byte
  • Docker integration suite: end to end behind 64:ff9b::/96 and a /64, with conntrack for IPv6 as sixup's firewall has it (ping, the router's own ping, TCP, UDP, fragments both ways, fragmented ping, UDP without checksum, UDP GSO both ways, ICMP errors incl. quoted fragments, PTB both ways, mapping sweep); the ICMP tables and the RFC 6052 examples through BPF_PROG_TEST_RUN; bpf.go, nat64bpf.go and nat64slow.go at 100% coverage
  • On a real router, and against Jool for performance

馃 Generated with Claude Code

A tc BPF program on the egress of the dummy device sixup-nat64 translates
statelessly (RFC 7915): each IPv6 source gets an address of its own from
198.18.0.0/15, and conntrack and the source NAT on the way out do the
stateful part, as for any IPv4 host behind the router. Translated packets
go back to the device's ingress. TCP, UDP, ICMP and ICMP errors with their
quotes are translated, fragments one by one, behind a prefix of any length
RFC 6052 allows. Fragmented ICMP and IPv4 UDP without a checksum need the
whole datagram and go through a slow path in sixup, which reassembles,
translates and sends them back marked. Mappings conntrack has no flow for
are removed. Linux 6.6 or later is needed for tcx.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov-commenter

Copy link
Copy Markdown

Welcome to Codecov 馃帀

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered 鈽傦笍

cilium/ebpf grew the binary by 1.6 MB, past the 6 MiB limit, and its perf
package does not build for 32-bit big-endian MIPS. tools/bpfgen now
compiles bpf/nat64.c for either byte order at go generate time and writes
the instructions, maps, read-only data and relocations, and bpf.go loads
them with the bpf() system call alone. The slow path reads a BPF ring
buffer instead of a perf buffer. The binary is now 98 KB over main's.

The recipes and the standards document recommend -nat64 bpf, with Jool
for kernels older than 6.6, and sixup refuses to start when the pool
198.18.0.0/15 overlaps an address or route of the host, as it does for
Jool's /31.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@lqs
lqs merged commit 61a6b26 into main Oct 11, 2026
10 checks passed
@lqs
lqs deleted the nat64-bpf branch October 11, 2026 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants