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