diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index 63d07832d10..9dba6d1bd0a 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -185,33 +185,57 @@ let path = [ pkgs.iproute ]; script = '' - # FIXME: shouldn't this be done in network-link? - echo "bringing up interface..." - ip link set "${i.name}" up - state="/run/nixos/network/addresses/${i.name}" - mkdir -p $(dirname "$state") - '' + flip concatMapStrings (ips) (ip: - let - address = "${ip.address}/${toString ip.prefixLength}"; - in - '' - echo "${address}" >> $state - if out=$(ip addr add "${address}" dev "${i.name}" 2>&1); then - echo "added ip ${address}" - elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then - echo "failed to add ${address}" - exit 1 - fi - ''); + ${flip concatMapStrings ips (ip: + let + cidr = "${ip.address}/${toString ip.prefixLength}"; + in + '' + echo "${cidr}" >> $state + echo -n "adding address ${cidr}... " + if out=$(ip addr add "${cidr}" dev "${i.name}" 2>&1); then + echo "done" + elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then + echo "failed" + exit 1 + fi + '' + )} + + state="/run/nixos/network/routes/${i.name}" + mkdir -p $(dirname "$state") + + ${flip concatMapStrings (i.ipv4Routes ++ i.ipv6Routes) (route: + let + cidr = "${route.address}/${toString route.prefixLength}"; + nextHop = optionalString (route.nextHop != null) ''via "${route.nextHop}"''; + in + '' + echo "${cidr}" >> $state + echo -n "adding route ${cidr}... " + if out=$(ip route add "${cidr}" ${route.options} ${nextHop} dev "${i.name}" 2>&1); then + echo "done" + elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then + echo "failed" + exit 1 + fi + '' + )} + ''; preStop = '' + state="/run/nixos/network/routes/${i.name}" + while read cidr; do + echo -n "deleting route $cidr... " + ip route del "$cidr" dev "${i.name}" >/dev/null 2>&1 && echo "done" || echo "failed" + done < "$state" + rm -f "$state" + state="/run/nixos/network/addresses/${i.name}" - while read address; do - echo -n "deleting $address..." - ip addr del "$address" dev "${i.name}" >/dev/null 2>&1 || echo -n " Failed" - echo "" + while read cidr; do + echo -n "deleting address $cidr... " + ip addr del "$cidr" dev "${i.name}" >/dev/null 2>&1 && echo "done" || echo "failed" done < "$state" rm -f "$state" ''; diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index f80c5045c07..d437a829be5 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -101,7 +101,7 @@ let address = mkOption { type = types.str; description = '' - IPv${toString v} address of the interface. Leave empty to configure the + IPv${toString v} address of the interface. Leave empty to configure the interface using DHCP. ''; }; @@ -116,6 +116,40 @@ let }; }; + routeOpts = v: + { options = { + address = mkOption { + type = types.str; + description = "IPv${toString v} address of the network."; + }; + + prefixLength = mkOption { + type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128)); + description = '' + Subnet mask of the network, specified as the number of + bits in the prefix (${if v == 4 then "24" else "64"}). + ''; + }; + + nextHop = mkOption { + type = types.nullOr types.str; + default = null; + description = "IPv${toString v} address of the next hop."; + }; + + options = mkOption { + type = types.str; + default = ""; + example = "mtu 1492 window 524288"; + description = '' + Other route options. See the symbol OPTION + in the ip-route(8) manual page for the details. + ''; + }; + + }; + }; + gatewayCoerce = address: { inherit address; }; gatewayOpts = { ... }: { @@ -199,6 +233,30 @@ let ''; }; + ipv4Routes = mkOption { + default = []; + example = [ + { address = "10.0.0.0"; prefixLength = 16; } + { address = "192.168.2.0"; prefixLength = 24; nextHop = "192.168.1.1"; } + ]; + type = with types; listOf (submodule (routeOpts 4)); + description = '' + List of extra IPv4 static routes that will be assigned to the interface. + ''; + }; + + ipv6Routes = mkOption { + default = []; + example = [ + { address = "fdfd:b3f0::"; prefixLength = 48; } + { address = "2001:1470:fffd:2098::"; prefixLength = 64; nextHop = "fdfd:b3f0::1"; } + ]; + type = with types; listOf (submodule (routeOpts 6)); + description = '' + List of extra IPv6 static routes that will be assigned to the interface. + ''; + }; + ipAddress = mkOption { default = null; example = "10.0.0.1"; @@ -1089,6 +1147,9 @@ in '' + optionalString (i.mtu != null) '' echo "setting MTU to ${toString i.mtu}..." ip link set "${i.name}" mtu "${toString i.mtu}" + '' + '' + echo -n "bringing up interface... " + ip link set "${i.name}" up && echo "done" || (echo "failed"; exit 1) ''; })));