Give `river` a dedicated RDMA VF and two RSTP trunk attachments. Keep client services on the router VIPs and carry Digiweb VLANs over both switch paths. Set VF trust, multicast reception, bridge MAC and ARP behavior for local switching. Wait for Kea interface readiness and apply RSTP costs through `mstpd` despite port-registration and rename races. Load `palace`'s RAID module in the initrd. Record RouterOS and RouterBOOT upgrades and validate port, carrier and switch outages. Document the deployed architecture, interface handoffs and recovery procedures. Add physical socket maps, NIC capacities and cable connections alongside the logical topology and failover checks.
225 lines
6.4 KiB
Nix
225 lines
6.4 KiB
Nix
index: { lib, pkgs, config, assignments, allAssignments, ... }:
|
|
let
|
|
inherit (lib) mkForce concatStringsSep;
|
|
inherit (lib.my) net netbootKeaClientClasses;
|
|
inherit (lib.my.c.home) domain searchDomains prefixes vips hiMTU;
|
|
|
|
dns-servers = [
|
|
{
|
|
ip-address = net.cidr.host 1 prefixes.core.v4;
|
|
port = 5353;
|
|
}
|
|
{
|
|
ip-address = net.cidr.host 2 prefixes.core.v4;
|
|
port = 5353;
|
|
}
|
|
];
|
|
in
|
|
{
|
|
users = with lib.my.c.ids; {
|
|
users.kea= {
|
|
isSystemUser = true;
|
|
uid = uids.kea;
|
|
group = "kea";
|
|
};
|
|
groups.kea.gid = gids.kea;
|
|
};
|
|
|
|
systemd.services = {
|
|
kea-dhcp4-server = {
|
|
unitConfig.StartLimitIntervalSec = 0;
|
|
preStart = ''
|
|
${config.systemd.package}/lib/systemd/systemd-networkd-wait-online \
|
|
--interface=lan-hi:routable --interface=lan-lo:routable \
|
|
--interface=lan-untrusted:routable --ipv4 --timeout=60
|
|
'';
|
|
serviceConfig = {
|
|
Restart = "on-failure";
|
|
RestartSec = 5;
|
|
DynamicUser = mkForce false;
|
|
};
|
|
};
|
|
kea-dhcp-ddns-server.serviceConfig.DynamicUser = mkForce false;
|
|
};
|
|
|
|
services = {
|
|
kea = {
|
|
dhcp4 = {
|
|
enable = true;
|
|
settings = {
|
|
interfaces-config = {
|
|
interfaces = [
|
|
"lan-hi/${assignments.hi.ipv4.address}"
|
|
"lan-lo/${assignments.lo.ipv4.address}"
|
|
"lan-untrusted/${assignments.untrusted.ipv4.address}"
|
|
];
|
|
};
|
|
lease-database = {
|
|
type = "memfile";
|
|
persist = true;
|
|
name = "/var/lib/kea/dhcp.leases";
|
|
};
|
|
|
|
option-data = [
|
|
{
|
|
name = "domain-name";
|
|
data = domain;
|
|
}
|
|
{
|
|
name = "domain-search";
|
|
data = concatStringsSep ", " searchDomains;
|
|
always-send = true;
|
|
}
|
|
];
|
|
client-classes = netbootKeaClientClasses {
|
|
tftpIP = allAssignments.river.lo.ipv4.address;
|
|
hostname = "boot.${domain}";
|
|
systems = {
|
|
sfh = "52:54:00:a5:7e:93";
|
|
castle = "c8:7f:54:6e:17:0f";
|
|
};
|
|
};
|
|
subnet4 = [
|
|
{
|
|
id = 1;
|
|
subnet = prefixes.hi.v4;
|
|
interface = "lan-hi";
|
|
option-data = [
|
|
{
|
|
name = "routers";
|
|
data = vips.hi.v4;
|
|
}
|
|
{
|
|
name = "domain-name-servers";
|
|
# VRRP VIP so DNS follows the master and clients never hit a dead router
|
|
data = vips.hi.v4;
|
|
}
|
|
{
|
|
name = "interface-mtu";
|
|
data = toString hiMTU;
|
|
}
|
|
];
|
|
pools = [
|
|
{
|
|
pool = if index == 0
|
|
then "192.168.68.120 - 192.168.69.255"
|
|
else "192.168.70.0 - 192.168.71.240";
|
|
}
|
|
];
|
|
reservations = [
|
|
{
|
|
# castle
|
|
hw-address = "24:8a:07:a8:fe:3a";
|
|
ip-address = net.cidr.host 40 prefixes.hi.v4;
|
|
}
|
|
];
|
|
}
|
|
{
|
|
id = 2;
|
|
subnet = prefixes.lo.v4;
|
|
interface = "lan-lo";
|
|
option-data = [
|
|
{
|
|
name = "routers";
|
|
data = vips.lo.v4;
|
|
}
|
|
{
|
|
name = "domain-name-servers";
|
|
# VRRP VIP so DNS follows the master and clients never hit a dead router
|
|
data = vips.lo.v4;
|
|
}
|
|
];
|
|
pools = [
|
|
{
|
|
pool = if index == 0
|
|
then "192.168.72.120 - 192.168.75.255"
|
|
else "192.168.76.0 - 192.168.79.240";
|
|
}
|
|
];
|
|
reservations = [
|
|
{
|
|
# castle
|
|
hw-address = "24:8a:07:a8:fe:3a";
|
|
ip-address = net.cidr.host 40 prefixes.lo.v4;
|
|
}
|
|
|
|
{
|
|
# avr
|
|
hw-address = "8c:a9:6f:30:03:6b";
|
|
ip-address = net.cidr.host 41 prefixes.lo.v4;
|
|
}
|
|
{
|
|
# tv
|
|
hw-address = "00:a1:59:b8:4d:86";
|
|
ip-address = net.cidr.host 42 prefixes.lo.v4;
|
|
}
|
|
{
|
|
# android tv
|
|
hw-address = "b8:7b:d4:95:c6:74";
|
|
ip-address = net.cidr.host 43 prefixes.lo.v4;
|
|
}
|
|
{
|
|
# hass-panel
|
|
hw-address = "80:30:49:cd:d7:51";
|
|
ip-address = net.cidr.host 44 prefixes.lo.v4;
|
|
}
|
|
{
|
|
# reolink-living-room
|
|
hw-address = "ec:71:db:30:69:a4";
|
|
ip-address = net.cidr.host 45 prefixes.lo.v4;
|
|
}
|
|
{
|
|
# nixlight
|
|
hw-address = "00:4b:12:3b:d3:14";
|
|
ip-address = net.cidr.host 46 prefixes.lo.v4;
|
|
}
|
|
];
|
|
}
|
|
{
|
|
id = 3;
|
|
subnet = prefixes.untrusted.v4;
|
|
interface = "lan-untrusted";
|
|
option-data = [
|
|
{
|
|
name = "routers";
|
|
data = vips.untrusted.v4;
|
|
}
|
|
{
|
|
name = "domain-name-servers";
|
|
data = "1.1.1.1, 1.0.0.1";
|
|
}
|
|
];
|
|
pools = [
|
|
{
|
|
pool = if index == 0
|
|
then "192.168.80.10 - 192.168.80.127"
|
|
else "192.168.80.128 - 192.168.80.250";
|
|
}
|
|
];
|
|
}
|
|
];
|
|
ddns-send-updates = true;
|
|
ddns-replace-client-name = "when-not-present";
|
|
ddns-qualifying-suffix = "dyn.${domain}";
|
|
ddns-generated-prefix = "ip";
|
|
ddns-update-on-renew = true;
|
|
|
|
dhcp-ddns.enable-updates = true;
|
|
};
|
|
};
|
|
|
|
dhcp-ddns = {
|
|
enable = true;
|
|
settings = {
|
|
forward-ddns.ddns-domains = [
|
|
{
|
|
name = "dyn.${domain}.";
|
|
inherit dns-servers;
|
|
}
|
|
];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|