1import ./make-test.nix ({ pkgs, networkd, test, ... }:
2 let
3 router = { config, pkgs, ... }:
4 with pkgs.lib;
5 let
6 vlanIfs = range 1 (length config.virtualisation.vlans);
7 in {
8 virtualisation.vlans = [ 1 2 3 ];
9 networking = {
10 useDHCP = false;
11 useNetworkd = networkd;
12 firewall.allowPing = true;
13 interfaces = mkOverride 0 (listToAttrs (flip map vlanIfs (n:
14 nameValuePair "eth${toString n}" {
15 ipAddress = "192.168.${toString n}.1";
16 prefixLength = 24;
17 })));
18 };
19 services.dhcpd = {
20 enable = true;
21 interfaces = map (n: "eth${toString n}") vlanIfs;
22 extraConfig = ''
23 option subnet-mask 255.255.255.0;
24 '' + flip concatMapStrings vlanIfs (n: ''
25 subnet 192.168.${toString n}.0 netmask 255.255.255.0 {
26 option broadcast-address 192.168.${toString n}.255;
27 option routers 192.168.${toString n}.1;
28 range 192.168.${toString n}.2 192.168.${toString n}.254;
29 }
30 '');
31 };
32 };
33 testCases = {
34 static = {
35 name = "Static";
36 nodes.router = router;
37 nodes.client = { config, pkgs, ... }: with pkgs.lib; {
38 virtualisation.vlans = [ 1 2 ];
39 networking = {
40 useNetworkd = networkd;
41 firewall.allowPing = true;
42 useDHCP = false;
43 defaultGateway = "192.168.1.1";
44 interfaces.eth1.ip4 = mkOverride 0 [
45 { address = "192.168.1.2"; prefixLength = 24; }
46 { address = "192.168.1.3"; prefixLength = 32; }
47 { address = "192.168.1.10"; prefixLength = 32; }
48 ];
49 interfaces.eth2.ip4 = mkOverride 0 [
50 { address = "192.168.2.2"; prefixLength = 24; }
51 ];
52 };
53 };
54 testScript = { nodes, ... }:
55 ''
56 startAll;
57
58 $client->waitForUnit("network-interfaces.target");
59 $client->waitForUnit("network.target");
60 $router->waitForUnit("network-interfaces.target");
61 $router->waitForUnit("network.target");
62
63 # Make sure dhcpcd is not started
64 $client->fail("systemctl status dhcpcd.service");
65
66 # Test vlan 1
67 $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
68 $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
69 $client->waitUntilSucceeds("ping -c 1 192.168.1.3");
70 $client->waitUntilSucceeds("ping -c 1 192.168.1.10");
71
72 $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
73 $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
74 $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
75 $router->waitUntilSucceeds("ping -c 1 192.168.1.10");
76
77 # Test vlan 2
78 $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
79 $client->waitUntilSucceeds("ping -c 1 192.168.2.2");
80
81 $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
82 $router->waitUntilSucceeds("ping -c 1 192.168.2.2");
83
84 # Test default gateway
85 $router->waitUntilSucceeds("ping -c 1 192.168.3.1");
86 $client->waitUntilSucceeds("ping -c 1 192.168.3.1");
87 '';
88 };
89 dhcpSimple = {
90 name = "SimpleDHCP";
91 nodes.router = router;
92 nodes.client = { config, pkgs, ... }: with pkgs.lib; {
93 virtualisation.vlans = [ 1 2 ];
94 networking = {
95 useNetworkd = networkd;
96 firewall.allowPing = true;
97 useDHCP = true;
98 interfaces.eth1.ip4 = mkOverride 0 [ ];
99 interfaces.eth2.ip4 = mkOverride 0 [ ];
100 };
101 };
102 testScript = { nodes, ... }:
103 ''
104 startAll;
105
106 $client->waitForUnit("network-interfaces.target");
107 $client->waitForUnit("network.target");
108 $router->waitForUnit("network-interfaces.target");
109 $router->waitForUnit("network.target");
110
111 # Wait until we have an ip address on each interface
112 $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
113 $client->waitUntilSucceeds("ip addr show dev eth2 | grep -q '192.168.2'");
114
115 # Test vlan 1
116 $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
117 $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
118
119 $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
120 $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
121
122 # Test vlan 2
123 $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
124 $client->waitUntilSucceeds("ping -c 1 192.168.2.2");
125
126 $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
127 $router->waitUntilSucceeds("ping -c 1 192.168.2.2");
128 '';
129 };
130 dhcpOneIf = {
131 name = "OneInterfaceDHCP";
132 nodes.router = router;
133 nodes.client = { config, pkgs, ... }: with pkgs.lib; {
134 virtualisation.vlans = [ 1 2 ];
135 networking = {
136 useNetworkd = networkd;
137 firewall.allowPing = true;
138 useDHCP = false;
139 interfaces.eth1 = {
140 ip4 = mkOverride 0 [ ];
141 useDHCP = true;
142 };
143 interfaces.eth2.ip4 = mkOverride 0 [ ];
144 };
145 };
146 testScript = { nodes, ... }:
147 ''
148 startAll;
149
150 # Wait for networking to come up
151 $client->waitForUnit("network-interfaces.target");
152 $client->waitForUnit("network.target");
153 $router->waitForUnit("network-interfaces.target");
154 $router->waitForUnit("network.target");
155
156 # Wait until we have an ip address on each interface
157 $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
158
159 # Test vlan 1
160 $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
161 $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
162
163 $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
164 $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
165
166 # Test vlan 2
167 $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
168 $client->fail("ping -c 1 192.168.2.2");
169
170 $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
171 $router->fail("ping -c 1 192.168.2.2");
172 '';
173 };
174 bond = let
175 node = address: { config, pkgs, ... }: with pkgs.lib; {
176 virtualisation.vlans = [ 1 2 ];
177 networking = {
178 useNetworkd = networkd;
179 firewall.allowPing = true;
180 useDHCP = false;
181 bonds.bond = {
182 mode = "balance-rr";
183 interfaces = [ "eth1" "eth2" ];
184 };
185 interfaces.eth1.ip4 = mkOverride 0 [ ];
186 interfaces.eth2.ip4 = mkOverride 0 [ ];
187 interfaces.bond.ip4 = mkOverride 0
188 [ { inherit address; prefixLength = 30; } ];
189 };
190 };
191 in {
192 name = "Bond";
193 nodes.client1 = node "192.168.1.1";
194 nodes.client2 = node "192.168.1.2";
195 testScript = { nodes, ... }:
196 ''
197 startAll;
198
199 # Wait for networking to come up
200 $client1->waitForUnit("network-interfaces.target");
201 $client1->waitForUnit("network.target");
202 $client2->waitForUnit("network-interfaces.target");
203 $client2->waitForUnit("network.target");
204
205 # Test bonding
206 $client1->waitUntilSucceeds("ping -c 2 192.168.1.1");
207 $client1->waitUntilSucceeds("ping -c 2 192.168.1.2");
208
209 $client2->waitUntilSucceeds("ping -c 2 192.168.1.1");
210 $client2->waitUntilSucceeds("ping -c 2 192.168.1.2");
211 '';
212 };
213 bridge = let
214 node = { address, vlan }: { config, pkgs, ... }: with pkgs.lib; {
215 virtualisation.vlans = [ vlan ];
216 networking = {
217 useNetworkd = networkd;
218 firewall.allowPing = true;
219 useDHCP = false;
220 interfaces.eth1.ip4 = mkOverride 0
221 [ { inherit address; prefixLength = 24; } ];
222 };
223 };
224 in {
225 name = "Bridge";
226 nodes.client1 = node { address = "192.168.1.2"; vlan = 1; };
227 nodes.client2 = node { address = "192.168.1.3"; vlan = 2; };
228 nodes.router = { config, pkgs, ... }: with pkgs.lib; {
229 virtualisation.vlans = [ 1 2 ];
230 networking = {
231 useNetworkd = networkd;
232 firewall.allowPing = true;
233 useDHCP = false;
234 bridges.bridge.interfaces = [ "eth1" "eth2" ];
235 interfaces.eth1.ip4 = mkOverride 0 [ ];
236 interfaces.eth2.ip4 = mkOverride 0 [ ];
237 interfaces.bridge.ip4 = mkOverride 0
238 [ { address = "192.168.1.1"; prefixLength = 24; } ];
239 };
240 };
241 testScript = { nodes, ... }:
242 ''
243 startAll;
244
245 # Wait for networking to come up
246 $client1->waitForUnit("network-interfaces.target");
247 $client1->waitForUnit("network.target");
248 $client2->waitForUnit("network-interfaces.target");
249 $client2->waitForUnit("network.target");
250 $router->waitForUnit("network-interfaces.target");
251 $router->waitForUnit("network.target");
252
253 # Test bridging
254 $client1->waitUntilSucceeds("ping -c 1 192.168.1.1");
255 $client1->waitUntilSucceeds("ping -c 1 192.168.1.2");
256 $client1->waitUntilSucceeds("ping -c 1 192.168.1.3");
257
258 $client2->waitUntilSucceeds("ping -c 1 192.168.1.1");
259 $client2->waitUntilSucceeds("ping -c 1 192.168.1.2");
260 $client2->waitUntilSucceeds("ping -c 1 192.168.1.3");
261
262 $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
263 $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
264 $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
265 '';
266 };
267 macvlan = {
268 name = "MACVLAN";
269 nodes.router = router;
270 nodes.client = { config, pkgs, ... }: with pkgs.lib; {
271 virtualisation.vlans = [ 1 ];
272 networking = {
273 useNetworkd = networkd;
274 firewall.allowPing = true;
275 useDHCP = true;
276 macvlans.macvlan.interface = "eth1";
277 interfaces.eth1.ip4 = mkOverride 0 [ ];
278 };
279 };
280 testScript = { nodes, ... }:
281 ''
282 startAll;
283
284 # Wait for networking to come up
285 $client->waitForUnit("network-interfaces.target");
286 $client->waitForUnit("network.target");
287 $router->waitForUnit("network-interfaces.target");
288 $router->waitForUnit("network.target");
289
290 # Wait until we have an ip address on each interface
291 $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
292 $client->waitUntilSucceeds("ip addr show dev macvlan | grep -q '192.168.1'");
293
294 # Print diagnosting information
295 $router->succeed("ip addr >&2");
296 $client->succeed("ip addr >&2");
297
298 # Test macvlan creates routable ips
299 $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
300 $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
301 $client->waitUntilSucceeds("ping -c 1 192.168.1.3");
302
303 $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
304 $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
305 $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
306 '';
307 };
308 sit = let
309 node = { address4, remote, address6 }: { config, pkgs, ... }: with pkgs.lib; {
310 virtualisation.vlans = [ 1 ];
311 networking = {
312 useNetworkd = networkd;
313 firewall.enable = false;
314 useDHCP = false;
315 sits.sit = {
316 inherit remote;
317 local = address4;
318 dev = "eth1";
319 };
320 interfaces.eth1.ip4 = mkOverride 0
321 [ { address = address4; prefixLength = 24; } ];
322 interfaces.sit.ip6 = mkOverride 0
323 [ { address = address6; prefixLength = 64; } ];
324 };
325 };
326 in {
327 name = "Sit";
328 nodes.client1 = node { address4 = "192.168.1.1"; remote = "192.168.1.2"; address6 = "fc00::1"; };
329 nodes.client2 = node { address4 = "192.168.1.2"; remote = "192.168.1.1"; address6 = "fc00::2"; };
330 testScript = { nodes, ... }:
331 ''
332 startAll;
333
334 # Wait for networking to be configured
335 $client1->waitForUnit("network-interfaces.target");
336 $client1->waitForUnit("network.target");
337 $client2->waitForUnit("network-interfaces.target");
338 $client2->waitForUnit("network.target");
339
340 # Print diagnostic information
341 $client1->succeed("ip addr >&2");
342 $client2->succeed("ip addr >&2");
343
344 # Test ipv6
345 $client1->waitUntilSucceeds("ping6 -c 1 fc00::1");
346 $client1->waitUntilSucceeds("ping6 -c 1 fc00::2");
347
348 $client2->waitUntilSucceeds("ping6 -c 1 fc00::1");
349 $client2->waitUntilSucceeds("ping6 -c 1 fc00::2");
350 '';
351 };
352 vlan = let
353 node = address: { config, pkgs, ... }: with pkgs.lib; {
354 #virtualisation.vlans = [ 1 ];
355 networking = {
356 useNetworkd = networkd;
357 firewall.allowPing = true;
358 useDHCP = false;
359 vlans.vlan = {
360 id = 1;
361 interface = "eth0";
362 };
363 interfaces.eth0.ip4 = mkOverride 0 [ ];
364 interfaces.eth1.ip4 = mkOverride 0 [ ];
365 interfaces.vlan.ip4 = mkOverride 0
366 [ { inherit address; prefixLength = 24; } ];
367 };
368 };
369 in {
370 name = "vlan";
371 nodes.client1 = node "192.168.1.1";
372 nodes.client2 = node "192.168.1.2";
373 testScript = { nodes, ... }:
374 ''
375 startAll;
376
377 # Wait for networking to be configured
378 $client1->waitForUnit("network-interfaces.target");
379 $client1->waitForUnit("network.target");
380 $client2->waitForUnit("network-interfaces.target");
381 $client2->waitForUnit("network.target");
382
383 # Test vlan is setup
384 $client1->succeed("ip addr show dev vlan >&2");
385 $client2->succeed("ip addr show dev vlan >&2");
386 '';
387 };
388 };
389 case = testCases.${test};
390 in case // {
391 name = "${case.name}-Networking-${if networkd then "Networkd" else "Scripted"}";
392 meta = with pkgs.stdenv.lib.maintainers; {
393 maintainers = [ wkennington ];
394 };
395 })