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

Commit c4ffee7c authored by Mark Zhang's avatar Mark Zhang Committed by Jason Gunthorpe
Browse files

RDMA/netlink: Implement counter dumpit calback



This patch adds the ability to return all available counters together with
their properties and hwstats.

Signed-off-by: default avatarMark Zhang <markz@mellanox.com>
Reviewed-by: default avatarMajd Dibbiny <majd@mellanox.com>
Signed-off-by: default avatarLeon Romanovsky <leonro@mellanox.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
parent b47ae6f8
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ static struct rdma_counter *rdma_counter_alloc(struct ib_device *dev, u8 port,
{
	struct rdma_counter *counter;

	if (!dev->ops.counter_dealloc)
	if (!dev->ops.counter_dealloc || !dev->ops.counter_alloc_stats)
		return NULL;

	counter = kzalloc(sizeof(*counter), GFP_KERNEL);
@@ -69,16 +69,25 @@ static struct rdma_counter *rdma_counter_alloc(struct ib_device *dev, u8 port,
	counter->device    = dev;
	counter->port      = port;
	counter->res.type  = RDMA_RESTRACK_COUNTER;
	counter->stats     = dev->ops.counter_alloc_stats(counter);
	if (!counter->stats)
		goto err_stats;

	counter->mode.mode = mode;
	kref_init(&counter->kref);
	mutex_init(&counter->lock);

	return counter;

err_stats:
	kfree(counter);
	return NULL;
}

static void rdma_counter_free(struct rdma_counter *counter)
{
	rdma_restrack_del(&counter->res);
	kfree(counter->stats);
	kfree(counter);
}

@@ -275,6 +284,21 @@ int rdma_counter_unbind_qp(struct ib_qp *qp, bool force)
	return 0;
}

int rdma_counter_query_stats(struct rdma_counter *counter)
{
	struct ib_device *dev = counter->device;
	int ret;

	if (!dev->ops.counter_update_stats)
		return -EINVAL;

	mutex_lock(&counter->lock);
	ret = dev->ops.counter_update_stats(counter);
	mutex_unlock(&counter->lock);

	return ret;
}

void rdma_counter_init(struct ib_device *dev)
{
	struct rdma_port_counter *port_counter;
+2 −0
Original line number Diff line number Diff line
@@ -2471,9 +2471,11 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
	SET_DEVICE_OP(dev_ops, alloc_xrcd);
	SET_DEVICE_OP(dev_ops, attach_mcast);
	SET_DEVICE_OP(dev_ops, check_mr_status);
	SET_DEVICE_OP(dev_ops, counter_alloc_stats);
	SET_DEVICE_OP(dev_ops, counter_bind_qp);
	SET_DEVICE_OP(dev_ops, counter_dealloc);
	SET_DEVICE_OP(dev_ops, counter_unbind_qp);
	SET_DEVICE_OP(dev_ops, counter_update_stats);
	SET_DEVICE_OP(dev_ops, create_ah);
	SET_DEVICE_OP(dev_ops, create_counters);
	SET_DEVICE_OP(dev_ops, create_cq);
+213 −0
Original line number Diff line number Diff line
@@ -129,6 +129,13 @@ static const struct nla_policy nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
	[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK]	= { .type = NLA_U32 },
	[RDMA_NLDEV_ATTR_STAT_MODE]		= { .type = NLA_U32 },
	[RDMA_NLDEV_ATTR_STAT_RES]		= { .type = NLA_U32 },
	[RDMA_NLDEV_ATTR_STAT_COUNTER]		= { .type = NLA_NESTED },
	[RDMA_NLDEV_ATTR_STAT_COUNTER_ENTRY]	= { .type = NLA_NESTED },
	[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]       = { .type = NLA_U32 },
	[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS]       = { .type = NLA_NESTED },
	[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY]  = { .type = NLA_NESTED },
	[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME] = { .type = NLA_NUL_STRING },
	[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE] = { .type = NLA_U64 },
	[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID]	= { .type = NLA_U64 },
	[RDMA_NLDEV_ATTR_UVERBS_DRIVER_ID]	= { .type = NLA_U32 },
	[RDMA_NLDEV_NET_NS_FD]			= { .type = NLA_U32 },
@@ -636,6 +643,152 @@ static int fill_res_pd_entry(struct sk_buff *msg, bool has_cap_net_admin,
err:	return -EMSGSIZE;
}

static int fill_stat_counter_mode(struct sk_buff *msg,
				  struct rdma_counter *counter)
{
	struct rdma_counter_mode *m = &counter->mode;

	if (nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_MODE, m->mode))
		return -EMSGSIZE;

	if (m->mode == RDMA_COUNTER_MODE_AUTO)
		if ((m->mask & RDMA_COUNTER_MASK_QP_TYPE) &&
		    nla_put_u8(msg, RDMA_NLDEV_ATTR_RES_TYPE, m->param.qp_type))
			return -EMSGSIZE;

	return 0;
}

static int fill_stat_counter_qp_entry(struct sk_buff *msg, u32 qpn)
{
	struct nlattr *entry_attr;

	entry_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_QP_ENTRY);
	if (!entry_attr)
		return -EMSGSIZE;

	if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LQPN, qpn))
		goto err;

	nla_nest_end(msg, entry_attr);
	return 0;

