From: David Gibson <david@gibson.dropbear.id.au>
To: Stefano Brivio <sbrivio@redhat.com>
Cc: passt-dev@passt.top
Subject: Re: [PATCH v27 2/2] test: Add migration tests
Date: Mon, 17 Feb 2025 14:47:03 +1100 [thread overview]
Message-ID: <Z7KxN5DAlygeo1_R@zatzit> (raw)
In-Reply-To: <20250216222227.2017788-3-sbrivio@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 45198 bytes --]
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 <david@gibson.dropbear.id.au>
> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> 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 <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
> 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 <sbrivio@redhat.com>
> +# Copyright (c) 2025 Red Hat
> +# Author: David Gibson <david@gibson.dropbear.id.au>
>
> 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 <sbrivio@redhat.com>
> +# Copyright (c) 2025 Red Hat
> +# Author: David Gibson <david@gibson.dropbear.id.au>
>
> 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
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
prev parent reply other threads:[~2025-02-17 3:47 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-16 22:22 [PATCH v27 0/2] State migration, perhaps final (#2)? Stefano Brivio
2025-02-16 22:22 ` [PATCH v27 1/2] migrate: Migrate TCP flows Stefano Brivio
2025-02-17 3:46 ` David Gibson
2025-02-16 22:22 ` [PATCH v27 2/2] test: Add migration tests Stefano Brivio
2025-02-17 3:47 ` David Gibson [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Z7KxN5DAlygeo1_R@zatzit \
--to=david@gibson.dropbear.id.au \
--cc=passt-dev@passt.top \
--cc=sbrivio@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://passt.top/passt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).