From: Gabriele Monaco <gmonaco@redhat.com>
To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
bpf@vger.kernel.org, Steven Rostedt <rostedt@goodmis.org>,
Gabriele Monaco <gmonaco@redhat.com>
Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>,
Nam Cao <namcao@linutronix.de>, Wen Yang <wen.yang@linux.dev>,
Tobias Schaffner <tobias.schaffner@siemens.com>,
Viktor Malik <vmalik@redhat.com>
Subject: [PATCH v2 07/15] tools/rv: Implement BPF monitor discovery and listing
Date: Thu, 1 Oct 2026 17:20:34 +0200 [thread overview]
Message-ID: <20261001152042.124445-8-gmonaco@redhat.com> (raw)
In-Reply-To: <20261001152042.124445-1-gmonaco@redhat.com>
Implement the BPF monitor listing functionality that scans for compiled
BPF monitor object files and displays them in the monitor list.
If enabled, running rv list shows in-kernel and BPF monitors found in
/usr/share/rv/bpf_monitors/ or in ./bpf_monitors/ relative to the RV
binary's location (used during development).
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
tools/verification/rv/Makefile | 4 +-
tools/verification/rv/Makefile.config | 23 ++
tools/verification/rv/include/bpf_monitor.h | 14 ++
tools/verification/rv/src/Build | 5 +
tools/verification/rv/src/bpf_monitor.c | 223 ++++++++++++++++++++
tools/verification/rv/src/rv.c | 2 +
6 files changed, 270 insertions(+), 1 deletion(-)
create mode 100644 tools/verification/rv/include/bpf_monitor.h
create mode 100644 tools/verification/rv/src/bpf_monitor.c
diff --git a/tools/verification/rv/Makefile b/tools/verification/rv/Makefile
index 8ae5fc0d1d17..0a8c7a656f7f 100644
--- a/tools/verification/rv/Makefile
+++ b/tools/verification/rv/Makefile
@@ -32,8 +32,10 @@ DOCSRC := ../../../Documentation/tools/rv/
FEATURE_TESTS := libtraceevent
FEATURE_TESTS += libtracefs
+FEATURE_TESTS += libbpf
FEATURE_DISPLAY := libtraceevent
FEATURE_DISPLAY += libtracefs
+FEATURE_DISPLAY += libbpf
all: $(RV)
@@ -57,7 +59,7 @@ endif
CFLAGS += $(INCLUDES) $(LIB_INCLUDES)
-export CFLAGS OUTPUT srctree
+export CFLAGS OUTPUT srctree BUILD_BPF
$(RV): $(RV_IN)
$(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RV) $(RV_IN) $(EXTLIBS)
diff --git a/tools/verification/rv/Makefile.config b/tools/verification/rv/Makefile.config
index 066302230eb2..0600170ac217 100644
--- a/tools/verification/rv/Makefile.config
+++ b/tools/verification/rv/Makefile.config
@@ -43,6 +43,29 @@ else
$(info libtracefs is missing. Please install libtracefs-dev/libtracefs-devel)
endif
+ifndef BUILD_BPF
+ # BPF monitors are optional but enabled by default
+ BUILD_BPF := 1
+endif
+
+ifeq ($(BUILD_BPF),0)
+ $(info BPF monitor support disabled, building without BPF monitor support.)
+endif
+
+$(call feature_check,libbpf)
+ifeq ($(feature-libbpf), 1)
+ $(call detected,CONFIG_LIBBPF)
+else
+ $(info libbpf is missing, building without BPF monitor support.)
+ $(info Please install libbpf-dev/libbpf-devel)
+ BUILD_BPF := 0
+endif
+
+ifeq ($(BUILD_BPF),1)
+ CFLAGS += -DHAVE_LIBBPF
+ $(call lib_setup,bpf)
+endif
+
ifeq ($(STOP_ERROR),1)
$(error Please, check the errors above.)
endif
diff --git a/tools/verification/rv/include/bpf_monitor.h b/tools/verification/rv/include/bpf_monitor.h
new file mode 100644
index 000000000000..e58bc45c5f75
--- /dev/null
+++ b/tools/verification/rv/include/bpf_monitor.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef _BPF_MONITOR_H
+#define _BPF_MONITOR_H
+
+#ifdef HAVE_LIBBPF
+int bpf_list_monitors(char *container);
+#else
+static inline int bpf_list_monitors(char *container)
+{
+ return 0;
+}
+#endif /* HAVE_LIBBPF */
+
+#endif
diff --git a/tools/verification/rv/src/Build b/tools/verification/rv/src/Build
index d781983c1a79..326503c22915 100644
--- a/tools/verification/rv/src/Build
+++ b/tools/verification/rv/src/Build
@@ -1,4 +1,9 @@
rv-y += trace.o
rv-y += utils.o
rv-y += in_kernel.o
+
+ifeq ($(BUILD_BPF),1)
+ rv-y += bpf_monitor.o
+endif
+
rv-y += rv.o
diff --git a/tools/verification/rv/src/bpf_monitor.c b/tools/verification/rv/src/bpf_monitor.c
new file mode 100644
index 000000000000..a1de0c157712
--- /dev/null
+++ b/tools/verification/rv/src/bpf_monitor.c
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * BPF monitor support: allows rv to control BPF monitors.
+ *
+ * Copyright (C) 2026 Red Hat Inc, Gabriele Monaco <gmonaco@redhat.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <errno.h>
+#include <bpf/libbpf.h>
+#include <bpf/bpf.h>
+#include <bpf/btf.h>
+
+#include <bpf_monitor.h>
+#include <utils.h>
+#include <rv.h>
+
+static char bpf_base_paths[][MAX_PATH] = {
+ ".",
+ "/etc/rv",
+ "/usr/local/share/rv",
+ "/usr/share/rv",
+ "", /* Marker */
+};
+
+/* Path used for development, searched first */
+#define DEVEL_PATH 0
+
+
+/*
+ * bpf_read_enable - reads monitor's enable status
+ *
+ * Iterate through all BPF maps in the system, if the rv_mon_NAME map is
+ * loaded, the monitor is enabled.
+ * Since map names have limited size and may get truncated, check that also the
+ * corresponding BTF matches.
+ */
+static int bpf_read_enable(const char *monitor_name)
+{
+ char ringbuf_name[2 * MAX_DA_NAME_LEN];
+ uint32_t id = 0;
+
+ snprintf(ringbuf_name, sizeof(ringbuf_name),
+ "rv_mon_%s", monitor_name);
+
+ while (bpf_map_get_next_id(id, &id) == 0) {
+ struct bpf_map_info info = { 0 };
+ uint32_t info_len = sizeof(info);
+ struct btf *btf;
+ int type_id;
+ int fd = bpf_map_get_fd_by_id(id);
+
+ if (fd < 0)
+ continue;
+
+ if (bpf_map_get_info_by_fd(fd, &info, &info_len) != 0) {
+ close(fd);
+ continue;
+ }
+ close(fd);
+
+ if (strncmp(info.name, ringbuf_name, BPF_OBJ_NAME_LEN - 1) != 0)
+ continue;
+
+ if (!info.btf_id)
+ continue;
+ btf = btf__load_from_kernel_by_id(info.btf_id);
+ if (!btf)
+ continue;
+
+ type_id = btf__find_by_name_kind(btf, ringbuf_name, BTF_KIND_VAR);
+ btf__free(btf);
+ if (type_id > 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * bpf_read_desc - read monitors' description
+ *
+ * Return the provided string containing the monitor's description, NULL
+ * otherwise.
+ */
+static char *bpf_read_desc(char *desc, struct bpf_object *obj, const char *monitor_name)
+{
+ struct bpf_map *map = bpf_object__find_map_by_name(obj, ".rodata.description");
+ const char *desc_data;
+ size_t desc_size;
+
+ if (!map) {
+ debug_msg("bpf: cannot find description for %s\n",
+ monitor_name);
+ return NULL;
+ }
+ desc_data = bpf_map__initial_value(map, &desc_size);
+ if (!desc_data || desc_size == 0) {
+ debug_msg("bpf: empty description for %s\n", monitor_name);
+ *desc = 0;
+ return desc;
+ }
+
+ if (desc_size >= MAX_DESCRIPTION)
+ desc_size = MAX_DESCRIPTION - 1;
+ strncpy(desc, desc_data, desc_size);
+ desc[desc_size] = '\0';
+
+ return desc;
+}
+
+/*
+ * bpf_fill_base_paths - fill the path for development builds
+ *
+ * RV searches for BPF monitors on absolute paths on the system as well
+ * as in the same directory of the rv binary. This is useful when running
+ * rv from the kernel tree. This function resolves the right location.
+ */
+static void bpf_fill_base_paths(void)
+{
+ char tmp_path[MAX_PATH], *dir;
+ ssize_t len;
+
+ len = readlink("/proc/self/exe", tmp_path, MAX_PATH);
+ if (len > 0 && len != MAX_PATH) {
+ tmp_path[len] = '\0';
+ dir = dirname(tmp_path);
+ snprintf(bpf_base_paths[DEVEL_PATH], MAX_PATH, "%s", dir);
+ }
+}
+
+static void bpf_object_iterate_path(const char *base_path, const char *subdir,
+ void (*action)(const char *name, struct bpf_object *obj))
+{
+ char path[MAX_PATH];
+ struct dirent *entry;
+ DIR *dir;
+ char *ext;
+
+ snprintf(path, sizeof(path), "%s/%s", base_path, subdir);
+ dir = opendir(path);
+ if (!dir) {
+ debug_msg("bpf: error opening directory: %s\n", path);
+ return;
+ }
+
+ while ((entry = readdir(dir)) != NULL) {
+ size_t size;
+ struct bpf_object *obj;
+ char name[MAX_DA_NAME_LEN], obj_path[MAX_PATH];
+
+ if (entry->d_name[0] == '.')
+ continue;
+
+ ext = strrchr(entry->d_name, '.');
+ if (!ext || strcmp(ext, ".o") != 0)
+ continue;
+
+ size = snprintf(obj_path, sizeof(obj_path), "%s/%s", path,
+ entry->d_name);
+ obj = bpf_object__open_file(obj_path, NULL);
+ if (!obj || size > MAX_PATH) {
+ err_msg("bpf: error opening object file %s: %s\n",
+ obj_path, strerror(errno));
+ continue;
+ }
+
+ strncpy(name, entry->d_name, sizeof(name));
+ ext = strrchr(name, '.');
+ if (ext)
+ *ext = '\0';
+
+ action(name, obj);
+
+ bpf_object__close(obj);
+ }
+
+ closedir(dir);
+}
+
+static void list_monitor_action(const char *name, struct bpf_object *obj)
+{
+ char desc[MAX_DESCRIPTION];
+
+ if (!bpf_read_desc(desc, obj, name)) {
+ err_msg("bpf: monitor %s does not have desc map, bug?\n", name);
+ return;
+ }
+
+ printf("%-*s %s %s\n", MAX_DA_NAME_LEN, name,
+ desc, bpf_read_enable(name) ? "[ON]" : "[OFF]");
+}
+
+/*
+ * list_monitors_from_path - list monitors from a specific base path
+ */
+static void list_monitors_from_path(const char *base_path)
+{
+ bpf_object_iterate_path(base_path, "bpf_monitors", list_monitor_action);
+}
+
+/*
+ * bpf_list_monitors - list available BPF monitors from all sources
+ *
+ * @container: BPF monitors are not nested, skip listing.
+ *
+ * Returns 0 on success
+ */
+int bpf_list_monitors(char *container)
+{
+ if (container)
+ return 0;
+ bpf_fill_base_paths();
+ for (int i = 0; bpf_base_paths[i][0]; i++)
+ list_monitors_from_path(bpf_base_paths[i]);
+
+ return 0;
+}
diff --git a/tools/verification/rv/src/rv.c b/tools/verification/rv/src/rv.c
index 09e0d8598619..7c4a2e49ff9d 100644
--- a/tools/verification/rv/src/rv.c
+++ b/tools/verification/rv/src/rv.c
@@ -13,6 +13,7 @@
#include <trace.h>
#include <utils.h>
#include <in_kernel.h>
+#include <bpf_monitor.h>
static int stop_session;
@@ -76,6 +77,7 @@ static void rv_list(int argc, char **argv)
}
ikm_list_monitors(container);
+ bpf_list_monitors(container);
exit(EXIT_SUCCESS);
}
--
2.55.0
next prev parent reply other threads:[~2026-10-01 15:22 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 15:20 [PATCH v2 00/15] rv: Add support for BPF monitors Gabriele Monaco
2026-10-01 15:20 ` [PATCH v2 01/15] sched: Add task enqueue/dequeue trace points Gabriele Monaco
2026-10-01 15:49 ` Peter Zijlstra
2026-10-02 7:09 ` Gabriele Monaco
2026-10-02 10:29 ` Peter Zijlstra
2026-10-02 11:55 ` Gabriele Monaco
2026-10-02 19:18 ` Peter Zijlstra
2026-10-02 19:40 ` Gabriele Monaco
2026-10-04 7:57 ` Steven Rostedt
2026-10-04 7:45 ` Steven Rostedt
2026-10-02 0:42 ` bot+bpf-ci
2026-10-01 15:20 ` [PATCH v2 02/15] tools/rv: Skip empty pid error in selftest if command failed Gabriele Monaco
2026-10-02 0:42 ` bot+bpf-ci
2026-10-01 15:20 ` [PATCH v2 03/15] rv: Refactor da_trace() functions to get strings internally Gabriele Monaco
2026-10-01 15:20 ` [PATCH v2 04/15] rv: Cast result of model_get_*_name() Gabriele Monaco
2026-10-01 15:20 ` [PATCH v2 05/15] tools/rv: Move argument parsing from in_kernel to utils Gabriele Monaco
2026-10-02 0:25 ` bot+bpf-ci
2026-10-01 15:20 ` [PATCH v2 06/15] tools/build: Add a feature test for bpftool-btf Gabriele Monaco
2026-10-01 15:20 ` Gabriele Monaco [this message]
2026-10-01 15:40 ` [PATCH v2 07/15] tools/rv: Implement BPF monitor discovery and listing sashiko-bot
2026-10-02 0:42 ` bot+bpf-ci
2026-10-01 15:20 ` [PATCH v2 08/15] tools/rv: Implement BPF monitor loading and tracing Gabriele Monaco
2026-10-01 15:41 ` sashiko-bot
2026-10-02 0:43 ` bot+bpf-ci
2026-10-01 15:20 ` [PATCH v2 09/15] tools/rv: Copy stripped bpf_atomic.h from libarena Gabriele Monaco
2026-10-02 0:42 ` bot+bpf-ci
2026-10-07 12:59 ` Nam Cao
2026-10-08 9:00 ` Gabriele Monaco
2026-10-08 11:16 ` Nam Cao
2026-10-09 10:09 ` Gabriele Monaco
2026-10-01 15:20 ` [PATCH v2 10/15] tools/rv: Add BPF monitors Gabriele Monaco
2026-10-01 15:55 ` sashiko-bot
2026-10-02 0:43 ` bot+bpf-ci
2026-10-06 13:29 ` Alexei Starovoitov
2026-10-08 9:54 ` Gabriele Monaco
2026-10-01 15:20 ` [PATCH v2 11/15] tools/rv: Define CONFIG_X86_64 statically for " Gabriele Monaco
2026-10-01 15:49 ` sashiko-bot
2026-10-01 15:20 ` [PATCH v2 12/15] tools/rv: Add reactors support to " Gabriele Monaco
2026-10-01 15:57 ` sashiko-bot
2026-10-02 0:43 ` bot+bpf-ci
2026-10-01 15:20 ` [PATCH v2 13/15] verification/rvgen: Add support for " Gabriele Monaco
2026-10-02 0:25 ` bot+bpf-ci
2026-10-01 15:20 ` [PATCH v2 14/15] tools/rv: Add selftest for rv bpf monitors Gabriele Monaco
2026-10-01 16:03 ` sashiko-bot
2026-10-02 0:43 ` bot+bpf-ci
2026-10-01 15:20 ` [PATCH v2 15/15] verification/rvgen: Add selftest for rvgen -b Gabriele Monaco
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261001152042.124445-8-gmonaco@redhat.com \
--to=gmonaco@redhat.com \
--cc=alexei.starovoitov@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=namcao@linutronix.de \
--cc=rostedt@goodmis.org \
--cc=tobias.schaffner@siemens.com \
--cc=vmalik@redhat.com \
--cc=wen.yang@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.