Skip to content

0.9.26 — rootless: create_epair (first response-data verb)#184

Merged
click0 merged 1 commit into
mainfrom
claude/release-0.9.26
May 9, 2026
Merged

0.9.26 — rootless: create_epair (first response-data verb)#184
click0 merged 1 commit into
mainfrom
claude/release-0.9.26

Conversation

@click0
Copy link
Copy Markdown
Owner

@click0 click0 commented May 9, 2026

Summary

Twenty-seventh 0.9.x release. First response-data verb + last iface verb needed for full host-side plumbing.

Wraps IfconfigOps::createEpair() — kernel auto-assigns the next free epair unit number, verb returns the A/B iface names so client can plumb them downstream.

What lands

New privops verb

create_epair — no request fields. Response body shape:

{"created":true,"a":"epair17a","b":"epair17b"}

First verb whose response carries non-trivial data. Previously all verbs returned status + confirmation body the client could ignore. create_epair is different because the operator needs the assigned names for next steps (move B-half into vnet, attach A-half to bridge).

Wire protocol

  • Daemon: formatCreateEpairSuccess(a, b) produces the JSON.
  • Client (run_net.cpp): receives Response.body as JSON string, calls existing PrivOpsWirePure::extractStringField twice. No new JSON parser — extractStringField already handles top-level string fields.
  • libnv transport wraps the same JSON body in nvlist, both transports use the same client-side extraction.

CLI wiring

createEpairPrivopsOrLocal() returns std::pair<std::string, std::string>. Two call sites migrate (lines 239 / 518) — both auto epairPair = IfconfigOps::createEpair(); patterns.

🎉 Milestone: full host-side iface plumbing via privops

All 5 IfconfigOps::* operations crate run uses now have privops paths:

Op Release
createEpair 0.9.26 (this PR)
disableOffload 0.9.23
setUp 0.9.23
setInetAddr 0.9.25
bridgeAddMember / DelMember 0.9.24

Combined with 0.9.22 createJail and 0.9.21 removeJail, crate run and crate stop no longer need root for any privileged step when the privops socket is detected. Legacy setuid fallback is now optional.

Trade-offs

  • JSON body extraction at the client. Native nvlist responses (per-verb structured fields) would be cleaner for libnv but require refactoring 14 handlers. JSON-in-nvlist ships today.
  • No retry on transient failures. If create_epair succeeds on daemon but response is dropped, an orphan epair leaks. Same as direct IfconfigOps::createEpair() constraint.

Test plan

  • 1 new ATF test in privops_pure_test (create_epair_no_fields_required)
  • 1 new ATF test in privops_wire_pure_test (format_create_epair_response_extracts) — locks down the response shape AND verifies it round-trips through the client's extractStringField extraction path
  • verb_token_roundtrips_for_every_verb updated
  • Suite: 1299 → 1301
  • FreeBSD CI must pass

Series state

Remaining:

  • 0.9.27 — network_lease.cpp per-user paths + RCTL umbrella (uses 0.9.10 sub-CIDR + 0.9.11 loginclass)
  • 0.9.28 — default flip (rootless_per_user: true becomes default)
  • 1.0.0 — setuid bit removed from Makefile

Files

Same set as 0.9.23-0.9.25 plus tests/unit/privops_wire_pure_test.cpp.


Generated by Claude Code

Twenty-seventh 0.9.x release. Wraps IfconfigOps::createEpair —
kernel auto-assigns next free epair unit number, verb returns
the A/B iface names so client can plumb them downstream.

create_epair — no request fields. Response body:
  {"created":true,"a":"epair17a","b":"epair17b"}

First verb whose response carries non-trivial data.
Previously all verbs returned status + confirmation body the
client could ignore. create_epair is different because operator
NEEDS the assigned names for next steps (move B to vnet, attach
A to bridge).

Wire: daemon handler builds JSON via formatCreateEpairSuccess.
Client (run_net.cpp) calls existing PrivOpsWirePure::
extractStringField twice (for a + b). No new JSON parser
needed.

CLI wiring: createEpairPrivopsOrLocal returning std::pair.
Two call sites migrate (lines 239 / 518).

Full host-side iface plumbing via privops now achieved:
createEpair (this) / disableOffload (0.9.23) / setUp (0.9.23) /
setInetAddr (0.9.25) / bridgeAddMember (0.9.24) — all 5 IfconfigOps
ops crate run uses have privops paths. With 0.9.22 createJail
and 0.9.21 removeJail, crate run and crate stop no longer need
root for any privileged step when privops socket detected;
legacy setuid fallback is now optional.

2 new ATF tests + verb_token_roundtrips updated.
Suite: 1299 -> 1301.

Remaining: network_lease per-user (0.9.27), default flip
(0.9.28), setuid removed (1.0.0).
@click0 click0 merged commit d49d57f into main May 9, 2026
2 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.

2 participants