Derive default network ranges and switch overlapping networks
Every first network previously proposed 10.13.37.0/24. Independently created networks therefore collided when a device joined more than one of them. Use the existing stable NetworkId-derived /24 in 10/8 for every new network, independent of activation order or peer availability. Legacy and explicit signed ranges outrank the derived default; remaining range disagreements still use author-id ordering. The derivation, identity labels, handshake and signed record encoding stay unchanged. There is no creator, timestamp or vote. Reserve ranges before starting network actors and serialise start, stop and switching through the agent lifecycle lock. Refuse equal or nested overlaps without changing a network's subnet locally. A late authenticated range that collides suspends only its network before updating plugins or the interface. Coalesced watch notifications let the agent clean up outside the network actor and reconsider suspended networks when ranges change. An explicit switch stops every blocker before activating the chosen network. Suspended networks retain their startup request and resume whenever their ranges become free, including switching from a wide range to a narrow one. A manual stop cancels that request even for an already suspended network. Persist preference order and enabling together in an SQLite transaction so the user's selection survives restart; no database schema migration is needed. CLI status and network listing show blocker names, ids, ranges and the start command. Network start switches explicitly and reports suspended networks; joining an overlapping network reports it as configured but inactive. The tray adds conflict details, an amber icon, Switch to this network and Keep stopped actions. Local IPC wire version is 19 for the extended reports, so restart the agent and tray together. Release versions and peer wire formats are unchanged. Update the user documentation and compatibility tests. Validation on Linux through nix develop: - cargo fmt --all -- --check - cargo clippy --locked --workspace --all-targets -- -D warnings - cargo test --locked --workspace --all-targets with TSUNAGI_CONTROL_SOCKET removed from the test environment: 486 passed, 2 pre-existing ignored tests - final focused range_conflicts integration suite after making discovery fixtures deterministic: 6 passed Earlier validation attempts caught outdated diagnostic assertions, a new test helper scope error, and the inherited system control socket override. Those were corrected before the successful runs. Plain cargo was unavailable in the host shell, so validation used the Nix development toolchain. macOS, Windows, privileged host TUN operations and manual tray interaction were not exercised.
This commit is contained in:
1 parent
781e359775
commit
ed28e86748
24 files changed
+1291
-318
No files matched your search
@@ -98,6 +98,13 @@ a batch does not stop the rest, and allocation is deterministic, spread out,
|
||||
walks past everything taken and reports a full range instead of handing out a
|
||||
duplicate.
|
||||
|
||||
`tests/range_conflicts.rs` checks isolated first members choosing the same
|
||||
range, persistence across restart, preservation of legacy ranges, exclusion
|
||||
of equal and nested ranges, late authenticated conflicts, switching all
|
||||
blockers, automatic resume, cancelling a suspended network's resume and
|
||||
concurrent switch requests. These use real agents, loopback handshakes and
|
||||
SQLite; they do not change host network settings.
|
||||
|
||||
`tests/local_control.rs` covers the local control socket end to end: a client
|
||||
asking a running agent for status over a real Unix socket, joining and
|
||||
leaving a network through it, a leftover socket file being replaced while a
|
||||
|
||||
+30
-7
@@ -92,8 +92,8 @@ and then recorded as a signed fact**, using the model in
|
||||
[sync-model.md](sync-model.md).
|
||||
|
||||
```text
|
||||
default range 10.13.37.0/24 (override with --ipv4-range)
|
||||
who decides the first member to claim; later ones adopt what they find
|
||||
default range stable pseudorandom /24 in 10/8, derived from NetworkId
|
||||
who decides all members derive the default; signed explicit ranges win
|
||||
who signs the claiming member, with its persistent device key
|
||||
where it is kept state.sqlite, and every replica that has seen it
|
||||
what a return costs nothing: the old address is reclaimed
|
||||
@@ -120,11 +120,34 @@ the same address at the same moment are resolved by a rule both compute
|
||||
identically — the lower endpoint id keeps it — and the loser simply allocates
|
||||
again with a higher version.
|
||||
|
||||
**The range is agreed, not configured per member.** `--ipv4-range` says what
|
||||
this agent would use; a network that has already settled on something else
|
||||
wins, and the agent adopts it. So the flag matters for whoever starts the
|
||||
network and is harmless afterwards. Pass `--ipv4-range none` for an IPv6-only
|
||||
overlay.
|
||||
**The range is agreed, not configured per member.** New networks use the
|
||||
same deterministic `/24` on every device, independently of which network a
|
||||
member activates first or whether any peers are reachable. The derivation
|
||||
is unchanged from the former fallback; network identity and signed record
|
||||
encoding are unchanged. Distinct network ids can still derive the same range.
|
||||
|
||||
`--ipv4-range` proposes an explicit range; existing signed ranges take
|
||||
precedence over the new derived default, including the former `10.13.37.0/24`.
|
||||
Among disagreeing non-default ranges the lowest author id still wins. Updated
|
||||
members propagate their adopted range in their signed claims; older releases
|
||||
still apply their original selection rule until those claims converge.
|
||||
`--ipv4-range none` disables local proposals, as before.
|
||||
|
||||
An agent reserves each active network's range before starting its runtime.
|
||||
Overlapping ranges, including nested blocks such as a `/24` inside a `/16`,
|
||||
cannot run simultaneously. A late authenticated state update that introduces
|
||||
an overlap suspends that network before publishing new allocations to plugins
|
||||
or the interface. Other networks continue running.
|
||||
|
||||
Status includes every blocking network's name, id and range. `tsng network
|
||||
start <name-or-id>` and the tray's switch button stop all blockers before
|
||||
starting the selected network. Suspended networks keep their startup request
|
||||
and resume when the blocker stops or is forgotten. A manual stop cancels that
|
||||
request even for a network already suspended. The user's preference order is
|
||||
stored locally, so the same selection wins at the next startup; it is never
|
||||
advertised or treated as a remote network setting. Local IPC uses wire version
|
||||
19 for the new reports: restart the agent and tray together after upgrading.
|
||||
The peer control protocol and signed record encoding do not change.
|
||||
|
||||
The agent puts the address on the interface itself, as soon as the network has
|
||||
agreed on it — no restart, and the interface is not recreated, which would
|
||||
|
||||
Reference in new issue
Block a user