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
|
@ -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 New Issue