at 22.05-pre 30 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 machine.networking.useDHCP = false; 81 machine.networking.useNetworkd = networkd; 82 testScript = '' 83 start_all() 84 machine.wait_for_unit("network.target") 85 loopback_addresses = machine.succeed("ip addr show lo") 86 assert "inet 127.0.0.1/8" in loopback_addresses 87 assert "inet6 ::1/128" in loopback_addresses 88 ''; 89 }; 90 static = { 91 name = "Static"; 92 nodes.router = router; 93 nodes.client = { pkgs, ... }: with pkgs.lib; { 94 virtualisation.vlans = [ 1 2 ]; 95 networking = { 96 useNetworkd = networkd; 97 useDHCP = false; 98 defaultGateway = "192.168.1.1"; 99 interfaces.eth1.ipv4.addresses = mkOverride 0 [ 100 { address = "192.168.1.2"; prefixLength = 24; } 101 { address = "192.168.1.3"; prefixLength = 32; } 102 { address = "192.168.1.10"; prefixLength = 32; } 103 ]; 104 interfaces.eth2.ipv4.addresses = mkOverride 0 [ 105 { address = "192.168.2.2"; prefixLength = 24; } 106 ]; 107 }; 108 }; 109 testScript = { ... }: 110 '' 111 start_all() 112 113 client.wait_for_unit("network.target") 114 router.wait_for_unit("network-online.target") 115 116 with subtest("Make sure dhcpcd is not started"): 117 client.fail("systemctl status dhcpcd.service") 118 119 with subtest("Test vlan 1"): 120 client.wait_until_succeeds("ping -c 1 192.168.1.1") 121 client.wait_until_succeeds("ping -c 1 192.168.1.2") 122 client.wait_until_succeeds("ping -c 1 192.168.1.3") 123 client.wait_until_succeeds("ping -c 1 192.168.1.10") 124 125 router.wait_until_succeeds("ping -c 1 192.168.1.1") 126 router.wait_until_succeeds("ping -c 1 192.168.1.2") 127 router.wait_until_succeeds("ping -c 1 192.168.1.3") 128 router.wait_until_succeeds("ping -c 1 192.168.1.10") 129 130 with subtest("Test vlan 2"): 131 client.wait_until_succeeds("ping -c 1 192.168.2.1") 132 client.wait_until_succeeds("ping -c 1 192.168.2.2") 133 134 router.wait_until_succeeds("ping -c 1 192.168.2.1") 135 router.wait_until_succeeds("ping -c 1 192.168.2.2") 136 137 with subtest("Test default gateway"): 138 router.wait_until_succeeds("ping -c 1 192.168.3.1") 139 client.wait_until_succeeds("ping -c 1 192.168.3.1") 140 ''; 141 }; 142 dhcpSimple = { 143 name = "SimpleDHCP"; 144 nodes.router = router; 145 nodes.client = { pkgs, ... }: with pkgs.lib; { 146 virtualisation.vlans = [ 1 2 ]; 147 networking = { 148 useNetworkd = networkd; 149 useDHCP = false; 150 interfaces.eth1 = { 151 ipv4.addresses = mkOverride 0 [ ]; 152 ipv6.addresses = mkOverride 0 [ ]; 153 useDHCP = true; 154 }; 155 interfaces.eth2 = { 156 ipv4.addresses = mkOverride 0 [ ]; 157 ipv6.addresses = mkOverride 0 [ ]; 158 useDHCP = true; 159 }; 160 }; 161 }; 162 testScript = { ... }: 163 '' 164 start_all() 165 166 client.wait_for_unit("network.target") 167 router.wait_for_unit("network-online.target") 168 169 with subtest("Wait until we have an ip address on each interface"): 170 client.wait_until_succeeds("ip addr show dev eth1 | grep -q '192.168.1'") 171 client.wait_until_succeeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'") 172 client.wait_until_succeeds("ip addr show dev eth2 | grep -q '192.168.2'") 173 client.wait_until_succeeds("ip addr show dev eth2 | grep -q 'fd00:1234:5678:2:'") 174 175 with subtest("Test vlan 1"): 176 client.wait_until_succeeds("ping -c 1 192.168.1.1") 177 client.wait_until_succeeds("ping -c 1 192.168.1.2") 178 client.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::1") 179 client.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::2") 180 181 router.wait_until_succeeds("ping -c 1 192.168.1.1") 182 router.wait_until_succeeds("ping -c 1 192.168.1.2") 183 router.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::1") 184 router.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::2") 185 186 with subtest("Test vlan 2"): 187 client.wait_until_succeeds("ping -c 1 192.168.2.1") 188 client.wait_until_succeeds("ping -c 1 192.168.2.2") 189 client.wait_until_succeeds("ping -c 1 fd00:1234:5678:2::1") 190 client.wait_until_succeeds("ping -c 1 fd00:1234:5678:2::2") 191 192 router.wait_until_succeeds("ping -c 1 192.168.2.1") 193 router.wait_until_succeeds("ping -c 1 192.168.2.2") 194 router.wait_until_succeeds("ping -c 1 fd00:1234:5678:2::1") 195 router.wait_until_succeeds("ping -c 1 fd00:1234:5678:2::2") 196 ''; 197 }; 198 dhcpOneIf = { 199 name = "OneInterfaceDHCP"; 200 nodes.router = router; 201 nodes.client = { pkgs, ... }: with pkgs.lib; { 202 virtualisation.vlans = [ 1 2 ]; 203 networking = { 204 useNetworkd = networkd; 205 useDHCP = false; 206 interfaces.eth1 = { 207 ipv4.addresses = mkOverride 0 [ ]; 208 mtu = 1343; 209 useDHCP = true; 210 }; 211 interfaces.eth2.ipv4.addresses = mkOverride 0 [ ]; 212 }; 213 }; 214 testScript = { ... }: 215 '' 216 start_all() 217 218 with subtest("Wait for networking to come up"): 219 client.wait_for_unit("network.target") 220 router.wait_for_unit("network.target") 221 222 with subtest("Wait until we have an ip address on each interface"): 223 client.wait_until_succeeds("ip addr show dev eth1 | grep -q '192.168.1'") 224 225 with subtest("ensure MTU is set"): 226 assert "mtu 1343" in client.succeed("ip link show dev eth1") 227 228 with subtest("Test vlan 1"): 229 client.wait_until_succeeds("ping -c 1 192.168.1.1") 230 client.wait_until_succeeds("ping -c 1 192.168.1.2") 231 232 router.wait_until_succeeds("ping -c 1 192.168.1.1") 233 router.wait_until_succeeds("ping -c 1 192.168.1.2") 234 235 with subtest("Test vlan 2"): 236 client.wait_until_succeeds("ping -c 1 192.168.2.1") 237 client.fail("ping -c 1 192.168.2.2") 238 239 router.wait_until_succeeds("ping -c 1 192.168.2.1") 240 router.fail("ping -c 1 192.168.2.2") 241 ''; 242 }; 243 bond = let 244 node = address: { pkgs, ... }: with pkgs.lib; { 245 virtualisation.vlans = [ 1 2 ]; 246 networking = { 247 useNetworkd = networkd; 248 useDHCP = false; 249 bonds.bond = { 250 interfaces = [ "eth1" "eth2" ]; 251 driverOptions.mode = "balance-rr"; 252 }; 253 interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; 254 interfaces.eth2.ipv4.addresses = mkOverride 0 [ ]; 255 interfaces.bond.ipv4.addresses = mkOverride 0 256 [ { inherit address; prefixLength = 30; } ]; 257 }; 258 }; 259 in { 260 name = "Bond"; 261 nodes.client1 = node "192.168.1.1"; 262 nodes.client2 = node "192.168.1.2"; 263 testScript = { ... }: 264 '' 265 start_all() 266 267 with subtest("Wait for networking to come up"): 268 client1.wait_for_unit("network.target") 269 client2.wait_for_unit("network.target") 270 271 with subtest("Test bonding"): 272 client1.wait_until_succeeds("ping -c 2 192.168.1.1") 273 client1.wait_until_succeeds("ping -c 2 192.168.1.2") 274 275 client2.wait_until_succeeds("ping -c 2 192.168.1.1") 276 client2.wait_until_succeeds("ping -c 2 192.168.1.2") 277 ''; 278 }; 279 bridge = let 280 node = { address, vlan }: { pkgs, ... }: with pkgs.lib; { 281 virtualisation.vlans = [ vlan ]; 282 networking = { 283 useNetworkd = networkd; 284 useDHCP = false; 285 interfaces.eth1.ipv4.addresses = mkOverride 0 286 [ { inherit address; prefixLength = 24; } ]; 287 }; 288 }; 289 in { 290 name = "Bridge"; 291 nodes.client1 = node { address = "192.168.1.2"; vlan = 1; }; 292 nodes.client2 = node { address = "192.168.1.3"; vlan = 2; }; 293 nodes.router = { pkgs, ... }: with pkgs.lib; { 294 virtualisation.vlans = [ 1 2 ]; 295 networking = { 296 useNetworkd = networkd; 297 useDHCP = false; 298 bridges.bridge.interfaces = [ "eth1" "eth2" ]; 299 interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; 300 interfaces.eth2.ipv4.addresses = mkOverride 0 [ ]; 301 interfaces.bridge.ipv4.addresses = mkOverride 0 302 [ { address = "192.168.1.1"; prefixLength = 24; } ]; 303 }; 304 }; 305 testScript = { ... }: 306 '' 307 start_all() 308 309 with subtest("Wait for networking to come up"): 310 for machine in client1, client2, router: 311 machine.wait_for_unit("network.target") 312 313 with subtest("Test bridging"): 314 client1.wait_until_succeeds("ping -c 1 192.168.1.1") 315 client1.wait_until_succeeds("ping -c 1 192.168.1.2") 316 client1.wait_until_succeeds("ping -c 1 192.168.1.3") 317 318 client2.wait_until_succeeds("ping -c 1 192.168.1.1") 319 client2.wait_until_succeeds("ping -c 1 192.168.1.2") 320 client2.wait_until_succeeds("ping -c 1 192.168.1.3") 321 322 router.wait_until_succeeds("ping -c 1 192.168.1.1") 323 router.wait_until_succeeds("ping -c 1 192.168.1.2") 324 router.wait_until_succeeds("ping -c 1 192.168.1.3") 325 ''; 326 }; 327 macvlan = { 328 name = "MACVLAN"; 329 nodes.router = router; 330 nodes.client = { pkgs, ... }: with pkgs.lib; { 331 environment.systemPackages = [ pkgs.iptables ]; # to debug firewall rules 332 virtualisation.vlans = [ 1 ]; 333 networking = { 334 useNetworkd = networkd; 335 useDHCP = false; 336 firewall.logReversePathDrops = true; # to debug firewall rules 337 # reverse path filtering rules for the macvlan interface seem 338 # to be incorrect, causing the test to fail. Disable temporarily. 339 firewall.checkReversePath = false; 340 macvlans.macvlan.interface = "eth1"; 341 interfaces.eth1 = { 342 ipv4.addresses = mkOverride 0 [ ]; 343 useDHCP = true; 344 }; 345 interfaces.macvlan = { 346 useDHCP = true; 347 }; 348 }; 349 }; 350 testScript = { ... }: 351 '' 352 start_all() 353 354 with subtest("Wait for networking to come up"): 355 client.wait_for_unit("network.target") 356 router.wait_for_unit("network.target") 357 358 with subtest("Wait until we have an ip address on each interface"): 359 client.wait_until_succeeds("ip addr show dev eth1 | grep -q '192.168.1'") 360 client.wait_until_succeeds("ip addr show dev macvlan | grep -q '192.168.1'") 361 362 with subtest("Print lots of diagnostic information"): 363 router.log("**********************************************") 364 router.succeed("ip addr >&2") 365 router.succeed("ip route >&2") 366 router.execute("iptables-save >&2") 367 client.log("==============================================") 368 client.succeed("ip addr >&2") 369 client.succeed("ip route >&2") 370 client.execute("iptables-save >&2") 371 client.log("##############################################") 372 373 with subtest("Test macvlan creates routable ips"): 374 client.wait_until_succeeds("ping -c 1 192.168.1.1") 375 client.wait_until_succeeds("ping -c 1 192.168.1.2") 376 client.wait_until_succeeds("ping -c 1 192.168.1.3") 377 378 router.wait_until_succeeds("ping -c 1 192.168.1.1") 379 router.wait_until_succeeds("ping -c 1 192.168.1.2") 380 router.wait_until_succeeds("ping -c 1 192.168.1.3") 381 ''; 382 }; 383 fou = { 384 name = "foo-over-udp"; 385 nodes.machine = { ... }: { 386 virtualisation.vlans = [ 1 ]; 387 networking = { 388 useNetworkd = networkd; 389 useDHCP = false; 390 interfaces.eth1.ipv4.addresses = mkOverride 0 391 [ { address = "192.168.1.1"; prefixLength = 24; } ]; 392 fooOverUDP = { 393 fou1 = { port = 9001; }; 394 fou2 = { port = 9002; protocol = 41; }; 395 fou3 = mkIf (!networkd) 396 { port = 9003; local.address = "192.168.1.1"; }; 397 fou4 = mkIf (!networkd) 398 { port = 9004; local = { address = "192.168.1.1"; dev = "eth1"; }; }; 399 }; 400 }; 401 systemd.services = { 402 fou3-fou-encap.after = optional (!networkd) "network-addresses-eth1.service"; 403 }; 404 }; 405 testScript = { ... }: 406 '' 407 import json 408 409 machine.wait_for_unit("network.target") 410 fous = json.loads(machine.succeed("ip -json fou show")) 411 assert {"port": 9001, "gue": None, "family": "inet"} in fous, "fou1 exists" 412 assert {"port": 9002, "ipproto": 41, "family": "inet"} in fous, "fou2 exists" 413 '' + optionalString (!networkd) '' 414 assert { 415 "port": 9003, 416 "gue": None, 417 "family": "inet", 418 "local": "192.168.1.1", 419 } in fous, "fou3 exists" 420 assert { 421 "port": 9004, 422 "gue": None, 423 "family": "inet", 424 "local": "192.168.1.1", 425 "dev": "eth1", 426 } in fous, "fou4 exists" 427 ''; 428 }; 429 sit = let 430 node = { address4, remote, address6 }: { pkgs, ... }: with pkgs.lib; { 431 virtualisation.vlans = [ 1 ]; 432 networking = { 433 useNetworkd = networkd; 434 useDHCP = false; 435 sits.sit = { 436 inherit remote; 437 local = address4; 438 dev = "eth1"; 439 }; 440 interfaces.eth1.ipv4.addresses = mkOverride 0 441 [ { address = address4; prefixLength = 24; } ]; 442 interfaces.sit.ipv6.addresses = mkOverride 0 443 [ { address = address6; prefixLength = 64; } ]; 444 }; 445 }; 446 in { 447 name = "Sit"; 448 # note on firewalling: the two nodes are explicitly asymmetric. 449 # client1 sends SIT packets in UDP, but accepts only proto-41 incoming. 450 # client2 does the reverse, sending in proto-41 and accepting only UDP incoming. 451 # that way we'll notice when either SIT itself or FOU breaks. 452 nodes.client1 = args@{ pkgs, ... }: 453 mkMerge [ 454 (node { address4 = "192.168.1.1"; remote = "192.168.1.2"; address6 = "fc00::1"; } args) 455 { 456 networking = { 457 firewall.extraCommands = "iptables -A INPUT -p 41 -j ACCEPT"; 458 sits.sit.encapsulation = { type = "fou"; port = 9001; }; 459 }; 460 } 461 ]; 462 nodes.client2 = args@{ pkgs, ... }: 463 mkMerge [ 464 (node { address4 = "192.168.1.2"; remote = "192.168.1.1"; address6 = "fc00::2"; } args) 465 { 466 networking = { 467 firewall.allowedUDPPorts = [ 9001 ]; 468 fooOverUDP.fou1 = { port = 9001; protocol = 41; }; 469 }; 470 } 471 ]; 472 testScript = { ... }: 473 '' 474 start_all() 475 476 with subtest("Wait for networking to be configured"): 477 client1.wait_for_unit("network.target") 478 client2.wait_for_unit("network.target") 479 480 # Print diagnostic information 481 client1.succeed("ip addr >&2") 482 client2.succeed("ip addr >&2") 483 484 with subtest("Test ipv6"): 485 client1.wait_until_succeeds("ping -c 1 fc00::1") 486 client1.wait_until_succeeds("ping -c 1 fc00::2") 487 488 client2.wait_until_succeeds("ping -c 1 fc00::1") 489 client2.wait_until_succeeds("ping -c 1 fc00::2") 490 ''; 491 }; 492 vlan = let 493 node = address: { pkgs, ... }: with pkgs.lib; { 494 #virtualisation.vlans = [ 1 ]; 495 networking = { 496 useNetworkd = networkd; 497 useDHCP = false; 498 vlans.vlan = { 499 id = 1; 500 interface = "eth0"; 501 }; 502 interfaces.eth0.ipv4.addresses = mkOverride 0 [ ]; 503 interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; 504 interfaces.vlan.ipv4.addresses = mkOverride 0 505 [ { inherit address; prefixLength = 24; } ]; 506 }; 507 }; 508 in { 509 name = "vlan"; 510 nodes.client1 = node "192.168.1.1"; 511 nodes.client2 = node "192.168.1.2"; 512 testScript = { ... }: 513 '' 514 start_all() 515 516 with subtest("Wait for networking to be configured"): 517 client1.wait_for_unit("network.target") 518 client2.wait_for_unit("network.target") 519 520 with subtest("Test vlan is setup"): 521 client1.succeed("ip addr show dev vlan >&2") 522 client2.succeed("ip addr show dev vlan >&2") 523 ''; 524 }; 525 virtual = { 526 name = "Virtual"; 527 machine = { 528 networking.useNetworkd = networkd; 529 networking.useDHCP = false; 530 networking.interfaces.tap0 = { 531 ipv4.addresses = [ { address = "192.168.1.1"; prefixLength = 24; } ]; 532 ipv6.addresses = [ { address = "2001:1470:fffd:2096::"; prefixLength = 64; } ]; 533 virtual = true; 534 mtu = 1342; 535 macAddress = "02:de:ad:be:ef:01"; 536 }; 537 networking.interfaces.tun0 = { 538 ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ]; 539 ipv6.addresses = [ { address = "2001:1470:fffd:2097::"; prefixLength = 64; } ]; 540 virtual = true; 541 mtu = 1343; 542 }; 543 }; 544 545 testScript = '' 546 targetList = """ 547 tap0: tap persist user 0 548 tun0: tun persist user 0 549 """.strip() 550 551 with subtest("Wait for networking to come up"): 552 machine.start() 553 machine.wait_for_unit("network.target") 554 555 with subtest("Test interfaces set up"): 556 list = machine.succeed("ip tuntap list | sort").strip() 557 assert ( 558 list == targetList 559 ), """ 560 The list of virtual interfaces does not match the expected one: 561 Result: 562 {} 563 Expected: 564 {} 565 """.format( 566 list, targetList 567 ) 568 with subtest("Test MTU and MAC Address are configured"): 569 machine.wait_until_succeeds("ip link show dev tap0 | grep 'mtu 1342'") 570 machine.wait_until_succeeds("ip link show dev tun0 | grep 'mtu 1343'") 571 assert "02:de:ad:be:ef:01" in machine.succeed("ip link show dev tap0") 572 '' # network-addresses-* only exist in scripted networking 573 + optionalString (!networkd) '' 574 with subtest("Test interfaces clean up"): 575 machine.succeed("systemctl stop network-addresses-tap0") 576 machine.sleep(10) 577 machine.succeed("systemctl stop network-addresses-tun0") 578 machine.sleep(10) 579 residue = machine.succeed("ip tuntap list") 580 assert ( 581 residue == "" 582 ), "Some virtual interface has not been properly cleaned:\n{}".format(residue) 583 ''; 584 }; 585 privacy = { 586 name = "Privacy"; 587 nodes.router = { ... }: { 588 virtualisation.vlans = [ 1 ]; 589 boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = true; 590 networking = { 591 useNetworkd = networkd; 592 useDHCP = false; 593 interfaces.eth1.ipv6.addresses = singleton { 594 address = "fd00:1234:5678:1::1"; 595 prefixLength = 64; 596 }; 597 }; 598 services.radvd = { 599 enable = true; 600 config = '' 601 interface eth1 { 602 AdvSendAdvert on; 603 AdvManagedFlag on; 604 AdvOtherConfigFlag on; 605 606 prefix fd00:1234:5678:1::/64 { 607 AdvAutonomous on; 608 AdvOnLink on; 609 }; 610 }; 611 ''; 612 }; 613 }; 614 nodes.client_with_privacy = { pkgs, ... }: with pkgs.lib; { 615 virtualisation.vlans = [ 1 ]; 616 networking = { 617 useNetworkd = networkd; 618 useDHCP = false; 619 interfaces.eth1 = { 620 tempAddress = "default"; 621 ipv4.addresses = mkOverride 0 [ ]; 622 ipv6.addresses = mkOverride 0 [ ]; 623 useDHCP = true; 624 }; 625 }; 626 }; 627 nodes.client = { pkgs, ... }: with pkgs.lib; { 628 virtualisation.vlans = [ 1 ]; 629 networking = { 630 useNetworkd = networkd; 631 useDHCP = false; 632 interfaces.eth1 = { 633 tempAddress = "enabled"; 634 ipv4.addresses = mkOverride 0 [ ]; 635 ipv6.addresses = mkOverride 0 [ ]; 636 useDHCP = true; 637 }; 638 }; 639 }; 640 testScript = { ... }: 641 '' 642 start_all() 643 644 client.wait_for_unit("network.target") 645 client_with_privacy.wait_for_unit("network.target") 646 router.wait_for_unit("network-online.target") 647 648 with subtest("Wait until we have an ip address"): 649 client_with_privacy.wait_until_succeeds( 650 "ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'" 651 ) 652 client.wait_until_succeeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'") 653 654 with subtest("Test vlan 1"): 655 client_with_privacy.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::1") 656 client.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::1") 657 658 with subtest("Test address used is temporary"): 659 client_with_privacy.wait_until_succeeds( 660 "! ip route get fd00:1234:5678:1::1 | grep -q ':[a-f0-9]*ff:fe[a-f0-9]*:'" 661 ) 662 663 with subtest("Test address used is EUI-64"): 664 client.wait_until_succeeds( 665 "ip route get fd00:1234:5678:1::1 | grep -q ':[a-f0-9]*ff:fe[a-f0-9]*:'" 666 ) 667 ''; 668 }; 669 routes = { 670 name = "routes"; 671 machine = { 672 networking.useDHCP = false; 673 networking.interfaces.eth0 = { 674 ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ]; 675 ipv6.addresses = [ { address = "2001:1470:fffd:2097::"; prefixLength = 64; } ]; 676 ipv6.routes = [ 677 { address = "fdfd:b3f0::"; prefixLength = 48; } 678 { address = "2001:1470:fffd:2098::"; prefixLength = 64; via = "fdfd:b3f0::1"; } 679 ]; 680 ipv4.routes = [ 681 { address = "10.0.0.0"; prefixLength = 16; options = { mtu = "1500"; }; } 682 { address = "192.168.2.0"; prefixLength = 24; via = "192.168.1.1"; } 683 ]; 684 }; 685 virtualisation.vlans = [ ]; 686 }; 687 688 testScript = '' 689 targetIPv4Table = [ 690 "10.0.0.0/16 proto static scope link mtu 1500", 691 "192.168.1.0/24 proto kernel scope link src 192.168.1.2", 692 "192.168.2.0/24 via 192.168.1.1 proto static", 693 ] 694 695 targetIPv6Table = [ 696 "2001:1470:fffd:2097::/64 proto kernel metric 256 pref medium", 697 "2001:1470:fffd:2098::/64 via fdfd:b3f0::1 proto static metric 1024 pref medium", 698 "fdfd:b3f0::/48 proto static metric 1024 pref medium", 699 ] 700 701 machine.start() 702 machine.wait_for_unit("network.target") 703 704 with subtest("test routing tables"): 705 ipv4Table = machine.succeed("ip -4 route list dev eth0 | head -n3").strip() 706 ipv6Table = machine.succeed("ip -6 route list dev eth0 | head -n3").strip() 707 assert [ 708 l.strip() for l in ipv4Table.splitlines() 709 ] == targetIPv4Table, """ 710 The IPv4 routing table does not match the expected one: 711 Result: 712 {} 713 Expected: 714 {} 715 """.format( 716 ipv4Table, targetIPv4Table 717 ) 718 assert [ 719 l.strip() for l in ipv6Table.splitlines() 720 ] == targetIPv6Table, """ 721 The IPv6 routing table does not match the expected one: 722 Result: 723 {} 724 Expected: 725 {} 726 """.format( 727 ipv6Table, targetIPv6Table 728 ) 729 730 with subtest("test clean-up of the tables"): 731 machine.succeed("systemctl stop network-addresses-eth0") 732 ipv4Residue = machine.succeed("ip -4 route list dev eth0 | head -n-3").strip() 733 ipv6Residue = machine.succeed("ip -6 route list dev eth0 | head -n-3").strip() 734 assert ( 735 ipv4Residue == "" 736 ), "The IPv4 routing table has not been properly cleaned:\n{}".format(ipv4Residue) 737 assert ( 738 ipv6Residue == "" 739 ), "The IPv6 routing table has not been properly cleaned:\n{}".format(ipv6Residue) 740 ''; 741 }; 742 rename = { 743 name = "RenameInterface"; 744 machine = { pkgs, ... }: { 745 virtualisation.vlans = [ 1 ]; 746 networking = { 747 useNetworkd = networkd; 748 useDHCP = false; 749 }; 750 } // 751 (if networkd 752 then { systemd.network.links."10-custom_name" = { 753 matchConfig.MACAddress = "52:54:00:12:01:01"; 754 linkConfig.Name = "custom_name"; 755 }; 756 } 757 else { services.udev.initrdRules = '' 758 SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="52:54:00:12:01:01", KERNEL=="eth*", NAME="custom_name" 759 ''; 760 }); 761 testScript = '' 762 machine.succeed("udevadm settle") 763 print(machine.succeed("ip link show dev custom_name")) 764 ''; 765 }; 766 # even with disabled networkd, systemd.network.links should work 767 # (as it's handled by udev, not networkd) 768 link = { 769 name = "Link"; 770 nodes.client = { pkgs, ... }: { 771 virtualisation.vlans = [ 1 ]; 772 networking = { 773 useNetworkd = networkd; 774 useDHCP = false; 775 }; 776 systemd.network.links."50-foo" = { 777 matchConfig = { 778 Name = "foo"; 779 Driver = "dummy"; 780 }; 781 linkConfig.MTUBytes = "1442"; 782 }; 783 }; 784 testScript = '' 785 print(client.succeed("ip l add name foo type dummy")) 786 print(client.succeed("stat /etc/systemd/network/50-foo.link")) 787 client.succeed("udevadm settle") 788 assert "mtu 1442" in client.succeed("ip l show dummy0") 789 ''; 790 }; 791 wlanInterface = let 792 testMac = "06:00:00:00:02:00"; 793 in { 794 name = "WlanInterface"; 795 machine = { pkgs, ... }: { 796 boot.kernelModules = [ "mac80211_hwsim" ]; 797 networking.wlanInterfaces = { 798 wlan0 = { device = "wlan0"; }; 799 wap0 = { device = "wlan0"; mac = testMac; }; 800 }; 801 }; 802 testScript = '' 803 machine.start() 804 machine.wait_for_unit("network.target") 805 machine.wait_until_succeeds("ip address show wap0 | grep -q ${testMac}") 806 machine.fail("ip address show wlan0 | grep -q ${testMac}") 807 ''; 808 }; 809 }; 810 811in mapAttrs (const (attrs: makeTest (attrs // { 812 name = "${attrs.name}-Networking-${if networkd then "Networkd" else "Scripted"}"; 813}))) testCases