at 23.05-pre 38 kB view raw
1{ system ? builtins.currentSystem 2, config ? {} 3, pkgs ? import ../.. { inherit system config; } 4# bool: whether to use networkd in the tests 5, networkd }: 6 7with import ../lib/testing-python.nix { inherit system pkgs; }; 8with pkgs.lib; 9 10let 11 qemu-common = import ../lib/qemu-common.nix { inherit (pkgs) lib pkgs; }; 12 13 router = { config, pkgs, lib, ... }: 14 with pkgs.lib; 15 let 16 vlanIfs = range 1 (length config.virtualisation.vlans); 17 in { 18 environment.systemPackages = [ pkgs.iptables ]; # to debug firewall rules 19 virtualisation.vlans = [ 1 2 3 ]; 20 boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = true; 21 networking = { 22 useDHCP = false; 23 useNetworkd = networkd; 24 firewall.checkReversePath = true; 25 firewall.allowedUDPPorts = [ 547 ]; 26 interfaces = mkOverride 0 (listToAttrs (forEach vlanIfs (n: 27 nameValuePair "eth${toString n}" { 28 ipv4.addresses = [ { address = "192.168.${toString n}.1"; prefixLength = 24; } ]; 29 ipv6.addresses = [ { address = "fd00:1234:5678:${toString n}::1"; prefixLength = 64; } ]; 30 }))); 31 }; 32 services.dhcpd4 = { 33 enable = true; 34 interfaces = map (n: "eth${toString n}") vlanIfs; 35 extraConfig = flip concatMapStrings vlanIfs (n: '' 36 subnet 192.168.${toString n}.0 netmask 255.255.255.0 { 37 option routers 192.168.${toString n}.1; 38 range 192.168.${toString n}.3 192.168.${toString n}.254; 39 } 40 '') 41 ; 42 machines = flip map vlanIfs (vlan: 43 { 44 hostName = "client${toString vlan}"; 45 ethernetAddress = qemu-common.qemuNicMac vlan 1; 46 ipAddress = "192.168.${toString vlan}.2"; 47 } 48 ); 49 }; 50 services.radvd = { 51 enable = true; 52 config = flip concatMapStrings vlanIfs (n: '' 53 interface eth${toString n} { 54 AdvSendAdvert on; 55 AdvManagedFlag on; 56 AdvOtherConfigFlag on; 57 58 prefix fd00:1234:5678:${toString n}::/64 { 59 AdvAutonomous off; 60 }; 61 }; 62 ''); 63 }; 64 services.dhcpd6 = { 65 enable = true; 66 interfaces = map (n: "eth${toString n}") vlanIfs; 67 extraConfig = '' 68 authoritative; 69 '' + flip concatMapStrings vlanIfs (n: '' 70 subnet6 fd00:1234:5678:${toString n}::/64 { 71 range6 fd00:1234:5678:${toString n}::2 fd00:1234:5678:${toString n}::2; 72 } 73 ''); 74 }; 75 }; 76 77 testCases = { 78 loopback = { 79 name = "Loopback"; 80 nodes.client = { pkgs, ... }: with pkgs.lib; { 81 networking.useDHCP = false; 82 networking.useNetworkd = networkd; 83 }; 84 testScript = '' 85 start_all() 86 client.wait_for_unit("network.target") 87 loopback_addresses = client.succeed("ip addr show lo") 88 assert "inet 127.0.0.1/8" in loopback_addresses 89 assert "inet6 ::1/128" in loopback_addresses 90 ''; 91 }; 92 static = { 93 name = "Static"; 94 nodes.router = router; 95 nodes.client = { pkgs, ... }: with pkgs.lib; { 96 virtualisation.vlans = [ 1 2 ]; 97 networking = { 98 useNetworkd = networkd; 99 useDHCP = false; 100 defaultGateway = "192.168.1.1"; 101 defaultGateway6 = "fd00:1234:5678:1::1"; 102 interfaces.eth1.ipv4.addresses = mkOverride 0 [ 103 { address = "192.168.1.2"; prefixLength = 24; } 104 { address = "192.168.1.3"; prefixLength = 32; } 105 { address = "192.168.1.10"; prefixLength = 32; } 106 ]; 107 interfaces.eth2.ipv4.addresses = mkOverride 0 [ 108 { address = "192.168.2.2"; prefixLength = 24; } 109 ]; 110 }; 111 }; 112 testScript = { ... }: 113 '' 114 start_all() 115 116 client.wait_for_unit("network.target") 117 router.wait_for_unit("network-online.target") 118 119 with subtest("Make sure dhcpcd is not started"): 120 client.fail("systemctl status dhcpcd.service") 121 122 with subtest("Test vlan 1"): 123 client.wait_until_succeeds("ping -c 1 192.168.1.1") 124 client.wait_until_succeeds("ping -c 1 192.168.1.2") 125 client.wait_until_succeeds("ping -c 1 192.168.1.3") 126 client.wait_until_succeeds("ping -c 1 192.168.1.10") 127 128 router.wait_until_succeeds("ping -c 1 192.168.1.1") 129 router.wait_until_succeeds("ping -c 1 192.168.1.2") 130 router.wait_until_succeeds("ping -c 1 192.168.1.3") 131 router.wait_until_succeeds("ping -c 1 192.168.1.10") 132 133 with subtest("Test vlan 2"): 134 client.wait_until_succeeds("ping -c 1 192.168.2.1") 135 client.wait_until_succeeds("ping -c 1 192.168.2.2") 136 137 router.wait_until_succeeds("ping -c 1 192.168.2.1") 138 router.wait_until_succeeds("ping -c 1 192.168.2.2") 139 140 with subtest("Test default gateway"): 141 router.wait_until_succeeds("ping -c 1 192.168.3.1") 142 client.wait_until_succeeds("ping -c 1 192.168.3.1") 143 router.wait_until_succeeds("ping -c 1 fd00:1234:5678:3::1") 144 client.wait_until_succeeds("ping -c 1 fd00:1234:5678:3::1") 145 ''; 146 }; 147 routeType = { 148 name = "RouteType"; 149 nodes.client = { pkgs, ... }: with pkgs.lib; { 150 networking = { 151 useDHCP = false; 152 useNetworkd = networkd; 153 interfaces.eth1.ipv4.routes = [{ 154 address = "192.168.1.127"; 155 prefixLength = 32; 156 type = "local"; 157 }]; 158 }; 159 }; 160 testScript = '' 161 start_all() 162 client.wait_for_unit("network.target") 163 client.succeed("ip -4 route list table local | grep 'local 192.168.1.127'") 164 ''; 165 }; 166 dhcpDefault = { 167 name = "useDHCP-by-default"; 168 nodes.router = router; 169 nodes.client = { lib, ... }: { 170 # Disable test driver default config 171 networking.interfaces = lib.mkForce {}; 172 networking.useNetworkd = networkd; 173 virtualisation.vlans = [ 1 ]; 174 }; 175 testScript = '' 176 start_all() 177 client.wait_for_unit("multi-user.target") 178 client.wait_until_succeeds("ip addr show dev eth1 | grep '192.168.1'") 179 client.shell_interact() 180 client.succeed("ping -c 1 192.168.1.1") 181 router.succeed("ping -c 1 192.168.1.1") 182 router.succeed("ping -c 1 192.168.1.2") 183 client.succeed("ping -c 1 192.168.1.2") 184 ''; 185 }; 186 dhcpSimple = { 187 name = "SimpleDHCP"; 188 nodes.router = router; 189 nodes.client = { pkgs, ... }: with pkgs.lib; { 190 virtualisation.vlans = [ 1 2 ]; 191 networking = { 192 useNetworkd = networkd; 193 useDHCP = false; 194 interfaces.eth1 = { 195 ipv4.addresses = mkOverride 0 [ ]; 196 ipv6.addresses = mkOverride 0 [ ]; 197 useDHCP = true; 198 }; 199 interfaces.eth2 = { 200 ipv4.addresses = mkOverride 0 [ ]; 201 ipv6.addresses = mkOverride 0 [ ]; 202 useDHCP = true; 203 }; 204 }; 205 }; 206 testScript = { ... }: 207 '' 208 start_all() 209 210 client.wait_for_unit("network.target") 211 router.wait_for_unit("network-online.target") 212 213 with subtest("Wait until we have an ip address on each interface"): 214 client.wait_until_succeeds("ip addr show dev eth1 | grep -q '192.168.1'") 215 client.wait_until_succeeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'") 216 client.wait_until_succeeds("ip addr show dev eth2 | grep -q '192.168.2'") 217 client.wait_until_succeeds("ip addr show dev eth2 | grep -q 'fd00:1234:5678:2:'") 218 219 with subtest("Test vlan 1"): 220 client.wait_until_succeeds("ping -c 1 192.168.1.1") 221 client.wait_until_succeeds("ping -c 1 192.168.1.2") 222 client.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::1") 223 client.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::2") 224 225 router.wait_until_succeeds("ping -c 1 192.168.1.1") 226 router.wait_until_succeeds("ping -c 1 192.168.1.2") 227 router.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::1") 228 router.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::2") 229 230 with subtest("Test vlan 2"): 231 client.wait_until_succeeds("ping -c 1 192.168.2.1") 232 client.wait_until_succeeds("ping -c 1 192.168.2.2") 233 client.wait_until_succeeds("ping -c 1 fd00:1234:5678:2::1") 234 client.wait_until_succeeds("ping -c 1 fd00:1234:5678:2::2") 235 236 router.wait_until_succeeds("ping -c 1 192.168.2.1") 237 router.wait_until_succeeds("ping -c 1 192.168.2.2") 238 router.wait_until_succeeds("ping -c 1 fd00:1234:5678:2::1") 239 router.wait_until_succeeds("ping -c 1 fd00:1234:5678:2::2") 240 ''; 241 }; 242 dhcpOneIf = { 243 name = "OneInterfaceDHCP"; 244 nodes.router = router; 245 nodes.client = { pkgs, ... }: with pkgs.lib; { 246 virtualisation.vlans = [ 1 2 ]; 247 networking = { 248 useNetworkd = networkd; 249 useDHCP = false; 250 interfaces.eth1 = { 251 ipv4.addresses = mkOverride 0 [ ]; 252 mtu = 1343; 253 useDHCP = true; 254 }; 255 interfaces.eth2.ipv4.addresses = mkOverride 0 [ ]; 256 }; 257 }; 258 testScript = { ... }: 259 '' 260 start_all() 261 262 with subtest("Wait for networking to come up"): 263 client.wait_for_unit("network.target") 264 router.wait_for_unit("network.target") 265 266 with subtest("Wait until we have an ip address on each interface"): 267 client.wait_until_succeeds("ip addr show dev eth1 | grep -q '192.168.1'") 268 269 with subtest("ensure MTU is set"): 270 assert "mtu 1343" in client.succeed("ip link show dev eth1") 271 272 with subtest("Test vlan 1"): 273 client.wait_until_succeeds("ping -c 1 192.168.1.1") 274 client.wait_until_succeeds("ping -c 1 192.168.1.2") 275 276 router.wait_until_succeeds("ping -c 1 192.168.1.1") 277 router.wait_until_succeeds("ping -c 1 192.168.1.2") 278 279 with subtest("Test vlan 2"): 280 client.wait_until_succeeds("ping -c 1 192.168.2.1") 281 client.fail("ping -c 1 192.168.2.2") 282 283 router.wait_until_succeeds("ping -c 1 192.168.2.1") 284 router.fail("ping -c 1 192.168.2.2") 285 ''; 286 }; 287 bond = let 288 node = address: { pkgs, ... }: with pkgs.lib; { 289 virtualisation.vlans = [ 1 2 ]; 290 networking = { 291 useNetworkd = networkd; 292 useDHCP = false; 293 bonds.bond0 = { 294 interfaces = [ "eth1" "eth2" ]; 295 driverOptions.mode = "802.3ad"; 296 }; 297 interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; 298 interfaces.eth2.ipv4.addresses = mkOverride 0 [ ]; 299 interfaces.bond0.ipv4.addresses = mkOverride 0 300 [ { inherit address; prefixLength = 30; } ]; 301 }; 302 }; 303 in { 304 name = "Bond"; 305 nodes.client1 = node "192.168.1.1"; 306 nodes.client2 = node "192.168.1.2"; 307 testScript = { ... }: 308 '' 309 start_all() 310 311 with subtest("Wait for networking to come up"): 312 client1.wait_for_unit("network.target") 313 client2.wait_for_unit("network.target") 314 315 with subtest("Test bonding"): 316 client1.wait_until_succeeds("ping -c 2 192.168.1.1") 317 client1.wait_until_succeeds("ping -c 2 192.168.1.2") 318 319 client2.wait_until_succeeds("ping -c 2 192.168.1.1") 320 client2.wait_until_succeeds("ping -c 2 192.168.1.2") 321 322 with subtest("Verify bonding mode"): 323 for client in client1, client2: 324 client.succeed('grep -q "Bonding Mode: IEEE 802.3ad Dynamic link aggregation" /proc/net/bonding/bond0') 325 ''; 326 }; 327 bridge = let 328 node = { address, vlan }: { pkgs, ... }: with pkgs.lib; { 329 virtualisation.vlans = [ vlan ]; 330 networking = { 331 useNetworkd = networkd; 332 useDHCP = false; 333 interfaces.eth1.ipv4.addresses = mkOverride 0 334 [ { inherit address; prefixLength = 24; } ]; 335 }; 336 }; 337 in { 338 name = "Bridge"; 339 nodes.client1 = node { address = "192.168.1.2"; vlan = 1; }; 340 nodes.client2 = node { address = "192.168.1.3"; vlan = 2; }; 341 nodes.router = { pkgs, ... }: with pkgs.lib; { 342 virtualisation.vlans = [ 1 2 ]; 343 networking = { 344 useNetworkd = networkd; 345 useDHCP = false; 346 bridges.bridge.interfaces = [ "eth1" "eth2" ]; 347 interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; 348 interfaces.eth2.ipv4.addresses = mkOverride 0 [ ]; 349 interfaces.bridge.ipv4.addresses = mkOverride 0 350 [ { address = "192.168.1.1"; prefixLength = 24; } ]; 351 }; 352 }; 353 testScript = { ... }: 354 '' 355 start_all() 356 357 with subtest("Wait for networking to come up"): 358 for machine in client1, client2, router: 359 machine.wait_for_unit("network.target") 360 361 with subtest("Test bridging"): 362 client1.wait_until_succeeds("ping -c 1 192.168.1.1") 363 client1.wait_until_succeeds("ping -c 1 192.168.1.2") 364 client1.wait_until_succeeds("ping -c 1 192.168.1.3") 365 366 client2.wait_until_succeeds("ping -c 1 192.168.1.1") 367 client2.wait_until_succeeds("ping -c 1 192.168.1.2") 368 client2.wait_until_succeeds("ping -c 1 192.168.1.3") 369 370 router.wait_until_succeeds("ping -c 1 192.168.1.1") 371 router.wait_until_succeeds("ping -c 1 192.168.1.2") 372 router.wait_until_succeeds("ping -c 1 192.168.1.3") 373 ''; 374 }; 375 macvlan = { 376 name = "MACVLAN"; 377 nodes.router = router; 378 nodes.client = { pkgs, ... }: with pkgs.lib; { 379 environment.systemPackages = [ pkgs.iptables ]; # to debug firewall rules 380 virtualisation.vlans = [ 1 ]; 381 networking = { 382 useNetworkd = networkd; 383 useDHCP = false; 384 firewall.logReversePathDrops = true; # to debug firewall rules 385 # reverse path filtering rules for the macvlan interface seem 386 # to be incorrect, causing the test to fail. Disable temporarily. 387 firewall.checkReversePath = false; 388 macvlans.macvlan.interface = "eth1"; 389 interfaces.eth1 = { 390 ipv4.addresses = mkOverride 0 [ ]; 391 useDHCP = true; 392 }; 393 interfaces.macvlan = { 394 useDHCP = true; 395 }; 396 }; 397 }; 398 testScript = { ... }: 399 '' 400 start_all() 401 402 with subtest("Wait for networking to come up"): 403 client.wait_for_unit("network.target") 404 router.wait_for_unit("network.target") 405 406 with subtest("Wait until we have an ip address on each interface"): 407 client.wait_until_succeeds("ip addr show dev eth1 | grep -q '192.168.1'") 408 client.wait_until_succeeds("ip addr show dev macvlan | grep -q '192.168.1'") 409 410 with subtest("Print lots of diagnostic information"): 411 router.log("**********************************************") 412 router.succeed("ip addr >&2") 413 router.succeed("ip route >&2") 414 router.execute("iptables-save >&2") 415 client.log("==============================================") 416 client.succeed("ip addr >&2") 417 client.succeed("ip route >&2") 418 client.execute("iptables-save >&2") 419 client.log("##############################################") 420 421 with subtest("Test macvlan creates routable ips"): 422 client.wait_until_succeeds("ping -c 1 192.168.1.1") 423 client.wait_until_succeeds("ping -c 1 192.168.1.2") 424 client.wait_until_succeeds("ping -c 1 192.168.1.3") 425 426 router.wait_until_succeeds("ping -c 1 192.168.1.1") 427 router.wait_until_succeeds("ping -c 1 192.168.1.2") 428 router.wait_until_succeeds("ping -c 1 192.168.1.3") 429 ''; 430 }; 431 fou = { 432 name = "foo-over-udp"; 433 nodes.machine = { ... }: { 434 virtualisation.vlans = [ 1 ]; 435 networking = { 436 useNetworkd = networkd; 437 useDHCP = false; 438 interfaces.eth1.ipv4.addresses = mkOverride 0 439 [ { address = "192.168.1.1"; prefixLength = 24; } ]; 440 fooOverUDP = { 441 fou1 = { port = 9001; }; 442 fou2 = { port = 9002; protocol = 41; }; 443 fou3 = mkIf (!networkd) 444 { port = 9003; local.address = "192.168.1.1"; }; 445 fou4 = mkIf (!networkd) 446 { port = 9004; local = { address = "192.168.1.1"; dev = "eth1"; }; }; 447 }; 448 }; 449 systemd.services = { 450 fou3-fou-encap.after = optional (!networkd) "network-addresses-eth1.service"; 451 }; 452 }; 453 testScript = { ... }: 454 '' 455 import json 456 457 machine.wait_for_unit("network.target") 458 fous = json.loads(machine.succeed("ip -json fou show")) 459 assert {"port": 9001, "gue": None, "family": "inet"} in fous, "fou1 exists" 460 assert {"port": 9002, "ipproto": 41, "family": "inet"} in fous, "fou2 exists" 461 '' + optionalString (!networkd) '' 462 assert { 463 "port": 9003, 464 "gue": None, 465 "family": "inet", 466 "local": "192.168.1.1", 467 } in fous, "fou3 exists" 468 assert { 469 "port": 9004, 470 "gue": None, 471 "family": "inet", 472 "local": "192.168.1.1", 473 "dev": "eth1", 474 } in fous, "fou4 exists" 475 ''; 476 }; 477 sit = let 478 node = { address4, remote, address6 }: { pkgs, ... }: with pkgs.lib; { 479 virtualisation.vlans = [ 1 ]; 480 networking = { 481 useNetworkd = networkd; 482 useDHCP = false; 483 sits.sit = { 484 inherit remote; 485 local = address4; 486 dev = "eth1"; 487 }; 488 interfaces.eth1.ipv4.addresses = mkOverride 0 489 [ { address = address4; prefixLength = 24; } ]; 490 interfaces.sit.ipv6.addresses = mkOverride 0 491 [ { address = address6; prefixLength = 64; } ]; 492 }; 493 }; 494 in { 495 name = "Sit"; 496 # note on firewalling: the two nodes are explicitly asymmetric. 497 # client1 sends SIT packets in UDP, but accepts only proto-41 incoming. 498 # client2 does the reverse, sending in proto-41 and accepting only UDP incoming. 499 # that way we'll notice when either SIT itself or FOU breaks. 500 nodes.client1 = args@{ pkgs, ... }: 501 mkMerge [ 502 (node { address4 = "192.168.1.1"; remote = "192.168.1.2"; address6 = "fc00::1"; } args) 503 { 504 networking = { 505 firewall.extraCommands = "iptables -A INPUT -p 41 -j ACCEPT"; 506 sits.sit.encapsulation = { type = "fou"; port = 9001; }; 507 }; 508 } 509 ]; 510 nodes.client2 = args@{ pkgs, ... }: 511 mkMerge [ 512 (node { address4 = "192.168.1.2"; remote = "192.168.1.1"; address6 = "fc00::2"; } args) 513 { 514 networking = { 515 firewall.allowedUDPPorts = [ 9001 ]; 516 fooOverUDP.fou1 = { port = 9001; protocol = 41; }; 517 }; 518 } 519 ]; 520 testScript = { ... }: 521 '' 522 start_all() 523 524 with subtest("Wait for networking to be configured"): 525 client1.wait_for_unit("network.target") 526 client2.wait_for_unit("network.target") 527 528 # Print diagnostic information 529 client1.succeed("ip addr >&2") 530 client2.succeed("ip addr >&2") 531 532 with subtest("Test ipv6"): 533 client1.wait_until_succeeds("ping -c 1 fc00::1") 534 client1.wait_until_succeeds("ping -c 1 fc00::2") 535 536 client2.wait_until_succeeds("ping -c 1 fc00::1") 537 client2.wait_until_succeeds("ping -c 1 fc00::2") 538 ''; 539 }; 540 gre = let 541 node = { pkgs, ... }: with pkgs.lib; { 542 networking = { 543 useNetworkd = networkd; 544 useDHCP = false; 545 firewall.extraCommands = "ip6tables -A nixos-fw -p gre -j nixos-fw-accept"; 546 }; 547 }; 548 in { 549 name = "GRE"; 550 nodes.client1 = args@{ pkgs, ... }: 551 mkMerge [ 552 (node args) 553 { 554 virtualisation.vlans = [ 1 2 4 ]; 555 networking = { 556 greTunnels = { 557 greTunnel = { 558 local = "192.168.2.1"; 559 remote = "192.168.2.2"; 560 dev = "eth2"; 561 ttl = 225; 562 type = "tap"; 563 }; 564 gre6Tunnel = { 565 local = "fd00:1234:5678:4::1"; 566 remote = "fd00:1234:5678:4::2"; 567 dev = "eth3"; 568 ttl = 255; 569 type = "tun6"; 570 }; 571 }; 572 bridges.bridge.interfaces = [ "greTunnel" "eth1" ]; 573 interfaces.eth1.ipv4.addresses = mkOverride 0 []; 574 interfaces.bridge.ipv4.addresses = mkOverride 0 [ 575 { address = "192.168.1.1"; prefixLength = 24; } 576 ]; 577 interfaces.eth3.ipv6.addresses = [ 578 { address = "fd00:1234:5678:4::1"; prefixLength = 64; } 579 ]; 580 interfaces.gre6Tunnel.ipv6.addresses = mkOverride 0 [ 581 { address = "fc00::1"; prefixLength = 64; } 582 ]; 583 }; 584 } 585 ]; 586 nodes.client2 = args@{ pkgs, ... }: 587 mkMerge [ 588 (node args) 589 { 590 virtualisation.vlans = [ 2 3 4 ]; 591 networking = { 592 greTunnels = { 593 greTunnel = { 594 local = "192.168.2.2"; 595 remote = "192.168.2.1"; 596 dev = "eth1"; 597 ttl = 225; 598 type = "tap"; 599 }; 600 gre6Tunnel = { 601 local = "fd00:1234:5678:4::2"; 602 remote = "fd00:1234:5678:4::1"; 603 dev = "eth3"; 604 ttl = 255; 605 type = "tun6"; 606 }; 607 }; 608 bridges.bridge.interfaces = [ "greTunnel" "eth2" ]; 609 interfaces.eth2.ipv4.addresses = mkOverride 0 []; 610 interfaces.bridge.ipv4.addresses = mkOverride 0 [ 611 { address = "192.168.1.2"; prefixLength = 24; } 612 ]; 613 interfaces.eth3.ipv6.addresses = [ 614 { address = "fd00:1234:5678:4::2"; prefixLength = 64; } 615 ]; 616 interfaces.gre6Tunnel.ipv6.addresses = mkOverride 0 [ 617 { address = "fc00::2"; prefixLength = 64; } 618 ]; 619 }; 620 } 621 ]; 622 testScript = { ... }: 623 '' 624 import json 625 start_all() 626 627 with subtest("Wait for networking to be configured"): 628 client1.wait_for_unit("network.target") 629 client2.wait_for_unit("network.target") 630 631 # Print diagnostic information 632 client1.succeed("ip addr >&2") 633 client2.succeed("ip addr >&2") 634 635 with subtest("Test GRE tunnel bridge over VLAN"): 636 client1.wait_until_succeeds("ping -c 1 192.168.1.2") 637 638 client2.wait_until_succeeds("ping -c 1 192.168.1.1") 639 640 client1.wait_until_succeeds("ping -c 1 fc00::2") 641 642 client2.wait_until_succeeds("ping -c 1 fc00::1") 643 644 with subtest("Test GRE tunnel TTL"): 645 links = json.loads(client1.succeed("ip -details -json link show greTunnel")) 646 assert links[0]['linkinfo']['info_data']['ttl'] == 225, "ttl not set for greTunnel" 647 648 links = json.loads(client2.succeed("ip -details -json link show gre6Tunnel")) 649 assert links[0]['linkinfo']['info_data']['ttl'] == 255, "ttl not set for gre6Tunnel" 650 ''; 651 }; 652 vlan = let 653 node = address: { pkgs, ... }: with pkgs.lib; { 654 #virtualisation.vlans = [ 1 ]; 655 networking = { 656 useNetworkd = networkd; 657 useDHCP = false; 658 vlans.vlan = { 659 id = 1; 660 interface = "eth0"; 661 }; 662 interfaces.eth0.ipv4.addresses = mkOverride 0 [ ]; 663 interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; 664 interfaces.vlan.ipv4.addresses = mkOverride 0 665 [ { inherit address; prefixLength = 24; } ]; 666 }; 667 }; 668 in { 669 name = "vlan"; 670 nodes.client1 = node "192.168.1.1"; 671 nodes.client2 = node "192.168.1.2"; 672 testScript = { ... }: 673 '' 674 start_all() 675 676 with subtest("Wait for networking to be configured"): 677 client1.wait_for_unit("network.target") 678 client2.wait_for_unit("network.target") 679 680 with subtest("Test vlan is setup"): 681 client1.succeed("ip addr show dev vlan >&2") 682 client2.succeed("ip addr show dev vlan >&2") 683 ''; 684 }; 685 vlan-ping = let 686 baseIP = number: "10.10.10.${number}"; 687 vlanIP = number: "10.1.1.${number}"; 688 baseInterface = "eth1"; 689 vlanInterface = "vlan42"; 690 node = number: {pkgs, ... }: with pkgs.lib; { 691 virtualisation.vlans = [ 1 ]; 692 networking = { 693 #useNetworkd = networkd; 694 useDHCP = false; 695 vlans.${vlanInterface} = { id = 42; interface = baseInterface; }; 696 interfaces.${baseInterface}.ipv4.addresses = mkOverride 0 [{ address = baseIP number; prefixLength = 24; }]; 697 interfaces.${vlanInterface}.ipv4.addresses = mkOverride 0 [{ address = vlanIP number; prefixLength = 24; }]; 698 }; 699 }; 700 701 serverNodeNum = "1"; 702 clientNodeNum = "2"; 703 704 in { 705 name = "vlan-ping"; 706 nodes.server = node serverNodeNum; 707 nodes.client = node clientNodeNum; 708 testScript = { ... }: 709 '' 710 start_all() 711 712 with subtest("Wait for networking to be configured"): 713 server.wait_for_unit("network.target") 714 client.wait_for_unit("network.target") 715 716 with subtest("Test ping on base interface in setup"): 717 client.succeed("ping -I ${baseInterface} -c 1 ${baseIP serverNodeNum}") 718 server.succeed("ping -I ${baseInterface} -c 1 ${baseIP clientNodeNum}") 719 720 with subtest("Test ping on vlan subinterface in setup"): 721 client.succeed("ping -I ${vlanInterface} -c 1 ${vlanIP serverNodeNum}") 722 server.succeed("ping -I ${vlanInterface} -c 1 ${vlanIP clientNodeNum}") 723 ''; 724 }; 725 virtual = { 726 name = "Virtual"; 727 nodes.machine = { 728 networking.useNetworkd = networkd; 729 networking.useDHCP = false; 730 networking.interfaces.tap0 = { 731 ipv4.addresses = [ { address = "192.168.1.1"; prefixLength = 24; } ]; 732 ipv6.addresses = [ { address = "2001:1470:fffd:2096::"; prefixLength = 64; } ]; 733 virtual = true; 734 mtu = 1342; 735 macAddress = "02:de:ad:be:ef:01"; 736 }; 737 networking.interfaces.tun0 = { 738 ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ]; 739 ipv6.addresses = [ { address = "2001:1470:fffd:2097::"; prefixLength = 64; } ]; 740 virtual = true; 741 mtu = 1343; 742 }; 743 }; 744 745 testScript = '' 746 targetList = """ 747 tap0: tap persist user 0 748 tun0: tun persist user 0 749 """.strip() 750 751 with subtest("Wait for networking to come up"): 752 machine.start() 753 machine.wait_for_unit("network.target") 754 755 with subtest("Test interfaces set up"): 756 list = machine.succeed("ip tuntap list | sort").strip() 757 assert ( 758 list == targetList 759 ), """ 760 The list of virtual interfaces does not match the expected one: 761 Result: 762 {} 763 Expected: 764 {} 765 """.format( 766 list, targetList 767 ) 768 with subtest("Test MTU and MAC Address are configured"): 769 machine.wait_until_succeeds("ip link show dev tap0 | grep 'mtu 1342'") 770 machine.wait_until_succeeds("ip link show dev tun0 | grep 'mtu 1343'") 771 assert "02:de:ad:be:ef:01" in machine.succeed("ip link show dev tap0") 772 '' # network-addresses-* only exist in scripted networking 773 + optionalString (!networkd) '' 774 with subtest("Test interfaces clean up"): 775 machine.succeed("systemctl stop network-addresses-tap0") 776 machine.sleep(10) 777 machine.succeed("systemctl stop network-addresses-tun0") 778 machine.sleep(10) 779 residue = machine.succeed("ip tuntap list") 780 assert ( 781 residue == "" 782 ), "Some virtual interface has not been properly cleaned:\n{}".format(residue) 783 ''; 784 }; 785 privacy = { 786 name = "Privacy"; 787 nodes.router = { ... }: { 788 virtualisation.vlans = [ 1 ]; 789 boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = true; 790 networking = { 791 useNetworkd = networkd; 792 useDHCP = false; 793 interfaces.eth1.ipv6.addresses = singleton { 794 address = "fd00:1234:5678:1::1"; 795 prefixLength = 64; 796 }; 797 }; 798 services.radvd = { 799 enable = true; 800 config = '' 801 interface eth1 { 802 AdvSendAdvert on; 803 AdvManagedFlag on; 804 AdvOtherConfigFlag on; 805 806 prefix fd00:1234:5678:1::/64 { 807 AdvAutonomous on; 808 AdvOnLink on; 809 }; 810 }; 811 ''; 812 }; 813 }; 814 nodes.client_with_privacy = { pkgs, ... }: with pkgs.lib; { 815 virtualisation.vlans = [ 1 ]; 816 networking = { 817 useNetworkd = networkd; 818 useDHCP = false; 819 interfaces.eth1 = { 820 tempAddress = "default"; 821 ipv4.addresses = mkOverride 0 [ ]; 822 ipv6.addresses = mkOverride 0 [ ]; 823 useDHCP = true; 824 }; 825 }; 826 }; 827 nodes.client = { pkgs, ... }: with pkgs.lib; { 828 virtualisation.vlans = [ 1 ]; 829 networking = { 830 useNetworkd = networkd; 831 useDHCP = false; 832 interfaces.eth1 = { 833 tempAddress = "enabled"; 834 ipv4.addresses = mkOverride 0 [ ]; 835 ipv6.addresses = mkOverride 0 [ ]; 836 useDHCP = true; 837 }; 838 }; 839 }; 840 testScript = { ... }: 841 '' 842 start_all() 843 844 client.wait_for_unit("network.target") 845 client_with_privacy.wait_for_unit("network.target") 846 router.wait_for_unit("network-online.target") 847 848 with subtest("Wait until we have an ip address"): 849 client_with_privacy.wait_until_succeeds( 850 "ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'" 851 ) 852 client.wait_until_succeeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'") 853 854 with subtest("Test vlan 1"): 855 client_with_privacy.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::1") 856 client.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::1") 857 858 with subtest("Test address used is temporary"): 859 client_with_privacy.wait_until_succeeds( 860 "! ip route get fd00:1234:5678:1::1 | grep -q ':[a-f0-9]*ff:fe[a-f0-9]*:'" 861 ) 862 863 with subtest("Test address used is EUI-64"): 864 client.wait_until_succeeds( 865 "ip route get fd00:1234:5678:1::1 | grep -q ':[a-f0-9]*ff:fe[a-f0-9]*:'" 866 ) 867 ''; 868 }; 869 routes = { 870 name = "routes"; 871 nodes.machine = { 872 networking.useNetworkd = networkd; 873 networking.useDHCP = false; 874 networking.interfaces.eth0 = { 875 ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ]; 876 ipv6.addresses = [ { address = "2001:1470:fffd:2097::"; prefixLength = 64; } ]; 877 ipv6.routes = [ 878 { address = "fdfd:b3f0::"; prefixLength = 48; } 879 { address = "2001:1470:fffd:2098::"; prefixLength = 64; via = "fdfd:b3f0::1"; } 880 ]; 881 ipv4.routes = [ 882 { address = "10.0.0.0"; prefixLength = 16; options = { 883 mtu = "1500"; 884 # Explicitly set scope because iproute and systemd-networkd 885 # disagree on what the scope should be 886 # if the type is the default "unicast" 887 scope = "link"; 888 }; } 889 { address = "192.168.2.0"; prefixLength = 24; via = "192.168.1.1"; } 890 ]; 891 }; 892 virtualisation.vlans = [ ]; 893 }; 894 895 testScript = '' 896 targetIPv4Table = [ 897 "10.0.0.0/16 proto static scope link mtu 1500", 898 "192.168.1.0/24 proto kernel scope link src 192.168.1.2", 899 "192.168.2.0/24 via 192.168.1.1 proto static", 900 ] 901 902 targetIPv6Table = [ 903 "2001:1470:fffd:2097::/64 proto kernel metric 256 pref medium", 904 "2001:1470:fffd:2098::/64 via fdfd:b3f0::1 proto static metric 1024 pref medium", 905 "fdfd:b3f0::/48 proto static metric 1024 pref medium", 906 ] 907 908 machine.start() 909 machine.wait_for_unit("network.target") 910 911 with subtest("test routing tables"): 912 ipv4Table = machine.succeed("ip -4 route list dev eth0 | head -n3").strip() 913 ipv6Table = machine.succeed("ip -6 route list dev eth0 | head -n3").strip() 914 assert [ 915 l.strip() for l in ipv4Table.splitlines() 916 ] == targetIPv4Table, """ 917 The IPv4 routing table does not match the expected one: 918 Result: 919 {} 920 Expected: 921 {} 922 """.format( 923 ipv4Table, targetIPv4Table 924 ) 925 assert [ 926 l.strip() for l in ipv6Table.splitlines() 927 ] == targetIPv6Table, """ 928 The IPv6 routing table does not match the expected one: 929 Result: 930 {} 931 Expected: 932 {} 933 """.format( 934 ipv6Table, targetIPv6Table 935 ) 936 937 '' + optionalString (!networkd) '' 938 with subtest("test clean-up of the tables"): 939 machine.succeed("systemctl stop network-addresses-eth0") 940 ipv4Residue = machine.succeed("ip -4 route list dev eth0 | head -n-3").strip() 941 ipv6Residue = machine.succeed("ip -6 route list dev eth0 | head -n-3").strip() 942 assert ( 943 ipv4Residue == "" 944 ), "The IPv4 routing table has not been properly cleaned:\n{}".format(ipv4Residue) 945 assert ( 946 ipv6Residue == "" 947 ), "The IPv6 routing table has not been properly cleaned:\n{}".format(ipv6Residue) 948 ''; 949 }; 950 rename = { 951 name = "RenameInterface"; 952 nodes.machine = { pkgs, ... }: { 953 virtualisation.vlans = [ 1 ]; 954 networking = { 955 useNetworkd = networkd; 956 useDHCP = false; 957 }; 958 } // 959 (if networkd 960 then { systemd.network.links."10-custom_name" = { 961 matchConfig.MACAddress = "52:54:00:12:01:01"; 962 linkConfig.Name = "custom_name"; 963 }; 964 } 965 else { boot.initrd.services.udev.rules = '' 966 SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="52:54:00:12:01:01", KERNEL=="eth*", NAME="custom_name" 967 ''; 968 }); 969 testScript = '' 970 machine.succeed("udevadm settle") 971 print(machine.succeed("ip link show dev custom_name")) 972 ''; 973 }; 974 # even with disabled networkd, systemd.network.links should work 975 # (as it's handled by udev, not networkd) 976 link = { 977 name = "Link"; 978 nodes.client = { pkgs, ... }: { 979 virtualisation.vlans = [ 1 ]; 980 networking = { 981 useNetworkd = networkd; 982 useDHCP = false; 983 }; 984 systemd.network.links."50-foo" = { 985 matchConfig = { 986 Name = "foo"; 987 Driver = "dummy"; 988 }; 989 linkConfig.MTUBytes = "1442"; 990 }; 991 }; 992 testScript = '' 993 print(client.succeed("ip l add name foo type dummy")) 994 print(client.succeed("stat /etc/systemd/network/50-foo.link")) 995 client.succeed("udevadm settle") 996 assert "mtu 1442" in client.succeed("ip l show dev foo") 997 ''; 998 }; 999 wlanInterface = let 1000 testMac = "06:00:00:00:02:00"; 1001 in { 1002 name = "WlanInterface"; 1003 nodes.machine = { pkgs, ... }: { 1004 boot.kernelModules = [ "mac80211_hwsim" ]; 1005 networking.wlanInterfaces = { 1006 wlan0 = { device = "wlan0"; }; 1007 wap0 = { device = "wlan0"; mac = testMac; }; 1008 }; 1009 }; 1010 testScript = '' 1011 machine.start() 1012 machine.wait_for_unit("network.target") 1013 machine.wait_until_succeeds("ip address show wap0 | grep -q ${testMac}") 1014 machine.fail("ip address show wlan0 | grep -q ${testMac}") 1015 ''; 1016 }; 1017 }; 1018 1019in mapAttrs (const (attrs: makeTest (attrs // { 1020 name = "${attrs.name}-Networking-${if networkd then "Networkd" else "Scripted"}"; 1021}))) testCases