[PATCH 01/12] libibverbs: add ibv_read_counters_ex()
From: Doug Ledford
Date: Sat Oct 31 2026 - 15:27:21 EST
Expose the counters read extension of the kernel. ibv_read_counters_ex()
reads a caller chosen list of driver defined counter items into a
values array and, optionally, a timestamps array holding the time in
nanoseconds each item was sampled. It is implemented with the
optional ITEMS and TIMESTAMPS attributes of the existing counters read
method, and is dispatched to a new read_counters_ex provider op. It
returns EOPNOTSUPP when the provider or kernel lacks it.
The new provider op and ibv_cmd_read_counters_ex() extend the private
provider ABI. IBVERBS_PABI_VERSION is deliberately not bumped: the UET
series this is based on already raised it to 66 and 66.0 has not been
released, so these additions join that unreleased private ABI.
Signed-off-by: Doug Ledford <doug.ledford@xxxxxxx>
---
debian/libibverbs1.symbols | 1 +
kernel-headers/rdma/ib_user_ioctl_cmds.h | 2 ++
libibverbs/cmd_counters.c | 25 +++++++++++++++++++++++++
libibverbs/driver.h | 8 ++++++++
libibverbs/dummy_ops.c | 10 ++++++++++
libibverbs/libibverbs.map.in | 2 ++
libibverbs/verbs.c | 10 ++++++++++
libibverbs/verbs.h | 17 +++++++++++++++++
8 files changed, 75 insertions(+)
diff --git a/debian/libibverbs1.symbols b/debian/libibverbs1.symbols
index 61ee1e16f850..9b7d95924571 100644
--- a/debian/libibverbs1.symbols
+++ b/debian/libibverbs1.symbols
@@ -136,6 +136,7 @@ libibverbs.so.1 libibverbs1 #MINVER#
ibv_rate_to_mbps@IBVERBS_1.1 1.1.8
ibv_rate_to_mult@IBVERBS_1.0 1.1.6
ibv_read_comp_cntr@IBVERBS_1.18 65
+ ibv_read_counters_ex@IBVERBS_1.19 66
ibv_read_err_comp_cntr@IBVERBS_1.18 65
ibv_read_sysfs_file@IBVERBS_1.0 1.1.6
ibv_reg_buf_mr@IBVERBS_1.17 64
diff --git a/kernel-headers/rdma/ib_user_ioctl_cmds.h b/kernel-headers/rdma/ib_user_ioctl_cmds.h
index 8de110b8db34..9ee083eed044 100644
--- a/kernel-headers/rdma/ib_user_ioctl_cmds.h
+++ b/kernel-headers/rdma/ib_user_ioctl_cmds.h
@@ -404,6 +404,8 @@ enum uverbs_attrs_read_counters_cmd_attr_ids {
UVERBS_ATTR_READ_COUNTERS_HANDLE,
UVERBS_ATTR_READ_COUNTERS_BUFF,
UVERBS_ATTR_READ_COUNTERS_FLAGS,
+ UVERBS_ATTR_READ_COUNTERS_ITEMS,
+ UVERBS_ATTR_READ_COUNTERS_TIMESTAMPS,
};
enum uverbs_methods_actions_counters_ops {
diff --git a/libibverbs/cmd_counters.c b/libibverbs/cmd_counters.c
index 8964fed5ea1b..d6fd18b39429 100644
--- a/libibverbs/cmd_counters.c
+++ b/libibverbs/cmd_counters.c
@@ -76,6 +76,31 @@ int ibv_cmd_destroy_counters(struct verbs_counters *vcounters)
return 0;
}
+int ibv_cmd_read_counters_ex(struct verbs_counters *vcounters,
+ const uint64_t *items, uint64_t *counters_value,
+ uint64_t *timestamps, uint32_t ncounters,
+ uint32_t flags, struct ibv_command_buffer *link)
+{
+ DECLARE_COMMAND_BUFFER_LINK(cmd, UVERBS_OBJECT_COUNTERS,
+ UVERBS_METHOD_COUNTERS_READ,
+ 5,
+ link);
+
+ fill_attr_in_obj(cmd, UVERBS_ATTR_READ_COUNTERS_HANDLE,
+ vcounters->handle);
+ fill_attr_out_ptr_array(cmd, UVERBS_ATTR_READ_COUNTERS_BUFF,
+ counters_value, ncounters);
+ fill_attr_in_uint32(cmd, UVERBS_ATTR_READ_COUNTERS_FLAGS, flags);
+ if (items)
+ fill_attr_in_ptr_array(cmd, UVERBS_ATTR_READ_COUNTERS_ITEMS,
+ items, ncounters);
+ if (timestamps)
+ fill_attr_out_ptr_array(cmd, UVERBS_ATTR_READ_COUNTERS_TIMESTAMPS,
+ timestamps, ncounters);
+
+ return execute_ioctl(vcounters->counters.context, cmd);
+}
+
int ibv_cmd_read_counters(struct verbs_counters *vcounters,
uint64_t *counters_value,
uint32_t ncounters,
diff --git a/libibverbs/driver.h b/libibverbs/driver.h
index 6c3e73f37037..8327550231f4 100644
--- a/libibverbs/driver.h
+++ b/libibverbs/driver.h
@@ -530,6 +530,10 @@ struct verbs_context_ops {
uint64_t *counters_value,
uint32_t ncounters,
uint32_t flags);
+ int (*read_counters_ex)(struct ibv_counters *counters,
+ const uint64_t *items, uint64_t *counters_value,
+ uint64_t *timestamps, uint32_t ncounters,
+ uint32_t flags);
int (*read_err_comp_cntr)(struct ibv_comp_cntr *comp_cntr,
uint64_t *value);
struct ibv_mr *(*reg_dm_mr)(struct ibv_pd *pd, struct ibv_dm *dm,
@@ -819,6 +823,10 @@ int ibv_cmd_read_counters(struct verbs_counters *vcounters,
uint32_t ncounters,
uint32_t flags,
struct ibv_command_buffer *link);
+int ibv_cmd_read_counters_ex(struct verbs_counters *vcounters,
+ const uint64_t *items, uint64_t *counters_value,
+ uint64_t *timestamps, uint32_t ncounters,
+ uint32_t flags, struct ibv_command_buffer *link);
/*
* Adjust fork protection for the given range. Return 0 on success, or a
* non-zero value on failure with errno set to indicate the reason.
diff --git a/libibverbs/dummy_ops.c b/libibverbs/dummy_ops.c
index 7a83b1da9d45..fee27c1f6687 100644
--- a/libibverbs/dummy_ops.c
+++ b/libibverbs/dummy_ops.c
@@ -616,6 +616,14 @@ static int read_counters(struct ibv_counters *counters,
return EOPNOTSUPP;
}
+static int read_counters_ex(struct ibv_counters *counters,
+ const uint64_t *items, uint64_t *counters_value,
+ uint64_t *timestamps, uint32_t ncounters,
+ uint32_t flags)
+{
+ return EOPNOTSUPP;
+}
+
static int read_err_comp_cntr(struct ibv_comp_cntr *comp_cntr, uint64_t *value)
{
return EOPNOTSUPP;
@@ -846,6 +854,7 @@ const struct verbs_context_ops verbs_dummy_ops = {
query_srq,
read_comp_cntr,
read_counters,
+ read_counters_ex,
read_err_comp_cntr,
reg_dm_mr,
reg_dmabuf_mr,
@@ -1002,6 +1011,7 @@ void verbs_set_ops(struct verbs_context *vctx,
SET_OP(vctx, query_rt_values);
SET_PRIV_OP_IC(vctx, read_comp_cntr);
SET_OP(vctx, read_counters);
+ SET_PRIV_OP_IC(vctx, read_counters_ex);
SET_PRIV_OP_IC(vctx, read_err_comp_cntr);
SET_PRIV_OP(ctx, query_srq);
SET_OP(vctx, reg_dm_mr);
diff --git a/libibverbs/libibverbs.map.in b/libibverbs/libibverbs.map.in
index 51e8b85db478..0301e32d24ab 100644
--- a/libibverbs/libibverbs.map.in
+++ b/libibverbs/libibverbs.map.in
@@ -215,6 +215,7 @@ IBVERBS_1.19 {
ibv_destroy_jkey;
ibv_create_ah_ex;
ibv_ah_to_ah_ex;
+ ibv_read_counters_ex;
} IBVERBS_1.18;
/* If any symbols in this stanza change ABI then the entire staza gets a new symbol
@@ -295,6 +296,7 @@ IBVERBS_PRIVATE_@IBVERBS_PABI_VERSION@ {
ibv_cmd_query_srq;
ibv_cmd_read_comp_cntr;
ibv_cmd_read_counters;
+ ibv_cmd_read_counters_ex;
ibv_cmd_read_err_comp_cntr;
ibv_cmd_reg_dm_mr;
ibv_cmd_reg_dmabuf_mr;
diff --git a/libibverbs/verbs.c b/libibverbs/verbs.c
index 2f73c01fec7f..1df4dbf94dcc 100644
--- a/libibverbs/verbs.c
+++ b/libibverbs/verbs.c
@@ -1034,6 +1034,16 @@ int ibv_read_comp_cntr(struct ibv_comp_cntr *comp_cntr, uint64_t *value)
return get_ops(comp_cntr->context)->read_comp_cntr(comp_cntr, value);
}
+int ibv_read_counters_ex(struct ibv_counters *counters, const uint64_t *items,
+ uint64_t *counters_value, uint64_t *timestamps,
+ uint32_t ncounters, uint32_t flags)
+{
+ return get_ops(counters->context)->read_counters_ex(counters, items,
+ counters_value,
+ timestamps, ncounters,
+ flags);
+}
+
int ibv_read_err_comp_cntr(struct ibv_comp_cntr *comp_cntr, uint64_t *value)
{
return get_ops(comp_cntr->context)->read_err_comp_cntr(comp_cntr, value);
diff --git a/libibverbs/verbs.h b/libibverbs/verbs.h
index f887dc5bc356..1bb680b7be39 100644
--- a/libibverbs/verbs.h
+++ b/libibverbs/verbs.h
@@ -3484,6 +3484,23 @@ int ibv_inc_err_comp_cntr(struct ibv_comp_cntr *comp_cntr, uint64_t amount);
*/
int ibv_read_comp_cntr(struct ibv_comp_cntr *comp_cntr, uint64_t *value);
+/**
+ * ibv_read_counters_ex - Read selected counters, with timestamps
+ * @counters: counters object from ibv_create_counters()
+ * @items: counter numbers to read, or NULL to read counters 0..ncounters-1
+ * @counters_value: receives the value of each counter
+ * @timestamps: if not NULL, receives the time in nanoseconds each counter
+ * was read, as defined by the provider
+ * @ncounters: number of entries in each array
+ * @flags: enum ibv_read_counters_flags
+ *
+ * Only providers that implement the extended read support it. Returns 0 on
+ * success, else an errno value.
+ */
+int ibv_read_counters_ex(struct ibv_counters *counters, const uint64_t *items,
+ uint64_t *counters_value, uint64_t *timestamps,
+ uint32_t ncounters, uint32_t flags);
+
/**
* ibv_read_err_comp_cntr - Read the error count value
* @comp_cntr: The completion counter to read.
--
2.56.0