xref: /freebsd/tests/sys/netinet/output.sh (revision 100353cfbf882e23c911300ebd0cb458bd3ee975)
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		atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
343	fi
344	if [ ${pkt_1} -le 10 ]; then
345		atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
346		exit 1
347	fi
348	echo "TCP Balancing: 1: ${pkt_0} 2: ${pkt_1}"
349}
350
351output_tcp_flowid_mpath_success_cleanup()
352{
353	vnet_cleanup
354}
355
356atf_test_case "output_udp_flowid_mpath_success" "cleanup"
357output_udp_flowid_mpath_success_head()
358{
359
360	atf_set descr 'Test valid IPv4 UDP output flowid generation'
361	atf_set require.user root
362}
363
364output_udp_flowid_mpath_success_body()
365{
366
367	vnet_init
368	mpath_check
369
370	# Note this test will spawn around ~100 nc processes
371
372	net_src="192.0.2."
373	net_dst="198.51.100."
374	ip_src="${net_src}1"
375	ip_dst="${net_dst}1"
376	plen=24
377	text="testtesttst"
378
379	script_name=`dirname $0`/../common/net_receiver.py
380	script_name=`realpath ${script_name}`
381	jname="v4t-output_tcp_flowid_mpath_success"
382
383	epair0=$(vnet_mkepair)
384	epair1=$(vnet_mkepair)
385	lo_src=$(vnet_mkloopback)
386	lo_dst=$(vnet_mkloopback)
387
388	vnet_mkjail ${jname}a ${epair0}a ${epair1}a ${lo_src}
389	# Setup transit IPv4 networks
390	jexec ${jname}a ifconfig ${epair0}a up
391	jexec ${jname}a ifconfig ${epair0}a inet 203.0.113.1/30
392	jexec ${jname}a ifconfig ${epair1}a up
393	jexec ${jname}a ifconfig ${epair1}a inet 203.0.113.5/30
394	jexec ${jname}a ifconfig ${lo_src} up
395
396	vnet_mkjail ${jname}b ${epair0}b ${epair1}b ${lo_dst}
397	jexec ${jname}b ifconfig ${epair0}b up
398	jexec ${jname}b ifconfig ${epair0}b inet 203.0.113.2/30
399	jexec ${jname}b ifconfig ${epair1}b up
400	jexec ${jname}b ifconfig ${epair1}b inet 203.0.113.6/30
401	jexec ${jname}b ifconfig ${lo_dst} up
402
403	# DST ips/ports to test
404	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"
405	ports="53540 49743 43067 9131 16734 5150 14379 40292 20634 51302 3387 24387 9282 14275 42103 26881 42461 29520 45714 11096"
406
407	jexec ${jname}a ifconfig ${lo_src} inet ${ip_src}/32
408
409	jexec ${jname}b ifconfig ${lo_dst} inet ${ip_dst}/32
410	for i in ${ips}; do
411		jexec ${jname}b ifconfig ${lo_dst} alias ${net_dst}${i}/32
412	done
413
414	# Add routes
415	# A -> towards B via epair0a
416	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.2
417	# A -> towards B via epair1a
418	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.6
419
420	# B towards A via epair0b
421	jexec ${jname}b route add -4 -net ${net_src}0/${plen} 203.0.113.1
422
423	# Base setup verification
424	atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst}
425
426	# run listener
427	num_ports=`echo ${ports} | wc -w`
428	num_ips=`echo ${ips} | wc -w`
429	count_examples=$((num_ports*num_ips))
430	listener_ports=`echo ${ports} | tr ' ' '\n' | sort -n | tr '\n' ',' | sed -e 's?,$??'`
431	args="--family inet --ports ${listener_ports} --count ${count_examples} --match_str ${text}"
432	echo jexec ${jname}b ${script_name} ${args}
433	jexec ${jname}b ${script_name} --test_name "test_listen_udp" ${args} &
434	cmd_pid=$!
435
436	# wait for the app init
437	counter=0
438	init=0
439	while [ ${counter} -le 50 ]; do
440		_ports=`jexec ${jname}b sockstat -4ql | awk "\\\$3 == ${cmd_pid} {print \\\$6}"|awk -F: "{print \\\$2}" | sort -n | tr '\n' ','`
441		if [ "${_ports}" = "${listener_ports}," ]; then
442			init=1
443			break;
444		fi
445	done
446	if [ ${init} -eq 0 ]; then
447		jexec ${jname}b sockstat -4ql | awk "\$3 == ${cmd_pid}"
448		echo "App setup failed"
449		exit 1
450	fi
451	echo "App setup done"
452
453	# run sender
454	for _ip in ${ips}; do
455		ip="${net_dst}${_ip}"
456		for port in ${ports}; do
457			# XXX: switch to something that allows immediate exit
458			echo -n "${text}" | jexec ${jname}a nc -nuNw1 ${ip} ${port} &
459			sleep 0.01
460		done
461	done
462
463	wait ${cmd_pid}
464	exit_code=$?
465	if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi
466
467	pkt_0=`jexec ${jname}a netstat -Wf link -I ${epair0}a | head | awk '$1!~/^Name/{print$8}'`
468	pkt_1=`jexec ${jname}a netstat -Wf link -I ${epair1}a | head | awk '$1!~/^Name/{print$8}'`
469	if [ ${pkt_0} -le 10 ]; then
470		atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
471	fi
472	if [ ${pkt_1} -le 10 ]; then
473		atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
474	fi
475	echo "UDP BALANCING: 1: ${pkt_0} 2: ${pkt_1}"
476}
477
478output_udp_flowid_mpath_success_cleanup()
479{
480	vnet_cleanup
481}
482
483atf_test_case "output_raw_flowid_mpath_success" "cleanup"
484output_raw_flowid_mpath_success_head()
485{
486
487	atf_set descr 'Test valid IPv4 raw output flowid generation'
488	atf_set require.user root
489}
490
491output_raw_flowid_mpath_success_body()
492{
493
494	vnet_init
495	mpath_check
496
497	net_src="192.0.2."
498	net_dst="198.51.100."
499	ip_src="${net_src}1"
500	ip_dst="${net_dst}1"
501	plen=24
502	text="testtesttst"
503
504	jname="v4t-output_tcp_flowid_mpath_success"
505
506	epair0=$(vnet_mkepair)
507	epair1=$(vnet_mkepair)
508	lo_src=$(vnet_mkloopback)
509	lo_dst=$(vnet_mkloopback)
510
511	vnet_mkjail ${jname}a ${epair0}a ${epair1}a ${lo_src}
512	# Setup transit IPv4 networks
513	jexec ${jname}a ifconfig ${epair0}a up
514	jexec ${jname}a ifconfig ${epair0}a inet 203.0.113.1/30
515	jexec ${jname}a ifconfig ${epair1}a up
516	jexec ${jname}a ifconfig ${epair1}a inet 203.0.113.5/30
517	jexec ${jname}a ifconfig ${lo_src} up
518
519	vnet_mkjail ${jname}b ${epair0}b ${epair1}b ${lo_dst}
520	jexec ${jname}b ifconfig ${epair0}b up
521	jexec ${jname}b ifconfig ${epair0}b inet 203.0.113.2/30
522	jexec ${jname}b ifconfig ${epair1}b up
523	jexec ${jname}b ifconfig ${epair1}b inet 203.0.113.6/30
524	jexec ${jname}b ifconfig ${lo_dst} up
525
526	# DST ips/ports to test
527	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"
528
529	jexec ${jname}a ifconfig ${lo_src} inet ${ip_src}/32
530
531	jexec ${jname}b ifconfig ${lo_dst} inet ${ip_dst}/32
532	for i in ${ips}; do
533		jexec ${jname}b ifconfig ${lo_dst} alias ${net_dst}${i}/32
534	done
535
536	# Add routes
537	# A -> towards B via epair0a
538	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.2
539	# A -> towards B via epair1a
540	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.6
541
542	# B towards A via epair0b
543	jexec ${jname}b route add -4 -net ${net_src}0/${plen} 203.0.113.1
544
545	# Base setup verification
546	atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst}
547
548	# run sender
549	valid_message='1 packets transmitted, 1 packets received'
550	for _ip in ${ips}; do
551		ip="${net_dst}${_ip}"
552		atf_check -o match:"${valid_message}" jexec ${jname}a ping -nc1 ${ip}
553	done
554
555	pkt_0=`jexec ${jname}a netstat -Wf link -I ${epair0}a | head | awk '$1!~/^Name/{print$8}'`
556	pkt_1=`jexec ${jname}a netstat -Wf link -I ${epair1}a | head | awk '$1!~/^Name/{print$8}'`
557
558	jexec ${jname}a netstat -bWf link -I ${epair0}a
559	jexec ${jname}a netstat -bWf link -I ${epair1}a
560	if [ ${pkt_0} -le 10 ]; then
561		atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
562	fi
563	if [ ${pkt_1} -le 10 ]; then
564		atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
565	fi
566	echo "RAW BALANCING: 1: ${pkt_0} 2: ${pkt_1}"
567}
568
569output_raw_flowid_mpath_success_cleanup()
570{
571	vnet_cleanup
572}
573
574atf_init_test_cases()
575{
576	atf_add_test_case "output_tcp_setup_success"
577	atf_add_test_case "output_udp_setup_success"
578	atf_add_test_case "output_raw_success"
579	atf_add_test_case "output_tcp_flowid_mpath_success"
580	atf_add_test_case "output_udp_flowid_mpath_success"
581	atf_add_test_case "output_raw_flowid_mpath_success"
582}
583
584