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