diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix index 07f3cb9e952..b8d04953e9e 100644 --- a/nixos/modules/system/boot/systemd-unit-options.nix +++ b/nixos/modules/system/boot/systemd-unit-options.nix @@ -441,4 +441,321 @@ in rec { targetOptions = commonUnitOptions; + commonNetworkOptions = { + + enable = mkOption { + default = true; + type = types.bool; + description = '' + If set to false, this unit will be a symlink to + /dev/null. + ''; + }; + + matchConfig = mkOption { + default = {}; + example = { Name = "eth0"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [Match] section of the unit. See + systemd.link5 + systemd.netdev5 + systemd.network5 + for details. + ''; + }; + + }; + + linkOptions = commonNetworkOptions // { + + linkConfig = mkOption { + default = {}; + example = { MACAddress = "00:ff:ee:aa:cc:dd"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [Link] section of the unit. See + systemd.link + 5 for details. + ''; + }; + + }; + + netdevOptions = commonNetworkOptions // { + + netdevConfig = mkOption { + default = {}; + example = { Name = "mybridge"; Kind = "bridge"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [Netdev] section of the unit. See + systemd.netdev + 5 for details. + ''; + }; + + vlanConfig = mkOption { + default = {}; + example = { Id = "4"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [VLAN] section of the unit. See + systemd.netdev + 5 for details. + ''; + }; + + macvlanConfig = mkOption { + default = {}; + example = { Mode = "private"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [MACVLAN] section of the unit. See + systemd.netdev + 5 for details. + ''; + }; + + vxlanConfig = mkOption { + default = {}; + example = { Id = "4"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [VXLAN] section of the unit. See + systemd.netdev + 5 for details. + ''; + }; + + tunnelConfig = mkOption { + default = {}; + example = { Remote = "192.168.1.1"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [Tunnel] section of the unit. See + systemd.netdev + 5 for details. + ''; + }; + + peerConfig = mkOption { + default = {}; + example = { Name = "veth2"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [Peer] section of the unit. See + systemd.netdev + 5 for details. + ''; + }; + + tunConfig = mkOption { + default = {}; + example = { User = "openvpn"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [Tun] section of the unit. See + systemd.netdev + 5 for details. + ''; + }; + + tapConfig = mkOption { + default = {}; + example = { User = "openvpn"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [Tap] section of the unit. See + systemd.netdev + 5 for details. + ''; + }; + + bondConfig = mkOption { + default = {}; + example = { Mode = "802.3ad"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [Bond] section of the unit. See + systemd.netdev + 5 for details. + ''; + }; + + }; + + addressOptions = { + + addressConfig = mkOption { + default = {}; + example = { Address = "192.168.0.100/24"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [Address] section of the unit. See + systemd.network + 5 for details. + ''; + }; + + }; + + routeOptions = { + + routeConfig = mkOption { + default = {}; + example = { Gateway = "192.168.0.1"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [Route] section of the unit. See + systemd.network + 5 for details. + ''; + }; + + }; + + networkOptions = commonNetworkOptions // { + + networkConfig = mkOption { + default = {}; + example = { Description = "My Network"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [Network] section of the unit. See + systemd.network + 5 for details. + ''; + }; + + dhcpConfig = mkOption { + default = {}; + example = { UseDNS = true; UseRoutes = true; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + [DHCP] section of the unit. See + systemd.network + 5 for details. + ''; + }; + + address = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of addresses to be added to the network section of the + unit. See systemd.network + 5 for details. + ''; + }; + + gateway = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of gateways to be added to the network section of the + unit. See systemd.network + 5 for details. + ''; + }; + + dns = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of dns servers to be added to the network section of the + unit. See systemd.network + 5 for details. + ''; + }; + + ntp = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of ntp servers to be added to the network section of the + unit. See systemd.network + 5 for details. + ''; + }; + + vlan = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of vlan interfaces to be added to the network section of the + unit. See systemd.network + 5 for details. + ''; + }; + + macvlan = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of macvlan interfaces to be added to the network section of the + unit. See systemd.network + 5 for details. + ''; + }; + + vxlan = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of vxlan interfaces to be added to the network section of the + unit. See systemd.network + 5 for details. + ''; + }; + + tunnel = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of tunnel interfaces to be added to the network section of the + unit. See systemd.network + 5 for details. + ''; + }; + + addresses = mkOption { + default = [ ]; + type = types.listOf types.optionSet; + options = [ addressOptions ]; + description = '' + A list of address sections to be added to the unit. See + systemd.network + 5 for details. + ''; + }; + + routes = mkOption { + default = [ ]; + type = types.listOf types.optionSet; + options = [ routeOptions ]; + description = '' + A list of route sections to be added to the unit. See + systemd.network + 5 for details. + ''; + }; + + }; + } diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 8a86149a9e1..a24edf2b191 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -96,6 +96,9 @@ let "systemd-modules-load.service" "kmod-static-nodes.service" + # Networking + "systemd-networkd.service" + # Filesystems. "systemd-fsck@.service" "systemd-fsck-root.service" @@ -384,6 +387,103 @@ let ''; }; + commonMatchText = def: '' + [Match] + ${attrsToSection def.matchConfig} + ''; + + linkToUnit = name: def: + { inherit (def) enable; + text = commonMatchText def + + '' + [Link] + ${attrsToSection def.linkConfig} + ''; + }; + + netdevToUnit = name: def: + { inherit (def) enable; + text = commonMatchText def + + '' + [NetDev] + ${attrsToSection def.netdevConfig} + + ${optionalString (def.vlanConfig != { }) '' + [VLAN] + ${attrsToSection def.vlanConfig} + + ''} + ${optionalString (def.macvlanConfig != { }) '' + [MACVLAN] + ${attrsToSection def.macvlanConfig} + + ''} + ${optionalString (def.vxlanConfig != { }) '' + [VXLAN] + ${attrsToSection def.vxlanConfig} + + ''} + ${optionalString (def.tunnelConfig != { }) '' + [Tunnel] + ${attrsToSection def.tunnelConfig} + + ''} + ${optionalString (def.peerConfig != { }) '' + [Peer] + ${attrsToSection def.peerConfig} + + ''} + ${optionalString (def.tunConfig != { }) '' + [Tun] + ${attrsToSection def.tunConfig} + + ''} + ${optionalString (def.tapConfig != { }) '' + [Tap] + ${attrsToSection def.tapConfig} + + ''} + ${optionalString (def.bondConfig != { }) '' + [Bond] + ${attrsToSection def.bondConfig} + + ''} + ''; + }; + + networkToUnit = name: def: + { inherit (def) enable; + text = commonMatchText def + + '' + [Network] + ${attrsToSection def.networkConfig} + ${concatStringsSep "\n" (map (s: "Address=${s}") def.address)} + ${concatStringsSep "\n" (map (s: "Gateway=${s}") def.gateway)} + ${concatStringsSep "\n" (map (s: "DNS=${s}") def.dns)} + ${concatStringsSep "\n" (map (s: "NTP=${s}") def.ntp)} + ${concatStringsSep "\n" (map (s: "VLAN=${s}") def.vlan)} + ${concatStringsSep "\n" (map (s: "MACVLAN=${s}") def.macvlan)} + ${concatStringsSep "\n" (map (s: "VXLAN=${s}") def.vxlan)} + ${concatStringsSep "\n" (map (s: "Tunnel=${s}") def.tunnel)} + + ${optionalString (def.dhcpConfig != { }) '' + [DHCP] + ${attrsToSection def.dhcpConfig} + + ''} + ${flip concatMapStrings def.addresses (x: '' + [Address] + ${attrsToSection x.addressConfig} + + '')} + ${flip concatMapStrings def.routes (x: '' + [Route] + ${attrsToSection x.routeConfig} + + '')} + ''; + }; + generateUnits = type: units: upstreamUnits: upstreamWants: pkgs.runCommand "${type}-units" { preferLocalBuild = true; } '' mkdir -p $out @@ -562,6 +662,47 @@ in ''; }; + systemd.network.enable = mkOption { + default = false; + type = types.bool; + description = '' + Whether to enable networkd or not. + ''; + }; + + systemd.network.links = mkOption { + default = {}; + type = types.attrsOf types.optionSet; + options = [ linkOptions ]; + description = "Definiton of systemd network links."; + }; + + systemd.network.netdevs = mkOption { + default = {}; + type = types.attrsOf types.optionSet; + options = [ netdevOptions ]; + description = "Definiton of systemd network devices."; + }; + + systemd.network.networks = mkOption { + default = {}; + type = types.attrsOf types.optionSet; + options = [ networkOptions ]; + description = "Definiton of systemd networks."; + }; + + systemd.network.units = mkOption { + description = "Definition of networkd units."; + default = {}; + type = types.attrsOf types.optionSet; + options = { name, config, ... }: + { options = concreteUnitOptions; + config = { + unit = mkDefault (makeUnit name config); + }; + }; + }; + systemd.defaultUnit = mkOption { default = "multi-user.target"; type = types.str; @@ -714,6 +855,9 @@ in environment.etc."systemd/system".source = generateUnits "system" cfg.units upstreamSystemUnits upstreamSystemWants; + environment.etc."systemd/network".source = + generateUnits "network" cfg.network.units [] []; + environment.etc."systemd/user".source = generateUnits "user" cfg.user.units upstreamUserUnits []; @@ -779,6 +923,11 @@ in (v: let n = escapeSystemdPath v.where; in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts); + systemd.network.units = + mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.network.links + // mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.network.netdevs + // mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.network.networks; + systemd.user.units = mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.user.services // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.user.sockets; @@ -800,6 +949,14 @@ in users.extraUsers.systemd-journal-gateway.uid = config.ids.uids.systemd-journal-gateway; users.extraGroups.systemd-journal-gateway.gid = config.ids.gids.systemd-journal-gateway; + # Networkd + users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network; + users.extraGroups.systemd-network.gid = config.ids.gids.systemd-network; + systemd.services.systemd-networkd.wantedBy = + optional config.systemd.network.enable "multi-user.target"; + systemd.services.systemd-networkd.restartTriggers = + [ config.environment.etc."systemd/network".source ]; + # Generate timer units for all services that have a ‘startAt’ value. systemd.timers = mapAttrs (name: service: