net/smc: process add/delete link messages
[platform/kernel/linux-rpi.git] / net / smc / af_smc.c
index 3583c8a..5267ed1 100644 (file)
@@ -7,7 +7,6 @@
  *  applicable with RoCE-cards only
  *
  *  Initial restrictions:
- *    - non-blocking connect postponed
  *    - IPv6 support postponed
  *    - support for alternate links postponed
  *    - partial support for non-blocking sockets only
@@ -24,7 +23,6 @@
 
 #include <linux/module.h>
 #include <linux/socket.h>
-#include <linux/inetdevice.h>
 #include <linux/workqueue.h>
 #include <linux/in.h>
 #include <linux/sched/signal.h>
@@ -273,47 +271,7 @@ static void smc_copy_sock_settings_to_smc(struct smc_sock *smc)
        smc_copy_sock_settings(&smc->sk, smc->clcsock->sk, SK_FLAGS_CLC_TO_SMC);
 }
 
-/* determine subnet and mask of internal TCP socket */
-int smc_netinfo_by_tcpsk(struct socket *clcsock,
-                        __be32 *subnet, u8 *prefix_len)
-{
-       struct dst_entry *dst = sk_dst_get(clcsock->sk);
-       struct in_device *in_dev;
-       struct sockaddr_in addr;
-       int rc = -ENOENT;
-       int len;
-
-       if (!dst) {
-               rc = -ENOTCONN;
-               goto out;
-       }
-       if (!dst->dev) {
-               rc = -ENODEV;
-               goto out_rel;
-       }
-
-       /* get address to which the internal TCP socket is bound */
-       kernel_getsockname(clcsock, (struct sockaddr *)&addr, &len);
-       /* analyze IPv4 specific data of net_device belonging to TCP socket */
-       rcu_read_lock();
-       in_dev = __in_dev_get_rcu(dst->dev);
-       for_ifa(in_dev) {
-               if (!inet_ifa_match(addr.sin_addr.s_addr, ifa))
-                       continue;
-               *prefix_len = inet_mask_len(ifa->ifa_mask);
-               *subnet = ifa->ifa_address & ifa->ifa_mask;
-               rc = 0;
-               break;
-       } endfor_ifa(in_dev);
-       rcu_read_unlock();
-
-out_rel:
-       dst_release(dst);
-out:
-       return rc;
-}
-
-static int smc_clnt_conf_first_link(struct smc_sock *smc, union ib_gid *gid)
+static int smc_clnt_conf_first_link(struct smc_sock *smc)
 {
        struct smc_link_group *lgr = smc->conn.lgr;
        struct smc_link *link;
@@ -333,6 +291,9 @@ static int smc_clnt_conf_first_link(struct smc_sock *smc, union ib_gid *gid)
                return rc;
        }
 
+       if (link->llc_confirm_rc)
+               return SMC_CLC_DECL_RMBE_EC;
+
        rc = smc_ib_modify_qp_rts(link);
        if (rc)
                return SMC_CLC_DECL_INTERR;
@@ -347,11 +308,33 @@ static int smc_clnt_conf_first_link(struct smc_sock *smc, union ib_gid *gid)
        /* send CONFIRM LINK response over RoCE fabric */
        rc = smc_llc_send_confirm_link(link,
                                       link->smcibdev->mac[link->ibport - 1],
-                                      gid, SMC_LLC_RESP);
+                                      &link->smcibdev->gid[link->ibport - 1],
+                                      SMC_LLC_RESP);
        if (rc < 0)
                return SMC_CLC_DECL_TCL;
 
