Skip to content

Commit 8571248

Browse files
mjmartineaudavem330
authored andcommitted
tcp: coalesce/collapse must respect MPTCP extensions
Coalesce and collapse of packets carrying MPTCP extensions is allowed when the newer packet has no extension or the extensions carried by both packets are equal. This allows merging of TSO packet trains and even cross-TSO packets, and does not require any additional action when moving data into existing SKBs. v3 -> v4: - allow collapsing, under mptcp_skb_can_collapse() constraint v5 -> v6: - clarify MPTCP skb extensions must always be cleared at allocation time Co-developed-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 3ee17bc commit 8571248

File tree

4 files changed

+74
-4
lines changed

4 files changed

+74
-4
lines changed

include/net/mptcp.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#ifndef __NET_MPTCP_H
99
#define __NET_MPTCP_H
1010

11+
#include <linux/skbuff.h>
1112
#include <linux/types.h>
1213

1314
/* MPTCP sk_buff extension data */
@@ -25,4 +26,60 @@ struct mptcp_ext {
2526
/* one byte hole */
2627
};
2728

29+
#ifdef CONFIG_MPTCP
30+
31+
/* move the skb extension owership, with the assumption that 'to' is
32+
* newly allocated
33+
*/
34+
static inline void mptcp_skb_ext_move(struct sk_buff *to,
35+
struct sk_buff *from)
36+
{
37+
if (!skb_ext_exist(from, SKB_EXT_MPTCP))
38+
return;
39+
40+
if (WARN_ON_ONCE(to->active_extensions))
41+
skb_ext_put(to);
42+
43+
to->active_extensions = from->active_extensions;
44+
to->extensions = from->extensions;
45+
from->active_extensions = 0;
46+
}
47+
48+
static inline bool mptcp_ext_matches(const struct mptcp_ext *to_ext,
49+
const struct mptcp_ext *from_ext)
50+
{
51+
/* MPTCP always clears the ext when adding it to the skb, so
52+
* holes do not bother us here
53+
*/
54+
return !from_ext ||
55+
(to_ext && from_ext &&
56+
!memcmp(from_ext, to_ext, sizeof(struct mptcp_ext)));
57+
}
58+
59+
/* check if skbs can be collapsed.
60+
* MPTCP collapse is allowed if neither @to or @from carry an mptcp data
61+
* mapping, or if the extension of @to is the same as @from.
62+
* Collapsing is not possible if @to lacks an extension, but @from carries one.
63+
*/
64+
static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
65+
const struct sk_buff *from)
66+
{
67+
return mptcp_ext_matches(skb_ext_find(to, SKB_EXT_MPTCP),
68+
skb_ext_find(from, SKB_EXT_MPTCP));
69+
}
70+
71+
#else
72+
73+
static inline void mptcp_skb_ext_move(struct sk_buff *to,
74+
const struct sk_buff *from)
75+
{
76+
}
77+
78+
static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
79+
const struct sk_buff *from)
80+
{
81+
return true;
82+
}
83+
84+
#endif /* CONFIG_MPTCP */
2885
#endif /* __NET_MPTCP_H */

include/net/tcp.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <net/tcp_states.h>
4040
#include <net/inet_ecn.h>
4141
#include <net/dst.h>
42+
#include <net/mptcp.h>
4243

4344
#include <linux/seq_file.h>
4445
#include <linux/memcontrol.h>
@@ -978,6 +979,13 @@ static inline bool tcp_skb_can_collapse_to(const struct sk_buff *skb)
978979
return likely(!TCP_SKB_CB(skb)->eor);
979980
}
980981

982+
static inline bool tcp_skb_can_collapse(const struct sk_buff *to,
983+
const struct sk_buff *from)
984+
{
985+
return likely(tcp_skb_can_collapse_to(to) &&
986+
mptcp_skb_can_collapse(to, from));
987+
}
988+
981989
/* Events passed to congestion control interface */
982990
enum tcp_ca_event {
983991
CA_EVENT_TX_START, /* first transmit when no packets in flight */

net/ipv4/tcp_input.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,7 +1422,7 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
14221422
if ((TCP_SKB_CB(prev)->sacked & TCPCB_TAGBITS) != TCPCB_SACKED_ACKED)
14231423
goto fallback;
14241424

1425-
if (!tcp_skb_can_collapse_to(prev))
1425+
if (!tcp_skb_can_collapse(prev, skb))
14261426
goto fallback;
14271427

14281428
in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
@@ -4423,6 +4423,9 @@ static bool tcp_try_coalesce(struct sock *sk,
44234423
if (TCP_SKB_CB(from)->seq != TCP_SKB_CB(to)->end_seq)
44244424
return false;
44254425

4426+
if (!mptcp_skb_can_collapse(to, from))
4427+
return false;
4428+
44264429
#ifdef CONFIG_TLS_DEVICE
44274430
if (from->decrypted != to->decrypted)
44284431
return false;
@@ -4932,7 +4935,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
49324935
/* The first skb to collapse is:
49334936
* - not SYN/FIN and
49344937
* - bloated or contains data before "start" or
4935-
* overlaps to the next one.
4938+
* overlaps to the next one and mptcp allow collapsing.
49364939
*/
49374940
if (!(TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)) &&
49384941
(tcp_win_from_space(sk, skb->truesize) > skb->len ||
@@ -4941,7 +4944,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
49414944
break;
49424945
}
49434946

4944-
if (n && n != tail &&
4947+
if (n && n != tail && mptcp_skb_can_collapse(skb, n) &&
49454948
TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(n)->seq) {
49464949
end_of_skbs = false;
49474950
break;
@@ -4974,6 +4977,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
49744977
else
49754978
__skb_queue_tail(&tmp, nskb); /* defer rbtree insertion */
49764979
skb_set_owner_r(nskb, sk);
4980+
mptcp_skb_ext_move(nskb, skb);
49774981

49784982
/* Copy data, releasing collapsed skbs. */
49794983
while (copy > 0) {
@@ -4993,6 +4997,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
49934997
skb = tcp_collapse_one(sk, skb, list, root);
49944998
if (!skb ||
49954999
skb == tail ||
5000+
!mptcp_skb_can_collapse(nskb, skb) ||
49965001
(TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)))
49975002
goto end;
49985003
#ifdef CONFIG_TLS_DEVICE

net/ipv4/tcp_output.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2865,7 +2865,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to,
28652865
if (!tcp_can_collapse(sk, skb))
28662866
break;
28672867

2868-
if (!tcp_skb_can_collapse_to(to))
2868+
if (!tcp_skb_can_collapse(to, skb))
28692869
break;
28702870

28712871
space -= skb->len;

0 commit comments

Comments
 (0)