]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/infiniband/core/cma.c
IB/cma: Destination and source addr families must match
[karo-tx-linux.git] / drivers / infiniband / core / cma.c
index e7dcfac877ca2eb7b86601a9115b4c2fc27f4c01..ba60e4b5114cdc01989983369ae29ddfb6328fde 100644 (file)
@@ -198,6 +198,7 @@ struct cma_device {
        atomic_t                refcount;
        struct list_head        id_list;
        enum ib_gid_type        *default_gid_type;
+       u8                      *default_roce_tos;
 };
 
 struct rdma_bind_list {
@@ -269,8 +270,7 @@ struct cma_device *cma_enum_devices_by_ibdev(cma_device_filter      filter,
 int cma_get_default_gid_type(struct cma_device *cma_dev,
                             unsigned int port)
 {
-       if (port < rdma_start_port(cma_dev->device) ||
-           port > rdma_end_port(cma_dev->device))
+       if (!rdma_is_port_valid(cma_dev->device, port))
                return -EINVAL;
 
        return cma_dev->default_gid_type[port - rdma_start_port(cma_dev->device)];
@@ -282,8 +282,7 @@ int cma_set_default_gid_type(struct cma_device *cma_dev,
 {
        unsigned long supported_gids;
 
-       if (port < rdma_start_port(cma_dev->device) ||
-           port > rdma_end_port(cma_dev->device))
+       if (!rdma_is_port_valid(cma_dev->device, port))
                return -EINVAL;
 
        supported_gids = roce_gid_type_mask_support(cma_dev->device, port);
@@ -297,6 +296,25 @@ int cma_set_default_gid_type(struct cma_device *cma_dev,
        return 0;
 }
 
+int cma_get_default_roce_tos(struct cma_device *cma_dev, unsigned int port)
+{
+       if (!rdma_is_port_valid(cma_dev->device, port))
+               return -EINVAL;
+
+       return cma_dev->default_roce_tos[port - rdma_start_port(cma_dev->device)];
+}
+
+int cma_set_default_roce_tos(struct cma_device *cma_dev, unsigned int port,
+                            u8 default_roce_tos)
+{
+       if (!rdma_is_port_valid(cma_dev->device, port))
+               return -EINVAL;
+
+       cma_dev->default_roce_tos[port - rdma_start_port(cma_dev->device)] =
+                default_roce_tos;
+
+       return 0;
+}
 struct ib_device *cma_get_ib_dev(struct cma_device *cma_dev)
 {
        return cma_dev->device;
@@ -343,6 +361,7 @@ struct rdma_id_private {
        u32                     options;
        u8                      srq;
        u8                      tos;
+       bool                    tos_set;
        u8                      reuseaddr;
        u8                      afonly;
        enum ib_gid_type        gid_type;
@@ -709,6 +728,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
        union ib_gid gid, sgid, *dgid;
        u16 pkey, index;
        u8 p;
+       enum ib_port_state port_state;
        int i;
 
        cma_dev = NULL;
@@ -724,6 +744,8 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
                        if (ib_find_cached_pkey(cur_dev->device, p, pkey, &index))
                                continue;
 
+                       if (ib_get_cached_port_state(cur_dev->device, p, &port_state))
+                               continue;
                        for (i = 0; !ib_get_cached_gid(cur_dev->device, p, i,
                                                       &gid, NULL);
                             i++) {
@@ -735,7 +757,8 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
                                }
 
                                if (!cma_dev && (gid.global.subnet_prefix ==
-                                                dgid->global.subnet_prefix)) {
+                                   dgid->global.subnet_prefix) &&
+                                   port_state == IB_PORT_ACTIVE) {
                                        cma_dev = cur_dev;
                                        sgid = gid;
                                        id_priv->id.port_num = p;
@@ -778,6 +801,7 @@ struct rdma_cm_id *rdma_create_id(struct net *net,
        id_priv->id.event_handler = event_handler;
        id_priv->id.ps = ps;
        id_priv->id.qp_type = qp_type;
+       id_priv->tos_set = false;
        spin_lock_init(&id_priv->lock);
        mutex_init(&id_priv->qp_mutex);
        init_completion(&id_priv->comp);
@@ -1689,6 +1713,7 @@ static int cma_rep_recv(struct rdma_id_private *id_priv)
 
        return 0;
 reject:
+       pr_debug_ratelimited("RDMA CM: CONNECT_ERROR: failed to handle reply. status %d\n", ret);
        cma_modify_qp_err(id_priv);
        ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED,
                       NULL, 0, NULL, 0);
@@ -1760,6 +1785,8 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
                /* ignore event */
                goto out;
        case IB_CM_REJ_RECEIVED:
+               pr_debug_ratelimited("RDMA CM: REJECTED: %s\n", rdma_reject_msg(&id_priv->id,
+                                                                               ib_event->param.rej_rcvd.reason));
                cma_modify_qp_err(id_priv);
                event.status = ib_event->param.rej_rcvd.reason;
                event.event = RDMA_CM_EVENT_REJECTED;
@@ -2266,6 +2293,7 @@ void rdma_set_service_type(struct rdma_cm_id *id, int tos)
 
        id_priv = container_of(id, struct rdma_id_private, id);
        id_priv->tos = (u8) tos;
+       id_priv->tos_set = true;
 }
 EXPORT_SYMBOL(rdma_set_service_type);
 
@@ -2285,6 +2313,8 @@ static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
                work->new_state = RDMA_CM_ADDR_RESOLVED;
                work->event.event = RDMA_CM_EVENT_ROUTE_ERROR;
                work->event.status = status;
+               pr_debug_ratelimited("RDMA CM: ROUTE_ERROR: failed to query path. status %d\n",
+                                    status);
        }
 
        queue_work(cma_wq, &work->work);
@@ -2500,6 +2530,9 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
        struct cma_work *work;
        int ret;
        struct net_device *ndev = NULL;
+       u8 default_roce_tos = id_priv->cma_dev->default_roce_tos[id_priv->id.port_num -
+                                       rdma_start_port(id_priv->cma_dev->device)];
+       u8 tos = id_priv->tos_set ? id_priv->tos : default_roce_tos;
 
 
        work = kzalloc(sizeof *work, GFP_KERNEL);
@@ -2573,7 +2606,8 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
        route->path_rec->reversible = 1;
        route->path_rec->pkey = cpu_to_be16(0xffff);
        route->path_rec->mtu_selector = IB_SA_EQ;
-       route->path_rec->sl = iboe_tos_to_sl(ndev, id_priv->tos);
+       route->path_rec->sl = iboe_tos_to_sl(ndev, tos);
+       route->path_rec->traffic_class = tos;
        route->path_rec->mtu = iboe_get_mtu(ndev->mtu);
        route->path_rec->rate_selector = IB_SA_EQ;
        route->path_rec->rate = iboe_get_rate(ndev);
@@ -2652,8 +2686,8 @@ static void cma_set_loopback(struct sockaddr *addr)
 static int cma_bind_loopback(struct rdma_id_private *id_priv)
 {
        struct cma_device *cma_dev, *cur_dev;
-       struct ib_port_attr port_attr;
        union ib_gid gid;
+       enum ib_port_state port_state;
        u16 pkey;
        int ret;
        u8 p;
@@ -2669,8 +2703,8 @@ static int cma_bind_loopback(struct rdma_id_private *id_priv)
                        cma_dev = cur_dev;
 
                for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) {
-                       if (!ib_query_port(cur_dev->device, p, &port_attr) &&
-                           port_attr.state == IB_PORT_ACTIVE) {
+                       if (!ib_get_cached_port_state(cur_dev->device, p, &port_state) &&
+                           port_state == IB_PORT_ACTIVE) {
                                cma_dev = cur_dev;
                                goto port_found;
                        }
@@ -2720,8 +2754,14 @@ static void addr_handler(int status, struct sockaddr *src_addr,
                goto out;
 
        memcpy(cma_src_addr(id_priv), src_addr, rdma_addr_size(src_addr));
-       if (!status && !id_priv->cma_dev)
+       if (!status && !id_priv->cma_dev) {
                status = cma_acquire_dev(id_priv, NULL);
+               if (status)
+                       pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to acquire device. status %d\n",
+                                            status);
+       } else {
+               pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to resolve IP. status %d\n", status);
+       }
 
        if (status) {
                if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
@@ -2832,20 +2872,26 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
        int ret;
 
        id_priv = container_of(id, struct rdma_id_private, id);
+       memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
        if (id_priv->state == RDMA_CM_IDLE) {
                ret = cma_bind_addr(id, src_addr, dst_addr);
-               if (ret)
+               if (ret) {
+                       memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
                        return ret;
+               }
        }
 
-       if (cma_family(id_priv) != dst_addr->sa_family)
+       if (cma_family(id_priv) != dst_addr->sa_family) {
+               memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
                return -EINVAL;
+       }
 
-       if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY))
+       if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) {
+               memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
                return -EINVAL;
+       }
 
        atomic_inc(&id_priv->refcount);
-       memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
        if (cma_any_addr(dst_addr)) {
                ret = cma_resolve_loopback(id_priv);
        } else {
@@ -2961,6 +3007,43 @@ err:
        return ret == -ENOSPC ? -EADDRNOTAVAIL : ret;
 }
 
+static int cma_port_is_unique(struct rdma_bind_list *bind_list,
+                             struct rdma_id_private *id_priv)
+{
+       struct rdma_id_private *cur_id;
+       struct sockaddr  *daddr = cma_dst_addr(id_priv);
+       struct sockaddr  *saddr = cma_src_addr(id_priv);
+       __be16 dport = cma_port(daddr);
+
+       hlist_for_each_entry(cur_id, &bind_list->owners, node) {
+               struct sockaddr  *cur_daddr = cma_dst_addr(cur_id);
+               struct sockaddr  *cur_saddr = cma_src_addr(cur_id);
+               __be16 cur_dport = cma_port(cur_daddr);
+
+               if (id_priv == cur_id)
+                       continue;
+
+               /* different dest port -> unique */
+               if (!cma_any_port(cur_daddr) &&
+                   (dport != cur_dport))
+                       continue;
+
+               /* different src address -> unique */
+               if (!cma_any_addr(saddr) &&
+                   !cma_any_addr(cur_saddr) &&
+                   cma_addr_cmp(saddr, cur_saddr))
+                       continue;
+
+               /* different dst address -> unique */
+               if (!cma_any_addr(cur_daddr) &&
+                   cma_addr_cmp(daddr, cur_daddr))
+                       continue;
+
+               return -EADDRNOTAVAIL;
+       }
+       return 0;
+}
+
 static int cma_alloc_any_port(enum rdma_port_space ps,
                              struct rdma_id_private *id_priv)
 {
@@ -2973,9 +3056,19 @@ static int cma_alloc_any_port(enum rdma_port_space ps,
        remaining = (high - low) + 1;
        rover = prandom_u32() % remaining + low;
 retry:
-       if (last_used_port != rover &&
-           !cma_ps_find(net, ps, (unsigned short)rover)) {
-               int ret = cma_alloc_port(ps, id_priv, rover);
+       if (last_used_port != rover) {
+               struct rdma_bind_list *bind_list;
+               int ret;
+
+               bind_list = cma_ps_find(net, ps, (unsigned short)rover);
+
+               if (!bind_list) {
+                       ret = cma_alloc_port(ps, id_priv, rover);
+               } else {
+                       ret = cma_port_is_unique(bind_list, id_priv);
+                       if (!ret)
+                               cma_bind_port(bind_list, id_priv);
+               }
                /*
                 * Remember previously used port number in order to avoid
                 * re-using same port immediately after it is closed.
@@ -3204,6 +3297,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
 {
        struct rdma_id_private *id_priv;
        int ret;
+       struct sockaddr  *daddr;
 
        if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 &&
            addr->sa_family != AF_IB)
@@ -3243,6 +3337,9 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
        if (ret)
                goto err2;
 
+       daddr = cma_dst_addr(id_priv);
+       daddr->sa_family = addr->sa_family;
+
        return 0;
 err2:
        if (id_priv->cma_dev)
@@ -3307,10 +3404,13 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
                if (rep->status != IB_SIDR_SUCCESS) {
                        event.event = RDMA_CM_EVENT_UNREACHABLE;
                        event.status = ib_event->param.sidr_rep_rcvd.status;
+                       pr_debug_ratelimited("RDMA CM: UNREACHABLE: bad SIDR reply. status %d\n",
+                                            event.status);
                        break;
                }
                ret = cma_set_qkey(id_priv, rep->qkey);
                if (ret) {
+                       pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to set qkey. status %d\n", ret);
                        event.event = RDMA_CM_EVENT_ADDR_ERROR;
                        event.status = ret;
                        break;
@@ -3759,10 +3859,17 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
 
        if (!status)
                status = cma_set_qkey(id_priv, be32_to_cpu(multicast->rec.qkey));
+       else
+               pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to join multicast. status %d\n",
+                                    status);
        mutex_lock(&id_priv->qp_mutex);
-       if (!status && id_priv->id.qp)
+       if (!status && id_priv->id.qp) {
                status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid,
                                         be16_to_cpu(multicast->rec.mlid));
+               if (status)
+                       pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to attach QP. status %d\n",
+                                            status);
+       }
        mutex_unlock(&id_priv->qp_mutex);
 
        memset(&event, 0, sizeof event);
@@ -4228,15 +4335,21 @@ static void cma_add_one(struct ib_device *device)
        cma_dev->default_gid_type = kcalloc(device->phys_port_cnt,
                                            sizeof(*cma_dev->default_gid_type),
                                            GFP_KERNEL);
-       if (!cma_dev->default_gid_type) {
-               kfree(cma_dev);
-               return;
-       }
+       if (!cma_dev->default_gid_type)
+               goto free_cma_dev;
+
+       cma_dev->default_roce_tos = kcalloc(device->phys_port_cnt,
+                                           sizeof(*cma_dev->default_roce_tos),
+                                           GFP_KERNEL);
+       if (!cma_dev->default_roce_tos)
+               goto free_gid_type;
+
        for (i = rdma_start_port(device); i <= rdma_end_port(device); i++) {
                supported_gids = roce_gid_type_mask_support(device, i);
                WARN_ON(!supported_gids);
                cma_dev->default_gid_type[i - rdma_start_port(device)] =
                        find_first_bit(&supported_gids, BITS_PER_LONG);
+               cma_dev->default_roce_tos[i - rdma_start_port(device)] = 0;
        }
 
        init_completion(&cma_dev->comp);
@@ -4249,6 +4362,16 @@ static void cma_add_one(struct ib_device *device)
        list_for_each_entry(id_priv, &listen_any_list, list)
                cma_listen_on_dev(id_priv, cma_dev);
        mutex_unlock(&lock);
+
+       return;
+
+free_gid_type:
+       kfree(cma_dev->default_gid_type);
+
+free_cma_dev:
+       kfree(cma_dev);
+
+       return;
 }
 
 static int cma_remove_id_dev(struct rdma_id_private *id_priv)
@@ -4317,6 +4440,7 @@ static void cma_remove_one(struct ib_device *device, void *client_data)
        mutex_unlock(&lock);
 
        cma_process_remove(cma_dev);
+       kfree(cma_dev->default_roce_tos);
        kfree(cma_dev->default_gid_type);
        kfree(cma_dev);
 }