-       return rc;
+       /* receive ADD LINK request from server over RoCE fabric */
+       rest = wait_for_completion_interruptible_timeout(&link->llc_add,
+                                                        SMC_LLC_WAIT_TIME);
+       if (rest <= 0) {
+               struct smc_clc_msg_decline dclc;
+
+               rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc),
+                                     SMC_CLC_DECLINE);
+               return rc;
+       }
+
+       /* send add link reject message, only one link supported for now */
+       rc = smc_llc_send_add_link(link,
+                                  link->smcibdev->mac[link->ibport - 1],
+                                  &link->smcibdev->gid[link->ibport - 1],
+                                  SMC_LLC_RESP);
+       if (rc < 0)
+               return SMC_CLC_DECL_TCL;
+
+       link->state = SMC_LNK_ACTIVE;
+
+       return 0;
 }
 
 static void smc_conn_save_peer_info(struct smc_sock *smc,
@@ -385,7 +368,6 @@ static void smc_lgr_forget(struct smc_link_group *lgr)
 /* setup for RDMA connection of client */
 static int smc_connect_rdma(struct smc_sock *smc)
 {
-       struct sockaddr_in *inaddr = (struct sockaddr_in *)smc->addr;
        struct smc_clc_msg_accept_confirm aclc;
        int local_contact = SMC_FIRST_CONTACT;
        struct smc_ib_device *smcibdev;
@@ -439,8 +421,8 @@ static int smc_connect_rdma(struct smc_sock *smc)
 
        srv_first_contact = aclc.hdr.flag;
        mutex_lock(&smc_create_lgr_pending);
-       local_contact = smc_conn_create(smc, inaddr->sin_addr.s_addr, smcibdev,
-                                       ibport, &aclc.lcl, srv_first_contact);
+       local_contact = smc_conn_create(smc, smcibdev, ibport, &aclc.lcl,
+                                       srv_first_contact);
        if (local_contact < 0) {
                rc = local_contact;
                if (rc == -ENOMEM)
@@ -499,8 +481,7 @@ static int smc_connect_rdma(struct smc_sock *smc)
 
        if (local_contact == SMC_FIRST_CONTACT) {
                /* QP confirmation over RoCE fabric */
-               reason_code = smc_clnt_conf_first_link(
-                       smc, &smcibdev->gid[ibport - 1]);
+               reason_code = smc_clnt_conf_first_link(smc);
                if (reason_code < 0) {
                        rc = reason_code;
                        goto out_err_unlock;
@@ -559,7 +540,6 @@ static int smc_connect(struct socket *sock, struct sockaddr *addr,
                goto out_err;
        if (addr->sa_family != AF_INET)
                goto out_err;
-       smc->addr = addr;       /* needed for nonblocking connect */
 
        lock_sock(sk);
        switch (sk->sk_state) {
@@ -749,9 +729,34 @@ static int smc_serv_conf_first_link(struct smc_sock *smc)
 
                rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc),
                                      SMC_CLC_DECLINE);
+               return rc;
        }
 
-       return rc;
+       if (link->llc_confirm_resp_rc)
+               return SMC_CLC_DECL_RMBE_EC;
+
+       /* send ADD LINK request to client over the RoCE fabric */
+       rc = smc_llc_send_add_link(link,
+                                  link->smcibdev->mac[link->ibport - 1],
+                                  &link->smcibdev->gid[link->ibport - 1],
+                                  SMC_LLC_REQ);
+       if (rc < 0)
+               return SMC_CLC_DECL_TCL;
+
+       /* receive ADD LINK response from client over the RoCE fabric */
+       rest = wait_for_completion_interruptible_timeout(&link->llc_add_resp,
+                                                        SMC_LLC_WAIT_TIME);
+       if (rest <= 0) {
+               struct smc_clc_msg_decline dclc;
+
+               rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc),
+                                     SMC_CLC_DECLINE);
+               return rc;
+       }
+
+       link->state = SMC_LNK_ACTIVE;
+
+       return 0;
 }
 
 /* setup for RDMA connection of server */
@@ -767,11 +772,10 @@ static void smc_listen_work(struct work_struct *work)
        struct sock *newsmcsk = &new_smc->sk;
        struct smc_clc_msg_proposal *pclc;
        struct smc_ib_device *smcibdev;
-       struct sockaddr_in peeraddr;
        u8 buf[SMC_CLC_MAX_LEN];
        struct smc_link *link;
        int reason_code = 0;
-       int rc = 0, len;
+       int rc = 0;
        __be32 subnet;
        u8 prefix_len;
        u8 ibport;
@@ -809,7 +813,7 @@ static void smc_listen_work(struct work_struct *work)
        }
 
        /* determine subnet and mask from internal TCP socket */
-       rc = smc_netinfo_by_tcpsk(newclcsock, &subnet, &prefix_len);
+       rc = smc_clc_netinfo_by_tcpsk(newclcsock, &subnet, &prefix_len);
        if (rc) {
                reason_code = SMC_CLC_DECL_CNFERR; /* configuration error */
                goto decline_rdma;
@@ -823,13 +827,10 @@ static void smc_listen_work(struct work_struct *work)
                goto decline_rdma;
        }
 
