xref: /freebsd/tests/sys/netpfil/common/dummynet.sh (revision d7d962ead0b6e5e8a39202d0590022082bf5bfb6)
1# $FreeBSD$
2#
3# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4#
5# Copyright (c) 2021 Rubicon Communications, LLC (Netgate)
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27
28. $(atf_get_srcdir)/utils.subr
29. $(atf_get_srcdir)/runner.subr
30
31pipe_head()
32{
33	atf_set descr 'Basic pipe test'
34	atf_set require.user root
35}
36
37pipe_body()
38{
39	fw=$1
40	firewall_init $fw
41	dummynet_init $fw
42
43	epair=$(vnet_mkepair)
44	vnet_mkjail alcatraz ${epair}b
45
46	ifconfig ${epair}a 192.0.2.1/24 up
47	jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
48
49	# Sanity check
50	atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2
51
52	jexec alcatraz dnctl pipe 1 config bw 30Byte/s
53
54	firewall_config alcatraz ${fw} \
55		"ipfw"	\
56			"ipfw add 1000 pipe 1 ip from any to any"
57
58	# single ping succeeds just fine
59	atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2
60
61	# Saturate the link
62	ping -i .1 -c 5 -s 1200 192.0.2.2
63
64	# We should now be hitting the limits and get this packet dropped.
65	atf_check -s exit:2 -o ignore ping -c 1 -s 1200 192.0.2.2
66}
67
68pipe_cleanup()
69{
70	firewall_cleanup $1
71}
72
73pipe_v6_head()
74{
75	atf_set descr 'Basic IPv6 pipe test'
76	atf_set require.user root
77}
78
79pipe_v6_body()
80{
81	fw=$1
82	firewall_init $fw
83	dummynet_init $fw
84
85	epair=$(vnet_mkepair)
86	vnet_mkjail alcatraz ${epair}b
87
88	ifconfig ${epair}a inet6 2001:db8:42::1/64 up no_dad
89	jexec alcatraz ifconfig ${epair}b inet6 2001:db8:42::2/64 up no_dad
90
91	# Sanity check
92	atf_check -s exit:0 -o ignore ping6 -i .1 -c 3 -s 1200 2001:db8:42::2
93
94	jexec alcatraz dnctl pipe 1 config bw 100Byte/s
95
96	firewall_config alcatraz ${fw} \
97		"ipfw"	\
98			"ipfw add 1000 pipe 1 ip6 from any to any"
99
100	# Single ping succeeds
101	atf_check -s exit:0 -o ignore ping6 -c 1 2001:db8:42::2
102
103	# Saturate the link
104	ping6 -i .1 -c 5 -s 1200 2001:db8:42::2
105
106	# We should now be hitting the limit and get this packet dropped.
107	atf_check -s exit:2 -o ignore ping6 -c 1 -s 1200 2001:db8:42::2
108}
109
110pipe_v6_cleanup()
111{
112	firewall_cleanup $1
113}
114
115queue_head()
116{
117	atf_set descr 'Basic queue test'
118	atf_set require.user root
119}
120
121queue_body()
122{
123	fw=$1
124	firewall_init $fw
125	dummynet_init $fw
126
127	epair=$(vnet_mkepair)
128	vnet_mkjail alcatraz ${epair}b
129
130	ifconfig ${epair}a 192.0.2.1/24 up
131	jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
132	jexec alcatraz /usr/sbin/inetd -p inetd-alcatraz.pid \
133	    $(atf_get_srcdir)/../pf/echo_inetd.conf
134
135	# Sanity check
136	atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2
137	reply=$(echo "foo" | nc -N 192.0.2.2 7)
138	if [ "$reply" != "foo" ];
139	then
140		atf_fail "Echo sanity check failed"
141	fi
142
143	jexec alcatraz dnctl pipe 1 config bw 1MByte/s
144	jexec alcatraz dnctl sched 1 config pipe 1 type wf2q+
145	jexec alcatraz dnctl queue 100 config sched 1 weight 99 mask all
146	jexec alcatraz dnctl queue 200 config sched 1 weight 1 mask all
147
148	firewall_config alcatraz ${fw} \
149		"ipfw"	\
150			"ipfw add 1000 queue 100 tcp from 192.0.2.2 to any out" \
151			"ipfw add 1001 queue 200 icmp from 192.0.2.2 to any out" \
152			"ipfw add 1002 allow ip from any to any"
153
154	# Single ping succeeds
155	atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2
156
157	# Unsaturated TCP succeeds
158	reply=$(echo "foo" | nc -w 5 -N 192.0.2.2 7)
159	if [ "$reply" != "foo" ];
160	then
161		atf_fail "Unsaturated echo failed"
162	fi
163
164	# Saturate the link
165	ping -f -s 1300 192.0.2.2 &
166
167	# Allow this to fill the queue
168	sleep 1
169
170	# TCP should still just pass
171	fails=0
172	for i in `seq 1 3`
173	do
174		result=$(dd if=/dev/zero bs=1024 count=2000 | timeout 3 nc -w 5 -N 192.0.2.2 7 | wc -c)
175		if [ $result -ne 2048000 ];
176		then
177			echo "Failed to prioritise TCP traffic. Got only $result bytes"
178			fails=$(( ${fails} + 1 ))
179		fi
180	done
181	if [ ${fails} -gt 0 ];
182	then
183		atf_fail "We failed prioritisation ${fails} times"
184	fi
185
186	# This will fail if we reverse the pola^W priority
187	firewall_config alcatraz ${fw} \
188		"ipfw"	\
189			"ipfw add 1000 queue 200 tcp from 192.0.2.2 to any out" \
190			"ipfw add 1001 queue 100 icmp from 192.0.2.2 to any out" \
191			"ipfw add 1002 allow ip from any to any"
192
193	jexec alcatraz ping -f -s 1300 192.0.2.1 &
194	sleep 1
195
196	fails=0
197	for i in `seq 1 3`
198	do
199		result=$(dd if=/dev/zero bs=1024 count=2000 | timeout 3 nc -w 5 -N 192.0.2.2 7 | wc -c)
200		if [ $result -ne 2048000 ];
201		then
202			echo "Failed to prioritise TCP traffic. Got only $result bytes"
203			fails=$(( ${fails} + 1 ))
204		fi
205	done
206	if [ ${fails} -lt 3 ];
207	then
208		atf_fail "We failed reversed prioritisation only ${fails} times."
209	fi
210}
211
212queue_cleanup()
213{
214	firewall_cleanup $1
215}
216
217queue_v6_head()
218{
219	atf_set descr 'Basic queue test'
220	atf_set require.user root
221}
222
223queue_v6_body()
224{
225	fw=$1
226	firewall_init $fw
227	dummynet_init $fw
228
229	epair=$(vnet_mkepair)
230	vnet_mkjail alcatraz ${epair}b
231
232	ifconfig ${epair}a inet6 2001:db8:42::1/64 no_dad up
233	jexec alcatraz ifconfig ${epair}b inet6 2001:db8:42::2 no_dad up
234	jexec alcatraz /usr/sbin/inetd -p inetd-alcatraz.pid \
235	    $(atf_get_srcdir)/../pf/echo_inetd.conf
236
237	# Sanity check
238	atf_check -s exit:0 -o ignore ping6 -i .1 -c 3 -s 1200 2001:db8:42::2
239	reply=$(echo "foo" | nc -N 2001:db8:42::2 7)
240	if [ "$reply" != "foo" ];
241	then
242		atf_fail "Echo sanity check failed"
243	fi
244
245	jexec alcatraz dnctl pipe 1 config bw 1MByte/s
246	jexec alcatraz dnctl sched 1 config pipe 1 type wf2q+
247	jexec alcatraz dnctl queue 100 config sched 1 weight 99 mask all
248	jexec alcatraz dnctl queue 200 config sched 1 weight 1 mask all
249
250	firewall_config alcatraz ${fw} \
251		"ipfw"	\
252			"ipfw add 1001 queue 100 tcp from 2001:db8:42::2 to any out" \
253			"ipfw add 1000 queue 200 ipv6-icmp from 2001:db8:42::2 to any out" \
254			"ipfw add 1002 allow ip6 from any to any" \
255		"pf" \
256			"pass out proto tcp dnqueue 100"	\
257			"pass out proto icmp6 dnqueue 200"
258
259	# Single ping succeeds
260	atf_check -s exit:0 -o ignore ping6 -c 1 2001:db8:42::2
261
262	# Unsaturated TCP succeeds
263	reply=$(echo "foo" | nc -w 5 -N 2001:db8:42::2 7)
264	if [ "$reply" != "foo" ];
265	then
266		atf_fail "Unsaturated echo failed"
267	fi
268
269	# Saturate the link
270	ping6 -f -s 1200 2001:db8:42::2 &
271
272	# Allow this to fill the queue
273	sleep 1
274
275	# TCP should still just pass
276	fails=0
277	for i in `seq 1 3`
278	do
279		result=$(dd if=/dev/zero bs=1024 count=1000 | timeout 3 nc -w 5 -N 2001:db8:42::2 7 | wc -c)
280		if [ $result -ne 1024000 ];
281		then
282			echo "Failed to prioritise TCP traffic. Got only $result bytes"
283			fails=$(( ${fails} + 1 ))
284		fi
285	done
286	if [ ${fails} -gt 0 ];
287	then
288		atf_fail "We failed prioritisation ${fails} times"
289	fi
290
291	# What happens if we prioritise ICMP over TCP?
292	firewall_config alcatraz ${fw} \
293		"ipfw"	\
294			"ipfw add 1001 queue 200 tcp from 2001:db8:42::2 to any out" \
295			"ipfw add 1000 queue 100 ipv6-icmp from 2001:db8:42::2 to any out" \
296			"ipfw add 1002 allow ip6 from any to any" \
297		"pf" \
298			"pass out proto tcp dnqueue 200"	\
299			"pass out proto icmp6 dnqueue 100"
300
301	fails=0
302	for i in `seq 1 3`
303	do
304		result=$(dd if=/dev/zero bs=1024 count=1000 | timeout 3 nc -w 5 -N 2001:db8:42::2 7 | wc -c)
305		if [ $result -ne 1024000 ];
306		then
307			echo "Failed to prioritise TCP traffic. Got only $result bytes"
308			fails=$(( ${fails} + 1 ))
309		fi
310	done
311	if [ ${fails} -lt 3 ];
312	then
313		atf_fail "We failed reversed prioritisation only ${fails} times."
314	fi
315}
316
317queue_v6_cleanup()
318{
319	firewall_cleanup $1
320}
321
322setup_tests		\
323	pipe		\
324		ipfw	\
325	pipe_v6		\
326		ipfw	\
327	queue		\
328		ipfw	\
329	queue_v6	\
330		ipfw
331