From nobody Mon May 25 03:32:20 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E9A3C3148D2 for ; Sat, 9 May 2026 07:49:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312956; cv=none; b=a3yPRq+w4zIZuYmiOMnTWB2snVJPEySelYZNrEwQ/RBQ4zjj/PWo+dJekJImI31vl8cYKEni2BzHaVmex1jBK0gEDJeynyEjDN9+dB0mu6wyqlC97NE1FcZgeKL6yrnG3DaMGIxCMdy/Cg0Uhgyo+iuUYWCb040Jr2wDSYHo9BU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312956; c=relaxed/simple; bh=3VCa83AcpaacCx65vxHhpDCf+g+R7ZQ5GWRpiU2rC1w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=A+ekN2m8AEKicwljCEmrVb6D2Y04+PyTHNbNvoAfl8q3HuZ1P42Ay/TXGhQvhBgyYhaKezhfTf+tym9hXmOw7bPS7raDQmr2i2T3PeoWzraZ9RgIeWAd1n4Cyc6pFaCLhx8T2hpRgIe/Xls9MczHo/OD9RbK2kG4qOfAxoz7nRM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=AgRAkukG; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="AgRAkukG" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778312954; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=jJ8n5T+90W+nWBesYEPr/vtutLq1A528Fq/2kDkYXXg=; b=AgRAkukGyhaQPf9SIeMYJLo1l2f5+EZ6zNiKXxoBXraFpx69dZrYQTPThpchS3xoYGwFpk 5wrKehcLk+4pxfnc5HQ7NfQys4VbGiQRMx08pvKjDlqG2F32yDcVZ9TWCYopdo07Gz3KD2 Cv79uH3KtrQWWujJW65k68Mq082JADE= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-252-_IfQotUXNVOZiW2CSxs5BA-1; Sat, 09 May 2026 03:49:10 -0400 X-MC-Unique: _IfQotUXNVOZiW2CSxs5BA-1 X-Mimecast-MFC-AGG-ID: _IfQotUXNVOZiW2CSxs5BA_1778312949 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 10B8A195608B; Sat, 9 May 2026 07:49:09 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.32.24]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id EC84A18004A3; Sat, 9 May 2026 07:49:07 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Cc: Shardul Bankar Subject: [PATCH mptcp-next 01/12] mptcp: do not drop partial packets Date: Sat, 9 May 2026 09:48:21 +0200 Message-ID: <2a88c5905617e57f9523a7a47c9f4e49e80ec81f.1778312843.git.pabeni@redhat.com> In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: OlZDIguJcW6LvCGkCLBwdAXaSRBVCT1G-o2doQpZgKE_1778312949 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8"; x-default="true" From: Shardul Bankar When a packet arrives with map_seq < ack_seq < end_seq, the beginning of the packet has already been acknowledged but the end contains new data. Currently the entire packet is dropped as "old data," forcing the sender to retransmit. Instead, skip the already-acked bytes by adjusting the skb offset and enqueue only the new portion. Update bytes_received and ack_seq to reflect the new data consumed. A previous attempt at this fix (commit 1d2ce718811a ("mptcp: do not drop partial packets"), reverted in commit bf39160c4218 ("Revert "mptcp: do not drop partial packets"")) also added a zero-window check and changed rcv_wnd_sent initialization, which caused test regressions. This version addresses only the partial packet handling without modifying receive window accounting. Fixes: ab174ad8ef76 ("mptcp: move ooo skbs into msk out of order queue.") Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/600 Signed-off-by: Shardul Bankar [pabeni@redhat.com: update map] Signed-off-by: Paolo Abeni --- v2 -> v3: - update map_seq, too v2: https://lore.kernel.org/mptcp/20260422143931.43281-1-shardul.b@mpiricso= ftware.com/ Note: - this introduces some code duplication. will be cleaned-up in later patches --- net/mptcp/protocol.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 93e7a42fc65c..ce8372fb3c6a 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -397,12 +397,26 @@ static bool __mptcp_move_skb(struct sock *sk, struct = sk_buff *skb) return false; } =20 - /* old data, keep it simple and drop the whole pkt, sender - * will retransmit as needed, if needed. + /* Completely old data? */ + if (!after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) { + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); + mptcp_drop(sk, skb); + return false; + } + + /* Partial packet: map_seq < ack_seq < end_seq. + * Skip the already-acked bytes and enqueue the new data. */ - MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); - mptcp_drop(sk, skb); - return false; + copy_len =3D MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq; + MPTCP_SKB_CB(skb)->offset +=3D msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; + MPTCP_SKB_CB(skb)->map_seq +=3D msk->ack_seq - + MPTCP_SKB_CB(skb)->map_seq; + msk->bytes_received +=3D copy_len; + WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len); + + skb_set_owner_r(skb, sk); + __skb_queue_tail(&sk->sk_receive_queue, skb); + return true; } =20 static void mptcp_stop_rtx_timer(struct sock *sk) --=20 2.54.0 From nobody Mon May 25 03:32:20 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1D7EF23ED5B for ; Sat, 9 May 2026 07:49:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312955; cv=none; b=EAV5HPjLEpvdN0g/W6U4RzySaa2AszD8TTiGD3Yn8IUp2F5Cz6/arNT2DLxlYC2ONm6ZRJM/unxu1wWe5mm3sddof71gx6RVOr9/09tlNd2uOGV/BW13sexBPpeJ3NX/XSAR9HT6HwUVShsCKu3x6/1LBHzQqh4sNReKAtZH9QQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312955; c=relaxed/simple; bh=lur4HQqPw7hF0oJSkWuC2N7C+JkQ7kRlcYSBHpoXtME=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=ba9hFHGGfk78I2b7z3WT1YWSy50BlB9w02EuqMcvNmgXEhQtsZIGIAOsIKr2TGymIyLHZlu3xjpL5oP/7U9pRGq7S4dZ5yAt8j83MKMxNCBGFhHn9EsLO8mK6HgY0t5X8mXHHqPYC2Em6Zs7iRJ7W4eFGM7ssCCUdAmfI737a10= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Crlj5/nx; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Crlj5/nx" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778312953; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=k+yR1Dud48WDg7YYavWvbc7vkPJ3+jR+QX6+uxUtBXk=; b=Crlj5/nxZ6HrIr0uHLw95cSr2+N6/sube+pXmzWljRvbFbFib98Q4rYdS0rKil2b49a+sE aofy8ehW7OW8mDW2wU5A5uzHBRAYeyF7+e0gIW95gRDgFdl8ZRPriuB7pMaf5Oefn7367r Eoa4DjULiITvhDnGDtA40k+mIg9hR4Y= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-353-z8qs8l3qPP6EpXLZxxuEuw-1; Sat, 09 May 2026 03:49:11 -0400 X-MC-Unique: z8qs8l3qPP6EpXLZxxuEuw-1 X-Mimecast-MFC-AGG-ID: z8qs8l3qPP6EpXLZxxuEuw_1778312950 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 93953180035D; Sat, 9 May 2026 07:49:10 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.32.24]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9098318004A3; Sat, 9 May 2026 07:49:09 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Cc: Shardul Bankar Subject: [PATCH mptcp-next 02/12] mptcp: explicitly drop over memory limits Date: Sat, 9 May 2026 09:48:22 +0200 Message-ID: In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: Sc5wXcNmOQJYq4I30mqueiZ9nmTWlhN2xyUUwH1Yv1k_1778312950 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8"; x-default="true" Currently the enforcement of the rcvbuf constraint is implemented when moving the skbs into the msk receive or OoO queue, keeping the incoming skbs in the subflow queue when over limit. Under significant memory pressure the above can cause permanent data transfer stalls. Hard enforce the memory limits as early as possible, before landing even in the subflow queues, and refine the check when owning the msk socket lock. Note that fallback socket must not drop on the later checks, as the incoming skb is already acked, and such drop would break the stream. Signed-off-by: Paolo Abeni --- v3 -> v4: - schedule TCP ack on drop - enforce limits in __mptcp_move_skb() and __mptcp_add_backlog(), too but only if not fallback. v1 -> v2: - deal correctly with tcp fin and zero win probe RFC -> v1: - limit vs actual buffer size - use CB info instead of skb->len Note that: - this needs the follow-up patches to really fix the stall - sashiko can assume ZWP carries unacked data and may be silently dropped. AFAIK that is false. - the memory comparison is intentionally very rough, as the msk socket lock is not currently held where the condition is now enforced. This should require some refinement, shared as-is to avoid more latency on my side --- net/mptcp/options.c | 31 +++++++++++++++++++++++++++++-- net/mptcp/protocol.c | 29 +++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 4cc583fdc7a9..19c0bc92f04e 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -1158,8 +1158,29 @@ static bool add_addr_hmac_valid(struct mptcp_sock *m= sk, return hmac =3D=3D mp_opt->ahmac; } =20 -/* Return false in case of error (or subflow has been reset), - * else return true. +static bool mptcp_over_limit(struct sock *sk, struct sock *ssk, + const struct sk_buff *skb) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + + if (likely(sk_rmem_alloc_get(sk) + READ_ONCE(msk->backlog_len) <=3D + READ_ONCE(sk->sk_rcvbuf))) + return false; + + /* Avoid silently dropping pure acks, fin or zero win probes. */ + if (TCP_SKB_CB(skb)->seq =3D=3D TCP_SKB_CB(skb)->end_seq || + TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN || + !after(TCP_SKB_CB(skb)->end_seq, tcp_sk(ssk)->rcv_nxt)) + return false; + + /* Dropped due to memory constraints, schedule an ack. */ + inet_csk(ssk)->icsk_ack.pending |=3D ICSK_ACK_NOMEM | ICSK_ACK_NOW; + inet_csk_schedule_ack(ssk); + return true; +} + +/* Return false when the caller must drop the packet, i.e. in case of erro= r, + * subflow has been reset, or over memory limits. */ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) { @@ -1185,6 +1206,9 @@ bool mptcp_incoming_options(struct sock *sk, struct s= k_buff *skb) =20 __mptcp_data_acked(subflow->conn); mptcp_data_unlock(subflow->conn); + + if (mptcp_over_limit(subflow->conn, sk, skb)) + return false; return true; } =20 @@ -1263,6 +1287,9 @@ bool mptcp_incoming_options(struct sock *sk, struct s= k_buff *skb) return true; } =20 + if (mptcp_over_limit(subflow->conn, sk, skb)) + return false; + mpext =3D skb_ext_add(skb, SKB_EXT_MPTCP); if (!mpext) return false; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index ce8372fb3c6a..492ee9ca9c77 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -381,6 +381,15 @@ static bool __mptcp_move_skb(struct sock *sk, struct s= k_buff *skb) =20 mptcp_borrow_fwdmem(sk, skb); =20 + /* Can't drop packets for fallback socket this late, or the stream + * will break. + */ + if (unlikely(sk_rmem_alloc_get(sk) > READ_ONCE(sk->sk_rcvbuf)) && + !__mptcp_check_fallback(msk)) { + mptcp_drop(sk, skb); + return false; + } + if (MPTCP_SKB_CB(skb)->map_seq =3D=3D msk->ack_seq) { /* in sequence */ msk->bytes_received +=3D copy_len; @@ -675,6 +684,7 @@ static void __mptcp_add_backlog(struct sock *sk, struct sk_buff *tail =3D NULL; struct sock *ssk =3D skb->sk; bool fragstolen; + u64 limit; int delta; =20 if (unlikely(sk->sk_state =3D=3D TCP_CLOSE)) { @@ -682,6 +692,15 @@ static void __mptcp_add_backlog(struct sock *sk, return; } =20 + /* Similar additional allowance as plain TCP. */ + limit =3D READ_ONCE(sk->sk_rcvbuf); + limit +=3D (limit >> 1) + 64 * 1024; + limit =3D min_t(u64, limit, UINT_MAX); + if (msk->backlog_len > limit && !__mptcp_check_fallback(msk)) { + kfree_skb_reason(skb, SKB_DROP_REASON_SOCKET_RCVBUFF); + return; + } + /* Try to coalesce with the last skb in our backlog */ if (!list_empty(&msk->backlog_list)) tail =3D list_last_entry(&msk->backlog_list, struct sk_buff, list); @@ -753,7 +772,7 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp= _sock *msk, =20 mptcp_init_skb(ssk, skb, offset, len); =20 - if (own_msk && sk_rmem_alloc_get(sk) < sk->sk_rcvbuf) { + if (own_msk) { mptcp_subflow_lend_fwdmem(subflow, skb); ret |=3D __mptcp_move_skb(sk, skb); } else { @@ -2211,10 +2230,6 @@ static bool __mptcp_move_skbs(struct sock *sk, struc= t list_head *skbs, u32 *delt =20 *delta =3D 0; while (1) { - /* If the msk recvbuf is full stop, don't drop */ - if (sk_rmem_alloc_get(sk) > sk->sk_rcvbuf) - break; - prefetch(skb->next); list_del(&skb->list); *delta +=3D skb->truesize; @@ -2242,9 +2257,7 @@ static bool mptcp_can_spool_backlog(struct sock *sk, = struct list_head *skbs) DEBUG_NET_WARN_ON_ONCE(msk->backlog_unaccounted && sk->sk_socket && mem_cgroup_from_sk(sk)); =20 - /* Don't spool the backlog if the rcvbuf is full. */ - if (list_empty(&msk->backlog_list) || - sk_rmem_alloc_get(sk) > sk->sk_rcvbuf) + if (list_empty(&msk->backlog_list)) return false; =20 INIT_LIST_HEAD(skbs); --=20 2.54.0 From nobody Mon May 25 03:32:20 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8474637AA98 for ; Sat, 9 May 2026 07:49:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312956; cv=none; b=KoACy6d48yaQOmJ9qnVR6CxJJUvkOw+PvR3bDT66kpUuYlncW79MPtP4VsD16rAi9FukWwxZRRcRs75fkdsVLQzTCNMb3JDtf00sZRqfX9c609xyTiKnCa+jVQmkyWylsRmFSMP0cY4DlllyZzNY7xXeNL4Dt5i4NcicwY+7aHs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312956; c=relaxed/simple; bh=7MaERAeqcKTrEv10JN7EF2hxQUhjahhaOgEknPsDsfY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=HKLokiXxFbKO2ny6mRax5pGGuERUfXNqkVyEYze95TxcAzpZMB5nvGr9EWTsWh9y0aKkthINrgLxK1Sufj/YGd7LPy65B9TlJpZb2rMxq+6fIe4LmsH9hzseg8PkPfb8Cfp/PEWQJSy93ZCZ4bCx+qvh4gImvf6ruPvgn6Jq4K8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=LY2SMUl2; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="LY2SMUl2" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778312954; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=B5Ed9P4jg0pggi3U+CHHwzBkVTw9luG4n8YLRCogm08=; b=LY2SMUl2pve7jYGj3lA/ddeN3mhpo9TRocYuXI7Ywvsrd9BX1U2iVy3+kSgnvegd4erMW9 CxsRagsRJj/qgq/RI/C7Rghw5QUqN4BXqBGERFZC4KYPqI7zWGy9p6ReKCux/ebSi3moj9 Dhsd1P6rN+RUQcl3t521blLkNem3WpI= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-592-XDsXA-BTNRmM4DKQ-J_44Q-1; Sat, 09 May 2026 03:49:13 -0400 X-MC-Unique: XDsXA-BTNRmM4DKQ-J_44Q-1 X-Mimecast-MFC-AGG-ID: XDsXA-BTNRmM4DKQ-J_44Q_1778312952 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 24A0819560BB; Sat, 9 May 2026 07:49:12 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.32.24]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 10C7318001EF; Sat, 9 May 2026 07:49:10 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Cc: Shardul Bankar Subject: [PATCH mptcp-next 03/12] mptcp: enforce hard limit on backlog flushing Date: Sat, 9 May 2026 09:48:23 +0200 Message-ID: <1b843778da0a0f5bab3833f5129c29993f70f126.1778312843.git.pabeni@redhat.com> In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 7AFcRzItdsEDGEY2NGcg4BCEfznhz47fhjDiTxcUoho_1778312952 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8"; x-default="true" Currently a wild producer could keep the backlog flushing operation spinning for an unbound time. Since the previous patch the amount of data present in the backlog is hard-limited. Move the backlog len update at the end of the flush loop to prevent it spinning forever. Also, no need to splice back the remaining skbs list into the backlog, as such list is always empty after each backlog processing loop. Signed-off-by: Paolo Abeni --- net/mptcp/protocol.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 492ee9ca9c77..b329d1dc4161 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2228,7 +2228,6 @@ static bool __mptcp_move_skbs(struct sock *sk, struct= list_head *skbs, u32 *delt struct mptcp_sock *msk =3D mptcp_sk(sk); bool moved =3D false; =20 - *delta =3D 0; while (1) { prefetch(skb->next); list_del(&skb->list); @@ -2265,20 +2264,12 @@ static bool mptcp_can_spool_backlog(struct sock *sk= , struct list_head *skbs) return true; } =20 -static void mptcp_backlog_spooled(struct sock *sk, u32 moved, - struct list_head *skbs) -{ - struct mptcp_sock *msk =3D mptcp_sk(sk); - - WRITE_ONCE(msk->backlog_len, msk->backlog_len - moved); - list_splice(skbs, &msk->backlog_list); -} - static bool mptcp_move_skbs(struct sock *sk) { + struct mptcp_sock *msk =3D mptcp_sk(sk); struct list_head skbs; bool enqueued =3D false; - u32 moved; + u32 moved =3D 0; =20 mptcp_data_lock(sk); while (mptcp_can_spool_backlog(sk, &skbs)) { @@ -2286,8 +2277,8 @@ static bool mptcp_move_skbs(struct sock *sk) enqueued |=3D __mptcp_move_skbs(sk, &skbs, &moved); =20 mptcp_data_lock(sk); - mptcp_backlog_spooled(sk, moved, &skbs); } + WRITE_ONCE(msk->backlog_len, msk->backlog_len - moved); mptcp_data_unlock(sk); return enqueued; } @@ -3670,12 +3661,12 @@ static void mptcp_release_cb(struct sock *sk) __must_hold(&sk->sk_lock.slock) { struct mptcp_sock *msk =3D mptcp_sk(sk); + u32 moved =3D 0; =20 for (;;) { unsigned long flags =3D (msk->cb_flags & MPTCP_FLAGS_PROCESS_CTX_NEED); struct list_head join_list, skbs; bool spool_bl; - u32 moved; =20 spool_bl =3D mptcp_can_spool_backlog(sk, &skbs); if (!flags && !spool_bl) @@ -3708,9 +3699,9 @@ static void mptcp_release_cb(struct sock *sk) =20 cond_resched(); spin_lock_bh(&sk->sk_lock.slock); - if (spool_bl) - mptcp_backlog_spooled(sk, moved, &skbs); } + if (moved) + WRITE_ONCE(msk->backlog_len, msk->backlog_len - moved); =20 if (__test_and_clear_bit(MPTCP_CLEAN_UNA, &msk->cb_flags)) __mptcp_clean_una_wakeup(sk); --=20 2.54.0 From nobody Mon May 25 03:32:20 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D0749381AFC for ; Sat, 9 May 2026 07:49:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312958; cv=none; b=ZmaM7hleHYqF+7PCwvFaoUeXsRUxUCdFCyHL+znVvuhtZiyfPO/IAhibC4bV0kp7BYK1PED5iuaSGUq+NqfzlePYR8lk99UZlU19e5HJB2qdxwihd6RyaX+5bWtF1OndvQd3npTxyghv6U4YQ3BFKlS379jLfkByQoxxNRKShM8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312958; c=relaxed/simple; bh=bCqkzhgOX9C8yOXbNgN/gyMTUEQPAUS30/DqVTi4Cy4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=s2FSotT3BEQ688F/4se4Hz5o52EjQOip9lq7TgOgqNvthfVuwtvhUWxcAiRtXMmGRnkai1lPXapHStlmwXjs/wCEUiQH1/9tWknVsBofK4Z5qjw/EtRureviMSC/YEPZH7UPzvYAmfbltt341pT54U5CAmD+iDFX30AFK06u8bQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=iJkv9xkz; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="iJkv9xkz" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778312956; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hh5KFny65B6KXUR7vP8XRzftFOydm2RnKa/BKmKg8uE=; b=iJkv9xkz7xIvFVLmEpDswpKN/dLM2/ZZEj6BVaimDt3tPFLjR8NtJKX8qkpNOCfInvPi1c CAM66AwH1kWecVKw7/UciQT8jujQSeL3U/58RC1w1gALZRJTWCW7xj6PmMoXtAOQ9yHNOX jszdMYJjbxk5iTCN0r7xGuguy3XMqPo= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-600-AcbnbxiGM4is5-p2fMZlhQ-1; Sat, 09 May 2026 03:49:14 -0400 X-MC-Unique: AcbnbxiGM4is5-p2fMZlhQ-1 X-Mimecast-MFC-AGG-ID: AcbnbxiGM4is5-p2fMZlhQ_1778312953 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 98D8418005B6; Sat, 9 May 2026 07:49:13 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.32.24]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 8DEE518004A3; Sat, 9 May 2026 07:49:12 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Cc: Shardul Bankar Subject: [PATCH mptcp-next 04/12] mptcp: drop the mptcp_ooo_try_coalesce() helper Date: Sat, 9 May 2026 09:48:24 +0200 Message-ID: In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 7ROxc3uMB9p7Z3li9_bMhYs2tIOnWiYd1UtA5YHpE8Q_1778312953 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8"; x-default="true" It's used to save an additional comparison for in-order skbs, but is also a barrier to remove CB offset. Remove the helper, let __mptcp_try_coalesce() always perform the sequence check and remove duplicate checks from the callers. Signed-off-by: Paolo Abeni --- net/mptcp/protocol.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index b329d1dc4161..479e653ddc0d 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -159,7 +159,8 @@ static bool __mptcp_try_coalesce(struct sock *sk, struc= t sk_buff *to, { int limit =3D READ_ONCE(sk->sk_rcvbuf); =20 - if (unlikely(MPTCP_SKB_CB(to)->cant_coalesce) || + if (MPTCP_SKB_CB(from)->map_seq !=3D MPTCP_SKB_CB(to)->end_seq || + unlikely(MPTCP_SKB_CB(to)->cant_coalesce) || MPTCP_SKB_CB(from)->offset || ((to->len + from->len) > (limit >> 3)) || !skb_try_coalesce(to, from, fragstolen, delta)) @@ -192,15 +193,6 @@ static bool mptcp_try_coalesce(struct sock *sk, struct= sk_buff *to, return true; } =20 -static bool mptcp_ooo_try_coalesce(struct mptcp_sock *msk, struct sk_buff = *to, - struct sk_buff *from) -{ - if (MPTCP_SKB_CB(from)->map_seq !=3D MPTCP_SKB_CB(to)->end_seq) - return false; - - return mptcp_try_coalesce((struct sock *)msk, to, from); -} - /* "inspired" by tcp_rcvbuf_grow(), main difference: * - mptcp does not maintain a msk-level window clamp * - returns true when the receive buffer is actually updated @@ -275,7 +267,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk= , struct sk_buff *skb) /* with 2 subflows, adding at end of ooo queue is quite likely * Use of ooo_last_skb avoids the O(Log(N)) rbtree lookup. */ - if (mptcp_ooo_try_coalesce(msk, msk->ooo_last_skb, skb)) { + if (mptcp_try_coalesce(sk, msk->ooo_last_skb, skb)) { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOMERGE); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOQUEUETAIL); return; @@ -321,7 +313,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk= , struct sk_buff *skb) MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); goto merge_right; } - } else if (mptcp_ooo_try_coalesce(msk, skb1, skb)) { + } else if (mptcp_try_coalesce(sk, skb1, skb)) { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOMERGE); return; } @@ -705,8 +697,7 @@ static void __mptcp_add_backlog(struct sock *sk, if (!list_empty(&msk->backlog_list)) tail =3D list_last_entry(&msk->backlog_list, struct sk_buff, list); =20 - if (tail && MPTCP_SKB_CB(skb)->map_seq =3D=3D MPTCP_SKB_CB(tail)->end_seq= && - ssk =3D=3D tail->sk && + if (tail && ssk =3D=3D tail->sk && __mptcp_try_coalesce(sk, tail, skb, &fragstolen, &delta)) { skb->truesize -=3D delta; kfree_skb_partial(skb, fragstolen); @@ -830,7 +821,7 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) =20 end_seq =3D MPTCP_SKB_CB(skb)->end_seq; tail =3D skb_peek_tail(&sk->sk_receive_queue); - if (!tail || !mptcp_ooo_try_coalesce(msk, tail, skb)) { + if (!tail || !mptcp_try_coalesce(sk, tail, skb)) { int delta =3D msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; =20 /* skip overlapping data, if any */ --=20 2.54.0 From nobody Mon May 25 03:32:20 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2CCB63148D2 for ; Sat, 9 May 2026 07:49:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312962; cv=none; b=fheAPeWBvgRSPEjhuRVztCbqf8ldrQ8aRCbSuCEIhn8c1VULGUXH2Vr+m+Yoof9ZrTzJb/8VgreSwCRex20weQJCdumjKMMkiTb5uP268nWld7tUbdZPga0zl9u3n8sS/yuy5pF0n8/0YfGyPzXzf196tazD6Tu9crCctyx5/AM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312962; c=relaxed/simple; bh=PZlHDjrJPBw3DJi5zeUXn5BFnwYsNUpLFXEA9EaDRDY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=u4v5AWMW62LMykQT7qlNfy06b3tjUePyAAFCVWx4KO8XiN+M2x1FRzEC631iJSqakCmlGEdwXt1s2zne48VEKVMYj1/ZoDqWETgQLRBlCZw89JMnSf+tNoR9BbE+VzNZ8M1G/JQ0HeUdIM0F7AZmRzHnxq+dQpMnqTi3b9WtyAY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=ewEMqxu7; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ewEMqxu7" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778312959; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9vVOU7v1L6UtSoVwp9hG2huP7W/mPR6L8xIFiYJB1RU=; b=ewEMqxu779X8OkAEZpkxdGgUL2boUNnXdBq/3d9ITio47Yy+Ce+/czuKOGsuaR9CnXH8VL NPy1y2NXxmu8ipvWyhVN5w/OFMOD6fQvyGvFuApUKzy0Q8L40IVcwuESuOtvl68UuSM/el E/UWw+xrgBudMmKAoF/+SeHxg2LXJfo= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-636-0xqnjTTjOxSel2OqS8a2Rw-1; Sat, 09 May 2026 03:49:16 -0400 X-MC-Unique: 0xqnjTTjOxSel2OqS8a2Rw-1 X-Mimecast-MFC-AGG-ID: 0xqnjTTjOxSel2OqS8a2Rw_1778312955 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 2740018005B4; Sat, 9 May 2026 07:49:15 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.32.24]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 165BC18004A3; Sat, 9 May 2026 07:49:13 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Cc: Shardul Bankar Subject: [PATCH mptcp-next 05/12] mptcp: drop the cant_coalesce CB field Date: Sat, 9 May 2026 09:48:25 +0200 Message-ID: <3dd1b7277acbd03eb37d5103b6a1cfa68d24f599.1778312843.git.pabeni@redhat.com> In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: sEvhdZK-O37dQzcdrMdNI3WhMv_N8bETJcddCkGtqtc_1778312955 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8"; x-default="true" Such field is used to ensure in-sequence processing in case of fastopen. Instead let's perform synchronization of the fastopen skb sequence when the IASN becomes available with the 3rd ack. When the `cant_coalesce` field has been introduced, commit f03afb3aeb9d ("mptcp: drop __mptcp_fastopen_gen_msk_ackseq()") noted that updating the already queued skb for passive fastopen socket at 3rd ack time would be difficult and race prone. The main point is that such update don't need to be synchronously performed at 3rd ack time, but is sufficient to perform it before the next segment is introduced into the msk. To such extent, add an explicit test in __mptcp_move_skb(). Performance wise this trades a conditional in the fast path - in __mptcp_try_coalesce() - with a similar one in __mptcp_move_skb() and a couple more in slow paths. After this change the user-space will always observe consistent sequence numbers in the receive queue, even in the TFO dummy mapping case. Signed-off-by: Paolo Abeni --- net/mptcp/fastopen.c | 2 +- net/mptcp/protocol.c | 28 ++++++++++++++++++++++++++-- net/mptcp/protocol.h | 4 +++- net/mptcp/subflow.c | 7 +++++++ 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index 082c46c0f50e..c7d5bee8088e 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -48,11 +48,11 @@ void mptcp_fastopen_subflow_synack_set_params(struct mp= tcp_subflow_context *subf MPTCP_SKB_CB(skb)->end_seq =3D 0; MPTCP_SKB_CB(skb)->offset =3D 0; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; - MPTCP_SKB_CB(skb)->cant_coalesce =3D 1; =20 mptcp_data_lock(sk); DEBUG_NET_WARN_ON_ONCE(sock_owned_by_user_nocheck(sk)); =20 + mptcp_sk(sk)->rcvd_dummy_seq =3D true; mptcp_borrow_fwdmem(sk, skb); skb_set_owner_r(skb, sk); __skb_queue_tail(&sk->sk_receive_queue, skb); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 479e653ddc0d..6909586a3090 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -160,7 +160,6 @@ static bool __mptcp_try_coalesce(struct sock *sk, struc= t sk_buff *to, int limit =3D READ_ONCE(sk->sk_rcvbuf); =20 if (MPTCP_SKB_CB(from)->map_seq !=3D MPTCP_SKB_CB(to)->end_seq || - unlikely(MPTCP_SKB_CB(to)->cant_coalesce) || MPTCP_SKB_CB(from)->offset || ((to->len + from->len) > (limit >> 3)) || !skb_try_coalesce(to, from, fragstolen, delta)) @@ -357,7 +356,6 @@ static void mptcp_init_skb(struct sock *ssk, struct sk_= buff *skb, int offset, MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + copy_len; MPTCP_SKB_CB(skb)->offset =3D offset; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; - MPTCP_SKB_CB(skb)->cant_coalesce =3D 0; =20 __skb_unlink(skb, &ssk->sk_receive_queue); =20 @@ -365,6 +363,24 @@ static void mptcp_init_skb(struct sock *ssk, struct sk= _buff *skb, int offset, skb_dst_drop(skb); } =20 +void __mptcp_sync_rcv_sequence(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct sk_buff *skb; + + if (likely(!msk->rcvd_dummy_seq)) + return; + + /* User space can have already received the TFO skb. */ + msk->rcvd_dummy_seq =3D false; + skb =3D skb_peek_tail(&sk->sk_receive_queue); + if (!skb) + return; + + MPTCP_SKB_CB(skb)->map_seq =3D msk->ack_seq - skb->len; + MPTCP_SKB_CB(skb)->end_seq =3D msk->ack_seq; +} + static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) { u64 copy_len =3D MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; @@ -373,6 +389,12 @@ static bool __mptcp_move_skb(struct sock *sk, struct s= k_buff *skb) =20 mptcp_borrow_fwdmem(sk, skb); =20 + /* Be sure to sync the eventual fastopen dummy mapping before any other + * skb lands into the msk. + */ + if (unlikely(msk->rcvd_dummy_seq)) + __mptcp_sync_rcv_sequence(sk); + /* Can't drop packets for fallback socket this late, or the stream * will break. */ @@ -3707,6 +3729,8 @@ static void mptcp_release_cb(struct sock *sk) __mptcp_error_report(sk); if (__test_and_clear_bit(MPTCP_SYNC_SNDBUF, &msk->cb_flags)) __mptcp_sync_sndbuf(sk); + if (__test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) + __mptcp_sync_rcv_sequence(sk); } } =20 diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 661600f8b573..16a1f4531dad 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -124,13 +124,13 @@ #define MPTCP_FLUSH_JOIN_LIST 5 #define MPTCP_SYNC_STATE 6 #define MPTCP_SYNC_SNDBUF 7 +#define MPTCP_SYNC_SEQ 8 =20 struct mptcp_skb_cb { u64 map_seq; u64 end_seq; u32 offset; u8 has_rxtstamp; - u8 cant_coalesce; }; =20 #define MPTCP_SKB_CB(__skb) ((struct mptcp_skb_cb *)&((__skb)->cb[0])) @@ -310,6 +310,7 @@ struct mptcp_sock { u32 token; unsigned long flags; unsigned long cb_flags; + bool rcvd_dummy_seq; bool recovery; /* closing subflow write queue reinjected */ bool can_ack; bool fully_established; @@ -1172,6 +1173,7 @@ void mptcp_event_pm_listener(const struct sock *ssk, enum mptcp_event_type event); bool mptcp_userspace_pm_active(const struct mptcp_sock *msk); =20 +void __mptcp_sync_rcv_sequence(struct sock *sk); void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context= *subflow, struct request_sock *req); int mptcp_pm_genl_fill_addr(struct sk_buff *msg, diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index d562e149606f..5f371bf773f8 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -478,6 +478,8 @@ static void subflow_set_remote_key(struct mptcp_sock *m= sk, struct mptcp_subflow_context *subflow, const struct mptcp_options_received *mp_opt) { + struct sock *sk =3D (struct sock *)msk; + /* active MPC subflow will reach here multiple times: * at subflow_finish_connect() time and at 4th ack time */ @@ -496,6 +498,11 @@ static void subflow_set_remote_key(struct mptcp_sock *= msk, WRITE_ONCE(msk->ack_seq, subflow->iasn); WRITE_ONCE(msk->can_ack, true); atomic64_set(&msk->rcv_wnd_sent, subflow->iasn); + + if (!sock_owned_by_user(sk)) + __mptcp_sync_rcv_sequence(sk); + else + __set_bit(MPTCP_SYNC_SEQ, &msk->cb_flags); } =20 static void mptcp_propagate_state(struct sock *sk, struct sock *ssk, --=20 2.54.0 From nobody Mon May 25 03:32:20 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0161235B63D for ; Sat, 9 May 2026 07:49:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312961; cv=none; b=NzMMzbFMEyjLNuUDGfdqCHm7h6HxuMCyoUAFpl/iGO6uV0wxmgf1kwDO9UKhFD3wiv9QqZ04KT8/Zx9F8Yo0TqsRQwM3qY6Kad4/EUVm1z3dVQbWzd/Bu9b7bom4pITtbf2lij1R7aaj+uPLg8iVb43N7IaSB2PL7XZJihRETqU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312961; c=relaxed/simple; bh=8GkVV7UehmmYE8pkzDJ303W1AsGuwuX2M1NqfqIGqcg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=S5Gv62p3WMEPAPlQ9bilyMwjwTZnkDPTfEHYT4A8l2OeO1ocymPt8GC4KCzWl6uGYxugDMdeOHMd0imiisSku508nBI4BVM6k+hWxVgXpmPvhuD411LmhBbUOD741ToNRQLAI6YXxea17Y746CaVPQiLr47y2xlEqRWky4har5Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=bNRAvA9Z; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="bNRAvA9Z" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778312959; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=SPa/qHxDDBaN3pGsLDvVm7U2XWuhUW+k2BaDVf3GGNY=; b=bNRAvA9Zx7RZXSd4Qf+skR5yRHBu2zjD/YiXtATBjc+C1ytFhO9Mj4D1jVAFBtXQrRqrAK nRGuCxHsK4Nu9ilErE5UhR+gnSHMb1DOtRFekivDqZyY+2mfoKMl6h4EUTDotFjmLFtX3N TJfqHlwrRuWhvEDhQ1KyQeEqEcTZiC0= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-495-LflxGEPdO5qzVJaveramsw-1; Sat, 09 May 2026 03:49:17 -0400 X-MC-Unique: LflxGEPdO5qzVJaveramsw-1 X-Mimecast-MFC-AGG-ID: LflxGEPdO5qzVJaveramsw_1778312956 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9E386180034A; Sat, 9 May 2026 07:49:16 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.32.24]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9C2AB18004A3; Sat, 9 May 2026 07:49:15 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Cc: Shardul Bankar Subject: [PATCH mptcp-next 06/12] mptcp: remove CB offset field Date: Sat, 9 May 2026 09:48:26 +0200 Message-ID: In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: gnU6xZnlJ6_A1fJ21mYrObZk6T3kbozEHEl219D_g6w_1778312956 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8"; x-default="true" Instead, use a new msk-level field to track the bytes already consumed inside each skb, carrying the amount of bytes already copied to user-space, alike what TCP is already doing. The newly introduce `copied_seq` field is always accessed under the msk socket lock, delegating the synchronization with IASN to the msk release CB, when the socket is owned by the user-space at remote key reception time. Such synchronization preserves any partial progress (copy) made on the TFO packet. Note that the explicit synchronization in __mptcp_move_skb() is needed to ensure that the TFO skb in the receive queue got its map_seq synched before the next skb lands into the receive queue when spooling the backlog at mptcp_release_cb() time, as the release CB synchronization will happen later. Prior to this patch, the TFO skb dummy mapping was always ignored, now it affects the `copied_seq` initial update: be sure to extends the sign correctly of such mapping initialization time. Overall this simplify a bit the __mptcp_recvmsg_mskq() and mptcp_inq_hint() code and will also make possible the next patch. Signed-off-by: Paolo Abeni --- v3 -> v4: - fix peek seq race v2 -> v3: - do not use msk->first in release_cb to deal with MPTCP_SYNC_SEQ: subflow->iasn access is (data) racy and msk->first can be null, instead recompute iasn from msk bytes_received and TFO skb len - when updating copied_seq after remote key reception, add iasn to it instead of overwriting, to avoid deleting any partial progress. v1 -> v2: - deal correctly with peek, as usally "inspired" from the correspondent tcp code - update mptcp_inq_hint(), too Notes: - this explicitly relays on "mptcp: do not drop partial packets" to avoid dropping partially consumed packets - sashiko may confuse the 'offset' in mptcp_init_skb for an MPTCP-level one, but it refers to the TCP sequence space. Conclusion out of the that assumptions are wrong. - the data race in mptcp_inq_hint() is real, but pre-existing and can impact only sockopt() output - the other call-sites are race free, as ack_seq updates are serialized by the RX path. Fixing the race for good without sashiko tripping on other similar minor races would require another largish series. Postponed. - sashiko may see a race with `copied_seq` in mptcp_recv_skb(), that is not real: subflow_set_remote_key()/__mptcp_sync_rcv_sequence() has seen the msk owned; if mptcp_data_ready() has seen again the msk owend, the only skb in the receive queue can be the (unsynched) TFO one, with dummy sequence. If mptcp_data_ready() observed msk not owned and queued more skbs, the release_cb() has run and synched `copied_seq` and TFO skb map_seq. --- net/mptcp/fastopen.c | 15 ++++--- net/mptcp/protocol.c | 93 +++++++++++++++++++------------------------- net/mptcp/protocol.h | 8 +++- net/mptcp/subflow.c | 7 +++- 4 files changed, 63 insertions(+), 60 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index c7d5bee8088e..03e605b050f8 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -9,6 +9,7 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context= *subflow, struct request_sock *req) { + struct mptcp_sock *msk; struct sock *sk, *ssk; struct sk_buff *skb; struct tcp_sock *tp; @@ -43,20 +44,24 @@ void mptcp_fastopen_subflow_synack_set_params(struct mp= tcp_subflow_context *subf subflow->ssn_offset +=3D skb->len; has_rxtstamp =3D TCP_SKB_CB(skb)->has_rxtstamp; =20 - /* Only the sequence delta is relevant */ - MPTCP_SKB_CB(skb)->map_seq =3D -skb->len; + /* The TFO segment data sits before the IASN; before receiving + * the remote key, IASN is assumed being 0. + */ + MPTCP_SKB_CB(skb)->map_seq =3D -(u64)skb->len; MPTCP_SKB_CB(skb)->end_seq =3D 0; - MPTCP_SKB_CB(skb)->offset =3D 0; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; =20 mptcp_data_lock(sk); DEBUG_NET_WARN_ON_ONCE(sock_owned_by_user_nocheck(sk)); =20 - mptcp_sk(sk)->rcvd_dummy_seq =3D true; + msk =3D mptcp_sk(sk); + msk->rcvd_dummy_seq =3D true; + msk->copied_seq =3D MPTCP_SKB_CB(skb)->map_seq; + msk->tfo_skb_len =3D skb->len; mptcp_borrow_fwdmem(sk, skb); skb_set_owner_r(skb, sk); __skb_queue_tail(&sk->sk_receive_queue, skb); - mptcp_sk(sk)->bytes_received +=3D skb->len; + msk->bytes_received +=3D skb->len; =20 sk->sk_data_ready(sk); =20 diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 6909586a3090..87df66a682c9 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -160,7 +160,6 @@ static bool __mptcp_try_coalesce(struct sock *sk, struc= t sk_buff *to, int limit =3D READ_ONCE(sk->sk_rcvbuf); =20 if (MPTCP_SKB_CB(from)->map_seq !=3D MPTCP_SKB_CB(to)->end_seq || - MPTCP_SKB_CB(from)->offset || ((to->len + from->len) > (limit >> 3)) || !skb_try_coalesce(to, from, fragstolen, delta)) return false; @@ -342,8 +341,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk= , struct sk_buff *skb) skb_set_owner_r(skb, sk); } =20 -static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int offs= et, - int copy_len) +static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int offs= et) { struct mptcp_subflow_context *subflow =3D mptcp_subflow_ctx(ssk); bool has_rxtstamp =3D TCP_SKB_CB(skb)->has_rxtstamp; @@ -352,9 +350,9 @@ static void mptcp_init_skb(struct sock *ssk, struct sk_= buff *skb, int offset, * mptcp_subflow_get_mapped_dsn() is based on the current tp->copied_seq * value */ - MPTCP_SKB_CB(skb)->map_seq =3D mptcp_subflow_get_mapped_dsn(subflow); - MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + copy_len; - MPTCP_SKB_CB(skb)->offset =3D offset; + MPTCP_SKB_CB(skb)->map_seq =3D mptcp_subflow_get_mapped_dsn(subflow) - + offset; + MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; =20 __skb_unlink(skb, &ssk->sk_receive_queue); @@ -377,8 +375,8 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) if (!skb) return; =20 - MPTCP_SKB_CB(skb)->map_seq =3D msk->ack_seq - skb->len; - MPTCP_SKB_CB(skb)->end_seq =3D msk->ack_seq; + MPTCP_SKB_CB(skb)->map_seq =3D mptcp_iasn(msk) - skb->len; + MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; } =20 static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) @@ -783,7 +781,7 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp= _sock *msk, if (offset < skb->len) { size_t len =3D skb->len - offset; =20 - mptcp_init_skb(ssk, skb, offset, len); + mptcp_init_skb(ssk, skb, offset); =20 if (own_msk) { mptcp_subflow_lend_fwdmem(subflow, skb); @@ -850,8 +848,6 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) pr_debug("uncoalesced seq=3D%llx ack seq=3D%llx delta=3D%d\n", MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq, delta); - MPTCP_SKB_CB(skb)->offset +=3D delta; - MPTCP_SKB_CB(skb)->map_seq +=3D delta; __skb_queue_tail(&sk->sk_receive_queue, skb); } msk->bytes_received +=3D end_seq - msk->ack_seq; @@ -2095,34 +2091,22 @@ static void mptcp_eat_recv_skb(struct sock *sk, str= uct sk_buff *skb) } =20 static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg, - size_t len, int flags, int copied_total, + size_t len, int flags, u64 *seq, struct scm_timestamping_internal *tss, int *cmsg_flags, struct sk_buff **last) { struct mptcp_sock *msk =3D mptcp_sk(sk); struct sk_buff *skb, *tmp; - int total_data_len =3D 0; int copied =3D 0; =20 skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) { - u32 delta, offset =3D MPTCP_SKB_CB(skb)->offset; - u32 data_len =3D skb->len - offset; - u32 count; + u64 offset =3D *seq - MPTCP_SKB_CB(skb)->map_seq; + u32 count, data_len =3D skb->len - offset; int err; =20 - if (flags & MSG_PEEK) { - /* skip already peeked skbs */ - if (total_data_len + data_len <=3D copied_total) { - total_data_len +=3D data_len; - *last =3D skb; - continue; - } - - /* skip the already peeked data in the current skb */ - delta =3D copied_total - total_data_len; - offset +=3D delta; - data_len -=3D delta; - } + /* Skip the already peeked data. */ + if (offset >=3D skb->len) + continue; =20 count =3D min_t(size_t, len - copied, data_len); if (!(flags & MSG_TRUNC)) { @@ -2140,14 +2124,12 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, st= ruct msghdr *msg, } =20 copied +=3D count; + *seq +=3D count; =20 if (!(flags & MSG_PEEK)) { msk->bytes_consumed +=3D count; - if (count < data_len) { - MPTCP_SKB_CB(skb)->offset +=3D count; - MPTCP_SKB_CB(skb)->map_seq +=3D count; + if (count < data_len) break; - } =20 mptcp_eat_recv_skb(sk, skb); } else { @@ -2299,22 +2281,17 @@ static bool mptcp_move_skbs(struct sock *sk) static unsigned int mptcp_inq_hint(const struct sock *sk) { const struct mptcp_sock *msk =3D mptcp_sk(sk); - const struct sk_buff *skb; - - skb =3D skb_peek(&sk->sk_receive_queue); - if (skb) { - u64 hint_val =3D READ_ONCE(msk->ack_seq) - MPTCP_SKB_CB(skb)->map_seq; + u64 hint_val; =20 - if (hint_val >=3D INT_MAX) - return INT_MAX; + hint_val =3D READ_ONCE(msk->ack_seq) - msk->copied_seq; + if (hint_val >=3D INT_MAX) + return INT_MAX; =20 - return (unsigned int)hint_val; - } - - if (sk->sk_state =3D=3D TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN)) + if (!hint_val && + (sk->sk_state =3D=3D TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN))) return 1; =20 - return 0; + return (unsigned int)hint_val; } =20 static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, @@ -2323,6 +2300,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msgh= dr *msg, size_t len, struct mptcp_sock *msk =3D mptcp_sk(sk); struct scm_timestamping_internal tss; int copied =3D 0, cmsg_flags =3D 0; + u64 peek_seq, *seq; int target; long timeo; =20 @@ -2342,6 +2320,11 @@ static int mptcp_recvmsg(struct sock *sk, struct msg= hdr *msg, size_t len, =20 len =3D min_t(size_t, len, INT_MAX); target =3D sock_rcvlowat(sk, flags & MSG_WAITALL, len); + seq =3D &msk->copied_seq; + if (flags & MSG_PEEK) { + peek_seq =3D msk->copied_seq; + seq =3D &peek_seq; + } =20 if (unlikely(msk->recvmsg_inq)) cmsg_flags =3D MPTCP_CMSG_INQ; @@ -2351,7 +2334,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msgh= dr *msg, size_t len, int err, bytes_read; =20 bytes_read =3D __mptcp_recvmsg_mskq(sk, msg, len - copied, flags, - copied, &tss, &cmsg_flags, + seq, &tss, &cmsg_flags, &last); if (unlikely(bytes_read < 0)) { if (!copied) @@ -2406,6 +2389,10 @@ static int mptcp_recvmsg(struct sock *sk, struct msg= hdr *msg, size_t len, err =3D copied ? : err; goto out_err; } + + /* Recompute peek offset after eventual seq resync. */ + if (flags & MSG_PEEK) + peek_seq =3D msk->copied_seq + copied; } =20 mptcp_cleanup_rbuf(msk, copied); @@ -3500,11 +3487,13 @@ static int mptcp_disconnect(struct sock *sk, int fl= ags) msk->bytes_retrans =3D 0; msk->rcvspace_init =3D 0; msk->fastclosing =3D 0; + msk->tfo_skb_len =3D 0; mptcp_init_rtt_est(msk); =20 /* for fallback's sake */ WRITE_ONCE(msk->ack_seq, 0); atomic64_set(&msk->rcv_wnd_sent, 0); + msk->copied_seq =3D 0; =20 WRITE_ONCE(sk->sk_shutdown, 0); sk_error_report(sk); @@ -3729,8 +3718,10 @@ static void mptcp_release_cb(struct sock *sk) __mptcp_error_report(sk); if (__test_and_clear_bit(MPTCP_SYNC_SNDBUF, &msk->cb_flags)) __mptcp_sync_sndbuf(sk); - if (__test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) + if (__test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) { + msk->copied_seq +=3D mptcp_iasn(msk); __mptcp_sync_rcv_sequence(sk); + } } } =20 @@ -4390,7 +4381,7 @@ static struct sk_buff *mptcp_recv_skb(struct sock *sk= , u32 *off) mptcp_move_skbs(sk); =20 while ((skb =3D skb_peek(&sk->sk_receive_queue)) !=3D NULL) { - offset =3D MPTCP_SKB_CB(skb)->offset; + offset =3D msk->copied_seq - MPTCP_SKB_CB(skb)->map_seq; if (offset < skb->len) { *off =3D offset; return skb; @@ -4432,11 +4423,9 @@ static int __mptcp_read_sock(struct sock *sk, read_d= escriptor_t *desc, copied +=3D count; =20 msk->bytes_consumed +=3D count; - if (count < data_len) { - MPTCP_SKB_CB(skb)->offset +=3D count; - MPTCP_SKB_CB(skb)->map_seq +=3D count; + msk->copied_seq +=3D count; + if (count < data_len) break; - } =20 mptcp_eat_recv_skb(sk, skb); } diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 16a1f4531dad..f3d852e52982 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -129,7 +129,6 @@ struct mptcp_skb_cb { u64 map_seq; u64 end_seq; - u32 offset; u8 has_rxtstamp; }; =20 @@ -289,6 +288,7 @@ struct mptcp_sock { u64 bytes_sent; u64 snd_nxt; u64 bytes_received; + u64 copied_seq; u64 ack_seq; atomic64_t rcv_wnd_sent; u64 rcv_data_fin_seq; @@ -308,6 +308,7 @@ struct mptcp_sock { u32 last_ack_recv; unsigned long timer_ival; u32 token; + u32 tfo_skb_len; unsigned long flags; unsigned long cb_flags; bool rcvd_dummy_seq; @@ -859,6 +860,11 @@ struct sock *mptcp_subflow_get_retrans(struct mptcp_so= ck *msk); int mptcp_sched_get_send(struct mptcp_sock *msk); int mptcp_sched_get_retrans(struct mptcp_sock *msk); =20 +static inline u64 mptcp_iasn(const struct mptcp_sock *msk) +{ + return msk->ack_seq - msk->bytes_received + msk->tfo_skb_len; +} + static inline u64 mptcp_data_avail(const struct mptcp_sock *msk) { return READ_ONCE(msk->bytes_received) - READ_ONCE(msk->bytes_consumed); diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 5f371bf773f8..c8ea876bdd03 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -499,10 +499,13 @@ static void subflow_set_remote_key(struct mptcp_sock = *msk, WRITE_ONCE(msk->can_ack, true); atomic64_set(&msk->rcv_wnd_sent, subflow->iasn); =20 - if (!sock_owned_by_user(sk)) + if (!sock_owned_by_user(sk)) { + /* User space could have already read partially the TFO skb */ + msk->copied_seq +=3D subflow->iasn; __mptcp_sync_rcv_sequence(sk); - else + } else { __set_bit(MPTCP_SYNC_SEQ, &msk->cb_flags); + } } =20 static void mptcp_propagate_state(struct sock *sk, struct sock *ssk, --=20 2.54.0 From nobody Mon May 25 03:32:20 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DFF1923ED5B for ; Sat, 9 May 2026 07:49:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312965; cv=none; b=KPwjMqG2/GCsqTkrW3ePrZvZxOq+ddhA/5nRLR+EuR+waXxE+MTL6fwFdiizyjC09TDJzJ+A5cJO76rqYKSMCJZ0UoXYsGsBupGq9UhVIbm64iTqGXwg3KtQMZMDM/j1CggmNV9xKyr68ECsWbkYtgJoe8KFAz8i/dXxw/LyJxw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312965; c=relaxed/simple; bh=OKowSt75jIrv7MZU6hMgG/xeLnWTFVXjEfNrahFK9nY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=PxurDLbpjE9FwelZ06farj4EutUPDBpnQ6dxJCGmAJOBcJoxAxi5L4mUOo5REcnVEQITQJG2h2ZSvYxqUm4HPpHts+gTfbWDeO99pr08ucuU/GKxegEOTbwcZFD4AG8zbbsyH2i1tgxiccsCERx3vZm+dDVycBxltzWMvOAe8Y4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=QpNxpyqO; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="QpNxpyqO" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778312962; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LEoiiKpaFpBcwSOPtUHAw4svUC/cxtL/toFxqQ2jpMg=; b=QpNxpyqOwiMr+Jb3eVNyZtaEZwo7IjCKxd6OA+r/r94ohlK1434Dt7N7/WT2rAkwl7nwVb yz5hkilfTckwyzsSA1k1fSn3+r9Am1a82t2LSphjB4tXGkwSWTbbRw2VyPXGydKfKifC4l oj22VnsiXv4w1x85DZDaXHhbS88fNto= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-122-u19Us9WsNJy3NPY0Sdr7tg-1; Sat, 09 May 2026 03:49:19 -0400 X-MC-Unique: u19Us9WsNJy3NPY0Sdr7tg-1 X-Mimecast-MFC-AGG-ID: u19Us9WsNJy3NPY0Sdr7tg_1778312958 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 5AFBB1800343; Sat, 9 May 2026 07:49:18 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.32.24]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3FD4818004A3; Sat, 9 May 2026 07:49:16 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Cc: Shardul Bankar Subject: [PATCH mptcp-next 07/12] mptcp: sync mptcp skb cb layout with tcp one Date: Sat, 9 May 2026 09:48:27 +0200 Message-ID: <1e267ae38b704d5c97483073156b044971faeec4.1778312843.git.pabeni@redhat.com> In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 5F84D-9wL2F9cXjXmeCTtdHphve0fejg2L6VoIoUXbQ_1778312958 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8"; x-default="true" The MPTCP protocol uses a significantly different CB layout WRT TCP, as it includes different information and use 64 bits for the sequence numbers. As the msk-level rcvbuf buffer size is limited by the core socket code the INT_MAX; after validating the incoming skb vs the current receive window, we can safely use 32 bits for MPTCP-level sequence number. This allow updating the MPTCP CB layout so that fields with a corresponding TCP-level data use the same area inside the CB itself. Add build time check to ensure the latter invariant. Signed-off-by: Paolo Abeni --- v3 -> v4: - fix wrong check for OoO skb in mptcp_move_skb(). v1 -> v2: - use u64 for admission checks rfc -> v1: - keep `ack_seq` up2date --- net/mptcp/fastopen.c | 6 ++- net/mptcp/protocol.c | 106 +++++++++++++++++++++++-------------------- net/mptcp/protocol.h | 7 ++- 3 files changed, 66 insertions(+), 53 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index 03e605b050f8..a9e90dc14f77 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -47,8 +47,10 @@ void mptcp_fastopen_subflow_synack_set_params(struct mpt= cp_subflow_context *subf /* The TFO segment data sits before the IASN; before receiving * the remote key, IASN is assumed being 0. */ - MPTCP_SKB_CB(skb)->map_seq =3D -(u64)skb->len; + MPTCP_SKB_CB(skb)->map_seq64 =3D -(u64)skb->len; + MPTCP_SKB_CB(skb)->map_seq =3D MPTCP_SKB_CB(skb)->map_seq64; MPTCP_SKB_CB(skb)->end_seq =3D 0; + MPTCP_SKB_CB(skb)->flags =3D 0; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; =20 mptcp_data_lock(sk); @@ -56,7 +58,7 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptc= p_subflow_context *subf =20 msk =3D mptcp_sk(sk); msk->rcvd_dummy_seq =3D true; - msk->copied_seq =3D MPTCP_SKB_CB(skb)->map_seq; + msk->copied_seq =3D MPTCP_SKB_CB(skb)->map_seq64; msk->tfo_skb_len =3D skb->len; mptcp_borrow_fwdmem(sk, skb); skb_set_owner_r(skb, sk); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 87df66a682c9..f03f967d8679 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -164,7 +164,7 @@ static bool __mptcp_try_coalesce(struct sock *sk, struc= t sk_buff *to, !skb_try_coalesce(to, from, fragstolen, delta)) return false; =20 - pr_debug("colesced seq %llx into %llx new len %d new end seq %llx\n", + pr_debug("colesced seq %x into %x new len %d new end seq %x\n", MPTCP_SKB_CB(from)->map_seq, MPTCP_SKB_CB(to)->map_seq, to->len, MPTCP_SKB_CB(from)->end_seq); MPTCP_SKB_CB(to)->end_seq =3D MPTCP_SKB_CB(from)->end_seq; @@ -234,14 +234,18 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *m= sk, struct sk_buff *skb) { struct sock *sk =3D (struct sock *)msk; struct rb_node **p, *parent; - u64 seq, end_seq, max_seq; + u64 end_seq, max_seq; struct sk_buff *skb1; + u32 seq; =20 seq =3D MPTCP_SKB_CB(skb)->map_seq; - end_seq =3D MPTCP_SKB_CB(skb)->end_seq; + end_seq =3D MPTCP_SKB_CB(skb)->map_seq64 + skb->len; max_seq =3D atomic64_read(&msk->rcv_wnd_sent); =20 - pr_debug("msk=3D%p seq=3D%llx limit=3D%llx empty=3D%d\n", msk, seq, max_s= eq, + /* Use the full sequence space to perform the admission checks, to + * protect vs possible wrap-arounds. + */ + pr_debug("msk=3D%p seq=3D%x limit=3D%llx empty=3D%d\n", msk, seq, max_seq, RB_EMPTY_ROOT(&msk->out_of_order_queue)); if (after64(end_seq, max_seq)) { /* out of window */ @@ -272,7 +276,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk= , struct sk_buff *skb) } =20 /* Can avoid an rbtree lookup if we are adding skb after ooo_last_skb */ - if (!before64(seq, MPTCP_SKB_CB(msk->ooo_last_skb)->end_seq)) { + if (!before(seq, MPTCP_SKB_CB(msk->ooo_last_skb)->end_seq)) { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOQUEUETAIL); parent =3D &msk->ooo_last_skb->rbnode; p =3D &parent->rb_right; @@ -284,18 +288,18 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *m= sk, struct sk_buff *skb) while (*p) { parent =3D *p; skb1 =3D rb_to_skb(parent); - if (before64(seq, MPTCP_SKB_CB(skb1)->map_seq)) { + if (before(seq, MPTCP_SKB_CB(skb1)->map_seq)) { p =3D &parent->rb_left; continue; } - if (before64(seq, MPTCP_SKB_CB(skb1)->end_seq)) { - if (!after64(end_seq, MPTCP_SKB_CB(skb1)->end_seq)) { + if (before(seq, MPTCP_SKB_CB(skb1)->end_seq)) { + if (!after(end_seq, MPTCP_SKB_CB(skb1)->end_seq)) { /* All the bits are present. Drop. */ mptcp_drop(sk, skb); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); return; } - if (after64(seq, MPTCP_SKB_CB(skb1)->map_seq)) { + if (after(seq, MPTCP_SKB_CB(skb1)->map_seq)) { /* partial overlap: * | skb | * | skb1 | @@ -326,7 +330,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk= , struct sk_buff *skb) merge_right: /* Remove other segments covered by skb. */ while ((skb1 =3D skb_rb_next(skb)) !=3D NULL) { - if (before64(end_seq, MPTCP_SKB_CB(skb1)->end_seq)) + if (before((u32)end_seq, MPTCP_SKB_CB(skb1)->end_seq)) break; rb_erase(&skb1->rbnode, &msk->out_of_order_queue); mptcp_drop(sk, skb1); @@ -346,13 +350,15 @@ static void mptcp_init_skb(struct sock *ssk, struct s= k_buff *skb, int offset) struct mptcp_subflow_context *subflow =3D mptcp_subflow_ctx(ssk); bool has_rxtstamp =3D TCP_SKB_CB(skb)->has_rxtstamp; =20 - /* the skb map_seq accounts for the skb offset: + /* The skb map_seq accounts for the skb offset: * mptcp_subflow_get_mapped_dsn() is based on the current tp->copied_seq - * value + * value; note that end seq number is only available in 32bits format. */ - MPTCP_SKB_CB(skb)->map_seq =3D mptcp_subflow_get_mapped_dsn(subflow) - - offset; + MPTCP_SKB_CB(skb)->map_seq64 =3D mptcp_subflow_get_mapped_dsn(subflow) - + offset; + MPTCP_SKB_CB(skb)->map_seq =3D (u32)MPTCP_SKB_CB(skb)->map_seq64; MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; + MPTCP_SKB_CB(skb)->flags =3D 0; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; =20 __skb_unlink(skb, &ssk->sk_receive_queue); @@ -375,13 +381,14 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) if (!skb) return; =20 - MPTCP_SKB_CB(skb)->map_seq =3D mptcp_iasn(msk) - skb->len; + MPTCP_SKB_CB(skb)->map_seq64 =3D mptcp_iasn(msk) - skb->len; + MPTCP_SKB_CB(skb)->map_seq =3D (u32)MPTCP_SKB_CB(skb)->map_seq64; MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; } =20 static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) { - u64 copy_len =3D MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; + u32 copy_len =3D MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; struct mptcp_sock *msk =3D mptcp_sk(sk); struct sk_buff *tail; =20 @@ -402,7 +409,8 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk= _buff *skb) return false; } =20 - if (MPTCP_SKB_CB(skb)->map_seq =3D=3D msk->ack_seq) { + if (MPTCP_SKB_CB(skb)->map_seq64 =3D=3D msk->ack_seq) { +add_queue: /* in sequence */ msk->bytes_received +=3D copy_len; WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len); @@ -413,31 +421,19 @@ static bool __mptcp_move_skb(struct sock *sk, struct = sk_buff *skb) skb_set_owner_r(skb, sk); __skb_queue_tail(&sk->sk_receive_queue, skb); return true; - } else if (after64(MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq)) { + } else if (after64(MPTCP_SKB_CB(skb)->map_seq64, msk->ack_seq)) { mptcp_data_queue_ofo(msk, skb); return false; + } else if (after64(MPTCP_SKB_CB(skb)->map_seq64 + skb->len, + msk->ack_seq)) { + /* Partial packet: map_seq < ack_seq < end_seq.*/ + copy_len -=3D (u32)msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; + goto add_queue; } =20 - /* Completely old data? */ - if (!after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) { - MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); - mptcp_drop(sk, skb); - return false; - } - - /* Partial packet: map_seq < ack_seq < end_seq. - * Skip the already-acked bytes and enqueue the new data. - */ - copy_len =3D MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq; - MPTCP_SKB_CB(skb)->offset +=3D msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; - MPTCP_SKB_CB(skb)->map_seq +=3D msk->ack_seq - - MPTCP_SKB_CB(skb)->map_seq; - msk->bytes_received +=3D copy_len; - WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len); - - skb_set_owner_r(skb, sk); - __skb_queue_tail(&sk->sk_receive_queue, skb); - return true; + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); + mptcp_drop(sk, skb); + return false; } =20 static void mptcp_stop_rtx_timer(struct sock *sk) @@ -818,40 +814,40 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) { struct sock *sk =3D (struct sock *)msk; struct sk_buff *skb, *tail; + u32 seq_delta, ack_seq; bool moved =3D false; struct rb_node *p; - u64 end_seq; =20 p =3D rb_first(&msk->out_of_order_queue); pr_debug("msk=3D%p empty=3D%d\n", msk, RB_EMPTY_ROOT(&msk->out_of_order_q= ueue)); while (p) { + ack_seq =3D msk->ack_seq; skb =3D rb_to_skb(p); - if (after64(MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq)) + if (after(MPTCP_SKB_CB(skb)->map_seq, ack_seq)) break; =20 p =3D rb_next(p); rb_erase(&skb->rbnode, &msk->out_of_order_queue); =20 - if (unlikely(!after64(MPTCP_SKB_CB(skb)->end_seq, - msk->ack_seq))) { + if (unlikely(!after(MPTCP_SKB_CB(skb)->end_seq, ack_seq))) { mptcp_drop(sk, skb); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); continue; } =20 - end_seq =3D MPTCP_SKB_CB(skb)->end_seq; + seq_delta =3D MPTCP_SKB_CB(skb)->end_seq - ack_seq; tail =3D skb_peek_tail(&sk->sk_receive_queue); if (!tail || !mptcp_try_coalesce(sk, tail, skb)) { - int delta =3D msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; + int delta =3D ack_seq - MPTCP_SKB_CB(skb)->map_seq; =20 /* skip overlapping data, if any */ - pr_debug("uncoalesced seq=3D%llx ack seq=3D%llx delta=3D%d\n", - MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq, + pr_debug("uncoalesced seq=3D%x ack seq=3D%x delta=3D%d\n", + MPTCP_SKB_CB(skb)->map_seq, ack_seq, delta); __skb_queue_tail(&sk->sk_receive_queue, skb); } - msk->bytes_received +=3D end_seq - msk->ack_seq; - WRITE_ONCE(msk->ack_seq, end_seq); + msk->bytes_received +=3D seq_delta; + WRITE_ONCE(msk->ack_seq, msk->ack_seq + seq_delta); moved =3D true; } return moved; @@ -2100,7 +2096,7 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, stru= ct msghdr *msg, int copied =3D 0; =20 skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) { - u64 offset =3D *seq - MPTCP_SKB_CB(skb)->map_seq; + u32 offset =3D (u32)(*seq) - MPTCP_SKB_CB(skb)->map_seq; u32 count, data_len =3D skb->len - offset; int err; =20 @@ -4630,11 +4626,23 @@ static int mptcp_napi_poll(struct napi_struct *napi= , int budget) return work_done; } =20 +#define CHK_CB_FIELD(mptcp_field, tcp_field) \ + ({ \ + BUILD_BUG_ON(offsetof(struct mptcp_skb_cb, mptcp_field) !=3D \ + offsetof(struct tcp_skb_cb, tcp_field)); \ + BUILD_BUG_ON(offsetofend(struct mptcp_skb_cb, mptcp_field) !=3D \ + offsetofend(struct tcp_skb_cb, tcp_field)); \ + }) + void __init mptcp_proto_init(void) { struct mptcp_delegated_action *delegated; int cpu; =20 + CHK_CB_FIELD(map_seq, seq); + CHK_CB_FIELD(end_seq, end_seq); + CHK_CB_FIELD(flags, tcp_flags); + mptcp_prot.h.hashinfo =3D tcp_prot.h.hashinfo; =20 if (percpu_counter_init(&mptcp_sockets_allocated, 0, GFP_KERNEL)) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index f3d852e52982..6786da97bbc8 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -127,9 +127,12 @@ #define MPTCP_SYNC_SEQ 8 =20 struct mptcp_skb_cb { - u64 map_seq; - u64 end_seq; + u32 map_seq; + u32 end_seq; + u32 unused; + u16 flags; u8 has_rxtstamp; + u64 map_seq64; }; =20 #define MPTCP_SKB_CB(__skb) ((struct mptcp_skb_cb *)&((__skb)->cb[0])) --=20 2.54.0 From nobody Mon May 25 03:32:20 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C9FB535B63D for ; Sat, 9 May 2026 07:49:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312966; cv=none; b=WofFG3quGTQ8kHkesyv895UTRJP5KfgZlBQTTDeu2KbZHdNFACLrK2sY1a6Eiaii9hxi7xoqk3JAnaAyVkb/c27FIW8IH6KdzfuzQr6lvTFC59Y39kfQxLnJyww6e5PrZg/Vul0n42fZXXNTlLYSV1tr4K7UqXyvzmltsjXe+Y8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312966; c=relaxed/simple; bh=UDCaZvRv7gDkJ07pxdE++l8/RAT0pQI3X7NGimeVDM4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=AW2WQP+qsFdz4mGk0XeyU6vWmYnRr7Fm+OeEk3Ctm3lp7GiEILhhmsvrxrO5c6LffvwmwpHWjIFlVxWKxx1lZNdUwFKvMzL+A/AZuUY1VpnTSmHh8HWf9RrBpAWVijA3RIqm9CUcOTCAJJT781OmLzEEZDaUmgi9dI+eiKPhQPc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=RnG8GvwK; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="RnG8GvwK" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778312963; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=t3G+mG30DBLQKs/e9SvtKSYkN3vFkF0C6KztWGvBcDo=; b=RnG8GvwKxENQe4XAkoN4/apW0qTt0VIDowdmouYIzi14Zmnfd6gSRcizNn4lS7ENk0JVE+ 5hpU2xl1v6chMhOnoW5qNHHr+cz5Du3mSAA3r+wpnnc3UkcmP/3wDpOUG/ZehvWf0tcuh9 XGGgrkoy1eVC97vh6fkPjXXQYUWbmqI= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-163-cr7vAh97Nqu7_CqTy7cfRA-1; Sat, 09 May 2026 03:49:20 -0400 X-MC-Unique: cr7vAh97Nqu7_CqTy7cfRA-1 X-Mimecast-MFC-AGG-ID: cr7vAh97Nqu7_CqTy7cfRA_1778312959 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id BA3A61800283; Sat, 9 May 2026 07:49:19 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.32.24]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id BA40F18004A3; Sat, 9 May 2026 07:49:18 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Cc: Shardul Bankar Subject: [PATCH mptcp-next 08/12] tcp: expose the tcp_collapse_ofo_queue() helper to mptcp usage, too Date: Sat, 9 May 2026 09:48:28 +0200 Message-ID: <93f79a5483ee6c3d337be59788c40de7ef836e1e.1778312843.git.pabeni@redhat.com> In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: PsLaJrfHIzt4IxkmcBlZqoOwh0Yw6jpZus4XpvqhIwY_1778312959 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8"; x-default="true" The end goal is to avoid duplicating the quite untrivial strategy at MPTCP level. After the previous patch, the mentioned helpers could process skbs standing in MPTCP-level queues without any CB-related adaptation. The only additional adjustment needed is explicitly providing the OoO queue reference, to cope with different sk layout. Additionally rename the helper to clearly document its hybrid nature and let it return the number of collapsed skbs, to allow proper accounting from the future MPTCP caller. Signed-off-by: Paolo Abeni --- rfc -> v1: - fix arg typo Note: - this will need a significant amount of testing at the TCP level and explicit approval from Eric, which I can't guess if we can hope. --- include/net/tcp.h | 8 +++++++ net/ipv4/tcp_input.c | 54 ++++++++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 3c4e6adb0dbd..b21189858d66 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1838,6 +1838,14 @@ extern void tcp_openreq_init_rwin(struct request_soc= k *req, =20 void tcp_enter_memory_pressure(struct sock *sk); void tcp_leave_memory_pressure(struct sock *sk); +unsigned int xtcp_collapse(struct sock *sk, struct sk_buff_head *list, + struct rb_root *root, struct sk_buff *head, + struct sk_buff *tail, u32 start, u32 end, + u8 scaling_ratio); +unsigned int xtcp_collapse_ofo_queue(struct sock *sk, + struct rb_root *out_of_order_queue, + struct sk_buff **ooo_last_skb, + u8 scaling_ratio); =20 static inline int keepalive_intvl_when(const struct tcp_sock *tp) { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 7995a89bafc9..f3a9cf0a1e6c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5731,16 +5731,22 @@ static struct sk_buff *tcp_collapse_one(struct sock= *sk, struct sk_buff *skb, /* Collapse contiguous sequence of skbs head..tail with * sequence numbers start..end. * + * sk can be either a TCP or an MPTCP socket. + * * If tail is NULL, this means until the end of the queue. * * Segments with FIN/SYN are not collapsed (only because this * simplifies code) + * + * Returns the number of collapsed skbs. */ -static void -tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *r= oot, - struct sk_buff *head, struct sk_buff *tail, u32 start, u32 end) +unsigned int +xtcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *= root, + struct sk_buff *head, struct sk_buff *tail, u32 start, u32 end, + u8 scaling_ratio) { struct sk_buff *skb =3D head, *n; + unsigned int collapsed =3D 0; struct sk_buff_head tmp; bool end_of_skbs; =20 @@ -5756,6 +5762,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *li= st, struct rb_root *root, =20 /* No new bits? It is possible on ofo queue. */ if (!before(start, TCP_SKB_CB(skb)->end_seq)) { + collapsed++; skb =3D tcp_collapse_one(sk, skb, list, root); if (!skb) break; @@ -5768,7 +5775,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *li= st, struct rb_root *root, * overlaps to the next one and mptcp allow collapsing. */ if (!(TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)) && - (tcp_win_from_space(sk, skb->truesize) > skb->len || + (__tcp_win_from_space(scaling_ratio, skb->truesize) > skb->len || before(TCP_SKB_CB(skb)->seq, start))) { end_of_skbs =3D false; break; @@ -5788,7 +5795,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *li= st, struct rb_root *root, if (end_of_skbs || (TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)) || !skb_frags_readable(skb)) - return; + return collapsed; =20 __skb_queue_head_init(&tmp); =20 @@ -5825,6 +5832,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *li= st, struct rb_root *root, start +=3D size; } if (!before(start, TCP_SKB_CB(skb)->end_seq)) { + collapsed++; skb =3D tcp_collapse_one(sk, skb, list, root); if (!skb || skb =3D=3D tail || @@ -5838,23 +5846,27 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *= list, struct rb_root *root, end: skb_queue_walk_safe(&tmp, skb, n) tcp_rbtree_insert(root, skb); + return collapsed; } =20 /* Collapse ofo queue. Algorithm: select contiguous sequence of skbs - * and tcp_collapse() them until all the queue is collapsed. + * and xtcp_collapse() them until all the queue is collapsed. */ -static void tcp_collapse_ofo_queue(struct sock *sk) +unsigned int xtcp_collapse_ofo_queue(struct sock *sk, + struct rb_root *ooo_queue, + struct sk_buff **ooo_last_skb, + u8 scaling_ratio) { - struct tcp_sock *tp =3D tcp_sk(sk); u32 range_truesize, sum_tiny =3D 0; struct sk_buff *skb, *head; + unsigned int collapsed =3D 0; u32 start, end; =20 - skb =3D skb_rb_first(&tp->out_of_order_queue); + skb =3D skb_rb_first(ooo_queue); new_range: if (!skb) { - tp->ooo_last_skb =3D skb_rb_last(&tp->out_of_order_queue); - return; + *ooo_last_skb =3D skb_rb_last(ooo_queue); + return collapsed; } start =3D TCP_SKB_CB(skb)->seq; end =3D TCP_SKB_CB(skb)->end_seq; @@ -5872,12 +5884,13 @@ static void tcp_collapse_ofo_queue(struct sock *sk) /* Do not attempt collapsing tiny skbs */ if (range_truesize !=3D head->truesize || end - start >=3D SKB_WITH_OVERHEAD(PAGE_SIZE)) { - tcp_collapse(sk, NULL, &tp->out_of_order_queue, - head, skb, start, end); + collapsed +=3D xtcp_collapse(sk, NULL, ooo_queue, + head, skb, start, end, + scaling_ratio); } else { sum_tiny +=3D range_truesize; if (sum_tiny > sk->sk_rcvbuf >> 3) - return; + return collapsed; } goto new_range; } @@ -5888,6 +5901,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk) if (after(TCP_SKB_CB(skb)->end_seq, end)) end =3D TCP_SKB_CB(skb)->end_seq; } + return collapsed; } =20 /* @@ -5975,12 +5989,14 @@ static int tcp_prune_queue(struct sock *sk, const s= truct sk_buff *in_skb) if (tcp_can_ingest(sk, in_skb)) return 0; =20 - tcp_collapse_ofo_queue(sk); + xtcp_collapse_ofo_queue(sk, &tp->out_of_order_queue, + &tp->ooo_last_skb, tp->scaling_ratio); if (!skb_queue_empty(&sk->sk_receive_queue)) - tcp_collapse(sk, &sk->sk_receive_queue, NULL, - skb_peek(&sk->sk_receive_queue), - NULL, - tp->copied_seq, tp->rcv_nxt); + xtcp_collapse(sk, &sk->sk_receive_queue, NULL, + skb_peek(&sk->sk_receive_queue), + NULL, + tp->copied_seq, tp->rcv_nxt, + tp->scaling_ratio); =20 if (tcp_can_ingest(sk, in_skb)) return 0; --=20 2.54.0 From nobody Mon May 25 03:32:20 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 722C937AA98 for ; Sat, 9 May 2026 07:49:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312968; cv=none; b=HiaS1bOQx9ZEQUtFowYjKcXlBYSFIqeuKNOXZC0pvi7QtsmPkOJM/6irK57hjmroHhc0oGiS2Am00LTnzUphoZRoYmBL2RBODRyC0axgjYeUBR5hqM22Qe6ibsBbY/kRJWgI2jrRMt+NacCZExnMpo5JxjPqlTavW9pgz6d0RP4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312968; c=relaxed/simple; bh=g15amtVo3sD45psbFPdkeJWrQqY2ebGG/5yLClHvK3M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=q4Dup6TcNCMJQEHFGIyhNSW4+tl8Zx1XWR5raMTui5oAkiQmzutYHrFogn9MKBriKjAxzgSMAEmn5US5mjU4xCUdBauQtzXMDGwmS1zERxo4ji8kVGJuRojyN6eINZadex4pvqqJtn1oVxzri86ytGYvUTYbr7rbqISmB6e7hn8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=dUf7AZqZ; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="dUf7AZqZ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778312965; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=x/egfToxNaYd2WeWloTD+USy3SRE+oESIt6EnJRKBPk=; b=dUf7AZqZbIus595TNIS59X28DOLgiPUhxb2NsDV7DK0OYMK8UtK/T3bn5EEv8vE4HPDFCJ cDc9Q/5Lprt2RvdO+BewaLN1yYZgzxPi5K4nO5m2CFiiWEVh5xpb6dcngOGAos/MmXKMpM D7BNb/bKv1gCwQc/tWtvsCca2hQ5tGg= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-136-k_XiRgoXOai_S6M78g8joA-1; Sat, 09 May 2026 03:49:22 -0400 X-MC-Unique: k_XiRgoXOai_S6M78g8joA-1 X-Mimecast-MFC-AGG-ID: k_XiRgoXOai_S6M78g8joA_1778312961 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 427BE1956061; Sat, 9 May 2026 07:49:21 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.32.24]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3E62318004A3; Sat, 9 May 2026 07:49:20 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Cc: Shardul Bankar Subject: [PATCH mptcp-next 09/12] mptcp: implemented OoO queue pruning Date: Sat, 9 May 2026 09:48:29 +0200 Message-ID: <2f2a0f359e54d949cf90ebb92cc3886693b00bda.1778312843.git.pabeni@redhat.com> In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: CJcAFDwpUb0CbCDdOJf1dAT67DwtuR7pygGSGj0qLPk_1778312961 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8"; x-default="true" Leverage the hybrid helpers to implement the receive queue and OoO queue collapsing at ingress time when reaching memory bounds. If the msk is owned by the user-space at incoming skb time, perform the pruning in the release_cb. The prune check is additionally performed when the skb reaches the msk-level queues. Signed-off-by: Paolo Abeni --- v2 -> v3: - deal with unsynced TFO skb at prune time - only possible when pruning in mptcp_over_limit() v1 -> v2: - collapse rcv queue, too - deal with MPC map, too - drop left-over sentence in the commit message RFC -> v1: - use data_seq only when available - avoid ack_seq lockless access - drop limit on fallback - collapse rcvqueue, too - drop only when pruning is not possible and over rcvbuf * 2 Note: - sashiko can be confused about fwd memory lifecycle (I can understand that :). Any exceeding amount of fwd allocated memory is always released by the next sk_mem_uncharge() - i.e. fwd memory is not tied to the current skb. --- net/mptcp/mib.c | 3 +++ net/mptcp/mib.h | 3 +++ net/mptcp/options.c | 49 +++++++++++++++++++++++++++++----- net/mptcp/protocol.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ net/mptcp/protocol.h | 2 ++ 5 files changed, 112 insertions(+), 7 deletions(-) diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c index f23fda0c55a7..5128feec942c 100644 --- a/net/mptcp/mib.c +++ b/net/mptcp/mib.c @@ -85,6 +85,9 @@ static const struct snmp_mib mptcp_snmp_list[] =3D { SNMP_MIB_ITEM("SimultConnectFallback", MPTCP_MIB_SIMULTCONNFALLBACK), SNMP_MIB_ITEM("FallbackFailed", MPTCP_MIB_FALLBACKFAILED), SNMP_MIB_ITEM("WinProbe", MPTCP_MIB_WINPROBE), + SNMP_MIB_ITEM("OfoPruned", MPTCP_MIB_OFO_PRUNED), + SNMP_MIB_ITEM("RcvPruned", MPTCP_MIB_RCVPRUNED), + SNMP_MIB_ITEM("RcvCollapsed", MPTCP_MIB_RCVCOLLAPSED), }; =20 /* mptcp_mib_alloc - allocate percpu mib counters diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h index 812218b5ed2b..2f8f68e33ac5 100644 --- a/net/mptcp/mib.h +++ b/net/mptcp/mib.h @@ -88,6 +88,9 @@ enum linux_mptcp_mib_field { MPTCP_MIB_SIMULTCONNFALLBACK, /* Simultaneous connect */ MPTCP_MIB_FALLBACKFAILED, /* Can't fallback due to msk status */ MPTCP_MIB_WINPROBE, /* MPTCP-level zero window probe */ + MPTCP_MIB_OFO_PRUNED, /* MPTCP-level OoO queue pruned */ + MPTCP_MIB_RCVPRUNED, /* Dropped due to memory constrains */ + MPTCP_MIB_RCVCOLLAPSED, /* Collapsed due to memory pressure */ __MPTCP_MIB_MAX }; =20 diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 19c0bc92f04e..d7e712171d3b 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -1159,9 +1159,12 @@ static bool add_addr_hmac_valid(struct mptcp_sock *m= sk, } =20 static bool mptcp_over_limit(struct sock *sk, struct sock *ssk, - const struct sk_buff *skb) + const struct sk_buff *skb, + const struct mptcp_options_received *mp_opt) { struct mptcp_sock *msk =3D mptcp_sk(sk); + u64 limit; + bool ret; =20 if (likely(sk_rmem_alloc_get(sk) + READ_ONCE(msk->backlog_len) <=3D READ_ONCE(sk->sk_rcvbuf))) @@ -1173,10 +1176,38 @@ static bool mptcp_over_limit(struct sock *sk, struc= t sock *ssk, !after(TCP_SKB_CB(skb)->end_seq, tcp_sk(ssk)->rcv_nxt)) return false; =20 - /* Dropped due to memory constraints, schedule an ack. */ - inet_csk(ssk)->icsk_ack.pending |=3D ICSK_ACK_NOMEM | ICSK_ACK_NOW; - inet_csk_schedule_ack(ssk); - return true; + mptcp_data_lock(sk); + if (!sock_owned_by_user(sk)) { + /* When the data sequence is not (yet) available for the + * incoming skb, allow pruning the whole OoO queue. + */ + u32 seq =3D (u32)((!mp_opt->use_map || mp_opt->mpc_map) ? + msk->ack_seq : mp_opt->data_seq); + + /* Be sure TFO skb sequence number is in-sync, as the + * TCP pruning helper will be badly fouled otherwise. + */ + if (unlikely(msk->rcvd_dummy_seq)) + __mptcp_sync_rcv_sequence(sk); + + limit =3D sk->sk_rcvbuf; + __mptcp_check_prune(sk, seq); + } else { + /* Pruning will take place later in the RX path, allow + * some extra slack. + */ + limit =3D ((u64)READ_ONCE(sk->sk_rcvbuf)) << 1; + __set_bit(MPTCP_PRUNE, &msk->cb_flags); + } + ret =3D sk_rmem_alloc_get(sk) + msk->backlog_len > limit; + mptcp_data_unlock(sk); + + if (ret) { + /* Dropped due to memory constraints, schedule an ack. */ + inet_csk(ssk)->icsk_ack.pending |=3D ICSK_ACK_NOMEM | ICSK_ACK_NOW; + inet_csk_schedule_ack(ssk); + } + return ret; } =20 /* Return false when the caller must drop the packet, i.e. in case of erro= r, @@ -1207,7 +1238,11 @@ bool mptcp_incoming_options(struct sock *sk, struct = sk_buff *skb) __mptcp_data_acked(subflow->conn); mptcp_data_unlock(subflow->conn); =20 - if (mptcp_over_limit(subflow->conn, sk, skb)) + /* Will use ack_seq as limit for OoO pruning; any value would do + * as OoO queue must be empty. + */ + mp_opt.use_map =3D 0; + if (mptcp_over_limit(subflow->conn, sk, skb, &mp_opt)) return false; return true; } @@ -1287,7 +1322,7 @@ bool mptcp_incoming_options(struct sock *sk, struct s= k_buff *skb) return true; } =20 - if (mptcp_over_limit(subflow->conn, sk, skb)) + if (mptcp_over_limit(subflow->conn, sk, skb, &mp_opt)) return false; =20 mpext =3D skb_ext_add(skb, SKB_EXT_MPTCP); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index f03f967d8679..d9aab7bbff98 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -386,6 +386,64 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; } =20 +/* "Inspired" from the TCP version */ +static void mptcp_prune_ofo_queue(struct sock *sk, u32 seq) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct rb_node *node, *prev; + bool pruned =3D false; + + if (RB_EMPTY_ROOT(&msk->out_of_order_queue)) + return; + + node =3D &msk->ooo_last_skb->rbnode; + + do { + struct sk_buff *skb =3D rb_to_skb(node); + + /* Stop pruning if the incoming skb would land in OoO tail. */ + if (after(seq, MPTCP_SKB_CB(skb)->map_seq)) + break; + + pruned =3D true; + prev =3D rb_prev(node); + rb_erase(node, &msk->out_of_order_queue); + mptcp_drop(sk, skb); + msk->ooo_last_skb =3D rb_to_skb(prev); + if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf) + break; + + node =3D prev; + } while (node); + + if (pruned) + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFO_PRUNED); +} + +bool __mptcp_check_prune(struct sock *sk, u32 seq) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + unsigned int dropped; + + dropped =3D xtcp_collapse_ofo_queue(sk, &msk->out_of_order_queue, + &msk->ooo_last_skb, + msk->scaling_ratio); + if (!skb_queue_empty(&sk->sk_receive_queue)) + dropped +=3D xtcp_collapse(sk, &sk->sk_receive_queue, NULL, + skb_peek(&sk->sk_receive_queue), + NULL, + msk->copied_seq, msk->ack_seq, + msk->scaling_ratio); + + if (dropped) + MPTCP_ADD_STATS(sock_net(sk), MPTCP_MIB_RCVCOLLAPSED, dropped); + if (likely(atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf)) + return false; + + mptcp_prune_ofo_queue(sk, seq); + return atomic_read(&sk->sk_rmem_alloc) >=3D sk->sk_rcvbuf; +} + static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) { u32 copy_len =3D MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; @@ -404,7 +462,9 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk= _buff *skb) * will break. */ if (unlikely(sk_rmem_alloc_get(sk) > READ_ONCE(sk->sk_rcvbuf)) && + __mptcp_check_prune(sk, MPTCP_SKB_CB(skb)->map_seq) && !__mptcp_check_fallback(msk)) { + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED); mptcp_drop(sk, skb); return false; } @@ -3718,6 +3778,8 @@ static void mptcp_release_cb(struct sock *sk) msk->copied_seq +=3D mptcp_iasn(msk); __mptcp_sync_rcv_sequence(sk); } + if (__test_and_clear_bit(MPTCP_PRUNE, &msk->cb_flags)) + __mptcp_check_prune(sk, (u32)(msk->ack_seq - 1)); } } =20 diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 6786da97bbc8..ae019a10e1c8 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -125,6 +125,7 @@ #define MPTCP_SYNC_STATE 6 #define MPTCP_SYNC_SNDBUF 7 #define MPTCP_SYNC_SEQ 8 +#define MPTCP_PRUNE 9 =20 struct mptcp_skb_cb { u32 map_seq; @@ -832,6 +833,7 @@ bool __mptcp_close(struct sock *sk, long timeout); void mptcp_cancel_work(struct sock *sk); void __mptcp_unaccepted_force_close(struct sock *sk); void mptcp_set_state(struct sock *sk, int state); +bool __mptcp_check_prune(struct sock *sk, u32 seq); =20 bool mptcp_addresses_equal(const struct mptcp_addr_info *a, const struct mptcp_addr_info *b, bool use_port); --=20 2.54.0 From nobody Mon May 25 03:32:20 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EE90B23ED5B for ; Sat, 9 May 2026 07:49:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312969; cv=none; b=KofdEz/eeq2bx9bILaxWbOY8JH+98iUHzyg+N+rM2ZfM7bTKQVm2LWc4Vu5OHLF+xuMLq7FTzTQ1r9IsMF+axVCW7UTjpb/cm/T5n2wTJUB1JBTG7w9HXKBczf3v9KKtT1dM6c6kwpHJdMDjDcrq5cw9cGJ0AAYhPukK5JhFX9c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312969; c=relaxed/simple; bh=F3pN08Fp36nClCW6lx91KaZJ/XwbXhanRbzSvrVi9YE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=h1kphcDudKcBj3924hMdCPc/3RHkHh+PVuUlKZqKEUxd70M2RS96aXpeBsKuRbZ4k4ion1y7VMHDCtzjbo79HisHarZF/bXee56GtyEOhRte7ZYmQ+YVC4Uv+251zSXGeXvEcFTcusoDIdzfHrZeHkr/ldSY3svrYbsX2f1C1v0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=HR13F4pY; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="HR13F4pY" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778312966; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9CmJbuDmKQf7CZQ2IlWheYstILBqTCxYB5kKLiKGGag=; b=HR13F4pYiF9xwh8lvLXR0/esDed5e7V1fLxuhVqKefn/nfvTH4HmzvdJFQFwGd5TIOHmeZ KwpxLlJFA3+Ixro83yZHTroPoWj3ocF9KxyZrPXAs7iml03/cUV5lnrfTiKSoUVn25VT0x zl+JJ1R+dN0easXK81UJFKALIwzfJnA= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-125-nq2u0hxVOzm0Hr6EZ-2v2A-1; Sat, 09 May 2026 03:49:23 -0400 X-MC-Unique: nq2u0hxVOzm0Hr6EZ-2v2A-1 X-Mimecast-MFC-AGG-ID: nq2u0hxVOzm0Hr6EZ-2v2A_1778312962 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B9DAC1956088; Sat, 9 May 2026 07:49:22 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.32.24]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id B77E918004A3; Sat, 9 May 2026 07:49:21 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Cc: Shardul Bankar Subject: [PATCH mptcp-next 10/12] mptcp: track prune recovery status Date: Sat, 9 May 2026 09:48:30 +0200 Message-ID: In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: Xv2-E9Lff2-sy9JWZnrIrP-O5Vi_WVpB5oA_4WMz8RU_1778312962 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8"; x-default="true" After dropping any data already acked at the TCP level, the MPTCP must avoid inducing TCP-level retransmission until the pruned data has been successfully acked at MPTCP level. Otherwise the subflows could keep retransmitting skbs carring OoO MPTCP data, preventing reinjections and stalling completely the data transfer. Explicitly keep track of the highest pruned MPTCP-level seq number and stop dropping at TCP level until such sequence has been acked. Signed-off-by: Paolo Abeni --- net/mptcp/options.c | 7 +++++++ net/mptcp/protocol.c | 16 ++++++++++++++-- net/mptcp/protocol.h | 3 +++ net/mptcp/subflow.c | 1 + 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index d7e712171d3b..9b8de027848b 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -1200,6 +1200,13 @@ static bool mptcp_over_limit(struct sock *sk, struct= sock *ssk, __set_bit(MPTCP_PRUNE, &msk->cb_flags); } ret =3D sk_rmem_alloc_get(sk) + msk->backlog_len > limit; + + /* After pruning any packets ensure that MPTCP-driven drops do not + * cause TCP-level retransmission. + */ + if (before((u32)(msk->ack_seq), READ_ONCE(msk->pruned_seq))) + ret =3D false; + mptcp_data_unlock(sk); =20 if (ret) { diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index d9aab7bbff98..7907d82115d0 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -392,12 +392,14 @@ static void mptcp_prune_ofo_queue(struct sock *sk, u3= 2 seq) struct mptcp_sock *msk =3D mptcp_sk(sk); struct rb_node *node, *prev; bool pruned =3D false; + u32 pruned_seq; =20 if (RB_EMPTY_ROOT(&msk->out_of_order_queue)) return; =20 node =3D &msk->ooo_last_skb->rbnode; =20 + pruned_seq =3D msk->pruned_seq; do { struct sk_buff *skb =3D rb_to_skb(node); =20 @@ -408,16 +410,21 @@ static void mptcp_prune_ofo_queue(struct sock *sk, u3= 2 seq) pruned =3D true; prev =3D rb_prev(node); rb_erase(node, &msk->out_of_order_queue); + if (after(MPTCP_SKB_CB(skb)->end_seq, pruned_seq)) + pruned_seq =3D MPTCP_SKB_CB(skb)->end_seq; mptcp_drop(sk, skb); msk->ooo_last_skb =3D rb_to_skb(prev); + if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf) break; =20 node =3D prev; } while (node); =20 - if (pruned) + if (pruned) { + WRITE_ONCE(msk->pruned_seq, pruned_seq); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFO_PRUNED); + } } =20 bool __mptcp_check_prune(struct sock *sk, u32 seq) @@ -464,6 +471,8 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk= _buff *skb) if (unlikely(sk_rmem_alloc_get(sk) > READ_ONCE(sk->sk_rcvbuf)) && __mptcp_check_prune(sk, MPTCP_SKB_CB(skb)->map_seq) && !__mptcp_check_fallback(msk)) { + if (after(MPTCP_SKB_CB(skb)->end_seq, msk->pruned_seq)) + WRITE_ONCE(msk->pruned_seq, MPTCP_SKB_CB(skb)->end_seq); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED); mptcp_drop(sk, skb); return false; @@ -881,7 +890,7 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) p =3D rb_first(&msk->out_of_order_queue); pr_debug("msk=3D%p empty=3D%d\n", msk, RB_EMPTY_ROOT(&msk->out_of_order_q= ueue)); while (p) { - ack_seq =3D msk->ack_seq; + ack_seq =3D (u32)(msk->ack_seq); skb =3D rb_to_skb(p); if (after(MPTCP_SKB_CB(skb)->map_seq, ack_seq)) break; @@ -910,6 +919,8 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) WRITE_ONCE(msk->ack_seq, msk->ack_seq + seq_delta); moved =3D true; } + if (after(msk->ack_seq, msk->pruned_seq)) + WRITE_ONCE(msk->pruned_seq, (u32)msk->ack_seq); return moved; } =20 @@ -3550,6 +3561,7 @@ static int mptcp_disconnect(struct sock *sk, int flag= s) WRITE_ONCE(msk->ack_seq, 0); atomic64_set(&msk->rcv_wnd_sent, 0); msk->copied_seq =3D 0; + WRITE_ONCE(msk->pruned_seq, 0); =20 WRITE_ONCE(sk->sk_shutdown, 0); sk_error_report(sk); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index ae019a10e1c8..70431cde1757 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -307,6 +307,9 @@ struct mptcp_sock { u64 bytes_acked; u64 snd_una; u64 wnd_end; + u32 pruned_seq; /* If strictly above ack_seq, + * the highest seq pruned. + */ u32 last_data_sent; u32 last_data_recv; u32 last_ack_recv; diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index c8ea876bdd03..f35afe64d9cd 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -496,6 +496,7 @@ static void subflow_set_remote_key(struct mptcp_sock *m= sk, =20 WRITE_ONCE(msk->remote_key, subflow->remote_key); WRITE_ONCE(msk->ack_seq, subflow->iasn); + WRITE_ONCE(msk->pruned_seq, subflow->iasn); WRITE_ONCE(msk->can_ack, true); atomic64_set(&msk->rcv_wnd_sent, subflow->iasn); =20 --=20 2.54.0 From nobody Mon May 25 03:32:20 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DD26F23ED5B for ; Sat, 9 May 2026 07:49:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312971; cv=none; b=q2n4V69Yn5+nkb54SrttUj4cwGFnyCrc6VpWPYYbSDsvuJhJ08qzHEDMG0wcPvniuTX5DGUFGNw+KULdSZOfxe4ADdI5pdTKpgc9lTBeYf7nO1PaHaY6/Y1qVuvKkoGBNfSlOnqmkIacl4rtxLwoY3XSifZw9QBHND5wyg3mrEU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312971; c=relaxed/simple; bh=pHYPaHJ9eS629f29H1fHsZMyB3Wq+SYCScWMWE+daaM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=M752nKUZ2nXG1URYCkIsAxykYtVW8uzC46hMVynzAa7OrVTFO7QobbJk5Decc31FUQqnOf+biLTYFQk/X23n84iwbMmXOAxC/75Wn+JZ/I5UmE8gcP5Wzc1hBEP+QZht71LJ4ch9vDZjiEplf9IpLI4TYFkwYc8KkcXUanxWIXA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=UViiH6rz; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="UViiH6rz" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778312969; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=PScvW8zl2Zmq3LghqZQskb4zyG9OUt+MR5eU/r6riAI=; b=UViiH6rzH0pwV7N2DOK8a8UhnXNEe2rzndpbQV5gGO+hulqOwS36TKHyE3qh75wGiv6Hir XXDJHVI/lcJACk+RrUhyxbN8hyFND1DppPPXGSaHYS5u3JD4Jgr9X3+GFhLVVema0X2u+I xUUVJkukv2b/hKwpw0hc2BJFn4a4n/0= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-421-16Y6-lsUNIuq5aH2lcBiXQ-1; Sat, 09 May 2026 03:49:25 -0400 X-MC-Unique: 16Y6-lsUNIuq5aH2lcBiXQ-1 X-Mimecast-MFC-AGG-ID: 16Y6-lsUNIuq5aH2lcBiXQ_1778312964 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 3BB731800371; Sat, 9 May 2026 07:49:24 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.32.24]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3691B18004A3; Sat, 9 May 2026 07:49:22 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Cc: Shardul Bankar Subject: [PATCH mptcp-next 11/12] mptcp: move the retrans loop to a separate helper Date: Sat, 9 May 2026 09:48:31 +0200 Message-ID: In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: M13IqpYncRAKLN9F0qt7bBkUVlMB_qV8IJ7ejdXKC6M_1778312964 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8"; x-default="true" This is a cleanup in order to make the next patch simpler. No functional change intended. Signed-off-by: Paolo Abeni --- net/mptcp/protocol.c | 74 +++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 7907d82115d0..fd4b5eb40383 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2847,41 +2847,14 @@ static void mptcp_check_fastclose(struct mptcp_sock= *msk) sk_error_report(sk); } =20 -static void __mptcp_retrans(struct sock *sk) +/* Retransmit the specified data fragment on all the selected subflows. */ +static int __mptcp_push_retrans(struct sock *sk, struct mptcp_data_frag *d= frag) { struct mptcp_sendmsg_info info =3D { .data_lock_held =3D true, }; struct mptcp_sock *msk =3D mptcp_sk(sk); struct mptcp_subflow_context *subflow; - struct mptcp_data_frag *dfrag; struct sock *ssk; - int ret, err; - u16 len =3D 0; - - mptcp_clean_una_wakeup(sk); - - /* first check ssk: need to kick "stale" logic */ - err =3D mptcp_sched_get_retrans(msk); - dfrag =3D mptcp_rtx_head(sk); - if (!dfrag) { - if (mptcp_data_fin_enabled(msk)) { - struct inet_connection_sock *icsk =3D inet_csk(sk); - - WRITE_ONCE(icsk->icsk_retransmits, - icsk->icsk_retransmits + 1); - mptcp_set_datafin_timeout(sk); - mptcp_send_ack(msk); - - goto reset_timer; - } - - if (!mptcp_send_head(sk)) - goto clear_scheduled; - - goto reset_timer; - } - - if (err) - goto reset_timer; + int ret, len =3D 0; =20 mptcp_for_each_subflow(msk, subflow) { if (READ_ONCE(subflow->scheduled)) { @@ -2909,7 +2882,7 @@ static void __mptcp_retrans(struct sock *sk) !msk->allow_subflows) { spin_unlock_bh(&msk->fallback_lock); release_sock(ssk); - goto clear_scheduled; + return -1; } =20 while (info.sent < info.limit) { @@ -2932,6 +2905,45 @@ static void __mptcp_retrans(struct sock *sk) release_sock(ssk); } } + return len; +} + +static void __mptcp_retrans(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct mptcp_subflow_context *subflow; + struct mptcp_data_frag *dfrag; + int err, len; + + mptcp_clean_una_wakeup(sk); + + /* first check ssk: need to kick "stale" logic */ + err =3D mptcp_sched_get_retrans(msk); + dfrag =3D mptcp_rtx_head(sk); + if (!dfrag) { + if (mptcp_data_fin_enabled(msk)) { + struct inet_connection_sock *icsk =3D inet_csk(sk); + + WRITE_ONCE(icsk->icsk_retransmits, + icsk->icsk_retransmits + 1); + mptcp_set_datafin_timeout(sk); + mptcp_send_ack(msk); + + goto reset_timer; + } + + if (!mptcp_send_head(sk)) + goto clear_scheduled; + + goto reset_timer; + } + + if (err) + goto reset_timer; + + len =3D __mptcp_push_retrans(sk, dfrag); + if (len < 0) + goto clear_scheduled; =20 msk->bytes_retrans +=3D len; dfrag->already_sent =3D max(dfrag->already_sent, len); --=20 2.54.0 From nobody Mon May 25 03:32:20 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8A60D35B63D for ; Sat, 9 May 2026 07:49:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312971; cv=none; b=MEtzcXKOxxcNs6G/9n+v25GCwoAi967BzrPvd8fLkGKCBjDwIw/3aWmORdkOnqWJeobhHFz/fzeTc/cDsihKLQSHbxY0qvSBiTyamUNEn/eTlPpNd3TmWjR9wHuXg7T/xS91XPRakw5A6w7W1aOldnE981uxVNzRtQ37J0ewL9A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778312971; c=relaxed/simple; bh=AuPFjFvnEVi5+DDWRQ6TzJpXahWw7LopJnEYK+Rus6I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=Wl61KLyhKhiUBovvJ/LlUxNzPnWflioAxFS+DXxqhWFapELihT22RZGHB8jSlZSmu1yMYAUSESTbNDZ1W6uhy90CEsOZbF9st5PWjQLFgd12BjGz/baUmd9HiR8hnmqHilrJoqxbB4jGoGDcWzh9vg5uwzal/c0kJ88HSggeDxk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=HmCyw8Or; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="HmCyw8Or" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778312968; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OMkB4UhAE0gUiWxy8sTzjgf8YZZvO6CR+ZulXny0WiQ=; b=HmCyw8OrmvGI9EIWtlCr3PnSk6uuVdOPqlViIel/Qi+3bL7KRvZRW90ZykRgm8ly+kcv7d Jmb6ItSO3EfZHQhF+/j2i/hqu558Yfd4QQRq5QZ7Unn7tfAlHpMGRNUoaCSoyHkp+Iu1vK O9vq3DEbQYipr74OWP0Z8VMIfZz9li4= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-441-XjwICCGgO5KCLUe20fLATg-1; Sat, 09 May 2026 03:49:26 -0400 X-MC-Unique: XjwICCGgO5KCLUe20fLATg-1 X-Mimecast-MFC-AGG-ID: XjwICCGgO5KCLUe20fLATg_1778312965 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B2E271956080; Sat, 9 May 2026 07:49:25 +0000 (UTC) Received: from gerbillo.redhat.com (unknown [10.44.32.24]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id AEB431800374; Sat, 9 May 2026 07:49:24 +0000 (UTC) From: Paolo Abeni To: mptcp@lists.linux.dev Cc: Shardul Bankar Subject: [PATCH mptcp-next 12/12] mptcp: let the retrans scheduler do its job. Date: Sat, 9 May 2026 09:48:32 +0200 Message-ID: <12423a1b9db777fc5326d9e623a5d28bb72fe8b2.1778312843.git.pabeni@redhat.com> In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: yKM4bD6wcpL6aNn-GduZ7W5nF10xlI9gLkrEkCYsGe8_1778312965 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8"; x-default="true" Currently the MPTCP core enforces that when MPTCP-level retrans timer fires, at most a single dfrag is retransmitted. If some corner-cases it may be necessary retransmit multiple dfrags, and the MPTCP socket will need to wait multiple retrans timeout to accomplish that. Remove the mentioned constraint, allowing to transmit multiple dfrags per retrans period, as long as the scheduler keeps selecting subflows for retransmissions and pending data is available in the rtx queue. The default scheduler will transmit a dfrag per available subflow. Signed-off-by: Paolo Abeni --- v3 -> v4: - avoid quadratic behavior, fix retrans_seq update - fix rtx timer re-schedule miss v2 -> v3: - fix infinite loop issue (should address tls tests failures) v1 -> v2: - fix retrans sequence update (sashiko) --- net/mptcp/protocol.c | 104 +++++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 28 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index fd4b5eb40383..067143efdd8e 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1231,13 +1231,6 @@ static void __mptcp_clean_una_wakeup(struct sock *sk) mptcp_write_space(sk); } =20 -static void mptcp_clean_una_wakeup(struct sock *sk) -{ - mptcp_data_lock(sk); - __mptcp_clean_una_wakeup(sk); - mptcp_data_unlock(sk); -} - static void mptcp_enter_memory_pressure(struct sock *sk) { struct mptcp_subflow_context *subflow; @@ -2847,8 +2840,12 @@ static void mptcp_check_fastclose(struct mptcp_sock = *msk) sk_error_report(sk); } =20 -/* Retransmit the specified data fragment on all the selected subflows. */ -static int __mptcp_push_retrans(struct sock *sk, struct mptcp_data_frag *d= frag) +/* + * Retransmit the specified data fragment on all the selected subflows, + * starting from the specified sequence + */ +static int __mptcp_push_retrans(struct sock *sk, struct mptcp_data_frag *d= frag, + u64 sent_seq) { struct mptcp_sendmsg_info info =3D { .data_lock_held =3D true, }; struct mptcp_sock *msk =3D mptcp_sk(sk); @@ -2858,6 +2855,7 @@ static int __mptcp_push_retrans(struct sock *sk, stru= ct mptcp_data_frag *dfrag) =20 mptcp_for_each_subflow(msk, subflow) { if (READ_ONCE(subflow->scheduled)) { + u16 offset =3D sent_seq - dfrag->data_seq; u16 copied =3D 0; =20 mptcp_subflow_set_scheduled(subflow, false); @@ -2867,9 +2865,12 @@ static int __mptcp_push_retrans(struct sock *sk, str= uct mptcp_data_frag *dfrag) lock_sock(ssk); =20 /* limit retransmission to the bytes already sent on some subflows */ - info.sent =3D 0; + info.sent =3D offset; info.limit =3D READ_ONCE(msk->csum_enabled) ? dfrag->data_len : dfrag->already_sent; + DEBUG_NET_WARN_ON_ONCE(!before64(sent_seq, + dfrag->data_seq + + info.limit)); =20 /* * make the whole retrans decision, xmit, disallow @@ -2913,41 +2914,88 @@ static void __mptcp_retrans(struct sock *sk) struct mptcp_sock *msk =3D mptcp_sk(sk); struct mptcp_subflow_context *subflow; struct mptcp_data_frag *dfrag; + bool retransmitted =3D false; + u64 retrans_seq; int err, len; =20 - mptcp_clean_una_wakeup(sk); - - /* first check ssk: need to kick "stale" logic */ - err =3D mptcp_sched_get_retrans(msk); + mptcp_data_lock(sk); + __mptcp_clean_una_wakeup(sk); + retrans_seq =3D msk->snd_una; dfrag =3D mptcp_rtx_head(sk); + mptcp_data_unlock(sk); + if (!dfrag) + goto check_data_fin; + + for (;;) { + bool already_retrans; + + /* The scheduler may clean the RTX queue. */ + get_page(dfrag->page); + + /* The default scheduler will kick "stale" logic. */ + err =3D mptcp_sched_get_retrans(msk); + if (err) { + put_page(dfrag->page); + break; + } + + /* Incoming acks can have moved retrans sequence after + * the current dfrag, if so try to start again from RTX head. + */ + mptcp_data_lock(sk); + already_retrans =3D !dfrag->already_sent || + !before64(msk->snd_una, dfrag->data_seq + + dfrag->already_sent); + put_page(dfrag->page); + if (already_retrans) { + __mptcp_clean_una_wakeup(sk); + retrans_seq =3D msk->snd_una; + dfrag =3D mptcp_rtx_head(sk); + } + mptcp_data_unlock(sk); + if (!dfrag) + break; + + len =3D __mptcp_push_retrans(sk, dfrag, retrans_seq); + if (len < 0) + goto clear_scheduled; + + retransmitted =3D true; + retrans_seq +=3D len; + msk->bytes_retrans +=3D len; + dfrag->already_sent =3D max(dfrag->already_sent, len); + + /* Attempt the next fragment only if the current one is + * completely retransmitted. + */ + if (before64(retrans_seq, dfrag->data_seq + dfrag->data_len)) + break; + + dfrag =3D list_is_last(&dfrag->list, &msk->rtx_queue) ? + NULL : list_next_entry(dfrag, list); + if (!dfrag || !dfrag->already_sent) + break; + } + + /* Data fin retransmission needed only if no data retransmission took + * place, and RTX queue is empty. + */ +check_data_fin: if (!dfrag) { - if (mptcp_data_fin_enabled(msk)) { + if (!retransmitted && mptcp_data_fin_enabled(msk)) { struct inet_connection_sock *icsk =3D inet_csk(sk); =20 WRITE_ONCE(icsk->icsk_retransmits, icsk->icsk_retransmits + 1); mptcp_set_datafin_timeout(sk); mptcp_send_ack(msk); - goto reset_timer; } =20 if (!mptcp_send_head(sk)) goto clear_scheduled; - - goto reset_timer; } =20 - if (err) - goto reset_timer; - - len =3D __mptcp_push_retrans(sk, dfrag); - if (len < 0) - goto clear_scheduled; - - msk->bytes_retrans +=3D len; - dfrag->already_sent =3D max(dfrag->already_sent, len); - reset_timer: mptcp_check_and_set_pending(sk); =20 --=20 2.54.0