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 } ] ++ flip mapAttrsToList cfg.bridges (n: { rstp, ... }: {
42 assertion = !rstp;
43 message = "networking.bridges.${n}.rstp is not supported by networkd.";
44 });
45
46 systemd.services.dhcpcd.enable = mkDefault false;
47
48 systemd.services.network-local-commands = {
49 after = [ "systemd-networkd.service" ];
50 bindsTo = [ "systemd-networkd.service" ];
51 };
52
53 systemd.network =
54 let
55 domains = cfg.search ++ (optional (cfg.domain != null) cfg.domain);
56 genericNetwork = override: {
57 DHCP = override (dhcpStr cfg.useDHCP);
58 } // optionalAttrs (cfg.defaultGateway != null) {
59 gateway = override [ cfg.defaultGateway ];
60 } // optionalAttrs (cfg.defaultGateway6 != null) {
61 gateway = override [ cfg.defaultGateway6 ];
62 } // optionalAttrs (domains != [ ]) {
63 domains = override domains;
64 };
65 in mkMerge [ {
66 enable = true;
67 networks."99-main" = genericNetwork mkDefault;
68 }
69 (mkMerge (flip map interfaces (i: {
70 netdevs = mkIf i.virtual (
71 let
72 devType = if i.virtualType != null then i.virtualType
73 else (if hasPrefix "tun" i.name then "tun" else "tap");
74 in {
75 "40-${i.name}" = {
76 netdevConfig = {
77 Name = i.name;
78 Kind = devType;
79 };
80 "${devType}Config" = optionalAttrs (i.virtualOwner != null) {
81 User = i.virtualOwner;
82 };
83 };
84 });
85 networks."40-${i.name}" = mkMerge [ (genericNetwork mkDefault) {
86 name = mkDefault i.name;
87 DHCP = mkForce (dhcpStr
88 (if i.useDHCP != null then i.useDHCP else cfg.useDHCP && interfaceIps i == [ ]));
89 address = flip map (interfaceIps i)
90 (ip: "${ip.address}/${toString ip.prefixLength}");
91 } ];
92 })))
93 (mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: {
94 netdevs."40-${name}" = {
95 netdevConfig = {
96 Name = name;
97 Kind = "bridge";
98 };
99 };
100 networks = listToAttrs (flip map bridge.interfaces (bi:
101 nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) {
102 DHCP = mkOverride 0 (dhcpStr false);
103 networkConfig.Bridge = name;
104 } ])));
105 })))
106 (mkMerge (flip mapAttrsToList cfg.bonds (name: bond: {
107 netdevs."40-${name}" = {
108 netdevConfig = {
109 Name = name;
110 Kind = "bond";
111 };
112 bondConfig =
113 (optionalAttrs (bond.lacp_rate != null) {
114 LACPTransmitRate = bond.lacp_rate;
115 }) // (optionalAttrs (bond.miimon != null) {
116 MIIMonitorSec = bond.miimon;
117 }) // (optionalAttrs (bond.mode != null) {
118 Mode = bond.mode;
119 }) // (optionalAttrs (bond.xmit_hash_policy != null) {
120 TransmitHashPolicy = bond.xmit_hash_policy;
121 });
122 };
123 networks = listToAttrs (flip map bond.interfaces (bi:
124 nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) {
125 DHCP = mkOverride 0 (dhcpStr false);
126 networkConfig.Bond = name;
127 } ])));
128 })))
129 (mkMerge (flip mapAttrsToList cfg.macvlans (name: macvlan: {
130 netdevs."40-${name}" = {
131 netdevConfig = {
132 Name = name;
133 Kind = "macvlan";
134 };
135 macvlanConfig = optionalAttrs (macvlan.mode != null) { Mode = macvlan.mode; };
136 };
137 networks."40-${macvlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) {
138 macvlan = [ name ];
139 } ]);
140 })))
141 (mkMerge (flip mapAttrsToList cfg.sits (name: sit: {
142 netdevs."40-${name}" = {
143 netdevConfig = {
144 Name = name;
145 Kind = "sit";
146 };
147 tunnelConfig =
148 (optionalAttrs (sit.remote != null) {
149 Remote = sit.remote;
150 }) // (optionalAttrs (sit.local != null) {
151 Local = sit.local;
152 }) // (optionalAttrs (sit.ttl != null) {
153 TTL = sit.ttl;
154 });
155 };
156 networks = mkIf (sit.dev != null) {
157 "40-${sit.dev}" = (mkMerge [ (genericNetwork (mkOverride 999)) {
158 tunnel = [ name ];
159 } ]);
160 };
161 })))
162 (mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: {
163 netdevs."40-${name}" = {
164 netdevConfig = {
165 Name = name;
166 Kind = "vlan";
167 };
168 vlanConfig.Id = vlan.id;
169 };
170 networks."40-${vlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) {
171 vlan = [ name ];
172 } ]);
173 })))
174 ];
175
176 # We need to prefill the slaved devices with networking options
177 # This forces the network interface creator to initialize slaves.
178 networking.interfaces = listToAttrs (map (i: nameValuePair i { }) slaves);
179
180 };
181
182}