summary refs log tree commit diff
path: root/nixos/modules/tasks/network-interfaces.nix
diff options
context:
space:
mode:
authorRicardo M. Correia <rcorreia@wizy.org>2014-10-23 04:59:06 +0200
committerRicardo M. Correia <rcorreia@wizy.org>2014-11-12 22:31:49 +0100
commite9affb4274a4d72d6aa1fde9d34862dfd93173cc (patch)
tree0b5be35e36c74321b6f7d9109f6e564973dcba31 /nixos/modules/tasks/network-interfaces.nix
parent12e77fdc3f6f223be1a4d5c88d6c79bff63ae70c (diff)
downloadnixpkgs-e9affb4274a4d72d6aa1fde9d34862dfd93173cc.tar
nixpkgs-e9affb4274a4d72d6aa1fde9d34862dfd93173cc.tar.gz
nixpkgs-e9affb4274a4d72d6aa1fde9d34862dfd93173cc.tar.bz2
nixpkgs-e9affb4274a4d72d6aa1fde9d34862dfd93173cc.tar.lz
nixpkgs-e9affb4274a4d72d6aa1fde9d34862dfd93173cc.tar.xz
nixpkgs-e9affb4274a4d72d6aa1fde9d34862dfd93173cc.tar.zst
nixpkgs-e9affb4274a4d72d6aa1fde9d34862dfd93173cc.zip
nixos: Add system-wide option to set the hostid
The old boot.spl.hostid option was not working correctly due to an
upstream bug.

Instead, now we will create the /etc/hostid file so that all applications
(including the ZFS kernel modules, ZFS user-space applications and other
unrelated programs) pick-up the same system-wide host id. Note that glibc
(and by extension, the `hostid` program) also respect the host id configured in
/etc/hostid, if it exists.

The hostid option is now mandatory when using ZFS because otherwise, ZFS will
require you to force-import your ZFS pools if you want to use them, which is
undesirable because it disables some of the checks that ZFS does to make sure it
is safe to import a ZFS pool.

The /etc/hostid file must also exist when booting the initrd, before the SPL
kernel module is loaded, so that ZFS picks up the hostid correctly.

The complexity in creating the /etc/hostid file is due to having to
write the host ID as a 32-bit binary value, taking into account the
endianness of the machine, while using only shell commands and/or simple
utilities (to avoid exploding the size of the initrd).
Diffstat (limited to 'nixos/modules/tasks/network-interfaces.nix')
-rw-r--r--nixos/modules/tasks/network-interfaces.nix50
1 files changed, 44 insertions, 6 deletions
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index 22b52f77b14..9579eaa77d0 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -189,6 +189,10 @@ let
 
   };
 
+  hexChars = stringToCharacters "0123456789abcdef";
+
+  isHexString = s: all (c: elem c hexChars) (stringToCharacters (toLower s));
+
 in
 
 {
@@ -205,6 +209,20 @@ in
       '';
     };
 
+    networking.hostId = mkOption {
+      default = null;
+      example = "4e98920d";
+      type = types.nullOr types.str;
+      description = ''
+        The 32-bit host ID of the machine, formatted as 8 hexadecimal characters.
+
+        You should try to make this ID unique among your machines. You can
+        generate a random 32-bit ID using the following command:
+
+        <literal>head -c4 /dev/urandom | od -A none -t x4</literal>
+      '';
+    };
+
     networking.enableIPv6 = mkOption {
       default = true;
       description = ''
@@ -513,10 +531,15 @@ in
   config = {
 
     assertions =
-      flip map interfaces (i: {
+      (flip map interfaces (i: {
         assertion = i.subnetMask == null;
         message = "The networking.interfaces.${i.name}.subnetMask option is defunct. Use prefixLength instead.";
-      });
+      })) ++ [
+        {
+          assertion = cfg.hostId == null || (stringLength cfg.hostId == 8 && isHexString cfg.hostId);
+          message = "Invalid value given to the networking.hostId option.";
+        }
+      ];
 
     boot.kernelModules = [ ]
       ++ optional cfg.enableIPv6 "ipv6"
@@ -872,14 +895,29 @@ in
     # clear it if it's not configured in the NixOS configuration,
     # since it may have been set by dhcpcd in the meantime.
     system.activationScripts.hostname =
-      optionalString (config.networking.hostName != "") ''
-        hostname "${config.networking.hostName}"
+      optionalString (cfg.hostName != "") ''
+        hostname "${cfg.hostName}"
       '';
     system.activationScripts.domain =
-      optionalString (config.networking.domain != "") ''
-        domainname "${config.networking.domain}"
+      optionalString (cfg.domain != "") ''
+        domainname "${cfg.domain}"
       '';
 
+    environment.etc = mkIf (cfg.hostId != null)
+      [
+        {
+          target = "hostid";
+          source = pkgs.runCommand "gen-hostid" {} ''
+            hi="${cfg.hostId}"
+            ${if pkgs.stdenv.isBigEndian then ''
+              echo -ne "\x''${hi:0:2}\x''${hi:2:2}\x''${hi:4:2}\x''${hi:6:2}" > $out
+            '' else ''
+              echo -ne "\x''${hi:6:2}\x''${hi:4:2}\x''${hi:2:2}\x''${hi:0:2}" > $out
+            ''}
+          '';
+        }
+      ];
+
     services.udev.extraRules =
       ''
         KERNEL=="tun", TAG+="systemd"