On Sun, Feb 16, 2025 at 11:22:27PM +0100, Stefano Brivio wrote: > PCAP=1 ./run migrate/bidirectional gives an overview of how the > whole thing is working. > > Add 12 tests in total, checking basic functionality with and without > flows in both directions, with and without sockets in half-closed > states (both inbound and outbound), migration behaviour under traffic > flood, under traffic flood with > 253 flows, and strict checking of > sequences under flood with ramp patterns in both directions. > > These tests need preparation and teardown for each case, as we need > to restore the source guest in its own context and pane before we can > test again. Eventually, we could consider alternating source and > target so that we don't need to restart from scratch every time, but > that's beyond the scope of this initial test implementation. > > Trick: './run migrate/*' runs all the tests with preparation and > teardown steps. > > Co-authored-by: David Gibson > Signed-off-by: Stefano Brivio Reviewed-by: David Gibson > --- > test/lib/layout | 55 ++++++++++++- > test/lib/setup | 138 ++++++++++++++++++++++++++++++++- > test/lib/test | 48 ++++++++++++ > test/migrate/basic | 59 ++++++++++++++ > test/migrate/basic_fin | 62 +++++++++++++++ > test/migrate/bidirectional | 64 +++++++++++++++ > test/migrate/bidirectional_fin | 64 +++++++++++++++ > test/migrate/iperf3_bidir6 | 58 ++++++++++++++ > test/migrate/iperf3_in4 | 50 ++++++++++++ > test/migrate/iperf3_in6 | 58 ++++++++++++++ > test/migrate/iperf3_many_out6 | 60 ++++++++++++++ > test/migrate/iperf3_out4 | 47 +++++++++++ > test/migrate/iperf3_out6 | 58 ++++++++++++++ > test/migrate/rampstream_in | 12 +-- > test/migrate/rampstream_out | 8 +- > test/run | 42 +++++++++- > 16 files changed, 870 insertions(+), 13 deletions(-) > create mode 100644 test/migrate/basic > create mode 100644 test/migrate/basic_fin > create mode 100644 test/migrate/bidirectional > create mode 100644 test/migrate/bidirectional_fin > create mode 100644 test/migrate/iperf3_bidir6 > create mode 100644 test/migrate/iperf3_in4 > create mode 100644 test/migrate/iperf3_in6 > create mode 100644 test/migrate/iperf3_many_out6 > create mode 100644 test/migrate/iperf3_out4 > create mode 100644 test/migrate/iperf3_out6 > > diff --git a/test/lib/layout b/test/lib/layout > index 4d03572..fddcdc4 100644 > --- a/test/lib/layout > +++ b/test/lib/layout > @@ -134,6 +134,54 @@ 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 > > @@ -141,11 +189,16 @@ layout_two_guests() { > 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 > } > diff --git a/test/lib/setup b/test/lib/setup > index ee67152..575bc21 100755 > --- a/test/lib/setup > +++ b/test/lib/setup > @@ -305,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 > @@ -375,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 > @@ -384,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/test b/test/lib/test > index e6726be..758250a 100755 > --- a/test/lib/test > +++ b/test/lib/test > @@ -68,6 +68,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 +216,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 +337,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 > + > +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 > + > +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 > + > +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 > + > +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 > + > +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 > + > +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 > + > +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 > + > +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 > + > +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 > + > +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 > index 46f4143..df333ba 100644 > --- a/test/migrate/rampstream_in > +++ b/test/migrate/rampstream_in > @@ -6,10 +6,10 @@ > # PASTA - Pack A Subtle Tap Abstraction > # for network namespace/tap device mode > # > -# test/migrate/basic - Check basic migration functionality > +# test/migrate/rampstream_in - Check sequence correctness with inbound ramp > # > -# Copyright (c) 2025 Red Hat GmbH > -# Author: Stefano Brivio > +# Copyright (c) 2025 Red Hat > +# Author: David Gibson > > g1tools ip jq dhclient socat cat > htools ip jq > @@ -43,15 +43,15 @@ g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__") > 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: host > guest > +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 > +sleep 1 > > -#mon echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock > +monb echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qemu_1_mon.sock > > hostw > > diff --git a/test/migrate/rampstream_out b/test/migrate/rampstream_out > index 91b9c63..8ed3229 100644 > --- a/test/migrate/rampstream_out > +++ b/test/migrate/rampstream_out > @@ -6,10 +6,10 @@ > # PASTA - Pack A Subtle Tap Abstraction > # for network namespace/tap device mode > # > -# test/migrate/basic - Check basic migration functionality > +# test/migrate/rampstream_out - Check sequence correctness with outbound ramp > # > -# Copyright (c) 2025 Red Hat GmbH > -# Author: Stefano Brivio > +# Copyright (c) 2025 Red Hat > +# Author: David Gibson > > g1tools ip jq dhclient socat cat > htools ip jq > @@ -43,7 +43,7 @@ g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__") > 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: guest > host > +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 > diff --git a/test/run b/test/run > index f188d8e..4e86f30 100755 > --- a/test/run > +++ b/test/run > @@ -130,6 +130,43 @@ run() { > 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 > @@ -186,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}" -- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson