forked from mirrors/linux
		
	mptcp: introduce implicit endpoints
In some edge scenarios, an MPTCP subflows can use a local address mapped by a "implicit" endpoint created by the in-kernel path manager. Such endpoints presence can be confusing, as it's creation is hard to track and will prevent the later endpoint creation from the user-space using the same address. Define a new endpoint flag to mark implicit endpoints and allow the user-space to replace implicit them with user-provided data at endpoint creation time. Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
		
							parent
							
								
									6fa0174a7c
								
							
						
					
					
						commit
						d045b9eb95
					
				
					 3 changed files with 47 additions and 19 deletions
				
			
		|  | @ -81,6 +81,7 @@ enum { | |||
| #define MPTCP_PM_ADDR_FLAG_SUBFLOW			(1 << 1) | ||||
| #define MPTCP_PM_ADDR_FLAG_BACKUP			(1 << 2) | ||||
| #define MPTCP_PM_ADDR_FLAG_FULLMESH			(1 << 3) | ||||
| #define MPTCP_PM_ADDR_FLAG_IMPLICIT			(1 << 4) | ||||
| 
 | ||||
| enum { | ||||
| 	MPTCP_PM_CMD_UNSPEC, | ||||
|  |  | |||
|  | @ -877,10 +877,18 @@ static bool address_use_port(struct mptcp_pm_addr_entry *entry) | |||
| 		MPTCP_PM_ADDR_FLAG_SIGNAL; | ||||
| } | ||||
| 
 | ||||
| /* caller must ensure the RCU grace period is already elapsed */ | ||||
| static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry *entry) | ||||
| { | ||||
| 	if (entry->lsk) | ||||
| 		sock_release(entry->lsk); | ||||
| 	kfree(entry); | ||||
| } | ||||
| 
 | ||||
