IB/cma: Accept connection without a valid netdev on RoCE
authorHaggai Eran <haggaie@mellanox.com>
Tue, 6 Oct 2015 14:56:00 +0000 (17:56 +0300)
committerDoug Ledford <dledford@redhat.com>
Tue, 6 Oct 2015 18:25:16 +0000 (14:25 -0400)
The netdev checks recently added to RDMA CM expect a valid netdev to be
found for both InfiniBand and RoCE, but the code that find a netdev is
only implemented for InfiniBand.

Currently RoCE doesn't provide an API to find the netdev matching a
given set of parameters, so this patch just disables the netdev enforcement
for each incoming connections when the link layer is RoCE.

Fixes: 4c21b5bcef73 ("IB/cma: Add net_dev and private data checks to RDMA CM")
Reported-by: Kamal Heib <kamalh@mellanox.com>
Signed-off-by: Haggai Eran <haggaie@mellanox.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/core/cma.c

index b1ab13f3e182bb520cc986512d11e9016ecf1362..59a2dafc8c574df13b5d186f9b0987c06c8e58c6 100644 (file)
@@ -1232,14 +1232,32 @@ static bool cma_match_private_data(struct rdma_id_private *id_priv,
        return true;
 }
 
+static bool cma_protocol_roce_dev_port(struct ib_device *device, int port_num)
+{
+       enum rdma_link_layer ll = rdma_port_get_link_layer(device, port_num);
+       enum rdma_transport_type transport =
+               rdma_node_get_transport(device->node_type);
+
+       return ll == IB_LINK_LAYER_ETHERNET && transport == RDMA_TRANSPORT_IB;
+}
+
+static bool cma_protocol_roce(const struct rdma_cm_id *id)
+{
+       struct ib_device *device = id->device;
+       const int port_num = id->port_num ?: rdma_start_port(device);
+
+       return cma_protocol_roce_dev_port(device, port_num);
+}
+
 static bool cma_match_net_dev(const struct rdma_id_private *id_priv,
                              const struct net_device *net_dev)
 {
        const struct rdma_addr *addr = &id_priv->id.route.addr;
 
        if (!net_dev)
-               /* This request is an AF_IB request */
-               return addr->src_addr.ss_family == AF_IB;
+               /* This request is an AF_IB request or a RoCE request */
+               return addr->src_addr.ss_family == AF_IB ||
+                      cma_protocol_roce(&id_priv->id);
 
        return !addr->dev_addr.bound_dev_if ||
               (net_eq(dev_net(net_dev), &init_net) &&
@@ -1294,6 +1312,10 @@ static struct rdma_id_private *cma_id_from_event(struct ib_cm_id *cm_id,
                if (PTR_ERR(*net_dev) == -EAFNOSUPPORT) {
                        /* Assuming the protocol is AF_IB */
                        *net_dev = NULL;
+               } else if (cma_protocol_roce_dev_port(req.device, req.port)) {
+                       /* TODO find the net dev matching the request parameters
+                        * through the RoCE GID table */
+                       *net_dev = NULL;
                } else {
                        return ERR_CAST(*net_dev);
                }
@@ -1593,11 +1615,16 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
                if (ret)
                        goto err;
        } else {
-               /* An AF_IB connection */
-               WARN_ON_ONCE(ss_family != AF_IB);
-
-               cma_translate_ib((struct sockaddr_ib *)cma_src_addr(id_priv),
-                                &rt->addr.dev_addr);
+               if (!cma_protocol_roce(listen_id) &&
+                   cma_any_addr(cma_src_addr(id_priv))) {
+                       rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND;
+                       rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
+                       ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey));
+               } else if (!cma_any_addr(cma_src_addr(id_priv))) {
+                       ret = cma_translate_addr(cma_src_addr(id_priv), &rt->addr.dev_addr);
+                       if (ret)
+                               goto err;
+               }
        }
        rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
 
@@ -1635,13 +1662,12 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
                if (ret)
                        goto err;
        } else {
-               /* An AF_IB connection */
-               WARN_ON_ONCE(ss_family != AF_IB);
-
-               if (!cma_any_addr(cma_src_addr(id_priv)))
-                       cma_translate_ib((struct sockaddr_ib *)
-                                               cma_src_addr(id_priv),
-                                        &id->route.addr.dev_addr);
+               if (!cma_any_addr(cma_src_addr(id_priv))) {
+                       ret = cma_translate_addr(cma_src_addr(id_priv),
+                                                &id->route.addr.dev_addr);
+                       if (ret)
+                               goto err;
+               }
        }
 
        id_priv->state = RDMA_CM_CONNECT;