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