Skip to content

Commit 849fd44

Browse files
committed
Merge branch 'mptcp-Connection-and-accounting-fixes'
Mat Martineau says: ==================== mptcp: Connection and accounting fixes Here are some miscellaneous fixes for MPTCP: Patch 1 modifies an MPTCP hash so it doesn't depend on one of skb->dev and skb->sk being non-NULL. Patch 2 removes an extra destructor call when rejecting a join due to port mismatch. Patches 3 and 5 more cleanly handle error conditions with MP_JOIN and syncookies, and update a related self test. Patch 4 makes sure packets that trigger a subflow TCP reset during MPTCP option header processing are correctly dropped. Patch 6 addresses a rmem accounting issue that could keep packets in subflow receive buffers longer than necessary, delaying MPTCP-level ACKs. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 5d52c90 + ce599c5 commit 849fd44

File tree

10 files changed

+68
-28
lines changed

10 files changed

+68
-28
lines changed

include/net/mptcp.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ bool mptcp_synack_options(const struct request_sock *req, unsigned int *size,
105105
bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
106106
unsigned int *size, unsigned int remaining,
107107
struct mptcp_out_options *opts);
108-
void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb);
108+
bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb);
109109

110110
void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
111111
struct mptcp_out_options *opts);
@@ -227,9 +227,10 @@ static inline bool mptcp_established_options(struct sock *sk,
227227
return false;
228228
}
229229

230-
static inline void mptcp_incoming_options(struct sock *sk,
230+
static inline bool mptcp_incoming_options(struct sock *sk,
231231
struct sk_buff *skb)
232232
{
233+
return true;
233234
}
234235

235236
static inline void mptcp_skb_ext_move(struct sk_buff *to,

net/ipv4/tcp_input.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4247,6 +4247,9 @@ void tcp_reset(struct sock *sk, struct sk_buff *skb)
42474247
{
42484248
trace_tcp_receive_reset(sk);
42494249

4250+
/* mptcp can't tell us to ignore reset pkts,
4251+
* so just ignore the return value of mptcp_incoming_options().
4252+
*/
42504253
if (sk_is_mptcp(sk))
42514254
mptcp_incoming_options(sk, skb);
42524255

@@ -4941,8 +4944,13 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
49414944
bool fragstolen;
49424945
int eaten;
49434946

4944-
if (sk_is_mptcp(sk))
4945-
mptcp_incoming_options(sk, skb);
4947+
/* If a subflow has been reset, the packet should not continue
4948+
* to be processed, drop the packet.
4949+
*/
4950+
if (sk_is_mptcp(sk) && !mptcp_incoming_options(sk, skb)) {
4951+
__kfree_skb(skb);
4952+
return;
4953+
}
49464954

49474955
if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) {
49484956
__kfree_skb(skb);
@@ -6523,8 +6531,11 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)
65236531
case TCP_CLOSING:
65246532
case TCP_LAST_ACK:
65256533
if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
6526-
if (sk_is_mptcp(sk))
6527-
mptcp_incoming_options(sk, skb);
6534+
/* If a subflow has been reset, the packet should not
6535+
* continue to be processed, drop the packet.
6536+
*/
6537+
if (sk_is_mptcp(sk) && !mptcp_incoming_options(sk, skb))
6538+
goto discard;
65286539
break;
65296540
}
65306541
fallthrough;

net/mptcp/mib.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ static const struct snmp_mib mptcp_snmp_list[] = {
4444
SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW),
4545
SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX),
4646
SNMP_MIB_ITEM("MPPrioRx", MPTCP_MIB_MPPRIORX),
47+
SNMP_MIB_ITEM("RcvPruned", MPTCP_MIB_RCVPRUNED),
4748
SNMP_MIB_SENTINEL
4849
};
4950

net/mptcp/mib.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ enum linux_mptcp_mib_field {
3737
MPTCP_MIB_RMSUBFLOW, /* Remove a subflow */
3838
MPTCP_MIB_MPPRIOTX, /* Transmit a MP_PRIO */
3939
MPTCP_MIB_MPPRIORX, /* Received a MP_PRIO */
40+
MPTCP_MIB_RCVPRUNED, /* Incoming packet dropped due to memory limit */
4041
__MPTCP_MIB_MAX
4142
};
4243

