forked from mariux64/mxtools
-
Notifications
You must be signed in to change notification settings - Fork 0
mx-networkd: replace mxnetctl/mxvlanctl with a systemd-networkd generator #1
Open
pmenzel
wants to merge
5
commits into
master
Choose a base branch
from
mx-networkd
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
bf0ca37
mx-networkd: Add a systemd generator for the MarIuX network configuraβ¦
87f4d1a
Makefile, install.sh: Build and install mx-networkd
9f031a9
mx-networkd: Make the migration switchover reboot-based
82d8245
mx-networkd: Condition the switchover on hostconfig tag mx-network-geβ¦
264f72a
mx-networkd: Add migration helper script
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| setuid/setuid | ||
| prun/*.1 | ||
| mx-networkd/target/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
etc/systemd/system/systemd-networkd.service.d/mx-network-generator.conf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # Run systemd-networkd only on machines that have been switched over to the | ||
| # mx-networkd generator (hostconfig tag mx-network-generator). On all other | ||
| # machines network.service/mxvlan.service keep configuring the network; the | ||
| # two mechanisms must never run at the same time. See mx-networkd/README.md, | ||
| # section Migration. /node/tags/ is populated by startup-tags.service, which | ||
| # runs Before=sysinit.target, i.e. before this unit's condition is checked. | ||
| [Unit] | ||
| ConditionPathExists=/node/tags/mx-network-generator |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| [package] | ||
| name = "mx-networkd" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
| rust-version = "1.70" | ||
| description = "Translate the central MarIuX network configuration into systemd-networkd and udev configuration" | ||
| license = "MIT" | ||
| publish = false | ||
|
|
||
| # No dependencies on purpose: this runs as a systemd generator before any | ||
| # file system other than / is guaranteed to be there, and it has to be | ||
| # auditable by everyone who maintains the network configuration. | ||
| [dependencies] | ||
|
|
||
| [profile.release] | ||
| opt-level = "s" | ||
| panic = "abort" | ||
| strip = true | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,169 @@ | ||
| # mx-networkd | ||
|
|
||
| Translates the centrally managed MarIuX network configuration into | ||
| systemd-networkd and udev configuration, so that `mxnetctl`, `mxvlanctl`, | ||
| `network.service` and `mxvlan.service` can be retired without changing any of | ||
| the pushed configuration files. | ||
|
|
||
| Status: **not yet in use anywhere.** Nothing in this directory is installed or | ||
| enabled by default; the old units keep running until someone switches a | ||
| machine over by hand (see [Migration](#migration)). | ||
|
|
||
| ## What it does | ||
|
|
||
| It runs as a **systemd generator**. Generators run at every boot and at every | ||
| `systemctl daemon-reload`, before any unit starts β including | ||
| `systemd-udevd.service`. That is early enough for the `.link` files to be in | ||
| place before the first network device is coldplugged, and it means | ||
| `/etc/systemd/network/` stays permanently empty: everything is written to | ||
| `/run/systemd/network/`, which is also a search path for udev and networkd. | ||
|
|
||
| /etc/local/mxnet ββ ββ /run/systemd/network/10-mx-<name>.link | ||
| /etc/local/mxhost.conf ββΌβ mx-networkd βββββββΌβ /run/systemd/network/10-mx-<vlan>.netdev | ||
| /etc/mxvlans ββ ββ /run/systemd/network/20-mx-<iface>.network | ||
|
|
||
| The three input files keep their current format and stay the single source of | ||
| truth. No file below `/etc` is written (except by `mx-networkd learn`, see | ||
| below). | ||
|
|
||
| ### Mapping | ||
|
|
||
| | today | with mx-networkd | | ||
| | --- | --- | | ||
| | `mxnetctl start` renames by MAC | `.link` file per interface, applied by udev | | ||
| | `network.service` adds `MX_IPADDR/20` and the default route | `.network` file for `MX_NETDEV` | | ||
| | `mxvlanctl start` creates VLANs and their addresses | `.netdev` + `.network` per VLAN | | ||
| | `mxvlanctl` brings the base device up | `.network` for the base device | | ||
|
|
||
| The prefix length (20), the gateway (141.14.16.128) and the broadcast address | ||
| were hard coded in `network.service`. They are defaults here and can be | ||
| overridden per host with `MX_PREFIXLEN`, `MX_GATEWAY` and `MX_BROADCAST` in | ||
| `mxhost.conf` without touching the tool. | ||
|
|
||
| ### One rule worth knowing | ||
|
|
||
| systemd-networkd applies **only the first matching `.network` file** to an | ||
| interface. Everything belonging to one interface therefore has to be in one | ||
| file, even when it comes from two different inputs β the primary address from | ||
| `mxhost.conf` and the `VLAN=` entries from `mxvlans` end up in the same | ||
| `20-mx-net00.network`. That is why this is a program and not a pair of | ||
| `sed` scripts. | ||
|
|
||
| ## Usage | ||
|
|
||
| mx-networkd generate [--root DIR] [--output DIR] [-n] | ||
| mx-networkd check [--root DIR] | ||
| mx-networkd learn [--root DIR] [-n] | ||
|
|
||
| `generate` is what the generator symlink runs; systemd passes three directory | ||
| arguments, which are accepted and ignored. Output is deterministic β no time | ||
| stamps β so re-running it rewrites nothing and `daemon-reload` does not churn | ||
| the network configuration. Files that mx-networkd generated earlier and no | ||
| longer wants are removed; files in `/run/systemd/network/` belonging to | ||
| anything else are never touched. | ||
|
|
||
| `check` parses the same inputs and exits non-zero if anything is wrong. Run it | ||
| on the master before pushing `/etc/mxvlans`, and a typo stops there instead of | ||
| on 300 machines. At boot the same problems are logged and the offending line | ||
| is skipped: a partially configured network beats no network at all. | ||
|
|
||
| `learn` replaces the one thing `.link` files cannot do β inventing a name for a | ||
| MAC address nobody has seen before. It uses mxnetctl's algorithm (prefer | ||
| `netNN` matching the kernel's `ethN`, otherwise the lowest free number), writes | ||
| `/etc/local/mxnet`, and like mxnetctl it refuses to write when | ||
| `/etc/local/USB.usb` exists. It does not rename anything; that is udev's job | ||
| after the next `generate`. Only needed on first installation. | ||
|
|
||
| To preview on any machine without touching it: | ||
|
|
||
| mx-networkd generate --root / --dry-run | ||
|
|
||
| ## Building | ||
|
|
||
| cargo build --release | ||
| cargo test | ||
|
|
||
| No dependencies, no build script, `std` only. This is deliberate: the binary | ||
| runs as a generator before most of the system exists, and everyone who | ||
| maintains the network configuration should be able to read all of it. | ||
|
|
||
| `make` in the repository root builds it and `make install` installs the binary | ||
| as `/usr/sbin/mx-networkd` and as the generator | ||
| `/usr/lib/systemd/system-generators/mx-networkd-generator`. | ||
|
|
||
| ## Migration | ||
|
|
||
| The switch per machine is the **hostconfig tag `mx-network-generator`** | ||
| (hostconfig allows hyphens in tag names: a tag term matches | ||
| `[a-z][a-z0-9$_-]*`). Tags live in the centrally pushed `/etc/hostconfig` | ||
| and are materialised as files below `/node/tags/` by `startup-tags.service` | ||
| (`hostconfig --populate-node`) at every boot. Everything is conditioned on | ||
| that one tag: | ||
|
|
||
| | | with the tag | without the tag | | ||
| | --- | --- | --- | | ||
| | `mx-networkd generate` | writes to `/run/systemd/network/` | writes nothing, prunes its old files | | ||
| | `systemd-networkd.service` | runs (drop-in `ConditionPathExists=/node/tags/mx-network-generator`) | skipped | | ||
| | `network.service`, `mxvlan.service` | skipped (`ConditionPathExists=!/node/tags/mx-network-generator`) | run as before | | ||
|
|
||
| `/node/tags/` is on the root file system and persists across boots, so the | ||
| tag file is already there when the generators run β before | ||
| `startup-tags.service` has run again. The old and the new mechanism never | ||
| run at the same time. `--dry-run` ignores the tag, so the preview always | ||
| works. | ||
|
|
||
| Per machine, reversible at every step β use the helper script: | ||
|
|
||
| migrate-to-mx-networkd | ||
|
|
||
| It validates the prerequisites and the configuration (`mx-networkd check`), | ||
| shows the `--dry-run` preview, verifies the tag is set in `/etc/hostconfig` | ||
| (and tells you what to add on the distmaster if it is not), refreshes | ||
| `/node/tags/` and enables `systemd-networkd.service` for the next boot. It | ||
| never starts, stops or reloads anything, so it is safe to run over SSH and | ||
| safe to run repeatedly. Do **not** flip the services by hand on a running | ||
| machine: `network.service` deletes the primary address on stop | ||
| (`ExecStop=ip addr del β¦`), so stopping it over SSH cuts the connection and | ||
| locks you out. The switchover is the reboot: | ||
|
|
||
| 1. Add `tag mx-network-generator` for the host to `/etc/hostconfig` on the | ||
| distmaster and push it. | ||
| 2. Run `migrate-to-mx-networkd`, read its output, compare the preview with | ||
| `ip -br addr` and `ip -d link show type vlan`. | ||
| 3. `reboot`. The generator runs before udev, the `.link` files rename the | ||
| devices at coldplug, and networkd owns the addresses from the start. A | ||
| reboot is needed anyway: renaming only happens on device *add* β a | ||
| running interface is not renamed. | ||
| 4. After the reboot, verify: `ip -br addr`, `ip -d link show type vlan`, | ||
| `networkctl status`. | ||
|
|
||
| To go back β also at the next boot, not live, for the same reason in | ||
| reverse (`ip addr add` on an address networkd still holds fails, and the | ||
| units fight over the interface): | ||
|
|
||
| 1. Remove the tag from `/etc/hostconfig` on the distmaster and push it. | ||
| 2. `hostconfig --populate-node` | ||
| 3. `systemctl disable systemd-networkd.service` | ||
| 4. `reboot` β the old units run again; the generator removes its files. | ||
|
|
||
| ## Deliberate non-goals | ||
|
|
||
| * **No `apply` subcommand.** Applying the configuration is | ||
| `networkctl reload`. A second implementation of "make the kernel match the | ||
| files" is exactly the divergence this change is supposed to remove. | ||
| * **No new file format.** If `/etc/mxvlans` needs to grow a field one day, | ||
| that is a separate discussion; this change must be a no-op for the people | ||
| who edit it. | ||
| * **No IPv6.** The current scripts do not configure any, so neither does this. | ||
| `.network` files are the obvious place to add it later. | ||
|
|
||
| ## Known gaps | ||
|
|
||
| * `learn` assumes kernel names of the form `ethN`, i.e. `net.ifnames=0`, which | ||
| is what mxnetctl assumed too. On a machine with predictable names | ||
| (`enp1s0f0`) it will find nothing and say so. | ||
| * Renaming still only happens at device add. Changing a name in | ||
| `/etc/local/mxnet` needs a reboot (or `udevadm trigger` plus taking the | ||
| interface down), same as before. | ||
| * `/etc/mxvlans` is read for the local host only, matched on the short host | ||
| name, as mxvlanctl does. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| #! /bin/bash | ||
|
|
||
| # migrate-to-mx-networkd - switch this machine from network.service/mxnetctl/ | ||
| # mxvlanctl to systemd-networkd fed by the mx-networkd generator. | ||
| # | ||
| # The switchover happens at the NEXT BOOT, never live: network.service | ||
| # deletes the primary address on stop, so flipping services on a running | ||
| # machine over SSH locks you out (see mx-networkd/README.md, Migration). | ||
| # This script therefore never starts, stops or reloads anything -- it only | ||
| # validates the configuration, checks the hostconfig tag, refreshes | ||
| # /node/tags/ and enables systemd-networkd for the next boot. It is | ||
| # idempotent: run it as often as you like, over SSH too. | ||
| # | ||
| # The single switch is the hostconfig tag 'mx-network-generator': | ||
| # - with the tag: mx-networkd generates, systemd-networkd runs, | ||
| # network.service/mxvlan.service are skipped by their | ||
| # ConditionPathExists=!/node/tags/mx-network-generator | ||
| # - without the tag: mx-networkd writes nothing, systemd-networkd is | ||
| # skipped by its drop-in condition, the old units run | ||
| # | ||
| # Written by OnkelClaude (AI) on behalf of Boris Bergenroth. | ||
|
|
||
| TAG=mx-network-generator | ||
| TAGFILE=/node/tags/$TAG | ||
| DROPIN=/etc/systemd/system/systemd-networkd.service.d/$TAG.conf | ||
|
|
||
| die() { | ||
| echo "$0: error: $*" >&2 | ||
| exit 1 | ||
| } | ||
|
|
||
| step() { | ||
| echo | ||
| echo "== $*" | ||
| } | ||
|
|
||
| [ "$(id -u)" = 0 ] || die "must be run as root" | ||
|
|
||
| step "checking prerequisites" | ||
|
|
||
| [ -x /usr/sbin/mx-networkd ] \ | ||
| || die "/usr/sbin/mx-networkd is not installed - update mxtools first" | ||
| [ -x /usr/lib/systemd/system-generators/mx-networkd-generator ] \ | ||
| || die "generator /usr/lib/systemd/system-generators/mx-networkd-generator is not installed - update mxtools first" | ||
| [ -x /usr/sbin/hostconfig ] \ | ||
| || die "/usr/sbin/hostconfig is not installed" | ||
| [ -e /etc/local/mxhost.conf ] \ | ||
| || die "/etc/local/mxhost.conf does not exist - this machine does not use the MarIuX network configuration" | ||
| [ -e /etc/local/mxnet ] \ | ||
| || die "/etc/local/mxnet does not exist - run 'mx-networkd learn' (or mxnetctl) first" | ||
| [ -e "$DROPIN" ] \ | ||
| || die "$DROPIN is missing - update mxtools first" | ||
| systemctl cat systemd-networkd.service >/dev/null 2>&1 \ | ||
| || die "systemd-networkd.service does not exist on this machine" | ||
| grep -q 'ConditionPathExists=!'"$TAGFILE" /etc/systemd/system/network.service 2>/dev/null \ | ||
| || die "/etc/systemd/system/network.service is not conditioned on the tag yet - update mxtools first" | ||
| echo "ok" | ||
|
|
||
| step "validating the network configuration (mx-networkd check)" | ||
| /usr/sbin/mx-networkd check \ | ||
| || die "configuration problems found - fix them first; nothing was changed" | ||
|
|
||
| step "preview of the generated configuration (nothing is applied)" | ||
| /usr/sbin/mx-networkd generate --dry-run | ||
| echo | ||
| echo "Compare with the running state: ip -br addr ; ip -d link show type vlan" | ||
|
|
||
| step "checking hostconfig tag '$TAG'" | ||
| if /usr/sbin/hostconfig "$TAG"; then | ||
| echo "tag '$TAG' is set for this host in /etc/hostconfig" | ||
| else | ||
| cat >&2 <<__EOF__ | ||
|
|
||
| The tag '$TAG' is NOT set for this host in /etc/hostconfig. | ||
| /node/tags/ is rebuilt from /etc/hostconfig at every boot, so the tag has | ||
| to come from there to survive. Add it on the distmaster: | ||
|
|
||
| $(uname -n | cut -d. -f1) tag $TAG | ||
|
|
||
| push /etc/hostconfig to this machine, then run this script again. | ||
|
|
||
| Nothing was changed. | ||
| __EOF__ | ||
| exit 1 | ||
| fi | ||
|
|
||
| step "refreshing /node/tags/ (hostconfig --populate-node)" | ||
| /usr/sbin/hostconfig --populate-node \ | ||
| || die "hostconfig --populate-node failed" | ||
| [ -e "$TAGFILE" ] \ | ||
| || die "$TAGFILE did not appear after populate-node" | ||
| echo "ok: $TAGFILE" | ||
|
|
||
| step "enabling systemd-networkd.service for the next boot (not starting it)" | ||
| systemctl enable systemd-networkd.service \ | ||
| || die "systemctl enable systemd-networkd.service failed" | ||
|
|
||
| cat <<__EOF__ | ||
|
|
||
| == done - this machine switches to mx-networkd at the next boot | ||
|
|
||
| Nothing has changed on the running system: network.service keeps the | ||
| addresses until shutdown. network.service and mxvlan.service stay enabled; | ||
| from the next boot on they are skipped by their tag condition, and | ||
| systemd-networkd takes over. Reboot when ready, then verify with: | ||
|
|
||
| ip -br addr | ||
| ip -d link show type vlan | ||
| networkctl status | ||
|
|
||
| Rollback (also reboot-based, do NOT flip services on a running machine): | ||
|
|
||
| 1. remove the '$TAG' tag for this host from /etc/hostconfig | ||
| on the distmaster and push the file | ||
| 2. hostconfig --populate-node | ||
| 3. systemctl disable systemd-networkd.service | ||
| 4. reboot | ||
|
|
||
| __EOF__ |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you choose this name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π€ (Claude, im Auftrag von Boris)
The
mxprefix follows the toolbox convention in this repository (mxnetctl,mxvlanctl,mxgrub,mxmount,mxraid,mxrouter, β¦): a MarIuX-specific tool that knows our configuration.-networkdbecause the program exists solely to feed systemd-networkd β it produces.link/.netdev/.networkfiles and nothing else, so naming it after the thing it configures seemed clearest, mirroring howsystemd-networkditself is named. It is not a daemon; the "d" belongs to networkd, not to it.I did consider
mx-networkd-generator, but that felt redundant as a package name: the generator aspect is already expressed where systemd expects it, in the install name/usr/lib/systemd/system-generators/mx-networkd-generator(install.sh installs the same binary twice: as/usr/sbin/mx-networkdforcheck/learn/--dry-runuse by admins, and under the-generatorname for systemd). Something likemxnetgenwould have been shorter but breaks the association with bothsystemd-networkdand the tag/unit names. Happy to rename if you prefer something else β it is one line in Cargo.toml plus the install.sh paths.β bearbeitet mit Claude Fable 5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I meant just the line I commented on:
edition = "2021". Why 2021?