err:
	nla_nest_cancel(msg, entry_attr);
	return -EMSGSIZE;
}

static int fill_stat_counter_qps(struct sk_buff *msg,
				 struct rdma_counter *counter)
{
	struct rdma_restrack_entry *res;
	struct rdma_restrack_root *rt;
	struct nlattr *table_attr;
	struct ib_qp *qp = NULL;
	unsigned long id = 0;
	int ret = 0;

	table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_QP);

	rt = &counter->device->res[RDMA_RESTRACK_QP];
	xa_lock(&rt->xa);
	xa_for_each(&rt->xa, id, res) {
		if (!rdma_is_visible_in_pid_ns(res))
			continue;

		qp = container_of(res, struct ib_qp, res);
		if (qp->qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
			continue;

		if (!qp->counter || (qp->counter->id != counter->id))
			continue;

		ret = fill_stat_counter_qp_entry(msg, qp->qp_num);
		if (ret)
			goto err;
	}

	xa_unlock(&rt->xa);
	nla_nest_end(msg, table_attr);
	return 0;

err:
	xa_unlock(&rt->xa);
	nla_nest_cancel(msg, table_attr);
	return ret;
}

static int fill_stat_hwcounter_entry(struct sk_buff *msg,
				     const char *name, u64 value)
{
	struct nlattr *entry_attr;

	entry_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY);
	if (!entry_attr)
		return -EMSGSIZE;

	if (nla_put_string(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME,
			   name))
		goto err;
	if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE,
			      value, RDMA_NLDEV_ATTR_PAD))
		goto err;

	nla_nest_end(msg, entry_attr);
	return 0;

err:
	nla_nest_cancel(msg, entry_attr);
	return -EMSGSIZE;
}

static int fill_stat_counter_hwcounters(struct sk_buff *msg,
					struct rdma_counter *counter)
{
	struct rdma_hw_stats *st = counter->stats;
	struct nlattr *table_attr;
	int i;

	table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTERS);
	if (!table_attr)
		return -EMSGSIZE;

	for (i = 0; i < st->num_counters; i++)
		if (fill_stat_hwcounter_entry(msg, st->names[i], st->value[i]))
			goto err;

	nla_nest_end(msg, table_attr);
	return 0;

err:
	nla_nest_cancel(msg, table_attr);
	return -EMSGSIZE;
}

static int fill_res_counter_entry(struct sk_buff *msg, bool has_cap_net_admin,
				  struct rdma_restrack_entry *res,
				  uint32_t port)
{
	struct rdma_counter *counter =
		container_of(res, struct rdma_counter, res);

	if (port && port != counter->port)
		return 0;

	/* Dump it even query failed */
	rdma_counter_query_stats(counter);

	if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, counter->port) ||
	    nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_COUNTER_ID, counter->id) ||
	    fill_res_name_pid(msg, &counter->res) ||
	    fill_stat_counter_mode(msg, counter) ||
	    fill_stat_counter_qps(msg, counter) ||
	    fill_stat_counter_hwcounters(msg, counter))
		return -EMSGSIZE;

	return 0;
}

