aboutsummaryrefslogtreecommitdiff
path: root/nixpkgs/nixos/modules/tasks
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/tasks')
-rw-r--r--nixpkgs/nixos/modules/tasks/auto-upgrade.nix15
-rw-r--r--nixpkgs/nixos/modules/tasks/encrypted-devices.nix2
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems.nix9
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix7
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/zfs.nix6
-rw-r--r--nixpkgs/nixos/modules/tasks/network-interfaces-scripted.nix49
-rw-r--r--nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix69
-rw-r--r--nixpkgs/nixos/modules/tasks/network-interfaces.nix119
8 files changed, 227 insertions, 49 deletions
diff --git a/nixpkgs/nixos/modules/tasks/auto-upgrade.nix b/nixpkgs/nixos/modules/tasks/auto-upgrade.nix
index 7fe06699191..bfc1e301efa 100644
--- a/nixpkgs/nixos/modules/tasks/auto-upgrade.nix
+++ b/nixpkgs/nixos/modules/tasks/auto-upgrade.nix
@@ -63,6 +63,19 @@ let cfg = config.system.autoUpgrade; in
'';
};
+ randomizedDelaySec = mkOption {
+ default = "0";
+ type = types.str;
+ example = "45min";
+ description = ''
+ Add a randomized delay before each automatic upgrade.
+ The delay will be chozen between zero and this value.
+ This value must be a time span in the format specified by
+ <citerefentry><refentrytitle>systemd.time</refentrytitle>
+ <manvolnum>7</manvolnum></citerefentry>
+ '';
+ };
+
};
};
@@ -109,6 +122,8 @@ let cfg = config.system.autoUpgrade; in
startAt = cfg.dates;
};
+ systemd.timers.nixos-upgrade.timerConfig.RandomizedDelaySec = cfg.randomizedDelaySec;
+
};
}
diff --git a/nixpkgs/nixos/modules/tasks/encrypted-devices.nix b/nixpkgs/nixos/modules/tasks/encrypted-devices.nix
index 2c9231f5523..bc0933f16fe 100644
--- a/nixpkgs/nixos/modules/tasks/encrypted-devices.nix
+++ b/nixpkgs/nixos/modules/tasks/encrypted-devices.nix
@@ -65,7 +65,7 @@ in
boot.initrd = {
luks = {
devices =
- map (dev: { name = dev.encrypted.label; device = dev.encrypted.blkDev; } ) keylessEncDevs;
+ builtins.listToAttrs (map (dev: { name = dev.encrypted.label; value = { device = dev.encrypted.blkDev; }; }) keylessEncDevs);
forceLuksSupportInInitrd = true;
};
postMountCommands =
diff --git a/nixpkgs/nixos/modules/tasks/filesystems.nix b/nixpkgs/nixos/modules/tasks/filesystems.nix
index 688c77cb22d..0ade74b957a 100644
--- a/nixpkgs/nixos/modules/tasks/filesystems.nix
+++ b/nixpkgs/nixos/modules/tasks/filesystems.nix
@@ -304,6 +304,11 @@ in
in listToAttrs (map formatDevice (filter (fs: fs.autoFormat) fileSystems));
+ systemd.tmpfiles.rules = [
+ "d /run/keys 0750 root ${toString config.ids.gids.keys}"
+ "z /run/keys 0750 root ${toString config.ids.gids.keys}"
+ ];
+
# Sync mount options with systemd's src/core/mount-setup.c: mount_table.
boot.specialFileSystems = {
"/proc" = { fsType = "proc"; options = [ "nosuid" "noexec" "nodev" ]; };
@@ -312,8 +317,8 @@ in
"/dev/shm" = { fsType = "tmpfs"; options = [ "nosuid" "nodev" "strictatime" "mode=1777" "size=${config.boot.devShmSize}" ]; };
"/dev/pts" = { fsType = "devpts"; options = [ "nosuid" "noexec" "mode=620" "ptmxmode=0666" "gid=${toString config.ids.gids.tty}" ]; };
- # To hold secrets that shouldn't be written to disk (generally used for NixOps, harmless elsewhere)
- "/run/keys" = { fsType = "ramfs"; options = [ "nosuid" "nodev" "mode=750" "gid=${toString config.ids.gids.keys}" ]; };
+ # To hold secrets that shouldn't be written to disk
+ "/run/keys" = { fsType = "ramfs"; options = [ "nosuid" "nodev" "mode=750" ]; };
} // optionalAttrs (!config.boot.isContainer) {
# systemd-nspawn populates /sys by itself, and remounting it causes all
# kinds of weird issues (most noticeably, waiting for host disk device
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix
index 48be18c7102..f64493e1a3c 100644
--- a/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix
+++ b/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix
@@ -118,12 +118,17 @@ in
fs' = utils.escapeSystemdPath fs;
in nameValuePair "btrfs-scrub-${fs'}" {
description = "btrfs scrub on ${fs}";
+ # scrub prevents suspend2ram or proper shutdown
+ conflicts = [ "shutdown.target" "sleep.target" ];
+ before = [ "shutdown.target" "sleep.target" ];
serviceConfig = {
- Type = "oneshot";
+ # simple and not oneshot, otherwise ExecStop is not used
+ Type = "simple";
Nice = 19;
IOSchedulingClass = "idle";
ExecStart = "${pkgs.btrfs-progs}/bin/btrfs scrub start -B ${fs}";
+ ExecStop = "${pkgs.btrfs-progs}/bin/btrfs scrub cancel ${fs}";
};
};
in listToAttrs (map scrubService cfgScrub.fileSystems);
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix
index d14ba98ec48..09c7e074e12 100644
--- a/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix
+++ b/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix
@@ -623,7 +623,11 @@ in
after = [ "zfs-import.target" ];
path = [ packages.zfsUser ];
startAt = cfgTrim.interval;
- serviceConfig.ExecStart = "${pkgs.runtimeShell} -c 'zpool list -H -o name | xargs --no-run-if-empty -n1 zpool trim'";
+ # By default we ignore errors returned by the trim command, in case:
+ # - HDDs are mixed with SSDs
+ # - There is a SSDs in a pool that is currently trimmed.
+ # - There are only HDDs and we would set the system in a degraded state
+ serviceConfig.ExecStart = ''${pkgs.runtimeShell} -c 'for pool in $(zpool list -H -o name); do zpool trim $pool; done || true' '';
};
})
];
diff --git a/nixpkgs/nixos/modules/tasks/network-interfaces-scripted.nix b/nixpkgs/nixos/modules/tasks/network-interfaces-scripted.nix
index 1726d05115e..4d25137c5df 100644
--- a/nixpkgs/nixos/modules/tasks/network-interfaces-scripted.nix
+++ b/nixpkgs/nixos/modules/tasks/network-interfaces-scripted.nix
@@ -10,7 +10,7 @@ let
slaves = concatMap (i: i.interfaces) (attrValues cfg.bonds)
++ concatMap (i: i.interfaces) (attrValues cfg.bridges)
- ++ concatMap (i: i.interfaces) (attrValues cfg.vswitches)
+ ++ concatMap (i: attrNames (filterAttrs (_: config: config.type != "internal") i.interfaces)) (attrValues cfg.vswitches)
++ concatMap (i: [i.interface]) (attrValues cfg.macvlans)
++ concatMap (i: [i.interface]) (attrValues cfg.vlans);
@@ -336,34 +336,47 @@ let
createVswitchDevice = n: v: nameValuePair "${n}-netdev"
(let
- deps = concatLists (map deviceDependency v.interfaces);
+ deps = concatLists (map deviceDependency (attrNames (filterAttrs (_: config: config.type != "internal") v.interfaces)));
+ internalConfigs = concatMap (i: ["network-link-${i}.service" "network-addresses-${i}.service"]) (attrNames (filterAttrs (_: config: config.type == "internal") v.interfaces));
ofRules = pkgs.writeText "vswitch-${n}-openFlowRules" v.openFlowRules;
in
{ description = "Open vSwitch Interface ${n}";
- wantedBy = [ "network-setup.service" "vswitchd.service" ] ++ deps;
- bindsTo = [ "vswitchd.service" (subsystemDevice n) ] ++ deps;
- partOf = [ "network-setup.service" "vswitchd.service" ];
- after = [ "network-pre.target" "vswitchd.service" ] ++ deps;
- before = [ "network-setup.service" ];
+ wantedBy = [ "network-setup.service" (subsystemDevice n) ] ++ internalConfigs;
+ # before = [ "network-setup.service" ];
+ # should work without internalConfigs dependencies because address/link configuration depends
+ # on the device, which is created by ovs-vswitchd with type=internal, but it does not...
+ before = [ "network-setup.service" ] ++ internalConfigs;
+ partOf = [ "network-setup.service" ]; # shutdown the bridge when network is shutdown
+ bindsTo = [ "ovs-vswitchd.service" ]; # requires ovs-vswitchd to be alive at all times
+ after = [ "network-pre.target" "ovs-vswitchd.service" ] ++ deps; # start switch after physical interfaces and vswitch daemon
+ wants = deps; # if one or more interface fails, the switch should continue to run
serviceConfig.Type = "oneshot";
serviceConfig.RemainAfterExit = true;
path = [ pkgs.iproute config.virtualisation.vswitch.package ];
+ preStart = ''
+ echo "Resetting Open vSwitch ${n}..."
+ ovs-vsctl --if-exists del-br ${n} -- add-br ${n} \
+ -- set bridge ${n} protocols=${concatStringsSep "," v.supportedOpenFlowVersions}
+ '';
script = ''
- echo "Removing old Open vSwitch ${n}..."
- ovs-vsctl --if-exists del-br ${n}
-
- echo "Adding Open vSwitch ${n}..."
- ovs-vsctl -- add-br ${n} ${concatMapStrings (i: " -- add-port ${n} ${i}") v.interfaces} \
+ echo "Configuring Open vSwitch ${n}..."
+ ovs-vsctl ${concatStrings (mapAttrsToList (name: config: " -- add-port ${n} ${name}" + optionalString (config.vlan != null) " tag=${toString config.vlan}") v.interfaces)} \
+ ${concatStrings (mapAttrsToList (name: config: optionalString (config.type != null) " -- set interface ${name} type=${config.type}") v.interfaces)} \
${concatMapStrings (x: " -- set-controller ${n} " + x) v.controllers} \
${concatMapStrings (x: " -- " + x) (splitString "\n" v.extraOvsctlCmds)}
+
echo "Adding OpenFlow rules for Open vSwitch ${n}..."
- ovs-ofctl add-flows ${n} ${ofRules}
+ ovs-ofctl --protocols=${v.openFlowVersion} add-flows ${n} ${ofRules}
'';
postStop = ''
+ echo "Cleaning Open vSwitch ${n}"
+ echo "Shuting down internal ${n} interface"
ip link set ${n} down || true
- ovs-ofctl del-flows ${n} || true
- ovs-vsctl --if-exists del-br ${n}
+ echo "Deleting flows for ${n}"
+ ovs-ofctl --protocols=${v.openFlowVersion} del-flows ${n} || true
+ echo "Deleting Open vSwitch ${n}"
+ ovs-vsctl --if-exists del-br ${n} || true
'';
});
@@ -476,9 +489,9 @@ let
# Remove Dead Interfaces
ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
ip link add link "${v.interface}" name "${n}" type vlan id "${toString v.id}"
-
- # We try to bring up the logical VLAN interface. If the master
- # interface the logical interface is dependent upon is not up yet we will
+
+ # We try to bring up the logical VLAN interface. If the master
+ # interface the logical interface is dependent upon is not up yet we will
# fail to immediately bring up the logical interface. The resulting logical
# interface will brought up later when the master interface is up.
ip link set "${n}" up || true
diff --git a/nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix b/nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix
index e25dc0c0b39..41deceb000e 100644
--- a/nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix
+++ b/nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix
@@ -1,4 +1,4 @@
-{ config, lib, utils, ... }:
+{ config, lib, utils, pkgs, ... }:
with utils;
with lib;
@@ -18,7 +18,10 @@ let
concatLists (map (bond: bond.interfaces) (attrValues cfg.bonds))
++ concatLists (map (bridge: bridge.interfaces) (attrValues cfg.bridges))
++ map (sit: sit.dev) (attrValues cfg.sits)
- ++ map (vlan: vlan.interface) (attrValues cfg.vlans);
+ ++ map (vlan: vlan.interface) (attrValues cfg.vlans)
+ # add dependency to physical or independently created vswitch member interface
+ # TODO: warn the user that any address configured on those interfaces will be useless
+ ++ concatMap (i: attrNames (filterAttrs (_: config: config.type != "internal") i.interfaces)) (attrValues cfg.vswitches);
in
@@ -51,11 +54,6 @@ in
networking.dhcpcd.enable = mkDefault false;
- systemd.services.network-local-commands = {
- after = [ "systemd-networkd.service" ];
- bindsTo = [ "systemd-networkd.service" ];
- };
-
systemd.network =
let
domains = cfg.search ++ (optional (cfg.domain != null) cfg.domain);
@@ -233,6 +231,63 @@ in
# This forces the network interface creator to initialize slaves.
networking.interfaces = listToAttrs (map (i: nameValuePair i { }) slaves);
+ systemd.services = let
+ # We must escape interfaces due to the systemd interpretation
+ subsystemDevice = interface:
+ "sys-subsystem-net-devices-${escapeSystemdPath interface}.device";
+ # support for creating openvswitch switches
+ createVswitchDevice = n: v: nameValuePair "${n}-netdev"
+ (let
+ deps = map subsystemDevice (attrNames (filterAttrs (_: config: config.type != "internal") v.interfaces));
+ ofRules = pkgs.writeText "vswitch-${n}-openFlowRules" v.openFlowRules;
+ in
+ { description = "Open vSwitch Interface ${n}";
+ wantedBy = [ "network.target" (subsystemDevice n) ];
+ # and create bridge before systemd-networkd starts because it might create internal interfaces
+ before = [ "systemd-networkd.service" ];
+ # shutdown the bridge when network is shutdown
+ partOf = [ "network.target" ];
+ # requires ovs-vswitchd to be alive at all times
+ bindsTo = [ "ovs-vswitchd.service" ];
+ # start switch after physical interfaces and vswitch daemon
+ after = [ "network-pre.target" "ovs-vswitchd.service" ] ++ deps;
+ wants = deps; # if one or more interface fails, the switch should continue to run
+ serviceConfig.Type = "oneshot";
+ serviceConfig.RemainAfterExit = true;
+ path = [ pkgs.iproute config.virtualisation.vswitch.package ];
+ preStart = ''
+ echo "Resetting Open vSwitch ${n}..."
+ ovs-vsctl --if-exists del-br ${n} -- add-br ${n} \
+ -- set bridge ${n} protocols=${concatStringsSep "," v.supportedOpenFlowVersions}
+ '';
+ script = ''
+ echo "Configuring Open vSwitch ${n}..."
+ ovs-vsctl ${concatStrings (mapAttrsToList (name: config: " -- add-port ${n} ${name}" + optionalString (config.vlan != null) " tag=${toString config.vlan}") v.interfaces)} \
+ ${concatStrings (mapAttrsToList (name: config: optionalString (config.type != null) " -- set interface ${name} type=${config.type}") v.interfaces)} \
+ ${concatMapStrings (x: " -- set-controller ${n} " + x) v.controllers} \
+ ${concatMapStrings (x: " -- " + x) (splitString "\n" v.extraOvsctlCmds)}
+
+
+ echo "Adding OpenFlow rules for Open vSwitch ${n}..."
+ ovs-ofctl --protocols=${v.openFlowVersion} add-flows ${n} ${ofRules}
+ '';
+ postStop = ''
+ echo "Cleaning Open vSwitch ${n}"
+ echo "Shuting down internal ${n} interface"
+ ip link set ${n} down || true
+ echo "Deleting flows for ${n}"
+ ovs-ofctl --protocols=${v.openFlowVersion} del-flows ${n} || true
+ echo "Deleting Open vSwitch ${n}"
+ ovs-vsctl --if-exists del-br ${n} || true
+ '';
+ });
+ in mapAttrs' createVswitchDevice cfg.vswitches
+ // {
+ "network-local-commands" = {
+ after = [ "systemd-networkd.service" ];
+ bindsTo = [ "systemd-networkd.service" ];
+ };
+ };
};
}
diff --git a/nixpkgs/nixos/modules/tasks/network-interfaces.nix b/nixpkgs/nixos/modules/tasks/network-interfaces.nix
index 31e2ed1cd1e..9542a60beee 100644
--- a/nixpkgs/nixos/modules/tasks/network-interfaces.nix
+++ b/nixpkgs/nixos/modules/tasks/network-interfaces.nix
@@ -13,7 +13,7 @@ let
slaves = concatMap (i: i.interfaces) (attrValues cfg.bonds)
++ concatMap (i: i.interfaces) (attrValues cfg.bridges)
- ++ concatMap (i: i.interfaces) (attrValues cfg.vswitches);
+ ++ concatMap (i: attrNames (filterAttrs (name: config: ! (config.type == "internal" || hasAttr name cfg.interfaces)) i.interfaces)) (attrValues cfg.vswitches);
slaveIfs = map (i: cfg.interfaces.${i}) (filter (i: cfg.interfaces ? ${i}) slaves);
@@ -143,13 +143,34 @@ let
description = "Name of the interface.";
};
- preferTempAddress = mkOption {
- type = types.bool;
- default = cfg.enableIPv6;
- defaultText = literalExample "config.networking.enableIPv6";
+ tempAddress = mkOption {
+ type = types.enum [ "default" "enabled" "disabled" ];
+ default = if cfg.enableIPv6 then "default" else "disabled";
+ defaultText = literalExample ''if cfg.enableIPv6 then "default" else "disabled"'';
description = ''
- When using SLAAC prefer a temporary (IPv6) address over the EUI-64
- address for originating connections. This is used to reduce tracking.
+ When IPv6 is enabled with SLAAC, this option controls the use of
+ temporary address (aka privacy extensions). This is used to reduce tracking.
+ The three possible values are:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>"default"</literal> to generate temporary addresses and use
+ them by default;
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>"enabled"</literal> to generate temporary addresses but keep
+ using the standard EUI-64 ones by default;
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>"disabled"</literal> to completely disable temporary addresses.
+ </para>
+ </listitem>
+ </itemizedlist>
'';
};
@@ -287,6 +308,11 @@ let
let
defined = x: x != "_mkMergedOptionModule";
in [
+ (mkChangedOptionModule [ "preferTempAddress" ] [ "tempAddress" ]
+ (config:
+ let bool = getAttrFromPath [ "preferTempAddress" ] config;
+ in if bool then "default" else "enabled"
+ ))
(mkRenamedOptionModule [ "ip4" ] [ "ipv4" "addresses"])
(mkRenamedOptionModule [ "ip6" ] [ "ipv6" "addresses"])
(mkRemovedOptionModule [ "subnetMask" ] ''
@@ -310,6 +336,32 @@ let
};
+ vswitchInterfaceOpts = {name, ...}: {
+
+ options = {
+
+ name = mkOption {
+ description = "Name of the interface";
+ example = "eth0";
+ type = types.str;
+ };
+
+ vlan = mkOption {
+ description = "Vlan tag to apply to interface";
+ example = 10;
+ type = types.nullOr types.int;
+ default = null;
+ };
+
+ type = mkOption {
+ description = "Openvswitch type to assign to interface";
+ example = "internal";
+ type = types.nullOr types.str;
+ default = null;
+ };
+ };
+ };
+
hexChars = stringToCharacters "0123456789abcdef";
isHexString = s: all (c: elem c hexChars) (stringToCharacters (toLower s));
@@ -460,8 +512,8 @@ in
networking.vswitches = mkOption {
default = { };
example =
- { vs0.interfaces = [ "eth0" "eth1" ];
- vs1.interfaces = [ "eth2" "wlan0" ];
+ { vs0.interfaces = { eth0 = { }; lo1 = { type="internal"; }; };
+ vs1.interfaces = [ { name = "eth2"; } { name = "lo2"; type="internal"; } ];
};
description =
''
@@ -478,9 +530,8 @@ in
interfaces = mkOption {
example = [ "eth0" "eth1" ];
- type = types.listOf types.str;
- description =
- "The physical network interfaces connected by the vSwitch.";
+ description = "The physical network interfaces connected by the vSwitch.";
+ type = with types; loaOf (submodule vswitchInterfaceOpts);
};
controllers = mkOption {
@@ -504,6 +555,25 @@ in
'';
};
+ # TODO: custom "openflow version" type, with list from existing openflow protocols
+ supportedOpenFlowVersions = mkOption {
+ type = types.listOf types.str;
+ example = [ "OpenFlow10" "OpenFlow13" "OpenFlow14" ];
+ default = [ "OpenFlow13" ];
+ description = ''
+ Supported versions to enable on this switch.
+ '';
+ };
+
+ # TODO: use same type as elements from supportedOpenFlowVersions
+ openFlowVersion = mkOption {
+ type = types.str;
+ default = "OpenFlow13";
+ description = ''
+ Version of OpenFlow protocol to use when communicating with the switch internally (e.g. with <literal>openFlowRules</literal>).
+ '';
+ };
+
extraOvsctlCmds = mkOption {
type = types.lines;
default = "";
@@ -945,7 +1015,7 @@ in
The networking.interfaces."${i.name}" must not have any defined ips when it is a slave.
'';
})) ++ (forEach interfaces (i: {
- assertion = i.preferTempAddress -> cfg.enableIPv6;
+ assertion = i.tempAddress != "disabled" -> cfg.enableIPv6;
message = ''
Temporary addresses are only needed when IPv6 is enabled.
'';
@@ -973,8 +1043,11 @@ in
"net.ipv6.conf.all.forwarding" = mkDefault (any (i: i.proxyARP) interfaces);
} // listToAttrs (flip concatMap (filter (i: i.proxyARP) interfaces)
(i: forEach [ "4" "6" ] (v: nameValuePair "net.ipv${v}.conf.${replaceChars ["."] ["/"] i.name}.proxy_arp" true)))
- // listToAttrs (forEach (filter (i: i.preferTempAddress) interfaces)
- (i: nameValuePair "net.ipv6.conf.${replaceChars ["."] ["/"] i.name}.use_tempaddr" 2));
+ // listToAttrs (forEach interfaces
+ (i: let
+ opt = i.tempAddress;
+ val = { disabled = 0; enabled = 1; default = 2; }.${opt};
+ in nameValuePair "net.ipv6.conf.${replaceChars ["."] ["/"] i.name}.use_tempaddr" val));
# Capabilities won't work unless we have at-least a 4.3 Linux
# kernel because we need the ambient capability
@@ -1103,10 +1176,18 @@ in
(pkgs.writeTextFile rec {
name = "ipv6-privacy-extensions.rules";
destination = "/etc/udev/rules.d/99-${name}";
- text = concatMapStrings (i: ''
- # enable IPv6 privacy addresses but prefer EUI-64 addresses for ${i.name}
- ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.procps}/bin/sysctl net.ipv6.conf.${replaceChars ["."] ["/"] i.name}.use_tempaddr=1"
- '') (filter (i: !i.preferTempAddress) interfaces);
+ text = concatMapStrings (i:
+ let
+ opt = i.tempAddress;
+ val = if opt == "disabled" then 0 else 1;
+ msg = if opt == "disabled"
+ then "completely disable IPv6 privacy addresses"
+ else "enable IPv6 privacy addresses but prefer EUI-64 addresses";
+ in
+ ''
+ # override to ${msg} for ${i.name}
+ ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.procps}/bin/sysctl net.ipv6.conf.${replaceChars ["."] ["/"] i.name}.use_tempaddr=${toString val}"
+ '') (filter (i: i.tempAddress != "default") interfaces);
})
] ++ lib.optional (cfg.wlanInterfaces != {})
(pkgs.writeTextFile {