vmtest.sh 34 KB

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