nixos/testing: Add ipv6 configuration

This contribution enables a working IPv6 setup by default. This works
analog to the current automatic IPv4 setup.
This commit is contained in:
Frédéric Christ 2024-06-12 13:24:42 +02:00
parent f322e8f25c
commit c6f6c28218
13 changed files with 84 additions and 43 deletions

View File

@ -224,6 +224,8 @@
- [`lib.options.mkPackageOptionMD`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.options.mkPackageOptionMD) is now obsolete; use the identical [`lib.options.mkPackageOption`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.options.mkPackageOption) instead. - [`lib.options.mkPackageOptionMD`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.options.mkPackageOptionMD) is now obsolete; use the identical [`lib.options.mkPackageOption`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.options.mkPackageOption) instead.
- `nixosTests` now provide a working IPv6 setup for VLAN 1 by default.
- To facilitate dependency injection, the `imgui` package now builds a static archive using vcpkg' CMake rules. - To facilitate dependency injection, the `imgui` package now builds a static archive using vcpkg' CMake rules.
The derivation now installs "impl" headers selectively instead of by a wildcard. The derivation now installs "impl" headers selectively instead of by a wildcard.
Use `imgui.src` if you just want to access the unpacked sources. Use `imgui.src` if you just want to access the unpacked sources.

View File

