Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 22 additions & 20 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
# Software Components

| Test Name | Tested Software Components |
|-------------------------------------------|----------------------------|
| bgp-bird-tcpao | BIRD3 | <!-- Add FRR when TCP-AO is supported -->
| bgp-extended-nexthop | FRR, BIRD3 |
| bgp-frr-unnumbered | FRR | <!-- Add BIRD when unnumbered peerings are supported -->
| bgp-md5 | FRR, BIRD3 |
| bgp-prefsource | FRR, BIRD3 |
| bgp-simple | FRR, BIRD3, GoBGP |
| bgp-ttl-security | FRR, BIRD3 |
| dhcpv4 | Kea DHCP Server, dhclient | <!-- Extend by NetworkManager/systemd-networkd clients -->
| dns-knot | Knot DNS Server |
| dns-knot-dnssec | Knot DNS Server |
| dns-knot-xfr | Knot DNS Server |
| dns-knot-xfr-dnssec | Knot DNS Server |
| dns-knot-xfr-tsig | Knot DNS Server |
| dns-knot-xfr-tsig-explicit-notify | Knot DNS Server |
| ipsec-transport | strongswan |
| nat64-dns64 | Jool, BIND9 |
| ospf | FRR, BIRD3 |
| ping6-local-link | |
| Test Name | Tested Software Components |
|-------------------------------------------|---------------------------------------------------------------|
| bgp-bird-tcpao | BIRD3 | <!-- Add FRR when TCP-AO is supported -->
| bgp-extended-nexthop | FRR, BIRD3 |
| bgp-frr-unnumbered | FRR | <!-- Add BIRD when unnumbered peerings are supported -->
| bgp-md5 | FRR, BIRD3 |
| bgp-prefsource | FRR, BIRD3 |
| bgp-simple | FRR, BIRD3, GoBGP |
| bgp-ttl-security | FRR, BIRD3 |
| dhcpv4 | Kea DHCP Server, dhclient | <!-- Extend by NetworkManager/systemd-networkd clients -->
| dhcpv6 | Kea DHCP Server, radvd, dhclient, systemd-networkd, NetworkManager |
| dhcpv6-pd | Kea DHCP Server, radvd, systemd-networkd |
| dns-knot | Knot DNS Server |
| dns-knot-dnssec | Knot DNS Server |
| dns-knot-xfr | Knot DNS Server |
| dns-knot-xfr-dnssec | Knot DNS Server |
| dns-knot-xfr-tsig | Knot DNS Server |
| dns-knot-xfr-tsig-explicit-notify | Knot DNS Server |
| ipsec-transport | strongswan |
| nat64-dns64 | Jool, BIND9 |
| ospf | FRR, BIRD3 |
| ping6-local-link | |
172 changes: 172 additions & 0 deletions tests/dhcpv6-pd/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
{ pkgs, lib, ... }:
{
name = "dhcpv6-pd";

defaults = {
networking = {
firewall.enable = false;
useDHCP = lib.mkDefault false;
};
};

nodes = {
server = {
virtualisation.interfaces.eth1 = {
vlan = 1;
assignIP = false;
};

networking.interfaces.eth1.ipv6.addresses = [
{
address = "2001:db8::1";
prefixLength = 64;
}
];

boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = 1;

services = {
kea.dhcp6 = {
enable = true;
settings = {
interfaces-config.interfaces = [ "eth1" ];
hooks-libraries = [
{
library = "${pkgs.kea}/lib/kea/hooks/libdhcp_run_script.so";
parameters = {
name = pkgs.writeShellScript "kea-dhcpv6-pd-add-routes-hook.sh" (builtins.readFile ./hook.sh);
sync = false;
};
}
];
subnet6 = [
{
id = 1;
subnet = "2001:db8::/48";
interface = "eth1";
pools = [
{
pool = "2001:db8::100-2001:db8::1ff";
}
];
pd-pools = [
{
prefix = "2001:db8:0:1000::";
prefix-len = 52;
delegated-len = 56;
}
];
}
];

};
};
radvd = {
enable = true;
config = ''
interface eth1 {
AdvSendAdvert on;

# Tell clients to use DHCPv6
AdvManagedFlag on;
AdvOtherConfigFlag on;

prefix 2001:db8::/64 {
AdvOnLink on;

# Disable SLAAC, force DHCPv6
AdvAutonomous off;
};
};
'';
};
};
};
router = {
virtualisation.interfaces = {
eth1 = {
vlan = 1;
assignIP = false;
};
eth2 = {
vlan = 2;
assignIP = false;
};
};

boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = 1;

systemd.network = {
enable = true;
networks = {
"10-eth1" = {
matchConfig.Name = "eth1";
networkConfig = {
IPv6AcceptRA = true;
DHCP = "ipv6";
};
dhcpV6Config.PrefixDelegationHint = 56;
};
"20-eth2" = {
matchConfig.Name = "eth2";
networkConfig = {
IPv6SendRA = true;
DHCPPrefixDelegation = true;
};
dhcpPrefixDelegationConfig.UplinkInterface = "eth1";
};
};
};
};
client = {
virtualisation.interfaces.eth1 = {
vlan = 2;
assignIP = false;
};
networking.interfaces.eth1.ipv6.addresses = [ ];
};
};

interactive.nodes = lib.listToAttrs (
map
(name: {
inherit name;
value.environment.systemPackages = with pkgs; [
tcpdump
];
})
[
"server"
"router"
"client"
]
);

testScript = ''
start_all()

server.wait_for_unit("network.target")
server.wait_for_unit("radvd.service")
server.wait_for_unit("kea-dhcp6-server.service")

# Wait for IPv6 Duplicate Address Detection (DAD) to complete.
server.wait_until_succeeds("""
ip -j -6 a sh eth1 | \
${lib.getExe pkgs.jq} -e -r '.[] | .addr_info | .[] | select((.family == "inet6") and .scope == "link") | has("tentative") == false'
""")

server.succeed("systemctl restart kea-dhcp6-server")

router.wait_for_unit("systemd-networkd.service")

router.wait_until_succeeds("ip -6 -br a | grep -E 'eth1.*2001:db8::1[0-9a-f]{2}'", timeout=30)
router.succeed("ip -6 route show default dev eth1 | grep default")

router.succeed("ip -6 -br a | grep -E 'eth2.*2001:db8:0:1000:'")

client.succeed("ip -6 -br a | grep -E 'eth1.*2001:db8:0:1000:'")
client.succeed("ip -6 route show default dev eth1 | grep default")

client.succeed("ping -c 1 2001:db8::1")
'';
}
52 changes: 52 additions & 0 deletions tests/dhcpv6-pd/hook.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# https://kea.readthedocs.io/en/latest/arm/hooks.html#run-script-run-script-support-for-external-hook-scripts
# This script adds/removes IPv6 routes on prefix-delegation from KEA/DHCP server

