vxlan over wireless: first try

This commit is contained in:
Astro 2022-01-18 01:05:16 +01:00
parent 5f675b13d2
commit 1327680612
6 changed files with 214 additions and 52 deletions

View File

@ -1,3 +1,4 @@
{ config, ... }:
{ {
site.hosts = { site.hosts = {
ap-test1 = { ap-test1 = {
@ -1722,8 +1723,90 @@
}; };
}; };
}; };
ap57 = { }; ap57 = {
ap58 = { }; role = "ap";
model = "unifiac-mesh";
location = "Dach";
interfaces = {
mgmt = {
gw4 = "mgmt-gw";
gw6 = "mgmt-gw";
type = "bridge";
};
pub.type = "bridge";
roof.type = "phys";
ap58 = {
type = "vxlan";
vxlan.peer = config.site.net.roof.hosts6.dn42.ap58;
};
priv43.type = "bridge";
};
wifi = {
"pci0000:00/0000:00:00.0" = {
channel = 100;
htmode = "VHT80";
ssids = {
"Zentralwerk" = {
net = "roof";
};
};
};
"platform/ahb/18100000.wmac" = {
channel = 1;
htmode = "HT20";
ssids = {
# wifi on the roof
"ZW public".net = "pub";
};
};
};
links = {
switch-dach.ports = [ "lan" ];
ap58.ports = [ "ap58" ];
};
};
ap58 = {
role = "ap";
model = "unifiac-mesh";
location = "Coswiger Str.";
interfaces = {
mgmt = {
gw4 = "mgmt-gw";
gw6 = "mgmt-gw";
type = "phys";
};
pub.type = "bridge";
ap57 = {
type = "vxlan";
vxlan.peer = config.site.net.roof.hosts6.dn42.ap57;
};
priv43.type = "bridge";
};
wifi = {
"pci0000:00/0000:00:00.0" = {
channel = 100;
htmode = "VHT80";
ssids = {
"Zentralwerk" = {
net = "roof";
type = "sta";
};
};
};
"platform/ahb/18100000.wmac" = {
channel = 9;
htmode = "HT20";
ssids = {
"ZW public".net = "pub";
"LIZA".net = "priv43";
};
};
};
links = {
priv43.ports = [ "lan" ];
ap57.ports = [ "ap57" ];
};
};
ap59 = { }; ap59 = { };
ap6 = { ap6 = {
interfaces = { interfaces = {

13
config/net/roof.nix Normal file
View File

@ -0,0 +1,13 @@
{
site.net.roof = {
# not switched, only a wifi
vlan = null;
# leave space for vxlan
mtu = 2048;
hosts6.dn42 = {
ap57 = "fd23:42:c3d2:584::39";
ap58 = "fd23:42:c3d2:584::40";
};
subnets6.dn42 = "fd23:42:c3d2:584::/64";
};
}

View File

@ -57,6 +57,8 @@
ap54.password = "encrypted"; ap54.password = "encrypted";
ap55.password = "encrypted"; ap55.password = "encrypted";
ap56.password = "encrypted"; ap56.password = "encrypted";
ap57.password = "encrypted";
ap58.password = "encrypted";
switch-a1.password = "encrypted"; switch-a1.password = "encrypted";
switch-b1.password = "encrypted"; switch-b1.password = "encrypted";
switch-b2.password = "encrypted"; switch-b2.password = "encrypted";
@ -234,6 +236,13 @@
"pci0000:00/0000:00:00.0".ssids."MagLAN".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."MagLAN".psk = "encrypted";
"platform/qca956x_wmac".ssids."MagLAN (legacy)".psk = "encrypted"; "platform/qca956x_wmac".ssids."MagLAN (legacy)".psk = "encrypted";
}; };
ap57.wifi = {
"pci0000:00/0000:00:00.0".ssids."Zentralwerk".psk = "encrypted";
};
ap58.wifi = {
"pci0000:00/0000:00:00.0".ssids."Zentralwerk".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."LIZA".psk = "encrypted";
};
ap7.wifi."platform/qca953x_wmac".ssids."mino".psk = "encrypted"; ap7.wifi."platform/qca953x_wmac".ssids."mino".psk = "encrypted";
ap8.wifi = { ap8.wifi = {
"pci0000:00/0000:00:00.0".ssids."C3D2".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."C3D2".psk = "encrypted";

View File

@ -252,6 +252,8 @@
serv.ports = [ "6-9" ]; serv.ports = [ "6-9" ];
# Starlink # Starlink
up3.ports = [ "3" ]; up3.ports = [ "3" ];
# unifiac-mesh
ap57.ports = [ "5" ];
}; };
}; };
}; };

View File

