From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202502 header.b=B31IYs44; dkim-atps=neutral Received: from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id 9D8FB5A0275 for ; Mon, 17 Feb 2025 04:47:24 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202502; t=1739764033; bh=LAHICmzq3CqM2TLTJcSItSNZrSGwPZlpUzQiOQkAhzI=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=B31IYs44/7OO7l/sYQm5TzjinaZIVOD7hIJfLx+MN8xR0+IOYpXyjf4uFF5nd1M/B vN2M+znB2WyAlhhrQC2r1LBOPoWHC3bpqDOZLNjNNZovAIG3/AOVhPxl78LkaRuQIw x/r71U7xH/9VBB8WbkE/3kPwifLPYAPaNvwduLOYUNL1Ut/u4lu1iucpqRZjZ00HHD VN4fjwSmlUP9Vk6Ox8vKp5ZEpcVGI4poWeld6ITSISohhQM4gnsOTqwGqQRyJrZjOw Q9y+zLRueMJYDpX4lareONQQL7UwPjbUH9ZmAirdeJJBTBue3ktP3P+ZfuR3wa1at8 efOLVX/3XNRzQ== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4Yx7rd5SLzz4wc4; Mon, 17 Feb 2025 14:47:13 +1100 (AEDT) Date: Mon, 17 Feb 2025 14:47:03 +1100 From: David Gibson To: Stefano Brivio Subject: Re: [PATCH v27 2/2] test: Add migration tests Message-ID: References: <20250216222227.2017788-1-sbrivio@redhat.com> <20250216222227.2017788-3-sbrivio@redhat.com> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="nJvXLZjQD8De6lZi" Content-Disposition: inline In-Reply-To: <20250216222227.2017788-3-sbrivio@redhat.com> Message-ID-Hash: UE2WIBSJNZH5V5E74EZL72UDCA6NRHSO X-Message-ID-Hash: UE2WIBSJNZH5V5E74EZL72UDCA6NRHSO X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: passt-dev@passt.top X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: --nJvXLZjQD8De6lZi Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Sun, Feb 16, 2025 at 11:22:27PM +0100, Stefano Brivio wrote: > PCAP=3D1 ./run migrate/bidirectional gives an overview of how the > whole thing is working. >=20 > 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. >=20 > 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. >=20 > Trick: './run migrate/*' runs all the tests with preparation and > teardown steps. >=20 > 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 >=20 > 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() { > =20 > get_info_cols > =20 > + pane_watch_contexts ${PANE_GUEST_1} "guest #1 in namespace #1" qemu_1 g= uest_1 > + pane_watch_contexts ${PANE_GUEST_2} "guest #2 in namespace #1" qemu_2 g= uest_2 > + > + tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; d= o :; 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=3D0 > + PANE_GUEST_2=3D1 > + PANE_INFO=3D2 > + PANE_MON=3D3 > + PANE_HOST=3D4 > + PANE_PASST_REPAIR_1=3D5 > + PANE_PASST_1=3D6 > + PANE_PASST_REPAIR_2=3D7 > + PANE_PASST_2=3D8 > + > + get_info_cols > + > pane_watch_contexts ${PANE_GUEST_1} "guest #1 in namespace #1" qemu_1 g= uest_1 > pane_watch_contexts ${PANE_GUEST_2} "guest #2 in namespace #2" qemu_2 g= uest_2 > =20 > @@ -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" > =20 > + 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 namespac= e #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 namespac= e #2" repair_2 passt_repair_2 > pane_watch_contexts ${PANE_PASST_2} "passt #2 in namespace #2" pasta_2 = passt_2 > =20 > - info_layout "two guests, two passt instances, in namespaces" > + info_layout "two guests, two passt + passt-repair instances, in namespa= ces" > =20 > 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} > } > =20 > +# setup_migrate() - Set up two namespace, run qemu, passt/passt-repair i= n 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=3D > + [ ${PCAP} -eq 1 ] && __opts=3D"${__opts} -p ${LOGDIR}/pasta_1.pcap" > + [ ${DEBUG} -eq 1 ] && __opts=3D"${__opts} -d" > + [ ${TRACE} -eq 1 ] && __opts=3D"${__opts} --trace" > + > + __map_host4=3D192.0.2.1 > + __map_host6=3D2001:db8:9a55::1 > + __map_ns4=3D192.0.2.2 > + __map_ns6=3D2001:db8:9a55::2 > + > + # Option 1: send stuff via spliced path in pasta > + # context_run_bg pasta_1 "./pasta ${__opts} -P ${STATESETUP}/pasta_1.pi= d -t 10001,10002 -T 10003 -u 10001,10002 -U 10003 --config-net ${NSTOOL} ho= ld ${STATESETUP}/ns1.hold" > + # Option 2: send stuff via tap (--map-guest-addr) instead (useful to se= e 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-add= r ${__map_host4} --map-guest-addr ${__map_host6} --config-net ${NSTOOL} hol= d ${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=3D"$(context_run qemu_1 "ip -j link show | jq -rM '.[] | selec= t(.link_type =3D=3D \"ether\").ifname'")" > + > + sleep 1 > + > + __opts=3D"--vhost-user" > + [ ${PCAP} -eq 1 ] && __opts=3D"${__opts} -p ${LOGDIR}/passt_1.pcap" > + [ ${DEBUG} -eq 1 ] && __opts=3D"${__opts} -d" > + [ ${TRACE} -eq 1 ] && __opts=3D"${__opts} --trace" > + > + context_run_bg passt_1 "./passt -s ${STATESETUP}/passt_1.socket -P ${ST= ATESETUP}/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.soc= ket.repair" > + > + __opts=3D"--vhost-user" > + [ ${PCAP} -eq 1 ] && __opts=3D"${__opts} -p ${LOGDIR}/passt_2.pcap" > + [ ${DEBUG} -eq 1 ] && __opts=3D"${__opts} -d" > + [ ${TRACE} -eq 1 ] && __opts=3D"${__opts} --trace" > + > + context_run_bg passt_2 "./passt -s ${STATESETUP}/passt_2.socket -P ${ST= ATESETUP}/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.soc= ket.repair" > + > + __vmem=3D"512M" # Keep migration fast > + __qemu_netdev1=3D" \ > + -chardev socket,id=3Dc,path=3D${STATESETUP}/passt_1.socket \ > + -netdev vhost-user,id=3Dv,chardev=3Dc \ > + -device virtio-net,netdev=3Dv \ > + -object memory-backend-memfd,id=3Dm,share=3Don,size=3D${__vmem} \ > + -numa node,memdev=3Dm" > + __qemu_netdev2=3D" \ > + -chardev socket,id=3Dc,path=3D${STATESETUP}/passt_2.socket \ > + -netdev vhost-user,id=3Dv,chardev=3Dc \ > + -device virtio-net,netdev=3Dv \ > + -object memory-backend-memfd,id=3Dm,share=3Don,size=3D${__vmem} \ > + -numa node,memdev=3Dm" > + > + GUEST_1_CID=3D94557 > + context_run_bg qemu_1 'qemu-system-'"${QEMU_ARCH}" \ > + ' -M accel=3Dkvm:tcg' \ > + ' -m '${__vmem}' -cpu host -smp '${VCPUS} \ > + ' -kernel '"${KERNEL}" \ > + ' -initrd '${INITRAMFS}' -nographic -serial stdio' \ > + ' -nodefaults' \ > + ' -append "console=3DttyS0 mitigations=3Doff apparmor=3D0" ' \ > + " ${__qemu_netdev1}" \ > + " -pidfile ${STATESETUP}/qemu_1.pid" \ > + " -device vhost-vsock-pci,guest-cid=3D$GUEST_1_CID" \ > + " -monitor unix:${STATESETUP}/qemu_1_mon.sock,server,nowait" > + > + GUEST_2_CID=3D94558 > + context_run_bg qemu_2 'qemu-system-'"${QEMU_ARCH}" \ > + ' -M accel=3Dkvm:tcg' \ > + ' -m '${__vmem}' -cpu host -smp '${VCPUS} \ > + ' -kernel '"${KERNEL}" \ > + ' -initrd '${INITRAMFS}' -nographic -serial stdio' \ > + ' -nodefaults' \ > + ' -append "console=3DttyS0 mitigations=3Doff apparmor=3D0" ' \ > + " ${__qemu_netdev2}" \ > + " -pidfile ${STATESETUP}/qemu_2.pid" \ > + " -device vhost-vsock-pci,guest-cid=3D$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 > =20 > - 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" > =20 > 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 > } > =20 > +# teardown_migrate() - Exit namespaces, kill qemu processes, passt and p= asta > +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}/pass= t_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=3D"$(list_add_pair "${TEST_ONE_subs}" "__${__var}__" "${_= _bw}" )" > } > =20 > +# test_iperf3m() - Ugly helper for iperf3 directive, guest migration var= iant > +# $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=3D"${1}"; shift > + __cctx=3D"${1}"; shift > + __cctx2=3D"${1}"; shift > + __dest=3D"${1}"; shift > + __port=3D"${1}"; shift > + __time=3D"${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=3D1000 > + pane_or_context_run_bg "${__cctx}" \ > + 'iperf3 -J -c '${__dest}' -p '${__port} \ > + ' --connect-timeout '${__timeout} \ > + ' -t'${__time}' -i0 '"${@}"' > c.json' \ > + > + __jval=3D".end.sum_received.bits_per_second" > + > + sleep $((${__time} + 3)) > + > + pane_or_context_output "${__cctx2}" \ > + 'cat c.json' > + > + __bw=3D$(pane_or_context_output "${__cctx2}" \ > + 'cat c.json | jq -rMs "map('${__jval}') | add"') > + > + TEST_ONE_subs=3D"$(list_add_pair "${TEST_ONE_subs}" "__${__var}__" "${_= _bw}" )" > +} > + > test_one_line() { > __line=3D"${1}" > =20 > @@ -177,6 +216,12 @@ test_one_line() { > "guest2w") > pane_or_context_wait guest_2 || TEST_ONE_nok=3D1 > ;; > + "mon") > + pane_or_context_run mon "${__arg}" || TEST_ONE_nok=3D1 > + ;; > + "monb") > + pane_or_context_run_bg mon "${__arg}" > + ;; > "ns") > pane_or_context_run ns "${__arg}" || TEST_ONE_nok=3D1 > ;; > @@ -292,6 +337,9 @@ test_one_line() { > "iperf3") > test_iperf3 ${__arg} > ;; > + "iperf3m") > + test_iperf3m ${__arg} > + ;; > "set") > TEST_ONE_subs=3D"$(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 =3D=3D "= ether").ifname' > +hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst =3D=3D "= default").dev] | .[0]' > +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst =3D=3D = "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 =3D=3D "__IF= NAME1__").addr_info[0].local' > +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname =3D=3D "_= _HOST_IFNAME__").addr_info[0].local' > +check [ "__ADDR1__" =3D "__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 sl= eep 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 sl= eep 0.1; done > +g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D "_= _IFNAME1__").addr_info[] | select(.prefixlen =3D=3D 128).local] | .[0]' > +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D = "__HOST_IFNAME6__").addr_info[] | select(.scope =3D=3D "global" and .deprec= ated !=3D true).local] | .[0]' > +check [ "__ADDR1_6__" =3D "__HOST_ADDR6__" ] > + > +test TCP/IPv4: guest1/guest2 > host > +g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst =3D=3D "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 gue= st 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__" =3D "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-close= d 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 =3D=3D "= ether").ifname' > +hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst =3D=3D "= default").dev] | .[0]' > +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst =3D=3D = "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 =3D=3D "__IF= NAME1__").addr_info[0].local' > +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname =3D=3D "_= _HOST_IFNAME__").addr_info[0].local' > +check [ "__ADDR1__" =3D "__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 sl= eep 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 sl= eep 0.1; done > +g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D "_= _IFNAME1__").addr_info[] | select(.prefixlen =3D=3D 128).local] | .[0]' > +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D = "__HOST_IFNAME6__").addr_info[] | select(.scope =3D=3D "global" and .deprec= ated !=3D true).local] | .[0]' > +check [ "__ADDR1_6__" =3D "__HOST_ADDR6__" ] > + > +test TCP/IPv4: guest1, half-close, guest2 > host > +g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst =3D=3D "default"= ).gateway' > + > +hostb echo FIN | socat TCP4-LISTEN:10006,shut-down STDIO,ignoreeof > __S= TATESETUP__/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 gue= st 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__" =3D "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 dir= ections > +# > +# 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 =3D=3D "= ether").ifname' > +hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst =3D=3D "= default").dev] | .[0]' > +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst =3D=3D = "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 =3D=3D "__IF= NAME1__").addr_info[0].local' > +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname =3D=3D "_= _HOST_IFNAME__").addr_info[0].local' > +check [ "__ADDR1__" =3D "__HOST_ADDR__" ] > + > +test TCP/IPv4: guest1/guest2 > host, host > guest1/guest2 > +g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst =3D=3D "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.s= ock > +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 gu= est #1, > +# use sleep 1 for the moment > +sleep 1 > + > +hout MSG cat __STATESETUP__/msg > +check [ "__MSG__" =3D "Hello from guest 1 and from guest 2" ] > + > +g2out MSG cat msg > +check [ "__MSG__" =3D "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 =3D=3D "= ether").ifname' > +hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst =3D=3D "= default").dev] | .[0]' > +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst =3D=3D = "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 =3D=3D "__IF= NAME1__").addr_info[0].local' > +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname =3D=3D "_= _HOST_IFNAME__").addr_info[0].local' > +check [ "__ADDR1__" =3D "__HOST_ADDR__" ] > + > +test TCP/IPv4: guest1/guest2 <- (half closed) -> host > +g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst =3D=3D "default"= ).gateway' > + > +hostb echo FIN | socat TCP4-LISTEN:10006,shut-down STDIO,ignoreeof > __S= TATESETUP__/msg > +guest1b echo FIN | socat TCP4-LISTEN:10001,shut-down STDIO,ignoreeof > m= sg > +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.s= ock > +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 gu= est #1, > +# use sleep 1 for the moment > +sleep 1 > + > +hout MSG cat __STATESETUP__/msg > +check [ "__MSG__" =3D "Hello from guest 1 and from guest 2" ] > + > +g2out MSG cat msg > +check [ "__MSG__" =3D "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 bidirection= al 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 =3D=3D "= ether").ifname' > +hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst =3D=3D "= default").dev] | .[0]' > +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst =3D=3D = "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 =3D=3D "__IF= NAME1__").addr_info[0].local' > +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname =3D=3D "_= _HOST_IFNAME__").addr_info[0].local' > +check [ "__ADDR1__" =3D "__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 sl= eep 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 sl= eep 0.1; done > +g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D "_= _IFNAME1__").addr_info[] | select(.prefixlen =3D=3D 128).local] | .[0]' > +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D = "__HOST_IFNAME6__").addr_info[] | select(.scope =3D=3D "global" and .deprec= ated !=3D true).local] | .[0]' > +check [ "__ADDR1_6__" =3D "__HOST_ADDR6__" ] > + > +test TCP/IPv6 host <-> guest flood, many flows, during migration > + > +monb sleep 1; echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESE= TUP__/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=3D33554432 > +guest1 /sbin/sysctl -w net.core.wmem_max=3D33554432 > + > +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 =3D=3D "= ether").ifname' > +hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst =3D=3D "= 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 =3D=3D "__IF= NAME1__").addr_info[0].local' > +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname =3D=3D "_= _HOST_IFNAME__").addr_info[0].local' > +check [ "__ADDR1__" =3D "__HOST_ADDR__" ] > + > +test TCP/IPv4 host to guest throughput during migration > + > +monb sleep 1; echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESE= TUP__/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 =3D=3D "= ether").ifname' > +hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst =3D=3D "= default").dev] | .[0]' > +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst =3D=3D = "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 =3D=3D "__IF= NAME1__").addr_info[0].local' > +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname =3D=3D "_= _HOST_IFNAME__").addr_info[0].local' > +check [ "__ADDR1__" =3D "__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 sl= eep 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 sl= eep 0.1; done > +g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D "_= _IFNAME1__").addr_info[] | select(.prefixlen =3D=3D 128).local] | .[0]' > +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D = "__HOST_IFNAME6__").addr_info[] | select(.scope =3D=3D "global" and .deprec= ated !=3D true).local] | .[0]' > +check [ "__ADDR1_6__" =3D "__HOST_ADDR6__" ] > + > +test TCP/IPv6 host to guest throughput during migration > + > +monb sleep 1; echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESE= TUP__/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 =3D=3D "= ether").ifname' > +hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst =3D=3D "= default").dev] | .[0]' > +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst =3D=3D = "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 =3D=3D "__IF= NAME1__").addr_info[0].local' > +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname =3D=3D "_= _HOST_IFNAME__").addr_info[0].local' > +check [ "__ADDR1__" =3D "__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 sl= eep 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 sl= eep 0.1; done > +g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D "_= _IFNAME1__").addr_info[] | select(.prefixlen =3D=3D 128).local] | .[0]' > +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D = "__HOST_IFNAME6__").addr_info[] | select(.scope =3D=3D "global" and .deprec= ated !=3D true).local] | .[0]' > +check [ "__ADDR1_6__" =3D "__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:__STATESE= TUP__/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 flo= od > +# > +# 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 =3D=3D "= ether").ifname' > +hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst =3D=3D "= 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 =3D=3D "__IF= NAME1__").addr_info[0].local' > +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname =3D=3D "_= _HOST_IFNAME__").addr_info[0].local' > +check [ "__ADDR1__" =3D "__HOST_ADDR__" ] > + > +test TCP/IPv4 guest to host throughput during migration > + > +monb sleep 1; echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESE= TUP__/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 flo= od > +# > +# 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 =3D=3D "= ether").ifname' > +hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst =3D=3D "= default").dev] | .[0]' > +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst =3D=3D = "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 =3D=3D "__IF= NAME1__").addr_info[0].local' > +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname =3D=3D "_= _HOST_IFNAME__").addr_info[0].local' > +check [ "__ADDR1__" =3D "__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 sl= eep 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 sl= eep 0.1; done > +g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D "_= _IFNAME1__").addr_info[] | select(.prefixlen =3D=3D 128).local] | .[0]' > +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D = "__HOST_IFNAME6__").addr_info[] | select(.scope =3D=3D "global" and .deprec= ated !=3D true).local] | .[0]' > +check [ "__ADDR1_6__" =3D "__HOST_ADDR6__" ] > + > +test TCP/IPv6 guest to host throughput during migration > + > +monb sleep 1; echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESE= TUP__/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 r= amp > # > -# Copyright (c) 2025 Red Hat GmbH > -# Author: Stefano Brivio > +# Copyright (c) 2025 Red Hat > +# Author: David Gibson > =20 > g1tools ip jq dhclient socat cat > htools ip jq > @@ -43,15 +43,15 @@ g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | selec= t(.ifname =3D=3D "__IFNAME1__") > hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D = "__HOST_IFNAME6__").addr_info[] | select(.scope =3D=3D "global" and .deprec= ated !=3D true).local] | .[0]' > check [ "__ADDR1_6__" =3D "__HOST_ADDR6__" ] > =20 > -test TCP/IPv4: host > guest > +test TCP/IPv4: sequence check, ramps, inbound > g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst =3D=3D "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 > =20 > -sleep 1 > +sleep 1 > =20 > -#mon echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qem= u_1_mon.sock > +monb echo "migrate tcp:0:20005" | socat -u STDIN UNIX:__STATESETUP__/qem= u_1_mon.sock > =20 > hostw > =20 > 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 > =20 > g1tools ip jq dhclient socat cat > htools ip jq > @@ -43,7 +43,7 @@ g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(= =2Eifname =3D=3D "__IFNAME1__") > hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname =3D=3D = "__HOST_IFNAME6__").addr_info[] | select(.scope =3D=3D "global" and .deprec= ated !=3D true).local] | .[0]' > check [ "__ADDR1_6__" =3D "__HOST_ADDR6__" ] > =20 > -test TCP/IPv4: guest > host > +test TCP/IPv4: sequence check, ramps, outbound > g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst =3D=3D "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 > =20 > + 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=3D0 > VHOST_USER=3D0 > setup passt_in_ns > @@ -186,7 +223,10 @@ run_selected() { > =20 > __setup=3D > for __test; do > - if [ "${__test%%/*}" !=3D "${__setup}" ]; then > + # HACK: the migrate tests need the setup repeated for > + # each test > + if [ "${__test%%/*}" !=3D "${__setup}" -o \ > + "${__test%%/*}" =3D "migrate" ]; then > [ -n "${__setup}" ] && teardown "${__setup}" > __setup=3D"${__test%%/*}" > setup "${__setup}" --=20 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 --nJvXLZjQD8De6lZi Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmeysTYACgkQzQJF27ox 2Gfo7Q//Se7Aty0LHKq50KSzCSEzqrXogmc1Mf61S8qTEGJJ2O9EpGaYNFtjujYB h7wCcDR1JieOy1lX6khlqLB7nChuSVQGrAJGImMAlAG+geUSLUAI82j+1g1sWFxj IOjjNJdiGedUSxZIhJrhacmTU/sDfzYP09WyxlRObP7C1jrlL5sFgLmjJE1iVIv7 g7X6ZP/7X7qlpHdIC3F+UDwQCN/g04PBBGPwNpmqmeKKcMzMmmRZRQTyuNQoofiu oPYbPI6TIWaRrPmtZ72OslzWHMEgG5s3X3n6+92tMgw7w1kV9eKEUQb1azMrVTgd 1okAWXHz1fX5muv0gaKx+0lz7tCmcfqBVPJxNlZPKze2VaGoJ2jGqUMUwhXyn62M RNKyYrsmJ5ShXeBGVOdHkmMxvrE98lB489Z80+mlVZV0zgpXpetqAw0XiAf47ehd jBmN84lWRrTvoiNhsvvFX43eztp1Rb2kJTLyUW2qMaF5c5JCAuInnPo/uS97XPkt NPtnE+f9vs+zHD+yhALCde9GTQ60MeePq4wlbIwifWtYq0W2JGGGQax+C/fnMbL4 HIB8fYtyef5bq0e06HiZtYVYd7ORsxHlxi4IFVx4I4UpV2kOxkYIkaXHOjHuysR4 iBu/nj0IjWmvkguNv/EoMIUmeg58sVws8FUoMJY3JNYl9FXdsy0= =va06 -----END PGP SIGNATURE----- --nJvXLZjQD8De6lZi--