8.5 KiB
topic, status, date, deciders, reconstructed, extends
| topic | status | date | deciders | reconstructed | extends |
|---|---|---|---|---|---|
| what runs on it | accepted | 2026-09-26 | jochen | false | 0110-a-seat-is-a-module-assignment-from-a-closed-set.md |
117. A machine's uplink is a seat: the mesh configures the manager, never the link
Context
The mesh installs on top of a machine's own networking. The private network's generator says so in as many words: a machine has an address and a route to the broker before the mesh exists, the broker's address travels in the enrolment token rather than being resolved, and the private network is something the mesh installs on top, like anything else. Nothing in the mesh says who manages that uplink, or what the mesh needs from whoever does.
Adopting the first workstations showed that the mesh does need something from it, and gets it by accident:
- The resolver the mesh owns depends on a file the mesh does not.
resolv-confwrites/etc/resolv.confand names the mesh's resolver. On a machine running NetworkManager, the manager rewrites that file on every connectivity change unless it is tolddns=none; on one running dhcpcd, every lease renewal rewrites it unless it is toldnohook resolv.conf. On the adopted machines both settings exist only because the predecessor wrote them. No module declares them. Remove the predecessor's file and the mesh's resolver is silently replaced the next time a laptop changes network, while every surface of the mesh still reads green. resolv-confcannot declare them itself. Which setting is needed depends on which manager runs, and aserviceresource for a manager that is not installed fails the declaration. A resolver module that knew about network managers would be the wrong module knowing the wrong thing.- The private network's interface is exposed to the manager. A manager that considers
every interface its own may try to configure
mesh0, or tear it down on a profile change. Nothing tells it not to. - Two managers on one machine go unnoticed. Among the machines adopted so far, one runs NetworkManager and dhcpcd at once: two programs that each believe they own the machine's addresses and its resolver file. Nothing detected it, because nothing in the mesh knows the role exists.
The machines differ in a way that matters: servers are wired and never move, while workstations join wireless networks, captive portals and phone hotspots wherever they are.
Considered Options
1. The mesh manages the uplink: links, addressing, wireless networks and their
credentials. Rejected. The mesh reaches a machine only over that link. A declaration that
gets it wrong — a mistyped network, a stale credential, a manager that fails to start — takes
the machine off the network, and with it the only channel a fix could arrive on. That is the
one failure the sshd module's listens rule forbids the firewall to arrange; a mesh that owned
the link could arrange it with any push. And a wireless network is joined at the machine, by
the person using it, in the moment. A declaration composed elsewhere cannot answer a captive
portal.
2. Leave the uplink unmanaged; accept the implicit dependency. Rejected. It keeps the resolver working only for as long as a predecessor's file survives, and it leaves two managers on one machine undetectable.
3. The uplink is a seat. The module holding it configures the manager's relationship to the mesh, and never the link. Chosen.
Decision
the-uplink is a node-scoped seat in the closed set (ADR 0110).
It delivers no provision. It is held by the module for the program that manages the machine's
own network, one per manager: networkmanager, systemd-networkd, and dhcpcd for a machine
with nothing more. Assigning a second is refused, naming the first.
What a holder declares — only what keeps the manager and the mesh from contradicting each other:
- the manager's package, present — and its service with no state: the manager's lifecycle is the machine's. The mesh never starts, stops, enables or disables it, because stopping it takes the link down, and a holder unassigned by mistake — or the wrong holder assigned — must not be able to do that, nor start a second manager beside the one the machine runs. The service is declared only so a change to the holder's settings reaches a running manager;
- the manager's own configuration that leaves the resolver file to the mesh (
dns=nonefor NetworkManager,nohook resolv.conffor dhcpcd, and nothing for systemd-networkd, which never writes the resolver file); - the manager's own configuration that leaves the private network's interface alone
(NetworkManager's
unmanaged-devicesnamingmesh0; dhcpcd'sdenyinterfaces mesh0; for systemd-networkd a network file of the module's matchingmesh0asUnmanaged=yes); - each as a drop-in beside the manager's main file where the manager reads one, and written
into a shared file otherwise, as a marked region the host owns
(ADR 0102's idea for text files),
placed where the manager reads it as global — at the start of
dhcpcd.conf, above anyinterfaceline, because every line after one belongs to that interface; - the service reloaded when a drop-in changes, never restarted — a restart drops the link,
and the link is the mesh's own channel to the machine. A manager that cannot reload is not
restarted instead: its setting takes effect at the manager's next start. Measured on the
adopted machines: NetworkManager (1.58) and systemd-networkd (systemd 261) both report
CanReload=yes; dhcpcd (10.3) reportsCanReload=no, so its module declares no trigger at all. Whether each setting is actually applied by a reload is confirmed on a machine before the module is taken there, not assumed.
What a holder never declares: a link, an address, a route, a connection profile, a
wireless network or its credentials. Those are the operator's, in the sense of
ADR 0051: the mesh does not create, change or delete
them, and the module's access, if it needs one, is read-only.
Consequences
resolv-confstays generic. The condition it could not express — "only if NetworkManager runs" — is expressed by assigning the module for the manager that does.- The dependency on the predecessor's
dns=nonefile becomes a declared resource. On an adopted node the holder's drop-in arrives beside the predecessor's; both say the same thing, and the predecessor's is retired by hand after the take, like any other file the mesh replaced under another name. - A setting a manager reads only at its start is not in force until then. On an adopted machine the predecessor's identical line normally already is; on a machine that was not adopted, dhcpcd's resolver hook keeps rewriting the resolver file until dhcpcd next starts, and the operator restarts it once, in a window of their choosing.
- A machine running two managers is found at assignment: the second holder is refused, and the operator decides which manager the machine keeps before either module is taken.
- Workstations keep joining networks the way they always have. Under NetworkManager and systemd-networkd the host already cooperates with the manager — its dispatcher hook wakes it on every connectivity change — and nothing here changes that. A dhcpcd-only machine has no such hook, and nothing here adds one.
- The seat table gains one entry:
the-uplink, node scope, delivering nothing, decided here. - Not decided here: whether the mesh should ever offer known networks to a machine — a sealed, add-only list the operator curates once for all workstations. That is a different question (the mesh holding credentials for links it must never be able to break) and gets its own record if it is wanted.
References
- ADR 0110: the closed set this seat joins; to-be 26: the seat table
- ADR 0102: written into, never over
- ADR 0051: what is the operator's stays the operator's
- mesh-controller
internal/catalogue/seats.go(the seat),internal/overlay/generator.go(the mesh installs on top of the machine's own networking) - mesh-catalog
modules/networkmanager,modules/systemd-networkd,modules/dhcpcd - mesh-host
internal/apply/block.go(a file written into a marked region,atstart or end)