diff options
Diffstat (limited to 'nixpkgs/nixos/modules/tasks')
-rw-r--r-- | nixpkgs/nixos/modules/tasks/auto-upgrade.nix | 15 | ||||
-rw-r--r-- | nixpkgs/nixos/modules/tasks/encrypted-devices.nix | 2 | ||||
-rw-r--r-- | nixpkgs/nixos/modules/tasks/filesystems.nix | 9 | ||||
-rw-r--r-- | nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix | 7 | ||||
-rw-r--r-- | nixpkgs/nixos/modules/tasks/filesystems/zfs.nix | 6 | ||||
-rw-r--r-- | nixpkgs/nixos/modules/tasks/network-interfaces-scripted.nix | 49 | ||||
-rw-r--r-- | nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix | 69 | ||||
-rw-r--r-- | nixpkgs/nixos/modules/tasks/network-interfaces.nix | 119 |
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 { |