From nobody Sat Sep 26 12:28:31 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 7F1403CB2E5 for ; Sun, 13 Sep 2026 10:15:11 +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=1789294512; cv=none; b=juT/zN6see0LjZqnWiVbTAAEySE8M1xp4NVtbpf7GbxttLBwHioXSo5CRESl9CEca6YF+t6KOKbGww62G4alGytqq4nxhEkEvE09Xxk8emHoVt5rw9qQpwKmHYYJoQhQRdvIhAXWTF+RYoOSDisW4D60VHhNxQ7uQz4tFTbcAXI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294512; c=relaxed/simple; bh=RxoTMHi2eYGxpCaMXdPOdcSjL1ljG8sBzQz+V8SQ4tc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kqVjb5grtFmGiGeU0nPpS9YmxTocx2cH92VCNHH3jbaDThYWIoe6nqezk7mlrkEFeeoA77anmjjay6m87yxDuDi383Sls6kmezP885UBWQyJDpfHN2pSzjSUSiPqPYWYSKbVaPEawIeCLD100LiJNmw6b87THTmn3xosDEh0cww= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kk5VlZCd; 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="kk5VlZCd" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3AD921F000FF; Sun, 13 Sep 2026 10:15:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294511; bh=P58NL2/mI6DUTBx90Lj/Px+Pfvek7navtJiOzC2xuDo=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=kk5VlZCdrwfYt641BB2b/C4x/EKTYeeH0vV+w6wNBFdNYNkEDxXLJ3BvOBsNrPy1i UsfES2xPV2XUtNsvi1TVVceyLTQO4j8eLT2m32rvB93jKagiPK0WEM040NCHQ76hK+ oDLydI0jrrZX0ErK8MnKcmb8K0eG0b988stN+KYOO+Gj4qunnO5OUCA+DIkv/CvDEl Jq9OJXTRPHAj5gDqcQg8DGLD4kt7SeU5t7KqhmVKZqJz0DFlMzJ6YzqhMcCga4hiFN 445AZzVLPg602jQkF9d0T2MtGBfa6Qy90Bacuhx/l5Z8VLjU/yqnsSqy+BRZsFicTg t9uhH8mUq2Naw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v5 01/16] mptcp: defer read_sock cleanup to mptcp_worker Date: Sun, 13 Sep 2026 18:14:40 +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: Paolo Abeni When MPTCP carries TLS, the data path runs under mptcp_data_lock(). Reaching sk->sk_data_ready(sk) synchronously ends up at tls_strp_check_rcv() -> mptcp_recv_skb() -> mptcp_move_skbs(), which calls mptcp_data_lock() on the same sk and recurses on sk_lock.slock. The TLS path is not the only constraint: before the mptcp_recv_skb() calls, the TLS code would also reach __mptcp_read_sock(), which calls mptcp_rcv_space_adjust() and mptcp_cleanup_rbuf(). Both require holding the msk socket lock in process context, while the mptcp/TLS caller is in BH scope. Fix this by deferring sk->sk_data_ready(sk) to mptcp_worker() via a new MPTCP_WORK_READ_COMPLETE bit, reusing the existing mptcp_schedule_work()/ mptcp_cancel_work() infrastructure. The wakeup bit is consumed after the SOCK_DEAD && TCP_CLOSE destroy branch, so a socket that reaches the destroy path drops the pending wakeup rather than running it post-free. Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Paolo Abeni --- net/mptcp/protocol.c | 33 ++++++++++++++++++++++++--------- net/mptcp/protocol.h | 2 ++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 0b24e0afedfb..be1b8e626653 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3118,6 +3118,20 @@ static void mptcp_backlog_purge(struct sock *sk) sk_mem_reclaim(sk); } =20 +static void mptcp_read_complete(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + int read_copied; + + mptcp_data_lock(sk); + read_copied =3D msk->read_copied; + msk->read_copied =3D 0; + mptcp_data_unlock(sk); + + mptcp_rcv_space_adjust(msk, read_copied); + mptcp_cleanup_rbuf(msk, read_copied); +} + static void mptcp_do_fastclose(struct sock *sk) { struct mptcp_subflow_context *subflow, *tmp; @@ -3193,6 +3207,9 @@ static void mptcp_worker(struct work_struct *work) if (test_and_clear_bit(MPTCP_WORK_RTX, &msk->flags)) __mptcp_retrans(sk); =20 + if (test_and_clear_bit(MPTCP_WORK_READ_COMPLETE, &msk->flags)) + mptcp_read_complete(sk); + fail_tout =3D msk->first ? READ_ONCE(mptcp_subflow_ctx(msk->first)->fail_= tout) : 0; if (fail_tout && time_after(jiffies, fail_tout)) mptcp_mp_fail_no_response(msk); @@ -4565,13 +4582,9 @@ static __poll_t mptcp_poll(struct file *file, struct= socket *sock, =20 static struct sk_buff *mptcp_recv_skb(struct sock *sk, u32 *off) { - struct mptcp_sock *msk =3D mptcp_sk(sk); struct sk_buff *skb; u32 offset; =20 - if (!list_empty(&msk->backlog_list)) - mptcp_move_skbs(sk); - while ((skb =3D skb_peek(&sk->sk_receive_queue)) !=3D NULL) { offset =3D MPTCP_SKB_CB(skb)->offset; if (offset < skb->len) { @@ -4586,6 +4599,7 @@ static struct sk_buff *mptcp_recv_skb(struct sock *sk= , u32 *off) /* * Note: * - It is assumed that the socket was locked by the caller. + * - Can be invoked in BH scope. */ static int __mptcp_read_sock(struct sock *sk, read_descriptor_t *desc, sk_read_actor_t recv_actor, bool noack) @@ -4595,8 +4609,6 @@ static int __mptcp_read_sock(struct sock *sk, read_de= scriptor_t *desc, int copied =3D 0; u32 offset; =20 - msk_owned_by_me(msk); - if (sk->sk_state =3D=3D TCP_LISTEN) return -ENOTCONN; while ((skb =3D mptcp_recv_skb(sk, &offset)) !=3D NULL) { @@ -4629,11 +4641,14 @@ static int __mptcp_read_sock(struct sock *sk, read_= descriptor_t *desc, if (noack) goto out; =20 - mptcp_rcv_space_adjust(msk, copied); - + /* The backlog flushing is only needed when some data is actually + * moved and will take place in the workers's release callback. + */ if (copied > 0) { mptcp_recv_skb(sk, &offset); - mptcp_cleanup_rbuf(msk, copied); + msk->read_copied +=3D copied; + set_bit(MPTCP_WORK_READ_COMPLETE, &msk->flags); + mptcp_schedule_work(sk); } out: return copied; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 4453db7a33cf..3f8997f15bec 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -117,6 +117,7 @@ #define MPTCP_FALLBACK_DONE 2 #define MPTCP_WORK_CLOSE_SUBFLOW 3 #define MPTCP_RTX_ENABLED 4 +#define MPTCP_WORK_READ_COMPLETE 5 =20 /* MPTCP socket release cb flags */ #define MPTCP_PUSH_PENDING 1 @@ -323,6 +324,7 @@ struct mptcp_sock { u32 last_data_sent; u32 last_data_recv; u32 last_ack_recv; + int read_copied; unsigned long timer_ival; u32 token; unsigned long flags; --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 41276232395 for ; Sun, 13 Sep 2026 10:15:12 +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=1789294514; cv=none; b=CSTBhjPxLlmR2jt/FfZVrKIOJtIujT67vZYuoB4J9WSimDQrZ0N3uqd2se0sRYKL6fhv/rz0jnp298s2POExA3TSu+LUclkOfcCte6tYOVvZEz88o7siIRSio4/8tU3bRh8N8bZc19ehj+2HwppGR28POCNzBAA9Y+1J32J8z3E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294514; c=relaxed/simple; bh=Dkb/v1LvMxv1WKvcJCIrtOMuaUNg2ImBYOoxOiFjPTc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=S/GDYla0vakXzU/aMNVFLY5PyJj4qwtAgOOQsPfyck8iiyMEhLSbMPdrmm5UaL0kO+c0lqhw15qxUh4SBLyIH06gEv5bd582UuBVwPIXIAQB/SY76lZbwcR4gxySOIp4eA0JFey3RmyIJjiNerpIJA01IZxOA/ojNFZzVE6U3CY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YPfjAHDZ; 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="YPfjAHDZ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BDC171F00893; Sun, 13 Sep 2026 10:15:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294512; bh=6mdnjTyTsgauAefpBWZeGGkDrXT8VXuHP77m76pO31Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=YPfjAHDZDOs6jb1lFbmgescR4nG8a1bjEQIXH68Dl9NiIC/Ah2gO4OhQOljnF1FXR Hh46tSbirisgp6tOM9QI+RmTHKDUwC68zNs93dBPHWP1qgJKiP3+Rl3c85GlE+t1KH qeyOM2IjIgm8qoJSUSWwKTfgeR/RQxDgC8jArAiry9ihGL1juqAzdp/aq9y8j0d+nm 4VB4FDI82uOGkAIWbhr/o/gSonnDVeR3VKUVRzjEv7o3YVb8f0MtVxrt6WD0VjWSQn kasZkO6qZzPNtO6bKe670vcIi0+0AwqDM5zlEwFdKEa3LZ+zka8T/lT/PdE4pX5z8m wiTE7tCJnEhpw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 02/16] mptcp: add sendmsg_locked to proto_ops Date: Sun, 13 Sep 2026 18:14:41 +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 MPTCP currently provides a standard sendmsg() implementation which acquires and releases the socket lock internally. However, certain upper layers need to call the sendmsg method while the socket lock is already held. Split the existing mptcp_sendmsg() into mptcp_sendmsg_locked() which assumes the caller holds the socket lock, and a tiny wrapper mptcp_sendmsg() that acquires the lock and calls the locked version. Expose .sendmsg_locked in both mptcp_stream_ops and mptcp_v6_stream_ops. Signed-off-by: Geliang Tang --- net/mptcp/protocol.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index be1b8e626653..29e2cd2be815 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2030,7 +2030,7 @@ static void mptcp_rps_record_subflows(const struct mp= tcp_sock *msk) } } =20 -static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) +static int mptcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_= t len) { struct mptcp_sock *msk =3D mptcp_sk(sk); struct page_frag *pfrag; @@ -2042,8 +2042,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msgh= dr *msg, size_t len) msg->msg_flags &=3D MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_FASTOPEN | MSG_EOR; =20 - lock_sock(sk); - mptcp_rps_record_subflows(msk); =20 if (unlikely(inet_test_bit(DEFER_CONNECT, sk) || @@ -2159,7 +2157,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msgh= dr *msg, size_t len) } =20 out: - release_sock(sk); return copied; =20 do_error: @@ -2170,6 +2167,17 @@ static int mptcp_sendmsg(struct sock *sk, struct msg= hdr *msg, size_t len) goto out; } =20 +static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) +{ + int ret; + + lock_sock(sk); + ret =3D mptcp_sendmsg_locked(sk, msg, len); + release_sock(sk); + + return ret; +} + static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied); =20 static void mptcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb) @@ -4795,6 +4803,7 @@ static const struct proto_ops mptcp_stream_ops =3D { .set_rcvlowat =3D mptcp_set_rcvlowat, .read_sock =3D mptcp_read_sock, .splice_read =3D mptcp_splice_read, + .sendmsg_locked =3D mptcp_sendmsg_locked, }; =20 static struct inet_protosw mptcp_protosw =3D { @@ -4907,6 +4916,7 @@ static const struct proto_ops mptcp_v6_stream_ops =3D= { .set_rcvlowat =3D mptcp_set_rcvlowat, .read_sock =3D mptcp_read_sock, .splice_read =3D mptcp_splice_read, + .sendmsg_locked =3D mptcp_sendmsg_locked, }; =20 static struct proto mptcp_v6_prot; --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 F18883A3815 for ; Sun, 13 Sep 2026 10:15:13 +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=1789294515; cv=none; b=DgadRaIuJ/UmQ1T58x0gCuyOQMq3iJ6TDOVfqz2qFfDaa70eRuXI/F0Mo/KkLBKV2xVmGL/nQdvVAqV7HAbDJjmngb9fGBbVp59Mbtuv17vcS1OCcZDi0Ap9DSPphM38mCgaPGfYcG5GyhcSy3M99qOvFEIfSMDS3c4FL0RyJFM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294515; c=relaxed/simple; bh=2Pn5MzR3BgSJzo498vpaCSrowmL617tWaKGHE1wjacY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rLL7UiypOGqHsm7oag8xdvd8bEFFHgJvm5MbSGNACaJPw5KSrkdTfFOZ0hKsPitmEDGPXaZd2xcx5WpEPuBg+pQLjUfGaf4edlDbihINymngR75qIRtqQ5hIpBUiC1DNIcuidubm6/MXtqt0JnpFbZIvU8+Tou5T87Vcrbk8GmI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ouWVQcPJ; 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="ouWVQcPJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1A64E1F000FF; Sun, 13 Sep 2026 10:15:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294513; bh=wCyGUwuv7mB+3E3tApz1cajoAZyg715r4he6ihLz7ow=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=ouWVQcPJ6CC/scNsaCQTkpcmSQulqIe8sYrAUM3MO0VPQqUrQ1ssnkaJ7mybS8fHD Fg6Tr+T8L5Hr9lKSEJqtd7pXFcHWkgyrpQPaKZyYuzDGEM+2v+61+585tgYgTQHCVv woRXllF2Cfq/MoITXn0MiKYX8D1pEFFRMibQ+mT30MIt6Fz9X6DJrcPFfQ1jDpBYtP 3sXBkGRDpN34PNJV85eRL/yHGnzExdnZg3WWIWdD1pojTAzc2NkMEetV+7rDOq2dbF jfSya0yGDXxJAAYLsPF+9sBnF+BcCTS1MNCIh5skJnloLK8pJ22ZA0ToxXsvVhCzos uItNuS/fcMEXA== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 03/16] mptcp: track app-limited state in mptcp_sendmsg Date: Sun, 13 Sep 2026 18:14:42 +0800 Message-ID: <4b585d4bedcd753fee14485a25772eeffb1a2b96.1789294365.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 The application-limited accounting in TCP is updated by tcp_rate_check_app_limited(), which currently takes a struct sock * and internally calls tcp_sk(). MPTCP needs to apply the same accounting to each subflow individually - every subflow is an independent TCP socket with its own tp->app_limited / delivered state - so wrapping the call as a struct sock * -> tcp_sk() helper is awkward at the call site. Split the existing function: keep the logic as tcp_sock_rate_check_app_limited(struct tcp_sock *tp), and turn tcp_rate_check_app_limited(struct sock *) into a thin wrapper so the exported API is unchanged for other TCP users. Then add mptcp_sock_rate_check_app_limited() that walks every subflow of the mptcp_sock and runs tcp_sock_rate_check_app_limited() under each subflow's socket lock. Invoke it from mptcp_sendmsg() right after the send-side setup, so the delivery-rate app_limited state stays in sync with what the application actually has to send across each subflow. With this in place, TCP_INFO.tcpi_delivery_rate_app_limited is reported correctly for MPTCP connections instead of being left at 0. Signed-off-by: Geliang Tang --- include/net/tcp.h | 1 + net/ipv4/tcp.c | 9 +++++++-- net/mptcp/protocol.c | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 5e5f5f9b89a3..14baee01c74b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -851,6 +851,7 @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock= *tp, int pktsize) =20 /* tcp.c */ void tcp_get_info(struct sock *, struct tcp_info *); +void tcp_sock_rate_check_app_limited(struct tcp_sock *tp); void tcp_rate_check_app_limited(struct sock *sk); =20 /* Read 'sendfile()'-style from a TCP socket */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 1dd80a75f223..cd4347bfa029 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1096,9 +1096,9 @@ int tcp_sendmsg_fastopen(struct sock *sk, struct msgh= dr *msg, int *copied, } =20 /* If a gap is detected between sends, mark the socket application-limited= . */ -void tcp_rate_check_app_limited(struct sock *sk) +void tcp_sock_rate_check_app_limited(struct tcp_sock *tp) { - struct tcp_sock *tp =3D tcp_sk(sk); + struct sock *sk =3D (struct sock *)tp; =20 if (/* We have less than one packet to send. */ tp->write_seq - tp->snd_nxt < tp->mss_cache && @@ -1111,6 +1111,11 @@ void tcp_rate_check_app_limited(struct sock *sk) tp->app_limited =3D (tp->delivered + tcp_packets_in_flight(tp)) ? : 1; } + +void tcp_rate_check_app_limited(struct sock *sk) +{ + tcp_sock_rate_check_app_limited(tcp_sk(sk)); +} EXPORT_SYMBOL_GPL(tcp_rate_check_app_limited); =20 int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 29e2cd2be815..1a19e494c609 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2030,6 +2030,21 @@ static void mptcp_rps_record_subflows(const struct m= ptcp_sock *msk) } } =20 +static void mptcp_rate_check_app_limited(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct mptcp_subflow_context *subflow; + + mptcp_for_each_subflow(msk, subflow) { + struct sock *ssk =3D mptcp_subflow_tcp_sock(subflow); + bool slow; + + slow =3D lock_sock_fast_nested(ssk); + tcp_sock_rate_check_app_limited(tcp_sk(ssk)); + unlock_sock_fast(ssk, slow); + } +} + static int mptcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_= t len) { struct mptcp_sock *msk =3D mptcp_sk(sk); @@ -2058,6 +2073,9 @@ static int mptcp_sendmsg_locked(struct sock *sk, stru= ct msghdr *msg, size_t len) =20 timeo =3D sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); =20 + /* is sending application-limited? */ + mptcp_rate_check_app_limited(sk); + if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) { ret =3D sk_stream_wait_connect(sk, &timeo); if (ret) --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 65B2E39F168 for ; Sun, 13 Sep 2026 10:15:15 +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=1789294516; cv=none; b=qS+RCQaTx8LztWHjJTwwvowBDw+KmCRrCZnJ0h94tPz3fU0f/vUcuj5iDSPfwjzYDPbO7ckrGI0d9/T/GzZvXPlVDMhcEgXP/NijKe5PLd3OJ0fHPkfrR/C4093OlpPgr9btr1ujXKIz93Fo9WE0JGfZ0cAlpBQNqnhu9Gg7UdQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294516; c=relaxed/simple; bh=JxT3qeiSHuBS12KtGnTPLFRzVxKd0fvCXwqrRkI3nnM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gQt2m2/6PdfBai+JgGVphntv16Xsyw64t0lLvIs7K4ILFpxBMu4KawjeMx7lA8pHMpBDCNI6nGJBbV1fS8kYYKZOr4fEjthA+rYrsGmFPtq7pImTvmWvZyVXn7TJ6lIFNaxJJ3A7bELkgenAkXSvY8o6RZbXAefOzpfixBfvSyc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nXo1iZSw; 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="nXo1iZSw" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6B4391F00898; Sun, 13 Sep 2026 10:15:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294515; bh=xNNDwMcimuhvgxiiYj/oGzahS6NB1VtBfCB7+LyvfjA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=nXo1iZSw1ankJJ4Zdk6shXxP2fsfThzNkCmUYJU/a8RsEPawE/evSiARxFURcBQ2h mks/3S1O32Yq3Duh620wocUmBo2OxJb/bM7ywjfacJ9fzItX0BgZwBf9J4Oj9G3Zb6 GSpJ8De3je6zP7Ana5yVSQVdHCB5mPXsd+vI2YK9FNXX0wuUUwpR4HJuohyYBolgAV /ZZgnKmQyf/XnsLBV0h4lnFTw7TK/Gp950JTAA6o+QPwRtodWPlneJjt+a4dIm77ck 30faRsAQKUT17fQpmrJk8kkmWpq0R5EW4cB3aIFecAfWLhzxLwG8rbfNhP3iPaDXuw F+VvgYgwH5MlA== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 04/16] selftests: mptcp: sockopt: check app_limited Date: Sun, 13 Sep 2026 18:14:43 +0800 Message-ID: <413428cff69bac9db9fb42c04897810f3c4fba10.1789294365.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 connect_one_server() in mptcp_sockopt exchanges only a few packets between the client and server, then closes the socket. After such a small transfer the application has nothing further to send, so the connection is, by definition, application-limited. Extend the TCP_INFO readback at the end of the function to assert s.tcp_info.tcpi_delivery_rate_app_limited =3D=3D 1. Without the preceding commit, mptcp_sendmsg() never updates the per-subflow app-limited state, and this field stays at 0 - the assertion would fail. With it in place, the value is forced to 1, turning this into a regression guard for the subflow-side application-limited accounting. Signed-off-by: Geliang Tang --- tools/testing/selftests/net/mptcp/mptcp_sockopt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/test= ing/selftests/net/mptcp/mptcp_sockopt.c index d68515b7903b..8d712bdb4325 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c @@ -640,6 +640,7 @@ static void connect_one_server(int fd, int pipefd) total +=3D 1; /* sequence advances due to FIN */ =20 assert(s.mptcpi_rcv_delta =3D=3D (uint64_t)total); + assert(s.tcp_info.tcpi_delivery_rate_app_limited =3D=3D 1); close(fd); } =20 --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 D533828B517 for ; Sun, 13 Sep 2026 10:15:16 +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=1789294517; cv=none; b=bdalhfVQuAyB4aPnDrsqnFVDCGgMQsDMerF7v39nNuTIo6aY7GlpTQ0R96p8hAHA2Kj2NZE7dE2vvIDRSVDNf8ZIbxV/dduFDFUQdOs+TdVNL48jatES3zqAWiBCqewWpiEwXaIhikXDAIiprlXd/SpE915xHlt1jaGh8TFw+AQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294517; c=relaxed/simple; bh=evwOVVzP3bV9lky+yEW4hj8wM2hLsbXXNUEDVM1QNJc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=C2+gK9Zjrhr2bL1CwF74Y09LvlVmgLvnuYIaLwJ1FPtCERZPc8XL39DdltVdsWjdUpedpQ7Yi53F7+rV7qjk/rh1+EJckJWD6fA16gQ10qgxgMgyb5tq/KQ8jZUHBJeqbvnTrQaj5Z8zYRU/JPHFDOkHXzYl+gKPRQ90b/+iv9Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QTz9znSt; 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="QTz9znSt" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BBEAC1F000FF; Sun, 13 Sep 2026 10:15:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294516; bh=yublTTmzSqfIpACCeNgVITq9sLg/Hk2l5mmY37cJKD4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=QTz9znStvrdN+h2Ys0Ixz807d46s4lC7b9Q2q3Qq6SWLk+VXlFta0JpOlk2H5X16K dwu50rxTh1Y22PBVr+VlsvLWfoNu9FBSWzaUBlNy0ybmlMVGf5saAZdOQz6kXGRrIi BOQCTzpKZE+nhQLQj1dXtsH0Detkna1fHRkE1wABJ1VRJQsAGJ9ouHgzpuGGwqTZdm 1BYEF8rM1kjQrHMSoCK50a8xfrcmVxOQCjTpIord1o+vwBZCx6Di5DwrZLDvnlrpaF af+dVlbCecHY6r+cIL7dZrGBbwhp95xbVAdFJnr9Ck6hYxbtsjnYq7tnE4Zjp6CjJz 2d+5u+YbXrh2A== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 05/16] bpf: drop duplicate check_app_limited in tcp_bpf_push Date: Sun, 13 Sep 2026 18:14:44 +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 When the sendpage->MSG_SPLICE_PAGES migration series replaced do_tcp_sendpages() with direct tcp_sendmsg_locked() calls, callers that had used do_tcp_sendpages() kept an explicit tcp_rate_check_app_limited(sk) that was originally needed to cover do_tcp_sendpages() (which did not call tcp_rate_check_app_limited() itself). After the inlining, tcp_sendmsg_locked() always provides the check, and the outer call became redundant. The site changed here, tcp_bpf_push(), is a MSG_SPLICE_PAGES loop that holds the socket lock and only iterates when size > 0; tcp_sendmsg_locked() is invoked on every iteration with state identical to what the outer call sees, so dropping the outer call is safe and behavior-preserving. Signed-off-by: Geliang Tang --- net/ipv4/tcp_bpf.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index 2e234d155b5e..d5fcf3ce4861 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -108,7 +108,6 @@ static int tcp_bpf_push(struct sock *sk, struct sk_msg = *msg, u32 apply_bytes, off =3D sge->offset; page =3D sg_page(sge); =20 - tcp_rate_check_app_limited(sk); retry: msghdr.msg_flags =3D flags | MSG_SPLICE_PAGES; has_tx_ulp =3D tls_sw_has_ctx_tx(sk); --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 8D36F28B517 for ; Sun, 13 Sep 2026 10:15:18 +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=1789294520; cv=none; b=u96iOMdM2zrSXjcciLMRaEML7UAc35d00Jb/mPmDtOfrjhne7s/4wE0QoU2cEqrpX90rCMgoyy53kfq3Mct4d/stx7sp5hOtIdLD3hEaMvqxLza8ucm7CnS0KAy2wtE4wIZ0h/1/f2Hz2b5/nfJ37uY5pjRtr22gJ16zCHp0Azg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294520; c=relaxed/simple; bh=oobUPJEudZmhj9feGhiTdzTJ0VlF2/E9WCWmqUpRlgQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cRgZkmnaY51zw1Rwuy94HYXUudU0bfOIwq3JmURchbeQF4bx9o+S7ea9nCCMPkfwR6rvzFtB9n2CXE7X6PD29l+P/u9+miAFNE+NtFZmDT5W2BaEOnlc9M14J24XAWsx2Yvg21xrWdiLPYThBumdORbuuTYLeZLn1tdsiPGv0Q8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MJpyPBVc; 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="MJpyPBVc" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 191521F00893; Sun, 13 Sep 2026 10:15:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294518; bh=Y/105J6kQOvqY/Q2Tgh/CaBz9o7hdSirjUI8VbCzzts=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=MJpyPBVcuTOslGk8GmQknOPQYncv940qRCUFe9Uo4zQAdOAfgtMGxhiA5TVrLRzmV Zjh81QcsLzAiOxJldRw2YPmSUhvvEkK17kOYTBHiMDAvSPwIMoqVBvDRPWYjuZZ3YU ih11hrFPVpWBAYycInI+LP/4h7WpL2Tja6ITj8EKIKUvm7tF5RUKMYNGT5dEYTvXQz c0OH4LUe/0w1h3qARh4eGrDM3zehdTPBAzEfHot171lSLIcGAlZXUQdNVOanZ+m/jp BXe5Ue+RB0MgxzqXiM4HqbqpquWCBc2K5k73BwokUQ+0NBoBLhIWwJOlKrDuI/5J65 BYuJa4UhMZUaQ== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang , kernel test robot , Cong Wang Subject: [PATCH mptcp-next v5 06/16] mptcp: implement psock_update_sk_prot for sockmap Date: Sun, 13 Sep 2026 18:14:45 +0800 Message-ID: <39ae7a2bebed6f38d02356c7e288a21a70bdd07f.1789294365.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 This patch adds basic MPTCP support for BPF sockmap by implementing the psock_update_sk_prot callback (mptcp_bpf_update_proto). This allows MPTCP sockets to be added to sockmap and enables the sk_skb stream_verdict redirect path via the read_skb callback. Separate protocol structures are maintained for IPv4/IPv6 and BASE/TX/RX/TXRX configurations, mirroring tcp_bpf_update_proto(). The IPv6 variant is lazily rebuilt via mptcp_bpf_check_v6_needs_rebuild() when the underlying protocol ops change. MPTCP delegates to the original protocol operations so that MPTCP-specific logic (multi-path scheduling in sendmsg, ordered reassembly in recvmsg) is preserved. recvmsg is overridden in all BPF configurations with mptcp_bpf_recvmsg, which checks the psock ingress queue first and falls back to mptcp_recvmsg via the shared __tcp_bpf_recvmsg() helper. sendmsg is overridden in the TX/TXRX configurations with mptcp_bpf_sendmsg, which processes sk_msg redirect before delegating to mptcp_sendmsg via __tcp_bpf_sendmsg(). Export mptcp_sendmsg, mptcp_recvmsg and mptcp_prot from protocol.c so they can be referenced by bpf.c. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202512261144.DxrvwMS3-lkp@int= el.com/ Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/521 Cc: Cong Wang Signed-off-by: Geliang Tang --- include/net/tcp.h | 5 ++ net/ipv4/tcp_bpf.c | 29 +++++++--- net/mptcp/bpf.c | 129 +++++++++++++++++++++++++++++++++++++++++++ net/mptcp/protocol.c | 10 ++-- net/mptcp/protocol.h | 18 ++++++ 5 files changed, 179 insertions(+), 12 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 14baee01c74b..d9c0214328e3 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -2873,6 +2873,11 @@ static inline void tcp_eat_skb(struct sock *sk, stru= ct sk_buff *skb) =20 int tcp_bpf_sendmsg_redir(struct sock *sk, bool ingress, struct sk_msg *msg, u32 bytes, int flags); +int +__tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int fla= gs, + int (*recvmsg)(struct sock *, struct msghdr *, size_t, int)); +int __tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t size, + int (*sendmsg)(struct sock *, struct msghdr *, size_t)); #endif /* CONFIG_NET_SOCK_MSG */ =20 #if !defined(CONFIG_BPF_SYSCALL) || !defined(CONFIG_NET_SOCK_MSG) diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index d5fcf3ce4861..e006131696e9 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -119,7 +119,7 @@ static int tcp_bpf_push(struct sock *sk, struct sk_msg = *msg, u32 apply_bytes, =20 bvec_set_page(&bvec, page, size, off); iov_iter_bvec(&msghdr.msg_iter, ITER_SOURCE, &bvec, 1, size); - ret =3D tcp_sendmsg_locked(sk, &msghdr, size); + ret =3D sk->sk_socket->ops->sendmsg_locked(sk, &msghdr, size); if (ret <=3D 0) return ret; =20 @@ -364,8 +364,9 @@ static int tcp_bpf_ioctl(struct sock *sk, int cmd, int = *karg) return 0; } =20 -static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, - int flags) +int +__tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int fla= gs, + int (*recvmsg)(struct sock *, struct msghdr *, size_t, int)) { struct sk_psock *psock; int copied, ret; @@ -378,11 +379,11 @@ static int tcp_bpf_recvmsg(struct sock *sk, struct ms= ghdr *msg, size_t len, =20 psock =3D sk_psock_get(sk); if (unlikely(!psock)) - return tcp_recvmsg(sk, msg, len, flags); + return recvmsg(sk, msg, len, flags); if (!skb_queue_empty(&sk->sk_receive_queue) && sk_psock_queue_empty(psock)) { sk_psock_put(sk, psock); - return tcp_recvmsg(sk, msg, len, flags); + return recvmsg(sk, msg, len, flags); } lock_sock(sk); msg_bytes_ready: @@ -402,7 +403,7 @@ static int tcp_bpf_recvmsg(struct sock *sk, struct msgh= dr *msg, size_t len, goto msg_bytes_ready; release_sock(sk); sk_psock_put(sk, psock); - return tcp_recvmsg(sk, msg, len, flags); + return recvmsg(sk, msg, len, flags); } copied =3D -EAGAIN; } @@ -414,6 +415,12 @@ static int tcp_bpf_recvmsg(struct sock *sk, struct msg= hdr *msg, size_t len, return ret; } =20 +static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, + int flags) +{ + return __tcp_bpf_recvmsg(sk, msg, len, flags, tcp_recvmsg); +} + static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock, struct sk_msg *msg, int *copied, int flags) { @@ -530,7 +537,8 @@ static int tcp_bpf_send_verdict(struct sock *sk, struct= sk_psock *psock, return ret; } =20 -static int tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t siz= e) +int __tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t size, + int (*sendmsg)(struct sock *, struct msghdr *, size_t)) { struct sk_msg tmp, *msg_tx =3D NULL; int copied =3D 0, err =3D 0, ret =3D 0; @@ -544,7 +552,7 @@ static int tcp_bpf_sendmsg(struct sock *sk, struct msgh= dr *msg, size_t size) =20 psock =3D sk_psock_get(sk); if (unlikely(!psock)) - return tcp_sendmsg(sk, msg, size); + return sendmsg(sk, msg, size); =20 lock_sock(sk); timeo =3D sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); @@ -618,6 +626,11 @@ static int tcp_bpf_sendmsg(struct sock *sk, struct msg= hdr *msg, size_t size) return copied > 0 ? copied : err; } =20 +static int tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t siz= e) +{ + return __tcp_bpf_sendmsg(sk, msg, size, tcp_sendmsg); +} + enum { TCP_BPF_IPV4, TCP_BPF_IPV6, diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c index 82b0ad25f700..662b80ce2cf6 100644 --- a/net/mptcp/bpf.c +++ b/net/mptcp/bpf.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "protocol.h" =20 @@ -361,3 +362,131 @@ static int __init bpf_mptcp_kfunc_init(void) return ret; } late_initcall(bpf_mptcp_kfunc_init); + +enum { + MPTCP_BPF_IPV4, + MPTCP_BPF_IPV6, + MPTCP_BPF_NUM_PROTS, +}; + +enum { + MPTCP_BPF_BASE, + MPTCP_BPF_TX, + MPTCP_BPF_RX, + MPTCP_BPF_TXRX, + MPTCP_BPF_NUM_CFGS, +}; + +static struct proto mptcp_bpf_prots[MPTCP_BPF_NUM_PROTS][MPTCP_BPF_NUM_CFG= S]; + +static int mptcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t l= en, + int flags) +{ + return __tcp_bpf_recvmsg(sk, msg, len, flags, mptcp_recvmsg); +} + +static int mptcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t s= ize) +{ + return __tcp_bpf_sendmsg(sk, msg, size, mptcp_sendmsg); +} + +static void mptcp_bpf_rebuild_protos(struct proto prot[MPTCP_BPF_NUM_CFGS], + struct proto *base) +{ + prot[MPTCP_BPF_BASE] =3D *base; + prot[MPTCP_BPF_BASE].destroy =3D sock_map_destroy; + prot[MPTCP_BPF_BASE].close =3D sock_map_close; + prot[MPTCP_BPF_BASE].recvmsg =3D mptcp_bpf_recvmsg; + prot[MPTCP_BPF_BASE].sock_is_readable =3D sk_msg_is_readable; + + prot[MPTCP_BPF_TX] =3D prot[MPTCP_BPF_BASE]; + prot[MPTCP_BPF_TX].sendmsg =3D mptcp_bpf_sendmsg; + + prot[MPTCP_BPF_RX] =3D prot[MPTCP_BPF_BASE]; + + prot[MPTCP_BPF_TXRX] =3D prot[MPTCP_BPF_TX]; +} + +#if IS_ENABLED(CONFIG_MPTCP_IPV6) +static struct proto *mptcpv6_prot_saved __read_mostly; +static DEFINE_SPINLOCK(mptcpv6_prot_lock); + +static void mptcp_bpf_check_v6_needs_rebuild(struct proto *ops) +{ + /* Load with acquire semantics to ensure we see the latest protocol + * structure before checking for rebuild. + */ + if (unlikely(ops !=3D smp_load_acquire(&mptcpv6_prot_saved))) { + spin_lock_bh(&mptcpv6_prot_lock); + if (likely(ops !=3D mptcpv6_prot_saved)) { + struct proto *v6_prots; + + v6_prots =3D mptcp_bpf_prots[MPTCP_BPF_IPV6]; + mptcp_bpf_rebuild_protos(v6_prots, ops); + /* Ensure mptcpv6_prot_saved update is visible before + * releasing lock + */ + smp_store_release(&mptcpv6_prot_saved, ops); + } + spin_unlock_bh(&mptcpv6_prot_lock); + } +} + +static int mptcp_bpf_assert_proto_ops(struct proto *ops) +{ + /* In order to avoid retpoline, we make assumptions when we call + * into ops if e.g. a psock is not present. Make sure they are + * indeed valid assumptions. + */ + return ops->recvmsg =3D=3D mptcp_recvmsg && + ops->sendmsg =3D=3D mptcp_sendmsg ? 0 : -EOPNOTSUPP; +} +#endif + +int mptcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, + bool restore) +{ + int family =3D sk->sk_family =3D=3D AF_INET6 ? MPTCP_BPF_IPV6 : + MPTCP_BPF_IPV4; + int config =3D psock->progs.msg_parser ? MPTCP_BPF_TX : + MPTCP_BPF_BASE; + + if (psock->progs.stream_verdict || psock->progs.skb_verdict) + config =3D (config =3D=3D MPTCP_BPF_TX) ? MPTCP_BPF_TXRX : + MPTCP_BPF_RX; + + if (restore) { + WRITE_ONCE(sk->sk_write_space, psock->saved_write_space); + /* Pairs with lockless read in sk_clone() */ + sock_replace_proto(sk, psock->sk_proto); + return 0; + } + +#if IS_ENABLED(CONFIG_MPTCP_IPV6) + if (sk->sk_family =3D=3D AF_INET6) { + if (mptcp_bpf_assert_proto_ops(psock->sk_proto)) + return -EINVAL; + + mptcp_bpf_check_v6_needs_rebuild(psock->sk_proto); + } +#endif + + /* Pairs with lockless read in sk_clone() */ + sock_replace_proto(sk, &mptcp_bpf_prots[family][config]); + return 0; +} + +void mptcp_bpf_clone(const struct sock *sk, struct sock *newsk) +{ + struct proto *prot =3D newsk->sk_prot; + + if (is_insidevar(prot, mptcp_bpf_prots)) + newsk->sk_prot =3D sk->sk_prot_creator; +} + +static int __init mptcp_bpf_v4_build_proto(void) +{ + mptcp_bpf_rebuild_protos(mptcp_bpf_prots[MPTCP_BPF_IPV4], &mptcp_prot); + return 0; +} +late_initcall(mptcp_bpf_v4_build_proto); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 1a19e494c609..3d3c5af7c266 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2185,7 +2185,7 @@ static int mptcp_sendmsg_locked(struct sock *sk, stru= ct msghdr *msg, size_t len) goto out; } =20 -static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) +int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) { int ret; =20 @@ -2436,8 +2436,7 @@ static unsigned int mptcp_inq_hint(const struct sock = *sk) return 0; } =20 -static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, - int flags) +int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int fla= gs) { struct mptcp_sock *msk =3D mptcp_sk(sk); struct scm_timestamping_internal tss; @@ -3795,6 +3794,8 @@ struct sock *mptcp_sk_clone_init(const struct sock *s= k, if (!nsk) return NULL; =20 + mptcp_bpf_clone(sk, nsk); + #if IS_ENABLED(CONFIG_MPTCP_IPV6) if (nsk->sk_family =3D=3D AF_INET6) inet_sk(nsk)->pinet6 =3D mptcp_inet6_sk(nsk); @@ -4298,7 +4299,7 @@ static int mptcp_connect(struct sock *sk, struct sock= addr_unsized *uaddr, return 0; } =20 -static struct proto mptcp_prot =3D { +struct proto mptcp_prot =3D { .name =3D "MPTCP", .owner =3D THIS_MODULE, .init =3D mptcp_init_sock, @@ -4329,6 +4330,7 @@ static struct proto mptcp_prot =3D { .obj_size =3D sizeof(struct mptcp_sock), .slab_flags =3D SLAB_TYPESAFE_BY_RCU, .no_autobind =3D true, + .psock_update_sk_prot =3D mptcp_bpf_update_proto, }; =20 static int mptcp_bind(struct socket *sock, struct sockaddr_unsized *uaddr,= int addr_len) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 3f8997f15bec..ae1e9ab78724 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -1393,4 +1393,22 @@ mptcp_token_join_cookie_init_state(struct mptcp_subf= low_request_sock *subflow_re static inline void mptcp_join_cookie_init(void) {} #endif =20 +extern struct proto mptcp_prot; +int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int fla= gs); +int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len); + +#ifdef CONFIG_BPF_SYSCALL +int mptcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, + bool restore); +void mptcp_bpf_clone(const struct sock *sk, struct sock *newsk); +#else +static inline int +mptcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool resto= re) +{ + return -EOPNOTSUPP; +} + +static inline void mptcp_bpf_clone(const struct sock *sk, struct sock *new= sk) {} +#endif + #endif /* __MPTCP_PROTOCOL_H */ --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 B10CB39F168 for ; Sun, 13 Sep 2026 10:15:19 +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=1789294521; cv=none; b=n6/Krr2lce3vTL6ITeNKOdTXXGjl0sLhZ/pWzJQG7J+tcMjivCSbEEn+MPc+H6SmHXZK7cs6zIhEz/ypeW2udpdpyU6KMlaie0rlqTmzQOBycT/0tMR7P7Rq9Rr95FU2ecrkScE7ez2ijA1TWAbcaKb4oFUFaYCcev3BMmsnCik= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294521; c=relaxed/simple; bh=IhGxWJ+FTY+0ahv8lZfYgUdZHU0zvCR8CqNF4te/ZYA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SrfZako4e0rGOhqdR1aZNdPAGjz60eqk3PDUUe+GQkv+BMcPBR8n0C9+WebP9WOzkgb+t7ubNdSzn+gNYpDeslcyn2iRKecoopFEjCVIOBPXVInHMlO7zlL8uvLGZNMqrOj0IUSa9/+806dOfm9oqIgxZOJEcEKX7x72xSTpdpo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ihktVzRV; 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="ihktVzRV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B47691F000FF; Sun, 13 Sep 2026 10:15:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294519; bh=wX5klhHYwyrBMg+hgAgC1bIWrCwyKCypeqmLKLavp0c=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=ihktVzRVve5LECV3QNLLI2NAzeAP4OKHeEDJk4MH5lSOLkKIAjBkotWtRSGGsJ3fi sUJR+OMYL8O3GDo04Ipl0tIDIeTrg87lNuYqiNRj1xMPM6D814frenuqt/zfxQRbdG /F9hlXaSamYpQABqKeEBX0pM+r3b7pMvtj0FqJfC3ytrwm+NKDgNuDZMqFmP7oFWRv iJcTzEFcw3BJ60Uu3NGFnk6aZbyQzD/76+KH8CHqfA/7WGI106krJcjEzWVD29dLqK a0GsPrQmJTk/c7+OPPvYG9iM58IprpfFeokpXu+DFmeAnCtyB49XzO+dOPjcAqLVFM 7H4sr0IftTcjw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 07/16] mptcp: add sock_map_update BPF helper Date: Sun, 13 Sep 2026 18:14:46 +0800 Message-ID: <393478c81ea50e72c49041752385e9b4fc82d469.1789294365.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 BPF helper bpf_mptcp_sock_map_update() that allows sockops programs running on MPTCP subflows to insert the parent MPTCP socket into a sockmap or sockhash. When called from a sockops callback on a subflow, it resolves the parent MPTCP socket via bpf_mptcp_sock_from_subflow() and validates that the subflow is the first subflow (msk->first) before inserting the MPTCP socket into the map via sock_map_update_common(). Export sock_map_update_common() from sock_map.c and register the helper in the BPF function mapper (id 212) with corresponding verifier compatibility checks. Signed-off-by: Geliang Tang --- include/linux/bpf.h | 7 +++++++ include/uapi/linux/bpf.h | 10 ++++++++++ kernel/bpf/verifier.c | 2 ++ net/core/filter.c | 18 ++++++++++++++++++ net/core/sock_map.c | 4 ++-- net/mptcp/bpf.c | 20 ++++++++++++++++++++ 6 files changed, 59 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index e57af902560c..ecb53a7ad0e8 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -4022,6 +4022,13 @@ u32 bpf_xdp_sock_convert_ctx_access(enum bpf_access_= type type, struct bpf_insn *insn_buf, struct bpf_prog *prog, u32 *target_size); + +int sock_map_update_common(struct bpf_map *map, u32 idx, + struct sock *sk, u64 flags); + +#ifdef CONFIG_MPTCP +u64 mptcp_sock_map_update(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); +#endif #else static inline bool bpf_tcp_sock_is_valid_access(int off, int size, enum bpf_access_type type, diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 732b35cc08d1..41eecb8622ac 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5998,6 +5998,15 @@ union bpf_attr { * 0 on success. * * **-ENOENT** if the bpf_local_storage cannot be found. + * + * long bpf_mptcp_sock_map_update(struct bpf_sock_ops *skops, struct bpf_m= ap *map, void *key, u64 flags) + * Description + * MPTCP-aware variant of **bpf_sock_map_update**\ (). + * When called from a sockops callback on an MPTCP subflow, + * it resolves to the parent MPTCP socket before inserting + * it into the *map*. + * Return + * 0 on success, or a negative error in case of failure. */ #define ___BPF_FUNC_MAPPER(FN, ctx...) \ FN(unspec, 0, ##ctx) \ @@ -6212,6 +6221,7 @@ union bpf_attr { FN(user_ringbuf_drain, 209, ##ctx) \ FN(cgrp_storage_get, 210, ##ctx) \ FN(cgrp_storage_delete, 211, ##ctx) \ + FN(mptcp_sock_map_update, 212, ##ctx) \ /* This helper list is effectively frozen. If you are trying to \ * add a new helper, you should add a kfunc instead which has \ * less stability guarantees. See Documentation/bpf/kfuncs.rst \ diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 72a3f5998dd2..c58c2ba87d26 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -9066,6 +9066,7 @@ static int check_map_func_compatibility(struct bpf_ve= rifier_env *env, func_id !=3D BPF_FUNC_msg_redirect_map && func_id !=3D BPF_FUNC_sk_select_reuseport && func_id !=3D BPF_FUNC_map_lookup_elem && + func_id !=3D BPF_FUNC_mptcp_sock_map_update && !may_update_sockmap(env, func_id)) goto error; break; @@ -9075,6 +9076,7 @@ static int check_map_func_compatibility(struct bpf_ve= rifier_env *env, func_id !=3D BPF_FUNC_msg_redirect_hash && func_id !=3D BPF_FUNC_sk_select_reuseport && func_id !=3D BPF_FUNC_map_lookup_elem && + func_id !=3D BPF_FUNC_mptcp_sock_map_update && !may_update_sockmap(env, func_id)) goto error; break; diff --git a/net/core/filter.c b/net/core/filter.c index 61940e753552..0b4fec5a8848 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -8830,6 +8830,10 @@ xdp_func_proto(enum bpf_func_id func_id, const struc= t bpf_prog *prog) const struct bpf_func_proto bpf_sock_map_update_proto __weak; const struct bpf_func_proto bpf_sock_hash_update_proto __weak; =20 +#if IS_ENABLED(CONFIG_MPTCP) +static const struct bpf_func_proto mptcp_sock_map_update_proto; +#endif + static const struct bpf_func_proto * sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { @@ -8850,6 +8854,10 @@ sock_ops_func_proto(enum bpf_func_id func_id, const = struct bpf_prog *prog) return &bpf_sock_map_update_proto; case BPF_FUNC_sock_hash_update: return &bpf_sock_hash_update_proto; +#if IS_ENABLED(CONFIG_MPTCP) + case BPF_FUNC_mptcp_sock_map_update: + return &mptcp_sock_map_update_proto; +#endif case BPF_FUNC_get_socket_cookie: return &bpf_get_socket_cookie_sock_ops_proto; case BPF_FUNC_perf_event_output: @@ -11790,6 +11798,16 @@ static const struct bpf_func_proto sk_select_reuse= port_proto =3D { .arg4_type =3D ARG_ANYTHING, }; =20 +static const struct bpf_func_proto mptcp_sock_map_update_proto =3D { + .func =3D mptcp_sock_map_update, + .gpl_only =3D false, + .ret_type =3D RET_INTEGER, + .arg1_type =3D ARG_PTR_TO_CTX, + .arg2_type =3D ARG_CONST_MAP_PTR, + .arg3_type =3D ARG_PTR_TO_MAP_KEY, + .arg4_type =3D ARG_ANYTHING, +}; + BPF_CALL_4(sk_reuseport_load_bytes, const struct sk_reuseport_kern *, reuse_kern, u32, offset, void *, to, u32, len) diff --git a/net/core/sock_map.c b/net/core/sock_map.c index ca49bc7f8687..3e3e85e3bd54 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -467,8 +467,8 @@ static int sock_map_get_next_key(struct bpf_map *map, v= oid *key, void *next) return 0; } =20 -static int sock_map_update_common(struct bpf_map *map, u32 idx, - struct sock *sk, u64 flags) +int sock_map_update_common(struct bpf_map *map, u32 idx, + struct sock *sk, u64 flags) { struct bpf_stab *stab =3D container_of(map, struct bpf_stab, map); struct sk_psock_link *link; diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c index 662b80ce2cf6..7ecafbf51fa0 100644 --- a/net/mptcp/bpf.c +++ b/net/mptcp/bpf.c @@ -490,3 +490,23 @@ static int __init mptcp_bpf_v4_build_proto(void) return 0; } late_initcall(mptcp_bpf_v4_build_proto); + +BPF_CALL_4(mptcp_sock_map_update, struct bpf_sock_ops_kern *, sops, + struct bpf_map *, map, void *, key, u64, flags) +{ + struct sock *sk =3D sops->sk; + struct mptcp_sock *msk; + + WARN_ON_ONCE(!rcu_read_lock_held()); + + msk =3D bpf_mptcp_sock_from_subflow(sk); + if (msk) { + if (sk !=3D READ_ONCE(msk->first)) + return -EINVAL; + + sk =3D (struct sock *)msk; + } + + return sock_map_update_common(map, *(u32 *)key, sk, flags); +} +EXPORT_SYMBOL_GPL(mptcp_sock_map_update); --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 590F93E16A9 for ; Sun, 13 Sep 2026 10:15:21 +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=1789294523; cv=none; b=NpoT8QI5IGBPCoaekFPkH6PvlkxZrxX0VW6cZPgtq6aF/AywXFa0kcXLfWao3pOl4u8dYe+Bqzwnq41DwteCTTMI2Nzwdpt4AVw0DUUS0E1nx5tWQgq7sVxmEOTLj5f6/Y+cnwktLmBDqexanYTrrAMqb7QreC0CoimBC3yMgPg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294523; c=relaxed/simple; bh=M8i5Itm8HEYRMa8EmHeGu/lEUv6svLMMRkIxnYZASsM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uA07tCv5a9WlDnsYBemGoGfk/4ubD2KSUsTbhC8itfXcdGnLQRoS2HwvsnRD65896OwSBICsAFkLBCJms4s1DqRQUh4JDSOSTrfXebN5HZa2DhcFsTu2FCENjzdyGdzTjXvsuvgs0Ch8YT7aDTOep7sHDWB9n8XKSH54t/j+1v4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PJWxMBOJ; 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="PJWxMBOJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 113851F00898; Sun, 13 Sep 2026 10:15:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294520; bh=zaUslCg2NGFqGsTOCGPfuYrCUiPhrTkj78xHlnj1UuU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=PJWxMBOJ/dmypFRkzsY6VoOjoUXYVK7GhmgJB6lABMki0suIf7XtEoi9SMtE3mjAl Rnjj6SzlUdfjtCj+Gyny9l48BzIk9yCRpBWszs7664SrNu8rGnmqMT2Uxo8erWDdVM H7kYOngxGj2fNcyYbNrfXmJDQc+S0zB+ScsyDsZ4nNZQl/EA7EnWUkKwVOQmuAzHrq at/4Z77CEK5pRbiLRkYqeKYnvqtT+TIvHbTCFZrP19K2N61bmXI2hzNS5lNTc6w1SA +QGiWKFR0PXafEBT75FiP5c9382sHxS2yLDDOXoKdgPs5L+IqEOu/sVKgT5yaWXWaW x7Jx4v1Q96KbQ== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 08/16] selftests/bpf: enable MPTCP support in sockmap tests Date: Sun, 13 Sep 2026 18:14:47 +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 Update sockmap tests to reflect new MPTCP support. MPTCP sockets are now allowed in sockmap, so test expectations are adjusted accordingly. Use a different key (1) for MPTCP client sockets to validate sockmap. In test_sockmap_with_mptcp, client_fd1 is changed from TCP fallback to MPTCP. The sockops program now uses bpf_mptcp_sock_map_update() to insert the parent MPTCP socket into the sockmap, which succeeds (returns 0). Since the server socket is already inserted by the sockops program, a duplicate userspace insertion at the same key returns -EBUSY. The client socket is additionally inserted at a different key (1) from userspace to verify that MPTCP client sockets are allowed in sockmap. Signed-off-by: Geliang Tang --- .../testing/selftests/bpf/prog_tests/mptcp.c | 27 ++++++++++--------- .../selftests/bpf/progs/mptcp_sockmap.c | 8 ++++-- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing= /selftests/bpf/prog_tests/mptcp.c index d77c9f8c53c7..59ea562882a0 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -552,11 +552,11 @@ static void test_sockmap_with_mptcp_fallback(struct m= ptcp_sockmap *skel) close(listen_fd); } =20 -/* Test sockmap rejection of MPTCP sockets - both server and client sides.= */ -static void test_sockmap_reject_mptcp(struct mptcp_sockmap *skel) +/* Test sockmap on MPTCP sockets - both server and client sides. */ +static void test_sockmap_with_mptcp(struct mptcp_sockmap *skel) { int listen_fd =3D -1, server_fd =3D -1, client_fd1 =3D -1; - int err, zero =3D 0; + int err, zero =3D 0, one =3D 1; =20 /* start server with MPTCP enabled */ listen_fd =3D start_mptcp_server(AF_INET, NULL, 0, 0); @@ -570,20 +570,20 @@ static void test_sockmap_reject_mptcp(struct mptcp_so= ckmap *skel) if (!ASSERT_OK_FD(client_fd1, "connect_to_fd client_fd1")) goto end; =20 - /* bpf_sock_map_update() called from sockops should reject MPTCP sk */ - if (!ASSERT_EQ(skel->bss->helper_ret, -EOPNOTSUPP, "should reject")) + /* bpf_mptcp_sock_map_update() called from sockops should be allowed */ + if (!ASSERT_EQ(skel->bss->helper_ret, 0, "should be allowed")) goto end; =20 server_fd =3D accept(listen_fd, NULL, 0); err =3D bpf_map_update_elem(bpf_map__fd(skel->maps.sock_map), &zero, &server_fd, BPF_NOEXIST); - if (!ASSERT_EQ(err, -EOPNOTSUPP, "server should be disallowed")) + if (!ASSERT_EQ(err, -EBUSY, "server should be allowed")) goto end; =20 - /* MPTCP client should also be disallowed */ + /* MPTCP client should also be allowed */ err =3D bpf_map_update_elem(bpf_map__fd(skel->maps.sock_map), - &zero, &client_fd1, BPF_NOEXIST); - if (!ASSERT_EQ(err, -EOPNOTSUPP, "client should be disallowed")) + &one, &client_fd1, BPF_NOEXIST); + if (!ASSERT_EQ(err, 0, "client should be allowed")) goto end; end: if (client_fd1 >=3D 0) @@ -607,9 +607,10 @@ static void test_mptcp_sockmap(void) if (!ASSERT_OK_PTR(skel, "skel_open_load: mptcp_sockmap")) goto close_cgroup; =20 - skel->links.mptcp_sockmap_inject =3D - bpf_program__attach_cgroup(skel->progs.mptcp_sockmap_inject, cgroup_fd); - if (!ASSERT_OK_PTR(skel->links.mptcp_sockmap_inject, "attach sockmap")) + skel->links.mptcp_sockmap_update =3D + bpf_program__attach_cgroup(skel->progs.mptcp_sockmap_update, + cgroup_fd); + if (!ASSERT_OK_PTR(skel->links.mptcp_sockmap_update, "attach sockmap")) goto skel_destroy; =20 err =3D bpf_prog_attach(bpf_program__fd(skel->progs.mptcp_sockmap_redirec= t), @@ -626,7 +627,7 @@ static void test_mptcp_sockmap(void) goto close_netns; =20 test_sockmap_with_mptcp_fallback(skel); - test_sockmap_reject_mptcp(skel); + test_sockmap_with_mptcp(skel); =20 close_netns: netns_free(netns); diff --git a/tools/testing/selftests/bpf/progs/mptcp_sockmap.c b/tools/test= ing/selftests/bpf/progs/mptcp_sockmap.c index d4eef0cbadb9..085e14bea015 100644 --- a/tools/testing/selftests/bpf/progs/mptcp_sockmap.c +++ b/tools/testing/selftests/bpf/progs/mptcp_sockmap.c @@ -2,6 +2,9 @@ =20 #include "bpf_tracing_net.h" =20 +static long (*bpf_mptcp_sock_map_update)(struct bpf_sock_ops *, void *, + void *, __u64) =3D (void *)212; + char _license[] SEC("license") =3D "GPL"; =20 int sk_index; @@ -16,7 +19,7 @@ struct { } sock_map SEC(".maps"); =20 SEC("sockops") -int mptcp_sockmap_inject(struct bpf_sock_ops *skops) +int mptcp_sockmap_update(struct bpf_sock_ops *skops) { struct bpf_sock *sk; =20 @@ -30,7 +33,8 @@ int mptcp_sockmap_inject(struct bpf_sock_ops *skops) return 1; =20 /* update sk handler */ - helper_ret =3D bpf_sock_map_update(skops, &sock_map, &sk_index, BPF_NOEXI= ST); + helper_ret =3D bpf_mptcp_sock_map_update(skops, &sock_map, &sk_index, + BPF_NOEXIST); =20 return 1; } --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 06325232395 for ; Sun, 13 Sep 2026 10:15:22 +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=1789294524; cv=none; b=KECvIBcrQhPXUDVMTuP3BgKY+Ziy0vGNXt139Vb5b2awrc/RymDQ3/2ELtutQM55BlejoFV81xdb9ydtjjhz4yjMBg9M5NUuXD8uwueHzOvL9JJoy0TxwuMSZnA/551F5XOUFFjQhJGy0TRCmhP8l8vtXiMvfOFqoJQiq8SvWbs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294524; c=relaxed/simple; bh=lW/QuE9Zs69ZCHUMesZ2lOArc8dS09q/gw0hvX60Ry0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=g9TwqQG7Qp12GaXmu7Y0S7cIu4X/HPeey1eZGws87B8jcMtZLiiNFO/lrcOna9fPnob6sDROZ+BjSnlJhXSCuAMRY7ol1pzGYtrAlapemPesg2D352tqUDyRzSSzizxVMOvmxDMLqwfamCH7sc90sp7UKmejUloDa+yywWU5JBU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lSIJQklb; 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="lSIJQklb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 623941F000FF; Sun, 13 Sep 2026 10:15:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294522; bh=gajEtr8iM0vx7FN0XlO4gi98FWlievrAivweiTNXO7U=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=lSIJQklbGwEoqIQw5BaXQJb/5rCAI79oVC/pG89lgKxSda+YcQlO0ApqDYZ/or2q8 wE/UMzVlypgs5UKcalmECv8CjvIrgK1eZIv+ocOBeEhvy+4Qq3hbkWpsO4qxM+g3jn yqz4XV6u8mfFi1TAw7wqXNO62I/WsjmnNblheAwqXhB2SoebgEChAn+y4TaccZFPiU MZr0o9rGuMYwZLs4HzYJu3vrWSDoswAOFrRXUwaLMAntjU0EzHHgCJ0IOv+MHar5f0 2BXewgYgcLhCwcJGEFDoMkiG/2wPoyx1f9LRC88wtKWqZdSxx6nfx8KaibFb7br5jk M0kqMUiAZ82Cg== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 09/16] mptcp: implement read_skb for sockmap stream verdict Date: Sun, 13 Sep 2026 18:14:48 +0800 Message-ID: <08dd128a702b7b1d7023d64aea1b94907a981ed9.1789294365.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 BPF sockmap's stream verdict path (sk_psock_verdict_data_ready) calls ops->read_skb() to dequeue skbs from the socket and pass them to the verdict BPF program. MPTCP's proto_ops (mptcp_stream_ops and mptcp_v6_stream_ops) did not define .read_skb, causing sk_psock_verdict_data_ready() to return early without processing any data. This made the stream verdict redirect completely non-functional for MPTCP sockets. Add mptcp_read_skb() as the skb_read_actor_t callback. It peeks skbs from the socket receive queue, unlinks each one, and passes it to the recv_actor. Processing continues until the queue is drained or the actor returns a negative value. This follows the same pattern as tcp_read_skb() in net/ipv4/tcp.c. Signed-off-by: Geliang Tang --- net/mptcp/protocol.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 3d3c5af7c266..c5be29767cb1 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -4801,6 +4801,31 @@ static ssize_t mptcp_splice_read(struct socket *sock= , loff_t *ppos, return ret; } =20 +static int mptcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor) +{ + struct sk_buff *skb; + int copied =3D 0; + + if (sk->sk_state =3D=3D TCP_LISTEN) + return -ENOTCONN; + + while ((skb =3D skb_peek(&sk->sk_receive_queue)) !=3D NULL) { + int used; + + __skb_unlink(skb, &sk->sk_receive_queue); + WARN_ON_ONCE(!skb_set_owner_sk_safe(skb, sk)); + used =3D recv_actor(sk, skb); + if (used < 0) { + if (!copied) + copied =3D used; + break; + } + copied +=3D used; + } + + return copied; +} + static const struct proto_ops mptcp_stream_ops =3D { .family =3D PF_INET, .owner =3D THIS_MODULE, @@ -4824,6 +4849,7 @@ static const struct proto_ops mptcp_stream_ops =3D { .read_sock =3D mptcp_read_sock, .splice_read =3D mptcp_splice_read, .sendmsg_locked =3D mptcp_sendmsg_locked, + .read_skb =3D mptcp_read_skb, }; =20 static struct inet_protosw mptcp_protosw =3D { @@ -4937,6 +4963,7 @@ static const struct proto_ops mptcp_v6_stream_ops =3D= { .read_sock =3D mptcp_read_sock, .splice_read =3D mptcp_splice_read, .sendmsg_locked =3D mptcp_sendmsg_locked, + .read_skb =3D mptcp_read_skb, }; =20 static struct proto mptcp_v6_prot; --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 929C03CAA3F for ; Sun, 13 Sep 2026 10:15:23 +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=1789294525; cv=none; b=iq+B1bQ17K2gIYjTCXxgEt8rqDD/Rl43N8pOMO9fm3R5sCwK69sTFN65pWPxv+mbkBVhwzeuLs/oX5cIeXD6eIWG9LpT55/QXkNax/Elz/rvyKU+smpSXt7vTHxQwSR1hYdylFeJiv3g54s2s+JLByt9nRqV/CLE1Vp/tyOgkkY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294525; c=relaxed/simple; bh=QsUsZzytdewlwtHwBdJZZp80n/f+kPmNpUe7FTysRgA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=F+Imz78/XNiCI0LfYLPJxdsMG7KbHdvGit6Iel2fn9CqncVj57QAL1CGpKqDKe/sqy71hATi6v4b4dnCmcjIDj+iQaoWEN0gph/ZUhg9r6KieHYgpig+dApKxGRcvXWbSgF5JUF2VAxQMwpGLjm8D3s3oX942HYqXQGzLCfppv4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OKDrl8wu; 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="OKDrl8wu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 99F241F00893; Sun, 13 Sep 2026 10:15:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294523; bh=G0dYdhSNyJlerIWRd18N/LVtU8y6aN7oswuYCjl46Zg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=OKDrl8wud8Q9VHGGPzMc9e/70dtSOaRzm1wh8u8DD7MZPYu2E6N1noF25V+MyJ1Cr A34Lnjhq3+OuoFoAPeAIPQ7UCrJ0OiLT0AK+ODHf+MbIZ5Q4B8gpzKFc2Yr06aa8n6 JrwVdFold6ru/3PLb2uOaUDNRpTTgj28YSKmjDewtu6evTyE0F6K/f0SoyY/luQ2ws st++bAakGkbvxsNUb98cu9mjLnxEv5FdUA4bI4POpmYVUSebONOA/cTDlnsnx4qnGq BG8lSZoVWbUDL34BE/mLT40HakboUrKQuRvNAs/bz1ooZ8jy30ahvZM18RqFlHTQQX BTie6h4ms5bLw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 10/16] bpf: export and generalize tcp_bpf_ioctl Date: Sun, 13 Sep 2026 18:14:49 +0800 Message-ID: <2470bdd0b43b4b4530edd7d0448e0e92bd8e578f.1789294365.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 Export tcp_bpf_ioctl() and generalize it to use protocol-specific operations (sk->sk_prot->ioctl and sk->sk_socket->ops->peek_len) instead of hard-coded tcp_ioctl() and tcp_inq(). Wire it into the MPTCP BPF protocol structures so that SIOCINQ returns correct results accounting for data in the psock ingress queue. Signed-off-by: Geliang Tang --- include/net/tcp.h | 1 + net/ipv4/tcp_bpf.c | 10 +++++----- net/mptcp/bpf.c | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index d9c0214328e3..fb4dec998adc 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -2878,6 +2878,7 @@ __tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg= , size_t len, int flags, int (*recvmsg)(struct sock *, struct msghdr *, size_t, int)); int __tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t size, int (*sendmsg)(struct sock *, struct msghdr *, size_t)); +int tcp_bpf_ioctl(struct sock *sk, int cmd, int *karg); #endif /* CONFIG_NET_SOCK_MSG */ =20 #if !defined(CONFIG_BPF_SYSCALL) || !defined(CONFIG_NET_SOCK_MSG) diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index e006131696e9..8aed3c309b0d 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -331,15 +331,15 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, return copied; } =20 -static int tcp_bpf_ioctl(struct sock *sk, int cmd, int *karg) +int tcp_bpf_ioctl(struct sock *sk, int cmd, int *karg) { struct sk_psock *psock; bool slow; =20 if (cmd !=3D SIOCINQ) - return tcp_ioctl(sk, cmd, karg); + return sk->sk_prot->ioctl(sk, cmd, karg); =20 - /* works similar as tcp_ioctl */ + /* works similar as sk_prot->ioctl */ if (sk->sk_state =3D=3D TCP_LISTEN) return -EINVAL; =20 @@ -347,7 +347,7 @@ static int tcp_bpf_ioctl(struct sock *sk, int cmd, int = *karg) psock =3D sk_psock_get(sk); if (unlikely(!psock)) { unlock_sock_fast(sk, slow); - return tcp_ioctl(sk, cmd, karg); + return sk->sk_prot->ioctl(sk, cmd, karg); } *karg =3D sk_psock_get_msg_len_nolock(psock); /* Without a verdict program, ingress data is never diverted to @@ -357,7 +357,7 @@ static int tcp_bpf_ioctl(struct sock *sk, int cmd, int = *karg) */ if (!READ_ONCE(psock->progs.stream_verdict) && !READ_ONCE(psock->progs.skb_verdict)) - *karg +=3D tcp_inq(sk); + *karg +=3D sk->sk_socket->ops->peek_len(sk->sk_socket); sk_psock_put(sk, psock); unlock_sock_fast(sk, slow); =20 diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c index 7ecafbf51fa0..f6fd610f7077 100644 --- a/net/mptcp/bpf.c +++ b/net/mptcp/bpf.c @@ -398,6 +398,7 @@ static void mptcp_bpf_rebuild_protos(struct proto prot[= MPTCP_BPF_NUM_CFGS], prot[MPTCP_BPF_BASE].close =3D sock_map_close; prot[MPTCP_BPF_BASE].recvmsg =3D mptcp_bpf_recvmsg; prot[MPTCP_BPF_BASE].sock_is_readable =3D sk_msg_is_readable; + prot[MPTCP_BPF_BASE].ioctl =3D tcp_bpf_ioctl; =20 prot[MPTCP_BPF_TX] =3D prot[MPTCP_BPF_BASE]; prot[MPTCP_BPF_TX].sendmsg =3D mptcp_bpf_sendmsg; --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 CAA723CCFC3 for ; Sun, 13 Sep 2026 10:15:24 +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=1789294526; cv=none; b=eS25FbTwbvJWek+DqjorVv+/UrIlsrLFCD5aPqszWSYDb9WkiA5o6/bGSqyCy25nIZx11ScnWAo83o8+Ik6QhfOHE60WB7dBsbZyVeXfCjxjYgen9ZFdu7dDC6r2DAMp6npjGPRHQv+ZqFkqMKGn9N+PX8QkShKWK3fP7G7NVRs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294526; c=relaxed/simple; bh=sKHPyg7Dyb5XBXHV9dGnc3tWy0/8cddOICo+Obcc4ys=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YWSbxwhUb1nbW0Jv2dT2KbsdCur9dkHVyzD86SkRaIFsYDe8mXHPclEADn9NNpWXQdo2fDKpB2pAmfhepq10f420rTnE8BFwN8lduVX4paNMb+Oxutz+qUOKyWBkYy0J7O5jwB4dqs733k8+m0wxYMCT0QaNySR4Alwz6Q1rnRc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MWrPdG2O; 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="MWrPdG2O" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EAED81F00899; Sun, 13 Sep 2026 10:15:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294524; bh=h5OZpAKohlbk3worVQMNC6fVZBm3WDQiMVA4IsjTpYY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=MWrPdG2OZ4MPj//Qg0ctyqr4dmbDmPGfjWdJiq3I9pPdvX3W108xn5wxqEByFPgZj GOFz9mPHXRWc0/7QrR01HIfa3Quo2fJNADVTTL05NoPrlCCTjHULkWonevXS/L0Q2f l4qc9HU5NPeYurPEhNQiPyQ4L/lDmBgNJpUG0i91Q9K+LmWiJNhUuWw9N1y/if9rZU mybCQ2yW/l6gfMV58/f33IzA2j6FAqKov8PwpmM32uwAfX6ebfSsNXcib2+A4w5WD8 niIyeo0GPDEWH5sUxrmagzxQeGZ/SxWf+yGt4NDul5I2OrfvFfieuXlp0ci+Trw8Lf aJJ5CkIyNiqMg== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 11/16] mptcp: add TCP_REPAIR sockopt support Date: Sun, 13 Sep 2026 18:14:50 +0800 Message-ID: <15960ae7fff68167e041400db0480e55950ea1c1.1789294365.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 TCP_REPAIR socket option support for MPTCP, required for sockmap CRIU checkpoint/restore. When TCP_REPAIR is set on the first subflow, skip the normal connection handshake in mptcp_connect() and transition directly to TCP_ESTABLISHED. On close, skip the shutdown sequence and jump to cleanup when repair mode is active. Signed-off-by: Geliang Tang --- net/mptcp/protocol.c | 10 ++++++++++ net/mptcp/sockopt.c | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index c5be29767cb1..07132976016e 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3560,6 +3560,11 @@ bool __mptcp_close(struct sock *sk, long timeout) __mptcp_wr_shutdown(sk); } =20 + if (msk->first && tcp_sk(msk->first)->repair) { + mptcp_set_state(sk, TCP_CLOSE); + goto cleanup; + } + sk_stream_wait_close(sk, timeout); =20 cleanup: @@ -4281,6 +4286,11 @@ static int mptcp_connect(struct sock *sk, struct soc= kaddr_unsized *uaddr, =20 inet_assign_bit(DEFER_CONNECT, sk, inet_test_bit(DEFER_CONNECT, ssk)); =20 + if (unlikely(tcp_sk(ssk)->repair)) { + mptcp_set_state(sk, TCP_ESTABLISHED); + sk->sk_state_change(sk); + } + out: if (!msk->fastopening) release_sock(ssk); diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index 922f6ae5c80c..d2d1c9d1ed1d 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -671,12 +671,13 @@ static bool mptcp_supported_sockopt(int level, int op= tname) case TCP_FASTOPEN_CONNECT: case TCP_FASTOPEN_KEY: case TCP_FASTOPEN_NO_COOKIE: + case TCP_REPAIR: return true; } =20 /* TCP_MD5SIG, TCP_MD5SIG_EXT are not supported, MD5 is not compatible w= ith MPTCP */ =20 - /* TCP_REPAIR, TCP_REPAIR_QUEUE, TCP_QUEUE_SEQ, TCP_REPAIR_OPTIONS, + /* TCP_REPAIR_QUEUE, TCP_QUEUE_SEQ, TCP_REPAIR_OPTIONS, * TCP_REPAIR_WINDOW are not supported, better avoid this mess */ } @@ -918,6 +919,7 @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *= msk, int optname, case TCP_CONGESTION: return mptcp_setsockopt_sol_tcp_congestion(msk, optval, optlen); case TCP_DEFER_ACCEPT: + case TCP_REPAIR: /* See tcp.c: TCP_DEFER_ACCEPT does not fail */ mptcp_setsockopt_first_sf_only(msk, SOL_TCP, optname, optval, optlen); return 0; --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 0EA2028B517 for ; Sun, 13 Sep 2026 10:15:26 +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=1789294527; cv=none; b=A7ynJU3FC8RNm+/+vzDVvP59/Lghx3GvXrB9K3pv+/BXIfo/tNaMuoaU2N+ymVWO1fm8Ouvi5xLJbBVCLWQj7tWHMOovlxtRiNaLmTOHG/u2TXSZdy4aXA7ylyUKZJDoxfmDWIrf1mLAGVmEhRn16LrO/ENbVEteyYiv3pDEiRY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294527; c=relaxed/simple; bh=JIAGIDjk37WAUMAosEyQmye9Ccb2pEQj4dgM7AA7uuE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hAiTQ63XUrqjSujscaRIYfkd/S0Z7Z2XNzoV2l6sREODdRjmDWL21iYnYJFRQ/Xk0cAcDfqMe5/73MQOIfWUYf65x2knPtMn+930TybJ7R+jWxvr0hZgLDG2HHQFJeFnAaMq/2OxqYoePpKwrhUHQLdWMxn1nx6/K0WpKFQj0BM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=cUNpVy5G; 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="cUNpVy5G" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2EBE41F000FF; Sun, 13 Sep 2026 10:15:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294526; bh=sz7uxiLJZYWJmfx3X3b1TnlwqN0LCR6/Z6UaxaoE1go=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=cUNpVy5GMkLf9dRG6Q04rH3zqcm+SLzRcIeI0oNjqT0ocOgQvjCMrvJV0On7wO9uh q01jM640Uuih5xUGAq5L7BWIC0SE1NoJBJUMpMuVJUEgQGfYpapDZq5teRVFBP0GwZ th7cM8XQucBJmsxmRwAGuWpmmlxGcCwjiv0H8bxxmEPNtZFYNjKBj7oBJP7ilWOyWA YgDcFT+yiMFt2nDUbw5VjGv5ce/zZhvopecSYK8qD8mdpna9sXrTKkZ0gH+9MgOKLH RmKPsoawHyiCtSAeDnJgZSkfu+vWH2HPvjy/2oGRDFyJJZuN6n9SFWijC80vHgLAJk djwbmG8W64bGA== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 12/16] selftests/bpf: add MPTCP coverage to sockmap_basic Date: Sun, 13 Sep 2026 18:14:51 +0800 Message-ID: <7aa10507517cb94460de386bd4bb81108d61aba2.1789294365.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 This patch extends socket_helpers.h with protocol-aware variants (socket_loopback_proto, create_pair_proto) that accept an explicit protocol parameter. Run the sockmap_basic test suite in both TCP and MPTCP modes by looping over run_basic_tests() with a mptcp flag. Skip UDP-specific tests in MPTCP mode since UDP is unaffected by MPTCP. Signed-off-by: Geliang Tang --- .../selftests/bpf/prog_tests/socket_helpers.h | 25 ++++++++++---- .../selftests/bpf/prog_tests/sockmap_basic.c | 33 ++++++++++++++----- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/socket_helpers.h b/tool= s/testing/selftests/bpf/prog_tests/socket_helpers.h index 0d59503a0c73..d9bd6b11e2cc 100644 --- a/tools/testing/selftests/bpf/prog_tests/socket_helpers.h +++ b/tools/testing/selftests/bpf/prog_tests/socket_helpers.h @@ -231,7 +231,8 @@ static inline int enable_reuseport(int s, int progfd) return 0; } =20 -static inline int socket_loopback_reuseport(int family, int sotype, int pr= ogfd) +static inline int socket_loopback_reuseport_proto(int family, int sotype, + int proto, int progfd) { struct sockaddr_storage addr; socklen_t len =3D 0; @@ -239,7 +240,7 @@ static inline int socket_loopback_reuseport(int family,= int sotype, int progfd) =20 init_addr_loopback(family, &addr, &len); =20 - s =3D xsocket(family, sotype, 0); + s =3D xsocket(family, sotype, proto); if (s =3D=3D -1) return -1; =20 @@ -263,11 +264,17 @@ static inline int socket_loopback_reuseport(int famil= y, int sotype, int progfd) return -1; } =20 -static inline int socket_loopback(int family, int sotype) +#define socket_loopback_reuseport(family, sotype, progfd) \ + socket_loopback_reuseport_proto(family, sotype, 0, progfd) + +static inline int socket_loopback_proto(int family, int sotype, int proto) { - return socket_loopback_reuseport(family, sotype, -1); + return socket_loopback_reuseport_proto(family, sotype, proto, -1); } =20 +#define socket_loopback(family, sotype) \ + socket_loopback_proto(family, sotype, 0) + static inline int poll_connect(int fd, unsigned int timeout_sec) { struct timeval timeout =3D { .tv_sec =3D timeout_sec }; @@ -329,18 +336,19 @@ static inline int recv_timeout(int fd, void *buf, siz= e_t len, int flags, } =20 =20 -static inline int create_pair(int family, int sotype, int *p0, int *p1) +static inline int create_pair_proto(int family, int sotype, int proto, + int *p0, int *p1) { __close_fd int s, c =3D -1, p =3D -1; struct sockaddr_storage addr; socklen_t len; int err; =20 - s =3D socket_loopback(family, sotype); + s =3D socket_loopback_proto(family, sotype, proto); if (s < 0) return s; =20 - c =3D xsocket(family, sotype, 0); + c =3D xsocket(family, sotype, proto); if (c < 0) return c; =20 @@ -397,6 +405,9 @@ static inline int create_pair(int family, int sotype, i= nt *p0, int *p1) return 0; } =20 +#define create_pair(family, sotype, p0, p1) \ + create_pair_proto(family, sotype, 0, p0, p1) + static inline int create_socket_pairs(int family, int sotype, int *c0, int= *c1, int *p0, int *p1) { diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools= /testing/selftests/bpf/prog_tests/sockmap_basic.c index 1fef6ec2ba7a..80919a5fef49 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c @@ -32,6 +32,8 @@ #define SOL_TCP 6 #endif =20 +static bool mptcp; + static int connected_socket_v4(void) { struct sockaddr_in addr =3D { @@ -42,7 +44,7 @@ static int connected_socket_v4(void) socklen_t len =3D sizeof(addr); int s, repair, err; =20 - s =3D socket(AF_INET, SOCK_STREAM, 0); + s =3D socket(AF_INET, SOCK_STREAM, mptcp ? IPPROTO_MPTCP : 0); if (!ASSERT_GE(s, 0, "socket")) goto error; =20 @@ -466,7 +468,8 @@ static void test_sockmap_skb_verdict_shutdown(void) if (!ASSERT_OK(err, "bpf_prog_attach")) goto out; =20 - err =3D create_pair(AF_INET, SOCK_STREAM, &c1, &p1); + err =3D create_pair_proto(AF_INET, SOCK_STREAM, + mptcp ? IPPROTO_MPTCP : 0, &c1, &p1); if (err < 0) goto out; =20 @@ -568,7 +571,9 @@ static void do_test_sockmap_skb_verdict_fionread(int so= type, bool pass_prog) static void test_sockmap_skb_verdict_fionread(bool pass_prog) { do_test_sockmap_skb_verdict_fionread(SOCK_STREAM, pass_prog); - do_test_sockmap_skb_verdict_fionread(SOCK_DGRAM, pass_prog); + /* UDP is unaffected by MPTCP, only run it once (in tcp mode) */ + if (!mptcp) + do_test_sockmap_skb_verdict_fionread(SOCK_DGRAM, pass_prog); } =20 static void test_sockmap_skb_verdict_change_tail(void) @@ -588,7 +593,8 @@ static void test_sockmap_skb_verdict_change_tail(void) err =3D bpf_prog_attach(verdict, map, BPF_SK_SKB_STREAM_VERDICT, 0); if (!ASSERT_OK(err, "bpf_prog_attach")) goto out; - err =3D create_pair(AF_INET, SOCK_STREAM, &c1, &p1); + err =3D create_pair_proto(AF_INET, SOCK_STREAM, + mptcp ? IPPROTO_MPTCP : 0, &c1, &p1); if (!ASSERT_OK(err, "create_pair()")) goto out; err =3D bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST); @@ -639,7 +645,8 @@ static void test_sockmap_msg_verdict_pop_data(void) if (!ASSERT_OK(err, "bpf_prog_attach")) goto out; =20 - err =3D create_pair(AF_INET, SOCK_STREAM, &c1, &p1); + err =3D create_pair_proto(AF_INET, SOCK_STREAM, + mptcp ? IPPROTO_MPTCP : 0, &c1, &p1); if (!ASSERT_OK(err, "create_pair")) goto out; =20 @@ -670,7 +677,8 @@ static void test_sockmap_skb_verdict_peek_helper(int ma= p) char snd[256] =3D "0123456789"; char rcv[256] =3D "0"; =20 - err =3D create_pair(AF_INET, SOCK_STREAM, &c1, &p1); + err =3D create_pair_proto(AF_INET, SOCK_STREAM, + mptcp ? IPPROTO_MPTCP : 0, &c1, &p1); if (!ASSERT_OK(err, "create_pair()")) return; =20 @@ -1362,7 +1370,7 @@ static void test_sockmap_no_verdict_fionread(void) test_sockmap_pass_prog__destroy(skel); } =20 -void test_sockmap_basic(void) +static void run_basic_tests(void) { if (test__start_subtest("sockmap create_update_free")) test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKMAP); @@ -1436,6 +1444,15 @@ void test_sockmap_basic(void) test_sockmap_copied_seq(true); if (test__start_subtest("sockmap tcp multi channels")) test_sockmap_multi_channels(SOCK_STREAM); - if (test__start_subtest("sockmap udp multi channels")) + /* UDP is unaffected by MPTCP, only run it once (in tcp mode) */ + if (!mptcp && test__start_subtest("sockmap udp multi channels")) test_sockmap_multi_channels(SOCK_DGRAM); } + +void test_sockmap_basic(void) +{ + for (int i =3D 0; i < 2; i++) { + mptcp =3D i; + run_basic_tests(); + } +} --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 6C53939F168 for ; Sun, 13 Sep 2026 10:15:27 +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=1789294528; cv=none; b=WPylIC/IAyWkO6d2qOSkhKfna6dr/jkRSx7fuUVZ5BJ5S4ZQ+fx01zgZ9t0l+M/pAk+F3XMVi9n2onGeGbW4rtv8qRQKLGf2n34PMOBAtXIzbg+YK9RySvg12mm6RPE5J7hoh/hVIAKcY8gesLfY381VoXa0pmqf6weOSASVFE0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294528; c=relaxed/simple; bh=YCAKtc9Y53WbhN9EpsdfoNSajkqfASwyTG2aFpSRkgo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sOoQVifSIwriYQX5KByzPkVK8nxiUC1ptJ5yRKzPEivvyLLjIVmiv6yY7L1e1MLb62hln4zv9/aoNB0go6tU2ice+iiy9dI5On8ZNsY9ZnY0pxTrpHelOUpLvh0W1Od5THXmEx6hJoBVy1tITymI38BZVAgjxbw++wJc4UWbNGs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ENb89wyp; 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="ENb89wyp" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7F8701F00893; Sun, 13 Sep 2026 10:15:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294527; bh=6i4fNQa/xgVC6yxvV84RgV+u48LDEveAR9LFSEh/+mw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=ENb89wypk5kgxiTswdMiJyoEhS7StVkJyizLAHXfghY2TCIiEvZM5iUCD7L5O3SW8 E2znRKRzPGvu/CJ6IORQU/fT7an/kKIUusUCgkz+A7fqd9NqUwQWaBRYSw9xUFUsAn Mh5+rsGDhDxGkkjJ1y3HUnV5+b45qlIWfORINYbfxZFSVY3z736EMK4q/x15j3IiEL prwoyBVrvNpM2m5Jz8qr9VsD+7dp3i1bVpTgrClegPurdYHgf6c8NpRIuRYPx/a+jI lTRiRoqWlP1JK/yR6F4UJrqACfTH5i0PUupdBEmpC67lAw54WaEhuozljVRsHdD5X5 DMslYrZs/h70w== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 13/16] mptcp: add sk_is_msk() helper and use it in sockmap Date: Sun, 13 Sep 2026 18:14:52 +0800 Message-ID: <29ec7b3fc7febc1c8946add34f859c8253d9714f.1789294365.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 Introduce sk_is_msk() to check whether a socket is an MPTCP socket (IPPROTO_MPTCP on SOCK_STREAM), modeled after sk_is_tcp(). Unlike sk_is_mptcp() which tests a subflow socket, this helper takes an MPTCP parent socket directly. Use it alongside sk_is_tcp() in sock_map.c so that MPTCP sockets are treated the same as TCP sockets for strp linking, redirect checks, state validation and egress redirect in bpf_msg_redirect_{map,hash}. Signed-off-by: Geliang Tang --- include/net/mptcp.h | 12 ++++++++++++ net/core/sock_map.c | 10 +++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/include/net/mptcp.h b/include/net/mptcp.h index 333bde2a0b76..6ab8d3e5e0f8 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -150,6 +150,13 @@ static inline bool rsk_drop_req(const struct request_s= ock *req) return tcp_rsk(req)->is_mptcp && tcp_rsk(req)->drop_req; } =20 +static inline bool sk_is_msk(const struct sock *sk) +{ + return sk_is_inet(sk) && + sk->sk_type =3D=3D SOCK_STREAM && + sk->sk_protocol =3D=3D IPPROTO_MPTCP; +} + void mptcp_space(const struct sock *ssk, int *space, int *full_space); bool mptcp_syn_options(struct sock *sk, const struct sk_buff *skb, unsigned int *size, struct mptcp_out_options *opts); @@ -258,6 +265,11 @@ static inline bool rsk_drop_req(const struct request_s= ock *req) return false; } =20 +static inline bool sk_is_msk(const struct sock *sk) +{ + return false; +} + static inline bool mptcp_syn_options(struct sock *sk, const struct sk_buff= *skb, unsigned int *size, struct mptcp_out_options *opts) diff --git a/net/core/sock_map.c b/net/core/sock_map.c index 3e3e85e3bd54..e9e0b676aa1c 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -303,7 +303,7 @@ static int sock_map_link(struct bpf_map *map, struct so= ck *sk) =20 write_lock_bh(&sk->sk_callback_lock); if (stream_parser && stream_verdict && !psock->saved_data_ready) { - if (sk_is_tcp(sk)) + if (sk_is_tcp(sk) || sk_is_msk(sk)) ret =3D sk_psock_init_strp(sk, psock); else ret =3D -EOPNOTSUPP; @@ -527,7 +527,7 @@ static bool sock_map_op_okay(const struct bpf_sock_ops_= kern *ops) =20 static bool sock_map_redirect_allowed(const struct sock *sk) { - if (sk_is_tcp(sk)) + if (sk_is_tcp(sk) || sk_is_msk(sk)) return sk->sk_state !=3D TCP_LISTEN; else return READ_ONCE(sk->sk_state) =3D=3D TCP_ESTABLISHED; @@ -540,7 +540,7 @@ static bool sock_map_sk_is_suitable(const struct sock *= sk) =20 static bool sock_map_sk_state_allowed(const struct sock *sk) { - if (sk_is_tcp(sk)) + if (sk_is_tcp(sk) || sk_is_msk(sk)) return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_LISTEN); if (sk_is_udp(sk)) return sk_hashed(sk); @@ -683,7 +683,7 @@ BPF_CALL_4(bpf_msg_redirect_map, struct sk_msg *, msg, sk =3D __sock_map_lookup_elem(map, key); if (unlikely(!sk || !sock_map_redirect_allowed(sk))) return SK_DROP; - if (!(flags & BPF_F_INGRESS) && !sk_is_tcp(sk)) + if (!(flags & BPF_F_INGRESS) && !(sk_is_tcp(sk) || sk_is_msk(sk))) return SK_DROP; if (sk_is_vsock(sk)) return SK_DROP; @@ -1289,7 +1289,7 @@ BPF_CALL_4(bpf_msg_redirect_hash, struct sk_msg *, ms= g, sk =3D __sock_hash_lookup_elem(map, key); if (unlikely(!sk || !sock_map_redirect_allowed(sk))) return SK_DROP; - if (!(flags & BPF_F_INGRESS) && !sk_is_tcp(sk)) + if (!(flags & BPF_F_INGRESS) && !(sk_is_tcp(sk) || sk_is_msk(sk))) return SK_DROP; if (sk_is_vsock(sk)) return SK_DROP; --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 A8623356754 for ; Sun, 13 Sep 2026 10:15:28 +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=1789294529; cv=none; b=OIu1b+6C5b0r4HLv2HVJlQdFFKg4QSIi0DiF57TxaOjzD/iaTfP1kGLlSH44gGQyXHpMfxpbj/OHLeCedTAm/qK2Zkw7g4MH/SephNY9P/FogdhKJsDpOi0nl4JqSWx7TIISFIVnJUe83vmoPgV/2zOrgIuGK7op0eu/UzBC5hg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294529; c=relaxed/simple; bh=jjqtykYGtXXv6+EvzDwNfY8QyD5HhYlzWFJHkxaSSxE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ew1px8n93jTOSIxRmgnnknvFXt2m6jPsK6dRfAmip021DODFWosj/onll1kq/9zl5imOUjtxnnRgKr2NoNhPwVUvH9NtqEx1B/PwXguoQgcdQUOTbewzOuK3n47DueOrZafXmc73BRKa68JRnIrawc2FjoUO6bceEXyy7T0xWA4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MuiISwdi; 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="MuiISwdi" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B74DB1F000FF; Sun, 13 Sep 2026 10:15:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294528; bh=ayBL6lZs1xweCV6e2FL/UZlwP0pu/Rx0XOYDCx9CWUY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=MuiISwdi+Qgrq/Vv570lv9lk/OiyzhzIjD5VDJOShQklECxDCk7QH2AiOcsYe5j1G kSKcZmOF4YkmeCYkUAoCFwTFPAPXuFU1RruHw/Au4rmjEfFZWYtfy3R8UFo19tpxj9 3wHz45uf/AN5wH/bf7b6TM4n+yMTW9g2wNIYyMI6zBKlDJ2UKHnFPgU7SlX9/SUSlj wFz8OawNqL9v0iIinkdZ3I8+pu5MqPllEViDBEdUGAhBQNAeA/Jkt+WfkUXWyLizY6 aGklqZoHA3W10CKw2e60EHUWUEmQcQTO4wguUU1d0JJsg3bgUhb/mN45ByTdpNWWy/ diBPMnofsXv9A== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 14/16] mptcp: add SO_ATTACH_REUSEPORT_EBPF support Date: Sun, 13 Sep 2026 18:14:53 +0800 Message-ID: <89f683b22bcd2e0ade93fe16108444ea1aee0e52.1789294365.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 MPTCP support for SO_ATTACH_REUSEPORT_EBPF and SO_DETACH_REUSEPORT_BPF socket options by forwarding them to the first subflow via sk_setsockopt(). This enables MPTCP listener sockets to use reuseport BPF programs, which is required for sockmap reuseport integration. Signed-off-by: Geliang Tang --- net/mptcp/sockopt.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index d2d1c9d1ed1d..e740207f05ce 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -338,6 +338,18 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_so= ck *msk, int optname, } release_sock(sk); return ret; + case SO_ATTACH_REUSEPORT_EBPF: + case SO_DETACH_REUSEPORT_BPF: + lock_sock(sk); + ssk =3D __mptcp_nmpc_sk(msk); + if (IS_ERR(ssk)) { + release_sock(sk); + return PTR_ERR(ssk); + } + + ret =3D sk_setsockopt(ssk, SOL_SOCKET, optname, optval, optlen); + release_sock(sk); + return ret; case SO_KEEPALIVE: case SO_PRIORITY: case SO_SNDBUF: @@ -385,12 +397,9 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_so= ck *msk, int optname, =20 /* SO_OOBINLINE is not supported, let's avoid the related mess * SO_ATTACH_FILTER, SO_ATTACH_BPF, SO_ATTACH_REUSEPORT_CBPF, - * SO_DETACH_REUSEPORT_BPF, SO_DETACH_FILTER, SO_LOCK_FILTER, + * SO_DETACH_FILTER, SO_LOCK_FILTER, * we must be careful with subflows * - * SO_ATTACH_REUSEPORT_EBPF is not supported, at it checks - * explicitly the sk_protocol field - * * SO_PEEK_OFF is unsupported, as it is for plain TCP * SO_MAX_PACING_RATE is unsupported, we must be careful with subflows * SO_CNX_ADVICE is currently unsupported, could possibly be relevant, --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 CEDBA232395 for ; Sun, 13 Sep 2026 10:15:29 +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=1789294531; cv=none; b=TR52SwGdqmLvjlvclWWogMCN/gJciJdhUJCaISyGLO8N48vSGwvLV462GDSI4daJZyeyOquAygGtNDpy+EhEHC1BCvpwF8cmH3B3wwcYflyhdb0fc2xtFsfPHnVjPuJ3gapoKcnqY05o0IQK6zZChgnHuAHrfAwf9ST2Foc9cVg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294531; c=relaxed/simple; bh=W9HGCG3ybaj9jWkMrMSfDjEK5CWytb8aKSuWxwhQGBs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Y51rQjaOi8uYyUfTrnPUMcWnlT7dAeAT2pJRYWHdngiHoDYNW23XajoihKL7SDzXuSCcSZbOqlNhTrFezlUS/3u/q58kJlOSHDIB0HxSdmysI8h+0sv8SmIy5dFvBdT5m70pzAvTcvZbAGVOduubqaJiHmvTNy+02KawKuQ9eQg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AJRscfNp; 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="AJRscfNp" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EF11D1F00893; Sun, 13 Sep 2026 10:15:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294529; bh=lY+E/NXB2Mb5QJ8FTBLpZqVD6HSvK2dD7vPaQWVmz7E=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=AJRscfNpVDSAy130lhOoigTeGXRG8XsGRLnLWI9oTtubmABZmGGhaQJHhHWKpLwow wTvdU1vJvuE2iqCCWUyRKDpKNFcEMiBqLE7p7L0RW2RBznNUTzRV8lcnPOAxeZ0MJM LP3dKr7XbedqUbURMuyI5x3c2aFKiI/PwTgVgvKOT+OnoE7bBlwDqnnD4lHDzYXtMK AzZZ7QOqy+U2xOT7r9soPlFwNuJs3kYahmOBXwMM39YDGBXm4ybIkBmQb4c9w7PSpK jwF8fN/608xB2fTgETv9SR0pg9t2nEFl4nnc76teura+Im3SipL6UWDP6H5li9l0ca RtyCx2iMim3kg== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 15/16] mptcp: add sk_select_reuseport BPF helper Date: Sun, 13 Sep 2026 18:14:54 +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 Add an MPTCP-aware variant of bpf_sk_select_reuseport() (helper id 213). When the map contains an MPTCP parent socket, it resolves to the first subflow (msk->first) before selecting it for reuseport dispatch. Refactor sk_select_reuseport() to extract the core selection logic into sk_select_reuseport_lookup(), which is reused by the MPTCP variant. Register the helper for both sock_ops and sk_reuseport BPF program types with corresponding verifier compatibility checks. Signed-off-by: Geliang Tang --- include/linux/bpf.h | 6 ++++++ include/uapi/linux/bpf.h | 9 +++++++++ kernel/bpf/verifier.c | 6 +++++- net/core/filter.c | 42 +++++++++++++++++++++++++++++++++------- net/mptcp/bpf.c | 22 +++++++++++++++++++++ 5 files changed, 77 insertions(+), 8 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index ecb53a7ad0e8..00061ef54d57 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -4026,8 +4026,14 @@ u32 bpf_xdp_sock_convert_ctx_access(enum bpf_access_= type type, int sock_map_update_common(struct bpf_map *map, u32 idx, struct sock *sk, u64 flags); =20 +int sk_select_reuseport_lookup(struct sk_reuseport_kern *reuse_kern, + struct sock *selected_sk, + struct bpf_map *map); + #ifdef CONFIG_MPTCP u64 mptcp_sock_map_update(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); + +u64 mptcp_sk_select_reuseport(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); #endif #else static inline bool bpf_tcp_sock_is_valid_access(int off, int size, diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 41eecb8622ac..b44450a3e7ae 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -6007,6 +6007,14 @@ union bpf_attr { * it into the *map*. * Return * 0 on success, or a negative error in case of failure. + * + * long bpf_mptcp_sk_select_reuseport(struct sk_reuseport_md *reuse, struc= t bpf_map *map, void *key, u64 flags) + * Description + * MPTCP-aware variant of **bpf_sk_select_reuseport**\ (). + * When the *map* contains an MPTCP parent socket, it + * resolves to the first subflow before selecting it. + * Return + * 0 on success, or a negative error in case of failure. */ #define ___BPF_FUNC_MAPPER(FN, ctx...) \ FN(unspec, 0, ##ctx) \ @@ -6222,6 +6230,7 @@ union bpf_attr { FN(cgrp_storage_get, 210, ##ctx) \ FN(cgrp_storage_delete, 211, ##ctx) \ FN(mptcp_sock_map_update, 212, ##ctx) \ + FN(mptcp_sk_select_reuseport, 213, ##ctx) \ /* This helper list is effectively frozen. If you are trying to \ * add a new helper, you should add a kfunc instead which has \ * less stability guarantees. See Documentation/bpf/kfuncs.rst \ diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c58c2ba87d26..33a36afd0eaf 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -9067,6 +9067,7 @@ static int check_map_func_compatibility(struct bpf_ve= rifier_env *env, func_id !=3D BPF_FUNC_sk_select_reuseport && func_id !=3D BPF_FUNC_map_lookup_elem && func_id !=3D BPF_FUNC_mptcp_sock_map_update && + func_id !=3D BPF_FUNC_mptcp_sk_select_reuseport && !may_update_sockmap(env, func_id)) goto error; break; @@ -9077,11 +9078,13 @@ static int check_map_func_compatibility(struct bpf_= verifier_env *env, func_id !=3D BPF_FUNC_sk_select_reuseport && func_id !=3D BPF_FUNC_map_lookup_elem && func_id !=3D BPF_FUNC_mptcp_sock_map_update && + func_id !=3D BPF_FUNC_mptcp_sk_select_reuseport && !may_update_sockmap(env, func_id)) goto error; break; case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY: - if (func_id !=3D BPF_FUNC_sk_select_reuseport) + if (func_id !=3D BPF_FUNC_sk_select_reuseport && + func_id !=3D BPF_FUNC_mptcp_sk_select_reuseport) goto error; break; case BPF_MAP_TYPE_QUEUE: @@ -9191,6 +9194,7 @@ static int check_map_func_compatibility(struct bpf_ve= rifier_env *env, goto error; break; case BPF_FUNC_sk_select_reuseport: + case BPF_FUNC_mptcp_sk_select_reuseport: if (map->map_type !=3D BPF_MAP_TYPE_REUSEPORT_SOCKARRAY && map->map_type !=3D BPF_MAP_TYPE_SOCKMAP && map->map_type !=3D BPF_MAP_TYPE_SOCKHASH) diff --git a/net/core/filter.c b/net/core/filter.c index 0b4fec5a8848..f1415ff42a51 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -8832,6 +8832,7 @@ const struct bpf_func_proto bpf_sock_hash_update_prot= o __weak; =20 #if IS_ENABLED(CONFIG_MPTCP) static const struct bpf_func_proto mptcp_sock_map_update_proto; +static const struct bpf_func_proto mptcp_sk_select_reuseport_proto; #endif =20 static const struct bpf_func_proto * @@ -8857,6 +8858,8 @@ sock_ops_func_proto(enum bpf_func_id func_id, const s= truct bpf_prog *prog) #if IS_ENABLED(CONFIG_MPTCP) case BPF_FUNC_mptcp_sock_map_update: return &mptcp_sock_map_update_proto; + case BPF_FUNC_mptcp_sk_select_reuseport: + return &mptcp_sk_select_reuseport_proto; #endif case BPF_FUNC_get_socket_cookie: return &bpf_get_socket_cookie_sock_ops_proto; @@ -11738,15 +11741,14 @@ struct sock *bpf_run_sk_reuseport(struct sock_reu= seport *reuse, struct sock *sk, return ERR_PTR(-ECONNREFUSED); } =20 -BPF_CALL_4(sk_select_reuseport, struct sk_reuseport_kern *, reuse_kern, - struct bpf_map *, map, void *, key, u32, flags) +int sk_select_reuseport_lookup(struct sk_reuseport_kern *reuse_kern, + struct sock *selected_sk, + struct bpf_map *map) { bool is_sockarray =3D map->map_type =3D=3D BPF_MAP_TYPE_REUSEPORT_SOCKARR= AY; struct sock_reuseport *reuse; - struct sock *selected_sk; int err; =20 - selected_sk =3D map->ops->map_lookup_elem(map, key); if (!selected_sk) return -ENOENT; =20 @@ -11781,10 +11783,20 @@ BPF_CALL_4(sk_select_reuseport, struct sk_reusepo= rt_kern *, reuse_kern, =20 return 0; error: - /* Lookup in sock_map can return TCP ESTABLISHED sockets. */ - if (sk_is_refcounted(selected_sk)) - sock_put(selected_sk); + return err; +} +EXPORT_SYMBOL(sk_select_reuseport_lookup); + +BPF_CALL_4(sk_select_reuseport, struct sk_reuseport_kern *, reuse_kern, + struct bpf_map *, map, void *, key, u32, flags) +{ + struct sock *selected_sk; + int err; =20 + selected_sk =3D map->ops->map_lookup_elem(map, key); + err =3D sk_select_reuseport_lookup(reuse_kern, selected_sk, map); + if (unlikely(err) && selected_sk && sk_is_refcounted(selected_sk)) + sock_put(selected_sk); return err; } =20 @@ -11798,6 +11810,7 @@ static const struct bpf_func_proto sk_select_reusep= ort_proto =3D { .arg4_type =3D ARG_ANYTHING, }; =20 +#if IS_ENABLED(CONFIG_MPTCP) static const struct bpf_func_proto mptcp_sock_map_update_proto =3D { .func =3D mptcp_sock_map_update, .gpl_only =3D false, @@ -11808,6 +11821,17 @@ static const struct bpf_func_proto mptcp_sock_map_= update_proto =3D { .arg4_type =3D ARG_ANYTHING, }; =20 +static const struct bpf_func_proto mptcp_sk_select_reuseport_proto =3D { + .func =3D mptcp_sk_select_reuseport, + .gpl_only =3D true, + .ret_type =3D RET_INTEGER, + .arg1_type =3D ARG_PTR_TO_CTX, + .arg2_type =3D ARG_CONST_MAP_PTR, + .arg3_type =3D ARG_PTR_TO_MAP_KEY, + .arg4_type =3D ARG_ANYTHING, +}; +#endif + BPF_CALL_4(sk_reuseport_load_bytes, const struct sk_reuseport_kern *, reuse_kern, u32, offset, void *, to, u32, len) @@ -11851,6 +11875,10 @@ sk_reuseport_func_proto(enum bpf_func_id func_id, switch (func_id) { case BPF_FUNC_sk_select_reuseport: return &sk_select_reuseport_proto; +#if IS_ENABLED(CONFIG_MPTCP) + case BPF_FUNC_mptcp_sk_select_reuseport: + return &mptcp_sk_select_reuseport_proto; +#endif case BPF_FUNC_skb_load_bytes: return &sk_reuseport_load_bytes_proto; case BPF_FUNC_skb_load_bytes_relative: diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c index f6fd610f7077..fe10c5ed28f0 100644 --- a/net/mptcp/bpf.c +++ b/net/mptcp/bpf.c @@ -511,3 +511,25 @@ BPF_CALL_4(mptcp_sock_map_update, struct bpf_sock_ops_= kern *, sops, return sock_map_update_common(map, *(u32 *)key, sk, flags); } EXPORT_SYMBOL_GPL(mptcp_sock_map_update); + +BPF_CALL_4(mptcp_sk_select_reuseport, struct sk_reuseport_kern *, reuse_ke= rn, + struct bpf_map *, map, void *, key, u32, flags) +{ + struct sock *sk, *selected_sk; + + sk =3D map->ops->map_lookup_elem(map, key); + if (!sk) + return -ENOENT; + + selected_sk =3D READ_ONCE(mptcp_sk(sk)->first); + if (!selected_sk) { + if (sk_is_refcounted(sk)) + sock_put(sk); + return -ENOENT; + } + + if (sk_is_refcounted(sk)) + sock_put(sk); + return sk_select_reuseport_lookup(reuse_kern, selected_sk, map); +} +EXPORT_SYMBOL_GPL(mptcp_sk_select_reuseport); --=20 2.53.0 From nobody Sat Sep 26 12:28:31 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 72C9B3BD653 for ; Sun, 13 Sep 2026 10:15:31 +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=1789294533; cv=none; b=T2K8IswOOge9CtCwj3WqREKHMgucjcHl/NhH48R6p5ivaBm5k9BuDarRvlH4Gb30Bm5hM8NvTKs0yoACYriV107lkuJCNJ4n9EC855xb4guyljqxIW6zIDFuoHa9CcYeUCptiVOJMqFi3rgpdKb4CzKfeZ84lBeqFxjsn9NQGVw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789294533; c=relaxed/simple; bh=HVEnPnnpumA9OCH93A5gRXcOnQOVHzetAtq0gickHJA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DWnzlumbOF0iML2c8XSGQL3U3ZgJthaHUTscg0uond0T2n5ZOuVA8R4FLPYUUj66BBckk/+hzMxZgb/hkcIjelertkZwjmoyXBcUagAgiY6jrzSKnz1YbGE9gQpffolM7cQjKpnlEPgsByysHJkNfaBQ6YImdP8YhyHsWwWMbRE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=jyk+9kO/; 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="jyk+9kO/" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 32E201F000FF; Sun, 13 Sep 2026 10:15:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789294531; bh=UjFuTpymvaVQtQhikpqbeQUg+od0VtOhW5da+fyqNb0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=jyk+9kO/yb++B6D/6HnbECqv7hngh22zB5oBBSL0Jd5ocrC6NaGw+sihdaj3x51fK Ws/uCNNLWGrbqhBWccgs+r5HnKQBhMXFpmj9UjxUOuCs/ZbW++FS6S2pJa+ZdDJulJ tXigsQzRWKlDtVlZ+HMdQ+m5u2FfB6fmIE571kHauAF1z7gxzhOQ+C/KjkU+3aE5wF FF4XxEWCa9xU9G3Ejjs+L2amAJIs24lF/TxyTvVg4n84Z/KCVW8aj+RSzo6hH3UGND KNATgZyeBm7+J9thN2U7KgCZcjX56myXLjd1GP+IjOzn8yupoN7uoNxU9D/UpodZnz Q3eAaHXRytCRw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v5 16/16] selftests/bpf: add MPTCP coverage to sockmap_listen Date: Sun, 13 Sep 2026 18:14:55 +0800 Message-ID: <3857608bd79abf9079a7bebd3d589194bb6433ff.1789294365.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 Extend sockmap_listen tests to cover MPTCP sockets. Run the full test suite (ops, redir, reuseport) in both TCP and MPTCP modes, using IPPROTO_MPTCP for stream sockets when in MPTCP mode. Skip UDP-specific tests in MPTCP mode. Add a dedicated BPF reuseport program (prog_reuseport_mptcp) that uses bpf_mptcp_sk_select_reuseport() for MPTCP-aware reuseport selection. Prefix subtest names with the protocol (tcp/mptcp) for clarity. Signed-off-by: Geliang Tang --- .../selftests/bpf/prog_tests/sockmap_listen.c | 122 +++++++++++------- .../selftests/bpf/progs/test_sockmap_listen.c | 25 ++++ 2 files changed, 101 insertions(+), 46 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tool= s/testing/selftests/bpf/prog_tests/sockmap_listen.c index 1c96a3cf4b97..d31f3eb661d6 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c @@ -31,6 +31,10 @@ =20 #define NO_FLAGS 0 =20 +static bool mptcp; +#define SOTYPE_PROTO(st) \ + (mptcp && ((st) & SOCK_STREAM) ? IPPROTO_MPTCP : 0) + static void test_insert_invalid(struct test_sockmap_listen *skel __always_= unused, int family, int sotype, int mapfd) { @@ -56,7 +60,7 @@ static void test_insert_opened(struct test_sockmap_listen= *skel __always_unused, int err, s; u64 value; =20 - s =3D xsocket(family, sotype, 0); + s =3D xsocket(family, sotype, SOTYPE_PROTO(sotype)); if (s =3D=3D -1) return; =20 @@ -79,7 +83,7 @@ static void test_insert_bound(struct test_sockmap_listen = *skel __always_unused, =20 init_addr_loopback(family, &addr, &len); =20 - s =3D xsocket(family, sotype, 0); + s =3D xsocket(family, sotype, SOTYPE_PROTO(sotype)); if (s =3D=3D -1) return; =20 @@ -107,7 +111,7 @@ static void test_insert(struct test_sockmap_listen *ske= l __always_unused, u32 key; int s; =20 - s =3D socket_loopback(family, sotype); + s =3D socket_loopback_proto(family, sotype, SOTYPE_PROTO(sotype)); if (s < 0) return; =20 @@ -124,7 +128,7 @@ static void test_delete_after_insert(struct test_sockma= p_listen *skel __always_u u32 key; int s; =20 - s =3D socket_loopback(family, sotype); + s =3D socket_loopback_proto(family, sotype, SOTYPE_PROTO(sotype)); if (s < 0) return; =20 @@ -142,7 +146,7 @@ static void test_delete_after_close(struct test_sockmap= _listen *skel __always_un u64 value; u32 key; =20 - s =3D socket_loopback(family, sotype); + s =3D socket_loopback_proto(family, sotype, SOTYPE_PROTO(sotype)); if (s < 0) return; =20 @@ -167,7 +171,7 @@ static void test_lookup_after_insert(struct test_sockma= p_listen *skel __always_u u32 key; int s; =20 - s =3D socket_loopback(family, sotype); + s =3D socket_loopback_proto(family, sotype, SOTYPE_PROTO(sotype)); if (s < 0) return; =20 @@ -195,7 +199,7 @@ static void test_lookup_after_delete(struct test_sockma= p_listen *skel __always_u u64 value; u32 key; =20 - s =3D socket_loopback(family, sotype); + s =3D socket_loopback_proto(family, sotype, SOTYPE_PROTO(sotype)); if (s < 0) return; =20 @@ -218,7 +222,7 @@ static void test_lookup_32_bit_value(struct test_sockma= p_listen *skel __always_u u32 key, value32; int err, s; =20 - s =3D socket_loopback(family, sotype); + s =3D socket_loopback_proto(family, sotype, SOTYPE_PROTO(sotype)); if (s < 0) return; =20 @@ -250,11 +254,11 @@ static void test_update_existing(struct test_sockmap_= listen *skel __always_unuse u64 value; u32 key; =20 - s1 =3D socket_loopback(family, sotype); + s1 =3D socket_loopback_proto(family, sotype, SOTYPE_PROTO(sotype)); if (s1 < 0) return; =20 - s2 =3D socket_loopback(family, sotype); + s2 =3D socket_loopback_proto(family, sotype, SOTYPE_PROTO(sotype)); if (s2 < 0) goto close_s1; =20 @@ -280,7 +284,7 @@ static void do_destroy_orphan_child(int family, int sot= ype, int mapfd) u64 value; u32 key; =20 - s =3D socket_loopback(family, sotype); + s =3D socket_loopback_proto(family, sotype, SOTYPE_PROTO(sotype)); if (s < 0) return; =20 @@ -293,7 +297,7 @@ static void do_destroy_orphan_child(int family, int sot= ype, int mapfd) value =3D s; xbpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST); =20 - c =3D xsocket(family, sotype, 0); + c =3D xsocket(family, sotype, SOTYPE_PROTO(sotype)); if (c =3D=3D -1) goto close_srv; =20 @@ -342,7 +346,7 @@ static void test_clone_after_delete(struct test_sockmap= _listen *skel __always_un u64 value; u32 key; =20 - s =3D socket_loopback(family, sotype); + s =3D socket_loopback_proto(family, sotype, SOTYPE_PROTO(sotype)); if (s < 0) return; =20 @@ -356,7 +360,7 @@ static void test_clone_after_delete(struct test_sockmap= _listen *skel __always_un xbpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST); xbpf_map_delete_elem(mapfd, &key); =20 - c =3D xsocket(family, sotype, 0); + c =3D xsocket(family, sotype, SOTYPE_PROTO(sotype)); if (c < 0) goto close_srv; =20 @@ -379,7 +383,8 @@ static void test_accept_after_delete(struct test_sockma= p_listen *skel __always_u socklen_t len; u64 value; =20 - s =3D socket_loopback(family, sotype | SOCK_NONBLOCK); + s =3D socket_loopback_proto(family, sotype | SOCK_NONBLOCK, + SOTYPE_PROTO(sotype)); if (s =3D=3D -1) return; =20 @@ -393,7 +398,7 @@ static void test_accept_after_delete(struct test_sockma= p_listen *skel __always_u if (err) goto close_srv; =20 - c =3D xsocket(family, sotype, 0); + c =3D xsocket(family, sotype, SOTYPE_PROTO(sotype)); if (c =3D=3D -1) goto close_srv; =20 @@ -434,7 +439,8 @@ static void test_accept_before_delete(struct test_sockm= ap_listen *skel __always_ socklen_t len; u64 value; =20 - s =3D socket_loopback(family, sotype | SOCK_NONBLOCK); + s =3D socket_loopback_proto(family, sotype | SOCK_NONBLOCK, + SOTYPE_PROTO(sotype)); if (s =3D=3D -1) return; =20 @@ -448,7 +454,7 @@ static void test_accept_before_delete(struct test_sockm= ap_listen *skel __always_ if (err) goto close_srv; =20 - c =3D xsocket(family, sotype, 0); + c =3D xsocket(family, sotype, SOTYPE_PROTO(sotype)); if (c =3D=3D -1) goto close_srv; =20 @@ -511,7 +517,7 @@ static void *connect_accept_thread(void *arg) for (i =3D 0; i < ctx->nr_iter; i++) { int c, p; =20 - c =3D xsocket(family, socktype, 0); + c =3D xsocket(family, socktype, SOTYPE_PROTO(socktype)); if (c < 0) break; =20 @@ -546,7 +552,8 @@ static void test_syn_recv_insert_delete(struct test_soc= kmap_listen *skel __alway int err, s; u64 value; =20 - s =3D socket_loopback(family, sotype | SOCK_NONBLOCK); + s =3D socket_loopback_proto(family, sotype | SOCK_NONBLOCK, + SOTYPE_PROTO(sotype)); if (s < 0) return; =20 @@ -609,7 +616,7 @@ static void test_race_insert_listen(struct test_sockmap= _listen *skel __always_un int err, s; u64 value; =20 - s =3D xsocket(family, socktype, 0); + s =3D xsocket(family, socktype, SOTYPE_PROTO(socktype)); if (s < 0) return; =20 @@ -795,7 +802,8 @@ static void redir_to_listening(int family, int sotype, = int sock_mapfd, =20 zero_verdict_count(verd_mapfd); =20 - s =3D socket_loopback(family, sotype | SOCK_NONBLOCK); + s =3D socket_loopback_proto(family, sotype | SOCK_NONBLOCK, + SOTYPE_PROTO(sotype)); if (s < 0) return; =20 @@ -804,7 +812,7 @@ static void redir_to_listening(int family, int sotype, = int sock_mapfd, if (err) goto close_srv; =20 - c =3D xsocket(family, sotype, 0); + c =3D xsocket(family, sotype, SOTYPE_PROTO(sotype)); if (c < 0) goto close_srv; err =3D xconnect(c, sockaddr(&addr), len); @@ -984,8 +992,9 @@ static void test_reuseport_select_listening(int family,= int sotype, =20 zero_verdict_count(verd_map); =20 - s =3D socket_loopback_reuseport(family, sotype | SOCK_NONBLOCK, - reuseport_prog); + s =3D socket_loopback_reuseport_proto(family, sotype | SOCK_NONBLOCK, + SOTYPE_PROTO(sotype), + reuseport_prog); if (s < 0) return; =20 @@ -1000,7 +1009,7 @@ static void test_reuseport_select_listening(int famil= y, int sotype, if (err) goto close_srv; =20 - c =3D xsocket(family, sotype, 0); + c =3D xsocket(family, sotype, SOTYPE_PROTO(sotype)); if (c < 0) goto close_srv; err =3D xconnect(c, sockaddr(&addr), len); @@ -1053,7 +1062,9 @@ static void test_reuseport_select_connected(int famil= y, int sotype, =20 zero_verdict_count(verd_map); =20 - s =3D socket_loopback_reuseport(family, sotype, reuseport_prog); + s =3D socket_loopback_reuseport_proto(family, sotype, + SOTYPE_PROTO(sotype), + reuseport_prog); if (s < 0) return; =20 @@ -1069,7 +1080,7 @@ static void test_reuseport_select_connected(int famil= y, int sotype, if (err) goto close_srv; =20 - c0 =3D xsocket(family, sotype, 0); + c0 =3D xsocket(family, sotype, SOTYPE_PROTO(sotype)); if (c0 < 0) goto close_srv; =20 @@ -1082,7 +1093,7 @@ static void test_reuseport_select_connected(int famil= y, int sotype, if (p0 < 0) goto close_cli0; } else { - p0 =3D xsocket(family, sotype, 0); + p0 =3D xsocket(family, sotype, SOTYPE_PROTO(sotype)); if (p0 < 0) goto close_cli0; =20 @@ -1103,7 +1114,7 @@ static void test_reuseport_select_connected(int famil= y, int sotype, if (err) goto close_peer0; =20 - c1 =3D xsocket(family, sotype, 0); + c1 =3D xsocket(family, sotype, SOTYPE_PROTO(sotype)); if (c1 < 0) goto close_peer0; =20 @@ -1158,11 +1169,15 @@ static void test_reuseport_mixed_groups(int family,= int sotype, int sock_map, zero_verdict_count(verd_map); =20 /* Create two listeners, each in its own reuseport group */ - s1 =3D socket_loopback_reuseport(family, sotype, reuseport_prog); + s1 =3D socket_loopback_reuseport_proto(family, sotype, + SOTYPE_PROTO(sotype), + reuseport_prog); if (s1 < 0) return; =20 - s2 =3D socket_loopback_reuseport(family, sotype, reuseport_prog); + s2 =3D socket_loopback_reuseport_proto(family, sotype, + SOTYPE_PROTO(sotype), + reuseport_prog); if (s2 < 0) goto close_srv1; =20 @@ -1176,7 +1191,7 @@ static void test_reuseport_mixed_groups(int family, i= nt sotype, int sock_map, if (err) goto close_srv2; =20 - c =3D xsocket(family, sotype, 0); + c =3D xsocket(family, sotype, SOTYPE_PROTO(sotype)); if (c < 0) goto close_srv2; =20 @@ -1272,7 +1287,7 @@ static const char *sotype_str(int sotype) case SOCK_DGRAM: return "UDP"; case SOCK_STREAM: - return "TCP"; + return mptcp ? "MPTCP" : "TCP"; default: return "unknown"; } @@ -1321,7 +1336,8 @@ static void test_ops(struct test_sockmap_listen *skel= , struct bpf_map *map, map_fd =3D bpf_map__fd(map); =20 for (t =3D tests; t < tests + ARRAY_SIZE(tests); t++) { - snprintf(s, sizeof(s), "%s %s %s %s", map_name, family_name, + snprintf(s, sizeof(s), "%s %s %s %s %s", + mptcp ? "mptcp" : "tcp", map_name, family_name, sotype_name, t->name); =20 if (t->sotype !=3D 0 && t->sotype !=3D sotype) @@ -1359,7 +1375,8 @@ static void test_redir(struct test_sockmap_listen *sk= el, struct bpf_map *map, map_name =3D map_type_str(map); =20 for (t =3D tests; t < tests + ARRAY_SIZE(tests); t++) { - snprintf(s, sizeof(s), "%s %s %s", map_name, family_name, + snprintf(s, sizeof(s), "%s %s %s %s", + mptcp ? "mptcp" : "tcp", map_name, family_name, t->name); =20 if (!test__start_subtest(s)) @@ -1393,10 +1410,15 @@ static void test_reuseport(struct test_sockmap_list= en *skel, =20 socket_map =3D bpf_map__fd(map); verdict_map =3D bpf_map__fd(skel->maps.verdict_map); - reuseport_prog =3D bpf_program__fd(skel->progs.prog_reuseport); + if (mptcp) + reuseport_prog =3D + bpf_program__fd(skel->progs.prog_reuseport_mptcp); + else + reuseport_prog =3D bpf_program__fd(skel->progs.prog_reuseport); =20 for (t =3D tests; t < tests + ARRAY_SIZE(tests); t++) { - snprintf(s, sizeof(s), "%s %s %s %s", map_name, family_name, + snprintf(s, sizeof(s), "%s %s %s %s %s", + mptcp ? "mptcp" : "tcp", map_name, family_name, sotype_name, t->name); =20 if (t->sotype !=3D 0 && t->sotype !=3D sotype) @@ -1413,10 +1435,14 @@ static void run_tests(struct test_sockmap_listen *s= kel, struct bpf_map *map, int family) { test_ops(skel, map, family, SOCK_STREAM); - test_ops(skel, map, family, SOCK_DGRAM); test_redir(skel, map, family, SOCK_STREAM); test_reuseport(skel, map, family, SOCK_STREAM); - test_reuseport(skel, map, family, SOCK_DGRAM); + + /* UDP is unaffected by MPTCP, only run it once (in tcp mode) */ + if (!mptcp) { + test_ops(skel, map, family, SOCK_DGRAM); + test_reuseport(skel, map, family, SOCK_DGRAM); + } } =20 void serial_test_sockmap_listen(void) @@ -1429,13 +1455,17 @@ void serial_test_sockmap_listen(void) return; } =20 - skel->bss->test_sockmap =3D true; - run_tests(skel, skel->maps.sock_map, AF_INET); - run_tests(skel, skel->maps.sock_map, AF_INET6); + for (int i =3D 0; i < 2; i++) { + mptcp =3D i; =20 - skel->bss->test_sockmap =3D false; - run_tests(skel, skel->maps.sock_hash, AF_INET); - run_tests(skel, skel->maps.sock_hash, AF_INET6); + skel->bss->test_sockmap =3D true; + run_tests(skel, skel->maps.sock_map, AF_INET); + run_tests(skel, skel->maps.sock_map, AF_INET6); + + skel->bss->test_sockmap =3D false; + run_tests(skel, skel->maps.sock_hash, AF_INET); + run_tests(skel, skel->maps.sock_hash, AF_INET6); + } =20 test_sockmap_listen__destroy(skel); } diff --git a/tools/testing/selftests/bpf/progs/test_sockmap_listen.c b/tool= s/testing/selftests/bpf/progs/test_sockmap_listen.c index b7250eb9c30c..46e9929ba7c4 100644 --- a/tools/testing/selftests/bpf/progs/test_sockmap_listen.c +++ b/tools/testing/selftests/bpf/progs/test_sockmap_listen.c @@ -7,6 +7,9 @@ =20 #include =20 +static long (*bpf_mptcp_sk_select_reuseport)(struct sk_reuseport_md *, voi= d *, + void *, __u64) =3D (void *)213; + struct { __uint(type, BPF_MAP_TYPE_SOCKMAP); __uint(max_entries, 2); @@ -137,4 +140,26 @@ int prog_reuseport(struct sk_reuseport_md *reuse) return verdict; } =20 +SEC("sk_reuseport") +int prog_reuseport_mptcp(struct sk_reuseport_md *reuse) +{ + unsigned int *count; + int err, verdict; + __u32 zero =3D 0; + + if (test_sockmap) + err =3D bpf_mptcp_sk_select_reuseport(reuse, &sock_map, + &zero, 0); + else + err =3D bpf_mptcp_sk_select_reuseport(reuse, &sock_hash, + &zero, 0); + verdict =3D err ? SK_DROP : SK_PASS; + + count =3D bpf_map_lookup_elem(&verdict_map, &verdict); + if (count) + (*count)++; + + return verdict; +} + char _license[] SEC("license") =3D "GPL"; --=20 2.53.0