-       /* get address of the peer connected to the internal TCP socket */
-       kernel_getpeername(newclcsock, (struct sockaddr *)&peeraddr, &len);
-
        /* allocate connection / link group */
        mutex_lock(&smc_create_lgr_pending);
-       local_contact = smc_conn_create(new_smc, peeraddr.sin_addr.s_addr,
-                                       smcibdev, ibport, &pclc->lcl, 0);
+       local_contact = smc_conn_create(new_smc, smcibdev, ibport, &pclc->lcl,
+                                       0);
        if (local_contact < 0) {
                rc = local_contact;
                if (rc == -ENOMEM)
@@ -1075,7 +1076,7 @@ out:
 }
 
 static int smc_getname(struct socket *sock, struct sockaddr *addr,
-                      int *len, int peer)
+                      int peer)
 {
        struct smc_sock *smc;
 
@@ -1085,7 +1086,7 @@ static int smc_getname(struct socket *sock, struct sockaddr *addr,
 
        smc = smc_sk(sock->sk);
 
-       return smc->clcsock->ops->getname(smc->clcsock, addr, len, peer);
+       return smc->clcsock->ops->getname(smc->clcsock, addr, peer);
 }
 
 static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
@@ -1141,11 +1142,11 @@ out:
 static __poll_t smc_accept_poll(struct sock *parent)
 {
        struct smc_sock *isk = smc_sk(parent);
-       int mask = 0;
+       __poll_t mask = 0;
 
        spin_lock(&isk->accept_q_lock);
        if (!list_empty(&isk->accept_q))
-               mask = POLLIN | POLLRDNORM;
+               mask = EPOLLIN | EPOLLRDNORM;
        spin_unlock(&isk->accept_q_lock);
 
        return mask;
@@ -1160,7 +1161,7 @@ static __poll_t smc_poll(struct file *file, struct socket *sock,
        int rc;
 
        if (!sk)
-               return POLLNVAL;
+               return EPOLLNVAL;
 
        smc = smc_sk(sock->sk);
        sock_hold(sk);
@@ -1171,16 +1172,16 @@ static __poll_t smc_poll(struct file *file, struct socket *sock,
                mask = smc->clcsock->ops->poll(file, smc->clcsock, wait);
                /* if non-blocking connect finished ... */
                lock_sock(sk);
-               if ((sk->sk_state == SMC_INIT) && (mask & POLLOUT)) {
+               if ((sk->sk_state == SMC_INIT) && (mask & EPOLLOUT)) {
                        sk->sk_err = smc->clcsock->sk->sk_err;
                        if (sk->sk_err) {
-                               mask |= POLLERR;
+                               mask |= EPOLLERR;
                        } else {
                                rc = smc_connect_rdma(smc);
                                if (rc < 0)
-                                       mask |= POLLERR;
+                                       mask |= EPOLLERR;
                                /* success cases including fallback */
-                               mask |= POLLOUT | POLLWRNORM;
+                               mask |= EPOLLOUT | EPOLLWRNORM;
                        }
                }
        } else {
@@ -1190,27 +1191,27 @@ static __poll_t smc_poll(struct file *file, struct socket *sock,
                        lock_sock(sk);
                }
                if (sk->sk_err)
-                       mask |= POLLERR;
+                       mask |= EPOLLERR;
                if ((sk->sk_shutdown == SHUTDOWN_MASK) ||
                    (sk->sk_state == SMC_CLOSED))
-                       mask |= POLLHUP;
+                       mask |= EPOLLHUP;
                if (sk->sk_state == SMC_LISTEN) {
                        /* woken up by sk_data_ready in smc_listen_work() */
                        mask = smc_accept_poll(sk);
                } else {
                        if (atomic_read(&smc->conn.sndbuf_space) ||
                            sk->sk_shutdown & SEND_SHUTDOWN) {
-                               mask |= POLLOUT | POLLWRNORM;
+                               mask |= EPOLLOUT | EPOLLWRNORM;
                        } else {
                                sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
                                set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
                        }
                        if (atomic_read(&smc->conn.bytes_to_rcv))
-                               mask |= POLLIN | POLLRDNORM;
+                               mask |= EPOLLIN | EPOLLRDNORM;
                        if (sk->sk_shutdown & RCV_SHUTDOWN)
-                               mask |= POLLIN | POLLRDNORM | POLLRDHUP;
+                               mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP;
                        if (sk->sk_state == SMC_APPCLOSEWAIT1)
-                               mask |= POLLIN;
+                               mask |= EPOLLIN;
                }
 
        }