87cdfdbd97
portcullis is wired over 10G to fergal, which uplinks to jim's spare SFP+ port. That uplink is untagged VLAN 1, so hi is carried tagged on a lan-hi VLAN interface: a static assignment at 192.168.68.41 / ::6:1, resolving through the router VIPs like any other hi client. Its gateway route outranks the DHCP default, making 10G the preferred path while the 2.5G bootstrap stays as a fallback. Deploy now targets that address. The hi MTU goes on the .network rather than the .link, since a .link is only applied at udev device-add -- with it there, et10g-0 stays at 1500 across a switch and lan-hi cannot take 9000. jim's sfp-spare was tagged into hi and lo out of band to match. fergal turns out to belong with portcullis rather than to the home fabric -- it goes to Nikhef when the box does -- so its documentation moves to the colony site, leaving home/switches.md a short section on what it borrows from that fabric. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
104 lines
4.3 KiB
Markdown
104 lines
4.3 KiB
Markdown
# Flashing an OpenWrt box
|
|
|
|
Guided procedure for putting a flake-built OpenWrt image onto a box. The images themselves are
|
|
declared in [`openwrt/default.nix`](../openwrt/default.nix) and described in
|
|
[`deployment.md`](deployment.md#openwrt-images); the boxes are listed on their site pages (today
|
|
that is [fergal](sites/colony/fergal.md)).
|
|
|
|
Packages are baked into the image, so this runs whenever the package list changes — not only for
|
|
version upgrades. Work through the phases in order; ⏸ marks the point to stop and confirm.
|
|
|
|
## Phase 1 — Build
|
|
|
|
```sh
|
|
nix build .#openwrt-<box>
|
|
```
|
|
|
|
The result holds the `-squashfs-sysupgrade.bin` to flash, plus a `.manifest` listing every package
|
|
in the image and an SBOM. Check the manifest for the packages the change was meant to add — an
|
|
unknown package name is not an error at build time, it just silently isn't there.
|
|
|
|
## Phase 2 — Pre-flight
|
|
|
|
Confirm on the box:
|
|
|
|
```sh
|
|
grep -E 'RELEASE|REVISION' /etc/openwrt_release # what is running now
|
|
mount | grep -E ' / | /overlay | /rom ' # flash or RAM? (see below)
|
|
uci get network.lan.ipaddr # will it come back reachable?
|
|
cat /lib/upgrade/keep.d/* # what survives the flash
|
|
df -h /tmp # room for the image
|
|
```
|
|
|
|
**Flash or RAM matters.** A box booted normally shows a squashfs `/rom` plus a jffs2 `/overlay`;
|
|
one booted from an initramfs has `/` on tmpfs. The initramfs case has its own hazards — see
|
|
[Flashing from an initramfs](sites/colony/fergal.md#flashing-notes).
|
|
|
|
**Check the address is in UCI**, not just present on the interface. An address added by hand with
|
|
`ip` disappears on reboot and the box comes back unreachable.
|
|
|
|
`keep.d` normally lists `/etc/config/`, `/etc/dropbear/authorized_keys` and the dropbear host keys,
|
|
so an ordinary flash preserves both access and identity. Verify rather than assume — losing
|
|
`authorized_keys` on a box reachable only over SSH means a serial console recovery.
|
|
|
|
## Phase 3 — Back up
|
|
|
|
```sh
|
|
sysupgrade -b /tmp/<box>-config-backup.tar.gz
|
|
```
|
|
|
|
Fetch it with `ssh <box> 'cat /tmp/…' > local.tar.gz`. **`scp` does not work** — these boxes have no
|
|
`/usr/libexec/sftp-server`, so it fails with `Connection closed`. (`scp -O` forces the legacy
|
|
protocol if you prefer it.)
|
|
|
|
For a box being flashed off its **vendor** firmware for the first time, back up the whole flash
|
|
first — the vendor partitions hold per-unit MAC addresses and licence data that cannot be
|
|
regenerated. See [fergal's flash layout](sites/colony/fergal.md#flash-layout).
|
|
|
|
## Phase 4 — Stage and validate
|
|
|
|
```sh
|
|
ssh <box> 'cat > /tmp/sysupgrade.bin' < <image>.bin
|
|
ssh <box> 'sha256sum /tmp/sysupgrade.bin; sysupgrade -T /tmp/sysupgrade.bin'
|
|
```
|
|
|
|
Compare the sha256 against the local file, and require `sysupgrade -T` to exit 0. `-T` validates the
|
|
image and its device-compatibility metadata without writing anything, which is the last cheap chance
|
|
to catch a wrong-profile image.
|
|
|
|
## Phase 5 — Flash ⏸
|
|
|
|
Confirm before this point. It reboots the box and is not interruptible.
|
|
|
|
```sh
|
|
ssh <box> 'setsid sh -c "sleep 2; sysupgrade -v /tmp/sysupgrade.bin" \
|
|
</dev/null >/tmp/upgrade.log 2>&1 & echo detached'
|
|
```
|
|
|
|
**Detaching matters.** `sysupgrade` kills the SSH session partway through; without `setsid` the
|
|
upgrade dies with it, potentially after the flash has been erased. `nohup` is not available on these
|
|
boxes' busybox — use `setsid`.
|
|
|
|
Plain `sysupgrade` keeps the config in `keep.d`. Do not reach for `-c` out of caution: it needs
|
|
`/overlay/upper/etc` and aborts *after* erasing the firmware if that is missing.
|
|
|
|
## Phase 6 — Wait and verify
|
|
|
|
Poll SSH, not ping. A successful ping returns in milliseconds, so a naive "wait for it to go down"
|
|
loop finishes before the box has even started rebooting. Sleep between probes and wait on something
|
|
that only succeeds once userspace is up:
|
|
|
|
```sh
|
|
for i in $(seq 1 40); do
|
|
sleep 15
|
|
ssh -o ConnectTimeout=5 -o BatchMode=yes <box> 'grep REVISION /etc/openwrt_release' && break
|
|
done
|
|
```
|
|
|
|
Expect roughly three minutes. Then confirm the revision changed, the management address returned,
|
|
the package count matches the manifest, and the new packages are actually present and running.
|
|
Connecting without host-key overrides also confirms the host keys survived.
|
|
|
|
If the box does not return, it needs the serial console — have that confirmed as reachable *before*
|
|
Phase 5, not after.
|