net_common.sh revision 1.41 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
32 export PATH="/sbin:/usr/sbin:/bin:/usr/bin"
33
34 HIJACKING="env LD_PRELOAD=/usr/lib/librumphijack.so \
35 RUMPHIJACK=path=/rump,socket=all:nolocal,sysctl=yes"
36 ONEDAYISH="(23h5[0-9]m|1d0h0m)[0-9]+s ?"
37
38 extract_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
54 check_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
73 check_route_flags()
74 {
75
76 check_route "$1" "" "$2" ""
77 }
78
79 check_route_gw()
80 {
81
82 check_route "$1" "$2" "" ""
83 }
84
85 check_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
92 get_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
101 get_macaddr()
102 {
103
104 RUMP_SERVER=${1} rump.ifconfig ${2} | awk '/address/ {print $2;}'
105 }
106
107 HTTPD_PID=./.__httpd.pid
108 start_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
125 stop_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
135 NC_PID=./.__nc.pid
136 start_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
167 stop_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
177 BASIC_LIBS="-lrumpnet -lrumpnet_net -lrumpnet_netinet -lrumpnet_shmif"
178 FS_LIBS="$BASIC_LIBS -lrumpdev -lrumpvfs -lrumpfs_ffs"
179 CRYPTO_LIBS="$BASIC_LIBS -lrumpdev -lrumpdev_opencrypto \
180 -lrumpkern_z -lrumpkern_crypto"
181 NPF_LIBS="$BASIC_LIBS -lrumpdev -lrumpvfs -lrumpdev_bpf -lrumpnet_npf"
182 CRYPTO_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
190 DEBUG_SYSCTL_ENTRIES="net.inet.arp.debug net.inet6.icmp6.nd6_debug \
191 net.inet.ipsec.debug"
192
193 IPSEC_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
228 rump_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
246 rump_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
264 rump_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
282 rump_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
300 rump_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
318 rump_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
354 rump_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 #
375 rump_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
385 rump_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
434 rump_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
447 extract_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
457 dump_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
477 rump_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
491 rump_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
506 cleanup()
507 {
508
509 rump_server_halt_servers
510 }
511
512 dump()
513 {
514
515 rump_server_dump_servers
516 rump_server_dump_buses
517 }
518
519 skip_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
527 test_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