mptcp: support TCP_CORK and TCP_NODELAY
First, add cork and nodelay fields to the mptcp_sock structure so they can be used in sync_socket_options(), and fill them on setsockopt while holding the msk socket lock. Then, on setsockopt set proper tcp_sk(ssk)->nonagle values for subflows by calling __tcp_sock_set_cork() or __tcp_sock_set_nodelay() on the ssk while holding the ssk socket lock. tcp_push_pending_frames() will be invoked on the ssk if a cork was cleared or nodelay was set. Also set MPTCP_PUSH_PENDING bit by calling mptcp_check_and_set_pending(). This will lead to __mptcp_push_pending() being called inside mptcp_release_cb() with new tcp_sk(ssk)->nonagle. Also add getsockopt support for TCP_CORK and TCP_NODELAY. Acked-by: Paolo Abeni <pabeni@redhat.com> Reviewed-by: Matthieu Baerts <matthieu.baerts@tessares.net> Signed-off-by: Maxim Galaganov <max@internet.ru> Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
		
				
					committed by
					
						 Jakub Kicinski
						Jakub Kicinski
					
				
			
			
				
	
			
			
			
						parent
						
							8b38217a2a
						
					
				
				
					commit
					4f6e14bd19
				
			| @@ -616,6 +616,66 @@ static int mptcp_setsockopt_sol_tcp_congestion(struct mptcp_sock *msk, sockptr_t | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int mptcp_setsockopt_sol_tcp_cork(struct mptcp_sock *msk, sockptr_t optval, | ||||
| 					 unsigned int optlen) | ||||
| { | ||||
| 	struct mptcp_subflow_context *subflow; | ||||
| 	struct sock *sk = (struct sock *)msk; | ||||
| 	int val; | ||||
| 
 | ||||
| 	if (optlen < sizeof(int)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (copy_from_sockptr(&val, optval, sizeof(val))) | ||||
| 		return -EFAULT; | ||||
| 
 | ||||
| 	lock_sock(sk); | ||||
| 	sockopt_seq_inc(msk); | ||||
| 	msk->cork = !!val; | ||||
| 	mptcp_for_each_subflow(msk, subflow) { | ||||
| 		struct sock *ssk = mptcp_subflow_tcp_sock(subflow); | ||||
| 
 | ||||
| 		lock_sock(ssk); | ||||
| 		__tcp_sock_set_cork(ssk, !!val); | ||||
| 		release_sock(ssk); | ||||
| 	} | ||||
| 	if (!val) | ||||
| 		mptcp_check_and_set_pending(sk); | ||||
| 	release_sock(sk); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int mptcp_setsockopt_sol_tcp_nodelay(struct mptcp_sock *msk, sockptr_t optval, | ||||
| 					    unsigned int optlen) | ||||
| { | ||||
| 	struct mptcp_subflow_context *subflow; | ||||
| 	struct sock *sk = (struct sock *)msk; | ||||
| 	int val; | ||||
| 
 | ||||
| 	if (optlen < sizeof(int)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (copy_from_sockptr(&val, optval, sizeof(val))) | ||||
| 		return -EFAULT; | ||||
| 
 | ||||
| 	lock_sock(sk); | ||||
| 	sockopt_seq_inc(msk); | ||||
| 	msk->nodelay = !!val; | ||||
| 	mptcp_for_each_subflow(msk, subflow) { | ||||
| 		struct sock *ssk = mptcp_subflow_tcp_sock(subflow); | ||||
| 
 | ||||
| 		lock_sock(ssk); | ||||
| 		__tcp_sock_set_nodelay(ssk, !!val); | ||||
| 		release_sock(ssk); | ||||
| 	} | ||||
| 	if (val) | ||||
| 		mptcp_check_and_set_pending(sk); | ||||
| 	release_sock(sk); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int mptcp_setsockopt_sol_ip_set_transparent(struct mptcp_sock *msk, int optname, | ||||
| 						   sockptr_t optval, unsigned int optlen) | ||||
| { | ||||
| @@ -717,6 +777,10 @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname, | ||||
| 		return -EOPNOTSUPP; | ||||
| 	case TCP_CONGESTION: | ||||
| 		return mptcp_setsockopt_sol_tcp_congestion(msk, optval, optlen); | ||||
| 	case TCP_CORK: | ||||
| 		return mptcp_setsockopt_sol_tcp_cork(msk, optval, optlen); | ||||
| 	case TCP_NODELAY: | ||||
| 		return mptcp_setsockopt_sol_tcp_nodelay(msk, optval, optlen); | ||||
| 	} | ||||
| 
 | ||||
| 	return -EOPNOTSUPP; | ||||
| @@ -1087,6 +1151,10 @@ static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname, | ||||
| 						      optval, optlen); | ||||
| 	case TCP_INQ: | ||||
| 		return mptcp_put_int_option(msk, optval, optlen, msk->recvmsg_inq); | ||||
| 	case TCP_CORK: | ||||
| 		return mptcp_put_int_option(msk, optval, optlen, msk->cork); | ||||
| 	case TCP_NODELAY: | ||||
| 		return mptcp_put_int_option(msk, optval, optlen, msk->nodelay); | ||||
| 	} | ||||
| 	return -EOPNOTSUPP; | ||||
| } | ||||
| @@ -1189,6 +1257,8 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk) | ||||
| 
 | ||||
| 	if (inet_csk(sk)->icsk_ca_ops != inet_csk(ssk)->icsk_ca_ops) | ||||
| 		tcp_set_congestion_control(ssk, msk->ca_name, false, true); | ||||
| 	__tcp_sock_set_cork(ssk, !!msk->cork); | ||||
| 	__tcp_sock_set_nodelay(ssk, !!msk->nodelay); | ||||
| 
 | ||||
| 	inet_sk(ssk)->transparent = inet_sk(sk)->transparent; | ||||
| 	inet_sk(ssk)->freebind = inet_sk(sk)->freebind; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user