aboutgitcodebugslistschat
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/.gitignore1
-rw-r--r--test/Makefile15
-rw-r--r--test/README.md9
-rw-r--r--test/lib/layout69
-rwxr-xr-xtest/lib/perf_report15
-rwxr-xr-xtest/lib/setup250
-rwxr-xr-xtest/lib/setup_ugly2
-rwxr-xr-xtest/lib/term48
-rwxr-xr-xtest/lib/test57
-rw-r--r--test/migrate/basic59
-rw-r--r--test/migrate/basic_fin62
-rw-r--r--test/migrate/bidirectional64
-rw-r--r--test/migrate/bidirectional_fin64
-rw-r--r--test/migrate/iperf3_bidir658
-rw-r--r--test/migrate/iperf3_in450
-rw-r--r--test/migrate/iperf3_in658
-rw-r--r--test/migrate/iperf3_many_out660
-rw-r--r--test/migrate/iperf3_out447
-rw-r--r--test/migrate/iperf3_out658
-rw-r--r--test/migrate/rampstream_in59
-rw-r--r--test/migrate/rampstream_out55
-rw-r--r--test/nstool.c40
-rwxr-xr-xtest/passt.mbuto20
-rw-r--r--test/passt/dhcp17
-rw-r--r--test/passt/ndp8
-rw-r--r--test/passt_in_ns/dhcp75
-rw-r--r--test/passt_in_ns/tcp46
-rw-r--r--test/passt_in_ns/udp26
l---------test/passt_vu1
l---------test/passt_vu_in_ns1
-rw-r--r--test/pasta/dhcp2
-rw-r--r--test/pasta/ndp7
-rw-r--r--test/pasta/tcp16
-rw-r--r--test/pasta/udp8
-rw-r--r--test/pasta_options/log_to_file4
-rw-r--r--test/pasta_podman/bats2
-rw-r--r--test/perf/passt_tcp49
-rw-r--r--test/perf/passt_udp33
-rw-r--r--test/perf/passt_vu_tcp211
-rw-r--r--test/perf/passt_vu_udp159
-rw-r--r--test/perf/pasta_tcp57
-rw-r--r--test/perf/pasta_udp29
-rwxr-xr-xtest/rampstream-check.sh3
-rw-r--r--test/rampstream.c143
-rwxr-xr-xtest/run80
-rw-r--r--test/two_guests/basic14
l---------test/two_guests_vu1
-rw-r--r--test/valgrind.supp9
48 files changed, 1974 insertions, 247 deletions
diff --git a/test/.gitignore b/test/.gitignore
index 6dd4790..3573444 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -8,5 +8,6 @@ QEMU_EFI.fd
*.raw.xz
*.bin
nstool
+rampstream
guest-key
guest-key.pub
diff --git a/test/Makefile b/test/Makefile
index 35a3b55..bf63db8 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -8,7 +8,6 @@
WGET = wget -c
DEBIAN_IMGS = debian-8.11.0-openstack-amd64.qcow2 \
- debian-9-nocloud-amd64-daily-20200210-166.qcow2 \
debian-10-nocloud-amd64.qcow2 \
debian-10-generic-arm64.qcow2 \
debian-10-generic-ppc64el-20220911-1135.qcow2 \
@@ -42,8 +41,7 @@ OPENSUSE_IMGS = openSUSE-Leap-15.1-JeOS.x86_64-kvm-and-xen.qcow2 \
openSUSE-Leap-15.2-JeOS.x86_64-kvm-and-xen.qcow2 \
openSUSE-Leap-15.3-JeOS.x86_64-kvm-and-xen.qcow2 \
openSUSE-Tumbleweed-ARM-JeOS-efi.aarch64.raw.xz \
- openSUSE-Tumbleweed-ARM-JeOS-efi.armv7l.raw.xz \
- openSUSE-Tumbleweed-JeOS.x86_64-kvm-and-xen.qcow2
+ openSUSE-Tumbleweed-ARM-JeOS-efi.armv7l.raw.xz
UBUNTU_OLD_IMGS = trusty-server-cloudimg-amd64-disk1.img \
trusty-server-cloudimg-i386-disk1.img \
@@ -54,7 +52,8 @@ UBUNTU_IMGS = $(UBUNTU_OLD_IMGS) $(UBUNTU_NEW_IMGS)
DOWNLOAD_ASSETS = mbuto podman \
$(DEBIAN_IMGS) $(FEDORA_IMGS) $(OPENSUSE_IMGS) $(UBUNTU_IMGS)
-TESTDATA_ASSETS = small.bin big.bin medium.bin
+TESTDATA_ASSETS = small.bin big.bin medium.bin \
+ rampstream
LOCAL_ASSETS = mbuto.img mbuto.mem.img podman/bin/podman QEMU_EFI.fd \
$(DEBIAN_IMGS:%=prepared-%) $(FEDORA_IMGS:%=prepared-%) \
$(UBUNTU_NEW_IMGS:%=prepared-%) \
@@ -87,7 +86,7 @@ podman/bin/podman: pull-podman
guest-key guest-key.pub:
ssh-keygen -f guest-key -N ''
-mbuto.img: passt.mbuto mbuto/mbuto guest-key.pub $(TESTDATA_ASSETS)
+mbuto.img: passt.mbuto mbuto/mbuto guest-key.pub rampstream-check.sh $(TESTDATA_ASSETS)
./mbuto/mbuto -p ./$< -c lz4 -f $@
mbuto.mem.img: passt.mem.mbuto mbuto ../passt.avx2
@@ -135,9 +134,6 @@ realclean: clean
debian-8.11.0-openstack-%.qcow2:
$(WGET) -O $@ https://cloud.debian.org/images/cloud/OpenStack/archive/8.11.0/debian-8.11.0-openstack-$*.qcow2
-debian-9-nocloud-%-daily-20200210-166.qcow2:
- $(WGET) -O $@ https://cloud.debian.org/images/cloud/stretch/daily/20200210-166/debian-9-nocloud-$*-daily-20200210-166.qcow2
-
debian-10-nocloud-%.qcow2:
$(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/latest/debian-10-nocloud-$*.qcow2
@@ -203,9 +199,6 @@ openSUSE-Tumbleweed-ARM-JeOS-efi.aarch64.raw.xz:
openSUSE-Tumbleweed-ARM-JeOS-efi.armv7l.raw.xz:
$(WGET) -O $@ http://download.opensuse.org/ports/armv7hl/tumbleweed/appliances/openSUSE-Tumbleweed-ARM-JeOS-efi.armv7l.raw.xz
-openSUSE-Tumbleweed-JeOS.x86_64-kvm-and-xen.qcow2:
- $(WGET) -O $@ https://download.opensuse.org/tumbleweed/appliances/openSUSE-Tumbleweed-JeOS.x86_64-kvm-and-xen.qcow2
-
# Ubuntu downloads
trusty-server-cloudimg-%-disk1.img:
$(WGET) -O $@ https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-$*-disk1.img
diff --git a/test/README.md b/test/README.md
index 0936b04..91ca603 100644
--- a/test/README.md
+++ b/test/README.md
@@ -28,10 +28,11 @@ on a system, i.e. common utilities such as a shell are not included here.
Example for Debian, and possibly most Debian-based distributions:
- build-essential git jq strace iperf3 qemu-system-x86 tmux sipcalc bats bc
- catatonit clang-tidy cppcheck go isc-dhcp-common psmisc linux-cpupower socat
- netcat-openbsd fakeroot lz4 lm-sensors qemu-system-arm qemu-system-ppc
- qemu-system-misc qemu-system-x86 valgrind
+ bats bc build-essential catatonit clang-tidy conmon cppcheck crun fakeroot
+ git go iperf3 isc-dhcp-common jq libgpgme-dev libseccomp-dev linux-cpupower
+ lm-sensors lz4 netavark netcat-openbsd psmisc qemu-efi-aarch64
+ qemu-system-arm qemu-system-misc qemu-system-ppc qemu-system-x86
+ qemu-system-x86 sipcalc socat strace tmux uidmap valgrind
NOTE: the tests need a qemu version >= 7.2, or one that contains commit
13c6be96618c ("net: stream: add unix socket"): this change introduces support
diff --git a/test/lib/layout b/test/lib/layout
index f9a1cf1..fddcdc4 100644
--- a/test/lib/layout
+++ b/test/lib/layout
@@ -15,7 +15,7 @@
# layout_pasta() - Panes for host, pasta, and separate one for namespace
layout_pasta() {
- sleep 3
+ sleep 1
tmux kill-pane -a -t 0
cmd_write 0 clear
@@ -46,7 +46,7 @@ layout_pasta() {
# layout_passt() - Panes for host, passt, and guest
layout_passt() {
- sleep 3
+ sleep 1
tmux kill-pane -a -t 0
cmd_write 0 clear
@@ -77,7 +77,7 @@ layout_passt() {
# layout_passt_in_pasta() - Host, passt within pasta, namespace and guest
layout_passt_in_pasta() {
- sleep 3
+ sleep 1
tmux kill-pane -a -t 0
cmd_write 0 clear
@@ -113,7 +113,7 @@ layout_passt_in_pasta() {
# layout_two_guests() - Two guest panes, two passt panes, plus host and log
layout_two_guests() {
- sleep 3
+ sleep 1
tmux kill-pane -a -t 0
cmd_write 0 clear
@@ -135,24 +135,77 @@ layout_two_guests() {
get_info_cols
pane_watch_contexts ${PANE_GUEST_1} "guest #1 in namespace #1" qemu_1 guest_1
+ pane_watch_contexts ${PANE_GUEST_2} "guest #2 in namespace #1" qemu_2 guest_2
+
+ tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done'
+ tmux send-keys -t ${PANE_INFO} -N 100 C-m
+ tmux select-pane -t ${PANE_INFO} -T "test log"
+
+ pane_watch_contexts ${PANE_HOST} host host
+ pane_watch_contexts ${PANE_PASST_1} "passt #1 in namespace #1" pasta_1 passt_1
+ pane_watch_contexts ${PANE_PASST_2} "passt #2 in namespace #1" pasta_1 passt_2
+
+ info_layout "two guests, two passt instances, in namespaces"
+
+ sleep 1
+}
+
+# layout_migrate() - Two guest panes, two passt panes, two passt-repair panes,
+# plus host and log
+layout_migrate() {
+ sleep 1
+
+ tmux kill-pane -a -t 0
+ cmd_write 0 clear
+
+ tmux split-window -v -t passt_test
+ tmux split-window -h -l '33%'
+ tmux split-window -h -t passt_test:1.1
+
+ tmux split-window -h -l '35%' -t passt_test:1.0
+ tmux split-window -v -t passt_test:1.0
+
+ tmux split-window -v -t passt_test:1.4
+ tmux split-window -v -t passt_test:1.6
+
+ tmux split-window -v -t passt_test:1.3
+
+ PANE_GUEST_1=0
+ PANE_GUEST_2=1
+ PANE_INFO=2
+ PANE_MON=3
+ PANE_HOST=4
+ PANE_PASST_REPAIR_1=5
+ PANE_PASST_1=6
+ PANE_PASST_REPAIR_2=7
+ PANE_PASST_2=8
+
+ get_info_cols
+
+ pane_watch_contexts ${PANE_GUEST_1} "guest #1 in namespace #1" qemu_1 guest_1
pane_watch_contexts ${PANE_GUEST_2} "guest #2 in namespace #2" qemu_2 guest_2
tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done'
tmux send-keys -t ${PANE_INFO} -N 100 C-m
tmux select-pane -t ${PANE_INFO} -T "test log"
+ pane_watch_contexts ${PANE_MON} "QEMU monitor" mon mon
+
pane_watch_contexts ${PANE_HOST} host host
+ pane_watch_contexts ${PANE_PASST_REPAIR_1} "passt-repair #1 in namespace #1" repair_1 passt_repair_1
pane_watch_contexts ${PANE_PASST_1} "passt #1 in namespace #1" pasta_1 passt_1
+
+ pane_watch_contexts ${PANE_PASST_REPAIR_2} "passt-repair #2 in namespace #2" repair_2 passt_repair_2
pane_watch_contexts ${PANE_PASST_2} "passt #2 in namespace #2" pasta_2 passt_2
- info_layout "two guests, two passt instances, in namespaces"
+ info_layout "two guests, two passt + passt-repair instances, in namespaces"
sleep 1
}
# layout_demo_pasta() - Four panes for pasta demo
layout_demo_pasta() {
- sleep 3
+ sleep 1
cmd_write 0 cd ${BASEPATH}
cmd_write 0 clear
@@ -188,7 +241,7 @@ layout_demo_pasta() {
# layout_demo_passt() - Four panes for passt demo
layout_demo_passt() {
- sleep 3
+ sleep 1
cmd_write 0 cd ${BASEPATH}
cmd_write 0 clear
@@ -224,7 +277,7 @@ layout_demo_passt() {
# layout_demo_podman() - Four panes for pasta demo with Podman
layout_demo_podman() {
- sleep 3
+ sleep 1
cmd_write 0 cd ${BASEPATH}
cmd_write 0 clear
diff --git a/test/lib/perf_report b/test/lib/perf_report
index d1ef50b..c4ec817 100755
--- a/test/lib/perf_report
+++ b/test/lib/perf_report
@@ -49,6 +49,21 @@ td:empty { visibility: hidden; }
__passt_tcp_LINE__ __passt_udp_LINE__
</table>
+</li><li><p>passt with vhost-user support</p>
+<table class="passt" width="70%">
+ <tr>
+ <th/>
+ <th id="perf_passt_vu_tcp" colspan="__passt_vu_tcp_cols__">TCP, __passt_vu_tcp_threads__ at __passt_vu_tcp_freq__ GHz</th>
+ <th id="perf_passt_vu_udp" colspan="__passt_vu_udp_cols__">UDP, __passt_vu_udp_threads__ at __passt_vu_udp_freq__ GHz</th>
+ </tr>
+ <tr>
+ <td align="right">MTU:</td>
+ __passt_vu_tcp_header__
+ __passt_vu_udp_header__
+ </tr>
+ __passt_vu_tcp_LINE__ __passt_vu_udp_LINE__
+</table>
+
<style type="text/CSS">
table.pasta_local td { border: 0px solid; padding: 6px; line-height: 1; }
table.pasta_local td { text-align: right; }
diff --git a/test/lib/setup b/test/lib/setup
index 9b39b9f..575bc21 100755
--- a/test/lib/setup
+++ b/test/lib/setup
@@ -15,8 +15,9 @@
INITRAMFS="${BASEPATH}/mbuto.img"
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))"
+MEM_KIB="$(sed -n 's/MemTotal:[ ]*\([0-9]*\) kB/\1/p' /proc/meminfo)"
+QEMU_ARCH="$(uname -m)"
+[ "${QEMU_ARCH}" = "i686" ] && QEMU_ARCH=i386
# setup_build() - Set up pane layout for build tests
setup_build() {
@@ -44,24 +45,38 @@ setup_passt() {
[ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt.pcap"
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
+ [ ${VHOST_USER} -eq 1 ] && __opts="${__opts} --vhost-user"
context_run passt "make clean"
context_run passt "make valgrind"
- context_run_bg passt "valgrind --max-stackframe=$((4 * 1024 * 1024)) --trace-children=yes --vgdb=no --error-exitcode=1 --suppressions=test/valgrind.supp ./passt ${__opts} -s ${STATESETUP}/passt.socket -f -t 10001 -u 10001 -P ${STATESETUP}/passt.pid"
+ context_run_bg passt "valgrind --max-stackframe=$((4 * 1024 * 1024)) --trace-children=yes --vgdb=no --error-exitcode=1 --suppressions=test/valgrind.supp ./passt ${__opts} -s ${STATESETUP}/passt.socket -f -t 10001 -u 10001 -H hostname1 --fqdn fqdn1.passt.test -P ${STATESETUP}/passt.pid"
# pidfile isn't created until passt is listening
wait_for [ -f "${STATESETUP}/passt.pid" ]
+ __vmem="$((${MEM_KIB} / 1024 / 4))"
+ if [ ${VHOST_USER} -eq 1 ]; then
+ __vmem="$(((${__vmem} + 500) / 1000))G"
+ __qemu_netdev=" \
+ -chardev socket,id=c,path=${STATESETUP}/passt.socket \
+ -netdev vhost-user,id=v,chardev=c \
+ -device virtio-net,netdev=v \
+ -object memory-backend-memfd,id=m,share=on,size=${__vmem} \
+ -numa node,memdev=m"
+ else
+ __qemu_netdev="-device virtio-net-pci,netdev=s \
+ -netdev stream,id=s,server=off,addr.type=unix,addr.path=${STATESETUP}/passt.socket"
+ fi
+
GUEST_CID=94557
- context_run_bg qemu 'qemu-system-$(uname -m)' \
+ context_run_bg qemu 'qemu-system-'"${QEMU_ARCH}" \
' -machine accel=kvm' \
- ' -m '${VMEM}' -cpu host -smp '${VCPUS} \
- ' -kernel ' "/boot/vmlinuz-$(uname -r)" \
+ ' -m '${__vmem}' -cpu host -smp '${VCPUS} \
+ ' -kernel '"${KERNEL}" \
' -initrd '${INITRAMFS}' -nographic -serial stdio' \
' -nodefaults' \
' -append "console=ttyS0 mitigations=off apparmor=0" ' \
- ' -device virtio-net-pci,netdev=s0 ' \
- " -netdev stream,id=s0,server=off,addr.type=unix,addr.path=${STATESETUP}/passt.socket " \
+ " ${__qemu_netdev}" \
" -pidfile ${STATESETUP}/qemu.pid" \
" -device vhost-vsock-pci,guest-cid=$GUEST_CID"
@@ -124,7 +139,12 @@ setup_passt_in_ns() {
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
- context_run_bg pasta "./pasta ${__opts} -t 10001,10002,10011,10012 -T 10003,10013 -u 10001,10002,10011,10012 -U 10003,10013 -P ${STATESETUP}/pasta.pid --config-net ${NSTOOL} hold ${STATESETUP}/ns.hold"
+ __map_host4=192.0.2.1
+ __map_host6=2001:db8:9a55::1
+ __map_ns4=192.0.2.2
+ __map_ns6=2001:db8:9a55::2
+
+ context_run_bg pasta "./pasta ${__opts} -t 10001,10002,10011,10012 -T 10003,10013 -u 10001,10002,10011,10012 -U 10003,10013 -P ${STATESETUP}/pasta.pid --map-host-loopback ${__map_host4} --map-host-loopback ${__map_host6} --config-net ${NSTOOL} hold ${STATESETUP}/ns.hold"
wait_for [ -f "${STATESETUP}/pasta.pid" ]
context_setup_nstool qemu ${STATESETUP}/ns.hold
@@ -135,29 +155,43 @@ setup_passt_in_ns() {
[ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt_in_pasta.pcap"
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
+ [ ${VHOST_USER} -eq 1 ] && __opts="${__opts} --vhost-user"
if [ ${VALGRIND} -eq 1 ]; then
context_run passt "make clean"
context_run passt "make valgrind"
- context_run_bg passt "valgrind --max-stackframe=$((4 * 1024 * 1024)) --trace-children=yes --vgdb=no --error-exitcode=1 --suppressions=test/valgrind.supp ./passt -f ${__opts} -s ${STATESETUP}/passt.socket -t 10001,10011,10021,10031 -u 10001,10011,10021,10031 -P ${STATESETUP}/passt.pid"
+ context_run_bg passt "valgrind --max-stackframe=$((4 * 1024 * 1024)) --trace-children=yes --vgdb=no --error-exitcode=1 --suppressions=test/valgrind.supp ./passt -f ${__opts} -s ${STATESETUP}/passt.socket -H hostname1 --fqdn fqdn1.passt.test -t 10001,10011,10021,10031 -u 10001,10011,10021,10031 -P ${STATESETUP}/passt.pid --map-host-loopback ${__map_ns4} --map-host-loopback ${__map_ns6}"
else
context_run passt "make clean"
context_run passt "make"
- context_run_bg passt "./passt -f ${__opts} -s ${STATESETUP}/passt.socket -t 10001,10011,10021,10031 -u 10001,10011,10021,10031 -P ${STATESETUP}/passt.pid"
+ context_run_bg passt "./passt -f ${__opts} -s ${STATESETUP}/passt.socket -H hostname1 --fqdn fqdn1.passt.test -t 10001,10011,10021,10031 -u 10001,10011,10021,10031 -P ${STATESETUP}/passt.pid --map-host-loopback ${__map_ns4} --map-host-loopback ${__map_ns6}"
fi
wait_for [ -f "${STATESETUP}/passt.pid" ]
+ __vmem="$((${MEM_KIB} / 1024 / 4))"
+ if [ ${VHOST_USER} -eq 1 ]; then
+ __vmem="$(((${__vmem} + 500) / 1000))G"
+ __qemu_netdev=" \
+ -chardev socket,id=c,path=${STATESETUP}/passt.socket \
+ -netdev vhost-user,id=v,chardev=c \
+ -device virtio-net,netdev=v \
+ -object memory-backend-memfd,id=m,share=on,size=${__vmem} \
+ -numa node,memdev=m"
+ else
+ __qemu_netdev="-device virtio-net-pci,netdev=s \
+ -netdev stream,id=s,server=off,addr.type=unix,addr.path=${STATESETUP}/passt.socket"
+ fi
+
GUEST_CID=94557
- context_run_bg qemu 'qemu-system-$(uname -m)' \
+ context_run_bg qemu 'qemu-system-'"${QEMU_ARCH}" \
' -machine accel=kvm' \
' -M accel=kvm:tcg' \
- ' -m '${VMEM}' -cpu host -smp '${VCPUS} \
- ' -kernel ' "/boot/vmlinuz-$(uname -r)" \
+ ' -m '${__vmem}' -cpu host -smp '${VCPUS} \
+ ' -kernel '"${KERNEL}" \
' -initrd '${INITRAMFS}' -nographic -serial stdio' \
' -nodefaults' \
' -append "console=ttyS0 mitigations=off apparmor=0" ' \
- ' -device virtio-net-pci,netdev=s0 ' \
- " -netdev stream,id=s0,server=off,addr.type=unix,addr.path=${STATESETUP}/passt.socket " \
+ " ${__qemu_netdev}" \
" -pidfile ${STATESETUP}/qemu.pid" \
" -device vhost-vsock-pci,guest-cid=$GUEST_CID"
@@ -207,41 +241,63 @@ setup_two_guests() {
[ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt_1.pcap"
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
+ [ ${VHOST_USER} -eq 1 ] && __opts="${__opts} --vhost-user"
- context_run_bg passt_1 "./passt -s ${STATESETUP}/passt_1.socket -P ${STATESETUP}/passt_1.pid -f ${__opts} -t 10001 -u 10001"
+ context_run_bg passt_1 "./passt -s ${STATESETUP}/passt_1.socket -P ${STATESETUP}/passt_1.pid -f ${__opts} --fqdn fqdn1.passt.test -H hostname1 -t 10001 -u 10001"
wait_for [ -f "${STATESETUP}/passt_1.pid" ]
__opts=
[ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt_2.pcap"
[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
+ [ ${VHOST_USER} -eq 1 ] && __opts="${__opts} --vhost-user"
- context_run_bg passt_2 "./passt -s ${STATESETUP}/passt_2.socket -P ${STATESETUP}/passt_2.pid -f ${__opts} -t 10004 -u 10004"
+ context_run_bg passt_2 "./passt -s ${STATESETUP}/passt_2.socket -P ${STATESETUP}/passt_2.pid -f ${__opts} --hostname hostname2 --fqdn fqdn2 -t 10004 -u 10004"
wait_for [ -f "${STATESETUP}/passt_2.pid" ]
+ __vmem="$((${MEM_KIB} / 1024 / 4))"
+ if [ ${VHOST_USER} -eq 1 ]; then
+ __vmem="$(((${__vmem} + 500) / 1000))G"
+ __qemu_netdev1=" \
+ -chardev socket,id=c,path=${STATESETUP}/passt_1.socket \
+ -netdev vhost-user,id=v,chardev=c \
+ -device virtio-net,netdev=v \
+ -object memory-backend-memfd,id=m,share=on,size=${__vmem} \
+ -numa node,memdev=m"
+ __qemu_netdev2=" \
+ -chardev socket,id=c,path=${STATESETUP}/passt_2.socket \
+ -netdev vhost-user,id=v,chardev=c \
+ -device virtio-net,netdev=v \
+ -object memory-backend-memfd,id=m,share=on,size=${__vmem} \
+ -numa node,memdev=m"
+ else
+ __qemu_netdev1="-device virtio-net-pci,netdev=s \
+ -netdev stream,id=s,server=off,addr.type=unix,addr.path=${STATESETUP}/passt_1.socket"
+ __qemu_netdev2="-device virtio-net-pci,netdev=s \
+ -netdev stream,id=s,server=off,addr.type=unix,addr.path=${STATESETUP}/passt_2.socket"
+ fi
+
GUEST_1_CID=94557
- context_run_bg qemu_1 'qemu-system-$(uname -m)' \
+ context_run_bg qemu_1 'qemu-system-'"${QEMU_ARCH}" \
' -M accel=kvm:tcg' \
- ' -m '${VMEM}' -cpu host -smp '${VCPUS} \
- ' -kernel ' "/boot/vmlinuz-$(uname -r)" \
+ ' -m '${__vmem}' -cpu host -smp '${VCPUS} \
+ ' -kernel '"${KERNEL}" \
' -initrd '${INITRAMFS}' -nographic -serial stdio' \
' -nodefaults' \
' -append "console=ttyS0 mitigations=off apparmor=0" ' \
- ' -device virtio-net-pci,netdev=s0 ' \
- " -netdev stream,id=s0,server=off,addr.type=unix,addr.path=${STATESETUP}/passt_1.socket " \
+ " ${__qemu_netdev1}" \
" -pidfile ${STATESETUP}/qemu_1.pid" \
" -device vhost-vsock-pci,guest-cid=$GUEST_1_CID"
GUEST_2_CID=94558
- context_run_bg qemu_2 'qemu-system-$(uname -m)' \
+ context_run_bg qemu_2 'qemu-system-'"${QEMU_ARCH}" \
' -M accel=kvm:tcg' \
- ' -m '${VMEM}' -cpu host -smp '${VCPUS} \
- ' -kernel ' "/boot/vmlinuz-$(uname -r)" \
+ ' -m '${__vmem}' -cpu host -smp '${VCPUS} \
+ ' -kernel '"${KERNEL}" \
' -initrd '${INITRAMFS}' -nographic -serial stdio' \
' -nodefaults' \
' -append "console=ttyS0 mitigations=off apparmor=0" ' \
- ' -device virtio-net-pci,netdev=s0 ' \
- " -netdev stream,id=s0,server=off,addr.type=unix,addr.path=${STATESETUP}/passt_2.socket " \
+ " ${__qemu_netdev2}" \
" -pidfile ${STATESETUP}/qemu_2.pid" \
" -device vhost-vsock-pci,guest-cid=$GUEST_2_CID"
@@ -249,6 +305,117 @@ setup_two_guests() {
context_setup_guest guest_2 ${GUEST_2_CID}
}
+# setup_migrate() - Set up two namespace, run qemu, passt/passt-repair in both
+setup_migrate() {
+ context_setup_host host
+ context_setup_host mon
+ context_setup_host pasta_1
+ context_setup_host pasta_2
+
+ layout_migrate
+
+ # Ports:
+ #
+ # guest #1 | guest #2 | ns #1 | host
+ # --------- |-----------|-----------|------------
+ # 10001 as server | | to guest | to ns #1
+ # 10002 | | as server | to ns #1
+ # 10003 | | to init | as server
+ # 10004 | as server | to guest | to ns #1
+
+ __opts=
+ [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/pasta_1.pcap"
+ [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
+ [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
+
+ __map_host4=192.0.2.1
+ __map_host6=2001:db8:9a55::1
+ __map_ns4=192.0.2.2
+ __map_ns6=2001:db8:9a55::2
+
+ # Option 1: send stuff via spliced path in pasta
+ # context_run_bg pasta_1 "./pasta ${__opts} -P ${STATESETUP}/pasta_1.pid -t 10001,10002 -T 10003 -u 10001,10002 -U 10003 --config-net ${NSTOOL} hold ${STATESETUP}/ns1.hold"
+ # Option 2: send stuff via tap (--map-guest-addr) instead (useful to see capture of full migration)
+ context_run_bg pasta_1 "./pasta ${__opts} -P ${STATESETUP}/pasta_1.pid -t 10001,10002,10004 -T 10003 -u 10001,10002,10004 -U 10003 --map-guest-addr ${__map_host4} --map-guest-addr ${__map_host6} --config-net ${NSTOOL} hold ${STATESETUP}/ns1.hold"
+ context_setup_nstool passt_1 ${STATESETUP}/ns1.hold
+ context_setup_nstool passt_repair_1 ${STATESETUP}/ns1.hold
+
+ context_setup_nstool passt_2 ${STATESETUP}/ns1.hold
+ context_setup_nstool passt_repair_2 ${STATESETUP}/ns1.hold
+
+ context_setup_nstool qemu_1 ${STATESETUP}/ns1.hold
+ context_setup_nstool qemu_2 ${STATESETUP}/ns1.hold
+
+ __ifname="$(context_run qemu_1 "ip -j link show | jq -rM '.[] | select(.link_type == \"ether\").ifname'")"
+
+ sleep 1
+
+ __opts="--vhost-user"
+ [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt_1.pcap"
+ [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
+ [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
+
+ context_run_bg passt_1 "./passt -s ${STATESETUP}/passt_1.socket -P ${STATESETUP}/passt_1.pid -f ${__opts} -t 10001 -u 10001"
+ wait_for [ -f "${STATESETUP}/passt_1.pid" ]
+
+ context_run_bg passt_repair_1 "./passt-repair ${STATESETUP}/passt_1.socket.repair"
+
+ __opts="--vhost-user"
+ [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt_2.pcap"
+ [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
+ [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
+
+ context_run_bg passt_2 "./passt -s ${STATESETUP}/passt_2.socket -P ${STATESETUP}/passt_2.pid -f ${__opts} -t 10004 -u 10004"
+ wait_for [ -f "${STATESETUP}/passt_2.pid" ]
+
+ context_run_bg passt_repair_2 "./passt-repair ${STATESETUP}/passt_2.socket.repair"
+
+ __vmem="512M" # Keep migration fast
+ __qemu_netdev1=" \
+ -chardev socket,id=c,path=${STATESETUP}/passt_1.socket \
+ -netdev vhost-user,id=v,chardev=c \
+ -device virtio-net,netdev=v \
+ -object memory-backend-memfd,id=m,share=on,size=${__vmem} \
+ -numa node,memdev=m"
+ __qemu_netdev2=" \
+ -chardev socket,id=c,path=${STATESETUP}/passt_2.socket \
+ -netdev vhost-user,id=v,chardev=c \
+ -device virtio-net,netdev=v \
+ -object memory-backend-memfd,id=m,share=on,size=${__vmem} \
+ -numa node,memdev=m"
+
+ GUEST_1_CID=94557
+ context_run_bg qemu_1 'qemu-system-'"${QEMU_ARCH}" \
+ ' -M accel=kvm:tcg' \
+ ' -m '${__vmem}' -cpu host -smp '${VCPUS} \
+ ' -kernel '"${KERNEL}" \
+ ' -initrd '${INITRAMFS}' -nographic -serial stdio' \
+ ' -nodefaults' \
+ ' -append "console=ttyS0 mitigations=off apparmor=0" ' \
+ " ${__qemu_netdev1}" \
+ " -pidfile ${STATESETUP}/qemu_1.pid" \
+ " -device vhost-vsock-pci,guest-cid=$GUEST_1_CID" \
+ " -monitor unix:${STATESETUP}/qemu_1_mon.sock,server,nowait"
+
+ GUEST_2_CID=94558
+ context_run_bg qemu_2 'qemu-system-'"${QEMU_ARCH}" \
+ ' -M accel=kvm:tcg' \
+ ' -m '${__vmem}' -cpu host -smp '${VCPUS} \
+ ' -kernel '"${KERNEL}" \
+ ' -initrd '${INITRAMFS}' -nographic -serial stdio' \
+ ' -nodefaults' \
+ ' -append "console=ttyS0 mitigations=off apparmor=0" ' \
+ " ${__qemu_netdev2}" \
+ " -pidfile ${STATESETUP}/qemu_2.pid" \
+ " -device vhost-vsock-pci,guest-cid=$GUEST_2_CID" \
+ " -monitor unix:${STATESETUP}/qemu_2_mon.sock,server,nowait" \
+ " -incoming tcp:0:20005"
+
+ context_setup_guest guest_1 ${GUEST_1_CID}
+ # Only available after migration:
+ ( context_setup_guest guest_2 ${GUEST_2_CID} & )
+}
+
# teardown_context_watch() - Remove contexts and stop panes watching them
# $1: Pane number watching
# $@: Context names
@@ -319,7 +486,8 @@ teardown_two_guests() {
context_wait pasta_1
context_wait pasta_2
- rm -f "${STATESETUP}/passt__[12].pid" "${STATESETUP}/pasta_[12].pid"
+ rm "${STATESETUP}/passt_1.pid" "${STATESETUP}/passt_2.pid"
+ rm "${STATESETUP}/pasta_1.pid" "${STATESETUP}/pasta_2.pid"
teardown_context_watch ${PANE_HOST} host
teardown_context_watch ${PANE_GUEST_1} qemu_1 guest_1
@@ -328,6 +496,30 @@ teardown_two_guests() {
teardown_context_watch ${PANE_PASST_2} pasta_2 passt_2
}
+# teardown_migrate() - Exit namespaces, kill qemu processes, passt and pasta
+teardown_migrate() {
+ ${NSTOOL} exec ${STATESETUP}/ns1.hold -- kill $(cat "${STATESETUP}/qemu_1.pid")
+ ${NSTOOL} exec ${STATESETUP}/ns1.hold -- kill $(cat "${STATESETUP}/qemu_2.pid")
+ context_wait qemu_1
+ context_wait qemu_2
+
+ ${NSTOOL} exec ${STATESETUP}/ns1.hold -- kill $(cat "${STATESETUP}/passt_2.pid")
+ context_wait passt_1
+ context_wait passt_2
+ ${NSTOOL} stop "${STATESETUP}/ns1.hold"
+ context_wait pasta_1
+
+ rm -f "${STATESETUP}/passt_1.pid" "${STATESETUP}/passt_2.pid"
+ rm -f "${STATESETUP}/pasta_1.pid" "${STATESETUP}/pasta_2.pid"
+
+ teardown_context_watch ${PANE_HOST} host
+
+ teardown_context_watch ${PANE_GUEST_1} qemu_1 guest_1
+ teardown_context_watch ${PANE_GUEST_2} qemu_2 guest_2
+ teardown_context_watch ${PANE_PASST_1} pasta_1 passt_1
+ teardown_context_watch ${PANE_PASST_2} pasta_1 passt_2
+}
+
# teardown_demo_passt() - Exit namespace, kill qemu, passt and pasta
teardown_demo_passt() {
tmux send-keys -t ${PANE_GUEST} "C-c"
diff --git a/test/lib/setup_ugly b/test/lib/setup_ugly
index 4b2a077..2802cc3 100755
--- a/test/lib/setup_ugly
+++ b/test/lib/setup_ugly
@@ -33,7 +33,7 @@ setup_memory() {
pane_or_context_run guest 'qemu-system-$(uname -m)' \
' -machine accel=kvm' \
- ' -m '${VMEM}' -cpu host -smp '${VCPUS} \
+ ' -m '$((${MEM_KIB} / 1024 / 4))' -cpu host -smp '${VCPUS} \
' -kernel ' "/boot/vmlinuz-$(uname -r)" \
' -initrd '${INITRAMFS_MEM}' -nographic -serial stdio' \
' -nodefaults' \
diff --git a/test/lib/term b/test/lib/term
index 262937e..089364c 100755
--- a/test/lib/term
+++ b/test/lib/term
@@ -19,6 +19,7 @@ STATUS_FILE_INDEX=0
STATUS_COLS=
STATUS_PASS=0
STATUS_FAIL=0
+STATUS_SKIPPED=0
PR_RED='\033[1;31m'
PR_GREEN='\033[1;32m'
@@ -31,8 +32,8 @@ PR_DELAY_INIT=100 # ms
# $@: Message to print
info() {
tmux select-pane -t ${PANE_INFO}
- echo "${@}" >> $STATEBASE/log_pipe
- echo "${@}" >> "${LOGFILE}"
+ printf "${@}\n" >> $STATEBASE/log_pipe
+ printf "${@}\n" >> "${LOGFILE}"
}
# info_n() - Highlight, print message to pane and to log file without newline
@@ -47,13 +48,13 @@ info_n() {
# $@: Message to print
info_nolog() {
tmux select-pane -t ${PANE_INFO}
- echo "${@}" >> $STATEBASE/log_pipe
+ printf "${@}\n" >> $STATEBASE/log_pipe
}
# info_nolog() - Print message to log file
# $@: Message to print
log() {
- echo "${@}" >> "${LOGFILE}"
+ printf "${@}\n" >> "${LOGFILE}"
}
# info_nolog_n() - Send message to pane without highlighting it, without newline
@@ -97,7 +98,6 @@ display_delay() {
switch_pane() {
tmux select-pane -t ${1}
PR_DELAY=${PR_DELAY_INIT}
- display_delay "0.2"
}
# cmd_write() - Write a command to a pane, letter by letter, and execute it
@@ -199,7 +199,7 @@ pane_run() {
# $1: Pane name
pane_wait() {
__lc="$(echo "${1}" | tr [A-Z] [a-z])"
- sleep 0.1 || sleep 1
+ sleep 0.01 || sleep 1
__done=0
while
@@ -207,7 +207,7 @@ pane_wait() {
case ${__l} in
*"$ " | *"# ") return ;;
esac
- do sleep 0.1 || sleep 1; done
+ do sleep 0.01 || sleep 1; done
}
# pane_parse() - Print last line, @EMPTY@ if command had no output
@@ -231,7 +231,7 @@ pane_status() {
__status="$(pane_parse "${1}")"
while ! [ "${__status}" -eq "${__status}" ] 2>/dev/null; do
- sleep 1
+ sleep 0.01 || sleep 1
pane_run "${1}" 'echo $?'
pane_wait "${1}"
__status="$(pane_parse "${1}")"
@@ -383,6 +383,16 @@ info_check_failed() {
printf " < failed.\n" >> "${LOGFILE}"
}
+# status_bar_blink() - Make status bar blink
+status_bar_blink() {
+ for i in `seq 1 3`; do
+ tmux set status-right-style 'bg=colour1 fg=colour196 bold'
+ sleep 0.1 || sleep 1
+ tmux set status-right-style 'bg=colour1 fg=colour233 bold'
+ sleep 0.1 || sleep 1
+ done
+}
+
# info_passed() - Display, log, and make status bar blink when a test passes
info_passed() {
switch_pane ${PANE_INFO}
@@ -391,12 +401,7 @@ info_passed() {
log "...passed."
log
- for i in `seq 1 3`; do
- tmux set status-right-style 'bg=colour1 fg=colour2 bold'
- sleep "0.1"
- tmux set status-right-style 'bg=colour1 fg=colour233 bold'
- sleep "0.1"
- done
+ [ ${FAST} -eq 1 ] || status_bar_blink
}
# info_failed() - Display, log, and make status bar blink when a test passes
@@ -407,12 +412,7 @@ info_failed() {
log "...failed."
log
- for i in `seq 1 3`; do
- tmux set status-right-style 'bg=colour1 fg=colour196 bold'
- sleep "0.1"
- tmux set status-right-style 'bg=colour1 fg=colour233 bold'
- sleep "0.1"
- done
+ [ ${FAST} -eq 1 ] || status_bar_blink
pause_continue \
"Press any key to pause test session" \
@@ -440,19 +440,21 @@ info_layout() {
# status_test_ok() - Update counter of passed tests, log and display message
status_test_ok() {
STATUS_PASS=$((STATUS_PASS + 1))
- tmux set status-right "PASS: ${STATUS_PASS} | FAIL: ${STATUS_FAIL} | #(TZ="UTC" date -Iseconds)"
+ tmux set status-right "PASS: ${STATUS_PASS} | FAIL: ${STATUS_FAIL} | SKIPPED: ${STATUS_SKIPPED} | #(TZ="UTC" date -Iseconds)"
info_passed
}
# status_test_fail() - Update counter of failed tests, log and display message
status_test_fail() {
STATUS_FAIL=$((STATUS_FAIL + 1))
- tmux set status-right "PASS: ${STATUS_PASS} | FAIL: ${STATUS_FAIL} | #(TZ="UTC" date -Iseconds)"
+ tmux set status-right "PASS: ${STATUS_PASS} | FAIL: ${STATUS_FAIL} | SKIPPED: ${STATUS_SKIPPED} | #(TZ="UTC" date -Iseconds)"
info_failed
}
# status_test_fail() - Update counter of failed tests, log and display message
status_test_skip() {
+ STATUS_SKIPPED=$((STATUS_SKIPPED + 1))
+ tmux set status-right "PASS: ${STATUS_PASS} | FAIL: ${STATUS_FAIL} | SKIPPED: ${STATUS_SKIPPED} | #(TZ="UTC" date -Iseconds)"
info_skipped
}
@@ -665,7 +667,7 @@ pause_continue() {
# run_term() - Start tmux session, running entry point, with recording if needed
run_term() {
- TMUX="tmux new-session -s passt_test -eSTATEBASE=$STATEBASE -ePCAP=$PCAP -eDEBUG=$DEBUG"
+ TMUX="tmux new-session -s passt_test -eSTATEBASE=$STATEBASE -ePCAP=$PCAP -eDEBUG=$DEBUG -eTRACE=$TRACE -eKERNEL=$KERNEL"
if [ ${CI} -eq 1 ]; then
printf '\e[8;50;240t'
diff --git a/test/lib/test b/test/lib/test
index c525f8e..7349674 100755
--- a/test/lib/test
+++ b/test/lib/test
@@ -20,10 +20,7 @@ test_iperf3s() {
__sctx="${1}"
__port="${2}"
- pane_or_context_run_bg "${__sctx}" \
- 'iperf3 -s -p'${__port}' & echo $! > s.pid' \
-
- sleep 1 # Wait for server to be ready
+ pane_or_context_run "${__sctx}" 'iperf3 -s -p'${__port}' -D -I s.pid'
}
# test_iperf3k() - Kill iperf3 server
@@ -31,9 +28,9 @@ test_iperf3s() {
test_iperf3k() {
__sctx="${1}"
- pane_or_context_run "${__sctx}" 'kill -INT $(cat s.pid); rm s.pid'
+ pane_or_context_run "${__sctx}" 'kill -INT $(cat s.pid)'
- sleep 3 # Wait for kernel to free up ports
+ sleep 1 # Wait for kernel to free up ports
}
# test_iperf3() - Ugly helper for iperf3 directive
@@ -68,6 +65,45 @@ test_iperf3() {
TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__var}__" "${__bw}" )"
}
+# test_iperf3m() - Ugly helper for iperf3 directive, guest migration variant
+# $1: Variable name: to put the measure bandwidth into
+# $2: Initial source/client context
+# $3: Second source/client context the guest is moving to
+# $4: Destination name or address for client
+# $5: Port number, ${i} is translated to process index
+# $6: Run time, in seconds
+# $7: Client options
+test_iperf3m() {
+ __var="${1}"; shift
+ __cctx="${1}"; shift
+ __cctx2="${1}"; shift
+ __dest="${1}"; shift
+ __port="${1}"; shift
+ __time="${1}"; shift
+
+ pane_or_context_run "${__cctx}" 'rm -f c.json'
+
+ # A 1s wait for connection on what's basically a local link
+ # indicates something is pretty wrong
+ __timeout=1000
+ pane_or_context_run_bg "${__cctx}" \
+ 'iperf3 -J -c '${__dest}' -p '${__port} \
+ ' --connect-timeout '${__timeout} \
+ ' -t'${__time}' -i0 '"${@}"' > c.json' \
+
+ __jval=".end.sum_received.bits_per_second"
+
+ sleep $((${__time} + 3))
+
+ pane_or_context_output "${__cctx2}" \
+ 'cat c.json'
+
+ __bw=$(pane_or_context_output "${__cctx2}" \
+ 'cat c.json | jq -rMs "map('${__jval}') | add"')
+
+ TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__var}__" "${__bw}" )"
+}
+
test_one_line() {
__line="${1}"
@@ -177,6 +213,12 @@ test_one_line() {
"guest2w")
pane_or_context_wait guest_2 || TEST_ONE_nok=1
;;
+ "mon")
+ pane_or_context_run mon "${__arg}" || TEST_ONE_nok=1
+ ;;
+ "monb")
+ pane_or_context_run_bg mon "${__arg}"
+ ;;
"ns")
pane_or_context_run ns "${__arg}" || TEST_ONE_nok=1
;;
@@ -292,6 +334,9 @@ test_one_line() {
"iperf3")
test_iperf3 ${__arg}
;;
+ "iperf3m")
+ test_iperf3m ${__arg}
+ ;;
"set")
TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__arg%% *}__" "${__arg#* }")"
;;
diff --git a/test/migrate/basic b/test/migrate/basic
new file mode 100644
index 0000000..3f11f7d
--- /dev/null
+++ b/test/migrate/basic
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: GPL-2.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/migrate/basic - Check basic migration functionality
+#
+# Copyright (c) 2025 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+g1tools ip jq dhclient socat cat
+htools ip jq
+
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+test Interface name
+g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME1__" ]
+
+test DHCP: address
+guest1 ip link set dev __IFNAME1__ up
+guest1 /sbin/dhclient -4 __IFNAME1__
+g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR1__" = "__HOST_ADDR__" ]
+
+test DHCPv6: address
+# Link is up now, wait for DAD to complete
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+guest1 /sbin/dhclient -6 __IFNAME1__
+# Wait for DAD to complete on the DHCP address
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
+hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
+check [ "__ADDR1_6__" = "__HOST_ADDR6__" ]
+
+test TCP/IPv4: guest1/guest2 > host
+g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
+hostb socat -u TCP4-LISTEN:10006 OPEN:__STATESETUP__/msg,create,trunc
+sleep 1
+# Option 1: via spliced path in pasta, namespace to host
+# guest1b { printf "Hello from guest 1"; sleep 10; printf " and from guest 2\n"; } | socat -u STDIN TCP4:__GW1__:10003
+# Option 2: via --map-guest-addr (tap) in pasta, namespace to host
+guest1b { printf "Hello from guest 1"; sleep 3; printf " and from guest 2\n"; } | socat -u STDIN TCP4:__MAP_HOST4__:10006
+sleep 1
+
+mon echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
+
+hostw
+hout MSG cat __STATESETUP__/msg
+check [ "__MSG__" = "Hello from guest 1 and from guest 2" ]
diff --git a/test/migrate/basic_fin b/test/migrate/basic_fin
new file mode 100644
index 0000000..aa61ec5
--- /dev/null
+++ b/test/migrate/basic_fin
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: GPL-2.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/migrate/basic_fin - Outbound traffic across migration, half-closed socket
+#
+# Copyright (c) 2025 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+g1tools ip jq dhclient socat cat
+htools ip jq
+
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+test Interface name
+g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME1__" ]
+
+test DHCP: address
+guest1 ip link set dev __IFNAME1__ up
+guest1 /sbin/dhclient -4 __IFNAME1__
+g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR1__" = "__HOST_ADDR__" ]
+
+test DHCPv6: address
+# Link is up now, wait for DAD to complete
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+guest1 /sbin/dhclient -6 __IFNAME1__
+# Wait for DAD to complete on the DHCP address
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
+hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
+check [ "__ADDR1_6__" = "__HOST_ADDR6__" ]
+
+test TCP/IPv4: guest1, half-close, guest2 > host
+g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
+
+hostb echo FIN | socat TCP4-LISTEN:10006,shut-down STDIO,ignoreeof > __STATESETUP__/msg
+#hostb socat -u TCP4-LISTEN:10006 OPEN:__STATESETUP__/msg,create,trunc
+
+#sleep 20
+# Option 1: via spliced path in pasta, namespace to host
+# guest1b { printf "Hello from guest 1"; sleep 10; printf " and from guest 2\n"; } | socat -u STDIN TCP4:__GW1__:10003
+# Option 2: via --map-guest-addr (tap) in pasta, namespace to host
+guest1b { printf "Hello from guest 1"; sleep 3; printf " and from guest 2\n"; } | socat -u STDIN TCP4:__MAP_HOST4__:10006
+sleep 1
+
+mon echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
+
+hostw
+hout MSG cat __STATESETUP__/msg
+check [ "__MSG__" = "Hello from guest 1 and from guest 2" ]
diff --git a/test/migrate/bidirectional b/test/migrate/bidirectional
new file mode 100644
index 0000000..4c04081
--- /dev/null
+++ b/test/migrate/bidirectional
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: GPL-2.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/migrate/bidirectional - Check migration with messages in both directions
+#
+# Copyright (c) 2025 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+g1tools ip jq dhclient socat cat
+htools ip jq
+
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+test Interface name
+g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME1__" ]
+
+test DHCP: address
+guest1 ip link set dev __IFNAME1__ up
+guest1 /sbin/dhclient -4 __IFNAME1__
+g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR1__" = "__HOST_ADDR__" ]
+
+test TCP/IPv4: guest1/guest2 > host, host > guest1/guest2
+g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
+
+hostb socat -u TCP4-LISTEN:10006 OPEN:__STATESETUP__/msg,create,trunc
+guest1b socat -u TCP4-LISTEN:10001 OPEN:msg,create,trunc
+sleep 1
+
+guest1b socat -u UNIX-RECV:proxy.sock,null-eof TCP4:__MAP_HOST4__:10006
+hostb socat -u UNIX-RECV:__STATESETUP__/proxy.sock,null-eof TCP4:__ADDR1__:10001
+sleep 1
+guest1 printf "Hello from guest 1" | socat -u STDIN UNIX:proxy.sock
+host printf "Dear guest 1," | socat -u STDIN UNIX:__STATESETUP__/proxy.sock
+sleep 1
+
+mon echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
+
+sleep 2
+guest2 printf " and from guest 2" | socat -u STDIN UNIX:proxy.sock,shut-null
+host printf " you are now guest 2" | socat -u STDIN UNIX:__STATESETUP__/proxy.sock,shut-null
+
+hostw
+# FIXME: guest2w doesn't work here because shell jobs are (also) from guest #1,
+# use sleep 1 for the moment
+sleep 1
+
+hout MSG cat __STATESETUP__/msg
+check [ "__MSG__" = "Hello from guest 1 and from guest 2" ]
+
+g2out MSG cat msg
+check [ "__MSG__" = "Dear guest 1, you are now guest 2" ]
diff --git a/test/migrate/bidirectional_fin b/test/migrate/bidirectional_fin
new file mode 100644
index 0000000..1c13527
--- /dev/null
+++ b/test/migrate/bidirectional_fin
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: GPL-2.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/migrate/bidirectional_fin - Both directions, half-closed sockets
+#
+# Copyright (c) 2025 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+g1tools ip jq dhclient socat cat
+htools ip jq
+
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+test Interface name
+g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME1__" ]
+
+test DHCP: address
+guest1 ip link set dev __IFNAME1__ up
+guest1 /sbin/dhclient -4 __IFNAME1__
+g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR1__" = "__HOST_ADDR__" ]
+
+test TCP/IPv4: guest1/guest2 <- (half closed) -> host
+g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
+
+hostb echo FIN | socat TCP4-LISTEN:10006,shut-down STDIO,ignoreeof > __STATESETUP__/msg
+guest1b echo FIN | socat TCP4-LISTEN:10001,shut-down STDIO,ignoreeof > msg
+sleep 1
+
+guest1b socat -u UNIX-RECV:proxy.sock,null-eof TCP4:__MAP_HOST4__:10006
+hostb socat -u UNIX-RECV:__STATESETUP__/proxy.sock,null-eof TCP4:__ADDR1__:10001
+sleep 1
+guest1 printf "Hello from guest 1" | socat -u STDIN UNIX:proxy.sock
+host printf "Dear guest 1," | socat -u STDIN UNIX:__STATESETUP__/proxy.sock
+sleep 1
+
+mon echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
+
+sleep 2
+guest2 printf " and from guest 2" | socat -u STDIN UNIX:proxy.sock,shut-null
+host printf " you are now guest 2" | socat -u STDIN UNIX:__STATESETUP__/proxy.sock,shut-null
+
+hostw
+# FIXME: guest2w doesn't work here because shell jobs are (also) from guest #1,
+# use sleep 1 for the moment
+sleep 1
+
+hout MSG cat __STATESETUP__/msg
+check [ "__MSG__" = "Hello from guest 1 and from guest 2" ]
+
+g2out MSG cat msg
+check [ "__MSG__" = "Dear guest 1, you are now guest 2" ]
diff --git a/test/migrate/iperf3_bidir6 b/test/migrate/iperf3_bidir6
new file mode 100644
index 0000000..4bfefb5
--- /dev/null
+++ b/test/migrate/iperf3_bidir6
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.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/migrate/iperf3_bidir6 - Migration behaviour with many bidirectional flows
+#
+# Copyright (c) 2025 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+g1tools ip jq dhclient socat cat
+htools ip jq
+
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+set THREADS 128
+set TIME 3
+set OMIT 0.1
+set OPTS -Z -P __THREADS__ -O__OMIT__ -N --bidir
+
+test Interface name
+g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME1__" ]
+
+test DHCP: address
+guest1 ip link set dev __IFNAME1__ up
+guest1 /sbin/dhclient -4 __IFNAME1__
+g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR1__" = "__HOST_ADDR__" ]
+
+test DHCPv6: address
+# Link is up now, wait for DAD to complete
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+guest1 /sbin/dhclient -6 __IFNAME1__
+# Wait for DAD to complete on the DHCP address
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
+hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
+check [ "__ADDR1_6__" = "__HOST_ADDR6__" ]
+
+test TCP/IPv6 host <-> guest flood, many flows, during migration
+
+monb sleep 1; echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
+
+iperf3s host 10006
+iperf3m BW guest_1 guest_2 __MAP_HOST6__ 10006 __TIME__ __OPTS__
+bw __BW__ 1 2
+
+iperf3k host
diff --git a/test/migrate/iperf3_in4 b/test/migrate/iperf3_in4
new file mode 100644
index 0000000..c5f3916
--- /dev/null
+++ b/test/migrate/iperf3_in4
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: GPL-2.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/migrate/iperf3_in4 - Migration behaviour under inbound IPv4 flood
+#
+# Copyright (c) 2025 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+g1tools ip jq dhclient socat cat
+htools ip jq
+
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+guest1 /sbin/sysctl -w net.core.rmem_max=33554432
+guest1 /sbin/sysctl -w net.core.wmem_max=33554432
+
+set THREADS 1
+set TIME 4
+set OMIT 0.1
+set OPTS -Z -P __THREADS__ -O__OMIT__ -N -R
+
+test Interface name
+g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME1__" ]
+
+test DHCP: address
+guest1 ip link set dev __IFNAME1__ up
+guest1 /sbin/dhclient -4 __IFNAME1__
+g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR1__" = "__HOST_ADDR__" ]
+
+test TCP/IPv4 host to guest throughput during migration
+
+monb sleep 1; echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
+
+iperf3s host 10006
+iperf3m BW guest_1 guest_2 __MAP_HOST4__ 10006 __TIME__ __OPTS__
+bw __BW__ 1 2
+
+iperf3k host
diff --git a/test/migrate/iperf3_in6 b/test/migrate/iperf3_in6
new file mode 100644
index 0000000..16cf504
--- /dev/null
+++ b/test/migrate/iperf3_in6
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.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/migrate/iperf3_in6 - Migration behaviour under inbound IPv6 flood
+#
+# Copyright (c) 2025 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+g1tools ip jq dhclient socat cat
+htools ip jq
+
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+set THREADS 4
+set TIME 3
+set OMIT 0.1
+set OPTS -Z -P __THREADS__ -O__OMIT__ -N -R
+
+test Interface name
+g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME1__" ]
+
+test DHCP: address
+guest1 ip link set dev __IFNAME1__ up
+guest1 /sbin/dhclient -4 __IFNAME1__
+g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR1__" = "__HOST_ADDR__" ]
+
+test DHCPv6: address
+# Link is up now, wait for DAD to complete
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+guest1 /sbin/dhclient -6 __IFNAME1__
+# Wait for DAD to complete on the DHCP address
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
+hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
+check [ "__ADDR1_6__" = "__HOST_ADDR6__" ]
+
+test TCP/IPv6 host to guest throughput during migration
+
+monb sleep 1; echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
+
+iperf3s host 10006
+iperf3m BW guest_1 guest_2 __MAP_HOST6__ 10006 __TIME__ __OPTS__
+bw __BW__ 1 2
+
+iperf3k host
diff --git a/test/migrate/iperf3_many_out6 b/test/migrate/iperf3_many_out6
new file mode 100644
index 0000000..88133f2
--- /dev/null
+++ b/test/migrate/iperf3_many_out6
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: GPL-2.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/migrate/iperf3_many_out6 - Migration behaviour with many outbound flows
+#
+# Copyright (c) 2025 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+g1tools ip jq dhclient socat cat
+htools ip jq
+
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+set THREADS 16
+set TIME 3
+set OMIT 0.1
+set OPTS -Z -P __THREADS__ -O__OMIT__ -N -l 1M
+
+test Interface name
+g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME1__" ]
+
+test DHCP: address
+guest1 ip link set dev __IFNAME1__ up
+guest1 /sbin/dhclient -4 __IFNAME1__
+g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR1__" = "__HOST_ADDR__" ]
+
+test DHCPv6: address
+# Link is up now, wait for DAD to complete
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+guest1 /sbin/dhclient -6 __IFNAME1__
+# Wait for DAD to complete on the DHCP address
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
+hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
+check [ "__ADDR1_6__" = "__HOST_ADDR6__" ]
+
+test TCP/IPv6 guest to host flood, many flows, during migration
+
+test TCP/IPv6 host to guest throughput during migration
+
+monb sleep 1; echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
+
+iperf3s host 10006
+iperf3m BW guest_1 guest_2 __MAP_HOST6__ 10006 __TIME__ __OPTS__
+bw __BW__ 1 2
+
+iperf3k host
diff --git a/test/migrate/iperf3_out4 b/test/migrate/iperf3_out4
new file mode 100644
index 0000000..968057b
--- /dev/null
+++ b/test/migrate/iperf3_out4
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: GPL-2.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/migrate/iperf3_out4 - Migration behaviour under outbound IPv4 flood
+#
+# Copyright (c) 2025 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+g1tools ip jq dhclient socat cat
+htools ip jq
+
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+set THREADS 6
+set TIME 2
+set OMIT 0.1
+set OPTS -P __THREADS__ -O__OMIT__ -Z -N -l 1M
+
+test Interface name
+g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME1__" ]
+
+test DHCP: address
+guest1 ip link set dev __IFNAME1__ up
+guest1 /sbin/dhclient -4 __IFNAME1__
+g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR1__" = "__HOST_ADDR__" ]
+
+test TCP/IPv4 guest to host throughput during migration
+
+monb sleep 1; echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
+
+iperf3s host 10006
+iperf3m BW guest_1 guest_2 __MAP_HOST4__ 10006 __TIME__ __OPTS__
+bw __BW__ 1 2
+
+iperf3k host
diff --git a/test/migrate/iperf3_out6 b/test/migrate/iperf3_out6
new file mode 100644
index 0000000..21fbfcd
--- /dev/null
+++ b/test/migrate/iperf3_out6
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.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/migrate/iperf3_out6 - Migration behaviour under outbound IPv6 flood
+#
+# Copyright (c) 2025 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+g1tools ip jq dhclient socat cat
+htools ip jq
+
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+set THREADS 6
+set TIME 2
+set OMIT 0.1
+set OPTS -P __THREADS__ -O__OMIT__ -Z -N -l 1M
+
+test Interface name
+g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME1__" ]
+
+test DHCP: address
+guest1 ip link set dev __IFNAME1__ up
+guest1 /sbin/dhclient -4 __IFNAME1__
+g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR1__" = "__HOST_ADDR__" ]
+
+test DHCPv6: address
+# Link is up now, wait for DAD to complete
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+guest1 /sbin/dhclient -6 __IFNAME1__
+# Wait for DAD to complete on the DHCP address
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
+hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
+check [ "__ADDR1_6__" = "__HOST_ADDR6__" ]
+
+test TCP/IPv6 guest to host throughput during migration
+
+monb sleep 1; echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
+
+iperf3s host 10006
+iperf3m BW guest_1 guest_2 __MAP_HOST6__ 10006 __TIME__ __OPTS__
+bw __BW__ 1 2
+
+iperf3k host
diff --git a/test/migrate/rampstream_in b/test/migrate/rampstream_in
new file mode 100644
index 0000000..df333ba
--- /dev/null
+++ b/test/migrate/rampstream_in
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: GPL-2.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/migrate/rampstream_in - Check sequence correctness with inbound ramp
+#
+# Copyright (c) 2025 Red Hat
+# Author: David Gibson <david@gibson.dropbear.id.au>
+
+g1tools ip jq dhclient socat cat
+htools ip jq
+
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+set RAMPS 6000000
+
+test Interface name
+g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME1__" ]
+
+test DHCP: address
+guest1 ip link set dev __IFNAME1__ up
+guest1 /sbin/dhclient -4 __IFNAME1__
+g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR1__" = "__HOST_ADDR__" ]
+
+test DHCPv6: address
+# Link is up now, wait for DAD to complete
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+guest1 /sbin/dhclient -6 __IFNAME1__
+# Wait for DAD to complete on the DHCP address
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
+hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
+check [ "__ADDR1_6__" = "__HOST_ADDR6__" ]
+
+test TCP/IPv4: sequence check, ramps, inbound
+g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
+guest1b socat -u TCP4-LISTEN:10001 EXEC:"rampstream-check.sh __RAMPS__"
+sleep 1
+hostb socat -u EXEC:"test/rampstream send __RAMPS__" TCP4:__ADDR1__:10001
+
+sleep 1
+
+monb echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
+
+hostw
+
+guest2 cat rampstream.err
+guest2 [ $(cat rampstream.status) -eq 0 ]
diff --git a/test/migrate/rampstream_out b/test/migrate/rampstream_out
new file mode 100644
index 0000000..8ed3229
--- /dev/null
+++ b/test/migrate/rampstream_out
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: GPL-2.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/migrate/rampstream_out - Check sequence correctness with outbound ramp
+#
+# Copyright (c) 2025 Red Hat
+# Author: David Gibson <david@gibson.dropbear.id.au>
+
+g1tools ip jq dhclient socat cat
+htools ip jq
+
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+set RAMPS 6000000
+
+test Interface name
+g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME1__" ]
+
+test DHCP: address
+guest1 ip link set dev __IFNAME1__ up
+guest1 /sbin/dhclient -4 __IFNAME1__
+g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR1__" = "__HOST_ADDR__" ]
+
+test DHCPv6: address
+# Link is up now, wait for DAD to complete
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+guest1 /sbin/dhclient -6 __IFNAME1__
+# Wait for DAD to complete on the DHCP address
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
+hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
+check [ "__ADDR1_6__" = "__HOST_ADDR6__" ]
+
+test TCP/IPv4: sequence check, ramps, outbound
+g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
+hostb socat -u TCP4-LISTEN:10006 EXEC:"test/rampstream check __RAMPS__"
+sleep 1
+guest1b socat -u EXEC:"rampstream send __RAMPS__" TCP4:__MAP_HOST4__:10006
+sleep 1
+
+mon echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock
+
+hostw
diff --git a/test/nstool.c b/test/nstool.c
index fc357d8..7ab5d2a 100644
--- a/test/nstool.c
+++ b/test/nstool.c
@@ -31,10 +31,15 @@
#define ARRAY_SIZE(a) ((int)(sizeof(a) / sizeof((a)[0])))
-#define die(...) \
- do { \
- fprintf(stderr, __VA_ARGS__); \
- exit(1); \
+#define die(...) \
+ do { \
+ fprintf(stderr, "nstool: " __VA_ARGS__); \
+ exit(1); \
+ } while (0)
+
+#define err(...) \
+ do { \
+ fprintf(stderr, "nstool: " __VA_ARGS__); \
} while (0)
struct ns_type {
@@ -156,6 +161,9 @@ static int connect_ctl(const char *sockpath, bool wait,
static void cmd_hold(int argc, char *argv[])
{
+ struct sigaction sa = {
+ .sa_handler = SIG_IGN,
+ };
int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNIX);
struct sockaddr_un addr;
const char *sockpath = argv[1];
@@ -185,6 +193,10 @@ static void cmd_hold(int argc, char *argv[])
if (!getcwd(info.cwd, sizeof(info.cwd)))
die("getcwd(): %s\n", strerror(errno));
+ rc = sigaction(SIGPIPE, &sa, NULL);
+ if (rc)
+ die("sigaction(SIGPIPE): %s\n", strerror(errno));
+
do {
int afd = accept(fd, NULL, NULL);
char buf;
@@ -193,17 +205,21 @@ static void cmd_hold(int argc, char *argv[])
die("accept(): %s\n", strerror(errno));
rc = write(afd, &info, sizeof(info));
- if (rc < 0)
- die("write(): %s\n", strerror(errno));
+ if (rc < 0) {
+ err("holder write() to control socket: %s\n",
+ strerror(errno));
+ }
if ((size_t)rc < sizeof(info))
- die("short write() on control socket\n");
+ err("holder short write() on control socket\n");
rc = read(afd, &buf, sizeof(buf));
- if (rc < 0)
- die("read(): %s\n", strerror(errno));
+ if (rc < 0) {
+ err("holder read() on control socket: %s\n",
+ strerror(errno));
+ }
close(afd);
- } while (rc == 0);
+ } while (rc <= 0);
unlink(sockpath);
}
@@ -346,7 +362,7 @@ static int openns(const char *fmt, ...)
}
static pid_t sig_pid;
-static void sig_handler(int signum)
+static void sig_propagate(int signum)
{
int err;
@@ -358,7 +374,7 @@ static void sig_handler(int signum)
static void wait_for_child(pid_t pid)
{
struct sigaction sa = {
- .sa_handler = sig_handler,
+ .sa_handler = sig_propagate,
.sa_flags = SA_RESETHAND,
};
int status, err;
diff --git a/test/passt.mbuto b/test/passt.mbuto
index 436eecc..5e00132 100755
--- a/test/passt.mbuto
+++ b/test/passt.mbuto
@@ -13,7 +13,16 @@
PROGS="${PROGS:-ash,dash,bash ip mount ls insmod mkdir ln cat chmod lsmod
modprobe find grep mknod mv rm umount jq iperf3 dhclient hostname
sed tr chown sipcalc cut socat dd strace ping tail killall sleep sysctl
- nproc tcp_rr tcp_crr udp_rr which tee seq bc sshd ssh-keygen cmp}"
+ nproc tcp_rr tcp_crr udp_rr which tee seq bc sshd ssh-keygen cmp tcpdump
+ env}"
+
+# OpenSSH 9.8 introduced split binaries, with sshd being the daemon, and
+# sshd-session the per-session program. We need the latter as well, and the path
+# depends on the distribution. It doesn't exist on older versions.
+for bin in /usr/lib/openssh/sshd-session /usr/lib/ssh/sshd-session \
+ /usr/libexec/openssh/sshd-session; do
+ command -v "${bin}" >/dev/null && PROGS="${PROGS} ${bin}"
+done
KMODS="${KMODS:- virtio_net virtio_pci vmw_vsock_virtio_transport}"
@@ -23,7 +32,7 @@ LINKS="${LINKS:-
DIRS="${DIRS} /tmp /usr/sbin /usr/share /var/log /var/lib /etc/ssh /run/sshd /root/.ssh"
-COPIES="${COPIES} small.bin,/root/small.bin medium.bin,/root/medium.bin big.bin,/root/big.bin"
+COPIES="${COPIES} small.bin,/root/small.bin medium.bin,/root/medium.bin big.bin,/root/big.bin rampstream,/bin/rampstream rampstream-check.sh,/bin/rampstream-check.sh"
FIXUP="${FIXUP}"'
mv /sbin/* /usr/sbin || :
@@ -33,6 +42,7 @@ FIXUP="${FIXUP}"'
#!/bin/sh
LOG=/var/log/dhclient-script.log
echo \${reason} \${interface} >> \$LOG
+env >> \$LOG
set >> \$LOG
[ -n "\${new_interface_mtu}" ] && ip link set dev \${interface} mtu \${new_interface_mtu}
@@ -46,7 +56,8 @@ set >> \$LOG
[ -n "\${new_ip6_address}" ] && ip addr add \${new_ip6_address}/\${new_ip6_prefixlen} dev \${interface}
[ -n "\${new_dhcp6_name_servers}" ] && for d in \${new_dhcp6_name_servers}; do echo "nameserver \${d}%\${interface}" >> /etc/resolv.conf; done
[ -n "\${new_dhcp6_domain_search}" ] && (printf "search"; for d in \${new_dhcp6_domain_search}; do printf " %s" "\${d}"; done; printf "\n") >> /etc/resolv.conf
-[ -n "\${new_host_name}" ] && hostname "\${new_host_name}"
+[ -n "\${new_host_name}" ] && echo "\${new_host_name}" > /tmp/new_host_name
+[ -n "\${new_fqdn_fqdn}" ] && echo "\${new_fqdn_fqdn}" > /tmp/new_fqdn_fqdn
exit 0
EOF
chmod 755 /sbin/dhclient-script
@@ -57,6 +68,7 @@ EOF
# sshd via vsock
cat > /etc/passwd << EOF
root:x:0:0:root:/root:/bin/sh
+tcpdump:x:72:72:tcpdump:/:/sbin/nologin
sshd:x:100:100:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
EOF
cat > /etc/shadow << EOF
@@ -78,7 +90,7 @@ EOF
EOF
chmod 600 /root/.ssh/authorized_keys
chmod 700 /root
- socat VSOCK-LISTEN:22,fork EXEC:"sshd -i -e" 2> /var/log/vsock-ssh.log &
+ socat VSOCK-LISTEN:22,fork EXEC:"/sbin/sshd -i -e" 2> /var/log/vsock-ssh.log &
sh +m
'
diff --git a/test/passt/dhcp b/test/passt/dhcp
index e05a4bb..145f1ba 100644
--- a/test/passt/dhcp
+++ b/test/passt/dhcp
@@ -11,7 +11,7 @@
# Copyright (c) 2021 Red Hat GmbH
# Author: Stefano Brivio <sbrivio@redhat.com>
-gtools ip jq dhclient sed tr
+gtools ip jq dhclient sed tr hostname
htools ip jq sed tr head
test Interface name
@@ -47,8 +47,19 @@ gout SEARCH sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^searc
hout HOST_SEARCH sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/'
check [ "__SEARCH__" = "__HOST_SEARCH__" ]
+test DHCP: Hostname
+gout NEW_HOST_NAME cat /tmp/new_host_name
+check [ "__NEW_HOST_NAME__" = "hostname1" ]
+
+test DHCP: Client FQDN
+gout NEW_FQDN_FQDN cat /tmp/new_fqdn_fqdn
+check [ "__NEW_FQDN_FQDN__" = "fqdn1.passt.test" ]
+
test DHCPv6: address
+guest rm /tmp/new_fqdn_fqdn
guest /sbin/dhclient -6 __IFNAME__
+# Wait for DAD to complete
+guest while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
gout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
check [ "__ADDR6__" = "__HOST_ADDR6__" ]
@@ -68,3 +79,7 @@ test DHCPv6: search list
gout SEARCH6 sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/'
hout HOST_SEARCH6 sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/'
check [ "__SEARCH6__" = "__HOST_SEARCH6__" ]
+
+test DHCPv6: Hostname
+gout NEW_FQDN_FQDN cat /tmp/new_fqdn_fqdn
+check [ "__NEW_FQDN_FQDN__" = "fqdn1.passt.test" ]
diff --git a/test/passt/ndp b/test/passt/ndp
index 6bf8af3..516cd6b 100644
--- a/test/passt/ndp
+++ b/test/passt/ndp
@@ -16,13 +16,15 @@ htools ip jq sipcalc grep cut
test Interface name
gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
-guest ip link set dev __IFNAME__ up && sleep 2
+guest ip link set dev __IFNAME__ up
+# Wait for SLAAC & DAD to complete
+guest while ! ip -j -6 addr show dev __IFNAME__ | jq -e '.[].addr_info.[] | select(.protocol == "kernel_ra")'; do sleep 0.1; done
hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
check [ -n "__IFNAME__" ]
test SLAAC: prefix
-gout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global" and .prefixlen == 64).local] | .[0]'
-gout PREFIX6 sipcalc __ADDR6__/64 | grep prefix | cut -d' ' -f4
+gout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.protocol == "kernel_ra") | .local + "/" + (.prefixlen | tostring)] | .[0]'
+gout PREFIX6 sipcalc __ADDR6__ | grep prefix | cut -d' ' -f4
hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
hout HOST_PREFIX6 sipcalc __HOST_ADDR6__/64 | grep prefix | cut -d' ' -f4
check [ "__PREFIX6__" = "__HOST_PREFIX6__" ]
diff --git a/test/passt_in_ns/dhcp b/test/passt_in_ns/dhcp
new file mode 100644
index 0000000..a38a690
--- /dev/null
+++ b/test/passt_in_ns/dhcp
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: GPL-2.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/passt/dhcp - Check DHCP and DHCPv6 functionality in passt mode
+#
+# Copyright (c) 2021 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+gtools ip jq dhclient sed tr
+htools ip jq sed tr head
+
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+test Interface name
+gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check [ -n "__IFNAME__" ]
+
+test DHCP: address
+guest /sbin/dhclient -4 __IFNAME__
+gout ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local'
+hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check [ "__ADDR__" = "__HOST_ADDR__" ]
+
+test DHCP: route
+gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
+hout HOST_GW ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]'
+check [ "__GW__" = "__HOST_GW__" ]
+
+test DHCP: MTU
+gout MTU ip -j link show | jq -rM '.[] | select(.ifname == "__IFNAME__").mtu'
+check [ __MTU__ = 65520 ]
+
+test DHCP: DNS
+gout DNS sed -n 's/^nameserver \([0-9]*\.\)\(.*\)/\1\2/p' /etc/resolv.conf | tr '\n' ',' | sed 's/,$//;s/$/\n/'
+hout HOST_DNS sed -n 's/^nameserver \([0-9]*\.\)\(.*\)/\1\2/p' /etc/resolv.conf | head -n3 | tr '\n' ',' | sed 's/,$//;s/$/\n/'
+check [ "__DNS__" = "__HOST_DNS__" ] || ( [ "__DNS__" = "__MAP_NS4__" ] && expr "__HOST_DNS__" : "127[.]" )
+
+# FQDNs should be terminated by dots, but the guest DHCP client might omit them:
+# strip them first
+test DHCP: search list
+gout SEARCH sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/'
+hout HOST_SEARCH sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/'
+check [ "__SEARCH__" = "__HOST_SEARCH__" ]
+
+test DHCPv6: address
+guest /sbin/dhclient -6 __IFNAME__
+# Wait for DAD to complete
+guest while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+gout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
+hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
+check [ "__ADDR6__" = "__HOST_ADDR6__" ]
+
+test DHCPv6: route
+gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
+hout HOST_GW6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]'
+check [ "__GW6__" = "__HOST_GW6__" ]
+
+# Strip interface specifier: interface names might differ between host and guest
+test DHCPv6: DNS
+gout DNS6 sed -n 's/^nameserver \([^:]*:\)\([^%]*\).*/\1\2/p' /etc/resolv.conf | tr '\n' ',' | sed 's/,$//;s/$/\n/'
+hout HOST_DNS6 sed -n 's/^nameserver \([^:]*:\)\([^%]*\).*/\1\2/p' /etc/resolv.conf | tr '\n' ',' | sed 's/,$//;s/$/\n/'
+check [ "__DNS6__" = "__HOST_DNS6__" ] || [ "__DNS6__" = "__MAP_NS6__" -a "__HOST_DNS6__" = "::1" ]
+
+test DHCPv6: search list
+gout SEARCH6 sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/'
+hout HOST_SEARCH6 sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/'
+check [ "__SEARCH6__" = "__HOST_SEARCH6__" ]
diff --git a/test/passt_in_ns/tcp b/test/passt_in_ns/tcp
index cdb7060..319880b 100644
--- a/test/passt_in_ns/tcp
+++ b/test/passt_in_ns/tcp
@@ -15,6 +15,11 @@ gtools socat ip jq
htools socat ip jq
nstools socat ip jq
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
set TEMP_BIG __STATEDIR__/test_big.bin
set TEMP_SMALL __STATEDIR__/test_small.bin
set TEMP_NS_BIG __STATEDIR__/test_ns_big.bin
@@ -27,7 +32,7 @@ host socat -u OPEN:__BASEPATH__/big.bin TCP4:127.0.0.1:10001
guestw
guest cmp test_big.bin /root/big.bin
-test TCP/IPv4: host to ns: big transfer
+test TCP/IPv4: host to ns (spliced): big transfer
nsb socat -u TCP4-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc
sleep 1
host socat -u OPEN:__BASEPATH__/big.bin TCP4:127.0.0.1:10002
@@ -36,16 +41,15 @@ check cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin
test TCP/IPv4: guest to host: big transfer
hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc
-gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
sleep 1
-guest socat -u OPEN:/root/big.bin TCP4:__GW__:10003
+guest socat -u OPEN:/root/big.bin TCP4:__MAP_HOST4__:10003
hostw
check cmp __TEMP_BIG__ __BASEPATH__/big.bin
test TCP/IPv4: guest to ns: big transfer
nsb socat -u TCP4-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc
sleep 1
-guest socat -u OPEN:/root/big.bin TCP4:__GW__:10002
+guest socat -u OPEN:/root/big.bin TCP4:__MAP_NS4__:10002
nsw
check cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin
@@ -59,7 +63,7 @@ check cmp __TEMP_BIG__ __BASEPATH__/big.bin
test TCP/IPv4: ns to host (via tap): big transfer
hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc
sleep 1
-ns socat -u OPEN:__BASEPATH__/big.bin TCP4:__GW__:10003
+ns socat -u OPEN:__BASEPATH__/big.bin TCP4:__MAP_HOST4__:10003
hostw
check cmp __TEMP_BIG__ __BASEPATH__/big.bin
@@ -86,7 +90,7 @@ host socat -u OPEN:__BASEPATH__/small.bin TCP4:127.0.0.1:10001
guestw
guest cmp test_small.bin /root/small.bin
-test TCP/IPv4: host to ns: small transfer
+test TCP/IPv4: host to ns (spliced): small transfer
nsb socat -u TCP4-LISTEN:10002 OPEN:__TEMP_NS_SMALL__,create,trunc
sleep 1
host socat -u OPEN:__BASEPATH__/small.bin TCP4:127.0.0.1:10002
@@ -95,16 +99,15 @@ check cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin
test TCP/IPv4: guest to host: small transfer
hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc
-gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
sleep 1
-guest socat -u OPEN:/root/small.bin TCP4:__GW__:10003
+guest socat -u OPEN:/root/small.bin TCP4:__MAP_HOST4__:10003
hostw
check cmp __TEMP_SMALL__ __BASEPATH__/small.bin
test TCP/IPv4: guest to ns: small transfer
nsb socat -u TCP4-LISTEN:10002 OPEN:__TEMP_NS_SMALL__,create,trunc
sleep 1
-guest socat -u OPEN:/root/small.bin TCP4:__GW__:10002
+guest socat -u OPEN:/root/small.bin TCP4:__MAP_NS4__:10002
nsw
check cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin
@@ -118,7 +121,7 @@ check cmp __TEMP_SMALL__ __BASEPATH__/small.bin
test TCP/IPv4: ns to host (via tap): small transfer
hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc
sleep 1
-ns socat -u OPEN:__BASEPATH__/small.bin TCP4:__GW__:10003
+ns socat -u OPEN:__BASEPATH__/small.bin TCP4:__MAP_HOST4__:10003
hostw
check cmp __TEMP_SMALL__ __BASEPATH__/small.bin
@@ -143,7 +146,7 @@ host socat -u OPEN:__BASEPATH__/big.bin TCP6:[::1]:10001
guestw
guest cmp test_big.bin /root/big.bin
-test TCP/IPv6: host to ns: big transfer
+test TCP/IPv6: host to ns (spliced): big transfer
nsb socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc
sleep 1
host socat -u OPEN:__BASEPATH__/big.bin TCP6:[::1]:10002
@@ -152,17 +155,15 @@ check cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin
test TCP/IPv6: guest to host: big transfer
hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc
-gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
-gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
sleep 1
-guest socat -u OPEN:/root/big.bin TCP6:[__GW6__%__IFNAME__]:10003
+guest socat -u OPEN:/root/big.bin TCP6:[__MAP_HOST6__]:10003
hostw
check cmp __TEMP_BIG__ __BASEPATH__/big.bin
test TCP/IPv6: guest to ns: big transfer
nsb socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc
sleep 1
-guest socat -u OPEN:/root/big.bin TCP6:[__GW6__%__IFNAME__]:10002
+guest socat -u OPEN:/root/big.bin TCP6:[__MAP_NS6__]:10002
nsw
check cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin
@@ -175,9 +176,8 @@ check cmp __TEMP_BIG__ __BASEPATH__/big.bin
test TCP/IPv6: ns to host (via tap): big transfer
hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc
-nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
sleep 1
-ns socat -u OPEN:__BASEPATH__/big.bin TCP6:[__GW6__%__IFNAME__]:10003
+ns socat -u OPEN:__BASEPATH__/big.bin TCP6:[__MAP_HOST6__]:10003
hostw
check cmp __TEMP_BIG__ __BASEPATH__/big.bin
@@ -190,6 +190,7 @@ guest cmp test_big.bin /root/big.bin
test TCP/IPv6: ns to guest (using namespace address): big transfer
guestb socat -u TCP6-LISTEN:10001 OPEN:test_big.bin,create,trunc
+nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local'
sleep 1
ns socat -u OPEN:__BASEPATH__/big.bin TCP6:[__ADDR6__]:10001
@@ -203,7 +204,7 @@ host socat -u OPEN:__BASEPATH__/small.bin TCP6:[::1]:10001
guestw
guest cmp test_small.bin /root/small.bin
-test TCP/IPv6: host to ns: small transfer
+test TCP/IPv6: host to ns (spliced): small transfer
nsb socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_SMALL__,create,trunc
sleep 1
host socat -u OPEN:__BASEPATH__/small.bin TCP6:[::1]:10002
@@ -212,17 +213,15 @@ check cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin
test TCP/IPv6: guest to host: small transfer
hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc
-gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
-gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
sleep 1
-guest socat -u OPEN:/root/small.bin TCP6:[__GW6__%__IFNAME__]:10003
+guest socat -u OPEN:/root/small.bin TCP6:[__MAP_HOST6__]:10003
hostw
check cmp __TEMP_SMALL__ __BASEPATH__/small.bin
test TCP/IPv6: guest to ns: small transfer
nsb socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_SMALL__
sleep 1
-guest socat -u OPEN:/root/small.bin TCP6:[__GW6__%__IFNAME__]:10002
+guest socat -u OPEN:/root/small.bin TCP6:[__MAP_NS6__]:10002
nsw
check cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin
@@ -235,9 +234,8 @@ check cmp __TEMP_SMALL__ __BASEPATH__/small.bin
test TCP/IPv6: ns to host (via tap): small transfer
hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc
-nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
sleep 1
-ns socat -u OPEN:__BASEPATH__/small.bin TCP6:[__GW6__%__IFNAME__]:10003
+ns socat -u OPEN:__BASEPATH__/small.bin TCP6:[__MAP_HOST6__]:10003
hostw
check cmp __TEMP_SMALL__ __BASEPATH__/small.bin
diff --git a/test/passt_in_ns/udp b/test/passt_in_ns/udp
index 8a02513..791511c 100644
--- a/test/passt_in_ns/udp
+++ b/test/passt_in_ns/udp
@@ -15,6 +15,11 @@ gtools socat ip jq
nstools socat ip jq
htools socat ip jq
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
set TEMP __STATEDIR__/test.bin
set TEMP_NS __STATEDIR__/test_ns.bin
@@ -25,7 +30,7 @@ host socat -u OPEN:__BASEPATH__/medium.bin UDP4:127.0.0.1:10001,shut-null
guestw
guest cmp test.bin /root/medium.bin
-test UDP/IPv4: host to ns
+test UDP/IPv4: host to ns (recvmmsg/sendmmsg)
nsb socat -u UDP4-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc
sleep 1
host socat -u OPEN:__BASEPATH__/medium.bin UDP4:127.0.0.1:10002,shut-null
@@ -34,16 +39,15 @@ check cmp __TEMP_NS__ __BASEPATH__/medium.bin
test UDP/IPv4: guest to host
hostb socat -u UDP4-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc
-gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
sleep 1
-guest socat -u OPEN:/root/medium.bin UDP4:__GW__:10003,shut-null
+guest socat -u OPEN:/root/medium.bin UDP4:__MAP_HOST4__:10003,shut-null
hostw
check cmp __TEMP__ __BASEPATH__/medium.bin
test UDP/IPv4: guest to ns
nsb socat -u UDP4-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc
sleep 1
-guest socat -u OPEN:/root/medium.bin UDP4:__GW__:10002,shut-null
+guest socat -u OPEN:/root/medium.bin UDP4:__MAP_NS4__:10002,shut-null
nsw
check cmp __TEMP_NS__ __BASEPATH__/medium.bin
@@ -57,7 +61,7 @@ check cmp __TEMP__ __BASEPATH__/medium.bin
test UDP/IPv4: ns to host (via tap)
hostb socat -u UDP4-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc
sleep 1
-ns socat -u OPEN:__BASEPATH__/medium.bin UDP4:__GW__:10003,shut-null
+ns socat -u OPEN:__BASEPATH__/medium.bin UDP4:__MAP_HOST4__:10003,shut-null
hostw
check cmp __TEMP__ __BASEPATH__/medium.bin
@@ -84,7 +88,7 @@ host socat -u OPEN:__BASEPATH__/medium.bin UDP6:[::1]:10001,shut-null
guestw
guest cmp test.bin /root/medium.bin
-test UDP/IPv6: host to ns
+test UDP/IPv6: host to ns (recvmmsg/sendmmsg)
nsb socat -u UDP6-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc
sleep 1
host socat -u OPEN:__BASEPATH__/medium.bin UDP6:[::1]:10002,shut-null
@@ -93,17 +97,15 @@ check cmp __TEMP_NS__ __BASEPATH__/medium.bin
test UDP/IPv6: guest to host
hostb socat -u UDP6-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc
-gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
-gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
sleep 1
-guest socat -u OPEN:/root/medium.bin UDP6:[__GW6__%__IFNAME__]:10003,shut-null
+guest socat -u OPEN:/root/medium.bin UDP6:[__MAP_HOST6__]:10003,shut-null
hostw
check cmp __TEMP__ __BASEPATH__/medium.bin
test UDP/IPv6: guest to ns
nsb socat -u UDP6-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc
sleep 1
-guest socat -u OPEN:/root/medium.bin UDP6:[__GW6__%__IFNAME__]:10002,shut-null
+guest socat -u OPEN:/root/medium.bin UDP6:[__MAP_NS6__]:10002,shut-null
nsw
check cmp __TEMP_NS__ __BASEPATH__/medium.bin
@@ -116,9 +118,8 @@ check cmp __TEMP__ __BASEPATH__/medium.bin
test UDP/IPv6: ns to host (via tap)
hostb socat -u UDP6-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc
-nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
sleep 1
-ns socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__GW6__%__IFNAME__]:10003,shut-null
+ns socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__MAP_HOST6__]:10003,shut-null
hostw
check cmp __TEMP__ __BASEPATH__/medium.bin
@@ -131,6 +132,7 @@ guest cmp test.bin /root/medium.bin
test UDP/IPv6: ns to guest (using namespace address)
guestb socat -u UDP6-LISTEN:10001,null-eof OPEN:test.bin,create,trunc
+nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local'
sleep 1
ns socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__ADDR6__]:10001,shut-null
diff --git a/test/passt_vu b/test/passt_vu
new file mode 120000
index 0000000..22f1840
--- /dev/null
+++ b/test/passt_vu
@@ -0,0 +1 @@
+passt \ No newline at end of file
diff --git a/test/passt_vu_in_ns b/test/passt_vu_in_ns
new file mode 120000
index 0000000..3ff479e
--- /dev/null
+++ b/test/passt_vu_in_ns
@@ -0,0 +1 @@
+passt_in_ns \ No newline at end of file
diff --git a/test/pasta/dhcp b/test/pasta/dhcp
index 41556b8..d4f3ad5 100644
--- a/test/pasta/dhcp
+++ b/test/pasta/dhcp
@@ -35,6 +35,8 @@ check [ __MTU__ = 65520 ]
test DHCPv6: address
ns /sbin/dhclient -6 --no-pid __IFNAME__
+# Wait for DAD to complete
+ns while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
nsout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
diff --git a/test/pasta/ndp b/test/pasta/ndp
index d45ff7b..952c1ea 100644
--- a/test/pasta/ndp
+++ b/test/pasta/ndp
@@ -18,11 +18,12 @@ test Interface name
nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
check [ -n "__IFNAME__" ]
ns ip link set dev __IFNAME__ up
-sleep 2
+# Wait for SLAAC & DAD to complete
+ns while ! ip -j -6 addr show dev __IFNAME__ | jq -e '.[].addr_info.[] | select(.protocol == "kernel_ra")'; do sleep 0.1; done
test SLAAC: prefix
-nsout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global" and .prefixlen == 64).local] | .[0]'
-nsout PREFIX6 sipcalc __ADDR6__/64 | grep prefix | cut -d' ' -f4
+nsout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.protocol == "kernel_ra") | .local + "/" + (.prefixlen | tostring)] | .[0]'
+nsout PREFIX6 sipcalc __ADDR6__ | grep prefix | cut -d' ' -f4
hout HOST_ADDR6 ip -j -6 addr show|jq -rM ['.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
hout HOST_PREFIX6 sipcalc __HOST_ADDR6__/64 | grep prefix | cut -d' ' -f4
check [ "__PREFIX6__" = "__HOST_PREFIX6__" ]
diff --git a/test/pasta/tcp b/test/pasta/tcp
index 6ab18c5..53b6f25 100644
--- a/test/pasta/tcp
+++ b/test/pasta/tcp
@@ -19,8 +19,8 @@ set TEMP_NS_BIG __STATEDIR__/test_ns_big.bin
set TEMP_SMALL __STATEDIR__/test_small.bin
set TEMP_NS_SMALL __STATEDIR__/test_ns_small.bin
-test TCP/IPv4: host to ns: big transfer
-nsb socat -u TCP4-LISTEN:10002,bind=127.0.0.1 OPEN:__TEMP_NS_BIG__,create,trunc
+test TCP/IPv4: host to ns (spliced): big transfer
+nsb socat -u TCP4-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc
host socat -u OPEN:__BASEPATH__/big.bin TCP4:127.0.0.1:10002
nsw
check cmp __BASEPATH__/big.bin __TEMP_NS_BIG__
@@ -38,8 +38,8 @@ ns socat -u OPEN:__BASEPATH__/big.bin TCP4:__GW__:10003
hostw
check cmp __BASEPATH__/big.bin __TEMP_BIG__
-test TCP/IPv4: host to ns: small transfer
-nsb socat -u TCP4-LISTEN:10002,bind=127.0.0.1 OPEN:__TEMP_NS_SMALL__,create,trunc
+test TCP/IPv4: host to ns (spliced): small transfer
+nsb socat -u TCP4-LISTEN:10002 OPEN:__TEMP_NS_SMALL__,create,trunc
host socat OPEN:__BASEPATH__/small.bin TCP4:127.0.0.1:10002
nsw
check cmp __BASEPATH__/small.bin __TEMP_NS_SMALL__
@@ -57,8 +57,8 @@ ns socat -u OPEN:__BASEPATH__/small.bin TCP4:__GW__:10003
hostw
check cmp __BASEPATH__/small.bin __TEMP_SMALL__
-test TCP/IPv6: host to ns: big transfer
-nsb socat -u TCP6-LISTEN:10002,bind=[::1] OPEN:__TEMP_NS_BIG__,create,trunc
+test TCP/IPv6: host to ns (spliced): big transfer
+nsb socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc
host socat -u OPEN:__BASEPATH__/big.bin TCP6:[::1]:10002
nsw
check cmp __BASEPATH__/big.bin __TEMP_NS_BIG__
@@ -77,8 +77,8 @@ ns socat -u OPEN:__BASEPATH__/big.bin TCP6:[__GW6__%__IFNAME__]:10003
hostw
check cmp __BASEPATH__/big.bin __TEMP_BIG__
-test TCP/IPv6: host to ns: small transfer
-nsb socat -u TCP6-LISTEN:10002,bind=[::1] OPEN:__TEMP_NS_SMALL__,create,trunc
+test TCP/IPv6: host to ns (spliced): small transfer
+nsb socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_SMALL__,create,trunc
host socat -u OPEN:__BASEPATH__/small.bin TCP6:[::1]:10002
nsw
check cmp __BASEPATH__/small.bin __TEMP_NS_SMALL__
diff --git a/test/pasta/udp b/test/pasta/udp
index 30e3a85..7734d02 100644
--- a/test/pasta/udp
+++ b/test/pasta/udp
@@ -17,8 +17,8 @@ htools dd socat ip jq
set TEMP __STATEDIR__/test.bin
set TEMP_NS __STATEDIR__/test_ns.bin
-test UDP/IPv4: host to ns
-nsb socat -u UDP4-LISTEN:10002,bind=127.0.0.1,null-eof OPEN:__TEMP_NS__,create,trunc
+test UDP/IPv4: host to ns (recvmmsg/sendmmsg)
+nsb socat -u UDP4-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc
host socat OPEN:__BASEPATH__/medium.bin UDP4:127.0.0.1:10002,shut-null
nsw
check cmp __BASEPATH__/medium.bin __TEMP_NS__
@@ -37,8 +37,8 @@ ns socat -u OPEN:__BASEPATH__/medium.bin UDP4:__GW__:10003,shut-null
hostw
check cmp __BASEPATH__/medium.bin __TEMP__
-test UDP/IPv6: host to ns
-nsb socat -u UDP6-LISTEN:10002,bind=[::1],null-eof OPEN:__TEMP_NS__,create,trunc
+test UDP/IPv6: host to ns (recvmmsg/sendmmsg)
+nsb socat -u UDP6-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc
host socat -u OPEN:__BASEPATH__/medium.bin UDP6:[::1]:10002,shut-null
nsw
check cmp __BASEPATH__/medium.bin __TEMP_NS__
diff --git a/test/pasta_options/log_to_file b/test/pasta_options/log_to_file
index fe50e50..3ead06c 100644
--- a/test/pasta_options/log_to_file
+++ b/test/pasta_options/log_to_file
@@ -19,7 +19,7 @@ sleep 1
endef
def flood_log_client
-host tcp_crr --nolog -P 10001 -C 10002 -6 -c -H ::1
+host tcp_crr --nolog -l1 -P 10001 -C 10002 -6 -c -H ::1
endef
def check_log_size_mountns
@@ -42,7 +42,7 @@ pout PID2 echo $!
check head -1 __LOG_FILE__ | grep '^pasta .* [(]__PID2__[)]$'
test Maximum log size
-passtb ./pasta --config-net -d -f -l __LOG_FILE__ --log-size $((100 * 1024)) -- sh -c 'while true; do tcp_crr --nolog -P 10001 -C 10002 -6; done'
+passtb ./pasta --config-net -d -f -l __LOG_FILE__ --log-size $((100 * 1024)) -- sh -c 'while true; do tcp_crr --nolog -l1 -P 10001 -C 10002 -6; done'
sleep 1
flood_log_client
diff --git a/test/pasta_podman/bats b/test/pasta_podman/bats
index 6b1c575..2f07be8 100644
--- a/test/pasta_podman/bats
+++ b/test/pasta_podman/bats
@@ -23,4 +23,4 @@ check [ "__PASTA_BIN__" = "__WD__/pasta" ]
test Podman system test with bats
-host PODMAN="__PODMAN__" CONTAINERS_HELPER_BINARY_DIR="__WD__" bats test/podman/test/system/505-networking-pasta.bats
+host PODMAN="__PODMAN__" CONTAINERS_HELPER_BINARY_DIR="__WD__" taskset -c 1 bats test/podman/test/system/505-networking-pasta.bats
diff --git a/test/perf/passt_tcp b/test/perf/passt_tcp
index 14343cb..5978c49 100644
--- a/test/perf/passt_tcp
+++ b/test/perf/passt_tcp
@@ -15,6 +15,9 @@ gtools /sbin/sysctl ip jq nproc seq sleep iperf3 tcp_rr tcp_crr # From neper
nstools /sbin/sysctl ip jq nproc seq sleep iperf3 tcp_rr tcp_crr
htools bc head sed seq
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
test passt: throughput and latency
guest /sbin/sysctl -w net.core.rmem_max=536870912
@@ -29,8 +32,6 @@ ns /sbin/sysctl -w net.ipv4.tcp_rmem="4096 524288 134217728"
ns /sbin/sysctl -w net.ipv4.tcp_wmem="4096 524288 134217728"
ns /sbin/sysctl -w net.ipv4.tcp_timestamps=0
-gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
hout FREQ_PROCFS (echo "scale=1"; sed -n 's/cpu MHz.*: \([0-9]*\)\..*$/(\1+10^2\/2)\/10^3/p' /proc/cpuinfo) | bc -l | head -n1
@@ -38,7 +39,7 @@ hout FREQ_CPUFREQ (echo "scale=1"; printf '( %i + 10^5 / 2 ) / 10^6\n' $(cat /sy
hout FREQ [ -n "__FREQ_CPUFREQ__" ] && echo __FREQ_CPUFREQ__ || echo __FREQ_PROCFS__
set THREADS 4
-set TIME 10
+set TIME 1
set OMIT 0.1
set OPTS -Z -P __THREADS__ -l 1M -O__OMIT__
@@ -54,16 +55,16 @@ iperf3s ns 10002
bw -
bw -
guest ip link set dev __IFNAME__ mtu 1280
-iperf3 BW guest __GW6__%__IFNAME__ 10002 __TIME__ __OPTS__ -w 4M
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -w 4M
bw __BW__ 1.2 1.5
guest ip link set dev __IFNAME__ mtu 1500
-iperf3 BW guest __GW6__%__IFNAME__ 10002 __TIME__ __OPTS__ -w 4M
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -w 4M
bw __BW__ 1.6 1.8
guest ip link set dev __IFNAME__ mtu 9000
-iperf3 BW guest __GW6__%__IFNAME__ 10002 __TIME__ __OPTS__ -w 8M
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -w 8M
bw __BW__ 4.0 5.0
guest ip link set dev __IFNAME__ mtu 65520
-iperf3 BW guest __GW6__%__IFNAME__ 10002 __TIME__ __OPTS__ -w 16M
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -w 16M
bw __BW__ 7.0 8.0
iperf3k ns
@@ -75,7 +76,7 @@ lat -
lat -
lat -
nsb tcp_rr --nolog -6
-gout LAT tcp_rr --nolog -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout LAT tcp_rr --nolog -l1 -6 -c -H __MAP_NS6__ | sed -n 's/^throughput=\(.*\)/\1/p'
lat __LAT__ 200 150
tl TCP CRR latency over IPv6: guest to host
@@ -85,33 +86,39 @@ lat -
lat -
lat -
nsb tcp_crr --nolog -6
-gout LAT tcp_crr --nolog -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout LAT tcp_crr --nolog -l1 -6 -c -H __MAP_NS6__ | sed -n 's/^throughput=\(.*\)/\1/p'
lat __LAT__ 500 400
tr TCP throughput over IPv4: guest to host
iperf3s ns 10002
guest ip link set dev __IFNAME__ mtu 256
-iperf3 BW guest __GW__ 10002 __TIME__ __OPTS__ -w 1M
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -w 1M
bw __BW__ 0.2 0.3
guest ip link set dev __IFNAME__ mtu 576
-iperf3 BW guest __GW__ 10002 __TIME__ __OPTS__ -w 1M
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -w 1M
bw __BW__ 0.5 0.8
guest ip link set dev __IFNAME__ mtu 1280
-iperf3 BW guest __GW__ 10002 __TIME__ __OPTS__ -w 4M
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -w 4M
bw __BW__ 1.2 1.5
guest ip link set dev __IFNAME__ mtu 1500
-iperf3 BW guest __GW__ 10002 __TIME__ __OPTS__ -w 4M
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -w 4M
bw __BW__ 1.6 1.8
guest ip link set dev __IFNAME__ mtu 9000
-iperf3 BW guest __GW__ 10002 __TIME__ __OPTS__ -w 8M
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -w 8M
bw __BW__ 4.0 5.0
guest ip link set dev __IFNAME__ mtu 65520
-iperf3 BW guest __GW__ 10002 __TIME__ __OPTS__ -w 16M
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -w 16M
bw __BW__ 7.0 8.0
iperf3k ns
+# Reducing MTU below 1280 deconfigures IPv6, get our address back
+guest dhclient -6 -x
+guest dhclient -6 __IFNAME__
+# Wait for DAD to complete
+guest while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+
tl TCP RR latency over IPv4: guest to host
lat -
lat -
@@ -119,7 +126,7 @@ lat -
lat -
lat -
nsb tcp_rr --nolog -4
-gout LAT tcp_rr --nolog -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout LAT tcp_rr --nolog -l1 -4 -c -H __MAP_NS4__ | sed -n 's/^throughput=\(.*\)/\1/p'
lat __LAT__ 200 150
tl TCP CRR latency over IPv4: guest to host
@@ -129,7 +136,7 @@ lat -
lat -
lat -
nsb tcp_crr --nolog -4
-gout LAT tcp_crr --nolog -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout LAT tcp_crr --nolog -l1 -4 -c -H __MAP_NS4__ | sed -n 's/^throughput=\(.*\)/\1/p'
lat __LAT__ 500 400
tr TCP throughput over IPv6: host to guest
@@ -153,7 +160,7 @@ lat -
lat -
guestb tcp_rr --nolog -P 10001 -C 10011 -6
sleep 1
-nsout LAT tcp_rr --nolog -P 10001 -C 10011 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT tcp_rr --nolog -l1 -P 10001 -C 10011 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
lat __LAT__ 200 150
tl TCP CRR latency over IPv6: host to guest
@@ -164,7 +171,7 @@ lat -
lat -
guestb tcp_crr --nolog -P 10001 -C 10011 -6
sleep 1
-nsout LAT tcp_crr --nolog -P 10001 -C 10011 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT tcp_crr --nolog -l1 -P 10001 -C 10011 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
lat __LAT__ 500 350
@@ -189,7 +196,7 @@ lat -
lat -
guestb tcp_rr --nolog -P 10001 -C 10011 -4
sleep 1
-nsout LAT tcp_rr --nolog -P 10001 -C 10011 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT tcp_rr --nolog -l1 -P 10001 -C 10011 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
lat __LAT__ 200 150
tl TCP CRR latency over IPv6: host to guest
@@ -200,7 +207,7 @@ lat -
lat -
guestb tcp_crr --nolog -P 10001 -C 10011 -4
sleep 1
-nsout LAT tcp_crr --nolog -P 10001 -C 10011 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT tcp_crr --nolog -l1 -P 10001 -C 10011 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
lat __LAT__ 500 300
te
diff --git a/test/perf/passt_udp b/test/perf/passt_udp
index 8919280..4c66c41 100644
--- a/test/perf/passt_udp
+++ b/test/perf/passt_udp
@@ -15,6 +15,9 @@ gtools /sbin/sysctl ip jq nproc sleep iperf3 udp_rr # From neper
nstools ip jq sleep iperf3 udp_rr
htools bc head sed
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
test passt: throughput and latency
guest /sbin/sysctl -w net.core.rmem_max=16777216
@@ -22,16 +25,12 @@ guest /sbin/sysctl -w net.core.wmem_max=16777216
guest /sbin/sysctl -w net.core.rmem_default=16777216
guest /sbin/sysctl -w net.core.wmem_default=16777216
-gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
-gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
-
hout FREQ_PROCFS (echo "scale=1"; sed -n 's/cpu MHz.*: \([0-9]*\)\..*$/(\1+10^2\/2)\/10^3/p' /proc/cpuinfo) | bc -l | head -n1
hout FREQ_CPUFREQ (echo "scale=1"; printf '( %i + 10^5 / 2 ) / 10^6\n' $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq) ) | bc -l
hout FREQ [ -n "__FREQ_CPUFREQ__" ] && echo __FREQ_CPUFREQ__ || echo __FREQ_PROCFS__
set THREADS 2
-set TIME 10
+set TIME 1
set OPTS -u -P __THREADS__ --pacing-timer 1000
info Throughput in Gbps, latency in µs, __THREADS__ threads at __FREQ__ GHz
@@ -46,13 +45,13 @@ iperf3s ns 10002
bw -
bw -
-iperf3 BW guest __GW6__%__IFNAME__ 10002 __TIME__ __OPTS__ -b 3G -l 1232
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -b 3G -l 1232
bw __BW__ 0.8 1.2
-iperf3 BW guest __GW6__%__IFNAME__ 10002 __TIME__ __OPTS__ -b 4G -l 1452
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -b 4G -l 1452
bw __BW__ 1.0 1.5
-iperf3 BW guest __GW6__%__IFNAME__ 10002 __TIME__ __OPTS__ -b 8G -l 8952
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -b 8G -l 8952
bw __BW__ 4.0 5.0
-iperf3 BW guest __GW6__%__IFNAME__ 10002 __TIME__ __OPTS__ -b 15G -l 64372
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -b 15G -l 64372
bw __BW__ 4.0 5.0
iperf3k ns
@@ -64,7 +63,7 @@ lat -
lat -
lat -
nsb udp_rr --nolog -6
-gout LAT udp_rr --nolog -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout LAT udp_rr --nolog -6 -c -H __MAP_NS6__ | sed -n 's/^throughput=\(.*\)/\1/p'
lat __LAT__ 200 150
@@ -72,17 +71,17 @@ tr UDP throughput over IPv4: guest to host
iperf3s ns 10002
# (datagram size) = (packet size) - 28: 20 bytes of IPv4 header, 8 of UDP header
-iperf3 BW guest __GW__ 10002 __TIME__ __OPTS__ -b 1G -l 228
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -b 1G -l 228
bw __BW__ 0.0 0.0
-iperf3 BW guest __GW__ 10002 __TIME__ __OPTS__ -b 2G -l 548
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -b 2G -l 548
bw __BW__ 0.4 0.6
-iperf3 BW guest __GW__ 10002 __TIME__ __OPTS__ -b 3G -l 1252
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -b 3G -l 1252
bw __BW__ 0.8 1.2
-iperf3 BW guest __GW__ 10002 __TIME__ __OPTS__ -b 4G -l 1472
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -b 4G -l 1472
bw __BW__ 1.0 1.5
-iperf3 BW guest __GW__ 10002 __TIME__ __OPTS__ -b 8G -l 8972
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -b 8G -l 8972
bw __BW__ 4.0 5.0
-iperf3 BW guest __GW__ 10002 __TIME__ __OPTS__ -b 15G -l 65492
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -b 15G -l 65492
bw __BW__ 4.0 5.0
iperf3k ns
@@ -94,7 +93,7 @@ lat -
lat -
lat -
nsb udp_rr --nolog -4
-gout LAT udp_rr --nolog -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout LAT udp_rr --nolog -4 -c -H __MAP_NS4__ | sed -n 's/^throughput=\(.*\)/\1/p'
lat __LAT__ 200 150
diff --git a/test/perf/passt_vu_tcp b/test/perf/passt_vu_tcp
new file mode 100644
index 0000000..c4409b9
--- /dev/null
+++ b/test/perf/passt_vu_tcp
@@ -0,0 +1,211 @@
+# SPDX-License-Identifier: GPL-2.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/perf/passt_vu_tcp - Check TCP performance in passt vhost-user mode
+#
+# Copyright (c) 2021 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+gtools /sbin/sysctl ip jq nproc seq sleep iperf3 tcp_rr tcp_crr # From neper
+nstools /sbin/sysctl ip jq nproc seq sleep iperf3 tcp_rr tcp_crr
+htools bc head sed seq
+
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+test passt: throughput and latency
+
+guest /sbin/sysctl -w net.core.rmem_max=536870912
+guest /sbin/sysctl -w net.core.wmem_max=536870912
+guest /sbin/sysctl -w net.core.rmem_default=33554432
+guest /sbin/sysctl -w net.core.wmem_default=33554432
+guest /sbin/sysctl -w net.ipv4.tcp_rmem="4096 131072 268435456"
+guest /sbin/sysctl -w net.ipv4.tcp_wmem="4096 131072 268435456"
+guest /sbin/sysctl -w net.ipv4.tcp_timestamps=0
+
+ns /sbin/sysctl -w net.ipv4.tcp_rmem="4096 524288 134217728"
+ns /sbin/sysctl -w net.ipv4.tcp_wmem="4096 524288 134217728"
+ns /sbin/sysctl -w net.ipv4.tcp_timestamps=0
+
+gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+
+hout FREQ_PROCFS (echo "scale=1"; sed -n 's/cpu MHz.*: \([0-9]*\)\..*$/(\1+10^2\/2)\/10^3/p' /proc/cpuinfo) | bc -l | head -n1
+hout FREQ_CPUFREQ (echo "scale=1"; printf '( %i + 10^5 / 2 ) / 10^6\n' $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq) ) | bc -l
+hout FREQ [ -n "__FREQ_CPUFREQ__" ] && echo __FREQ_CPUFREQ__ || echo __FREQ_PROCFS__
+
+set THREADS 6
+set TIME 2
+set OMIT 0.1
+set OPTS -Z -P __THREADS__ -O__OMIT__ -N
+
+info Throughput in Gbps, latency in µs, __THREADS__ threads at __FREQ__ GHz
+report passt_vu tcp __THREADS__ __FREQ__
+
+th MTU 256B 576B 1280B 1500B 9000B 65520B
+
+
+tr TCP throughput over IPv6: guest to host
+iperf3s ns 10002
+
+bw -
+bw -
+guest ip link set dev __IFNAME__ mtu 1280
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -w 16M -l 1M
+bw __BW__ 1.2 1.5
+guest ip link set dev __IFNAME__ mtu 1500
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -w 32M -l 1M
+bw __BW__ 1.6 1.8
+guest ip link set dev __IFNAME__ mtu 9000
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -w 64M -l 1M
+bw __BW__ 4.0 5.0
+guest ip link set dev __IFNAME__ mtu 65520
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -w 64M -l 1M
+bw __BW__ 7.0 8.0
+
+iperf3k ns
+
+tl TCP RR latency over IPv6: guest to host
+lat -
+lat -
+lat -
+lat -
+lat -
+nsb tcp_rr --nolog -6
+gout LAT tcp_rr --nolog -l1 -6 -c -H __MAP_NS6__ | sed -n 's/^throughput=\(.*\)/\1/p'
+lat __LAT__ 200 150
+
+tl TCP CRR latency over IPv6: guest to host
+lat -
+lat -
+lat -
+lat -
+lat -
+nsb tcp_crr --nolog -6
+gout LAT tcp_crr --nolog -l1 -6 -c -H __MAP_NS6__ | sed -n 's/^throughput=\(.*\)/\1/p'
+lat __LAT__ 500 400
+
+tr TCP throughput over IPv4: guest to host
+iperf3s ns 10002
+
+guest ip link set dev __IFNAME__ mtu 256
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -w 2M -l 1M
+bw __BW__ 0.2 0.3
+guest ip link set dev __IFNAME__ mtu 576
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -w 4M -l 1M
+bw __BW__ 0.5 0.8
+guest ip link set dev __IFNAME__ mtu 1280
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -w 8M -l 1M
+bw __BW__ 1.2 1.5
+guest ip link set dev __IFNAME__ mtu 1500
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -w 16M -l 1M
+bw __BW__ 1.6 1.8
+guest ip link set dev __IFNAME__ mtu 9000
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -w 64M -l 1M
+bw __BW__ 4.0 5.0
+guest ip link set dev __IFNAME__ mtu 65520
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -w 64M -l 1M
+bw __BW__ 7.0 8.0
+
+iperf3k ns
+
+# Reducing MTU below 1280 deconfigures IPv6, get our address back
+guest dhclient -6 -x
+guest dhclient -6 __IFNAME__
+
+tl TCP RR latency over IPv4: guest to host
+lat -
+lat -
+lat -
+lat -
+lat -
+nsb tcp_rr --nolog -4
+gout LAT tcp_rr --nolog -l1 -4 -c -H __MAP_NS4__ | sed -n 's/^throughput=\(.*\)/\1/p'
+lat __LAT__ 200 150
+
+tl TCP CRR latency over IPv4: guest to host
+lat -
+lat -
+lat -
+lat -
+lat -
+nsb tcp_crr --nolog -4
+gout LAT tcp_crr --nolog -l1 -4 -c -H __MAP_NS4__ | sed -n 's/^throughput=\(.*\)/\1/p'
+lat __LAT__ 500 400
+
+tr TCP throughput over IPv6: host to guest
+iperf3s guest 10001
+
+bw -
+bw -
+bw -
+bw -
+bw -
+iperf3 BW ns ::1 10001 __TIME__ __OPTS__ -w 256M -l 16k
+bw __BW__ 6.0 6.8
+
+iperf3k guest
+
+tl TCP RR latency over IPv6: host to guest
+lat -
+lat -
+lat -
+lat -
+lat -
+guestb tcp_rr --nolog -P 10001 -C 10011 -6
+sleep 1
+nsout LAT tcp_rr --nolog -l1 -P 10001 -C 10011 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
+lat __LAT__ 200 150
+
+tl TCP CRR latency over IPv6: host to guest
+lat -
+lat -
+lat -
+lat -
+lat -
+guestb tcp_crr --nolog -P 10001 -C 10011 -6
+sleep 1
+nsout LAT tcp_crr --nolog -l1 -P 10001 -C 10011 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
+lat __LAT__ 500 350
+
+
+tr TCP throughput over IPv4: host to guest
+iperf3s guest 10001
+
+bw -
+bw -
+bw -
+bw -
+bw -
+iperf3 BW ns 127.0.0.1 10001 __TIME__ __OPTS__ -w 256M -l 16k
+bw __BW__ 6.0 6.8
+
+iperf3k guest
+
+tl TCP RR latency over IPv4: host to guest
+lat -
+lat -
+lat -
+lat -
+lat -
+guestb tcp_rr --nolog -P 10001 -C 10011 -4
+sleep 1
+nsout LAT tcp_rr --nolog -l1 -P 10001 -C 10011 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
+lat __LAT__ 200 150
+
+tl TCP CRR latency over IPv6: host to guest
+lat -
+lat -
+lat -
+lat -
+lat -
+guestb tcp_crr --nolog -P 10001 -C 10011 -4
+sleep 1
+nsout LAT tcp_crr --nolog -l1 -P 10001 -C 10011 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
+lat __LAT__ 500 300
+
+te
diff --git a/test/perf/passt_vu_udp b/test/perf/passt_vu_udp
new file mode 100644
index 0000000..943ac11
--- /dev/null
+++ b/test/perf/passt_vu_udp
@@ -0,0 +1,159 @@
+# SPDX-License-Identifier: GPL-2.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/perf/passt_vu_udp - Check UDP performance in passt vhost-user mode
+#
+# Copyright (c) 2021 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+gtools /sbin/sysctl ip jq nproc sleep iperf3 udp_rr # From neper
+nstools ip jq sleep iperf3 udp_rr
+htools bc head sed
+
+set MAP_NS4 192.0.2.2
+set MAP_NS6 2001:db8:9a55::2
+
+test passt: throughput and latency
+
+guest /sbin/sysctl -w net.core.rmem_max=16777216
+guest /sbin/sysctl -w net.core.wmem_max=16777216
+guest /sbin/sysctl -w net.core.rmem_default=16777216
+guest /sbin/sysctl -w net.core.wmem_default=16777216
+
+hout FREQ_PROCFS (echo "scale=1"; sed -n 's/cpu MHz.*: \([0-9]*\)\..*$/(\1+10^2\/2)\/10^3/p' /proc/cpuinfo) | bc -l | head -n1
+hout FREQ_CPUFREQ (echo "scale=1"; printf '( %i + 10^5 / 2 ) / 10^6\n' $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq) ) | bc -l
+hout FREQ [ -n "__FREQ_CPUFREQ__" ] && echo __FREQ_CPUFREQ__ || echo __FREQ_PROCFS__
+
+set THREADS 2
+set TIME 1
+set OPTS -u -P __THREADS__ --pacing-timer 1000
+
+info Throughput in Gbps, latency in µs, __THREADS__ threads at __FREQ__ GHz
+
+report passt_vu udp __THREADS__ __FREQ__
+
+th pktlen 256B 576B 1280B 1500B 9000B 65520B
+
+tr UDP throughput over IPv6: guest to host
+iperf3s ns 10002
+# (datagram size) = (packet size) - 48: 40 bytes of IPv6 header, 8 of UDP header
+
+bw -
+bw -
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -b 3G -l 1232
+bw __BW__ 0.8 1.2
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -b 4G -l 1452
+bw __BW__ 1.0 1.5
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -b 10G -l 8952
+bw __BW__ 4.0 5.0
+iperf3 BW guest __MAP_NS6__ 10002 __TIME__ __OPTS__ -b 20G -l 64372
+bw __BW__ 4.0 5.0
+
+iperf3k ns
+
+tl UDP RR latency over IPv6: guest to host
+lat -
+lat -
+lat -
+lat -
+lat -
+nsb udp_rr --nolog -6
+gout LAT udp_rr --nolog -6 -c -H __MAP_NS6__ | sed -n 's/^throughput=\(.*\)/\1/p'
+lat __LAT__ 200 150
+
+
+tr UDP throughput over IPv4: guest to host
+iperf3s ns 10002
+# (datagram size) = (packet size) - 28: 20 bytes of IPv4 header, 8 of UDP header
+
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -b 1G -l 228
+bw __BW__ 0.0 0.0
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -b 2G -l 548
+bw __BW__ 0.4 0.6
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -b 3G -l 1252
+bw __BW__ 0.8 1.2
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -b 4G -l 1472
+bw __BW__ 1.0 1.5
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -b 10G -l 8972
+bw __BW__ 4.0 5.0
+iperf3 BW guest __MAP_NS4__ 10002 __TIME__ __OPTS__ -b 20G -l 65492
+bw __BW__ 4.0 5.0
+
+iperf3k ns
+
+tl UDP RR latency over IPv4: guest to host
+lat -
+lat -
+lat -
+lat -
+lat -
+nsb udp_rr --nolog -4
+gout LAT udp_rr --nolog -4 -c -H __MAP_NS4__ | sed -n 's/^throughput=\(.*\)/\1/p'
+lat __LAT__ 200 150
+
+
+tr UDP throughput over IPv6: host to guest
+iperf3s guest 10001
+# (datagram size) = (packet size) - 48: 40 bytes of IPv6 header, 8 of UDP header
+
+bw -
+bw -
+iperf3 BW ns ::1 10001 __TIME__ __OPTS__ -b 3G -l 1232
+bw __BW__ 0.8 1.2
+iperf3 BW ns ::1 10001 __TIME__ __OPTS__ -b 4G -l 1452
+bw __BW__ 1.0 1.5
+iperf3 BW ns ::1 10001 __TIME__ __OPTS__ -b 10G -l 8952
+bw __BW__ 3.0 4.0
+iperf3 BW ns ::1 10001 __TIME__ __OPTS__ -b 20G -l 64372
+bw __BW__ 3.0 4.0
+
+iperf3k guest
+
+tl UDP RR latency over IPv6: host to guest
+lat -
+lat -
+lat -
+lat -
+lat -
+guestb udp_rr --nolog -P 10001 -C 10011 -6
+sleep 1
+nsout LAT udp_rr --nolog -P 10001 -C 10011 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
+lat __LAT__ 200 150
+
+
+tr UDP throughput over IPv4: host to guest
+iperf3s guest 10001
+# (datagram size) = (packet size) - 28: 20 bytes of IPv4 header, 8 of UDP header
+
+iperf3 BW ns 127.0.0.1 10001 __TIME__ __OPTS__ -b 1G -l 228
+bw __BW__ 0.0 0.0
+iperf3 BW ns 127.0.0.1 10001 __TIME__ __OPTS__ -b 2G -l 548
+bw __BW__ 0.4 0.6
+iperf3 BW ns 127.0.0.1 10001 __TIME__ __OPTS__ -b 3G -l 1252
+bw __BW__ 0.8 1.2
+iperf3 BW ns 127.0.0.1 10001 __TIME__ __OPTS__ -b 4G -l 1472
+bw __BW__ 1.0 1.5
+iperf3 BW ns 127.0.0.1 10001 __TIME__ __OPTS__ -b 10G -l 8972
+bw __BW__ 3.0 4.0
+iperf3 BW ns 127.0.0.1 10001 __TIME__ __OPTS__ -b 20G -l 65492
+bw __BW__ 3.0 4.0
+
+iperf3k guest
+
+tl UDP RR latency over IPv4: host to guest
+lat -
+lat -
+lat -
+lat -
+lat -
+guestb udp_rr --nolog -P 10001 -C 10011 -4
+sleep 1
+nsout LAT udp_rr --nolog -P 10001 -C 10011 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
+lat __LAT__ 200 150
+
+te
diff --git a/test/perf/pasta_tcp b/test/perf/pasta_tcp
index 8d2f911..bc0de3c 100644
--- a/test/perf/pasta_tcp
+++ b/test/perf/pasta_tcp
@@ -14,6 +14,9 @@
htools head ip seq bc sleep iperf3 tcp_rr tcp_crr jq sed
nstools /sbin/sysctl nproc ip seq sleep iperf3 tcp_rr tcp_crr jq sed
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+
test pasta: throughput and latency (local connections)
ns /sbin/sysctl -w net.ipv4.tcp_rmem="131072 524288 134217728"
@@ -22,7 +25,7 @@ ns /sbin/sysctl -w net.ipv4.tcp_timestamps=0
set THREADS 4
-set TIME 10
+set TIME 1
set OMIT 0.1
set OPTS -Z -w 4M -l 1M -P __THREADS__ -O__OMIT__
@@ -46,13 +49,13 @@ iperf3k host
tl TCP RR latency over IPv6: ns to host
hostb tcp_rr --nolog -P 10003 -C 10013 -6
-nsout LAT tcp_rr --nolog -P 10003 -C 10013 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT tcp_rr --nolog -l1 -P 10003 -C 10013 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
hostw
lat __LAT__ 150 100
tl TCP CRR latency over IPv6: ns to host
hostb tcp_crr --nolog -P 10003 -C 10013 -6
-nsout LAT tcp_crr --nolog -P 10003 -C 10013 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT tcp_crr --nolog -l1 -P 10003 -C 10013 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
hostw
lat __LAT__ 500 350
@@ -67,13 +70,13 @@ iperf3k host
tl TCP RR latency over IPv4: ns to host
hostb tcp_rr --nolog -P 10003 -C 10013 -4
-nsout LAT tcp_rr --nolog -P 10003 -C 10013 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT tcp_rr --nolog -l1 -P 10003 -C 10013 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
hostw
lat __LAT__ 150 100
tl TCP CRR latency over IPv4: ns to host
hostb tcp_crr --nolog -P 10003 -C 10013 -4
-nsout LAT tcp_crr --nolog -P 10003 -C 10013 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT tcp_crr --nolog -l1 -P 10003 -C 10013 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
hostw
lat __LAT__ 500 350
@@ -87,13 +90,13 @@ iperf3k ns
tl TCP RR latency over IPv6: host to ns
nsb tcp_rr --nolog -P 10002 -C 10012 -6
-hout LAT tcp_rr --nolog -P 10002 -C 10012 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
+hout LAT tcp_rr --nolog -l1 -P 10002 -C 10012 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
nsw
lat __LAT__ 150 100
tl TCP CRR latency over IPv6: host to ns
nsb tcp_crr --nolog -P 10002 -C 10012 -6
-hout LAT tcp_crr --nolog -P 10002 -C 10012 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
+hout LAT tcp_crr --nolog -l1 -P 10002 -C 10012 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p'
nsw
lat __LAT__ 1000 700
@@ -108,13 +111,13 @@ iperf3k ns
tl TCP RR latency over IPv4: host to ns
nsb tcp_rr --nolog -P 10002 -C 10012 -4
-hout LAT tcp_rr --nolog -P 10002 -C 10012 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
+hout LAT tcp_rr --nolog -l1 -P 10002 -C 10012 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
nsw
lat __LAT__ 150 100
tl TCP CRR latency over IPv4: host to ns
nsb tcp_crr --nolog -P 10002 -C 10012 -4
-hout LAT tcp_crr --nolog -P 10002 -C 10012 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
+hout LAT tcp_crr --nolog -l1 -P 10002 -C 10012 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p'
nsw
lat __LAT__ 1000 700
@@ -122,8 +125,6 @@ te
test pasta: throughput and latency (connections via tap)
-nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
set THREADS 2
set OPTS -Z -P __THREADS__ -i1 -O__OMIT__
@@ -137,16 +138,16 @@ tr TCP throughput over IPv6: ns to host
iperf3s host 10003
ns ip link set dev __IFNAME__ mtu 1500
-iperf3 BW ns __GW6__%__IFNAME__ 10003 __TIME__ __OPTS__ -w 512k
+iperf3 BW ns __MAP_HOST6__ 10003 __TIME__ __OPTS__ -w 512k
bw __BW__ 0.2 0.4
ns ip link set dev __IFNAME__ mtu 4000
-iperf3 BW ns __GW6__%__IFNAME__ 10003 __TIME__ __OPTS__ -w 1M
+iperf3 BW ns __MAP_HOST6__ 10003 __TIME__ __OPTS__ -w 1M
bw __BW__ 0.3 0.5
ns ip link set dev __IFNAME__ mtu 16384
-iperf3 BW ns __GW6__%__IFNAME__ 10003 __TIME__ __OPTS__ -w 8M
+iperf3 BW ns __MAP_HOST6__ 10003 __TIME__ __OPTS__ -w 8M
bw __BW__ 1.5 2.0
ns ip link set dev __IFNAME__ mtu 65520
-iperf3 BW ns __GW6__%__IFNAME__ 10003 __TIME__ __OPTS__ -w 8M
+iperf3 BW ns __MAP_HOST6__ 10003 __TIME__ __OPTS__ -w 8M
bw __BW__ 2.0 2.5
iperf3k host
@@ -156,7 +157,7 @@ lat -
lat -
lat -
hostb tcp_rr --nolog -P 10003 -C 10013 -6
-nsout LAT tcp_rr --nolog -P 10003 -C 10013 -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT tcp_rr --nolog -l1 -P 10003 -C 10013 -6 -c -H __MAP_HOST6__ | sed -n 's/^throughput=\(.*\)/\1/p'
hostw
lat __LAT__ 150 100
@@ -165,7 +166,7 @@ lat -
lat -
lat -
hostb tcp_crr --nolog -P 10003 -C 10013 -6
-nsout LAT tcp_crr --nolog -P 10003 -C 10013 -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT tcp_crr --nolog -l1 -P 10003 -C 10013 -6 -c -H __MAP_HOST6__ | sed -n 's/^throughput=\(.*\)/\1/p'
hostw
lat __LAT__ 1500 500
@@ -174,16 +175,16 @@ tr TCP throughput over IPv4: ns to host
iperf3s host 10003
ns ip link set dev __IFNAME__ mtu 1500
-iperf3 BW ns __GW__ 10003 __TIME__ __OPTS__ -w 512k
+iperf3 BW ns __MAP_HOST4__ 10003 __TIME__ __OPTS__ -w 512k
bw __BW__ 0.2 0.4
ns ip link set dev __IFNAME__ mtu 4000
-iperf3 BW ns __GW__ 10003 __TIME__ __OPTS__ -w 1M
+iperf3 BW ns __MAP_HOST4__ 10003 __TIME__ __OPTS__ -w 1M
bw __BW__ 0.3 0.5
ns ip link set dev __IFNAME__ mtu 16384
-iperf3 BW ns __GW__ 10003 __TIME__ __OPTS__ -w 8M
+iperf3 BW ns __MAP_HOST4__ 10003 __TIME__ __OPTS__ -w 8M
bw __BW__ 1.5 2.0
ns ip link set dev __IFNAME__ mtu 65520
-iperf3 BW ns __GW__ 10003 __TIME__ __OPTS__ -w 8M
+iperf3 BW ns __MAP_HOST4__ 10003 __TIME__ __OPTS__ -w 8M
bw __BW__ 2.0 2.5
iperf3k host
@@ -193,7 +194,7 @@ lat -
lat -
lat -
hostb tcp_rr --nolog -P 10003 -C 10013 -4
-nsout LAT tcp_rr --nolog -P 10003 -C 10013 -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT tcp_rr --nolog -l1 -P 10003 -C 10013 -4 -c -H __MAP_HOST4__ | sed -n 's/^throughput=\(.*\)/\1/p'
hostw
lat __LAT__ 150 100
@@ -202,7 +203,7 @@ lat -
lat -
lat -
hostb tcp_crr --nolog -P 10003 -C 10013 -4
-nsout LAT tcp_crr --nolog -P 10003 -C 10013 -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT tcp_crr --nolog -l1 -P 10003 -C 10013 -4 -c -H __MAP_HOST4__ | sed -n 's/^throughput=\(.*\)/\1/p'
hostw
lat __LAT__ 1500 500
@@ -210,7 +211,7 @@ tr TCP throughput over IPv6: host to ns
iperf3s ns 10002
nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
-nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global" and .prefixlen == 64).local'
+nsout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global").local] | .[0]'
bw -
bw -
bw -
@@ -224,7 +225,7 @@ lat -
lat -
lat -
nsb tcp_rr --nolog -P 10002 -C 10012 -6
-hout LAT tcp_rr --nolog -P 10002 -C 10012 -6 -c -H __ADDR6__ | sed -n 's/^throughput=\(.*\)/\1/p'
+hout LAT tcp_rr --nolog -l1 -P 10002 -C 10012 -6 -c -H __ADDR6__ | sed -n 's/^throughput=\(.*\)/\1/p'
nsw
lat __LAT__ 150 100
@@ -234,7 +235,7 @@ lat -
lat -
sleep 1
nsb tcp_crr --nolog -P 10002 -C 10012 -6
-hout LAT tcp_crr --nolog -P 10002 -C 10012 -6 -c -H __ADDR6__ | sed -n 's/^throughput=\(.*\)/\1/p'
+hout LAT tcp_crr --nolog -l1 -P 10002 -C 10012 -6 -c -H __ADDR6__ | sed -n 's/^throughput=\(.*\)/\1/p'
nsw
lat __LAT__ 5000 10000
@@ -256,7 +257,7 @@ lat -
lat -
lat -
nsb tcp_rr --nolog -P 10002 -C 10012 -4
-hout LAT tcp_rr --nolog -P 10002 -C 10012 -4 -c -H __ADDR__ | sed -n 's/^throughput=\(.*\)/\1/p'
+hout LAT tcp_rr --nolog -l1 -P 10002 -C 10012 -4 -c -H __ADDR__ | sed -n 's/^throughput=\(.*\)/\1/p'
nsw
lat __LAT__ 150 100
@@ -266,7 +267,7 @@ lat -
lat -
sleep 1
nsb tcp_crr --nolog -P 10002 -C 10012 -4
-hout LAT tcp_crr --nolog -P 10002 -C 10012 -4 -c -H __ADDR__ | sed -n 's/^throughput=\(.*\)/\1/p'
+hout LAT tcp_crr --nolog -l1 -P 10002 -C 10012 -4 -c -H __ADDR__ | sed -n 's/^throughput=\(.*\)/\1/p'
nsw
lat __LAT__ 5000 10000
diff --git a/test/perf/pasta_udp b/test/perf/pasta_udp
index 6acbfd3..ab2f3e8 100644
--- a/test/perf/pasta_udp
+++ b/test/perf/pasta_udp
@@ -14,6 +14,9 @@
htools bc head ip sleep iperf3 udp_rr jq sed
nstools ip sleep iperf3 udp_rr jq sed
+set MAP_HOST4 192.0.2.1
+set MAP_HOST6 2001:db8:9a55::1
+
test pasta: throughput and latency (local traffic)
hout FREQ_PROCFS (echo "scale=1"; sed -n 's/cpu MHz.*: \([0-9]*\)\..*$/(\1+10^2\/2)\/10^3/p' /proc/cpuinfo) | bc -l | head -n1
@@ -21,7 +24,7 @@ hout FREQ_CPUFREQ (echo "scale=1"; printf '( %i + 10^5 / 2 ) / 10^6\n' $(cat /sy
hout FREQ [ -n "__FREQ_CPUFREQ__" ] && echo __FREQ_CPUFREQ__ || echo __FREQ_PROCFS__
set THREADS 1
-set TIME 10
+set TIME 1
set OPTS -u -P __THREADS__
info Throughput in Gbps, latency in µs, one thread at __FREQ__ GHz
@@ -133,8 +136,6 @@ te
test pasta: throughput and latency (traffic via tap)
-nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
info Throughput in Gbps, latency in µs, one thread at __FREQ__ GHz
@@ -146,13 +147,13 @@ tr UDP throughput over IPv6: ns to host
iperf3s host 10003
# (datagram size) = (packet size) - 48: 40 bytes of IPv6 header, 8 of UDP header
-iperf3 BW ns __GW6__%__IFNAME__ 10003 __TIME__ __OPTS__ -b 8G -l 1472
+iperf3 BW ns __MAP_HOST6__ 10003 __TIME__ __OPTS__ -b 8G -l 1472
bw __BW__ 0.3 0.5
-iperf3 BW ns __GW6__%__IFNAME__ 10003 __TIME__ __OPTS__ -b 12G -l 3972
+iperf3 BW ns __MAP_HOST6__ 10003 __TIME__ __OPTS__ -b 12G -l 3972
bw __BW__ 0.5 0.8
-iperf3 BW ns __GW6__%__IFNAME__ 10003 __TIME__ __OPTS__ -b 20G -l 16356
+iperf3 BW ns __MAP_HOST6__ 10003 __TIME__ __OPTS__ -b 20G -l 16356
bw __BW__ 3.0 4.0
-iperf3 BW ns __GW6__%__IFNAME__ 10003 __TIME__ __OPTS__ -b 30G -l 65472
+iperf3 BW ns __MAP_HOST6__ 10003 __TIME__ __OPTS__ -b 30G -l 65472
bw __BW__ 6.0 7.0
iperf3k host
@@ -162,7 +163,7 @@ lat -
lat -
lat -
hostb udp_rr --nolog -P 10003 -C 10013 -6
-nsout LAT udp_rr --nolog -P 10003 -C 10013 -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT udp_rr --nolog -P 10003 -C 10013 -6 -c -H __MAP_HOST6__ | sed -n 's/^throughput=\(.*\)/\1/p'
hostw
lat __LAT__ 200 150
@@ -171,13 +172,13 @@ tr UDP throughput over IPv4: ns to host
iperf3s host 10003
# (datagram size) = (packet size) - 28: 20 bytes of IPv4 header, 8 of UDP header
-iperf3 BW ns __GW__ 10003 __TIME__ __OPTS__ -b 8G -l 1472
+iperf3 BW ns __MAP_HOST4__ 10003 __TIME__ __OPTS__ -b 8G -l 1472
bw __BW__ 0.3 0.5
-iperf3 BW ns __GW__ 10003 __TIME__ __OPTS__ -b 12G -l 3972
+iperf3 BW ns __MAP_HOST4__ 10003 __TIME__ __OPTS__ -b 12G -l 3972
bw __BW__ 0.5 0.8
-iperf3 BW ns __GW__ 10003 __TIME__ __OPTS__ -b 20G -l 16356
+iperf3 BW ns __MAP_HOST4__ 10003 __TIME__ __OPTS__ -b 20G -l 16356
bw __BW__ 3.0 4.0
-iperf3 BW ns __GW__ 10003 __TIME__ __OPTS__ -b 30G -l 65492
+iperf3 BW ns __MAP_HOST4__ 10003 __TIME__ __OPTS__ -b 30G -l 65492
bw __BW__ 6.0 7.0
iperf3k host
@@ -187,7 +188,7 @@ lat -
lat -
lat -
hostb udp_rr --nolog -P 10003 -C 10013 -4
-nsout LAT udp_rr --nolog -P 10003 -C 10013 -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout LAT udp_rr --nolog -P 10003 -C 10013 -4 -c -H __MAP_HOST4__ | sed -n 's/^throughput=\(.*\)/\1/p'
hostw
lat __LAT__ 200 150
@@ -195,7 +196,7 @@ tr UDP throughput over IPv6: host to ns
iperf3s ns 10002
nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
-nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global" and .prefixlen == 64).local'
+nsout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global").local] | .[0]'
iperf3 BW host __ADDR6__ 10002 __TIME__ __OPTS__ -b 8G -l 1472
bw __BW__ 0.3 0.5
iperf3 BW host __ADDR6__ 10002 __TIME__ __OPTS__ -b 12G -l 3972
diff --git a/test/rampstream-check.sh b/test/rampstream-check.sh
new file mode 100755
index 0000000..c27acdb
--- /dev/null
+++ b/test/rampstream-check.sh
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+(rampstream check "$@" 2>&1; echo $? > rampstream.status) | tee rampstream.err
diff --git a/test/rampstream.c b/test/rampstream.c
new file mode 100644
index 0000000..8d81296
--- /dev/null
+++ b/test/rampstream.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/* rampstream - Generate a check and stream of bytes in a ramp pattern
+ *
+ * Copyright Red Hat
+ * Author: David Gibson <david@gibson.dropbear.id.au>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+/* Length of the repeating ramp. This is a deliberately not a "round" number so
+ * that we're very likely to misalign with likely block or chunk sizes of the
+ * transport. That means we'll detect gaps in the stream, even if they occur
+ * neatly on block boundaries. Specifically this is the largest 8-bit prime. */
+#define RAMPLEN 251
+
+#define INTERVAL 10000
+
+#define ARRAY_SIZE(a) ((int)(sizeof(a) / sizeof((a)[0])))
+
+#define die(...) \
+ do { \
+ fprintf(stderr, "rampstream: " __VA_ARGS__); \
+ exit(1); \
+ } while (0)
+
+static void usage(void)
+{
+ die("Usage:\n"
+ " rampstream send <number>\n"
+ " Generate a ramp pattern of bytes on stdout, repeated <number>\n"
+ " times\n"
+ " rampstream check <number>\n"
+ " Check a ramp pattern of bytes on stdin, repeater <number>\n"
+ " times\n");
+}
+
+static void ramp_send(unsigned long long num, const uint8_t *ramp)
+{
+ unsigned long long i;
+
+ for (i = 0; i < num; i++) {
+ int off = 0;
+ ssize_t rc;
+
+ if (i % INTERVAL == 0)
+ fprintf(stderr, "%llu...\r", i);
+
+ while (off < RAMPLEN) {
+ rc = write(1, ramp + off, RAMPLEN - off);
+ if (rc < 0) {
+ if (errno == EINTR ||
+ errno == EAGAIN ||
+ errno == EWOULDBLOCK)
+ continue;
+ die("Error writing ramp: %s\n",
+ strerror(errno));
+ }
+ if (rc == 0)
+ die("Zero length write\n");
+ off += rc;
+ }
+ }
+}
+
+static void ramp_check(unsigned long long num, const uint8_t *ramp)
+{
+ unsigned long long i;
+
+ for (i = 0; i < num; i++) {
+ uint8_t buf[RAMPLEN];
+ int off = 0;
+ ssize_t rc;
+
+ if (i % INTERVAL == 0)
+ fprintf(stderr, "%llu...\r", i);
+
+ while (off < RAMPLEN) {
+ rc = read(0, buf + off, RAMPLEN - off);
+ if (rc < 0) {
+ if (errno == EINTR ||
+ errno == EAGAIN ||
+ errno == EWOULDBLOCK)
+ continue;
+ die("Error reading ramp: %s\n",
+ strerror(errno));
+ }
+ if (rc == 0)
+ die("Unexpected EOF, ramp %llu, byte %d\n",
+ i, off);
+ off += rc;
+ }
+
+ if (memcmp(buf, ramp, sizeof(buf)) != 0) {
+ int j, k;
+
+ for (j = 0; j < RAMPLEN; j++)
+ if (buf[j] != ramp[j])
+ break;
+ for (k = j; k < RAMPLEN && k < j + 16; k++)
+ fprintf(stderr,
+ "Byte %d: expected 0x%02x, got 0x%02x\n",
+ k, ramp[k], buf[k]);
+ die("Data mismatch, ramp %llu, byte %d\n", i, j);
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ const char *subcmd = argv[1];
+ unsigned long long num;
+ uint8_t ramp[RAMPLEN];
+ char *e;
+ int i;
+
+ if (argc < 2)
+ usage();
+
+ errno = 0;
+ num = strtoull(argv[2], &e, 0);
+ if (*e || errno)
+ usage();
+
+ /* Initialize the ramp block */
+ for (i = 0; i < RAMPLEN; i++)
+ ramp[i] = i;
+
+ if (strcmp(subcmd, "send") == 0)
+ ramp_send(num, ramp);
+ else if (strcmp(subcmd, "check") == 0)
+ ramp_check(num, ramp);
+ else
+ usage();
+
+ exit(0);
+}
diff --git a/test/run b/test/run
index 3b37663..f73c311 100755
--- a/test/run
+++ b/test/run
@@ -38,6 +38,9 @@ TRACE=${TRACE:-0}
# If set, tell passt and pasta to take packet captures
PCAP=${PCAP:-0}
+# Custom kernel to boot guests with, if given
+KERNEL=${KERNEL:-"/boot/vmlinuz-$(uname -r)"}
+
COMMIT="$(git log --oneline --no-decorate -1)"
. lib/util
@@ -90,6 +93,7 @@ run() {
test memory/passt
teardown memory
+ VHOST_USER=0
setup passt
test passt/ndp
test passt/dhcp
@@ -101,7 +105,7 @@ run() {
VALGRIND=1
setup passt_in_ns
test passt/ndp
- test passt/dhcp
+ test passt_in_ns/dhcp
test passt_in_ns/icmp
test passt_in_ns/tcp
test passt_in_ns/udp
@@ -112,10 +116,62 @@ run() {
test two_guests/basic
teardown two_guests
+ VHOST_USER=1
+ setup passt_in_ns
+ test passt_vu/ndp
+ test passt_vu_in_ns/dhcp
+ test passt_vu_in_ns/icmp
+ test passt_vu_in_ns/tcp
+ test passt_vu_in_ns/udp
+ test passt_vu_in_ns/shutdown
+ teardown passt_in_ns
+
+ setup two_guests
+ test two_guests_vu/basic
+ teardown two_guests
+
+ setup migrate
+ test migrate/basic
+ teardown migrate
+ setup migrate
+ test migrate/basic_fin
+ teardown migrate
+ setup migrate
+ test migrate/bidirectional
+ teardown migrate
+ setup migrate
+ test migrate/bidirectional_fin
+ teardown migrate
+ setup migrate
+ test migrate/iperf3_out4
+ teardown migrate
+ setup migrate
+ test migrate/iperf3_out6
+ teardown migrate
+ setup migrate
+ test migrate/iperf3_in4
+ teardown migrate
+ setup migrate
+ test migrate/iperf3_in6
+ teardown migrate
+ setup migrate
+ test migrate/iperf3_bidir6
+ teardown migrate
+ setup migrate
+ test migrate/iperf3_many_out6
+ teardown migrate
+ setup migrate
+ test migrate/rampstream_in
+ teardown migrate
+ setup migrate
+ test migrate/rampstream_out
+ teardown migrate
+
VALGRIND=0
+ VHOST_USER=0
setup passt_in_ns
test passt/ndp
- test passt/dhcp
+ test passt_in_ns/dhcp
test perf/passt_tcp
test perf/passt_udp
test perf/pasta_tcp
@@ -123,6 +179,15 @@ run() {
test passt_in_ns/shutdown
teardown passt_in_ns
+ VHOST_USER=1
+ setup passt_in_ns
+ test passt_vu/ndp
+ test passt_vu_in_ns/dhcp
+ test perf/passt_vu_tcp
+ test perf/passt_vu_udp
+ test passt_vu_in_ns/shutdown
+ teardown passt_in_ns
+
# TODO: Make those faster by at least pre-installing gcc and make on
# non-x86 images, then re-enable.
skip_distro() {
@@ -137,7 +202,7 @@ skip_distro() {
perf_finish
[ ${CI} -eq 1 ] && video_stop
- log "PASS: ${STATUS_PASS}, FAIL: ${STATUS_FAIL}"
+ log "PASS: ${STATUS_PASS}, FAIL: ${STATUS_FAIL}, SKIPPED: ${STATUS_SKIPPED}"
pause_continue \
"Press any key to keep test session open" \
@@ -158,7 +223,10 @@ run_selected() {
__setup=
for __test; do
- if [ "${__test%%/*}" != "${__setup}" ]; then
+ # HACK: the migrate tests need the setup repeated for
+ # each test
+ if [ "${__test%%/*}" != "${__setup}" -o \
+ "${__test%%/*}" = "migrate" ]; then
[ -n "${__setup}" ] && teardown "${__setup}"
__setup="${__test%%/*}"
setup "${__setup}"
@@ -168,7 +236,7 @@ run_selected() {
done
teardown "${__setup}"
- log "PASS: ${STATUS_PASS}, FAIL: ${STATUS_FAIL}"
+ log "PASS: ${STATUS_PASS}, FAIL: ${STATUS_FAIL}, SKIPPED: ${STATUS_SKIPPED}"
pause_continue \
"Press any key to keep test session open" \
@@ -239,4 +307,4 @@ fi
tail -n1 ${LOGFILE}
echo "Log at ${LOGFILE}"
-exit $(tail -n1 ${LOGFILE} | sed -n 's/.*FAIL: \(.*\)$/\1/p')
+exit $(tail -n1 ${LOGFILE} | sed -n 's/.*FAIL: \(.*\),.*$/\1/p')
diff --git a/test/two_guests/basic b/test/two_guests/basic
index 4d49e85..e2338ff 100644
--- a/test/two_guests/basic
+++ b/test/two_guests/basic
@@ -36,9 +36,13 @@ check [ "__ADDR2__" = "__HOST_ADDR__" ]
test DHCPv6: addresses
# Link is up now, wait for DAD to complete
-sleep 2
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+guest2 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
guest1 /sbin/dhclient -6 __IFNAME1__
guest2 /sbin/dhclient -6 __IFNAME2__
+# Wait for DAD to complete on the DHCP address
+guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
+guest2 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done
g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
g2out ADDR2_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME2__").addr_info[] | select(.prefixlen == 128).local] | .[0]'
hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]'
@@ -48,33 +52,33 @@ check [ "__ADDR2_6__" = "__HOST_ADDR6__" ]
test TCP/IPv4: guest 1 > guest 2
g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
guest2b socat -u TCP4-LISTEN:10004 OPEN:msg,create,trunc
+sleep 1
guest1 echo "Hello_from_guest_1" | socat -u STDIN TCP4:__GW1__:10004
guest2w
-sleep 1
g2out MSG2 cat msg
check [ "__MSG2__" = "Hello_from_guest_1" ]
test TCP/IPv6: guest 2 > guest 1
g2out GW2_6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
guest1b socat -u TCP6-LISTEN:10001 OPEN:msg,create,trunc
+sleep 1
guest2 echo "Hello_from_guest_2" | socat -u STDIN TCP6:[__GW2_6__%__IFNAME2__]:10001
guest1w
-sleep 1
g1out MSG1 cat msg
check [ "__MSG1__" = "Hello_from_guest_2" ]
test UDP/IPv4: guest 1 > guest 2
guest2b socat -u TCP4-LISTEN:10004 OPEN:msg,create,trunc
+sleep 1
guest1 echo "Hello_from_guest_1" | socat -u STDIN TCP4:__GW1__:10004
guest2w
-sleep 1
g2out MSG2 cat msg
check [ "__MSG2__" = "Hello_from_guest_1" ]
test UDP/IPv6: guest 2 > guest 1
guest1b socat -u TCP6-LISTEN:10001 OPEN:msg,create,trunc
+sleep 1
guest2 echo "Hello_from_guest_2" | socat -u STDIN TCP6:[__GW2_6__%__IFNAME2__]:10001
guest1w
-sleep 1
g1out MSG1 cat msg
check [ "__MSG1__" = "Hello_from_guest_2" ]
diff --git a/test/two_guests_vu b/test/two_guests_vu
new file mode 120000
index 0000000..a8648fc
--- /dev/null
+++ b/test/two_guests_vu
@@ -0,0 +1 @@
+two_guests \ No newline at end of file
diff --git a/test/valgrind.supp b/test/valgrind.supp
index a158394..735b5f6 100644
--- a/test/valgrind.supp
+++ b/test/valgrind.supp
@@ -6,3 +6,12 @@
...
fun:tcp_sock_consume
}
+
+# same as above, for architectures with the recv() system call (at least i686):
+{
+ passt_recv_MSG_TRUNC_into_NULL_buffer
+ Memcheck:Param
+ socketcall.recv(buf)
+ ...
+ fun:tcp_sock_consume
+}