@@ -0,0 +1,205 @@
1+# This test does a basic functionality check for all bird variants and demonstrates a use
2+# of the preCheckConfig option.
3+
4+{ system ? builtins.currentSystem
5+, pkgs ? import ../.. { inherit system; config = { }; }
6+}:
7+
8+let
9+ inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest;
10+ inherit (pkgs.lib) optionalString;
11+
12+ hostShared = hostId: { pkgs, ... }: {
13+ virtualisation.vlans = [ 1 ];
14+
15+ environment.systemPackages = with pkgs; [ jq ];
16+
17+ networking = {
18+ useNetworkd = true;
19+ useDHCP = false;
20+ firewall.enable = false;
21+ };
22+
23+ systemd.network.networks."01-eth1" = {
24+ name = "eth1";
25+ networkConfig.Address = "10.0.0.${hostId}/24";
26+ };
27+ };
28+
29+ birdTest = v4:
30+ let variant = "bird${optionalString (!v4) "6"}"; in
31+ makeTest {
32+ name = variant;
33+
34+ nodes.host1 = makeBirdHost variant "1";
35+ nodes.host2 = makeBirdHost variant "2";
36+
37+ testScript = makeTestScript variant v4 (!v4);
38+ };
39+
40+ bird2Test = makeTest {
41+ name = "bird2";
42+
43+ nodes.host1 = makeBird2Host "1";
44+ nodes.host2 = makeBird2Host "2";
45+
46+ testScript = makeTestScript "bird2" true true;
47+ };
48+
49+ makeTestScript = variant: v4: v6: ''
50+ start_all()
51+
52+ host1.wait_for_unit("${variant}.service")
53+ host2.wait_for_unit("${variant}.service")
54+
55+ ${optionalString v4 ''
56+ with subtest("Waiting for advertised IPv4 routes"):
57+ host1.wait_until_succeeds("ip --json r | jq -e 'map(select(.dst == \"10.10.0.2\")) | any'")
58+ host2.wait_until_succeeds("ip --json r | jq -e 'map(select(.dst == \"10.10.0.1\")) | any'")
59+ ''}
60+ ${optionalString v6 ''
61+ with subtest("Waiting for advertised IPv6 routes"):
62+ host1.wait_until_succeeds("ip --json -6 r | jq -e 'map(select(.dst == \"fdff::2\")) | any'")
63+ host2.wait_until_succeeds("ip --json -6 r | jq -e 'map(select(.dst == \"fdff::1\")) | any'")
64+ ''}
65+
66+ with subtest("Check fake routes in preCheckConfig do not exists"):
67+ ${optionalString v4 ''host1.fail("ip --json r | jq -e 'map(select(.dst == \"1.2.3.4\")) | any'")''}
68+ ${optionalString v4 ''host2.fail("ip --json r | jq -e 'map(select(.dst == \"1.2.3.4\")) | any'")''}
69+
70+ ${optionalString v6 ''host1.fail("ip --json -6 r | jq -e 'map(select(.dst == \"fd00::\")) | any'")''}
71+ ${optionalString v6 ''host2.fail("ip --json -6 r | jq -e 'map(select(.dst == \"fd00::\")) | any'")''}
72+ '';
73+
74+ makeBirdHost = variant: hostId: { pkgs, ... }: {
75+ imports = [ (hostShared hostId) ];
76+
77+ services.${variant} = {
78+ enable = true;
79+
80+ config = ''
81+ log syslog all;
82+
83+ debug protocols all;
84+
85+ router id 10.0.0.${hostId};
86+
87+ protocol device {
88+ }
89+
90+ protocol kernel {
91+ import none;
92+ export all;
93+ }
94+
95+ protocol static {
96+ include "static.conf";
97+ }
98+
99+ protocol ospf {
100+ export all;
101+ area 0 {
102+ interface "eth1" {
103+ hello 5;
104+ wait 5;
105+ };
106+ };
107+ }
108+ '';
109+
110+ preCheckConfig =
111+ let
112+ route = { bird = "1.2.3.4/32"; bird6 = "fd00::/128"; }.${variant};
113+ in
114+ ''echo "route ${route} blackhole;" > static.conf'';
115+ };
116+
117+ systemd.tmpfiles.rules =
118+ let
119+ route = { bird = "10.10.0.${hostId}/32"; bird6 = "fdff::${hostId}/128"; }.${variant};
120+ in
121+ [ "f /etc/bird/static.conf - - - - route ${route} blackhole;" ];
122+ };
123+
124+ makeBird2Host = hostId: { pkgs, ... }: {
125+ imports = [ (hostShared hostId) ];
126+
127+ services.bird2 = {
128+ enable = true;
129+
130+ config = ''
131+ log syslog all;
132+
133+ debug protocols all;
134+
135+ router id 10.0.0.${hostId};
136+
137+ protocol device {
138+ }
139+
140+ protocol kernel kernel4 {
141+ ipv4 {
142+ import none;
143+ export all;
144+ };
145+ }
146+
147+ protocol static static4 {
148+ ipv4;
149+ include "static4.conf";
150+ }
151+
152+ protocol ospf v2 ospf4 {
153+ ipv4 {
154+ export all;
155+ };
156+ area 0 {
157+ interface "eth1" {
158+ hello 5;
159+ wait 5;
160+ };
161+ };
162+ }
163+
164+ protocol kernel kernel6 {
165+ ipv6 {
166+ import none;
167+ export all;
168+ };
169+ }
170+
171+ protocol static static6 {
172+ ipv6;
173+ include "static6.conf";
174+ }
175+
176+ protocol ospf v3 ospf6 {
177+ ipv6 {
178+ export all;
179+ };
180+ area 0 {
181+ interface "eth1" {
182+ hello 5;
183+ wait 5;
184+ };
185+ };
186+ }
187+ '';
188+
189+ preCheckConfig = ''
190+ echo "route 1.2.3.4/32 blackhole;" > static4.conf
191+ echo "route fd00::/128 blackhole;" > static6.conf
192+ '';
193+ };
194+
195+ systemd.tmpfiles.rules = [
196+ "f /etc/bird/static4.conf - - - - route 10.10.0.${hostId}/32 blackhole;"
197+ "f /etc/bird/static6.conf - - - - route fdff::${hostId}/128 blackhole;"
198+ ];
199+ };
200+in
201+{
202+ bird = birdTest true;
203+ bird6 = birdTest false;
204+ bird2 = bird2Test;
205+}