at 18.03-beta 22 kB view raw
1{ system ? builtins.currentSystem 2# bool: whether to use networkd in the tests 3, networkd }: 4 5with import ../lib/testing.nix { inherit system; }; 6with pkgs.lib; 7 8let 9 router = { config, pkgs, ... }: 10 with pkgs.lib; 11 let 12 vlanIfs = range 1 (length config.virtualisation.vlans); 13 in { 14 virtualisation.vlans = [ 1 2 3 ]; 15 boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = true; 16 networking = { 17 useDHCP = false; 18 useNetworkd = networkd; 19 firewall.allowPing = true; 20 firewall.checkReversePath = true; 21 firewall.allowedUDPPorts = [ 547 ]; 22 interfaces = mkOverride 0 (listToAttrs (flip map vlanIfs (n: 23 nameValuePair "eth${toString n}" { 24 ipv4.addresses = [ { address = "192.168.${toString n}.1"; prefixLength = 24; } ]; 25 ipv6.addresses = [ { address = "fd00:1234:5678:${toString n}::1"; prefixLength = 64; } ]; 26 }))); 27 }; 28 services.dhcpd4 = { 29 enable = true; 30 interfaces = map (n: "eth${toString n}") vlanIfs; 31 extraConfig = '' 32 authoritative; 33 '' + flip concatMapStrings vlanIfs (n: '' 34 subnet 192.168.${toString n}.0 netmask 255.255.255.0 { 35 option routers 192.168.${toString n}.1; 36 # XXX: technically it's _not guaranteed_ that IP addresses will be 37 # issued from the first item in range onwards! We assume that in 38 # our tests however. 39 range 192.168.${toString n}.2 192.168.${toString n}.254; 40 } 41 ''); 42 }; 43 services.radvd = { 44 enable = true; 45 config = flip concatMapStrings vlanIfs (n: '' 46 interface eth${toString n} { 47 AdvSendAdvert on; 48 AdvManagedFlag on; 49 AdvOtherConfigFlag on; 50 51 prefix fd00:1234:5678:${toString n}::/64 { 52 AdvAutonomous off; 53 }; 54 }; 55 ''); 56 }; 57 services.dhcpd6 = { 58 enable = true; 59 interfaces = map (n: "eth${toString n}") vlanIfs; 60 extraConfig = '' 61 authoritative; 62 '' + flip concatMapStrings vlanIfs (n: '' 63 subnet6 fd00:1234:5678:${toString n}::/64 { 64 range6 fd00:1234:5678:${toString n}::2 fd00:1234:5678:${toString n}::2; 65 } 66 ''); 67 }; 68 }; 69 70 testCases = { 71 loopback = { 72 name = "Loopback"; 73 machine.networking.useNetworkd = networkd; 74 testScript = '' 75 startAll; 76 $machine->waitForUnit("network.target"); 77 $machine->succeed("ip addr show lo | grep -q 'inet 127.0.0.1/8 '"); 78 $machine->succeed("ip addr show lo | grep -q 'inet6 ::1/128 '"); 79 ''; 80 }; 81 static = { 82 name = "Static"; 83 nodes.router = router; 84 nodes.client = { config, pkgs, ... }: with pkgs.lib; { 85 virtualisation.vlans = [ 1 2 ]; 86 networking = { 87 useNetworkd = networkd; 88 firewall.allowPing = true; 89 useDHCP = false; 90 defaultGateway = "192.168.1.1"; 91 interfaces.eth1.ipv4.addresses = mkOverride 0 [ 92 { address = "192.168.1.2"; prefixLength = 24; } 93 { address = "192.168.1.3"; prefixLength = 32; } 94 { address = "192.168.1.10"; prefixLength = 32; } 95 ]; 96 interfaces.eth2.ipv4.addresses = mkOverride 0 [ 97 { address = "192.168.2.2"; prefixLength = 24; } 98 ]; 99 }; 100 }; 101 testScript = { nodes, ... }: 102 '' 103 startAll; 104 105 $client->waitForUnit("network.target"); 106 $router->waitForUnit("network-online.target"); 107 108 # Make sure dhcpcd is not started 109 $client->fail("systemctl status dhcpcd.service"); 110 111 # Test vlan 1 112 $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); 113 $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); 114 $client->waitUntilSucceeds("ping -c 1 192.168.1.3"); 115 $client->waitUntilSucceeds("ping -c 1 192.168.1.10"); 116 117 $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); 118 $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); 119 $router->waitUntilSucceeds("ping -c 1 192.168.1.3"); 120 $router->waitUntilSucceeds("ping -c 1 192.168.1.10"); 121 122 # Test vlan 2 123 $client->waitUntilSucceeds("ping -c 1 192.168.2.1"); 124 $client->waitUntilSucceeds("ping -c 1 192.168.2.2"); 125 126 $router->waitUntilSucceeds("ping -c 1 192.168.2.1"); 127 $router->waitUntilSucceeds("ping -c 1 192.168.2.2"); 128 129 # Test default gateway 130 $router->waitUntilSucceeds("ping -c 1 192.168.3.1"); 131 $client->waitUntilSucceeds("ping -c 1 192.168.3.1"); 132 ''; 133 }; 134 dhcpSimple = { 135 name = "SimpleDHCP"; 136 nodes.router = router; 137 nodes.client = { config, pkgs, ... }: with pkgs.lib; { 138 virtualisation.vlans = [ 1 2 ]; 139 networking = { 140 useNetworkd = networkd; 141 firewall.allowPing = true; 142 useDHCP = true; 143 interfaces.eth1 = { 144 ipv4.addresses = mkOverride 0 [ ]; 145 ipv6.addresses = mkOverride 0 [ ]; 146 }; 147 interfaces.eth2 = { 148 ipv4.addresses = mkOverride 0 [ ]; 149 ipv6.addresses = mkOverride 0 [ ]; 150 }; 151 }; 152 }; 153 testScript = { nodes, ... }: 154 '' 155 startAll; 156 157 $client->waitForUnit("network.target"); 158 $router->waitForUnit("network-online.target"); 159 160 # Wait until we have an ip address on each interface 161 $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'"); 162 $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'"); 163 $client->waitUntilSucceeds("ip addr show dev eth2 | grep -q '192.168.2'"); 164 $client->waitUntilSucceeds("ip addr show dev eth2 | grep -q 'fd00:1234:5678:2:'"); 165 166 # Test vlan 1 167 $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); 168 $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); 169 $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::1"); 170 $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::2"); 171 172 $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); 173 $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); 174 $router->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::1"); 175 $router->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::2"); 176 177 # Test vlan 2 178 $client->waitUntilSucceeds("ping -c 1 192.168.2.1"); 179 $client->waitUntilSucceeds("ping -c 1 192.168.2.2"); 180 $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:2::1"); 181 $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:2::2"); 182 183 $router->waitUntilSucceeds("ping -c 1 192.168.2.1"); 184 $router->waitUntilSucceeds("ping -c 1 192.168.2.2"); 185 $router->waitUntilSucceeds("ping -c 1 fd00:1234:5678:2::1"); 186 $router->waitUntilSucceeds("ping -c 1 fd00:1234:5678:2::2"); 187 ''; 188 }; 189 dhcpOneIf = { 190 name = "OneInterfaceDHCP"; 191 nodes.router = router; 192 nodes.client = { config, pkgs, ... }: with pkgs.lib; { 193 virtualisation.vlans = [ 1 2 ]; 194 networking = { 195 useNetworkd = networkd; 196 firewall.allowPing = true; 197 useDHCP = false; 198 interfaces.eth1 = { 199 ipv4.addresses = mkOverride 0 [ ]; 200 useDHCP = true; 201 }; 202 interfaces.eth2.ipv4.addresses = mkOverride 0 [ ]; 203 }; 204 }; 205 testScript = { nodes, ... }: 206 '' 207 startAll; 208 209 # Wait for networking to come up 210 $client->waitForUnit("network.target"); 211 $router->waitForUnit("network.target"); 212 213 # Wait until we have an ip address on each interface 214 $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'"); 215 216 # Test vlan 1 217 $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); 218 $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); 219 220 $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); 221 $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); 222 223 # Test vlan 2 224 $client->waitUntilSucceeds("ping -c 1 192.168.2.1"); 225 $client->fail("ping -c 1 192.168.2.2"); 226 227 $router->waitUntilSucceeds("ping -c 1 192.168.2.1"); 228 $router->fail("ping -c 1 192.168.2.2"); 229 ''; 230 }; 231 bond = let 232 node = address: { config, pkgs, ... }: with pkgs.lib; { 233 virtualisation.vlans = [ 1 2 ]; 234 networking = { 235 useNetworkd = networkd; 236 firewall.allowPing = true; 237 useDHCP = false; 238 bonds.bond = { 239 interfaces = [ "eth1" "eth2" ]; 240 driverOptions.mode = "balance-rr"; 241 }; 242 interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; 243 interfaces.eth2.ipv4.addresses = mkOverride 0 [ ]; 244 interfaces.bond.ipv4.addresses = mkOverride 0 245 [ { inherit address; prefixLength = 30; } ]; 246 }; 247 }; 248 in { 249 name = "Bond"; 250 nodes.client1 = node "192.168.1.1"; 251 nodes.client2 = node "192.168.1.2"; 252 testScript = { nodes, ... }: 253 '' 254 startAll; 255 256 # Wait for networking to come up 257 $client1->waitForUnit("network.target"); 258 $client2->waitForUnit("network.target"); 259 260 # Test bonding 261 $client1->waitUntilSucceeds("ping -c 2 192.168.1.1"); 262 $client1->waitUntilSucceeds("ping -c 2 192.168.1.2"); 263 264 $client2->waitUntilSucceeds("ping -c 2 192.168.1.1"); 265 $client2->waitUntilSucceeds("ping -c 2 192.168.1.2"); 266 ''; 267 }; 268 bridge = let 269 node = { address, vlan }: { config, pkgs, ... }: with pkgs.lib; { 270 virtualisation.vlans = [ vlan ]; 271 networking = { 272 useNetworkd = networkd; 273 firewall.allowPing = true; 274 useDHCP = false; 275 interfaces.eth1.ipv4.addresses = mkOverride 0 276 [ { inherit address; prefixLength = 24; } ]; 277 }; 278 }; 279 in { 280 name = "Bridge"; 281 nodes.client1 = node { address = "192.168.1.2"; vlan = 1; }; 282 nodes.client2 = node { address = "192.168.1.3"; vlan = 2; }; 283 nodes.router = { config, pkgs, ... }: with pkgs.lib; { 284 virtualisation.vlans = [ 1 2 ]; 285 networking = { 286 useNetworkd = networkd; 287 firewall.allowPing = true; 288 useDHCP = false; 289 bridges.bridge.interfaces = [ "eth1" "eth2" ]; 290 interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; 291 interfaces.eth2.ipv4.addresses = mkOverride 0 [ ]; 292 interfaces.bridge.ipv4.addresses = mkOverride 0 293 [ { address = "192.168.1.1"; prefixLength = 24; } ]; 294 }; 295 }; 296 testScript = { nodes, ... }: 297 '' 298 startAll; 299 300 # Wait for networking to come up 301 $client1->waitForUnit("network.target"); 302 $client2->waitForUnit("network.target"); 303 $router->waitForUnit("network.target"); 304 305 # Test bridging 306 $client1->waitUntilSucceeds("ping -c 1 192.168.1.1"); 307 $client1->waitUntilSucceeds("ping -c 1 192.168.1.2"); 308 $client1->waitUntilSucceeds("ping -c 1 192.168.1.3"); 309 310 $client2->waitUntilSucceeds("ping -c 1 192.168.1.1"); 311 $client2->waitUntilSucceeds("ping -c 1 192.168.1.2"); 312 $client2->waitUntilSucceeds("ping -c 1 192.168.1.3"); 313 314 $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); 315 $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); 316 $router->waitUntilSucceeds("ping -c 1 192.168.1.3"); 317 ''; 318 }; 319 macvlan = { 320 name = "MACVLAN"; 321 nodes.router = router; 322 nodes.client = { config, pkgs, ... }: with pkgs.lib; { 323 virtualisation.vlans = [ 1 ]; 324 networking = { 325 useNetworkd = networkd; 326 firewall.allowPing = true; 327 useDHCP = true; 328 macvlans.macvlan.interface = "eth1"; 329 interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; 330 }; 331 }; 332 testScript = { nodes, ... }: 333 '' 334 startAll; 335 336 # Wait for networking to come up 337 $client->waitForUnit("network.target"); 338 $router->waitForUnit("network.target"); 339 340 # Wait until we have an ip address on each interface 341 $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'"); 342 $client->waitUntilSucceeds("ip addr show dev macvlan | grep -q '192.168.1'"); 343 344 # Print diagnosting information 345 $router->succeed("ip addr >&2"); 346 $client->succeed("ip addr >&2"); 347 348 # Test macvlan creates routable ips 349 $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); 350 $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); 351 $client->waitUntilSucceeds("ping -c 1 192.168.1.3"); 352 353 $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); 354 $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); 355 $router->waitUntilSucceeds("ping -c 1 192.168.1.3"); 356 ''; 357 }; 358 sit = let 359 node = { address4, remote, address6 }: { config, pkgs, ... }: with pkgs.lib; { 360 virtualisation.vlans = [ 1 ]; 361 networking = { 362 useNetworkd = networkd; 363 firewall.enable = false; 364 useDHCP = false; 365 sits.sit = { 366 inherit remote; 367 local = address4; 368 dev = "eth1"; 369 }; 370 interfaces.eth1.ipv4.addresses = mkOverride 0 371 [ { address = address4; prefixLength = 24; } ]; 372 interfaces.sit.ipv6.addresses = mkOverride 0 373 [ { address = address6; prefixLength = 64; } ]; 374 }; 375 }; 376 in { 377 name = "Sit"; 378 nodes.client1 = node { address4 = "192.168.1.1"; remote = "192.168.1.2"; address6 = "fc00::1"; }; 379 nodes.client2 = node { address4 = "192.168.1.2"; remote = "192.168.1.1"; address6 = "fc00::2"; }; 380 testScript = { nodes, ... }: 381 '' 382 startAll; 383 384 # Wait for networking to be configured 385 $client1->waitForUnit("network.target"); 386 $client2->waitForUnit("network.target"); 387 388 # Print diagnostic information 389 $client1->succeed("ip addr >&2"); 390 $client2->succeed("ip addr >&2"); 391 392 # Test ipv6 393 $client1->waitUntilSucceeds("ping -c 1 fc00::1"); 394 $client1->waitUntilSucceeds("ping -c 1 fc00::2"); 395 396 $client2->waitUntilSucceeds("ping -c 1 fc00::1"); 397 $client2->waitUntilSucceeds("ping -c 1 fc00::2"); 398 ''; 399 }; 400 vlan = let 401 node = address: { config, pkgs, ... }: with pkgs.lib; { 402 #virtualisation.vlans = [ 1 ]; 403 networking = { 404 useNetworkd = networkd; 405 firewall.allowPing = true; 406 useDHCP = false; 407 vlans.vlan = { 408 id = 1; 409 interface = "eth0"; 410 }; 411 interfaces.eth0.ipv4.addresses = mkOverride 0 [ ]; 412 interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; 413 interfaces.vlan.ipv4.addresses = mkOverride 0 414 [ { inherit address; prefixLength = 24; } ]; 415 }; 416 }; 417 in { 418 name = "vlan"; 419 nodes.client1 = node "192.168.1.1"; 420 nodes.client2 = node "192.168.1.2"; 421 testScript = { nodes, ... }: 422 '' 423 startAll; 424 425 # Wait for networking to be configured 426 $client1->waitForUnit("network.target"); 427 $client2->waitForUnit("network.target"); 428 429 # Test vlan is setup 430 $client1->succeed("ip addr show dev vlan >&2"); 431 $client2->succeed("ip addr show dev vlan >&2"); 432 ''; 433 }; 434 virtual = { 435 name = "Virtual"; 436 machine = { 437 networking.interfaces."tap0" = { 438 ipv4.addresses = [ { address = "192.168.1.1"; prefixLength = 24; } ]; 439 ipv6.addresses = [ { address = "2001:1470:fffd:2096::"; prefixLength = 64; } ]; 440 virtual = true; 441 }; 442 networking.interfaces."tun0" = { 443 ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ]; 444 ipv6.addresses = [ { address = "2001:1470:fffd:2097::"; prefixLength = 64; } ]; 445 virtual = true; 446 }; 447 }; 448 449 testScript = '' 450 my $targetList = <<'END'; 451 tap0: tap UNKNOWN_FLAGS:800 user 0 452 tun0: tun UNKNOWN_FLAGS:800 user 0 453 END 454 455 # Wait for networking to come up 456 $machine->start; 457 $machine->waitForUnit("network.target"); 458 459 # Test interfaces set up 460 my $list = $machine->succeed("ip tuntap list | sort"); 461 "$list" eq "$targetList" or die( 462 "The list of virtual interfaces does not match the expected one:\n", 463 "Result:\n", "$list\n", 464 "Expected:\n", "$targetList\n" 465 ); 466 467 # Test interfaces clean up 468 $machine->succeed("systemctl stop network-addresses-tap0"); 469 $machine->succeed("systemctl stop network-addresses-tun0"); 470 my $residue = $machine->succeed("ip tuntap list"); 471 $residue eq "" or die( 472 "Some virtual interface has not been properly cleaned:\n", 473 "$residue\n" 474 ); 475 ''; 476 }; 477 privacy = { 478 name = "Privacy"; 479 nodes.router = { config, pkgs, ... }: { 480 virtualisation.vlans = [ 1 ]; 481 boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = true; 482 networking = { 483 useNetworkd = networkd; 484 interfaces.eth1.ipv6.addresses = singleton { 485 address = "fd00:1234:5678:1::1"; 486 prefixLength = 64; 487 }; 488 }; 489 services.radvd = { 490 enable = true; 491 config = '' 492 interface eth1 { 493 AdvSendAdvert on; 494 AdvManagedFlag on; 495 AdvOtherConfigFlag on; 496 497 prefix fd00:1234:5678:1::/64 { 498 AdvAutonomous on; 499 AdvOnLink on; 500 }; 501 }; 502 ''; 503 }; 504 }; 505 nodes.client = { config, pkgs, ... }: with pkgs.lib; { 506 virtualisation.vlans = [ 1 ]; 507 networking = { 508 useNetworkd = networkd; 509 useDHCP = true; 510 interfaces.eth1 = { 511 preferTempAddress = true; 512 ipv4.addresses = mkOverride 0 [ ]; 513 ipv6.addresses = mkOverride 0 [ ]; 514 }; 515 }; 516 }; 517 testScript = { nodes, ... }: 518 '' 519 startAll; 520 521 $client->waitForUnit("network.target"); 522 $router->waitForUnit("network-online.target"); 523 524 # Wait until we have an ip address 525 $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'"); 526 527 # Test vlan 1 528 $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::1"); 529 530 # Test address used is temporary 531 $client->waitUntilSucceeds("! ip route get fd00:1234:5678:1::1 | grep -q ':[a-f0-9]*ff:fe[a-f0-9]*:'"); 532 ''; 533 }; 534 routes = { 535 name = "routes"; 536 machine = { 537 networking.useDHCP = false; 538 networking.interfaces."eth0" = { 539 ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ]; 540 ipv6.addresses = [ { address = "2001:1470:fffd:2097::"; prefixLength = 64; } ]; 541 ipv6.routes = [ 542 { address = "fdfd:b3f0::"; prefixLength = 48; } 543 { address = "2001:1470:fffd:2098::"; prefixLength = 64; via = "fdfd:b3f0::1"; } 544 ]; 545 ipv4.routes = [ 546 { address = "10.0.0.0"; prefixLength = 16; options = { mtu = "1500"; }; } 547 { address = "192.168.2.0"; prefixLength = 24; via = "192.168.1.1"; } 548 ]; 549 }; 550 virtualisation.vlans = [ ]; 551 }; 552 553 testScript = '' 554 my $targetIPv4Table = <<'END'; 555 10.0.0.0/16 scope link mtu 1500 556 192.168.1.0/24 proto kernel scope link src 192.168.1.2 557 192.168.2.0/24 via 192.168.1.1 558 END 559 560 my $targetIPv6Table = <<'END'; 561 2001:1470:fffd:2097::/64 proto kernel metric 256 pref medium 562 2001:1470:fffd:2098::/64 via fdfd:b3f0::1 metric 1024 pref medium 563 fdfd:b3f0::/48 metric 1024 pref medium 564 END 565 566 $machine->start; 567 $machine->waitForUnit("network.target"); 568 569 # test routing tables 570 my $ipv4Table = $machine->succeed("ip -4 route list dev eth0 | head -n3"); 571 my $ipv6Table = $machine->succeed("ip -6 route list dev eth0 | head -n3"); 572 "$ipv4Table" eq "$targetIPv4Table" or die( 573 "The IPv4 routing table does not match the expected one:\n", 574 "Result:\n", "$ipv4Table\n", 575 "Expected:\n", "$targetIPv4Table\n" 576 ); 577 "$ipv6Table" eq "$targetIPv6Table" or die( 578 "The IPv6 routing table does not match the expected one:\n", 579 "Result:\n", "$ipv6Table\n", 580 "Expected:\n", "$targetIPv6Table\n" 581 ); 582 583 # test clean-up of the tables 584 $machine->succeed("systemctl stop network-addresses-eth0"); 585 my $ipv4Residue = $machine->succeed("ip -4 route list dev eth0 | head -n-3"); 586 my $ipv6Residue = $machine->succeed("ip -6 route list dev eth0 | head -n-3"); 587 $ipv4Residue eq "" or die( 588 "The IPv4 routing table has not been properly cleaned:\n", 589 "$ipv4Residue\n" 590 ); 591 $ipv6Residue eq "" or die( 592 "The IPv6 routing table has not been properly cleaned:\n", 593 "$ipv6Residue\n" 594 ); 595 ''; 596 }; 597 }; 598 599in mapAttrs (const (attrs: makeTest (attrs // { 600 name = "${attrs.name}-Networking-${if networkd then "Networkd" else "Scripted"}"; 601 meta = with pkgs.stdenv.lib.maintainers; { 602 maintainers = [ wkennington ]; 603 }; 604}))) testCases