From nobody Fri Apr 26 22:05:40 2024 Delivered-To: wpasupplicant.patchew@gmail.com Received: by 2002:a02:cbb9:0:0:0:0:0 with SMTP id v25csp690495jap; Thu, 11 Nov 2021 07:14:37 -0800 (PST) X-Google-Smtp-Source: ABdhPJwaBIDOeZTw8BdyzuWuJ9tbXvwr2vUZkuxUcMJDFmo42pWUGSzuCgnR4mDtNOtzRFD4eCsH X-Received: by 2002:a17:903:31d3:b0:142:5da6:299e with SMTP id v19-20020a17090331d300b001425da6299emr8609756ple.30.1636643677266; Thu, 11 Nov 2021 07:14:37 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1636643677; cv=none; d=google.com; s=arc-20160816; b=mrG0KsAmctKf6owUQzdtu+edsLIg3svWZsU+5LMlESR7rk1FS9QlNEOyGyiI0F12lD XmB+bKVpuJg/TitrrZepAoqQ1U8xJS5stgwOnRU/EFj3RR/HeGSd/mfIZC9x5U6OhIkG 0GIPIe69Rv0gsS0KS2m1Jg16aE4dy5r+QIHVztzMFtFKeF5igMmi1FzsCMICRWmrXB1s qKYgOgbaOHYIJEJ4UpI9qoAPLKSxtKuA8dEK2PVvRoN1U7nDSp5WqdZIQIdRdB6YLnS2 11zom6Wri28tlVWu0HO525/dH/PgRf6gb+VVtePWkUq2FnyYYSwvLSwZsk5SyAdcu2nn /XdA== 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:cc:to:from; bh=gmXWFLmTSktceE3Dr1ZFYeeo7O8TiprMphyZQ6yn88w=; b=r1ELkokXz/3IGLS07hD8fte7ND4e9vSvr8Av+KfU1Mu+k0wWxozl9YRkxK2dibr0yJ MezDvaLrIhKSHVphaz4pVJS9p3MMXmccylxPD+X+EjhlqeFTvxGmKJFm56E5XHOBGOcS ORyCDUK7v8L62g5zxqC9J+4WHvbw8sdxtsLX/TaFMPfS5ida7ClLONXbpZbzM14kvyeI mUjjb4RarpZ+nMEJJM9vRheNozpUJo+iY9dAg7G4scnqvTxxyGAncrjW2EitOETnS60e 6/UKFQoSbulq+vp8QedVflaBzU0MH31RYaY8UzVvwOaDdMG2tHaRZSeV+vevT2VjwfMV 30YA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of mptcp+bounces-2418-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 2604:1380:1000:8100::1 as permitted sender) smtp.mailfrom="mptcp+bounces-2418-wpasupplicant.patchew=gmail.com@lists.linux.dev" Return-Path: Received: from sjc.edge.kernel.org (sjc.edge.kernel.org. [2604:1380:1000:8100::1]) by mx.google.com with ESMTPS id h24si5548004plr.143.2021.11.11.07.14.37 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 11 Nov 2021 07:14:37 -0800 (PST) Received-SPF: pass (google.com: domain of mptcp+bounces-2418-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; spf=pass (google.com: domain of mptcp+bounces-2418-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 2604:1380:1000:8100::1 as permitted sender) smtp.mailfrom="mptcp+bounces-2418-wpasupplicant.patchew=gmail.com@lists.linux.dev" 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 C38D23E0FF3 for ; Thu, 11 Nov 2021 15:14:36 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5E3A52C82; Thu, 11 Nov 2021 15:14:36 +0000 (UTC) X-Original-To: mptcp@lists.linux.dev Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [193.142.43.52]) (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 4586E2C81 for ; Thu, 11 Nov 2021 15:14:35 +0000 (UTC) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1mlBmV-0000Mf-SW; Thu, 11 Nov 2021 16:14:27 +0100 From: Florian Westphal To: Cc: Florian Westphal Subject: [PATCH v2 mptcp-next 1/4] mptcp: add TCP_INQ cmsg support Date: Thu, 11 Nov 2021 16:14:15 +0100 Message-Id: <20211111151418.17276-2-fw@strlen.de> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211111151418.17276-1-fw@strlen.de> References: <20211111151418.17276-1-fw@strlen.de> 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" Support the TCP_INQ setsockopt. This is a boolean that tells recvmsg path to include the remaining in-sequence bytes in the cmsg data. v2: do not use CB(skb)->offset, increment map_seq instead (Paolo Abeni) Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/224 Signed-off-by: Florian Westphal --- net/mptcp/protocol.c | 35 ++++++++++++++++++++++++++++++++++- net/mptcp/protocol.h | 1 + net/mptcp/sockopt.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index b0bfe20d6bb0..61047d04e849 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -46,6 +46,7 @@ struct mptcp_skb_cb { =20 enum { MPTCP_CMSG_TS =3D BIT(0), + MPTCP_CMSG_INQ =3D BIT(1), }; =20 static struct percpu_counter mptcp_sockets_allocated; @@ -1825,8 +1826,10 @@ static int __mptcp_recvmsg_mskq(struct mptcp_sock *m= sk, copied +=3D count; =20 if (count < data_len) { - if (!(flags & MSG_PEEK)) + if (!(flags & MSG_PEEK)) { MPTCP_SKB_CB(skb)->offset +=3D count; + MPTCP_SKB_CB(skb)->map_seq +=3D count; + } break; } =20 @@ -2006,6 +2009,27 @@ static bool __mptcp_move_skbs(struct mptcp_sock *msk) return !skb_queue_empty(&msk->receive_queue); } =20 +static unsigned int mptcp_inq_hint(const struct sock *sk) +{ + const struct mptcp_sock *msk =3D mptcp_sk(sk); + const struct sk_buff *skb; + + skb =3D skb_peek(&msk->receive_queue); + if (skb) { + u64 hint_val =3D msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; + + if (hint_val >=3D INT_MAX) + return INT_MAX; + + return (unsigned int)hint_val; + } + + if (sk->sk_state =3D=3D TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN)) + return 1; + + return 0; +} + static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, int flags, int *addr_len) { @@ -2030,6 +2054,9 @@ static int mptcp_recvmsg(struct sock *sk, struct msgh= dr *msg, size_t len, len =3D min_t(size_t, len, INT_MAX); target =3D sock_rcvlowat(sk, flags & MSG_WAITALL, len); =20 + if (unlikely(msk->recvmsg_inq)) + cmsg_flags =3D MPTCP_CMSG_INQ; + while (copied < len) { int bytes_read; =20 @@ -2103,6 +2130,12 @@ static int mptcp_recvmsg(struct sock *sk, struct msg= hdr *msg, size_t len, if (cmsg_flags && copied >=3D 0) { if (cmsg_flags & MPTCP_CMSG_TS) tcp_recv_timestamp(msg, sk, &tss); + + if (cmsg_flags & MPTCP_CMSG_INQ) { + unsigned int inq =3D mptcp_inq_hint(sk); + + put_cmsg(msg, SOL_TCP, TCP_CM_INQ, sizeof(inq), &inq); + } } =20 pr_debug("msk=3D%p rx queue empty=3D%d:%d copied=3D%d", diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 906509c6cde5..e77de7662df0 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -250,6 +250,7 @@ struct mptcp_sock { bool use_64bit_ack; /* Set when we received a 64-bit DSN */ bool csum_enabled; bool allow_infinite_fallback; + u8 recvmsg_inq:1; spinlock_t join_list_lock; struct work_struct work; struct sk_buff *ooo_last_skb; diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index b818e91f2e09..7405152691e0 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -557,6 +557,7 @@ static bool mptcp_supported_sockopt(int level, int optn= ame) case TCP_TIMESTAMP: case TCP_NOTSENT_LOWAT: case TCP_TX_DELAY: + case TCP_INQ: return true; } =20 @@ -698,7 +699,21 @@ static int mptcp_setsockopt_v4(struct mptcp_sock *msk,= int optname, static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname, sockptr_t optval, unsigned int optlen) { + struct sock *sk =3D (void *)msk; + int ret, val; + switch (optname) { + case TCP_INQ: + ret =3D mptcp_get_int_option(msk, optval, optlen, &val); + if (ret) + return ret; + if (val < 0 || val > 1) + return -EINVAL; + + lock_sock(sk); + msk->recvmsg_inq =3D !!val; + release_sock(sk); + return 0; case TCP_ULP: return -EOPNOTSUPP; case TCP_CONGESTION: @@ -1032,6 +1047,26 @@ static int mptcp_getsockopt_subflow_addrs(struct mpt= cp_sock *msk, char __user *o return 0; } =20 +static int mptcp_put_int_option(struct mptcp_sock *msk, char __user *optva= l, + int __user *optlen, int val) +{ + int len; + + if (get_user(len, optlen)) + return -EFAULT; + + len =3D min_t(unsigned int, len, sizeof(int)); + if (len < 0) + return -EINVAL; + + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} + static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname, char __user *optval, int __user *optlen) { @@ -1042,6 +1077,8 @@ static int mptcp_getsockopt_sol_tcp(struct mptcp_sock= *msk, int optname, case TCP_CC_INFO: return mptcp_getsockopt_first_sf_only(msk, SOL_TCP, optname, optval, optlen); + case TCP_INQ: + return mptcp_put_int_option(msk, optval, optlen, msk->recvmsg_inq); } return -EOPNOTSUPP; } --=20 2.32.0 From nobody Fri Apr 26 22:05:40 2024 Delivered-To: wpasupplicant.patchew@gmail.com Received: by 2002:a02:cbb9:0:0:0:0:0 with SMTP id v25csp690477jap; Thu, 11 Nov 2021 07:14:36 -0800 (PST) X-Google-Smtp-Source: ABdhPJw11pDX1P/djMsHMrg9fRtX2GHsHEAXdZU5FH2/dJpzJV0rFn8ReQnSxNrDWqch3tn9vU+s X-Received: by 2002:a05:6808:2187:: with SMTP id be7mr11948607oib.97.1636643676454; Thu, 11 Nov 2021 07:14:36 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1636643676; cv=none; d=google.com; s=arc-20160816; b=B4+0PdCAOyx3ISVX6BRh9sGJT10ULdU0pighlP2CQE5I+8/tHHgdzIsRA2RrbFs/+/ k3MlkQabDR1Vc/WAP6CmhYSIYerl1Fb10jvzi4d1lp0KgOMD8mNEvTw84IlCTNaUgPw2 TPqC0JNi4sUERgf7HXPvAl23IfD05MhROCUg1ZhWER4imKLK5TRL7HU/oXe4OpaVkz2J Th2MgdVyhIm2DbJa3Ifh8JFAvqv/wi6BwMM/hGD+N+ML15CF4jOkFOQlVCNtrifmSMR1 38oDv8nh3zWlb++kgGkNA6Djbuszc036b/y1kNxJTthcqroluwMr206DabLM7pIZMcyN BxGw== 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:cc:to:from; bh=qgkT64WZVTuVA59luxJdqTNCqDHNJebqupWXp7xOfos=; b=fMrcMPdfeoxKQXHwHyvZA5I09rVyNZUiLyvSyMrVBvYKRWJ53aTVxx1kNXMUN4e7uC +XghqNs4rQU7UdgWEWMPtKzL/SO7LIF8ePGkw1jsjC+mTSM13i+9CCMeJ3Te0W0BUmQ7 9eC6+KnvkNs9rBMGEe+WtbEw4N4sodBaNRtULMQp//5toRrbj7EgnXqSv3EvtNmbzs1J 01hW2GcLPsH2OUpzzSRaeZya5CaFVlkN0RZC1X3b/Ec7HI1yZ43U6iDJNk9NPCWtRois aymK86mU8gBWWJjqOamoJUEpvoL7PW/H6lIe/zpIUz1hZGmRcAyeQkFWfBP+PibwYM/J Pnxw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of mptcp+bounces-2417-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 147.75.197.195 as permitted sender) smtp.mailfrom="mptcp+bounces-2417-wpasupplicant.patchew=gmail.com@lists.linux.dev" Return-Path: Received: from ewr.edge.kernel.org (ewr.edge.kernel.org. [147.75.197.195]) by mx.google.com with ESMTPS id y2si6952206oiv.224.2021.11.11.07.14.36 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 11 Nov 2021 07:14:36 -0800 (PST) Received-SPF: pass (google.com: domain of mptcp+bounces-2417-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 147.75.197.195 as permitted sender) client-ip=147.75.197.195; Authentication-Results: mx.google.com; spf=pass (google.com: domain of mptcp+bounces-2417-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 147.75.197.195 as permitted sender) smtp.mailfrom="mptcp+bounces-2417-wpasupplicant.patchew=gmail.com@lists.linux.dev" 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 ewr.edge.kernel.org (Postfix) with ESMTPS id E50431C05A1 for ; Thu, 11 Nov 2021 15:14:35 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 00E742C83; Thu, 11 Nov 2021 15:14:35 +0000 (UTC) X-Original-To: mptcp@lists.linux.dev Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [193.142.43.52]) (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 B2EC32C81 for ; Thu, 11 Nov 2021 15:14:33 +0000 (UTC) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1mlBma-0000Mu-24; Thu, 11 Nov 2021 16:14:32 +0100 From: Florian Westphal To: Cc: Florian Westphal Subject: [PATCH v2 mptcp-next 2/4] selftests: mptcp: add TCP_INQ support Date: Thu, 11 Nov 2021 16:14:16 +0100 Message-Id: <20211111151418.17276-3-fw@strlen.de> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211111151418.17276-1-fw@strlen.de> References: <20211111151418.17276-1-fw@strlen.de> 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" Do checks on the returned inq counter. Fail on: 1. Huge value (> 1 kbyte, test case files are 1 kb) 2. last hint larger than returned bytes when read was short 3. erronenous indication of EOF. 3) happens when a hint of X bytes reads X-1 on next call but next recvmsg returns more data (instead of EOF). Signed-off-by: Florian Westphal --- .../selftests/net/mptcp/mptcp_connect.c | 58 ++++++++++++++++++- .../selftests/net/mptcp/mptcp_sockopt.sh | 4 +- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/test= ing/selftests/net/mptcp/mptcp_connect.c index ada9b80774d4..0e396af4545a 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.c +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c @@ -73,12 +73,20 @@ static uint32_t cfg_mark; struct cfg_cmsg_types { unsigned int cmsg_enabled:1; unsigned int timestampns:1; + unsigned int tcp_inq:1; }; =20 struct cfg_sockopt_types { unsigned int transparent:1; }; =20 +struct tcp_inq_state { + unsigned int last; + bool expect_eof; +}; + +static struct tcp_inq_state tcp_inq; + static struct cfg_cmsg_types cfg_cmsg_types; static struct cfg_sockopt_types cfg_sockopt_types; =20 @@ -389,7 +397,9 @@ static size_t do_write(const int fd, char *buf, const s= ize_t len) static void process_cmsg(struct msghdr *msgh) { struct __kernel_timespec ts; + bool inq_found =3D false; bool ts_found =3D false; + unsigned int inq =3D 0; struct cmsghdr *cmsg; =20 for (cmsg =3D CMSG_FIRSTHDR(msgh); cmsg ; cmsg =3D CMSG_NXTHDR(msgh, cmsg= )) { @@ -398,12 +408,27 @@ static void process_cmsg(struct msghdr *msgh) ts_found =3D true; continue; } + if (cmsg->cmsg_level =3D=3D IPPROTO_TCP && cmsg->cmsg_type =3D=3D TCP_CM= _INQ) { + memcpy(&inq, CMSG_DATA(cmsg), sizeof(inq)); + inq_found =3D true; + continue; + } + } =20 if (cfg_cmsg_types.timestampns) { if (!ts_found) xerror("TIMESTAMPNS not present\n"); } + + if (cfg_cmsg_types.tcp_inq) { + if (!inq_found) + xerror("TCP_INQ not present\n"); + + if (inq > 1024) + xerror("tcp_inq %u is larger than one kbyte\n", inq); + tcp_inq.last =3D inq; + } } =20 static ssize_t do_recvmsg_cmsg(const int fd, char *buf, const size_t len) @@ -420,10 +445,23 @@ static ssize_t do_recvmsg_cmsg(const int fd, char *bu= f, const size_t len) .msg_controllen =3D sizeof(msg_buf), }; int flags =3D 0; + unsigned int last_hint =3D tcp_inq.last; int ret =3D recvmsg(fd, &msg, flags); =20 - if (ret <=3D 0) + if (ret <=3D 0) { + if (ret =3D=3D 0 && tcp_inq.expect_eof) + return ret; + + if (ret =3D=3D 0 && cfg_cmsg_types.tcp_inq) + if (last_hint !=3D 1 && last_hint !=3D 0) + xerror("EOF but last tcp_inq hint was %u\n", last_hint); + return ret; + } + + if (tcp_inq.expect_eof) + xerror("expected EOF, last_hint %u, now %u\n", + last_hint, tcp_inq.last); =20 if (msg.msg_controllen && !cfg_cmsg_types.cmsg_enabled) xerror("got %lu bytes of cmsg data, expected 0\n", @@ -435,6 +473,17 @@ static ssize_t do_recvmsg_cmsg(const int fd, char *buf= , const size_t len) if (msg.msg_controllen) process_cmsg(&msg); =20 + if (cfg_cmsg_types.tcp_inq) { + if ((size_t)ret < len && last_hint > (unsigned int)ret) { + if (ret + 1 !=3D (int)last_hint) { + int next =3D read(fd, msg_buf, sizeof(msg_buf)); + + xerror("read %u of %u, last_hint was %u tcp_inq hint now %u next_read = returned %d/%m\n", ret, (unsigned int)len, last_hint, tcp_inq.last, next); + } else + tcp_inq.expect_eof =3D true; + } + } + return ret; } =20 @@ -944,6 +993,8 @@ static void apply_cmsg_types(int fd, const struct cfg_c= msg_types *cmsg) =20 if (cmsg->timestampns) xsetsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS_NEW, &on, sizeof(on)); + if (cmsg->tcp_inq) + xsetsockopt(fd, IPPROTO_TCP, TCP_INQ, &on, sizeof(on)); } =20 static void parse_cmsg_types(const char *type) @@ -965,6 +1016,11 @@ static void parse_cmsg_types(const char *type) return; } =20 + if (strncmp(type, "TCPINQ", len) =3D=3D 0) { + cfg_cmsg_types.tcp_inq =3D 1; + return; + } + fprintf(stderr, "Unrecognized cmsg option %s\n", type); exit(1); } diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh b/tools/tes= ting/selftests/net/mptcp/mptcp_sockopt.sh index 41de643788b8..c8c364369599 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh @@ -178,7 +178,7 @@ do_transfer() =20 timeout ${timeout_test} \ ip netns exec ${listener_ns} \ - $mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c T= IMESTAMPNS \ + $mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c T= IMESTAMPNS,TCPINQ \ ${local_addr} < "$sin" > "$sout" & spid=3D$! =20 @@ -186,7 +186,7 @@ do_transfer() =20 timeout ${timeout_test} \ ip netns exec ${connector_ns} \ - $mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c TIMES= TAMPNS \ + $mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c TIMES= TAMPNS,TCPINQ \ $connect_addr < "$cin" > "$cout" & =20 cpid=3D$! --=20 2.32.0 From nobody Fri Apr 26 22:05:40 2024 Delivered-To: wpasupplicant.patchew@gmail.com Received: by 2002:a02:cbb9:0:0:0:0:0 with SMTP id v25csp690549jap; Thu, 11 Nov 2021 07:14:40 -0800 (PST) X-Google-Smtp-Source: ABdhPJx2ITVRTAuyrJIV7H2SZgu+zARaAcZ4JDdkyKDzzQ0MkpGl39tGMPaMdYpeNrW8A8TSVW37 X-Received: by 2002:a65:6643:: with SMTP id z3mr5100166pgv.16.1636643680433; Thu, 11 Nov 2021 07:14:40 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1636643680; cv=none; d=google.com; s=arc-20160816; b=zXCpUL2O4dRatcMw/oBgHQ6jU4FqwGjOshnNi1zQXeTkiOnodwmdwknorVww+vyKrn a5il6VmJIwdEeNjagFwXzrT9CUCsVSp9sMafEX7WI3vY+VcmtkirFvGhrxJSW6Iy5ji/ TzfH4UD/NsOcN9v4y/i1Ur/5cKKhdAXLHOqZEAXU6PIpugKOti68eSzMOlKgl84mcOal S0qY2FiYHdc44rN2QT0ikFikSrdgy2+dOb++7bPjtAm1uWICtknWnlf1lXm3WtqyE+EJ 0Ky6t/SYlrQQzXi8IQyJWvrMdYskvjpQETgyO/FX6girrcdN9llGW2tHUBGAaukSOe5Q 3xRw== 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:cc:to:from; bh=pVpQYWN+cceFE/qcx/S1wSWvAs/WwIvABpsCyMkEOO8=; b=039EeOL8+c+NtFE98qeJGnWqld2aa7qL8DIez7NsoqCMMrqlcroGUQ4J1IlGbwM0F9 ko8RkK4P4luuRwuhNJ+/xcuZVDF7WNK/9Nzv4/iDdCc8r5OY9R0KowThwlRUr1hH3Zwt 9qOJSMT8N5Chr+J7BIbn1y6O1MZGd6YnFVNPD04Wu//Do+hsKylP3U1/BuKYm9af+jpb 6MSFA1S5axg0j2Kitae7c3P0v/UEwLz6bJslR7qKq29H7/ApEretNmptesuYQ6bbb5UR Ir86LMIGFfo7F2ic2PpdnByrYb9FobCD/xydQaO5Zwv4Fpscy/Z0V55R3Xj/48EIVZPc owPA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of mptcp+bounces-2419-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 2604:1380:1000:8100::1 as permitted sender) smtp.mailfrom="mptcp+bounces-2419-wpasupplicant.patchew=gmail.com@lists.linux.dev" Return-Path: Received: from sjc.edge.kernel.org (sjc.edge.kernel.org. [2604:1380:1000:8100::1]) by mx.google.com with ESMTPS id u12si4685439pfc.163.2021.11.11.07.14.40 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 11 Nov 2021 07:14:40 -0800 (PST) Received-SPF: pass (google.com: domain of mptcp+bounces-2419-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; spf=pass (google.com: domain of mptcp+bounces-2419-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 2604:1380:1000:8100::1 as permitted sender) smtp.mailfrom="mptcp+bounces-2419-wpasupplicant.patchew=gmail.com@lists.linux.dev" 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 E39F53E103B for ; Thu, 11 Nov 2021 15:14:39 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 192E12C82; Thu, 11 Nov 2021 15:14:39 +0000 (UTC) X-Original-To: mptcp@lists.linux.dev Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [193.142.43.52]) (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 DFDB82C81 for ; Thu, 11 Nov 2021 15:14:37 +0000 (UTC) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1mlBme-0000N6-7d; Thu, 11 Nov 2021 16:14:36 +0100 From: Florian Westphal To: Cc: Florian Westphal Subject: [PATCH v2 mptcp-next 3/4] mptcp: add SIOCINQ, OUTQ and OUTQNSD ioctls Date: Thu, 11 Nov 2021 16:14:17 +0100 Message-Id: <20211111151418.17276-4-fw@strlen.de> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211111151418.17276-1-fw@strlen.de> References: <20211111151418.17276-1-fw@strlen.de> 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" Allows to query in-sequence data ready for read(), total bytes in write queue and total bytes in write queue that have not yet been sent. v2: remove unneeded READ_ONCE() (Paolo Abeni) Signed-off-by: Florian Westphal --- net/mptcp/protocol.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 61047d04e849..1c4604283b00 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -22,6 +22,7 @@ #endif #include #include +#include #include "protocol.h" #include "mib.h" =20 @@ -3260,6 +3261,58 @@ static int mptcp_forward_alloc_get(const struct sock= *sk) return sk->sk_forward_alloc + mptcp_sk(sk)->rmem_fwd_alloc; } =20 +static int mptcp_ioctl_outq(const struct mptcp_sock *msk, u64 v) +{ + const struct sock *sk =3D (void *)msk; + u64 delta; + + if (sk->sk_state =3D=3D TCP_LISTEN) + return -EINVAL; + + if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) + return 0; + + delta =3D msk->write_seq - v; + if (delta > INT_MAX) + delta =3D INT_MAX; + + return (int)delta; +} + +static int mptcp_ioctl(struct sock *sk, int cmd, unsigned long arg) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + int answ; + bool slow; + + switch (cmd) { + case SIOCINQ: + if (sk->sk_state =3D=3D TCP_LISTEN) + return -EINVAL; + + lock_sock(sk); + if (skb_queue_empty(&msk->receive_queue)) + __mptcp_move_skbs(msk); + answ =3D mptcp_inq_hint(sk); + release_sock(sk); + break; + case SIOCOUTQ: + slow =3D lock_sock_fast(sk); + answ =3D mptcp_ioctl_outq(msk, READ_ONCE(msk->snd_una)); + unlock_sock_fast(sk, slow); + break; + case SIOCOUTQNSD: + slow =3D lock_sock_fast(sk); + answ =3D mptcp_ioctl_outq(msk, msk->snd_nxt); + unlock_sock_fast(sk, slow); + break; + default: + return -ENOIOCTLCMD; + } + + return put_user(answ, (int __user *)arg); +} + static struct proto mptcp_prot =3D { .name =3D "MPTCP", .owner =3D THIS_MODULE, @@ -3272,6 +3325,7 @@ static struct proto mptcp_prot =3D { .shutdown =3D mptcp_shutdown, .destroy =3D mptcp_destroy, .sendmsg =3D mptcp_sendmsg, + .ioctl =3D mptcp_ioctl, .recvmsg =3D mptcp_recvmsg, .release_cb =3D mptcp_release_cb, .hash =3D mptcp_hash, --=20 2.32.0 From nobody Fri Apr 26 22:05:40 2024 Delivered-To: wpasupplicant.patchew@gmail.com Received: by 2002:a02:cbb9:0:0:0:0:0 with SMTP id v25csp690654jap; Thu, 11 Nov 2021 07:14:45 -0800 (PST) X-Google-Smtp-Source: ABdhPJwKUgEcUQ8Fs5ACsQtLL27PiSvt8M01qcAy6YQJGuczgihhy1f23XHNzMzDW4++C5AYYr9K X-Received: by 2002:a05:6808:ec3:: with SMTP id q3mr6510346oiv.57.1636643685886; Thu, 11 Nov 2021 07:14:45 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1636643685; cv=none; d=google.com; s=arc-20160816; b=qjkN9mFYqwGnKvZdhiafPtaBtf8v5S42Zk4TeSua3NNmLW7WfyVJ1sXmSuJicykTTD z5zUqiMSRdIAbNqBoeKwU+ebw02b4Pkyq+tOmsW0dG8XvlGWFYkkaHK8zoHfU1pXvlDj Qm1FeDddAg9u/rwpANFiPxtDtwDxPh14KVdVsY5quJmb3JNh5BpwullRqm6ywi6xogee MwhbPTKVPYMXqttT3OoKAzj+G8hNoKza/sqayMGYdgREs8A2PY8oEoSDu5q8xa48gAAP n3VftrXEdyU16BN1FHGR2D5G2VPJnwtLyiJsQKQy0+nk6Dcf7bF1aBty3GSTJM//BuwW 9WPQ== 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:cc:to:from; bh=sfi55wqswJL4Muq4xM0zM8uK3jJndb3IXc13YTMr7Xc=; b=If3P9+CSLEC0tPOmEZ6BPPShFl+rSwHO+NifksKqqETnJP22WiVRd+YO/+ZqbU7BjE OYhjgDMc9vY+iLT5xx0onBCmwZe9gxCebwHlTXsn0lRfivRPjcmu6UGTesqPJYJToHJq QNaI8Rwfmpa3wdLezRI9Ofqt8NwyWpSDoXtloTB/dKU9fTpACNxumY6G3ey35oBnTvTT Xq3uwqUCdWrQ60sP/NdgV7IGOy8nWZqN7XceXNVWYesEKZt3Q94fJaHTPcuyDgJPqrEE Ppv1xUZcTtjhBSnivGsUUCRtU9xxJJXwsqhtW/VtR+TjL8oD4ddyBntoXw04dFJtR+rH /5aA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of mptcp+bounces-2420-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 147.75.197.195 as permitted sender) smtp.mailfrom="mptcp+bounces-2420-wpasupplicant.patchew=gmail.com@lists.linux.dev" Return-Path: Received: from ewr.edge.kernel.org (ewr.edge.kernel.org. [147.75.197.195]) by mx.google.com with ESMTPS id r62si4370214oib.308.2021.11.11.07.14.45 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 11 Nov 2021 07:14:45 -0800 (PST) Received-SPF: pass (google.com: domain of mptcp+bounces-2420-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 147.75.197.195 as permitted sender) client-ip=147.75.197.195; Authentication-Results: mx.google.com; spf=pass (google.com: domain of mptcp+bounces-2420-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 147.75.197.195 as permitted sender) smtp.mailfrom="mptcp+bounces-2420-wpasupplicant.patchew=gmail.com@lists.linux.dev" 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 ewr.edge.kernel.org (Postfix) with ESMTPS id 0E2AE1C0441 for ; Thu, 11 Nov 2021 15:14:45 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BEC822C82; Thu, 11 Nov 2021 15:14:43 +0000 (UTC) X-Original-To: mptcp@lists.linux.dev Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [193.142.43.52]) (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 1ACF12C81 for ; Thu, 11 Nov 2021 15:14:42 +0000 (UTC) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1mlBmi-0000NX-Ch; Thu, 11 Nov 2021 16:14:40 +0100 From: Florian Westphal To: Cc: Florian Westphal , Mat Martineau Subject: [PATCH v2 mptcp-next 4/4] selftests: mptcp: add inq test case Date: Thu, 11 Nov 2021 16:14:18 +0100 Message-Id: <20211111151418.17276-5-fw@strlen.de> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211111151418.17276-1-fw@strlen.de> References: <20211111151418.17276-1-fw@strlen.de> 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" client & server use a unix socket connection to communicate outside of the mptcp connection. This allows the consumer to know in advance how many bytes have been (or will be) sent by the peer. This allows stricter checks on the bytecounts reported by TCP_INQ cmsg. Suggested-by: Mat Martineau Signed-off-by: Florian Westphal --- tools/testing/selftests/net/mptcp/.gitignore | 1 + tools/testing/selftests/net/mptcp/Makefile | 2 +- tools/testing/selftests/net/mptcp/mptcp_inq.c | 603 ++++++++++++++++++ .../selftests/net/mptcp/mptcp_sockopt.sh | 40 ++ 4 files changed, 645 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/net/mptcp/mptcp_inq.c diff --git a/tools/testing/selftests/net/mptcp/.gitignore b/tools/testing/s= elftests/net/mptcp/.gitignore index 7569d892967a..49daae73c41e 100644 --- a/tools/testing/selftests/net/mptcp/.gitignore +++ b/tools/testing/selftests/net/mptcp/.gitignore @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only mptcp_connect +mptcp_inq mptcp_sockopt pm_nl_ctl *.pcap diff --git a/tools/testing/selftests/net/mptcp/Makefile b/tools/testing/sel= ftests/net/mptcp/Makefile index bbf4e448bad9..0356c4501c99 100644 --- a/tools/testing/selftests/net/mptcp/Makefile +++ b/tools/testing/selftests/net/mptcp/Makefile @@ -8,7 +8,7 @@ CFLAGS =3D -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir= )/usr/include TEST_PROGS :=3D mptcp_connect.sh pm_netlink.sh mptcp_join.sh diag.sh \ simult_flows.sh mptcp_sockopt.sh =20 -TEST_GEN_FILES =3D mptcp_connect pm_nl_ctl mptcp_sockopt +TEST_GEN_FILES =3D mptcp_connect pm_nl_ctl mptcp_sockopt mptcp_inq =20 TEST_FILES :=3D settings =20 diff --git a/tools/testing/selftests/net/mptcp/mptcp_inq.c b/tools/testing/= selftests/net/mptcp/mptcp_inq.c new file mode 100644 index 000000000000..62ee2dd63b5f --- /dev/null +++ b/tools/testing/selftests/net/mptcp/mptcp_inq.c @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#ifndef IPPROTO_MPTCP +#define IPPROTO_MPTCP 262 +#endif +#ifndef SOL_MPTCP +#define SOL_MPTCP 284 +#endif + +static int pf =3D AF_INET; +static int proto_tx =3D IPPROTO_MPTCP; +static int proto_rx =3D IPPROTO_MPTCP; + +static void die_perror(const char *msg) +{ + perror(msg); + exit(1); +} + +static void die_usage(int r) +{ + fprintf(stderr, "Usage: mptcp_inq [-6] [ -t tcp|mptcp ] [ -r tcp|mptcp]\n= "); + exit(r); +} + +static void xerror(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputc('\n', stderr); + exit(1); +} + +static const char *getxinfo_strerr(int err) +{ + if (err =3D=3D EAI_SYSTEM) + return strerror(errno); + + return gai_strerror(err); +} + +static void xgetaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ + int err =3D getaddrinfo(node, service, hints, res); + + if (err) { + const char *errstr =3D getxinfo_strerr(err); + + fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n", + node ? node : "", service ? service : "", errstr); + exit(1); + } +} + +static int sock_listen_mptcp(const char * const listenaddr, + const char * const port) +{ + int sock; + struct addrinfo hints =3D { + .ai_protocol =3D IPPROTO_TCP, + .ai_socktype =3D SOCK_STREAM, + .ai_flags =3D AI_PASSIVE | AI_NUMERICHOST + }; + + hints.ai_family =3D pf; + + struct addrinfo *a, *addr; + int one =3D 1; + + xgetaddrinfo(listenaddr, port, &hints, &addr); + hints.ai_family =3D pf; + + for (a =3D addr; a; a =3D a->ai_next) { + sock =3D socket(a->ai_family, a->ai_socktype, proto_rx); + if (sock < 0) + continue; + + if (-1 =3D=3D setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, + sizeof(one))) + perror("setsockopt"); + + if (bind(sock, a->ai_addr, a->ai_addrlen) =3D=3D 0) + break; /* success */ + + perror("bind"); + close(sock); + sock =3D -1; + } + + freeaddrinfo(addr); + + if (sock < 0) + xerror("could not create listen socket"); + + if (listen(sock, 20)) + die_perror("listen"); + + return sock; +} + +static int sock_connect_mptcp(const char * const remoteaddr, + const char * const port, int proto) +{ + struct addrinfo hints =3D { + .ai_protocol =3D IPPROTO_TCP, + .ai_socktype =3D SOCK_STREAM, + }; + struct addrinfo *a, *addr; + int sock =3D -1; + + hints.ai_family =3D pf; + + xgetaddrinfo(remoteaddr, port, &hints, &addr); + for (a =3D addr; a; a =3D a->ai_next) { + sock =3D socket(a->ai_family, a->ai_socktype, proto); + if (sock < 0) + continue; + + if (connect(sock, a->ai_addr, a->ai_addrlen) =3D=3D 0) + break; /* success */ + + die_perror("connect"); + } + + if (sock < 0) + xerror("could not create connect socket"); + + freeaddrinfo(addr); + return sock; +} + +static int protostr_to_num(const char *s) +{ + if (strcasecmp(s, "tcp") =3D=3D 0) + return IPPROTO_TCP; + if (strcasecmp(s, "mptcp") =3D=3D 0) + return IPPROTO_MPTCP; + + die_usage(1); + return 0; +} + +static void parse_opts(int argc, char **argv) +{ + int c; + + while ((c =3D getopt(argc, argv, "h6t:r:")) !=3D -1) { + switch (c) { + case 'h': + die_usage(0); + break; + case '6': + pf =3D AF_INET6; + break; + case 't': + proto_tx =3D protostr_to_num(optarg); + break; + case 'r': + proto_rx =3D protostr_to_num(optarg); + break; + default: + die_usage(1); + break; + } + } +} + +/* wait up to timeout milliseconds */ +static void wait_for_ack(int fd, int timeout, size_t total) +{ + int i; + + for (i =3D 0; i < timeout; i++) { + int nsd, ret, queued =3D -1; + struct timespec req; + + ret =3D ioctl(fd, TIOCOUTQ, &queued); + if (ret < 0) + die_perror("TIOCOUTQ"); + + ret =3D ioctl(fd, SIOCOUTQNSD, &nsd); + if (ret < 0) + die_perror("SIOCOUTQNSD"); + + if ((size_t)queued > total) + xerror("TIOCOUTQ %u, but only %zu expected\n", queued, total); + assert(nsd <=3D queued); + + if (queued =3D=3D 0) + return; + + /* wait for peer to ack rx of all data */ + req.tv_sec =3D 0; + req.tv_nsec =3D 1 * 1000 * 1000ul; /* 1ms */ + nanosleep(&req, NULL); + } + + xerror("still tx data queued after %u ms\n", timeout); +} + +static void connect_one_server(int fd, int unixfd) +{ + size_t len, i, total, sent; + char buf[4096], buf2[4096]; + int queued, on =3D 1; + ssize_t ret; + + len =3D rand() % (sizeof(buf) - 1); + + if (len < 128) + len =3D 128; + + for (i =3D 0; i < len ; i++) { + buf[i] =3D rand() % 26; + buf[i] +=3D 'A'; + } + + buf[i] =3D '\n'; + + /* un-block server */ + ret =3D read(unixfd, buf2, 4); + assert(ret =3D=3D 4); + + assert(strncmp(buf2, "xmit", 4) =3D=3D 0); + + ret =3D write(unixfd, &len, sizeof(len)); + assert(ret =3D=3D (ssize_t)sizeof(len)); + + ret =3D write(fd, buf, len); + if (ret < 0) + die_perror("write"); + + if (ret !=3D (ssize_t)len) + xerror("short write"); + + ret =3D read(unixfd, buf2, 4); + assert(strncmp(buf2, "huge", 4) =3D=3D 0); + + total =3D rand() % (16 * 1024 * 1024); + total +=3D (1 * 1024 * 1024); + sent =3D total; + + ret =3D write(unixfd, &total, sizeof(total)); + assert(ret =3D=3D (ssize_t)sizeof(total)); + + wait_for_ack(fd, 5000, len); + + while (total > 0) { + if (total > sizeof(buf)) + len =3D sizeof(buf); + else + len =3D total; + + ret =3D write(fd, buf, len); + if (ret < 0) + die_perror("write"); + total -=3D ret; + + /* we don't have to care about buf content, only + * number of total bytes sent + */ + } + + ret =3D read(unixfd, buf2, 4); + assert(ret =3D=3D 4); + assert(strncmp(buf2, "shut", 4) =3D=3D 0); + + wait_for_ack(fd, 5000, sent); + + write(fd, buf, 1); + close(fd); + ret =3D write(unixfd, "closed", 6); + assert(ret =3D=3D 6); + + close(unixfd); +} + +static void get_tcp_inq(struct msghdr *msgh, unsigned int *inqv) +{ + struct cmsghdr *cmsg; + + for (cmsg =3D CMSG_FIRSTHDR(msgh); cmsg ; cmsg =3D CMSG_NXTHDR(msgh, cmsg= )) { + if (cmsg->cmsg_level =3D=3D IPPROTO_TCP && cmsg->cmsg_type =3D=3D TCP_CM= _INQ) { + memcpy(inqv, CMSG_DATA(cmsg), sizeof(*inqv)); + return; + } + } + + xerror("could not find TCP_CM_INQ cmsg type"); +} + +static void process_one_client(int fd, int unixfd) +{ + unsigned int tcp_inq; + size_t expect_len; + char msg_buf[4096]; + char buf[4096]; + char tmp[16]; + struct iovec iov =3D { + .iov_base =3D buf, + .iov_len =3D 1, + }; + struct msghdr msg =3D { + .msg_iov =3D &iov, + .msg_iovlen =3D 1, + .msg_control =3D msg_buf, + .msg_controllen =3D sizeof(msg_buf), + }; + ssize_t ret, tot; + + ret =3D write(unixfd, "xmit", 4); + assert(ret =3D=3D 4); + + ret =3D read(unixfd, &expect_len, sizeof(expect_len)); + assert(ret =3D=3D (ssize_t)sizeof(expect_len)); + + if (expect_len > sizeof(buf)) + xerror("expect len %zu exceeds buffer size", expect_len); + + for (;;) { + struct timespec req; + unsigned int queued; + + ret =3D ioctl(fd, FIONREAD, &queued); + if (ret < 0) + die_perror("FIONREAD"); + if (queued > expect_len) + xerror("FIONREAD returned %u, but only %zu expected\n", + queued, expect_len); + if (queued =3D=3D expect_len) + break; + + req.tv_sec =3D 0; + req.tv_nsec =3D 1000 * 1000ul; + nanosleep(&req, NULL); + } + + /* read one byte, expect cmsg to return expected - 1 */ + ret =3D recvmsg(fd, &msg, 0); + if (ret < 0) + die_perror("recvmsg"); + + if (msg.msg_controllen =3D=3D 0) + xerror("msg_controllen is 0"); + + get_tcp_inq(&msg, &tcp_inq); + + assert((size_t)tcp_inq =3D=3D (expect_len - 1)); + + iov.iov_len =3D sizeof(buf); + ret =3D recvmsg(fd, &msg, 0); + if (ret < 0) + die_perror("recvmsg"); + + /* should have gotten exact remainder of all pending data */ + assert(ret =3D=3D (ssize_t)tcp_inq); + + /* should be 0, all drained */ + get_tcp_inq(&msg, &tcp_inq); + assert(tcp_inq =3D=3D 0); + + /* request a large swath of data. */ + ret =3D write(unixfd, "huge", 4); + assert(ret =3D=3D 4); + + ret =3D read(unixfd, &expect_len, sizeof(expect_len)); + assert(ret =3D=3D (ssize_t)sizeof(expect_len)); + + /* peer should send us a few mb of data */ + if (expect_len <=3D sizeof(buf)) + xerror("expect len %zu too small\n", expect_len); + + tot =3D 0; + do { + iov.iov_len =3D sizeof(buf); + ret =3D recvmsg(fd, &msg, 0); + if (ret < 0) + die_perror("recvmsg"); + + tot +=3D ret; + + get_tcp_inq(&msg, &tcp_inq); + + if (tcp_inq > expect_len - tot) + xerror("inq %d, remaining %d total_len %d\n", + tcp_inq, expect_len - tot, (int)expect_len); + + assert(tcp_inq <=3D expect_len - tot); + } while ((size_t)tot < expect_len); + + ret =3D write(unixfd, "shut", 4); + assert(ret =3D=3D 4); + + /* wait for hangup. Should have received one more byte of data. */ + ret =3D read(unixfd, tmp, sizeof(tmp)); + assert(ret =3D=3D 6); + assert(strncmp(tmp, "closed", 6) =3D=3D 0); + + sleep(1); + + iov.iov_len =3D 1; + ret =3D recvmsg(fd, &msg, 0); + if (ret < 0) + die_perror("recvmsg"); + assert(ret =3D=3D 1); + + get_tcp_inq(&msg, &tcp_inq); + + /* tcp_inq should be 1 due to received fin. */ + assert(tcp_inq =3D=3D 1); + + iov.iov_len =3D 1; + ret =3D recvmsg(fd, &msg, 0); + if (ret < 0) + die_perror("recvmsg"); + + /* expect EOF */ + assert(ret =3D=3D 0); + get_tcp_inq(&msg, &tcp_inq); + assert(tcp_inq =3D=3D 1); + + close(fd); +} + +static int xaccept(int s) +{ + int fd =3D accept(s, NULL, 0); + + if (fd < 0) + die_perror("accept"); + + return fd; +} + +static int server(int unixfd) +{ + int fd =3D -1, r, on =3D 1; + + switch (pf) { + case AF_INET: + fd =3D sock_listen_mptcp("127.0.0.1", "15432"); + break; + case AF_INET6: + fd =3D sock_listen_mptcp("::1", "15432"); + break; + default: + xerror("Unknown pf %d\n", pf); + break; + } + + r =3D write(unixfd, "conn", 4); + assert(r =3D=3D 4); + + alarm(15); + r =3D xaccept(fd); + + if (-1 =3D=3D setsockopt(r, IPPROTO_TCP, TCP_INQ, &on, sizeof(on))) + die_perror("setsockopt"); + + process_one_client(r, unixfd); + + return 0; +} + +static int client(int unixfd) +{ + int fd =3D -1; + + alarm(15); + + switch (pf) { + case AF_INET: + fd =3D sock_connect_mptcp("127.0.0.1", "15432", proto_tx); + break; + case AF_INET6: + fd =3D sock_connect_mptcp("::1", "15432", proto_tx); + break; + default: + xerror("Unknown pf %d\n", pf); + } + + connect_one_server(fd, unixfd); + + return 0; +} + +static void init_rng(void) +{ + int fd =3D open("/dev/urandom", O_RDONLY); + unsigned int foo; + + if (fd > 0) { + int ret =3D read(fd, &foo, sizeof(foo)); + + if (ret < 0) + srand(fd + foo); + close(fd); + } + + srand(foo); +} + +static pid_t xfork(void) +{ + pid_t p =3D fork(); + + if (p < 0) + die_perror("fork"); + else if (p =3D=3D 0) + init_rng(); + + return p; +} + +static int rcheck(int wstatus, const char *what) +{ + if (WIFEXITED(wstatus)) { + if (WEXITSTATUS(wstatus) =3D=3D 0) + return 0; + fprintf(stderr, "%s exited, status=3D%d\n", what, WEXITSTATUS(wstatus)); + return WEXITSTATUS(wstatus); + } else if (WIFSIGNALED(wstatus)) { + xerror("%s killed by signal %d\n", what, WTERMSIG(wstatus)); + } else if (WIFSTOPPED(wstatus)) { + xerror("%s stopped by signal %d\n", what, WSTOPSIG(wstatus)); + } + + return 111; +} + +int main(int argc, char *argv[]) +{ + int e1, e2, wstatus; + pid_t s, c, ret; + int unixfds[2]; + + parse_opts(argc, argv); + + e1 =3D socketpair(AF_UNIX, SOCK_DGRAM, 0, unixfds); + if (e1 < 0) + die_perror("pipe"); + + s =3D xfork(); + if (s =3D=3D 0) + return server(unixfds[1]); + + close(unixfds[1]); + + /* wait until server bound a socket */ + e1 =3D read(unixfds[0], &e1, 4); + assert(e1 =3D=3D 4); + + c =3D xfork(); + if (c =3D=3D 0) + return client(unixfds[0]); + + close(unixfds[0]); + + ret =3D waitpid(s, &wstatus, 0); + if (ret =3D=3D -1) + die_perror("waitpid"); + e1 =3D rcheck(wstatus, "server"); + ret =3D waitpid(c, &wstatus, 0); + if (ret =3D=3D -1) + die_perror("waitpid"); + e2 =3D rcheck(wstatus, "client"); + + return e1 ? e1 : e2; +} diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh b/tools/tes= ting/selftests/net/mptcp/mptcp_sockopt.sh index c8c364369599..0879da915014 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh @@ -279,6 +279,45 @@ run_tests() fi } =20 +do_tcpinq_test() +{ + ip netns exec "$ns1" ./mptcp_inq "$@" + lret=3D$? + if [ $lret -ne 0 ];then + ret=3D$lret + echo "FAIL: mptcp_inq $@" 1>&2 + return $lret + fi + + echo "PASS: TCP_INQ cmsg/ioctl $@" + return $lret +} + +do_tcpinq_tests() +{ + local lret=3D0 + + ip netns exec "$ns1" iptables -F + ip netns exec "$ns1" ip6tables -F + + for args in "-t tcp" "-r tcp"; do + do_tcpinq_test $args + lret=3D$? + if [ $lret -ne 0 ] ; then + return $lret + fi + do_tcpinq_test -6 $args + lret=3D$? + if [ $lret -ne 0 ] ; then + return $lret + fi + done + + do_tcpinq_test -r tcp -t tcp + + return $? +} + sin=3D$(mktemp) sout=3D$(mktemp) cin=3D$(mktemp) @@ -300,4 +339,5 @@ if [ $ret -eq 0 ];then echo "PASS: SOL_MPTCP getsockopt has expected information" fi =20 +do_tcpinq_tests exit $ret --=20 2.32.0