docs/boxes: Document deployed boxes
Add per-site and per-box inventories, consolidate shared network design, and relocate the switch and access-point references under the home site.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
# Home site
|
||||
|
||||
The home network (domain `h.nul.ie`): a redundant pair of routers in front of a VM host, an
|
||||
NVMe-oF storage target, an IoT container host, and a workstation. The two routers — `river` (a VM)
|
||||
and `stream` (a physical box) — are built from one shared
|
||||
[`routing-common`](../../../nixos/boxes/home/routing-common) definition as an active/backup VRRP
|
||||
pair, and everything clients touch (gateway, DNS) is a floating VIP that follows the master.
|
||||
|
||||
- **Source:** [`nixos/boxes/home/`](../../../nixos/boxes/home)
|
||||
|
||||
## Boxes
|
||||
|
||||
| Box | Role | Host |
|
||||
|---|---|---|
|
||||
| [`palace`](palace.md) | VM host | physical |
|
||||
| [`river`](river.md) | Primary router (VRRP pair with `stream`) | VM on `palace` |
|
||||
| [`stream`](stream.md) | Secondary router (VRRP pair with `river`) | physical |
|
||||
| [`cellar`](cellar.md) | NVMe-oF / SPDK storage target | VM on `palace` |
|
||||
| [`sfh`](sfh/README.md) | NixOS container host (containers on its page) | VM on `palace` |
|
||||
| [`castle`](castle.md) | Workstation / gaming desktop | physical |
|
||||
|
||||
## Router VIPs
|
||||
|
||||
Clients use per-VLAN floating VIPs as their gateway and DNS server; `keepalived` moves them between
|
||||
`river` and `stream`. The addresses, DHCP/RA behavior and failover mechanics are documented once in
|
||||
[Router VIPs](../../networking.md#router-vips) and [Router HA](../../networking.md#router-ha).
|
||||
|
||||
## Networks
|
||||
|
||||
The site separates core management, high-MTU trusted traffic, general trusted traffic, untrusted
|
||||
clients and the two WAN paths. VLAN IDs, prefixes, MTUs and router addressing live in the canonical
|
||||
[`home` section of networking.md](../../networking.md#home).
|
||||
|
||||
## Switch fabric
|
||||
|
||||
The boxes hang off three hand-configured switches — `jim` and `dave` (MikroTik, RouterOS) and
|
||||
`brian` (Ubiquiti, UniFi) — which are **not** managed by this flake. The physical topology, VLAN
|
||||
map, the Digiweb WAN path (trunked VLAN 10 + PVID 140 at the ONT edge), and the multi-ONT plan are
|
||||
documented in [switches.md](switches.md).
|
||||
|
||||
## Wireless APs
|
||||
|
||||
The Wi-Fi APs — `vibe` (MikroTik cAP ax) and `wave` (Cudy AX3000 on OpenWrt) — are dumb APs, also
|
||||
**not** managed by this flake. The shared VLAN-trunk design, SSIDs, per-AP management addressing,
|
||||
and the OpenWrt flash/config for `wave` are in [aps.md](aps.md).
|
||||
@@ -0,0 +1,151 @@
|
||||
# Home wireless APs
|
||||
|
||||
Reference for the home Wi-Fi access points. Like the switches ([switches.md](switches.md)), these
|
||||
are **not** managed by this flake — they are configured on-device (RouterOS on the MikroTik,
|
||||
OpenWrt/UCI on the Cudy). This file documents the shared VLAN/trunk design and each AP.
|
||||
|
||||
Only the DNS records live in the flake
|
||||
([`nixos/boxes/home/routing-common/dns.nix`](../../../nixos/boxes/home/routing-common/dns.nix),
|
||||
`h.nul.ie` zone). Everything else here is applied by hand on the device.
|
||||
|
||||
## The APs
|
||||
|
||||
| | vibe | wave |
|
||||
|---|---|---|
|
||||
| Model | MikroTik **cAP ax** (`cAPGi-5HaxD2HaxD`) | Cudy **AX3000** (OpenWrt id `cudy,ap3000-v1`) |
|
||||
| OS | RouterOS 7.x | OpenWrt 25.12.x (MT7981B / Filogic 820) |
|
||||
| Radio | 2×2 both bands | 2×2 both bands (2 spatial streams) |
|
||||
| Uplink | trunk (multi-port; `ether2` is a wired LAN port) | single **2.5 GbE** trunk |
|
||||
| Management | core/hi/lo `.15` | core/lo `.14` (**not** `hi`; see below) |
|
||||
|
||||
Both mirror the same two SSIDs. `wave` replaced an older AP of the same name; the new one is the
|
||||
Cudy running OpenWrt.
|
||||
|
||||
> **Note on "AX3000":** MT7981B is 2×2 (2 spatial streams). The "3000" is *aggregate* Mbps —
|
||||
> 574 (2.4 GHz 2ss) + 2402 (5 GHz 2ss @ **160 MHz**) — not three streams. `iw` confirms 2×2
|
||||
> (`Available Antennas TX/RX 0x3`; "3 streams: not supported"). 160 MHz is what earns the "3000".
|
||||
|
||||
## Shared design (dumb AP)
|
||||
|
||||
Every AP is a **dumb AP**: it bridges wireless clients onto the right VLAN and does **no** routing,
|
||||
DHCP, RA or firewalling. The home routers (`river`/`stream`) own DHCP/RA/gateway (per-VLAN VRRP VIPs)
|
||||
and firewalling. The uplink is a **tagged trunk**:
|
||||
|
||||
| VLAN | `lib.my.c.home.vlans` | Role | AP use |
|
||||
|---|---|---|---|
|
||||
| — (native) | `core` | switch/fabric management (1500) | backup management (untagged) |
|
||||
| 100 | `hi` | trusted LAN, **high-MTU** (jumbo 9000) | `vibe` management (it's jumbo-capable) |
|
||||
| 110 | `lo` | trusted LAN (1500) | main SSID `wlan0`; `wave` management |
|
||||
| 120 | `untrusted` | guest network | guest SSID `wlan1` |
|
||||
|
||||
`hi` and `lo` are both **trusted** client VLANs — the only difference is MTU (`hi` carries jumbo
|
||||
9000, `lo` is standard 1500). An AP puts its own management on whichever it can do: `vibe` (jumbo)
|
||||
sits on `hi`, `wave` (eth0 capped at 2026) sits on `lo`. The main SSID lands on `lo` because Wi-Fi
|
||||
clients are 1500 regardless.
|
||||
|
||||
### SSIDs
|
||||
|
||||
| SSID | Bands | Security | VLAN |
|
||||
|---|---|---|---|
|
||||
| `wlan0` (main) | 5 GHz + 2.4 GHz | WPA2/WPA3-PSK (`sae-mixed`) | 110 (`lo`) |
|
||||
| `wlan1` (guest) | 2.4 GHz | WPA2-PSK (`psk2`) | 120 (`untrusted`) |
|
||||
|
||||
**Passphrases are never stored in this repo.** `vibe` is the source of truth; read them out-of-band
|
||||
with `ssh admin@vibe '/interface wifi export show-sensitive'` (`.passphrase=` prints **unquoted**).
|
||||
|
||||
## vibe (MikroTik cAP ax)
|
||||
|
||||
RouterOS, one hardware-offloaded bridge `main` with `vlan-filtering=yes`. Access: `ssh admin@vibe`
|
||||
— key auth for `admin` is installed (`~/.ssh/id_rsa`), with `admin`/`admin` as a fallback.
|
||||
|
||||
- **Uplink `ether1`** — trunk, tagged VLANs 100/110/120; native/untagged is the default VLAN 1
|
||||
(PVID, no IP). `ether2` is a wired **access port** on VLAN 110 (`lo`). `l2mtu 9214`.
|
||||
- **Radios** — `wifi1` (5 GHz, 20/40/80) + `wifi2` (2.4 GHz, 20/40) both broadcast `wlan0`
|
||||
(WPA2/WPA3-PSK), untagged onto VLAN 110. `wifi3` is a virtual AP on `wifi2` broadcasting `wlan1`
|
||||
(WPA2-PSK), untagged onto VLAN 120. `country=Ireland`.
|
||||
- **Bridge VLANs** — 100 tagged `main,ether1`; 110 tagged `main,ether1` + untagged
|
||||
`ether2,wifi1,wifi2`; 120 tagged `main,ether1` + untagged `wifi3`.
|
||||
- **Roaming** — 802.11k/v via a `/interface wifi steering` profile (`rrm=yes wnm=yes`,
|
||||
`neighbor-group=home-aps`) assigned to `wifi1`/`wifi2`/`wifi3`.
|
||||
- **Resolver** — the hi VIP `192.168.71.254` / `2a0e:97c0:4d0:1::ffff`.
|
||||
|
||||
### Management
|
||||
|
||||
Management uses host `.15`: `192.168.64.15` on native/core as a backup,
|
||||
`192.168.68.15/22` + `2a0e:97c0:4d0:1::1:6` on `hi` VLAN 100, and
|
||||
`192.168.72.15/21` + `2a0e:97c0:4d0:2::1:6` on `lo` VLAN 110. The `hi` address holds the default
|
||||
route through its VIP; `untrusted` has no address. With `l2mtu 9214`, `vibe` can use the jumbo
|
||||
`hi` network unlike `wave`.
|
||||
|
||||
## wave (Cudy AX3000, OpenWrt)
|
||||
|
||||
Single-port AP, so the port is a VLAN **trunk** carrying management + both SSIDs.
|
||||
|
||||
### Management addressing
|
||||
|
||||
`wave` takes host `.14`, on **`lo` (primary) and `core` (backup)** — deliberately **not** `hi`,
|
||||
unlike the switches and `vibe`. `hi` is the jumbo (9000) VLAN, but `wave`'s eth0 caps at 2026 (see
|
||||
MTU note), so there's no reason to put it there; `lo` is 1500 with a proper VRRP VIP for the default
|
||||
route + resolver, and `core` has no VIP/v6 so it can only be a backup. No IP on `untrusted`. Records
|
||||
in `dns.nix`:
|
||||
|
||||
| Name | VLAN | Address |
|
||||
|---|---|---|
|
||||
| `wave-core` | core (native/untagged) | `192.168.64.14/24` — backup, like the switches (no VIP → backup only) |
|
||||
| `wave` | lo 110 | `192.168.72.14/21`, `2a0e:97c0:4d0:2::1:5` — primary; holds the default route + resolver (lo VIP `192.168.79.254` / `2a0e:97c0:4d0:2::ffff`) |
|
||||
|
||||
**Firewall:** management (SSH/LuCI) reachable from `core`/`lo` only; `untrusted` is a separate
|
||||
zone with `input REJECT` (and `wave` has no IP there) — **no management via the guest VLAN**.
|
||||
|
||||
### brian switch port
|
||||
|
||||
`wave` hangs off **brian** (UniFi). Its port is a **trunk**: tagged VLAN **110/120** (`lo` + guest),
|
||||
and **native/untagged = core** (the fabric's management VLAN, carrying `wave-core`). VLAN 100 (`hi`)
|
||||
is **not** needed here — `wave` isn't on `hi` (see Management addressing). Configure via the UniFi
|
||||
controller (brian has no CLI); see [switches.md](switches.md).
|
||||
|
||||
### Flashing OpenWrt (Cudy AX3000 / `cudy_ap3000-v1`)
|
||||
|
||||
Hardware: MT7981B, 512 MB RAM, 256 MB SPI-NAND, 1× 2.5 GbE (RTL8221B), 2×2 WiFi 6.
|
||||
|
||||
> ⚠️ **Serial caveat:** units with a serial starting `2543…` (post ~Nov 2025) use a different flash
|
||||
> chip and can brick with older firmware. Match firmware to the unit.
|
||||
|
||||
OpenWrt can't be flashed directly over stock. Two-stage, via a Cudy **transition** firmware (Cudy
|
||||
OpenWrt download page / `support@cudy.com`; `warnning.txt` in that bundle has the steps):
|
||||
|
||||
1. Stock Cudy UI: update to **≥ 2.4.7** (adds TFTP `recovery.bin` recovery), then flash the Cudy
|
||||
**intermediate** firmware (`cudy_ap3000-v1-sysupgrade_*.bin`), "keep settings" **unchecked**.
|
||||
It reboots into an OpenWrt-based build at `192.168.1.1` (SSH `root`, empty password).
|
||||
2. From there, `sysupgrade -n` to vanilla OpenWrt (`…-cudy_ap3000-v1-squashfs-sysupgrade.bin` from
|
||||
`downloads.openwrt.org`; this release ships **no** factory image — sysupgrade only).
|
||||
|
||||
Stock default (out of box) is a DHCP client falling back to **`192.168.10.254`**; the stock UI is a
|
||||
customised LuCI (only 80/443, no SSH) with a first-boot "create admin password" wizard — so the
|
||||
stock-side flashing is done from a browser, not headless.
|
||||
|
||||
### On-device config notes
|
||||
|
||||
#### Wireless packages
|
||||
|
||||
The package manager is `apk`, not `opkg`. Wi-Fi uses the full `wpad-mbedtls` package so all SSIDs
|
||||
can enable 802.11k/v (`ieee80211k` + `bss_transition`). Replacing `wpad-basic-mbedtls` live leaves
|
||||
the mac80211 interfaces in a start/teardown loop that reloads cannot recover; reboot after
|
||||
`apk add wpad-mbedtls`.
|
||||
|
||||
- Radios: `radio0` = 2.4 GHz, `radio1` = 5 GHz (keyed by `band`, don't assume). 5 GHz is pinned to
|
||||
**channel 36 / HE160** (any 160 MHz block in IE is DFS; ch36 has the shortest ~60 s CAC).
|
||||
- Bridge: `br-lan` with `vlan_filtering`, single port `eth0` — tagged `110/120`, untagged/PVID
|
||||
VLAN 1 (= native/core). SSIDs attach via `network` = `lo`/`untrusted` (= `br-lan.110`/`.120`).
|
||||
- Dumb-AP: no DHCP pools, `odhcpd.maindhcp=0`, `delegate=0` on the L3 interfaces.
|
||||
- **MTU:** all interfaces are **1500**. The `mtk_eth_soc` 2.5 GbE (`eth0`) caps at **2026 bytes**
|
||||
(`ip link set eth0 mtu 9000` → `SIOCSIFMTU: Invalid argument`), so `wave` can't join `hi`'s jumbo
|
||||
(9000) fabric like `vibe` does — which is precisely **why `wave` is managed on `lo`, not `hi`**
|
||||
(see Management addressing). Nothing on `wave` needs > 1500.
|
||||
- **LuCI:** enabled, login `root` / `admin`. **SSH:** key-only (`PasswordAuth`/`RootPasswordAuth off`).
|
||||
- `iperf3` installed for throughput testing.
|
||||
|
||||
### Access
|
||||
|
||||
- SSH: `ssh root@wave` (key-only; `wave`/`wave-core` resolve once `dns.nix` is deployed).
|
||||
- LuCI: `http://192.168.72.14/` (or `http://wave/`), `root` / `admin`.
|
||||
@@ -0,0 +1,63 @@
|
||||
# castle
|
||||
|
||||
The home workstation / gaming desktop. Diskless-style: it netboots from `river` and keeps its
|
||||
root storage on NVMe-oF volumes from `cellar`.
|
||||
|
||||
- **Source:** [`nixos/boxes/home/castle/`](../../../nixos/boxes/home/castle) (`default.nix`)
|
||||
- **Host:** physical
|
||||
- **nixpkgs:** `mine`
|
||||
|
||||
## Role
|
||||
|
||||
### Desktop
|
||||
|
||||
The AMD desktop runs the GUI stack (`my.gui.enable`, Sway/Wayland via home-manager), low-latency
|
||||
PipeWire, Bluetooth and Thunderbolt. Local `libvirtd`/`virt-manager` and the IOMMU are enabled, but
|
||||
the box has no VFIO or GPU-passthrough configuration.
|
||||
|
||||
### Netboot
|
||||
|
||||
With `my.netboot.client.enable`, the firmware iPXE-boots from the 2.5G NIC. Kea matches
|
||||
`et2.5g`'s MAC and directs it to `boot.h.nul.ie` on [`river`](river.md).
|
||||
|
||||
### NVMe-oF root
|
||||
|
||||
`/nix`, `/persist` and `/home` are `/dev/nvmeof/*` LVs in `cellar`'s
|
||||
`nqn.2016-06.io.spdk:castle` namespace (`my.nvme.boot`, RDMA). The initrd brings
|
||||
up `et100g`/`lan-hi` with `roceBootModules`; the running network keeps
|
||||
`KeepConfiguration=static` so networkd does not drop the storage address. The root filesystem is a
|
||||
size-limited tmpfs (`my.tmproot`).
|
||||
|
||||
### Other configuration
|
||||
|
||||
Both firewalls are disabled on this trusted `hi` desktop. Other settings include `binfmt`
|
||||
emulation for `aarch64-linux`/`armv7l-linux`, `recursive-nix`, Wireshark and `rdma-core`/`qperf`;
|
||||
a `drm-amd-display` flicker patch remains commented out.
|
||||
|
||||
## Network assignments
|
||||
|
||||
See the consolidated [network assignments](../../networking.md#box-assignments) table (this box: `castle`).
|
||||
|
||||
## Hardware
|
||||
|
||||
| Component | Inventory |
|
||||
|---|---|
|
||||
| Platform | ASUS ProArt X670E-CREATOR WIFI |
|
||||
| CPU | AMD Ryzen 9 7950X (16 cores / 32 threads) |
|
||||
| Memory | 64 GiB |
|
||||
| Graphics | Integrated AMD Radeon graphics |
|
||||
| Network | Mellanox ConnectX-4 100G, Aquantia AQC113CS 10G, Intel I225-V 2.5G and MediaTek MT7922 Wi-Fi 6E controllers |
|
||||
| System storage | No local root disk; the box netboots and uses the SPDK NVMe-oF namespace exported by `cellar` |
|
||||
|
||||
## Networking
|
||||
|
||||
- `et100g` (100G, MTU 9000) carries `lan-hi` (the `hi` assignment, also pinned by a kea
|
||||
reservation on its MAC) and `lan-lo`.
|
||||
- `lan-lo` is a secondary network attachment: DHCPv4 with `UseGateway`/`UseDNS` off and RAs
|
||||
accepted with gateway/DNS use off — present for reaching `lo` devices, never a default route.
|
||||
- `et2.5g` (netboot) and `et10g` are renamed but carry no network config.
|
||||
|
||||
## Notable config files
|
||||
|
||||
- [`nixos/boxes/home/castle/default.nix`](../../../nixos/boxes/home/castle/default.nix) — box
|
||||
config: netboot/NVMe-oF boot, 100G networking, GUI/audio, virtualisation.
|
||||
@@ -0,0 +1,48 @@
|
||||
# cellar
|
||||
|
||||
The home storage target. A VM on `palace` that drives three passed-through NVMe disks with SPDK
|
||||
and exports them over NVMe-oF/RDMA — `river`, `sfh` and `castle` all run their root storage off
|
||||
it.
|
||||
|
||||
- **Source:** [`nixos/boxes/home/palace/vms/cellar/`](../../../nixos/boxes/home/palace/vms/cellar)
|
||||
(`default.nix`, `spdk.nix`)
|
||||
- **Host:** VM on `palace`
|
||||
- **nixpkgs:** `mine`
|
||||
|
||||
## Role
|
||||
|
||||
- Runs an **SPDK userspace target** (`my.spdk`, [`spdk.nix`](../../../nixos/boxes/home/palace/vms/cellar/spdk.nix)):
|
||||
the kernel `nvme` driver is blacklisted so SPDK can claim the three NVMe controllers directly
|
||||
(host BDFs `41:00.0`–`43:00.0`, attached in the guest as `02:00.0`–`04:00.0`).
|
||||
- Builds a **RAID-0** (`NVMeRaid`) across the three drives and exports one
|
||||
partition per consumer as an **NVMe-oF subsystem over RDMA** (port 4420) on the `hi` network:
|
||||
|
||||
| Bdev | NQN | Consumer |
|
||||
|---|---|---|
|
||||
| `NVMeRaidp1` | `nqn.2016-06.io.spdk:river` | [`river`](river.md) |
|
||||
| `NVMeRaidp2` | `nqn.2016-06.io.spdk:castle` | [`castle`](castle.md) |
|
||||
| `NVMeRaidp3` | `nqn.2016-06.io.spdk:sfh` | [`sfh`](sfh/README.md) |
|
||||
|
||||
Each subsystem is pinned to its consumer's `hostnqn` (the `my.nvme.uuid` on the client side).
|
||||
- `spdk-tgt` is ordered after `lan-hi` is online; the RDMA listener binds the `hi` assignment on
|
||||
port 4420. The VM itself is pinned to NUMA node 1 on `palace` and gets SR-IOV VF 0.
|
||||
- `netdata` (port 19999 allowed in the firewall) and `fstrim`.
|
||||
|
||||
## Network assignments
|
||||
|
||||
See the consolidated [network assignments](../../networking.md#box-assignments) table (this box: `cellar`).
|
||||
|
||||
## Notes
|
||||
|
||||
- The `ublk_*` calls in `my.spdk.debugCommands` are only a debugging aid — they create a local
|
||||
ublk device so the RAID can be mounted and inspected on `cellar` itself. Client exports are the
|
||||
`nvmf` subsystems above.
|
||||
|
||||
## Notable config files
|
||||
|
||||
- [`nixos/boxes/home/palace/vms/cellar/default.nix`](../../../nixos/boxes/home/palace/vms/cellar/default.nix) —
|
||||
box config (assignment, networking, netdata).
|
||||
- [`nixos/boxes/home/palace/vms/cellar/spdk.nix`](../../../nixos/boxes/home/palace/vms/cellar/spdk.nix) —
|
||||
SPDK target: RAID-0, NVMe-oF/RDMA subsystems.
|
||||
- [`nixos/boxes/home/palace/vms/default.nix`](../../../nixos/boxes/home/palace/vms/default.nix) —
|
||||
the VM definition on `palace` (VF 0, NVMe passthrough, NUMA pinning).
|
||||
@@ -0,0 +1,70 @@
|
||||
# palace
|
||||
|
||||
The physical VM host for the home site. Runs the `river`, `cellar` and `sfh` VMs and feeds them
|
||||
SR-IOV VFs, PCI NVMe drives and LVM disks.
|
||||
|
||||
- **Source:** [`nixos/boxes/home/palace/default.nix`](../../../nixos/boxes/home/palace/default.nix)
|
||||
(VM definitions in [`palace/vms/default.nix`](../../../nixos/boxes/home/palace/vms/default.nix))
|
||||
- **Host:** physical
|
||||
- **nixpkgs:** `mine-stable`
|
||||
|
||||
## Role
|
||||
|
||||
- Home hypervisor: VMs are declared in `my.vms.instances`
|
||||
([`palace/vms/default.nix`](../../../nixos/boxes/home/palace/vms/default.nix)); disks are LVs in
|
||||
the `main` thin pool (`services.lvm.boot.thin.enable`).
|
||||
- AMD box (`kvm-amd`, `amd_iommu=on`, microcode updates); the kernel is built with
|
||||
`ACPI_APEI_PCIEAER`/`PCIEAER` for the PCIe passthrough work below.
|
||||
|
||||
## Network assignments
|
||||
|
||||
See the consolidated [network assignments](../../networking.md#box-assignments) table (this box: `palace`).
|
||||
|
||||
## Hardware
|
||||
|
||||
| Component | Inventory |
|
||||
|---|---|
|
||||
| Platform | Gigabyte X399 DESIGNARE EX |
|
||||
| CPU | AMD Ryzen Threadripper 1950X (16 cores / 32 threads) |
|
||||
| Memory | 128 GiB |
|
||||
| Host storage | 500 GB Samsung SSD 860 EVO containing the EFI partition and the `main` LVM thin pool |
|
||||
| Bulk storage | Three 8 TB Seagate IronWolf disks in the `hdds` VG, providing the RAID-backed `hdd-storage` and `frigate` LVs |
|
||||
| NVMe storage | Three 2 TB Samsung NVMe devices passed through to `cellar`; SPDK combines them as the `NVMeRaid` RAID 0 device |
|
||||
| Network / graphics | Mellanox ConnectX-4 100G adapter with four SR-IOV VFs, two Intel I211 Gigabit Ethernet controllers, and an AMD Radeon RX 550/560-family GPU |
|
||||
|
||||
## Networking
|
||||
|
||||
100G `et100g` (mlx5, MTU 9000) uplinks to the `dave` switch and carries `lan-hi` (VLAN 100, the
|
||||
`hi` assignment). A udev rule creates four SR-IOV VFs on the PF:
|
||||
|
||||
| VF | Consumer | VLAN handling |
|
||||
|---|---|---|
|
||||
| 0 | `cellar` | `hi` |
|
||||
| 1 | `river` | untagged VF; `river` tags its LAN and WAN VLANs |
|
||||
| 2 | `sfh` | `hi` |
|
||||
| 3 | `sfh` container MACVLAN parent | `hi` |
|
||||
|
||||
- `lan-core` is a bridge with the `core` assignment (no gateway); the 1G
|
||||
`lan-core-phy` and the `lan-lo-phy` VLAN ride on it. `lan-lo` is a second, L3-less bridge used
|
||||
for VM netboot and `lo` clients.
|
||||
- The 1G `et1g0` (igb) is exported to `river` as a passthru-mode macvtap (`vm-et1g0`) — river sees
|
||||
it as `wan-old`.
|
||||
|
||||
## VMs
|
||||
|
||||
| VM | vCPUs | RAM | Passthrough | Notes |
|
||||
|---|---|---|---|---|
|
||||
| `cellar` | 8c × 2t | 16 GiB | VF 0 (`44:00.1`); NVMe `41:00.0`–`43:00.0` | pinned to NUMA node 1; split IRQ chip + vIOMMU |
|
||||
| `river` | 3c × 2t | 4 GiB | VF 1 (`44:00.2`); macvtap `vm-et1g0` | only an ESP local disk (plus an installer ISO) — root is NVMe-oF from `cellar` |
|
||||
| `sfh` | 8c × 2t | 32 GiB | VF 2 (`44:00.3`), VF 3 (`44:00.4`); two USB host ports | no boot disk — netboots; gets the `hdds/frigate` LV |
|
||||
|
||||
Boot ordering is enforced with systemd dependencies: `vm@river` waits for `cellar`'s SSH port (and
|
||||
for the `vm-et1g0` device), and `vm@sfh` waits for `river` — storage first, then the router, then
|
||||
everything that boots off both.
|
||||
|
||||
## Notable config files
|
||||
|
||||
- [`nixos/boxes/home/palace/default.nix`](../../../nixos/boxes/home/palace/default.nix) — host
|
||||
hardware, networkd (links/bridges/SR-IOV), LVM.
|
||||
- [`nixos/boxes/home/palace/vms/default.nix`](../../../nixos/boxes/home/palace/vms/default.nix) —
|
||||
VM instances and boot ordering.
|
||||
@@ -0,0 +1,79 @@
|
||||
# river
|
||||
|
||||
A home router VM on `palace` with a Digiweb PPPoE WAN on the ISP's VLAN 10. It forms the redundant
|
||||
router pair with [`stream`](stream.md).
|
||||
|
||||
- **Source:** [`nixos/boxes/home/palace/vms/river.nix`](../../../nixos/boxes/home/palace/vms/river.nix)
|
||||
(shared router config: [`routing-common`](../../../nixos/boxes/home/routing-common), index 0)
|
||||
- **Host:** VM on `palace`
|
||||
- **nixpkgs:** `mine`
|
||||
|
||||
## Role
|
||||
|
||||
At `routing-common` index 0, `river` normally holds the primary position in the router pair.
|
||||
Pair-wide addressing, VIP, DHCP/DNS and failover behavior is documented in the
|
||||
[`home` networking overview](../../networking.md#home) and [Router HA](../../networking.md#router-ha).
|
||||
This page covers `river`'s Digiweb WAN, VM platform, storage and netboot duties.
|
||||
|
||||
## Network assignments
|
||||
|
||||
See the consolidated [network assignments](../../networking.md#box-assignments) table (this box: `river`).
|
||||
|
||||
## WAN (Digiweb PPPoE)
|
||||
|
||||
### Link and addressing
|
||||
|
||||
`services.pppd` peer `digiweb` attaches directly to `wan-pon-isp`, the raw ISP VLAN 10
|
||||
(`vlans.pon-isp`) trunked untranslated from the ONT through `brian` and `dave`; see
|
||||
[switches.md](switches.md). The netdev has no L3 configuration and uses `MTUBytes=1508`, leaving a
|
||||
clean `mtu`/`mru 1500` after PPPoE overhead.
|
||||
|
||||
The static `84.203.124.128` address is requested through IPCP. The provider-wide credentials are
|
||||
deliberately not secret; the peer persists indefinitely with LCP echo monitoring and ignores
|
||||
Digiweb DNS in favor of the local recursor.
|
||||
|
||||
### Management subnet
|
||||
|
||||
`wan-pon-ont` (VLAN 140, PVID'd at `brian`) holds `192.168.100.100/24`, reaching the ONT UI at
|
||||
`192.168.100.1`. The `.100` address follows `stream`'s modem-management convention.
|
||||
|
||||
### WAN readiness
|
||||
|
||||
The `pppd` hooks drive this shared gate with `DefaultDependencies=false`: `ip-up` installs the
|
||||
link-scoped default route and starts the target, while `ip-down` stops it and removes the route.
|
||||
`ipsec` and `ipv6-clear-default-route` attach through `wantedBy` + `partOf`, so they reload after
|
||||
every WAN flap.
|
||||
|
||||
### Traffic shaping
|
||||
|
||||
The shared `wan-ifb` ingress-shaping pieces are inert here. CAKE is specific to `stream`, and
|
||||
`networkd-dispatcher` is `mkForce false` pending scheduling tests.
|
||||
|
||||
## Platform
|
||||
|
||||
### Virtual machine and network attachment
|
||||
|
||||
The 100G `lan` NIC is VF 1 of `palace`'s `et100g` (MTU 9000), with every router VLAN tagged on top
|
||||
as `55-lan`. A macvtap of `palace`'s 1G `et1g0` remains as the old `wan-old` path without L3
|
||||
configuration. Deployments use the `hi` assignment.
|
||||
|
||||
### Storage
|
||||
|
||||
The VM's local disk holds only an ESP; `/nix` and `/persist` are LVs on `cellar`'s
|
||||
`nqn.2016-06.io.spdk:river` namespace over RDMA. The initrd brings up `lan-hi`
|
||||
with `roceBootModules`, and `KeepConfiguration=static` prevents networkd from dropping the address
|
||||
during reconfiguration. An installer ISO remains attached.
|
||||
|
||||
## Netboot
|
||||
|
||||
`my.netboot.server` serves iPXE/TFTP for `sfh` and `castle` at `boot.h.nul.ie` from the `lo`
|
||||
assignment, restricted to the `hi` and `lo` prefixes.
|
||||
|
||||
## Notable config files
|
||||
|
||||
- [`nixos/boxes/home/palace/vms/river.nix`](../../../nixos/boxes/home/palace/vms/river.nix) — box
|
||||
config: pppd, WAN VLANs, `wan-online.target` hooks, netboot server, NVMe-oF boot.
|
||||
- [`nixos/boxes/home/routing-common/default.nix`](../../../nixos/boxes/home/routing-common/default.nix) —
|
||||
shared router definition (assignments, firewall/NAT, `as211024`).
|
||||
- [`nixos/boxes/home/palace/vms/default.nix`](../../../nixos/boxes/home/palace/vms/default.nix) —
|
||||
the VM definition on `palace` (VF 1, macvtap, ESP disk).
|
||||
@@ -0,0 +1,59 @@
|
||||
# sfh
|
||||
|
||||
"Services for home" — the NixOS container host for the home site. A VM on `palace` that netboots
|
||||
from `river` and runs its root off NVMe-oF from `cellar`.
|
||||
|
||||
- **Source:** [`nixos/boxes/home/palace/vms/sfh/`](../../../../nixos/boxes/home/palace/vms/sfh)
|
||||
(`default.nix`, `containers/`)
|
||||
- **Host:** VM on `palace`
|
||||
- **nixpkgs:** `mine`
|
||||
|
||||
## Role
|
||||
|
||||
- Runs the home NixOS containers via `my.containers.instances` (systemd-nspawn); each container is
|
||||
its own `nixos.systems.*` entry rendered through `my.asContainer`.
|
||||
- **Netboot client** (`my.netboot.client.enable`): the VM has no boot disk — its `netboot` NIC
|
||||
on palace's `lan-lo` bridge is matched by a kea client-class on [`river`](../river.md) and
|
||||
iPXE-boots from `boot.h.nul.ie`.
|
||||
- **Root on NVMe-oF**: `my.nvme.boot` connects to `nqn.2016-06.io.spdk:sfh`
|
||||
([`cellar`](../cellar.md), RDMA) from the initrd (`lan-hi` up + `roceBootModules`); `/nix` and
|
||||
`/persist` are LVs on that volume. `KeepConfiguration=static` on `lan-hi` protects the
|
||||
NVMe-oF address from networkd reconfigures.
|
||||
- **Frigate footage disk**: palace passes the `hdds/frigate` LVM LV through as a virtio disk;
|
||||
sfh mounts it at `/mnt/frigate` (by label) and bind-mounts it into the `hass` container at
|
||||
`/var/lib/frigate`.
|
||||
- USB: two host ports are passed to the VM (qemu flags) for the Zigbee coordinator and webcam used
|
||||
by `hass`; the nspawn unit gets `DeviceAllow` for `char-ttyUSB` and `char-video4linux`.
|
||||
|
||||
## Network assignments
|
||||
|
||||
See the consolidated [network assignments](../../../networking.md#box-assignments) table (this box: `sfh`).
|
||||
|
||||
## Networking
|
||||
|
||||
Four NICs, all MTU 9000 where jumbo-capable:
|
||||
|
||||
- `lan-hi` — SR-IOV VF 2, the box's own `hi` assignment.
|
||||
- `lan-hi-ctrs` — SR-IOV VF 3, no L3: the MACVLAN parent for the containers' `hi` interfaces
|
||||
(`host0` inside each container).
|
||||
- `lan-core-ctrs` / `lan-lo-ctrs` — virtio NICs (bridged to palace's `lan-core` / `lan-lo`), no
|
||||
L3: MACVLAN parents for containers that need a `core` or `lo` interface.
|
||||
|
||||
The per-container MACVLAN wiring lives in `systemd.nspawn.*.networkConfig` in
|
||||
[`sfh/default.nix`](../../../../nixos/boxes/home/palace/vms/sfh/default.nix).
|
||||
|
||||
## Containers
|
||||
|
||||
| Container | Role |
|
||||
|---|---|
|
||||
| [`hass`](containers/hass.md) | Home Assistant + Frigate + MQTT |
|
||||
| [`unifi`](containers/unifi.md) | UniFi controller |
|
||||
|
||||
## Notable config files
|
||||
|
||||
- [`nixos/boxes/home/palace/vms/sfh/default.nix`](../../../../nixos/boxes/home/palace/vms/sfh/default.nix) —
|
||||
box config: netboot/NVMe-oF boot, container instances, MACVLAN plumbing, Frigate disk.
|
||||
- [`nixos/boxes/home/palace/vms/sfh/containers/`](../../../../nixos/boxes/home/palace/vms/sfh/containers) —
|
||||
the container system definitions.
|
||||
- [`nixos/boxes/home/palace/vms/default.nix`](../../../../nixos/boxes/home/palace/vms/default.nix) —
|
||||
the VM definition on `palace` (VFs, USB passthrough, netboot NIC, `hdds/frigate` disk).
|
||||
@@ -0,0 +1,59 @@
|
||||
# hass
|
||||
|
||||
Home automation container: Home Assistant plus its supporting services (MQTT, camera restreaming,
|
||||
Frigate NVR), running on [`sfh`](../README.md).
|
||||
|
||||
- **Source:** [`nixos/boxes/home/palace/vms/sfh/containers/hass.nix`](../../../../../nixos/boxes/home/palace/vms/sfh/containers/hass.nix)
|
||||
- **Host:** NixOS container on `sfh`
|
||||
- **nixpkgs:** `mine`
|
||||
|
||||
## Role
|
||||
|
||||
### Home Assistant
|
||||
|
||||
`services.home-assistant` uses declarative configuration (`configWritable = false`). It enables
|
||||
the `esphome`, `zha`, `denonavr`, `webostv`, `androidtv_remote`, `heos`, `mqtt`, `wled`, `met` and
|
||||
`google_translate` components, plus custom `alarmo`, `frigate`, `west_wood_club` and Irish Rail
|
||||
integrations. A `hass-cli` wrapper uses a token from `my.secrets` to reach the local server.
|
||||
|
||||
- **mosquitto** — MQTT broker (anonymous local listener; port 1883 allowed, alongside HTTP).
|
||||
- **go2rtc** — restreams the Reolink living-room camera (RTSP from `reolink-living-room`, on the
|
||||
`lo` network) and the office USB webcam (`/dev/video0` via ffmpeg).
|
||||
- **Frigate** (`services.frigate`, `frigate.h.nul.ie` — the `frigate` alt name on the `hi`
|
||||
assignment) — records both restreamed cameras with a short retention policy; detection is
|
||||
disabled.
|
||||
- External access is via `https://hass.nul.ie` through the `middleman` reverse proxy
|
||||
(`trusted_proxies`); internally it's `hass-ctr.h.nul.ie`.
|
||||
- Not a deploy-rs target (`my.deploy.enable = false`) — it's rendered via `my.asContainer` and
|
||||
started by `sfh`'s `my.containers.instances`.
|
||||
|
||||
## Network assignments
|
||||
|
||||
See the consolidated [network assignments](../../../../networking.md#box-assignments) table (this box: `hass`).
|
||||
|
||||
## Storage
|
||||
|
||||
Frigate footage lives on a **separate HDD LV**: `palace` passes the `hdds/frigate` LVM LV to the
|
||||
`sfh` VM, sfh mounts it at `/mnt/frigate`, and the container bind-mounts it at `/var/lib/frigate`
|
||||
(read-write). This keeps recording churn off the NVMe-oF root.
|
||||
|
||||
## Devices
|
||||
|
||||
Passed through from `sfh` (USB host ports on `palace`):
|
||||
|
||||
- Nabu Casa Connect ZBT-1 Zigbee coordinator → `/dev/ttyUSB0` (used by `zha`).
|
||||
- USB webcam → `/dev/video0` (go2rtc's `webcam_office` stream).
|
||||
- The matching raw USB device node allowed through from `sfh`.
|
||||
|
||||
## Networking
|
||||
|
||||
MACVLAN interfaces created from `sfh`'s container NICs: `host0` on `lan-hi-ctrs` (the `hi` assignment,
|
||||
alt name `frigate`, default gateway via the VIP) and `lan-lo` on `lan-lo-ctrs` (the `lo`
|
||||
assignment, no gateway) — the `lo` interface reaches the IoT devices (the Reolink camera lives there).
|
||||
|
||||
## Notable config files
|
||||
|
||||
- [`nixos/boxes/home/palace/vms/sfh/containers/hass.nix`](../../../../../nixos/boxes/home/palace/vms/sfh/containers/hass.nix) —
|
||||
container system: Home Assistant, Frigate, mosquitto, go2rtc.
|
||||
- [`nixos/boxes/home/palace/vms/sfh/default.nix`](../../../../../nixos/boxes/home/palace/vms/sfh/default.nix) —
|
||||
the `sfh` side: bind mounts, MACVLAN wiring, `DeviceAllow`.
|
||||
@@ -0,0 +1,42 @@
|
||||
# unifi
|
||||
|
||||
The UniFi network controller, running as a container on [`sfh`](../README.md). It manages the
|
||||
home UniFi switch `brian` (see [switches.md](../../switches.md)).
|
||||
|
||||
- **Source:** [`nixos/boxes/home/palace/vms/sfh/containers/unifi.nix`](../../../../../nixos/boxes/home/palace/vms/sfh/containers/unifi.nix)
|
||||
- **Host:** NixOS container on `sfh`
|
||||
- **nixpkgs:** `mine`
|
||||
|
||||
## Role
|
||||
|
||||
- **UniFi controller** (`services.unifi`, `pkgs.unifi` on `mongodb-7_0`, firewall open; TCP 8443
|
||||
allowed).
|
||||
- Not a deploy-rs target (`my.deploy.enable = false`) — it's rendered via `my.asContainer` and
|
||||
started by `sfh`'s `my.containers.instances`.
|
||||
|
||||
## Network assignments
|
||||
|
||||
See the consolidated [network assignments](../../../../networking.md#box-assignments) table (this box: `unifi`).
|
||||
|
||||
## Status
|
||||
|
||||
**Currently enabled.** The container spent a while disabled — its import was commented out of
|
||||
[`containers/default.nix`](../../../../../nixos/boxes/home/palace/vms/sfh/containers/default.nix)
|
||||
while there was no UniFi gear to manage — and was re-enabled when the UniFi switch `brian` was
|
||||
added, gaining a `core` interface (`unifi-ctr-core`) at the same time so it can reach the switch on its
|
||||
management network. It is imported, listed in `sfh`'s `my.containers.instances`, and
|
||||
`services.unifi.enable = true`.
|
||||
|
||||
## Networking
|
||||
|
||||
Two MACVLAN interfaces come from `sfh`'s container NICs: `host0` on `lan-hi-ctrs` carries the `hi`
|
||||
assignment (`unifi-ctr`, default gateway via the VIP), while `lan-core` on `lan-core-ctrs` carries
|
||||
the gatewayless `core` assignment (`unifi-ctr-core`). The `core` interface is how the controller
|
||||
talks to `brian` and the other switches on their management network.
|
||||
|
||||
## Notable config files
|
||||
|
||||
- [`nixos/boxes/home/palace/vms/sfh/containers/unifi.nix`](../../../../../nixos/boxes/home/palace/vms/sfh/containers/unifi.nix) —
|
||||
container system: UniFi service, assignments.
|
||||
- [`nixos/boxes/home/palace/vms/sfh/default.nix`](../../../../../nixos/boxes/home/palace/vms/sfh/default.nix) —
|
||||
the `sfh` side: container instance, MACVLAN wiring.
|
||||
@@ -0,0 +1,100 @@
|
||||
# stream
|
||||
|
||||
A physical Intel home router with a DHCP WAN from the Virgin Media cable modem. It forms the
|
||||
redundant router pair with [`river`](river.md) and is dual-homed to both switches.
|
||||
|
||||
- **Source:** [`nixos/boxes/home/stream.nix`](../../../nixos/boxes/home/stream.nix) (shared router
|
||||
config: [`routing-common`](../../../nixos/boxes/home/routing-common), index 1)
|
||||
- **Host:** physical
|
||||
- **nixpkgs:** `mine`
|
||||
|
||||
## Role
|
||||
|
||||
At `routing-common` index 1, `stream` normally holds the secondary position in the router pair.
|
||||
Pair-wide addressing, VIP, DHCP/DNS and failover behavior is documented in the
|
||||
[`home` networking overview](../../networking.md#home) and [Router HA](../../networking.md#router-ha).
|
||||
This page covers `stream`'s Virgin Media WAN, physical platform and redundant switch attachment.
|
||||
|
||||
## Network assignments
|
||||
|
||||
See the consolidated [network assignments](../../networking.md#box-assignments) table (this box: `stream`).
|
||||
|
||||
## WAN (Virgin Media DHCP)
|
||||
|
||||
### Link and addressing
|
||||
|
||||
`wan` is a renamed igc NIC (`00:f0:cb:ee:ca:dd`) towards the cable modem. The modem segment is
|
||||
switch VLAN 130; `jim` handles the tag, so the box interface is untagged. See
|
||||
[switches.md](switches.md) for the fabric side.
|
||||
|
||||
`DHCP=ipv4` pulls the public lease. `dhcpV4Config.UseDNS=false` points resolution at the local
|
||||
recursor, and `IPv6AcceptRA=false` because public IPv6 arrives over the tunnel rather than this WAN.
|
||||
|
||||
### Management subnet
|
||||
|
||||
The static `192.168.0.100/24` address (host `.100` of `prefixes.modem.v4`) sits on `wan` without a
|
||||
gateway, keeping the modem UI reachable alongside the DHCP lease.
|
||||
|
||||
### WAN readiness
|
||||
|
||||
`wan-wait-online.service` polls until the DHCP default route exists, then satisfies
|
||||
`wan-online.target`. The route is the gate because the permanent modem address would make
|
||||
networkd's wait-online report success before the public lease arrives, allowing `ipsec` to start
|
||||
without its public `left=` address.
|
||||
|
||||
### Traffic shaping
|
||||
|
||||
Egress is shaped at the `wan` root qdisc. A `routing-common` `networkd-dispatcher` rule redirects
|
||||
ingress through `tc`/`mirred` into `wan-ifb`; each direction has its own configured bandwidth and
|
||||
uses the DOCSIS overhead preset.
|
||||
|
||||
### Per-box `routing-common` options
|
||||
|
||||
The modem's management subnet shares the `wan` interface, which `routing-common` itself knows
|
||||
nothing about — it declares two per-box options
|
||||
([`routing-common/default.nix`](../../../nixos/boxes/home/routing-common/default.nix)) that this
|
||||
box sets:
|
||||
|
||||
- `my.homeRouter.dns.wanSkipBroadcasts` — skip the modem subnet's broadcast address when
|
||||
auto-selecting the router's own `wan` A record for the zone's LUA record.
|
||||
- `my.homeRouter.firewall.untrustedRejectV4` — reject untrusted clients from
|
||||
reaching the modem subnet (needed only because it shares `wan`; WAN egress is otherwise
|
||||
accepted).
|
||||
|
||||
## Platform
|
||||
|
||||
### Hardware
|
||||
|
||||
| Component | Inventory |
|
||||
|---|---|
|
||||
| Platform | BROUNION R86S |
|
||||
| CPU | Intel Celeron N5105 (4 cores / 4 threads) |
|
||||
| Memory | 16 GiB |
|
||||
| Storage | 512 GB Samsung SSD 970 PRO NVMe containing `/boot`, `/nix` and `/persist`; integrated 128 GB eMMC is present but is not used by the declared filesystems |
|
||||
| Network | Three Intel `igc` interfaces and a dual-port Mellanox `mlx4_en` adapter; `wan`, `lan-jim` and `lan-dave` use three of these ports |
|
||||
|
||||
The platform configuration enables `kvm-intel`, `intel_iommu=on` and Intel microcode updates.
|
||||
|
||||
### Switching (RSTP)
|
||||
|
||||
`stream` is dual-homed to both switches: `lan-jim` (igc) and `lan-dave` (mlx4_en), both MTU 9000,
|
||||
are enslaved to the `lan` bridge with `STP=true`. [`routing-common/mstpd.nix`](../../../nixos/boxes/home/routing-common/mstpd.nix)
|
||||
runs a patched `mstpd` and forces RSTP on `lan` once it's routable, so exactly one uplink carries
|
||||
traffic at a time. (The remaining NICs are renamed `et2`/`et5` and left unconfigured.)
|
||||
|
||||
### Deployment
|
||||
|
||||
`my.deploy.node.hostname` is currently commented out.
|
||||
|
||||
## Disabled printer services
|
||||
|
||||
`octoprint` and `mjpg-streamer` are defined but disabled (`enable = false`).
|
||||
|
||||
## Notable config files
|
||||
|
||||
- [`nixos/boxes/home/stream.nix`](../../../nixos/boxes/home/stream.nix) — box config: DHCP WAN,
|
||||
modem management, CAKE, `wan-online.target` gate, STP bridge.
|
||||
- [`nixos/boxes/home/routing-common/default.nix`](../../../nixos/boxes/home/routing-common/default.nix) —
|
||||
shared router definition (index 1).
|
||||
- [`nixos/boxes/home/routing-common/mstpd.nix`](../../../nixos/boxes/home/routing-common/mstpd.nix) —
|
||||
RSTP on the `lan` bridge.
|
||||
@@ -0,0 +1,206 @@
|
||||
# Home switches
|
||||
|
||||
Reference for the two MikroTik switches on the home network — **jim** and **dave** — plus the
|
||||
Ubiquiti switch **brian**, and how the home boxes and the Digiweb WAN hang off them. These switches
|
||||
are **not** managed by this flake; they are configured by hand (RouterOS on jim/dave, UniFi on
|
||||
brian). It covers the physical topology, the VLAN map, and how the Digiweb WAN reaches river.
|
||||
|
||||
In short: the Digiweb ISP VLAN (10) is trunked straight through to river (which runs PPPoE on it),
|
||||
and the ONT's untagged management is PVID'd onto VLAN 140 at brian, its edge switch. VLAN 10 is
|
||||
carried untranslated because a single ONT makes it unique on the fabric — see
|
||||
[the WAN path](#the-digiweb-wan-path-trunked-vlan-10--pvid-140) and
|
||||
[why not translation](#why-not-translation-for-one-ont). The router side lives in
|
||||
[river.md](river.md); the logical network map in [networking.md](../../networking.md). The Wi-Fi
|
||||
APs that hang off these switches are in [aps.md](aps.md).
|
||||
|
||||
## The switches
|
||||
|
||||
| | jim | dave | brian |
|
||||
|---|---|---|---|
|
||||
| Identity | `jim-sw` | `dave-sw` | (UniFi) |
|
||||
| Model | CRS326-24G-2S+ | CRS504-4XQ | Ubiquiti Switch Pro XG 8 PoE |
|
||||
| Switch chip | Marvell 98DX3236 | Marvell 98DX4310 (+ Atheros 8227 for the 1G mgmt port) | — |
|
||||
| OS | RouterOS | RouterOS | UniFi |
|
||||
| Ports | 24×1G + 2×SFP+ | 4×QSFP28 (100G, breakout-capable) + 1G mgmt | 8×10GBASE-T PoE + 2×10G SFP+ |
|
||||
| Bridge | `main`, `vlan-filtering=yes` | `main`, `vlan-filtering=yes` | UniFi VLAN profiles |
|
||||
|
||||
jim and dave run a single hardware-offloaded bridge (`main`) with VLAN filtering. Access to the
|
||||
MikroTiks is SSH as `admin` / `admin` by short hostname (see [Accessing the switches](#accessing-the-switches)).
|
||||
Only jim and dave can do hardware VLAN translation (`/interface ethernet switch rule` on the Marvell
|
||||
chips); brian cannot rewrite tags, only trunk/PVID them.
|
||||
|
||||
## Physical topology
|
||||
|
||||
The two WAN sources enter at the top: the Virgin Media modem lands on **jim** (VLAN 130), and the
|
||||
Digiweb **ONT** lands on **brian**. Both `jim` and `brian` are edge switches that uplink down into
|
||||
the **dave** core; the home boxes hang off dave's 100G ports, with backup links up to jim. jim's
|
||||
`wan-pon-in` (`sfp-sfpplus2`) is a spare SFP+ port, unused today.
|
||||
|
||||
```
|
||||
Virgin Media cable modem Digiweb ONT
|
||||
stream WAN, VLAN 130 river WAN, management + VLAN 10
|
||||
| |
|
||||
jim brian
|
||||
| 10G trunk 802.3ad LAG |
|
||||
+--------------------+ +---------------+
|
||||
| |
|
||||
+---+----------+---+
|
||||
| dave |
|
||||
+--------+---------+
|
||||
|
|
||||
+---------------------+---------------------+
|
||||
| | |
|
||||
palace (100G) castle (100G) stream
|
||||
river VM NVMe-oF root second router
|
||||
|
||||
Backup links to jim (normally idle):
|
||||
* palace: 1G
|
||||
* stream: 1G; STP selects the active link
|
||||
* castle: 2.5G, normally down; no live failover
|
||||
```
|
||||
|
||||
Notes:
|
||||
- **river** runs as a VM on the **palace** host; its uplink is dave's 100G `palace` port. jim also
|
||||
has 1G `palace`/`stream` ports, but those are secondary links and do **not** carry the WAN.
|
||||
- **stream** (the second router box) is dual-homed to both jim and dave (STP picks the active path).
|
||||
|
||||
### Castle storage dependency
|
||||
|
||||
`castle` is dual-homed without STP: its primary link is dave's 100G `castle` port (`et100g`), while
|
||||
the 2.5G link to jim (`et2.5g`) is normally down and provides no live failover. Its root disk is
|
||||
NVMe-oF over `et100g` and dave, so interrupting either freezes `castle` mid-I/O. Do dave maintenance
|
||||
from a box that does not depend on it, or power `castle` off cleanly first.
|
||||
|
||||
## VLANs
|
||||
|
||||
| VLAN | Name | Purpose |
|
||||
|---|---|---|
|
||||
| — (native) | core | Switch management, `192.168.64.0/24` (jim `.10`, dave `.11`, brian `.13`) |
|
||||
| 100 | hi | High-performance / jumbo network (MTU 9000) |
|
||||
| 110 | lo | Standard LAN |
|
||||
| 120 | untrusted | Guest / untrusted network |
|
||||
| 130 | wan | **stream's WAN** — Virgin Media cable modem (untagged on jim's `wan1`/`wan2`/`wan-in`) |
|
||||
| 140 | wan-pon-ont | ONT management, `192.168.100.0/24` (PVID'd at the ONT edge) |
|
||||
| 10 | pon-isp | Digiweb ISP transport — **trunked straight through** to river, PPPoE runs on it |
|
||||
| 141 | wan-pon-isp | **Reserved** — the translated ISP VLAN for the future multi-ONT design |
|
||||
|
||||
Switch L3 presence (`/interface vlan` on `main`) exists **only** for VLANs the switch is managed
|
||||
from — `hi` (100) and `lo` (110), plus native core. WAN and guest VLANs deliberately have no switch
|
||||
L3 interface.
|
||||
|
||||
## The Digiweb WAN path (trunked VLAN 10 + PVID 140)
|
||||
|
||||
The ONT presents two things on one wire:
|
||||
- **untagged** management traffic (`192.168.100.x`), and
|
||||
- **tagged VLAN 10** carrying the Digiweb ISP session (the BRAS requires VLAN 10).
|
||||
|
||||
With a **single ONT** there's no reason to translate anything — VLAN 10 is unique on the fabric, so
|
||||
we just carry it end to end and let river run PPPoE directly on it:
|
||||
|
||||
1. **Untagged mgmt → VLAN 140, at the ONT's edge switch (brian).** brian sets the ONT port's PVID to
|
||||
140 so the untagged management traffic becomes VLAN 140, and allows tagged VLAN 10 through the
|
||||
same port. river takes `192.168.100.100/24` on VLAN 140 (matching stream's modem-mgmt `.100`) to
|
||||
reach the ONT web UI at `192.168.100.1`. Doing the PVID at the ONT-facing edge keeps it clean —
|
||||
the untagged frames never share a domain with anything else.
|
||||
|
||||
2. **VLAN 10 (ISP) trunked straight through, untranslated.** brian → dave → palace carry tagged
|
||||
VLAN 10 by ordinary bridge-VLAN membership. No `/interface ethernet switch rule`, no pinning, no
|
||||
asymmetric-learning issues — it's just a normal tagged VLAN. river attaches PPPoE to VLAN 10
|
||||
directly (`wan-pon-isp` netdev = VLAN `pon-isp` = 10; baby-jumbo MTU 1508 so PPP nets a clean
|
||||
1500).
|
||||
|
||||
Net result: **river runs PPPoE single-tagged on VLAN 10 and holds a VLAN 140 address to reach the
|
||||
ONT.** See [`nixos/boxes/home/palace/vms/river.nix`](../../../nixos/boxes/home/palace/vms/river.nix)
|
||||
for the river side.
|
||||
|
||||
```
|
||||
ONT -- untagged + VLAN 10 -- brian -- VLAN 140 + VLAN 10 -- dave -- palace -- river
|
||||
|
|
||||
+-- ONT port PVID 140; VLAN 10 remains tagged
|
||||
```
|
||||
|
||||
### Why not translation (for one ONT)?
|
||||
|
||||
Translation would swap VLAN 10 → 141 with two pinned hardware ACL rules to keep VLAN 10 off the rest
|
||||
of the fabric. That buys nothing with a single ONT — VLAN 10 is already unique, so trunking it is
|
||||
simpler and rule-free. Translation only earns its keep when **two** ONTs both deliver VLAN 10 and
|
||||
would collide (below).
|
||||
|
||||
## Switch configuration
|
||||
|
||||
How each switch is set up for the Digiweb WAN path. **Confirm any change on the box before applying**
|
||||
(see [Accessing the switches](#accessing-the-switches)).
|
||||
|
||||
**brian (UniFi)** — hosts the ONT:
|
||||
- The ONT port has **native/untagged network = VLAN 140** (PVID) and is a **tagged member of VLAN 10**,
|
||||
so the ONT's untagged management lands on 140 and its tagged ISP frames pass through.
|
||||
- The `brian-downlink` LAG up to dave trunks **tagged 140 + tagged 10** (alongside the LAN VLANs).
|
||||
|
||||
**dave (RouterOS)** — trunks both WAN-pon VLANs to `brian-downlink` and `palace`. The ISP VLAN 10 row:
|
||||
```
|
||||
/interface bridge vlan add bridge=main vlan-ids=10 tagged=brian-downlink,palace
|
||||
```
|
||||
VLAN 140 also spans `brian-downlink,palace` (it carries a few other members too). No switch rules —
|
||||
this is plain tagged bridging.
|
||||
|
||||
**jim (RouterOS)** — carries **none** of the Digiweb WAN path: no translation rules, and no VLAN
|
||||
10/140/141 rows. `wan-pon-in` (`sfp-sfpplus2`) sits at `pvid=1` as a spare port. jim only handles
|
||||
stream's VLAN-130 WAN and the LAN VLANs.
|
||||
|
||||
## Future: multiple ONTs (per-port VLAN translation)
|
||||
|
||||
If a second ONT arrives (e.g. a Digiweb line for stream, or a second river), trunking breaks: both
|
||||
ONTs deliver **tagged VLAN 10**, and plain bridge-VLAN filtering can't tell them apart. That's when
|
||||
translation earns its place — a switch rule matches on the **ingress port**, so each ONT's VLAN 10
|
||||
becomes a *distinct* fabric VLAN:
|
||||
|
||||
- ONT-A port: VLAN 10 → **141** (→ river)
|
||||
- ONT-B port: VLAN 10 → **142** (→ stream / second river)
|
||||
- mgmt: PVID each ONT port onto its own VLAN (140, 143, …) so both ONTs' `192.168.100.1` stay in
|
||||
separate L2/L3 domains.
|
||||
|
||||
The forward direction isolates naturally (each ONT maps to a different fabric VLAN). The **return**
|
||||
direction is where port targeting is mandatory: both translate *back* to VLAN 10, so bridge VLAN 10
|
||||
now has two members and a plain FDB-miss flood would leak one ONT's upstream to the other. Each
|
||||
return must be pinned to its port with `new-dst-ports`:
|
||||
```
|
||||
# ONT-A: 141 in on palace → 10, forced out ONT-A's port
|
||||
# ONT-B: 142 in on stream → 10, forced out ONT-B's port
|
||||
```
|
||||
Each ONT port must also be a tagged member of bridge VLAN 10 for correct egress tagging (the missing
|
||||
piece that otherwise shows up as pppd "Timeout waiting for PADO"). The pins bypass the FDB, so the
|
||||
two ISP sessions never mix.
|
||||
|
||||
**Why a new switch:** jim (the only box with spare SFP+ *and* the translation feature) has just
|
||||
**one** free SFP+ port, so it can't host two ONTs. The plan is a dedicated
|
||||
**CRS305-1G-4S+** (4×SFP+, same Marvell rule support) to land multiple ONTs and do the per-port
|
||||
translation there, feeding distinct fabric VLANs up to dave.
|
||||
|
||||
## Accessing the switches
|
||||
|
||||
The switches resolve by **short hostname** on the home network — the home routers serve their
|
||||
records in the home zone
|
||||
([`nixos/boxes/home/routing-common/dns.nix`](../../../nixos/boxes/home/routing-common/dns.nix):
|
||||
`jim` → hi `.10`, `dave` → hi `.11`, `brian` → core `.13`). From a box on the home network just
|
||||
`ssh admin@jim` / `admin@dave`.
|
||||
|
||||
**Key auth** for `admin` is installed on jim/dave (and the `vibe` AP) — `ssh -i ~/.ssh/id_rsa
|
||||
admin@jim` works keyless (imported via `/user ssh-keys import`). Password `admin`/`admin` remains as
|
||||
a fallback. Non-interactive password pattern (avoids the ssh-agent hang) if the key isn't available:
|
||||
|
||||
```
|
||||
sshpass -p admin ssh -o IdentityAgent=none -o PubkeyAuthentication=no \
|
||||
-o PreferredAuthentications=password -o StrictHostKeyChecking=accept-new \
|
||||
-o UserKnownHostsFile=/tmp/sw_known_hosts admin@jim
|
||||
```
|
||||
|
||||
**Always confirm config changes on the switch** (print the affected menu, apply, re-verify). brian
|
||||
is UniFi — configured through its controller, not RouterOS CLI.
|
||||
|
||||
## Management IPs
|
||||
|
||||
| | core (`192.168.64.0/24`) | hi (`192.168.68.0/22`) | lo (`192.168.72.0/21`) |
|
||||
|---|---|---|---|
|
||||
| jim | `.10` (on `main`) | `.10` | `.10` |
|
||||
| dave | `.11` (on `management`, the 1G Atheros port) | `.11` | `.11` |
|
||||
| brian | `.13` (core) | — | — |
|
||||
Reference in New Issue
Block a user