xref: /freebsd/tests/sys/netinet/output.sh (revision ce6a89e27cd190313be39bb479880aeda4778436)
1#!/usr/bin/env atf-sh
2#-
3# SPDX-License-Identifier: BSD-2-Clause
4#
5# Copyright (c) 2020 Alexander V. Chernikov
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# $FreeBSD$
29#
30
31. $(atf_get_srcdir)/../common/vnet.subr
32
33atf_test_case "output_tcp_setup_success" "cleanup"
34output_tcp_setup_success_head()
35{
36
37	atf_set descr 'Test valid IPv4 TCP output'
38	atf_set require.user root
39}
40
41output_tcp_setup_success_body()
42{
43
44	vnet_init
45
46	net_src="192.0.2."
47	net_dst="192.0.2."
48	ip_src="${net_src}1"
49	ip_dst="${net_dst}2"
50	plen=24
51	text="testtesttst"
52	port=4242
53
54	script_name=`dirname $0`/../common/net_receiver.py
55	script_name=`realpath ${script_name}`
56	jname="v4t-output_tcp_setup_success"
57
58	epair=$(vnet_mkepair)
59
60	vnet_mkjail ${jname}a ${epair}a
61	jexec ${jname}a ifconfig ${epair}a up
62	jexec ${jname}a ifconfig ${epair}a inet ${ip_src}/${plen}
63
64	vnet_mkjail ${jname}b ${epair}b
65	jexec ${jname}b ifconfig ${epair}b up
66
67	jexec ${jname}b ifconfig ${epair}b inet ${ip_dst}/${plen}
68
69	# run listener
70	args="--family inet --ports ${port} --match_str ${text}"
71	echo jexec ${jname}b ${script_name} ${args}
72	jexec ${jname}b ${script_name} --test_name "test_listen_tcp" ${args} &
73	cmd_pid=$!
74
75	# wait for the script init
76	counter=0
77	while [ `jexec ${jname}b sockstat -4qlp ${port} | wc -l` != "1" ]; do
78		sleep 0.01
79		counter=$((counter+1))
80		if [ ${counter} -ge 50 ]; then break; fi
81	done
82	if [ `jexec ${jname}b sockstat -4qlp ${port} | wc -l` != "1" ]; then
83		echo "App setup failed"
84		exit 1
85	fi
86
87	# run sender
88	echo -n "${text}" | jexec ${jname}a nc -N ${ip_dst} ${port}
89	exit_code=$?
90	if [ $exit_code -ne 0 ]; then atf_fail "sender exit code $exit_code" ; fi
91
92	wait ${cmd_pid}
93	exit_code=$?
94	if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi
95}
96
97output_tcp_setup_success_cleanup()
98{
99	vnet_cleanup
100}
101
102
103atf_test_case "output_udp_setup_success" "cleanup"
104output_udp_setup_success_head()
105{
106
107	atf_set descr 'Test valid IPv4 UDP output'
108	atf_set require.user root
109}
110
111output_udp_setup_success_body()
112{
113
114	vnet_init
115
116	net_src="192.0.2."
117	net_dst="192.0.2."
118	ip_src="${net_src}1"
119	ip_dst="${net_dst}2"
120	plen=24
121	text="testtesttst"
122	port=4242
123
124	script_name=`dirname $0`/../common/net_receiver.py
125	script_name=`realpath ${script_name}`
126	jname="v4t-output_udp_setup_success"
127
128	epair=$(vnet_mkepair)
129
130	vnet_mkjail ${jname}a ${epair}a
131	jexec ${jname}a ifconfig ${epair}a up
132	jexec ${jname}a ifconfig ${epair}a inet ${ip_src}/${plen}
133
134	vnet_mkjail ${jname}b ${epair}b
135	jexec ${jname}b ifconfig ${epair}b up
136	jexec ${jname}b ifconfig ${epair}b inet ${ip_dst}/${plen}
137
138	# run listener
139	args="--family inet --ports ${port} --match_str ${text}"
140	echo jexec ${jname}b ${script_name} ${args}
141	jexec ${jname}b ${script_name} --test_name "test_listen_udp" ${args} &
142	cmd_pid=$!
143
144	# wait for the script init
145	counter=0
146	while [ `jexec ${jname}b sockstat -4qlp ${port} | wc -l` != "1" ]; do
147		sleep 0.1
148		counterc=$((counter+1))
149		if [ ${counter} -ge 50 ]; then break; fi
150	done
151	if [ `jexec ${jname}b sockstat -4qlp ${port} | wc -l` != "1" ]; then
152		echo "App setup failed"
153		exit 1
154	fi
155
156	# run sender
157	# TODO: switch from nc to some alternative to avoid 1-second delay
158	echo -n "${text}" | jexec ${jname}a nc -uNw1 ${ip_dst} ${port}
159	exit_code=$?
160	if [ $exit_code -ne 0 ]; then atf_fail "sender exit code $exit_code" ; fi
161
162	wait ${cmd_pid}
163	exit_code=$?
164	if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi
165}
166
167output_udp_setup_success_cleanup()
168{
169	vnet_cleanup
170}
171
172atf_test_case "output_raw_success" "cleanup"
173output_raw_success_head()
174{
175
176	atf_set descr 'Test valid IPv4 raw output'
177	atf_set require.user root
178}
179
180output_raw_success_body()
181{
182
183	vnet_init
184
185	net_src="192.0.2."
186	net_dst="192.0.2."
187	ip_src="${net_src}1"
188	ip_dst="${net_dst}2"
189	plen=24
190
191	script_name=`dirname $0`/../common/net_receiver.py
192	script_name=`realpath ${script_name}`
193	jname="v4t-output_raw_success"
194
195	epair=$(vnet_mkepair)
196
197	vnet_mkjail ${jname}a ${epair}a
198	jexec ${jname}a ifconfig ${epair}a up
199	jexec ${jname}a ifconfig ${epair}a inet ${ip_src}/${plen}
200
201	vnet_mkjail ${jname}b ${epair}b
202	jexec ${jname}b ifconfig ${epair}b up
203
204	jexec ${jname}b ifconfig ${epair}b inet ${ip_dst}/${plen}
205
206	atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst}
207}
208
209output_raw_success_cleanup()
210{
211	vnet_cleanup
212}
213
214# Multipath tests are done the following way:
215#            epair0
216# jailA lo <        > lo jailB
217#            epair1
218# jailA has 2 routes towards /24 prefix on jailB loopback, via 2 epairs
219# jailB has 1 route towards /24 prefix on jailA loopback, via epair0
220#
221# jailA initiates connections/sends packets towards IPs on jailB loopback.
222# Script then compares amount of packets sent via epair0 and epair1
223
224mpath_check()
225{
226	if [ "`sysctl -i -n net.route.multipath`" != 1 ]; then
227		atf_skip "This test requires ROUTE_MPATH enabled"
228	fi
229}
230
231atf_test_case "output_tcp_flowid_mpath_success" "cleanup"
232output_tcp_flowid_mpath_success_head()
233{
234
235	atf_set descr 'Test valid IPv4 TCP output flowid generation'
236	atf_set require.user root
237}
238
239output_tcp_flowid_mpath_success_body()
240{
241	vnet_init
242	mpath_check
243
244	net_src="192.0.2."
245	net_dst="198.51.100."
246	ip_src="${net_src}1"
247	ip_dst="${net_dst}1"
248	plen=24
249	text="testtesttst"
250
251	script_name=`dirname $0`/../common/net_receiver.py
252	script_name=`realpath ${script_name}`
253	jname="v4t-output_tcp_flowid_mpath_success"
254
255	epair0=$(vnet_mkepair)
256	epair1=$(vnet_mkepair)
257	lo_src=$(vnet_mkloopback)
258	lo_dst=$(vnet_mkloopback)
259
260	vnet_mkjail ${jname}a ${epair0}a ${epair1}a ${lo_src}
261	# Setup transit IPv4 networks
262	jexec ${jname}a ifconfig ${epair0}a up
263	jexec ${jname}a ifconfig ${epair0}a inet 203.0.113.1/30
264	jexec ${jname}a ifconfig ${epair1}a up
265	jexec ${jname}a ifconfig ${epair1}a inet 203.0.113.5/30
266	jexec ${jname}a ifconfig ${lo_src} up
267
268	vnet_mkjail ${jname}b ${epair0}b ${epair1}b ${lo_dst}
269	jexec ${jname}b ifconfig ${epair0}b up
270	jexec ${jname}b ifconfig ${epair0}b inet 203.0.113.2/30
271	jexec ${jname}b ifconfig ${epair1}b up
272	jexec ${jname}b ifconfig ${epair1}b inet 203.0.113.6/30
273	jexec ${jname}b ifconfig ${lo_dst} up
274
275	# DST ips/ports to test
276	ips="4 29 48 53 55 61 71 80 84 87 90 91 119 131 137 153 154 158 162 169 169 171 176 187 197 228 233 235 236 237 245 251"
277	ports="53540 49743 43067 9131 16734 5150 14379 40292 20634 51302 3387 24387 9282 14275 42103 26881 42461 29520 45714 11096"
278
279	jexec ${jname}a ifconfig ${lo_src} inet ${ip_src}/32
280
281	jexec ${jname}b ifconfig ${lo_dst} inet ${ip_dst}/32
282	for i in ${ips}; do
283		jexec ${jname}b ifconfig ${lo_dst} alias ${net_dst}${i}/32
284	done
285
286	# Add routes
287	# A -> towards B via epair0a
288	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.2
289	# A -> towards B via epair1a
290	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.6
291
292	# B towards A via epair0b
293	jexec ${jname}b route add -4 -net ${net_src}0/${plen} 203.0.113.1
294
295	# Base setup verification
296	atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst}
297
298	# run listener
299	num_ports=`echo ${ports} | wc -w`
300	num_ips=`echo ${ips} | wc -w`
301	count_examples=$((num_ports*num_ips))
302	listener_ports=`echo ${ports} | tr ' ' '\n' | sort -n | tr '\n' ',' | sed -e 's?,$??'`
303	args="--family inet --ports ${listener_ports} --count ${count_examples} --match_str ${text}"
304	echo jexec ${jname}b ${script_name} ${args}
305	jexec ${jname}b ${script_name} --test_name "test_listen_tcp" ${args} &
306	cmd_pid=$!
307
308	# wait for the app init
309	counter=0
310	init=0
311	while [ ${counter} -le 50 ]; do
312		_ports=`jexec ${jname}b sockstat -4ql | awk "\\\$3 == ${cmd_pid} {print \\\$6}"|awk -F: "{print \\\$2}" | sort -n | tr '\n' ','`
313		if [ "${_ports}" = "${listener_ports}," ]; then
314			init=1
315			break;
316		fi
317	done
318	if [ ${init} -eq 0 ]; then
319		jexec ${jname}b sockstat -6ql | awk "\$3 == ${cmd_pid}"
320		echo "App setup failed"
321		exit 1
322	fi
323	echo "App setup done"
324
325	# run sender
326	for _ip in ${ips}; do
327		ip="${net_dst}${_ip}"
328		for port in ${ports}; do
329			echo -n "${text}" | jexec ${jname}a nc -nN ${ip} ${port}
330			exit_code=$?
331			if [ $exit_code -ne 0 ]; then atf_fail "sender exit code $exit_code" ; fi
332		done
333	done
334
335	wait ${cmd_pid}
336	exit_code=$?
337	if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi
338
339	pkt_0=`jexec ${jname}a netstat -Wf link -I ${epair0}a | head | awk '$1!~/^Name/{print$8}'`
340	pkt_1=`jexec ${jname}a netstat -Wf link -I ${epair1}a | head | awk '$1!~/^Name/{print$8}'`
341	if [ ${pkt_0} -le 10 ]; then
342		echo "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
343		exit 1
344	fi
345	if [ ${pkt_1} -le 10 ]; then
346		echo "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
347		exit 1
348	fi
349	echo "TCP Balancing: 1: ${pkt_0} 2: ${pkt_1}"
350}
351
352output_tcp_flowid_mpath_success_cleanup()
353{
354	vnet_cleanup
355}
356
357atf_test_case "output_udp_flowid_mpath_success" "cleanup"
358output_udp_flowid_mpath_success_head()
359{
360
361	atf_set descr 'Test valid IPv4 UDP output flowid generation'
362	atf_set require.user root
363}
364
365output_udp_flowid_mpath_success_body()
366{
367
368	vnet_init
369	mpath_check
370
371	# Note this test will spawn around ~100 nc processes
372
373	net_src="192.0.2."
374	net_dst="198.51.100."
375	ip_src="${net_src}1"
376	ip_dst="${net_dst}1"
377	plen=24
378	text="testtesttst"
379
380	script_name=`dirname $0`/../common/net_receiver.py
381	script_name=`realpath ${script_name}`
382	jname="v4t-output_tcp_flowid_mpath_success"
383
384	epair0=$(vnet_mkepair)
385	epair1=$(vnet_mkepair)
386	lo_src=$(vnet_mkloopback)
387	lo_dst=$(vnet_mkloopback)
388
389	vnet_mkjail ${jname}a ${epair0}a ${epair1}a ${lo_src}
390	# Setup transit IPv4 networks
391	jexec ${jname}a ifconfig ${epair0}a up
392	jexec ${jname}a ifconfig ${epair0}a inet 203.0.113.1/30
393	jexec ${jname}a ifconfig ${epair1}a up
394	jexec ${jname}a ifconfig ${epair1}a inet 203.0.113.5/30
395	jexec ${jname}a ifconfig ${lo_src} up
396
397	vnet_mkjail ${jname}b ${epair0}b ${epair1}b ${lo_dst}
398	jexec ${jname}b ifconfig ${epair0}b up
399	jexec ${jname}b ifconfig ${epair0}b inet 203.0.113.2/30
400	jexec ${jname}b ifconfig ${epair1}b up
401	jexec ${jname}b ifconfig ${epair1}b inet 203.0.113.6/30
402	jexec ${jname}b ifconfig ${lo_dst} up
403
404	# DST ips/ports to test
405	ips="4 29 48 53 55 61 71 80 84 87 90 91 119 131 137 153 154 158 162 169 169 171 176 187 197 228 233 235 236 237 245 251"
406	ports="53540 49743 43067 9131 16734 5150 14379 40292 20634 51302 3387 24387 9282 14275 42103 26881 42461 29520 45714 11096"
407
408	jexec ${jname}a ifconfig ${lo_src} inet ${ip_src}/32
409
410	jexec ${jname}b ifconfig ${lo_dst} inet ${ip_dst}/32
411	for i in ${ips}; do
412		jexec ${jname}b ifconfig ${lo_dst} alias ${net_dst}${i}/32
413	done
414
415	# Add routes
416	# A -> towards B via epair0a
417	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.2
418	# A -> towards B via epair1a
419	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.6
420
421	# B towards A via epair0b
422	jexec ${jname}b route add -4 -net ${net_src}0/${plen} 203.0.113.1
423
424	# Base setup verification
425	atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst}
426
427	# run listener
428	num_ports=`echo ${ports} | wc -w`
429	num_ips=`echo ${ips} | wc -w`
430	count_examples=$((num_ports*num_ips))
431	listener_ports=`echo ${ports} | tr ' ' '\n' | sort -n | tr '\n' ',' | sed -e 's?,$??'`
432	args="--family inet --ports ${listener_ports} --count ${count_examples} --match_str ${text}"
433	echo jexec ${jname}b ${script_name} ${args}
434	jexec ${jname}b ${script_name} --test_name "test_listen_udp" ${args} &
435	cmd_pid=$!
436
437	# wait for the app init
438	counter=0
439	init=0
440	while [ ${counter} -le 50 ]; do
441		_ports=`jexec ${jname}b sockstat -4ql | awk "\\\$3 == ${cmd_pid} {print \\\$6}"|awk -F: "{print \\\$2}" | sort -n | tr '\n' ','`
442		if [ "${_ports}" = "${listener_ports}," ]; then
443			init=1
444			break;
445		fi
446	done
447	if [ ${init} -eq 0 ]; then
448		jexec ${jname}b sockstat -4ql | awk "\$3 == ${cmd_pid}"
449		echo "App setup failed"
450		exit 1
451	fi
452	echo "App setup done"
453
454	# run sender
455	for _ip in ${ips}; do
456		ip="${net_dst}${_ip}"
457		for port in ${ports}; do
458			# XXX: switch to something that allows immediate exit
459			echo -n "${text}" | jexec ${jname}a nc -nuNw1 ${ip} ${port} &
460			sleep 0.01
461		done
462	done
463
464	wait ${cmd_pid}
465	exit_code=$?
466	if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi
467
468	pkt_0=`jexec ${jname}a netstat -Wf link -I ${epair0}a | head | awk '$1!~/^Name/{print$8}'`
469	pkt_1=`jexec ${jname}a netstat -Wf link -I ${epair1}a | head | awk '$1!~/^Name/{print$8}'`
470	if [ ${pkt_0} -le 10 ]; then
471		echo "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
472		exit 1
473	fi
474	if [ ${pkt_1} -le 10 ]; then
475		echo "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
476		exit 1
477	fi
478	echo "UDP BALANCING: 1: ${pkt_0} 2: ${pkt_1}"
479}
480
481output_udp_flowid_mpath_success_cleanup()
482{
483	vnet_cleanup
484}
485
486atf_test_case "output_raw_flowid_mpath_success" "cleanup"
487output_raw_flowid_mpath_success_head()
488{
489
490	atf_set descr 'Test valid IPv4 raw output flowid generation'
491	atf_set require.user root
492}
493
494output_raw_flowid_mpath_success_body()
495{
496
497	vnet_init
498	mpath_check
499
500	net_src="192.0.2."
501	net_dst="198.51.100."
502	ip_src="${net_src}1"
503	ip_dst="${net_dst}1"
504	plen=24
505	text="testtesttst"
506
507	jname="v4t-output_tcp_flowid_mpath_success"
508
509	epair0=$(vnet_mkepair)
510	epair1=$(vnet_mkepair)
511	lo_src=$(vnet_mkloopback)
512	lo_dst=$(vnet_mkloopback)
513
514	vnet_mkjail ${jname}a ${epair0}a ${epair1}a ${lo_src}
515	# Setup transit IPv4 networks
516	jexec ${jname}a ifconfig ${epair0}a up
517	jexec ${jname}a ifconfig ${epair0}a inet 203.0.113.1/30
518	jexec ${jname}a ifconfig ${epair1}a up
519	jexec ${jname}a ifconfig ${epair1}a inet 203.0.113.5/30
520	jexec ${jname}a ifconfig ${lo_src} up
521
522	vnet_mkjail ${jname}b ${epair0}b ${epair1}b ${lo_dst}
523	jexec ${jname}b ifconfig ${epair0}b up
524	jexec ${jname}b ifconfig ${epair0}b inet 203.0.113.2/30
525	jexec ${jname}b ifconfig ${epair1}b up
526	jexec ${jname}b ifconfig ${epair1}b inet 203.0.113.6/30
527	jexec ${jname}b ifconfig ${lo_dst} up
528
529	# DST ips/ports to test
530	ips="4 29 48 53 55 61 71 80 84 87 90 91 119 131 137 153 154 158 162 169 169 171 176 187 197 228 233 235 236 237 245 251"
531
532	jexec ${jname}a ifconfig ${lo_src} inet ${ip_src}/32
533
534	jexec ${jname}b ifconfig ${lo_dst} inet ${ip_dst}/32
535	for i in ${ips}; do
536		jexec ${jname}b ifconfig ${lo_dst} alias ${net_dst}${i}/32
537	done
538
539	# Add routes
540	# A -> towards B via epair0a
541	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.2
542	# A -> towards B via epair1a
543	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.6
544
545	# B towards A via epair0b
546	jexec ${jname}b route add -4 -net ${net_src}0/${plen} 203.0.113.1
547
548	# Base setup verification
549	atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst}
550
551	# run sender
552	valid_message='1 packets transmitted, 1 packets received'
553	for _ip in ${ips}; do
554		ip="${net_dst}${_ip}"
555		atf_check -o match:"${valid_message}" jexec ${jname}a ping -nc1 ${ip}
556	done
557
558	pkt_0=`jexec ${jname}a netstat -Wf link -I ${epair0}a | head | awk '$1!~/^Name/{print$8}'`
559	pkt_1=`jexec ${jname}a netstat -Wf link -I ${epair1}a | head | awk '$1!~/^Name/{print$8}'`
560
561	jexec ${jname}a netstat -bWf link -I ${epair0}a
562	jexec ${jname}a netstat -bWf link -I ${epair1}a
563	if [ ${pkt_0} -le 10 ]; then
564		echo "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
565		exit 1
566	fi
567	if [ ${pkt_1} -le 10 ]; then
568		echo "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
569		exit 1
570	fi
571	echo "RAW BALANCING: 1: ${pkt_0} 2: ${pkt_1}"
572}
573
574output_raw_flowid_mpath_success_cleanup()
575{
576	vnet_cleanup
577}
578
579atf_init_test_cases()
580{
581	atf_add_test_case "output_tcp_setup_success"
582	atf_add_test_case "output_udp_setup_success"
583	atf_add_test_case "output_raw_success"
584	atf_add_test_case "output_tcp_flowid_mpath_success"
585	atf_add_test_case "output_udp_flowid_mpath_success"
586	atf_add_test_case "output_raw_flowid_mpath_success"
587}
588
589