forked from mirrors/linux
		
	net/smc: Dynamic control handshake limitation by socket options
This patch aims to add dynamic control for SMC handshake limitation for every smc sockets, in production environment, it is possible for the same applications to handle different service types, and may have different opinion on SMC handshake limitation. This patch try socket options to complete it, since we don't have socket option level for SMC yet, which requires us to implement it at the same time. This patch does the following: - add new socket option level: SOL_SMC. - add new SMC socket option: SMC_LIMIT_HS. - provide getter/setter for SMC socket options. Link: https://lore.kernel.org/all/20f504f961e1a803f85d64229ad84260434203bd.1644323503.git.alibuda@linux.alibaba.com/ Signed-off-by: D. Wythe <alibuda@linux.alibaba.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									48b6190a00
								
							
						
					
					
						commit
						a6a6fe27ba
					
				
					 4 changed files with 74 additions and 1 deletions
				
			
		| 
						 | 
					@ -366,6 +366,7 @@ struct ucred {
 | 
				
			||||||
#define SOL_XDP		283
 | 
					#define SOL_XDP		283
 | 
				
			||||||
#define SOL_MPTCP	284
 | 
					#define SOL_MPTCP	284
 | 
				
			||||||
#define SOL_MCTP	285
 | 
					#define SOL_MCTP	285
 | 
				
			||||||
 | 
					#define SOL_SMC		286
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* IPX options */
 | 
					/* IPX options */
 | 
				
			||||||
#define IPX_TYPE	1
 | 
					#define IPX_TYPE	1
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -284,4 +284,8 @@ enum {
 | 
				
			||||||
	__SMC_NLA_SEID_TABLE_MAX,
 | 
						__SMC_NLA_SEID_TABLE_MAX,
 | 
				
			||||||
	SMC_NLA_SEID_TABLE_MAX = __SMC_NLA_SEID_TABLE_MAX - 1
 | 
						SMC_NLA_SEID_TABLE_MAX = __SMC_NLA_SEID_TABLE_MAX - 1
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* SMC socket options */
 | 
				
			||||||
 | 
					#define SMC_LIMIT_HS 1	/* constraint on smc handshake */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _UAPI_LINUX_SMC_H */
 | 
					#endif /* _UAPI_LINUX_SMC_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2326,7 +2326,8 @@ static int smc_listen(struct socket *sock, int backlog)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inet_csk(smc->clcsock->sk)->icsk_af_ops = &smc->af_ops;
 | 
						inet_csk(smc->clcsock->sk)->icsk_af_ops = &smc->af_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tcp_sk(smc->clcsock->sk)->smc_hs_congested = smc_hs_congested;
 | 
						if (smc->limit_smc_hs)
 | 
				
			||||||
 | 
							tcp_sk(smc->clcsock->sk)->smc_hs_congested = smc_hs_congested;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = kernel_listen(smc->clcsock, backlog);
 | 
						rc = kernel_listen(smc->clcsock, backlog);
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
| 
						 | 
					@ -2621,6 +2622,67 @@ static int smc_shutdown(struct socket *sock, int how)
 | 
				
			||||||
	return rc ? rc : rc1;
 | 
						return rc ? rc : rc1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __smc_getsockopt(struct socket *sock, int level, int optname,
 | 
				
			||||||
 | 
								    char __user *optval, int __user *optlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct smc_sock *smc;
 | 
				
			||||||
 | 
						int val, len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						smc = smc_sk(sock->sk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (get_user(len, optlen))
 | 
				
			||||||
 | 
							return -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len = min_t(int, len, sizeof(int));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (len < 0)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (optname) {
 | 
				
			||||||
 | 
						case SMC_LIMIT_HS:
 | 
				
			||||||
 | 
							val = smc->limit_smc_hs;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (put_user(len, optlen))
 | 
				
			||||||
 | 
							return -EFAULT;
 | 
				
			||||||
 | 
						if (copy_to_user(optval, &val, len))
 | 
				
			||||||
 | 
							return -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __smc_setsockopt(struct socket *sock, int level, int optname,
 | 
				
			||||||
 | 
								    sockptr_t optval, unsigned int optlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sock *sk = sock->sk;
 | 
				
			||||||
 | 
						struct smc_sock *smc;
 | 
				
			||||||
 | 
						int val, rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						smc = smc_sk(sk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lock_sock(sk);
 | 
				
			||||||
 | 
						switch (optname) {
 | 
				
			||||||
 | 
						case SMC_LIMIT_HS:
 | 
				
			||||||
 | 
							if (optlen < sizeof(int))
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							if (copy_from_sockptr(&val, optval, sizeof(int)))
 | 
				
			||||||
 | 
								return -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							smc->limit_smc_hs = !!val;
 | 
				
			||||||
 | 
							rc = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							rc = -EOPNOTSUPP;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						release_sock(sk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int smc_setsockopt(struct socket *sock, int level, int optname,
 | 
					static int smc_setsockopt(struct socket *sock, int level, int optname,
 | 
				
			||||||
			  sockptr_t optval, unsigned int optlen)
 | 
								  sockptr_t optval, unsigned int optlen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -2630,6 +2692,8 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (level == SOL_TCP && optname == TCP_ULP)
 | 
						if (level == SOL_TCP && optname == TCP_ULP)
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
						else if (level == SOL_SMC)
 | 
				
			||||||
 | 
							return __smc_setsockopt(sock, level, optname, optval, optlen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	smc = smc_sk(sk);
 | 
						smc = smc_sk(sk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2712,6 +2776,9 @@ static int smc_getsockopt(struct socket *sock, int level, int optname,
 | 
				
			||||||
	struct smc_sock *smc;
 | 
						struct smc_sock *smc;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (level == SOL_SMC)
 | 
				
			||||||
 | 
							return __smc_getsockopt(sock, level, optname, optval, optlen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	smc = smc_sk(sock->sk);
 | 
						smc = smc_sk(sock->sk);
 | 
				
			||||||
	mutex_lock(&smc->clcsock_release_lock);
 | 
						mutex_lock(&smc->clcsock_release_lock);
 | 
				
			||||||
	if (!smc->clcsock) {
 | 
						if (!smc->clcsock) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -249,6 +249,7 @@ struct smc_sock {				/* smc sock container */
 | 
				
			||||||
	struct work_struct	smc_listen_work;/* prepare new accept socket */
 | 
						struct work_struct	smc_listen_work;/* prepare new accept socket */
 | 
				
			||||||
	struct list_head	accept_q;	/* sockets to be accepted */
 | 
						struct list_head	accept_q;	/* sockets to be accepted */
 | 
				
			||||||
	spinlock_t		accept_q_lock;	/* protects accept_q */
 | 
						spinlock_t		accept_q_lock;	/* protects accept_q */
 | 
				
			||||||
 | 
						bool			limit_smc_hs;	/* put constraint on handshake */
 | 
				
			||||||
	bool			use_fallback;	/* fallback to tcp */
 | 
						bool			use_fallback;	/* fallback to tcp */
 | 
				
			||||||
	int			fallback_rsn;	/* reason for fallback */
 | 
						int			fallback_rsn;	/* reason for fallback */
 | 
				
			||||||
	u32			peer_diagnosis; /* decline reason from peer */
 | 
						u32			peer_diagnosis; /* decline reason from peer */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue