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