@ -32,10 +32,19 @@ let
# Automatically assign IP addresses to requested interfaces. # Automatically assign IP addresses to requested interfaces.
assignIPs = lib.filter (i: i.assignIP) interfaces; assignIPs = lib.filter (i: i.assignIP) interfaces;
ipInterfaces = forEach assignIPs (i: ipInterfaces = forEach assignIPs (i:
nameValuePair i.name { ipv4.addresses = nameValuePair i.name {
[ { address = "192.168.${toString i.vlan}.${toString config.virtualisation.test.nodeNumber}"; ipv4.addresses = [
{
address = "192.168.${toString i.vlan}.${toString config.virtualisation.test.nodeNumber}";
prefixLength = 24; prefixLength = 24;
}]; }
];
ipv6.addresses = [
{
address = "2001:db8:${toString i.vlan}::${toString config.virtualisation.test.nodeNumber}";
prefixLength = 64;
}
];
}); });
qemuOptions = lib.flatten (forEach interfacesNumbered ({ fst, snd }: qemuOptions = lib.flatten (forEach interfacesNumbered ({ fst, snd }:
@ -53,6 +62,9 @@ let
networking.primaryIPAddress = networking.primaryIPAddress =
optionalString (ipInterfaces != [ ]) (head (head ipInterfaces).value.ipv4.addresses).address; optionalString (ipInterfaces != [ ]) (head (head ipInterfaces).value.ipv4.addresses).address;
networking.primaryIPv6Address =
optionalString (ipInterfaces != [ ]) (head (head ipInterfaces).value.ipv6.addresses).address;
# Put the IP addresses of all VMs in this machine's # Put the IP addresses of all VMs in this machine's
# /etc/hosts file. If a machine has multiple # /etc/hosts file. If a machine has multiple
# interfaces, use the IP address corresponding to # interfaces, use the IP address corresponding to
@ -60,12 +72,16 @@ let
# virtualisation.vlans option). # virtualisation.vlans option).
networking.extraHosts = flip concatMapStrings (attrNames nodes) networking.extraHosts = flip concatMapStrings (attrNames nodes)
(m': (m':
let config = nodes.${m'}; in let
config = nodes.${m'};
hostnames =
optionalString (config.networking.domain != null) "${config.networking.hostName}.${config.networking.domain} " +
"${config.networking.hostName}\n";
in
optionalString (config.networking.primaryIPAddress != "") optionalString (config.networking.primaryIPAddress != "")
("${config.networking.primaryIPAddress} " + "${config.networking.primaryIPAddress} ${hostnames}" +
optionalString (config.networking.domain != null) optionalString (config.networking.primaryIPv6Address != "")
"${config.networking.hostName}.${config.networking.domain} " + ("${config.networking.primaryIPv6Address} ${hostnames}"));
"${config.networking.hostName}\n"));
virtualisation.qemu.options = qemuOptions; virtualisation.qemu.options = qemuOptions;
boot.initrd.services.udev.rules = concatMapStrings (x: x + "\n") udevRules; boot.initrd.services.udev.rules = concatMapStrings (x: x + "\n") udevRules;

View File

@ -665,6 +665,14 @@ in
description = "Primary IP address used in /etc/hosts."; 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 { virtualisation.host.pkgs = mkOption {
type = options.nixpkgs.pkgs.type; type = options.nixpkgs.pkgs.type;
default = pkgs; default = pkgs;

View File

@ -36,7 +36,7 @@ import ./make-test-python.nix ( { pkgs, nftables, ... } : {
}; };
testScript = { nodes, ... }: let testScript = { nodes, ... }: let
newSystem = nodes.walled2.config.system.build.toplevel; newSystem = nodes.walled2.system.build.toplevel;
unit = if nftables then "nftables" else "firewall"; unit = if nftables then "nftables" else "firewall";
in '' in ''
start_all() start_all()

View File

@ -39,6 +39,8 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
{ services.httpd.enable = true; { services.httpd.enable = true;
services.httpd.adminAddr = "foo@example.org"; services.httpd.adminAddr = "foo@example.org";
networking.firewall.allowedTCPPorts = [ 80 ]; networking.firewall.allowedTCPPorts = [ 80 ];
# disable testing driver's default IPv6 address.
networking.interfaces.eth1.ipv6.addresses = lib.mkForce [ ];
}; };
router = router =

View File

@ -59,7 +59,7 @@ import ./make-test-python.nix (
]; ];
portals = [ portals = [
{ {
ip_address = "0.0.0.0"; ip_address = "[::]";
iser = false; iser = false;
offload = false; offload = false;
port = 3260; port = 3260;
@ -93,7 +93,7 @@ import ./make-test-python.nix (
xfsprogs xfsprogs
]; ];
system.extraDependencies = [ nodes.initiatorRootDisk.config.system.build.toplevel ]; system.extraDependencies = [ nodes.initiatorRootDisk.system.build.toplevel ];
nix.settings = { nix.settings = {
substituters = lib.mkForce []; substituters = lib.mkForce [];
@ -108,7 +108,7 @@ import ./make-test-python.nix (
[ [
"boot.shell_on_fail" "boot.shell_on_fail"
"console=tty1" "console=tty1"
"ip=${config.networking.primaryIPAddress}:::255.255.255.0::ens9:none" "ip=${config.networking.primaryIPAddress}:::255.255.255.0::eth1:none"
] ]
); );

View File

@ -165,9 +165,12 @@ in
virtualisation.vlans = [ 1 ]; virtualisation.vlans = [ 1 ];
networking.interfaces.eth1.ipv6 = { networking.interfaces.eth1.ipv6 = {
addresses = [ { address = "2001:db8::8"; prefixLength = 96; } ]; addresses = lib.mkForce [ { address = "2001:db8::8"; prefixLength = 96; } ];
routes = [ { address = "64:ff9b::"; prefixLength = 96; routes = lib.mkForce [ {
via = "2001:db8::1"; } ]; address = "64:ff9b::";
prefixLength = 96;
via = "2001:db8::1";
} ];
}; };
}; };
@ -177,9 +180,12 @@ in
virtualisation.vlans = [ 1 ]; virtualisation.vlans = [ 1 ];
networking.interfaces.eth1.ipv6 = { networking.interfaces.eth1.ipv6 = {
addresses = [ { address = "2001:db8::9"; prefixLength = 96; } ]; addresses = lib.mkForce [ { address = "2001:db8::9"; prefixLength = 96; } ];
routes = [ { address = "64:ff9b::"; prefixLength = 96; routes = lib.mkForce [ {
via = "2001:db8::1"; } ]; address = "64:ff9b::";
prefixLength = 96;
via = "2001:db8::1";
} ];
}; };
}; };

View File

@ -30,15 +30,22 @@ import ./make-test-python.nix {
client = {}; client = {};
}; };
testScript = '' testScript = { nodes, ... }:
let
serverIP = nodes.server.networking.primaryIPAddress;
serverIPv6 = nodes.server.networking.primaryIPv6Address;
in
''
start_all() start_all()
server.wait_for_unit("mediatomb") server.wait_for_unit("mediatomb")
server.wait_until_succeeds("nc -z 192.168.1.2 49152") server.wait_until_succeeds("nc -z ${serverIP} 49152")
server.succeed("curl -v --fail http://server:49152/") server.succeed("curl -v --fail http://${serverIP}:49152/")
server.succeed("curl -v --fail http://[${serverIPv6}]:49152/")
client.wait_for_unit("multi-user.target") client.wait_for_unit("multi-user.target")
page = client.succeed("curl -v --fail http://server:49152/") page = client.succeed("curl -v --fail http://${serverIP}:49152/")
page = client.succeed("curl -v --fail http://[${serverIPv6}]:49152/")
assert "Gerbera" in page and "MediaTomb" not in page assert "Gerbera" in page and "MediaTomb" not in page
''; '';
} }

View File

@ -31,7 +31,7 @@ import ./make-test-python.nix ({ pkgs, lib, withFirewall, nftables ? false, ...
lib.mkMerge [ lib.mkMerge [
{ virtualisation.vlans = [ 1 ]; { virtualisation.vlans = [ 1 ];
networking.defaultGateway = networking.defaultGateway =
(pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ipv4.addresses).address; (pkgs.lib.head nodes.router.networking.interfaces.eth2.ipv4.addresses).address;
networking.nftables.enable = nftables; networking.nftables.enable = nftables;
} }
]; ];
@ -61,8 +61,8 @@ import ./make-test-python.nix ({ pkgs, lib, withFirewall, nftables ? false, ...
testScript = testScript =
{ nodes, ... }: let { nodes, ... }: let
routerDummyNoNatClosure = nodes.routerDummyNoNat.config.system.build.toplevel; routerDummyNoNatClosure = nodes.routerDummyNoNat.system.build.toplevel;
routerClosure = nodes.router.config.system.build.toplevel; routerClosure = nodes.router.system.build.toplevel;
in '' in ''
client.start() client.start()
router.start() router.start()
@ -72,13 +72,13 @@ import ./make-test-python.nix ({ pkgs, lib, withFirewall, nftables ? false, ...
server.wait_for_unit("network.target") server.wait_for_unit("network.target")
server.wait_for_unit("httpd") server.wait_for_unit("httpd")
router.wait_for_unit("network.target") router.wait_for_unit("network.target")
router.succeed("curl --fail http://server/ >&2") router.succeed("curl -4 --fail http://server/ >&2")
# The client should be also able to connect via the NAT router. # The client should be also able to connect via the NAT router.
router.wait_for_unit("${unit}") router.wait_for_unit("${unit}")
client.wait_for_unit("network.target") client.wait_for_unit("network.target")
client.succeed("curl --fail http://server/ >&2") client.succeed("curl --fail http://server/ >&2")
client.succeed("ping -c 1 server >&2") client.succeed("ping -4 -c 1 server >&2")
# Test whether passive FTP works. # Test whether passive FTP works.
server.wait_for_unit("vsftpd") server.wait_for_unit("vsftpd")
@ -89,15 +89,15 @@ import ./make-test-python.nix ({ pkgs, lib, withFirewall, nftables ? false, ...
client.fail("curl -v -P - ftp://server/foo.txt >&2") client.fail("curl -v -P - ftp://server/foo.txt >&2")
# Test ICMP. # Test ICMP.
client.succeed("ping -c 1 router >&2") client.succeed("ping -4 -c 1 router >&2")
router.succeed("ping -c 1 client >&2") router.succeed("ping -4 -c 1 client >&2")
# If we turn off NAT, the client shouldn't be able to reach the server. # If we turn off NAT, the client shouldn't be able to reach the server.
router.succeed( router.succeed(
"${routerDummyNoNatClosure}/bin/switch-to-configuration test 2>&1" "${routerDummyNoNatClosure}/bin/switch-to-configuration test 2>&1"
) )
client.fail("curl --fail --connect-timeout 5 http://server/ >&2") client.fail("curl -4 --fail --connect-timeout 5 http://server/ >&2")
client.fail("ping -c 1 server >&2") client.fail("ping -4 -c 1 server >&2")
# And make sure that reloading the NAT job works. # And make sure that reloading the NAT job works.
router.succeed( router.succeed(
@ -109,7 +109,7 @@ import ./make-test-python.nix ({ pkgs, lib, withFirewall, nftables ? false, ...
${lib.optionalString (!withFirewall && !nftables) '' ${lib.optionalString (!withFirewall && !nftables) ''
router.succeed("systemctl start nat.service") router.succeed("systemctl start nat.service")
''} ''}
client.succeed("curl --fail http://server/ >&2") client.succeed("curl -4 --fail http://server/ >&2")
client.succeed("ping -c 1 server >&2") client.succeed("ping -4 -c 1 server >&2")
''; '';
}) })

View File

@ -27,7 +27,7 @@ import ./make-test-python.nix ({ lib, ... }: {
with subtest("Bind subsystem to port"): with subtest("Bind subsystem to port"):
server.wait_for_unit("network-online.target") server.wait_for_unit("network-online.target")
server.succeed("nvmet port add 1 tcp 0.0.0.0:4420") server.succeed("nvmet port add 1 tcp [::]:4420")
server.succeed("nvmet port add-subsystem 1 ${subsystem}") server.succeed("nvmet port add-subsystem 1 ${subsystem}")
with subtest("Discover and connect to available subsystems"): with subtest("Discover and connect to available subsystems"):

View File

@ -16,7 +16,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
{ config, pkgs, ... }: { { config, pkgs, ... }: {
services.step-ca = { services.step-ca = {
enable = true; enable = true;
address = "0.0.0.0"; address = "[::]";
port = 8443; port = 8443;
openFirewall = true; openFirewall = true;
intermediatePasswordFile = "${test-certificates}/intermediate-password-file"; intermediatePasswordFile = "${test-certificates}/intermediate-password-file";

View File

@ -133,7 +133,7 @@ let
enable = true; enable = true;
dbBackend = backend; dbBackend = backend;
config = { config = {
rocketAddress = "0.0.0.0"; rocketAddress = "::";
rocketPort = 8080; rocketPort = 8080;
}; };
}; };

View File

@ -49,7 +49,7 @@ in
settings = { settings = {
server = { server = {
interface = [ "0.0.0.0" "::" ]; interface = [ "0.0.0.0" "::" ];
access-control = [ "192.168.1.0/24 allow" ]; access-control = [ "192.168.0.0/24 allow" "::/0 allow" ];
domain-insecure = "local"; domain-insecure = "local";
private-domain = "local"; private-domain = "local";