convert network link/address to module-based-service

... and make bridge use it.

We also had to convert bridge back into a pair of services.
Downstreams want to depend on the bridge it self being configured
even if not necessarily all the members are up. e.g. don't want
to break ssh on lan if there's a misconfigured wlan device
This commit is contained in:
Daniel Barlow 2023-08-27 23:45:27 +01:00
parent 1580857fde
commit 31f0213b6f
9 changed files with 185 additions and 58 deletions

View file

@ -80,6 +80,8 @@
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs.liminix.networking) interface;
in {
imports = [ ../../modules/network];
programs.busybox.options = {
FEATURE_DD_IBS_OBS = "y"; # ath10k_cal_data needs skip_bytes,fullblock
};
@ -100,16 +102,17 @@
];
};
networkInterfaces = {
lan = interface { device = "eth0"; };
wan = interface { device = "eth1"; };
wlan_24 = interface {
device = "wlan0";
networkInterfaces =
let inherit (config.system.service.network) link;
in {
lan = link.build { ifname = "eth0"; };
wan = link.build { ifname = "eth1"; };
wlan_24 = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan_5 = interface {
device = "wlan1";
wlan_5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ath10k_cal_data ];
};
};

View file

@ -44,6 +44,7 @@ in rec {
imports = [
../modules/wlan.nix
../modules/standard.nix
../modules/network
../modules/ppp
../modules/dnsmasq
../modules/firewall
@ -78,15 +79,15 @@ in rec {
} // wirelessConfig;
};
services.int =
let iface = svc.bridge.build {
ifname = "int";
members = with config.hardware.networkInterfaces; [
wlan_24 lan wlan_5
];
services.int = svc.network.address.build {
interface = svc.bridge.primary.build { ifname = "int"; };# services.int;
family = "inet"; address ="10.8.0.1"; prefixLength = 16;
};
in address iface {
family = "inet4"; address ="10.8.0.1"; prefixLength = 16;
services.bridge = svc.bridge.members.build {
primary = services.int;
members = with config.hardware.networkInterfaces;
[ wlan_24 wlan_5 lan ];
};
services.ntp = svc.ntp.build {
@ -204,8 +205,8 @@ in rec {
name = "default";
contents = with config.services; [
config.hardware.networkInterfaces.lo
config.hardware.networkInterfaces.lan
int
bridge
hostap
hostap5
ntp

View file

@ -15,21 +15,29 @@ let
in
{
options = {
system.service.bridge = mkOption {
type = liminix.lib.types.serviceDefn;
system.service.bridge = {
primary = mkOption { type = liminix.lib.types.serviceDefn; };
members = mkOption { type = liminix.lib.types.serviceDefn; };
};
};
config.system.service = {
bridge = liminix.callService ./service.nix {
members = mkOption {
type = types.listOf liminix.lib.types.service;
description = "interfaces to add to the bridge";
};
config.system.service.bridge = {
primary = liminix.callService ./primary.nix {
ifname = mkOption {
type = types.str;
description = "bridge interface name to create";
};
};
members = liminix.callService ./members.nix {
primary = mkOption {
type = liminix.lib.types.interface;
description = "primary bridge interface";
};
members = mkOption {
type = types.listOf liminix.lib.types.interface;
description = "interfaces to add to the bridge";
};
};
};
config.kernel.config.BRIDGE = "y";
}

View file

@ -0,0 +1,25 @@
{
liminix
, ifwait
, lib
}:
{ members, primary } :
let
inherit (liminix.networking) interface;
inherit (liminix.services) bundle oneshot;
inherit (lib) mkOption types;
addif = member :
oneshot {
name = "${primary.name}.member.${member.name}";
up = ''
dev=$(output ${member} ifname)
${ifwait}/bin/ifwait $dev running && ip link set dev $dev master $(output ${primary} ifname)
'';
down = "ip link set dev $(output ${member} ifname) nomaster";
dependencies = [ primary member ];
};
in bundle {
name = "${primary.name}.members";
contents = map addif members;
}

View file

@ -0,0 +1,18 @@
{
liminix
, ifwait
, lib
}:
{ ifname } :
let
inherit (liminix.networking) interface;
inherit (liminix.services) bundle oneshot;
inherit (lib) mkOption types;
in oneshot rec {
name = "${ifname}.link";
up = ''
ip link add name ${ifname} type bridge
${liminix.networking.ifup name ifname}
'';
down = "ip link set down dev ${ifname}";
}

View file

@ -1,27 +0,0 @@
{
liminix
, ifwait
, lib
}:
{ members, ifname } :
let
inherit (liminix.networking) interface;
inherit (liminix.services) bundle oneshot;
inherit (lib) mkOption types;
primary = interface {
device = ifname;
type = "bridge";
};
addif = member :
let ifname = "$(output ${member} ifname)";
in oneshot {
name = "add-${member.name}-to-br-${primary.name}";
up = "${ifwait}/bin/ifwait ${ifname} running && ip link set dev ${ifname} master $(output ${primary} ifname)";
down = "ip link set dev ${ifname} nomaster";
dependencies = [ primary member ];
};
in bundle {
name = "bridge-${primary.name}-members";
contents = [ primary ] ++ map addif members;
}

View file

@ -0,0 +1,29 @@
{
liminix
, ifwait
, serviceFns
, lib
}:
{interface, family, address, prefixLength} :
let
inherit (liminix.services) oneshot;
# rather depending on the assumption that nobody will
# ever add two addresses which are the same but with different
# prefixes, or the same but different protocols
name = "${interface.name}.a.${address}";
up = ''
. ${serviceFns}
dev=$(output ${interface} ifname)
ip address add ${address}/${toString prefixLength} dev $dev
(in_outputs ${name}
echo ${address} > address
echo ${toString prefixLength} > prefix-length
echo ${family} > family
echo $dev > ifname
)
'';
in oneshot {
inherit name up;
down = "true"; # this has been broken for ~ ages
dependencies = [ interface ];
}

View file

@ -0,0 +1,54 @@
## Network
## =======
##
## Basic network services for creating hardware ethernet devices
## and adding addresses
{ lib, pkgs, config, ...}:
let
inherit (lib) mkOption types;
inherit (pkgs) liminix;
in {
options = {
system.service.network = {
link = mkOption {
description = "hardware network interface";
type = liminix.lib.types.serviceDefn;
};
address = mkOption {
description = "network interface address";
type = liminix.lib.types.serviceDefn;
};
};
};
config = {
system.service.network = {
link = liminix.callService ./link.nix {
ifname = mkOption {
type = types.str;
example = "eth0";
};
# other "ip link add" options could go here as well
mtu = mkOption {
type = types.nullOr types.int;
example = 1480;
};
};
address = liminix.callService ./address.nix {
interface = mkOption {
type = liminix.lib.types.service;
};
family = mkOption {
type = types.enum [ "inet" "inet6" ];
};
address = mkOption {
type = types.str;
};
prefixLength = mkOption {
type = types.ints.between 0 128;
};
};
};
};
}

16
modules/network/link.nix Normal file
View file

@ -0,0 +1,16 @@
{
liminix
, ifwait
, serviceFns
, lib
}:
{ifname, mtu} :
let
inherit (liminix.services) longrun oneshot;
inherit (lib) concatStringsSep;
name = "${ifname}.link";
up = liminix.networking.ifup name ifname;
in oneshot {
inherit name up;
down = "ip link set down dev ${ifname}";
}