From: Aharon Landau <aharonl@xxxxxxxxxx> This patch adds the ability to show the added and supported optional counters for each link through RDMA netlink. Examples: $ rdma statistic mode link rocep8s0f0/1 Optional-set: cc_rx_ce_pkts $ rdma statistic mode supported link rocep8s0f0/1 Optional-set: cc_rx_ce_pkts cc_rx_cnp_pkts cc_tx_cnp_pkts link rocep8s0f1/1 Optional-set: cc_rx_ce_pkts cc_rx_cnp_pkts cc_tx_cnp_pkts Signed-off-by: Aharon Landau <aharonl@xxxxxxxxxx> Signed-off-by: Neta Ostrovsky <netao@xxxxxxxxxx> Signed-off-by: Mark Zhang <markzhang@xxxxxxxxxx> --- drivers/infiniband/core/nldev.c | 91 +++++++++++++++++++++++++++++++- include/uapi/rdma/rdma_netlink.h | 2 + 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c index b665651dfb1d..611e4fe6a244 100644 --- a/drivers/infiniband/core/nldev.c +++ b/drivers/infiniband/core/nldev.c @@ -159,6 +159,8 @@ static const struct nla_policy nldev_policy[RDMA_NLDEV_ATTR_MAX] = { [RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENTRY_NAME] = { .type = NLA_NUL_STRING, .len = RDMA_NLDEV_ATTR_OPCOUNTER_NAME_SIZE }, [RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENTRY_VALUE] = { .type = NLA_U64 }, + [RDMA_NLDEV_ATTR_STAT_OP_MODE_LIST] = { .type = NLA_U8 }, + [RDMA_NLDEV_ATTR_STAT_OP_MODE_LIST_SUPPORTED] = { .type = NLA_U8 }, }; static int put_driver_name_print_type(struct sk_buff *msg, const char *name, @@ -946,7 +948,7 @@ int rdma_nl_stat_hwcounter_entry(struct sk_buff *msg, const char *name, EXPORT_SYMBOL(rdma_nl_stat_hwcounter_entry); static int rdma_nl_stat_opcounter_entry(struct sk_buff *msg, const char *name, - u64 value) + u64 value, bool send_value) { struct nlattr *entry_attr; @@ -960,6 +962,12 @@ static int rdma_nl_stat_opcounter_entry(struct sk_buff *msg, const char *name, if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENTRY_VALUE, value, RDMA_NLDEV_ATTR_PAD)) goto err; + if (send_value) { + if (nla_put_u64_64bit(msg, + RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENTRY_VALUE, + value, RDMA_NLDEV_ATTR_PAD)) + goto err; + } nla_nest_end(msg, entry_attr); return 0; @@ -2148,6 +2156,79 @@ static int nldev_stat_del_doit(struct sk_buff *skb, struct nlmsghdr *nlh, return ret; } +static int stat_get_doit_list_opstats(struct sk_buff *skb, + struct nlmsghdr *nlh, + struct netlink_ext_ack *extack, + struct nlattr *tb[], u32 index, + struct ib_device *device, u32 port) +{ + struct rdma_op_stats *opstats; + struct nlattr *opstats_list; + bool list_supported = false; + struct sk_buff *msg; + int i, ret; + + if (tb[RDMA_NLDEV_ATTR_STAT_OP_MODE_LIST_SUPPORTED]) + list_supported = true; + + opstats = device->port_data[port].port_counter.opstats; + if (!opstats) + return -EOPNOTSUPP; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) { + ret = -ENOMEM; + goto err; + } + + nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, + RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, + RDMA_NLDEV_CMD_STAT_GET), + 0, 0); + + if (fill_nldev_handle(msg, device) || + nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port)) { + ret = -EMSGSIZE; + goto err_msg; + } + + opstats_list = + nla_nest_start(msg, RDMA_NLDEV_ATTR_STAT_OPCOUNTERS); + + if (!opstats_list) { + ret = -EMSGSIZE; + goto err_msg; + } + + mutex_lock(&opstats->lock); + + for (i = 0; i < opstats->num_opcounters; i++) { + if (!opstats->opcounters[i].enabled && !list_supported) + continue; + ret = rdma_nl_stat_opcounter_entry(msg, + opstats->opcounters[i].name, + 0, false); + if (ret) + goto err_opstats_msg; + } + nla_nest_end(msg, opstats_list); + + mutex_unlock(&opstats->lock); + + nlmsg_end(msg, nlh); + ib_device_put(device); + return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid); + +err_opstats_msg: + nla_nest_cancel(msg, opstats_list); + mutex_unlock(&opstats->lock); +err_msg: + nlmsg_free(msg); +err: + ib_device_put(device); + return ret; +} + static int stat_get_optional_counter(struct sk_buff *msg, struct ib_device *device, u32 port) { @@ -2172,7 +2253,8 @@ static int stat_get_optional_counter(struct sk_buff *msg, continue; ret = rdma_nl_stat_opcounter_entry(msg, opstats->opcounters[i].name, - opstats->opcounters[i].value); + opstats->opcounters[i].value, + true); if (ret) goto err; } @@ -2212,6 +2294,11 @@ static int stat_get_doit_default_counter(struct sk_buff *skb, goto err; } + if (tb[RDMA_NLDEV_ATTR_STAT_OP_MODE_LIST] || + tb[RDMA_NLDEV_ATTR_STAT_OP_MODE_LIST_SUPPORTED]) + return stat_get_doit_list_opstats(skb, nlh, extack, tb, + index, device, port); + if (!device->ops.alloc_hw_port_stats || !device->ops.get_hw_stats) { ret = -EINVAL; goto err; diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h index 79e6ca87d2e0..57f39d8fe434 100644 --- a/include/uapi/rdma/rdma_netlink.h +++ b/include/uapi/rdma/rdma_netlink.h @@ -557,6 +557,8 @@ enum rdma_nldev_attr { RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENTRY, /* nested table */ RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENTRY_NAME, /* string */ RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENTRY_VALUE, /* u64 */ + RDMA_NLDEV_ATTR_STAT_OP_MODE_LIST, /* u8 */ + RDMA_NLDEV_ATTR_STAT_OP_MODE_LIST_SUPPORTED, /* u8 */ /* * Always the end -- 2.26.2