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 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 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 167stop_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 177BASIC_LIBS="-lrumpnet -lrumpnet_net -lrumpnet_netinet -lrumpnet_shmif" 178FS_LIBS="$BASIC_LIBS -lrumpdev -lrumpvfs -lrumpfs_ffs" 179CRYPTO_LIBS="$BASIC_LIBS -lrumpdev -lrumpdev_opencrypto \ 180 -lrumpkern_z -lrumpkern_crypto" 181NPF_LIBS="$BASIC_LIBS -lrumpdev -lrumpvfs -lrumpdev_bpf -lrumpnet_npf" 182CRYPTO_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 190DEBUG_SYSCTL_ENTRIES="net.inet.arp.debug net.inet6.icmp6.nd6_debug \ 191 net.inet.ipsec.debug" 192 193IPSEC_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 228rump_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 246rump_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 264rump_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 282rump_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 300rump_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 318rump_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 354rump_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# 375rump_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 385rump_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 434rump_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 447extract_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 457dump_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 477rump_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 491rump_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 506cleanup() 507{ 508 509 rump_server_halt_servers 510} 511 512dump() 513{ 514 515 rump_server_dump_servers 516 rump_server_dump_buses 517} 518 519skip_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 527test_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