[PATCH] mptcp: do not drop partial packets

Shardul Bankar posted 1 patch 1 week, 5 days ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/multipath-tcp/mptcp_net-next tags/patchew/20260422120954.8877-1-shardul.b@mpiricsoftware.com
There is a newer version of this series
net/mptcp/protocol.c | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
[PATCH] mptcp: do not drop partial packets
Posted by Shardul Bankar 1 week, 5 days ago
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 <shardul.b@mpiricsoftware.com>
---
 net/mptcp/protocol.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 614c3f583ca0..6858e6e283e3 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -397,12 +397,27 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb)
 		return false;
 	}
 
-	/* 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 = MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq;
+	MPTCP_SKB_CB(skb)->offset += msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq;
+	msk->bytes_received += copy_len;
+	WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len);
+	tail = skb_peek_tail(&sk->sk_receive_queue);
+	if (tail && mptcp_try_coalesce(sk, tail, skb))
+		return true;
+
+	skb_set_owner_r(skb, sk);
+	__skb_queue_tail(&sk->sk_receive_queue, skb);
+	return true;
 }
 
 static void mptcp_stop_rtx_timer(struct sock *sk)
-- 
2.34.1
Re: [PATCH] mptcp: do not drop partial packets
Posted by Paolo Abeni 1 week, 5 days ago
On 4/22/26 2:09 PM, Shardul Bankar wrote:
> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
> index 614c3f583ca0..6858e6e283e3 100644
> --- a/net/mptcp/protocol.c
> +++ b/net/mptcp/protocol.c
> @@ -397,12 +397,27 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb)
>  		return false;
>  	}
>  
> -	/* 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 = MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq;
> +	MPTCP_SKB_CB(skb)->offset += msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq;

here MPTCP_SKB_CB(skb)->offset is always != 0 ...

> +	msk->bytes_received += copy_len;
> +	WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len);
> +	tail = skb_peek_tail(&sk->sk_receive_queue);
> +	if (tail && mptcp_try_coalesce(sk, tail, skb))

... so mptcp_try_coalesce() will always fail.

/P
Re: [PATCH] mptcp: do not drop partial packets
Posted by Shardul Bankar 1 week, 5 days ago
On Wed, 2026-04-22 at 15:51 +0200, Paolo Abeni wrote:
> On 4/22/26 2:09 PM, Shardul Bankar wrote:
> > +
> > +       /* 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 = MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq;
> > +       MPTCP_SKB_CB(skb)->offset += msk->ack_seq -
> > MPTCP_SKB_CB(skb)->map_seq;
> 
> here MPTCP_SKB_CB(skb)->offset is always != 0 ...
> 
> > +       msk->bytes_received += copy_len;
> > +       WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len);
> > +       tail = skb_peek_tail(&sk->sk_receive_queue);
> > +       if (tail && mptcp_try_coalesce(sk, tail, skb))
> 
> ... so mptcp_try_coalesce() will always fail.

Thanks, good catch. Fixed in v2.

Regards,
Shardul
Re: [PATCH] mptcp: do not drop partial packets
Posted by MPTCP CI 1 week, 5 days ago
Hi Shardul,

Thank you for your modifications, that's great!

Our CI did some validations and here is its report:

- KVM Validation: normal (except selftest_mptcp_join): Success! ✅
- KVM Validation: normal (only selftest_mptcp_join): Success! ✅
- KVM Validation: debug (except selftest_mptcp_join): Unstable: 1 failed test(s): packetdrill_dss ⚠️ 
- KVM Validation: debug (only selftest_mptcp_join): Success! ✅
- KVM Validation: btf-normal (only bpftest_all): Success! ✅
- KVM Validation: btf-debug (only bpftest_all): Success! ✅
- Task: https://github.com/multipath-tcp/mptcp_net-next/actions/runs/24778310704

Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/46be5a27087c
Patchwork: https://patchwork.kernel.org/project/mptcp/list/?series=1084260


If there are some issues, you can reproduce them using the same environment as
the one used by the CI thanks to a docker image, e.g.:

    $ cd [kernel source code]
    $ docker run -v "${PWD}:${PWD}:rw" -w "${PWD}" --privileged --rm -it \
        --pull always mptcp/mptcp-upstream-virtme-docker:latest \
        auto-normal

For more details:

    https://github.com/multipath-tcp/mptcp-upstream-virtme-docker


Please note that despite all the efforts that have been already done to have a
stable tests suite when executed on a public CI like here, it is possible some
reported issues are not due to your modifications. Still, do not hesitate to
help us improve that ;-)

Cheers,
MPTCP GH Action bot
Bot operated by Matthieu Baerts (NGI0 Core)