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