All of lore.kernel.org
 help / color / mirror / Atom feed
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(&regs);
+}
+
+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


  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 ` [PATCH v2 07/15] tools/rv: Implement BPF monitor discovery and listing Gabriele Monaco
2026-10-01 15:40   ` 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 ` Gabriele Monaco [this message]
2026-10-01 15:57   ` [PATCH v2 12/15] tools/rv: Add reactors support to " 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-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 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.