From nobody Sun Feb 8 23:57:48 2026 Delivered-To: wpasupplicant.patchew@gmail.com Received: by 2002:a02:cbb9:0:0:0:0:0 with SMTP id v25csp222011jap; Wed, 10 Nov 2021 04:32:42 -0800 (PST) X-Google-Smtp-Source: ABdhPJzEMxDpy3NTS61zY6JMPhS7CaFz5SDrvtPqvbyfzGReK6al3enKui8o8c4OBmoaHaiRThG5 X-Received: by 2002:a17:90a:8a82:: with SMTP id x2mr15991619pjn.187.1636547561986; Wed, 10 Nov 2021 04:32:41 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1636547561; cv=none; d=google.com; s=arc-20160816; b=iUvdMEZb22O7MXnKgSPJT9fGDiVOvvWf9usxG0ZFQLwCbRxPx/PYrKy9g3F7IxGy6m gwRClrV42omsmaMcdpltpT0OpL/Rx1dQ26IR9WE71pNM5+s5kTcBIDaS6NfoPZDbNpvk DVkZjBeIHOrd72UKdsrKE0C8BNq6SW7wdeLSITsVdyw8IV6msNYOw3+aRVrKvRooZ4PW 1vqVMmCUsrcYPccZ//LAtpdHmCdSIkOagI2/X/b7BKiCuhJKzwwacKgrUmlSI57FT7EZ RLLFghKGzf31KsqW1DkjKFdPv0T6pBti4b5MlAUDy35GpbpJUvDZbJ+cxeb29U7tAIWw KXhg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:to:from:dkim-signature; bh=ScJYSNpmQwJA3Fv8pM9B1JvJEC83TvWc2ZMuarAv30c=; b=mMI69G3xaps1XanUsocpn3w2z3iwiYLJlAOdwvpdNaASPJnU8gTXTAgFcPWW6aN3hj 0eGvChwqsnPVNf0dSP+wgDyb6Fj4EmJwxH1tpF7c413HW5j4+8/77yFag9Sr59aqGW7t gE3fAhV8GnMyjK6DnR1fwCbNhdaXqvBgzax26Nge0NBzkzmN2xlSjpcRJtsWULbkGkYK mRNotsKh0+CAiUcwzlcqnz6bfdsN1yPmE7mCmXvHuo/ms78/oqbHo2ZTVGHN8x66Mx/H jEVU1jONNVNXFHxWWcimm95nNGabqi8KWBdVacfu7vdbzOHC3j5n9ewbfKH7kdIXlSBN VK0Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=OXCBCKap; spf=pass (google.com: domain of mptcp+bounces-2406-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 2604:1380:1000:8100::1 as permitted sender) smtp.mailfrom="mptcp+bounces-2406-wpasupplicant.patchew=gmail.com@lists.linux.dev"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from sjc.edge.kernel.org (sjc.edge.kernel.org. [2604:1380:1000:8100::1]) by mx.google.com with ESMTPS id x16si37712668pll.9.2021.11.10.04.32.41 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Nov 2021 04:32:41 -0800 (PST) Received-SPF: pass (google.com: domain of mptcp+bounces-2406-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 2604:1380:1000:8100::1 as permitted sender) client-ip=2604:1380:1000:8100::1; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=OXCBCKap; spf=pass (google.com: domain of mptcp+bounces-2406-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 2604:1380:1000:8100::1 as permitted sender) smtp.mailfrom="mptcp+bounces-2406-wpasupplicant.patchew=gmail.com@lists.linux.dev"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sjc.edge.kernel.org (Postfix) with ESMTPS id 6ABB83E1068 for ; Wed, 10 Nov 2021 12:32:41 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6BB572C8B; Wed, 10 Nov 2021 12:32:39 +0000 (UTC) X-Original-To: mptcp@lists.linux.dev Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 0836E2C88 for ; Wed, 10 Nov 2021 12:32:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1636547557; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ScJYSNpmQwJA3Fv8pM9B1JvJEC83TvWc2ZMuarAv30c=; b=OXCBCKapIpm3jvNSOGs2W1yChO1BgzsjTGBCHNW7uSvvlULO2dEWVE+vXFFAljVHC4Nurf Woj8P2fFfOZsV/bgMkL3LPrKDW2HXe8fsYBlkc/RlzAPYngHalTUt+0X12tbYZCQoU0Hgm SoyjZajxjaatm44XA/QhYnvh2YQiZY8= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-568-emYlOCp1NBGtQiKqLkY9Hw-1; Wed, 10 Nov 2021 07:32:34 -0500 X-MC-Unique: emYlOCp1NBGtQiKqLkY9Hw-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 18E8D804143 for ; Wed, 10 Nov 2021 12:32:34 +0000 (UTC) Received: from gerbillo.fritz.box (unknown [10.39.194.200]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7BF1C60843 for ; Wed, 10 Nov 2021 12:32:33 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Subject: [PATCH net-next 7/7] mptcp: add disconnect selftests Date: Wed, 10 Nov 2021 13:31:40 +0100 Message-Id: <992a16d382afe5932897687bb6b5f383af6e887e.1636545174.git.pabeni@redhat.com> In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=pabeni@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Performs several disconnect/reconnect on the same socket, ensuring the overall transfer is succesful. Additionally leverages ioctl(SIOCOUTQ) to ensure all the pending data is acked before disconnecting. Signed-off-by: Paolo Abeni --- notes: - this is on top of Florian's patches - yep, I just contradicted myself leveraging again mptcp_connect for self-tests, despite I proposed otherwise. I admit is tempting. The downside is that the program is growing as uncontrolled blob. Suggestion for better solution more then welcome! --- .../selftests/net/mptcp/mptcp_connect.c | 119 +++++++++++++++--- .../selftests/net/mptcp/mptcp_connect.sh | 38 +++++- 2 files changed, 140 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/test= ing/selftests/net/mptcp/mptcp_connect.c index e3e4338d610f..8a545e196f1d 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.c +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c @@ -16,6 +16,7 @@ #include #include =20 +#include #include #include #include @@ -28,6 +29,7 @@ =20 #include #include +#include =20 extern int optind; =20 @@ -69,6 +71,8 @@ static unsigned int cfg_time; static unsigned int cfg_do_w; static int cfg_wait; static uint32_t cfg_mark; +static char *cfg_input =3D NULL; +static int cfg_repeat =3D 1; =20 struct cfg_cmsg_types { unsigned int cmsg_enabled:1; @@ -307,7 +311,8 @@ static bool sock_test_tcpulp(const char * const remotea= ddr, } =20 static int sock_connect_mptcp(const char * const remoteaddr, - const char * const port, int proto) + const char * const port, int proto, + struct addrinfo **peer) { struct addrinfo hints =3D { .ai_protocol =3D IPPROTO_TCP, @@ -329,8 +334,10 @@ static int sock_connect_mptcp(const char * const remot= eaddr, if (cfg_mark) set_mark(sock, cfg_mark); =20 - if (connect(sock, a->ai_addr, a->ai_addrlen) =3D=3D 0) + if (connect(sock, a->ai_addr, a->ai_addrlen) =3D=3D 0) { + *peer =3D a; break; /* success */ + } =20 perror("connect()"); close(sock); @@ -513,14 +520,17 @@ static ssize_t do_rnd_read(const int fd, char *buf, c= onst size_t len) return ret; } =20 -static void set_nonblock(int fd) +static void set_nonblock(int fd, bool nonblock) { int flags =3D fcntl(fd, F_GETFL); =20 if (flags =3D=3D -1) return; =20 - fcntl(fd, F_SETFL, flags | O_NONBLOCK); + if (nonblock) + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + else + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); } =20 static int copyfd_io_poll(int infd, int peerfd, int outfd, bool *in_closed= _after_out) @@ -532,7 +542,7 @@ static int copyfd_io_poll(int infd, int peerfd, int out= fd, bool *in_closed_after unsigned int woff =3D 0, wlen =3D 0; char wbuf[8192]; =20 - set_nonblock(peerfd); + set_nonblock(peerfd, true); =20 for (;;) { char rbuf[8192]; @@ -627,7 +637,6 @@ static int copyfd_io_poll(int infd, int peerfd, int out= fd, bool *in_closed_after if (cfg_remove) usleep(cfg_wait); =20 - close(peerfd); return 0; } =20 @@ -769,7 +778,7 @@ static int copyfd_io_sendfile(int infd, int peerfd, int= outfd, return err; } =20 -static int copyfd_io(int infd, int peerfd, int outfd) +static int copyfd_io(int infd, int peerfd, int outfd, bool close_peerfd) { bool in_closed_after_out =3D false; struct timespec start, end; @@ -808,6 +817,9 @@ static int copyfd_io(int infd, int peerfd, int outfd) if (ret) return ret; =20 + if (close_peerfd) + close(peerfd); + if (cfg_time) { unsigned int delta_ms; =20 @@ -919,7 +931,7 @@ static void maybe_close(int fd) { unsigned int r =3D rand(); =20 - if (!(cfg_join || cfg_remove) && (r & 1)) + if (!(cfg_join || cfg_remove || (cfg_repeat > 1)) && (r & 1)) close(fd); } =20 @@ -929,7 +941,9 @@ int main_loop_s(int listensock) struct pollfd polls; socklen_t salen; int remotesock; + int fd =3D 0; =20 +again: polls.fd =3D listensock; polls.events =3D POLLIN; =20 @@ -950,12 +964,25 @@ int main_loop_s(int listensock) check_sockaddr(pf, &ss, salen); check_getpeername(remotesock, &ss, salen); =20 - return copyfd_io(0, remotesock, 1); + if (cfg_input) { + fd =3D open(cfg_input, O_RDONLY); + if (fd < 0) + xerror("can't open %s: %d", cfg_input, errno); + } + + copyfd_io(fd, remotesock, 1, true); + } else { + perror("accept"); + return 1; } =20 - perror("accept"); + if (--cfg_repeat > 0) { + if (cfg_input) + close(fd); + goto again; + } =20 - return 1; + return 0; } =20 static void init_rng(void) @@ -1044,15 +1071,47 @@ static void parse_setsock_options(const char *name) exit(1); } =20 +void xdisconnect(int fd, int addrlen) +{ + struct sockaddr_storage empty; + int msec_sleep =3D 10; + int queued =3D 1; + int i; + + shutdown(fd, SHUT_WR); + + /* while until the pending data is completely flushed, the later + * disconnect will bypass/ingore/drop any pending data. + */ + for (i =3D 0; ; i +=3D msec_sleep) { + if (ioctl(fd, SIOCOUTQ, &queued) < 0) + xerror("can't query out socket queue: %d", errno); + + if (!queued) + break; + + if (i > poll_timeout) + xerror("timeout while wating for spool to complete"); + usleep(msec_sleep * 1000); + } + + memset(&empty, 0, sizeof(empty)); + empty.ss_family =3D AF_UNSPEC; + if (connect(fd, (struct sockaddr *)&empty, addrlen) < 0) + xerror("can't disconnect: %d", errno); +} + int main_loop(void) { - int fd; + int fd, ret, fd_in =3D 0; + struct addrinfo *peer; =20 /* listener is ready. */ - fd =3D sock_connect_mptcp(cfg_host, cfg_port, cfg_sock_proto); + fd =3D sock_connect_mptcp(cfg_host, cfg_port, cfg_sock_proto, &peer); if (fd < 0) return 2; =20 +again: check_getpeername_connect(fd); =20 if (cfg_rcvbuf) @@ -1062,7 +1121,31 @@ int main_loop(void) if (cfg_cmsg_types.cmsg_enabled) apply_cmsg_types(fd, &cfg_cmsg_types); =20 - return copyfd_io(0, fd, 1); + if (cfg_input) { + fd_in =3D open(cfg_input, O_RDONLY); + if (fd < 0) + xerror("can't open %s:%d", cfg_input, errno); + } + + /* 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); + if (ret) + return ret; + + if (--cfg_repeat > 0) { + xdisconnect(fd, peer->ai_addrlen); + + /* the socket could be unblocking at this point, we need the + * connect to be blocking + */ + set_nonblock(fd, false); + if (connect(fd, peer->ai_addr, peer->ai_addrlen)) + xerror("can't reconnect: %d", errno); + if (cfg_input) + close(fd_in); + goto again; + } + return 0; } =20 int parse_proto(const char *proto) @@ -1147,7 +1230,7 @@ static void parse_opts(int argc, char **argv) { int c; =20 - while ((c =3D getopt(argc, argv, "6jr:lp:s:hut:T:m:S:R:w:M:P:c:o:")) !=3D= -1) { + while ((c =3D getopt(argc, argv, "6jr:lp:s:hi:I:ut:T:m:S:R:w:M:P:c:o:")) = !=3D -1) { switch (c) { case 'j': cfg_join =3D true; @@ -1161,6 +1244,12 @@ static void parse_opts(int argc, char **argv) if (cfg_do_w <=3D 0) cfg_do_w =3D 50; break; + case 'i': + cfg_input =3D optarg; + break; + case 'I': + cfg_repeat =3D atoi(optarg); + break; case 'l': listen_mode =3D true; break; diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/tes= ting/selftests/net/mptcp/mptcp_connect.sh index a4226b608c68..6553fa3dceec 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh @@ -7,6 +7,7 @@ optstring=3D"S:R:d:e:l:r:h4cm:f:tC" ret=3D0 sin=3D"" sout=3D"" +cin_disconnect=3D"" cin=3D"" cout=3D"" ksft_skip=3D4 @@ -24,6 +25,7 @@ options_log=3Dtrue do_tcp=3D0 checksum=3Dfalse filesize=3D0 +connect_per_transfer=3D1 =20 if [ $tc_loss -eq 100 ];then tc_loss=3D1% @@ -127,6 +129,7 @@ TEST_COUNT=3D0 =20 cleanup() { + rm -f "$cin_disconnect" "$cout_disconnect" rm -f "$cin" "$cout" rm -f "$sin" "$sout" rm -f "$capout" @@ -149,6 +152,8 @@ sout=3D$(mktemp) cin=3D$(mktemp) cout=3D$(mktemp) capout=3D$(mktemp) +cin_disconnect=3D"$cin".disconnect +cout_disconnect=3D"$cout".disconnect trap cleanup EXIT =20 for i in "$ns1" "$ns2" "$ns3" "$ns4";do @@ -518,8 +523,8 @@ do_transfer() cookies=3D${cookies##*=3D} =20 if [ ${cl_proto} =3D "MPTCP" ] && [ ${srv_proto} =3D "MPTCP" ]; then - expect_synrx=3D$((stat_synrx_last_l+1)) - expect_ackrx=3D$((stat_ackrx_last_l+1)) + expect_synrx=3D$((stat_synrx_last_l+$connect_per_transfer)) + expect_ackrx=3D$((stat_ackrx_last_l+$connect_per_transfer)) fi =20 if [ ${stat_synrx_now_l} -lt ${expect_synrx} ]; then @@ -756,6 +761,33 @@ run_tests_peekmode() run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1 "-P ${peekmode}" } =20 +run_tests_disconnect() +{ + local peekmode=3D"$1" + local old_cin=3D$cin + local old_sin=3D$sin + + cat $cin $cin $cin > "$cin".disconnect + + # force do_transfer to cope with the multiple tranmissions + sin=3D"$cin.disconnect" + sin_disconnect=3D$old_sin + cin=3D"$cin.disconnect" + cin_disconnect=3D"$old_cin" + connect_per_transfer=3D3 + + echo "INFO: disconnect" + run_tests_lo "$ns1" "$ns1" 10.0.1.1 1 "-I 3 -i $old_cin" + run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1 "-I 3 -i $old_cin" + + # restore previous status + cout=3D$old_cout + cout_disconnect=3D"$cout".disconnect + cin=3D$old_cin + cin_disconnect=3D"$cin".disconnect + connect_per_transfer=3D1 +} + display_time() { time_end=3D$(date +%s) @@ -874,5 +906,7 @@ stop_if_error "Tests with peek mode have failed" run_test_transparent 10.0.3.1 "tproxy ipv4" run_test_transparent dead:beef:3::1 "tproxy ipv6" =20 +run_tests_disconnect + display_time exit $ret --=20 2.33.1