Agent (edge-agent, ea)¶
One static Go binary per router CPU, started by procd (/etc/init.d/edge-agent,
link shipped in the image). Source: edge/agent.
Loop¶
Every poll (1 min, 5 s while a change waits for confirmation, sooner when the control plane pushes):
- Roll back a change that was never confirmed (also right after a restart).
GetDesiredState. Success confirms a pending change.- Converge: a new version is rendered to uci lines and applied through the guard. A version that failed or was rolled back is not retried until the control plane sends a new one.
- Maintain: put VXLAN back into its bridge if it fell out; home re-discovers its endpoints every 10 min (renews leases); travel re-dials a path whose last handshake is older than 3 min.
ReportState: key, endpoints, active endpoint, last handshake, apply status. Success confirms a change applied in this sync.
Alongside: the path watcher (probe each path every 2 s, fail over after 2 misses, move back after 3 good probes) and the realtime client (WebSocket, heartbeat every 30 s, reconnect with backoff, "state changed" and debug commands).
Packages¶
| Package | Role |
|---|---|
internal/netconfig |
Facts (stock uplink, LAN bridge), render uci lines, bridge repair |
internal/guard |
Snapshot network, firewall, dhcp; apply; confirm or roll back; deadline on flash |
internal/ladder |
Home endpoint discovery (IPv6 pinhole, UPnP mapping); travel dialer (wg set live, proof = ping reply through the path) |
internal/pathwatch |
Route VXLAN over a healthy path |
internal/realtime |
WebSocket client, debug command execution (timeout, 64 KB cap) |
internal/wireguard |
Key on first start (crypto/ecdh X25519); private key never leaves the router |
internal/identity, internal/fsutil |
Atomic writes (temp + fsync + rename) |
internal/doctor |
ea doctor checks |
CLI¶
| Command | |
|---|---|
ea serve |
The daemon |
ea status |
Identity, role, config version, last sync, apply status, endpoints, paths, path in use |
ea sync |
Ask the daemon to sync now (SIGUSR1) and wait for the result |
ea enroll |
Enroll again; a running daemon switches to the new identity |
ea doctor |
Enroll code, identity, DNS, HTTPS (clock hint), token; exit 1 on failure |
ea version |
All take --json. Files: /etc/jumo/agent.json (overrides),
identity.json, wg.key, facts.json, desired.pb, rollback/ (pending
change); /var/run/jumo/status.json, agent.pid.
Lessons from the lab (each has a test or a code comment)¶
- Replace a running binary by temp file + rename (ETXTBSY).
- Log to stdout: procd files stderr as
daemon.err. - Ship
/etc/rc.d/S99edge-agentin the image: anenablefrom uci-defaults only works from the second boot. - No VXLAN
tunlink: a WireGuard restart destroyed the VXLAN device. - Allow SSDP replies (UDP source port 1900) on the uplink, or UPnP looks absent.
- Request a pinhole for the address the kernel uses as source; keep a stable
SLAAC address (
wan6.reqaddress=none). - Judge a dialed endpoint by a reply through its interface, not by a new handshake (established sessions do not renegotiate for 2 minutes).