Skip to content

Commit

Permalink
RDMA/netlink: Implement counter dumpit calback
Browse files Browse the repository at this point in the history
This patch adds the ability to return all available counters together with
their properties and hwstats.

Signed-off-by: Mark Zhang <[email protected]>
Reviewed-by: Majd Dibbiny <[email protected]>
Signed-off-by: Leon Romanovsky <[email protected]>
Signed-off-by: Jason Gunthorpe <[email protected]>
  • Loading branch information
Mark Zhang authored and jgunthorpe committed Jul 5, 2019
1 parent b47ae6f commit c4ffee7
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 8 deletions.
26 changes: 25 additions & 1 deletion drivers/infiniband/core/counters.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions drivers/infiniband/core/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
213 changes: 213 additions & 0 deletions drivers/infiniband/core/nldev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
10 changes: 10 additions & 0 deletions include/rdma/ib_verbs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions include/rdma/rdma_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand All @@ -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_ */
22 changes: 15 additions & 7 deletions include/uapi/rdma/rdma_netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ enum rdma_nldev_command {

RDMA_NLDEV_CMD_STAT_SET,

RDMA_NLDEV_CMD_STAT_GET, /* can dump */

RDMA_NLDEV_NUM_OPS
};

Expand Down Expand Up @@ -490,13 +492,6 @@ enum rdma_nldev_attr {
* File descriptor handle of the net namespace object
*/
RDMA_NLDEV_NET_NS_FD, /* u32 */
/*
* Counter-specific attributes.
*/
RDMA_NLDEV_ATTR_STAT_MODE, /* u32 */
RDMA_NLDEV_ATTR_STAT_RES, /* u32 */
RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK, /* u32 */

/*
* Information about a chardev.
* CHARDEV_TYPE is the name of the chardev ABI (ie uverbs, umad, etc)
Expand All @@ -509,6 +504,19 @@ enum rdma_nldev_attr {
RDMA_NLDEV_ATTR_CHARDEV_ABI, /* u64 */
RDMA_NLDEV_ATTR_CHARDEV, /* u64 */
RDMA_NLDEV_ATTR_UVERBS_DRIVER_ID, /* u64 */
/*
* Counter-specific attributes.
*/
RDMA_NLDEV_ATTR_STAT_MODE, /* u32 */
RDMA_NLDEV_ATTR_STAT_RES, /* u32 */
RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK, /* u32 */
RDMA_NLDEV_ATTR_STAT_COUNTER, /* nested table */
RDMA_NLDEV_ATTR_STAT_COUNTER_ENTRY, /* nested table */
RDMA_NLDEV_ATTR_STAT_COUNTER_ID, /* u32 */
RDMA_NLDEV_ATTR_STAT_HWCOUNTERS, /* nested table */
RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY, /* nested table */
RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME, /* string */
RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE, /* u64 */

/*
* Always the end
Expand Down

0 comments on commit c4ffee7

Please sign in to comment.