diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index be70bdbf0a91..f96dde153610 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -79,7 +79,7 @@ let checkBond = checkUnitConfig "Bond" [ (assertOnlyFields [ "Mode" "TransmitHashPolicy" "LACPTransmitRate" "MIIMonitorSec" - "UpDelaySec" "DownDelaySec" + "UpDelaySec" "DownDelaySec" "GratuitousARP" ]) (assertValueOneOf "Mode" [ "balance-rr" "active-backup" "balance-xor" diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix index cd599d8b8941..736292400fd4 100644 --- a/nixos/modules/tasks/network-interfaces-systemd.nix +++ b/nixos/modules/tasks/network-interfaces-systemd.nix @@ -115,17 +115,65 @@ in Name = name; Kind = "bond"; }; - bondConfig = - (optionalAttrs (bond.lacp_rate != null) { - LACPTransmitRate = bond.lacp_rate; - }) // (optionalAttrs (bond.miimon != null) { - MIIMonitorSec = bond.miimon; - }) // (optionalAttrs (bond.mode != null) { - Mode = bond.mode; - }) // (optionalAttrs (bond.xmit_hash_policy != null) { - TransmitHashPolicy = bond.xmit_hash_policy; - }); + 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"; + TransmitHashPolixy = 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 (flip map bond.interfaces (bi: nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { DHCP = mkOverride 0 (dhcpStr false);