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