xref: /netbsd-src/tests/net/net_common.sh (revision e6c7e151de239c49d2e38720a061ed9d1fa99309)
1#	$NetBSD: net_common.sh,v 1.41 2020/04/01 00:49:04 christos Exp $
2#
3# Copyright (c) 2016 Internet Initiative Japan Inc.
4# All rights reserved.
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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25# POSSIBILITY OF SUCH DAMAGE.
26#
27
28#
29# Common utility functions for tests/net
30#
31
32export PATH="/sbin:/usr/sbin:/bin:/usr/bin"
33
34HIJACKING="env LD_PRELOAD=/usr/lib/librumphijack.so \
35    RUMPHIJACK=path=/rump,socket=all:nolocal,sysctl=yes"
36ONEDAYISH="(23h5[0-9]m|1d0h0m)[0-9]+s ?"
37
38extract_new_packets()
39{
40	local bus=$1
41	local old=./.__old
42
43	if [ ! -f $old ]; then
44		old=/dev/null
45	fi
46
47	shmif_dumpbus -p - $bus 2>/dev/null |
48	    tcpdump -n -e -r - 2>/dev/null > ./.__new
49	diff -u $old ./.__new | grep '^+' | cut -d '+' -f 2   > ./.__diff
50	mv -f ./.__new ./.__old
51	cat ./.__diff
52}
53
54check_route()
55{
56	local target=$1
57	local gw=$2
58	local flags=${3:-\.\+}
59	local ifname=${4:-\.\+}
60
61	target=$(echo $target | sed 's/\./\\./g')
62	if [ "$gw" = "" ]; then
63		gw=".+"
64	else
65		gw=$(echo $gw | sed 's/\./\\./g')
66	fi
67
68	atf_check -s exit:0 -e ignore \
69	    -o match:"^$target +$gw +$flags +- +- +.+ +$ifname" \
70	    rump.netstat -rn
71}
72
73check_route_flags()
74{
75
76	check_route "$1" "" "$2" ""
77}
78
79check_route_gw()
80{
81
82	check_route "$1" "$2" "" ""
83}
84
85check_route_no_entry()
86{
87	local target=$(echo "$1" | sed 's/\./\\./g')
88
89	atf_check -s exit:0 -e ignore -o not-match:"^$target" rump.netstat -rn
90}
91
92get_linklocal_addr()
93{
94
95	RUMP_SERVER=${1} rump.ifconfig ${2} inet6 |
96	    awk "/fe80/ {sub(/%$2/, \"\"); sub(/\\/[0-9]*/, \"\"); print \$2;}"
97
98	return 0
99}
100
101get_macaddr()
102{
103
104	RUMP_SERVER=${1} rump.ifconfig ${2} | awk '/address/ {print $2;}'
105}
106
107HTTPD_PID=./.__httpd.pid
108start_httpd()
109{
110	local sock=$1
111	local ip=$2
112	local backup=$RUMP_SERVER
113
114	export RUMP_SERVER=$sock
115
116	# start httpd in daemon mode
117	atf_check -s exit:0 env LD_PRELOAD=/usr/lib/librumphijack.so \
118	    /usr/libexec/httpd -P $HTTPD_PID -i $ip -b -s $(pwd)
119
120	export RUMP_SERVER=$backup
121
122	sleep 3
123}
124
125stop_httpd()
126{
127
128	if [ -f $HTTPD_PID ]; then
129		kill -9 $(cat $HTTPD_PID)
130		rm -f $HTTPD_PID
131		sleep 1
132	fi
133}
134
135NC_PID=./.__nc.pid
136start_nc_server()
137{
138	local sock=$1
139	local port=$2
140	local outfile=$3
141	local proto=${4:-ipv4}
142	local backup=$RUMP_SERVER
143	local opts=
144
145	export RUMP_SERVER=$sock
146
147	if [ $proto = ipv4 ]; then
148		opts="-l -4"
149	else
150		opts="-l -6"
151	fi
152
153	env LD_PRELOAD=/usr/lib/librumphijack.so nc $opts $port > $outfile &
154	echo $! > $NC_PID
155
156	if [ $proto = ipv4 ]; then
157		$DEBUG && rump.netstat -a -f inet
158	else
159		$DEBUG && rump.netstat -a -f inet6
160	fi
161
162	export RUMP_SERVER=$backup
163
164	sleep 1
165}
166
167stop_nc_server()
168{
169
170	if [ -f $NC_PID ]; then
171		kill -9 $(cat $NC_PID)
172		rm -f $NC_PID
173		sleep 1
174	fi
175}
176
177BASIC_LIBS="-lrumpnet -lrumpnet_net -lrumpnet_netinet -lrumpnet_shmif"
178FS_LIBS="$BASIC_LIBS -lrumpdev -lrumpvfs -lrumpfs_ffs"
179CRYPTO_LIBS="$BASIC_LIBS -lrumpdev -lrumpdev_opencrypto \
180    -lrumpkern_z -lrumpkern_crypto"
181NPF_LIBS="$BASIC_LIBS -lrumpdev -lrumpvfs -lrumpdev_bpf -lrumpnet_npf"
182CRYPTO_NPF_LIBS="$CRYPTO_LIBS -lrumpvfs -lrumpdev_bpf -lrumpnet_npf"
183
184# We cannot keep variables between test phases, so need to store in files
185_rump_server_socks=./.__socks
186_rump_server_ifaces=./.__ifaces
187_rump_server_buses=./.__buses
188_rump_server_macaddrs=./.__macaddrs
189
190DEBUG_SYSCTL_ENTRIES="net.inet.arp.debug net.inet6.icmp6.nd6_debug \
191    net.inet.ipsec.debug"
192
193IPSEC_KEY_DEBUG=${IPSEC_KEY_DEBUG:-false}
194
195_rump_server_start_common()
196{
197	local sock=$1
198	local backup=$RUMP_SERVER
199
200	shift 1
201
202	atf_check -s exit:0 rump_server "$@" "$sock"
203
204	if $DEBUG; then
205		# Enable debugging features in the kernel
206		export RUMP_SERVER=$sock
207		for ent in $DEBUG_SYSCTL_ENTRIES; do
208			if rump.sysctl -q $ent; then
209				atf_check -s exit:0 rump.sysctl -q -w $ent=1
210			fi
211		done
212		export RUMP_SERVER=$backup
213	fi
214	if $IPSEC_KEY_DEBUG; then
215		# Enable debugging features in the kernel
216		export RUMP_SERVER=$sock
217		if rump.sysctl -q net.key.debug; then
218			atf_check -s exit:0 \
219			    rump.sysctl -q -w net.key.debug=0xffff
220		fi
221		export RUMP_SERVER=$backup
222	fi
223
224	echo $sock >> $_rump_server_socks
225	$DEBUG && cat $_rump_server_socks
226}
227
228rump_server_start()
229{
230	local sock=$1
231	local lib=
232	local libs="$BASIC_LIBS"
233
234	shift 1
235
236	for lib
237	do
238		libs="$libs -lrumpnet_$lib"
239	done
240
241	_rump_server_start_common $sock $libs
242
243	return 0
244}
245
246rump_server_fs_start()
247{
248	local sock=$1
249	local lib=
250	local libs="$FS_LIBS"
251
252	shift 1
253
254	for lib
255	do
256		libs="$libs -lrumpnet_$lib"
257	done
258
259	_rump_server_start_common $sock $libs
260
261	return 0
262}
263
264rump_server_crypto_start()
265{
266	local sock=$1
267	local lib=
268	local libs="$CRYPTO_LIBS"
269
270	shift 1
271
272	for lib
273	do
274		libs="$libs -lrumpnet_$lib"
275	done
276
277	_rump_server_start_common $sock $libs
278
279	return 0
280}
281
282rump_server_npf_start()
283{
284	local sock=$1
285	local lib=
286	local libs="$NPF_LIBS"
287
288	shift 1
289
290	for lib
291	do
292		libs="$libs -lrumpnet_$lib"
293	done
294
295	_rump_server_start_common $sock $libs
296
297	return 0
298}
299
300rump_server_crypto_npf_start()
301{
302	local sock=$1
303	local lib=
304	local libs="$CRYPTO_NPF_LIBS"
305
306	shift 1
307
308	for lib
309	do
310		libs="$libs -lrumpnet_$lib"
311	done
312
313	_rump_server_start_common $sock $libs
314
315	return 0
316}
317
318rump_server_add_iface()
319{
320	local sock=$1
321	local ifname=$2
322	local bus=$3
323	local backup=$RUMP_SERVER
324	local macaddr=
325
326	export RUMP_SERVER=$sock
327	atf_check -s exit:0 rump.ifconfig $ifname create
328	if [ -n "$bus" ]; then
329		atf_check -s exit:0 rump.ifconfig $ifname linkstr $bus
330	fi
331
332	macaddr=$(get_macaddr $sock $ifname)
333	if [ -n "$macaddr" ]; then
334		if [ -f $_rump_server_macaddrs ]; then
335			atf_check -s not-exit:0 \
336			    grep -q $macaddr $_rump_server_macaddrs
337		fi
338		echo $macaddr >> $_rump_server_macaddrs
339	fi
340
341	export RUMP_SERVER=$backup
342
343	echo $sock $ifname >> $_rump_server_ifaces
344	$DEBUG && cat $_rump_server_ifaces
345
346	echo $bus >> $_rump_server_buses
347	cat $_rump_server_buses |sort -u >./.__tmp
348	mv -f ./.__tmp $_rump_server_buses
349	$DEBUG && cat $_rump_server_buses
350
351	return 0
352}
353
354rump_server_check_poolleaks()
355{
356	local target=$1
357
358	# XXX rumphijack doesn't work with a binary with suid/sgid bits like
359	# vmstat.  Use a copied one to drop sgid bit as a workaround until
360	# vmstat stops using kvm(3) for /dev/kmem and the sgid bit.
361	cp /usr/bin/vmstat ./vmstat
362	reqs=$($HIJACKING ./vmstat -mv | awk "/$target/ {print \$3;}")
363	rels=$($HIJACKING ./vmstat -mv | awk "/$target/ {print \$5;}")
364	rm -f ./vmstat
365	atf_check_equal '$target$reqs' '$target$rels'
366}
367
368#
369# rump_server_check_memleaks detects memory leaks.  It can detect leaks of pool
370# objects that are guaranteed to be all deallocated at this point, i.e., all
371# created interfaces are destroyed.  Currently only llentpl satisfies this
372# constraint.  This mechanism can't be applied to objects allocated through
373# pool_cache(9) because it doesn't track released objects explicitly.
374#
375rump_server_check_memleaks()
376{
377
378	rump_server_check_poolleaks llentrypl
379	# This doesn't work for objects allocated through pool_cache
380	#rump_server_check_poolleaks mbpl
381	#rump_server_check_poolleaks mclpl
382	#rump_server_check_poolleaks socket
383}
384
385rump_server_destroy_ifaces()
386{
387	local backup=$RUMP_SERVER
388	local output=ignore
389	local reqs= rels=
390
391	$DEBUG && cat $_rump_server_ifaces
392
393	# Try to dump states before destroying interfaces
394	for sock in $(cat $_rump_server_socks); do
395		export RUMP_SERVER=$sock
396		if $DEBUG; then
397			output=save:/dev/stdout
398		fi
399		atf_check -s exit:0 -o $output rump.ifconfig
400		atf_check -s exit:0 -o $output rump.netstat -nr
401		# XXX still need hijacking
402		atf_check -s exit:0 -o $output $HIJACKING rump.netstat -nai
403		atf_check -s exit:0 -o $output rump.arp -na
404		atf_check -s exit:0 -o $output rump.ndp -na
405		atf_check -s exit:0 -o $output $HIJACKING ifmcstat
406	done
407
408	# XXX using pipe doesn't work. See PR bin/51667
409	#cat $_rump_server_ifaces | while read sock ifname; do
410	# Destroy interfaces in the reverse order
411	tac $_rump_server_ifaces > __ifaces
412	while read sock ifname; do
413		export RUMP_SERVER=$sock
414		if rump.ifconfig -l |grep -q $ifname; then
415			if $DEBUG; then
416				rump.ifconfig -v $ifname
417			fi
418			atf_check -s exit:0 rump.ifconfig $ifname destroy
419		fi
420		atf_check -s exit:0 -o ignore rump.ifconfig
421	done < __ifaces
422	rm -f __ifaces
423
424	for sock in $(cat $_rump_server_socks); do
425		export RUMP_SERVER=$sock
426		rump_server_check_memleaks
427	done
428
429	export RUMP_SERVER=$backup
430
431	return 0
432}
433
434rump_server_halt_servers()
435{
436	local backup=$RUMP_SERVER
437
438	$DEBUG && cat $_rump_server_socks
439	for sock in $(cat $_rump_server_socks); do
440		env RUMP_SERVER=$sock rump.halt
441	done
442	export RUMP_SERVER=$backup
443
444	return 0
445}
446
447extract_rump_server_core()
448{
449
450	if [ -f rump_server.core ]; then
451		gdb -ex bt /usr/bin/rump_server rump_server.core
452		# Extract kernel logs including a panic message
453		strings rump_server.core |grep -E '^\[.+\] '
454	fi
455}
456
457dump_kernel_stats()
458{
459	local sock=$1
460
461	echo "### Dumping $sock"
462	export RUMP_SERVER=$sock
463	rump.ifconfig -av
464	rump.netstat -nr
465	# XXX still need hijacking
466	$HIJACKING rump.netstat -nai
467	# XXX workaround for vmstat with the sgid bit
468	cp /usr/bin/vmstat ./vmstat
469	$HIJACKING ./vmstat -m
470	rm -f ./vmstat
471	rump.arp -na
472	rump.ndp -na
473	$HIJACKING ifmcstat
474	$HIJACKING dmesg
475}
476
477rump_server_dump_servers()
478{
479	local backup=$RUMP_SERVER
480
481	$DEBUG && cat $_rump_server_socks
482	for sock in $(cat $_rump_server_socks); do
483		dump_kernel_stats $sock
484	done
485	export RUMP_SERVER=$backup
486
487	extract_rump_server_core
488	return 0
489}
490
491rump_server_dump_buses()
492{
493
494	if [ ! -f $_rump_server_buses ]; then
495		return 0
496	fi
497
498	$DEBUG && cat $_rump_server_buses
499	for bus in $(cat $_rump_server_buses); do
500		echo "### Dumping $bus"
501		shmif_dumpbus -p - $bus 2>/dev/null| tcpdump -n -e -r -
502	done
503	return 0
504}
505
506cleanup()
507{
508
509	rump_server_halt_servers
510}
511
512dump()
513{
514
515	rump_server_dump_servers
516	rump_server_dump_buses
517}
518
519skip_if_qemu()
520{
521	if sysctl machdep.cpu_brand 2>/dev/null | grep QEMU >/dev/null 2>&1
522	then
523	    atf_skip "unreliable under qemu, skip until PR kern/43997 fixed"
524	fi
525}
526
527test_create_destroy_common()
528{
529	local sock=$1
530	local ifname=$2
531	local test_address=${3:-false}
532	local ipv4="10.0.0.1/24"
533	local ipv6="fc00::1"
534
535	export RUMP_SERVER=$sock
536
537	atf_check -s exit:0 rump.ifconfig $ifname create
538	atf_check -s exit:0 rump.ifconfig $ifname destroy
539
540	atf_check -s exit:0 rump.ifconfig $ifname create
541	atf_check -s exit:0 rump.ifconfig $ifname up
542	atf_check -s exit:0 rump.ifconfig $ifname down
543	atf_check -s exit:0 rump.ifconfig $ifname destroy
544
545	# Destroy while UP
546	atf_check -s exit:0 rump.ifconfig $ifname create
547	atf_check -s exit:0 rump.ifconfig $ifname up
548	atf_check -s exit:0 rump.ifconfig $ifname destroy
549
550	if ! $test_address; then
551		return
552	fi
553
554	# With an IPv4 address
555	atf_check -s exit:0 rump.ifconfig $ifname create
556	atf_check -s exit:0 rump.ifconfig $ifname inet $ipv4
557	atf_check -s exit:0 rump.ifconfig $ifname up
558	atf_check -s exit:0 rump.ifconfig $ifname destroy
559
560	# With an IPv6 address
561	atf_check -s exit:0 rump.ifconfig $ifname create
562	atf_check -s exit:0 rump.ifconfig $ifname inet6 $ipv6
563	atf_check -s exit:0 rump.ifconfig $ifname up
564	atf_check -s exit:0 rump.ifconfig $ifname destroy
565
566	unset RUMP_SERVER
567}
568