[RFC PATCH bpf-next 7/7] selftests/bpf: Test BPF_LINK_UPDATE behavior for tracing links
Jordan Rife
jordan at jrife.io
Mon Nov 17 16:52:59 PST 2025
Exercise a series of edge cases and happy path scenarios across a gamut
of link types (fentry, fmod_ret, fexit, freplace) to test
BPF_LINK_UPDATE behavior for tracing links. This test swaps
fentry/fmod_ret/fexit programs in-place and makes sure that the sequence
and attach cookie are as expected based on the link positions.
Signed-off-by: Jordan Rife <jordan at jrife.io>
---
.../bpf/prog_tests/prog_update_tracing.c | 460 ++++++++++++++++++
.../selftests/bpf/progs/prog_update_tracing.c | 133 +++++
2 files changed, 593 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/prog_update_tracing.c
create mode 100644 tools/testing/selftests/bpf/progs/prog_update_tracing.c
diff --git a/tools/testing/selftests/bpf/prog_tests/prog_update_tracing.c b/tools/testing/selftests/bpf/prog_tests/prog_update_tracing.c
new file mode 100644
index 000000000000..0b1e0d780c82
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/prog_update_tracing.c
@@ -0,0 +1,460 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <network_helpers.h>
+#include <test_progs.h>
+#include "prog_update_tracing.skel.h"
+#include "test_pkt_access.skel.h"
+
+static bool assert_program_order(struct prog_update_tracing *skel_trace,
+ struct test_pkt_access *skel_pkt,
+ const struct prog_update_tracing__bss *expected)
+{
+ LIBBPF_OPTS(bpf_test_run_opts, topts_trace);
+ LIBBPF_OPTS(bpf_test_run_opts, topts_skb,
+ .data_in = &pkt_v4,
+ .data_size_in = sizeof(pkt_v4),
+ .repeat = 1,
+ );
+ int prog_fd;
+
+ prog_fd = bpf_program__fd(skel_trace->progs.fmod_ret1);
+ if (!ASSERT_OK(bpf_prog_test_run_opts(prog_fd, &topts_trace),
+ "bpf_prog_test_run trace"))
+ return false;
+
+ if (!ASSERT_EQ(skel_trace->bss->fentry1_seq,
+ expected->fentry1_seq, "fentry1_seq"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fentry1_cookie,
+ expected->fentry1_cookie, "fentry1_cookie"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fentry2_seq,
+ expected->fentry2_seq, "fentry2_seq"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fentry2_cookie,
+ expected->fentry2_cookie, "fentry2_cookie"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fmod_ret1_seq,
+ expected->fmod_ret1_seq, "fmod_ret1_seq"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fmod_ret1_cookie,
+ expected->fmod_ret1_cookie, "fmod_ret1_cookie"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fmod_ret2_seq,
+ expected->fmod_ret2_seq, "fmod_ret2_seq"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fmod_ret2_cookie,
+ expected->fmod_ret2_cookie, "fmod_ret2_cookie"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fexit1_seq,
+ expected->fexit1_seq, "fexit1_seq"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fexit1_cookie,
+ expected->fexit1_cookie, "fexit1_cookie"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fexit2_seq,
+ expected->fexit2_seq, "fexit2_seq"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fexit2_cookie,
+ expected->fexit2_cookie, "fexit2_cookie"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->sequence, expected->sequence,
+ "sequence"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->sequence_bpf, 0, "sequence_bpf"))
+ return false;
+
+ prog_fd = bpf_program__fd(skel_pkt->progs.test_pkt_access);
+ if (!ASSERT_OK(bpf_prog_test_run_opts(prog_fd, &topts_skb),
+ "bpf_prog_test_run skb"))
+ return false;
+
+ if (!ASSERT_EQ(skel_trace->bss->sequence, expected->sequence,
+ "sequence"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fentry1_bpf_seq,
+ expected->fentry1_bpf_seq, "fentry1_bpf_seq"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fentry1_bpf_cookie,
+ expected->fentry1_bpf_cookie, "fentry1_bpf_cookie"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fentry2_bpf_seq,
+ expected->fentry2_bpf_seq, "fentry2_bpf_seq"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fentry2_bpf_cookie,
+ expected->fentry2_bpf_cookie, "fentry2_bpf_cookie"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->freplace1_bpf_seq,
+ expected->freplace1_bpf_seq, "freplace1_bpf_seq"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->freplace2_bpf_seq,
+ expected->freplace2_bpf_seq, "freplace2_bpf_seq"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fexit1_bpf_seq,
+ expected->fexit1_bpf_seq, "fexit1_bpf_seq"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fexit1_bpf_cookie,
+ expected->fexit1_bpf_cookie, "fexit1_bpf_cookie"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fexit2_bpf_seq,
+ expected->fexit2_bpf_seq, "fexit2_bpf_seq"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->fexit2_bpf_cookie,
+ expected->fexit2_bpf_cookie, "fexit2_bpf_cookie"))
+ return false;
+ if (!ASSERT_EQ(skel_trace->bss->sequence_bpf, expected->sequence_bpf,
+ "sequence_bpf"))
+ return false;
+
+ memset(skel_trace->bss, 0, sizeof(*skel_trace->bss));
+
+ return true;
+}
+
+void test_prog_update_tracing(void)
+{
+ const struct prog_update_tracing__bss expected_inverted = {
+ .fentry1_seq = 2,
+ .fentry1_cookie = 102,
+ .fentry2_seq = 1,
+ .fentry2_cookie = 101,
+ .fmod_ret1_seq = 4,
+ .fmod_ret1_cookie = 104,
+ .fmod_ret2_seq = 3,
+ .fmod_ret2_cookie = 103,
+ .fexit1_seq = 6,
+ .fexit1_cookie = 106,
+ .fexit2_seq = 5,
+ .fexit2_cookie = 105,
+ .sequence = 6,
+ .fentry1_bpf_seq = 2,
+ .fentry1_bpf_cookie = 202,
+ .fentry2_bpf_seq = 1,
+ .fentry2_bpf_cookie = 201,
+ .freplace1_bpf_seq = 3,
+ .freplace2_bpf_seq = 0,
+ .fexit1_bpf_seq = 5,
+ .fexit1_bpf_cookie = 205,
+ .fexit2_bpf_seq = 4,
+ .fexit2_bpf_cookie = 204,
+ .sequence_bpf = 5,
+ };
+ const struct prog_update_tracing__bss expected_normal = {
+ .fentry1_seq = 1,
+ .fentry1_cookie = 101,
+ .fentry2_seq = 2,
+ .fentry2_cookie = 102,
+ .fmod_ret1_seq = 3,
+ .fmod_ret1_cookie = 103,
+ .fmod_ret2_seq = 4,
+ .fmod_ret2_cookie = 104,
+ .fexit1_seq = 5,
+ .fexit1_cookie = 105,
+ .fexit2_seq = 6,
+ .fexit2_cookie = 106,
+ .sequence = 6,
+ .fentry1_bpf_seq = 1,
+ .fentry1_bpf_cookie = 201,
+ .fentry2_bpf_seq = 2,
+ .fentry2_bpf_cookie = 202,
+ .freplace1_bpf_seq = 3,
+ .freplace2_bpf_seq = 0,
+ .fexit1_bpf_seq = 4,
+ .fexit1_bpf_cookie = 204,
+ .fexit2_bpf_seq = 5,
+ .fexit2_bpf_cookie = 205,
+ .sequence_bpf = 5,
+ };
+ LIBBPF_OPTS(bpf_link_update_opts, update_opts);
+ LIBBPF_OPTS(bpf_trace_opts, trace_opts);
+ struct prog_update_tracing *skel_trace1 = NULL;
+ struct prog_update_tracing *skel_trace2 = NULL;
+ struct test_pkt_access *skel_pkt1 = NULL;
+ struct test_pkt_access *skel_pkt2 = NULL;
+ int link_fd, prog_fd, err;
+ struct bpf_link *link;
+
+ skel_trace1 = prog_update_tracing__open();
+ if (!ASSERT_OK_PTR(skel_trace1, "skel_trace1"))
+ goto cleanup;
+ skel_pkt1 = test_pkt_access__open_and_load();
+ if (!ASSERT_OK_PTR(skel_pkt1, "skel_pkt1"))
+ goto cleanup;
+ prog_fd = bpf_program__fd(skel_pkt1->progs.test_pkt_access);
+ bpf_program__set_attach_target(skel_trace1->progs.fentry1_bpf, prog_fd,
+ NULL);
+ bpf_program__set_attach_target(skel_trace1->progs.fentry2_bpf, prog_fd,
+ NULL);
+ bpf_program__set_attach_target(skel_trace1->progs.fexit1_bpf, prog_fd,
+ NULL);
+ bpf_program__set_attach_target(skel_trace1->progs.fexit2_bpf, prog_fd,
+ NULL);
+ bpf_program__set_attach_target(skel_trace1->progs.freplace1_bpf,
+ prog_fd, "test_pkt_access_subprog3");
+ bpf_program__set_attach_target(skel_trace1->progs.freplace2_bpf,
+ prog_fd, "test_pkt_access_subprog3");
+ bpf_program__set_attach_target(skel_trace1->progs.freplace3_bpf,
+ prog_fd, "get_skb_ifindex");
+ err = prog_update_tracing__load(skel_trace1);
+ if (!ASSERT_OK(err, "skel_trace1 load"))
+ goto cleanup;
+ trace_opts.cookie = expected_normal.fentry2_cookie;
+ link = bpf_program__attach_trace_opts(skel_trace1->progs.fentry2,
+ &trace_opts);
+ if (!ASSERT_OK_PTR(link, "attach fentry2"))
+ goto cleanup;
+ skel_trace1->links.fentry2 = link;
+ trace_opts.cookie = expected_normal.fentry1_cookie;
+ link = bpf_program__attach_trace_opts(skel_trace1->progs.fentry1,
+ &trace_opts);
+ if (!ASSERT_OK_PTR(link, "attach fentry1"))
+ goto cleanup;
+ skel_trace1->links.fentry1 = link;
+ trace_opts.cookie = expected_normal.fmod_ret2_cookie;
+ link = bpf_program__attach_trace_opts(skel_trace1->progs.fmod_ret2,
+ &trace_opts);
+ if (!ASSERT_OK_PTR(link, "attach fmod_ret2"))
+ goto cleanup;
+ skel_trace1->links.fmod_ret2 = link;
+ trace_opts.cookie = expected_normal.fmod_ret1_cookie;
+ link = bpf_program__attach_trace_opts(skel_trace1->progs.fmod_ret1,
+ &trace_opts);
+ if (!ASSERT_OK_PTR(link, "attach fmod_ret1"))
+ goto cleanup;
+ skel_trace1->links.fmod_ret1 = link;
+ trace_opts.cookie = expected_normal.fexit2_cookie;
+ link = bpf_program__attach_trace_opts(skel_trace1->progs.fexit2,
+ &trace_opts);
+ if (!ASSERT_OK_PTR(link, "attach fexit2"))
+ goto cleanup;
+ skel_trace1->links.fexit2 = link;
+ trace_opts.cookie = expected_normal.fexit1_cookie;
+ link = bpf_program__attach_trace_opts(skel_trace1->progs.fexit1,
+ &trace_opts);
+ if (!ASSERT_OK_PTR(link, "attach fexit1"))
+ goto cleanup;
+ skel_trace1->links.fexit1 = link;
+ trace_opts.cookie = expected_normal.fentry2_bpf_cookie;
+ link = bpf_program__attach_trace_opts(skel_trace1->progs.fentry2_bpf,
+ &trace_opts);
+ if (!ASSERT_OK_PTR(link, "attach fentry2_bpf"))
+ goto cleanup;
+ skel_trace1->links.fentry2_bpf = link;
+ trace_opts.cookie = expected_normal.fentry1_bpf_cookie;
+ link = bpf_program__attach_trace_opts(skel_trace1->progs.fentry1_bpf,
+ &trace_opts);
+ if (!ASSERT_OK_PTR(link, "attach fentry1_bpf"))
+ goto cleanup;
+ skel_trace1->links.fentry1_bpf = link;
+ trace_opts.cookie = expected_normal.fexit2_bpf_cookie;
+ link = bpf_program__attach_trace_opts(skel_trace1->progs.fexit2_bpf,
+ &trace_opts);
+ if (!ASSERT_OK_PTR(link, "attach fexit2_bpf"))
+ goto cleanup;
+ skel_trace1->links.fexit2_bpf = link;
+ trace_opts.cookie = expected_normal.fexit1_bpf_cookie;
+ link = bpf_program__attach_trace_opts(skel_trace1->progs.fexit1_bpf,
+ &trace_opts);
+ if (!ASSERT_OK_PTR(link, "attach fexit1_bpf"))
+ goto cleanup;
+ skel_trace1->links.fexit1_bpf = link;
+ link = bpf_program__attach_trace(skel_trace1->progs.freplace1_bpf);
+ if (!ASSERT_OK_PTR(link, "attach freplace1_bpf"))
+ goto cleanup;
+ skel_trace1->links.freplace1_bpf = link;
+ if (!assert_program_order(skel_trace1, skel_pkt1, &expected_normal))
+ goto cleanup;
+
+ /* Program update should fail if expected_attach_type is a mismatch. */
+ err = bpf_link__update_program(skel_trace1->links.fentry1,
+ skel_trace1->progs.fexit1);
+ if (!ASSERT_EQ(err, -EINVAL,
+ "fentry1 update wrong expected_attach_type"))
+ goto cleanup;
+ if (!assert_program_order(skel_trace1, skel_pkt1, &expected_normal))
+ goto cleanup;
+
+ /* Program update should fail if type is a mismatch. */
+ err = bpf_link__update_program(skel_trace1->links.fentry1,
+ skel_pkt1->progs.test_pkt_access);
+ if (!ASSERT_EQ(err, -EINVAL, "fentry1 update wrong type"))
+ goto cleanup;
+ if (!assert_program_order(skel_trace1, skel_pkt1, &expected_normal))
+ goto cleanup;
+
+ /* Program update should fail if program is incompatible */
+ err = bpf_link__update_program(skel_trace1->links.freplace1_bpf,
+ skel_trace1->progs.freplace3_bpf);
+ if (!ASSERT_EQ(err, -EINVAL, "freplace1_bpf update incompatible"))
+ goto cleanup;
+ if (!assert_program_order(skel_trace1, skel_pkt1, &expected_normal))
+ goto cleanup;
+
+ /* Update with BPF_F_REPLACE should fail if old_prog_fd does not match
+ * current link program.
+ */
+ prog_fd = bpf_program__fd(skel_trace1->progs.fentry2);
+ link_fd = bpf_link__fd(skel_trace1->links.fentry1);
+ update_opts.old_prog_fd = bpf_program__fd(skel_trace1->progs.fentry2);
+ update_opts.flags = BPF_F_REPLACE;
+ err = bpf_link_update(link_fd, prog_fd, &update_opts);
+ if (!ASSERT_EQ(err, -EPERM, "BPF_F_REPLACE EPERM"))
+ goto cleanup;
+ if (!assert_program_order(skel_trace1, skel_pkt1, &expected_normal))
+ goto cleanup;
+
+ /* Do an in-place swap of program order using link updates.
+ *
+ * Update with BPF_F_REPLACE should succeed if old_prog_fd matches
+ * current link program.
+ * Update should succeed if the new program's dst_trampoline has been
+ * cleared by a previous attach operation.
+ */
+ update_opts.old_prog_fd = bpf_program__fd(skel_trace1->progs.fentry1);
+ err = bpf_link_update(link_fd, prog_fd, &update_opts);
+ if (!ASSERT_OK(err, "BPF_F_REPLACE"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fentry2,
+ skel_trace1->progs.fentry1);
+ if (!ASSERT_OK(err, "fentry2 update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fmod_ret1,
+ skel_trace1->progs.fmod_ret2);
+ if (!ASSERT_OK(err, "fmod_ret1 update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fmod_ret2,
+ skel_trace1->progs.fmod_ret1);
+ if (!ASSERT_OK(err, "fmod_ret2 update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fexit1,
+ skel_trace1->progs.fexit2);
+ if (!ASSERT_OK(err, "fexit1 update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fexit2,
+ skel_trace1->progs.fexit1);
+ if (!ASSERT_OK(err, "fexit2 update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fentry1_bpf,
+ skel_trace1->progs.fentry2_bpf);
+ if (!ASSERT_OK(err, "fentry1_bpf update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fentry2_bpf,
+ skel_trace1->progs.fentry1_bpf);
+ if (!ASSERT_OK(err, "fentry2_bpf update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fexit1_bpf,
+ skel_trace1->progs.fexit2_bpf);
+ if (!ASSERT_OK(err, "fexit1_bpf update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fexit2_bpf,
+ skel_trace1->progs.fexit1_bpf);
+ if (!ASSERT_OK(err, "fexit2_bpf update"))
+ goto cleanup;
+ /* Only one freplace program can be attached at a time, so instead of
+ * swapping the order as with fentry/fmod_ret/fexit just shuffle
+ * freplace1_bpf and freplace_bpf2.
+ */
+ err = bpf_link__destroy(skel_trace1->links.freplace1_bpf);
+ if (!ASSERT_OK(err, "freplace1_bpf destroy"))
+ goto cleanup;
+ skel_trace1->links.freplace1_bpf = NULL;
+ link = bpf_program__attach_trace(skel_trace1->progs.freplace2_bpf);
+ if (!ASSERT_OK_PTR(link, "attach freplace2_bpf"))
+ goto cleanup;
+ skel_trace1->links.freplace2_bpf = link;
+ err = bpf_link__update_program(skel_trace1->links.freplace2_bpf,
+ skel_trace1->progs.freplace1_bpf);
+ if (!ASSERT_OK(err, "freplace2_bpf update"))
+ goto cleanup;
+ if (!assert_program_order(skel_trace1, skel_pkt1, &expected_inverted))
+ goto cleanup;
+
+ /* Update should work when the new program's dst_trampoline points to
+ * another trampoline or the same trampoline.
+ */
+ skel_trace2 = prog_update_tracing__open();
+ if (!ASSERT_OK_PTR(skel_trace2, "skel_trace2"))
+ goto cleanup;
+ skel_pkt2 = test_pkt_access__open_and_load();
+ if (!ASSERT_OK_PTR(skel_pkt2, "skel_pkt2"))
+ goto cleanup;
+ prog_fd = bpf_program__fd(skel_pkt2->progs.test_pkt_access);
+ bpf_program__set_attach_target(skel_trace2->progs.fentry1_bpf, prog_fd,
+ NULL);
+ bpf_program__set_attach_target(skel_trace2->progs.fentry2_bpf, prog_fd,
+ NULL);
+ bpf_program__set_attach_target(skel_trace2->progs.fexit1_bpf, prog_fd,
+ NULL);
+ bpf_program__set_attach_target(skel_trace2->progs.fexit2_bpf, prog_fd,
+ NULL);
+ bpf_program__set_attach_target(skel_trace2->progs.freplace1_bpf,
+ prog_fd, "test_pkt_access_subprog3");
+ bpf_program__set_attach_target(skel_trace2->progs.freplace2_bpf,
+ prog_fd, "test_pkt_access_subprog3");
+ bpf_program__set_attach_target(skel_trace2->progs.freplace3_bpf,
+ prog_fd, "get_skb_ifindex");
+ err = prog_update_tracing__load(skel_trace2);
+ if (!ASSERT_OK(err, "skel_trace2 load"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fentry1,
+ skel_trace2->progs.fentry1);
+ if (!ASSERT_OK(err, "fentry1 update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fentry2,
+ skel_trace2->progs.fentry2);
+ if (!ASSERT_OK(err, "fentry2 update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fmod_ret1,
+ skel_trace2->progs.fmod_ret1);
+ if (!ASSERT_OK(err, "fmod_ret1 update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fmod_ret2,
+ skel_trace2->progs.fmod_ret2);
+ if (!ASSERT_OK(err, "fmod_ret2 update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fexit1,
+ skel_trace2->progs.fexit1);
+ if (!ASSERT_OK(err, "fexit1 update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fexit2,
+ skel_trace2->progs.fexit2);
+ if (!ASSERT_OK(err, "fexit2 update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fentry1_bpf,
+ skel_trace2->progs.fentry1_bpf);
+ if (!ASSERT_OK(err, "fentry1_bpf update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fentry2_bpf,
+ skel_trace2->progs.fentry2_bpf);
+ if (!ASSERT_OK(err, "fentry2_bpf update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.freplace2_bpf,
+ skel_trace2->progs.freplace1_bpf);
+ if (!ASSERT_OK(err, "freplace2_bpf update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fexit1_bpf,
+ skel_trace2->progs.fexit1_bpf);
+ if (!ASSERT_OK(err, "fexit1_bpf update"))
+ goto cleanup;
+ err = bpf_link__update_program(skel_trace1->links.fexit2_bpf,
+ skel_trace2->progs.fexit2_bpf);
+ if (!ASSERT_OK(err, "fexit2_bpf update"))
+ goto cleanup;
+ if (!assert_program_order(skel_trace2, skel_pkt1, &expected_normal))
+ goto cleanup;
+
+ /* Update should work when the new program is the same as the current
+ * program.
+ */
+ err = bpf_link__update_program(skel_trace1->links.fentry1,
+ skel_trace2->progs.fentry1);
+ if (!ASSERT_OK(err, "fentry1 update"))
+ goto cleanup;
+ if (!assert_program_order(skel_trace2, skel_pkt1, &expected_normal))
+ goto cleanup;
+cleanup:
+ prog_update_tracing__destroy(skel_trace1);
+ prog_update_tracing__destroy(skel_trace2);
+ test_pkt_access__destroy(skel_pkt1);
+ test_pkt_access__destroy(skel_pkt2);
+}
diff --git a/tools/testing/selftests/bpf/progs/prog_update_tracing.c b/tools/testing/selftests/bpf/progs/prog_update_tracing.c
new file mode 100644
index 000000000000..bdf314e28425
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/prog_update_tracing.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+__u64 sequence = 0;
+
+__u64 fentry1_seq = 0;
+__u64 fentry1_cookie = 0;
+SEC("fentry/bpf_modify_return_test")
+int BPF_PROG(fentry1, int a, __u64 b)
+{
+ fentry1_seq = ++sequence;
+ fentry1_cookie = bpf_get_attach_cookie(ctx);
+ return 0;
+}
+
+__u64 fentry2_seq = 0;
+__u64 fentry2_cookie = 0;
+SEC("fentry/bpf_modify_return_test")
+int BPF_PROG(fentry2, int a, __u64 b)
+{
+ fentry2_seq = ++sequence;
+ fentry2_cookie = bpf_get_attach_cookie(ctx);
+ return 0;
+}
+
+__u64 fmod_ret1_seq = 0;
+__u64 fmod_ret1_cookie = 0;
+SEC("fmod_ret/bpf_modify_return_test")
+int BPF_PROG(fmod_ret1, int a, int *b, int ret)
+{
+ fmod_ret1_seq = ++sequence;
+ fmod_ret1_cookie = bpf_get_attach_cookie(ctx);
+ return ret;
+}
+
+__u64 fmod_ret2_seq = 0;
+__u64 fmod_ret2_cookie = 0;
+SEC("fmod_ret/bpf_modify_return_test")
+int BPF_PROG(fmod_ret2, int a, int *b, int ret)
+{
+ fmod_ret2_seq = ++sequence;
+ fmod_ret2_cookie = bpf_get_attach_cookie(ctx);
+ return ret;
+}
+
+__u64 fexit1_seq = 0;
+__u64 fexit1_cookie = 0;
+SEC("fexit/bpf_modify_return_test")
+int BPF_PROG(fexit1, int a, __u64 b, int ret)
+{
+ fexit1_seq = ++sequence;
+ fexit1_cookie = bpf_get_attach_cookie(ctx);
+ return 0;
+}
+
+__u64 fexit2_seq = 0;
+__u64 fexit2_cookie = 0;
+SEC("fexit/bpf_modify_return_test")
+int BPF_PROG(fexit2, int a, __u64 b, int ret)
+{
+ fexit2_seq = ++sequence;
+ fexit2_cookie = bpf_get_attach_cookie(ctx);
+ return 0;
+}
+
+__u64 sequence_bpf = 0;
+
+__u64 fentry1_bpf_seq = 0;
+__u64 fentry1_bpf_cookie = 0;
+SEC("fentry/test_pkt_access")
+int fentry1_bpf(struct __sk_buff *skb)
+{
+ fentry1_bpf_seq = ++sequence_bpf;
+ fentry1_bpf_cookie = bpf_get_attach_cookie(skb);
+ return 0;
+}
+
+__u64 fentry2_bpf_seq = 0;
+__u64 fentry2_bpf_cookie = 0;
+SEC("fentry/test_pkt_access")
+int fentry2_bpf(struct __sk_buff *skb)
+{
+ fentry2_bpf_seq = ++sequence_bpf;
+ fentry2_bpf_cookie = bpf_get_attach_cookie(skb);
+ return 0;
+}
+
+__u64 freplace1_bpf_seq = 0;
+SEC("freplace/test_pkt_access_subprog3")
+int freplace1_bpf(int val, struct __sk_buff *skb)
+{
+ freplace1_bpf_seq = ++sequence_bpf;
+ return 0;
+}
+
+__u64 freplace2_bpf_seq = 0;
+SEC("freplace/test_pkt_access_subprog3")
+int freplace2_bpf(int val, struct __sk_buff *skb)
+{
+ freplace2_bpf_seq = ++sequence_bpf;
+ return 0;
+}
+
+SEC("freplace/get_skb_ifindex")
+int freplace3_bpf(int val, struct __sk_buff *skb, int var)
+{
+ return 0;
+}
+
+__u64 fexit1_bpf_seq = 0;
+__u64 fexit1_bpf_cookie = 0;
+SEC("fexit/test_pkt_access")
+int fexit1_bpf(struct __sk_buff *skb, int ret)
+{
+ fexit1_bpf_seq = ++sequence_bpf;
+ fexit1_bpf_cookie = bpf_get_attach_cookie(skb);
+ return 0;
+}
+
+__u64 fexit2_bpf_seq = 0;
+__u64 fexit2_bpf_cookie = 0;
+SEC("fexit/test_pkt_access")
+int fexit2_bpf(struct __sk_buff *skb, int ret)
+{
+ fexit2_bpf_seq = ++sequence_bpf;
+ fexit2_bpf_cookie = bpf_get_attach_cookie(skb);
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
--
2.43.0
More information about the linux-arm-kernel
mailing list