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