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

Commit dbf727de authored by Matan Barak's avatar Matan Barak Committed by Doug Ledford
Browse files

IB/core: Use GID table in AH creation and dmac resolution



Previously, vlan id and source MAC were used from QP attributes. Since
the net device is now stored in the GID attributes, they could be used
instead of getting this information from the QP attributes.

IB_QP_SMAC, IB_QP_ALT_SMAC, IB_QP_VID and IB_QP_ALT_VID were removed
because there is no known libibverbs that uses them.

This commit also modifies the vendors (mlx4, ocrdma) drivers in order
to use the new approach.

ocrdma driver changes were done by Somnath Kotur <Somnath.Kotur@Avagotech.Com>

Signed-off-by: default avatarMatan Barak <matanb@mellanox.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 99b27e3b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -458,7 +458,7 @@ static void resolve_cb(int status, struct sockaddr *src_addr,
}

int rdma_addr_find_dmac_by_grh(const union ib_gid *sgid, const union ib_gid *dgid,
			       u8 *dmac, u16 *vlan_id)
			       u8 *dmac, u16 *vlan_id, int if_index)
{
	int ret = 0;
	struct rdma_dev_addr dev_addr;
@@ -476,6 +476,7 @@ int rdma_addr_find_dmac_by_grh(const union ib_gid *sgid, const union ib_gid *dgi
	rdma_gid2ip(&dgid_addr._sockaddr, dgid);

	memset(&dev_addr, 0, sizeof(dev_addr));
	dev_addr.bound_dev_if = if_index;

	ctx.addr = &dev_addr;
	init_completion(&ctx.comp);
+2 −2
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ void ib_device_unregister_sysfs(struct ib_device *device);
void ib_cache_setup(void);
void ib_cache_cleanup(void);

int ib_resolve_eth_l2_attrs(struct ib_qp *qp,
int ib_resolve_eth_dmac(struct ib_qp *qp,
			struct ib_qp_attr *qp_attr, int *qp_attr_mask);

typedef void (*roce_netdev_callback)(struct ib_device *device, u8 port,
+1 −1
Original line number Diff line number Diff line
@@ -2345,7 +2345,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
	attr->alt_ah_attr.port_num 	    = cmd.alt_dest.port_num;

	if (qp->real_qp == qp) {
		ret = ib_resolve_eth_l2_attrs(qp, attr, &cmd.attr_mask);
		ret = ib_resolve_eth_dmac(qp, attr, &cmd.attr_mask);
		if (ret)
			goto release_qp;
		ret = qp->device->modify_qp(qp, attr,
+93 −67
Original line number Diff line number Diff line
@@ -41,6 +41,9 @@
#include <linux/export.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <net/addrconf.h>

#include <rdma/ib_verbs.h>
#include <rdma/ib_cache.h>
@@ -308,6 +311,35 @@ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
}
EXPORT_SYMBOL(ib_create_ah);

struct find_gid_index_context {
	u16 vlan_id;
};

static bool find_gid_index(const union ib_gid *gid,
			   const struct ib_gid_attr *gid_attr,
			   void *context)
{
	struct find_gid_index_context *ctx =
		(struct find_gid_index_context *)context;

	if ((!!(ctx->vlan_id != 0xffff) == !is_vlan_dev(gid_attr->ndev)) ||
	    (is_vlan_dev(gid_attr->ndev) &&
	     vlan_dev_vlan_id(gid_attr->ndev) != ctx->vlan_id))
		return false;

	return true;
}

static int get_sgid_index_from_eth(struct ib_device *device, u8 port_num,
				   u16 vlan_id, const union ib_gid *sgid,
				   u16 *gid_index)
{
	struct find_gid_index_context context = {.vlan_id = vlan_id};

	return ib_find_gid_by_filter(device, sgid, port_num, find_gid_index,
				     &context, gid_index);
}

int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,
		       const struct ib_wc *wc, const struct ib_grh *grh,
		       struct ib_ah_attr *ah_attr)
@@ -318,21 +350,30 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,

	memset(ah_attr, 0, sizeof *ah_attr);
	if (rdma_cap_eth_ah(device, port_num)) {
		u16 vlan_id = wc->wc_flags & IB_WC_WITH_VLAN ?
				wc->vlan_id : 0xffff;

		if (!(wc->wc_flags & IB_WC_GRH))
			return -EPROTOTYPE;

		if (wc->wc_flags & IB_WC_WITH_SMAC &&
		    wc->wc_flags & IB_WC_WITH_VLAN) {
			memcpy(ah_attr->dmac, wc->smac, ETH_ALEN);
			ah_attr->vlan_id = wc->vlan_id;
		} else {
		if (!(wc->wc_flags & IB_WC_WITH_SMAC) ||
		    !(wc->wc_flags & IB_WC_WITH_VLAN)) {
			ret = rdma_addr_find_dmac_by_grh(&grh->dgid, &grh->sgid,
					ah_attr->dmac, &ah_attr->vlan_id);
							 ah_attr->dmac,
							 wc->wc_flags & IB_WC_WITH_VLAN ?
							 NULL : &vlan_id,
							 0);
			if (ret)
				return ret;
		}
	} else {
		ah_attr->vlan_id = 0xffff;

		ret = get_sgid_index_from_eth(device, port_num, vlan_id,
					      &grh->dgid, &gid_index);
		if (ret)
			return ret;

		if (wc->wc_flags & IB_WC_WITH_SMAC)
			memcpy(ah_attr->dmac, wc->smac, ETH_ALEN);
	}

	ah_attr->dlid = wc->slid;
@@ -344,10 +385,13 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,
		ah_attr->ah_flags = IB_AH_GRH;
		ah_attr->grh.dgid = grh->sgid;

		ret = ib_find_cached_gid(device, &grh->dgid,
					 NULL, &port_num, &gid_index);
		if (!rdma_cap_eth_ah(device, port_num)) {
			ret = ib_find_cached_gid_by_port(device, &grh->dgid,
							 port_num, NULL,
							 &gid_index);
			if (ret)
				return ret;
		}

		ah_attr->grh.sgid_index = (u8) gid_index;
		flow_class = be32_to_cpu(grh->version_tclass_flow);
@@ -617,9 +661,7 @@ EXPORT_SYMBOL(ib_create_qp);
static const struct {
	int			valid;
	enum ib_qp_attr_mask	req_param[IB_QPT_MAX];
	enum ib_qp_attr_mask	req_param_add_eth[IB_QPT_MAX];
	enum ib_qp_attr_mask	opt_param[IB_QPT_MAX];
	enum ib_qp_attr_mask	opt_param_add_eth[IB_QPT_MAX];
} qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
	[IB_QPS_RESET] = {
		[IB_QPS_RESET] = { .valid = 1 },
@@ -700,12 +742,6 @@ static const struct {
						IB_QP_MAX_DEST_RD_ATOMIC	|
						IB_QP_MIN_RNR_TIMER),
			},
			.req_param_add_eth = {
				[IB_QPT_RC]  = (IB_QP_SMAC),
				[IB_QPT_UC]  = (IB_QP_SMAC),
				[IB_QPT_XRC_INI]  = (IB_QP_SMAC),
				[IB_QPT_XRC_TGT]  = (IB_QP_SMAC)
			},
			.opt_param = {
				 [IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
						 IB_QP_QKEY),
@@ -726,21 +762,7 @@ static const struct {
				 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
						 IB_QP_QKEY),
			 },
			.opt_param_add_eth = {
				[IB_QPT_RC]  = (IB_QP_ALT_SMAC			|
						IB_QP_VID			|
						IB_QP_ALT_VID),
				[IB_QPT_UC]  = (IB_QP_ALT_SMAC			|
						IB_QP_VID			|
						IB_QP_ALT_VID),
				[IB_QPT_XRC_INI]  = (IB_QP_ALT_SMAC			|
						IB_QP_VID			|
						IB_QP_ALT_VID),
				[IB_QPT_XRC_TGT]  = (IB_QP_ALT_SMAC			|
						IB_QP_VID			|
						IB_QP_ALT_VID)
			}
		}
		},
	},
	[IB_QPS_RTR]   = {
		[IB_QPS_RESET] = { .valid = 1 },
@@ -962,13 +984,6 @@ int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
	req_param = qp_state_table[cur_state][next_state].req_param[type];
	opt_param = qp_state_table[cur_state][next_state].opt_param[type];

	if (ll == IB_LINK_LAYER_ETHERNET) {
		req_param |= qp_state_table[cur_state][next_state].
			req_param_add_eth[type];
		opt_param |= qp_state_table[cur_state][next_state].
			opt_param_add_eth[type];
	}

	if ((mask & req_param) != req_param)
		return 0;

@@ -979,41 +994,52 @@ int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
}
EXPORT_SYMBOL(ib_modify_qp_is_ok);

int ib_resolve_eth_l2_attrs(struct ib_qp *qp,
int ib_resolve_eth_dmac(struct ib_qp *qp,
			struct ib_qp_attr *qp_attr, int *qp_attr_mask)
{
	int           ret = 0;
	union ib_gid  sgid;

	if ((*qp_attr_mask & IB_QP_AV)  &&
	    (rdma_cap_eth_ah(qp->device, qp_attr->ah_attr.port_num))) {
		ret = ib_query_gid(qp->device, qp_attr->ah_attr.port_num,
				   qp_attr->ah_attr.grh.sgid_index, &sgid,
				   NULL);
		if (ret)
			goto out;
	if (*qp_attr_mask & IB_QP_AV) {
		if (qp_attr->ah_attr.port_num < rdma_start_port(qp->device) ||
		    qp_attr->ah_attr.port_num > rdma_end_port(qp->device))
			return -EINVAL;

		if (!rdma_cap_eth_ah(qp->device, qp_attr->ah_attr.port_num))
			return 0;

		if (rdma_link_local_addr((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw)) {
			rdma_get_ll_mac((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw, qp_attr->ah_attr.dmac);
			rdma_get_ll_mac((struct in6_addr *)sgid.raw, qp_attr->smac);
			if (!(*qp_attr_mask & IB_QP_VID))
				qp_attr->vlan_id = rdma_get_vlan_id(&sgid);
			rdma_get_ll_mac((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw,
					qp_attr->ah_attr.dmac);
		} else {
			ret = rdma_addr_find_dmac_by_grh(&sgid, &qp_attr->ah_attr.grh.dgid,
					qp_attr->ah_attr.dmac, &qp_attr->vlan_id);
			if (ret)
				goto out;
			ret = rdma_addr_find_smac_by_sgid(&sgid, qp_attr->smac, NULL);
			if (ret)
			union ib_gid		sgid;
			struct ib_gid_attr	sgid_attr;
			int			ifindex;

			ret = ib_query_gid(qp->device,
					   qp_attr->ah_attr.port_num,
					   qp_attr->ah_attr.grh.sgid_index,
					   &sgid, &sgid_attr);

			if (ret || !sgid_attr.ndev) {
				if (!ret)
					ret = -ENXIO;
				goto out;
			}
		*qp_attr_mask |= IB_QP_SMAC;
		if (qp_attr->vlan_id < 0xFFFF)
			*qp_attr_mask |= IB_QP_VID;

			ifindex = sgid_attr.ndev->ifindex;

			ret = rdma_addr_find_dmac_by_grh(&sgid,
							 &qp_attr->ah_attr.grh.dgid,
							 qp_attr->ah_attr.dmac,
							 NULL, ifindex);

			dev_put(sgid_attr.ndev);
		}
	}
out:
	return ret;
}
EXPORT_SYMBOL(ib_resolve_eth_l2_attrs);
EXPORT_SYMBOL(ib_resolve_eth_dmac);


int ib_modify_qp(struct ib_qp *qp,
@@ -1022,7 +1048,7 @@ int ib_modify_qp(struct ib_qp *qp,
{
	int ret;

	ret = ib_resolve_eth_l2_attrs(qp, qp_attr, &qp_attr_mask);
	ret = ib_resolve_eth_dmac(qp, qp_attr, &qp_attr_mask);
	if (ret)
		return ret;

+15 −2
Original line number Diff line number Diff line
@@ -76,7 +76,10 @@ static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr
	struct mlx4_dev *dev = ibdev->dev;
	int is_mcast = 0;
	struct in6_addr in6;
	u16 vlan_tag;
	u16 vlan_tag = 0xffff;
	union ib_gid sgid;
	struct ib_gid_attr gid_attr;
	int ret;

	memcpy(&in6, ah_attr->grh.dgid.raw, sizeof(in6));
	if (rdma_is_multicast_addr(&in6)) {
@@ -85,7 +88,17 @@ static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr
	} else {
		memcpy(ah->av.eth.mac, ah_attr->dmac, ETH_ALEN);
	}
	vlan_tag = ah_attr->vlan_id;
	ret = ib_get_cached_gid(pd->device, ah_attr->port_num,
				ah_attr->grh.sgid_index, &sgid, &gid_attr);
	if (ret)
		return ERR_PTR(ret);
	memset(ah->av.eth.s_mac, 0, ETH_ALEN);
	if (gid_attr.ndev) {
		if (is_vlan_dev(gid_attr.ndev))
			vlan_tag = vlan_dev_vlan_id(gid_attr.ndev);
		memcpy(ah->av.eth.s_mac, gid_attr.ndev->dev_addr, ETH_ALEN);
		dev_put(gid_attr.ndev);
	}
	if (vlan_tag < 0x1000)
		vlan_tag |= (ah_attr->sl & 7) << 13;
	ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
Loading