xref: /freebsd/tests/sys/netinet/carp.sh (revision ebacd8013fe5f7fdf9f6a5b286f6680dd2891036)
1# $FreeBSD$
2#
3# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 "negative_demotion" "cleanup"
276negative_demotion_head()
277{
278	atf_set descr 'Test PR #259528'
279	atf_set require.user root
280}
281
282negative_demotion_body()
283{
284	carp_init
285
286	epair=$(vnet_mkepair)
287
288	vnet_mkjail one ${epair}a
289	jexec one sysctl net.inet.carp.preempt=1
290	jexec one ifconfig ${epair}a 192.0.2.1/24 up
291	jexec one ifconfig ${epair}a add vhid 1 192.0.2.254/24 \
292	    advskew 0 pass foobar
293
294	vnet_mkjail two ${epair}b
295	jexec two sysctl net.inet.carp.preempt=1
296	jexec two ifconfig ${epair}b 192.0.2.2/24 up
297	jexec two ifconfig ${epair}b add vhid 1 192.0.2.254/24 \
298	    advskew 100 pass foobar
299
300	# Allow things to settle
301	wait_for_carp one ${epair}a two ${epair}b
302
303	if is_master one ${epair}a && is_master two ${epair}b
304	then
305		atf_fail "Two masters!"
306	fi
307
308	jexec one sysctl net.inet.carp.demotion=-1
309	sleep 3
310
311	if is_master one ${epair}a && is_master two ${epair}b
312	then
313		atf_fail "Two masters!"
314	fi
315}
316
317negative_demotion_cleanup()
318{
319	vnet_cleanup
320}
321
322
323
324atf_test_case "nd6_ns_source_mac" "cleanup"
325nd6_ns_source_mac_head()
326{
327        atf_set descr 'CARP ndp neighbor solicitation MAC source test (IPv6)'
328        atf_set require.user root
329}
330
331nd6_ns_source_mac_body()
332{
333        carp_init
334
335        bridge=$(vnet_mkbridge)
336        epair_one=$(vnet_mkepair)
337        epair_two=$(vnet_mkepair)
338
339        vnet_mkjail carp_ndp_v6_bridge ${bridge} ${epair_one}a ${epair_two}a
340        vnet_mkjail carp_ndp_v6_master ${epair_one}b
341        vnet_mkjail carp_ndp_v6_slave ${epair_two}b
342
343        jexec carp_ndp_v6_bridge ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
344            no_dad
345        jexec carp_ndp_v6_bridge ifconfig ${bridge} addm ${epair_one}a \
346            addm ${epair_two}a
347        jexec carp_ndp_v6_bridge ifconfig ${epair_one}a up
348        jexec carp_ndp_v6_bridge ifconfig ${epair_two}a up
349
350        jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 \
351            2001:db8::1:2/64 up no_dad
352        jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 add vhid 1 \
353            advskew 0 2001:db8::0:1/64
354
355        jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 \
356	    2001:db8::1:3/64 up no_dad
357        jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 add vhid 1 \
358            advskew 100 2001:db8::0:1/64
359
360        wait_for_carp carp_ndp_v6_master ${epair_one}b \
361            carp_ndp_v6_slave ${epair_two}b
362
363	# carp_ndp_v6_master is MASTER
364
365	# trigger a NS from the virtual IP from the BACKUP
366        atf_check -s exit:2 -o ignore jexec carp_ndp_v6_slave \
367            ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4
368
369	# trigger a NS from the virtual IP from the MASTER,
370	# this ping should work
371        atf_check -s exit:0 -o ignore jexec carp_ndp_v6_master \
372            ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4
373
374        # ndp entry should be for the virtual mac
375        atf_check -o match:'2001:db8::1 +00:00:5e:00:01:01' \
376	    jexec carp_ndp_v6_bridge ndp -an
377}
378
379nd6_ns_source_mac_cleanup()
380{
381        vnet_cleanup
382}
383
384
385atf_test_case "switch" "cleanup"
386switch_head()
387{
388	atf_set descr 'Switch between master and backup'
389	atf_set require.user root
390}
391
392switch_body()
393{
394	carp_init
395
396	epair=$(vnet_mkepair)
397
398	ifconfig ${epair}a up
399	ifconfig ${epair}a vhid 1 advskew 100 192.0.2.1/24
400	ifconfig ${epair}a vhid 1 state backup
401	ifconfig ${epair}a vhid 1 state master
402}
403
404switch_cleanup()
405{
406	vnet_cleanup
407}
408
409atf_init_test_cases()
410{
411	atf_add_test_case "basic_v4"
412	atf_add_test_case "unicast_v4"
413	atf_add_test_case "basic_v6"
414	atf_add_test_case "unicast_v6"
415	atf_add_test_case "negative_demotion"
416	atf_add_test_case "nd6_ns_source_mac"
417	atf_add_test_case "switch"
418}
419