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