at 17.09-beta 9.6 kB view raw
1{ config, lib, pkgs, utils, ... }: 2 3with utils; 4with lib; 5 6let 7 8 cfg = config.networking; 9 interfaces = attrValues cfg.interfaces; 10 11 interfaceIps = i: 12 i.ip4 ++ optionals cfg.enableIPv6 i.ip6 13 ++ optional (i.ipAddress != null) { 14 address = i.ipAddress; 15 prefixLength = i.prefixLength; 16 } ++ optional (cfg.enableIPv6 && i.ipv6Address != null) { 17 address = i.ipv6Address; 18 prefixLength = i.ipv6PrefixLength; 19 }; 20 21 dhcpStr = useDHCP: if useDHCP == true || useDHCP == null then "both" else "none"; 22 23 slaves = 24 concatLists (map (bond: bond.interfaces) (attrValues cfg.bonds)) 25 ++ concatLists (map (bridge: bridge.interfaces) (attrValues cfg.bridges)) 26 ++ map (sit: sit.dev) (attrValues cfg.sits) 27 ++ map (vlan: vlan.interface) (attrValues cfg.vlans); 28 29in 30 31{ 32 33 config = mkIf cfg.useNetworkd { 34 35 assertions = [ { 36 assertion = cfg.defaultGatewayWindowSize == null; 37 message = "networking.defaultGatewayWindowSize is not supported by networkd."; 38 } { 39 assertion = cfg.vswitches == {}; 40 message = "networking.vswichtes are not supported by networkd."; 41 } { 42 assertion = cfg.defaultGateway == null || cfg.defaultGateway.interface == null; 43 message = "networking.defaultGateway.interface is not supported by networkd."; 44 } { 45 assertion = cfg.defaultGateway6 == null || cfg.defaultGateway6.interface == null; 46 message = "networking.defaultGateway6.interface is not supported by networkd."; 47 } ] ++ flip mapAttrsToList cfg.bridges (n: { rstp, ... }: { 48 assertion = !rstp; 49 message = "networking.bridges.${n}.rstp is not supported by networkd."; 50 }); 51 52 networking.dhcpcd.enable = mkDefault false; 53 54 systemd.services.network-local-commands = { 55 after = [ "systemd-networkd.service" ]; 56 bindsTo = [ "systemd-networkd.service" ]; 57 }; 58 59 systemd.network = 60 let 61 domains = cfg.search ++ (optional (cfg.domain != null) cfg.domain); 62 genericNetwork = override: 63 let gateway = optional (cfg.defaultGateway != null) cfg.defaultGateway.address 64 ++ optional (cfg.defaultGateway6 != null) cfg.defaultGateway6.address; 65 in { 66 DHCP = override (dhcpStr cfg.useDHCP); 67 } // optionalAttrs (gateway != [ ]) { 68 gateway = override gateway; 69 } // optionalAttrs (domains != [ ]) { 70 domains = override domains; 71 }; 72 in mkMerge [ { 73 enable = true; 74 networks."99-main" = genericNetwork mkDefault; 75 } 76 (mkMerge (flip map interfaces (i: { 77 netdevs = mkIf i.virtual ( 78 let 79 devType = if i.virtualType != null then i.virtualType 80 else (if hasPrefix "tun" i.name then "tun" else "tap"); 81 in { 82 "40-${i.name}" = { 83 netdevConfig = { 84 Name = i.name; 85 Kind = devType; 86 }; 87 "${devType}Config" = optionalAttrs (i.virtualOwner != null) { 88 User = i.virtualOwner; 89 }; 90 }; 91 }); 92 networks."40-${i.name}" = mkMerge [ (genericNetwork mkDefault) { 93 name = mkDefault i.name; 94 DHCP = mkForce (dhcpStr 95 (if i.useDHCP != null then i.useDHCP else cfg.useDHCP && interfaceIps i == [ ])); 96 address = flip map (interfaceIps i) 97 (ip: "${ip.address}/${toString ip.prefixLength}"); 98 } ]; 99 }))) 100 (mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: { 101 netdevs."40-${name}" = { 102 netdevConfig = { 103 Name = name; 104 Kind = "bridge"; 105 }; 106 }; 107 networks = listToAttrs (flip map bridge.interfaces (bi: 108 nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { 109 DHCP = mkOverride 0 (dhcpStr false); 110 networkConfig.Bridge = name; 111 } ]))); 112 }))) 113 (mkMerge (flip mapAttrsToList cfg.bonds (name: bond: { 114 netdevs."40-${name}" = { 115 netdevConfig = { 116 Name = name; 117 Kind = "bond"; 118 }; 119 bondConfig = let 120 # manual mapping as of 2017-02-03 121 # man 5 systemd.netdev [BOND] 122 # to https://www.kernel.org/doc/Documentation/networking/bonding.txt 123 # driver options. 124 driverOptionMapping = let 125 trans = f: optName: { valTransform = f; optNames = [optName]; }; 126 simp = trans id; 127 ms = trans (v: v + "ms"); 128 in { 129 Mode = simp "mode"; 130 TransmitHashPolicy = simp "xmit_hash_policy"; 131 LACPTransmitRate = simp "lacp_rate"; 132 MIIMonitorSec = ms "miimon"; 133 UpDelaySec = ms "updelay"; 134 DownDelaySec = ms "downdelay"; 135 LearnPacketIntervalSec = simp "lp_interval"; 136 AdSelect = simp "ad_select"; 137 FailOverMACPolicy = simp "fail_over_mac"; 138 ARPValidate = simp "arp_validate"; 139 # apparently in ms for this value?! Upstream bug? 140 ARPIntervalSec = simp "arp_interval"; 141 ARPIPTargets = simp "arp_ip_target"; 142 ARPAllTargets = simp "arp_all_targets"; 143 PrimaryReselectPolicy = simp "primary_reselect"; 144 ResendIGMP = simp "resend_igmp"; 145 PacketsPerSlave = simp "packets_per_slave"; 146 GratuitousARP = { valTransform = id; 147 optNames = [ "num_grat_arp" "num_unsol_na" ]; }; 148 AllSlavesActive = simp "all_slaves_active"; 149 MinLinks = simp "min_links"; 150 }; 151 152 do = bond.driverOptions; 153 assertNoUnknownOption = let 154 knownOptions = flatten (mapAttrsToList (_: kOpts: kOpts.optNames) 155 driverOptionMapping); 156 # options that apparently don’t exist in the networkd config 157 unknownOptions = [ "primary" ]; 158 assertTrace = bool: msg: if bool then true else builtins.trace msg false; 159 in assert all (driverOpt: assertTrace 160 (elem driverOpt (knownOptions ++ unknownOptions)) 161 "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.") 162 (mapAttrsToList (k: _: k) do); ""; 163 # get those driverOptions that have been set 164 filterSystemdOptions = filterAttrs (sysDOpt: kOpts: 165 any (kOpt: do ? "${kOpt}") kOpts.optNames); 166 # build final set of systemd options to bond values 167 buildOptionSet = mapAttrs (_: kOpts: with kOpts; 168 # we simply take the first set kernel bond option 169 # (one option has multiple names, which is silly) 170 head (map (optN: valTransform (do."${optN}")) 171 # only map those that exist 172 (filter (o: do ? "${o}") optNames))); 173 in seq assertNoUnknownOption 174 (buildOptionSet (filterSystemdOptions driverOptionMapping)); 175 176 }; 177 178 networks = listToAttrs (flip map bond.interfaces (bi: 179 nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { 180 DHCP = mkOverride 0 (dhcpStr false); 181 networkConfig.Bond = name; 182 } ]))); 183 }))) 184 (mkMerge (flip mapAttrsToList cfg.macvlans (name: macvlan: { 185 netdevs."40-${name}" = { 186 netdevConfig = { 187 Name = name; 188 Kind = "macvlan"; 189 }; 190 macvlanConfig = optionalAttrs (macvlan.mode != null) { Mode = macvlan.mode; }; 191 }; 192 networks."40-${macvlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) { 193 macvlan = [ name ]; 194 } ]); 195 }))) 196 (mkMerge (flip mapAttrsToList cfg.sits (name: sit: { 197 netdevs."40-${name}" = { 198 netdevConfig = { 199 Name = name; 200 Kind = "sit"; 201 }; 202 tunnelConfig = 203 (optionalAttrs (sit.remote != null) { 204 Remote = sit.remote; 205 }) // (optionalAttrs (sit.local != null) { 206 Local = sit.local; 207 }) // (optionalAttrs (sit.ttl != null) { 208 TTL = sit.ttl; 209 }); 210 }; 211 networks = mkIf (sit.dev != null) { 212 "40-${sit.dev}" = (mkMerge [ (genericNetwork (mkOverride 999)) { 213 tunnel = [ name ]; 214 } ]); 215 }; 216 }))) 217 (mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: { 218 netdevs."40-${name}" = { 219 netdevConfig = { 220 Name = name; 221 Kind = "vlan"; 222 }; 223 vlanConfig.Id = vlan.id; 224 }; 225 networks."40-${vlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) { 226 vlan = [ name ]; 227 } ]); 228 }))) 229 ]; 230 231 # We need to prefill the slaved devices with networking options 232 # This forces the network interface creator to initialize slaves. 233 networking.interfaces = listToAttrs (map (i: nameValuePair i { }) slaves); 234 235 }; 236 237}