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 418vm_start() { 419 local pidfile=$1 420 local ns=$2 421 local logfile=/dev/null 422 local verbose_opt="" 423 local kernel_opt="" 424 local qemu_opts="" 425 local ns_exec="" 426 local qemu 427 428 qemu=$(command -v "${QEMU}") 429 430 if [[ "${VERBOSE}" -eq 1 ]]; then 431 verbose_opt="--verbose" 432 logfile=/dev/stdout 433 fi 434 435 qemu_opts="\ 436 -netdev user,id=n0,${QEMU_TEST_PORT_FWD},${QEMU_SSH_PORT_FWD} \ 437 -device virtio-net-pci,netdev=n0 \ 438 -device vhost-vsock-pci,guest-cid=${VSOCK_CID} \ 439 --pidfile ${pidfile} 440 " 441 442 if [[ "${BUILD}" -eq 1 ]]; then 443 kernel_opt="${KERNEL_CHECKOUT}" 444 fi 445 446 if [[ "${ns}" != "init_ns" ]]; then 447 ns_exec="ip netns exec ${ns}" 448 fi 449 450 ${ns_exec} vng \ 451 --run \ 452 ${kernel_opt} \ 453 ${verbose_opt} \ 454 --qemu-opts="${qemu_opts}" \ 455 --qemu="${qemu}" \ 456 --user root \ 457 --append "${KERNEL_CMDLINE}" \ 458 --rw &> ${logfile} & 459 460 timeout "${WAIT_QEMU}" \ 461 bash -c 'while [[ ! -s '"${pidfile}"' ]]; do sleep 1; done; exit 0' 462} 463 464vm_wait_for_ssh() { 465 local ns=$1 466 local i 467 468 i=0 469 while true; do 470 if [[ ${i} -gt ${WAIT_PERIOD_MAX} ]]; then 471 die "Timed out waiting for guest ssh" 472 fi 473 474 if vm_ssh "${ns}" -- true; then 475 break 476 fi 477 i=$(( i + 1 )) 478 sleep ${WAIT_PERIOD} 479 done 480} 481 482# derived from selftests/net/net_helper.sh 483wait_for_listener() 484{ 485 local port=$1 486 local interval=$2 487 local max_intervals=$3 488 local protocol=$4 489 local i 490 491 for i in $(seq "${max_intervals}"); do 492 case "${protocol}" in 493 tcp) 494 if ss --listening --tcp --numeric | grep -q ":${port} "; then 495 break 496 fi 497 ;; 498 vsock) 499 if ss --listening --vsock --numeric | grep -q ":${port} "; then 500 break 501 fi 502 ;; 503 unix) 504 # For unix sockets, port is actually the socket path 505 if ss --listening --unix | grep -q "${port}"; then 506 break 507 fi 508 ;; 509 *) 510 echo "Unknown protocol: ${protocol}" >&2 511 break 512 ;; 513 esac 514 sleep "${interval}" 515 done 516} 517 518vm_wait_for_listener() { 519 local ns=$1 520 local port=$2 521 local protocol=$3 522 523 vm_ssh "${ns}" <<EOF 524$(declare -f wait_for_listener) 525wait_for_listener ${port} ${WAIT_PERIOD} ${WAIT_PERIOD_MAX} ${protocol} 526EOF 527} 528 529host_wait_for_listener() { 530 local ns=$1 531 local port=$2 532 local protocol=$3 533 534 if [[ "${ns}" == "init_ns" ]]; then 535 wait_for_listener "${port}" "${WAIT_PERIOD}" "${WAIT_PERIOD_MAX}" "${protocol}" 536 else 537 ip netns exec "${ns}" bash <<-EOF 538 $(declare -f wait_for_listener) 539 wait_for_listener ${port} ${WAIT_PERIOD} ${WAIT_PERIOD_MAX} ${protocol} 540 EOF 541 fi 542} 543 544vm_dmesg_oops_count() { 545 local ns=$1 546 547 vm_ssh "${ns}" -- dmesg 2>/dev/null | grep -c -i 'Oops' 548} 549 550vm_dmesg_warn_count() { 551 local ns=$1 552 553 vm_ssh "${ns}" -- dmesg --level=warn 2>/dev/null | grep -c -i 'vsock' 554} 555 556vm_dmesg_check() { 557 local pidfile=$1 558 local ns=$2 559 local oops_before=$3 560 local warn_before=$4 561 local oops_after warn_after 562 563 oops_after=$(vm_dmesg_oops_count "${ns}") 564 if [[ "${oops_after}" -gt "${oops_before}" ]]; then 565 echo "FAIL: kernel oops detected on vm in ns ${ns}" | log_host 566 return 1 567 fi 568 569 warn_after=$(vm_dmesg_warn_count "${ns}") 570 if [[ "${warn_after}" -gt "${warn_before}" ]]; then 571 echo "FAIL: kernel warning detected on vm in ns ${ns}" | log_host 572 return 1 573 fi 574 575 return 0 576} 577 578vm_vsock_test() { 579 local ns=$1 580 local host=$2 581 local cid=$3 582 local port=$4 583 local rc 584 585 # log output and use pipefail to respect vsock_test errors 586 set -o pipefail 587 if [[ "${host}" != server ]]; then 588 vm_ssh "${ns}" -- "${VSOCK_TEST}" \ 589 --mode=client \ 590 --control-host="${host}" \ 591 --peer-cid="${cid}" \ 592 --control-port="${port}" \ 593 2>&1 | log_guest 594 rc=$? 595 else 596 vm_ssh "${ns}" -- "${VSOCK_TEST}" \ 597 --mode=server \ 598 --peer-cid="${cid}" \ 599 --control-port="${port}" \ 600 2>&1 | log_guest & 601 rc=$? 602 603 if [[ $rc -ne 0 ]]; then 604 set +o pipefail 605 return $rc 606 fi 607 608 vm_wait_for_listener "${ns}" "${port}" "tcp" 609 rc=$? 610 fi 611 set +o pipefail 612 613 return $rc 614} 615 616host_vsock_test() { 617 local ns=$1 618 local host=$2 619 local cid=$3 620 local port=$4 621 shift 4 622 local extra_args=("$@") 623 local rc 624 625 local cmd="${VSOCK_TEST}" 626 if [[ "${ns}" != "init_ns" ]]; then 627 cmd="ip netns exec ${ns} ${cmd}" 628 fi 629 630 # log output and use pipefail to respect vsock_test errors 631 set -o pipefail 632 if [[ "${host}" != server ]]; then 633 ${cmd} \ 634 --mode=client \ 635 --peer-cid="${cid}" \ 636 --control-host="${host}" \ 637 --control-port="${port}" \ 638 "${extra_args[@]}" 2>&1 | log_host 639 rc=$? 640 else 641 ${cmd} \ 642 --mode=server \ 643 --peer-cid="${cid}" \ 644 --control-port="${port}" \ 645 "${extra_args[@]}" 2>&1 | log_host & 646 rc=$? 647 648 if [[ $rc -ne 0 ]]; then 649 set +o pipefail 650 return $rc 651 fi 652 653 host_wait_for_listener "${ns}" "${port}" "tcp" 654 rc=$? 655 fi 656 set +o pipefail 657 658 return $rc 659} 660 661log() { 662 local redirect 663 local prefix 664 665 if [[ ${VERBOSE} -eq 0 ]]; then 666 redirect=/dev/null 667 else 668 redirect=/dev/stdout 669 fi 670 671 prefix="${LOG_PREFIX:-}" 672 673 if [[ "$#" -eq 0 ]]; then 674 if [[ -n "${prefix}" ]]; then 675 awk -v prefix="${prefix}" '{printf "%s: %s\n", prefix, $0}' 676 else 677 cat 678 fi 679 else 680 if [[ -n "${prefix}" ]]; then 681 echo "${prefix}: " "$@" 682 else 683 echo "$@" 684 fi 685 fi | tee -a "${LOG}" > "${redirect}" 686} 687 688log_host() { 689 LOG_PREFIX=host log "$@" 690} 691 692log_guest() { 693 LOG_PREFIX=guest log "$@" 694} 695 696ns_get_mode() { 697 local ns=$1 698 699 ip netns exec "${ns}" cat /proc/sys/net/vsock/ns_mode 2>/dev/null 700} 701 702test_ns_host_vsock_ns_mode_ok() { 703 for mode in "${NS_MODES[@]}"; do 704 local actual 705 706 actual=$(ns_get_mode "${mode}0") 707 if [[ "${actual}" != "${mode}" ]]; then 708 log_host "expected mode ${mode}, got ${actual}" 709 return "${KSFT_FAIL}" 710 fi 711 done 712 713 return "${KSFT_PASS}" 714} 715 716test_ns_diff_global_host_connect_to_global_vm_ok() { 717 local oops_before warn_before 718 local pids pid pidfile 719 local ns0 ns1 port 720 declare -a pids 721 local unixfile 722 ns0="global0" 723 ns1="global1" 724 port=1234 725 local rc 726 727 init_namespaces 728 729 pidfile="$(create_pidfile)" 730 731 if ! vm_start "${pidfile}" "${ns0}"; then 732 return "${KSFT_FAIL}" 733 fi 734 735 vm_wait_for_ssh "${ns0}" 736 oops_before=$(vm_dmesg_oops_count "${ns0}") 737 warn_before=$(vm_dmesg_warn_count "${ns0}") 738 739 unixfile=$(mktemp -u /tmp/XXXX.sock) 740 ip netns exec "${ns1}" \ 741 socat TCP-LISTEN:"${TEST_HOST_PORT}",fork \ 742 UNIX-CONNECT:"${unixfile}" & 743 pids+=($!) 744 host_wait_for_listener "${ns1}" "${TEST_HOST_PORT}" "tcp" 745 746 ip netns exec "${ns0}" socat UNIX-LISTEN:"${unixfile}",fork \ 747 TCP-CONNECT:localhost:"${TEST_HOST_PORT}" & 748 pids+=($!) 749 host_wait_for_listener "${ns0}" "${unixfile}" "unix" 750 751 vm_vsock_test "${ns0}" "server" 2 "${TEST_GUEST_PORT}" 752 vm_wait_for_listener "${ns0}" "${TEST_GUEST_PORT}" "tcp" 753 host_vsock_test "${ns1}" "127.0.0.1" "${VSOCK_CID}" "${TEST_HOST_PORT}" 754 rc=$? 755 756 vm_dmesg_check "${pidfile}" "${ns0}" "${oops_before}" "${warn_before}" 757 dmesg_rc=$? 758 759 terminate_pids "${pids[@]}" 760 terminate_pidfiles "${pidfile}" 761 762 if [[ "${rc}" -ne 0 ]] || [[ "${dmesg_rc}" -ne 0 ]]; then 763 return "${KSFT_FAIL}" 764 fi 765 766 return "${KSFT_PASS}" 767} 768 769test_ns_diff_global_host_connect_to_local_vm_fails() { 770 local oops_before warn_before 771 local ns0="global0" 772 local ns1="local0" 773 local port=12345 774 local dmesg_rc 775 local pidfile 776 local result 777 local pid 778 779 init_namespaces 780 781 outfile=$(mktemp) 782 783 pidfile="$(create_pidfile)" 784 if ! vm_start "${pidfile}" "${ns1}"; then 785 log_host "failed to start vm (cid=${VSOCK_CID}, ns=${ns0})" 786 return "${KSFT_FAIL}" 787 fi 788 789 vm_wait_for_ssh "${ns1}" 790 oops_before=$(vm_dmesg_oops_count "${ns1}") 791 warn_before=$(vm_dmesg_warn_count "${ns1}") 792 793 vm_ssh "${ns1}" -- socat VSOCK-LISTEN:"${port}" STDOUT > "${outfile}" & 794 vm_wait_for_listener "${ns1}" "${port}" "vsock" 795 echo TEST | ip netns exec "${ns0}" \ 796 socat STDIN VSOCK-CONNECT:"${VSOCK_CID}":"${port}" 2>/dev/null 797 798 vm_dmesg_check "${pidfile}" "${ns1}" "${oops_before}" "${warn_before}" 799 dmesg_rc=$? 800 801 terminate_pidfiles "${pidfile}" 802 result=$(cat "${outfile}") 803 rm -f "${outfile}" 804 805 if [[ "${result}" == "TEST" ]] || [[ "${dmesg_rc}" -ne 0 ]]; then 806 return "${KSFT_FAIL}" 807 fi 808 809 return "${KSFT_PASS}" 810} 811 812test_ns_diff_global_vm_connect_to_global_host_ok() { 813 local oops_before warn_before 814 local ns0="global0" 815 local ns1="global1" 816 local port=12345 817 local unixfile 818 local dmesg_rc 819 local pidfile 820 local pids 821 local rc 822 823 init_namespaces 824 825 declare -a pids 826 827 log_host "Setup socat bridge from ns ${ns0} to ns ${ns1} over port ${port}" 828 829 unixfile=$(mktemp -u /tmp/XXXX.sock) 830 831 ip netns exec "${ns0}" \ 832 socat TCP-LISTEN:"${port}" UNIX-CONNECT:"${unixfile}" & 833 pids+=($!) 834 host_wait_for_listener "${ns0}" "${port}" "tcp" 835 836 ip netns exec "${ns1}" \ 837 socat UNIX-LISTEN:"${unixfile}" TCP-CONNECT:127.0.0.1:"${port}" & 838 pids+=($!) 839 host_wait_for_listener "${ns1}" "${unixfile}" "unix" 840 841 log_host "Launching ${VSOCK_TEST} in ns ${ns1}" 842 host_vsock_test "${ns1}" "server" "${VSOCK_CID}" "${port}" 843 844 pidfile="$(create_pidfile)" 845 if ! vm_start "${pidfile}" "${ns0}"; then 846 log_host "failed to start vm (cid=${cid}, ns=${ns0})" 847 terminate_pids "${pids[@]}" 848 rm -f "${unixfile}" 849 return "${KSFT_FAIL}" 850 fi 851 852 vm_wait_for_ssh "${ns0}" 853 854 oops_before=$(vm_dmesg_oops_count "${ns0}") 855 warn_before=$(vm_dmesg_warn_count "${ns0}") 856 857 vm_vsock_test "${ns0}" "10.0.2.2" 2 "${port}" 858 rc=$? 859 860 vm_dmesg_check "${pidfile}" "${ns0}" "${oops_before}" "${warn_before}" 861 dmesg_rc=$? 862 863 terminate_pidfiles "${pidfile}" 864 terminate_pids "${pids[@]}" 865 rm -f "${unixfile}" 866 867 if [[ "${rc}" -ne 0 ]] || [[ "${dmesg_rc}" -ne 0 ]]; then 868 return "${KSFT_FAIL}" 869 fi 870 871 return "${KSFT_PASS}" 872 873} 874 875test_ns_diff_global_vm_connect_to_local_host_fails() { 876 local ns0="global0" 877 local ns1="local0" 878 local port=12345 879 local oops_before warn_before 880 local dmesg_rc 881 local pidfile 882 local result 883 local pid 884 885 init_namespaces 886 887 log_host "Launching socat in ns ${ns1}" 888 outfile=$(mktemp) 889 890 ip netns exec "${ns1}" socat VSOCK-LISTEN:"${port}" STDOUT &> "${outfile}" & 891 pid=$! 892 host_wait_for_listener "${ns1}" "${port}" "vsock" 893 894 pidfile="$(create_pidfile)" 895 if ! vm_start "${pidfile}" "${ns0}"; then 896 log_host "failed to start vm (cid=${cid}, ns=${ns0})" 897 terminate_pids "${pid}" 898 rm -f "${outfile}" 899 return "${KSFT_FAIL}" 900 fi 901 902 vm_wait_for_ssh "${ns0}" 903 904 oops_before=$(vm_dmesg_oops_count "${ns0}") 905 warn_before=$(vm_dmesg_warn_count "${ns0}") 906 907 vm_ssh "${ns0}" -- \ 908 bash -c "echo TEST | socat STDIN VSOCK-CONNECT:2:${port}" 2>&1 | log_guest 909 910 vm_dmesg_check "${pidfile}" "${ns0}" "${oops_before}" "${warn_before}" 911 dmesg_rc=$? 912 913 terminate_pidfiles "${pidfile}" 914 terminate_pids "${pid}" 915 916 result=$(cat "${outfile}") 917 rm -f "${outfile}" 918 919 if [[ "${result}" != TEST ]] && [[ "${dmesg_rc}" -eq 0 ]]; then 920 return "${KSFT_PASS}" 921 fi 922 923 return "${KSFT_FAIL}" 924} 925 926test_ns_diff_local_host_connect_to_local_vm_fails() { 927 local ns0="local0" 928 local ns1="local1" 929 local port=12345 930 local oops_before warn_before 931 local dmesg_rc 932 local pidfile 933 local result 934 local pid 935 936 init_namespaces 937 938 outfile=$(mktemp) 939 940 pidfile="$(create_pidfile)" 941 if ! vm_start "${pidfile}" "${ns1}"; then 942 log_host "failed to start vm (cid=${cid}, ns=${ns0})" 943 return "${KSFT_FAIL}" 944 fi 945 946 vm_wait_for_ssh "${ns1}" 947 oops_before=$(vm_dmesg_oops_count "${ns1}") 948 warn_before=$(vm_dmesg_warn_count "${ns1}") 949 950 vm_ssh "${ns1}" -- socat VSOCK-LISTEN:"${port}" STDOUT > "${outfile}" & 951 vm_wait_for_listener "${ns1}" "${port}" "vsock" 952 953 echo TEST | ip netns exec "${ns0}" \ 954 socat STDIN VSOCK-CONNECT:"${VSOCK_CID}":"${port}" 2>/dev/null 955 956 vm_dmesg_check "${pidfile}" "${ns1}" "${oops_before}" "${warn_before}" 957 dmesg_rc=$? 958 959 terminate_pidfiles "${pidfile}" 960 961 result=$(cat "${outfile}") 962 rm -f "${outfile}" 963 964 if [[ "${result}" != TEST ]] && [[ "${dmesg_rc}" -eq 0 ]]; then 965 return "${KSFT_PASS}" 966 fi 967 968 return "${KSFT_FAIL}" 969} 970 971test_ns_diff_local_vm_connect_to_local_host_fails() { 972 local oops_before warn_before 973 local ns0="local0" 974 local ns1="local1" 975 local port=12345 976 local dmesg_rc 977 local pidfile 978 local result 979 local pid 980 981 init_namespaces 982 983 log_host "Launching socat in ns ${ns1}" 984 outfile=$(mktemp) 985 ip netns exec "${ns1}" socat VSOCK-LISTEN:"${port}" STDOUT &> "${outfile}" & 986 pid=$! 987 host_wait_for_listener "${ns1}" "${port}" "vsock" 988 989 pidfile="$(create_pidfile)" 990 if ! vm_start "${pidfile}" "${ns0}"; then 991 log_host "failed to start vm (cid=${cid}, ns=${ns0})" 992 rm -f "${outfile}" 993 return "${KSFT_FAIL}" 994 fi 995 996 vm_wait_for_ssh "${ns0}" 997 oops_before=$(vm_dmesg_oops_count "${ns0}") 998 warn_before=$(vm_dmesg_warn_count "${ns0}") 999 1000 vm_ssh "${ns0}" -- \ 1001 bash -c "echo TEST | socat STDIN VSOCK-CONNECT:2:${port}" 2>&1 | log_guest 1002 1003 vm_dmesg_check "${pidfile}" "${ns0}" "${oops_before}" "${warn_before}" 1004 dmesg_rc=$? 1005 1006 terminate_pidfiles "${pidfile}" 1007 terminate_pids "${pid}" 1008 1009 result=$(cat "${outfile}") 1010 rm -f "${outfile}" 1011 1012 if [[ "${result}" != TEST ]] && [[ "${dmesg_rc}" -eq 0 ]]; then 1013 return "${KSFT_PASS}" 1014 fi 1015 1016 return "${KSFT_FAIL}" 1017} 1018 1019__test_loopback_two_netns() { 1020 local ns0=$1 1021 local ns1=$2 1022 local port=12345 1023 local result 1024 local pid 1025 1026 modprobe vsock_loopback &> /dev/null || : 1027 1028 log_host "Launching socat in ns ${ns1}" 1029 outfile=$(mktemp) 1030 1031 ip netns exec "${ns1}" socat VSOCK-LISTEN:"${port}" STDOUT > "${outfile}" 2>/dev/null & 1032 pid=$! 1033 host_wait_for_listener "${ns1}" "${port}" "vsock" 1034 1035 log_host "Launching socat in ns ${ns0}" 1036 echo TEST | ip netns exec "${ns0}" socat STDIN VSOCK-CONNECT:1:"${port}" 2>/dev/null 1037 terminate_pids "${pid}" 1038 1039 result=$(cat "${outfile}") 1040 rm -f "${outfile}" 1041 1042 if [[ "${result}" == TEST ]]; then 1043 return 0 1044 fi 1045 1046 return 1 1047} 1048 1049test_ns_diff_global_to_local_loopback_local_fails() { 1050 init_namespaces 1051 1052 if ! __test_loopback_two_netns "global0" "local0"; then 1053 return "${KSFT_PASS}" 1054 fi 1055 1056 return "${KSFT_FAIL}" 1057} 1058 1059test_ns_diff_local_to_global_loopback_fails() { 1060 init_namespaces 1061 1062 if ! __test_loopback_two_netns "local0" "global0"; then 1063 return "${KSFT_PASS}" 1064 fi 1065 1066 return "${KSFT_FAIL}" 1067} 1068 1069test_ns_diff_local_to_local_loopback_fails() { 1070 init_namespaces 1071 1072 if ! __test_loopback_two_netns "local0" "local1"; then 1073 return "${KSFT_PASS}" 1074 fi 1075 1076 return "${KSFT_FAIL}" 1077} 1078 1079test_ns_diff_global_to_global_loopback_ok() { 1080 init_namespaces 1081 1082 if __test_loopback_two_netns "global0" "global1"; then 1083 return "${KSFT_PASS}" 1084 fi 1085 1086 return "${KSFT_FAIL}" 1087} 1088 1089test_ns_same_local_loopback_ok() { 1090 init_namespaces 1091 1092 if __test_loopback_two_netns "local0" "local0"; then 1093 return "${KSFT_PASS}" 1094 fi 1095 1096 return "${KSFT_FAIL}" 1097} 1098 1099test_ns_same_local_host_connect_to_local_vm_ok() { 1100 local oops_before warn_before 1101 local ns="local0" 1102 local port=1234 1103 local dmesg_rc 1104 local pidfile 1105 local rc 1106 1107 init_namespaces 1108 1109 pidfile="$(create_pidfile)" 1110 1111 if ! vm_start "${pidfile}" "${ns}"; then 1112 return "${KSFT_FAIL}" 1113 fi 1114 1115 vm_wait_for_ssh "${ns}" 1116 oops_before=$(vm_dmesg_oops_count "${ns}") 1117 warn_before=$(vm_dmesg_warn_count "${ns}") 1118 1119 vm_vsock_test "${ns}" "server" 2 "${TEST_GUEST_PORT}" 1120 1121 # Skip test 29 (transport release use-after-free): This test attempts 1122 # binding both G2H and H2G CIDs. Because virtio-vsock (G2H) doesn't 1123 # support local namespaces the test will fail when 1124 # transport_g2h->stream_allow() returns false. This edge case only 1125 # happens for vsock_test in client mode on the host in a local 1126 # namespace. This is a false positive. 1127 host_vsock_test "${ns}" "127.0.0.1" "${VSOCK_CID}" "${TEST_HOST_PORT}" --skip=29 1128 rc=$? 1129 1130 vm_dmesg_check "${pidfile}" "${ns}" "${oops_before}" "${warn_before}" 1131 dmesg_rc=$? 1132 1133 terminate_pidfiles "${pidfile}" 1134 1135 if [[ "${rc}" -ne 0 ]] || [[ "${dmesg_rc}" -ne 0 ]]; then 1136 return "${KSFT_FAIL}" 1137 fi 1138 1139 return "${KSFT_PASS}" 1140} 1141 1142test_ns_same_local_vm_connect_to_local_host_ok() { 1143 local oops_before warn_before 1144 local ns="local0" 1145 local port=1234 1146 local dmesg_rc 1147 local pidfile 1148 local rc 1149 1150 init_namespaces 1151 1152 pidfile="$(create_pidfile)" 1153 1154 if ! vm_start "${pidfile}" "${ns}"; then 1155 return "${KSFT_FAIL}" 1156 fi 1157 1158 vm_wait_for_ssh "${ns}" 1159 oops_before=$(vm_dmesg_oops_count "${ns}") 1160 warn_before=$(vm_dmesg_warn_count "${ns}") 1161 1162 host_vsock_test "${ns}" "server" "${VSOCK_CID}" "${port}" 1163 vm_vsock_test "${ns}" "10.0.2.2" 2 "${port}" 1164 rc=$? 1165 1166 vm_dmesg_check "${pidfile}" "${ns}" "${oops_before}" "${warn_before}" 1167 dmesg_rc=$? 1168 1169 terminate_pidfiles "${pidfile}" 1170 1171 if [[ "${rc}" -ne 0 ]] || [[ "${dmesg_rc}" -ne 0 ]]; then 1172 return "${KSFT_FAIL}" 1173 fi 1174 1175 return "${KSFT_PASS}" 1176} 1177 1178namespaces_can_boot_same_cid() { 1179 local ns0=$1 1180 local ns1=$2 1181 local pidfile1 pidfile2 1182 local rc 1183 1184 pidfile1="$(create_pidfile)" 1185 1186 # The first VM should be able to start. If it can't then we have 1187 # problems and need to return non-zero. 1188 if ! vm_start "${pidfile1}" "${ns0}"; then 1189 return 1 1190 fi 1191 1192 pidfile2="$(create_pidfile)" 1193 vm_start "${pidfile2}" "${ns1}" 1194 rc=$? 1195 terminate_pidfiles "${pidfile1}" "${pidfile2}" 1196 1197 return "${rc}" 1198} 1199 1200test_ns_global_same_cid_fails() { 1201 init_namespaces 1202 1203 if namespaces_can_boot_same_cid "global0" "global1"; then 1204 return "${KSFT_FAIL}" 1205 fi 1206 1207 return "${KSFT_PASS}" 1208} 1209 1210test_ns_local_global_same_cid_ok() { 1211 init_namespaces 1212 1213 if namespaces_can_boot_same_cid "local0" "global0"; then 1214 return "${KSFT_PASS}" 1215 fi 1216 1217 return "${KSFT_FAIL}" 1218} 1219 1220test_ns_global_local_same_cid_ok() { 1221 init_namespaces 1222 1223 if namespaces_can_boot_same_cid "global0" "local0"; then 1224 return "${KSFT_PASS}" 1225 fi 1226 1227 return "${KSFT_FAIL}" 1228} 1229 1230test_ns_local_same_cid_ok() { 1231 init_namespaces 1232 1233 if namespaces_can_boot_same_cid "local0" "local1"; then 1234 return "${KSFT_PASS}" 1235 fi 1236 1237 return "${KSFT_FAIL}" 1238} 1239 1240test_ns_host_vsock_child_ns_mode_ok() { 1241 local rc="${KSFT_PASS}" 1242 1243 for mode in "${NS_MODES[@]}"; do 1244 local ns="${mode}0" 1245 1246 if echo "${mode}" 2>/dev/null > /proc/sys/net/vsock/ns_mode; then 1247 log_host "ns_mode should be read-only but write succeeded" 1248 rc="${KSFT_FAIL}" 1249 continue 1250 fi 1251 1252 if ! echo "${mode}" | ip netns exec "${ns}" \ 1253 tee /proc/sys/net/vsock/child_ns_mode &>/dev/null; then 1254 rc="${KSFT_FAIL}" 1255 continue 1256 fi 1257 done 1258 1259 return "${rc}" 1260} 1261 1262test_vm_server_host_client() { 1263 if ! vm_vsock_test "init_ns" "server" 2 "${TEST_GUEST_PORT}"; then 1264 return "${KSFT_FAIL}" 1265 fi 1266 1267 if ! host_vsock_test "init_ns" "127.0.0.1" "${VSOCK_CID}" "${TEST_HOST_PORT}"; then 1268 return "${KSFT_FAIL}" 1269 fi 1270 1271 return "${KSFT_PASS}" 1272} 1273 1274test_vm_client_host_server() { 1275 if ! host_vsock_test "init_ns" "server" "${VSOCK_CID}" "${TEST_HOST_PORT_LISTENER}"; then 1276 return "${KSFT_FAIL}" 1277 fi 1278 1279 if ! vm_vsock_test "init_ns" "10.0.2.2" 2 "${TEST_HOST_PORT_LISTENER}"; then 1280 return "${KSFT_FAIL}" 1281 fi 1282 1283 return "${KSFT_PASS}" 1284} 1285 1286test_vm_loopback() { 1287 local port=60000 # non-forwarded local port 1288 1289 vm_ssh "init_ns" -- modprobe vsock_loopback &> /dev/null || : 1290 1291 if ! vm_vsock_test "init_ns" "server" 1 "${port}"; then 1292 return "${KSFT_FAIL}" 1293 fi 1294 1295 1296 if ! vm_vsock_test "init_ns" "127.0.0.1" 1 "${port}"; then 1297 return "${KSFT_FAIL}" 1298 fi 1299 1300 return "${KSFT_PASS}" 1301} 1302 1303check_ns_delete_doesnt_break_connection() { 1304 local pipefile pidfile outfile 1305 local ns0="global0" 1306 local ns1="global1" 1307 local port=12345 1308 local pids=() 1309 local rc=0 1310 1311 init_namespaces 1312 1313 pidfile="$(create_pidfile)" 1314 if ! vm_start "${pidfile}" "${ns0}"; then 1315 return "${KSFT_FAIL}" 1316 fi 1317 vm_wait_for_ssh "${ns0}" 1318 1319 outfile=$(mktemp) 1320 vm_ssh "${ns0}" -- \ 1321 socat VSOCK-LISTEN:"${port}",fork STDOUT > "${outfile}" 2>/dev/null & 1322 pids+=($!) 1323 vm_wait_for_listener "${ns0}" "${port}" "vsock" 1324 1325 # We use a pipe here so that we can echo into the pipe instead of using 1326 # socat and a unix socket file. We just need a name for the pipe (not a 1327 # regular file) so use -u. 1328 pipefile=$(mktemp -u /tmp/vmtest_pipe_XXXX) 1329 ip netns exec "${ns1}" \ 1330 socat PIPE:"${pipefile}" VSOCK-CONNECT:"${VSOCK_CID}":"${port}" & 1331 pids+=($!) 1332 1333 timeout "${WAIT_PERIOD}" \ 1334 bash -c 'while [[ ! -e '"${pipefile}"' ]]; do sleep 1; done; exit 0' 1335 1336 if [[ "$1" == "vm" ]]; then 1337 ip netns del "${ns0}" 1338 elif [[ "$1" == "host" ]]; then 1339 ip netns del "${ns1}" 1340 elif [[ "$1" == "both" ]]; then 1341 ip netns del "${ns0}" 1342 ip netns del "${ns1}" 1343 fi 1344 1345 echo "TEST" > "${pipefile}" 1346 1347 timeout "${WAIT_PERIOD}" \ 1348 bash -c 'while [[ ! -s '"${outfile}"' ]]; do sleep 1; done; exit 0' 1349 1350 if grep -q "TEST" "${outfile}"; then 1351 rc="${KSFT_PASS}" 1352 else 1353 rc="${KSFT_FAIL}" 1354 fi 1355 1356 terminate_pidfiles "${pidfile}" 1357 terminate_pids "${pids[@]}" 1358 rm -f "${outfile}" "${pipefile}" 1359 1360 return "${rc}" 1361} 1362 1363test_ns_delete_vm_ok() { 1364 check_ns_delete_doesnt_break_connection "vm" 1365} 1366 1367test_ns_delete_host_ok() { 1368 check_ns_delete_doesnt_break_connection "host" 1369} 1370 1371test_ns_delete_both_ok() { 1372 check_ns_delete_doesnt_break_connection "both" 1373} 1374 1375shared_vm_test() { 1376 local tname 1377 1378 tname="${1}" 1379 1380 for testname in "${USE_SHARED_VM[@]}"; do 1381 if [[ "${tname}" == "${testname}" ]]; then 1382 return 0 1383 fi 1384 done 1385 1386 return 1 1387} 1388 1389shared_vm_tests_requested() { 1390 for arg in "$@"; do 1391 if shared_vm_test "${arg}"; then 1392 return 0 1393 fi 1394 done 1395 1396 return 1 1397} 1398 1399run_shared_vm_tests() { 1400 local arg 1401 1402 for arg in "$@"; do 1403 if ! shared_vm_test "${arg}"; then 1404 continue 1405 fi 1406 1407 if ! check_netns "${arg}"; then 1408 check_result "${KSFT_SKIP}" "${arg}" 1409 continue 1410 fi 1411 1412 run_shared_vm_test "${arg}" 1413 check_result "$?" "${arg}" 1414 done 1415} 1416 1417run_shared_vm_test() { 1418 local host_oops_cnt_before 1419 local host_warn_cnt_before 1420 local vm_oops_cnt_before 1421 local vm_warn_cnt_before 1422 local host_oops_cnt_after 1423 local host_warn_cnt_after 1424 local vm_oops_cnt_after 1425 local vm_warn_cnt_after 1426 local name 1427 local rc 1428 1429 host_oops_cnt_before=$(dmesg | grep -c -i 'Oops') 1430 host_warn_cnt_before=$(dmesg --level=warn | grep -c -i 'vsock') 1431 vm_oops_cnt_before=$(vm_dmesg_oops_count "init_ns") 1432 vm_warn_cnt_before=$(vm_dmesg_warn_count "init_ns") 1433 1434 name=$(echo "${1}" | awk '{ print $1 }') 1435 eval test_"${name}" 1436 rc=$? 1437 1438 host_oops_cnt_after=$(dmesg | grep -i 'Oops' | wc -l) 1439 if [[ ${host_oops_cnt_after} -gt ${host_oops_cnt_before} ]]; then 1440 echo "FAIL: kernel oops detected on host" | log_host 1441 rc=$KSFT_FAIL 1442 fi 1443 1444 host_warn_cnt_after=$(dmesg --level=warn | grep -c -i 'vsock') 1445 if [[ ${host_warn_cnt_after} -gt ${host_warn_cnt_before} ]]; then 1446 echo "FAIL: kernel warning detected on host" | log_host 1447 rc=$KSFT_FAIL 1448 fi 1449 1450 vm_oops_cnt_after=$(vm_dmesg_oops_count "init_ns") 1451 if [[ ${vm_oops_cnt_after} -gt ${vm_oops_cnt_before} ]]; then 1452 echo "FAIL: kernel oops detected on vm" | log_host 1453 rc=$KSFT_FAIL 1454 fi 1455 1456 vm_warn_cnt_after=$(vm_dmesg_warn_count "init_ns") 1457 if [[ ${vm_warn_cnt_after} -gt ${vm_warn_cnt_before} ]]; then 1458 echo "FAIL: kernel warning detected on vm" | log_host 1459 rc=$KSFT_FAIL 1460 fi 1461 1462 return "${rc}" 1463} 1464 1465run_ns_tests() { 1466 for arg in "${ARGS[@]}"; do 1467 if shared_vm_test "${arg}"; then 1468 continue 1469 fi 1470 1471 if ! check_netns "${arg}"; then 1472 check_result "${KSFT_SKIP}" "${arg}" 1473 continue 1474 fi 1475 1476 add_namespaces 1477 1478 name=$(echo "${arg}" | awk '{ print $1 }') 1479 log_host "Executing test_${name}" 1480 1481 host_oops_before=$(dmesg 2>/dev/null | grep -c -i 'Oops') 1482 host_warn_before=$(dmesg --level=warn 2>/dev/null | grep -c -i 'vsock') 1483 eval test_"${name}" 1484 rc=$? 1485 1486 host_oops_after=$(dmesg 2>/dev/null | grep -c -i 'Oops') 1487 if [[ "${host_oops_after}" -gt "${host_oops_before}" ]]; then 1488 echo "FAIL: kernel oops detected on host" | log_host 1489 check_result "${KSFT_FAIL}" "${name}" 1490 del_namespaces 1491 continue 1492 fi 1493 1494 host_warn_after=$(dmesg --level=warn 2>/dev/null | grep -c -i 'vsock') 1495 if [[ "${host_warn_after}" -gt "${host_warn_before}" ]]; then 1496 echo "FAIL: kernel warning detected on host" | log_host 1497 check_result "${KSFT_FAIL}" "${name}" 1498 del_namespaces 1499 continue 1500 fi 1501 1502 check_result "${rc}" "${name}" 1503 1504 del_namespaces 1505 done 1506} 1507 1508BUILD=0 1509QEMU="qemu-system-$(uname -m)" 1510 1511while getopts :hvsq:b o 1512do 1513 case $o in 1514 v) VERBOSE=1;; 1515 b) BUILD=1;; 1516 q) QEMU=$OPTARG;; 1517 h|*) usage;; 1518 esac 1519done 1520shift $((OPTIND-1)) 1521 1522trap cleanup EXIT 1523 1524if [[ ${#} -eq 0 ]]; then 1525 ARGS=("${TEST_NAMES[@]}") 1526else 1527 ARGS=("$@") 1528fi 1529 1530check_args "${ARGS[@]}" 1531check_deps 1532check_vng 1533check_socat 1534handle_build 1535 1536echo "1..${#ARGS[@]}" 1537 1538cnt_pass=0 1539cnt_fail=0 1540cnt_skip=0 1541cnt_total=0 1542 1543if shared_vm_tests_requested "${ARGS[@]}"; then 1544 log_host "Booting up VM" 1545 pidfile="$(create_pidfile)" 1546 vm_start "${pidfile}" "init_ns" 1547 vm_wait_for_ssh "init_ns" 1548 log_host "VM booted up" 1549 1550 run_shared_vm_tests "${ARGS[@]}" 1551 terminate_pidfiles "${pidfile}" 1552fi 1553 1554run_ns_tests "${ARGS[@]}" 1555 1556echo "SUMMARY: PASS=${cnt_pass} SKIP=${cnt_skip} FAIL=${cnt_fail}" 1557echo "Log: ${LOG}" 1558 1559if [ $((cnt_pass + cnt_skip)) -eq ${cnt_total} ]; then 1560 exit "$KSFT_PASS" 1561else 1562 exit "$KSFT_FAIL" 1563fi 1564