about summary refs log tree commit diff
path: root/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix')
-rw-r--r--nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix332
1 files changed, 0 insertions, 332 deletions
diff --git a/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix b/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
deleted file mode 100644
index 6c056d9a1018..000000000000
--- a/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
+++ /dev/null
@@ -1,332 +0,0 @@
-# This test verifies that we can request and assign IPv6 prefixes from upstream
-# (e.g. ISP) routers.
-# The setup consists of three VMs. One for the ISP, as your residential router
-# and the third as a client machine in the residential network.
-#
-# There are two VLANs in this test:
-# - VLAN 1 is the connection between the ISP and the router
-# - VLAN 2 is the connection between the router and the client
-
-import ./make-test-python.nix ({ pkgs, lib, ... }: {
-  name = "systemd-networkd-ipv6-prefix-delegation";
-  meta = with lib.maintainers; {
-    maintainers = [ andir hexa ];
-  };
-  nodes = {
-
-    # The ISP's routers job is to delegate IPv6 prefixes via DHCPv6. Like with
-    # regular IPv6 auto-configuration it will also emit IPv6 router
-    # advertisements (RAs). Those RA's will not carry a prefix but in contrast
-    # just set the "Other" flag to indicate to the receiving nodes that they
-    # should attempt DHCPv6.
-    #
-    # Note: On the ISPs device we don't really care if we are using networkd in
-    # this example. That being said we can't use it (yet) as networkd doesn't
-    # implement the serving side of DHCPv6. We will use ISC Kea for that task.
-    isp = { lib, pkgs, ... }: {
-      virtualisation.vlans = [ 1 ];
-      networking = {
-        useDHCP = false;
-        firewall.enable = false;
-        interfaces.eth1 = lib.mkForce {}; # Don't use scripted networking
-      };
-
-      systemd.network = {
-        enable = true;
-
-        networks = {
-          "eth1" = {
-            matchConfig.Name = "eth1";
-            address = [
-              "2001:DB8::1/64"
-            ];
-            networkConfig.IPForward = true;
-          };
-        };
-      };
-
-      # Since we want to program the routes that we delegate to the "customer"
-      # into our routing table we must provide kea with the required capability.
-      systemd.services.kea-dhcp6-server.serviceConfig = {
-        AmbientCapabilities = [ "CAP_NET_ADMIN" ];
-        CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
-      };
-
-      services = {
-        # Configure the DHCPv6 server to hand out both IA_NA and IA_PD.
-        #
-        # We will hand out /48 prefixes from the subnet 2001:DB8:F000::/36.
-        # That gives us ~8k prefixes. That should be enough for this test.
-        #
-        # Since (usually) you will not receive a prefix with the router
-        # advertisements we also hand out /128 leases from the range
-        # 2001:DB8:0000:0000:FFFF::/112.
-        kea.dhcp6 = {
-          enable = true;
-          settings = {
-            interfaces-config.interfaces = [ "eth1" ];
-            subnet6 = [ {
-              id = 1;
-              interface = "eth1";
-              subnet = "2001:DB8::/32";
-              pd-pools = [ {
-                prefix = "2001:DB8:1000::";
-                prefix-len = 36;
-                delegated-len = 48;
-              } ];
-              pools = [ {
-                pool = "2001:DB8:0000:0000::-2001:DB8:0FFF:FFFF::FFFF";
-              } ];
-            } ];
-
-            # This is the glue between Kea and the Kernel FIB. DHCPv6
-            # rightfully has no concept of setting up a route in your
-            # FIB. This step really depends on your setup.
-            #
-            # In a production environment your DHCPv6 server is likely
-            # not the router. You might want to consider BGP, NETCONF
-            # calls, … in those cases.
-            #
-            # In this example we use the run script hook, that lets use
-            # execute anything and passes information via the environment.
-            # https://kea.readthedocs.io/en/kea-2.2.0/arm/hooks.html#run-script-run-script-support-for-external-hook-scripts
-            hooks-libraries = [ {
-              library = "${pkgs.kea}/lib/kea/hooks/libdhcp_run_script.so";
-              parameters = {
-                name = pkgs.writeShellScript "kea-run-hooks" ''
-                  export PATH="${lib.makeBinPath (with pkgs; [ coreutils iproute2 ])}"
-
-                  set -euxo pipefail
-
-                  leases6_committed() {
-                    for i in $(seq $LEASES6_SIZE); do
-                      idx=$((i-1))
-                      prefix_var="LEASES6_AT''${idx}_ADDRESS"
-                      plen_var="LEASES6_AT''${idx}_PREFIX_LEN"
-
-                      ip -6 route replace ''${!prefix_var}/''${!plen_var} via $QUERY6_REMOTE_ADDR dev $QUERY6_IFACE_NAME
-                    done
-                  }
-
-                  unknown_handler() {
-                    echo "Unhandled function call ''${*}"
-                    exit 123
-                  }
-
-                  case "$1" in
-                      "leases6_committed")
-                          leases6_committed
-                          ;;
-                      *)
-                          unknown_handler "''${@}"
-                          ;;
-                  esac
-                '';
-                sync = false;
-              };
-            } ];
-          };
-        };
-
-        # Finally we have to set up the router advertisements. While we could be
-        # using networkd or bird for this task `radvd` is probably the most
-        # venerable of them all. It was made explicitly for this purpose and
-        # the configuration is much more straightforward than what networkd
-        # requires.
-        # As outlined above we will have to set the `Managed` flag as otherwise
-        # the clients will not know if they should do DHCPv6. (Some do
-        # anyway/always)
-        radvd = {
-          enable = true;
-          config = ''
-            interface eth1 {
-              AdvSendAdvert on;
-              AdvManagedFlag on;
-              AdvOtherConfigFlag off; # we don't really have DNS or NTP or anything like that to distribute
-              prefix ::/64 {
-                AdvOnLink on;
-                AdvAutonomous on;
-              };
-            };
-          '';
-        };
-
-      };
-    };
-
-    # This will be our (residential) router that receives the IPv6 prefix (IA_PD)
-    # and /128 (IA_NA) allocation.
-    #
-    # Here we will actually start using networkd.
-    router = {
-      virtualisation.vlans = [ 1 2 ];
-      systemd.services.systemd-networkd.environment.SYSTEMD_LOG_LEVEL = "debug";
-
-      boot.kernel.sysctl = {
-        # we want to forward packets from the ISP to the client and back.
-        "net.ipv6.conf.all.forwarding" = 1;
-      };
-
-      networking = {
-        useNetworkd = true;
-        useDHCP = false;
-        # Consider enabling this in production and generating firewall rules
-        # for fowarding/input from the configured interfaces so you do not have
-        # to manage multiple places
-        firewall.enable = false;
-      };
-
-      systemd.network = {
-        networks = {
-          # systemd-networkd will load the first network unit file
-          # that matches, ordered lexiographically by filename.
-          # /etc/systemd/network/{40-eth1,99-main}.network already
-          # exists. This network unit must be loaded for the test,
-          # however, hence why this network is named such.
-
-          # Configuration of the interface to the ISP.
-          # We must request accept RAs and request the PD prefix.
-          "01-eth1" = {
-            name = "eth1";
-            networkConfig = {
-              Description = "ISP interface";
-              IPv6AcceptRA = true;
-              #DHCP = false; # no need for legacy IP
-            };
-            linkConfig = {
-              # We care about this interface when talking about being "online".
-              # If this interface is in the `routable` state we can reach
-              # others and they should be able to reach us.
-              RequiredForOnline = "routable";
-            };
-            # This configures the DHCPv6 client part towards the ISPs DHCPv6 server.
-            dhcpV6Config = {
-              # We have to include a request for a prefix in our DHCPv6 client
-              # request packets.
-              # Otherwise the upstream DHCPv6 server wouldn't know if we want a
-              # prefix or not.  Note: On some installation it makes sense to
-              # always force that option on the DHPCv6 server since there are
-              # certain CPEs that are just not setting this field but happily
-              # accept the delegated prefix.
-              PrefixDelegationHint  = "::/48";
-            };
-            ipv6SendRAConfig = {
-              # Let networkd know that we would very much like to use DHCPv6
-              # to obtain the "managed" information. Not sure why they can't
-              # just take that from the upstream RAs.
-              Managed = true;
-            };
-          };
-
-          # Interface to the client. Here we should redistribute a /64 from
-          # the prefix we received from the ISP.
-          "01-eth2" = {
-            name = "eth2";
-            networkConfig = {
-              Description = "Client interface";
-              # The client shouldn't be allowed to send us RAs, that would be weird.
-              IPv6AcceptRA = false;
-
-              # Delegate prefixes from the DHCPv6 PD pool.
-              DHCPPrefixDelegation = true;
-              IPv6SendRA = true;
-            };
-
-            # In a production environment you should consider setting these as well:
-            # ipv6SendRAConfig = {
-              #EmitDNS = true;
-              #EmitDomains = true;
-              #DNS= = "fe80::1"; # or whatever "well known" IP your router will have on the inside.
-            # };
-
-            # This adds a "random" ULA prefix to the interface that is being
-            # advertised to the clients.
-            # Not used in this test.
-            # ipv6Prefixes = [
-            #   {
-            #     ipv6PrefixConfig = {
-            #       AddressAutoconfiguration = true;
-            #       PreferredLifetimeSec = 1800;
-            #       ValidLifetimeSec = 1800;
-            #     };
-            #   }
-            # ];
-          };
-
-          # finally we are going to add a static IPv6 unique local address to
-          # the "lo" interface.  This will serve as ICMPv6 echo target to
-          # verify connectivity from the client to the router.
-          "01-lo" = {
-            name = "lo";
-            addresses = [
-              { Address = "FD42::1/128"; }
-            ];
-          };
-        };
-      };
-    };
-
-    # This is the client behind the router. We should be receiving router
-    # advertisements for both the ULA and the delegated prefix.
-    # All we have to do is boot with the default (networkd) configuration.
-    client = {
-      virtualisation.vlans = [ 2 ];
-      systemd.services.systemd-networkd.environment.SYSTEMD_LOG_LEVEL = "debug";
-      networking = {
-        useNetworkd = true;
-        useDHCP = false;
-      };
-    };
-  };
-
-  testScript = ''
-    # First start the router and wait for it it reach a state where we are
-    # certain networkd is up and it is able to send out RAs
-    router.start()
-    router.wait_for_unit("systemd-networkd.service")
-
-    # After that we can boot the client and wait for the network online target.
-    # Since we only care about IPv6 that should not involve waiting for legacy
-    # IP leases.
-    client.start()
-    client.systemctl("start network-online.target")
-    client.wait_for_unit("network-online.target")
-
-    # the static address on the router should not be reachable
-    client.wait_until_succeeds("ping -6 -c 1 FD42::1")
-
-    # the global IP of the ISP router should still not be a reachable
-    router.fail("ping -6 -c 1 2001:DB8::1")
-
-    # Once we have internal connectivity boot up the ISP
-    isp.start()
-
-    # Since for the ISP "being online" should have no real meaning we just
-    # wait for the target where all the units have been started.
-    # It probably still takes a few more seconds for all the RA timers to be
-    # fired etc..
-    isp.wait_for_unit("multi-user.target")
-
-    # wait until the uplink interface has a good status
-    router.systemctl("start network-online.target")
-    router.wait_for_unit("network-online.target")
-    router.wait_until_succeeds("ping -6 -c1 2001:DB8::1")
-
-    # shortly after that the client should have received it's global IPv6
-    # address and thus be able to ping the ISP
-    client.wait_until_succeeds("ping -6 -c1 2001:DB8::1")
-
-    # verify that we got a globally scoped address in eth1 from the
-    # documentation prefix
-    ip_output = client.succeed("ip --json -6 address show dev eth1")
-
-    import json
-
-    ip_json = json.loads(ip_output)[0]
-    assert any(
-        addr["local"].upper().startswith("2001:DB8:")
-        for addr in ip_json["addr_info"]
-        if addr["scope"] == "global"
-    )
-  '';
-})