From f41111c4da9a7eb5cade95d945eec7576757d27d Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 28 Jul 2017 16:45:58 +0200 Subject: [PATCH] nixos/tests: add test for static routes --- .../tasks/network-interfaces-scripted.nix | 5 +- nixos/modules/tasks/network-interfaces.nix | 12 ++-- nixos/tests/networking.nix | 63 +++++++++++++++++++ 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index 9dba6d1bd0a2..28bbc27a2693 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -210,12 +210,13 @@ let ${flip concatMapStrings (i.ipv4Routes ++ i.ipv6Routes) (route: let cidr = "${route.address}/${toString route.prefixLength}"; - nextHop = optionalString (route.nextHop != null) ''via "${route.nextHop}"''; + via = optionalString (route.via != null) ''via "${route.via}"''; + options = concatStrings (mapAttrsToList (name: val: "${name} ${val} ") route.options); in '' echo "${cidr}" >> $state echo -n "adding route ${cidr}... " - if out=$(ip route add "${cidr}" ${route.options} ${nextHop} dev "${i.name}" 2>&1); then + if out=$(ip route add "${cidr}" ${options} ${via} dev "${i.name}" 2>&1); then echo "done" elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then echo "failed" diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index d437a829be5f..6f8ee147649d 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -131,16 +131,16 @@ let ''; }; - nextHop = mkOption { + via = mkOption { type = types.nullOr types.str; default = null; description = "IPv${toString v} address of the next hop."; }; options = mkOption { - type = types.str; - default = ""; - example = "mtu 1492 window 524288"; + type = types.attrsOf types.str; + default = { }; + example = { mtu = "1492"; window = "524288"; }; description = '' Other route options. See the symbol OPTION in the ip-route(8) manual page for the details. @@ -237,7 +237,7 @@ let default = []; example = [ { address = "10.0.0.0"; prefixLength = 16; } - { address = "192.168.2.0"; prefixLength = 24; nextHop = "192.168.1.1"; } + { address = "192.168.2.0"; prefixLength = 24; via = "192.168.1.1"; } ]; type = with types; listOf (submodule (routeOpts 4)); description = '' @@ -249,7 +249,7 @@ let default = []; example = [ { address = "fdfd:b3f0::"; prefixLength = 48; } - { address = "2001:1470:fffd:2098::"; prefixLength = 64; nextHop = "fdfd:b3f0::1"; } + { address = "2001:1470:fffd:2098::"; prefixLength = 64; via = "fdfd:b3f0::1"; } ]; type = with types; listOf (submodule (routeOpts 6)); description = '' diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix index fa3dc0538729..e401004ab322 100644 --- a/nixos/tests/networking.nix +++ b/nixos/tests/networking.nix @@ -533,6 +533,69 @@ let $client->succeed("! ip route get fd00:1234:5678:1::1 | grep -q ':[a-f0-9]*ff:fe[a-f0-9]*:'"); ''; }; + routes = { + name = "routes"; + machine = { + networking.useDHCP = false; + networking.interfaces."eth0" = { + ip4 = [ { address = "192.168.1.2"; prefixLength = 24; } ]; + ip6 = [ { address = "2001:1470:fffd:2097::"; prefixLength = 64; } ]; + ipv6Routes = [ + { address = "fdfd:b3f0::"; prefixLength = 48; } + { address = "2001:1470:fffd:2098::"; prefixLength = 64; via = "fdfd:b3f0::1"; } + ]; + ipv4Routes = [ + { address = "10.0.0.0"; prefixLength = 16; options = { mtu = "1500"; }; } + { address = "192.168.2.0"; prefixLength = 24; via = "192.168.1.1"; } + ]; + }; + virtualisation.vlans = [ ]; + }; + + testScript = '' + my $targetIPv4Table = <<'END'; + 10.0.0.0/16 scope link mtu 1500 + 192.168.1.0/24 proto kernel scope link src 192.168.1.2 + 192.168.2.0/24 via 192.168.1.1 + END + + my $targetIPv6Table = <<'END'; + 2001:1470:fffd:2097::/64 proto kernel metric 256 pref medium + 2001:1470:fffd:2098::/64 via fdfd:b3f0::1 metric 1024 pref medium + fdfd:b3f0::/48 metric 1024 pref medium + END + + $machine->start; + $machine->waitForUnit("network.target"); + + # test routing tables + my $ipv4Table = $machine->succeed("ip -4 route list dev eth0 | head -n3"); + my $ipv6Table = $machine->succeed("ip -6 route list dev eth0 | head -n3"); + "$ipv4Table" eq "$targetIPv4Table" or die( + "The IPv4 routing table does not match the expected one:\n", + "Result:\n", "$ipv4Table\n", + "Expected:\n", "$targetIPv4Table\n" + ); + "$ipv6Table" eq "$targetIPv6Table" or die( + "The IPv6 routing table does not match the expected one:\n", + "Result:\n", "$ipv6Table\n", + "Expected:\n", "$targetIPv6Table\n" + ); + + # test clean-up of the tables + $machine->succeed("systemctl stop network-addresses-eth0"); + my $ipv4Residue = $machine->succeed("ip -4 route list dev eth0 | head -n-3"); + my $ipv6Residue = $machine->succeed("ip -6 route list dev eth0 | head -n-3"); + $ipv4Residue eq "" or die( + "The IPv4 routing table has not been properly cleaned:\n", + "$ipv4Residue\n" + ); + $ipv6Residue eq "" or die( + "The IPv6 routing table has not been properly cleaned:\n", + "$ipv6Residue\n" + ); + ''; + }; }; in mapAttrs (const (attrs: makeTest (attrs // {