diff options
Diffstat (limited to 'modules/networkd.nix')
| -rw-r--r-- | modules/networkd.nix | 297 |
1 files changed, 0 insertions, 297 deletions
diff --git a/modules/networkd.nix b/modules/networkd.nix deleted file mode 100644 index d0a48f98..00000000 --- a/modules/networkd.nix +++ /dev/null | |||
| @@ -1,297 +0,0 @@ | |||
| 1 | { config, lib, utils, pkgs, ... }: | ||
| 2 | |||
| 3 | with utils; | ||
| 4 | with lib; | ||
| 5 | |||
| 6 | let | ||
| 7 | |||
| 8 | cfg = config.networking; | ||
| 9 | interfaces = attrValues cfg.interfaces; | ||
| 10 | |||
| 11 | interfaceIps = i: | ||
| 12 | i.ipv4.addresses | ||
| 13 | ++ optionals cfg.enableIPv6 i.ipv6.addresses; | ||
| 14 | |||
| 15 | dhcpStr = useDHCP: if useDHCP == true || useDHCP == null then "yes" else "no"; | ||
| 16 | |||
| 17 | slaves = | ||
| 18 | concatLists (map (bond: bond.interfaces) (attrValues cfg.bonds)) | ||
| 19 | ++ concatLists (map (bridge: bridge.interfaces) (attrValues cfg.bridges)) | ||
| 20 | ++ map (sit: sit.dev) (attrValues cfg.sits) | ||
| 21 | ++ map (vlan: vlan.interface) (attrValues cfg.vlans) | ||
| 22 | # add dependency to physical or independently created vswitch member interface | ||
| 23 | # TODO: warn the user that any address configured on those interfaces will be useless | ||
| 24 | ++ concatMap (i: attrNames (filterAttrs (_: config: config.type != "internal") i.interfaces)) (attrValues cfg.vswitches); | ||
| 25 | |||
| 26 | in | ||
| 27 | |||
| 28 | { | ||
| 29 | disabledModules = [ "tasks/network-interfaces-systemd.nix" ]; | ||
| 30 | |||
| 31 | config = mkIf cfg.useNetworkd { | ||
| 32 | |||
| 33 | assertions = [ { | ||
| 34 | assertion = cfg.defaultGatewayWindowSize == null; | ||
| 35 | message = "networking.defaultGatewayWindowSize is not supported by networkd."; | ||
| 36 | } { | ||
| 37 | assertion = cfg.vswitches == {}; | ||
| 38 | message = "networking.vswitches are not supported by networkd."; | ||
| 39 | } { | ||
| 40 | assertion = cfg.defaultGateway == null || cfg.defaultGateway.interface == null; | ||
| 41 | message = "networking.defaultGateway.interface is not supported by networkd."; | ||
| 42 | } { | ||
| 43 | assertion = cfg.defaultGateway6 == null || cfg.defaultGateway6.interface == null; | ||
| 44 | message = "networking.defaultGateway6.interface is not supported by networkd."; | ||
| 45 | } { | ||
| 46 | assertion = cfg.useDHCP == false; | ||
| 47 | message = '' | ||
| 48 | networking.useDHCP is not supported by networkd. | ||
| 49 | Please use per interface configuration and set the global option to false. | ||
| 50 | ''; | ||
| 51 | } ] ++ flip mapAttrsToList cfg.bridges (n: { rstp, ... }: { | ||
| 52 | assertion = !rstp; | ||
| 53 | message = "networking.bridges.${n}.rstp is not supported by networkd."; | ||
| 54 | }); | ||
| 55 | |||
| 56 | networking.dhcpcd.enable = mkDefault false; | ||
| 57 | |||
| 58 | systemd.network = | ||
| 59 | let | ||
| 60 | domains = cfg.search ++ (optional (cfg.domain != null) cfg.domain); | ||
| 61 | genericNetwork = override: | ||
| 62 | let gateways = optional (cfg.defaultGateway != null && (cfg.defaultGateway.address or "") != "") cfg.defaultGateway.address | ||
| 63 | ++ optional (cfg.defaultGateway6 != null && (cfg.defaultGateway6.address or "") != "") cfg.defaultGateway6.address; | ||
| 64 | in optionalAttrs (gateways != [ ]) { | ||
| 65 | routes = override (map (gateway: { | ||
| 66 | routeConfig = { | ||
| 67 | Gateway = gateway; | ||
| 68 | GatewayOnLink = false; | ||
| 69 | }; | ||
| 70 | }) gateways); | ||
| 71 | } // optionalAttrs (domains != [ ]) { | ||
| 72 | domains = override domains; | ||
| 73 | }; | ||
| 74 | in mkMerge [ { | ||
| 75 | enable = true; | ||
| 76 | } | ||
| 77 | (mkMerge (forEach interfaces (i: { | ||
| 78 | netdevs = mkIf i.virtual ({ | ||
| 79 | "40-${i.name}" = { | ||
| 80 | netdevConfig = { | ||
| 81 | Name = i.name; | ||
| 82 | Kind = i.virtualType; | ||
| 83 | }; | ||
| 84 | "${i.virtualType}Config" = optionalAttrs (i.virtualOwner != null) { | ||
| 85 | User = i.virtualOwner; | ||
| 86 | }; | ||
| 87 | }; | ||
| 88 | }); | ||
| 89 | networks."40-${i.name}" = mkMerge [ (genericNetwork mkDefault) { | ||
| 90 | name = mkDefault i.name; | ||
| 91 | DHCP = mkForce (dhcpStr | ||
| 92 | (if i.useDHCP != null then i.useDHCP else false)); | ||
| 93 | address = forEach (interfaceIps i) | ||
| 94 | (ip: "${ip.address}/${toString ip.prefixLength}"); | ||
| 95 | networkConfig.IPv6PrivacyExtensions = "kernel"; | ||
| 96 | linkConfig = optionalAttrs (i.macAddress != null) { | ||
| 97 | MACAddress = i.macAddress; | ||
| 98 | } // optionalAttrs (i.mtu != null) { | ||
| 99 | MTUBytes = toString i.mtu; | ||
| 100 | }; | ||
| 101 | }]; | ||
| 102 | }))) | ||
| 103 | (mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: { | ||
| 104 | netdevs."40-${name}" = { | ||
| 105 | netdevConfig = { | ||
| 106 | Name = name; | ||
| 107 | Kind = "bridge"; | ||
| 108 | }; | ||
| 109 | }; | ||
| 110 | networks = listToAttrs (forEach bridge.interfaces (bi: | ||
| 111 | nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { | ||
| 112 | DHCP = mkOverride 0 (dhcpStr false); | ||
| 113 | networkConfig.Bridge = name; | ||
| 114 | } ]))); | ||
| 115 | }))) | ||
| 116 | (mkMerge (flip mapAttrsToList cfg.bonds (name: bond: { | ||
| 117 | netdevs."40-${name}" = { | ||
| 118 | netdevConfig = { | ||
| 119 | Name = name; | ||
| 120 | Kind = "bond"; | ||
| 121 | }; | ||
| 122 | bondConfig = let | ||
| 123 | # manual mapping as of 2017-02-03 | ||
| 124 | # man 5 systemd.netdev [BOND] | ||
| 125 | # to https://www.kernel.org/doc/Documentation/networking/bonding.txt | ||
| 126 | # driver options. | ||
| 127 | driverOptionMapping = let | ||
| 128 | trans = f: optName: { valTransform = f; optNames = [optName]; }; | ||
| 129 | simp = trans id; | ||
| 130 | ms = trans (v: v + "ms"); | ||
| 131 | in { | ||
| 132 | Mode = simp "mode"; | ||
| 133 | TransmitHashPolicy = simp "xmit_hash_policy"; | ||
| 134 | LACPTransmitRate = simp "lacp_rate"; | ||
| 135 | MIIMonitorSec = ms "miimon"; | ||
| 136 | UpDelaySec = ms "updelay"; | ||
| 137 | DownDelaySec = ms "downdelay"; | ||
| 138 | LearnPacketIntervalSec = simp "lp_interval"; | ||
| 139 | AdSelect = simp "ad_select"; | ||
| 140 | FailOverMACPolicy = simp "fail_over_mac"; | ||
| 141 | ARPValidate = simp "arp_validate"; | ||
| 142 | # apparently in ms for this value?! Upstream bug? | ||
| 143 | ARPIntervalSec = simp "arp_interval"; | ||
| 144 | ARPIPTargets = simp "arp_ip_target"; | ||
| 145 | ARPAllTargets = simp "arp_all_targets"; | ||
| 146 | PrimaryReselectPolicy = simp "primary_reselect"; | ||
| 147 | ResendIGMP = simp "resend_igmp"; | ||
| 148 | PacketsPerSlave = simp "packets_per_slave"; | ||
| 149 | GratuitousARP = { valTransform = id; | ||
| 150 | optNames = [ "num_grat_arp" "num_unsol_na" ]; }; | ||
| 151 | AllSlavesActive = simp "all_slaves_active"; | ||
| 152 | MinLinks = simp "min_links"; | ||
| 153 | }; | ||
| 154 | |||
| 155 | do = bond.driverOptions; | ||
| 156 | assertNoUnknownOption = let | ||
| 157 | knownOptions = flatten (mapAttrsToList (_: kOpts: kOpts.optNames) | ||
| 158 | driverOptionMapping); | ||
| 159 | # options that apparently don’t exist in the networkd config | ||
| 160 | unknownOptions = [ "primary" ]; | ||
| 161 | assertTrace = bool: msg: if bool then true else builtins.trace msg false; | ||
| 162 | in assert all (driverOpt: assertTrace | ||
| 163 | (elem driverOpt (knownOptions ++ unknownOptions)) | ||
| 164 | "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.") | ||
| 165 | (mapAttrsToList (k: _: k) do); ""; | ||
| 166 | # get those driverOptions that have been set | ||
| 167 | filterSystemdOptions = filterAttrs (sysDOpt: kOpts: | ||
| 168 | any (kOpt: do ? ${kOpt}) kOpts.optNames); | ||
| 169 | # build final set of systemd options to bond values | ||
| 170 | buildOptionSet = mapAttrs (_: kOpts: with kOpts; | ||
| 171 | # we simply take the first set kernel bond option | ||
| 172 | # (one option has multiple names, which is silly) | ||
| 173 | head (map (optN: valTransform (do.${optN})) | ||
| 174 | # only map those that exist | ||
| 175 | (filter (o: do ? ${o}) optNames))); | ||
| 176 | in seq assertNoUnknownOption | ||
| 177 | (buildOptionSet (filterSystemdOptions driverOptionMapping)); | ||
| 178 | |||
| 179 | }; | ||
| 180 | |||
| 181 | networks = listToAttrs (forEach bond.interfaces (bi: | ||
| 182 | nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { | ||
| 183 | DHCP = mkOverride 0 (dhcpStr false); | ||
| 184 | networkConfig.Bond = name; | ||
| 185 | } ]))); | ||
| 186 | }))) | ||
| 187 | (mkMerge (flip mapAttrsToList cfg.macvlans (name: macvlan: { | ||
| 188 | netdevs."40-${name}" = { | ||
| 189 | netdevConfig = { | ||
| 190 | Name = name; | ||
| 191 | Kind = "macvlan"; | ||
| 192 | }; | ||
| 193 | macvlanConfig = optionalAttrs (macvlan.mode != null) { Mode = macvlan.mode; }; | ||
| 194 | }; | ||
| 195 | networks."40-${macvlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) { | ||
| 196 | macvlan = [ name ]; | ||
| 197 | } ]); | ||
| 198 | }))) | ||
| 199 | (mkMerge (flip mapAttrsToList cfg.sits (name: sit: { | ||
| 200 | netdevs."40-${name}" = { | ||
| 201 | netdevConfig = { | ||
| 202 | Name = name; | ||
| 203 | Kind = "sit"; | ||
| 204 | }; | ||
| 205 | tunnelConfig = | ||
| 206 | (optionalAttrs (sit.remote != null) { | ||
| 207 | Remote = sit.remote; | ||
| 208 | }) // (optionalAttrs (sit.local != null) { | ||
| 209 | Local = sit.local; | ||
| 210 | }) // (optionalAttrs (sit.ttl != null) { | ||
| 211 | TTL = sit.ttl; | ||
| 212 | }); | ||
| 213 | }; | ||
| 214 | networks = mkIf (sit.dev != null) { | ||
| 215 | "40-${sit.dev}" = (mkMerge [ (genericNetwork (mkOverride 999)) { | ||
| 216 | tunnel = [ name ]; | ||
| 217 | } ]); | ||
| 218 | }; | ||
| 219 | }))) | ||
| 220 | (mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: { | ||
| 221 | netdevs."40-${name}" = { | ||
| 222 | netdevConfig = { | ||
| 223 | Name = name; | ||
| 224 | Kind = "vlan"; | ||
| 225 | }; | ||
| 226 | vlanConfig.Id = vlan.id; | ||
| 227 | }; | ||
| 228 | networks."40-${vlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) { | ||
| 229 | vlan = [ name ]; | ||
| 230 | } ]); | ||
| 231 | }))) | ||
| 232 | ]; | ||
| 233 | |||
| 234 | # We need to prefill the slaved devices with networking options | ||
| 235 | # This forces the network interface creator to initialize slaves. | ||
| 236 | networking.interfaces = listToAttrs (map (i: nameValuePair i { }) slaves); | ||
| 237 | |||
| 238 | systemd.services = let | ||
| 239 | # We must escape interfaces due to the systemd interpretation | ||
| 240 | subsystemDevice = interface: | ||
| 241 | "sys-subsystem-net-devices-${escapeSystemdPath interface}.device"; | ||
| 242 | # support for creating openvswitch switches | ||
| 243 | createVswitchDevice = n: v: nameValuePair "${n}-netdev" | ||
| 244 | (let | ||
| 245 | deps = map subsystemDevice (attrNames (filterAttrs (_: config: config.type != "internal") v.interfaces)); | ||
| 246 | ofRules = pkgs.writeText "vswitch-${n}-openFlowRules" v.openFlowRules; | ||
| 247 | in | ||
| 248 | { description = "Open vSwitch Interface ${n}"; | ||
| 249 | wantedBy = [ "network.target" (subsystemDevice n) ]; | ||
| 250 | # and create bridge before systemd-networkd starts because it might create internal interfaces | ||
| 251 | before = [ "systemd-networkd.service" ]; | ||
| 252 | # shutdown the bridge when network is shutdown | ||
| 253 | partOf = [ "network.target" ]; | ||
| 254 | # requires ovs-vswitchd to be alive at all times | ||
| 255 | bindsTo = [ "ovs-vswitchd.service" ]; | ||
| 256 | # start switch after physical interfaces and vswitch daemon | ||
| 257 | after = [ "network-pre.target" "ovs-vswitchd.service" ] ++ deps; | ||
| 258 | wants = deps; # if one or more interface fails, the switch should continue to run | ||
| 259 | serviceConfig.Type = "oneshot"; | ||
| 260 | serviceConfig.RemainAfterExit = true; | ||
| 261 | path = [ pkgs.iproute2 config.virtualisation.vswitch.package ]; | ||
| 262 | preStart = '' | ||
| 263 | echo "Resetting Open vSwitch ${n}..." | ||
| 264 | ovs-vsctl --if-exists del-br ${n} -- add-br ${n} \ | ||
| 265 | -- set bridge ${n} protocols=${concatStringsSep "," v.supportedOpenFlowVersions} | ||
| 266 | ''; | ||
| 267 | script = '' | ||
| 268 | echo "Configuring Open vSwitch ${n}..." | ||
| 269 | ovs-vsctl ${concatStrings (mapAttrsToList (name: config: " -- add-port ${n} ${name}" + optionalString (config.vlan != null) " tag=${toString config.vlan}") v.interfaces)} \ | ||
| 270 | ${concatStrings (mapAttrsToList (name: config: optionalString (config.type != null) " -- set interface ${name} type=${config.type}") v.interfaces)} \ | ||
| 271 | ${concatMapStrings (x: " -- set-controller ${n} " + x) v.controllers} \ | ||
| 272 | ${concatMapStrings (x: " -- " + x) (splitString "\n" v.extraOvsctlCmds)} | ||
| 273 | |||
| 274 | |||
| 275 | echo "Adding OpenFlow rules for Open vSwitch ${n}..." | ||
| 276 | ovs-ofctl --protocols=${v.openFlowVersion} add-flows ${n} ${ofRules} | ||
| 277 | ''; | ||
| 278 | postStop = '' | ||
| 279 | echo "Cleaning Open vSwitch ${n}" | ||
| 280 | echo "Shuting down internal ${n} interface" | ||
| 281 | ip link set ${n} down || true | ||
| 282 | echo "Deleting flows for ${n}" | ||
| 283 | ovs-ofctl --protocols=${v.openFlowVersion} del-flows ${n} || true | ||
| 284 | echo "Deleting Open vSwitch ${n}" | ||
| 285 | ovs-vsctl --if-exists del-br ${n} || true | ||
| 286 | ''; | ||
| 287 | }); | ||
| 288 | in mapAttrs' createVswitchDevice cfg.vswitches | ||
| 289 | // { | ||
| 290 | "network-local-commands" = { | ||
| 291 | after = [ "systemd-networkd.service" ]; | ||
| 292 | bindsTo = [ "systemd-networkd.service" ]; | ||
| 293 | }; | ||
| 294 | }; | ||
| 295 | }; | ||
| 296 | |||
| 297 | } | ||
