xref: /freebsd-14.2/tests/sys/netinet/carp.sh (revision c3fe41b3)
1#
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2020 Kristof Provost <[email protected]>
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26
27. $(atf_get_srcdir)/../common/vnet.subr
28
29is_master()
30{
31	jail=$1
32	itf=$2
33
34	jexec ${jail} ifconfig ${itf} | grep carp | grep MASTER
35}
36
37wait_for_carp()
38{
39	jail1=$1
40	itf1=$2
41	jail2=$3
42	itf2=$4
43
44	while [ -z "$(is_master ${jail1} ${itf1})" ] &&
45	    [ -z "$(is_master ${jail2} ${itf2})" ]; do
46		sleep 1
47	done
48
49	if [ -n "$(is_master ${jail1} ${itf1})" ] &&
50	    [ -n "$(is_master ${jail2} ${itf2})" ]; then
51		atf_fail "Both jails are master"
52	fi
53}
54
55carp_init()
56{
57	if ! kldstat -q -m carp; then
58		atf_skip "This test requires carp"
59	fi
60
61	vnet_init
62}
63
64atf_test_case "basic_v4" "cleanup"
65basic_v4_head()
66{
67	atf_set descr 'Basic CARP test (IPv4)'
68	atf_set require.user root
69}
70
71basic_v4_body()
72{
73	carp_init
74	vnet_init_bridge
75
76	bridge=$(vnet_mkbridge)
77	epair_one=$(vnet_mkepair)
78	epair_two=$(vnet_mkepair)
79
80	vnet_mkjail carp_basic_v4_one ${bridge} ${epair_one}a ${epair_two}a
81	vnet_mkjail carp_basic_v4_two ${epair_one}b
82	vnet_mkjail carp_basic_v4_three ${epair_two}b
83
84	jexec carp_basic_v4_one ifconfig ${bridge} 192.0.2.4/29 up
85	jexec carp_basic_v4_one ifconfig ${bridge} addm ${epair_one}a \
86	    addm ${epair_two}a
87	jexec carp_basic_v4_one ifconfig ${epair_one}a up
88	jexec carp_basic_v4_one ifconfig ${epair_two}a up
89
90	jexec carp_basic_v4_two ifconfig ${epair_one}b 192.0.2.202/29 up
91	jexec carp_basic_v4_two ifconfig ${epair_one}b add vhid 1 192.0.2.1/29
92
93	jexec carp_basic_v4_three ifconfig ${epair_two}b 192.0.2.203/29 up
94	jexec carp_basic_v4_three ifconfig ${epair_two}b add vhid 1 \
95	    192.0.2.1/29
96
97	wait_for_carp carp_basic_v4_two ${epair_one}b \
98	    carp_basic_v4_three ${epair_two}b
99
100	atf_check -s exit:0 -o ignore jexec carp_basic_v4_one \
101	    ping -c 3 192.0.2.1
102}
103
104basic_v4_cleanup()
105{
106	vnet_cleanup
107}
108
109atf_test_case "unicast_v4" "cleanup"
110unicast_v4_head()
111{
112	atf_set descr 'Unicast CARP test (IPv4)'
113	atf_set require.user root
114}
115
116unicast_v4_body()
117{
118	carp_init
119	vnet_init_bridge
120
121	bridge=$(vnet_mkbridge)
122	epair_one=$(vnet_mkepair)
123	epair_two=$(vnet_mkepair)
124
125	vnet_mkjail carp_uni_v4_one ${bridge} ${epair_one}a ${epair_two}a
126	vnet_mkjail carp_uni_v4_two ${epair_one}b
127	vnet_mkjail carp_uni_v4_three ${epair_two}b
128
129	jexec carp_uni_v4_one ifconfig ${bridge} 192.0.2.4/29 up
130	jexec carp_uni_v4_one sysctl net.inet.ip.forwarding=1
131	jexec carp_uni_v4_one ifconfig ${bridge} addm ${epair_one}a \
132	    addm ${epair_two}a
133	jexec carp_uni_v4_one ifconfig ${epair_one}a up
134	jexec carp_uni_v4_one ifconfig ${epair_two}a up
135	jexec carp_uni_v4_one ifconfig ${bridge} inet alias 198.51.100.1/25
136	jexec carp_uni_v4_one ifconfig ${bridge} inet alias 198.51.100.129/25
137
138	jexec carp_uni_v4_two ifconfig ${epair_one}b 198.51.100.2/25 up
139	jexec carp_uni_v4_two route add default 198.51.100.1
140	jexec carp_uni_v4_two ifconfig ${epair_one}b add vhid 1 \
141	    peer 198.51.100.130 192.0.2.1/29
142
143	jexec carp_uni_v4_three ifconfig ${epair_two}b 198.51.100.130/25 up
144	jexec carp_uni_v4_three route add default 198.51.100.129
145	jexec carp_uni_v4_three ifconfig ${epair_two}b add vhid 1 \
146	    peer 198.51.100.2 192.0.2.1/29
147
148	# Sanity check
149	atf_check -s exit:0 -o ignore jexec carp_uni_v4_two \
150	    ping -c 1 198.51.100.130
151
152	wait_for_carp carp_uni_v4_two ${epair_one}b \
153	    carp_uni_v4_three ${epair_two}b
154
155	atf_check -s exit:0 -o ignore jexec carp_uni_v4_one \
156	    ping -c 3 192.0.2.1
157
158	jexec carp_uni_v4_two ifconfig
159	jexec carp_uni_v4_three ifconfig
160}
161
162unicast_v4_cleanup()
163{
164	vnet_cleanup
165}
166
167atf_test_case "basic_v6" "cleanup"
168basic_v6_head()
169{
170	atf_set descr 'Basic CARP test (IPv6)'
171	atf_set require.user root
172}
173
174basic_v6_body()
175{
176	carp_init
177	vnet_init_bridge
178
179	bridge=$(vnet_mkbridge)
180	epair_one=$(vnet_mkepair)
181	epair_two=$(vnet_mkepair)
182
183	vnet_mkjail carp_basic_v6_one ${bridge} ${epair_one}a ${epair_two}a
184	vnet_mkjail carp_basic_v6_two ${epair_one}b
185	vnet_mkjail carp_basic_v6_three ${epair_two}b
186
187	jexec carp_basic_v6_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
188	    no_dad
189	jexec carp_basic_v6_one ifconfig ${bridge} addm ${epair_one}a \
190	    addm ${epair_two}a
191	jexec carp_basic_v6_one ifconfig ${epair_one}a up
192	jexec carp_basic_v6_one ifconfig ${epair_two}a up
193
194	jexec carp_basic_v6_two ifconfig ${epair_one}b inet6 \
195	    2001:db8::1:2/64 up no_dad
196	jexec carp_basic_v6_two ifconfig ${epair_one}b inet6 add vhid 1 \
197	    2001:db8::0:1/64
198
199	jexec carp_basic_v6_three ifconfig ${epair_two}b inet6 2001:db8::1:3/64 up no_dad
200	jexec carp_basic_v6_three ifconfig ${epair_two}b inet6 add vhid 1 \
201	    2001:db8::0:1/64
202
203	wait_for_carp carp_basic_v6_two ${epair_one}b \
204	    carp_basic_v6_three ${epair_two}b
205
206	atf_check -s exit:0 -o ignore jexec carp_basic_v6_one \
207	    ping -6 -c 3 2001:db8::0:1
208}
209
210basic_v6_cleanup()
211{
212	vnet_cleanup
213}
214
215atf_test_case "unicast_v6" "cleanup"
216unicast_v6_head()
217{
218	atf_set descr 'Unicast CARP test (IPv6)'
219	atf_set require.user root
220}
221
222unicast_v6_body()
223{
224	carp_init
225	vnet_init_bridge
226
227	bridge=$(vnet_mkbridge)
228	epair_one=$(vnet_mkepair)
229	epair_two=$(vnet_mkepair)
230
231	vnet_mkjail carp_uni_v6_one ${bridge} ${epair_one}a ${epair_two}a
232	vnet_mkjail carp_uni_v6_two ${epair_one}b
233	vnet_mkjail carp_uni_v6_three ${epair_two}b
234
235	jexec carp_uni_v6_one sysctl net.inet6.ip6.forwarding=1
236	jexec carp_uni_v6_one ifconfig ${bridge} addm ${epair_one}a \
237	    addm ${epair_two}a
238	jexec carp_uni_v6_one ifconfig ${epair_one}a up
239	jexec carp_uni_v6_one ifconfig ${epair_two}a up
240	jexec carp_uni_v6_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
241	    no_dad
242	jexec carp_uni_v6_one ifconfig ${bridge} inet6 alias 2001:db8:1::1/64 \
243	    no_dad up
244	jexec carp_uni_v6_one ifconfig ${bridge} inet6 alias 2001:db8:2::1/64 \
245	    no_dad up
246
247	jexec carp_uni_v6_two ifconfig ${epair_one}b inet6 2001:db8:1::2/64 \
248	    no_dad up
249	jexec carp_uni_v6_two route -6 add default 2001:db8:1::1
250	jexec carp_uni_v6_two ifconfig ${epair_one}b inet6 add vhid 1 \
251	    peer6 2001:db8:2::2 \
252	    2001:db8::0:1/64
253
254	jexec carp_uni_v6_three ifconfig ${epair_two}b inet6 2001:db8:2::2/64 \
255	    no_dad up
256	jexec carp_uni_v6_three route -6 add default 2001:db8:2::1
257	jexec carp_uni_v6_three ifconfig ${epair_two}b inet6 add vhid 1 \
258	    peer6 2001:db8:1::2 \
259	    2001:db8::0:1/64
260
261	# Sanity check
262	atf_check -s exit:0 -o ignore jexec carp_uni_v6_two \
263	    ping -6 -c 1 2001:db8:2::2
264
265	wait_for_carp carp_uni_v6_two ${epair_one}b \
266	    carp_uni_v6_three ${epair_two}b
267
268	atf_check -s exit:0 -o ignore jexec carp_uni_v6_one \
269	    ping -6 -c 3 2001:db8::0:1
270}
271
272unicast_v6_cleanup()
273{
274	vnet_cleanup
275}
276
277atf_test_case "unicast_ll_v6" "cleanup"
278unicast_ll_v6_head()
279{
280	atf_set descr 'Unicast CARP test (IPv6, link-local)'
281	atf_set require.user root
282}
283
284unicast_ll_v6_body()
285{
286	carp_init
287	vnet_init_bridge
288
289	j=carp_uni_ll_v6
290
291	bridge=$(vnet_mkbridge)
292	epair_one=$(vnet_mkepair)
293	epair_two=$(vnet_mkepair)
294
295	vnet_mkjail ${j}_one ${bridge} ${epair_one}a ${epair_two}a
296	vnet_mkjail ${j}_two ${epair_one}b
297	vnet_mkjail ${j}_three ${epair_two}b
298
299	jexec ${j}_one ifconfig ${bridge} addm ${epair_one}a \
300	    addm ${epair_two}a
301	jexec ${j}_one ifconfig ${epair_one}a up
302	jexec ${j}_one ifconfig ${epair_two}a up
303	jexec ${j}_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
304	    no_dad
305	jexec ${j}_one ifconfig ${bridge} inet6 alias 2001:db8:1::1/64 \
306	    no_dad up
307
308	jexec ${j}_two ifconfig ${epair_one}b inet6 2001:db8:1::2/64 \
309	    no_dad up
310	jexec ${j}_three ifconfig ${epair_two}b inet6 2001:db8:1::3/64 \
311	    no_dad up
312
313	ll_one=$(jexec ${j}_two ifconfig ${epair_one}b | awk "/ .*%${epair_one}b.* / { print \$2 }" | cut -d % -f 1)
314	ll_two=$(jexec ${j}_three ifconfig ${epair_two}b | awk "/ .*%${epair_two}b.* / { print \$2 }" | cut -d % -f 1)
315
316	jexec ${j}_two ifconfig ${epair_one}b inet6 add vhid 1 \
317	    peer6 ${ll_two} \
318	    2001:db8::0:1/64
319	jexec ${j}_three ifconfig ${epair_two}b inet6 add vhid 1 \
320	    peer6 ${ll_one} \
321	    2001:db8::0:1/64
322
323	# Sanity check
324	atf_check -s exit:0 -o ignore jexec ${j}_two \
325	    ping -6 -c 1 2001:db8:1::3
326
327	wait_for_carp ${j}_two ${epair_one}b \
328	    ${j}_three ${epair_two}b
329
330	atf_check -s exit:0 -o ignore jexec ${j}_one \
331	    ping -6 -c 3 2001:db8::0:1
332}
333
334unicast_ll_v6_cleanup()
335{
336	vnet_cleanup
337}
338
339atf_test_case "negative_demotion" "cleanup"
340negative_demotion_head()
341{
342	atf_set descr 'Test PR #259528'
343	atf_set require.user root
344}
345
346negative_demotion_body()
347{
348	carp_init
349
350	epair=$(vnet_mkepair)
351
352	vnet_mkjail one ${epair}a
353	jexec one sysctl net.inet.carp.preempt=1
354	jexec one ifconfig ${epair}a 192.0.2.1/24 up
355	jexec one ifconfig ${epair}a add vhid 1 192.0.2.254/24 \
356	    advskew 0 pass foobar
357
358	vnet_mkjail two ${epair}b
359	jexec two sysctl net.inet.carp.preempt=1
360	jexec two ifconfig ${epair}b 192.0.2.2/24 up
361	jexec two ifconfig ${epair}b add vhid 1 192.0.2.254/24 \
362	    advskew 100 pass foobar
363
364	# Allow things to settle
365	wait_for_carp one ${epair}a two ${epair}b
366
367	if is_master one ${epair}a && is_master two ${epair}b
368	then
369		atf_fail "Two masters!"
370	fi
371
372	jexec one sysctl net.inet.carp.demotion=-1
373	sleep 3
374
375	if is_master one ${epair}a && is_master two ${epair}b
376	then
377		atf_fail "Two masters!"
378	fi
379}
380
381negative_demotion_cleanup()
382{
383	vnet_cleanup
384}
385
386
387
388atf_test_case "nd6_ns_source_mac" "cleanup"
389nd6_ns_source_mac_head()
390{
391        atf_set descr 'CARP ndp neighbor solicitation MAC source test (IPv6)'
392        atf_set require.user root
393}
394
395nd6_ns_source_mac_body()
396{
397        carp_init
398        vnet_init_bridge
399
400        bridge=$(vnet_mkbridge)
401        epair_one=$(vnet_mkepair)
402        epair_two=$(vnet_mkepair)
403
404        vnet_mkjail carp_ndp_v6_bridge ${bridge} ${epair_one}a ${epair_two}a
405        vnet_mkjail carp_ndp_v6_master ${epair_one}b
406        vnet_mkjail carp_ndp_v6_slave ${epair_two}b
407
408        jexec carp_ndp_v6_bridge ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
409            no_dad
410        jexec carp_ndp_v6_bridge ifconfig ${bridge} addm ${epair_one}a \
411            addm ${epair_two}a
412        jexec carp_ndp_v6_bridge ifconfig ${epair_one}a up
413        jexec carp_ndp_v6_bridge ifconfig ${epair_two}a up
414
415        jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 \
416            2001:db8::1:2/64 up no_dad
417        jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 add vhid 1 \
418            advskew 0 2001:db8::0:1/64
419
420        jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 \
421	    2001:db8::1:3/64 up no_dad
422        jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 add vhid 1 \
423            advskew 100 2001:db8::0:1/64
424
425        wait_for_carp carp_ndp_v6_master ${epair_one}b \
426            carp_ndp_v6_slave ${epair_two}b
427
428	# carp_ndp_v6_master is MASTER
429
430	# trigger a NS from the virtual IP from the BACKUP
431        atf_check -s exit:2 -o ignore jexec carp_ndp_v6_slave \
432            ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4
433
434	# trigger a NS from the virtual IP from the MASTER,
435	# this ping should work
436        atf_check -s exit:0 -o ignore jexec carp_ndp_v6_master \
437            ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4
438
439        # ndp entry should be for the virtual mac
440        atf_check -o match:'2001:db8::1 +00:00:5e:00:01:01' \
441	    jexec carp_ndp_v6_bridge ndp -an
442}
443
444nd6_ns_source_mac_cleanup()
445{
446        vnet_cleanup
447}
448
449
450atf_test_case "switch" "cleanup"
451switch_head()
452{
453	atf_set descr 'Switch between master and backup'
454	atf_set require.user root
455}
456
457switch_body()
458{
459	carp_init
460
461	epair=$(vnet_mkepair)
462
463	ifconfig ${epair}a up
464	ifconfig ${epair}a vhid 1 advskew 100 192.0.2.1/24
465	ifconfig ${epair}a vhid 1 state backup
466	ifconfig ${epair}a vhid 1 state master
467}
468
469switch_cleanup()
470{
471	vnet_cleanup
472}
473
474atf_init_test_cases()
475{
476	atf_add_test_case "basic_v4"
477	atf_add_test_case "unicast_v4"
478	atf_add_test_case "basic_v6"
479	atf_add_test_case "unicast_v6"
480	atf_add_test_case "unicast_ll_v6"
481	atf_add_test_case "negative_demotion"
482	atf_add_test_case "nd6_ns_source_mac"
483	atf_add_test_case "switch"
484}
485