You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

networking.nix 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. { system ? builtins.currentSystem
  2. , config ? {}
  3. , pkgs ? import ../.. { inherit system config; }
  4. # bool: whether to use networkd in the tests
  5. , networkd }:
  6. with import ../lib/testing.nix { inherit system pkgs; };
  7. with pkgs.lib;
  8. let
  9. router = { config, pkgs, ... }:
  10. with pkgs.lib;
  11. let
  12. vlanIfs = range 1 (length config.virtualisation.vlans);
  13. in {
  14. environment.systemPackages = [ pkgs.iptables ]; # to debug firewall rules
  15. virtualisation.vlans = [ 1 2 3 ];
  16. boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = true;
  17. networking = {
  18. useDHCP = false;
  19. useNetworkd = networkd;
  20. firewall.checkReversePath = true;
  21. firewall.allowedUDPPorts = [ 547 ];
  22. interfaces = mkOverride 0 (listToAttrs (forEach vlanIfs (n:
  23. nameValuePair "eth${toString n}" {
  24. ipv4.addresses = [ { address = "192.168.${toString n}.1"; prefixLength = 24; } ];
  25. ipv6.addresses = [ { address = "fd00:1234:5678:${toString n}::1"; prefixLength = 64; } ];
  26. })));
  27. };
  28. services.dhcpd4 = {
  29. enable = true;
  30. interfaces = map (n: "eth${toString n}") vlanIfs;
  31. extraConfig = ''
  32. authoritative;
  33. '' + flip concatMapStrings vlanIfs (n: ''
  34. subnet 192.168.${toString n}.0 netmask 255.255.255.0 {
  35. option routers 192.168.${toString n}.1;
  36. # XXX: technically it's _not guaranteed_ that IP addresses will be
  37. # issued from the first item in range onwards! We assume that in
  38. # our tests however.
  39. range 192.168.${toString n}.2 192.168.${toString n}.254;
  40. }
  41. '');
  42. };
  43. services.radvd = {
  44. enable = true;
  45. config = flip concatMapStrings vlanIfs (n: ''
  46. interface eth${toString n} {
  47. AdvSendAdvert on;
  48. AdvManagedFlag on;
  49. AdvOtherConfigFlag on;
  50. prefix fd00:1234:5678:${toString n}::/64 {
  51. AdvAutonomous off;
  52. };
  53. };
  54. '');
  55. };
  56. services.dhcpd6 = {
  57. enable = true;
  58. interfaces = map (n: "eth${toString n}") vlanIfs;
  59. extraConfig = ''
  60. authoritative;
  61. '' + flip concatMapStrings vlanIfs (n: ''
  62. subnet6 fd00:1234:5678:${toString n}::/64 {
  63. range6 fd00:1234:5678:${toString n}::2 fd00:1234:5678:${toString n}::2;
  64. }
  65. '');
  66. };
  67. };
  68. testCases = {
  69. loopback = {
  70. name = "Loopback";
  71. machine.networking.useDHCP = false;
  72. machine.networking.useNetworkd = networkd;
  73. testScript = ''
  74. startAll;
  75. $machine->waitForUnit("network.target");
  76. $machine->succeed("ip addr show lo | grep -q 'inet 127.0.0.1/8 '");
  77. $machine->succeed("ip addr show lo | grep -q 'inet6 ::1/128 '");
  78. '';
  79. };
  80. static = {
  81. name = "Static";
  82. nodes.router = router;
  83. nodes.client = { pkgs, ... }: with pkgs.lib; {
  84. virtualisation.vlans = [ 1 2 ];
  85. networking = {
  86. useNetworkd = networkd;
  87. useDHCP = false;
  88. defaultGateway = "192.168.1.1";
  89. interfaces.eth1.ipv4.addresses = mkOverride 0 [
  90. { address = "192.168.1.2"; prefixLength = 24; }
  91. { address = "192.168.1.3"; prefixLength = 32; }
  92. { address = "192.168.1.10"; prefixLength = 32; }
  93. ];
  94. interfaces.eth2.ipv4.addresses = mkOverride 0 [
  95. { address = "192.168.2.2"; prefixLength = 24; }
  96. ];
  97. };
  98. };
  99. testScript = { ... }:
  100. ''
  101. startAll;
  102. $client->waitForUnit("network.target");
  103. $router->waitForUnit("network-online.target");
  104. # Make sure dhcpcd is not started
  105. $client->fail("systemctl status dhcpcd.service");
  106. # Test vlan 1
  107. $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
  108. $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
  109. $client->waitUntilSucceeds("ping -c 1 192.168.1.3");
  110. $client->waitUntilSucceeds("ping -c 1 192.168.1.10");
  111. $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
  112. $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
  113. $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
  114. $router->waitUntilSucceeds("ping -c 1 192.168.1.10");
  115. # Test vlan 2
  116. $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
  117. $client->waitUntilSucceeds("ping -c 1 192.168.2.2");
  118. $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
  119. $router->waitUntilSucceeds("ping -c 1 192.168.2.2");
  120. # Test default gateway
  121. $router->waitUntilSucceeds("ping -c 1 192.168.3.1");
  122. $client->waitUntilSucceeds("ping -c 1 192.168.3.1");
  123. '';
  124. };
  125. dhcpSimple = {
  126. name = "SimpleDHCP";
  127. nodes.router = router;
  128. nodes.client = { pkgs, ... }: with pkgs.lib; {
  129. virtualisation.vlans = [ 1 2 ];
  130. networking = {
  131. useNetworkd = networkd;
  132. useDHCP = false;
  133. interfaces.eth1 = {
  134. ipv4.addresses = mkOverride 0 [ ];
  135. ipv6.addresses = mkOverride 0 [ ];
  136. useDHCP = true;
  137. };
  138. interfaces.eth2 = {
  139. ipv4.addresses = mkOverride 0 [ ];
  140. ipv6.addresses = mkOverride 0 [ ];
  141. useDHCP = true;
  142. };
  143. };
  144. };
  145. testScript = { ... }:
  146. ''
  147. startAll;
  148. $client->waitForUnit("network.target");
  149. $router->waitForUnit("network-online.target");
  150. # Wait until we have an ip address on each interface
  151. $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
  152. $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'");
  153. $client->waitUntilSucceeds("ip addr show dev eth2 | grep -q '192.168.2'");
  154. $client->waitUntilSucceeds("ip addr show dev eth2 | grep -q 'fd00:1234:5678:2:'");
  155. # Test vlan 1
  156. $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
  157. $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
  158. $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::1");
  159. $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::2");
  160. $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
  161. $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
  162. $router->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::1");
  163. $router->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::2");
  164. # Test vlan 2
  165. $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
  166. $client->waitUntilSucceeds("ping -c 1 192.168.2.2");
  167. $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:2::1");
  168. $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:2::2");
  169. $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
  170. $router->waitUntilSucceeds("ping -c 1 192.168.2.2");
  171. $router->waitUntilSucceeds("ping -c 1 fd00:1234:5678:2::1");
  172. $router->waitUntilSucceeds("ping -c 1 fd00:1234:5678:2::2");
  173. '';
  174. };
  175. dhcpOneIf = {
  176. name = "OneInterfaceDHCP";
  177. nodes.router = router;
  178. nodes.client = { pkgs, ... }: with pkgs.lib; {
  179. virtualisation.vlans = [ 1 2 ];
  180. networking = {
  181. useNetworkd = networkd;
  182. useDHCP = false;
  183. interfaces.eth1 = {
  184. ipv4.addresses = mkOverride 0 [ ];
  185. useDHCP = true;
  186. };
  187. interfaces.eth2.ipv4.addresses = mkOverride 0 [ ];
  188. };
  189. };
  190. testScript = { ... }:
  191. ''
  192. startAll;
  193. # Wait for networking to come up
  194. $client->waitForUnit("network.target");
  195. $router->waitForUnit("network.target");
  196. # Wait until we have an ip address on each interface
  197. $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
  198. # Test vlan 1
  199. $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
  200. $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
  201. $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
  202. $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
  203. # Test vlan 2
  204. $client->waitUntilSucceeds("ping -c 1 192.168.2.1");
  205. $client->fail("ping -c 1 192.168.2.2");
  206. $router->waitUntilSucceeds("ping -c 1 192.168.2.1");
  207. $router->fail("ping -c 1 192.168.2.2");
  208. '';
  209. };
  210. bond = let
  211. node = address: { pkgs, ... }: with pkgs.lib; {
  212. virtualisation.vlans = [ 1 2 ];
  213. networking = {
  214. useNetworkd = networkd;
  215. useDHCP = false;
  216. bonds.bond = {
  217. interfaces = [ "eth1" "eth2" ];
  218. driverOptions.mode = "balance-rr";
  219. };
  220. interfaces.eth1.ipv4.addresses = mkOverride 0 [ ];
  221. interfaces.eth2.ipv4.addresses = mkOverride 0 [ ];
  222. interfaces.bond.ipv4.addresses = mkOverride 0
  223. [ { inherit address; prefixLength = 30; } ];
  224. };
  225. };
  226. in {
  227. name = "Bond";
  228. nodes.client1 = node "192.168.1.1";
  229. nodes.client2 = node "192.168.1.2";
  230. testScript = { ... }:
  231. ''
  232. startAll;
  233. # Wait for networking to come up
  234. $client1->waitForUnit("network.target");
  235. $client2->waitForUnit("network.target");
  236. # Test bonding
  237. $client1->waitUntilSucceeds("ping -c 2 192.168.1.1");
  238. $client1->waitUntilSucceeds("ping -c 2 192.168.1.2");
  239. $client2->waitUntilSucceeds("ping -c 2 192.168.1.1");
  240. $client2->waitUntilSucceeds("ping -c 2 192.168.1.2");
  241. '';
  242. };
  243. bridge = let
  244. node = { address, vlan }: { pkgs, ... }: with pkgs.lib; {
  245. virtualisation.vlans = [ vlan ];
  246. networking = {
  247. useNetworkd = networkd;
  248. useDHCP = false;
  249. interfaces.eth1.ipv4.addresses = mkOverride 0
  250. [ { inherit address; prefixLength = 24; } ];
  251. };
  252. };
  253. in {
  254. name = "Bridge";
  255. nodes.client1 = node { address = "192.168.1.2"; vlan = 1; };
  256. nodes.client2 = node { address = "192.168.1.3"; vlan = 2; };
  257. nodes.router = { pkgs, ... }: with pkgs.lib; {
  258. virtualisation.vlans = [ 1 2 ];
  259. networking = {
  260. useNetworkd = networkd;
  261. useDHCP = false;
  262. bridges.bridge.interfaces = [ "eth1" "eth2" ];
  263. interfaces.eth1.ipv4.addresses = mkOverride 0 [ ];
  264. interfaces.eth2.ipv4.addresses = mkOverride 0 [ ];
  265. interfaces.bridge.ipv4.addresses = mkOverride 0
  266. [ { address = "192.168.1.1"; prefixLength = 24; } ];
  267. };
  268. };
  269. testScript = { ... }:
  270. ''
  271. startAll;
  272. # Wait for networking to come up
  273. $client1->waitForUnit("network.target");
  274. $client2->waitForUnit("network.target");
  275. $router->waitForUnit("network.target");
  276. # Test bridging
  277. $client1->waitUntilSucceeds("ping -c 1 192.168.1.1");
  278. $client1->waitUntilSucceeds("ping -c 1 192.168.1.2");
  279. $client1->waitUntilSucceeds("ping -c 1 192.168.1.3");
  280. $client2->waitUntilSucceeds("ping -c 1 192.168.1.1");
  281. $client2->waitUntilSucceeds("ping -c 1 192.168.1.2");
  282. $client2->waitUntilSucceeds("ping -c 1 192.168.1.3");
  283. $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
  284. $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
  285. $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
  286. '';
  287. };
  288. macvlan = {
  289. name = "MACVLAN";
  290. nodes.router = router;
  291. nodes.client = { pkgs, ... }: with pkgs.lib; {
  292. environment.systemPackages = [ pkgs.iptables ]; # to debug firewall rules
  293. virtualisation.vlans = [ 1 ];
  294. networking = {
  295. useNetworkd = networkd;
  296. useDHCP = false;
  297. firewall.logReversePathDrops = true; # to debug firewall rules
  298. # reverse path filtering rules for the macvlan interface seem
  299. # to be incorrect, causing the test to fail. Disable temporarily.
  300. firewall.checkReversePath = false;
  301. macvlans.macvlan.interface = "eth1";
  302. interfaces.eth1 = {
  303. ipv4.addresses = mkOverride 0 [ ];
  304. useDHCP = true;
  305. };
  306. interfaces.macvlan = {
  307. useDHCP = true;
  308. };
  309. };
  310. };
  311. testScript = { ... }:
  312. ''
  313. startAll;
  314. # Wait for networking to come up
  315. $client->waitForUnit("network.target");
  316. $router->waitForUnit("network.target");
  317. # Wait until we have an ip address on each interface
  318. $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
  319. $client->waitUntilSucceeds("ip addr show dev macvlan | grep -q '192.168.1'");
  320. # Print lots of diagnostic information
  321. $router->log('**********************************************');
  322. $router->succeed("ip addr >&2");
  323. $router->succeed("ip route >&2");
  324. $router->execute("iptables-save >&2");
  325. $client->log('==============================================');
  326. $client->succeed("ip addr >&2");
  327. $client->succeed("ip route >&2");
  328. $client->execute("iptables-save >&2");
  329. $client->log('##############################################');
  330. # Test macvlan creates routable ips
  331. $client->waitUntilSucceeds("ping -c 1 192.168.1.1");
  332. $client->waitUntilSucceeds("ping -c 1 192.168.1.2");
  333. $client->waitUntilSucceeds("ping -c 1 192.168.1.3");
  334. $router->waitUntilSucceeds("ping -c 1 192.168.1.1");
  335. $router->waitUntilSucceeds("ping -c 1 192.168.1.2");
  336. $router->waitUntilSucceeds("ping -c 1 192.168.1.3");
  337. '';
  338. };
  339. sit = let
  340. node = { address4, remote, address6 }: { pkgs, ... }: with pkgs.lib; {
  341. virtualisation.vlans = [ 1 ];
  342. networking = {
  343. useNetworkd = networkd;
  344. firewall.enable = false;
  345. useDHCP = false;
  346. sits.sit = {
  347. inherit remote;
  348. local = address4;
  349. dev = "eth1";
  350. };
  351. interfaces.eth1.ipv4.addresses = mkOverride 0
  352. [ { address = address4; prefixLength = 24; } ];
  353. interfaces.sit.ipv6.addresses = mkOverride 0
  354. [ { address = address6; prefixLength = 64; } ];
  355. };
  356. };
  357. in {
  358. name = "Sit";
  359. nodes.client1 = node { address4 = "192.168.1.1"; remote = "192.168.1.2"; address6 = "fc00::1"; };
  360. nodes.client2 = node { address4 = "192.168.1.2"; remote = "192.168.1.1"; address6 = "fc00::2"; };
  361. testScript = { ... }:
  362. ''
  363. startAll;
  364. # Wait for networking to be configured
  365. $client1->waitForUnit("network.target");
  366. $client2->waitForUnit("network.target");
  367. # Print diagnostic information
  368. $client1->succeed("ip addr >&2");
  369. $client2->succeed("ip addr >&2");
  370. # Test ipv6
  371. $client1->waitUntilSucceeds("ping -c 1 fc00::1");
  372. $client1->waitUntilSucceeds("ping -c 1 fc00::2");
  373. $client2->waitUntilSucceeds("ping -c 1 fc00::1");
  374. $client2->waitUntilSucceeds("ping -c 1 fc00::2");
  375. '';
  376. };
  377. vlan = let
  378. node = address: { pkgs, ... }: with pkgs.lib; {
  379. #virtualisation.vlans = [ 1 ];
  380. networking = {
  381. useNetworkd = networkd;
  382. useDHCP = false;
  383. vlans.vlan = {
  384. id = 1;
  385. interface = "eth0";
  386. };
  387. interfaces.eth0.ipv4.addresses = mkOverride 0 [ ];
  388. interfaces.eth1.ipv4.addresses = mkOverride 0 [ ];
  389. interfaces.vlan.ipv4.addresses = mkOverride 0
  390. [ { inherit address; prefixLength = 24; } ];
  391. };
  392. };
  393. in {
  394. name = "vlan";
  395. nodes.client1 = node "192.168.1.1";
  396. nodes.client2 = node "192.168.1.2";
  397. testScript = { ... }:
  398. ''
  399. startAll;
  400. # Wait for networking to be configured
  401. $client1->waitForUnit("network.target");
  402. $client2->waitForUnit("network.target");
  403. # Test vlan is setup
  404. $client1->succeed("ip addr show dev vlan >&2");
  405. $client2->succeed("ip addr show dev vlan >&2");
  406. '';
  407. };
  408. virtual = {
  409. name = "Virtual";
  410. machine = {
  411. networking.useNetworkd = networkd;
  412. networking.interfaces.tap0 = {
  413. ipv4.addresses = [ { address = "192.168.1.1"; prefixLength = 24; } ];
  414. ipv6.addresses = [ { address = "2001:1470:fffd:2096::"; prefixLength = 64; } ];
  415. virtual = true;
  416. };
  417. networking.interfaces.tun0 = {
  418. ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ];
  419. ipv6.addresses = [ { address = "2001:1470:fffd:2097::"; prefixLength = 64; } ];
  420. virtual = true;
  421. };
  422. };
  423. testScript = ''
  424. my $targetList = <<'END';
  425. tap0: tap persist user 0
  426. tun0: tun persist user 0
  427. END
  428. # Wait for networking to come up
  429. $machine->start;
  430. $machine->waitForUnit("network-online.target");
  431. # Test interfaces set up
  432. my $list = $machine->succeed("ip tuntap list | sort");
  433. "$list" eq "$targetList" or die(
  434. "The list of virtual interfaces does not match the expected one:\n",
  435. "Result:\n", "$list\n",
  436. "Expected:\n", "$targetList\n"
  437. );
  438. # Test interfaces clean up
  439. $machine->succeed("systemctl stop network-addresses-tap0");
  440. $machine->sleep(10);
  441. $machine->succeed("systemctl stop network-addresses-tun0");
  442. $machine->sleep(10);
  443. my $residue = $machine->succeed("ip tuntap list");
  444. $residue eq "" or die(
  445. "Some virtual interface has not been properly cleaned:\n",
  446. "$residue\n"
  447. );
  448. '';
  449. };
  450. privacy = {
  451. name = "Privacy";
  452. nodes.router = { ... }: {
  453. virtualisation.vlans = [ 1 ];
  454. boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = true;
  455. networking = {
  456. useNetworkd = networkd;
  457. useDHCP = false;
  458. interfaces.eth1.ipv6.addresses = singleton {
  459. address = "fd00:1234:5678:1::1";
  460. prefixLength = 64;
  461. };
  462. };
  463. services.radvd = {
  464. enable = true;
  465. config = ''
  466. interface eth1 {
  467. AdvSendAdvert on;
  468. AdvManagedFlag on;
  469. AdvOtherConfigFlag on;
  470. prefix fd00:1234:5678:1::/64 {
  471. AdvAutonomous on;
  472. AdvOnLink on;
  473. };
  474. };
  475. '';
  476. };
  477. };
  478. nodes.clientWithPrivacy = { pkgs, ... }: with pkgs.lib; {
  479. virtualisation.vlans = [ 1 ];
  480. networking = {
  481. useNetworkd = networkd;
  482. useDHCP = false;
  483. interfaces.eth1 = {
  484. preferTempAddress = true;
  485. ipv4.addresses = mkOverride 0 [ ];
  486. ipv6.addresses = mkOverride 0 [ ];
  487. useDHCP = true;
  488. };
  489. };
  490. };
  491. nodes.client = { pkgs, ... }: with pkgs.lib; {
  492. virtualisation.vlans = [ 1 ];
  493. networking = {
  494. useNetworkd = networkd;
  495. useDHCP = false;
  496. interfaces.eth1 = {
  497. preferTempAddress = false;
  498. ipv4.addresses = mkOverride 0 [ ];
  499. ipv6.addresses = mkOverride 0 [ ];
  500. useDHCP = true;
  501. };
  502. };
  503. };
  504. testScript = { ... }:
  505. ''
  506. startAll;
  507. $client->waitForUnit("network.target");
  508. $clientWithPrivacy->waitForUnit("network.target");
  509. $router->waitForUnit("network-online.target");
  510. # Wait until we have an ip address
  511. $clientWithPrivacy->waitUntilSucceeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'");
  512. $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'");
  513. # Test vlan 1
  514. $clientWithPrivacy->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::1");
  515. $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::1");
  516. # Test address used is temporary
  517. $clientWithPrivacy->waitUntilSucceeds("! ip route get fd00:1234:5678:1::1 | grep -q ':[a-f0-9]*ff:fe[a-f0-9]*:'");
  518. # Test address used is EUI-64
  519. $client->waitUntilSucceeds("ip route get fd00:1234:5678:1::1 | grep -q ':[a-f0-9]*ff:fe[a-f0-9]*:'");
  520. '';
  521. };
  522. routes = {
  523. name = "routes";
  524. machine = {
  525. networking.useDHCP = false;
  526. networking.interfaces.eth0 = {
  527. ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ];
  528. ipv6.addresses = [ { address = "2001:1470:fffd:2097::"; prefixLength = 64; } ];
  529. ipv6.routes = [
  530. { address = "fdfd:b3f0::"; prefixLength = 48; }
  531. { address = "2001:1470:fffd:2098::"; prefixLength = 64; via = "fdfd:b3f0::1"; }
  532. ];
  533. ipv4.routes = [
  534. { address = "10.0.0.0"; prefixLength = 16; options = { mtu = "1500"; }; }
  535. { address = "192.168.2.0"; prefixLength = 24; via = "192.168.1.1"; }
  536. ];
  537. };
  538. virtualisation.vlans = [ ];
  539. };
  540. testScript = ''
  541. my $targetIPv4Table = <<'END';
  542. 10.0.0.0/16 proto static scope link mtu 1500
  543. 192.168.1.0/24 proto kernel scope link src 192.168.1.2
  544. 192.168.2.0/24 via 192.168.1.1 proto static
  545. END
  546. my $targetIPv6Table = <<'END';
  547. 2001:1470:fffd:2097::/64 proto kernel metric 256 pref medium
  548. 2001:1470:fffd:2098::/64 via fdfd:b3f0::1 proto static metric 1024 pref medium
  549. fdfd:b3f0::/48 proto static metric 1024 pref medium
  550. END
  551. $machine->start;
  552. $machine->waitForUnit("network.target");
  553. # test routing tables
  554. my $ipv4Table = $machine->succeed("ip -4 route list dev eth0 | head -n3");
  555. my $ipv6Table = $machine->succeed("ip -6 route list dev eth0 | head -n3");
  556. "$ipv4Table" eq "$targetIPv4Table" or die(
  557. "The IPv4 routing table does not match the expected one:\n",
  558. "Result:\n", "$ipv4Table\n",
  559. "Expected:\n", "$targetIPv4Table\n"
  560. );
  561. "$ipv6Table" eq "$targetIPv6Table" or die(
  562. "The IPv6 routing table does not match the expected one:\n",
  563. "Result:\n", "$ipv6Table\n",
  564. "Expected:\n", "$targetIPv6Table\n"
  565. );
  566. # test clean-up of the tables
  567. $machine->succeed("systemctl stop network-addresses-eth0");
  568. my $ipv4Residue = $machine->succeed("ip -4 route list dev eth0 | head -n-3");
  569. my $ipv6Residue = $machine->succeed("ip -6 route list dev eth0 | head -n-3");
  570. $ipv4Residue eq "" or die(
  571. "The IPv4 routing table has not been properly cleaned:\n",
  572. "$ipv4Residue\n"
  573. );
  574. $ipv6Residue eq "" or die(
  575. "The IPv6 routing table has not been properly cleaned:\n",
  576. "$ipv6Residue\n"
  577. );
  578. '';
  579. };
  580. };
  581. in mapAttrs (const (attrs: makeTest (attrs // {
  582. name = "${attrs.name}-Networking-${if networkd then "Networkd" else "Scripted"}";
  583. }))) testCases