Skip to content

v0.0.1 feasibility slice: workspace, config parser, §2.1 capability probes#1

Merged
lunarthegrey merged 2 commits intomainfrom
v0.0.1-feasibility-slice
Apr 20, 2026
Merged

v0.0.1 feasibility slice: workspace, config parser, §2.1 capability probes#1
lunarthegrey merged 2 commits intomainfrom
v0.0.1-feasibility-slice

Conversation

@lunarthegrey
Copy link
Copy Markdown
Contributor

@lunarthegrey lunarthegrey commented Apr 20, 2026

Summary

  • Stands up the Cargo workspace (common, cli, modules/fast-path), the line-based config parser (SPEC.md §6), the Module trait (§3.2), and a fully implemented packetframe feasibility subcommand that probes the host kernel for every requirement in SPEC.md §2.1 via direct bpf() syscalls — without loading any BPF programs.
  • Fast-path ships as a stub that returns NotImplemented from its lifecycle methods; real BPF loading, VLAN choreography, metrics, and the circuit breaker land in v0.1 per the approved plan.
  • CI (fmt / clippy -D warnings / test / cross-build ×4 targets via cross) and a tag-triggered release workflow (musl + gnu × aarch64 + x86_64, SHA256SUMS, optional GPG signature) are in place so v0.1 arrives as a drop-in binary upgrade.

Why this slice first

Rather than start on BPF code directly, v0.0.1 forces the scaffolding into existence: crate layout, config grammar, trait shape, toolchain pins, cross-compile, and release pipeline. It also gives operators the capability probe immediately — the first thing to run on a new host. Everything in v0.1 slots into this scaffolding without shape churn.

What's covered

  • Config parser with 20 unit tests: reference EFG config, unknown-directive rejection, per-line error messages, of rx reserved-but-rejected for forward-compat, interface existence check against /sys/class/net.
  • §2.1 probes: kconfig (gz-decoded /proc/config.gz with /boot/config-$(uname -r) fallback), bpf() syscall reachability, XDP + sched_cls program types, all six required map types (hash, array, percpu_array, lpm_trie with BPF_F_NO_PREALLOC, devmap_hash, ringbuf sized to survive 16 KiB page hosts), nine required helpers via minimal verifier-log probes, bpffs magic check, IPv4/IPv6 forwarding sysctls, RLIMIT_MEMLOCK.
  • Linux-only code is cfg-gated so cargo check/test succeed on macOS dev laptops; non-Linux stubs return ENOSYS and the report marks every BPF capability as Fail.
  • Per-interface native-XDP trial-attach (§2.3) is reported as Deferred — it needs a real program and will be wired up alongside the fast-path module in v0.1.
  • CLI via clap: feasibility (JSON default, --human for table); run parses config and runs probes before stubbing module load; detach/status/reconfigure/map exit 2. Exit codes match SPEC.md §7.3.

Reviewer notes

  • Probing helpers by verifier log is heuristic but tight: only the strings unknown func / unrecognized bpf_func_id / invalid func are treated as "helper missing". EPERM and ENOSYS outcomes are surfaced as Unknown/Fail rather than smuggled into a false Pass — see probe_helper in crates/common/src/probe/mod.rs.
  • Cargo.lock is committed since PacketFrame ships as a binary.
  • The design spec (SPEC.md) is deliberately not in the repo; inline code comments reference section numbers as breadcrumbs (e.g. "SPEC.md §4.2") so reviewers who have the spec can cross-check, and readers who don't still get structured pointers.
  • Toolchain is pinned to stable in rust-toolchain.toml. The split stable/nightly arrangement (SPEC.md §7.1) lands in v0.1 when the BPF crate appears under crates/modules/fast-path/bpf/.
  • Release workflow uses softprops/action-gh-release@v2 with generate_release_notes: true. GPG signing is opt-in via PACKETFRAME_GPG_KEY / PACKETFRAME_GPG_KEY_ID secrets — the step is skipped if either is unset, so initial releases can land before keys are provisioned.

Test plan

  • CI workflow passes on this PR (fmt + clippy + test + cross-build ×4).
  • cargo test --workspace locally: 32 tests pass.
  • cargo fmt --all --check and cargo clippy --workspace --all-targets --all-features -- -D warnings clean.
  • cargo build --release produces a working binary; ./packetframe --help and ./packetframe --version report correctly.
  • On a Linux host with BPF enabled, sudo packetframe feasibility --human reports every required capability as PASS and exits 0.
  • On the reference EFG (5.15.72-ui-cn9670, aarch64), packetframe feasibility --json output is archived as phase-0-feasibility-efg.json per SPEC.md §10.3.
  • packetframe feasibility --config conf/example.conf cleanly rejects with an interface-missing error on any host that isn't the reference EFG.
  • Deliberate-regression check: flip net.ipv4.ip_forward=0 on a test VM; the probe reports the exact sysctl to fix and exits 1.
  • After merge, tag v0.0.1 and confirm the release workflow publishes four tarballs with SHA256SUMS.

🤖 Generated with Claude Code

lunarthegrey and others added 2 commits April 20, 2026 02:57
This is the feasibility slice of the approved plan
(plans/i-m-handing-you-a-stateless-simon.md). It stands up the Cargo
workspace, config grammar, Module trait, and a `packetframe feasibility`
subcommand that probes the host kernel for the requirements in SPEC.md
§2.1 — without loading any BPF programs yet. The fast-path module ships
as a stub whose lifecycle methods return NotImplemented; the real BPF
program, aya loader, VLAN choreography, metrics, and circuit breaker
land in v0.1.

Why ship this first: it forces the crate layout, config grammar, trait
shape, toolchain pins, cross-compile, CI, and release workflow into
existence before any verifier work. The feasibility command is also
standalone-useful — the first thing an operator runs on a new host to
confirm the kernel can support PacketFrame at all.

What's in the slice:

- Cargo workspace: crates/common, crates/cli, crates/modules/fast-path.
- Config parser (SPEC.md §6): full grammar, strict unknown-directive
  rejection, interface-existence check against /sys/class/net, 20 unit
  tests including the reference EFG config. Circuit-breaker grammar
  accepts `of matched` today and rejects `of rx` with an explicit
  future-reservation message.
- Module trait (SPEC.md §3.2): shaped for the future libxdp dispatcher
  (priorities declared but not consulted in single-module MVP per §3.4).
- Capability probes (SPEC.md §2.1) via direct bpf() syscall: kconfig
  flags from /proc/config.gz or /boot/config-$(uname -r), syscall
  reachability, XDP + sched_cls program types, all six required map
  types (hash, array, percpu_array, lpm_trie, devmap_hash, ringbuf),
  nine required helpers via minimal verifier-log probes, bpffs mount
  check, IPv4/IPv6 forwarding sysctls, memlock. Per-interface
  native-XDP trial-attach (§2.3) is reported as Deferred — it needs a
  real program and lands with fast-path in v0.1.
- Linux-only code is cfg-gated so cargo check/test also succeeds on
  macOS dev laptops; non-Linux hosts receive ENOSYS-returning stubs and
  the report flags every BPF capability as Fail.
- CLI: `feasibility` (JSON default, --human for a table) is fully
  implemented; `run` parses config and runs probes before stubbing
  module load; `detach`/`status`/`reconfigure`/`map` exit 2. Exit codes
  follow SPEC.md §7.3.
- Fast-path stub crate claims NativeXdp at priority 1000; lifecycle
  returns NotImplemented except detach/sample_metrics/health_check
  which no-op so teardown paths are safe.
- conf/example.conf matches SPEC.md §4.8 for the reference EFG.
- CI: fmt, clippy -D warnings, test on ubuntu-latest plus cross-build
  of all four release targets via `cross`.
- Release workflow: tag-triggered, four tarballs (aarch64/x86_64 ×
  musl/gnu) with SHA256SUMS and optional GPG signature.

Verified locally:

- 32/32 workspace tests pass
- cargo fmt --check clean
- cargo clippy --all-targets --all-features -D warnings clean
- Release build produces a ~1.3 MB static binary
- `packetframe feasibility --human` runs end-to-end on macOS and
  correctly reports every BPF probe as Fail, exit code 1

Not done in this slice (per the plan's forward view): aya-ebpf
toolchain setup, BPF program compilation, XDP attach/detach, VLAN
push/pop/rewrite, metrics textfile, circuit breaker loop, SIGHUP
reconcile, QEMU verifier CI, on-EFG acceptance archival.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`statfs.f_type` is `u32` on macOS but `i64` on glibc Linux x86_64, and
`libc::syscall`'s return is `i64` on 64-bit Linux but `i32` on 32-bit.
Both casts are needed on at least one target but no-ops on another,
triggering `clippy::unnecessary_cast` on whichever target already has
the destination type. Add targeted `#[allow]`s with the rationale
inline rather than diverge the cfg branches — the casts stay because
they're load-bearing on any non-default target (32-bit Linux, any musl
flavor whose `f_type` happens to be `u64`).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lunarthegrey lunarthegrey merged commit ca0e0f6 into main Apr 20, 2026
5 checks passed
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.

1 participant