From nobody Fri Dec 19 19:10:34 2025 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 108355A7B for ; Fri, 30 Sep 2022 16:00:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1664553632; x=1696089632; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=WqJbDskOUo7L0c8HqZ5zeSVTdQNENPHNixig9QogiRs=; b=QfjPJ4+yJpNjFWvC+FrHuuAFmzn0ZU1uzkFzP3gipvxoJsKQ2RFWEi1Z 4Kf+xIJsqTx+k3BK6uszQ34gMphAdNievYnnnjvpJmruIPgBLdZAuiFKn t9QCB2HSdnwv6wQIu4AOuLdFSJsydsp6couviiE48A4C1hNTcxyy0O2yM uEyzxtjQX4rtF1XXtOuZSAbAXhcdBa4hPEzQFzyya7ghXK8Yd5kVlb/g4 FchaFSMusNx3IvuSn6WFbGStmSwSfhAbCn+/xniJGAXMHA5P5zk+N5T5M u8jIjrcGDzYDKjnfuz+rP58saxyT7+V4m09lCLlbFq5EVg9DbFVKigK7o w==; X-IronPort-AV: E=McAfee;i="6500,9779,10486"; a="289383897" X-IronPort-AV: E=Sophos;i="5.93,358,1654585200"; d="scan'208";a="289383897" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 30 Sep 2022 09:00:28 -0700 X-IronPort-AV: E=McAfee;i="6500,9779,10486"; a="655996110" X-IronPort-AV: E=Sophos;i="5.93,358,1654585200"; d="scan'208";a="655996110" Received: from cmforest-mobl1.amr.corp.intel.com (HELO mjmartin-desk2.intel.com) ([10.251.22.5]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 30 Sep 2022 09:00:28 -0700 From: Mat Martineau To: netdev@vger.kernel.org Cc: Paolo Abeni , davem@davemloft.net, kuba@kernel.org, edumazet@google.com, matthieu.baerts@tessares.net, mptcp@lists.linux.dev, Mat Martineau Subject: [PATCH net-next 3/4] selftests: mptcp: update and extend fastclose test-cases Date: Fri, 30 Sep 2022 08:59:33 -0700 Message-Id: <20220930155934.404466-4-mathew.j.martineau@linux.intel.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20220930155934.404466-1-mathew.j.martineau@linux.intel.com> References: <20220930155934.404466-1-mathew.j.martineau@linux.intel.com> Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Paolo Abeni After the previous patches, the MPTCP protocol can generate fast-closes on both ends of the connection. Rework the relevant test-case to carefully trigger the fast-close code-path on a single end at the time, while ensuring than a predictable amount of data is spooled on both ends. Additionally add another test-cases for the passive socket fast-close. Reviewed-by: Matthieu Baerts Reviewed-by: Mat Martineau Signed-off-by: Paolo Abeni Signed-off-by: Mat Martineau --- .../selftests/net/mptcp/mptcp_connect.c | 65 ++++++++++++-- .../testing/selftests/net/mptcp/mptcp_join.sh | 90 +++++++++++++++---- 2 files changed, 130 insertions(+), 25 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/test= ing/selftests/net/mptcp/mptcp_connect.c index 24d4e9cb617e..e54653ea2ed4 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.c +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c @@ -72,6 +72,8 @@ static int cfg_wait; static uint32_t cfg_mark; static char *cfg_input; static int cfg_repeat =3D 1; +static int cfg_truncate; +static int cfg_rcv_trunc; =20 struct cfg_cmsg_types { unsigned int cmsg_enabled:1; @@ -95,11 +97,15 @@ static struct cfg_sockopt_types cfg_sockopt_types; =20 static void die_usage(void) { - fprintf(stderr, "Usage: mptcp_connect [-6] [-c cmsg] [-i file] [-I num] [= -j] [-l] " + fprintf(stderr, "Usage: mptcp_connect [-6] [-c cmsg] [-f offset] [-i file= ] [-I num] [-j] [-l] " "[-m mode] [-M mark] [-o option] [-p port] [-P mode] [-j] [-l] [-r num] " "[-s MPTCP|TCP] [-S num] [-r num] [-t num] [-T num] [-u] [-w sec] connec= t_address\n"); fprintf(stderr, "\t-6 use ipv6\n"); fprintf(stderr, "\t-c cmsg -- test cmsg type \n"); + fprintf(stderr, "\t-f offset -- stop the I/O after receiving and sending = the specified amount " + "of bytes. If there are unread bytes in the receive queue, that will cau= se a MPTCP " + "fastclose at close/shutdown. If offset is negative, expect the peer to = close before " + "all the local data as been sent, thus toleration errors on write and EP= IPE signals\n"); fprintf(stderr, "\t-i file -- read the data to send from the given file i= nstead of stdin"); fprintf(stderr, "\t-I num -- repeat the transfer 'num' times. In listen m= ode accepts num " "incoming connections, in client mode, disconnect and reconnect to the s= erver\n"); @@ -382,7 +388,7 @@ static size_t do_rnd_write(const int fd, char *buf, con= st size_t len) =20 bw =3D write(fd, buf, do_w); if (bw < 0) - perror("write"); + return bw; =20 /* let the join handshake complete, before going on */ if (cfg_join && first) { @@ -571,7 +577,7 @@ static int copyfd_io_poll(int infd, int peerfd, int out= fd, bool *in_closed_after .fd =3D peerfd, .events =3D POLLIN | POLLOUT, }; - unsigned int woff =3D 0, wlen =3D 0; + unsigned int woff =3D 0, wlen =3D 0, total_wlen =3D 0, total_rlen =3D 0; char wbuf[8192]; =20 set_nonblock(peerfd, true); @@ -597,7 +603,16 @@ static int copyfd_io_poll(int infd, int peerfd, int ou= tfd, bool *in_closed_after } =20 if (fds.revents & POLLIN) { - len =3D do_rnd_read(peerfd, rbuf, sizeof(rbuf)); + ssize_t rb =3D sizeof(rbuf); + + /* limit the total amount of read data to the trunc value*/ + if (cfg_truncate > 0) { + if (rb + total_rlen > cfg_truncate) + rb =3D cfg_truncate - total_rlen; + len =3D read(peerfd, rbuf, rb); + } else { + len =3D do_rnd_read(peerfd, rbuf, sizeof(rbuf)); + } if (len =3D=3D 0) { /* no more data to receive: * peer has closed its write side @@ -612,10 +627,13 @@ static int copyfd_io_poll(int infd, int peerfd, int o= utfd, bool *in_closed_after =20 /* Else, still have data to transmit */ } else if (len < 0) { + if (cfg_rcv_trunc) + return 0; perror("read"); return 3; } =20 + total_rlen +=3D len; do_write(outfd, rbuf, len); } =20 @@ -628,12 +646,21 @@ static int copyfd_io_poll(int infd, int peerfd, int o= utfd, bool *in_closed_after if (wlen > 0) { ssize_t bw; =20 + /* limit the total amount of written data to the trunc value */ + if (cfg_truncate > 0 && wlen + total_wlen > cfg_truncate) + wlen =3D cfg_truncate - total_wlen; + bw =3D do_rnd_write(peerfd, wbuf + woff, wlen); - if (bw < 0) + if (bw < 0) { + if (cfg_rcv_trunc) + return 0; + perror("write"); return 111; + } =20 woff +=3D bw; wlen -=3D bw; + total_wlen +=3D bw; } else if (wlen =3D=3D 0) { /* We have no more data to send. */ fds.events &=3D ~POLLOUT; @@ -652,10 +679,16 @@ static int copyfd_io_poll(int infd, int peerfd, int o= utfd, bool *in_closed_after } =20 if (fds.revents & (POLLERR | POLLNVAL)) { + if (cfg_rcv_trunc) + return 0; fprintf(stderr, "Unexpected revents: " "POLLERR/POLLNVAL(%x)\n", fds.revents); return 5; } + + if (cfg_truncate > 0 && total_wlen >=3D cfg_truncate && + total_rlen >=3D cfg_truncate) + break; } =20 /* leave some time for late join/announce */ @@ -1160,11 +1193,13 @@ int main_loop(void) } =20 /* close the client socket open only if we are not going to reconnect */ - ret =3D copyfd_io(fd_in, fd, 1, cfg_repeat =3D=3D 1); + ret =3D copyfd_io(fd_in, fd, 1, 0); if (ret) return ret; =20 - if (--cfg_repeat > 0) { + if (cfg_truncate > 0) { + xdisconnect(fd, peer->ai_addrlen); + } else if (--cfg_repeat > 0) { xdisconnect(fd, peer->ai_addrlen); =20 /* the socket could be unblocking at this point, we need the @@ -1176,7 +1211,10 @@ int main_loop(void) if (cfg_input) close(fd_in); goto again; + } else { + close(fd); } + return 0; } =20 @@ -1262,8 +1300,19 @@ static void parse_opts(int argc, char **argv) { int c; =20 - while ((c =3D getopt(argc, argv, "6c:hi:I:jlm:M:o:p:P:r:R:s:S:t:T:w:")) != =3D -1) { + while ((c =3D getopt(argc, argv, "6c:f:hi:I:jlm:M:o:p:P:r:R:s:S:t:T:w:"))= !=3D -1) { switch (c) { + case 'f': + cfg_truncate =3D atoi(optarg); + + /* when receiving a fastclose, ignore PIPE signals and + * all the I/O errors later in the code + */ + if (cfg_truncate < 0) { + cfg_rcv_trunc =3D true; + signal(SIGPIPE, handle_signal); + } + break; case 'j': cfg_join =3D true; cfg_mode =3D CFG_MODE_POLL; diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testin= g/selftests/net/mptcp/mptcp_join.sh index 2957fe414639..f3dd5f2a0272 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -346,10 +346,21 @@ check_transfer() local in=3D$1 local out=3D$2 local what=3D$3 + local bytes=3D$4 local i a b =20 local line - cmp -l "$in" "$out" | while read -r i a b; do + if [ -n "$bytes" ]; then + # when truncating we must check the size explicitly + local out_size=3D$(wc -c $out | awk '{print $1}') + if [ $out_size -ne $bytes ]; then + echo "[ FAIL ] $what output file has wrong size ($out_size, $bytes)" + fail_test + return 1 + fi + bytes=3D"--bytes=3D${bytes}" + fi + cmp -l "$in" "$out" ${bytes} | while read -r i a b; do local sum=3D$((0${a} + 0${b})) if [ $check_invert -eq 0 ] || [ $sum -ne $((0xff)) ]; then echo "[ FAIL ] $what does not match (in, out):" @@ -707,9 +718,31 @@ do_transfer() fi =20 local flags=3D"subflow" + local extra_cl_args=3D"" + local extra_srv_args=3D"" + local trunc_size=3D"" if [[ "${addr_nr_ns2}" =3D "fastclose_"* ]]; then + if [ ${test_link_fail} -le 1 ]; then + echo "fastclose tests need test_link_fail argument" + fail_test + return 1 + fi + # disconnect - extra_args=3D"$extra_args -I ${addr_nr_ns2:10}" + trunc_size=3D${test_link_fail} + local side=3D${addr_nr_ns2:10} + + if [ ${side} =3D "client" ]; then + extra_cl_args=3D"-f ${test_link_fail}" + extra_srv_args=3D"-f -1" + elif [ ${side} =3D "server" ]; then + extra_srv_args=3D"-f ${test_link_fail}" + extra_cl_args=3D"-f -1" + else + echo "wrong/unknown fastclose spec ${side}" + fail_test + return 1 + fi addr_nr_ns2=3D0 elif [[ "${addr_nr_ns2}" =3D "userspace_"* ]]; then userspace_pm=3D1 @@ -737,39 +770,41 @@ do_transfer() local_addr=3D"0.0.0.0" fi =20 + extra_srv_args=3D"$extra_args $extra_srv_args" if [ "$test_link_fail" -gt 1 ];then timeout ${timeout_test} \ ip netns exec ${listener_ns} \ ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ - $extra_args ${local_addr} < "$sinfail" > "$sout" & + $extra_srv_args ${local_addr} < "$sinfail" > "$sout" & else timeout ${timeout_test} \ ip netns exec ${listener_ns} \ ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ - $extra_args ${local_addr} < "$sin" > "$sout" & + $extra_srv_args ${local_addr} < "$sin" > "$sout" & fi local spid=3D$! =20 wait_local_port_listen "${listener_ns}" "${port}" =20 + extra_cl_args=3D"$extra_args $extra_cl_args" if [ "$test_link_fail" -eq 0 ];then timeout ${timeout_test} \ ip netns exec ${connector_ns} \ ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ - $extra_args $connect_addr < "$cin" > "$cout" & + $extra_cl_args $connect_addr < "$cin" > "$cout" & elif [ "$test_link_fail" -eq 1 ] || [ "$test_link_fail" -eq 2 ];then ( cat "$cinfail" ; sleep 2; link_failure $listener_ns ; cat "$cinfail" )= | \ tee "$cinsent" | \ timeout ${timeout_test} \ ip netns exec ${connector_ns} \ ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ - $extra_args $connect_addr > "$cout" & + $extra_cl_args $connect_addr > "$cout" & else tee "$cinsent" < "$cinfail" | \ timeout ${timeout_test} \ ip netns exec ${connector_ns} \ ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ - $extra_args $connect_addr > "$cout" & + $extra_cl_args $connect_addr > "$cout" & fi local cpid=3D$! =20 @@ -971,15 +1006,15 @@ do_transfer() fi =20 if [ "$test_link_fail" -gt 1 ];then - check_transfer $sinfail $cout "file received by client" + check_transfer $sinfail $cout "file received by client" $trunc_size else - check_transfer $sin $cout "file received by client" + check_transfer $sin $cout "file received by client" $trunc_size fi retc=3D$? if [ "$test_link_fail" -eq 0 ];then - check_transfer $cin $sout "file received by server" + check_transfer $cin $sout "file received by server" $trunc_size else - check_transfer $cinsent $sout "file received by server" + check_transfer $cinsent $sout "file received by server" $trunc_size fi rets=3D$? =20 @@ -1188,12 +1223,23 @@ chk_fclose_nr() { local fclose_tx=3D$1 local fclose_rx=3D$2 + local ns_invert=3D$3 local count local dump_stats + local ns_tx=3D$ns2 + local ns_rx=3D$ns1 + local extra_msg=3D" " + + if [[ $ns_invert =3D "invert" ]]; then + ns_tx=3D$ns1 + ns_rx=3D$ns2 + extra_msg=3D${extra_msg}"invert" + fi =20 printf "%-${nr_blank}s %s" " " "ctx" - count=3D$(ip netns exec $ns2 nstat -as | grep MPTcpExtMPFastcloseTx | awk= '{print $2}') + count=3D$(ip netns exec $ns_tx nstat -as | grep MPTcpExtMPFastcloseTx | a= wk '{print $2}') [ -z "$count" ] && count=3D0 + [ "$count" !=3D "$fclose_tx" ] && extra_msg=3D"$extra_msg,tx=3D$count" if [ "$count" !=3D "$fclose_tx" ]; then echo "[fail] got $count MP_FASTCLOSE[s] TX expected $fclose_tx" fail_test @@ -1203,17 +1249,20 @@ chk_fclose_nr() fi =20 echo -n " - fclzrx" - count=3D$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPFastcloseRx | awk= '{print $2}') + count=3D$(ip netns exec $ns_rx nstat -as | grep MPTcpExtMPFastcloseRx | a= wk '{print $2}') [ -z "$count" ] && count=3D0 + [ "$count" !=3D "$fclose_rx" ] && extra_msg=3D"$extra_msg,rx=3D$count" if [ "$count" !=3D "$fclose_rx" ]; then echo "[fail] got $count MP_FASTCLOSE[s] RX expected $fclose_rx" fail_test dump_stats=3D1 else - echo "[ ok ]" + echo -n "[ ok ]" fi =20 [ "${dump_stats}" =3D 1 ] && dump_stats + + echo "$extra_msg" } =20 chk_rst_nr() @@ -1236,7 +1285,7 @@ chk_rst_nr() printf "%-${nr_blank}s %s" " " "rtx" count=3D$(ip netns exec $ns_tx nstat -as | grep MPTcpExtMPRstTx | awk '{p= rint $2}') [ -z "$count" ] && count=3D0 - if [ "$count" !=3D "$rst_tx" ]; then + if [ $count -lt $rst_tx ]; then echo "[fail] got $count MP_RST[s] TX expected $rst_tx" fail_test dump_stats=3D1 @@ -1247,7 +1296,7 @@ chk_rst_nr() echo -n " - rstrx " count=3D$(ip netns exec $ns_rx nstat -as | grep MPTcpExtMPRstRx | awk '{p= rint $2}') [ -z "$count" ] && count=3D0 - if [ "$count" !=3D "$rst_rx" ]; then + if [ "$count" -lt "$rst_rx" ]; then echo "[fail] got $count MP_RST[s] RX expected $rst_rx" fail_test dump_stats=3D1 @@ -2801,11 +2850,18 @@ fullmesh_tests() fastclose_tests() { if reset "fastclose test"; then - run_tests $ns1 $ns2 10.0.1.1 1024 0 fastclose_2 + run_tests $ns1 $ns2 10.0.1.1 1024 0 fastclose_client chk_join_nr 0 0 0 chk_fclose_nr 1 1 chk_rst_nr 1 1 invert fi + + if reset "fastclose server test"; then + run_tests $ns1 $ns2 10.0.1.1 1024 0 fastclose_server + chk_join_nr 0 0 0 + chk_fclose_nr 1 1 invert + chk_rst_nr 1 1 + fi } =20 pedit_action_pkts() --=20 2.37.3