RDMA/iwcm: Allow AFONLY binding for IPv6 addresses
authorBernard Metzler <bmt@zurich.ibm.com>
Fri, 19 Feb 2021 14:34:41 +0000 (15:34 +0100)
committerJason Gunthorpe <jgg@nvidia.com>
Wed, 10 Mar 2021 19:30:45 +0000 (15:30 -0400)
Binding IPv6 address/port to AF_INET6 domain only is provided via
rdma_set_afonly(), but was not signalled to the provider.  Applications
like NFS/RDMA bind the same port to both IPv4 and IPv6 addresses
simultaneously and thus rely on it working correctly.

Link: https://lore.kernel.org/r/20210219143441.1068-1-bmt@zurich.ibm.com
Tested-by: Chuck Lever <chuck.lever@oracle.com>
Tested-by: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Bernard Metzler <bmt@zurich.ibm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/infiniband/core/cma.c
drivers/infiniband/sw/siw/siw_cm.c
include/rdma/iw_cm.h

index 9409651..4fba08e 100644 (file)
@@ -2474,6 +2474,7 @@ static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog)
 
        id->tos = id_priv->tos;
        id->tos_set = id_priv->tos_set;
+       id->afonly = id_priv->afonly;
        id_priv->cm_id.iw = id;
 
        memcpy(&id_priv->cm_id.iw->local_addr, cma_src_addr(id_priv),
index 1f9e15b..7a5ed86 100644 (file)
@@ -1300,7 +1300,7 @@ static void siw_cm_llp_state_change(struct sock *sk)
 }
 
 static int kernel_bindconnect(struct socket *s, struct sockaddr *laddr,
-                             struct sockaddr *raddr)
+                             struct sockaddr *raddr, bool afonly)
 {
        int rv, flags = 0;
        size_t size = laddr->sa_family == AF_INET ?
@@ -1311,6 +1311,12 @@ static int kernel_bindconnect(struct socket *s, struct sockaddr *laddr,
         */
        sock_set_reuseaddr(s->sk);
 
+       if (afonly) {
+               rv = ip6_sock_set_v6only(s->sk);
+               if (rv)
+                       return rv;
+       }
+
        rv = s->ops->bind(s, laddr, size);
        if (rv < 0)
                return rv;
@@ -1371,7 +1377,7 @@ int siw_connect(struct iw_cm_id *id, struct iw_cm_conn_param *params)
         * mode. Might be reconsidered for async connection setup at
         * TCP level.
         */
-       rv = kernel_bindconnect(s, laddr, raddr);
+       rv = kernel_bindconnect(s, laddr, raddr, id->afonly);
        if (rv != 0) {
                siw_dbg_qp(qp, "kernel_bindconnect: error %d\n", rv);
                goto error;
@@ -1786,6 +1792,15 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
        } else {
                struct sockaddr_in6 *laddr = &to_sockaddr_in6(id->local_addr);
 
+               if (id->afonly) {
+                       rv = ip6_sock_set_v6only(s->sk);
+                       if (rv) {
+                               siw_dbg(id->device,
+                                       "ip6_sock_set_v6only erro: %d\n", rv);
+                               goto error;
+                       }
+               }
+
                /* For wildcard addr, limit binding to current device only */
                if (ipv6_addr_any(&laddr->sin6_addr))
                        s->sk->sk_bound_dev_if = sdev->netdev->ifindex;
index 9197540..03abd30 100644 (file)
@@ -70,6 +70,7 @@ struct iw_cm_id {
        u8  tos;
        bool tos_set:1;
        bool mapped:1;
+       bool afonly:1;
 };
 
 struct iw_cm_conn_param {