From nobody Sat Aug 15 20:33:11 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 55B1742DFF5; Fri, 31 Jul 2026 14:24:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785507888; cv=none; b=aiDr3jN5rMBvcPGX9kWClVBRppiPzIZIzlw7EcAw2m5esLTdCIVOb47teOEih0zNYdhCpFNBVdtviIcxzP+if17VnfseMNsTjSHeo6nZ/E1n6IPK6R6bSkA/C5bWuxQtU849xWBLB5V0dBlYafxXcQqvBkM910sLO75ROP0QiTQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785507888; c=relaxed/simple; bh=++AX/TdTvWwgODLnwbzLSGJMOH0kealvdqqMPU1BGdY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eiQRQsGOxDWOirYSOsHQz2/RtbyuIetEIjn+27ybQRdXf5lLiVYGm1B2LwO8uAIKd/cGSEQc3Pfb0uki9YmCzCTQYyrj+z+z8WLBS9doehVnFFsYvEiY8Vv7Odj4xRpdBiaGzgvxb6Feh6A1VGg5a57eRHkHXZ3BiZCQNFy69LU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Zd6Obkvj; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Zd6Obkvj" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 080681F00A3D; Fri, 31 Jul 2026 14:24:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785507887; bh=xB/FsxzRoiYwJDzNNomLKMj1scIXpQggJ8ZrpM9x+Gs=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=Zd6ObkvjqwR7iNosNxMCeMXkRw2qzeXfgGxKyd1U5XAN3o7Ty+UBEw+k3khc3SzUl 0vzqq2R/fNlwoY7pyd4LiYK1rmrxjpQXPclLebPieuMe1GT5d04mlDnF9iK4T3/syp tF3VvjiDM8N/t0QZxR5jNE8nmD1bIHJyrNJUzuYWAFri1E55rL8Dfi/ZZ6FxUc0ZQI +Y/1iuPr3eQyBXUg2C8iw92pXLrBs21inpbrDRdgTkk1zRjcoRMAL0RZyT3J0neAPC vZt+lOWrJKSg6At3Y0pAu8C2rdSDcRT4EzaVhZos7iPZ5VrLjArE2SuShJTPtqNIoL 3KKvoCDFAfX3A== From: "Matthieu Baerts (NGI0)" Date: Fri, 31 Jul 2026 16:24:17 +0200 Subject: [PATCH net-next v2 1/5] mptcp: move the retrans loop to a separate helper Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260731-net-next-mptcp-oooq-pruning-v2-1-24838164fa21@kernel.org> References: <20260731-net-next-mptcp-oooq-pruning-v2-0-24838164fa21@kernel.org> In-Reply-To: <20260731-net-next-mptcp-oooq-pruning-v2-0-24838164fa21@kernel.org> To: Mat Martineau , Geliang Tang , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman Cc: netdev@vger.kernel.org, mptcp@lists.linux.dev, linux-kernel@vger.kernel.org, "Matthieu Baerts (NGI0)" , Gang Yan X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=3211; i=matttbe@kernel.org; h=from:subject:message-id; bh=roDpodaahk2BWLOIYD/W304v8cqk1FmemTEUD9iezUs=; b=kA0DAAoWfCLwwvNHCpcByyZiAGpssCWgKNYOcIcDXYN0na3GKZb0dvBKW0b7LCNTi4Fxgfm9Z Ih1BAAWCgAdFiEEG4ZZb5nneg10Sk44fCLwwvNHCpcFAmpssCUACgkQfCLwwvNHCpcdNAD/Y+uL 57sS01MmVuLomjx7LP4T5ZJMS8ZYYUN7DLeD0iABAJiVsoy6Qfzs8nInLXkAHY80sqZgSS38ZEU DYcXxIrwD X-Developer-Key: i=matttbe@kernel.org; a=openpgp; fpr=E8CB85F76877057A6E27F77AF6B7824F4269A073 From: Paolo Abeni This is a cleanup in order to make the next patch simpler. No functional change intended. Tested-by: Gang Yan Tested-by: Geliang Tang Acked-by: Geliang Tang Signed-off-by: Paolo Abeni Signed-off-by: Matthieu Baerts (NGI0) --- 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 ca644ec53eed..290d14e2fa5b 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2785,41 +2785,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)) { @@ -2847,7 +2820,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) { @@ -2870,6 +2843,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.53.0 From nobody Sat Aug 15 20:33:11 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B8D0442DFFA; Fri, 31 Jul 2026 14:24:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785507891; cv=none; b=MwCEnnXKrEvxLdfGBRsQ5f6AlwYPMiMn4SEVL2ffbbiKKwBtBzPJuvGBKSKCBgEnPna/DMQTICJgynCTMI4efvskkqyuu27QBoj3t0HF4OHV/Nybk29EIi0jCqHrpN6ZV64hJf9yC/iutSe5MR3Igk4R472Dn4RWG2HxcF804o8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785507891; c=relaxed/simple; bh=+RqkXn1fraP6cVhzylmca3p6JDvhLR0jInwTN075Ip4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dhARAa/WvjeCkRWWgmX8Cww3wruMG+b4MoHsbiX32hUXbtlFInWwE8GvhUpemlDet934eAF5kst7mwsa84o4pezVciMnlu1VCzpln+3TSY/JyKYzvWcPP0RpZYer443EG76kiRkxhXa8zQFftI8pjvo0PcTiA84kbR206HHLZX0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=aM7z3dA5; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="aM7z3dA5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5CFAD1F000E9; Fri, 31 Jul 2026 14:24:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785507889; bh=5+GFzuFgZQNxbrz5hLonyNttgqfCDeTaSqr0K2b4YtA=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=aM7z3dA5AefnbSjnQzj2ji/x10YDUM3fbxUtUUDoJjGpOIGgE1OlZnKuQ/xNVTJv2 ksAroKFkohu2nt0PRF74ErCLOcaziBbiomabpGOQm30/PU1R0T2+tEGdho3kZK3qCA Dch/KfMx6o5ym2G9uLFnehCkm/MkDubcX4Wtr/p7ger0xGclnWDc7gdBC5Dnz9iyvA 86nTUt9vk17REOxp9gdXa0hIWp6PLh8i5ZTibWYQEIEU0m977bKLqtPnoab/dpvhCG QIZs+T+8anwqXWBU1Uo1qgvarL2dQ99vHXHg5ZLN6HiBwhwdNxJO7sZhHhpccgQN7H eihne0u5eOOkA== From: "Matthieu Baerts (NGI0)" Date: Fri, 31 Jul 2026 16:24:18 +0200 Subject: [PATCH net-next v2 2/5] mptcp: let the retrans scheduler do its job Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260731-net-next-mptcp-oooq-pruning-v2-2-24838164fa21@kernel.org> References: <20260731-net-next-mptcp-oooq-pruning-v2-0-24838164fa21@kernel.org> In-Reply-To: <20260731-net-next-mptcp-oooq-pruning-v2-0-24838164fa21@kernel.org> To: Mat Martineau , Geliang Tang , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman Cc: netdev@vger.kernel.org, mptcp@lists.linux.dev, linux-kernel@vger.kernel.org, "Matthieu Baerts (NGI0)" , Gang Yan X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=6309; i=matttbe@kernel.org; h=from:subject:message-id; bh=kPuyETNsuPEY+YBx+aLERj0Xbk9Jfu2rb6IkdWMvqvM=; b=owGbwMvMwCVWo/Th0Gd3rumMp9WSGLJyNqi90dMS+fP8Q1zW2hwF1bfzzkbqawdlfy2QlzL7f 3p1MO/LjlIWBjEuBlkxRRbptsj8mc+reEu8/Cxg5rAygQxh4OIUgIk82MLwvybk2NVVl1jOzU/i ZZuQ+UVNpn5WWKfzzCuPdXda7rumv4fhDx/jHYfzTbrP95+crNoWzM++IH3FWSmV2PCADVsmmJ3 YxgMA X-Developer-Key: i=matttbe@kernel.org; a=openpgp; fpr=E8CB85F76877057A6E27F77AF6B7824F4269A073 From: Paolo Abeni Currently the MPTCP core enforces that when MPTCP-level retrans timer fires, at most a single dfrag is retransmitted. In some corner-cases, it may be necessary to 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. Tested-by: Gang Yan Tested-by: Geliang Tang Acked-by: Geliang Tang Signed-off-by: Paolo Abeni Signed-off-by: Matthieu Baerts (NGI0) --- net/mptcp/protocol.c | 119 +++++++++++++++++++++++++++++++++++++----------= ---- 1 file changed, 87 insertions(+), 32 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 290d14e2fa5b..72b1fa3ca71c 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1136,13 +1136,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; @@ -2785,8 +2778,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); @@ -2796,6 +2793,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); @@ -2805,7 +2803,7 @@ static int __mptcp_push_retrans(struct sock *sk, stru= ct 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; =20 @@ -2851,14 +2849,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 need_retrans; + 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); - if (!dfrag) { + need_retrans =3D !!dfrag; + mptcp_data_unlock(sk); + if (!dfrag) + goto check_data_fin; + + for (;;) { + bool already_retrans; + u64 sent_seq; + + /* The default scheduler will kick "stale" logic, that in + * turn can process incoming acks and clean the RTX queue; + * ensure that the current dfrag will still be around + * afterwards. + */ + get_page(dfrag->page); + 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 !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); + need_retrans =3D !!dfrag; + } else if (after64(msk->snd_una, retrans_seq)) { + retrans_seq =3D msk->snd_una; + } + mptcp_data_unlock(sk); + + /* `already_sent` can be 0 for `dfrag` belonging to the RTX + * queue due to __mptcp_retransmit_pending_data(). + */ + if (!dfrag || !dfrag->already_sent) + break; + + /* Can fail only in case of fallback. */ + len =3D __mptcp_push_retrans(sk, dfrag, retrans_seq); + if (len < 0) + goto clear_scheduled; + + retrans_seq +=3D len; + msk->bytes_retrans +=3D len; + dfrag->already_sent =3D max_t(u16, dfrag->already_sent, + retrans_seq - dfrag->data_seq); + + /* With csum enabled retransmission can send new data. */ + sent_seq =3D dfrag->already_sent + dfrag->data_seq; + if (after64(sent_seq, msk->snd_nxt)) + WRITE_ONCE(msk->snd_nxt, sent_seq); + + /* 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) + break; + } + + /* Attempt data-fin retransmission only when the RTX queue is empty. */ + if (!need_retrans) { +check_data_fin: if (mptcp_data_fin_enabled(msk)) { struct inet_connection_sock *icsk =3D inet_csk(sk); =20 @@ -2866,30 +2938,13 @@ static void __mptcp_retrans(struct sock *sk) 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); - - /* With csum enabled retransmission can send new data. */ - if (after64(dfrag->already_sent + dfrag->data_seq, msk->snd_nxt)) - WRITE_ONCE(msk->snd_nxt, dfrag->already_sent + dfrag->data_seq); - reset_timer: mptcp_check_and_set_pending(sk); =20 --=20 2.53.0 From nobody Sat Aug 15 20:33:11 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2F31142E8F1; Fri, 31 Jul 2026 14:24:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785507893; cv=none; b=iUPiaiVCjTcdxDVGq05K9FouLADcIh5Ugh6/4r+jNrduP+tcvOU74M47FZBUAkohybWZ6Z3UYczU1yWApFI5taCC3X0Hb5jrouNQn8/OtsgkyZ3hyGS+kK/cHmWb2UtZpES9uyhOY5rHclMInbn6TZHr9lCZzHkJ3hn7tHZqDXw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785507893; c=relaxed/simple; bh=+Dx8cUPxw+YGZkvoq7PDBOxtGrIMgZdMTOCWbzCps+A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DMty5HuaKldeZkXmJ6MYwo0f7rd3uQzNWvBr7Hb4vgwSiTzUDWFRQMCU7WAts2Ig1yzkkGPNKOdkP+JgcwNlaCBiUdg5NmmQDivzL/+mcNXtnBXyt2mB8z36+cDhfYL8O1JcwqvdCstGldPJfyTAbHgdcpgCAsbBzW1GceWbnFE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=KEY7EBY5; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="KEY7EBY5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B1A5F1F00A3A; Fri, 31 Jul 2026 14:24:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785507891; bh=iMEczguGEeqG2dtckIYc08K1knNCRvfNyMKN/FdQiwA=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=KEY7EBY5WzUA6A0JqxWTGCj49kV/a6KzWKkWCGwrDqeLB+ZK65MZj4R5f+P+dtAna 3V7LOVT4+BU6f1YrCnPBfOMu5PuNgaHm2M372a+D7C+eYGYZcPBtqdd4HZ8XaxZf90 7Yy4DZf/C6r0to3KoNFj4UbUoY86DhtI0f8OJogs2q6B+mFXb0YMLph5cWE3m9XzBa pEgWCOWkILa/qJdvXyJao6IkZonhT2K2J24Z5PjSqVygWOFR7zX+1EABHur93gSW3J PtdBxAlgvqOpZStmt5aoUatYHdAcjwGfQAFpKgwCYcUKUk6cfhPdcK9lhE1jNgIcJr blyBBs2VaD7RQ== From: "Matthieu Baerts (NGI0)" Date: Fri, 31 Jul 2026 16:24:19 +0200 Subject: [PATCH net-next v2 3/5] mptcp: explicitly drop over memory limits Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260731-net-next-mptcp-oooq-pruning-v2-3-24838164fa21@kernel.org> References: <20260731-net-next-mptcp-oooq-pruning-v2-0-24838164fa21@kernel.org> In-Reply-To: <20260731-net-next-mptcp-oooq-pruning-v2-0-24838164fa21@kernel.org> To: Mat Martineau , Geliang Tang , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman Cc: netdev@vger.kernel.org, mptcp@lists.linux.dev, linux-kernel@vger.kernel.org, "Matthieu Baerts (NGI0)" X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7073; i=matttbe@kernel.org; h=from:subject:message-id; bh=LeIX1Vo+bsKwPXGsd8YW5pw/IYRaB8n/4Ijl3U2Mjrg=; b=owGbwMvMwCVWo/Th0Gd3rumMp9WSGLJyNqhvt2JLqFqnVMbk96dIZtOjX9IMpd8Wr3y0KFT9T NC/YvW8jlIWBjEuBlkxRRbptsj8mc+reEu8/Cxg5rAygQxh4OIUgInw7GZkmLr62o7Vs59/8XoV s2C9xCpjq7WCRvsCnr96wHvv2Ax2rlMM/4NXxE5/XBmjuF1y7iL2MIMyfq2TNideTVoQprAw7pu tMR8A X-Developer-Key: i=matttbe@kernel.org; a=openpgp; fpr=E8CB85F76877057A6E27F77AF6B7824F4269A073 From: Paolo Abeni 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 limits. Under significant memory pressure the above can cause permanent data transfer stalls, as the skb needed to make forward progress can be stuck in a subflow queue. Over memory limits, drop the incoming skb, relying on MPTCP-level retransmissions. Note that fallback socket must perform the limit before the skb reaches the subflow-level queue, as dropping an in-sequence already acked skb would break the stream. This is not a complete fix for the stall issue, as the drop strategy needs refinements that will come in the next patches. Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts (NGI0) [ Fix typo, comment, and bump LINUX_MIB_TCPRCVQDROP ] Signed-off-by: Matthieu Baerts (NGI0) --- v2: - mib: typo: "constrains" -> "constraints". - mptcp_over_limit: more than 0-win: retrans, dup or old acks. - mptcp_over_limit: bump LINUX_MIB_TCPRCVQDROP. - Note: Sashiko might point to a possible forward-allocated memory leak: this is a temp leak, and releasing additionally allocated fwd memory in the error path will be fix in a patch for -net. --- net/mptcp/mib.c | 2 ++ net/mptcp/mib.h | 2 ++ net/mptcp/options.c | 32 +++++++++++++++++++++++++++++--- net/mptcp/protocol.c | 31 +++++++++++++++++++++++-------- 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c index f23fda0c55a7..ef65e2df709f 100644 --- a/net/mptcp/mib.c +++ b/net/mptcp/mib.c @@ -85,6 +85,8 @@ 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("BacklogDrop", MPTCP_MIB_BACKLOGDROP), + SNMP_MIB_ITEM("RcvPruned", MPTCP_MIB_RCVPRUNED), }; =20 /* mptcp_mib_alloc - allocate percpu mib counters diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h index 812218b5ed2b..9271205f682e 100644 --- a/net/mptcp/mib.h +++ b/net/mptcp/mib.h @@ -88,6 +88,8 @@ 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_BACKLOGDROP, /* Backlog over memory limit */ + MPTCP_MIB_RCVPRUNED, /* Dropped due to memory constraints */ __MPTCP_MIB_MAX }; =20 diff --git a/net/mptcp/options.c b/net/mptcp/options.c index c664023d37ba..5642277c8b3d 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -1127,8 +1127,34 @@ 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); + u64 mem =3D sk_rmem_alloc_get(sk); + + mem +=3D READ_ONCE(msk->backlog_len); + if (likely(mem <=3D READ_ONCE(sk->sk_rcvbuf))) + return false; + + /* Avoid silently dropping pure acks, fin or already-acked segments. */ + 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); + + /* Plain TCP (fallback) and skb is dropped before the TCP recv queue. */ + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRCVQDROP); + + 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) { @@ -1154,7 +1180,7 @@ bool mptcp_incoming_options(struct sock *sk, struct s= k_buff *skb) =20 __mptcp_data_acked(subflow->conn); mptcp_data_unlock(subflow->conn); - return true; + return !mptcp_over_limit(subflow->conn, sk, skb); } =20 mptcp_get_options(skb, &mp_opt); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 72b1fa3ca71c..5f7d8340a3d9 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -381,6 +381,16 @@ 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_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED); + 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 +685,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 +693,16 @@ 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)) { + __MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_BACKLOGDROP); + kfree_skb_reason(skb, SKB_DROP_REASON_SOCKET_BACKLOG); + 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 +774,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 { @@ -2204,10 +2225,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; @@ -2235,9 +2252,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.53.0 From nobody Sat Aug 15 20:33:11 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 162D442F6FA; Fri, 31 Jul 2026 14:24:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785507895; cv=none; b=NgWt4kc6nRPIm/Mick2b7voSceKbf+njOIKjt7AAfEuUp4Hu4bWrtoCplIS4VBe1pjy4KmE1uPF7PkKwqbFTJdHjS2fMvueUEhzHGgwCvXLCzN6F1H6RAlmK0om1eLwbGfCDJ5Ij7rPm1qE/iF4wzKjgkF6Pk0RV6XCMQ8C76D8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785507895; c=relaxed/simple; bh=FGREC4W6Mh/CHWXFlthiI7UvopuXq/RVGFIwYGmO6W4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HPfE+kTYa1rFXeA3SkOY/jsHgWfS0tyd6Rwb/wSWHuk/zj7Ib4rLnfe03WgDfEFbvP2sc9hbX6X+tf+fsm17HvQiFohGu1NIsYn4oapIlHQ2BCiIIr6tIn6nUpEQWosb7MLEpYRo38IEoXWpZ+spcgL+gOP43mynegqJat+519k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OkFNi4wQ; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OkFNi4wQ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E216D1F000E9; Fri, 31 Jul 2026 14:24:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785507893; bh=36lAnMkjB07VIYCCBLdzVx8RoT1sIGgW6HHKCR5eWMg=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=OkFNi4wQRyeZEeky3tB+1cP8k75XzRMzqSTXxwPyL5fbOIdCcOjMWwSgLdCP5PY1t bMR4WWUsvGoCOyzyLxtT3WwyESUElfhEE32aD7nn1Sabfon4SGJBh8Wn/Q7OZUjM3w ZSfbb8bGz3Gt7d00SyQrmZ7vY44zaM5g5vHjeadYOPf0JIe14oNFQbgi1+Uivl5yXp 8P8qhBu5sjvFTqcDq3xxq/UHspPN0x1GVRnCTGYYIcFmHvg4RbvJgM29oljWlc8MVB il6ZiTNOXlnB37XGSN77GvuwJHaDs74WnsRvBSa89xHnuZuiJIUGR5QYP9n2ucLif9 Fe+LOpcgcxjig== From: "Matthieu Baerts (NGI0)" Date: Fri, 31 Jul 2026 16:24:20 +0200 Subject: [PATCH net-next v2 4/5] mptcp: enforce hard limit on backlog flushing Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260731-net-next-mptcp-oooq-pruning-v2-4-24838164fa21@kernel.org> References: <20260731-net-next-mptcp-oooq-pruning-v2-0-24838164fa21@kernel.org> In-Reply-To: <20260731-net-next-mptcp-oooq-pruning-v2-0-24838164fa21@kernel.org> To: Mat Martineau , Geliang Tang , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman Cc: netdev@vger.kernel.org, mptcp@lists.linux.dev, linux-kernel@vger.kernel.org, "Matthieu Baerts (NGI0)" X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=2868; i=matttbe@kernel.org; h=from:subject:message-id; bh=8oehzmC/Ja20Y/2KJD9sivd0mO9h5X8ufkiQiwQH0Fc=; b=owGbwMvMwCVWo/Th0Gd3rumMp9WSGLJyNmjOuviqcIXkuWupizz9bFbnHWJL3fLNfNu3DoXTk 1dP5pHd0lHKwiDGxSArpsgi3RaZP/N5FW+Jl58FzBxWJpAhDFycAjCRrYUM/8xfMx9rM8xac89u ySLbfrtJAftNty10X/A/7ng/39eg3SsYGS7Pdg8Ntg9p3LBxcrz9m38HhMvrDp25c/rDvAmTp13 Ls+cAAA== X-Developer-Key: i=matttbe@kernel.org; a=openpgp; fpr=E8CB85F76877057A6E27F77AF6B7824F4269A073 From: Paolo Abeni 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 Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) --- 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 5f7d8340a3d9..7f257419c5ea 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2223,7 +2223,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); @@ -2260,20 +2259,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)) { @@ -2281,8 +2272,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); =20 if (enqueued && mptcp_epollin_ready(sk)) @@ -3752,12 +3743,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) @@ -3790,9 +3781,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.53.0 From nobody Sat Aug 15 20:33:11 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2A074430CCF; Fri, 31 Jul 2026 14:24:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785507897; cv=none; b=ZnKQb0oqpDURYc6N0m9loyb6TVvoLjpM48sSkR7XhRhv1dmcUC5BwCMV7bMhssxr5ksnCcKiuu/6OxIEkySzEmkoiUwduH8gnbxkUV1cf3HGLvh6ZLDyA7It/2eQFcKXGLaY8EVMG7gguntr7tbJr70Kd6cbDos1rQtxLSAQteg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785507897; c=relaxed/simple; bh=8WTTDl4a9wwi9SJqmtB4tkmhZeXGLeshxgFYd3umo44=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=WIu8oTitA8wSRuuuMyZEi7XGcdIvpoSmTti3llRyfBswfoYFguBgImw+SOJR3kUvW1TtxHe5KHckJ/gwMVL9wEKlZw0xkV4Lom6WsZ26znIMYcn1kCrxGE6axflLn6y988CzAPwzrka+OKE6wm9e6VXPsmpHrqd1fwlY9vIeJnI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=l5yZtHA0; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="l5yZtHA0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1D2821F00A3A; Fri, 31 Jul 2026 14:24:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785507896; bh=ExSEsOdV4wuf/2uulhV5hDXrmpUu+s8RPklwU3Unvu8=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=l5yZtHA0PntBDJu8D5srmdMsGDVkfcO+uIGdrcB+DFwVbtfITl7E8mRnlptL8NZTP BxWCsLTmr20YGGt707OhJ4rRGd5J+66qJ/+u4IoyypCcYRskrt8lmOkknYoM3A+LmP GNr6dvEwg1JU85iG/DIoO/4iBzWm6V1yl9y+Dqmj3npLXQz+Z3TkKemZpvH3ex1Wf6 ShFUXGqhBKtK0K4JqqQOQduvhUMowjr/9qPQ8gxbp338+12yJoOMvJWHqRFpAZEwAB fo/aKY5xOjvOpsfA/UVbPRrIbR5KLkaGYc6Zdt1tTUd6ddACrXdjH/gWQ3GAbWehjk 9DXoj/M1MJEcA== From: "Matthieu Baerts (NGI0)" Date: Fri, 31 Jul 2026 16:24:21 +0200 Subject: [PATCH net-next v2 5/5] mptcp: implemented OoO queue pruning Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260731-net-next-mptcp-oooq-pruning-v2-5-24838164fa21@kernel.org> References: <20260731-net-next-mptcp-oooq-pruning-v2-0-24838164fa21@kernel.org> In-Reply-To: <20260731-net-next-mptcp-oooq-pruning-v2-0-24838164fa21@kernel.org> To: Mat Martineau , Geliang Tang , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman Cc: netdev@vger.kernel.org, mptcp@lists.linux.dev, linux-kernel@vger.kernel.org, "Matthieu Baerts (NGI0)" , Gang Yan X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=3674; i=matttbe@kernel.org; h=from:subject:message-id; bh=3BQN5XEdm09zV4M6DVMQUulq14bHbT2dtzRN+MyfgFE=; b=owGbwMvMwCVWo/Th0Gd3rumMp9WSGLJyNmi905jyO29hYN+T2//Sjga/MZIznXPNw+6pcv16z 0ZNiVsHO0pZGMS4GGTFFFmk2yLzZz6v4i3x8rOAmcPKBDKEgYtTACYSUsnwP778xP8DSuILJnid /M7rWPbvX9/0G872mjxXdeQXVHxjncfw318pmKMmgW3CmSlexpudPhRM5JjDpBkubBHYHOHJP+8 hJwA= X-Developer-Key: i=matttbe@kernel.org; a=openpgp; fpr=E8CB85F76877057A6E27F77AF6B7824F4269A073 From: Paolo Abeni When moving incoming skbs in the msk receive queue and the latter is above limits, prune it as needed quite alike what TCP is doing at the subflow level. The main difference relies in the stop condition: since MPTCP does not perform collapsing, it's better off dropping the bare minimum to fit the (newer) incoming packet. Signed-off-by: Paolo Abeni Tested-by: Gang Yan Reviewed-by: Matthieu Baerts (NGI0) [ Uniform OFO MIB counters ] Signed-off-by: Matthieu Baerts (NGI0) --- v2: - Uniform the new counter with the other OFO ones. --- net/mptcp/mib.c | 1 + net/mptcp/mib.h | 1 + net/mptcp/protocol.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c index ef65e2df709f..2569385bab7c 100644 --- a/net/mptcp/mib.c +++ b/net/mptcp/mib.c @@ -87,6 +87,7 @@ static const struct snmp_mib mptcp_snmp_list[] =3D { SNMP_MIB_ITEM("WinProbe", MPTCP_MIB_WINPROBE), SNMP_MIB_ITEM("BacklogDrop", MPTCP_MIB_BACKLOGDROP), SNMP_MIB_ITEM("RcvPruned", MPTCP_MIB_RCVPRUNED), + SNMP_MIB_ITEM("OFOPruned", MPTCP_MIB_OFOPRUNED), }; =20 /* mptcp_mib_alloc - allocate percpu mib counters diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h index 9271205f682e..3a3425e258a7 100644 --- a/net/mptcp/mib.h +++ b/net/mptcp/mib.h @@ -90,6 +90,7 @@ enum linux_mptcp_mib_field { MPTCP_MIB_WINPROBE, /* MPTCP-level zero window probe */ MPTCP_MIB_BACKLOGDROP, /* Backlog over memory limit */ MPTCP_MIB_RCVPRUNED, /* Dropped due to memory constraints */ + MPTCP_MIB_OFOPRUNED, /* MPTCP-level OoO queue pruned */ __MPTCP_MIB_MAX }; =20 diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 7f257419c5ea..68c9d952d1d3 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -373,6 +373,49 @@ static void mptcp_init_skb(struct sock *ssk, struct sk= _buff *skb, int offset, skb_dst_drop(skb); } =20 +/* "Inspired" from the TCP version; main difference: stop as soon as the M= PTCP + * socket is under memory limit. + */ +static bool mptcp_prune_ofo_queue(struct sock *sk, u64 seq) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct rb_node *node, *prev; + bool pruned =3D false; + u64 mem; + + if (RB_EMPTY_ROOT(&msk->out_of_order_queue)) + goto out; + + 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 (after64(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); + + mem =3D (unsigned int)sk_rmem_alloc_get(sk); + if (mem <=3D sk->sk_rcvbuf) + break; + + node =3D prev; + } while (node); + + if (pruned) + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOPRUNED); + +out: + mem =3D (unsigned int)sk_rmem_alloc_get(sk); + return mem <=3D sk->sk_rcvbuf; +} + 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; @@ -385,7 +428,8 @@ 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_fallback(msk)) { + !__mptcp_check_fallback(msk) && + !mptcp_prune_ofo_queue(sk, MPTCP_SKB_CB(skb)->map_seq)) { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED); mptcp_drop(sk, skb); return false; --=20 2.53.0