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