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 = config.networking.useDHCP || dhcpInterfaces != [];
11 dhcpIfShellExpr = if config.networking.useDHCP
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.extraArgs = mkOption {
83 default = [];
84 type = types.listOf types.str;
85 description = lib.mdDoc ''
86 Additional command-line arguments passed verbatim to udhcpc if
87 {option}`boot.initrd.network.enable` and {option}`networking.useDHCP`
88 are enabled.
89 '';
90 };
91
92 boot.initrd.network.postCommands = mkOption {
93 default = "";
94 type = types.lines;
95 description = lib.mdDoc ''
96 Shell commands to be executed after stage 1 of the
97 boot has initialised the network.
98 '';
99 };
100
101
102 };
103
104 config = mkIf cfg.enable {
105
106 boot.initrd.kernelModules = [ "af_packet" ];
107
108 boot.initrd.extraUtilsCommands = ''
109 copy_bin_and_libs ${pkgs.klibc}/lib/klibc/bin.static/ipconfig
110 '';
111
112 boot.initrd.preLVMCommands = mkBefore (
113 # Search for interface definitions in command line.
114 ''
115 ifaces=""
116 for o in $(cat /proc/cmdline); do
117 case $o in
118 ip=*)
119 ipconfig $o && ifaces="$ifaces $(echo $o | cut -d: -f6)"
120 ;;
121 esac
122 done
123 ''
124
125 # Otherwise, use DHCP.
126 + optionalString doDhcp ''
127 # Bring up all interfaces.
128 for iface in ${dhcpIfShellExpr}; do
129 echo "bringing up network interface $iface..."
130 ip link set "$iface" up && ifaces="$ifaces $iface"
131 done
132
133 # Acquire DHCP leases.
134 for iface in ${dhcpIfShellExpr}; do
135 echo "acquiring IP address via DHCP on $iface..."
136 udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs}
137 done
138 ''
139
140 + cfg.postCommands);
141
142 boot.initrd.postMountCommands = mkIf cfg.flushBeforeStage2 ''
143 for iface in $ifaces; do
144 ip address flush "$iface"
145 ip link set "$iface" down
146 done
147 '';
148
149 };
150
151}