net/mptcp/options.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,8 @@ static bool add_addr_hmac_valid(struct mptcp_sock *msk,
10351035
return hmac == mp_opt->ahmac;
10361036
}
10371037

1038-
void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
1038+
/* Return false if a subflow has been reset, else return true */
1039+
bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
10391040
{
10401041
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
10411042
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
@@ -1053,12 +1054,16 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
10531054
__mptcp_check_push(subflow->conn, sk);
10541055
__mptcp_data_acked(subflow->conn);
10551056
mptcp_data_unlock(subflow->conn);
1056-
return;
1057+
return true;
10571058
}
10581059

10591060
mptcp_get_options(sk, skb, &mp_opt);
1061+
1062+
/* The subflow can be in close state only if check_fully_established()
1063+
* just sent a reset. If so, tell the caller to ignore the current packet.
1064+
*/
10601065
if (!check_fully_established(msk, sk, subflow, skb, &mp_opt))
1061-
return;
1066+
return sk->sk_state != TCP_CLOSE;
10621067

10631068
if (mp_opt.fastclose &&
10641069
msk->local_key == mp_opt.rcvr_key) {
@@ -1100,7 +1105,7 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
11001105
}
11011106

11021107
if (!mp_opt.dss)
1103-
return;
1108+
return true;
11041109

11051110
/* we can't wait for recvmsg() to update the ack_seq, otherwise
11061111
* monodirectional flows will stuck
@@ -1119,12 +1124,12 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
11191124
schedule_work(&msk->work))
11201125
sock_hold(subflow->conn);
11211126

1122-
return;
1127+
return true;
11231128
}
11241129

11251130
mpext = skb_ext_add(skb, SKB_EXT_MPTCP);
11261131
if (!mpext)
1127-
return;
1132+
return true;
11281133

11291134
memset(mpext, 0, sizeof(*mpext));
11301135

@@ -1153,6 +1158,8 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
11531158
if (mpext->csum_reqd)
11541159
mpext->csum = mp_opt.csum;
11551160
}
1161+
1162+
return true;
11561163
}
11571164

11581165
static void mptcp_set_rwin(const struct tcp_sock *tp)

net/mptcp/protocol.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ static void mptcp_cleanup_rbuf(struct mptcp_sock *msk)
474474
bool cleanup, rx_empty;
475475

476476
cleanup = (space > 0) && (space >= (old_space << 1));
477-
rx_empty = !atomic_read(&sk->sk_rmem_alloc);
477+
rx_empty = !__mptcp_rmem(sk);
478478

479479
mptcp_for_each_subflow(msk, subflow) {
480480
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
@@ -720,8 +720,10 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk)
720720
sk_rbuf = ssk_rbuf;
721721

722722
/* over limit? can't append more skbs to msk, Also, no need to wake-up*/
723-
if (atomic_read(&sk->sk_rmem_alloc) > sk_rbuf)
723+
if (__mptcp_rmem(sk) > sk_rbuf) {
724+
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED);
724725
return;
726+
}
725727

726728
/* Wake-up the reader only for in-sequence data */
727729
mptcp_data_lock(sk);
@@ -1754,7 +1756,7 @@ static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk,
17541756
if (!(flags & MSG_PEEK)) {
17551757
/* we will bulk release the skb memory later */
17561758
skb->destructor = NULL;
1757-
msk->rmem_released += skb->truesize;
1759+
WRITE_ONCE(msk->rmem_released, msk->rmem_released + skb->truesize);
17581760
__skb_unlink(skb, &msk->receive_queue);
17591761
__kfree_skb(skb);
17601762
}
@@ -1873,7 +1875,7 @@ static void __mptcp_update_rmem(struct sock *sk)
18731875

18741876
atomic_sub(msk->rmem_released, &sk->sk_rmem_alloc);
18751877
sk_mem_uncharge(sk, msk->rmem_released);
1876-
msk->rmem_released = 0;
1878+
WRITE_ONCE(msk->rmem_released, 0);
18771879
}
18781880

18791881
static void __mptcp_splice_receive_queue(struct sock *sk)
@@ -2380,7 +2382,7 @@ static int __mptcp_init_sock(struct sock *sk)
23802382
msk->out_of_order_queue = RB_ROOT;
23812383
msk->first_pending = NULL;
23822384
msk->wmem_reserved = 0;
2383-
msk->rmem_released = 0;
2385+
WRITE_ONCE(msk->rmem_released, 0);
23842386
msk->tx_pending_data = 0;
23852387

