Skip to content

Instantly share code, notes, and snippets.

@lheckemann
Created April 22, 2021 15:27
Show Gist options
  • Save lheckemann/15cf1a6be26d442951cb0a09a0e50749 to your computer and use it in GitHub Desktop.
Save lheckemann/15cf1a6be26d442951cb0a09a0e50749 to your computer and use it in GitHub Desktop.
{ pkgs ? import <nixpkgs> {} }:
let
inherit (pkgs) lib;
defaults = {
options.networking.interfaces = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule {
useDHCP = false;
});
};
};
in pkgs.nixosTest {
name = "duplicated-routes";
nodes = {
client = { lib, ... }: {
imports = [defaults];
virtualisation.vlans = [1];
networking = {
useDHCP = false;
interfaces.eth1 = lib.mkForce {
tempAddress = "disabled";
ipv6.routes = [
# Intentionally bogus default route. This should be
# replaced by the route obtained via NDP, or prevent the
# route obtained from NDP from being added to the routing
# table. Instead, we get two entries in the routing table
# with the same destination and the same metric. When
# actual routing is taking place, the choice of which one
# is used seems to be arbitrary, but somewhat favour the
# NDP route.
{ address = "::"; prefixLength = 0; via = "fe80::5235"; }
];
};
};
};
router = { lib, ... }: {
imports = [defaults];
virtualisation.vlans = [1 2];
boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = true;
services.radvd = {
enable = true;
config = ''
interface eth1 {
AdvSendAdvert on;
prefix fd00::/64 {
AdvAutonomous on;
AdvOnLink on;
};
};
'';
};
networking = {
useDHCP = false;
interfaces = lib.mkForce {
eth1.ipv6.addresses = [
{ address = "fd00::"; prefixLength = 64; }
{ address = "fe80::1"; prefixLength = 64; }
];
eth2.ipv6.addresses = [
{ address = "2001:db8::"; prefixLength = 32; }
];
};
};
};
server = { lib, ... }: {
imports = [defaults];
virtualisation.vlans = [2];
networking.useDHCP = false;
networking.interfaces = lib.mkForce {
eth1.ipv6.addresses = [
{ address = "2001:db8::2"; prefixLength = 32; }
];
eth1.ipv6.routes = [
{ address = "fd00::"; prefixLength = 64; via = "2001:db8::";}
];
};
};
};
skipLint = true;
testScript = ''
start_all()
router.wait_for_unit("radvd.service")
client.wait_until_succeeds("ip -o a show scope global | grep inet6")
print(client.succeed("ip a"))
print(client.succeed("ip -6 r"))
for addr in "fe80::1%eth1 fd00:: 2001:db8::2".split():
client.wait_until_succeeds(f"ping -c 1 {addr}")
# 1200 pings * interval 0.1s + 5s of fudge = 125 seconds to send and receive all the pings
client.succeed(f"ping -c 1200 -i 0.1 -w 125 2001:db8::2")
'';
}
@mweinelt
Copy link

mweinelt commented Apr 26, 2021

Disable the firewall on the router or create a rule in the forward chain, that gets you a chunk further. The route selection is pretty stable here, it uses the proto ra default route.

client: must succeed: ip a
(0.02 seconds)
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
    altname enp0s3
    altname ens3
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:12:01:01 brd ff:ff:ff:ff:ff:ff
    inet6 fd00::5054:ff:fe12:101/64 scope global tentative dynamic mngtmpaddr
       valid_lft 86400sec preferred_lft 14400sec
    inet6 fe80::5054:ff:fe12:101/64 scope link
       valid_lft forever preferred_lft forever

client: must succeed: ip -6 r
(0.02 seconds)
::1 dev lo proto kernel metric 256 pref medium
fd00::/64 dev eth1 proto kernel metric 256 expires 86399sec pref medium
fe80::/64 dev eth1 proto kernel metric 256 pref medium
default via fe80::5235 dev eth1 proto static metric 1024 pref medium
default via fe80::1 dev eth1 proto ra metric 1024 expires 1799sec hoplimit 64 pref medium

client: waiting for success: ping -c 1 fe80::1%eth1
(0.07 seconds)
client: waiting for success: ping -c 1 fd00::
(0.03 seconds)
client: waiting for success: ping -c 1 2001:db8::2
(4.18 seconds)
client: must succeed: ip -6 route get 2001:db8::2
(0.02 seconds)
2001:db8::2 from :: via fe80::1 dev eth1 proto ra src fd00::5054:ff:fe12:101 metric 1024 hoplimit 64 pref medium

client: must succeed: ping -c 1200 -i 0.1 2001:db8::2
(121.11 seconds)
(136.81 seconds)
test script finished in 136.86s
cleaning up
killing client (pid 11)
killing router (pid 23)
killing server (pid 35)
(0.00 seconds)
copying 1 paths...
copying path '/nix/store/m2byj109xkdw6b1jazqy559sg3bgz2cm-vm-test-run-duplicated-routes' from 'ssh://hexa@foo'...
/nix/store/m2byj109xkdw6b1jazqy559sg3bgz2cm-vm-test-run-duplicated-routes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment