Unverified Commit 4bd4976b authored by Will Fancher's avatar Will Fancher Committed by GitHub
Browse files

Merge pull request #251290 from Majiir/systemd-initrd-networking-features

nixos/network-interfaces-systemd: support `vlans`, `bridges` in systemd-initrd
parents 801e33f5 1f34babe
Loading
Loading
Loading
Loading
+38 −26
Original line number Diff line number Diff line
@@ -173,6 +173,33 @@ let
    }];
  }));

  bridgeNetworks = mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: {
    netdevs."40-${name}" = {
      netdevConfig = {
        Name = name;
        Kind = "bridge";
      };
    };
    networks = listToAttrs (forEach bridge.interfaces (bi:
      nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) {
        DHCP = mkOverride 0 (dhcpStr false);
        networkConfig.Bridge = name;
      } ])));
  }));

  vlanNetworks = mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: {
    netdevs."40-${name}" = {
      netdevConfig = {
        Name = name;
        Kind = "vlan";
      };
      vlanConfig.Id = vlan.id;
    };
    networks."40-${vlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) {
      vlan = [ name ];
    } ]);
  }));

in

{
@@ -182,7 +209,15 @@ in
    # Note this is if initrd.network.enable, not if
    # initrd.systemd.network.enable. By setting the latter and not the
    # former, the user retains full control over the configuration.
    boot.initrd.systemd.network = mkMerge [(genericDhcpNetworks true) interfaceNetworks];
    boot.initrd.systemd.network = mkMerge [
      (genericDhcpNetworks true)
      interfaceNetworks
      bridgeNetworks
      vlanNetworks
    ];
    boot.initrd.availableKernelModules =
      optional (cfg.bridges != {}) "bridge" ++
      optional (cfg.vlans != {}) "8021q";
  })

  (mkIf cfg.useNetworkd {
@@ -212,19 +247,7 @@ in
      }
      (genericDhcpNetworks false)
      interfaceNetworks
      (mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: {
        netdevs."40-${name}" = {
          netdevConfig = {
            Name = name;
            Kind = "bridge";
          };
        };
        networks = listToAttrs (forEach bridge.interfaces (bi:
          nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) {
            DHCP = mkOverride 0 (dhcpStr false);
            networkConfig.Bridge = name;
          } ])));
      })))
      bridgeNetworks
      (mkMerge (flip mapAttrsToList cfg.bonds (name: bond: {
        netdevs."40-${name}" = {
          netdevConfig = {
@@ -377,18 +400,7 @@ in
          } ]);
        };
      })))
      (mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: {
        netdevs."40-${name}" = {
          netdevConfig = {
            Name = name;
            Kind = "vlan";
          };
          vlanConfig.Id = vlan.id;
        };
        networks."40-${vlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) {
          vlan = [ name ];
        } ]);
      })))
      vlanNetworks
    ];

    # We need to prefill the slaved devices with networking options
