net_common.sh revision 1.44 1 # $NetBSD: net_common.sh,v 1.44 2022/11/02 09:35:12 ozaki-r 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 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
169 stop_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
179 BASIC_LIBS="-lrumpnet -lrumpnet_net -lrumpnet_netinet -lrumpnet_shmif"
180 FS_LIBS="$BASIC_LIBS -lrumpdev -lrumpvfs -lrumpfs_ffs"
181 CRYPTO_LIBS="$BASIC_LIBS -lrumpdev -lrumpdev_opencrypto \
182 -lrumpkern_z -lrumpkern_crypto"
183 NPF_LIBS="$BASIC_LIBS -lrumpdev -lrumpvfs -lrumpdev_bpf -lrumpnet_npf"
184 CRYPTO_NPF_LIBS="$CRYPTO_LIBS -lrumpvfs -lrumpdev_bpf -lrumpnet_npf"
185 BPF_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
193 DEBUG_SYSCTL_ENTRIES="net.inet.arp.debug net.inet6.icmp6.nd6_debug \
194 net.inet.ipsec.debug"
195
196 IPSEC_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
231 rump_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
249 rump_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
267 rump_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
285 rump_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
303 rump_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
321 rump_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
339 rump_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
375 rump_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 #
396 rump_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
406 rump_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
455 rump_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
468 extract_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
478 dump_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
498 rump_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
512 rump_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
527 cleanup()
528 {
529
530 rump_server_halt_servers
531 }
532
533 dump()
534 {
535
536 rump_server_dump_servers
537 rump_server_dump_buses
538 }
539
540 skip_if_qemu()
541 {
542 if drvctl -l qemufwcfg0 >/dev/null 2>&1
543 then
544 atf_skip "unreliable under qemu, skip until PR kern/43997 fixed"
545 fi
546 }
547
548 test_create_destroy_common()
549 {
550 local sock=$1
551 local ifname=$2
552 local test_address=${3:-false}
553 local ipv4="10.0.0.1/24"
554 local ipv6="fc00::1"
555
556 export RUMP_SERVER=$sock
557
558 atf_check -s exit:0 rump.ifconfig $ifname create
559 atf_check -s exit:0 rump.ifconfig $ifname destroy
560
561 atf_check -s exit:0 rump.ifconfig $ifname create
562 atf_check -s exit:0 rump.ifconfig $ifname up
563 atf_check -s exit:0 rump.ifconfig $ifname down
564 atf_check -s exit:0 rump.ifconfig $ifname destroy
565
566 # Destroy while UP
567 atf_check -s exit:0 rump.ifconfig $ifname create
568 atf_check -s exit:0 rump.ifconfig $ifname up
569 atf_check -s exit:0 rump.ifconfig $ifname destroy
570
571 if ! $test_address; then
572 return
573 fi
574
575 # With an IPv4 address
576 atf_check -s exit:0 rump.ifconfig $ifname create
577 atf_check -s exit:0 rump.ifconfig $ifname inet $ipv4
578 atf_check -s exit:0 rump.ifconfig $ifname up
579 atf_check -s exit:0 rump.ifconfig $ifname destroy
580
581 # With an IPv6 address
582 atf_check -s exit:0 rump.ifconfig $ifname create
583 atf_check -s exit:0 rump.ifconfig $ifname inet6 $ipv6
584 atf_check -s exit:0 rump.ifconfig $ifname up
585 atf_check -s exit:0 rump.ifconfig $ifname destroy
586
587 unset RUMP_SERVER
588 }
589