network options working for basic functionality
This commit is contained in:
parent
e4cdc2cae5
commit
392375b046
9 changed files with 348 additions and 221 deletions
|
|
@ -1,8 +1,10 @@
|
||||||
{ pkgs, lib, system ? "x86_64-linux", ... }:
|
{ pkgs, lib, system ? "x86_64-linux", ... }:
|
||||||
let
|
let
|
||||||
images = import ./images { inherit pkgs lib system; };
|
images = import ./images { inherit pkgs lib system; };
|
||||||
|
network = import ./network.nix { inherit pkgs lib; };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
inherit images;
|
inherit images;
|
||||||
inherit (images.commons) customizeImage customizeImageFold;
|
inherit (images.commons) customizeImage customizeImageFold;
|
||||||
|
inherit network;
|
||||||
}
|
}
|
||||||
13
lib/network.nix
Normal file
13
lib/network.nix
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{ pkgs, lib, ... }: rec {
|
||||||
|
calc = (import ((builtins.fetchTarball "https://gist.github.com/duairc/5c9bb3c922e5d501a1edb9e7b3b845ba/archive/3885f7cd9ed0a746a9d675da6f265d41e9fd6704.tar.gz") + "/net.nix" ) { inherit lib; }).lib.net;
|
||||||
|
regex.ipv4 =
|
||||||
|
let
|
||||||
|
compRegex = "(25[0-5]|(2[0-4]|10|1?[1-9])?[0-9])";
|
||||||
|
in
|
||||||
|
"(${compRegex}\\.){3}${compRegex}";
|
||||||
|
|
||||||
|
regex.cidr4 = "${regex.ipv4}/(3[0-2]|[1-2]?[0-9])";
|
||||||
|
regex.ipOrCidr4 = "(${regex.ipv4}|${regex.cidr4})";
|
||||||
|
ipv4ToInt = ipv4: calc.ip.diff ipv4 "0.0.0.0";
|
||||||
|
intToipv4 = inte: calc.ip.add "0.0.0.0" inte;
|
||||||
|
}
|
||||||
|
|
@ -3,27 +3,8 @@ with lib;
|
||||||
let
|
let
|
||||||
vmixLib = import ./../lib {inherit pkgs lib; };
|
vmixLib = import ./../lib {inherit pkgs lib; };
|
||||||
vmixCfg = config.vmix;
|
vmixCfg = config.vmix;
|
||||||
vmixNetwork = import ./modules/network.nix { inherit config pkgs lib ;};
|
args = { inherit config pkgs lib vmixLib; };
|
||||||
vmixNetworkFunctions = import ./functions/network.nix { inherit pkgs lib ;};
|
|
||||||
#vmixVM = import ./modules/network.nix { inherit config pkgs lib ;};
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.vmix = {
|
imports = [ (import ./network args) ];
|
||||||
networks = lib.mkOption {
|
|
||||||
type = types.attrsOf
|
|
||||||
(types.submodule vmixNetwork);
|
|
||||||
default = { };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config =
|
|
||||||
with vmixNetworkFunctions;
|
|
||||||
#with vmixVMFunctions;
|
|
||||||
let
|
|
||||||
networkServices = lib.concatMapAttrs mkNetworkService vmixCfg.networks;
|
|
||||||
#vmServices = lib.concatMapAttrs mkVMService vmixCfg.vms;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
systemd.services = namespaceGlobalService // networkServices;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,121 +0,0 @@
|
||||||
{ pkgs, lib, ... }:
|
|
||||||
let
|
|
||||||
ipcalcFn = input: command:
|
|
||||||
let
|
|
||||||
runCmd = pkgs.runCommand "ipcalc-${command}" {} "export `${pkgs.ipcalc}/bin/ipcalc ${input} --${command}`; echo \$${lib.toUpper command} > $out;";
|
|
||||||
in
|
|
||||||
lib.removeSuffix "\n" (builtins.readFile runCmd);
|
|
||||||
in
|
|
||||||
{
|
|
||||||
namespaceGlobalService = {
|
|
||||||
"ns.vmix@" = {
|
|
||||||
description = "network namespace %I for vmix";
|
|
||||||
before = [ "network.target" ];
|
|
||||||
path = with pkgs; [ iproute2 utillinux ];
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
PrivateNetwork = true;
|
|
||||||
ExecStart = (pkgs.writeShellScript "ns.vmix-start" ''
|
|
||||||
NAMESPACE="$1.vmix"
|
|
||||||
ip netns add $NAMESPACE
|
|
||||||
umount /var/run/netns/$NAMESPACE
|
|
||||||
mount --bind /proc/self/ns/net /var/run/netns/$NAMESPACE
|
|
||||||
'') + " %I";
|
|
||||||
ExecStop = "${pkgs.iproute2}/bin/ip netns del %I.vmix";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
mkNetworkService = name: cfg:
|
|
||||||
let
|
|
||||||
netCfg = cfg // { inherit name; };
|
|
||||||
lanInterfaceName = "brx-${netCfg.name}";
|
|
||||||
lanInterfaceIPAddress = ipcalcFn netCfg.ipv4Range "minaddr";
|
|
||||||
hostIPAddressOnLan = ipcalcFn netCfg.ipv4Range "maxaddr";
|
|
||||||
networkAddress = ipcalcFn netCfg.ipv4Range "network";
|
|
||||||
netmask = ipcalcFn netCfg.ipv4Range "netmask";
|
|
||||||
networkPrefix = builtins.elemAt (lib.splitString "/" netCfg.ipv4Range) 1;
|
|
||||||
namespace = if netCfg.namespace != null then "${netCfg.namespace}.vmix" else "";
|
|
||||||
|
|
||||||
createLanInterface = pkgs.writeShellScript "create-lan-${netCfg.name}-vmix" ''
|
|
||||||
ip link add ${lanInterfaceName} type bridge
|
|
||||||
ip address add ${lanInterfaceIPAddress}/${networkPrefix} dev ${lanInterfaceName}
|
|
||||||
ip link set ${lanInterfaceName} up
|
|
||||||
'';
|
|
||||||
deleteLanInterface = pkgs.writeShellScript "delete-lan-${netCfg.name}-vmix" "ip link del ${lanInterfaceName}";
|
|
||||||
|
|
||||||
lanDomainName = "${netCfg.name}.vmix";
|
|
||||||
lanDnsmasqConf = pkgs.writeText "dnsmasq-${netCfg.name}.conf" ''
|
|
||||||
listen-address=${lanInterfaceIPAddress}
|
|
||||||
dhcp-range=${netCfg.dhcp.startAddress},${netCfg.dhcp.endAddress},${netmask},12h
|
|
||||||
dhcp-option=3,${hostIPAddressOnLan}
|
|
||||||
interface=${lanInterfaceName}
|
|
||||||
bind-interfaces
|
|
||||||
except-interface=lo
|
|
||||||
dhcp-authoritative
|
|
||||||
domain=${lanDomainName}
|
|
||||||
domain-needed
|
|
||||||
localise-queries
|
|
||||||
no-hosts
|
|
||||||
expand-hosts
|
|
||||||
dhcp-leasefile=/tmp/dhcp.leases
|
|
||||||
'' +
|
|
||||||
lib.concatStringsSep "\n" (lib.optionals (netCfg.dns.upstream != []) ([ "no-resolv" ] ++ (lib.map (dnsServer: "server ${dnsServer}") netCfg.dns.upstream)));
|
|
||||||
|
|
||||||
vethToHostInNS = "vh-${netCfg.name}";
|
|
||||||
vethOnHostToNS = "vn-${netCfg.name}";
|
|
||||||
createWanInterface = pkgs.writeShellScript "create-wan-${netCfg.name}-vmix" ''
|
|
||||||
ip link add ${vethOnHostToNS} type veth peer name ${vethToHostInNS}
|
|
||||||
ip address add ${hostIPAddressOnLan}/${networkPrefix} dev ${vethOnHostToNS}
|
|
||||||
|
|
||||||
#iptables -A FORWARD -i ${vethOnHostToNS} -j ACCEPT
|
|
||||||
#iptables -A FORWARD -o ${vethOnHostToNS} -j ACCEPT
|
|
||||||
#iptables -A INPUT -i ${vethOnHostToNS} -j DROP
|
|
||||||
iptables -t nat -A POSTROUTING -s ${networkAddress}/${networkPrefix} -j MASQUERADE
|
|
||||||
|
|
||||||
ip link set ${vethToHostInNS} netns ${netCfg.namespace}
|
|
||||||
ip netns exec ${netCfg.namespace} ip link set ${vethToHostInNS} master ${lanInterfaceName}
|
|
||||||
|
|
||||||
ip link set ${vethOnHostToNS} up
|
|
||||||
ip netns exec ${netCfg.namespace} ip link set ${vethToHostInNS} up
|
|
||||||
'';
|
|
||||||
|
|
||||||
deleteWanInterface = "";
|
|
||||||
in
|
|
||||||
{
|
|
||||||
"lan.net.vmix@${netCfg.name}" = lib.recursiveUpdate {
|
|
||||||
wantedBy = lib.optional netCfg.startOnBoot [ "net.vmix.target" ];
|
|
||||||
path = with pkgs; [ iproute2 ];
|
|
||||||
serviceConfig = {
|
|
||||||
ExecStartPre = createLanInterface;
|
|
||||||
ExecStart = "${pkgs.dnsmasq}/bin/dnsmasq -d -C ${lanDnsmasqConf}";
|
|
||||||
ExecReload = pkgs.writeShellScript "reload-dnsmasq" "kill -HUP $MAINPID";
|
|
||||||
ExecStopPost = deleteLanInterface;
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = "5";
|
|
||||||
PrivateTmp = true;
|
|
||||||
ProtectSystem = true;
|
|
||||||
ProtectHome = true;
|
|
||||||
};
|
|
||||||
} (lib.optionalAttrs (netCfg.namespace != null) rec {
|
|
||||||
bindsTo = [ "ns.vmix@${netCfg.namespace}.service" ];
|
|
||||||
after = bindsTo;
|
|
||||||
unitConfig.JoinsNamespaceOf = "ns.vmix@${netCfg.namespace}.service";
|
|
||||||
serviceConfig.PrivateNetwork = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
"wan.net.vmix@${netCfg.name}" = rec {
|
|
||||||
wantedBy = lib.optional netCfg.startOnBoot [ "net.vmix.target" ];
|
|
||||||
path = with pkgs; [ iproute2 iptables ];
|
|
||||||
bindsTo = [ "lan.net.vmix@${netCfg.name}.service" ];
|
|
||||||
after = bindsTo;
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
ExecStart = createWanInterface;
|
|
||||||
ExecStop = deleteWanInterface;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
{ config, pkgs, lib, ... }:
|
|
||||||
with lib;
|
|
||||||
let
|
|
||||||
ipv4Regex =
|
|
||||||
let
|
|
||||||
compRegex = "(25[0-5]|(2[0-4]|10|1?[1-9])?[0-9])";
|
|
||||||
in
|
|
||||||
"(${compRegex}\\.){3}${compRegex}";
|
|
||||||
|
|
||||||
cidr4Regex = "${ipv4Regex}/(3[0-2]|[1-2]?[0-9])";
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options = {
|
|
||||||
startOnBoot = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = "Whether to start this network on boot regardless if a VM is needing this network.";
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "Linux network namespace under which this network is created. If not declared, it will create under hosts network namespace.";
|
|
||||||
};
|
|
||||||
|
|
||||||
type = mkOption {
|
|
||||||
type =types.enum [ "user" "nat" "natWANOnly" "routed" "routedWANOnly" "isolated" "bridge" ];
|
|
||||||
description = ''
|
|
||||||
Network types.
|
|
||||||
- "user" is qemu slirp user network, which can be shared across multiple VMs if needed
|
|
||||||
- "nat" is a NAT with an internal network, with a DHCP/DNS server, a domainsearch name and masqueraded access to the host's network
|
|
||||||
- "natWANOnly" just like nat but no access to the host itself, or other networks on the host, while allowing WAN access through the hosts default gateway
|
|
||||||
- "routed" is an internal network, with a DHCP/DNS server, a domainsearch name and routed inbound and outbound access to the host's network
|
|
||||||
- "routedWANOnly" just like routed, but no access to the host itself, or other networks on the host, while allowing WAN inbound and outbound access through the hosts default gateway
|
|
||||||
- "isolated" creates an internal network, a DHCP/DNS server, a domainsearch name with no access to host's network or WAN
|
|
||||||
- "bridge" is a bridge with another network or a host's network interface
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
ipv4Range = mkOption {
|
|
||||||
type = types.strMatching cidr4Regex;
|
|
||||||
description = "IPv4 Range in x.x.x.x/y format to be assigned to the network.";
|
|
||||||
};
|
|
||||||
|
|
||||||
dhcp.enable = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
description = "Whether to start a DHCP server within this network.";
|
|
||||||
};
|
|
||||||
|
|
||||||
dhcp.startAddress = mkOption {
|
|
||||||
type = types.strMatching ipv4Regex;
|
|
||||||
description = "Starting IP Address for DHCP clients.";
|
|
||||||
};
|
|
||||||
|
|
||||||
dhcp.endAddress = mkOption {
|
|
||||||
type = types.strMatching ipv4Regex;
|
|
||||||
description = "Ending IP Address for DHCP clients.";
|
|
||||||
};
|
|
||||||
|
|
||||||
dns.upstream = mkOption {
|
|
||||||
type = types.listOf (types.strMatching ipv4Regex);
|
|
||||||
default = [];
|
|
||||||
description = "List of IP Addresses of DNS servers to use as upstream DNS servers in the DHCP/DNS server. If left empty, it will use host's DNS servers";
|
|
||||||
};
|
|
||||||
|
|
||||||
dns.zonefiles = mkOption {
|
|
||||||
description = "Additional zonefiles to add for the DNS server";
|
|
||||||
};
|
|
||||||
|
|
||||||
routes.internal.add = mkOption {
|
|
||||||
description = "Additional routes to add on the internal network";
|
|
||||||
};
|
|
||||||
|
|
||||||
routes.host.add = mkOption {
|
|
||||||
description = "Addtional routes to add on the host's network namespace";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
159
nixos/network/config.nix
Normal file
159
nixos/network/config.nix
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
{ config, pkgs, lib, vmixLib, ... }:
|
||||||
|
with vmixLib.network;
|
||||||
|
let
|
||||||
|
vmixCfg = config.vmix;
|
||||||
|
# creates a /30 network from available range for veth-pair wan interfaces
|
||||||
|
mkVethIPv4Range = index: availableIPv4Range:
|
||||||
|
let
|
||||||
|
vethIPv4RangeLength = 30;
|
||||||
|
in
|
||||||
|
(calc.cidr.subnet (vethIPv4RangeLength - (calc.cidr.length availableIPv4Range)) index availableIPv4Range);
|
||||||
|
|
||||||
|
namespaceGlobalService = {
|
||||||
|
"ns.net.vmix@" = {
|
||||||
|
description = "network namespace %I for vmix";
|
||||||
|
before = [ "network.target" ];
|
||||||
|
path = with pkgs; [ iproute2 utillinux ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
PrivateNetwork = true;
|
||||||
|
ExecStart = (pkgs.writeShellScript "ns.net.vmix-start" ''
|
||||||
|
NAMESPACE="$1.vmix"
|
||||||
|
ip netns add $NAMESPACE
|
||||||
|
umount /var/run/netns/$NAMESPACE
|
||||||
|
mount --bind /proc/self/ns/net /var/run/netns/$NAMESPACE
|
||||||
|
'') + " %I";
|
||||||
|
ExecStop = "${pkgs.iproute2}/bin/ip netns del %I.vmix";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mkLanService = networkName: lanName: cfg:
|
||||||
|
let
|
||||||
|
lanCfg = cfg // { name = lanName; namespace = "${networkName}"; };
|
||||||
|
lanInterfaceName = "brx-${lanCfg.name}";
|
||||||
|
lanInterfaceIPAddress = calc.cidr.host 1 lanCfg.ipv4.range;
|
||||||
|
netmask = calc.cidr.netmask lanCfg.ipv4.range;
|
||||||
|
networkPrefix = builtins.elemAt (lib.splitString "/" lanCfg.ipv4.range) 1;
|
||||||
|
|
||||||
|
createLanInterface = pkgs.writeShellScript "create-lan-${lanCfg.name}-vmix" ''
|
||||||
|
ip link add ${lanInterfaceName} type bridge
|
||||||
|
ip address add ${lanInterfaceIPAddress}/${networkPrefix} dev ${lanInterfaceName}
|
||||||
|
ip link set ${lanInterfaceName} up
|
||||||
|
'';
|
||||||
|
deleteLanInterface = pkgs.writeShellScript "delete-lan-${lanCfg.name}-vmix" "ip link del ${lanInterfaceName}";
|
||||||
|
|
||||||
|
lanDomainName = "${lanCfg.name}.vmix";
|
||||||
|
lanDnsmasqConf = pkgs.writeText "dnsmasq-${lanCfg.name}.conf" (''
|
||||||
|
listen-address=${lanInterfaceIPAddress}
|
||||||
|
dhcp-range=${lanCfg.ipv4.dhcp.startAddress},${lanCfg.ipv4.dhcp.endAddress},${netmask},12h
|
||||||
|
interface=${lanInterfaceName}
|
||||||
|
bind-interfaces
|
||||||
|
except-interface=lo
|
||||||
|
dhcp-authoritative
|
||||||
|
domain=${lanDomainName}
|
||||||
|
domain-needed
|
||||||
|
localise-queries
|
||||||
|
no-hosts
|
||||||
|
expand-hosts
|
||||||
|
dhcp-leasefile=/tmp/dhcp.leases
|
||||||
|
'' +
|
||||||
|
lib.concatStringsSep "\n" (lib.optionals (lanCfg.ipv4.dns.upstream != []) ([ "no-resolv" ] ++ (builtins.map (dnsServer: "server=${dnsServer}") lanCfg.ipv4.dns.upstream)))
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
"lan.net.vmix@${lanCfg.name}.${lanCfg.namespace}" = rec {
|
||||||
|
bindsTo = [ "ns.net.vmix@${lanCfg.namespace}.service" ];
|
||||||
|
after = bindsTo;
|
||||||
|
wantedBy = [ "net.vmix@${lanCfg.namespace}.target" ];
|
||||||
|
unitConfig.JoinsNamespaceOf = "ns.net.vmix@${lanCfg.namespace}.service";
|
||||||
|
path = with pkgs; [ iproute2 ];
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStartPre = createLanInterface;
|
||||||
|
ExecStart = "${pkgs.dnsmasq}/bin/dnsmasq -d -C ${lanDnsmasqConf}";
|
||||||
|
ExecReload = pkgs.writeShellScript "reload-dnsmasq" "kill -HUP $MAINPID";
|
||||||
|
ExecStopPost = deleteLanInterface;
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = "5";
|
||||||
|
PrivateTmp = true;
|
||||||
|
ProtectSystem = true;
|
||||||
|
ProtectHome = true;
|
||||||
|
PrivateNetwork = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mkWanService = networkName: cfg:
|
||||||
|
let
|
||||||
|
wanCfg = cfg // { namespace = networkName; };
|
||||||
|
vethInNSToHost.iface = "vhost";
|
||||||
|
vethOnHostToNS.iface = "vn-${wanCfg.namespace}";
|
||||||
|
vethOnHostToNS.ipv4.address = calc.cidr.host 1 wanCfg.ipv4.range;
|
||||||
|
vethInNSToHost.ipv4.address = calc.cidr.host 2 wanCfg.ipv4.range;
|
||||||
|
networkPrefix = builtins.elemAt (lib.splitString "/" wanCfg.ipv4.range) 1;
|
||||||
|
iptablesMark = builtins.toString (ipv4ToInt vethOnHostToNS.ipv4.address);
|
||||||
|
|
||||||
|
createWanCommands = ''
|
||||||
|
ip link add ${vethOnHostToNS.iface} type veth peer name ${vethInNSToHost.iface}
|
||||||
|
ip link set ${vethInNSToHost.iface} netns ${wanCfg.namespace}.vmix
|
||||||
|
|
||||||
|
ip address add ${vethOnHostToNS.ipv4.address}/${networkPrefix} dev ${vethOnHostToNS.iface}
|
||||||
|
ip netns exec ${wanCfg.namespace}.vmix ip address add ${vethInNSToHost.ipv4.address}/${networkPrefix} dev ${vethInNSToHost.iface}
|
||||||
|
|
||||||
|
iptables -A FORWARD -i ${vethOnHostToNS.iface} -j ACCEPT
|
||||||
|
iptables -A FORWARD -o ${vethOnHostToNS.iface} -j ACCEPT
|
||||||
|
#iptables -A INPUT -i ${vethOnHostToNS.iface} -j DROP
|
||||||
|
|
||||||
|
iptables -t mangle -A PREROUTING -i ${vethOnHostToNS.iface} -j MARK --set-mark ${iptablesMark}
|
||||||
|
iptables -t nat -A POSTROUTING -m mark --mark ${iptablesMark} -j MASQUERADE
|
||||||
|
|
||||||
|
ip link set ${vethOnHostToNS.iface} up
|
||||||
|
ip netns exec ${wanCfg.namespace}.vmix ip link set ${vethInNSToHost.iface} up
|
||||||
|
ip netns exec ${wanCfg.namespace}.vmix ip r add default via ${vethOnHostToNS.ipv4.address}
|
||||||
|
'';
|
||||||
|
|
||||||
|
createWan = pkgs.writeShellScript "create-wan-${wanCfg.namespace}-vmix" createWanCommands;
|
||||||
|
|
||||||
|
deleteWan =
|
||||||
|
let
|
||||||
|
createdIptablesRules = lib.filter (line: (lib.hasPrefix "iptables" line)) (lib.splitString "\n" createWanCommands);
|
||||||
|
delIptablesRules = builtins.map (rule: lib.replaceStrings [ "-A" ] [ "-D"] rule) createdIptablesRules;
|
||||||
|
in
|
||||||
|
pkgs.writeShellScript "delete-wan-${wanCfg.namespace}-vmix" (''
|
||||||
|
ip link del ${vethOnHostToNS.iface}
|
||||||
|
'' + (lib.concatStringsSep "\n" delIptablesRules));
|
||||||
|
in
|
||||||
|
{
|
||||||
|
"wan.net.vmix@${wanCfg.namespace}" = rec {
|
||||||
|
bindsTo = [ "ns.net.vmix@${wanCfg.namespace}.service" ];
|
||||||
|
after = bindsTo;
|
||||||
|
wantedBy = [ "net.vmix@${wanCfg.namespace}.target" ];
|
||||||
|
path = with pkgs; [ iproute2 iptables ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
ExecStart = createWan;
|
||||||
|
ExecStop = deleteWan;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mkMacvlanService = networkName: macvlanName: cfg:
|
||||||
|
{};
|
||||||
|
|
||||||
|
mkNetworkServices = networkName: cfg:
|
||||||
|
let
|
||||||
|
netCfg = cfg // { name = networkName; };
|
||||||
|
in
|
||||||
|
(lib.concatMapAttrs (mkLanService netCfg.name) netCfg.lans)
|
||||||
|
// (mkWanService netCfg.name (netCfg.wan // { ipv4.range = (mkVethIPv4Range netCfg.index vmixCfg.global.net.wan.ipv4.range); }))
|
||||||
|
// (lib.concatMapAttrs (mkMacvlanService netCfg.name) netCfg.bridges.macvlans);
|
||||||
|
|
||||||
|
networkNames = builtins.attrNames vmixCfg.networks;
|
||||||
|
|
||||||
|
networkServices = pkgs.unstable.lib.mergeAttrsList (lib.imap0 (index: networkName: (mkNetworkServices networkName (vmixCfg.networks.${networkName} // { inherit index;}))) networkNames);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
config.systemd.services = namespaceGlobalService // networkServices;
|
||||||
|
}
|
||||||
16
nixos/network/default.nix
Normal file
16
nixos/network/default.nix
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
args@{ config, pkgs, lib, vmixLib, ... }:
|
||||||
|
with lib;
|
||||||
|
{
|
||||||
|
options.vmix.global.net.wan.ipv4.range = lib.mkOption {
|
||||||
|
type = types.strMatching vmixLib.network.regex.cidr4;
|
||||||
|
default = "172.27.72.0/24"; # enough to create 64x /30 networks for veth pairs used for wan interfaces
|
||||||
|
};
|
||||||
|
|
||||||
|
options.vmix.networks = lib.mkOption {
|
||||||
|
type = types.attrsOf
|
||||||
|
(types.submodule (import ./options.nix args));
|
||||||
|
default = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
imports = [ (import ./config.nix args) ];
|
||||||
|
}
|
||||||
156
nixos/network/options.nix
Normal file
156
nixos/network/options.nix
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
{ config, pkgs, lib, vmixLib, ... }:
|
||||||
|
with lib;
|
||||||
|
with vmixLib.network;
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
bridges.macvlans = mkOption {
|
||||||
|
type = types.attrsOf (types.submodule {
|
||||||
|
options = {
|
||||||
|
uplink.iface = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
|
||||||
|
uplink.namespace = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
ipv4.static.address = mkOption {
|
||||||
|
type = types.nullOr (types.strMatching regex.ipOrCidr4);
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
ipv4.static.gateway = mkOption {
|
||||||
|
type = types.nullOr (types.strMatching regex.ipv4);
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
ipv4.dhcp.client = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
ipv4.dhcp.gateway = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
bridges.macvtaps = mkOption {
|
||||||
|
type = types.attrsOf (types.submodule {
|
||||||
|
options = {
|
||||||
|
uplink.iface = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
|
||||||
|
uplink.namespace = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
many = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
wan = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
host.wan.enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
host.wan.masquerade = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
host.lan.enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
host.lan.masquerade = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
host.self.enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
lans = mkOption {
|
||||||
|
type = types.attrsOf (types.submodule {
|
||||||
|
options.ipv4 = {
|
||||||
|
range = mkOption {
|
||||||
|
type = types.strMatching regex.cidr4;
|
||||||
|
description = "IPv4 Range in x.x.x.x/y format to be assigned to the network.";
|
||||||
|
};
|
||||||
|
|
||||||
|
address = mkOption {
|
||||||
|
type = types.nullOr (types.strMatching regex.ipv4);
|
||||||
|
default = null;
|
||||||
|
description = "IPv4 address to attach to the bridge interface of this Lan.";
|
||||||
|
};
|
||||||
|
|
||||||
|
dhcp.enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to start a DHCP server within this network.";
|
||||||
|
};
|
||||||
|
|
||||||
|
dhcp.startAddress = mkOption {
|
||||||
|
type = types.nullOr (types.strMatching regex.ipv4);
|
||||||
|
description = "Starting IP Address for DHCP clients.";
|
||||||
|
};
|
||||||
|
|
||||||
|
dhcp.endAddress = mkOption {
|
||||||
|
type = types.nullOr (types.strMatching regex.ipv4);
|
||||||
|
description = "Ending IP Address for DHCP clients.";
|
||||||
|
};
|
||||||
|
|
||||||
|
dns.upstream = mkOption {
|
||||||
|
type = types.listOf (types.strMatching regex.ipv4);
|
||||||
|
default = [];
|
||||||
|
description = "List of IP Addresses of DNS servers to use as upstream DNS servers in the DHCP/DNS server. If left empty, it will use host's DNS servers";
|
||||||
|
};
|
||||||
|
|
||||||
|
dns.useHostResolvConf = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to use host's /etc/resolv.conf for upstream DNS queries.";
|
||||||
|
};
|
||||||
|
|
||||||
|
dns.zonefiles = mkOption {
|
||||||
|
default = null;
|
||||||
|
description = "Additional zonefiles to add for the DNS server";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
# routes.internal.add = mkOption {
|
||||||
|
# description = "Additional routes to add on the internal network";
|
||||||
|
# };
|
||||||
|
|
||||||
|
# routes.host.add = mkOption {
|
||||||
|
# description = "Addtional routes to add on the host's network namespace";
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue