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