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