static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
			  struct netlink_ext_ack *extack)
{
@@ -1003,6 +1156,13 @@ static const struct nldev_fill_res_entry fill_entries[RDMA_RESTRACK_MAX] = {
		.entry = RDMA_NLDEV_ATTR_RES_PD_ENTRY,
		.id = RDMA_NLDEV_ATTR_RES_PDN,
	},
	[RDMA_RESTRACK_COUNTER] = {
		.fill_res_func = fill_res_counter_entry,
		.nldev_cmd = RDMA_NLDEV_CMD_STAT_GET,
		.nldev_attr = RDMA_NLDEV_ATTR_STAT_COUNTER,
		.entry = RDMA_NLDEV_ATTR_STAT_COUNTER_ENTRY,
		.id = RDMA_NLDEV_ATTR_STAT_COUNTER_ID,
	},
};

static int res_get_common_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -1239,6 +1399,7 @@ RES_GET_FUNCS(cm_id, RDMA_RESTRACK_CM_ID);
RES_GET_FUNCS(cq, RDMA_RESTRACK_CQ);
RES_GET_FUNCS(pd, RDMA_RESTRACK_PD);
RES_GET_FUNCS(mr, RDMA_RESTRACK_MR);
RES_GET_FUNCS(counter, RDMA_RESTRACK_COUNTER);

static LIST_HEAD(link_ops);
static DECLARE_RWSEM(link_ops_rwsem);
@@ -1557,6 +1718,54 @@ static int nldev_stat_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
	return ret;
}

static int nldev_stat_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
			       struct netlink_ext_ack *extack)
{
	struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
	int ret;

	ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
			  nldev_policy, extack);
	if (ret || !tb[RDMA_NLDEV_ATTR_STAT_RES])
		return -EINVAL;

	switch (nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_RES])) {
	case RDMA_NLDEV_ATTR_RES_QP:
		ret = nldev_res_get_counter_doit(skb, nlh, extack);
		break;

	default:
		ret = -EINVAL;
		break;
	}

	return ret;
}

static int nldev_stat_get_dumpit(struct sk_buff *skb,
				 struct netlink_callback *cb)
{
	struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
	int ret;

	ret = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
			  nldev_policy, NULL);
	if (ret || !tb[RDMA_NLDEV_ATTR_STAT_RES])
		return -EINVAL;

	switch (nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_RES])) {
	case RDMA_NLDEV_ATTR_RES_QP:
		ret = nldev_res_get_counter_dumpit(skb, cb);
		break;

	default:
		ret = -EINVAL;
		break;
	}

	return ret;
}

static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = {
	[RDMA_NLDEV_CMD_GET] = {
		.doit = nldev_get_doit,
@@ -1615,6 +1824,10 @@ static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = {
		.doit = nldev_stat_set_doit,
		.flags = RDMA_NL_ADMIN_PERM,
	},
	[RDMA_NLDEV_CMD_STAT_GET] = {
		.doit = nldev_stat_get_doit,
		.dump = nldev_stat_get_dumpit,
	},
};

void __init nldev_init(void)
+10 −0
Original line number Diff line number Diff line
@@ -2503,6 +2503,16 @@ struct ib_device_ops {
	 * counter_dealloc -De-allocate the hw counter
	 */
	int (*counter_dealloc)(struct rdma_counter *counter);
	/**
	 * counter_alloc_stats - Allocate a struct rdma_hw_stats and fill in
	 * the driver initialized data.
	 */
	struct rdma_hw_stats *(*counter_alloc_stats)(
		struct rdma_counter *counter);
	/**
	 * counter_update_stats - Query the stats value of this counter
	 */
	int (*counter_update_stats)(struct rdma_counter *counter);

	DECLARE_RDMA_OBJ_SIZE(ib_ah);
	DECLARE_RDMA_OBJ_SIZE(ib_cq);
+3 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ struct rdma_counter {
	struct kref			kref;
	struct rdma_counter_mode	mode;
	struct mutex			lock;
	struct rdma_hw_stats		*stats;
	u8				port;
};

@@ -47,4 +48,6 @@ int rdma_counter_set_auto_mode(struct ib_device *dev, u8 port,
int rdma_counter_bind_qp_auto(struct ib_qp *qp, u8 port);
int rdma_counter_unbind_qp(struct ib_qp *qp, bool force);

int rdma_counter_query_stats(struct rdma_counter *counter);

#endif /* _RDMA_COUNTER_H_ */
Loading