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: 17+ 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-01 15:20 ` [PATCH v2 02/15] tools/rv: Skip empty pid error in selftest if command failed Gabriele Monaco
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-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:20 ` [PATCH v2 08/15] tools/rv: Implement BPF monitor loading and tracing Gabriele Monaco
2026-10-01 15:20 ` [PATCH v2 09/15] tools/rv: Copy stripped bpf_atomic.h from libarena Gabriele Monaco
2026-10-01 15:20 ` [PATCH v2 10/15] tools/rv: Add BPF monitors 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:20 ` [PATCH v2 12/15] tools/rv: Add reactors support to " Gabriele Monaco
2026-10-01 15:20 ` [PATCH v2 13/15] verification/rvgen: Add support for " Gabriele Monaco
2026-10-01 15:20 ` [PATCH v2 14/15] tools/rv: Add selftest for rv bpf monitors Gabriele Monaco
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®