Repository navigation
Releases: zozo6015/wireMesh
Release list
WireMesh v0.11.1
WireMesh v0.11.1
Patch release: the data-plane fix for the Phase-0 "receive-side cap" — a ~380× throughput defect in the gateway's embedded WireGuard engine.
Fixed
- gateway: boringtun's per-peer connected UDP socket never worked (#106).
boringtun 0.6.0 creates the per-peer connected socket withType::STREAM+
IPPROTO_UDP(device/peer.rs:120) — the kernel returnsEPROTONOSUPPORT
on every received packet, so the connected-socket receive fast path was
silently dead and the device loop drained ~286 pps (~3 Mbit/s TCP through
the tunnel, 97% receiver-side UDP loss asRcvbufErrors). Upstream fixed
this on master (b8c668f, PR #430) but never cut a release; WireMesh now
pins boringtun 0.6.0 plus that exact cherry-picked commit via
[patch.crates-io](fork revb8c6ddc). The patch retires the day a
crates.io boringtun release >0.6.0 containsb8c668f.
Measured (G-2 harness, netns + veth, MTU 1280, EPYC 9454P bare metal)
| Metric | v0.11.0 | v0.11.1 |
|---|---|---|
| TCP through the tunnel (pinned 4 vCPU) | 3.04 Mbit/s | 966 Mbit/s |
| TCP through the tunnel (unpinned) | — | 1.15 Gbit/s |
| UDP 100M offered, receiver loss | 97% | 0% |
Evidence chain: docs/research/g2-bet1-receive-cap-reproduced-on-bare-metal.md
(#104) and docs/research/g2-root-cause-one-word-boringtun-fix.md (#105).
Notes
- No config, proto, or CLI surface changes; drop-in replacement for v0.11.0.
- All 7 CI jobs green on the PR, including the netns conformance suites —
the first behavioural exercise of the now-working connected-socket path
(mesh, NAT matrix, relay, rotation all pass unchanged). - G-2 formal standing: single-flow meets the ≥1 Gbps bar unpinned on EPYC
(966 Mbit/s pinned; per-core clocks below the reference c6i.xlarge); the
8-tunnel aggregate half still needs its harness.
WireMesh v0.11.0
v0.11.0 — version fields on the wire (B10)
Minor release. Additive proto fields and a schema migration (SCHEMA_V4); no behaviour depends on the new fields.
Added
- Every gateway and relay now reports its version.
WatchRequestandEnrollRequestcarryclient_version(gateways alsomax_ir_schema); everyStateSnapshotcarriescontroller_versionandmin_supported_version;Admin.ListGatewaysexposes the reported pair. The controller stores these and never consults them in this release — no gating of any kind. Shipping them now is what makes a future skew policy (PRD X-6: controller vN supports vN and vN−1, one minor, non-cumulative) able to attribute v1.0 peers at all. (PR #94) min_supported_versionis derived from the controller's own version, not hand-maintained (the previous minor once ≥ 1.0.0; the controller's own minor before that), so the advertised floor cannot go stale at a release. Advertised, not enforced.SCHEMA_V4:gateway.version,gateway.max_ir_schema,relay.version— all nullable; a never-reported value isNULL, never""/0. Relays have no policy IR, sorelaydeliberately has nomax_ir_schemacolumn.
Operator notes
- Legacy (pre-0.11) gateways and relays enroll and sync unchanged; their rows show
NULLfor the new columns. - The punch-retry log line now reads "broker re-punches on its ~5s sweep, up to a bounded retry budget".
Still off by default
Automatic key rotation remains off.
Full Changelog: v0.10.7...v0.11.0
WireMesh v0.10.7
v0.10.7 — the ROTATION STALLED warning names the right epoch
Patch release. Gateway-only.
Fixed
ROTATION STALLEDnamed the wrong epoch after an abort. The warning (introduced in v0.10.6) computed its target asold_epoch + 1; after a rotation abort the next directive skips an epoch, so the line an operator reads when a rotation is stuck named the aborted epoch beside the correct new tun. The epoch now comes from the rotation state machine's ownOverlapping { new_epoch }via a typed selection that cannot express the old arithmetic. (PR #93)
Test infrastructure
WIREMESH_TEST_OVERLAP_STALL_WARN_SECS(netns-tests feature only; compiled out of release binaries, verified with a positive control) lets the harness reach a genuine R2 stall in seconds instead of 90s. All test-only knobs now live inconfig::faultand nowhere else. The production threshold is unchanged at 90s.
Still off by default
Automatic key rotation remains off. Phase C items unchanged.
Full Changelog: v0.10.6...v0.10.7
WireMesh v0.10.6
v0.10.6 — a failed rotation unwinds itself (backlog item 9, route R1)
Patch release. Gateway-only; no proto or config change.
Fixed
- The rotation wedge (backlog item 9, route R1). A rotation that failed part-way left the gateway's rotation state machine parked off
Idle, andRotation::on_directiveis honoured only fromIdle— so the gateway silently ignored every laterRotateDirectiveuntil the process restarted, and the minted private key for the failed epoch survived on disk.handle_rotatenow unwinds its own failure synchronously: drops the in-flight role, tears the new epoch's tun down, evicts its enforcer, scrubs the orphan mint fromepoch_keys.json, and returns the state machine toIdlelast, so the next directive is honoured.EpochKeys::generate_nextis replaced bygenerate_next_at(n)— the gateway mints at the epoch the controller directed rather than keeping a second local counter that diverged the moment a scrub removed an entry. (PR #90) - Observability:
wiremesh_gateway_rotation_phase{phase}gauge androtation_aborts_total; aROTATION STALLEDwarning after 90s inOverlapping(route R2 is not aborted gateway-side — that would be a hard blackhole — it is surfaced). - Test-only fault hook (
netns-testsfeature; compiled out of release binaries, verified bystrings).
Found on the way
This release's done-bar (crates/wiremesh-gateway/tests/rotation_wedge.rs) found two controller defects that had been latent because clean aborts were never routine: the broker directing the aborted epoch's orphan sentinel (v0.10.4) and the tracker seeding from it and dropping the real epoch's ack (v0.10.5). This release depends on both.
Still off by default
Automatic key rotation remains off (no WIREMESH_ROTATION_INTERVAL = no timer). Route R1 of item 9 is closed; the timer stays off pending R2/R15 and the orphan-row lifecycle at abort ((C-drop)/(E)), all Phase C. Backlog item 34 records the 5s lost-directive window after an unwind (nothing retries a directive — C1).
Full Changelog: v0.10.5...v0.10.6
WireMesh v0.10.5
v0.10.5 — the rotation tracker seeds from the newest pending row
Patch release. Controller-only; no proto, config, or gateway change.
Fixed
- The controller's
RotationTrackerwas seeded from the oldestpendingkey row. After a gateway-side rotation abort (v0.10.x Phase B, backlog item 9), the aborted rotation leaves anawaiting-submissionsentinel row behind, and every later rotation's tracker was seeded from that orphan instead of the live rotation. The gateway's one-shotEpochAckfor the real epoch then failed the tracker's epoch check and was dropped silently, so the real epoch was not promoted until the orphan aborted (~300s) and a zero-ack grace promote fired (~390s total) — reaching the right state by the hazard path, not the designed one. Seen as a deterministic red inrotation_wedge's 120s poll (3/3). All three seed sites (seed_and_record_epoch_acks,drive_rotation_for,sweep_rotationsstep 2) now share one private selector that picks the max-epoch pending row, threaded to both the lazy seed and theevict_decisionstaleness input at the two sweep-side sites. (PR #88) - This is deliberately not the broker's newest-sentinel selector from v0.10.4: on
{orphan sentinel below an active epoch}the tracker must still seed the sentinel, because that tracker is the orphan's only garbage collector (AbortatABORT_AFTER→drop_pending_epoch); seeding nothing there strands the row andinitiate_due_rotationsskips the gateway permanently. A test pins the difference with the consequence in its failure message.
Observability
- The controller now logs an
EpochAckwhose epoch is not the rotation in flight (ignoring EpochAck(epoch=N) from gateway A for gateway B: the rotation in flight is epoch K). No state change on that path; a counter is a Phase-C item (the controller has no metrics surface yet).
Documented
docs/research/orphan-sentinel-mis-seeds-tracker.md— the mechanism, the ~390s self-heal (why a larger test budget would have passed a broken controller), the one-shot ack, and the measured site-guarding asymmetry (sweep_rotationsstep 2 is guarded only by the identity-stamp churn test, because step 2b re-arbitrates every gateway after it).docs/BACKLOG.mditem 35 (Phase C): make-before-break is enforced on the data plane, not on the roster — a rotating gateway destroys its retired key while the controller row still advertises itactive; the window exists on the healthy path, this release only shortens it back.
Still off by default
Automatic key rotation remains off (no WIREMESH_ROTATION_INTERVAL = no timer). This release clears the second controller defect found by the Phase-B rotation-wedge done-bar; the timer stays off pending the Phase-C items (R2/R15, (C-drop)/(E)).
Full Changelog: v0.10.4...v0.10.5
WireMesh v0.10.4
WireMesh v0.10.4
Patch release: the controller now directs a rotation only when the gateway's newest key row is still awaiting its key (PR1b, design Rev 1.40).
Fixed
- controller: after a gateway aborted a rotation cleanly, the aborted epoch's
pendingrow (sentinel pubkey) survived untilABORT_AFTER, andBroker::send_rotate_if_pendingselected the FIRST sentinel row in ascending epoch order — so the nextAdmin.RotateKeydirected the stale orphan epoch instead of the one it had just created; the gateway rotated to the stale epoch, refused the correct directives as in-flight, and the new epoch was never served. The broker now takes the max-epoch row over all rows and directs it only if it is a sentinel. Filter order matters: "highest sentinel" alone would later direct the orphan and rotate the fabric backwards, deleting the newer key.
Evidence
Six unit cases incl. the backwards-rotation guards; two falsification runs (.find() revert; filter-then-max) each redding exactly the cases that discriminate them; full controller suite green; no new clippy diagnostics.
Unchanged
Automatic key rotation stays off by default. Follow-ups filed for Phase C: an orphan pending row still suppresses timer-driven rotation for that gateway for up to 300s; epoch monotonicity guards on both sides.
Full diff: v0.10.3...v0.10.4
WireMesh v0.10.3
WireMesh v0.10.3
Patch release: relay ALPN pinned to one constant set with negotiated readback and distinguishable connect failures, plus a per-(peer, relay) connect back-off on the gateway (Phase B / D2, PR #82). Closes BACKLOG item 19.
Changed
- relay:
ALPN_V0/ALPN_SUPPORTEDare the single source of truth consumed by both server builders, the client endpoint, and the tests. The v1.0 client offerswiremesh-relay/0only (owner ruling 2026-08-25); a future/1is a one-line addition, and a test client offering[/1, /0]proves it negotiates/0. - relay:
Client::negotiated_alpn()reads the handshake result back; the registration log line carriesalpn="…"and a per-ALPN session counter (the deprecation anchor for/0). - relay: connect failures are classified at every
finish_connectstep on the raw error —AlpnMismatch,PeerRejectedCredentials(alert),Unreachable,Other— attached as the anyhow chain root; a credentials rejection surfaces at the ack read, not the connect. - gateway: a per-(peer, relay) connect back-off replaces the silent per-tick retry: 3 transient failures or 1 permanent (ALPN mismatch / rejected credentials) open a jittered window (30s base, 300s hard cap); an expired window always allows again, so a relay-only pair is never starved. An unparseable advertised endpoint is recorded like any other failure (found in review).
Evidence
relay/tests/alpn.rs8/8; relay lib + 14 integration targets green; gateway lib 114 +punch_backoff9 +relay_connect_backoff14 green.relay_matrixnetns done-bar full marks (3 passed, case5 ignored by design): the symmetric-NAT pair stayspath_state=relayed; relay eviction re-paths; relay-leg death recovers a real direct path.- Clippy identity diffs vs main: no new diagnostics in either crate.
Unchanged
Automatic key rotation stays off; unaffected by this release.
Full diff: v0.10.2...v0.10.3
WireMesh v0.10.2
WireMesh v0.10.2
Patch release: closes BACKLOG item 5 — the controller's Retire{0} wedge (Phase B / S3, PR #80).
Fixed
- controller: a rotation tracker seeded from a key snapshot with no
activerow gotprior_active_epoch = 0; once promoted it yieldedRetire{0}on every tick,Db::retire_epoch's CAS matched nothing forever, and the stale tracker silently cost the next rotation its firstEpochAck(falling back to the 90s grace promote).prior_active_epochis nowOption<u32>end to end, the coercion is gone from all three seed sites (drive_rotation_for,sweep_rotationsstep 2, and theSync.Reportack path via the hoistedseed_and_record_epoch_acks), anddecideyields the newRotationDecision::Finished— the tracker clears with no DB call.
Evidence
- Full
wiremesh-controllersuite green (47 targets); 54 lib tests incl. five new pins. - Falsification: each seed site's
.or(Some(0))restored in turn turned exactly its own test red (3 runs, 12/12 results), andrecorded_session_generation's unrelated.unwrap_or(0)is pinned as not-a-seed-site. - Clippy identity diff vs main: no new diagnostics.
Unchanged
Automatic key rotation stays off by default. This was hardening, not a timer gate; BACKLOG item 9 (the gateway rotation wedge, PR1/B2) is the remaining code gate, and the timer stays off pending R2/R15 (Phase C).
Full diff: v0.10.1...v0.10.2
WireMesh v0.10.1
v0.10.0 was tagged but never published: its Release workflow failed in
the linux-binaries jobs because deploy/docker/Dockerfile ran an unpinned
cargo install bpf-linker, upstream released 0.11.0 (which links against
system LLVM), and rust:1-bookworm ships no llvm-config. Nothing in this
repo had changed -- the same content built green two days earlier. This
release pins bpf-linker to 0.10.4 (the version the dev container carries
and the whole test suite is proven against) in both Dockerfiles, and is
otherwise v0.10.0. Its notes follow, and they apply in full.
Note for CI: container-images.yml restores a cached builder layer, so it
never re-ran the install and stayed green; only the cold build in
release.yml reaches that line. The failure mode is invisible until a
release. (Tracked under B4 in the v1.0 release-scope inventory.)
v0.10.0 — automatic key rotation is opt-in; every artifact reports its real version
BEHAVIOUR CHANGE, read before upgrading. An absent WIREMESH_ROTATION_INTERVAL
used to mean "rotate every gateway every 30 days". It now means NO TIMER.
Automatic key rotation is opt-in in every deployment path -- .deb/.rpm,
container image, and source build alike. If you were relying on the old
default, this upgrade silently stops rotating and you must set an explicit
interval to get it back.
Why: the timer pointed at a known-open defect (BACKLOG item 9, the rotation
wedge). A rotation that fails part-way parks a gateway's state machine
off-idle, and that gateway then silently ignores every later rotation until
its process restarts, never scrubbing the old key. The schedule is what makes
that fabric-wide. Explicit intervals, off, and every malformed-value
rejection are unchanged.
Know before you arm it: on-demand rotation has NO CLI. The Admin RotateKey
RPC exists and works, but fabricctl does not wrap it, so triggering a
rotation means a hand-rolled gRPC call against an Admin service that binds
loopback-only by design -- from the controller host. Earlier releases
documented fabricctl rotation as the supported path; that was never true.
Tracked as BACKLOG item 33.
FIXED: every published container image reported 0.1.0. container-images.yml
never invoked scripts/set-version.sh, so controller, gateway, relay,
fabricctl and operator images all self-reported the placeholder on every
release. Binaries and packages were always stamped correctly. This is the
first release whose images report their real version. set-version.sh also
gained wiremesh-operator, which it had never stamped.
Also: the README described a project three cycles stale and linked to
neither install guide; the spike/ directory (8 throwaway Phase-0 crates,
8 of 10 open Dependabot alerts) is deleted; and the controller --help
DEPLOYMENT block, wrong three ways since v0.8.0, is corrected.
What's Changed (since v0.9.2 — v0.10.0 was never published)
- fix(controller): automatic key rotation is now opt-in everywhere by @zozo6015 in #73
- fix(release): stamp the version into every shipped artifact by @zozo6015 in #74
- docs: rewrite the README, delete spike/, fix the manual-rotation claim by @zozo6015 in #75
- fix(build): pin bpf-linker to 0.10.4, unbreaking the release build by @zozo6015 in #76
Full Changelog: v0.9.2...v0.10.1
WireMesh v0.9.2
What's Changed
Full Changelog: v0.9.1...v0.9.2