Commit ee9dfbef authored by Ursula Braun's avatar Ursula Braun Committed by David S. Miller

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: default avatarUrsula Braun <ubraun@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 33825761
...@@ -391,6 +391,9 @@ static int smc_connect_rdma(struct smc_sock *smc) ...@@ -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) ...@@ -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) ...@@ -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,6 +1010,7 @@ static int smc_listen(struct socket *sock, int backlog) ...@@ -1004,6 +1010,7 @@ 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);
if (!smc->use_fallback)
tcp_sk(smc->clcsock->sk)->syn_smc = 1; tcp_sk(smc->clcsock->sk)->syn_smc = 1;
rc = kernel_listen(smc->clcsock, backlog); rc = kernel_listen(smc->clcsock, backlog);
...@@ -1097,6 +1104,16 @@ static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) ...@@ -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, ...@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment