forked from mirrors/linux
		
	mptcp: update per unacked sequence on pkt reception
So that we keep per unacked sequence number consistent; since we update per msk data, use an atomic64 cmpxchg() to protect against concurrent updates from multiple subflows. Initialize the snd_una at connect()/accept() time. Co-developed-by: Florian Westphal <fw@strlen.de> Signed-off-by: Florian Westphal <fw@strlen.de> 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>
This commit is contained in:
		
							parent
							
								
									926bdeab55
								
							
						
					
					
						commit
						cc9d256698
					
				
					 3 changed files with 49 additions and 6 deletions
				
			
		|  | @ -744,6 +744,46 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *sk, | |||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static u64 expand_ack(u64 old_ack, u64 cur_ack, bool use_64bit) | ||||
| { | ||||
| 	u32 old_ack32, cur_ack32; | ||||
| 
 | ||||
| 	if (use_64bit) | ||||
| 		return cur_ack; | ||||
| 
 | ||||
| 	old_ack32 = (u32)old_ack; | ||||
| 	cur_ack32 = (u32)cur_ack; | ||||
| 	cur_ack = (old_ack & GENMASK_ULL(63, 32)) + cur_ack32; | ||||
| 	if (unlikely(before(cur_ack32, old_ack32))) | ||||
| 		return cur_ack + (1LL << 32); | ||||
| 	return cur_ack; | ||||
| } | ||||
| 
 | ||||
| static void update_una(struct mptcp_sock *msk, | ||||
| 		       struct mptcp_options_received *mp_opt) | ||||
| { | ||||
| 	u64 new_snd_una, snd_una, old_snd_una = atomic64_read(&msk->snd_una); | ||||
| 	u64 write_seq = READ_ONCE(msk->write_seq); | ||||
| 
 | ||||
| 	/* avoid ack expansion on update conflict, to reduce the risk of
 | ||||
| 	 * wrongly expanding to a future ack sequence number, which is way | ||||
| 	 * more dangerous than missing an ack | ||||
| 	 */ | ||||
| 	new_snd_una = expand_ack(old_snd_una, mp_opt->data_ack, mp_opt->ack64); | ||||
| 
 | ||||
| 	/* ACK for data not even sent yet? Ignore. */ | ||||
| 	if (after64(new_snd_una, write_seq)) | ||||
| 		new_snd_una = old_snd_una; | ||||
| 
 | ||||
| 	while (after64(new_snd_una, old_snd_una)) { | ||||
| 		snd_una = old_snd_una; | ||||
| 		old_snd_una = atomic64_cmpxchg(&msk->snd_una, snd_una, | ||||
| 					       new_snd_una); | ||||
| 		if (old_snd_una == snd_una) | ||||
| 			break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static bool add_addr_hmac_valid(struct mptcp_sock *msk, | ||||
| 				struct mptcp_options_received *mp_opt) | ||||
| { | ||||
|  | @ -805,6 +845,12 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb, | |||
| 	if (!mp_opt->dss) | ||||
| 		return; | ||||
| 
 | ||||
| 	/* we can't wait for recvmsg() to update the ack_seq, otherwise
 | ||||
| 	 * monodirectional flows will stuck | ||||
| 	 */ | ||||
| 	if (mp_opt->use_ack) | ||||
| 		update_una(msk, mp_opt); | ||||
| 
 | ||||
| 	mpext = skb_ext_add(skb, SKB_EXT_MPTCP); | ||||
| 	if (!mpext) | ||||
| 		return; | ||||
|  | @ -831,12 +877,6 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb, | |||
| 		mpext->use_map = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mp_opt->use_ack) { | ||||
| 		mpext->data_ack = mp_opt->data_ack; | ||||
| 		mpext->use_ack = 1; | ||||
| 		mpext->ack64 = mp_opt->ack64; | ||||
| 	} | ||||
| 
 | ||||
| 	mpext->data_fin = mp_opt->data_fin; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -906,6 +906,7 @@ struct sock *mptcp_sk_clone(const struct sock *sk, struct request_sock *req) | |||
| 	} | ||||
| 
 | ||||
| 	msk->write_seq = subflow_req->idsn + 1; | ||||
| 	atomic64_set(&msk->snd_una, msk->write_seq); | ||||
| 	if (subflow_req->remote_key_valid) { | ||||
| 		msk->can_ack = true; | ||||
| 		msk->remote_key = subflow_req->remote_key; | ||||
|  | @ -1107,6 +1108,7 @@ void mptcp_finish_connect(struct sock *ssk) | |||
| 	WRITE_ONCE(msk->write_seq, subflow->idsn + 1); | ||||
| 	WRITE_ONCE(msk->ack_seq, ack_seq); | ||||
| 	WRITE_ONCE(msk->can_ack, 1); | ||||
| 	atomic64_set(&msk->snd_una, msk->write_seq); | ||||
| 
 | ||||
| 	mptcp_pm_new_connection(msk, 0); | ||||
| } | ||||
|  |  | |||
|  | @ -147,6 +147,7 @@ struct mptcp_sock { | |||
| 	u64		remote_key; | ||||
| 	u64		write_seq; | ||||
| 	u64		ack_seq; | ||||
| 	atomic64_t	snd_una; | ||||
| 	u32		token; | ||||
| 	unsigned long	flags; | ||||
| 	bool		can_ack; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Paolo Abeni
						Paolo Abeni