IB/core: Fix the validations of a multicast LID in attach or detach operations
authorNoa Osherovich <noaos@mellanox.com>
Mon, 12 Jun 2017 08:14:02 +0000 (11:14 +0300)
committerDoug Ledford <dledford@redhat.com>
Mon, 24 Jul 2017 14:40:23 +0000 (10:40 -0400)
RoCE Annex (A16.9.10/11) declares that during attach (detach) QP to a
multicast group, if the QP is associated with a RoCE port, the
multicast group MLID is unused and is ignored.

During attach or detach multicast, when the QP is associated with a
port, it is enough to check the port's link layer and validate the
LID only if it is Infiniband. Otherwise, avoid validating the
multicast LID.

Fixes: 8561eae60ff9 ("IB/core: For multicast functions, verify that LIDs are multicast LIDs")
Signed-off-by: Noa Osherovich <noaos@mellanox.com>
Reviewed-by: Moni Shoua <monis@mellanox.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/core/verbs.c

index fb98ed67d5bc684b8cc0b941d7140986b95aa99b..802bdc397a57f1449e95def30372777014be80cd 100644 (file)
@@ -1569,6 +1569,44 @@ EXPORT_SYMBOL(ib_dealloc_fmr);
 
 /* Multicast groups */
 
+static bool is_valid_mcast_lid(struct ib_qp *qp, u16 lid)
+{
+       struct ib_qp_init_attr init_attr = {};
+       struct ib_qp_attr attr = {};
+       int num_eth_ports = 0;
+       int port;
+
+       /* If QP state >= init, it is assigned to a port and we can check this
+        * port only.
+        */
+       if (!ib_query_qp(qp, &attr, IB_QP_STATE | IB_QP_PORT, &init_attr)) {
+               if (attr.qp_state >= IB_QPS_INIT) {
+                       if (qp->device->get_link_layer(qp->device, attr.port_num) !=
+                           IB_LINK_LAYER_INFINIBAND)
+                               return true;
+                       goto lid_check;
+               }
+       }
+
+       /* Can't get a quick answer, iterate over all ports */
+       for (port = 0; port < qp->device->phys_port_cnt; port++)
+               if (qp->device->get_link_layer(qp->device, port) !=
+                   IB_LINK_LAYER_INFINIBAND)
+                       num_eth_ports++;
+
+       /* If we have at lease one Ethernet port, RoCE annex declares that
+        * multicast LID should be ignored. We can't tell at this step if the
+        * QP belongs to an IB or Ethernet port.
+        */
+       if (num_eth_ports)
+               return true;
+
+       /* If all the ports are IB, we can check according to IB spec. */
+lid_check:
+       return !(lid < be16_to_cpu(IB_MULTICAST_LID_BASE) ||
+                lid == be16_to_cpu(IB_LID_PERMISSIVE));
+}
+
 int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
 {
        int ret;
@@ -1576,8 +1614,7 @@ int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
        if (!qp->device->attach_mcast)
                return -ENOSYS;
        if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD ||
-           lid < be16_to_cpu(IB_MULTICAST_LID_BASE) ||
-           lid == be16_to_cpu(IB_LID_PERMISSIVE))
+           !is_valid_mcast_lid(qp, lid))
                return -EINVAL;
 
        ret = qp->device->attach_mcast(qp, gid, lid);
@@ -1594,8 +1631,7 @@ int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
        if (!qp->device->detach_mcast)
                return -ENOSYS;
        if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD ||
-           lid < be16_to_cpu(IB_MULTICAST_LID_BASE) ||
-           lid == be16_to_cpu(IB_LID_PERMISSIVE))
+           !is_valid_mcast_lid(qp, lid))
                return -EINVAL;
 
        ret = qp->device->detach_mcast(qp, gid, lid);