lease6_renew () {
if [ "$LEASE6_TYPE" = "IA_PD" ]; then
# Add route for delegated prefix (next hop is the client)
ip -6 route replace "${LEASE6_ADDRESS}/${LEASE6_PREFIX_LEN}" via "${QUERY6_REMOTE_ADDR}" dev "${QUERY6_IFACE_NAME}" proto static
fi
exit 0

}

lease6_expire () {
if [ "$LEASE6_TYPE" = "IA_PD" ]; then
# Remove route for delegated prefix
ip -6 route del "${LEASE6_ADDRESS}/${LEASE6_PREFIX_LEN}" proto static
fi
exit 0
}

leases6_committed () {
# TODO: If i.e. addresses are also available via DHCP, there can be more than a single AT[index], so Loop 0..($LEASES6_SIZE-1)
# if [ "$LEASES6_AT0_TYPE" = "IA_NA" ]; then it's an address
if [ "$LEASES6_AT0_TYPE" = "IA_PD" ]; then
# Add route for delegated prefix (next hop is the client). Remote-addr (via) will typically be LinkLocal, unless KEA listens on Unicast
ip -6 route replace "${LEASES6_AT0_ADDRESS}/${LEASES6_AT0_PREFIX_LEN}" via "${QUERY6_REMOTE_ADDR}" dev "${QUERY6_IFACE_NAME}" proto static
fi
exit 0
}

lease6_release () {
if [ "$LEASE6_TYPE" = "IA_PD" ]; then
# Remove route for delegated prefix
ip -6 route del "${LEASE6_ADDRESS}/${LEASE6_PREFIX_LEN}" proto static
fi
exit 0
}

case "$1" in
"lease6_renew")
lease6_renew
;;
"lease6_expire")
lease6_expire
;;
"leases6_committed")
leases6_committed
;;
"lease6_release")
lease6_release
;;
esac
Loading
Loading