mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net/smc: handle sockopts forcing fallback
Several TCP sockopts do not work for SMC. One example are the TCP_FASTOPEN sockopts, since SMC-connection setup is based on the TCP three-way-handshake. If the SMC socket is still in state SMC_INIT, such sockopts trigger fallback to TCP. Otherwise an error is returned. Signed-off-by: Ursula Braun <ubraun@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									3382576106
								
							
						
					
					
						commit
						ee9dfbef02
					
				
					 1 changed files with 50 additions and 4 deletions
				
			
		| 
						 | 
					@ -391,6 +391,9 @@ static int smc_connect_rdma(struct smc_sock *smc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sock_hold(&smc->sk); /* sock put in passive closing */
 | 
						sock_hold(&smc->sk); /* sock put in passive closing */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (smc->use_fallback)
 | 
				
			||||||
 | 
							goto out_connected;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!tcp_sk(smc->clcsock->sk)->syn_smc) {
 | 
						if (!tcp_sk(smc->clcsock->sk)->syn_smc) {
 | 
				
			||||||
		/* peer has not signalled SMC-capability */
 | 
							/* peer has not signalled SMC-capability */
 | 
				
			||||||
		smc->use_fallback = true;
 | 
							smc->use_fallback = true;
 | 
				
			||||||
| 
						 | 
					@ -790,6 +793,9 @@ static void smc_listen_work(struct work_struct *work)
 | 
				
			||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	u8 ibport;
 | 
						u8 ibport;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (new_smc->use_fallback)
 | 
				
			||||||
 | 
							goto out_connected;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check if peer is smc capable */
 | 
						/* check if peer is smc capable */
 | 
				
			||||||
	if (!tcp_sk(newclcsock->sk)->syn_smc) {
 | 
						if (!tcp_sk(newclcsock->sk)->syn_smc) {
 | 
				
			||||||
		new_smc->use_fallback = true;
 | 
							new_smc->use_fallback = true;
 | 
				
			||||||
| 
						 | 
					@ -968,7 +974,7 @@ static void smc_tcp_listen_work(struct work_struct *work)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		new_smc->listen_smc = lsmc;
 | 
							new_smc->listen_smc = lsmc;
 | 
				
			||||||
		new_smc->use_fallback = false; /* assume rdma capability first*/
 | 
							new_smc->use_fallback = lsmc->use_fallback;
 | 
				
			||||||
		sock_hold(lsk); /* sock_put in smc_listen_work */
 | 
							sock_hold(lsk); /* sock_put in smc_listen_work */
 | 
				
			||||||
		INIT_WORK(&new_smc->smc_listen_work, smc_listen_work);
 | 
							INIT_WORK(&new_smc->smc_listen_work, smc_listen_work);
 | 
				
			||||||
		smc_copy_sock_settings_to_smc(new_smc);
 | 
							smc_copy_sock_settings_to_smc(new_smc);
 | 
				
			||||||
| 
						 | 
					@ -1004,7 +1010,8 @@ static int smc_listen(struct socket *sock, int backlog)
 | 
				
			||||||
	 * them to the clc socket -- copy smc socket options to clc socket
 | 
						 * them to the clc socket -- copy smc socket options to clc socket
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	smc_copy_sock_settings_to_clc(smc);
 | 
						smc_copy_sock_settings_to_clc(smc);
 | 
				
			||||||
	tcp_sk(smc->clcsock->sk)->syn_smc = 1;
 | 
						if (!smc->use_fallback)
 | 
				
			||||||
 | 
							tcp_sk(smc->clcsock->sk)->syn_smc = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = kernel_listen(smc->clcsock, backlog);
 | 
						rc = kernel_listen(smc->clcsock, backlog);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
| 
						 | 
					@ -1097,6 +1104,16 @@ static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 | 
				
			||||||
	    (sk->sk_state != SMC_APPCLOSEWAIT1) &&
 | 
						    (sk->sk_state != SMC_APPCLOSEWAIT1) &&
 | 
				
			||||||
	    (sk->sk_state != SMC_INIT))
 | 
						    (sk->sk_state != SMC_INIT))
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (msg->msg_flags & MSG_FASTOPEN) {
 | 
				
			||||||
 | 
							if (sk->sk_state == SMC_INIT) {
 | 
				
			||||||
 | 
								smc->use_fallback = true;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								rc = -EINVAL;
 | 
				
			||||||
 | 
								goto out;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (smc->use_fallback)
 | 
						if (smc->use_fallback)
 | 
				
			||||||
		rc = smc->clcsock->ops->sendmsg(smc->clcsock, msg, len);
 | 
							rc = smc->clcsock->ops->sendmsg(smc->clcsock, msg, len);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					@ -1274,14 +1291,43 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sock *sk = sock->sk;
 | 
						struct sock *sk = sock->sk;
 | 
				
			||||||
	struct smc_sock *smc;
 | 
						struct smc_sock *smc;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	smc = smc_sk(sk);
 | 
						smc = smc_sk(sk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* generic setsockopts reaching us here always apply to the
 | 
						/* generic setsockopts reaching us here always apply to the
 | 
				
			||||||
	 * CLC socket
 | 
						 * CLC socket
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	return smc->clcsock->ops->setsockopt(smc->clcsock, level, optname,
 | 
						rc = smc->clcsock->ops->setsockopt(smc->clcsock, level, optname,
 | 
				
			||||||
					     optval, optlen);
 | 
										   optval, optlen);
 | 
				
			||||||
 | 
						if (smc->clcsock->sk->sk_err) {
 | 
				
			||||||
 | 
							sk->sk_err = smc->clcsock->sk->sk_err;
 | 
				
			||||||
 | 
							sk->sk_error_report(sk);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lock_sock(sk);
 | 
				
			||||||
 | 
						switch (optname) {
 | 
				
			||||||
 | 
						case TCP_ULP:
 | 
				
			||||||
 | 
						case TCP_FASTOPEN:
 | 
				
			||||||
 | 
						case TCP_FASTOPEN_CONNECT:
 | 
				
			||||||
 | 
						case TCP_FASTOPEN_KEY:
 | 
				
			||||||
 | 
						case TCP_FASTOPEN_NO_COOKIE:
 | 
				
			||||||
 | 
							/* option not supported by SMC */
 | 
				
			||||||
 | 
							if (sk->sk_state == SMC_INIT) {
 | 
				
			||||||
 | 
								smc->use_fallback = true;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (!smc->use_fallback)
 | 
				
			||||||
 | 
									rc = -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						release_sock(sk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int smc_getsockopt(struct socket *sock, int level, int optname,
 | 
					static int smc_getsockopt(struct socket *sock, int level, int optname,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue