[PATCH 3.16 008/133] IB/core: Fix the validations of a multicast LID in attach or detach operations

From: Ben Hutchings
Date: Tue Nov 21 2017 - 21:26:36 EST


3.16.51-rc1 review patch. If anyone has any objections, please let me know.

------------------

From: Noa Osherovich <noaos@xxxxxxxxxxxx>

commit 5236333592244557a19694a51337df6ac018f0a7 upstream.

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@xxxxxxxxxxxx>
Reviewed-by: Moni Shoua <monis@xxxxxxxxxxxx>
Signed-off-by: Leon Romanovsky <leon@xxxxxxxxxx>
Signed-off-by: Doug Ledford <dledford@xxxxxxxxxx>
[bwh: Backported to 3.16: use literal number instead of IB_MULTICAST_LID_BASE]
Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
---
drivers/infiniband/core/verbs.c | 44 +++++++++++++++++++++++++++++++++++++----
1 file changed, 40 insertions(+), 4 deletions(-)

--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -1340,6 +1340,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 < 0xC000 ||
+ lid == be16_to_cpu(IB_LID_PERMISSIVE));
+}
+
int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
{
int ret;
@@ -1347,8 +1385,7 @@ int ib_attach_mcast(struct ib_qp *qp, un
if (!qp->device->attach_mcast)
return -ENOSYS;
if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD ||
- lid < 0xC000 ||
- lid == be16_to_cpu(IB_LID_PERMISSIVE))
+ !is_valid_mcast_lid(qp, lid))
return -EINVAL;

ret = qp->device->attach_mcast(qp, gid, lid);
@@ -1365,8 +1402,7 @@ int ib_detach_mcast(struct ib_qp *qp, un
if (!qp->device->detach_mcast)
return -ENOSYS;
if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD ||
- lid < 0xC000 ||
- lid == be16_to_cpu(IB_LID_PERMISSIVE))
+ !is_valid_mcast_lid(qp, lid))
return -EINVAL;

ret = qp->device->detach_mcast(qp, gid, lid);