nixpkgs/nixos/tests/ipv6.nix
Silvan Mosberger 4f0dadbf38 treewide: format all inactive Nix files
After final improvements to the official formatter implementation,
this commit now performs the first treewide reformat of Nix files using it.
This is part of the implementation of RFC 166.

Only "inactive" files are reformatted, meaning only files that
aren't being touched by any PR with activity in the past 2 months.
This is to avoid conflicts for PRs that might soon be merged.
Later we can do a full treewide reformat to get the rest,
which should not cause as many conflicts.

A CI check has already been running for some time to ensure that new and
already-formatted files are formatted, so the files being reformatted here
should also stay formatted.

This commit was automatically created and can be verified using

    nix-build a08b3a4d19.tar.gz \
      --argstr baseRev b32a094368
    result/bin/apply-formatting $NIXPKGS_PATH
2024-12-10 20:26:33 +01:00

134 lines
5.0 KiB
Nix

# Test of IPv6 functionality in NixOS, including whether router
# solicication/advertisement using radvd works.
import ./make-test-python.nix (
{ pkgs, lib, ... }:
{
name = "ipv6";
meta = with pkgs.lib.maintainers; {
maintainers = [ ];
};
nodes = {
# We use lib.mkForce here to remove the interface configuration
# provided by makeTest, so that the interfaces are all configured
# implicitly.
# This client should use privacy extensions fully, having a
# completely-default network configuration.
client_defaults.networking.interfaces = lib.mkForce { };
# Both of these clients should obtain temporary addresses, but
# not use them as the default source IP. We thus run the same
# checks against them — but the configuration resulting in this
# behaviour is different.
# Here, by using an altered default value for the global setting...
client_global_setting = {
networking.interfaces = lib.mkForce { };
networking.tempAddresses = "enabled";
};
# and here, by setting this on the interface explicitly.
client_interface_setting = {
networking.tempAddresses = "disabled";
networking.interfaces = lib.mkForce {
eth1.tempAddress = "enabled";
};
};
server = {
services.httpd.enable = true;
services.httpd.adminAddr = "foo@example.org";
networking.firewall.allowedTCPPorts = [ 80 ];
# disable testing driver's default IPv6 address.
networking.interfaces.eth1.ipv6.addresses = lib.mkForce [ ];
};
router =
{ ... }:
{
services.radvd.enable = true;
services.radvd.config = ''
interface eth1 {
AdvSendAdvert on;
# ULA prefix (RFC 4193).
prefix fd60:cc69:b537:1::/64 { };
};
'';
};
};
testScript = ''
import re
# Start the router first so that it respond to router solicitations.
router.wait_for_unit("radvd")
clients = [client_defaults, client_global_setting, client_interface_setting]
start_all()
for client in clients:
client.wait_for_unit("network.target")
server.wait_for_unit("network.target")
server.wait_for_unit("httpd.service")
# Wait until the given interface has a non-tentative address of
# the desired scope (i.e. has completed Duplicate Address
# Detection).
def wait_for_address(machine, iface, scope, temporary=False):
temporary_flag = "temporary" if temporary else "-temporary"
cmd = f"ip -o -6 addr show dev {iface} scope {scope} -tentative {temporary_flag}"
machine.wait_until_succeeds(f"[ `{cmd} | wc -l` -eq 1 ]")
output = machine.succeed(cmd)
ip = re.search(r"inet6 ([0-9a-f:]{2,})/", output).group(1)
if temporary:
scope = scope + " temporary"
machine.log(f"{scope} address on {iface} is {ip}")
return ip
with subtest("Loopback address can be pinged"):
client_defaults.succeed("ping -c 1 ::1 >&2")
client_defaults.fail("ping -c 1 2001:db8:: >&2")
with subtest("Local link addresses can be obtained and pinged"):
for client in clients:
client_ip = wait_for_address(client, "eth1", "link")
server_ip = wait_for_address(server, "eth1", "link")
client.succeed(f"ping -c 1 {client_ip}%eth1 >&2")
client.succeed(f"ping -c 1 {server_ip}%eth1 >&2")
with subtest("Global addresses can be obtained, pinged, and reached via http"):
for client in clients:
client_ip = wait_for_address(client, "eth1", "global")
server_ip = wait_for_address(server, "eth1", "global")
client.succeed(f"ping -c 1 {client_ip} >&2")
client.succeed(f"ping -c 1 {server_ip} >&2")
client.succeed(f"curl --fail -g http://[{server_ip}]")
client.fail(f"curl --fail -g http://[{client_ip}]")
with subtest(
"Privacy extensions: Global temporary address is used as default source address"
):
ip = wait_for_address(client_defaults, "eth1", "global", temporary=True)
# Default route should have "src <temporary address>" in it
client_defaults.succeed(f"ip route get 2001:db8:: | grep 'src {ip}'")
for client, setting_desc in (
(client_global_setting, "global"),
(client_interface_setting, "interface"),
):
with subtest(f'Privacy extensions: "enabled" through {setting_desc} setting)'):
# We should be obtaining both a temporary address and an EUI-64 address...
ip = wait_for_address(client, "eth1", "global")
assert "ff:fe" in ip
ip_temp = wait_for_address(client, "eth1", "global", temporary=True)
# But using the EUI-64 one.
client.succeed(f"ip route get 2001:db8:: | grep 'src {ip}'")
'';
}
)