systemd-networkd-wait-online interacts badly with non-routable interfaces. It ends up slowing down system config activation waiting for routes that never appear. Ignoring interfaces does not reliably fix this. Just disable the damn thing until I find a better solution.
196 lines
6.4 KiB
Nix
196 lines
6.4 KiB
Nix
# Host network configuration for vmsilo NixOS module
|
|
# TAP interfaces and NAT
|
|
{
|
|
config,
|
|
lib,
|
|
...
|
|
}:
|
|
|
|
let
|
|
cfg = config.programs.vmsilo;
|
|
helpers = import ./lib/helpers.nix { inherit lib; };
|
|
inherit (helpers)
|
|
parseCIDR
|
|
idxToIfIndex
|
|
generateMac
|
|
sortedInterfaceList
|
|
makeTapName
|
|
assignVmIds
|
|
;
|
|
|
|
vms = assignVmIds cfg.nixosVms;
|
|
|
|
# NOTE: getEffectiveInterfaces is intentionally duplicated in scripts.nix and services.nix.
|
|
# It cannot live in helpers.nix (which has no config access) and the three modules
|
|
# don't share a common let-binding scope. Keep the copies in sync.
|
|
getEffectiveInterfaces =
|
|
vm: vm.network.interfaces // (cfg._internal.netvmInjections.${vm.name}.interfaces or { });
|
|
|
|
# Get effective MAC for an interface (uses user-specified interface name)
|
|
getEffectiveIfaceMac =
|
|
vm: ifName: iface:
|
|
if iface.macAddress != null then iface.macAddress else generateMac vm.name ifName;
|
|
|
|
# Collect all TAP interfaces across all VMs
|
|
# Uses sortedInterfaceList for deterministic PCI slot assignment
|
|
allTapInterfaces = lib.flatten (
|
|
map (
|
|
vm:
|
|
lib.imap0 (
|
|
idx: entry:
|
|
let
|
|
ifName = entry.name;
|
|
iface = entry.value;
|
|
in
|
|
lib.optional (iface.type == "tap") {
|
|
inherit
|
|
vm
|
|
idx
|
|
ifName
|
|
iface
|
|
;
|
|
tapName =
|
|
if iface.tap != null && iface.tap.name != null then
|
|
iface.tap.name
|
|
else
|
|
makeTapName vm.name vm.id (idxToIfIndex idx);
|
|
}
|
|
) (sortedInterfaceList (getEffectiveInterfaces vm))
|
|
) vms
|
|
);
|
|
in
|
|
{
|
|
config = lib.mkIf cfg.enable {
|
|
# Enable IP forwarding
|
|
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
|
|
|
|
# Bridge changes are not reliable with the scripted approach
|
|
networking.useNetworkd = true;
|
|
|
|
# systemd-networkd-wait-online interacts badly with non-routable interfaces. It
|
|
# ends up slowing down system config activation waiting for routes that never
|
|
# appear. Ignoring interfaces does not reliably fix this. Just disable the damn
|
|
# thing until I find a better solution.
|
|
systemd.network.wait-online.enable = false;
|
|
|
|
# Configure vmsilo TAP/bridge network units:
|
|
# - Not required for online (VMs may not be running during nixos-rebuild)
|
|
# - ConfigureWithoutCarrier: assign static addresses even when link has no
|
|
# carrier (VM not running), so networkd reaches "configured" state
|
|
# immediately instead of getting stuck in "configuring"
|
|
# - No IPv6 autoconfiguration (prevents unwanted host addresses on
|
|
# VM-to-VM interfaces)
|
|
systemd.network.networks =
|
|
let
|
|
bridgedTaps = builtins.filter (
|
|
t: t.iface.tap != null && t.iface.tap.bridge != null
|
|
) allTapInterfaces;
|
|
bridgeNames = lib.unique (map (t: t.iface.tap.bridge) bridgedTaps);
|
|
unitConfig = {
|
|
linkConfig.RequiredForOnline = "no";
|
|
networkConfig.ConfigureWithoutCarrier = true;
|
|
networkConfig.IPv6AcceptRA = false;
|
|
networkConfig.LinkLocalAddressing = "no";
|
|
};
|
|
in
|
|
lib.listToAttrs (
|
|
map (t: lib.nameValuePair "40-${t.tapName}" unitConfig) allTapInterfaces
|
|
++ map (brName: lib.nameValuePair "40-${brName}" unitConfig) bridgeNames
|
|
);
|
|
|
|
# TAP interfaces for VMs with tap-type network interfaces.
|
|
# Also includes empty entries for bridge devices so that networkd generates
|
|
# .network files for them (without a .network file, networkd won't bring
|
|
# the bridge link up).
|
|
networking.interfaces =
|
|
let
|
|
tapEntries = map (
|
|
t:
|
|
lib.nameValuePair t.tapName (
|
|
{
|
|
virtual = true;
|
|
virtualOwner = cfg.user;
|
|
}
|
|
// lib.optionalAttrs (t.iface.tap != null && t.iface.tap.hostAddress != null) {
|
|
ipv4.addresses =
|
|
let
|
|
parsed = parseCIDR t.iface.tap.hostAddress;
|
|
in
|
|
[
|
|
{
|
|
address = parsed.ip;
|
|
prefixLength = parsed.prefix;
|
|
}
|
|
];
|
|
}
|
|
)
|
|
) allTapInterfaces;
|
|
bridgedTaps = builtins.filter (
|
|
t: t.iface.tap != null && t.iface.tap.bridge != null
|
|
) allTapInterfaces;
|
|
bridgeEntries = map (brName: lib.nameValuePair brName { }) (
|
|
lib.unique (map (t: t.iface.tap.bridge) bridgedTaps)
|
|
);
|
|
in
|
|
lib.listToAttrs (tapEntries ++ bridgeEntries);
|
|
|
|
# Bridge configuration for TAP interfaces with tap.bridge set
|
|
networking.bridges =
|
|
let
|
|
bridgedTaps = builtins.filter (
|
|
t: t.iface.tap != null && t.iface.tap.bridge != null
|
|
) allTapInterfaces;
|
|
bridgeNames = lib.unique (map (t: t.iface.tap.bridge) bridgedTaps);
|
|
in
|
|
lib.listToAttrs (
|
|
map (
|
|
brName:
|
|
lib.nameValuePair brName {
|
|
interfaces = map (t: t.tapName) (builtins.filter (t: t.iface.tap.bridge == brName) bridgedTaps);
|
|
}
|
|
) bridgeNames
|
|
);
|
|
|
|
# nftables NAT and forward rules for VMs routing through the host (network.netvm = "host").
|
|
# Same rules as mkNetvmGuestConfig in netvm.nix, but applied on the host using TAP names.
|
|
networking.nftables =
|
|
let
|
|
hostNetvmTaps = builtins.filter (
|
|
t: t.vm.network.netvm == "host" && t.ifName == "upstream"
|
|
) allTapInterfaces;
|
|
in
|
|
lib.mkIf (hostNetvmTaps != [ ]) {
|
|
enable = true;
|
|
tables = {
|
|
vmsilo-netvm-nat = {
|
|
family = "ip";
|
|
content =
|
|
let
|
|
ifSet = "{ ${lib.concatMapStringsSep ", " (t: ''"${t.tapName}"'') hostNetvmTaps} }";
|
|
in
|
|
''
|
|
chain postrouting {
|
|
type nat hook postrouting priority srcnat;
|
|
iifname ${ifSet} oifname != "lo" masquerade
|
|
}
|
|
'';
|
|
};
|
|
vmsilo-netvm-filter = {
|
|
family = "inet";
|
|
content =
|
|
let
|
|
ifSet = "{ ${lib.concatMapStringsSep ", " (t: ''"${t.tapName}"'') hostNetvmTaps} }";
|
|
in
|
|
''
|
|
chain forward {
|
|
type filter hook forward priority filter;
|
|
policy accept;
|
|
ct state established,related accept
|
|
iifname ${ifSet} oifname ${ifSet} drop
|
|
}
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|