xref: /freebsd/tests/sys/netinet/carp.sh (revision d316de24faa7453118a90fb0e9839e8026e36a4e)
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 -E '(carp|vrrp)' | 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
108atf_test_case "vrrp_v4" "cleanup"
109vrrp_v4_head()
110{
111	atf_set descr 'Basic VRRP test (IPv4)'
112	atf_set require.user root
113}
114
115vrrp_v4_body()
116{
117	carp_init
118
119	j=vrrp_basic_v4
120
121	bridge=$(vnet_mkbridge)
122	epair_one=$(vnet_mkepair)
123	epair_two=$(vnet_mkepair)
124
125	vnet_mkjail ${j}_one ${bridge} ${epair_one}a ${epair_two}a
126	vnet_mkjail ${j}_two ${epair_one}b
127	vnet_mkjail ${j}_three ${epair_two}b
128
129	jexec ${j}_one ifconfig ${bridge} 192.0.2.4/29 up
130	jexec ${j}_one ifconfig ${bridge} addm ${epair_one}a \
131	    addm ${epair_two}a
132	jexec ${j}_one ifconfig ${epair_one}a up
133	jexec ${j}_one ifconfig ${epair_two}a up
134
135	jexec ${j}_two ifconfig ${epair_one}b 192.0.2.202/29 up
136	jexec ${j}_two ifconfig ${epair_one}b add vhid 1 carpver 3 192.0.2.1/29
137
138	jexec ${j}_three ifconfig ${epair_two}b 192.0.2.203/29 up
139	jexec ${j}_three ifconfig ${epair_two}b add vhid 1 carpver 3 \
140	    192.0.2.1/29
141
142	wait_for_carp ${j}_two ${epair_one}b \
143	    ${j}_three ${epair_two}b
144
145	atf_check -s exit:0 -o ignore jexec ${j}_one \
146	    ping -c 3 192.0.2.1
147}
148
149vrrp_v4_cleanup()
150{
151	vnet_cleanup
152}
153
154atf_test_case "unicast_v4" "cleanup"
155unicast_v4_head()
156{
157	atf_set descr 'Unicast CARP test (IPv4)'
158	atf_set require.user root
159}
160
161unicast_v4_body()
162{
163	carp_init
164
165	bridge=$(vnet_mkbridge)
166	epair_one=$(vnet_mkepair)
167	epair_two=$(vnet_mkepair)
168
169	vnet_mkjail carp_uni_v4_one ${bridge} ${epair_one}a ${epair_two}a
170	vnet_mkjail carp_uni_v4_two ${epair_one}b
171	vnet_mkjail carp_uni_v4_three ${epair_two}b
172
173	jexec carp_uni_v4_one ifconfig ${bridge} 192.0.2.4/29 up
174	jexec carp_uni_v4_one sysctl net.inet.ip.forwarding=1
175	jexec carp_uni_v4_one ifconfig ${bridge} addm ${epair_one}a \
176	    addm ${epair_two}a
177	jexec carp_uni_v4_one ifconfig ${epair_one}a up
178	jexec carp_uni_v4_one ifconfig ${epair_two}a up
179	jexec carp_uni_v4_one ifconfig ${bridge} inet alias 198.51.100.1/25
180	jexec carp_uni_v4_one ifconfig ${bridge} inet alias 198.51.100.129/25
181
182	jexec carp_uni_v4_two ifconfig ${epair_one}b 198.51.100.2/25 up
183	jexec carp_uni_v4_two route add default 198.51.100.1
184	jexec carp_uni_v4_two ifconfig ${epair_one}b add vhid 1 \
185	    peer 198.51.100.130 192.0.2.1/29
186
187	jexec carp_uni_v4_three ifconfig ${epair_two}b 198.51.100.130/25 up
188	jexec carp_uni_v4_three route add default 198.51.100.129
189	jexec carp_uni_v4_three ifconfig ${epair_two}b add vhid 1 \
190	    peer 198.51.100.2 192.0.2.1/29
191
192	# Sanity check
193	atf_check -s exit:0 -o ignore jexec carp_uni_v4_two \
194	    ping -c 1 198.51.100.130
195
196	wait_for_carp carp_uni_v4_two ${epair_one}b \
197	    carp_uni_v4_three ${epair_two}b
198
199	atf_check -s exit:0 -o ignore jexec carp_uni_v4_one \
200	    ping -c 3 192.0.2.1
201
202	jexec carp_uni_v4_two ifconfig
203	jexec carp_uni_v4_three ifconfig
204}
205
206unicast_v4_cleanup()
207{
208	vnet_cleanup
209}
210
211atf_test_case "basic_v6" "cleanup"
212basic_v6_head()
213{
214	atf_set descr 'Basic CARP test (IPv6)'
215	atf_set require.user root
216}
217
218basic_v6_body()
219{
220	carp_init
221
222	bridge=$(vnet_mkbridge)
223	epair_one=$(vnet_mkepair)
224	epair_two=$(vnet_mkepair)
225
226	vnet_mkjail carp_basic_v6_one ${bridge} ${epair_one}a ${epair_two}a
227	vnet_mkjail carp_basic_v6_two ${epair_one}b
228	vnet_mkjail carp_basic_v6_three ${epair_two}b
229
230	jexec carp_basic_v6_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
231	    no_dad
232	jexec carp_basic_v6_one ifconfig ${bridge} addm ${epair_one}a \
233	    addm ${epair_two}a
234	jexec carp_basic_v6_one ifconfig ${epair_one}a up
235	jexec carp_basic_v6_one ifconfig ${epair_two}a up
236
237	jexec carp_basic_v6_two ifconfig ${epair_one}b inet6 \
238	    2001:db8::1:2/64 up no_dad
239	jexec carp_basic_v6_two ifconfig ${epair_one}b inet6 add vhid 1 \
240	    2001:db8::0:1/64
241
242	jexec carp_basic_v6_three ifconfig ${epair_two}b inet6 2001:db8::1:3/64 up no_dad
243	jexec carp_basic_v6_three ifconfig ${epair_two}b inet6 add vhid 1 \
244	    2001:db8::0:1/64
245
246	wait_for_carp carp_basic_v6_two ${epair_one}b \
247	    carp_basic_v6_three ${epair_two}b
248
249	atf_check -s exit:0 -o ignore jexec carp_basic_v6_one \
250	    ping -6 -c 3 2001:db8::0:1
251}
252
253basic_v6_cleanup()
254{
255	vnet_cleanup
256}
257
258atf_test_case "vrrp_v6" "cleanup"
259vrrp_v6_head()
260{
261	atf_set descr 'Basic VRRP test (IPv6)'
262	atf_set require.user root
263}
264
265vrrp_v6_body()
266{
267	carp_init
268
269	j=carp_basic_v6
270
271	bridge=$(vnet_mkbridge)
272	epair_one=$(vnet_mkepair)
273	epair_two=$(vnet_mkepair)
274
275	vnet_mkjail ${j}_one ${bridge} ${epair_one}a ${epair_two}a
276	vnet_mkjail ${j}_two ${epair_one}b
277	vnet_mkjail ${j}_three ${epair_two}b
278
279	jexec ${j}_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
280	    no_dad
281	jexec ${j}_one ifconfig ${bridge} addm ${epair_one}a \
282	    addm ${epair_two}a
283	jexec ${j}_one ifconfig ${epair_one}a up
284	jexec ${j}_one ifconfig ${epair_two}a up
285
286	jexec ${j}_two ifconfig ${epair_one}b inet6 \
287	    2001:db8::1:2/64 up no_dad
288	jexec ${j}_two ifconfig ${epair_one}b inet6 add vhid 1 carpver 3 \
289	    2001:db8::0:1/64
290
291	jexec ${j}_three ifconfig ${epair_two}b inet6 2001:db8::1:3/64 up no_dad
292	jexec ${j}_three ifconfig ${epair_two}b inet6 add vhid 1 carpver 3 \
293	    2001:db8::0:1/64
294
295	wait_for_carp ${j}_two ${epair_one}b \
296	    ${j}_three ${epair_two}b
297
298	atf_check -s exit:0 -o ignore jexec ${j}_one \
299	    ping -6 -c 3 2001:db8::0:1
300}
301
302vrrp_v6_cleanup()
303{
304	vnet_cleanup
305}
306
307atf_test_case "unicast_v6" "cleanup"
308unicast_v6_head()
309{
310	atf_set descr 'Unicast CARP test (IPv6)'
311	atf_set require.user root
312}
313
314unicast_v6_body()
315{
316	carp_init
317
318	bridge=$(vnet_mkbridge)
319	epair_one=$(vnet_mkepair)
320	epair_two=$(vnet_mkepair)
321
322	vnet_mkjail carp_uni_v6_one ${bridge} ${epair_one}a ${epair_two}a
323	vnet_mkjail carp_uni_v6_two ${epair_one}b
324	vnet_mkjail carp_uni_v6_three ${epair_two}b
325
326	jexec carp_uni_v6_one sysctl net.inet6.ip6.forwarding=1
327	jexec carp_uni_v6_one ifconfig ${bridge} addm ${epair_one}a \
328	    addm ${epair_two}a
329	jexec carp_uni_v6_one ifconfig ${epair_one}a up
330	jexec carp_uni_v6_one ifconfig ${epair_two}a up
331	jexec carp_uni_v6_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
332	    no_dad
333	jexec carp_uni_v6_one ifconfig ${bridge} inet6 alias 2001:db8:1::1/64 \
334	    no_dad up
335	jexec carp_uni_v6_one ifconfig ${bridge} inet6 alias 2001:db8:2::1/64 \
336	    no_dad up
337
338	jexec carp_uni_v6_two ifconfig ${epair_one}b inet6 2001:db8:1::2/64 \
339	    no_dad up
340	jexec carp_uni_v6_two route -6 add default 2001:db8:1::1
341	jexec carp_uni_v6_two ifconfig ${epair_one}b inet6 add vhid 1 \
342	    peer6 2001:db8:2::2 \
343	    2001:db8::0:1/64
344
345	jexec carp_uni_v6_three ifconfig ${epair_two}b inet6 2001:db8:2::2/64 \
346	    no_dad up
347	jexec carp_uni_v6_three route -6 add default 2001:db8:2::1
348	jexec carp_uni_v6_three ifconfig ${epair_two}b inet6 add vhid 1 \
349	    peer6 2001:db8:1::2 \
350	    2001:db8::0:1/64
351
352	# Sanity check
353	atf_check -s exit:0 -o ignore jexec carp_uni_v6_two \
354	    ping -6 -c 1 2001:db8:2::2
355
356	wait_for_carp carp_uni_v6_two ${epair_one}b \
357	    carp_uni_v6_three ${epair_two}b
358
359	atf_check -s exit:0 -o ignore jexec carp_uni_v6_one \
360	    ping -6 -c 3 2001:db8::0:1
361}
362
363unicast_v6_cleanup()
364{
365	vnet_cleanup
366}
367
368atf_test_case "unicast_ll_v6" "cleanup"
369unicast_ll_v6_head()
370{
371	atf_set descr 'Unicast CARP test (IPv6, link-local)'
372	atf_set require.user root
373}
374
375unicast_ll_v6_body()
376{
377	carp_init
378
379	j=carp_uni_ll_v6
380
381	bridge=$(vnet_mkbridge)
382	epair_one=$(vnet_mkepair)
383	epair_two=$(vnet_mkepair)
384
385	vnet_mkjail ${j}_one ${bridge} ${epair_one}a ${epair_two}a
386	vnet_mkjail ${j}_two ${epair_one}b
387	vnet_mkjail ${j}_three ${epair_two}b
388
389	jexec ${j}_one ifconfig ${bridge} addm ${epair_one}a \
390	    addm ${epair_two}a
391	jexec ${j}_one ifconfig ${epair_one}a up
392	jexec ${j}_one ifconfig ${epair_two}a up
393	jexec ${j}_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
394	    no_dad
395	jexec ${j}_one ifconfig ${bridge} inet6 alias 2001:db8:1::1/64 \
396	    no_dad up
397
398	jexec ${j}_two ifconfig ${epair_one}b inet6 2001:db8:1::2/64 \
399	    no_dad up
400	jexec ${j}_three ifconfig ${epair_two}b inet6 2001:db8:1::3/64 \
401	    no_dad up
402
403	ll_one=$(jexec ${j}_two ifconfig ${epair_one}b | awk "/ .*%${epair_one}b.* / { print \$2 }" | cut -d % -f 1)
404	ll_two=$(jexec ${j}_three ifconfig ${epair_two}b | awk "/ .*%${epair_two}b.* / { print \$2 }" | cut -d % -f 1)
405
406	jexec ${j}_two ifconfig ${epair_one}b inet6 add vhid 1 \
407	    peer6 ${ll_two} \
408	    2001:db8::0:1/64
409	jexec ${j}_three ifconfig ${epair_two}b inet6 add vhid 1 \
410	    peer6 ${ll_one} \
411	    2001:db8::0:1/64
412
413	# Sanity check
414	atf_check -s exit:0 -o ignore jexec ${j}_two \
415	    ping -6 -c 1 2001:db8:1::3
416
417	wait_for_carp ${j}_two ${epair_one}b \
418	    ${j}_three ${epair_two}b
419
420	atf_check -s exit:0 -o ignore jexec ${j}_one \
421	    ping -6 -c 3 2001:db8::0:1
422}
423
424unicast_ll_v6_cleanup()
425{
426	vnet_cleanup
427}
428
429atf_test_case "negative_demotion" "cleanup"
430negative_demotion_head()
431{
432	atf_set descr 'Test PR #259528'
433	atf_set require.user root
434}
435
436negative_demotion_body()
437{
438	carp_init
439
440	epair=$(vnet_mkepair)
441
442	vnet_mkjail one ${epair}a
443	jexec one sysctl net.inet.carp.preempt=1
444	jexec one ifconfig ${epair}a 192.0.2.1/24 up
445	jexec one ifconfig ${epair}a add vhid 1 192.0.2.254/24 \
446	    advskew 0 pass foobar
447
448	vnet_mkjail two ${epair}b
449	jexec two sysctl net.inet.carp.preempt=1
450	jexec two ifconfig ${epair}b 192.0.2.2/24 up
451	jexec two ifconfig ${epair}b add vhid 1 192.0.2.254/24 \
452	    advskew 100 pass foobar
453
454	# Allow things to settle
455	wait_for_carp one ${epair}a two ${epair}b
456
457	if is_master one ${epair}a && is_master two ${epair}b
458	then
459		atf_fail "Two masters!"
460	fi
461
462	jexec one sysctl net.inet.carp.demotion=-1
463	sleep 3
464
465	if is_master one ${epair}a && is_master two ${epair}b
466	then
467		atf_fail "Two masters!"
468	fi
469}
470
471negative_demotion_cleanup()
472{
473	vnet_cleanup
474}
475
476
477
478atf_test_case "nd6_ns_source_mac" "cleanup"
479nd6_ns_source_mac_head()
480{
481        atf_set descr 'CARP ndp neighbor solicitation MAC source test (IPv6)'
482        atf_set require.user root
483}
484
485nd6_ns_source_mac_body()
486{
487        carp_init
488
489        bridge=$(vnet_mkbridge)
490        epair_one=$(vnet_mkepair)
491        epair_two=$(vnet_mkepair)
492
493        vnet_mkjail carp_ndp_v6_bridge ${bridge} ${epair_one}a ${epair_two}a
494        vnet_mkjail carp_ndp_v6_master ${epair_one}b
495        vnet_mkjail carp_ndp_v6_slave ${epair_two}b
496
497        jexec carp_ndp_v6_bridge ifconfig ${bridge} inet6 2001:db8::0:4/64 up \
498            no_dad
499        jexec carp_ndp_v6_bridge ifconfig ${bridge} addm ${epair_one}a \
500            addm ${epair_two}a
501        jexec carp_ndp_v6_bridge ifconfig ${epair_one}a up
502        jexec carp_ndp_v6_bridge ifconfig ${epair_two}a up
503
504        jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 \
505            2001:db8::1:2/64 up no_dad
506        jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 add vhid 1 \
507            advskew 0 2001:db8::0:1/64
508
509        jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 \
510	    2001:db8::1:3/64 up no_dad
511        jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 add vhid 1 \
512            advskew 100 2001:db8::0:1/64
513
514        wait_for_carp carp_ndp_v6_master ${epair_one}b \
515            carp_ndp_v6_slave ${epair_two}b
516
517	# carp_ndp_v6_master is MASTER
518
519	# trigger a NS from the virtual IP from the BACKUP
520        atf_check -s exit:2 -o ignore jexec carp_ndp_v6_slave \
521            ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4
522
523	# trigger a NS from the virtual IP from the MASTER,
524	# this ping should work
525        atf_check -s exit:0 -o ignore jexec carp_ndp_v6_master \
526            ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4
527
528        # ndp entry should be for the virtual mac
529        atf_check -o match:'2001:db8::1 +00:00:5e:00:01:01' \
530	    jexec carp_ndp_v6_bridge ndp -an
531}
532
533nd6_ns_source_mac_cleanup()
534{
535        vnet_cleanup
536}
537
538
539atf_test_case "switch" "cleanup"
540switch_head()
541{
542	atf_set descr 'Switch between master and backup'
543	atf_set require.user root
544}
545
546switch_body()
547{
548	carp_init
549
550	epair=$(vnet_mkepair)
551
552	ifconfig ${epair}a up
553	ifconfig ${epair}a vhid 1 advskew 100 192.0.2.1/24
554	ifconfig ${epair}a vhid 1 state backup
555	ifconfig ${epair}a vhid 1 state master
556}
557
558switch_cleanup()
559{
560	vnet_cleanup
561}
562
563atf_init_test_cases()
564{
565	atf_add_test_case "basic_v4"
566	atf_add_test_case "vrrp_v4"
567	atf_add_test_case "unicast_v4"
568	atf_add_test_case "basic_v6"
569	atf_add_test_case "vrrp_v6"
570	atf_add_test_case "unicast_v6"
571	atf_add_test_case "unicast_ll_v6"
572	atf_add_test_case "negative_demotion"
573	atf_add_test_case "nd6_ns_source_mac"
574	atf_add_test_case "switch"
575}
576