23862388
msk->first = NULL;

net/mptcp/protocol.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,17 @@ static inline struct mptcp_sock *mptcp_sk(const struct sock *sk)
296296
return (struct mptcp_sock *)sk;
297297
}
298298

299+
/* the msk socket don't use the backlog, also account for the bulk
300+
* free memory
301+
*/
302+
static inline int __mptcp_rmem(const struct sock *sk)
303+
{
304+
return atomic_read(&sk->sk_rmem_alloc) - READ_ONCE(mptcp_sk(sk)->rmem_released);
305+
}
306+
299307
static inline int __mptcp_space(const struct sock *sk)
300308
{
301-
return tcp_space(sk) + READ_ONCE(mptcp_sk(sk)->rmem_released);
309+
return tcp_win_from_space(sk, READ_ONCE(sk->sk_rcvbuf) - __mptcp_rmem(sk));
302310
}
303311

304312
static inline struct mptcp_data_frag *mptcp_send_head(const struct sock *sk)

net/mptcp/subflow.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,6 @@ static int subflow_check_req(struct request_sock *req,
214214
ntohs(inet_sk(sk_listener)->inet_sport),
215215
ntohs(inet_sk((struct sock *)subflow_req->msk)->inet_sport));
216216
if (!mptcp_pm_sport_in_anno_list(subflow_req->msk, sk_listener)) {
217-
sock_put((struct sock *)subflow_req->msk);
218-
mptcp_token_destroy_request(req);
219-
tcp_request_sock_ops.destructor(req);
220-
subflow_req->msk = NULL;
221-
subflow_req->mp_join = 0;
222217
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTSYNRX);
223218
return -EPERM;
224219
}
@@ -230,6 +225,8 @@ static int subflow_check_req(struct request_sock *req,
230225
if (unlikely(req->syncookie)) {
231226
if (mptcp_can_accept_new_subflow(subflow_req->msk))
232227
subflow_init_req_cookie_join_save(subflow_req, skb);
228+
else
229+
return -EPERM;
233230
}
234231

235232
pr_debug("token=%u, remote_nonce=%u msk=%p", subflow_req->token,
@@ -269,9 +266,7 @@ int mptcp_subflow_init_cookie_req(struct request_sock *req,
269266
if (!mptcp_token_join_cookie_init_state(subflow_req, skb))
270267
return -EINVAL;
271268

272-
if (mptcp_can_accept_new_subflow(subflow_req->msk))
273-
subflow_req->mp_join = 1;
274-
269+
subflow_req->mp_join = 1;
275270
subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq - 1;
276271
}
277272

net/mptcp/syncookies.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,21 @@ static spinlock_t join_entry_locks[COOKIE_JOIN_SLOTS] __cacheline_aligned_in_smp
3737

3838
static u32 mptcp_join_entry_hash(struct sk_buff *skb, struct net *net)
3939
{
40-
u32 i = skb_get_hash(skb) ^ net_hash_mix(net);
40+
static u32 mptcp_join_hash_secret __read_mostly;
41+
struct tcphdr *th = tcp_hdr(skb);
42+
u32 seq, i;
43+
44+
net_get_random_once(&mptcp_join_hash_secret,
45+
sizeof(mptcp_join_hash_secret));
46+
47+
if (th->syn)
48+
seq = TCP_SKB_CB(skb)->seq;
49+
else
50+
seq = TCP_SKB_CB(skb)->seq - 1;
51+
52+
i = jhash_3words(seq, net_hash_mix(net),
53+
(__force __u32)th->source << 16 | (__force __u32)th->dest,
54+
mptcp_join_hash_secret);
4155

4256
return i % ARRAY_SIZE(join_entries);
4357
}

tools/testing/selftests/net/mptcp/mptcp_join.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,7 @@ syncookies_tests()
14091409
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
14101410
ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
14111411
run_tests $ns1 $ns2 10.0.1.1
1412-
chk_join_nr "subflows limited by server w cookies" 2 2 1
1412+
chk_join_nr "subflows limited by server w cookies" 2 1 1
14131413

14141414
# test signal address with cookies
14151415
reset_with_cookies

0 commit comments

Comments
 (0)