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 = ''
54 Add network connectivity support to initrd. The network may be
55 configured using the <literal>ip</literal> kernel parameter,
56 as described in <link
57 xlink:href="https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt">the
58 kernel documentation</link>. Otherwise, if
59 <option>networking.useDHCP</option> is enabled, an IP address
60 is acquired using DHCP.
61
62 You should add the module(s) required for your network card to
63 boot.initrd.availableKernelModules.
64 <literal>lspci -v | grep -iA8 'network\|ethernet'</literal>
65 will tell you which.
66 '';
67 };
68
69 boot.initrd.network.flushBeforeStage2 = mkOption {
70 type = types.bool;
71 default = true;
72 description = ''
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 };
78
79 boot.initrd.network.udhcpc.extraArgs = mkOption {
80 default = [];
81 type = types.listOf types.str;
82 description = ''
83 Additional command-line arguments passed verbatim to udhcpc if
84 <option>boot.initrd.network.enable</option> and <option>networking.useDHCP</option>
85 are enabled.
86 '';
87 };
88
89 boot.initrd.network.postCommands = mkOption {
90 default = "";
91 type = types.lines;
92 description = ''
93 Shell commands to be executed after stage 1 of the
94 boot has initialised the network.
95 '';
96 };
97
98
99 };
100
101 config = mkIf cfg.enable {
102
103 boot.initrd.kernelModules = [ "af_packet" ];
104
105 boot.initrd.extraUtilsCommands = ''
106 copy_bin_and_libs ${pkgs.klibc}/lib/klibc/bin.static/ipconfig
107 '';
108
109 boot.initrd.preLVMCommands = mkBefore (
110 # Search for interface definitions in command line.
111 ''
112 ifaces=""
113 for o in $(cat /proc/cmdline); do
114 case $o in
115 ip=*)
116 ipconfig $o && ifaces="$ifaces $(echo $o | cut -d: -f6)"
117 ;;
118 esac
119 done
120 ''
121
122 # Otherwise, use DHCP.
123 + optionalString doDhcp ''
124 # Bring up all interfaces.
125 for iface in ${dhcpIfShellExpr}; do
126 echo "bringing up network interface $iface..."
127 ip link set "$iface" up && ifaces="$ifaces $iface"
128 done
129
130 # Acquire DHCP leases.
131 for iface in ${dhcpIfShellExpr}; do
132 echo "acquiring IP address via DHCP on $iface..."
133 udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs}
134 done
135 ''
136
137 + cfg.postCommands);
138
139 boot.initrd.postMountCommands = mkIf cfg.flushBeforeStage2 ''
140 for iface in $ifaces; do
141 ip address flush "$iface"
142 ip link set "$iface" down
143 done
144 '';
145
146 };
147
148}