xref: /netbsd-src/tests/net/net_common.sh (revision 00617a3b4a7d32292865d5ae22a5c61a98dc0243)
1#	$NetBSD: net_common.sh,v 1.45 2024/08/09 02:20:13 rin 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 extra_opts="$5"
143	local backup=$RUMP_SERVER
144	local opts=
145
146	export RUMP_SERVER=$sock
147
148	if [ $proto = ipv4 ]; then
149		opts="-l -4"
150	else
151		opts="-l -6"
152	fi
153	opts="$opts $extra_opts"
154
155	env LD_PRELOAD=/usr/lib/librumphijack.so nc $opts $port > $outfile &
156	echo $! > $NC_PID
157
158	if [ $proto = ipv4 ]; then
159		$DEBUG && rump.netstat -a -f inet
160	else
161		$DEBUG && rump.netstat -a -f inet6
162	fi
163
164	export RUMP_SERVER=$backup
165
166	sleep 1
167}
168
169stop_nc_server()
170{
171
172	if [ -f $NC_PID ]; then
173		kill -9 $(cat $NC_PID)
174		rm -f $NC_PID
175		sleep 1
176	fi
177}
178
179BASIC_LIBS="-lrumpnet -lrumpnet_net -lrumpnet_netinet -lrumpnet_shmif"
180FS_LIBS="$BASIC_LIBS -lrumpdev -lrumpvfs -lrumpfs_ffs"
181CRYPTO_LIBS="$BASIC_LIBS -lrumpdev -lrumpdev_opencrypto \
182    -lrumpkern_z -lrumpkern_crypto"
183NPF_LIBS="$BASIC_LIBS -lrumpdev -lrumpvfs -lrumpdev_bpf -lrumpnet_npf"
184CRYPTO_NPF_LIBS="$CRYPTO_LIBS -lrumpvfs -lrumpdev_bpf -lrumpnet_npf"
185BPF_LIBS="$BASIC_LIBS -lrumpdev -lrumpvfs -lrumpdev_bpf"
186
187# We cannot keep variables between test phases, so need to store in files
188_rump_server_socks=./.__socks
189_rump_server_ifaces=./.__ifaces
190_rump_server_buses=./.__buses
191_rump_server_macaddrs=./.__macaddrs
192
193DEBUG_SYSCTL_ENTRIES="net.inet.arp.debug net.inet6.icmp6.nd6_debug \
194    net.inet.ipsec.debug"
195
196IPSEC_KEY_DEBUG=${IPSEC_KEY_DEBUG:-false}
197
198_rump_server_start_common()
199{
200	local sock=$1
201	local backup=$RUMP_SERVER
202
203	shift 1
204
205	atf_check -s exit:0 rump_server "$@" "$sock"
206
207	if $DEBUG; then
208		# Enable debugging features in the kernel
209		export RUMP_SERVER=$sock
210		for ent in $DEBUG_SYSCTL_ENTRIES; do
211			if rump.sysctl -q $ent; then
212				atf_check -s exit:0 rump.sysctl -q -w $ent=1
213			fi
214		done
215		export RUMP_SERVER=$backup
216	fi
217	if $IPSEC_KEY_DEBUG; then
218		# Enable debugging features in the kernel
219		export RUMP_SERVER=$sock
220		if rump.sysctl -q net.key.debug; then
221			atf_check -s exit:0 \
222			    rump.sysctl -q -w net.key.debug=0xffff
223		fi
224		export RUMP_SERVER=$backup
225	fi
226
227	echo $sock >> $_rump_server_socks
228	$DEBUG && cat $_rump_server_socks
229}
230
231rump_server_start()
232{
233	local sock=$1
234	local lib=
235	local libs="$BASIC_LIBS"
236
237	shift 1
238
239	for lib
240	do
241		libs="$libs -lrumpnet_$lib"
242	done
243
244	_rump_server_start_common $sock $libs
245
246	return 0
247}
248
249rump_server_fs_start()
250{
251	local sock=$1
252	local lib=
253	local libs="$FS_LIBS"
254
255	shift 1
256
257	for lib
258	do
259		libs="$libs -lrumpnet_$lib"
260	done
261
262	_rump_server_start_common $sock $libs
263
264	return 0
265}
266
267rump_server_crypto_start()
268{
269	local sock=$1
270	local lib=
271	local libs="$CRYPTO_LIBS"
272
273	shift 1
274
275	for lib
276	do
277		libs="$libs -lrumpnet_$lib"
278	done
279
280	_rump_server_start_common $sock $libs
281
282	return 0
283}
284
285rump_server_npf_start()
286{
287	local sock=$1
288	local lib=
289	local libs="$NPF_LIBS"
290
291	shift 1
292
293	for lib
294	do
295		libs="$libs -lrumpnet_$lib"
296	done
297
298	_rump_server_start_common $sock $libs
299
300	return 0
301}
302
303rump_server_crypto_npf_start()
304{
305	local sock=$1
306	local lib=
307	local libs="$CRYPTO_NPF_LIBS"
308
309	shift 1
310
311	for lib
312	do
313		libs="$libs -lrumpnet_$lib"
314	done
315
316	_rump_server_start_common $sock $libs
317
318	return 0
319}
320
321rump_server_bpf_start()
322{
323	local sock=$1
324	local lib=
325	local libs="$BPF_LIBS"
326
327	shift 1
328
329	for lib
330	do
331		libs="$libs -lrumpnet_$lib"
332	done
333
334	_rump_server_start_common $sock $libs
335
336	return 0
337}
338
339rump_server_add_iface()
340{
341	local sock=$1
342	local ifname=$2
343	local bus=$3
344	local backup=$RUMP_SERVER
345	local macaddr=
346
347	export RUMP_SERVER=$sock
348	atf_check -s exit:0 rump.ifconfig $ifname create
349	if [ -n "$bus" ]; then
350		atf_check -s exit:0 rump.ifconfig $ifname linkstr $bus
351	fi
352
353	macaddr=$(get_macaddr $sock $ifname)
354	if [ -n "$macaddr" ]; then
355		if [ -f $_rump_server_macaddrs ]; then
356			atf_check -s not-exit:0 \
357			    grep -q $macaddr $_rump_server_macaddrs
358		fi
359		echo $macaddr >> $_rump_server_macaddrs
360	fi
361
362	export RUMP_SERVER=$backup
363
364	echo $sock $ifname >> $_rump_server_ifaces
365	$DEBUG && cat $_rump_server_ifaces
366
367	echo $bus >> $_rump_server_buses
368	cat $_rump_server_buses |sort -u >./.__tmp
369	mv -f ./.__tmp $_rump_server_buses
370	$DEBUG && cat $_rump_server_buses
371
372	return 0
373}
374
375rump_server_check_poolleaks()
376{
377	local target=$1
378
379	# XXX rumphijack doesn't work with a binary with suid/sgid bits like
380	# vmstat.  Use a copied one to drop sgid bit as a workaround until
381	# vmstat stops using kvm(3) for /dev/kmem and the sgid bit.
382	cp /usr/bin/vmstat ./vmstat
383	reqs=$($HIJACKING ./vmstat -mv | awk "/$target/ {print \$3;}")
384	rels=$($HIJACKING ./vmstat -mv | awk "/$target/ {print \$5;}")
385	rm -f ./vmstat
386	atf_check_equal '$target$reqs' '$target$rels'
387}
388
389#
390# rump_server_check_memleaks detects memory leaks.  It can detect leaks of pool
391# objects that are guaranteed to be all deallocated at this point, i.e., all
392# created interfaces are destroyed.  Currently only llentpl satisfies this
393# constraint.  This mechanism can't be applied to objects allocated through
394# pool_cache(9) because it doesn't track released objects explicitly.
395#
396rump_server_check_memleaks()
397{
398
399	rump_server_check_poolleaks llentrypl
400	# This doesn't work for objects allocated through pool_cache
401	#rump_server_check_poolleaks mbpl
402	#rump_server_check_poolleaks mclpl
403	#rump_server_check_poolleaks socket
404}
405
406rump_server_destroy_ifaces()
407{
408	local backup=$RUMP_SERVER
409	local output=ignore
410	local reqs= rels=
411
412	$DEBUG && cat $_rump_server_ifaces
413
414	# Try to dump states before destroying interfaces
415	for sock in $(cat $_rump_server_socks); do
416		export RUMP_SERVER=$sock
417		if $DEBUG; then
418			output=save:/dev/stdout
419		fi
420		atf_check -s exit:0 -o $output rump.ifconfig
421		atf_check -s exit:0 -o $output rump.netstat -nr
422		# XXX still need hijacking
423		atf_check -s exit:0 -o $output $HIJACKING rump.netstat -nai
424		atf_check -s exit:0 -o $output rump.arp -na
425		atf_check -s exit:0 -o $output rump.ndp -na
426		atf_check -s exit:0 -o $output $HIJACKING ifmcstat
427	done
428
429	# XXX using pipe doesn't work. See PR bin/51667
430	#cat $_rump_server_ifaces | while read sock ifname; do
431	# Destroy interfaces in the reverse order
432	tac $_rump_server_ifaces > __ifaces
433	while read sock ifname; do
434		export RUMP_SERVER=$sock
435		if rump.ifconfig -l |grep -q $ifname; then
436			if $DEBUG; then
437				rump.ifconfig -v $ifname
438			fi
439			atf_check -s exit:0 rump.ifconfig $ifname destroy
440		fi
441		atf_check -s exit:0 -o ignore rump.ifconfig
442	done < __ifaces
443	rm -f __ifaces
444
445	for sock in $(cat $_rump_server_socks); do
446		export RUMP_SERVER=$sock
447		rump_server_check_memleaks
448	done
449
450	export RUMP_SERVER=$backup
451
452	return 0
453}
454
455rump_server_halt_servers()
456{
457	local backup=$RUMP_SERVER
458
459	$DEBUG && cat $_rump_server_socks
460	for sock in $(cat $_rump_server_socks); do
461		env RUMP_SERVER=$sock rump.halt
462	done
463	export RUMP_SERVER=$backup
464
465	return 0
466}
467
468extract_rump_server_core()
469{
470
471	if [ -f rump_server.core ]; then
472		gdb -ex bt /usr/bin/rump_server rump_server.core
473		# Extract kernel logs including a panic message
474		strings rump_server.core |grep -E '^\[.+\] '
475	fi
476}
477
478dump_kernel_stats()
479{
480	local sock=$1
481
482	echo "### Dumping $sock"
483	export RUMP_SERVER=$sock
484	rump.ifconfig -av
485	rump.netstat -nr
486	# XXX still need hijacking
487	$HIJACKING rump.netstat -nai
488	# XXX workaround for vmstat with the sgid bit
489	cp /usr/bin/vmstat ./vmstat
490	$HIJACKING ./vmstat -m
491	rm -f ./vmstat
492	rump.arp -na
493	rump.ndp -na
494	$HIJACKING ifmcstat
495	$HIJACKING dmesg
496}
497
498rump_server_dump_servers()
499{
500	local backup=$RUMP_SERVER
501
502	$DEBUG && cat $_rump_server_socks
503	for sock in $(cat $_rump_server_socks); do
504		dump_kernel_stats $sock
505	done
506	export RUMP_SERVER=$backup
507
508	extract_rump_server_core
509	return 0
510}
511
512rump_server_dump_buses()
513{
514
515	if [ ! -f $_rump_server_buses ]; then
516		return 0
517	fi
518
519	$DEBUG && cat $_rump_server_buses
520	for bus in $(cat $_rump_server_buses); do
521		echo "### Dumping $bus"
522		shmif_dumpbus -p - $bus 2>/dev/null| tcpdump -n -e -r -
523	done
524	return 0
525}
526
527cleanup()
528{
529
530	if [ -f $_rump_server_socks ]; then
531		rump_server_halt_servers
532	fi
533}
534
535dump()
536{
537
538	rump_server_dump_servers
539	rump_server_dump_buses
540}
541
542skip_if_qemu()
543{
544	if drvctl -l qemufwcfg0 >/dev/null 2>&1
545	then
546	    atf_skip "unreliable under qemu, skip until PR kern/43997 fixed"
547	fi
548}
549
550test_create_destroy_common()
551{
552	local sock=$1
553	local ifname=$2
554	local test_address=${3:-false}
555	local ipv4="10.0.0.1/24"
556	local ipv6="fc00::1"
557
558	export RUMP_SERVER=$sock
559
560	atf_check -s exit:0 rump.ifconfig $ifname create
561	atf_check -s exit:0 rump.ifconfig $ifname destroy
562
563	atf_check -s exit:0 rump.ifconfig $ifname create
564	atf_check -s exit:0 rump.ifconfig $ifname up
565	atf_check -s exit:0 rump.ifconfig $ifname down
566	atf_check -s exit:0 rump.ifconfig $ifname destroy
567
568	# Destroy while UP
569	atf_check -s exit:0 rump.ifconfig $ifname create
570	atf_check -s exit:0 rump.ifconfig $ifname up
571	atf_check -s exit:0 rump.ifconfig $ifname destroy
572
573	if ! $test_address; then
574		return
575	fi
576
577	# With an IPv4 address
578	atf_check -s exit:0 rump.ifconfig $ifname create
579	atf_check -s exit:0 rump.ifconfig $ifname inet $ipv4
580	atf_check -s exit:0 rump.ifconfig $ifname up
581	atf_check -s exit:0 rump.ifconfig $ifname destroy
582
583	# With an IPv6 address
584	atf_check -s exit:0 rump.ifconfig $ifname create
585	atf_check -s exit:0 rump.ifconfig $ifname inet6 $ipv6
586	atf_check -s exit:0 rump.ifconfig $ifname up
587	atf_check -s exit:0 rump.ifconfig $ifname destroy
588
589	unset RUMP_SERVER
590}
591