diff options
Diffstat (limited to 'nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix')
-rw-r--r-- | nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix b/nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix new file mode 100644 index 00000000000..7c6604922cf --- /dev/null +++ b/nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix @@ -0,0 +1,243 @@ +{ config, lib, utils, ... }: + +with utils; +with lib; + +let + + cfg = config.networking; + interfaces = attrValues cfg.interfaces; + + interfaceIps = i: + i.ipv4.addresses + ++ optionals cfg.enableIPv6 i.ipv6.addresses; + + dhcpStr = useDHCP: if useDHCP == true || useDHCP == null then "yes" else "no"; + + slaves = + concatLists (map (bond: bond.interfaces) (attrValues cfg.bonds)) + ++ concatLists (map (bridge: bridge.interfaces) (attrValues cfg.bridges)) + ++ map (sit: sit.dev) (attrValues cfg.sits) + ++ map (vlan: vlan.interface) (attrValues cfg.vlans); + +in + +{ + + config = mkIf cfg.useNetworkd { + + assertions = [ { + assertion = cfg.defaultGatewayWindowSize == null; + message = "networking.defaultGatewayWindowSize is not supported by networkd."; + } { + assertion = cfg.vswitches == {}; + message = "networking.vswichtes are not supported by networkd."; + } { + assertion = cfg.defaultGateway == null || cfg.defaultGateway.interface == null; + message = "networking.defaultGateway.interface is not supported by networkd."; + } { + assertion = cfg.defaultGateway6 == null || cfg.defaultGateway6.interface == null; + message = "networking.defaultGateway6.interface is not supported by networkd."; + } ] ++ flip mapAttrsToList cfg.bridges (n: { rstp, ... }: { + assertion = !rstp; + message = "networking.bridges.${n}.rstp is not supported by networkd."; + }); + + networking.dhcpcd.enable = mkDefault false; + + systemd.services.network-local-commands = { + after = [ "systemd-networkd.service" ]; + bindsTo = [ "systemd-networkd.service" ]; + }; + + systemd.network = + let + domains = cfg.search ++ (optional (cfg.domain != null) cfg.domain); + genericNetwork = override: + let gateway = optional (cfg.defaultGateway != null) cfg.defaultGateway.address + ++ optional (cfg.defaultGateway6 != null) cfg.defaultGateway6.address; + in { + DHCP = override (dhcpStr cfg.useDHCP); + } // optionalAttrs (gateway != [ ]) { + routes = override [ + { + routeConfig = { + Gateway = gateway; + GatewayOnLink = false; + }; + } + ]; + } // optionalAttrs (domains != [ ]) { + domains = override domains; + }; + in mkMerge [ { + enable = true; + networks."99-main" = (genericNetwork mkDefault) // { + # We keep the "broken" behaviour of applying this to all interfaces. + # In general we want to get rid of this workaround but there hasn't + # been any work on that. + # See the following issues for details: + # - https://github.com/NixOS/nixpkgs/issues/18962 + # - https://github.com/NixOS/nixpkgs/issues/61629 + matchConfig = mkDefault { Name = "*"; }; + }; + } + (mkMerge (forEach interfaces (i: { + netdevs = mkIf i.virtual ({ + "40-${i.name}" = { + netdevConfig = { + Name = i.name; + Kind = i.virtualType; + }; + "${i.virtualType}Config" = optionalAttrs (i.virtualOwner != null) { + User = i.virtualOwner; + }; + }; + }); + networks."40-${i.name}" = mkMerge [ (genericNetwork mkDefault) { + name = mkDefault i.name; + DHCP = mkForce (dhcpStr + (if i.useDHCP != null then i.useDHCP else cfg.useDHCP && interfaceIps i == [ ])); + address = forEach (interfaceIps i) + (ip: "${ip.address}/${toString ip.prefixLength}"); + networkConfig.IPv6PrivacyExtensions = "kernel"; + } ]; + }))) + (mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: { + netdevs."40-${name}" = { + netdevConfig = { + Name = name; + Kind = "bridge"; + }; + }; + networks = listToAttrs (forEach bridge.interfaces (bi: + nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { + DHCP = mkOverride 0 (dhcpStr false); + networkConfig.Bridge = name; + } ]))); + }))) + (mkMerge (flip mapAttrsToList cfg.bonds (name: bond: { + netdevs."40-${name}" = { + netdevConfig = { + Name = name; + Kind = "bond"; + }; + bondConfig = let + # manual mapping as of 2017-02-03 + # man 5 systemd.netdev [BOND] + # to https://www.kernel.org/doc/Documentation/networking/bonding.txt + # driver options. + driverOptionMapping = let + trans = f: optName: { valTransform = f; optNames = [optName]; }; + simp = trans id; + ms = trans (v: v + "ms"); + in { + Mode = simp "mode"; + TransmitHashPolicy = simp "xmit_hash_policy"; + LACPTransmitRate = simp "lacp_rate"; + MIIMonitorSec = ms "miimon"; + UpDelaySec = ms "updelay"; + DownDelaySec = ms "downdelay"; + LearnPacketIntervalSec = simp "lp_interval"; + AdSelect = simp "ad_select"; + FailOverMACPolicy = simp "fail_over_mac"; + ARPValidate = simp "arp_validate"; + # apparently in ms for this value?! Upstream bug? + ARPIntervalSec = simp "arp_interval"; + ARPIPTargets = simp "arp_ip_target"; + ARPAllTargets = simp "arp_all_targets"; + PrimaryReselectPolicy = simp "primary_reselect"; + ResendIGMP = simp "resend_igmp"; + PacketsPerSlave = simp "packets_per_slave"; + GratuitousARP = { valTransform = id; + optNames = [ "num_grat_arp" "num_unsol_na" ]; }; + AllSlavesActive = simp "all_slaves_active"; + MinLinks = simp "min_links"; + }; + + do = bond.driverOptions; + assertNoUnknownOption = let + knownOptions = flatten (mapAttrsToList (_: kOpts: kOpts.optNames) + driverOptionMapping); + # options that apparently donβt exist in the networkd config + unknownOptions = [ "primary" ]; + assertTrace = bool: msg: if bool then true else builtins.trace msg false; + in assert all (driverOpt: assertTrace + (elem driverOpt (knownOptions ++ unknownOptions)) + "The bond.driverOption `${driverOpt}` cannot be mapped to the list of known networkd bond options. Please add it to the mapping above the assert or to `unknownOptions` should it not exist in networkd.") + (mapAttrsToList (k: _: k) do); ""; + # get those driverOptions that have been set + filterSystemdOptions = filterAttrs (sysDOpt: kOpts: + any (kOpt: do ? ${kOpt}) kOpts.optNames); + # build final set of systemd options to bond values + buildOptionSet = mapAttrs (_: kOpts: with kOpts; + # we simply take the first set kernel bond option + # (one option has multiple names, which is silly) + head (map (optN: valTransform (do.${optN})) + # only map those that exist + (filter (o: do ? ${o}) optNames))); + in seq assertNoUnknownOption + (buildOptionSet (filterSystemdOptions driverOptionMapping)); + + }; + + networks = listToAttrs (forEach bond.interfaces (bi: + nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { + DHCP = mkOverride 0 (dhcpStr false); + networkConfig.Bond = name; + } ]))); + }))) + (mkMerge (flip mapAttrsToList cfg.macvlans (name: macvlan: { + netdevs."40-${name}" = { + netdevConfig = { + Name = name; + Kind = "macvlan"; + }; + macvlanConfig = optionalAttrs (macvlan.mode != null) { Mode = macvlan.mode; }; + }; + networks."40-${macvlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) { + macvlan = [ name ]; + } ]); + }))) + (mkMerge (flip mapAttrsToList cfg.sits (name: sit: { + netdevs."40-${name}" = { + netdevConfig = { + Name = name; + Kind = "sit"; + }; + tunnelConfig = + (optionalAttrs (sit.remote != null) { + Remote = sit.remote; + }) // (optionalAttrs (sit.local != null) { + Local = sit.local; + }) // (optionalAttrs (sit.ttl != null) { + TTL = sit.ttl; + }); + }; + networks = mkIf (sit.dev != null) { + "40-${sit.dev}" = (mkMerge [ (genericNetwork (mkOverride 999)) { + tunnel = [ name ]; + } ]); + }; + }))) + (mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: { + netdevs."40-${name}" = { + netdevConfig = { + Name = name; + Kind = "vlan"; + }; + vlanConfig.Id = vlan.id; + }; + networks."40-${vlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) { + vlan = [ name ]; + } ]); + }))) + ]; + + # We need to prefill the slaved devices with networking options + # This forces the network interface creator to initialize slaves. + networking.interfaces = listToAttrs (map (i: nameValuePair i { }) slaves); + + }; + +} |