[PATCH mptcp-next 4/6] mptcp: sync mptcp skb cb layout with tcp one
Geliang Tang <[email protected]> Mon, 27 Jul 2026 19:29:19 +0800
| Newsgroups | dev.linux.lists.mptcp |
|---|---|
| Message-ID | <ea8e846ed478ab1f7a9d68960cf5c0957186c958.1785150300.git.tanggeliang@kylinos.cn> |
From: Paolo Abeni <[email protected]> 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 <[email protected]> --- net/mptcp/fastopen.c | 6 ++-- net/mptcp/protocol.c | 82 +++++++++++++++++++++++++++----------------- net/mptcp/protocol.h | 7 ++-- 3 files changed, 60 insertions(+), 35 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index 421a50a85547..0d339dd454f9 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -48,8 +48,10 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_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 = -(u64)skb->len; + MPTCP_SKB_CB(skb)->map_seq64 = -(u64)skb->len; + MPTCP_SKB_CB(skb)->map_seq = MPTCP_SKB_CB(skb)->map_seq64; MPTCP_SKB_CB(skb)->end_seq = 0; + MPTCP_SKB_CB(skb)->flags = 0; MPTCP_SKB_CB(skb)->has_rxtstamp = has_rxtstamp; mptcp_data_lock(sk); @@ -57,7 +59,7 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf msk = mptcp_sk(sk); msk->rcvd_dummy_seq = true; - msk->copied_seq = MPTCP_SKB_CB(skb)->map_seq; + msk->copied_seq = MPTCP_SKB_CB(skb)->map_seq64; msk->tfo_skb_len = 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 74a426bf6680..b9e44c64c620 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -164,7 +164,7 @@ static bool __mptcp_try_coalesce(struct sock *sk, struct sk_buff *to, !skb_try_coalesce(to, from, fragstolen, delta)) return false; - 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 = MPTCP_SKB_CB(from)->end_seq; @@ -234,14 +234,18 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk, struct sk_buff *skb) { struct sock *sk = (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; seq = MPTCP_SKB_CB(skb)->map_seq; - end_seq = MPTCP_SKB_CB(skb)->end_seq; + end_seq = MPTCP_SKB_CB(skb)->map_seq64 + skb->len; max_seq = atomic64_read(&msk->rcv_wnd_sent); - pr_debug("msk=%p seq=%llx limit=%llx empty=%d\n", msk, seq, max_seq, + /* Use the full sequence space to perform the admission checks, to + * protect vs possible wrap-arounds. + */ + pr_debug("msk=%p seq=%x limit=%llx empty=%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) } /* 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 = &msk->ooo_last_skb->rbnode; p = &parent->rb_right; @@ -284,18 +288,18 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk, struct sk_buff *skb) while (*p) { parent = *p; skb1 = rb_to_skb(parent); - if (before64(seq, MPTCP_SKB_CB(skb1)->map_seq)) { + if (before(seq, MPTCP_SKB_CB(skb1)->map_seq)) { p = &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 = skb_rb_next(skb)) != 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); @@ -348,11 +352,13 @@ static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int 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 = mptcp_subflow_get_mapped_dsn(subflow) - - offset; + MPTCP_SKB_CB(skb)->map_seq64 = mptcp_subflow_get_mapped_dsn(subflow) - + offset; + MPTCP_SKB_CB(skb)->map_seq = (u32)MPTCP_SKB_CB(skb)->map_seq64; MPTCP_SKB_CB(skb)->end_seq = MPTCP_SKB_CB(skb)->map_seq + skb->len; + MPTCP_SKB_CB(skb)->flags = 0; MPTCP_SKB_CB(skb)->has_rxtstamp = has_rxtstamp; __skb_unlink(skb, &ssk->sk_receive_queue); @@ -418,13 +424,14 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) if (!skb) return; - MPTCP_SKB_CB(skb)->map_seq = mptcp_iasn(msk) - skb->len; + MPTCP_SKB_CB(skb)->map_seq64 = mptcp_iasn(msk) - skb->len; + MPTCP_SKB_CB(skb)->map_seq = (u32)MPTCP_SKB_CB(skb)->map_seq64; MPTCP_SKB_CB(skb)->end_seq = MPTCP_SKB_CB(skb)->map_seq + skb->len; } static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) { - u64 copy_len = MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; + u32 copy_len = MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; struct mptcp_sock *msk = mptcp_sk(sk); struct sk_buff *tail; @@ -447,7 +454,7 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) return false; } - if (MPTCP_SKB_CB(skb)->map_seq == msk->ack_seq) { + if (MPTCP_SKB_CB(skb)->map_seq64 == msk->ack_seq) { add_queue: /* in sequence */ msk->bytes_received += copy_len; @@ -459,12 +466,13 @@ 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)->end_seq, msk->ack_seq)) { + } else if (after64(MPTCP_SKB_CB(skb)->map_seq64 + skb->len, + msk->ack_seq)) { /* Partial packet: map_seq < ack_seq < end_seq. */ - int delta = msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; + int delta = (u32)msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; copy_len -= delta; goto add_queue; @@ -855,40 +863,40 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) { struct sock *sk = (struct sock *)msk; struct sk_buff *skb, *tail; + u32 seq_delta, ack_seq; bool moved = false; struct rb_node *p; - u64 end_seq; p = rb_first(&msk->out_of_order_queue); pr_debug("msk=%p empty=%d\n", msk, RB_EMPTY_ROOT(&msk->out_of_order_queue)); while (p) { + ack_seq = msk->ack_seq; skb = 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; p = rb_next(p); rb_erase(&skb->rbnode, &msk->out_of_order_queue); - 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; } - end_seq = MPTCP_SKB_CB(skb)->end_seq; + seq_delta = MPTCP_SKB_CB(skb)->end_seq - ack_seq; tail = skb_peek_tail(&sk->sk_receive_queue); if (!tail || !mptcp_try_coalesce(sk, tail, skb)) { - int delta = msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; + int delta = ack_seq - MPTCP_SKB_CB(skb)->map_seq; /* skip overlapping data, if any */ - pr_debug("uncoalesced seq=%llx ack seq=%llx delta=%d\n", - MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq, + pr_debug("uncoalesced seq=%x ack seq=%x delta=%d\n", + MPTCP_SKB_CB(skb)->map_seq, ack_seq, delta); __skb_queue_tail(&sk->sk_receive_queue, skb); } - msk->bytes_received += end_seq - msk->ack_seq; - WRITE_ONCE(msk->ack_seq, end_seq); + msk->bytes_received += seq_delta; + WRITE_ONCE(msk->ack_seq, msk->ack_seq + seq_delta); moved = true; } return moved; @@ -2130,7 +2138,7 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg, int copied = 0; skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) { - u64 offset = *seq - MPTCP_SKB_CB(skb)->map_seq; + u32 offset = (u32)(*seq) - MPTCP_SKB_CB(skb)->map_seq; u32 data_len = skb->len - offset; u32 count; int err; @@ -4503,7 +4511,7 @@ static struct sk_buff *mptcp_recv_skb(struct sock *sk, u32 *off) mptcp_move_skbs(sk); while ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) { - offset = msk->copied_seq - MPTCP_SKB_CB(skb)->map_seq; + offset = (u32)msk->copied_seq - MPTCP_SKB_CB(skb)->map_seq; if (offset < skb->len) { *off = offset; return skb; @@ -4754,11 +4762,23 @@ static int mptcp_napi_poll(struct napi_struct *napi, int budget) return work_done; } +#define CHK_CB_FIELD(mptcp_field, tcp_field) \ + ({ \ + BUILD_BUG_ON(offsetof(struct mptcp_skb_cb, mptcp_field) != \ + offsetof(struct tcp_skb_cb, tcp_field)); \ + BUILD_BUG_ON(offsetofend(struct mptcp_skb_cb, mptcp_field) != \ + offsetofend(struct tcp_skb_cb, tcp_field)); \ + }) + void __init mptcp_proto_init(void) { struct mptcp_delegated_action *delegated; int cpu; + CHK_CB_FIELD(map_seq, seq); + CHK_CB_FIELD(end_seq, end_seq); + CHK_CB_FIELD(flags, tcp_flags); + mptcp_prot.h.hashinfo = tcp_prot.h.hashinfo; if (percpu_counter_init(&mptcp_sockets_allocated, 0, GFP_KERNEL)) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 730af40ec9bc..8b16b0a4eb9f 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -127,9 +127,12 @@ #define MPTCP_SYNC_SEQ 8 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; }; #define MPTCP_SKB_CB(__skb) ((struct mptcp_skb_cb *)&((__skb)->cb[0])) -- 2.53.0