1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.boot.initrd.network;
8
9 dhcpInterfaces = lib.attrNames (lib.filterAttrs (iface: v: v.useDHCP == true) (config.networking.interfaces or {}));
10 doDhcp = cfg.udhcpc.enable || dhcpInterfaces != [];
11 dhcpIfShellExpr = if config.networking.useDHCP || cfg.udhcpc.enable
12 then "$(ls /sys/class/net/ | grep -v ^lo$)"
13 else lib.concatMapStringsSep " " lib.escapeShellArg dhcpInterfaces;
14
15 udhcpcScript = pkgs.writeScript "udhcp-script"
16 ''
17 #! /bin/sh
18 if [ "$1" = bound ]; then
19 ip address add "$ip/$mask" dev "$interface"
20 if [ -n "$mtu" ]; then
21 ip link set mtu "$mtu" dev "$interface"
22 fi
23 if [ -n "$staticroutes" ]; then
24 echo "$staticroutes" \
25 | sed -r "s@(\S+) (\S+)@ ip route add \"\1\" via \"\2\" dev \"$interface\" ; @g" \
26 | sed -r "s@ via \"0\.0\.0\.0\"@@g" \
27 | /bin/sh
28 fi
29 if [ -n "$router" ]; then
30 ip route add "$router" dev "$interface" # just in case if "$router" is not within "$ip/$mask" (e.g. Hetzner Cloud)
31 ip route add default via "$router" dev "$interface"
32 fi
33 if [ -n "$dns" ]; then
34 rm -f /etc/resolv.conf
35 for server in $dns; do
36 echo "nameserver $server" >> /etc/resolv.conf
37 done
38 fi
39 fi
40 '';
41
42 udhcpcArgs = toString cfg.udhcpc.extraArgs;
43
44in
45
46{
47
48 options = {
49
50 boot.initrd.network.enable = mkOption {
51 type = types.bool;
52 default = false;
53 description = lib.mdDoc ''
54 Add network connectivity support to initrd. The network may be
55 configured using the `ip` kernel parameter,
56 as described in [the kernel documentation](https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt).
57 Otherwise, if
58 {option}`networking.useDHCP` is enabled, an IP address
59 is acquired using DHCP.
60
61 You should add the module(s) required for your network card to
62 boot.initrd.availableKernelModules.
63 `lspci -v | grep -iA8 'network\|ethernet'`
64 will tell you which.
65 '';
66 };
67
68 boot.initrd.network.flushBeforeStage2 = mkOption {
69 type = types.bool;
70 default = !config.boot.initrd.systemd.enable;
71 defaultText = "!config.boot.initrd.systemd.enable";
72 description = lib.mdDoc ''
73 Whether to clear the configuration of the interfaces that were set up in
74 the initrd right before stage 2 takes over. Stage 2 will do the regular network
75 configuration based on the NixOS networking options.
76
77 The default is false when systemd is enabled in initrd,
78 because the systemd-networkd documentation suggests it.
79 '';
80 };
81
82 boot.initrd.network.udhcpc.enable = mkOption {
83 default = config.networking.useDHCP && !config.boot.initrd.systemd.enable;
84 defaultText = "networking.useDHCP";
85 type = types.bool;
86 description = lib.mdDoc ''
87 Enables the udhcpc service during stage 1 of the boot process. This
88 defaults to {option}`networking.useDHCP`. Therefore, this useful if
89 useDHCP is off but the initramfs should do dhcp.
90 '';
91 };
92
93 boot.initrd.network.udhcpc.extraArgs = mkOption {
94 default = [];
95 type = types.listOf types.str;
96 description = lib.mdDoc ''
97 Additional command-line arguments passed verbatim to
98 udhcpc if {option}`boot.initrd.network.enable` and
99 {option}`boot.initrd.network.udhcpc.enable` are enabled.
100 '';
101 };
102
103 boot.initrd.network.postCommands = mkOption {
104 default = "";
105 type = types.lines;
106 description = lib.mdDoc ''
107 Shell commands to be executed after stage 1 of the
108 boot has initialised the network.
109 '';
110 };
111
112
113 };
114
115 config = mkIf cfg.enable {
116
117 boot.initrd.kernelModules = [ "af_packet" ];
118
119 boot.initrd.extraUtilsCommands = mkIf (!config.boot.initrd.systemd.enable) ''
120 copy_bin_and_libs ${pkgs.klibc}/lib/klibc/bin.static/ipconfig
121 '';
122
123 boot.initrd.preLVMCommands = mkIf (!config.boot.initrd.systemd.enable) (mkBefore (
124 # Search for interface definitions in command line.
125 ''
126 ifaces=""
127 for o in $(cat /proc/cmdline); do
128 case $o in
129 ip=*)
130 ipconfig $o && ifaces="$ifaces $(echo $o | cut -d: -f6)"
131 ;;
132 esac
133 done
134 ''
135
136 # Otherwise, use DHCP.
137 + optionalString doDhcp ''
138 # Bring up all interfaces.
139 for iface in ${dhcpIfShellExpr}; do
140 echo "bringing up network interface $iface..."
141 ip link set dev "$iface" up && ifaces="$ifaces $iface"
142 done
143
144 # Acquire DHCP leases.
145 for iface in ${dhcpIfShellExpr}; do
146 echo "acquiring IP address via DHCP on $iface..."
147 udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs}
148 done
149 ''
150
151 + cfg.postCommands));
152
153 boot.initrd.postMountCommands = mkIf (cfg.flushBeforeStage2 && !config.boot.initrd.systemd.enable) ''
154 for iface in $ifaces; do
155 ip address flush dev "$iface"
156 ip link set dev "$iface" down
157 done
158 '';
159
160 };
161
162}