+2 −0
Original line number Diff line number Diff line
@@ -764,6 +764,7 @@ in {
  systemd-cryptenroll = handleTest ./systemd-cryptenroll.nix {};
  systemd-credentials-tpm2 = handleTest ./systemd-credentials-tpm2.nix {};
  systemd-escaping = handleTest ./systemd-escaping.nix {};
  systemd-initrd-bridge = handleTest ./systemd-initrd-bridge.nix {};
  systemd-initrd-btrfs-raid = handleTest ./systemd-initrd-btrfs-raid.nix {};
  systemd-initrd-luks-fido2 = handleTest ./systemd-initrd-luks-fido2.nix {};
  systemd-initrd-luks-keyfile = handleTest ./systemd-initrd-luks-keyfile.nix {};
@@ -778,6 +779,7 @@ in {
  systemd-initrd-networkd = handleTest ./systemd-initrd-networkd.nix {};
  systemd-initrd-networkd-ssh = handleTest ./systemd-initrd-networkd-ssh.nix {};
  systemd-initrd-networkd-openvpn = handleTest ./initrd-network-openvpn { systemdStage1 = true; };
  systemd-initrd-vlan = handleTest ./systemd-initrd-vlan.nix {};
  systemd-journal = handleTest ./systemd-journal.nix {};
  systemd-machinectl = handleTest ./systemd-machinectl.nix {};
  systemd-networkd = handleTest ./systemd-networkd.nix {};
+63 −0
Original line number Diff line number Diff line
import ./make-test-python.nix ({ lib, ... }: {
  name = "systemd-initrd-bridge";
  meta.maintainers = [ lib.maintainers.majiir ];

  # Tests bridge interface configuration in systemd-initrd.
  #
  # The 'a' and 'b' nodes are connected to a 'bridge' node through different
  # links. The 'bridge' node configures a bridge across them. It waits forever
  # in initrd (stage 1) with networking enabled. 'a' and 'b' ping 'bridge' to
  # test connectivity with the bridge interface. Then, 'a' pings 'b' to test
  # the bridge itself.

  nodes = {
    bridge = { config, lib, ... }: {
      boot.initrd.systemd.enable = true;
      boot.initrd.network.enable = true;
      boot.initrd.systemd.services.boot-blocker = {
        before = [ "initrd.target" ];
        wantedBy = [ "initrd.target" ];
        script = "sleep infinity";
        serviceConfig.Type = "oneshot";
      };

      networking.primaryIPAddress = "192.168.1.${toString config.virtualisation.test.nodeNumber}";

      virtualisation.vlans = [ 1 2 ];
      networking.bridges.br0.interfaces = [ "eth1" "eth2" ];

      networking.interfaces = {
        eth1.ipv4.addresses = lib.mkForce [];
        eth2.ipv4.addresses = lib.mkForce [];
        br0.ipv4.addresses = [{
          address = config.networking.primaryIPAddress;
          prefixLength = 24;
        }];
      };
    };

    a = {
      virtualisation.vlans = [ 1 ];
    };

    b = { config, ... }: {
      virtualisation.vlans = [ 2 ];
      networking.primaryIPAddress = lib.mkForce "192.168.1.${toString config.virtualisation.test.nodeNumber}";
      networking.interfaces.eth1.ipv4.addresses = lib.mkForce [{
        address = config.networking.primaryIPAddress;
        prefixLength = 24;
      }];
    };
  };

  testScript = ''
    start_all()
    a.wait_for_unit("network.target")
    b.wait_for_unit("network.target")

    a.succeed("ping -n -w 10 -c 1 bridge >&2")
    b.succeed("ping -n -w 10 -c 1 bridge >&2")

    a.succeed("ping -n -w 10 -c 1 b >&2")
  '';
})
+59 −0
Original line number Diff line number Diff line
import ./make-test-python.nix ({ lib, ... }: {
  name = "systemd-initrd-vlan";
  meta.maintainers = [ lib.maintainers.majiir ];

  # Tests VLAN interface configuration in systemd-initrd.
  #
  # Two nodes are configured for a tagged VLAN. (Note that they also still have
  # their ordinary eth0 and eth1 interfaces, which are not VLAN-tagged.)
  #
  # The 'server' node waits forever in initrd (stage 1) with networking
  # enabled. The 'client' node pings it to test network connectivity.

  nodes = let
    network = id: {
      networking = {
        vlans."eth1.10" = {
          id = 10;
          interface = "eth1";
        };
        interfaces."eth1.10" = {
          ipv4.addresses = [{
            address = "192.168.10.${id}";
            prefixLength = 24;
          }];
        };
      };
    };
  in {
    # Node that will use initrd networking.
    server = network "1" // {
      boot.initrd.systemd.enable = true;
      boot.initrd.network.enable = true;
      boot.initrd.systemd.services.boot-blocker = {
        before = [ "initrd.target" ];
        wantedBy = [ "initrd.target" ];
        script = "sleep infinity";
        serviceConfig.Type = "oneshot";
      };
    };

    # Node that will ping the server.
    client = network "2";
  };

  testScript = ''
    start_all()
    client.wait_for_unit("network.target")

    # Wait for the regular (untagged) interface to be up.
    def server_is_up(_) -> bool:
        status, _ = client.execute("ping -n -c 1 server >&2")
        return status == 0
    with client.nested("waiting for server to come up"):
        retry(server_is_up)

    # Try to ping the (tagged) VLAN interface.
    client.succeed("ping -n -w 10 -c 1 192.168.10.1 >&2")
  '';
})