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