WIP: ap01: towards our VLAN model #181

Draft
rlahfa wants to merge 7 commits from ap01-vlan into main
8 changed files with 143 additions and 54 deletions

View file

@ -116,6 +116,13 @@ in
pkgs.freeradius
pkgs.picocom # for serial access
# Daemon-less copy closure for Liminix systems.
(pkgs.callPackage (sources.liminix + "/pkgs/min-copy-closure") { nix = pkgs.lix; })
# Daemon-less garbage collection for Liminix systems.
(pkgs.callPackage (sources.liminix + "/pkgs/min-collect-garbage") { nix = pkgs.lix; })
# TFTP server, friendly for Nix builds.
(pkgs.callPackage (sources.liminix + "/pkgs/tufted") { })
(pkgs.callPackage ./lib/colmena {
colmena = pkgs.callPackage "${sources.colmena}/package.nix" { };
})

View file

@ -3,16 +3,18 @@ let
svc = config.system.service;
in
{
services.dhcpv4 = svc.network.dhcp.client.build {
services.init-dhcpv4 = svc.network.dhcp.client.build {
interface = config.services.int;
dependencies = [
config.services.bridge.components.lan
];
};
services.defaultroute4 = svc.network.route.build {
via = "$(output ${config.services.dhcpv4} router)";
services.init-defaultroute4 = svc.network.route.build {
via = "$(output ${config.services.init-dhcpv4} router)";
target = "default";
dependencies = [ config.services.dhcpv4 ];
dependencies = [ config.services.init-dhcpv4 ];
};
# TODO: ensure SLAAC for admin-vlan.
}

View file

@ -8,17 +8,18 @@ in
# TODO: support dynamic reconfiguration once we are in the target VLAN?
services.resolvconf = oneshot rec {
name = "resolvconf";
# TODO: imho, DNS should be static and provided by the router?
up = ''
. ${serviceFns}
( in_outputs ${name}
for i in $(output ${config.services.dhcpv4} dns); do
for i in $(output ${config.services.init-dhcpv4} dns); do
echo "nameserver $i" >> resolv.conf
done
)
'';
dependencies = [
config.services.dhcpv4
config.services.init-dhcpv4
];
};

View file

@ -3,37 +3,41 @@ let
svc = config.system.service;
in
{
services.int = svc.bridge.primary.build {
ifname = "int";
macAddressFromInterface = config.hardware.networkInterfaces.lan;
};
# Our bridging is a bit complicated, therefore, we need iproute2.
programs.iproute2.enable = true;
services.bridge = svc.bridge.members.build {
primary = config.services.int;
members = {
lan.member = config.hardware.networkInterfaces.lan;
wlan0 = {
member = config.hardware.networkInterfaces.wlan0;
# Bridge only once hostapd is ready.
dependencies = [ config.services.hostap-1-ready ];
};
wlan1 = {
member = config.hardware.networkInterfaces.wlan1;
# Bridge only once hostapd is ready.
dependencies = [ config.services.hostap-2-ready ];
services = {
int = svc.bridge.primary.build {
ifname = "int";
macAddressFromInterface = config.hardware.networkInterfaces.lan;
untagged = {
enable = true;
pvid = 1;
default-pvid = 1;
};
};
bridge = svc.bridge.members.build {
primary = config.services.int;
members = {
lan.member = config.hardware.networkInterfaces.lan;
wlan0 = {
member = config.hardware.networkInterfaces.wlan0;
# Bridge only once hostapd is ready.
dependencies = [ config.services.hostap-1-ready ];
};
wlan1 = {
member = config.hardware.networkInterfaces.wlan1;
# Bridge only once hostapd is ready.
dependencies = [ config.services.hostap-2-ready ];
};
};
};
admin-vlan = svc.vlan.build {
ifname = "admin";
primary = config.services.int;
vid = "3001";
};
};
# Default VLAN
# services.vlan-apro = svc.vlan.build {
# vlanId = 0;
# interface = config.services.int;
# };
# # Administration VLAN
# services.vlan-admin = svc.vlan.build {
# vlan = 3001;
# interface = config.services.int;
# };
}

View file

@ -6,11 +6,12 @@
}:
let
svc = config.system.service;
parentConfig = config;
in
{
defaultProfile.packages = with pkgs; [
defaultProfile.packages = [
# Levitate enable us to mass-reinstall the system on the fly.
(levitate.override {
(pkgs.levitate.override {
config = {
imports = [
"${modulesPath}/network"
@ -19,24 +20,33 @@ in
"${modulesPath}/kernel"
"${modulesPath}/outputs/tftpboot.nix"
"${modulesPath}/outputs.nix"
(
{ config, ... }:
{
services = {
# In this situation, we fallback to the appro VLAN.
# TODO: add support for the admin VLAN.
# Simplest DHCPv4 we can find.
dhcpv4 = svc.network.dhcp.client.build {
interface = parentConfig.hardware.networkInterfaces.lan;
};
inherit (parentConfig.services) sshd;
defaultroute4 = svc.network.route.build {
via = "$(output ${config.services.dhcpv4} router)";
target = "default";
dependencies = [ config.services.dhcpv4 ];
};
};
}
)
];
hostname = "${parentConfig.hostname}-live";
nixpkgs.buildPlatform = builtins.currentSystem;
services = {
# In this situation, we fallback to the appro VLAN.
# TODO: add support for the admin VLAN.
# Simplest DHCPv4 we can find.
dhcpv4 = svc.network.dhcp.client.build {
interface = config.hardware.networkInterfaces.lan;
};
inherit (config.services) sshd;
defaultroute4 = svc.network.route.build {
via = "$(output ${config.services.dhcpv4} router)";
target = "default";
dependencies = [ config.services.dhcpv4 ];
};
};
defaultProfile.packages = [ mtdutils ];
defaultProfile.packages = with pkgs; [
mtdutils
zyxel-bootconfig
];
# Only keep root, which should inherit from DGN access control's root permissions.
users.root = config.users.root;
};

View file

@ -131,9 +131,9 @@
"url": "https://git.dgnum.eu/DGNum/liminix"
},
"branch": "main",
"revision": "473d6acc3de70bd6dbbb4a77af54f508f25c3c9c",
"revision": "1322de1ee0cdb19fead79e12ab279ee0b575019a",
"url": null,
"hash": "00slsh0yqd8n8jcx3sbxgcmw1z28bnszy87pfs0ynfkl3bldzs3d"
"hash": "07nk6nik97k8a57cf17dcj3gn2lbhw1myymrxpqc2aqa3haj754k"
},
"linkal": {
"type": "Git",

View file

@ -0,0 +1,12 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p ubootTools
usage() {
echo "extract the firmware part to write it manually from a Zyxel NWA FIT image"
echo "$0 <zyxel_nwa_fit_image_path> <firmware_output_file>"
}
ZYXEL_NWA_FIT="$1"
FIRMWARE_OUTPUT="$2"
dumpimage -T flat_dt -p 0 $ZYXEL_NWA_FIT -o $FIRMWARE_OUTPUT

53
scripts/liminix-rebuild.sh Executable file
View file

@ -0,0 +1,53 @@
#!/usr/bin/env bash
# TODO: support automatic levitation when the rebuild counts does not fit in the target.
# TODO: support preflight checks where we detect the environment we are booted in (this requires the levitation to write a special file).
# TODO: use colmena to know the target host and focus on the node name.
set -Eeuo pipefail
ssh_command=${SSH_COMMAND-ssh}
root_prefix=${ROOT_PREFIX-/}
reboot="reboot"
case "$1" in
"--no-reboot")
unset reboot
shift
;;
"--fast")
reboot="soft"
shift
;;
"--live")
echo "Root prefix changed from $root_prefix to /mnt"
root_prefix="/mnt"
shift
;;
esac
target_host=$1
shift
if [ -z "$target_host" ] ; then
echo Usage: liminix-rebuild \[--no-reboot\] target-host params
exit 1
fi
if toplevel="$(nom-build $(colmena eval -E "{ nodes, ... }: nodes.$@.config.system.outputs.systemConfiguration" --instantiate))"; then
echo systemConfiguration $toplevel aimed at $root_prefix
sleep 3
min-copy-closure --root "$root_prefix" $target_host $toplevel
$ssh_command $target_host "$root_prefix/$toplevel/bin/install" "$root_prefix"
case "$reboot" in
reboot)
$ssh_command $target_host "sync; source /etc/profile; reboot"
;;
soft)
$ssh_command $target_host $toplevel/bin/restart-services
;;
*)
;;
esac
else
echo Rebuild failed
fi