# 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 config.virtualisation.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} ''; } ) ]; }; }