1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# 4# Copyright (c) 2025 Meta Platforms, Inc. and affiliates 5# 6# Dependencies: 7# * virtme-ng 8# * busybox-static (used by virtme-ng) 9# * qemu (used by virtme-ng) 10# * socat 11# 12# shellcheck disable=SC2317,SC2119 13 14readonly SCRIPT_DIR="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" 15readonly KERNEL_CHECKOUT=$(realpath "${SCRIPT_DIR}"/../../../../) 16 17source "${SCRIPT_DIR}"/../kselftest/ktap_helpers.sh 18 19readonly VSOCK_TEST="${SCRIPT_DIR}"/vsock_test 20readonly TEST_GUEST_PORT=51000 21readonly TEST_HOST_PORT=50000 22readonly TEST_HOST_PORT_LISTENER=50001 23readonly SSH_GUEST_PORT=22 24readonly SSH_HOST_PORT=2222 25readonly VSOCK_CID=1234 26readonly WAIT_PERIOD=3 27readonly WAIT_PERIOD_MAX=60 28readonly WAIT_QEMU=5 29readonly PIDFILE_TEMPLATE=/tmp/vsock_vmtest_XXXX.pid 30declare -A PIDFILES 31 32# virtme-ng offers a netdev for ssh when using "--ssh", but we also need a 33# control port forwarded for vsock_test. Because virtme-ng doesn't support 34# adding an additional port to forward to the device created from "--ssh" and 35# virtme-init mistakenly sets identical IPs to the ssh device and additional 36# devices, we instead opt out of using --ssh, add the device manually, and also 37# add the kernel cmdline options that virtme-init uses to setup the interface. 38readonly QEMU_TEST_PORT_FWD="hostfwd=tcp::${TEST_HOST_PORT}-:${TEST_GUEST_PORT}" 39readonly QEMU_SSH_PORT_FWD="hostfwd=tcp::${SSH_HOST_PORT}-:${SSH_GUEST_PORT}" 40readonly KERNEL_CMDLINE="\ 41 virtme.dhcp net.ifnames=0 biosdevname=0 \ 42 virtme.ssh virtme_ssh_channel=tcp virtme_ssh_user=$USER \ 43" 44readonly LOG=$(mktemp /tmp/vsock_vmtest_XXXX.log) 45 46# Namespace tests must use the ns_ prefix. This is checked in check_netns() and 47# is used to determine if a test needs namespace setup before test execution. 48readonly TEST_NAMES=( 49 vm_server_host_client 50 vm_client_host_server 51 vm_loopback 52 ns_host_vsock_ns_mode_ok 53 ns_host_vsock_child_ns_mode_ok 54 ns_global_same_cid_fails 55 ns_local_same_cid_ok 56 ns_global_local_same_cid_ok 57 ns_local_global_same_cid_ok 58 ns_diff_global_host_connect_to_global_vm_ok 59 ns_diff_global_host_connect_to_local_vm_fails 60 ns_diff_global_vm_connect_to_global_host_ok 61 ns_diff_global_vm_connect_to_local_host_fails 62 ns_diff_local_host_connect_to_local_vm_fails 63 ns_diff_local_vm_connect_to_local_host_fails 64 ns_diff_global_to_local_loopback_local_fails 65 ns_diff_local_to_global_loopback_fails 66 ns_diff_local_to_local_loopback_fails 67 ns_diff_global_to_global_loopback_ok 68 ns_same_local_loopback_ok 69 ns_same_local_host_connect_to_local_vm_ok 70 ns_same_local_vm_connect_to_local_host_ok 71 ns_delete_vm_ok 72 ns_delete_host_ok 73 ns_delete_both_ok 74) 75readonly TEST_DESCS=( 76 # vm_server_host_client 77 "Run vsock_test in server mode on the VM and in client mode on the host." 78 79 # vm_client_host_server 80 "Run vsock_test in client mode on the VM and in server mode on the host." 81 82 # vm_loopback 83 "Run vsock_test using the loopback transport in the VM." 84 85 # ns_host_vsock_ns_mode_ok 86 "Check /proc/sys/net/vsock/ns_mode strings on the host." 87 88 # ns_host_vsock_child_ns_mode_ok 89 "Check /proc/sys/net/vsock/ns_mode is read-only and child_ns_mode is writable." 90 91 # ns_global_same_cid_fails 92 "Check QEMU fails to start two VMs with same CID in two different global namespaces." 93 94 # ns_local_same_cid_ok 95 "Check QEMU successfully starts two VMs with same CID in two different local namespaces." 96 97 # ns_global_local_same_cid_ok 98 "Check QEMU successfully starts one VM in a global ns and then another VM in a local ns with the same CID." 99 100 # ns_local_global_same_cid_ok 101 "Check QEMU successfully starts one VM in a local ns and then another VM in a global ns with the same CID." 102 103 # ns_diff_global_host_connect_to_global_vm_ok 104 "Run vsock_test client in global ns with server in VM in another global ns." 105 106 # ns_diff_global_host_connect_to_local_vm_fails 107 "Run socat to test a process in a global ns fails to connect to a VM in a local ns." 108 109 # ns_diff_global_vm_connect_to_global_host_ok 110 "Run vsock_test client in VM in a global ns with server in another global ns." 111 112 # ns_diff_global_vm_connect_to_local_host_fails 113 "Run socat to test a VM in a global ns fails to connect to a host process in a local ns." 114 115 # ns_diff_local_host_connect_to_local_vm_fails 116 "Run socat to test a host process in a local ns fails to connect to a VM in another local ns." 117 118 # ns_diff_local_vm_connect_to_local_host_fails 119 "Run socat to test a VM in a local ns fails to connect to a host process in another local ns." 120 121 # ns_diff_global_to_local_loopback_local_fails 122 "Run socat to test a loopback vsock in a global ns fails to connect to a vsock in a local ns." 123 124 # ns_diff_local_to_global_loopback_fails 125 "Run socat to test a loopback vsock in a local ns fails to connect to a vsock in a global ns." 126 127 # ns_diff_local_to_local_loopback_fails 128 "Run socat to test a loopback vsock in a local ns fails to connect to a vsock in another local ns." 129 130 # ns_diff_global_to_global_loopback_ok 131 "Run socat to test a loopback vsock in a global ns successfully connects to a vsock in another global ns." 132 133 # ns_same_local_loopback_ok 134 "Run socat to test a loopback vsock in a local ns successfully connects to a vsock in the same ns." 135 136 # ns_same_local_host_connect_to_local_vm_ok 137 "Run vsock_test client in a local ns with server in VM in same ns." 138 139 # ns_same_local_vm_connect_to_local_host_ok 140 "Run vsock_test client in VM in a local ns with server in same ns." 141 142 # ns_delete_vm_ok 143 "Check that deleting the VM's namespace does not break the socket connection" 144 145 # ns_delete_host_ok 146 "Check that deleting the host's namespace does not break the socket connection" 147 148 # ns_delete_both_ok 149 "Check that deleting the VM and host's namespaces does not break the socket connection" 150) 151 152readonly USE_SHARED_VM=( 153 vm_server_host_client 154 vm_client_host_server 155 vm_loopback 156) 157readonly NS_MODES=("local" "global") 158 159VERBOSE=0 160 161usage() { 162 local name 163 local desc 164 local i 165 166 echo 167 echo "$0 [OPTIONS] [TEST]..." 168 echo "If no TEST argument is given, all tests will be run." 169 echo 170 echo "Options" 171 echo " -b: build the kernel from the current source tree and use it for guest VMs" 172 echo " -q: set the path to or name of qemu binary" 173 echo " -v: verbose output" 174 echo 175 echo "Available tests" 176 177 for ((i = 0; i < ${#TEST_NAMES[@]}; i++)); do 178 name=${TEST_NAMES[${i}]} 179 desc=${TEST_DESCS[${i}]} 180 printf "\t%-55s%-35s\n" "${name}" "${desc}" 181 done 182 echo 183 184 exit 1 185} 186 187die() { 188 echo "$*" >&2 189 exit "${KSFT_FAIL}" 190} 191 192check_result() { 193 local rc arg 194 195 rc=$1 196 arg=$2 197 198 cnt_total=$(( cnt_total + 1 )) 199 200 if [[ ${rc} -eq ${KSFT_PASS} ]]; then 201 cnt_pass=$(( cnt_pass + 1 )) 202 echo "ok ${cnt_total} ${arg}" 203 elif [[ ${rc} -eq ${KSFT_SKIP} ]]; then 204 cnt_skip=$(( cnt_skip + 1 )) 205 echo "ok ${cnt_total} ${arg} # SKIP" 206 elif [[ ${rc} -eq ${KSFT_FAIL} ]]; then 207 cnt_fail=$(( cnt_fail + 1 )) 208 echo "not ok ${cnt_total} ${arg} # exit=${rc}" 209 fi 210} 211 212add_namespaces() { 213 ip netns add "global-parent" 2>/dev/null 214 echo "global" | ip netns exec "global-parent" \ 215 tee /proc/sys/net/vsock/child_ns_mode &>/dev/null 216 ip netns add "local-parent" 2>/dev/null 217 echo "local" | ip netns exec "local-parent" \ 218 tee /proc/sys/net/vsock/child_ns_mode &>/dev/null 219 220 nsenter --net=/var/run/netns/global-parent \ 221 ip netns add "global0" 2>/dev/null 222 nsenter --net=/var/run/netns/global-parent \ 223 ip netns add "global1" 2>/dev/null 224 nsenter --net=/var/run/netns/local-parent \ 225 ip netns add "local0" 2>/dev/null 226 nsenter --net=/var/run/netns/local-parent \ 227 ip netns add "local1" 2>/dev/null 228} 229 230init_namespaces() { 231 for mode in "${NS_MODES[@]}"; do 232 # we need lo for qemu port forwarding 233 ip netns exec "${mode}0" ip link set dev lo up 234 ip netns exec "${mode}1" ip link set dev lo up 235 done 236} 237 238del_namespaces() { 239 for mode in "${NS_MODES[@]}"; do 240 ip netns del "${mode}0" &>/dev/null 241 ip netns del "${mode}1" &>/dev/null 242 log_host "removed ns ${mode}0" 243 log_host "removed ns ${mode}1" 244 done 245 ip netns del "global-parent" &>/dev/null 246 ip netns del "local-parent" &>/dev/null 247} 248 249vm_ssh() { 250 local ns_exec 251 252 if [[ "${1}" == init_ns ]]; then 253 ns_exec="" 254 else 255 ns_exec="ip netns exec ${1}" 256 fi 257 258 shift 259 260 ${ns_exec} ssh -q -o UserKnownHostsFile=/dev/null -p "${SSH_HOST_PORT}" localhost "$@" 261 262 return $? 263} 264 265cleanup() { 266 terminate_pidfiles "${!PIDFILES[@]}" 267 del_namespaces 268} 269 270check_args() { 271 local found 272 273 for arg in "$@"; do 274 found=0 275 for name in "${TEST_NAMES[@]}"; do 276 if [[ "${name}" = "${arg}" ]]; then 277 found=1 278 break 279 fi 280 done 281 282 if [[ "${found}" -eq 0 ]]; then 283 echo "${arg} is not an available test" >&2 284 usage 285 fi 286 done 287 288 for arg in "$@"; do 289 if ! command -v > /dev/null "test_${arg}"; then 290 echo "Test ${arg} not found" >&2 291 usage 292 fi 293 done 294} 295 296check_deps() { 297 for dep in vng ${QEMU} busybox pkill ssh ss socat nsenter; do 298 if [[ ! -x $(command -v "${dep}") ]]; then 299 echo -e "skip: dependency ${dep} not found!\n" 300 exit "${KSFT_SKIP}" 301 fi 302 done 303 304 if [[ ! -x $(command -v "${VSOCK_TEST}") ]]; then 305 printf "skip: %s not found!" "${VSOCK_TEST}" 306 printf " Please build the kselftest vsock target.\n" 307 exit "${KSFT_SKIP}" 308 fi 309} 310 311check_netns() { 312 local tname=$1 313 314 # If the test requires NS support, check if NS support exists 315 # using /proc/self/ns 316 if [[ "${tname}" =~ ^ns_ ]] && 317 [[ ! -e /proc/self/ns ]]; then 318 log_host "No NS support detected for test ${tname}" 319 return 1 320 fi 321 322 return 0 323} 324 325check_vng() { 326 local tested_versions 327 local version 328 local ok 329 330 tested_versions=("1.33" "1.36" "1.37") 331 version="$(vng --version)" 332 333 ok=0 334 for tv in "${tested_versions[@]}"; do 335 if [[ "${version}" == *"${tv}"* ]]; then 336 ok=1 337 break 338 fi 339 done 340 341 if [[ ! "${ok}" -eq 1 ]]; then 342 printf "warning: vng version '%s' has not been tested and may " "${version}" >&2 343 printf "not function properly.\n\tThe following versions have been tested: " >&2 344 echo "${tested_versions[@]}" >&2 345 fi 346} 347 348check_socat() { 349 local support_string 350 351 support_string="$(socat -V)" 352 353 if [[ "${support_string}" != *"WITH_VSOCK 1"* ]]; then 354 die "err: socat is missing vsock support" 355 fi 356 357 if [[ "${support_string}" != *"WITH_UNIX 1"* ]]; then 358 die "err: socat is missing unix support" 359 fi 360} 361 362handle_build() { 363 if [[ ! "${BUILD}" -eq 1 ]]; then 364 return 365 fi 366 367 if [[ ! -d "${KERNEL_CHECKOUT}" ]]; then 368 echo "-b requires vmtest.sh called from the kernel source tree" >&2 369 exit 1 370 fi 371 372 pushd "${KERNEL_CHECKOUT}" &>/dev/null 373 374 if ! vng --kconfig --config "${SCRIPT_DIR}"/config; then 375 die "failed to generate .config for kernel source tree (${KERNEL_CHECKOUT})" 376 fi 377 378 if ! make -j$(nproc); then 379 die "failed to build kernel from source tree (${KERNEL_CHECKOUT})" 380 fi 381 382 popd &>/dev/null 383} 384 385create_pidfile() { 386 local pidfile 387 388 pidfile=$(mktemp "${PIDFILE_TEMPLATE}") 389 PIDFILES["${pidfile}"]=1 390 391 echo "${pidfile}" 392} 393 394terminate_pidfiles() { 395 local pidfile 396 397 for pidfile in "$@"; do 398 if [[ -s "${pidfile}" ]]; then 399 pkill -SIGTERM -F "${pidfile}" > /dev/null 2>&1 400 fi 401 402 if [[ -e "${pidfile}" ]]; then 403 rm -f "${pidfile}" 404 fi 405 406 unset "PIDFILES[${pidfile}]" 407 done 408} 409 410terminate_pids() { 411 local pid 412 413 for pid in "$@"; do 414 kill -SIGTERM "${pid}" &>/dev/null || : 415 done 416} 417 418vng_dry_run() { 419 # WORKAROUND: use setsid to work around a virtme-ng bug where vng hangs 420 # when called from a background process group (e.g., under make 421 # kselftest). vng save/restores terminal settings using tcsetattr(), 422 # which is not allowed for background process groups because the 423 # controlling terminal is owned by the foreground process group. vng is 424 # stopped with SIGTTOU and hangs until kselftest's timer expires. 425 # setsid works around this by launching vng in a new session that has 426 # no controlling terminal, so tcsetattr() succeeds. 427 428 setsid -w vng --run "$@" --dry-run &>/dev/null 429} 430 431vm_start() { 432 local pidfile=$1 433 local ns=$2 434 local logfile=/dev/null 435 local verbose_opt="" 436 local kernel_opt="" 437 local qemu_opts="" 438 local ns_exec="" 439 local qemu 440 441 qemu=$(command -v "${QEMU}") 442 443 if [[ "${VERBOSE}" -eq 1 ]]; then 444 verbose_opt="--verbose" 445 logfile=/dev/stdout 446 fi 447 448 qemu_opts="\ 449 -netdev user,id=n0,${QEMU_TEST_PORT_FWD},${QEMU_SSH_PORT_FWD} \ 450 -device virtio-net-pci,netdev=n0 \ 451 -device vhost-vsock-pci,guest-cid=${VSOCK_CID} \ 452 --pidfile ${pidfile} 453 " 454 455 if [[ "${BUILD}" -eq 1 ]]; then 456 kernel_opt="${KERNEL_CHECKOUT}" 457 elif vng_dry_run; then 458 kernel_opt="" 459 elif vng_dry_run "${KERNEL_CHECKOUT}"; then 460 kernel_opt="${KERNEL_CHECKOUT}" 461 else 462 die "No suitable kernel found" 463 fi 464 465 if [[ "${ns}" != "init_ns" ]]; then 466 ns_exec="ip netns exec ${ns}" 467 fi 468 469 ${ns_exec} vng \ 470 --run \ 471 ${kernel_opt} \ 472 ${verbose_opt} \ 473 --qemu-opts="${qemu_opts}" \ 474 --qemu="${qemu}" \ 475 --user root \ 476 --append "${KERNEL_CMDLINE}" \ 477 --rw &> ${logfile} & 478 479 timeout "${WAIT_QEMU}" \ 480 bash -c 'while [[ ! -s '"${pidfile}"' ]]; do sleep 1; done; exit 0' 481} 482 483vm_wait_for_ssh() { 484 local ns=$1 485 local i 486 487 i=0 488 while true; do 489 if [[ ${i} -gt ${WAIT_PERIOD_MAX} ]]; then 490 die "Timed out waiting for guest ssh" 491 fi 492 493 if vm_ssh "${ns}" -- true; then 494 break 495 fi 496 i=$(( i + 1 )) 497 sleep ${WAIT_PERIOD} 498 done 499} 500 501# derived from selftests/net/net_helper.sh 502wait_for_listener() 503{ 504 local port=$1 505 local interval=$2 506 local max_intervals=$3 507 local protocol=$4 508 local i 509 510 for i in $(seq "${max_intervals}"); do 511 case "${protocol}" in 512 tcp) 513 if ss --listening --tcp --numeric | grep -q ":${port} "; then 514 break 515 fi 516 ;; 517 vsock) 518 if ss --listening --vsock --numeric | grep -q ":${port} "; then 519 break 520 fi 521 ;; 522 unix) 523 # For unix sockets, port is actually the socket path 524 if ss --listening --unix | grep -q "${port}"; then 525 break 526 fi 527 ;; 528 *) 529 echo "Unknown protocol: ${protocol}" >&2 530 break 531 ;; 532 esac 533 sleep "${interval}" 534 done 535} 536 537vm_wait_for_listener() { 538 local ns=$1 539 local port=$2 540 local protocol=$3 541 542 vm_ssh "${ns}" <<EOF 543$(declare -f wait_for_listener) 544wait_for_listener ${port} ${WAIT_PERIOD} ${WAIT_PERIOD_MAX} ${protocol} 545EOF 546} 547 548host_wait_for_listener() { 549 local ns=$1 550 local port=$2 551 local protocol=$3 552 553 if [[ "${ns}" == "init_ns" ]]; then 554 wait_for_listener "${port}" "${WAIT_PERIOD}" "${WAIT_PERIOD_MAX}" "${protocol}" 555 else 556 ip netns exec "${ns}" bash <<-EOF 557 $(declare -f wait_for_listener) 558 wait_for_listener ${port} ${WAIT_PERIOD} ${WAIT_PERIOD_MAX} ${protocol} 559 EOF 560 fi 561} 562 563vm_dmesg_oops_count() { 564 local ns=$1 565 566 vm_ssh "${ns}" -- dmesg 2>/dev/null | grep -c -i 'Oops' 567} 568 569vm_dmesg_warn_count() { 570 local ns=$1 571 572 vm_ssh "${ns}" -- dmesg --level=warn 2>/dev/null | grep -c -i 'vsock' 573} 574 575vm_dmesg_check() { 576 local pidfile=$1 577 local ns=$2 578 local oops_before=$3 579 local warn_before=$4 580 local oops_after warn_after 581 582 oops_after=$(vm_dmesg_oops_count "${ns}") 583 if [[ "${oops_after}" -gt "${oops_before}" ]]; then 584 echo "FAIL: kernel oops detected on vm in ns ${ns}" | log_host 585 return 1 586 fi 587 588 warn_after=$(vm_dmesg_warn_count "${ns}") 589 if [[ "${warn_after}" -gt "${warn_before}" ]]; then 590 echo "FAIL: kernel warning detected on vm in ns ${ns}" | log_host 591 return 1 592 fi 593 594 return 0 595} 596 597vm_vsock_test() { 598 local ns=$1 599 local host=$2 600 local cid=$3 601 local port=$4 602 local rc 603 604 # log output and use pipefail to respect vsock_test errors 605 set -o pipefail 606 if [[ "${host}" != server ]]; then 607 vm_ssh "${ns}" -- "${VSOCK_TEST}" \ 608 --mode=client \ 609 --control-host="${host}" \ 610 --peer-cid="${cid}" \ 611 --control-port="${port}" \ 612 2>&1 | log_guest 613 rc=$? 614 else 615 vm_ssh "${ns}" -- "${VSOCK_TEST}" \ 616 --mode=server \ 617 --peer-cid="${cid}" \ 618 --control-port="${port}" \ 619 2>&1 | log_guest & 620 rc=$? 621 622 if [[ $rc -ne 0 ]]; then 623 set +o pipefail 624 return $rc 625 fi 626 627 vm_wait_for_listener "${ns}" "${port}" "tcp" 628 rc=$? 629 fi 630 set +o pipefail 631 632 return $rc 633} 634 635host_vsock_test() { 636 local ns=$1 637 local host=$2 638 local cid=$3 639 local port=$4 640 shift 4 641 local extra_args=("$@") 642 local rc 643 644 local cmd="${VSOCK_TEST}" 645 if [[ "${ns}" != "init_ns" ]]; then 646 cmd="ip netns exec ${ns} ${cmd}" 647 fi 648 649 # log output and use pipefail to respect vsock_test errors 650 set -o pipefail 651 if [[ "${host}" != server ]]; then 652 ${cmd} \ 653 --mode=client \ 654 --peer-cid="${cid}" \ 655 --control-host="${host}" \ 656 --control-port="${port}" \ 657 "${extra_args[@]}" 2>&1 | log_host 658 rc=$? 659 else 660 ${cmd} \ 661 --mode=server \ 662 --peer-cid="${cid}" \ 663 --control-port="${port}" \ 664 "${extra_args[@]}" 2>&1 | log_host & 665 rc=$? 666 667 if [[ $rc -ne 0 ]]; then 668 set +o pipefail 669 return $rc 670 fi 671 672 host_wait_for_listener "${ns}" "${port}" "tcp" 673 rc=$? 674 fi 675 set +o pipefail 676 677 return $rc 678} 679 680log() { 681 local redirect 682 local prefix 683 684 if [[ ${VERBOSE} -eq 0 ]]; then 685 redirect=/dev/null 686 else 687 redirect=/dev/stdout 688 fi 689 690 prefix="${LOG_PREFIX:-}" 691 692 if [[ "$#" -eq 0 ]]; then 693 if [[ -n "${prefix}" ]]; then 694 awk -v prefix="${prefix}" '{printf "%s: %s\n", prefix, $0}' 695 else 696 cat 697 fi 698 else 699 if [[ -n "${prefix}" ]]; then 700 echo "${prefix}: " "$@" 701 else 702 echo "$@" 703 fi 704 fi | tee -a "${LOG}" > "${redirect}" 705} 706 707log_host() { 708 LOG_PREFIX=host log "$@" 709} 710 711log_guest() { 712 LOG_PREFIX=guest log "$@" 713} 714 715ns_get_mode() { 716 local ns=$1 717 718 ip netns exec "${ns}" cat /proc/sys/net/vsock/ns_mode 2>/dev/null 719} 720 721test_ns_host_vsock_ns_mode_ok() { 722 for mode in "${NS_MODES[@]}"; do 723 local actual 724 725 actual=$(ns_get_mode "${mode}0") 726 if [[ "${actual}" != "${mode}" ]]; then 727 log_host "expected mode ${mode}, got ${actual}" 728 return "${KSFT_FAIL}" 729 fi 730 done 731 732 return "${KSFT_PASS}" 733} 734 735test_ns_diff_global_host_connect_to_global_vm_ok() { 736 local oops_before warn_before 737 local pids pid pidfile 738 local ns0 ns1 port 739 declare -a pids 740 local unixfile 741 ns0="global0" 742 ns1="global1" 743 port=1234 744 local rc 745 746 init_namespaces 747 748 pidfile="$(create_pidfile)" 749 750 if ! vm_start "${pidfile}" "${ns0}"; then 751 return "${KSFT_FAIL}" 752 fi 753 754 vm_wait_for_ssh "${ns0}" 755 oops_before=$(vm_dmesg_oops_count "${ns0}") 756 warn_before=$(vm_dmesg_warn_count "${ns0}") 757 758 unixfile=$(mktemp -u /tmp/XXXX.sock) 759 ip netns exec "${ns1}" \ 760 socat TCP-LISTEN:"${TEST_HOST_PORT}",fork \ 761 UNIX-CONNECT:"${unixfile}" & 762 pids+=($!) 763 host_wait_for_listener "${ns1}" "${TEST_HOST_PORT}" "tcp" 764 765 ip netns exec "${ns0}" socat UNIX-LISTEN:"${unixfile}",fork \ 766 TCP-CONNECT:localhost:"${TEST_HOST_PORT}" & 767 pids+=($!) 768 host_wait_for_listener "${ns0}" "${unixfile}" "unix" 769 770 vm_vsock_test "${ns0}" "server" 2 "${TEST_GUEST_PORT}" 771 vm_wait_for_listener "${ns0}" "${TEST_GUEST_PORT}" "tcp" 772 host_vsock_test "${ns1}" "127.0.0.1" "${VSOCK_CID}" "${TEST_HOST_PORT}" 773 rc=$? 774 775 vm_dmesg_check "${pidfile}" "${ns0}" "${oops_before}" "${warn_before}" 776 dmesg_rc=$? 777 778 terminate_pids "${pids[@]}" 779 terminate_pidfiles "${pidfile}" 780 781 if [[ "${rc}" -ne 0 ]] || [[ "${dmesg_rc}" -ne 0 ]]; then 782 return "${KSFT_FAIL}" 783 fi 784 785 return "${KSFT_PASS}" 786} 787 788test_ns_diff_global_host_connect_to_local_vm_fails() { 789 local oops_before warn_before 790 local ns0="global0" 791 local ns1="local0" 792 local port=12345 793 local dmesg_rc 794 local pidfile 795 local result 796 local pid 797 798 init_namespaces 799 800 outfile=$(mktemp) 801 802 pidfile="$(create_pidfile)" 803 if ! vm_start "${pidfile}" "${ns1}"; then 804 log_host "failed to start vm (cid=${VSOCK_CID}, ns=${ns0})" 805 return "${KSFT_FAIL}" 806 fi 807 808 vm_wait_for_ssh "${ns1}" 809 oops_before=$(vm_dmesg_oops_count "${ns1}") 810 warn_before=$(vm_dmesg_warn_count "${ns1}") 811 812 vm_ssh "${ns1}" -- socat VSOCK-LISTEN:"${port}" STDOUT > "${outfile}" & 813 vm_wait_for_listener "${ns1}" "${port}" "vsock" 814 echo TEST | ip netns exec "${ns0}" \ 815 socat STDIN VSOCK-CONNECT:"${VSOCK_CID}":"${port}" 2>/dev/null 816 817 vm_dmesg_check "${pidfile}" "${ns1}" "${oops_before}" "${warn_before}" 818 dmesg_rc=$? 819 820 terminate_pidfiles "${pidfile}" 821 result=$(cat "${outfile}") 822 rm -f "${outfile}" 823 824 if [[ "${result}" == "TEST" ]] || [[ "${dmesg_rc}" -ne 0 ]]; then 825 return "${KSFT_FAIL}" 826 fi 827 828 return "${KSFT_PASS}" 829} 830 831test_ns_diff_global_vm_connect_to_global_host_ok() { 832 local oops_before warn_before 833 local ns0="global0" 834 local ns1="global1" 835 local port=12345 836 local unixfile 837 local dmesg_rc 838 local pidfile 839 local pids 840 local rc 841 842 init_namespaces 843 844 declare -a pids 845 846 log_host "Setup socat bridge from ns ${ns0} to ns ${ns1} over port ${port}" 847 848 unixfile=$(mktemp -u /tmp/XXXX.sock) 849 850 ip netns exec "${ns0}" \ 851 socat TCP-LISTEN:"${port}" UNIX-CONNECT:"${unixfile}" & 852 pids+=($!) 853 host_wait_for_listener "${ns0}" "${port}" "tcp" 854 855 ip netns exec "${ns1}" \ 856 socat UNIX-LISTEN:"${unixfile}" TCP-CONNECT:127.0.0.1:"${port}" & 857 pids+=($!) 858 host_wait_for_listener "${ns1}" "${unixfile}" "unix" 859 860 log_host "Launching ${VSOCK_TEST} in ns ${ns1}" 861 host_vsock_test "${ns1}" "server" "${VSOCK_CID}" "${port}" 862 863 pidfile="$(create_pidfile)" 864 if ! vm_start "${pidfile}" "${ns0}"; then 865 log_host "failed to start vm (cid=${cid}, ns=${ns0})" 866 terminate_pids "${pids[@]}" 867 rm -f "${unixfile}" 868 return "${KSFT_FAIL}" 869 fi 870 871 vm_wait_for_ssh "${ns0}" 872 873 oops_before=$(vm_dmesg_oops_count "${ns0}") 874 warn_before=$(vm_dmesg_warn_count "${ns0}") 875 876 vm_vsock_test "${ns0}" "10.0.2.2" 2 "${port}" 877 rc=$? 878 879 vm_dmesg_check "${pidfile}" "${ns0}" "${oops_before}" "${warn_before}" 880 dmesg_rc=$? 881 882 terminate_pidfiles "${pidfile}" 883 terminate_pids "${pids[@]}" 884 rm -f "${unixfile}" 885 886 if [[ "${rc}" -ne 0 ]] || [[ "${dmesg_rc}" -ne 0 ]]; then 887 return "${KSFT_FAIL}" 888 fi 889 890 return "${KSFT_PASS}" 891 892} 893 894test_ns_diff_global_vm_connect_to_local_host_fails() { 895 local ns0="global0" 896 local ns1="local0" 897 local port=12345 898 local oops_before warn_before 899 local dmesg_rc 900 local pidfile 901 local result 902 local pid 903 904 init_namespaces 905 906 log_host "Launching socat in ns ${ns1}" 907 outfile=$(mktemp) 908 909 ip netns exec "${ns1}" socat VSOCK-LISTEN:"${port}" STDOUT &> "${outfile}" & 910 pid=$! 911 host_wait_for_listener "${ns1}" "${port}" "vsock" 912 913 pidfile="$(create_pidfile)" 914 if ! vm_start "${pidfile}" "${ns0}"; then 915 log_host "failed to start vm (cid=${cid}, ns=${ns0})" 916 terminate_pids "${pid}" 917 rm -f "${outfile}" 918 return "${KSFT_FAIL}" 919 fi 920 921 vm_wait_for_ssh "${ns0}" 922 923 oops_before=$(vm_dmesg_oops_count "${ns0}") 924 warn_before=$(vm_dmesg_warn_count "${ns0}") 925 926 vm_ssh "${ns0}" -- \ 927 bash -c "echo TEST | socat STDIN VSOCK-CONNECT:2:${port}" 2>&1 | log_guest 928 929 vm_dmesg_check "${pidfile}" "${ns0}" "${oops_before}" "${warn_before}" 930 dmesg_rc=$? 931 932 terminate_pidfiles "${pidfile}" 933 terminate_pids "${pid}" 934 935 result=$(cat "${outfile}") 936 rm -f "${outfile}" 937 938 if [[ "${result}" != TEST ]] && [[ "${dmesg_rc}" -eq 0 ]]; then 939 return "${KSFT_PASS}" 940 fi 941 942 return "${KSFT_FAIL}" 943} 944 945test_ns_diff_local_host_connect_to_local_vm_fails() { 946 local ns0="local0" 947 local ns1="local1" 948 local port=12345 949 local oops_before warn_before 950 local dmesg_rc 951 local pidfile 952 local result 953 local pid 954 955 init_namespaces 956 957 outfile=$(mktemp) 958 959 pidfile="$(create_pidfile)" 960 if ! vm_start "${pidfile}" "${ns1}"; then 961 log_host "failed to start vm (cid=${cid}, ns=${ns0})" 962 return "${KSFT_FAIL}" 963 fi 964 965 vm_wait_for_ssh "${ns1}" 966 oops_before=$(vm_dmesg_oops_count "${ns1}") 967 warn_before=$(vm_dmesg_warn_count "${ns1}") 968 969 vm_ssh "${ns1}" -- socat VSOCK-LISTEN:"${port}" STDOUT > "${outfile}" & 970 vm_wait_for_listener "${ns1}" "${port}" "vsock" 971 972 echo TEST | ip netns exec "${ns0}" \ 973 socat STDIN VSOCK-CONNECT:"${VSOCK_CID}":"${port}" 2>/dev/null 974 975 vm_dmesg_check "${pidfile}" "${ns1}" "${oops_before}" "${warn_before}" 976 dmesg_rc=$? 977 978 terminate_pidfiles "${pidfile}" 979 980 result=$(cat "${outfile}") 981 rm -f "${outfile}" 982 983 if [[ "${result}" != TEST ]] && [[ "${dmesg_rc}" -eq 0 ]]; then 984 return "${KSFT_PASS}" 985 fi 986 987 return "${KSFT_FAIL}" 988} 989 990test_ns_diff_local_vm_connect_to_local_host_fails() { 991 local oops_before warn_before 992 local ns0="local0" 993 local ns1="local1" 994 local port=12345 995 local dmesg_rc 996 local pidfile 997 local result 998 local pid 999 1000 init_namespaces 1001 1002 log_host "Launching socat in ns ${ns1}" 1003 outfile=$(mktemp) 1004 ip netns exec "${ns1}" socat VSOCK-LISTEN:"${port}" STDOUT &> "${outfile}" & 1005 pid=$! 1006 host_wait_for_listener "${ns1}" "${port}" "vsock" 1007 1008 pidfile="$(create_pidfile)" 1009 if ! vm_start "${pidfile}" "${ns0}"; then 1010 log_host "failed to start vm (cid=${cid}, ns=${ns0})" 1011 rm -f "${outfile}" 1012 return "${KSFT_FAIL}" 1013 fi 1014 1015 vm_wait_for_ssh "${ns0}" 1016 oops_before=$(vm_dmesg_oops_count "${ns0}") 1017 warn_before=$(vm_dmesg_warn_count "${ns0}") 1018 1019 vm_ssh "${ns0}" -- \ 1020 bash -c "echo TEST | socat STDIN VSOCK-CONNECT:2:${port}" 2>&1 | log_guest 1021 1022 vm_dmesg_check "${pidfile}" "${ns0}" "${oops_before}" "${warn_before}" 1023 dmesg_rc=$? 1024 1025 terminate_pidfiles "${pidfile}" 1026 terminate_pids "${pid}" 1027 1028 result=$(cat "${outfile}") 1029 rm -f "${outfile}" 1030 1031 if [[ "${result}" != TEST ]] && [[ "${dmesg_rc}" -eq 0 ]]; then 1032 return "${KSFT_PASS}" 1033 fi 1034 1035 return "${KSFT_FAIL}" 1036} 1037 1038__test_loopback_two_netns() { 1039 local ns0=$1 1040 local ns1=$2 1041 local port=12345 1042 local result 1043 local pid 1044 1045 modprobe vsock_loopback &> /dev/null || : 1046 1047 log_host "Launching socat in ns ${ns1}" 1048 outfile=$(mktemp) 1049 1050 ip netns exec "${ns1}" socat VSOCK-LISTEN:"${port}" STDOUT > "${outfile}" 2>/dev/null & 1051 pid=$! 1052 host_wait_for_listener "${ns1}" "${port}" "vsock" 1053 1054 log_host "Launching socat in ns ${ns0}" 1055 echo TEST | ip netns exec "${ns0}" socat STDIN VSOCK-CONNECT:1:"${port}" 2>/dev/null 1056 terminate_pids "${pid}" 1057 1058 result=$(cat "${outfile}") 1059 rm -f "${outfile}" 1060 1061 if [[ "${result}" == TEST ]]; then 1062 return 0 1063 fi 1064 1065 return 1 1066} 1067 1068test_ns_diff_global_to_local_loopback_local_fails() { 1069 init_namespaces 1070 1071 if ! __test_loopback_two_netns "global0" "local0"; then 1072 return "${KSFT_PASS}" 1073 fi 1074 1075 return "${KSFT_FAIL}" 1076} 1077 1078test_ns_diff_local_to_global_loopback_fails() { 1079 init_namespaces 1080 1081 if ! __test_loopback_two_netns "local0" "global0"; then 1082 return "${KSFT_PASS}" 1083 fi 1084 1085 return "${KSFT_FAIL}" 1086} 1087 1088test_ns_diff_local_to_local_loopback_fails() { 1089 init_namespaces 1090 1091 if ! __test_loopback_two_netns "local0" "local1"; then 1092 return "${KSFT_PASS}" 1093 fi 1094 1095 return "${KSFT_FAIL}" 1096} 1097 1098test_ns_diff_global_to_global_loopback_ok() { 1099 init_namespaces 1100 1101 if __test_loopback_two_netns "global0" "global1"; then 1102 return "${KSFT_PASS}" 1103 fi 1104 1105 return "${KSFT_FAIL}" 1106} 1107 1108test_ns_same_local_loopback_ok() { 1109 init_namespaces 1110 1111 if __test_loopback_two_netns "local0" "local0"; then 1112 return "${KSFT_PASS}" 1113 fi 1114 1115 return "${KSFT_FAIL}" 1116} 1117 1118test_ns_same_local_host_connect_to_local_vm_ok() { 1119 local oops_before warn_before 1120 local ns="local0" 1121 local port=1234 1122 local dmesg_rc 1123 local pidfile 1124 local rc 1125 1126 init_namespaces 1127 1128 pidfile="$(create_pidfile)" 1129 1130 if ! vm_start "${pidfile}" "${ns}"; then 1131 return "${KSFT_FAIL}" 1132 fi 1133 1134 vm_wait_for_ssh "${ns}" 1135 oops_before=$(vm_dmesg_oops_count "${ns}") 1136 warn_before=$(vm_dmesg_warn_count "${ns}") 1137 1138 vm_vsock_test "${ns}" "server" 2 "${TEST_GUEST_PORT}" 1139 1140 # Skip test 29 (transport release use-after-free): This test attempts 1141 # binding both G2H and H2G CIDs. Because virtio-vsock (G2H) doesn't 1142 # support local namespaces the test will fail when 1143 # transport_g2h->stream_allow() returns false. This edge case only 1144 # happens for vsock_test in client mode on the host in a local 1145 # namespace. This is a false positive. 1146 host_vsock_test "${ns}" "127.0.0.1" "${VSOCK_CID}" "${TEST_HOST_PORT}" --skip=29 1147 rc=$? 1148 1149 vm_dmesg_check "${pidfile}" "${ns}" "${oops_before}" "${warn_before}" 1150 dmesg_rc=$? 1151 1152 terminate_pidfiles "${pidfile}" 1153 1154 if [[ "${rc}" -ne 0 ]] || [[ "${dmesg_rc}" -ne 0 ]]; then 1155 return "${KSFT_FAIL}" 1156 fi 1157 1158 return "${KSFT_PASS}" 1159} 1160 1161test_ns_same_local_vm_connect_to_local_host_ok() { 1162 local oops_before warn_before 1163 local ns="local0" 1164 local port=1234 1165 local dmesg_rc 1166 local pidfile 1167 local rc 1168 1169 init_namespaces 1170 1171 pidfile="$(create_pidfile)" 1172 1173 if ! vm_start "${pidfile}" "${ns}"; then 1174 return "${KSFT_FAIL}" 1175 fi 1176 1177 vm_wait_for_ssh "${ns}" 1178 oops_before=$(vm_dmesg_oops_count "${ns}") 1179 warn_before=$(vm_dmesg_warn_count "${ns}") 1180 1181 host_vsock_test "${ns}" "server" "${VSOCK_CID}" "${port}" 1182 vm_vsock_test "${ns}" "10.0.2.2" 2 "${port}" 1183 rc=$? 1184 1185 vm_dmesg_check "${pidfile}" "${ns}" "${oops_before}" "${warn_before}" 1186 dmesg_rc=$? 1187 1188 terminate_pidfiles "${pidfile}" 1189 1190 if [[ "${rc}" -ne 0 ]] || [[ "${dmesg_rc}" -ne 0 ]]; then 1191 return "${KSFT_FAIL}" 1192 fi 1193 1194 return "${KSFT_PASS}" 1195} 1196 1197namespaces_can_boot_same_cid() { 1198 local ns0=$1 1199 local ns1=$2 1200 local pidfile1 pidfile2 1201 local rc 1202 1203 pidfile1="$(create_pidfile)" 1204 1205 # The first VM should be able to start. If it can't then we have 1206 # problems and need to return non-zero. 1207 if ! vm_start "${pidfile1}" "${ns0}"; then 1208 return 1 1209 fi 1210 1211 pidfile2="$(create_pidfile)" 1212 vm_start "${pidfile2}" "${ns1}" 1213 rc=$? 1214 terminate_pidfiles "${pidfile1}" "${pidfile2}" 1215 1216 return "${rc}" 1217} 1218 1219test_ns_global_same_cid_fails() { 1220 init_namespaces 1221 1222 if namespaces_can_boot_same_cid "global0" "global1"; then 1223 return "${KSFT_FAIL}" 1224 fi 1225 1226 return "${KSFT_PASS}" 1227} 1228 1229test_ns_local_global_same_cid_ok() { 1230 init_namespaces 1231 1232 if namespaces_can_boot_same_cid "local0" "global0"; then 1233 return "${KSFT_PASS}" 1234 fi 1235 1236 return "${KSFT_FAIL}" 1237} 1238 1239test_ns_global_local_same_cid_ok() { 1240 init_namespaces 1241 1242 if namespaces_can_boot_same_cid "global0" "local0"; then 1243 return "${KSFT_PASS}" 1244 fi 1245 1246 return "${KSFT_FAIL}" 1247} 1248 1249test_ns_local_same_cid_ok() { 1250 init_namespaces 1251 1252 if namespaces_can_boot_same_cid "local0" "local1"; then 1253 return "${KSFT_PASS}" 1254 fi 1255 1256 return "${KSFT_FAIL}" 1257} 1258 1259test_ns_host_vsock_child_ns_mode_ok() { 1260 local rc="${KSFT_PASS}" 1261 1262 for mode in "${NS_MODES[@]}"; do 1263 local ns="${mode}0" 1264 1265 if echo "${mode}" 2>/dev/null > /proc/sys/net/vsock/ns_mode; then 1266 log_host "ns_mode should be read-only but write succeeded" 1267 rc="${KSFT_FAIL}" 1268 continue 1269 fi 1270 1271 if ! echo "${mode}" | ip netns exec "${ns}" \ 1272 tee /proc/sys/net/vsock/child_ns_mode &>/dev/null; then 1273 rc="${KSFT_FAIL}" 1274 continue 1275 fi 1276 done 1277 1278 return "${rc}" 1279} 1280 1281test_vm_server_host_client() { 1282 if ! vm_vsock_test "init_ns" "server" 2 "${TEST_GUEST_PORT}"; then 1283 return "${KSFT_FAIL}" 1284 fi 1285 1286 if ! host_vsock_test "init_ns" "127.0.0.1" "${VSOCK_CID}" "${TEST_HOST_PORT}"; then 1287 return "${KSFT_FAIL}" 1288 fi 1289 1290 return "${KSFT_PASS}" 1291} 1292 1293test_vm_client_host_server() { 1294 if ! host_vsock_test "init_ns" "server" "${VSOCK_CID}" "${TEST_HOST_PORT_LISTENER}"; then 1295 return "${KSFT_FAIL}" 1296 fi 1297 1298 if ! vm_vsock_test "init_ns" "10.0.2.2" 2 "${TEST_HOST_PORT_LISTENER}"; then 1299 return "${KSFT_FAIL}" 1300 fi 1301 1302 return "${KSFT_PASS}" 1303} 1304 1305test_vm_loopback() { 1306 local port=60000 # non-forwarded local port 1307 1308 vm_ssh "init_ns" -- modprobe vsock_loopback &> /dev/null || : 1309 1310 if ! vm_vsock_test "init_ns" "server" 1 "${port}"; then 1311 return "${KSFT_FAIL}" 1312 fi 1313 1314 1315 if ! vm_vsock_test "init_ns" "127.0.0.1" 1 "${port}"; then 1316 return "${KSFT_FAIL}" 1317 fi 1318 1319 return "${KSFT_PASS}" 1320} 1321 1322check_ns_delete_doesnt_break_connection() { 1323 local pipefile pidfile outfile 1324 local ns0="global0" 1325 local ns1="global1" 1326 local port=12345 1327 local pids=() 1328 local rc=0 1329 1330 init_namespaces 1331 1332 pidfile="$(create_pidfile)" 1333 if ! vm_start "${pidfile}" "${ns0}"; then 1334 return "${KSFT_FAIL}" 1335 fi 1336 vm_wait_for_ssh "${ns0}" 1337 1338 outfile=$(mktemp) 1339 vm_ssh "${ns0}" -- \ 1340 socat VSOCK-LISTEN:"${port}",fork STDOUT > "${outfile}" 2>/dev/null & 1341 pids+=($!) 1342 vm_wait_for_listener "${ns0}" "${port}" "vsock" 1343 1344 # We use a pipe here so that we can echo into the pipe instead of using 1345 # socat and a unix socket file. We just need a name for the pipe (not a 1346 # regular file) so use -u. 1347 pipefile=$(mktemp -u /tmp/vmtest_pipe_XXXX) 1348 ip netns exec "${ns1}" \ 1349 socat PIPE:"${pipefile}" VSOCK-CONNECT:"${VSOCK_CID}":"${port}" & 1350 pids+=($!) 1351 1352 timeout "${WAIT_PERIOD}" \ 1353 bash -c 'while [[ ! -e '"${pipefile}"' ]]; do sleep 1; done; exit 0' 1354 1355 if [[ "$1" == "vm" ]]; then 1356 ip netns del "${ns0}" 1357 elif [[ "$1" == "host" ]]; then 1358 ip netns del "${ns1}" 1359 elif [[ "$1" == "both" ]]; then 1360 ip netns del "${ns0}" 1361 ip netns del "${ns1}" 1362 fi 1363 1364 echo "TEST" > "${pipefile}" 1365 1366 timeout "${WAIT_PERIOD}" \ 1367 bash -c 'while [[ ! -s '"${outfile}"' ]]; do sleep 1; done; exit 0' 1368 1369 if grep -q "TEST" "${outfile}"; then 1370 rc="${KSFT_PASS}" 1371 else 1372 rc="${KSFT_FAIL}" 1373 fi 1374 1375 terminate_pidfiles "${pidfile}" 1376 terminate_pids "${pids[@]}" 1377 rm -f "${outfile}" "${pipefile}" 1378 1379 return "${rc}" 1380} 1381 1382test_ns_delete_vm_ok() { 1383 check_ns_delete_doesnt_break_connection "vm" 1384} 1385 1386test_ns_delete_host_ok() { 1387 check_ns_delete_doesnt_break_connection "host" 1388} 1389 1390test_ns_delete_both_ok() { 1391 check_ns_delete_doesnt_break_connection "both" 1392} 1393 1394shared_vm_test() { 1395 local tname 1396 1397 tname="${1}" 1398 1399 for testname in "${USE_SHARED_VM[@]}"; do 1400 if [[ "${tname}" == "${testname}" ]]; then 1401 return 0 1402 fi 1403 done 1404 1405 return 1 1406} 1407 1408shared_vm_tests_requested() { 1409 for arg in "$@"; do 1410 if shared_vm_test "${arg}"; then 1411 return 0 1412 fi 1413 done 1414 1415 return 1 1416} 1417 1418run_shared_vm_tests() { 1419 local arg 1420 1421 for arg in "$@"; do 1422 if ! shared_vm_test "${arg}"; then 1423 continue 1424 fi 1425 1426 if ! check_netns "${arg}"; then 1427 check_result "${KSFT_SKIP}" "${arg}" 1428 continue 1429 fi 1430 1431 run_shared_vm_test "${arg}" 1432 check_result "$?" "${arg}" 1433 done 1434} 1435 1436run_shared_vm_test() { 1437 local host_oops_cnt_before 1438 local host_warn_cnt_before 1439 local vm_oops_cnt_before 1440 local vm_warn_cnt_before 1441 local host_oops_cnt_after 1442 local host_warn_cnt_after 1443 local vm_oops_cnt_after 1444 local vm_warn_cnt_after 1445 local name 1446 local rc 1447 1448 host_oops_cnt_before=$(dmesg | grep -c -i 'Oops') 1449 host_warn_cnt_before=$(dmesg --level=warn | grep -c -i 'vsock') 1450 vm_oops_cnt_before=$(vm_dmesg_oops_count "init_ns") 1451 vm_warn_cnt_before=$(vm_dmesg_warn_count "init_ns") 1452 1453 name=$(echo "${1}" | awk '{ print $1 }') 1454 eval test_"${name}" 1455 rc=$? 1456 1457 host_oops_cnt_after=$(dmesg | grep -i 'Oops' | wc -l) 1458 if [[ ${host_oops_cnt_after} -gt ${host_oops_cnt_before} ]]; then 1459 echo "FAIL: kernel oops detected on host" | log_host 1460 rc=$KSFT_FAIL 1461 fi 1462 1463 host_warn_cnt_after=$(dmesg --level=warn | grep -c -i 'vsock') 1464 if [[ ${host_warn_cnt_after} -gt ${host_warn_cnt_before} ]]; then 1465 echo "FAIL: kernel warning detected on host" | log_host 1466 rc=$KSFT_FAIL 1467 fi 1468 1469 vm_oops_cnt_after=$(vm_dmesg_oops_count "init_ns") 1470 if [[ ${vm_oops_cnt_after} -gt ${vm_oops_cnt_before} ]]; then 1471 echo "FAIL: kernel oops detected on vm" | log_host 1472 rc=$KSFT_FAIL 1473 fi 1474 1475 vm_warn_cnt_after=$(vm_dmesg_warn_count "init_ns") 1476 if [[ ${vm_warn_cnt_after} -gt ${vm_warn_cnt_before} ]]; then 1477 echo "FAIL: kernel warning detected on vm" | log_host 1478 rc=$KSFT_FAIL 1479 fi 1480 1481 return "${rc}" 1482} 1483 1484run_ns_tests() { 1485 for arg in "${ARGS[@]}"; do 1486 if shared_vm_test "${arg}"; then 1487 continue 1488 fi 1489 1490 if ! check_netns "${arg}"; then 1491 check_result "${KSFT_SKIP}" "${arg}" 1492 continue 1493 fi 1494 1495 add_namespaces 1496 1497 name=$(echo "${arg}" | awk '{ print $1 }') 1498 log_host "Executing test_${name}" 1499 1500 host_oops_before=$(dmesg 2>/dev/null | grep -c -i 'Oops') 1501 host_warn_before=$(dmesg --level=warn 2>/dev/null | grep -c -i 'vsock') 1502 eval test_"${name}" 1503 rc=$? 1504 1505 host_oops_after=$(dmesg 2>/dev/null | grep -c -i 'Oops') 1506 if [[ "${host_oops_after}" -gt "${host_oops_before}" ]]; then 1507 echo "FAIL: kernel oops detected on host" | log_host 1508 check_result "${KSFT_FAIL}" "${name}" 1509 del_namespaces 1510 continue 1511 fi 1512 1513 host_warn_after=$(dmesg --level=warn 2>/dev/null | grep -c -i 'vsock') 1514 if [[ "${host_warn_after}" -gt "${host_warn_before}" ]]; then 1515 echo "FAIL: kernel warning detected on host" | log_host 1516 check_result "${KSFT_FAIL}" "${name}" 1517 del_namespaces 1518 continue 1519 fi 1520 1521 check_result "${rc}" "${name}" 1522 1523 del_namespaces 1524 done 1525} 1526 1527BUILD=0 1528QEMU="qemu-system-$(uname -m)" 1529 1530while getopts :hvsq:b o 1531do 1532 case $o in 1533 v) VERBOSE=1;; 1534 b) BUILD=1;; 1535 q) QEMU=$OPTARG;; 1536 h|*) usage;; 1537 esac 1538done 1539shift $((OPTIND-1)) 1540 1541trap cleanup EXIT 1542 1543if [[ ${#} -eq 0 ]]; then 1544 ARGS=("${TEST_NAMES[@]}") 1545else 1546 ARGS=("$@") 1547fi 1548 1549check_args "${ARGS[@]}" 1550check_deps 1551check_vng 1552check_socat 1553handle_build 1554 1555echo "1..${#ARGS[@]}" 1556 1557cnt_pass=0 1558cnt_fail=0 1559cnt_skip=0 1560cnt_total=0 1561 1562if shared_vm_tests_requested "${ARGS[@]}"; then 1563 log_host "Booting up VM" 1564 pidfile="$(create_pidfile)" 1565 vm_start "${pidfile}" "init_ns" 1566 vm_wait_for_ssh "init_ns" 1567 log_host "VM booted up" 1568 1569 run_shared_vm_tests "${ARGS[@]}" 1570 terminate_pidfiles "${pidfile}" 1571fi 1572 1573run_ns_tests "${ARGS[@]}" 1574 1575echo "SUMMARY: PASS=${cnt_pass} SKIP=${cnt_skip} FAIL=${cnt_fail}" 1576echo "Log: ${LOG}" 1577 1578if [ $((cnt_pass + cnt_skip)) -eq ${cnt_total} ]; then 1579 exit "$KSFT_PASS" 1580else 1581 exit "$KSFT_FAIL" 1582fi 1583