xref: /freebsd/tests/sys/netinet/carp.sh (revision d0b2dbfa)
1#
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2020 Kristof Provost <kp@FreeBSD.org>
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
75	bridge=$(vnet_mkbridge)
76	epair_one=$(vnet_mkepair)
77	epair_two=$(vnet_mkepair)
78
79	vnet_mkjail carp_basic_v4_one ${bridge} ${epair_one}a ${epair_two}a
80	vnet_mkjail carp_basic_v4_two ${epair_one}b
81	vnet_mkjail carp_basic_v4_three ${epair_two}b
82
83	jexec carp_basic_v4_one ifconfig ${bridge} 192.0.2.4/29 up
84	jexec carp_basic_v4_one ifconfig ${bridge} addm ${epair_one}a \
85	    addm ${epair_two}a
86	jexec carp_basic_v4_one ifconfig ${epair_one}a up
87	jexec carp_basic_v4_one ifconfig ${epair_two}a up
88
89	jexec carp_basic_v4_two ifconfig ${epair_one}b 192.0.2.202/29 up
90	jexec carp_basic_v4_two ifconfig ${epair_one}b add vhid 1 192.0.2.1/29
91
92	jexec carp_basic_v4_three ifconfig ${epair_two}b 192.0.2.203/29 up
93	jexec carp_basic_v4_three ifconfig ${epair_two}b add vhid 1 \
94	    192.0.2.1/29
95
96	wait_for_carp carp_basic_v4_two ${epair_one}b \
97	    carp_basic_v4_three ${epair_two}b
98
99	atf_check -s exit:0 -o ignore jexec carp_basic_v4_one \
100	    ping -c 3 192.0.2.1
101}
102
103basic_v4_cleanup()
104{
105	vnet_cleanup
106}
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
120	bridge=$(vnet_mkbridge)
121	epair_one=$(vnet_mkepair)
122	epair_two=$(vnet_mkepair)
123
124	vnet_mkjail carp_uni_v4_one ${bridge} ${epair_one}a ${epair_two}a
125	vnet_mkjail carp_uni_v4_two ${epair_one}b
126	vnet_mkjail carp_uni_v4_three ${epair_two}b
127
128	jexec carp_uni_v4_one ifconfig ${bridge} 192.0.2.4/29 up
129	jexec carp_uni_v4_one sysctl net.inet.ip.forwarding=1
130	jexec carp_uni_v4_one ifconfig ${bridge} addm ${epair_one}a \
131	    addm ${epair_two}a
132	jexec carp_uni_v4_one ifconfig ${epair_one}a up
133	jexec carp_uni_v4_one ifconfig ${epair_two}a up
134	jexec carp_uni_v4_one ifconfig ${bridge} inet alias 198.51.100.1/25
135	jexec carp_uni_v4_one ifconfig ${bridge} inet alias 198.51.100.129/25
136
137	jexec carp_uni_v4_two ifconfig ${epair_one}b 198.51.100.2/25 up
138	jexec carp_uni_v4_two route add default 198.51.100.1
139	jexec carp_uni_v4_two ifconfig ${epair_one}b add vhid 1 \
140	    peer 198.51.100.130 192.0.2.1/29
141
142	jexec carp_uni_v4_three ifconfig ${epair_two}b 198.51.100.130/25 up
143	jexec carp_uni_v4_three route add default 198.51.100.129
144	jexec carp_uni_v4_three ifconfig ${epair_two}b add vhid 1 \
145	    peer 198.51.100.2 192.0.2.1/29
146
147	# Sanity check
148	atf_check -s exit:0 -o ignore jexec carp_uni_v4_two \
149	    ping -c 1 198.51.100.130
150
151	wait_for_carp carp_uni_v4_two ${epair_one}b \
152	    carp_uni_v4_three ${epair_two}b
153
154	atf_check -s exit:0 -o ignore jexec carp_uni_v4_one \
155	    ping -c 3 192.0.2.1
156
157	jexec carp_uni_v4_two ifconfig
158	jexec carp_uni_v4_three ifconfig
159}
160
161unicast_v4_cleanup()
162{
163	vnet_cleanup
164}
165
166atf_test_case "basic_v6" "cleanup"
167basic_v6_head()
168{
169	atf_set descr 'Basic CARP test (IPv6)'
170	atf_set require.user root
171}
172
173basic_v6_body()
174{
175	carp_init
176
177	bridge=$(vnet_mkbridge)
178	epair_one=$(vnet_mkepair)
179	epair_two=$(vnet_mkepair)
180
181	vnet_mkjail carp_basic_v6_one ${bridge} ${epair_one}a ${epair_two}a
182	vnet_mkjail carp_basic_v6_two ${epair_one}b
183	vnet_mkjail carp_basic_v6_three ${epair_two}b
184
185	jexec carp_basic_v6_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
186	    no_dad
187	jexec carp_basic_v6_one ifconfig ${bridge} addm ${epair_one}a \
188	    addm ${epair_two}a
189	jexec carp_basic_v6_one ifconfig ${epair_one}a up
190	jexec carp_basic_v6_one ifconfig ${epair_two}a up
191
192	jexec carp_basic_v6_two ifconfig ${epair_one}b inet6 \
193	    2001:db8::1:2/64 up no_dad
194	jexec carp_basic_v6_two ifconfig ${epair_one}b inet6 add vhid 1 \
195	    2001:db8::0:1/64
196
197	jexec carp_basic_v6_three ifconfig ${epair_two}b inet6 2001:db8::1:3/64 up no_dad
198	jexec carp_basic_v6_three ifconfig ${epair_two}b inet6 add vhid 1 \
199	    2001:db8::0:1/64
200
201	wait_for_carp carp_basic_v6_two ${epair_one}b \
202	    carp_basic_v6_three ${epair_two}b
203
204	atf_check -s exit:0 -o ignore jexec carp_basic_v6_one \
205	    ping -6 -c 3 2001:db8::0:1
206}
207
208basic_v6_cleanup()
209{
210	vnet_cleanup
211}
212
213atf_test_case "unicast_v6" "cleanup"
214unicast_v6_head()
215{
216	atf_set descr 'Unicast CARP test (IPv6)'
217	atf_set require.user root
218}
219
220unicast_v6_body()
221{
222	carp_init
223
224	bridge=$(vnet_mkbridge)
225	epair_one=$(vnet_mkepair)
226	epair_two=$(vnet_mkepair)
227
228	vnet_mkjail carp_uni_v6_one ${bridge} ${epair_one}a ${epair_two}a
229	vnet_mkjail carp_uni_v6_two ${epair_one}b
230	vnet_mkjail carp_uni_v6_three ${epair_two}b
231
232	jexec carp_uni_v6_one sysctl net.inet6.ip6.forwarding=1
233	jexec carp_uni_v6_one ifconfig ${bridge} addm ${epair_one}a \
234	    addm ${epair_two}a
235	jexec carp_uni_v6_one ifconfig ${epair_one}a up
236	jexec carp_uni_v6_one ifconfig ${epair_two}a up
237	jexec carp_uni_v6_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
238	    no_dad
239	jexec carp_uni_v6_one ifconfig ${bridge} inet6 alias 2001:db8:1::1/64 \
240	    no_dad up
241	jexec carp_uni_v6_one ifconfig ${bridge} inet6 alias 2001:db8:2::1/64 \
242	    no_dad up
243
244	jexec carp_uni_v6_two ifconfig ${epair_one}b inet6 2001:db8:1::2/64 \
245	    no_dad up
246	jexec carp_uni_v6_two route -6 add default 2001:db8:1::1
247	jexec carp_uni_v6_two ifconfig ${epair_one}b inet6 add vhid 1 \
248	    peer6 2001:db8:2::2 \
249	    2001:db8::0:1/64
250
251	jexec carp_uni_v6_three ifconfig ${epair_two}b inet6 2001:db8:2::2/64 \
252	    no_dad up
253	jexec carp_uni_v6_three route -6 add default 2001:db8:2::1
254	jexec carp_uni_v6_three ifconfig ${epair_two}b inet6 add vhid 1 \
255	    peer6 2001:db8:1::2 \
256	    2001:db8::0:1/64
257
258	# Sanity check
259	atf_check -s exit:0 -o ignore jexec carp_uni_v6_two \
260	    ping -6 -c 1 2001:db8:2::2
261
262	wait_for_carp carp_uni_v6_two ${epair_one}b \
263	    carp_uni_v6_three ${epair_two}b
264
265	atf_check -s exit:0 -o ignore jexec carp_uni_v6_one \
266	    ping -6 -c 3 2001:db8::0:1
267}
268
269unicast_v6_cleanup()
270{
271	vnet_cleanup
272}
273
274atf_test_case "unicast_ll_v6" "cleanup"
275unicast_ll_v6_head()
276{
277	atf_set descr 'Unicast CARP test (IPv6, link-local)'
278	atf_set require.user root
279}
280
281unicast_ll_v6_body()
282{
283	carp_init
284
285	j=carp_uni_ll_v6
286
287	bridge=$(vnet_mkbridge)
288	epair_one=$(vnet_mkepair)
289	epair_two=$(vnet_mkepair)
290
291	vnet_mkjail ${j}_one ${bridge} ${epair_one}a ${epair_two}a
292	vnet_mkjail ${j}_two ${epair_one}b
293	vnet_mkjail ${j}_three ${epair_two}b
294
295	jexec ${j}_one ifconfig ${bridge} addm ${epair_one}a \
296	    addm ${epair_two}a
297	jexec ${j}_one ifconfig ${epair_one}a up
298	jexec ${j}_one ifconfig ${epair_two}a up
299	jexec ${j}_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
300	    no_dad
301	jexec ${j}_one ifconfig ${bridge} inet6 alias 2001:db8:1::1/64 \
302	    no_dad up
303
304	jexec ${j}_two ifconfig ${epair_one}b inet6 2001:db8:1::2/64 \
305	    no_dad up
306	jexec ${j}_three ifconfig ${epair_two}b inet6 2001:db8:1::3/64 \
307	    no_dad up
308
309	ll_one=$(jexec ${j}_two ifconfig ${epair_one}b | awk "/ .*%${epair_one}b.* / { print \$2 }" | cut -d % -f 1)
310	ll_two=$(jexec ${j}_three ifconfig ${epair_two}b | awk "/ .*%${epair_two}b.* / { print \$2 }" | cut -d % -f 1)
311
312	jexec ${j}_two ifconfig ${epair_one}b inet6 add vhid 1 \
313	    peer6 ${ll_two} \
314	    2001:db8::0:1/64
315	jexec ${j}_three ifconfig ${epair_two}b inet6 add vhid 1 \
316	    peer6 ${ll_one} \
317	    2001:db8::0:1/64
318
319	# Sanity check
320	atf_check -s exit:0 -o ignore jexec ${j}_two \
321	    ping -6 -c 1 2001:db8:1::3
322
323	wait_for_carp ${j}_two ${epair_one}b \
324	    ${j}_three ${epair_two}b
325
326	atf_check -s exit:0 -o ignore jexec ${j}_one \
327	    ping -6 -c 3 2001:db8::0:1
328}
329
330unicast_ll_v6_cleanup()
331{
332	vnet_cleanup
333}
334
335atf_test_case "negative_demotion" "cleanup"
336negative_demotion_head()
337{
338	atf_set descr 'Test PR #259528'
339	atf_set require.user root
340}
341
342negative_demotion_body()
343{
344	carp_init
345
346	epair=$(vnet_mkepair)
347
348	vnet_mkjail one ${epair}a
349	jexec one sysctl net.inet.carp.preempt=1
350	jexec one ifconfig ${epair}a 192.0.2.1/24 up
351	jexec one ifconfig ${epair}a add vhid 1 192.0.2.254/24 \
352	    advskew 0 pass foobar
353
354	vnet_mkjail two ${epair}b
355	jexec two sysctl net.inet.carp.preempt=1
356	jexec two ifconfig ${epair}b 192.0.2.2/24 up
357	jexec two ifconfig ${epair}b add vhid 1 192.0.2.254/24 \
358	    advskew 100 pass foobar
359
360	# Allow things to settle
361	wait_for_carp one ${epair}a two ${epair}b
362
363	if is_master one ${epair}a && is_master two ${epair}b
364	then
365		atf_fail "Two masters!"
366	fi
367
368	jexec one sysctl net.inet.carp.demotion=-1
369	sleep 3
370
371	if is_master one ${epair}a && is_master two ${epair}b
372	then
373		atf_fail "Two masters!"
374	fi
375}
376
377negative_demotion_cleanup()
378{
379	vnet_cleanup
380}
381
382
383
384atf_test_case "nd6_ns_source_mac" "cleanup"
385nd6_ns_source_mac_head()
386{
387        atf_set descr 'CARP ndp neighbor solicitation MAC source test (IPv6)'
388        atf_set require.user root
389}
390
391nd6_ns_source_mac_body()
392{
393        carp_init
394
395        bridge=$(vnet_mkbridge)
396        epair_one=$(vnet_mkepair)
397        epair_two=$(vnet_mkepair)
398
399        vnet_mkjail carp_ndp_v6_bridge ${bridge} ${epair_one}a ${epair_two}a
400        vnet_mkjail carp_ndp_v6_master ${epair_one}b
401        vnet_mkjail carp_ndp_v6_slave ${epair_two}b
402
403        jexec carp_ndp_v6_bridge ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
404            no_dad
405        jexec carp_ndp_v6_bridge ifconfig ${bridge} addm ${epair_one}a \
406            addm ${epair_two}a
407        jexec carp_ndp_v6_bridge ifconfig ${epair_one}a up
408        jexec carp_ndp_v6_bridge ifconfig ${epair_two}a up
409
410        jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 \
411            2001:db8::1:2/64 up no_dad
412        jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 add vhid 1 \
413            advskew 0 2001:db8::0:1/64
414
415        jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 \
416	    2001:db8::1:3/64 up no_dad
417        jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 add vhid 1 \
418            advskew 100 2001:db8::0:1/64
419
420        wait_for_carp carp_ndp_v6_master ${epair_one}b \
421            carp_ndp_v6_slave ${epair_two}b
422
423	# carp_ndp_v6_master is MASTER
424
425	# trigger a NS from the virtual IP from the BACKUP
426        atf_check -s exit:2 -o ignore jexec carp_ndp_v6_slave \
427            ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4
428
429	# trigger a NS from the virtual IP from the MASTER,
430	# this ping should work
431        atf_check -s exit:0 -o ignore jexec carp_ndp_v6_master \
432            ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4
433
434        # ndp entry should be for the virtual mac
435        atf_check -o match:'2001:db8::1 +00:00:5e:00:01:01' \
436	    jexec carp_ndp_v6_bridge ndp -an
437}
438
439nd6_ns_source_mac_cleanup()
440{
441        vnet_cleanup
442}
443
444
445atf_test_case "switch" "cleanup"
446switch_head()
447{
448	atf_set descr 'Switch between master and backup'
449	atf_set require.user root
450}
451
452switch_body()
453{
454	carp_init
455
456	epair=$(vnet_mkepair)
457
458	ifconfig ${epair}a up
459	ifconfig ${epair}a vhid 1 advskew 100 192.0.2.1/24
460	ifconfig ${epair}a vhid 1 state backup
461	ifconfig ${epair}a vhid 1 state master
462}
463
464switch_cleanup()
465{
466	vnet_cleanup
467}
468
469atf_init_test_cases()
470{
471	atf_add_test_case "basic_v4"
472	atf_add_test_case "unicast_v4"
473	atf_add_test_case "basic_v6"
474	atf_add_test_case "unicast_v6"
475	atf_add_test_case "unicast_ll_v6"
476	atf_add_test_case "negative_demotion"
477	atf_add_test_case "nd6_ns_source_mac"
478	atf_add_test_case "switch"
479}
480