@ -55,13 +55,13 @@ let
links' = builtins.tail links; links' = builtins.tail links;
in in
if config.site.hosts ? ${link} if config.site.hosts ? ${link}
then networksBehindLink' seen' ( then networksBehindLink' seen' (builtins.filter (link: ! seen' ? ${link}) (
links' ++ ( links' ++ (
builtins.attrNames config.site.hosts.${link}.interfaces builtins.attrNames config.site.hosts.${link}.interfaces
) ++ ( ) ++ (
onlyUnseen (builtins.attrNames config.site.hosts.${link}.links) onlyUnseen (builtins.attrNames config.site.hosts.${link}.links)
) )
) ))
else if config.site.net ? ${link} else if config.site.net ? ${link}
then networksBehindLink' seen' links' then networksBehindLink' seen' links'
@ -102,7 +102,7 @@ let
options = { options = {
vlan = mkOption { vlan = mkOption {
description = "VLAN tag number"; description = "VLAN tag number";
type = types.int; type = with types; nullOr int;
}; };
subnet4 = mkOption { subnet4 = mkOption {
description = "v.w.x.y/z"; description = "v.w.x.y/z";
@ -185,6 +185,10 @@ let
default = false; default = false;
description = "Domain updated by DHCP server?"; description = "Domain updated by DHCP server?";
}; };
mtu = mkOption {
type = with types; nullOr int;
default = null;
};
}; };
}; };
@ -228,7 +232,7 @@ let
description = "Static MAC address"; description = "Static MAC address";
}; };
type = mkOption { type = mkOption {
type = types.enum [ "phys" "veth" "pppoe" "bridge" "wireguard" ]; type = types.enum [ "phys" "veth" "pppoe" "bridge" "wireguard" "vxlan" ];
description = '' description = ''
veth: Virtual ethernet to be attached to a bridge. veth: Virtual ethernet to be attached to a bridge.
@ -271,6 +275,16 @@ let
}; };
}); });
}; };
vxlan = mkOption {
default = null;
type = with types; nullOr (submodule {
options = {
peer = mkOption {
type = str;
};
};
});
};
}; };
}; };
@ -438,6 +452,10 @@ let
type = nullOr str; type = nullOr str;
default = null; default = null;
}; };
type = mkOption {
type = enum [ "ap" "sta" ];
default = "ap";
};
}; };
} }
)); ));
@ -484,8 +502,12 @@ let
vlans = mkOption { vlans = mkOption {
type = with types; listOf int; type = with types; listOf int;
description = "Automatically generated, do not set"; description = "Automatically generated, do not set";
default = map (net: default = builtins.concatMap (net:
config.site.net.${net}.vlan let
inherit (config.site.net.${net}) vlan;
in if vlan != null
then [ vlan ]
else []
) config.site.hosts.${hostName}.links.${name}.nets; ) config.site.hosts.${hostName}.links.${name}.nets;
}; };
trunk = mkOption { trunk = mkOption {
@ -614,7 +636,7 @@ in
let let
vlan = toString config.site.net.${net}.vlan; vlan = toString config.site.net.${net}.vlan;
in in
if result ? ${vlan} if config.site.net.${net}.vlan != null && result ? ${vlan}
then result // { then result // {
"${vlan}" = result.${vlan} ++ [ net ]; "${vlan}" = result.${vlan} ++ [ net ];
} }

View File

