7bcc5930a6
A lot of tests and examples invoke qemu with the command "kvm". However, as far as I can tell, "kvm" being aliased to the appropriate qemu system binary is Debian specific. The binary names from qemu upstream - qemu-system-$ARCH - also aren't universal, but they are more common (they should be good for both Debian and Fedora at least). In order to still get KVM acceleration when available, we use the option "-M accel=kvm:tcg" to tell qemu to try using either KVM or TCG in that order A number of the places we invoked "kvm" are expecting specifically an x86 guest, and so it's also safer to explicitly invoke qemu-system-x86_64. Some others appear to be independent of the target arch (just wanting the same arch as the host to allow KVM acceleration). Although I suspect there may be more subtle x86 specific options in the qemu command lines, attempt to preserve arch independence by using $(uname -m). Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
405 lines
12 KiB
Bash
Executable file
405 lines
12 KiB
Bash
Executable file
#!/bin/sh
|
|
#
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
#
|
|
# PASST - Plug A Simple Socket Transport
|
|
# for qemu/UNIX domain socket mode
|
|
#
|
|
# PASTA - Pack A Subtle Tap Abstraction
|
|
# for network namespace/tap device mode
|
|
#
|
|
# test/lib/setup - Set up and tear down passt and pasta environments
|
|
#
|
|
# Copyright (c) 2021 Red Hat GmbH
|
|
# Author: Stefano Brivio <sbrivio@redhat.com>
|
|
|
|
VCPUS="$( [ $(nproc) -ge 8 ] && echo 6 || echo $(( $(nproc) / 2 + 1 )) )"
|
|
__mem_kib="$(sed -n 's/MemTotal:[ ]*\([0-9]*\) kB/\1/p' /proc/meminfo)"
|
|
VMEM="$((${__mem_kib} / 1024 / 4))"
|
|
|
|
# setup_build() - Set up pane layout for build tests
|
|
setup_build() {
|
|
MODE=build
|
|
|
|
layout_host
|
|
}
|
|
|
|
# setup_passt() - Build guest initrd with mbuto, start qemu and passt
|
|
setup_passt() {
|
|
MODE=passt
|
|
|
|
layout_passt
|
|
|
|
__mbuto_dir="$(mktemp -d)"
|
|
pane_run GUEST "git -C ${__mbuto_dir} clone git://mbuto.sh/mbuto"
|
|
pane_status GUEST
|
|
|
|
pane_run GUEST "${__mbuto_dir}/mbuto/mbuto -p test/passt.mbuto -c lz4 -f mbuto.img"
|
|
pane_status GUEST
|
|
|
|
rm -rf "${__mbuto_dir}"
|
|
|
|
# Ports:
|
|
#
|
|
# guest | host
|
|
# --------------|---------------------
|
|
# 10001 as server | forwarded to guest
|
|
# 10003 | as server
|
|
|
|
__opts=
|
|
[ ${PCAP} -eq 1 ] && __opts="${__opts} -p /tmp/passt.pcap"
|
|
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
|
|
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
|
|
|
|
pane_run PASST "make clean"
|
|
pane_status PASST
|
|
pane_run PASST "make valgrind"
|
|
pane_status PASST
|
|
pane_run PASST "valgrind --max-stackframe=$((4 * 1024 * 1024)) --trace-children=yes --vgdb=no --error-exitcode=1 --suppressions=test/valgrind.supp ./passt ${__opts} -f -t 10001 -u 10001 -P passt.pid"
|
|
sleep 5
|
|
|
|
pane_run GUEST './qrap 5 qemu-system-$(uname -m)' \
|
|
' -machine accel=kvm' \
|
|
' -m '${VMEM}' -cpu host -smp '${VCPUS} \
|
|
' -kernel ' "/boot/vmlinuz-$(uname -r)" \
|
|
' -initrd mbuto.img -nographic -serial stdio' \
|
|
' -nodefaults' \
|
|
' -append "console=ttyS0 mitigations=off apparmor=0 ' \
|
|
'virtio-net.napi_tx=1"' \
|
|
" -device virtio-net-pci,netdev=hostnet0,x-txburst=16384" \
|
|
" -netdev socket,fd=5,id=hostnet0"
|
|
pane_status GUEST
|
|
}
|
|
|
|
# setup_pasta() - Create a network and user namespace, connect pasta to it
|
|
setup_pasta() {
|
|
MODE=pasta
|
|
|
|
layout_pasta
|
|
|
|
pane_run NS 'echo $$'
|
|
pane_wait NS
|
|
__tty_pid="$(pane_parse NS)"
|
|
|
|
pane_run NS "unshare -rUnpf /bin/sh"
|
|
pane_status NS
|
|
|
|
pane_run PASST "pstree -p ${__tty_pid} | sed -n 's/.*(\([0-9].*\))$/\1/p'"
|
|
pane_wait PASST
|
|
__target_pid="$(pane_parse PASST)"
|
|
|
|
# Ports:
|
|
#
|
|
# ns | host
|
|
# ------------------|---------------------
|
|
# 10002 as server | spliced to ns
|
|
# 10003 spliced to init | as server
|
|
|
|
__opts=
|
|
[ ${PCAP} -eq 1 ] && __opts="${__opts} -p /tmp/pasta.pcap"
|
|
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
|
|
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
|
|
|
|
pane_run PASST "./pasta ${__opts} -f -t 10002 -T 10003 -u 10002 -U 10003 ${__target_pid}"
|
|
sleep 1
|
|
}
|
|
|
|
# setup_passt_in_ns() - Set up namespace (with pasta), run qemu and passt into it
|
|
setup_passt_in_ns() {
|
|
MODE=passt_in_ns
|
|
|
|
layout_passt_in_pasta
|
|
|
|
# Ports:
|
|
#
|
|
# guest | ns | host
|
|
# -------------|--------------------|-----------------
|
|
# 10001 as server | forwarded to guest | spliced to ns
|
|
# 10002 | as server | spliced to ns
|
|
# 10003 | spliced to init | as server
|
|
# 10011 as server | forwarded to guest | spliced to ns
|
|
# 10012 | as server | spliced to ns
|
|
# 10013 | spliced to init | as server
|
|
#
|
|
# 10021 as server | forwarded to guest |
|
|
# 10031 as server | forwarded to guest |
|
|
|
|
__opts=
|
|
[ ${PCAP} -eq 1 ] && __opts="${__opts} -p /tmp/pasta_with_passt.pcap"
|
|
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
|
|
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
|
|
|
|
__pid_file="$(mktemp)"
|
|
pane_run PASST "./pasta ${__opts} -t 10001,10002,10011,10012 -T 10003,10013 -u 10001,10002,10011,10012 -U 10003,10013 -P ${__pid_file}"
|
|
sleep 1
|
|
pane_run PASST ''
|
|
pane_status PASST
|
|
__pasta_pid="$(cat "${__pid_file}")"
|
|
__ns_pid="$(cat /proc/${__pasta_pid}/task/${__pasta_pid}/children | cut -f1 -d' ')"
|
|
rm "${__pid_file}"
|
|
|
|
pane_run GUEST "nsenter -t ${__ns_pid} -U -n --preserve-credentials"
|
|
pane_run NS "nsenter -t ${__ns_pid} -U -n -p --preserve-credentials"
|
|
pane_status GUEST
|
|
pane_status NS
|
|
|
|
pane_run NS "ip -j link show | jq -rM '.[] | select(.link_type == \"ether\").ifname'"
|
|
pane_wait NS
|
|
__ifname="$(pane_parse NS)"
|
|
pane_run NS "/sbin/dhclient -4 --no-pid ${__ifname}"
|
|
pane_status NS
|
|
sleep 2
|
|
pane_run NS "/sbin/dhclient -6 --no-pid ${__ifname}"
|
|
pane_status NS
|
|
|
|
__opts=
|
|
[ ${PCAP} -eq 1 ] && __opts="${__opts} -p /tmp/passt_in_pasta.pcap"
|
|
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
|
|
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
|
|
|
|
if [ ${VALGRIND} -eq 1 ]; then
|
|
pane_run PASST "make clean"
|
|
pane_status PASST
|
|
pane_run PASST "make valgrind"
|
|
pane_status PASST
|
|
pane_run PASST "valgrind --max-stackframe=$((4 * 1024 * 1024)) --trace-children=yes --vgdb=no --error-exitcode=1 --suppressions=test/valgrind.supp ./passt -f ${__opts} -t 10001,10011,10021,10031 -u 10001,10011,10021,10031 -P passt.pid"
|
|
else
|
|
pane_run PASST "make clean"
|
|
pane_status PASST
|
|
pane_run PASST "make"
|
|
pane_status PASST
|
|
pane_run PASST "./passt -f ${__opts} -t 10001,10011,10021,10031 -u 10001,10011,10021,10031 -P passt.pid"
|
|
fi
|
|
sleep 5
|
|
|
|
pane_run GUEST './qrap 5 qemu-system-$(uname -m)' \
|
|
' -machine accel=kvm' \
|
|
' -M accel=kvm:tcg' \
|
|
' -m '${VMEM}' -cpu host -smp '${VCPUS} \
|
|
' -kernel ' "/boot/vmlinuz-$(uname -r)" \
|
|
' -initrd mbuto.img -nographic -serial stdio' \
|
|
' -nodefaults' \
|
|
' -append "console=ttyS0 mitigations=off apparmor=0 ' \
|
|
'virtio-net.napi_tx=1"' \
|
|
" -device virtio-net-pci,netdev=hostnet0,x-txburst=524288" \
|
|
" -netdev socket,fd=5,id=hostnet0"
|
|
pane_status GUEST
|
|
}
|
|
|
|
# setup_two_guests() - Set up two namespace, run qemu and passt in both of them
|
|
setup_two_guests() {
|
|
MODE=passt_in_ns
|
|
|
|
layout_two_guests
|
|
|
|
# Ports:
|
|
#
|
|
# guest #1 | guest #2 | ns #1 | ns #2 | host
|
|
# --------- |-----------|-----------|------------|------------
|
|
# 10001 as server | | to guest | to init | to ns #1
|
|
# 10002 | | as server | | to ns #1
|
|
# 10003 | | to init | to init | as server
|
|
# 10004 | as server | to init | to guest | to ns #2
|
|
# 10005 | | | as server | to ns #2
|
|
|
|
__pid1_file="$(mktemp)"
|
|
__pid2_file="$(mktemp)"
|
|
|
|
__opts=
|
|
[ ${PCAP} -eq 1 ] && __opts="${__opts} -p /tmp/pasta_1.pcap"
|
|
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
|
|
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
|
|
pane_run PASST_1 "./pasta ${__opts} -P ${__pid1_file} -t 10001,10002 -T 10003,10004 -u 10001,10002 -U 10003,10004"
|
|
|
|
__opts=
|
|
[ ${PCAP} -eq 1 ] && __opts="${__opts} -p /tmp/pasta_2.pcap"
|
|
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
|
|
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
|
|
pane_run PASST_2 "./pasta ${__opts} -P ${__pid2_file} -t 10004,10005 -T 10003,10001 -u 10004,10005 -U 10003,10001"
|
|
|
|
sleep 1
|
|
pane_run PASST_1 ''
|
|
pane_run PASST_2 ''
|
|
|
|
pane_status PASST_1
|
|
pane_status PASST_2
|
|
__pasta1_pid="$(cat "${__pid1_file}")"
|
|
__ns1_pid="$(cat /proc/${__pasta1_pid}/task/${__pasta1_pid}/children | cut -f1 -d' ')"
|
|
rm "${__pid1_file}"
|
|
__pasta2_pid="$(cat "${__pid2_file}")"
|
|
__ns2_pid="$(cat /proc/${__pasta2_pid}/task/${__pasta2_pid}/children | cut -f1 -d' ')"
|
|
rm "${__pid2_file}"
|
|
|
|
pane_run GUEST_1 "nsenter -t ${__ns1_pid} -U -n --preserve-credentials"
|
|
pane_run GUEST_2 "nsenter -t ${__ns2_pid} -U -n --preserve-credentials"
|
|
|
|
pane_run PASST_1 "ip -j link show | jq -rM '.[] | select(.link_type == \"ether\").ifname'"
|
|
pane_wait PASST_1
|
|
__ifname="$(pane_parse PASST_1)"
|
|
|
|
pane_run GUEST_1 "/sbin/dhclient -4 ${__ifname}"
|
|
pane_run GUEST_2 "/sbin/dhclient -4 ${__ifname}"
|
|
pane_status GUEST_1
|
|
pane_status GUEST_2
|
|
sleep 2
|
|
pane_run GUEST_1 "/sbin/dhclient -6 ${__ifname}"
|
|
pane_run GUEST_2 "/sbin/dhclient -6 ${__ifname}"
|
|
pane_status GUEST_1
|
|
pane_status GUEST_2
|
|
|
|
__opts=
|
|
[ ${PCAP} -eq 1 ] && __opts="${__opts} -p /tmp/passt_1.pcap"
|
|
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
|
|
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
|
|
|
|
pane_run PASST_1 "./passt -f ${__opts} -t 10001 -u 10001"
|
|
sleep 1
|
|
|
|
__opts=
|
|
[ ${PCAP} -eq 1 ] && __opts="${__opts} -p /tmp/passt_2.pcap"
|
|
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
|
|
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
|
|
pane_run PASST_2 "./passt -f ${__opts} -t 10004 -u 10004"
|
|
|
|
pane_run GUEST_2 'cp mbuto.img mbuto_2.img'
|
|
pane_status GUEST_2
|
|
|
|
pane_run GUEST_1 './qrap 5 qemu-system-$(uname -m)' \
|
|
' -M accel=kvm:tcg' \
|
|
' -m '${VMEM}' -cpu host -smp '${VCPUS} \
|
|
' -kernel ' "/boot/vmlinuz-$(uname -r)" \
|
|
' -initrd mbuto.img -nographic -serial stdio' \
|
|
' -nodefaults' \
|
|
' -append "console=ttyS0 mitigations=off apparmor=0 ' \
|
|
'virtio-net.napi_tx=1"' \
|
|
" -device virtio-net-pci,netdev=hostnet0,x-txburst=16384" \
|
|
" -netdev socket,fd=5,id=hostnet0"
|
|
pane_run GUEST_2 './qrap 5 qemu-system-$(uname -m)' \
|
|
' -M accel=kvm:tcg' \
|
|
' -m '${VMEM}' -cpu host -smp '${VCPUS} \
|
|
' -kernel ' "/boot/vmlinuz-$(uname -r)" \
|
|
' -initrd mbuto_2.img -nographic -serial stdio' \
|
|
' -nodefaults' \
|
|
' -append "console=ttyS0 mitigations=off apparmor=0 ' \
|
|
'virtio-net.napi_tx=1"' \
|
|
" -device virtio-net-pci,netdev=hostnet0,x-txburst=16384" \
|
|
" -netdev socket,fd=5,id=hostnet0"
|
|
pane_status GUEST_1
|
|
pane_status GUEST_2
|
|
}
|
|
|
|
# teardown_passt() - Kill qemu, remove passt PID file
|
|
teardown_passt() {
|
|
tmux send-keys -t ${PANE_GUEST} "C-c"
|
|
pane_wait GUEST
|
|
rm passt.pid
|
|
}
|
|
|
|
# teardown_passt() - Exit namespace, kill pasta process
|
|
teardown_pasta() {
|
|
tmux send-keys -t ${PANE_PASST} "C-c"
|
|
pane_wait PASST
|
|
tmux send-keys -t ${PANE_NS} "C-d"
|
|
pane_wait NS
|
|
}
|
|
|
|
# teardown_passt_in_ns() - Exit namespace, kill qemu and pasta, remove pid file
|
|
teardown_passt_in_ns() {
|
|
tmux send-keys -t ${PANE_GUEST} "C-c"
|
|
pane_wait GUEST
|
|
tmux send-keys -t ${PANE_GUEST} "C-d"
|
|
|
|
[ ${VALGRIND} -eq 0 ] && tmux send-keys -t ${PANE_PASST} "C-c"
|
|
[ ${VALGRIND} -eq 0 ] && pane_status GUEST
|
|
tmux send-keys -t ${PANE_PASST} "C-d"
|
|
|
|
tmux send-keys -t ${PANE_NS} "C-d"
|
|
|
|
pane_wait GUEST
|
|
pane_wait NS
|
|
pane_wait PASST
|
|
|
|
rm passt.pid
|
|
}
|
|
|
|
# teardown_two_guests() - Exit namespaces, kill qemu processes, passt and pasta
|
|
teardown_two_guests() {
|
|
tmux send-keys -t ${PANE_GUEST_1} "C-c"
|
|
pane_wait GUEST_1
|
|
tmux send-keys -t ${PANE_GUEST_1} "C-d"
|
|
|
|
tmux send-keys -t ${PANE_GUEST_2} "C-c"
|
|
pane_wait GUEST_2
|
|
tmux send-keys -t ${PANE_GUEST_2} "C-d"
|
|
|
|
tmux send-keys -t ${PANE_PASST_1} "C-c"
|
|
pane_wait PASST_1
|
|
tmux send-keys -t ${PANE_PASST_1} "C-d"
|
|
|
|
tmux send-keys -t ${PANE_PASST_2} "C-c"
|
|
pane_wait PASST_2
|
|
tmux send-keys -t ${PANE_PASST_2} "C-d"
|
|
|
|
pane_wait GUEST_1
|
|
pane_wait GUEST_2
|
|
pane_wait PASST_1
|
|
pane_wait PASST_2
|
|
}
|
|
|
|
# teardown_demo_passt() - Exit namespace, kill qemu, passt and pasta
|
|
teardown_demo_passt() {
|
|
tmux send-keys -t ${PANE_GUEST} "C-c"
|
|
pane_wait GUEST
|
|
tmux send-keys -t ${PANE_GUEST} "C-d"
|
|
|
|
tmux send-keys -t ${PANE_HOST} "C-d"
|
|
|
|
tmux send-keys -t ${PANE_PASST} "C-c"
|
|
pane_wait PASST
|
|
tmux send-keys -t ${PANE_PASST} "C-d"
|
|
|
|
pane_wait GUEST
|
|
pane_wait HOST
|
|
pane_wait PASST
|
|
|
|
tmux kill-pane -a -t 0
|
|
tmux send-keys -t 0 "C-c"
|
|
}
|
|
|
|
# teardown_demo_pasta() - Exit perf and namespace from remaining pane
|
|
teardown_demo_pasta() {
|
|
tmux send-keys -t ${PANE_NS} "q"
|
|
pane_wait NS
|
|
tmux send-keys -t ${PANE_NS} "C-d"
|
|
pane_wait NS
|
|
|
|
tmux kill-pane -a -t 0
|
|
tmux send-keys -t 0 "C-c"
|
|
}
|
|
|
|
# teardown_demo_podman() - Exit namespaces
|
|
teardown_demo_podman() {
|
|
tmux send-keys -t ${PANE_NS1} "C-d"
|
|
tmux send-keys -t ${PANE_NS2} "C-d"
|
|
pane_wait NS1
|
|
pane_wait NS2
|
|
|
|
tmux kill-pane -a -t 0
|
|
tmux send-keys -t 0 "C-c"
|
|
}
|
|
|
|
# setup() - Run setup_*() functions
|
|
# $*: Suffix list of setup_*() functions to be called
|
|
setup() {
|
|
for arg do
|
|
eval setup_${arg}
|
|
done
|
|
}
|
|
|
|
# teardown() - Run teardown_*() functions
|
|
# $*: Suffix list of teardown_*() functions to be called
|
|
teardown() {
|
|
for arg do
|
|
eval teardown_${arg}
|
|
done
|
|
}
|