Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 52363335 authored by Noa Osherovich's avatar Noa Osherovich Committed by Doug Ledford
Browse files

IB/core: Fix the validations of a multicast LID in attach or detach operations



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: 8561eae6 ("IB/core: For multicast functions, verify that LIDs are multicast LIDs")
Signed-off-by: default avatarNoa Osherovich <noaos@mellanox.com>
Reviewed-by: default avatarMoni Shoua <monis@mellanox.com>
Signed-off-by: default avatarLeon Romanovsky <leon@kernel.org>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent fe248c3a
Loading
Loading
Loading
Loading
+40 −4
Original line number Diff line number Diff line
@@ -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);