@ -20,8 +20,12 @@ let
openwrtModel = self.lib.getOpenwrtModel hostConfig.model; openwrtModel = self.lib.getOpenwrtModel hostConfig.model;
hasSwitch = hasSwitch =
any ({ switch ? null, ... }: switch != null) if hostConfig.model == "unifiac-mesh"
(builtins.attrValues openwrtModel.ports); # ours don't come with a switch.
then false
else
any ({ switch ? null, ... }: switch != null)
(builtins.attrValues openwrtModel.ports);
portsDoc = portsDoc =
let let
@ -104,39 +108,35 @@ let
networkInterfaces = net: networkInterfaces = net:
let let
inherit (config.site.net.${net}) vlan; inherit (config.site.net.${net}) vlan;
in unique (
ifaces = builtins.concatMap ({ trunk, ports, switch ? null, ... }:
unique ( builtins.concatMap (port:
builtins.concatMap ({ trunk, ports, switch ? null, ... }: builtins.concatMap (portData:
builtins.concatMap (port: if portData ? port && port == portData.port
builtins.concatMap (portData: then [ ((
if portData ? port && port == portData.port if portData ? switch
then [ (( then switchHostInterface
if portData ? switch else if portData ? interface
then switchHostInterface then portData.interface
else if portData ? interface else throw "Cannot find interface for ${port} on OpenWRT model ${hostConfig.model}"
then portData.interface ) + (
else throw "Cannot find interface for ${port} on OpenWRT model ${hostConfig.model}" if trunk || switch != null
) + ( then ".${toString vlan}"
if trunk || switch != null else ""
then ".${toString vlan}" )) ]
else "" else []
)) ] ) (builtins.attrValues openwrtModel.ports)
else [] ++
) (builtins.attrValues openwrtModel.ports) lib.optionals (hostConfig.interfaces ? ${port}) [ "${port}.${toString vlan}" ]
) ports ) ports
) ( ) (
builtins.attrValues ( builtins.attrValues (
filterAttrs (link: { nets, ... }: filterAttrs (link: { nets, ... }:
link == net || builtins.elem net nets link == net || builtins.elem net nets
) hostConfig.links ) hostConfig.links
) )
) )
); );
in
if ifaces == []
then throw "No interfaces found for ${net} on ${hostName}"
else ifaces;
in '' in ''
#! ${pkgs.runtimeShell} -e #! ${pkgs.runtimeShell} -e
@ -193,12 +193,14 @@ in ''
# mgmt network # mgmt network
uci set network.mgmt=interface uci set network.mgmt=interface
uci set network.mgmt.ifname=${if builtins.length (networkInterfaces "mgmt") == 1 then builtins.head (networkInterfaces "mgmt") else throw "No interface for mgmt"} uci set network.mgmt.ifname=${
if builtins.length (networkInterfaces "mgmt") > 0
then lib.concatStringsSep " " (networkInterfaces "mgmt")
else throw "No interface for mgmt"
}
uci set network.mgmt.proto=static uci set network.mgmt.proto=static
uci set network.mgmt.ipaddr=${config.site.net.mgmt.hosts4.${hostName}} uci set network.mgmt.ipaddr=${config.site.net.mgmt.hosts4.${hostName}}
uci set network.mgmt.netmask=${self.lib.netmasks.${elemAt ( uci set network.mgmt.netmask=${self.lib.netmasks.${toString config.site.net.mgmt.subnet4Len}}
builtins.split "/" config.site.net.mgmt.subnet4
) 2}}
uci set network.mgmt.gateway=${config.site.net.mgmt.hosts4.mgmt-gw} uci set network.mgmt.gateway=${config.site.net.mgmt.hosts4.mgmt-gw}
uci set network.mgmt.ip6addr=${config.site.net.mgmt.hosts6.dn42.${hostName}}/64 uci set network.mgmt.ip6addr=${config.site.net.mgmt.hosts6.dn42.${hostName}}/64
uci set network.mgmt.ip6gw=${config.site.net.mgmt.hosts6.dn42.mgmt-gw} uci set network.mgmt.ip6gw=${config.site.net.mgmt.hosts6.dn42.mgmt-gw}
@ -214,15 +216,47 @@ in ''
'' ''
) ([ "lan" "wan" "wan6" ] ++ builtins.attrNames config.site.net)} ) ([ "lan" "wan" "wan6" ] ++ builtins.attrNames config.site.net)}
# bridged networks # bridged and static networks
${concatMapStrings (net: ${concatMapStrings (net:
let let
iface = hostConfig.interfaces.${net}; iface = hostConfig.interfaces.${net};
in optionalString (net != "mgmt" && iface.type == "bridge") '' in optionalString (net != "mgmt" && builtins.elem iface.type ["bridge" "phys"]) ''
uci set network.${net}=interface uci set network.${net}=interface
uci set network.${net}.type=bridge ${lib.optionalString (iface.type == "bridge") ''
uci set network.${net}.type=bridge
''}
uci set network.${net}.proto=static uci set network.${net}.proto=static
uci set network.${net}.ifname='${concatStringsSep " " (networkInterfaces net)}' uci set network.${net}.ifname='${concatStringsSep " " (networkInterfaces net)}'
${lib.optionalString (config.site.net.${net}.mtu != null) ''
uci set network.${net}.mtu=${toString config.site.net.${net}.mtu}
''}
${lib.optionalString (config.site.net.${net}.hosts4 ? ${hostName}) ''
# address in net
uci set network.${net}.ipaddr=${config.site.net.${net}.hosts4.${hostName}}
uci set network.${net}.netmask=${self.lib.netmasks.${toString config.site.net.${net}.subnet4Len}}
''}
${lib.concatMapStrings (ctx: lib.optionalString (ctx ? ${hostName}) ''
uci set network.mgmt.ip6addr=${config.site.net.${net}.hosts6.${ctx}.${hostName}}/64
'') (builtins.attrNames config.site.net.${net}.hosts6)}
'') (builtins.attrNames hostConfig.interfaces)
}
# vxlan trunks
${concatMapStrings (name:
let
iface = hostConfig.interfaces.${name};
in optionalString (iface.type == "vxlan") ''
uci set network.${name}=interface
uci set network.${name}.proto=vxlan
uci set network.${name}.tunlink='${name}'
uci set network.${name}.peeraddr='${iface.vxlan.peer}'
uci set network.${name}.port=4789
uci set network.${name}.mtu=1600
uci set network.${name}.rxcsum=0
uci set network.${name}.txcsum=0
uci set network.${name}.delegate=0
'') (builtins.attrNames hostConfig.interfaces) '') (builtins.attrNames hostConfig.interfaces)
} }
@ -265,7 +299,6 @@ in ''
uci set wireless.@wifi-iface[-1].encryption=none uci set wireless.@wifi-iface[-1].encryption=none
uci -q delete wireless.@wifi-iface[-1].key || true uci -q delete wireless.@wifi-iface[-1].key || true
''} ''}
'' ''
) (builtins.attrNames radioConfig.ssids)} ) (builtins.attrNames radioConfig.ssids)}
'') (builtins.attrNames hostConfig.wifi))} '') (builtins.attrNames hostConfig.wifi))}