| static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet, | ||||
| 					     struct mptcp_pm_addr_entry *entry) | ||||
| { | ||||
| 	struct mptcp_pm_addr_entry *cur; | ||||
| 	struct mptcp_pm_addr_entry *cur, *del_entry = NULL; | ||||
| 	unsigned int addr_max; | ||||
| 	int ret = -EINVAL; | ||||
| 
 | ||||
|  | @ -901,8 +909,22 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet, | |||
| 	list_for_each_entry(cur, &pernet->local_addr_list, list) { | ||||
| 		if (addresses_equal(&cur->addr, &entry->addr, | ||||
| 				    address_use_port(entry) && | ||||
| 				    address_use_port(cur))) | ||||
| 			goto out; | ||||
| 				    address_use_port(cur))) { | ||||
| 			/* allow replacing the exiting endpoint only if such
 | ||||
| 			 * endpoint is an implicit one and the user-space | ||||
| 			 * did not provide an endpoint id | ||||
| 			 */ | ||||
| 			if (!(cur->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT)) | ||||
| 				goto out; | ||||
| 			if (entry->addr.id) | ||||
| 				goto out; | ||||
| 
 | ||||
| 			pernet->addrs--; | ||||
| 			entry->addr.id = cur->addr.id; | ||||
| 			list_del_rcu(&cur->list); | ||||
| 			del_entry = cur; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!entry->addr.id) { | ||||
|  | @ -938,6 +960,12 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet, | |||
| 
 | ||||
| out: | ||||
| 	spin_unlock_bh(&pernet->lock); | ||||
| 
 | ||||
| 	/* just replaced an existing entry, free it */ | ||||
| 	if (del_entry) { | ||||
| 		synchronize_rcu(); | ||||
| 		__mptcp_pm_release_addr_entry(del_entry); | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  | @ -1036,7 +1064,7 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc) | |||
| 	entry->addr.id = 0; | ||||
| 	entry->addr.port = 0; | ||||
| 	entry->ifindex = 0; | ||||
| 	entry->flags = 0; | ||||
| 	entry->flags = MPTCP_PM_ADDR_FLAG_IMPLICIT; | ||||
| 	entry->lsk = NULL; | ||||
| 	ret = mptcp_pm_nl_append_new_local_addr(pernet, entry); | ||||
| 	if (ret < 0) | ||||
|  | @ -1249,6 +1277,11 @@ static int mptcp_nl_cmd_add_addr(struct sk_buff *skb, struct genl_info *info) | |||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (addr.flags & MPTCP_PM_ADDR_FLAG_IMPLICIT) { | ||||
| 		GENL_SET_ERR_MSG(info, "can't create IMPLICIT endpoint"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||||
| 	if (!entry) { | ||||
| 		GENL_SET_ERR_MSG(info, "can't allocate addr"); | ||||
|  | @ -1333,11 +1366,12 @@ static bool mptcp_pm_remove_anno_addr(struct mptcp_sock *msk, | |||
| } | ||||
| 
 | ||||
| static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, | ||||
| 						   struct mptcp_addr_info *addr) | ||||
| 						   const struct mptcp_pm_addr_entry *entry) | ||||
| { | ||||
| 	struct mptcp_sock *msk; | ||||
| 	long s_slot = 0, s_num = 0; | ||||
| 	const struct mptcp_addr_info *addr = &entry->addr; | ||||
| 	struct mptcp_rm_list list = { .nr = 0 }; | ||||
| 	long s_slot = 0, s_num = 0; | ||||
| 	struct mptcp_sock *msk; | ||||
| 
 | ||||
| 	pr_debug("remove_id=%d", addr->id); | ||||
| 
 | ||||
|  | @ -1354,7 +1388,8 @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, | |||
| 
 | ||||
| 		lock_sock(sk); | ||||
| 		remove_subflow = lookup_subflow_by_saddr(&msk->conn_list, addr); | ||||
| 		mptcp_pm_remove_anno_addr(msk, addr, remove_subflow); | ||||
| 		mptcp_pm_remove_anno_addr(msk, addr, remove_subflow && | ||||
| 					  !(entry->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT)); | ||||
| 		if (remove_subflow) | ||||
| 			mptcp_pm_remove_subflow(msk, &list); | ||||
| 		release_sock(sk); | ||||
|  | @ -1367,14 +1402,6 @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* caller must ensure the RCU grace period is already elapsed */ | ||||
| static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry *entry) | ||||
| { | ||||
| 	if (entry->lsk) | ||||
| 		sock_release(entry->lsk); | ||||
| 	kfree(entry); | ||||
| } | ||||
| 
 | ||||
| static int mptcp_nl_remove_id_zero_address(struct net *net, | ||||
| 					   struct mptcp_addr_info *addr) | ||||
| { | ||||
|  | @ -1451,7 +1478,7 @@ static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info) | |||
| 	__clear_bit(entry->addr.id, pernet->id_bitmap); | ||||
| 	spin_unlock_bh(&pernet->lock); | ||||
| 
 | ||||
| 	mptcp_nl_remove_subflow_and_signal_addr(sock_net(skb->sk), &entry->addr); | ||||
| 	mptcp_nl_remove_subflow_and_signal_addr(sock_net(skb->sk), entry); | ||||
| 	synchronize_rcu(); | ||||
| 	__mptcp_pm_release_addr_entry(entry); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1938,7 +1938,7 @@ backup_tests() | |||
| 	run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup | ||||
| 	chk_join_nr "single address, backup" 1 1 1 | ||||
| 	chk_add_nr 1 1 | ||||
| 	chk_prio_nr 1 0 | ||||
| 	chk_prio_nr 1 1 | ||||
| 
 | ||||
| 	# single address with port, backup | ||||
| 	reset | ||||
|  | @ -1948,7 +1948,7 @@ backup_tests() | |||
| 	run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup | ||||
| 	chk_join_nr "single address with port, backup" 1 1 1 | ||||
| 	chk_add_nr 1 1 | ||||
| 	chk_prio_nr 1 0 | ||||
| 	chk_prio_nr 1 1 | ||||
| } | ||||
| 
 | ||||
| add_addr_ports_tests() | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Paolo Abeni
						Paolo Abeni