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