mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	mptcp: factor out mptcp_connect()
The current MPTCP connect implementation duplicates a bit of inet
code and does not use nor provide a struct proto->connect callback,
which in turn will not fit the upcoming fastopen implementation.
Refactor such implementation to use the common helper, moving the
MPTCP-specific bits into mptcp_connect(). Additionally, avoid an
indirect call to the subflow connect callback.
Note that the fastopen call-path invokes mptcp_connect() while already
holding the subflow socket lock. Explicitly keep track of such path
via a new MPTCP-level flag and handle the locking accordingly.
Additionally, track the connect flags in a new msk field to allow
propagating them to the subflow inet_stream_connect call.
Fixes: d98a82a6af ("mptcp: handle defer connect in mptcp_sendmsg")
Reviewed-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
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
							
								
									e72e403263
								
							
						
					
					
						commit
						54f1944ed6
					
				
					 2 changed files with 73 additions and 67 deletions
				
			
		| 
						 | 
					@ -1698,7 +1698,10 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		lock_sock(ssk);
 | 
							lock_sock(ssk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							msk->connect_flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0;
 | 
				
			||||||
 | 
							msk->is_sendmsg = 1;
 | 
				
			||||||
		ret = tcp_sendmsg_fastopen(ssk, msg, &copied_syn, len, NULL);
 | 
							ret = tcp_sendmsg_fastopen(ssk, msg, &copied_syn, len, NULL);
 | 
				
			||||||
 | 
							msk->is_sendmsg = 0;
 | 
				
			||||||
		copied += copied_syn;
 | 
							copied += copied_syn;
 | 
				
			||||||
		if (ret == -EINPROGRESS && copied_syn > 0) {
 | 
							if (ret == -EINPROGRESS && copied_syn > 0) {
 | 
				
			||||||
			/* reflect the new state on the MPTCP socket */
 | 
								/* reflect the new state on the MPTCP socket */
 | 
				
			||||||
| 
						 | 
					@ -3507,10 +3510,73 @@ static int mptcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 | 
				
			||||||
	return put_user(answ, (int __user *)arg);
 | 
						return put_user(answ, (int __user *)arg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void mptcp_subflow_early_fallback(struct mptcp_sock *msk,
 | 
				
			||||||
 | 
										 struct mptcp_subflow_context *subflow)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						subflow->request_mptcp = 0;
 | 
				
			||||||
 | 
						__mptcp_do_fallback(msk);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int mptcp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mptcp_subflow_context *subflow;
 | 
				
			||||||
 | 
						struct mptcp_sock *msk = mptcp_sk(sk);
 | 
				
			||||||
 | 
						struct socket *ssock;
 | 
				
			||||||
 | 
						int err = -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ssock = __mptcp_nmpc_socket(msk);
 | 
				
			||||||
 | 
						if (!ssock)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mptcp_token_destroy(msk);
 | 
				
			||||||
 | 
						inet_sk_state_store(sk, TCP_SYN_SENT);
 | 
				
			||||||
 | 
						subflow = mptcp_subflow_ctx(ssock->sk);
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCP_MD5SIG
 | 
				
			||||||
 | 
						/* no MPTCP if MD5SIG is enabled on this socket or we may run out of
 | 
				
			||||||
 | 
						 * TCP option space.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (rcu_access_pointer(tcp_sk(ssock->sk)->md5sig_info))
 | 
				
			||||||
 | 
							mptcp_subflow_early_fallback(msk, subflow);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						if (subflow->request_mptcp && mptcp_token_new_connect(ssock->sk)) {
 | 
				
			||||||
 | 
							MPTCP_INC_STATS(sock_net(ssock->sk), MPTCP_MIB_TOKENFALLBACKINIT);
 | 
				
			||||||
 | 
							mptcp_subflow_early_fallback(msk, subflow);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (likely(!__mptcp_check_fallback(msk)))
 | 
				
			||||||
 | 
							MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* if reaching here via the fastopen/sendmsg path, the caller already
 | 
				
			||||||
 | 
						 * acquired the subflow socket lock, too.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (msk->is_sendmsg)
 | 
				
			||||||
 | 
							err = __inet_stream_connect(ssock, uaddr, addr_len, msk->connect_flags, 1);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							err = inet_stream_connect(ssock, uaddr, addr_len, msk->connect_flags);
 | 
				
			||||||
 | 
						inet_sk(sk)->defer_connect = inet_sk(ssock->sk)->defer_connect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* on successful connect, the msk state will be moved to established by
 | 
				
			||||||
 | 
						 * subflow_finish_connect()
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (unlikely(err && err != -EINPROGRESS)) {
 | 
				
			||||||
 | 
							inet_sk_state_store(sk, inet_sk_state_load(ssock->sk));
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mptcp_copy_inaddrs(sk, ssock->sk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* unblocking connect, mptcp-level inet_stream_connect will error out
 | 
				
			||||||
 | 
						 * without changing the socket state, update it here.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (err == -EINPROGRESS)
 | 
				
			||||||
 | 
							sk->sk_socket->state = ssock->state;
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct proto mptcp_prot = {
 | 
					static struct proto mptcp_prot = {
 | 
				
			||||||
	.name		= "MPTCP",
 | 
						.name		= "MPTCP",
 | 
				
			||||||
	.owner		= THIS_MODULE,
 | 
						.owner		= THIS_MODULE,
 | 
				
			||||||
	.init		= mptcp_init_sock,
 | 
						.init		= mptcp_init_sock,
 | 
				
			||||||
 | 
						.connect	= mptcp_connect,
 | 
				
			||||||
	.disconnect	= mptcp_disconnect,
 | 
						.disconnect	= mptcp_disconnect,
 | 
				
			||||||
	.close		= mptcp_close,
 | 
						.close		= mptcp_close,
 | 
				
			||||||
	.accept		= mptcp_accept,
 | 
						.accept		= mptcp_accept,
 | 
				
			||||||
| 
						 | 
					@ -3562,78 +3628,16 @@ static int mptcp_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void mptcp_subflow_early_fallback(struct mptcp_sock *msk,
 | 
					 | 
				
			||||||
					 struct mptcp_subflow_context *subflow)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	subflow->request_mptcp = 0;
 | 
					 | 
				
			||||||
	__mptcp_do_fallback(msk);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int mptcp_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 | 
					static int mptcp_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 | 
				
			||||||
				int addr_len, int flags)
 | 
									int addr_len, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mptcp_sock *msk = mptcp_sk(sock->sk);
 | 
						int ret;
 | 
				
			||||||
	struct mptcp_subflow_context *subflow;
 | 
					 | 
				
			||||||
	struct socket *ssock;
 | 
					 | 
				
			||||||
	int err = -EINVAL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lock_sock(sock->sk);
 | 
						lock_sock(sock->sk);
 | 
				
			||||||
	if (uaddr) {
 | 
						mptcp_sk(sock->sk)->connect_flags = flags;
 | 
				
			||||||
		if (addr_len < sizeof(uaddr->sa_family))
 | 
						ret = __inet_stream_connect(sock, uaddr, addr_len, flags, 0);
 | 
				
			||||||
			goto unlock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (uaddr->sa_family == AF_UNSPEC) {
 | 
					 | 
				
			||||||
			err = mptcp_disconnect(sock->sk, flags);
 | 
					 | 
				
			||||||
			sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;
 | 
					 | 
				
			||||||
			goto unlock;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (sock->state != SS_UNCONNECTED && msk->subflow) {
 | 
					 | 
				
			||||||
		/* pending connection or invalid state, let existing subflow
 | 
					 | 
				
			||||||
		 * cope with that
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		ssock = msk->subflow;
 | 
					 | 
				
			||||||
		goto do_connect;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ssock = __mptcp_nmpc_socket(msk);
 | 
					 | 
				
			||||||
	if (!ssock)
 | 
					 | 
				
			||||||
		goto unlock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mptcp_token_destroy(msk);
 | 
					 | 
				
			||||||
	inet_sk_state_store(sock->sk, TCP_SYN_SENT);
 | 
					 | 
				
			||||||
	subflow = mptcp_subflow_ctx(ssock->sk);
 | 
					 | 
				
			||||||
#ifdef CONFIG_TCP_MD5SIG
 | 
					 | 
				
			||||||
	/* no MPTCP if MD5SIG is enabled on this socket or we may run out of
 | 
					 | 
				
			||||||
	 * TCP option space.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (rcu_access_pointer(tcp_sk(ssock->sk)->md5sig_info))
 | 
					 | 
				
			||||||
		mptcp_subflow_early_fallback(msk, subflow);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	if (subflow->request_mptcp && mptcp_token_new_connect(ssock->sk)) {
 | 
					 | 
				
			||||||
		MPTCP_INC_STATS(sock_net(ssock->sk), MPTCP_MIB_TOKENFALLBACKINIT);
 | 
					 | 
				
			||||||
		mptcp_subflow_early_fallback(msk, subflow);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (likely(!__mptcp_check_fallback(msk)))
 | 
					 | 
				
			||||||
		MPTCP_INC_STATS(sock_net(sock->sk), MPTCP_MIB_MPCAPABLEACTIVE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
do_connect:
 | 
					 | 
				
			||||||
	err = ssock->ops->connect(ssock, uaddr, addr_len, flags);
 | 
					 | 
				
			||||||
	inet_sk(sock->sk)->defer_connect = inet_sk(ssock->sk)->defer_connect;
 | 
					 | 
				
			||||||
	sock->state = ssock->state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* on successful connect, the msk state will be moved to established by
 | 
					 | 
				
			||||||
	 * subflow_finish_connect()
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (!err || err == -EINPROGRESS)
 | 
					 | 
				
			||||||
		mptcp_copy_inaddrs(sock->sk, ssock->sk);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		inet_sk_state_store(sock->sk, inet_sk_state_load(ssock->sk));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
unlock:
 | 
					 | 
				
			||||||
	release_sock(sock->sk);
 | 
						release_sock(sock->sk);
 | 
				
			||||||
	return err;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int mptcp_listen(struct socket *sock, int backlog)
 | 
					static int mptcp_listen(struct socket *sock, int backlog)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -285,7 +285,9 @@ struct mptcp_sock {
 | 
				
			||||||
	u8		mpc_endpoint_id;
 | 
						u8		mpc_endpoint_id;
 | 
				
			||||||
	u8		recvmsg_inq:1,
 | 
						u8		recvmsg_inq:1,
 | 
				
			||||||
			cork:1,
 | 
								cork:1,
 | 
				
			||||||
			nodelay:1;
 | 
								nodelay:1,
 | 
				
			||||||
 | 
								is_sendmsg:1;
 | 
				
			||||||
 | 
						int		connect_flags;
 | 
				
			||||||
	struct work_struct work;
 | 
						struct work_struct work;
 | 
				
			||||||
	struct sk_buff  *ooo_last_skb;
 | 
						struct sk_buff  *ooo_last_skb;
 | 
				
			||||||
	struct rb_root  out_of_order_queue;
 | 
						struct rb_root  out_of_order_queue;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue