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 12/15] tools/rv: Add reactors support to BPF monitors
Date: Thu, 1 Oct 2026 17:20:39 +0200 [thread overview]
Message-ID: <20261001152042.124445-13-gmonaco@redhat.com> (raw)
In-Reply-To: <20261001152042.124445-1-gmonaco@redhat.com>
The BPF implementation of RV monitors cannot use standard reactors in
the kernel and currently reactions are skipped.
Add rv_react() to build the printk format using BPF macros and pass that
to a BPF function with a single message parameter, since BPF doesn't
support variable arguments.
This function is defined as weak, so the rv tool can link a different
implementation on top at load time.
Implement a printk reactor that is simply reimplementing this function
passing the message to bpf_printk().
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/rv/da_monitor.h | 4 +-
tools/verification/rv/Makefile | 12 ++-
tools/verification/rv/Makefile.rv | 5 +
.../rv/bpf_monitors/da_monitor_bpf.h | 12 ++-
tools/verification/rv/bpf_reactors/.gitignore | 2 +
tools/verification/rv/bpf_reactors/panic.c | 15 +++
tools/verification/rv/bpf_reactors/printk.c | 13 +++
tools/verification/rv/src/bpf_monitor.c | 102 +++++++++++++++++-
8 files changed, 157 insertions(+), 8 deletions(-)
create mode 100644 tools/verification/rv/bpf_reactors/.gitignore
create mode 100644 tools/verification/rv/bpf_reactors/panic.c
create mode 100644 tools/verification/rv/bpf_reactors/printk.c
diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h
index ee1cec73ec85..28cff26aecfe 100644
--- a/include/rv/da_monitor.h
+++ b/include/rv/da_monitor.h
@@ -84,7 +84,8 @@ static struct rv_monitor rv_this;
#ifdef __BPF__
#include "da_monitor_bpf.h"
-#else
+#endif
+
static void react(enum states curr_state, enum events event)
{
rv_react(&rv_this,
@@ -93,7 +94,6 @@ static void react(enum states curr_state, enum events event)
model_get_event_name(event),
model_get_state_name(curr_state));
}
-#endif
/*
* da_monitor_reset_state - reset a monitor and setting it to init state
diff --git a/tools/verification/rv/Makefile b/tools/verification/rv/Makefile
index bb81593acd71..44b0e3af1488 100644
--- a/tools/verification/rv/Makefile
+++ b/tools/verification/rv/Makefile
@@ -73,8 +73,11 @@ static: $(RV_IN)
$(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RV)-static $(RV_IN) $(EXTLIBS)
BPF_DIR := bpf_monitors
+BPF_REACT_DIR := bpf_reactors
BPF_SOURCES := $(wildcard $(BPF_DIR)/*.c)
BPF_OBJECTS := $(BPF_SOURCES:.c=.o)
+BPF_REACT_SOURCES := $(wildcard $(BPF_REACT_DIR)/*.c)
+BPF_REACT_OBJECTS := $(BPF_REACT_SOURCES:.c=.o)
VMLINUX_H := $(BPF_DIR)/vmlinux.h
BPF_INCLUDES := -I$(srctree)/include/uapi
@@ -95,9 +98,14 @@ $(BPF_DIR)/%.o: $(BPF_DIR)/%.c $(VMLINUX_H)
$(Q)$(LLVM_STRIP) -g $@
$(Q)$(LLVM_OBJCOPY) --remove-section=.rel.rodata $@
--include $(BPF_SOURCES:.c=.d)
+$(BPF_REACT_DIR)/%.o: $(BPF_REACT_DIR)/%.c $(VMLINUX_H)
+ $(QUIET_CLANG)$(CLANG) $(BPF_CFLAGS) -c $< -o $@
+ $(Q)$(LLVM_STRIP) -g $@
+ $(Q)$(LLVM_OBJCOPY) --remove-section=.rel.rodata $@
+
+-include $(BPF_SOURCES:.c=.d) $(BPF_REACT_SOURCES:.c=.d)
-bpf: $(BPF_OBJECTS)
+bpf: $(BPF_OBJECTS) $(BPF_REACT_OBJECTS)
rv.%: fixdep FORCE
make -f $(srctree)/tools/build/Makefile.build dir=. $@
diff --git a/tools/verification/rv/Makefile.rv b/tools/verification/rv/Makefile.rv
index 418748bc3aa1..3ac329851914 100644
--- a/tools/verification/rv/Makefile.rv
+++ b/tools/verification/rv/Makefile.rv
@@ -34,6 +34,7 @@ MKDIR := mkdir
STRIP := strip
BINDIR := /usr/bin
BPF_MON_DIR := /usr/share/rv/bpf_monitors
+BPF_REACT_DIR := /usr/share/rv/bpf_reactors
.PHONY: install
install: doc_install
@@ -44,6 +45,10 @@ ifneq ($(wildcard bpf_monitors/*.o),)
$(Q)$(MKDIR) -p $(DESTDIR)$(BPF_MON_DIR)
$(call QUIET_INSTALL,bpf_monitors)$(INSTALL) bpf_monitors/*.o -m 644 $(DESTDIR)$(BPF_MON_DIR)
endif
+ifneq ($(wildcard bpf_reactors/*.o),)
+ $(Q)$(MKDIR) -p $(DESTDIR)$(BPF_REACT_DIR)
+ $(call QUIET_INSTALL,bpf_reactors)$(INSTALL) bpf_reactors/*.o -m 644 $(DESTDIR)$(BPF_REACT_DIR)
+endif
.PHONY: doc doc_clean doc_install
doc:
diff --git a/tools/verification/rv/bpf_monitors/da_monitor_bpf.h b/tools/verification/rv/bpf_monitors/da_monitor_bpf.h
index 12f0f78b9c9d..a37d11fef6f1 100644
--- a/tools/verification/rv/bpf_monitors/da_monitor_bpf.h
+++ b/tools/verification/rv/bpf_monitors/da_monitor_bpf.h
@@ -17,7 +17,6 @@
#include "bpf_atomic.h"
/* BPF monitors don't support these */
-#define rv_react(...) do {} while (0)
#define trace_rv_retries_error(...) do {} while (0)
#define pr_warn(fmt, ...) bpf_printk(fmt, ##__VA_ARGS__)
#define rv_monitoring_on() 1
@@ -75,8 +74,15 @@ static const struct rv_trace_entry __used *_btf_trace;
static inline void da_monitor_reset(struct da_monitor *da_mon);
-/* BPF monitors do not use reactors */
-static inline void react(enum states curr_state, enum events event) { }
+__noinline __weak void bpf_rv_react(char *msg) { }
+
+#define rv_react(mon, fmt, ...) \
+ ({ \
+ char ___msg[256]; \
+ \
+ if (BPF_SNPRINTF(___msg, sizeof(___msg), fmt, ##__VA_ARGS__) > 0) \
+ bpf_rv_react(___msg); \
+ })
/*
* BPF monitor implementations
diff --git a/tools/verification/rv/bpf_reactors/.gitignore b/tools/verification/rv/bpf_reactors/.gitignore
new file mode 100644
index 000000000000..e5add9141ef5
--- /dev/null
+++ b/tools/verification/rv/bpf_reactors/.gitignore
@@ -0,0 +1,2 @@
+*.d
+vmlinux.h
diff --git a/tools/verification/rv/bpf_reactors/panic.c b/tools/verification/rv/bpf_reactors/panic.c
new file mode 100644
index 000000000000..775f91a300f0
--- /dev/null
+++ b/tools/verification/rv/bpf_reactors/panic.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+
+void bpf_rv_react(char *msg)
+{
+ struct pt_regs regs = { 0 };
+
+ crash_kexec(®s);
+}
+
+char LICENSE[] SEC("license") = "GPL";
+static char DESCRIPTION[] SEC(".rodata.description") =
+ "panic the system if an exception is found.";
diff --git a/tools/verification/rv/bpf_reactors/printk.c b/tools/verification/rv/bpf_reactors/printk.c
new file mode 100644
index 000000000000..580410d2a1fc
--- /dev/null
+++ b/tools/verification/rv/bpf_reactors/printk.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+
+void bpf_rv_react(char *msg)
+{
+ bpf_printk("%s", msg);
+}
+
+char LICENSE[] SEC("license") = "GPL";
+static char DESCRIPTION[] SEC(".rodata.description") =
+ "prints the exception msg to the trace buffer.";
diff --git a/tools/verification/rv/src/bpf_monitor.c b/tools/verification/rv/src/bpf_monitor.c
index d43ee75d3904..35bd1f40a109 100644
--- a/tools/verification/rv/src/bpf_monitor.c
+++ b/tools/verification/rv/src/bpf_monitor.c
@@ -5,6 +5,7 @@
* Copyright (C) 2026 Red Hat Inc, Gabriele Monaco <gmonaco@redhat.com>
*/
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -14,6 +15,7 @@
#include <libgen.h>
#include <errno.h>
#include <inttypes.h>
+#include <sys/mman.h>
#include <bpf/libbpf.h>
#include <bpf/bpf.h>
#include <bpf/btf.h>
@@ -36,6 +38,7 @@ static char bpf_base_paths[][MAX_PATH] = {
#define MAX_ENUMS 64
#define MAX_LINKS 16
#define PROG_ENABLE_MON "enable_monitor"
+#define BPF_REACTOR "bpf_rv_react"
#define RV_TRACE_STRUCT "rv_trace_entry"
#define RV_TRACE_TYPE_ENUM "rv_trace_type"
@@ -676,12 +679,31 @@ static struct ring_buffer *bpf_setup_ring_buffer(struct bpf_object *obj,
return rb;
}
+static void list_reactor_action(const char *name, struct bpf_object *obj)
+{
+ const struct btf *btf = bpf_object__btf(obj);
+
+ if (btf__find_by_name_kind(btf, BPF_REACTOR, BTF_KIND_FUNC) >= 0)
+ fprintf(stderr, "%s ", name);
+}
+
+/*
+ * list_reactors_from_path - list reactors from a specific base path
+ */
+static void list_reactors_from_path(const char *base_path)
+{
+ bpf_object_iterate_path(base_path, "bpf_reactors", list_reactor_action);
+}
+
/*
* bpf_usage_print_reactors - print available BPF reactors
*/
void bpf_usage_print_reactors(void)
{
- fprintf(stderr, " available BPF reactors: nop\n");
+ fprintf(stderr, " available BPF reactors: nop ");
+ for (int i = 0; bpf_base_paths[i][0]; i++)
+ list_reactors_from_path(bpf_base_paths[i]);
+ fprintf(stderr, "\n");
}
/*
@@ -720,6 +742,7 @@ static struct bpf_object *open_bpf_monitor(const char *path, struct bpf_monitor_
int res;
LIBBPF_OPTS(bpf_object_open_opts, opts,
+ .object_name = ctx->monitor_name,
/* Define statically as arch is known, Kconfig may not be available */
#ifdef __x86_64__
.kconfig = "CONFIG_X86_64=y\n",
@@ -795,6 +818,65 @@ static int attach_bpf_handlers(const char *monitor_name, struct bpf_object *obj,
return enable_mon_fd;
}
+static int find_bpf_reactor(const char *reactor_name, char *path_out, size_t path_len)
+{
+ return find_bpf_file("bpf_reactors", reactor_name, path_out, path_len);
+}
+
+/*
+ * link_bpf_reactor - link the reactor function to the monitor
+ *
+ * Reactors are objects defining the BPF_REACTOR function, link that over the
+ * weak definition present in the monitor and return a file descriptor to the
+ * final linked object in memory.
+ *
+ * Returns memfd of final object on success, -1 on error.
+ */
+static int link_bpf_reactor(const char *monitor_path, const char *reactor_path)
+{
+ struct bpf_linker *linker = NULL;
+ int memfd = -1;
+ int err = 0;
+
+ memfd = memfd_create("linked_bpf", 0);
+ if (memfd < 0) {
+ err_msg("bpf: failed to create memfd: %s\n", strerror(errno));
+ return -1;
+ }
+
+ linker = bpf_linker__new_fd(memfd, NULL);
+ if (!linker) {
+ err_msg("bpf: failed to create BPF linker\n");
+ goto out;
+ }
+
+ err = bpf_linker__add_file(linker, monitor_path, NULL);
+ if (err) {
+ err_msg("bpf: failed to add monitor file to linker: %s\n", strerror(-err));
+ goto out;
+ }
+
+ err = bpf_linker__add_file(linker, reactor_path, NULL);
+ if (err) {
+ err_msg("bpf: failed to add reactor file to linker: %s\n", strerror(-err));
+ goto out;
+ }
+
+ err = bpf_linker__finalize(linker);
+ if (err) {
+ err_msg("bpf: failed to finalize BPF linker: %s\n", strerror(-err));
+ goto out;
+ }
+
+ bpf_linker__free(linker);
+ return memfd;
+
+out:
+ bpf_linker__free(linker);
+ close(memfd);
+ return -1;
+}
+
/*
* bpf_run_monitor - load and run a BPF monitor
*
@@ -808,6 +890,7 @@ int bpf_run_monitor(char *monitor_name, int argc, char **argv)
struct bpf_object *obj = NULL;
int res, link_count = 0, enable_mon_fd, retval = -1;
char monitor_path[MAX_PATH];
+ int memfd = -1;
libbpf_set_print(libbpf_print_fn);
bpf_fill_base_paths();
@@ -830,8 +913,25 @@ int bpf_run_monitor(char *monitor_name, int argc, char **argv)
strncpy(ctx.monitor_name, monitor_name, sizeof(ctx.monitor_name) - 1);
+ if (config.reactor && strcmp(config.reactor, "nop")) {
+ char reactor_path[MAX_PATH];
+
+ if (!find_bpf_reactor(config.reactor, reactor_path, sizeof(reactor_path))) {
+ mon_usage(1, monitor_name,
+ "bpf: failed to set %s reactor, is it available?",
+ config.reactor);
+ goto cleanup;
+ }
+
+ memfd = link_bpf_reactor(monitor_path, reactor_path);
+ if (memfd < 0)
+ goto cleanup;
+
+ snprintf(monitor_path, sizeof(monitor_path), "/proc/self/fd/%d", memfd);
+ }
obj = open_bpf_monitor(monitor_path, &ctx);
+ close(memfd);
if (!obj)
goto cleanup;
--
2.55.0
next prev parent reply other threads:[~2026-10-01 15:22 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 15:20 [PATCH v2 00/15] rv: Add support for " 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 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 ` [PATCH v2 07/15] tools/rv: Implement BPF monitor discovery and listing Gabriele Monaco
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-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-01 15:20 ` [PATCH v2 10/15] tools/rv: Add BPF monitors Gabriele Monaco
2026-10-02 0:43 ` bot+bpf-ci
2026-10-01 15:20 ` [PATCH v2 11/15] tools/rv: Define CONFIG_X86_64 statically for " Gabriele Monaco
2026-10-01 15:20 ` Gabriele Monaco [this message]
2026-10-02 0:43 ` [PATCH v2 12/15] tools/rv: Add reactors support to " 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-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-13-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®