forked from mirrors/linux
		
	mptcp: retransmit ADD_ADDR when timeout
This patch implemented the retransmition of ADD_ADDR when no ADD_ADDR echo is received. It added a timer with the announced address. When timeout occurs, ADD_ADDR will be retransmitted. Suggested-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Suggested-by: Paolo Abeni <pabeni@redhat.com> Acked-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Geliang Tang <geliangtang@gmail.com> Reviewed-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									08b81d8731
								
							
						
					
					
						commit
						00cfd77b90
					
				
					 3 changed files with 96 additions and 17 deletions
				
			
		|  | @ -893,6 +893,7 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb, | ||||||
| 			mptcp_pm_add_addr_received(msk, &addr); | 			mptcp_pm_add_addr_received(msk, &addr); | ||||||
| 			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDR); | 			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDR); | ||||||
| 		} else { | 		} else { | ||||||
|  | 			mptcp_pm_del_add_timer(msk, &addr); | ||||||
| 			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD); | 			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD); | ||||||
| 		} | 		} | ||||||
| 		mp_opt.add_addr = 0; | 		mp_opt.add_addr = 0; | ||||||
|  |  | ||||||
|  | @ -31,6 +31,9 @@ struct mptcp_pm_addr_entry { | ||||||
| struct mptcp_pm_add_entry { | struct mptcp_pm_add_entry { | ||||||
| 	struct list_head	list; | 	struct list_head	list; | ||||||
| 	struct mptcp_addr_info	addr; | 	struct mptcp_addr_info	addr; | ||||||
|  | 	struct timer_list	add_timer; | ||||||
|  | 	struct mptcp_sock	*sock; | ||||||
|  | 	u8			retrans_times; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct pm_nl_pernet { | struct pm_nl_pernet { | ||||||
|  | @ -46,6 +49,7 @@ struct pm_nl_pernet { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define MPTCP_PM_ADDR_MAX	8 | #define MPTCP_PM_ADDR_MAX	8 | ||||||
|  | #define ADD_ADDR_RETRANS_MAX	3 | ||||||
| 
 | 
 | ||||||
| static bool addresses_equal(const struct mptcp_addr_info *a, | static bool addresses_equal(const struct mptcp_addr_info *a, | ||||||
| 			    struct mptcp_addr_info *b, bool use_port) | 			    struct mptcp_addr_info *b, bool use_port) | ||||||
|  | @ -183,23 +187,83 @@ static void check_work_pending(struct mptcp_sock *msk) | ||||||
| 		WRITE_ONCE(msk->pm.work_pending, false); | 		WRITE_ONCE(msk->pm.work_pending, false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool lookup_anno_list_by_saddr(struct mptcp_sock *msk, | static struct mptcp_pm_add_entry * | ||||||
|  | lookup_anno_list_by_saddr(struct mptcp_sock *msk, | ||||||
| 			  struct mptcp_addr_info *addr) | 			  struct mptcp_addr_info *addr) | ||||||
| { | { | ||||||
| 	struct mptcp_pm_add_entry *entry; | 	struct mptcp_pm_add_entry *entry; | ||||||
| 
 | 
 | ||||||
| 	list_for_each_entry(entry, &msk->pm.anno_list, list) { | 	list_for_each_entry(entry, &msk->pm.anno_list, list) { | ||||||
| 		if (addresses_equal(&entry->addr, addr, false)) | 		if (addresses_equal(&entry->addr, addr, false)) | ||||||
| 			return true; | 			return entry; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return false; | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void mptcp_pm_add_timer(struct timer_list *timer) | ||||||
|  | { | ||||||
|  | 	struct mptcp_pm_add_entry *entry = from_timer(entry, timer, add_timer); | ||||||
|  | 	struct mptcp_sock *msk = entry->sock; | ||||||
|  | 	struct sock *sk = (struct sock *)msk; | ||||||
|  | 
 | ||||||
|  | 	pr_debug("msk=%p", msk); | ||||||
|  | 
 | ||||||
|  | 	if (!msk) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (inet_sk_state_load(sk) == TCP_CLOSE) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (!entry->addr.id) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (mptcp_pm_should_add_signal(msk)) { | ||||||
|  | 		sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	spin_lock_bh(&msk->pm.lock); | ||||||
|  | 
 | ||||||
|  | 	if (!mptcp_pm_should_add_signal(msk)) { | ||||||
|  | 		pr_debug("retransmit ADD_ADDR id=%d", entry->addr.id); | ||||||
|  | 		mptcp_pm_announce_addr(msk, &entry->addr, false); | ||||||
|  | 		entry->retrans_times++; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (entry->retrans_times < ADD_ADDR_RETRANS_MAX) | ||||||
|  | 		sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX); | ||||||
|  | 
 | ||||||
|  | 	spin_unlock_bh(&msk->pm.lock); | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 	__sock_put(sk); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct mptcp_pm_add_entry * | ||||||
|  | mptcp_pm_del_add_timer(struct mptcp_sock *msk, | ||||||
|  | 		       struct mptcp_addr_info *addr) | ||||||
|  | { | ||||||
|  | 	struct mptcp_pm_add_entry *entry; | ||||||
|  | 	struct sock *sk = (struct sock *)msk; | ||||||
|  | 
 | ||||||
|  | 	spin_lock_bh(&msk->pm.lock); | ||||||
|  | 	entry = lookup_anno_list_by_saddr(msk, addr); | ||||||
|  | 	if (entry) | ||||||
|  | 		entry->retrans_times = ADD_ADDR_RETRANS_MAX; | ||||||
|  | 	spin_unlock_bh(&msk->pm.lock); | ||||||
|  | 
 | ||||||
|  | 	if (entry) | ||||||
|  | 		sk_stop_timer_sync(sk, &entry->add_timer); | ||||||
|  | 
 | ||||||
|  | 	return entry; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, | static bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, | ||||||
| 				     struct mptcp_pm_addr_entry *entry) | 				     struct mptcp_pm_addr_entry *entry) | ||||||
| { | { | ||||||
| 	struct mptcp_pm_add_entry *add_entry = NULL; | 	struct mptcp_pm_add_entry *add_entry = NULL; | ||||||
|  | 	struct sock *sk = (struct sock *)msk; | ||||||
| 
 | 
 | ||||||
| 	if (lookup_anno_list_by_saddr(msk, &entry->addr)) | 	if (lookup_anno_list_by_saddr(msk, &entry->addr)) | ||||||
| 		return false; | 		return false; | ||||||
|  | @ -210,21 +274,32 @@ static bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, | ||||||
| 
 | 
 | ||||||
| 	list_add(&add_entry->list, &msk->pm.anno_list); | 	list_add(&add_entry->list, &msk->pm.anno_list); | ||||||
| 
 | 
 | ||||||
|  | 	add_entry->addr = entry->addr; | ||||||
|  | 	add_entry->sock = msk; | ||||||
|  | 	add_entry->retrans_times = 0; | ||||||
|  | 
 | ||||||
|  | 	timer_setup(&add_entry->add_timer, mptcp_pm_add_timer, 0); | ||||||
|  | 	sk_reset_timer(sk, &add_entry->add_timer, jiffies + TCP_RTO_MAX); | ||||||
|  | 
 | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void mptcp_pm_free_anno_list(struct mptcp_sock *msk) | void mptcp_pm_free_anno_list(struct mptcp_sock *msk) | ||||||
| { | { | ||||||
| 	struct mptcp_pm_add_entry *entry, *tmp; | 	struct mptcp_pm_add_entry *entry, *tmp; | ||||||
|  | 	struct sock *sk = (struct sock *)msk; | ||||||
|  | 	LIST_HEAD(free_list); | ||||||
| 
 | 
 | ||||||
| 	pr_debug("msk=%p", msk); | 	pr_debug("msk=%p", msk); | ||||||
| 
 | 
 | ||||||
| 	spin_lock_bh(&msk->pm.lock); | 	spin_lock_bh(&msk->pm.lock); | ||||||
| 	list_for_each_entry_safe(entry, tmp, &msk->pm.anno_list, list) { | 	list_splice_init(&msk->pm.anno_list, &free_list); | ||||||
| 		list_del(&entry->list); | 	spin_unlock_bh(&msk->pm.lock); | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry_safe(entry, tmp, &free_list, list) { | ||||||
|  | 		sk_stop_timer_sync(sk, &entry->add_timer); | ||||||
| 		kfree(entry); | 		kfree(entry); | ||||||
| 	} | 	} | ||||||
| 	spin_unlock_bh(&msk->pm.lock); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk) | static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk) | ||||||
|  | @ -659,15 +734,14 @@ __lookup_addr_by_id(struct pm_nl_pernet *pernet, unsigned int id) | ||||||
| static bool remove_anno_list_by_saddr(struct mptcp_sock *msk, | static bool remove_anno_list_by_saddr(struct mptcp_sock *msk, | ||||||
| 				      struct mptcp_addr_info *addr) | 				      struct mptcp_addr_info *addr) | ||||||
| { | { | ||||||
| 	struct mptcp_pm_add_entry *entry, *tmp; | 	struct mptcp_pm_add_entry *entry; | ||||||
| 
 | 
 | ||||||
| 	list_for_each_entry_safe(entry, tmp, &msk->pm.anno_list, list) { | 	entry = mptcp_pm_del_add_timer(msk, addr); | ||||||
| 		if (addresses_equal(&entry->addr, addr, false)) { | 	if (entry) { | ||||||
| 		list_del(&entry->list); | 		list_del(&entry->list); | ||||||
| 		kfree(entry); | 		kfree(entry); | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
|  | @ -678,11 +752,12 @@ static bool mptcp_pm_remove_anno_addr(struct mptcp_sock *msk, | ||||||
| { | { | ||||||
| 	bool ret; | 	bool ret; | ||||||
| 
 | 
 | ||||||
| 	spin_lock_bh(&msk->pm.lock); |  | ||||||
| 	ret = remove_anno_list_by_saddr(msk, addr); | 	ret = remove_anno_list_by_saddr(msk, addr); | ||||||
| 	if (ret || force) | 	if (ret || force) { | ||||||
|  | 		spin_lock_bh(&msk->pm.lock); | ||||||
| 		mptcp_pm_remove_addr(msk, addr->id); | 		mptcp_pm_remove_addr(msk, addr->id); | ||||||
| 		spin_unlock_bh(&msk->pm.lock); | 		spin_unlock_bh(&msk->pm.lock); | ||||||
|  | 	} | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -444,6 +444,9 @@ void mptcp_pm_add_addr_received(struct mptcp_sock *msk, | ||||||
| 				const struct mptcp_addr_info *addr); | 				const struct mptcp_addr_info *addr); | ||||||
| void mptcp_pm_rm_addr_received(struct mptcp_sock *msk, u8 rm_id); | void mptcp_pm_rm_addr_received(struct mptcp_sock *msk, u8 rm_id); | ||||||
| void mptcp_pm_free_anno_list(struct mptcp_sock *msk); | void mptcp_pm_free_anno_list(struct mptcp_sock *msk); | ||||||
|  | struct mptcp_pm_add_entry * | ||||||
|  | mptcp_pm_del_add_timer(struct mptcp_sock *msk, | ||||||
|  | 		       struct mptcp_addr_info *addr); | ||||||
| 
 | 
 | ||||||
| int mptcp_pm_announce_addr(struct mptcp_sock *msk, | int mptcp_pm_announce_addr(struct mptcp_sock *msk, | ||||||
| 			   const struct mptcp_addr_info *addr, | 			   const struct mptcp_addr_info *addr, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Geliang Tang
						Geliang Tang