diff --git a/nixos/modules/virtualisation/guest-networking-options.nix b/nixos/modules/virtualisation/guest-networking-options.nix new file mode 100644 index 000000000000..fb450cfa09ba --- /dev/null +++ b/nixos/modules/virtualisation/guest-networking-options.nix @@ -0,0 +1,138 @@ +# This module defines networking options for virtual machines and containers. +# It is intended to be used with systemd-nspawn containers and QEMU virtual machines. +{ config, lib, ... }: +let + inherit (lib) types; + + interfaceType = types.submodule ( + { name, ... }: + { + options = { + name = lib.mkOption { + type = types.str; + default = name; + description = '' + Interface name + ''; + }; + + vlan = lib.mkOption { + type = types.ints.unsigned; + description = '' + VLAN to which the network interface is connected. + ''; + }; + + assignIP = lib.mkOption { + type = types.bool; + default = false; + description = '' + Automatically assign an IP address to the network interface using the same scheme as + virtualisation.vlans. + ''; + }; + }; + } + ); + + cfg = config.virtualisation; + + # Convert legacy VLANs to named interfaces. + vlansNumbered = lib.listToAttrs ( + lib.forEach (lib.zipLists cfg.vlans (lib.range 1 255)) ( + v: + let + name = "eth${toString v.snd}"; + in + lib.nameValuePair name { + inherit name; + vlan = v.fst; + assignIP = true; + } + ) + ); +in +{ + options = { + networking.primaryIPAddress = lib.mkOption { + type = types.str; + default = ""; + internal = true; + description = "Primary IP address used in /etc/hosts."; + }; + + networking.primaryIPv6Address = lib.mkOption { + type = types.str; + default = ""; + internal = true; + description = "Primary IPv6 address used in /etc/hosts."; + }; + + virtualisation.vlans = lib.mkOption { + type = types.listOf types.ints.unsigned; + default = if cfg.interfaces == { } then [ 1 ] else [ ]; + defaultText = lib.literalExpression ''if cfg.interfaces == {} then [ 1 ] else [ ]''; + example = [ + 1 + 2 + ]; + description = '' + Virtual networks to which the container or VM is connected. Each number «N» in + this list causes the container to have a virtual Ethernet interface + attached to a separate virtual network on which it will be assigned IP + address `192.168.«N».«M»`, where «M» is the index of this container in + the list of containers. + ''; + }; + + virtualisation.interfaces = lib.mkOption { + default = { }; + example = { + enp1s0.vlan = 1; + }; + description = '' + Extra network interfaces to add to the container or VM in addition to the ones + created by {option}`virtualisation.vlans`. + ''; + type = types.attrsOf interfaceType; + }; + + virtualisation.allInterfaces = lib.mkOption { + type = types.attrsOf interfaceType; + readOnly = true; + description = '' + All network interfaces for the container or VM. Combines + {option}`virtualisation.vlans` and {option}`virtualisation.interfaces`. + ''; + default = vlansNumbered // cfg.interfaces; + }; + }; + config = { + assertions = [ + ( + let + conflictingKeys = lib.intersectAttrs vlansNumbered cfg.interfaces; + in + { + assertion = conflictingKeys == { }; + message = '' + `virtualisation.vlans` and `virtualisation.interfaces` have conflicting keys: ${lib.concatStringsSep "," (lib.attrNames conflictingKeys)} + ''; + } + ) + ( + let + allInterfaceNames = + (lib.mapAttrsToList (k: i: i.name) vlansNumbered) + ++ (lib.mapAttrsToList (k: i: i.name) cfg.interfaces); + in + { + assertion = lib.allUnique allInterfaceNames; + message = '' + `virtualisation.vlans` and `virtualisation.interfaces` have conflicting interface names: ${lib.concatStringsSep "," allInterfaceNames} + ''; + } + ) + ]; + }; +} diff --git a/nixos/modules/virtualisation/nspawn-container/default.nix b/nixos/modules/virtualisation/nspawn-container/default.nix index c3dc37f1f269..c3ab6f1e4873 100644 --- a/nixos/modules/virtualisation/nspawn-container/default.nix +++ b/nixos/modules/virtualisation/nspawn-container/default.nix @@ -19,106 +19,11 @@ let inherit (lib) types; cfg = config.virtualisation; - - interfaceType = types.submodule ( - { name, ... }: - { - options = { - name = lib.mkOption { - type = types.str; - default = name; - description = '' - Interface name - ''; - }; - - vlan = lib.mkOption { - type = types.ints.unsigned; - description = '' - VLAN to which the network interface is connected. - ''; - }; - - assignIP = lib.mkOption { - type = types.bool; - default = false; - description = '' - Automatically assign an IP address to the network interface using the same scheme as - virtualisation.vlans. - ''; - }; - }; - } - ); - - # Convert legacy VLANs to named interfaces. - vlansNumbered = lib.listToAttrs ( - lib.forEach (lib.zipLists cfg.vlans (lib.range 1 255)) ( - v: - let - name = "eth${toString v.snd}"; - in - lib.nameValuePair name { - inherit name; - vlan = v.fst; - assignIP = true; - } - ) - ); in { + imports = [ ../guest-networking-options.nix ]; + options = { - networking.primaryIPAddress = lib.mkOption { - type = types.str; - default = ""; - internal = true; - description = "Primary IP address used in /etc/hosts."; - }; - - networking.primaryIPv6Address = lib.mkOption { - type = types.str; - default = ""; - internal = true; - description = "Primary IPv6 address used in /etc/hosts."; - }; - - virtualisation.vlans = lib.mkOption { - type = types.listOf types.ints.unsigned; - default = if cfg.interfaces == { } then [ 1 ] else [ ]; - defaultText = lib.literalExpression ''if cfg.interfaces == {} then [ 1 ] else [ ]''; - example = [ - 1 - 2 - ]; - description = '' - Virtual networks to which the container is connected. Each number «N» in - this list causes the container to have a virtual Ethernet interface - attached to a separate virtual network on which it will be assigned IP - address `192.168.«N».«M»`, where «M» is the index of this container in - the list of containers. - ''; - }; - - virtualisation.interfaces = lib.mkOption { - default = { }; - example = { - enp1s0.vlan = 1; - }; - description = '' - Network interfaces to add to the container. - ''; - type = types.attrsOf interfaceType; - }; - - virtualisation.allInterfaces = lib.mkOption { - type = types.attrsOf interfaceType; - readOnly = true; - description = '' - All network interfaces for the container. Combines - {option}`virtualisation.vlans` and {option}`virtualisation.interfaces`. - ''; - default = vlansNumbered // cfg.interfaces; - }; virtualisation.cmdline = lib.mkOption { type = types.listOf types.str; @@ -163,33 +68,6 @@ in }; config = { - assertions = [ - ( - let - conflictingKeys = lib.intersectAttrs vlansNumbered cfg.interfaces; - in - { - assertion = conflictingKeys == { }; - message = '' - `virtualisation.vlans` and `virtualisation.interfaces` have conflicting keys: ${lib.concatStringsSep "," (lib.attrNames conflictingKeys)} - ''; - } - ) - ( - let - allInterfaceNames = - (lib.mapAttrsToList (k: i: i.name) vlansNumbered) - ++ (lib.mapAttrsToList (k: i: i.name) cfg.interfaces); - in - { - assertion = lib.allUnique allInterfaceNames; - message = '' - `virtualisation.vlans` and `virtualisation.interfaces` have conflicting interface names: ${lib.concatStringsSep "," allInterfaceNames} - ''; - } - ) - ]; - boot.isNspawnContainer = true; # Needed since nixpkgs 7fb2f407c01b017737eafc26b065d7f56434a992 removed the getty unit by default. diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index a83f825de444..762349a39753 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -360,58 +360,12 @@ let copyChannel = false; OVMF = cfg.efi.OVMF; }; - - interfaceType = types.submodule ( - { name, ... }: - { - options = { - name = mkOption { - type = types.str; - default = name; - description = '' - Interface name - ''; - }; - - vlan = mkOption { - type = types.ints.unsigned; - description = '' - VLAN to which the network interface is connected. - ''; - }; - - assignIP = mkOption { - type = types.bool; - default = false; - description = '' - Automatically assign an IP address to the network interface using the same scheme as - virtualisation.vlans. - ''; - }; - }; - } - ); - - # Convert legacy VLANs to named interfaces. - vlansNumbered = lib.listToAttrs ( - lib.forEach (lib.zipLists cfg.vlans (lib.range 1 255)) ( - v: - let - name = "eth${toString v.snd}"; - in - lib.nameValuePair name { - inherit name; - vlan = v.fst; - assignIP = true; - } - ) - ); - in { imports = [ ../profiles/qemu-guest.nix ./disk-size-option.nix + ./guest-networking-options.nix (mkRenamedOptionModule [ "virtualisation" @@ -726,48 +680,6 @@ in ''; }; - virtualisation.vlans = mkOption { - type = types.listOf types.ints.unsigned; - default = if config.virtualisation.interfaces == { } then [ 1 ] else [ ]; - defaultText = lib.literalExpression ''if config.virtualisation.interfaces == {} then [ 1 ] else [ ]''; - example = [ - 1 - 2 - ]; - description = '' - Virtual networks to which the VM is connected. Each - number «N» in this list causes - the VM to have a virtual Ethernet interface attached to a - separate virtual network on which it will be assigned IP - address - `192.168.«N».«M»`, - where «M» is the index of this VM - in the list of VMs. - ''; - }; - - virtualisation.interfaces = mkOption { - default = { }; - example = { - enp1s0.vlan = 1; - }; - description = '' - Extra network interfaces to add to the VM in addition to the ones - created by {option}`virtualisation.vlans`. - ''; - type = types.attrsOf interfaceType; - }; - - virtualisation.allInterfaces = mkOption { - type = types.attrsOf interfaceType; - readOnly = true; - description = '' - All network interfaces for the VM. Combines - {option}`virtualisation.vlans` and {option}`virtualisation.interfaces`. - ''; - default = vlansNumbered // cfg.interfaces; - }; - virtualisation.writableStore = mkOption { type = types.bool; default = cfg.mountHostNixStore; @@ -790,20 +702,6 @@ in ''; }; - networking.primaryIPAddress = mkOption { - type = types.str; - default = ""; - internal = true; - description = "Primary IP address used in /etc/hosts."; - }; - - networking.primaryIPv6Address = mkOption { - type = types.str; - default = ""; - internal = true; - description = "Primary IPv6 address used in /etc/hosts."; - }; - virtualisation.host.pkgs = mkOption { type = options.nixpkgs.pkgs.type; default = pkgs; @@ -1286,30 +1184,6 @@ in ) ) ++ [ - ( - let - conflictingKeys = lib.intersectAttrs vlansNumbered cfg.interfaces; - in - { - assertion = conflictingKeys == { }; - message = '' - `virtualisation.vlans` and `virtualisation.interfaces` have conflicting keys: ${lib.concatStringsSep "," (lib.attrNames conflictingKeys)} - ''; - } - ) - ( - let - allInterfaceNames = - (lib.mapAttrsToList (k: i: i.name) vlansNumbered) - ++ (lib.mapAttrsToList (k: i: i.name) cfg.interfaces); - in - { - assertion = lib.allUnique allInterfaceNames; - message = '' - `virtualisation.vlans` and `virtualisation.interfaces` have conflicting interface names: ${lib.concatStringsSep "," allInterfaceNames} - ''; - } - ) { assertion = pkgs.stdenv.hostPlatform.is32bit -> cfg.memorySize < 2047; message = ''