From c4fd7cf16d531b09c6178294f5cdaaaa2bc55b01 Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Fri, 17 May 2024 18:21:52 +0200 Subject: [PATCH 1/2] nixos/networkd: get rid of *Config attributes in lists This patch is about removing `wireguardPeerConfig`, `dhcpServerStaticLeaseConfig` - a.k.a. the AbstractSingletonProxyFactoryBean of nixpkgs - and friends. As a former colleague said > worst abstraction ever I second that. I've written enough networkd config for NixOS systems so far to have a strong dislike. In fact, these don't even make sense: `netdevs.wireguardPeers._.wireguardPeerConfig` will be rendered into the key `[WireGuardPeer]` and every key from `wireguardPeerConfig` is in there. Since it's INI, there's no place where sections on the same level as wireguardPeerConfig fit into. Hence, get rid of it all. For the transition, using the old way is still allowed, but gives a warning. I think we could drop this after one release. The tests of rosenpass and systemd-networkd-dhcpserver-static-leases were broken on the rev before, hence they were updated, but are still not building. --- nixos/lib/systemd-lib.nix | 24 ++ nixos/lib/systemd-network-units.nix | 22 +- .../modules/services/networking/rosenpass.nix | 4 +- nixos/modules/system/boot/networkd.nix | 245 ++++-------------- .../tasks/network-interfaces-systemd.nix | 120 +++++---- nixos/tests/clatd.nix | 4 +- nixos/tests/rosenpass.nix | 14 +- ...temd-networkd-dhcpserver-static-leases.nix | 6 +- nixos/tests/systemd-networkd-dhcpserver.nix | 6 +- ...ystemd-networkd-ipv6-prefix-delegation.nix | 2 +- nixos/tests/systemd-networkd-vrf.nix | 4 +- nixos/tests/systemd-networkd.nix | 18 +- nixos/tests/tayga.nix | 4 +- 13 files changed, 171 insertions(+), 302 deletions(-) diff --git a/nixos/lib/systemd-lib.nix b/nixos/lib/systemd-lib.nix index 0641da8e7751..dac5cc7b700c 100644 --- a/nixos/lib/systemd-lib.nix +++ b/nixos/lib/systemd-lib.nix @@ -182,6 +182,30 @@ in rec { in if errors == [] then true else trace (concatStringsSep "\n" errors) false; + checkUnitConfigWithLegacyKey = legacyKey: group: checks: attrs: + let + dump = lib.generators.toPretty { } + (lib.generators.withRecursion { depthLimit = 2; throwOnDepthLimit = false; } attrs); + attrs' = + if legacyKey == null + then attrs + else if ! attrs?${legacyKey} + then attrs + else if removeAttrs attrs [ legacyKey ] == {} + then attrs.${legacyKey} + else throw '' + The declaration + + ${dump} + + must not mix unit options with the legacy key '${legacyKey}'. + + This can be fixed by moving all settings from within ${legacyKey} + one level up. + ''; + in + checkUnitConfig group checks attrs'; + toOption = x: if x == true then "true" else if x == false then "false" diff --git a/nixos/lib/systemd-network-units.nix b/nixos/lib/systemd-network-units.nix index ae581495772a..d15485240bd0 100644 --- a/nixos/lib/systemd-network-units.nix +++ b/nixos/lib/systemd-network-units.nix @@ -63,13 +63,13 @@ in { ${attrsToSection def.l2tpConfig} '' + flip concatMapStrings def.l2tpSessions (x: '' [L2TPSession] - ${attrsToSection x.l2tpSessionConfig} + ${attrsToSection x} '') + optionalString (def.wireguardConfig != { }) '' [WireGuard] ${attrsToSection def.wireguardConfig} '' + flip concatMapStrings def.wireguardPeers (x: '' [WireGuardPeer] - ${attrsToSection x.wireguardPeerConfig} + ${attrsToSection x} '') + optionalString (def.bondConfig != { }) '' [Bond] ${attrsToSection def.bondConfig} @@ -122,13 +122,13 @@ in { ${concatStringsSep "\n" (map (s: "Xfrm=${s}") def.xfrm)} '' + "\n" + flip concatMapStrings def.addresses (x: '' [Address] - ${attrsToSection x.addressConfig} + ${attrsToSection x} '') + flip concatMapStrings def.routingPolicyRules (x: '' [RoutingPolicyRule] - ${attrsToSection x.routingPolicyRuleConfig} + ${attrsToSection x} '') + flip concatMapStrings def.routes (x: '' [Route] - ${attrsToSection x.routeConfig} + ${attrsToSection x} '') + optionalString (def.dhcpV4Config != { }) '' [DHCPv4] ${attrsToSection def.dhcpV4Config} @@ -149,22 +149,22 @@ in { ${attrsToSection def.ipv6SendRAConfig} '' + flip concatMapStrings def.ipv6Prefixes (x: '' [IPv6Prefix] - ${attrsToSection x.ipv6PrefixConfig} + ${attrsToSection x} '') + flip concatMapStrings def.ipv6RoutePrefixes (x: '' [IPv6RoutePrefix] - ${attrsToSection x.ipv6RoutePrefixConfig} + ${attrsToSection x} '') + flip concatMapStrings def.dhcpServerStaticLeases (x: '' [DHCPServerStaticLease] - ${attrsToSection x.dhcpServerStaticLeaseConfig} + ${attrsToSection x} '') + optionalString (def.bridgeConfig != { }) '' [Bridge] ${attrsToSection def.bridgeConfig} '' + flip concatMapStrings def.bridgeFDBs (x: '' [BridgeFDB] - ${attrsToSection x.bridgeFDBConfig} + ${attrsToSection x} '') + flip concatMapStrings def.bridgeMDBs (x: '' [BridgeMDB] - ${attrsToSection x.bridgeMDBConfig} + ${attrsToSection x} '') + optionalString (def.lldpConfig != { }) '' [LLDP] ${attrsToSection def.lldpConfig} @@ -251,7 +251,7 @@ in { ${attrsToSection def.quickFairQueueingConfigClass} '' + flip concatMapStrings def.bridgeVLANs (x: '' [BridgeVLAN] - ${attrsToSection x.bridgeVLANConfig} + ${attrsToSection x} '') + def.extraConfig; } diff --git a/nixos/modules/services/networking/rosenpass.nix b/nixos/modules/services/networking/rosenpass.nix index 373a6c769079..ff45b9d64eed 100644 --- a/nixos/modules/services/networking/rosenpass.nix +++ b/nixos/modules/services/networking/rosenpass.nix @@ -130,8 +130,8 @@ in relevant = config.systemd.network.enable; root = config.systemd.network.netdevs; peer = (x: x.wireguardPeers); - key = (x: if x.wireguardPeerConfig ? PublicKey then x.wireguardPeerConfig.PublicKey else null); - description = "${options.systemd.network.netdevs}.\"\".wireguardPeers.*.wireguardPeerConfig.PublicKey"; + key = x: x.PublicKey or null; + description = "${options.systemd.network.netdevs}.\"\".wireguardPeers.*.PublicKey"; } { relevant = config.networking.wireguard.enable; diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index 7f53efbf83f5..79d76a8caa94 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -386,7 +386,7 @@ let (assertValueOneOf "UDP6ZeroChecksumRx" boolValues) ]; - sectionL2TPSession = checkUnitConfig "L2TPSession" [ + sectionL2TPSession = checkUnitConfigWithLegacyKey "l2tpSessionConfig" "L2TPSession" [ (assertOnlyFields [ "Name" "SessionId" @@ -421,7 +421,7 @@ let # NOTE The PresharedKey directive is missing on purpose here, please # do not add it to this list. The nix store is world-readable,let's # refrain ourselves from providing a footgun. - sectionWireGuardPeer = checkUnitConfig "WireGuardPeer" [ + sectionWireGuardPeer = checkUnitConfigWithLegacyKey "wireguardPeerConfig" "WireGuardPeer" [ (assertOnlyFields [ "PublicKey" "PresharedKeyFile" @@ -712,7 +712,7 @@ let (assertValueOneOf "KeepConfiguration" (boolValues ++ ["static" "dhcp-on-stop" "dhcp"])) ]; - sectionAddress = checkUnitConfig "Address" [ + sectionAddress = checkUnitConfigWithLegacyKey "addressConfig" "Address" [ (assertOnlyFields [ "Address" "Peer" @@ -737,7 +737,7 @@ let (assertValueOneOf "AutoJoin" boolValues) ]; - sectionRoutingPolicyRule = checkUnitConfig "RoutingPolicyRule" [ + sectionRoutingPolicyRule = checkUnitConfigWithLegacyKey "routingPolicyRuleConfig" "RoutingPolicyRule" [ (assertOnlyFields [ "TypeOfService" "From" @@ -772,7 +772,7 @@ let (assertRange "SuppressInterfaceGroup" 0 2147483647) ]; - sectionRoute = checkUnitConfig "Route" [ + sectionRoute = checkUnitConfigWithLegacyKey "routeConfig" "Route" [ (assertOnlyFields [ "Gateway" "GatewayOnLink" @@ -1033,7 +1033,7 @@ let (assertValueOneOf "EmitDomains" boolValues) ]; - sectionIPv6Prefix = checkUnitConfig "IPv6Prefix" [ + sectionIPv6Prefix = checkUnitConfigWithLegacyKey "ipv6PrefixConfig" "IPv6Prefix" [ (assertOnlyFields [ "AddressAutoconfiguration" "OnLink" @@ -1048,7 +1048,7 @@ let (assertValueOneOf "Assign" boolValues) ]; - sectionIPv6RoutePrefix = checkUnitConfig "IPv6RoutePrefix" [ + sectionIPv6RoutePrefix = checkUnitConfigWithLegacyKey "ipv6RoutePrefixConfig" "IPv6RoutePrefix" [ (assertOnlyFields [ "Route" "LifetimeSec" @@ -1057,7 +1057,7 @@ let (assertInt "LifetimeSec") ]; - sectionDHCPServerStaticLease = checkUnitConfig "DHCPServerStaticLease" [ + sectionDHCPServerStaticLease = checkUnitConfigWithLegacyKey "dhcpServerStaticLeaseConfig" "DHCPServerStaticLease" [ (assertOnlyFields [ "MACAddress" "Address" @@ -1104,7 +1104,7 @@ let (assertRange "Priority" 0 63) ]; - sectionBridgeFDB = checkUnitConfig "BridgeFDB" [ + sectionBridgeFDB = checkUnitConfigWithLegacyKey "bridgeFDBConfig" "BridgeFDB" [ (assertOnlyFields [ "MACAddress" "Destination" @@ -1121,7 +1121,7 @@ let (assertValueOneOf "AssociatedWith" [ "use" "self" "master" "router" ]) ]; - sectionBridgeMDB = checkUnitConfig "BridgeMDB" [ + sectionBridgeMDB = checkUnitConfigWithLegacyKey "bridgeMDBConfig" "BridgeMDB" [ (assertOnlyFields [ "MulticastGroupAddress" "VLANId" @@ -1524,7 +1524,7 @@ let (assertRange "Weight" 1 1023) ]; - sectionBridgeVLAN = checkUnitConfig "BridgeVLAN" [ + sectionBridgeVLAN = checkUnitConfigWithLegacyKey "bridgeVLANConfig" "BridgeVLAN" [ (assertOnlyFields [ "VLAN" "EgressUntagged" @@ -1627,34 +1627,21 @@ let }; - - l2tpSessionOptions = { - options = { - l2tpSessionConfig = mkOption { - default = {}; - type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionL2TPSession; - description = '' - Each attribute in this set specifies an option in the - `[L2TPSession]` section of the unit. See - {manpage}`systemd.netdev(5)` for details. - ''; - }; + mkSubsectionType = oldKey: checkF: + let + type = types.addCheck (types.attrsOf unitOption) checkF; + in type // { + merge = loc: defs: + let + final = type.merge loc defs; + in + if final?${oldKey} + then warn + "Using '${oldKey}' is deprecated! Move all attributes inside one level up and remove it." + final.${oldKey} + else + final; }; - }; - - wireguardPeerOptions = { - options = { - wireguardPeerConfig = mkOption { - default = {}; - type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionWireGuardPeer; - description = '' - Each attribute in this set specifies an option in the - `[WireGuardPeer]` section of the unit. See - {manpage}`systemd.netdev(5)` for details. - ''; - }; - }; - }; netdevOptions = commonNetworkOptions // { @@ -1805,12 +1792,12 @@ let l2tpSessions = mkOption { default = []; - example = [ { l2tpSessionConfig={ + example = [ { SessionId = 25; PeerSessionId = 26; Name = "l2tp-sess"; - };}]; - type = with types; listOf (submodule l2tpSessionOptions); + }]; + type = types.listOf (mkSubsectionType "l2tpSessionConfig" check.netdev.sectionL2TPSession); description = '' Each item in this array specifies an option in the `[L2TPSession]` section of the unit. See @@ -1838,14 +1825,14 @@ let wireguardPeers = mkOption { default = []; - example = [ { wireguardPeerConfig={ + example = [ { Endpoint = "192.168.1.1:51820"; PublicKey = "27s0OvaBBdHoJYkH9osZpjpgSOVNw+RaKfboT/Sfq0g="; PresharedKeyFile = "/etc/wireguard/psk.key"; AllowedIPs = [ "10.0.0.1/32" ]; PersistentKeepalive = 15; - };}]; - type = with types; listOf (submodule wireguardPeerOptions); + } ]; + type = types.listOf (mkSubsectionType "wireguardPeerConfig" check.netdev.sectionWireGuardPeer); description = '' Each item in this array specifies an option in the `[WireGuardPeer]` section of the unit. See @@ -1917,143 +1904,6 @@ let }; - addressOptions = { - options = { - addressConfig = mkOption { - example = { Address = "192.168.0.100/24"; }; - type = types.addCheck (types.attrsOf unitOption) check.network.sectionAddress; - description = '' - Each attribute in this set specifies an option in the - `[Address]` section of the unit. See - {manpage}`systemd.network(5)` for details. - ''; - }; - }; - }; - - routingPolicyRulesOptions = { - options = { - routingPolicyRuleConfig = mkOption { - default = { }; - example = { Table = 10; IncomingInterface = "eth1"; Family = "both"; }; - type = types.addCheck (types.attrsOf unitOption) check.network.sectionRoutingPolicyRule; - description = '' - Each attribute in this set specifies an option in the - `[RoutingPolicyRule]` section of the unit. See - {manpage}`systemd.network(5)` for details. - ''; - }; - }; - }; - - routeOptions = { - options = { - routeConfig = mkOption { - default = {}; - example = { Gateway = "192.168.0.1"; }; - type = types.addCheck (types.attrsOf unitOption) check.network.sectionRoute; - description = '' - Each attribute in this set specifies an option in the - `[Route]` section of the unit. See - {manpage}`systemd.network(5)` for details. - ''; - }; - }; - }; - - ipv6PrefixOptions = { - options = { - ipv6PrefixConfig = mkOption { - default = {}; - example = { Prefix = "fd00::/64"; }; - type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6Prefix; - description = '' - Each attribute in this set specifies an option in the - `[IPv6Prefix]` section of the unit. See - {manpage}`systemd.network(5)` for details. - ''; - }; - }; - }; - - ipv6RoutePrefixOptions = { - options = { - ipv6RoutePrefixConfig = mkOption { - default = {}; - example = { Route = "fd00::/64"; }; - type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6RoutePrefix; - description = '' - Each attribute in this set specifies an option in the - `[IPv6RoutePrefix]` section of the unit. See - {manpage}`systemd.network(5)` for details. - ''; - }; - }; - }; - - dhcpServerStaticLeaseOptions = { - options = { - dhcpServerStaticLeaseConfig = mkOption { - default = {}; - example = { MACAddress = "65:43:4a:5b:d8:5f"; Address = "192.168.1.42"; }; - type = types.addCheck (types.attrsOf unitOption) check.network.sectionDHCPServerStaticLease; - description = '' - Each attribute in this set specifies an option in the - `[DHCPServerStaticLease]` section of the unit. See - {manpage}`systemd.network(5)` for details. - - Make sure to configure the corresponding client interface to use - `ClientIdentifier=mac`. - ''; - }; - }; - }; - - bridgeFDBOptions = { - options = { - bridgeFDBConfig = mkOption { - default = {}; - example = { MACAddress = "65:43:4a:5b:d8:5f"; Destination = "192.168.1.42"; VNI = 20; }; - type = types.addCheck (types.attrsOf unitOption) check.network.sectionBridgeFDB; - description = '' - Each attribute in this set specifies an option in the - `[BridgeFDB]` section of the unit. See - {manpage}`systemd.network(5)` for details. - ''; - }; - }; - }; - - bridgeMDBOptions = { - options = { - bridgeMDBConfig = mkOption { - default = {}; - example = { MulticastGroupAddress = "ff02::1:2:3:4"; VLANId = 10; }; - type = types.addCheck (types.attrsOf unitOption) check.network.sectionBridgeMDB; - description = '' - Each attribute in this set specifies an option in the - `[BridgeMDB]` section of the unit. See - {manpage}`systemd.network(5)` for details. - ''; - }; - }; - }; - - bridgeVLANOptions = { - options = { - bridgeVLANConfig = mkOption { - default = {}; - example = { VLAN = 20; }; - type = types.addCheck (types.attrsOf unitOption) check.network.sectionBridgeVLAN; - description = '' - Each attribute in this set specifies an option in the - `[BridgeVLAN]` section of the unit. See - {manpage}`systemd.network(5)` for details. - ''; - }; - }; - }; - networkOptions = commonNetworkOptions // { linkConfig = mkOption { @@ -2165,8 +2015,8 @@ let dhcpServerStaticLeases = mkOption { default = []; - example = [ { dhcpServerStaticLeaseConfig = { MACAddress = "65:43:4a:5b:d8:5f"; Address = "192.168.1.42"; }; } ]; - type = with types; listOf (submodule dhcpServerStaticLeaseOptions); + example = [ { MACAddress = "65:43:4a:5b:d8:5f"; Address = "192.168.1.42"; } ]; + type = types.listOf (mkSubsectionType "dhcpServerStaticLeaseConfig" check.network.sectionDHCPServerStaticLease); description = '' A list of DHCPServerStaticLease sections to be added to the unit. See {manpage}`systemd.network(5)` for details. @@ -2175,8 +2025,8 @@ let ipv6Prefixes = mkOption { default = []; - example = [ { ipv6PrefixConfig = { AddressAutoconfiguration = true; OnLink = true; }; } ]; - type = with types; listOf (submodule ipv6PrefixOptions); + example = [ { AddressAutoconfiguration = true; OnLink = true; } ]; + type = types.listOf (mkSubsectionType "ipv6PrefixConfig" check.network.sectionIPv6Prefix); description = '' A list of ipv6Prefix sections to be added to the unit. See {manpage}`systemd.network(5)` for details. @@ -2185,8 +2035,8 @@ let ipv6RoutePrefixes = mkOption { default = []; - example = [ { ipv6RoutePrefixConfig = { Route = "fd00::/64"; LifetimeSec = 3600; }; } ]; - type = with types; listOf (submodule ipv6RoutePrefixOptions); + example = [ { Route = "fd00::/64"; LifetimeSec = 3600; } ]; + type = types.listOf (mkSubsectionType "ipv6RoutePrefixConfig" check.network.sectionIPv6RoutePrefix); description = '' A list of ipv6RoutePrefix sections to be added to the unit. See {manpage}`systemd.network(5)` for details. @@ -2206,8 +2056,8 @@ let bridgeFDBs = mkOption { default = []; - example = [ { bridgeFDBConfig = { MACAddress = "90:e2:ba:43:fc:71"; Destination = "192.168.100.4"; VNI = 3600; }; } ]; - type = with types; listOf (submodule bridgeFDBOptions); + example = [ { MACAddress = "90:e2:ba:43:fc:71"; Destination = "192.168.100.4"; VNI = 3600; } ]; + type = types.listOf (mkSubsectionType "bridgeFDBConfig" check.network.sectionBridgeFDB); description = '' A list of BridgeFDB sections to be added to the unit. See {manpage}`systemd.network(5)` for details. @@ -2216,8 +2066,8 @@ let bridgeMDBs = mkOption { default = []; - example = [ { bridgeMDBConfig = { MulticastGroupAddress = "ff02::1:2:3:4"; VLANId = 10; } ; } ]; - type = with types; listOf (submodule bridgeMDBOptions); + example = [ { MulticastGroupAddress = "ff02::1:2:3:4"; VLANId = 10; } ]; + type = types.listOf (mkSubsectionType "bridgeMDBConfig" check.network.sectionBridgeMDB); description = '' A list of BridgeMDB sections to be added to the unit. See {manpage}`systemd.network(5)` for details. @@ -2534,8 +2384,8 @@ let bridgeVLANs = mkOption { default = []; - example = [ { bridgeVLANConfig = { VLAN = "10-20"; }; } ]; - type = with types; listOf (submodule bridgeVLANOptions); + example = [ { VLAN = "10-20"; } ]; + type = types.listOf (mkSubsectionType "bridgeVLANConfig" check.network.sectionBridgeVLAN); description = '' A list of BridgeVLAN sections to be added to the unit. See {manpage}`systemd.network(5)` for details. @@ -2685,7 +2535,8 @@ let addresses = mkOption { default = [ ]; - type = with types; listOf (submodule addressOptions); + example = [ { Address = "192.168.0.100/24"; } ]; + type = types.listOf (mkSubsectionType "addressConfig" check.network.sectionAddress); description = '' A list of address sections to be added to the unit. See {manpage}`systemd.network(5)` for details. @@ -2694,7 +2545,8 @@ let routingPolicyRules = mkOption { default = [ ]; - type = with types; listOf (submodule routingPolicyRulesOptions); + example = [ { Table = 10; IncomingInterface = "eth1"; Family = "both"; } ]; + type = types.listOf (mkSubsectionType "routingPolicyRuleConfig" check.network.sectionRoutingPolicyRule); description = '' A list of routing policy rules sections to be added to the unit. See {manpage}`systemd.network(5)` for details. @@ -2703,7 +2555,8 @@ let routes = mkOption { default = [ ]; - type = with types; listOf (submodule routeOptions); + example = [ { Gateway = "192.168.0.1"; } ]; + type = types.listOf (mkSubsectionType "routeConfig" check.network.sectionRoute); description = '' A list of route sections to be added to the unit. See {manpage}`systemd.network(5)` for details. diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix index 2009c9a7e6e2..4bb0cd1857d2 100644 --- a/nixos/modules/tasks/network-interfaces-systemd.nix +++ b/nixos/modules/tasks/network-interfaces-systemd.nix @@ -32,13 +32,13 @@ let optionalAttrs (gateway != null && gateway.interface != null) { networks."40-${gateway.interface}" = { matchConfig.Name = gateway.interface; - routes = [{ - routeConfig = { + routes = [ + ({ Gateway = gateway.address; } // optionalAttrs (gateway.metric != null) { Metric = gateway.metric; - }; - }]; + }) + ]; }; } )); @@ -95,65 +95,63 @@ let address = forEach (interfaceIps i) (ip: "${ip.address}/${toString ip.prefixLength}"); routes = forEach (interfaceRoutes i) - (route: { + (route: # Most of these route options have not been tested. # Please fix or report any mistakes you may find. - routeConfig = - optionalAttrs (route.address != null && route.prefixLength != null) { - Destination = "${route.address}/${toString route.prefixLength}"; - } // - optionalAttrs (route.options ? fastopen_no_cookie) { - FastOpenNoCookie = route.options.fastopen_no_cookie; - } // - optionalAttrs (route.via != null) { - Gateway = route.via; - } // - optionalAttrs (route.type != null) { - Type = route.type; - } // - optionalAttrs (route.options ? onlink) { - GatewayOnLink = true; - } // - optionalAttrs (route.options ? initrwnd) { - InitialAdvertisedReceiveWindow = route.options.initrwnd; - } // - optionalAttrs (route.options ? initcwnd) { - InitialCongestionWindow = route.options.initcwnd; - } // - optionalAttrs (route.options ? pref) { - IPv6Preference = route.options.pref; - } // - optionalAttrs (route.options ? mtu) { - MTUBytes = route.options.mtu; - } // - optionalAttrs (route.options ? metric) { - Metric = route.options.metric; - } // - optionalAttrs (route.options ? src) { - PreferredSource = route.options.src; - } // - optionalAttrs (route.options ? protocol) { - Protocol = route.options.protocol; - } // - optionalAttrs (route.options ? quickack) { - QuickAck = route.options.quickack; - } // - optionalAttrs (route.options ? scope) { - Scope = route.options.scope; - } // - optionalAttrs (route.options ? from) { - Source = route.options.from; - } // - optionalAttrs (route.options ? table) { - Table = route.options.table; - } // - optionalAttrs (route.options ? advmss) { - TCPAdvertisedMaximumSegmentSize = route.options.advmss; - } // - optionalAttrs (route.options ? ttl-propagate) { - TTLPropagate = route.options.ttl-propagate == "enabled"; - }; - }); + optionalAttrs (route.address != null && route.prefixLength != null) { + Destination = "${route.address}/${toString route.prefixLength}"; + } // + optionalAttrs (route.options ? fastopen_no_cookie) { + FastOpenNoCookie = route.options.fastopen_no_cookie; + } // + optionalAttrs (route.via != null) { + Gateway = route.via; + } // + optionalAttrs (route.type != null) { + Type = route.type; + } // + optionalAttrs (route.options ? onlink) { + GatewayOnLink = true; + } // + optionalAttrs (route.options ? initrwnd) { + InitialAdvertisedReceiveWindow = route.options.initrwnd; + } // + optionalAttrs (route.options ? initcwnd) { + InitialCongestionWindow = route.options.initcwnd; + } // + optionalAttrs (route.options ? pref) { + IPv6Preference = route.options.pref; + } // + optionalAttrs (route.options ? mtu) { + MTUBytes = route.options.mtu; + } // + optionalAttrs (route.options ? metric) { + Metric = route.options.metric; + } // + optionalAttrs (route.options ? src) { + PreferredSource = route.options.src; + } // + optionalAttrs (route.options ? protocol) { + Protocol = route.options.protocol; + } // + optionalAttrs (route.options ? quickack) { + QuickAck = route.options.quickack; + } // + optionalAttrs (route.options ? scope) { + Scope = route.options.scope; + } // + optionalAttrs (route.options ? from) { + Source = route.options.from; + } // + optionalAttrs (route.options ? table) { + Table = route.options.table; + } // + optionalAttrs (route.options ? advmss) { + TCPAdvertisedMaximumSegmentSize = route.options.advmss; + } // + optionalAttrs (route.options ? ttl-propagate) { + TTLPropagate = route.options.ttl-propagate == "enabled"; + }); networkConfig.IPv6PrivacyExtensions = "kernel"; linkConfig = optionalAttrs (i.macAddress != null) { MACAddress = i.macAddress; diff --git a/nixos/tests/clatd.nix b/nixos/tests/clatd.nix index 00021d87ba5f..f4d2242ce54f 100644 --- a/nixos/tests/clatd.nix +++ b/nixos/tests/clatd.nix @@ -59,7 +59,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: "100.64.0.2/24" ]; routes = [ - { routeConfig = { Destination = "192.0.2.0/24"; Gateway = "100.64.0.1"; }; } + { Destination = "192.0.2.0/24"; Gateway = "100.64.0.1"; } ]; }; }; @@ -149,7 +149,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: "2001:db8::2/64" ]; routes = [ - { routeConfig = { Destination = "::/0"; Gateway = "2001:db8::1"; }; } + { Destination = "::/0"; Gateway = "2001:db8::1"; } ]; }; }; diff --git a/nixos/tests/rosenpass.nix b/nixos/tests/rosenpass.nix index ec4046c8c035..8765fd201c0e 100644 --- a/nixos/tests/rosenpass.nix +++ b/nixos/tests/rosenpass.nix @@ -74,10 +74,8 @@ in wireguardConfig.ListenPort = server.wg.listen; wireguardPeers = [ { - wireguardPeerConfig = { - AllowedIPs = [ "::/0" ]; - PublicKey = client.wg.public; - }; + AllowedIPs = [ "::/0" ]; + PublicKey = client.wg.public; } ]; }; @@ -97,11 +95,9 @@ in systemd.network.netdevs."10-${deviceName}".wireguardPeers = [ { - wireguardPeerConfig = { - AllowedIPs = [ "::/0" ]; - PublicKey = server.wg.public; - Endpoint = "server:${builtins.toString server.wg.listen}"; - }; + AllowedIPs = [ "::/0" ]; + PublicKey = server.wg.public; + Endpoint = "server:${builtins.toString server.wg.listen}"; } ]; diff --git a/nixos/tests/systemd-networkd-dhcpserver-static-leases.nix b/nixos/tests/systemd-networkd-dhcpserver-static-leases.nix index f6d5411aa5ca..2ff074b18cf4 100644 --- a/nixos/tests/systemd-networkd-dhcpserver-static-leases.nix +++ b/nixos/tests/systemd-networkd-dhcpserver-static-leases.nix @@ -28,10 +28,8 @@ import ./make-test-python.nix ({ lib, ... }: { Address = "10.0.0.1/24"; }; dhcpServerStaticLeases = [{ - dhcpServerStaticLeaseConfig = { - MACAddress = "02:de:ad:be:ef:01"; - Address = "10.0.0.10"; - }; + MACAddress = "02:de:ad:be:ef:01"; + Address = "10.0.0.10"; }]; }; }; diff --git a/nixos/tests/systemd-networkd-dhcpserver.nix b/nixos/tests/systemd-networkd-dhcpserver.nix index 665d8b5a0529..fda0c9d64193 100644 --- a/nixos/tests/systemd-networkd-dhcpserver.nix +++ b/nixos/tests/systemd-networkd-dhcpserver.nix @@ -54,7 +54,7 @@ import ./make-test-python.nix ({pkgs, ...}: { name = "eth1"; networkConfig.Bridge = "br0"; bridgeVLANs = [ - { bridgeVLANConfig = { PVID = 2; EgressUntagged = 2; }; } + { PVID = 2; EgressUntagged = 2; } ]; }; "02-br0" = { @@ -69,8 +69,8 @@ import ./make-test-python.nix ({pkgs, ...}: { PoolSize = 1; }; bridgeVLANs = [ - { bridgeVLANConfig = { PVID = 1; EgressUntagged = 1; }; } - { bridgeVLANConfig = { VLAN = 2; }; } + { PVID = 1; EgressUntagged = 1; } + { VLAN = 2; } ]; }; "02-vlan2" = { diff --git a/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix b/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix index 1e55341657bd..83c81f63d012 100644 --- a/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix +++ b/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix @@ -258,7 +258,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { "01-lo" = { name = "lo"; addresses = [ - { addressConfig.Address = "FD42::1/128"; } + { Address = "FD42::1/128"; } ]; }; }; diff --git a/nixos/tests/systemd-networkd-vrf.nix b/nixos/tests/systemd-networkd-vrf.nix index d4227526a30d..4f2a45577c16 100644 --- a/nixos/tests/systemd-networkd-vrf.nix +++ b/nixos/tests/systemd-networkd-vrf.nix @@ -59,14 +59,14 @@ in { matchConfig.Name = "vrf1"; networkConfig.IPForward = "yes"; routes = [ - { routeConfig = { Destination = "192.168.1.2"; Metric = 100; }; } + { Destination = "192.168.1.2"; Metric = 100; } ]; }; networks."10-vrf2" = { matchConfig.Name = "vrf2"; networkConfig.IPForward = "yes"; routes = [ - { routeConfig = { Destination = "192.168.2.3"; Metric = 100; }; } + { Destination = "192.168.2.3"; Metric = 100; } ]; }; diff --git a/nixos/tests/systemd-networkd.nix b/nixos/tests/systemd-networkd.nix index 6b241b93d511..44ad713cd6df 100644 --- a/nixos/tests/systemd-networkd.nix +++ b/nixos/tests/systemd-networkd.nix @@ -23,13 +23,13 @@ let generateNodeConf = { lib, pkgs, config, privk, pubk, peerId, nodeId, ...}: { ListenPort = 51820; FirewallMark = 42; }; - wireguardPeers = [ {wireguardPeerConfig={ + wireguardPeers = [ { Endpoint = "192.168.1.${peerId}:51820"; PublicKey = pubk; PresharedKeyFile = pkgs.writeText "psk.key" "yTL3sCOL33Wzi6yCnf9uZQl/Z8laSE+zwpqOHC4HhFU="; AllowedIPs = [ "10.0.0.${peerId}/32" ]; PersistentKeepalive = 15; - };}]; + } ]; }; }; networks = { @@ -41,8 +41,8 @@ let generateNodeConf = { lib, pkgs, config, privk, pubk, peerId, nodeId, ...}: { matchConfig = { Name = "wg0"; }; address = [ "10.0.0.${nodeId}/32" ]; routes = [ - { routeConfig = { Gateway = "10.0.0.${nodeId}"; Destination = "10.0.0.0/24"; }; } - { routeConfig = { Gateway = "10.0.0.${nodeId}"; Destination = "10.0.0.0/24"; Table = "custom"; }; } + { Gateway = "10.0.0.${nodeId}"; Destination = "10.0.0.0/24"; } + { Gateway = "10.0.0.${nodeId}"; Destination = "10.0.0.0/24"; Table = "custom"; } ]; }; "30-eth1" = { @@ -52,11 +52,11 @@ let generateNodeConf = { lib, pkgs, config, privk, pubk, peerId, nodeId, ...}: { "fe80::${nodeId}/64" ]; routingPolicyRules = [ - { routingPolicyRuleConfig = { Table = 10; IncomingInterface = "eth1"; Family = "both"; };} - { routingPolicyRuleConfig = { Table = 20; OutgoingInterface = "eth1"; };} - { routingPolicyRuleConfig = { Table = 30; From = "192.168.1.1"; To = "192.168.1.2"; SourcePort = 666 ; DestinationPort = 667; };} - { routingPolicyRuleConfig = { Table = 40; IPProtocol = "tcp"; InvertRule = true; };} - { routingPolicyRuleConfig = { Table = 50; IncomingInterface = "eth1"; Family = "ipv4"; };} + { Table = 10; IncomingInterface = "eth1"; Family = "both"; } + { Table = 20; OutgoingInterface = "eth1"; } + { Table = 30; From = "192.168.1.1"; To = "192.168.1.2"; SourcePort = 666 ; DestinationPort = 667; } + { Table = 40; IPProtocol = "tcp"; InvertRule = true; } + { Table = 50; IncomingInterface = "eth1"; Family = "ipv4"; } ]; }; }; diff --git a/nixos/tests/tayga.nix b/nixos/tests/tayga.nix index 204391d1312f..e3c57b7d58fe 100644 --- a/nixos/tests/tayga.nix +++ b/nixos/tests/tayga.nix @@ -55,7 +55,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: "100.64.0.2/24" ]; routes = [ - { routeConfig = { Destination = "192.0.2.0/24"; Gateway = "100.64.0.1"; }; } + { Destination = "192.0.2.0/24"; Gateway = "100.64.0.1"; } ]; }; }; @@ -202,7 +202,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: "2001:db8::2/64" ]; routes = [ - { routeConfig = { Destination = "64:ff9b::/96"; Gateway = "2001:db8::1"; }; } + { Destination = "64:ff9b::/96"; Gateway = "2001:db8::1"; } ]; }; }; From f9f943b36eb1f9f13b23a177fc6f8bc40071534b Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Mon, 20 May 2024 17:30:21 +0200 Subject: [PATCH 2/2] nixos/networking: use optionalAttrs -> mkIf for networkd route generation Suggested in https://github.com/NixOS/nixpkgs/pull/312472#discussion_r1605894882 --- .../tasks/network-interfaces-systemd.nix | 75 ++++++++++--------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix index 4bb0cd1857d2..c1241d11de87 100644 --- a/nixos/modules/tasks/network-interfaces-systemd.nix +++ b/nixos/modules/tasks/network-interfaces-systemd.nix @@ -95,63 +95,64 @@ let address = forEach (interfaceIps i) (ip: "${ip.address}/${toString ip.prefixLength}"); routes = forEach (interfaceRoutes i) - (route: + (route: mkMerge [ # Most of these route options have not been tested. # Please fix or report any mistakes you may find. - optionalAttrs (route.address != null && route.prefixLength != null) { + (mkIf (route.address != null && route.prefixLength != null) { Destination = "${route.address}/${toString route.prefixLength}"; - } // - optionalAttrs (route.options ? fastopen_no_cookie) { + }) + (mkIf (route.options ? fastopen_no_cookie) { FastOpenNoCookie = route.options.fastopen_no_cookie; - } // - optionalAttrs (route.via != null) { + }) + (mkIf (route.via != null) { Gateway = route.via; - } // - optionalAttrs (route.type != null) { + }) + (mkIf (route.type != null) { Type = route.type; - } // - optionalAttrs (route.options ? onlink) { + }) + (mkIf (route.options ? onlink) { GatewayOnLink = true; - } // - optionalAttrs (route.options ? initrwnd) { + }) + (mkIf (route.options ? initrwnd) { InitialAdvertisedReceiveWindow = route.options.initrwnd; - } // - optionalAttrs (route.options ? initcwnd) { + }) + (mkIf (route.options ? initcwnd) { InitialCongestionWindow = route.options.initcwnd; - } // - optionalAttrs (route.options ? pref) { + }) + (mkIf (route.options ? pref) { IPv6Preference = route.options.pref; - } // - optionalAttrs (route.options ? mtu) { + }) + (mkIf (route.options ? mtu) { MTUBytes = route.options.mtu; - } // - optionalAttrs (route.options ? metric) { + }) + (mkIf (route.options ? metric) { Metric = route.options.metric; - } // - optionalAttrs (route.options ? src) { + }) + (mkIf (route.options ? src) { PreferredSource = route.options.src; - } // - optionalAttrs (route.options ? protocol) { + }) + (mkIf (route.options ? protocol) { Protocol = route.options.protocol; - } // - optionalAttrs (route.options ? quickack) { + }) + (mkIf (route.options ? quickack) { QuickAck = route.options.quickack; - } // - optionalAttrs (route.options ? scope) { + }) + (mkIf (route.options ? scope) { Scope = route.options.scope; - } // - optionalAttrs (route.options ? from) { + }) + (mkIf (route.options ? from) { Source = route.options.from; - } // - optionalAttrs (route.options ? table) { + }) + (mkIf (route.options ? table) { Table = route.options.table; - } // - optionalAttrs (route.options ? advmss) { + }) + (mkIf (route.options ? advmss) { TCPAdvertisedMaximumSegmentSize = route.options.advmss; - } // - optionalAttrs (route.options ? ttl-propagate) { + }) + (mkIf (route.options ? ttl-propagate) { TTLPropagate = route.options.ttl-propagate == "enabled"; - }); + }) + ]); networkConfig.IPv6PrivacyExtensions = "kernel"; linkConfig = optionalAttrs (i.macAddress != null) { MACAddress = i.macAddress;