RDMA/cma: Allow user to restrict listens to bound address family
authorSean Hefty <sean.hefty@intel.com>
Thu, 14 Jun 2012 20:31:39 +0000 (20:31 +0000)
committerRoland Dreier <roland@purestorage.com>
Mon, 9 Jul 2012 01:02:24 +0000 (18:02 -0700)
Provide an option for the user to specify that listens should only
accept connections where the incoming address family matches that of
the locally bound address.  This is used to support the equivalent of
IPV6_V6ONLY socket option, which allows an app to only accept
connection requests directed to IPv6 addresses.

Signed-off-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
drivers/infiniband/core/cma.c
drivers/infiniband/core/ucma.c
include/rdma/rdma_cm.h
include/rdma/rdma_user_cm.h

index 454e7ea111e676bb49bc66129ca5f7bb904bfbd6..8734a6af35d7d5c21b183ed0448f1bf8048cc9f6 100644 (file)
@@ -99,6 +99,10 @@ struct rdma_bind_list {
        unsigned short          port;
 };
 
+enum {
+       CMA_OPTION_AFONLY,
+};
+
 /*
  * Device removal can occur at anytime, so we need extra handling to
  * serialize notifying the user of device removal with other callbacks.
@@ -137,6 +141,7 @@ struct rdma_id_private {
        u32                     qkey;
        u32                     qp_num;
        pid_t                   owner;
+       u32                     options;
        u8                      srq;
        u8                      tos;
        u8                      reuseaddr;
@@ -2104,6 +2109,26 @@ int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse)
 }
 EXPORT_SYMBOL(rdma_set_reuseaddr);
 
+int rdma_set_afonly(struct rdma_cm_id *id, int afonly)
+{
+       struct rdma_id_private *id_priv;
+       unsigned long flags;
+       int ret;
+
+       id_priv = container_of(id, struct rdma_id_private, id);
+       spin_lock_irqsave(&id_priv->lock, flags);
+       if (id_priv->state == RDMA_CM_IDLE || id_priv->state == RDMA_CM_ADDR_BOUND) {
+               id_priv->options |= (1 << CMA_OPTION_AFONLY);
+               id_priv->afonly = afonly;
+               ret = 0;
+       } else {
+               ret = -EINVAL;
+       }
+       spin_unlock_irqrestore(&id_priv->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL(rdma_set_afonly);
+
 static void cma_bind_port(struct rdma_bind_list *bind_list,
                          struct rdma_id_private *id_priv)
 {
@@ -2379,12 +2404,14 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
        }
 
        memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr));
-       if (addr->sa_family == AF_INET)
-               id_priv->afonly = 1;
+       if (!(id_priv->options & (1 << CMA_OPTION_AFONLY))) {
+               if (addr->sa_family == AF_INET)
+                       id_priv->afonly = 1;
 #if IS_ENABLED(CONFIG_IPV6)
-       else if (addr->sa_family == AF_INET6)
-               id_priv->afonly = init_net.ipv6.sysctl.bindv6only;
+               else if (addr->sa_family == AF_INET6)
+                       id_priv->afonly = init_net.ipv6.sysctl.bindv6only;
 #endif
+       }
        ret = cma_get_port(id_priv);
        if (ret)
                goto err2;
index 8002ae642cfebfb692364d85ac87fc0f7b6e5ca5..893cb879462cfe584ea26c314b838bdcd3e3a41f 100644 (file)
@@ -909,6 +909,13 @@ static int ucma_set_option_id(struct ucma_context *ctx, int optname,
                }
                ret = rdma_set_reuseaddr(ctx->cm_id, *((int *) optval) ? 1 : 0);
                break;
+       case RDMA_OPTION_ID_AFONLY:
+               if (optlen != sizeof(int)) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = rdma_set_afonly(ctx->cm_id, *((int *) optval) ? 1 : 0);
+               break;
        default:
                ret = -ENOSYS;
        }
index 51988f8081812f8c0f55f2bae2ac03110a05eb29..ad3a3142383af96774227410ae8da9b801abe2aa 100644 (file)
@@ -357,4 +357,14 @@ void rdma_set_service_type(struct rdma_cm_id *id, int tos);
  */
 int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse);
 
+/**
+ * rdma_set_afonly - Specify that listens are restricted to the
+ *    bound address family only.
+ * @id: Communication identifer to configure.
+ * @afonly: Value indicating if listens are restricted.
+ *
+ * Must be set before identifier is in the listening state.
+ */
+int rdma_set_afonly(struct rdma_cm_id *id, int afonly);
+
 #endif /* RDMA_CM_H */
index 5348a000c8f31f4472c6802afea665c4938ad01d..1ee9239ff8c2aa8db3cc92cd09d7e948eb2e9fa4 100644 (file)
@@ -224,6 +224,7 @@ enum {
 enum {
        RDMA_OPTION_ID_TOS       = 0,
        RDMA_OPTION_ID_REUSEADDR = 1,
+       RDMA_OPTION_ID_AFONLY    = 2,
        RDMA_OPTION_IB_PATH      = 1
 };