[RFC PATCH bpf-next 12/12] selftests/bpf: Add tests for bpf SDT probe

From: Xu Kuohai

Date: Sat Jun 27 2026 - 10:58:45 EST


From: Xu Kuohai <xukuohai@xxxxxxxxxx>

Add selftests for bpf SDT probe sites and observers.

The tests include argument check for observer program, multiple target
programs in the same ELF, and programs with subprog.

Signed-off-by: Xu Kuohai <xukuohai@xxxxxxxxxx>
---
.../selftests/bpf/prog_tests/test_bpf_sdt.c | 151 ++++++++++++++++++
.../selftests/bpf/progs/bpf_sdt_observer.c | 30 ++++
.../selftests/bpf/progs/bpf_sdt_target.c | 34 ++++
3 files changed, 215 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/test_bpf_sdt.c
create mode 100644 tools/testing/selftests/bpf/progs/bpf_sdt_observer.c
create mode 100644 tools/testing/selftests/bpf/progs/bpf_sdt_target.c

diff --git a/tools/testing/selftests/bpf/prog_tests/test_bpf_sdt.c b/tools/testing/selftests/bpf/prog_tests/test_bpf_sdt.c
new file mode 100644
index 000000000000..b2752e7b2b09
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/test_bpf_sdt.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+#include <bpf/bpf.h>
+#include "bpf_sdt_observer.skel.h"
+#include "bpf_sdt_target.skel.h"
+
+static int sdt_attach(struct bpf_program *obs)
+{
+ LIBBPF_OPTS(bpf_link_create_opts, opts);
+
+ return bpf_link_create(bpf_program__fd(obs), 0, BPF_TRACE_SDT, &opts);
+}
+
+static void read_args(void)
+{
+ LIBBPF_OPTS(bpf_test_run_opts, topts);
+ struct bpf_sdt_target *tgt_skel;
+ struct bpf_sdt_observer *skel;
+ char pkt[64] = {};
+ int link, err;
+
+ tgt_skel = bpf_sdt_target__open_and_load();
+ if (!ASSERT_OK_PTR(tgt_skel, "target open_and_load"))
+ return;
+
+ skel = bpf_sdt_observer__open();
+ if (!ASSERT_OK_PTR(skel, "observer open"))
+ goto out_tgt;
+
+ bpf_program__set_autoload(skel->progs.tc_trace_prog, false);
+ bpf_program__set_autoload(skel->progs.subprog_trace_prog, false);
+ bpf_program__set_attach_target(skel->progs.xdp_trace_prog,
+ bpf_program__fd(tgt_skel->progs.xdp_prog),
+ "xdp_probe_len_ret");
+ err = bpf_sdt_observer__load(skel);
+ if (!ASSERT_OK(err, "observer load"))
+ goto out_obs;
+
+ link = sdt_attach(skel->progs.xdp_trace_prog);
+ if (!ASSERT_GE(link, 0, "attach xdp_probe_len_ret"))
+ goto out_obs;
+
+ topts.data_in = pkt;
+ topts.data_size_in = sizeof(pkt);
+ topts.data_size_out = sizeof(pkt);
+ err = bpf_prog_test_run_opts(bpf_program__fd(tgt_skel->progs.xdp_prog), &topts);
+ if (!ASSERT_OK(err, "prog_test_run"))
+ goto out_link;
+
+ ASSERT_EQ(skel->bss->xdp_len, sizeof(pkt), "xdp_len");
+ ASSERT_EQ(skel->bss->xdp_ret, XDP_PASS, "xdp_ret");
+
+out_link:
+ close(link);
+out_obs:
+ bpf_sdt_observer__destroy(skel);
+out_tgt:
+ bpf_sdt_target__destroy(tgt_skel);
+}
+
+static void multi_prog(void)
+{
+ struct bpf_sdt_target *tgt_skel;
+ struct bpf_sdt_observer *skel;
+ int link1, link2, err;
+
+ tgt_skel = bpf_sdt_target__open_and_load();
+ if (!ASSERT_OK_PTR(tgt_skel, "target open_and_load"))
+ return;
+
+ skel = bpf_sdt_observer__open();
+ if (!ASSERT_OK_PTR(skel, "observer open"))
+ goto out_tgt;
+
+ bpf_program__set_autoload(skel->progs.subprog_trace_prog, false);
+ bpf_program__set_attach_target(skel->progs.xdp_trace_prog,
+ bpf_program__fd(tgt_skel->progs.xdp_prog),
+ "xdp_probe_len_ret");
+ bpf_program__set_attach_target(skel->progs.tc_trace_prog,
+ bpf_program__fd(tgt_skel->progs.tc_prog),
+ "tc_probe");
+ err = bpf_sdt_observer__load(skel);
+ if (!ASSERT_OK(err, "observer load"))
+ goto out_obs;
+
+ link1 = sdt_attach(skel->progs.xdp_trace_prog);
+ ASSERT_GE(link1, 0, "attach xdp xdp_probe_len_ret");
+
+ link2 = sdt_attach(skel->progs.tc_trace_prog);
+ ASSERT_GE(link2, 0, "attach tc_probe");
+
+ close(link1);
+ close(link2);
+out_obs:
+ bpf_sdt_observer__destroy(skel);
+out_tgt:
+ bpf_sdt_target__destroy(tgt_skel);
+}
+
+static void subprog_probe(void)
+{
+ LIBBPF_OPTS(bpf_test_run_opts, topts);
+ struct bpf_sdt_target *tgt_skel;
+ struct bpf_sdt_observer *skel;
+ char pkt[64] = {0, 1, 2, 3};
+ int link, err;
+
+ tgt_skel = bpf_sdt_target__open_and_load();
+ if (!ASSERT_OK_PTR(tgt_skel, "target open_and_load"))
+ return;
+
+ skel = bpf_sdt_observer__open();
+ if (!ASSERT_OK_PTR(skel, "observer open"))
+ goto out_tgt;
+
+ bpf_program__set_autoload(skel->progs.tc_trace_prog, false);
+ bpf_program__set_autoload(skel->progs.xdp_trace_prog, false);
+ bpf_program__set_attach_target(skel->progs.subprog_trace_prog,
+ bpf_program__fd(tgt_skel->progs.xdp_prog),
+ "xdp_probe_ctx");
+ err = bpf_sdt_observer__load(skel);
+ if (!ASSERT_OK(err, "observer load"))
+ goto out_obs;
+
+ link = sdt_attach(skel->progs.subprog_trace_prog);
+ if (!ASSERT_GE(link, 0, "attach xdp_probe_ctx"))
+ goto out_obs;
+
+ topts.data_in = pkt;
+ topts.data_size_in = sizeof(pkt);
+ topts.data_size_out = sizeof(pkt);
+ err = bpf_prog_test_run_opts(bpf_program__fd(tgt_skel->progs.xdp_prog), &topts);
+ ASSERT_OK(err, "prog_test_run");
+ ASSERT_EQ(skel->bss->xdp_len, sizeof(pkt), "xdp_len");
+
+ close(link);
+out_obs:
+ bpf_sdt_observer__destroy(skel);
+out_tgt:
+ bpf_sdt_target__destroy(tgt_skel);
+}
+
+void test_bpf_sdt(void)
+{
+ if (test__start_subtest("read_args"))
+ read_args();
+ if (test__start_subtest("multi_prog"))
+ multi_prog();
+ if (test__start_subtest("subprog_probe"))
+ subprog_probe();
+}
diff --git a/tools/testing/selftests/bpf/progs/bpf_sdt_observer.c b/tools/testing/selftests/bpf/progs/bpf_sdt_observer.c
new file mode 100644
index 000000000000..ec059e86b154
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/bpf_sdt_observer.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+volatile int xdp_len;
+volatile int xdp_ret;
+
+SEC("bpf_sdt")
+int BPF_PROG(tc_trace_prog)
+{
+ return 0;
+}
+
+SEC("bpf_sdt")
+int BPF_PROG(xdp_trace_prog, int len, int ret)
+{
+ xdp_len = len;
+ xdp_ret = ret;
+ return 0;
+}
+
+SEC("bpf_sdt")
+int BPF_PROG(subprog_trace_prog, struct xdp_md *xdp_ctx)
+{
+ xdp_len = bpf_xdp_get_buff_len((struct xdp_md *)xdp_ctx);
+ return 0;
+}
+
+char LICENSE[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/bpf_sdt_target.c b/tools/testing/selftests/bpf/progs/bpf_sdt_target.c
new file mode 100644
index 000000000000..e1c14b9d7e9a
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/bpf_sdt_target.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include "../../../../tools/lib/bpf/bpf_sdt.h"
+
+BPF_SDT_DECLARE(tc_probe);
+BPF_SDT_DECLARE1(xdp_probe_ctx, struct xdp_md *);
+BPF_SDT_DECLARE2(xdp_probe_len_ret, int, int);
+
+static __noinline int xdp_process(struct xdp_md *ctx)
+{
+ BPF_SDT_PROBE1(xdp_probe_ctx, ctx);
+ return XDP_PASS;
+}
+
+SEC("xdp")
+int xdp_prog(struct xdp_md *ctx)
+{
+ int len = (int)(ctx->data_end - ctx->data);
+
+ BPF_SDT_PROBE2(xdp_probe_len_ret, len, XDP_PASS);
+
+ return xdp_process(ctx);
+}
+
+SEC("tc")
+int tc_prog(struct __sk_buff *skb)
+{
+ BPF_SDT_PROBE(tc_probe);
+ return 0;
+}
+
+char LICENSE[] SEC("license") = "GPL";
--
2.47.3