From nobody Sat Jul 25 07:27:10 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 BEF2323D7E6 for ; Sun, 12 Jul 2026 02:15:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783822558; cv=none; b=ti+PfcxQDnwyzQUfrs7Ow0ftb7T01ROFliGFIAvOx+er7jP+xSsr/MyhF6Zx1/C/AvL1ODv9yYI31ZaAZ5TcZgnSQ5+QwImD82jqwFz3ASEke5faI9O4eSpQtatVFkrsBZHHNQ4tgin4SXekDdmoT4b+4UPOqPaTwxJBYVwDa/o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783822558; c=relaxed/simple; bh=jME7UwAhFGdpy0DC+LD1XLRwwMwYlVOX++7xseGcuGo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kYdE7YaVTdAtfFE6qWvyjjmKIhxO5HflAV6Ixg9HSyG2GH1T6w8cjvLUZyWB4u04Xzpy6Ypk4gGCHWoIvXZt5TAF75gjsvKLzd7JpYWshIsRMiPS7gIUjP8CjTy5aegcE3Kj7ZRzuPLTYOgi8M6AA3SHcIFPse9PrtvoPkfpq0I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JQ0xH23r; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JQ0xH23r" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8AB611F00A3A; Sun, 12 Jul 2026 02:15:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783822557; bh=EYeyAMGYwgrEvRqPliDbY8/sG7cAJUpla97WO7oBIDM=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=JQ0xH23rTbx7Pf5jOg1T0Kd1na6pble2bYul5hsNwhJRNDk7dpQaXPo1Vejmp8EOe 6GxRQuRecfkXGLDrZ0K7r6d2trMHhrwBLkTEjfxxhWfYiYFKmM2gsPBlWZ9v0Yb6yO l4l7eY4bcCoYU3H25vatcaxUGgjVbTj+ZDtgK56EDvgKR8HsGRitY0QilHqnjUff4n +dQieU1qg71OV9zAb5NB49dawCQkCKyhradTgbRRV6IL50pF0GGDEPBWHhIYphL5xD IC0uAeZzzHciiM+FK0URp6uwkTZF7pIkTbFt2RSFsGHe8yJy1Fe0jNPY+8Ju68OkfM Q4Q+1zDx/Q0bg== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang , Paolo Abeni Subject: [PATCH mptcp-next v2 1/5] mptcp: use local variable tp in sendmsg_frag Date: Sun, 12 Jul 2026 10:15:20 +0800 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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: Geliang Tang In mptcp_sendmsg_frag(), tcp_sk(ssk) is called multiple times. Introduce a local variable 'tp' to hold the tcp_sock pointer and use it throughout the function. This avoids repeated dereferencing and improves code readability, with no functional change. Suggested-by: Paolo Abeni Signed-off-by: Geliang Tang --- net/mptcp/protocol.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index ffcf5a1788f6..1cab07b1b9b1 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1375,6 +1375,7 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct= sock *ssk, u64 data_seq =3D dfrag->data_seq + info->sent; int offset =3D dfrag->offset + info->sent; struct mptcp_sock *msk =3D mptcp_sk(sk); + struct tcp_sock *tp =3D tcp_sk(ssk); bool zero_window_probe =3D false; struct mptcp_ext *mpext =3D NULL; bool can_coalesce =3D false; @@ -1410,14 +1411,14 @@ static int mptcp_sendmsg_frag(struct sock *sk, stru= ct sock *ssk, mpext =3D mptcp_get_ext(skb); if (!mptcp_skb_can_collapse_to(data_seq, skb, mpext)) { TCP_SKB_CB(skb)->eor =3D 1; - tcp_mark_push(tcp_sk(ssk), skb); + tcp_mark_push(tp, skb); goto alloc_skb; } =20 i =3D skb_shinfo(skb)->nr_frags; can_coalesce =3D skb_can_coalesce(skb, i, dfrag->page, offset); if (!can_coalesce && i >=3D READ_ONCE(net_hotdata.sysctl_max_skb_frags))= { - tcp_mark_push(tcp_sk(ssk), skb); + tcp_mark_push(tp, skb); goto alloc_skb; } =20 @@ -1471,7 +1472,7 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct= sock *ssk, skb->truesize +=3D copy; sk_wmem_queued_add(ssk, copy); sk_mem_charge(ssk, copy); - WRITE_ONCE(tcp_sk(ssk)->write_seq, tcp_sk(ssk)->write_seq + copy); + WRITE_ONCE(tp->write_seq, tp->write_seq + copy); TCP_SKB_CB(skb)->end_seq +=3D copy; tcp_skb_pcount_set(skb, 0); =20 --=20 2.53.0 From nobody Sat Jul 25 07:27:10 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 F2955346E7E for ; Sun, 12 Jul 2026 02:15:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783822560; cv=none; b=bGWap1MXtpPirQ7JkDVcQMK0BMbG9xLQv0CAAoLJrRNfOPxyrySBspqVc7JkVAtFCjYdbN8h08sXSR3zCe4MYARUPlXV/YQst03zYsoLX0sVef+3Zdd1SfmL5ko1e5AFbfbRQOCXjW/J3tttnkOlpUc04aI6KJAyqbwDMSIQEdc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783822560; c=relaxed/simple; bh=96Ex/79jqoQqyCf+wBNF02DUNZx7BYsA3aLk4x6JRBI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=c9TpP1TPPriSqkbWWQy2MOYotdcYsSYS+v29vLZfCX/Frb00XGvFBdXK1B9TSSh7ke3HaCiHHZ3onR7EMP0M+tkxlBUOkmHdj/kkke3BwkjkUN1gFqdh5XfugDD4dm7NoNEGbMd6taUai8Qgbl6qNUQJzCsxt+wSxL6EQrr6t8s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=b+sGU8d3; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="b+sGU8d3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CE6171F000E9; Sun, 12 Jul 2026 02:15:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783822558; bh=P//J4Wmrm9xDaizLi6ulIgS/gk8hnV8k7hNbXzs5CnQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=b+sGU8d3ceNp9FjM9VmV/CLafRfHnaptxanLCDjCf5Bq328TjVPxASRxGT1IuCL5l j/Pd3lRblwe8Wuq2jMh42lYPWFDd8JMEdab/JFKVP/FzdbnXzhshsG0gxA4LLnmK6+ 9qgHArB3NAuI5b/nxSSPU+A12NoR46PdTy8+pCSff7wfeI6SVIdo9dpl294QfYia9D yUHGuRNVGDcT170T9B5031wYkNYtBeHEsEart2lu99T9m98nMOH4cQrj1JVirBuPOE Ha7DKxkZICZiGnKcaAkEN2x4HJtDW66kYosu76anVb5jb408G16q3wSIT4APCuvIPs rb02DdhsFnziw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v2 2/5] mptcp: add MSG_ZEROCOPY support Date: Sun, 12 Jul 2026 10:15:21 +0800 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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: Geliang Tang This patch enables MSG_ZEROCOPY support for MPTCP sockets, allowing user-space to transmit data without intermediate kernel copies. The implementation follows the same lifecycle model as TCP: A single ubuf_info_msgzc is allocated per sendmsg via msg_zerocopy_realloc(). Its reference count consists of three parts: one 'caller' reference held until sendmsg returns, one reference per MPTCP dfrag in the retransmission queue (released when the dfrag is acked and cleared), and one reference per subflow skb that consumes dfrag bytes (released by TCP's skb_zcopy_clear() when the skb is acked). Completion is reported only after all bytes are acknowledged at both MPTCP and subflow levels. User pages are pinned via iov_iter_get_pages2() and stored directly in a newly allocated mptcp_data_frag. The dfrag takes one reference on the ubuf_info and one on the page. Subflow skbs take additional page references via get_page() and are marked with skb_zcopy_set() and SKBFL_PURE_ZEROCOPY, mirroring TCP's behavior and bypassing kernel memory accounting for those pages. The feature is silently downgraded to regular copy when MSG_FASTOPEN is set or the application has not opted in via setsockopt(SO_ZEROCOPY). If msg_zerocopy_realloc() fails (e.g. RLIMIT_MEMLOCK pressure), sendmsg(2) aborts with -ENOBUFS. Signed-off-by: Geliang Tang --- net/mptcp/protocol.c | 110 ++++++++++++++++++++++++++++++++++++++++--- net/mptcp/protocol.h | 1 + 2 files changed, 104 insertions(+), 7 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 1cab07b1b9b1..d0687a1da8df 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1118,9 +1118,11 @@ static bool mptcp_frag_can_collapse_to(const struct = mptcp_sock *msk, df->data_seq + df->data_len =3D=3D msk->write_seq; } =20 -static void dfrag_uncharge(struct sock *sk, int len) +static void dfrag_uncharge(struct sock *sk, int len, + struct mptcp_data_frag *dfrag) { - sk_mem_uncharge(sk, len); + if (!dfrag->ubuf) + sk_mem_uncharge(sk, len); sk_wmem_queued_add(sk, -len); } =20 @@ -1129,7 +1131,13 @@ static void dfrag_clear(struct sock *sk, struct mptc= p_data_frag *dfrag) int len =3D dfrag->data_len + dfrag->overhead; =20 list_del(&dfrag->list); - dfrag_uncharge(sk, len); + dfrag_uncharge(sk, len, dfrag); + if (dfrag->ubuf) { + net_zcopy_put(dfrag->ubuf); + put_page(dfrag->page); + kfree(dfrag); + return; + } put_page(dfrag->page); } =20 @@ -1174,7 +1182,7 @@ static void __mptcp_clean_una(struct sock *sk) dfrag->data_len -=3D delta; dfrag->already_sent -=3D delta; =20 - dfrag_uncharge(sk, delta); + dfrag_uncharge(sk, delta, dfrag); } =20 /* all retransmitted data acked, recovery completed */ @@ -1248,6 +1256,7 @@ mptcp_carve_data_frag(const struct mptcp_sock *msk, s= truct page_frag *pfrag, dfrag->already_sent =3D 0; dfrag->page =3D pfrag->page; dfrag->eor =3D 0; + dfrag->ubuf =3D NULL; =20 return dfrag; } @@ -1417,6 +1426,15 @@ static int mptcp_sendmsg_frag(struct sock *sk, struc= t sock *ssk, =20 i =3D skb_shinfo(skb)->nr_frags; can_coalesce =3D skb_can_coalesce(skb, i, dfrag->page, offset); + /* never mix PURE_ZEROCOPY frags with kernel-copy frags + * in the same skb + */ + if (can_coalesce) { + bool zc =3D skb_shinfo(skb)->flags & SKBFL_PURE_ZEROCOPY; + + if (!!dfrag->ubuf !=3D zc) + can_coalesce =3D false; + } if (!can_coalesce && i >=3D READ_ONCE(net_hotdata.sysctl_max_skb_frags))= { tcp_mark_push(tp, skb); goto alloc_skb; @@ -1455,7 +1473,7 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct= sock *ssk, } =20 copy =3D min_t(size_t, copy, info->limit - info->sent); - if (!sk_wmem_schedule(ssk, copy)) { + if (!dfrag->ubuf && !sk_wmem_schedule(ssk, copy)) { tcp_remove_empty_skb(ssk); return -ENOMEM; } @@ -1465,13 +1483,19 @@ static int mptcp_sendmsg_frag(struct sock *sk, stru= ct sock *ssk, } else { get_page(dfrag->page); skb_fill_page_desc(skb, i, dfrag->page, offset, copy); + + if (dfrag->ubuf && !skb_zcopy(skb)) { + skb_zcopy_set(skb, dfrag->ubuf, NULL); + skb_shinfo(skb)->flags |=3D SKBFL_PURE_ZEROCOPY; + } } =20 skb->len +=3D copy; skb->data_len +=3D copy; skb->truesize +=3D copy; sk_wmem_queued_add(ssk, copy); - sk_mem_charge(ssk, copy); + if (!skb_zcopy_pure(skb)) + sk_mem_charge(ssk, copy); WRITE_ONCE(tp->write_seq, tp->write_seq + copy); TCP_SKB_CB(skb)->end_seq +=3D copy; tcp_skb_pcount_set(skb, 0); @@ -1968,22 +1992,81 @@ static void mptcp_rps_record_subflows(const struct = mptcp_sock *msk) } } =20 +static int mptcp_sendmsg_zerocopy_iter(struct sock *sk, struct msghdr *msg, + struct ubuf_info *ubuf, u32 copy_limit, + ssize_t *copied, long *timeo) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct mptcp_data_frag *dfrag; + struct page *pages[1] =3D {}; + size_t pg_off =3D 0; + ssize_t pg_len; + + pg_len =3D iov_iter_get_pages2(&msg->msg_iter, pages, + copy_limit, 1, &pg_off); + if (pg_len < 0) + return pg_len; + /* pg_len =3D=3D 0 means the iterator is exhausted */ + if (pg_len =3D=3D 0) + return -EAGAIN; + + dfrag =3D kzalloc_obj(*dfrag, GFP_KERNEL_ACCOUNT); + if (!dfrag) { + put_page(pages[0]); + return -ENOMEM; + } + dfrag->data_len =3D pg_len; + dfrag->data_seq =3D msk->write_seq; + dfrag->offset =3D pg_off; + dfrag->page =3D pages[0]; + dfrag->ubuf =3D ubuf; + + /* one ref for the dfrag; released in dfrag_clear */ + net_zcopy_get(ubuf); + + *copied +=3D pg_len; + WRITE_ONCE(msk->write_seq, msk->write_seq + pg_len); + sk_wmem_queued_add(sk, pg_len); + + list_add_tail(&dfrag->list, &msk->rtx_queue); + if (!msk->first_pending) + msk->first_pending =3D dfrag; + + return 0; +} + static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) { struct mptcp_sock *msk =3D mptcp_sk(sk); + struct ubuf_info *ubuf =3D NULL; struct page_frag *pfrag; size_t copied =3D 0; + bool zc =3D false; int ret =3D 0; long timeo; =20 /* silently ignore everything else */ msg->msg_flags &=3D MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | - MSG_FASTOPEN | MSG_EOR; + MSG_FASTOPEN | MSG_EOR | MSG_ZEROCOPY; =20 lock_sock(sk); =20 mptcp_rps_record_subflows(msk); =20 + if (msg->msg_flags & MSG_FASTOPEN || + !sock_flag(__mptcp_check_fallback(msk) ? msk->first : sk, + SOCK_ZEROCOPY)) + msg->msg_flags &=3D ~MSG_ZEROCOPY; + + if ((msg->msg_flags & MSG_ZEROCOPY) && len) { + ubuf =3D msg_zerocopy_realloc(sk, len, NULL, false); + if (!ubuf) { + ret =3D -ENOBUFS; + goto do_error; + } + zc =3D true; + } + if (unlikely(inet_test_bit(DEFER_CONNECT, sk) || msg->msg_flags & MSG_FASTOPEN)) { int copied_syn =3D 0; @@ -2022,6 +2105,15 @@ static int mptcp_sendmsg(struct sock *sk, struct msg= hdr *msg, size_t len) if (!copy_limit) goto wait_for_memory; =20 + if (zc) { + ret =3D mptcp_sendmsg_zerocopy_iter(sk, msg, + ubuf, copy_limit, + &copied, &timeo); + if (ret) + goto do_error; + continue; + } + /* reuse tail pfrag, if possible, or carve a new one from the * page allocator */ @@ -2097,6 +2189,8 @@ static int mptcp_sendmsg(struct sock *sk, struct msgh= dr *msg, size_t len) } =20 out: + if (zc) + net_zcopy_put(ubuf); release_sock(sk); return copied; =20 @@ -2105,6 +2199,8 @@ static int mptcp_sendmsg(struct sock *sk, struct msgh= dr *msg, size_t len) goto out; =20 copied =3D sk_stream_error(sk, msg->msg_flags, ret); + if (zc) + net_zcopy_put_abort(ubuf, true); goto out; } =20 diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index da40c6f3705f..f4e69ea51a94 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -268,6 +268,7 @@ struct mptcp_data_frag { u8 eor; /* currently using 1 bit */ u16 already_sent; struct page *page; + struct ubuf_info *ubuf; }; =20 /* Arbitrary compromise between as low as possible to react timely to subf= low --=20 2.53.0 From nobody Sat Jul 25 07:27:10 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 DFB5B347FCD for ; Sun, 12 Jul 2026 02:15:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783822561; cv=none; b=PdjdkLKNhNgI9DHhTE0VpiutAoa2qkb4P3oktE/Yd1b5XsYctEFjQl2+nwHfgkmlWfG9LhrATXJZSx2EMXWaRU21EtyORHOnh6WjbbREwpyE6V1ihmYwseiT1UQWQQrZd14jWIyQB/J+v4KQB6wBJkLDhJ7kO5kuQRMhk+zTSlo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783822561; c=relaxed/simple; bh=kXKm6si4iXJLlyXEcj40GLiKTQcZdC35OqVbep9TFOA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cbJeD94eJfdrx+y4ZArtM6fLGiodRGvU6wwtmqIPADILofC/Yie2p2vIC9zWCUhjH41MTrRb1jURL7CUIpiLGxBojgIUA+VvONXJx7sJWRq8zhq4+o/ZRXfhMKAUv2IiWY2FBGTkVt7ZLhM7MMVSpEHUzpnCZB1kAOE2Qr57k6w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XSaUD+NB; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XSaUD+NB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E80261F00A3A; Sun, 12 Jul 2026 02:15:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783822559; bh=TH2i7nLzFOPv1VBrrH4KEavWgg+yYDYhiYKzgeKfSSk=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=XSaUD+NByGw/aTmgJtqL+LdcgDOQXT9fm749DOK5hjTzn7avxAas+aG297e11ctCf vFB0Ftmwlnn42SUCiDhh/pWU7meDeqIHJKT0M3VXyozbncWHU3WCEkjYzBDui3zgPk UvWDhhXk1nNZ3DImXzfdkJYrXBxHJG7wjHr+Ns8fSX1nYbbT51Pkz4XmSM/yy93jiL sUmU/dTKEVtEG1rz4COxxsUKqroYbUE1BNsWjBgwbrtOhGXerjnW4S7ry7xtXWzD0U gw+7c7NFfTW3yfmUGtNlKzyoGI2L8nF9H+lVqHqs5QRceh/lx6l7GfOmhzlcSjxLUo 95vs6dyjuqQ6A== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v2 3/5] mptcp: handle SO_ZEROCOPY in setsockopt Date: Sun, 12 Jul 2026 10:15:22 +0800 Message-ID: <42142dafc905e9a1efc1bca74a078daff71ac1e5.1783821830.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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: Geliang Tang SO_ZEROCOPY is currently rejected by MPTCP setsockopt with -EOPNOTSUPP, even though the matching MSG_ZEROCOPY path in mptcp_sendmsg() is wired up. As a result MSG_ZEROCOPY silently falls back to a copy on MPTCP sockets because the opt-in flag is never set. Expose SO_ZEROCOPY through the SOL_SOCKET setsockopt dispatcher. The new mptcp_setsockopt_sol_socket_zerocopy() helper flips the flag on whichever socket owns the data path: the msk in non-fallback mode, the subflow TCP socket in fallback mode. The check in mptcp_sendmsg() reads the flag from the same socket, so opt-in is honoured on either path. Signed-off-by: Geliang Tang --- net/mptcp/sockopt.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index fcf6feb2a9eb..c02373199616 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -175,6 +175,17 @@ static int mptcp_setsockopt_sol_socket_tstamp(struct m= ptcp_sock *msk, int optnam return 0; } =20 +static int mptcp_setsockopt_sol_socket_zerocopy(struct mptcp_sock *msk, in= t val) +{ + struct sock *sk =3D (struct sock *)msk, *ssk; + + lock_sock(sk); + ssk =3D __mptcp_tcp_fallback(msk); + sock_valbool_flag(ssk ?: sk, SOCK_ZEROCOPY, !!val); + release_sock(sk); + return 0; +} + static int mptcp_setsockopt_sol_socket_int(struct mptcp_sock *msk, int opt= name, sockptr_t optval, unsigned int optlen) @@ -203,6 +214,8 @@ static int mptcp_setsockopt_sol_socket_int(struct mptcp= _sock *msk, int optname, case SO_TIMESTAMPNS_OLD: case SO_TIMESTAMPNS_NEW: return mptcp_setsockopt_sol_socket_tstamp(msk, optname, val); + case SO_ZEROCOPY: + return mptcp_setsockopt_sol_socket_zerocopy(msk, val); } =20 return -ENOPROTOOPT; @@ -342,6 +355,7 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_soc= k *msk, int optname, case SO_TIMESTAMP_NEW: case SO_TIMESTAMPNS_OLD: case SO_TIMESTAMPNS_NEW: + case SO_ZEROCOPY: return mptcp_setsockopt_sol_socket_int(msk, optname, optval, optlen); case SO_TIMESTAMPING_OLD: @@ -387,7 +401,6 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_soc= k *msk, int optname, * SO_CNX_ADVICE is currently unsupported, could possibly be relevant, * but likely needs careful design * - * SO_ZEROCOPY is currently unsupported, TODO in sndmsg * SO_TXTIME is currently unsupported */ =20 --=20 2.53.0 From nobody Sat Jul 25 07:27:10 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 C535E2C1594 for ; Sun, 12 Jul 2026 02:16:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783822562; cv=none; b=KOBfFEIALY5NvD6Y4ySJQB8GrBvFEvlpH8n32bkcfeVBS4VfGTFWJ1xztXVAVp1OU39KXl4N3nDrEBlY5UQ694qvVdlKrynLbsPuQd8f2WbzqNDIER86TfCzdLkrSZJyytqkltE6YlAzN6A2adJCijKvz0w83iS2G8Oai8fhmJ8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783822562; c=relaxed/simple; bh=owLH+gb7OvY00mvj5JQkSym7AEf/tCeiQchTf6ZWAy0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Dn421zZy/MhM3RIaLB40rjD7CGWlIHhVkKJPDjxuqLT/todEWGf2nEXNMOzLpiDTYkB701awQW+BeteBU6eykPjajhs3SdQUAH4opXT2ZY0JraRDFF8hlxQFbm96C19SugVtDctlznEmXQrEDcsDMQWvpOdfdCaWIwJV/dxhorw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=B4d+o8h2; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="B4d+o8h2" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0C9891F00A3D; Sun, 12 Jul 2026 02:15:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783822560; bh=axjLnQ+S8CQ93he7gZ11b1dSyULFKMxC9Czno+GfL4k=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=B4d+o8h2jqul/vD77rfJEN36nc5vSpvMom4WBP4nmHS3wg9zQLRtUI53oZPXalpFQ nRDmPgQTtuzoQ3OszirGdcTbaRRuSd9apapV8s/4uO+JkYEo+wLV6OcuL88BRB2OJc nbTznySZNwozRhGLUYVQc/T4k6Aq5SX3TqN1+12Uxr7iXE8GVhNw7pjU78LTu1rVTq RJ0h48r0TVxNs7xmnwUM3h117w795Ph2F6gxEH4vXvi13CJ/PYhjYD7XcfollA47a3 GQU8Qcwabq41jELhZgNP28tPD8b/A4LdnMj6LAG+ogFA2bA2ih8ZlMCiCCofRUgaqx XU/fb1jWWiIeA== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v2 4/5] selftests: mptcp: connect: add zerocopy io mode Date: Sun, 12 Jul 2026 10:15:23 +0800 Message-ID: <77cfd82ece03d7ad82cc9b2c824cf8cf878df7db.1783821830.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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: Geliang Tang Add a new I/O mode 'zerocopy' to the mptcp_connect selftest, which uses sendmsg() with the MSG_ZEROCOPY flag to transmit data. This enables testing and performance validation of the zero-copy send path for both TCP and MPTCP connections. This mode is useful for benchmarking and for verifying correctness of MSG_ZEROCOPY handling in the MPTCP stack. Signed-off-by: Geliang Tang --- .../selftests/net/mptcp/mptcp_connect.c | 96 ++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/test= ing/selftests/net/mptcp/mptcp_connect.c index ea4cb6c1bd5e..770b94e3a2ca 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.c +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c @@ -33,6 +33,7 @@ #include #include #include +#include #include =20 extern int optind; @@ -53,6 +54,7 @@ enum cfg_mode { CFG_MODE_MMAP, CFG_MODE_SENDFILE, CFG_MODE_SPLICE, + CFG_MODE_ZEROCOPY, }; =20 enum cfg_peek { @@ -125,7 +127,7 @@ static void die_usage(void) fprintf(stderr, "\t-j -- add additional sleep at connection start and= tear down " "-- for MPJ tests\n"); fprintf(stderr, "\t-l -- listens mode, accepts incoming connection\n"= ); - fprintf(stderr, "\t-m [poll|mmap|sendfile|splice] -- use poll(default)/mm= ap+write/sendfile/splice\n"); + fprintf(stderr, "\t-m [poll|mmap|sendfile|splice|zerocopy] -- use poll(de= fault)/mmap+write/sendfile/splice/zerocopy\n"); fprintf(stderr, "\t-M mark -- set socket packet mark\n"); fprintf(stderr, "\t-o option -- test sockopt