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 ipAddress = "192.168.${toString n}.1";
25 prefixLength = 24;
26 ipv6Address = "fd00:1234:5678:${toString n}::1";
27 ipv6PrefixLength = 64;
28 })));
29 };
30 services.dhcpd4 = {
31 enable = true;
32 interfaces = map (n: "eth${toString n}") vlanIfs;
33 extraConfig = ''
34 authoritative;
35 '' + 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 # XXX: technically it's _not guaranteed_ that IP addresses will be
39 # issued from the first item in range onwards! We assume that in
40 # our tests however.
41 range 192.168.${toString n}.2 192.168.${toString n}.254;
42 }
43 '');
44 };
45 services.radvd = {
46 enable = true;
47 config = flip concatMapStrings vlanIfs (n: ''
48 interface eth${toString n} {
49 AdvSendAdvert on;
50 AdvManagedFlag on;
51 AdvOtherConfigFlag on;
52
53 prefix fd00:1234:5678:${toString n}::/64 {
54 AdvAutonomous off;
55 };
56 };
57 '');
58 };
59 services.dhcpd6 = {
60 enable = true;
61 interfaces = map (n: "eth${toString n}") vlanIfs;
62 extraConfig = ''
63 authoritative;
64 '' + flip concatMapStrings vlanIfs (n: ''
65 subnet6 fd00:1234:5678:${toString n}::/64 {
66 range6 fd00:1234:5678:${toString n}::2 fd00:1234:5678:${toString n}::2;
67 }
68 '');
69 };
70 };
71
72 testCases = {
73 loopback = {
74 name = "Loopback";
75 machine.networking.useNetworkd = networkd;
76 testScript = ''
77 startAll;
78 $machine->waitForUnit("network.target");
79 $machine->succeed("ip addr show lo | grep -q 'inet 127.0.0.1/8 '");
80 $machine->succeed("ip addr show lo | grep -q 'inet6 ::1/128 '");
81 '';
82 };
83 static = {
84 name = "Static";
85 nodes.router = router;
86 nodes.client = { config, pkgs, ... }: with pkgs.lib; {
87 virtualisation.vlans = [ 1 2 ];
88 networking = {
89 useNetworkd = networkd;
90 firewall.allowPing = true;
91 useDHCP = false;
92 defaultGateway = "192.168.1.1";
93 interfaces.eth1.ip4 = mkOverride 0 [
94 { address = "192.168.1.2"; prefixLength = 24; }
95 { address = "192.168.1.3"; prefixLength = 32; }
96 { address = "192.168.1.10"; prefixLength = 32; }
97 ];
98 interfaces.eth2.ip4 = mkOverride 0 [
99 { address = "192.168.2.2"; prefixLength = 24; }
100 ];
101 };
102 };
103 testScript = { nodes, ... }:
104 ''
105 startAll;
106
107 $client->waitForUnit("network.target");
108 $router->waitForUnit("network.target");
109
110 # Make sure dhcpcd is not started
111 $client->fail("systemctl status dhcpcd.service");
112
113 # Test vlan 1
114 $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
115 $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
116 $client->waitUntilSucceeds("ping -c 1 192.168.1.3");
117 $client->waitUntilSucceeds("ping -c 1 192.168.1.10");
118
119 $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
120 $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
121 $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
122 $router->waitUntilSucceeds("ping -c 1 192.168.1.10");
123
124 # Test vlan 2
125 $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
126 $client->waitUntilSucceeds("ping -c 1 192.168.2.2");
127
128 $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
129 $router->waitUntilSucceeds("ping -c 1 192.168.2.2");
130
131 # Test default gateway
132 $router->waitUntilSucceeds("ping -c 1 192.168.3.1");
133 $client->waitUntilSucceeds("ping -c 1 192.168.3.1");
134 '';
135 };
136 dhcpSimple = {
137 name = "SimpleDHCP";
138 nodes.router = router;
139 nodes.client = { config, pkgs, ... }: with pkgs.lib; {
140 virtualisation.vlans = [ 1 2 ];
141 networking = {
142 useNetworkd = networkd;
143 firewall.allowPing = true;
144 useDHCP = true;
145 interfaces.eth1 = {
146 ip4 = mkOverride 0 [ ];
147 ip6 = mkOverride 0 [ ];
148 };
149 interfaces.eth2 = {
150 ip4 = mkOverride 0 [ ];
151 ip6 = mkOverride 0 [ ];
152 };
153 };
154 };
155 testScript = { nodes, ... }:
156 ''
157 startAll;
158
159 $client->waitForUnit("network.target");
160 $router->waitForUnit("network.target");
161
162 # Wait until we have an ip address on each interface
163 $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
164 $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'");
165 $client->waitUntilSucceeds("ip addr show dev eth2 | grep -q '192.168.2'");
166 $client->waitUntilSucceeds("ip addr show dev eth2 | grep -q 'fd00:1234:5678:2:'");
167
168 # Test vlan 1
169 $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
170 $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
171 $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::1");
172 $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::2");
173
174 $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
175 $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
176 $router->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::1");
177 $router->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::2");
178
179 # Test vlan 2
180 $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
181 $client->waitUntilSucceeds("ping -c 1 192.168.2.2");
182 $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:2::1");
183 $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:2::2");
184
185 $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
186 $router->waitUntilSucceeds("ping -c 1 192.168.2.2");
187 $router->waitUntilSucceeds("ping -c 1 fd00:1234:5678:2::1");
188 $router->waitUntilSucceeds("ping -c 1 fd00:1234:5678:2::2");
189 '';
190 };
191 dhcpOneIf = {
192 name = "OneInterfaceDHCP";
193 nodes.router = router;
194 nodes.client = { config, pkgs, ... }: with pkgs.lib; {
195 virtualisation.vlans = [ 1 2 ];
196 networking = {
197 useNetworkd = networkd;
198 firewall.allowPing = true;
199 useDHCP = false;
200 interfaces.eth1 = {
201 ip4 = mkOverride 0 [ ];
202 useDHCP = true;
203 };
204 interfaces.eth2.ip4 = mkOverride 0 [ ];
205 };
206 };
207 testScript = { nodes, ... }:
208 ''
209 startAll;
210
211 # Wait for networking to come up
212 $client->waitForUnit("network.target");
213 $router->waitForUnit("network.target");
214
215 # Wait until we have an ip address on each interface
216 $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
217
218 # Test vlan 1
219 $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
220 $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
221
222 $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
223 $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
224
225 # Test vlan 2
226 $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
227 $client->fail("ping -c 1 192.168.2.2");
228
229 $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
230 $router->fail("ping -c 1 192.168.2.2");
231 '';
232 };
233 bond = let
234 node = address: { config, pkgs, ... }: with pkgs.lib; {
235 virtualisation.vlans = [ 1 2 ];
236 networking = {
237 useNetworkd = networkd;
238 firewall.allowPing = true;
239 useDHCP = false;
240 bonds.bond = {
241 interfaces = [ "eth1" "eth2" ];
242 driverOptions.mode = "balance-rr";
243 };
244 interfaces.eth1.ip4 = mkOverride 0 [ ];
245 interfaces.eth2.ip4 = mkOverride 0 [ ];
246 interfaces.bond.ip4 = mkOverride 0
247 [ { inherit address; prefixLength = 30; } ];
248 };
249 };
250 in {
251 name = "Bond";
252 nodes.client1 = node "192.168.1.1";
253 nodes.client2 = node "192.168.1.2";
254 testScript = { nodes, ... }:
255 ''
256 startAll;
257
258 # Wait for networking to come up
259 $client1->waitForUnit("network.target");
260 $client2->waitForUnit("network.target");
261
262 # Test bonding
263 $client1->waitUntilSucceeds("ping -c 2 192.168.1.1");
264 $client1->waitUntilSucceeds("ping -c 2 192.168.1.2");
265
266 $client2->waitUntilSucceeds("ping -c 2 192.168.1.1");
267 $client2->waitUntilSucceeds("ping -c 2 192.168.1.2");
268 '';
269 };
270 bridge = let
271 node = { address, vlan }: { config, pkgs, ... }: with pkgs.lib; {
272 virtualisation.vlans = [ vlan ];
273 networking = {
274 useNetworkd = networkd;
275 firewall.allowPing = true;
276 useDHCP = false;
277 interfaces.eth1.ip4 = mkOverride 0
278 [ { inherit address; prefixLength = 24; } ];
279 };
280 };
281 in {
282 name = "Bridge";
283 nodes.client1 = node { address = "192.168.1.2"; vlan = 1; };
284 nodes.client2 = node { address = "192.168.1.3"; vlan = 2; };
285 nodes.router = { config, pkgs, ... }: with pkgs.lib; {
286 virtualisation.vlans = [ 1 2 ];
287 networking = {
288 useNetworkd = networkd;
289 firewall.allowPing = true;
290 useDHCP = false;
291 bridges.bridge.interfaces = [ "eth1" "eth2" ];
292 interfaces.eth1.ip4 = mkOverride 0 [ ];
293 interfaces.eth2.ip4 = mkOverride 0 [ ];
294 interfaces.bridge.ip4 = mkOverride 0
295 [ { address = "192.168.1.1"; prefixLength = 24; } ];
296 };
297 };
298 testScript = { nodes, ... }:
299 ''
300 startAll;
301
302 # Wait for networking to come up
303 $client1->waitForUnit("network.target");
304 $client2->waitForUnit("network.target");
305 $router->waitForUnit("network.target");
306
307 # Test bridging
308 $client1->waitUntilSucceeds("ping -c 1 192.168.1.1");
309 $client1->waitUntilSucceeds("ping -c 1 192.168.1.2");
310 $client1->waitUntilSucceeds("ping -c 1 192.168.1.3");
311
312 $client2->waitUntilSucceeds("ping -c 1 192.168.1.1");
313 $client2->waitUntilSucceeds("ping -c 1 192.168.1.2");
314 $client2->waitUntilSucceeds("ping -c 1 192.168.1.3");
315
316 $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
317 $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
318 $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
319 '';
320 };
321 macvlan = {
322 name = "MACVLAN";
323 nodes.router = router;
324 nodes.client = { config, pkgs, ... }: with pkgs.lib; {
325 virtualisation.vlans = [ 1 ];
326 networking = {
327 useNetworkd = networkd;
328 firewall.allowPing = true;
329 useDHCP = true;
330 macvlans.macvlan.interface = "eth1";
331 interfaces.eth1.ip4 = mkOverride 0 [ ];
332 };
333 };
334 testScript = { nodes, ... }:
335 ''
336 startAll;
337
338 # Wait for networking to come up
339 $client->waitForUnit("network.target");
340 $router->waitForUnit("network.target");
341
342 # Wait until we have an ip address on each interface
343 $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
344 $client->waitUntilSucceeds("ip addr show dev macvlan | grep -q '192.168.1'");
345
346 # Print diagnosting information
347 $router->succeed("ip addr >&2");
348 $client->succeed("ip addr >&2");
349
350 # Test macvlan creates routable ips
351 $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
352 $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
353 $client->waitUntilSucceeds("ping -c 1 192.168.1.3");
354
355 $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
356 $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
357 $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
358 '';
359 };
360 sit = let
361 node = { address4, remote, address6 }: { config, pkgs, ... }: with pkgs.lib; {
362 virtualisation.vlans = [ 1 ];
363 networking = {
364 useNetworkd = networkd;
365 firewall.enable = false;
366 useDHCP = false;
367 sits.sit = {
368 inherit remote;
369 local = address4;
370 dev = "eth1";
371 };
372 interfaces.eth1.ip4 = mkOverride 0
373 [ { address = address4; prefixLength = 24; } ];
374 interfaces.sit.ip6 = mkOverride 0
375 [ { address = address6; prefixLength = 64; } ];
376 };
377 };
378 in {
379 name = "Sit";
380 nodes.client1 = node { address4 = "192.168.1.1"; remote = "192.168.1.2"; address6 = "fc00::1"; };
381 nodes.client2 = node { address4 = "192.168.1.2"; remote = "192.168.1.1"; address6 = "fc00::2"; };
382 testScript = { nodes, ... }:
383 ''
384 startAll;
385
386 # Wait for networking to be configured
387 $client1->waitForUnit("network.target");
388 $client2->waitForUnit("network.target");
389
390 # Print diagnostic information
391 $client1->succeed("ip addr >&2");
392 $client2->succeed("ip addr >&2");
393
394 # Test ipv6
395 $client1->waitUntilSucceeds("ping -c 1 fc00::1");
396 $client1->waitUntilSucceeds("ping -c 1 fc00::2");
397
398 $client2->waitUntilSucceeds("ping -c 1 fc00::1");
399 $client2->waitUntilSucceeds("ping -c 1 fc00::2");
400 '';
401 };
402 vlan = let
403 node = address: { config, pkgs, ... }: with pkgs.lib; {
404 #virtualisation.vlans = [ 1 ];
405 networking = {
406 useNetworkd = networkd;
407 firewall.allowPing = true;
408 useDHCP = false;
409 vlans.vlan = {
410 id = 1;
411 interface = "eth0";
412 };
413 interfaces.eth0.ip4 = mkOverride 0 [ ];
414 interfaces.eth1.ip4 = mkOverride 0 [ ];
415 interfaces.vlan.ip4 = mkOverride 0
416 [ { inherit address; prefixLength = 24; } ];
417 };
418 };
419 in {
420 name = "vlan";
421 nodes.client1 = node "192.168.1.1";
422 nodes.client2 = node "192.168.1.2";
423 testScript = { nodes, ... }:
424 ''
425 startAll;
426
427 # Wait for networking to be configured
428 $client1->waitForUnit("network.target");
429 $client2->waitForUnit("network.target");
430
431 # Test vlan is setup
432 $client1->succeed("ip addr show dev vlan >&2");
433 $client2->succeed("ip addr show dev vlan >&2");
434 '';
435 };
436 };
437
438in mapAttrs (const (attrs: makeTest (attrs // {
439 name = "${attrs.name}-Networking-${if networkd then "Networkd" else "Scripted"}";
440 meta = with pkgs.stdenv.lib.maintainers; {
441 maintainers = [ wkennington ];
442 };
443}))) testCases