From: Toke Høiland-Jørgensen <t...@redhat.com>

This adds a selftest for attaching an freplace program to multiple targets
simultaneously.

Signed-off-by: Toke Høiland-Jørgensen <t...@redhat.com>
---
 .../selftests/bpf/prog_tests/fexit_bpf2bpf.c       |  164 ++++++++++++++++----
 .../selftests/bpf/progs/freplace_get_constant.c    |   15 ++
 2 files changed, 150 insertions(+), 29 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/progs/freplace_get_constant.c

diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c 
b/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c
index a895bfed55db..feb3e11c5445 100644
--- a/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c
+++ b/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c
@@ -2,35 +2,78 @@
 /* Copyright (c) 2019 Facebook */
 #include <test_progs.h>
 #include <network_helpers.h>
+#include <bpf/btf.h>
+
+typedef int (*test_cb)(struct bpf_object *obj);
+
+static int check_data_map(struct bpf_object *obj, int prog_cnt, bool reset)
+{
+       struct bpf_map *data_map, *map;
+       const int zero = 0;
+       u64 *result = NULL;
+       __u32 duration = 0;
+       int ret = -1, i;
+
+       result = malloc((prog_cnt + 32 /* spare */) * sizeof(u64));
+       if (CHECK(!result, "alloc_memory", "failed to alloc memory"))
+               return -ENOMEM;
+
+       bpf_object__for_each_map(map, obj)
+               if (bpf_map__is_internal(map)) {
+                       data_map = map;
+                       break;
+               }
+       if (CHECK(!data_map, "find_data_map", "data map not found\n"))
+               goto out;
+
+       ret = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result);
+       if (CHECK(ret, "get_result",
+                 "failed to get output data: %d\n", ret))
+               goto out;
+
+       for (i = 0; i < prog_cnt; i++) {
+               if (CHECK(result[i] != 1, "result", "fexit_bpf2bpf failed err 
%ld\n",
+                         result[i]))
+                       goto out;
+               result[i] = 0;
+       }
+       if (reset) {
+               ret = bpf_map_update_elem(bpf_map__fd(data_map), &zero, result, 
0);
+               if (CHECK(ret, "reset_result", "failed to reset result\n"))
+                       goto out;
+       }
+
+       ret = 0;
+out:
+       free(result);
+       return ret;
+}
 
 static void test_fexit_bpf2bpf_common(const char *obj_file,
                                      const char *target_obj_file,
                                      int prog_cnt,
                                      const char **prog_name,
-                                     bool run_prog)
+                                     bool run_prog,
+                                     test_cb cb)
 {
-       struct bpf_object *obj = NULL, *pkt_obj;
-       int err, pkt_fd, i;
+       struct bpf_object *obj = NULL, *tgt_obj;
+       int err, tgt_fd, i;
        struct bpf_link **link = NULL;
        struct bpf_program **prog = NULL;
        __u32 duration = 0, retval;
-       struct bpf_map *data_map;
-       const int zero = 0;
-       u64 *result = NULL;
 
        err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC,
-                           &pkt_obj, &pkt_fd);
+                           &tgt_obj, &tgt_fd);
        if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n",
                  target_obj_file, err, errno))
                return;
        DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
-                           .attach_prog_fd = pkt_fd,
+                           .attach_prog_fd = tgt_fd,
                           );
 
        link = calloc(sizeof(struct bpf_link *), prog_cnt);
        prog = calloc(sizeof(struct bpf_program *), prog_cnt);
-       result = malloc((prog_cnt + 32 /* spare */) * sizeof(u64));
-       if (CHECK(!link || !prog || !result, "alloc_memory",
+       if (CHECK(!link || !prog, "alloc_memory",
                  "failed to alloc memory"))
                goto close_prog;
 
@@ -53,39 +96,33 @@ static void test_fexit_bpf2bpf_common(const char *obj_file,
                        goto close_prog;
        }
 
-       if (!run_prog)
-               goto close_prog;
+       if (cb) {
+               err = cb(obj);
+               if (err)
+                       goto close_prog;
+       }
 
-       data_map = bpf_object__find_map_by_name(obj, "fexit_bp.bss");
-       if (CHECK(!data_map, "find_data_map", "data map not found\n"))
+       if (!run_prog)
                goto close_prog;
 
-       err = bpf_prog_test_run(pkt_fd, 1, &pkt_v6, sizeof(pkt_v6),
+       err = bpf_prog_test_run(tgt_fd, 1, &pkt_v6, sizeof(pkt_v6),
                                NULL, NULL, &retval, &duration);
        CHECK(err || retval, "ipv6",
              "err %d errno %d retval %d duration %d\n",
              err, errno, retval, duration);
 
-       err = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result);
-       if (CHECK(err, "get_result",
-                 "failed to get output data: %d\n", err))
+       if (check_data_map(obj, prog_cnt, false))
                goto close_prog;
 
-       for (i = 0; i < prog_cnt; i++)
-               if (CHECK(result[i] != 1, "result", "fexit_bpf2bpf failed err 
%ld\n",
-                         result[i]))
-                       goto close_prog;
-
 close_prog:
        for (i = 0; i < prog_cnt; i++)
                if (!IS_ERR_OR_NULL(link[i]))
                        bpf_link__destroy(link[i]);
        if (!IS_ERR_OR_NULL(obj))
                bpf_object__close(obj);
-       bpf_object__close(pkt_obj);
+       bpf_object__close(tgt_obj);
        free(link);
        free(prog);
-       free(result);
 }
 
 static void test_target_no_callees(void)
@@ -96,7 +133,7 @@ static void test_target_no_callees(void)
        test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.o",
                                  "./test_pkt_md_access.o",
                                  ARRAY_SIZE(prog_name),
-                                 prog_name, true);
+                                 prog_name, true, NULL);
 }
 
 static void test_target_yes_callees(void)
@@ -110,7 +147,7 @@ static void test_target_yes_callees(void)
        test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",
                                  "./test_pkt_access.o",
                                  ARRAY_SIZE(prog_name),
-                                 prog_name, true);
+                                 prog_name, true, NULL);
 }
 
 static void test_func_replace(void)
@@ -127,7 +164,7 @@ static void test_func_replace(void)
        test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",
                                  "./test_pkt_access.o",
                                  ARRAY_SIZE(prog_name),
-                                 prog_name, true);
+                                 prog_name, true, NULL);
 }
 
 static void test_func_replace_verify(void)
@@ -138,7 +175,75 @@ static void test_func_replace_verify(void)
        test_fexit_bpf2bpf_common("./freplace_connect4.o",
                                  "./connect4_prog.o",
                                  ARRAY_SIZE(prog_name),
-                                 prog_name, false);
+                                 prog_name, false, NULL);
+}
+
+static int test_second_attach(struct bpf_object *obj)
+{
+       const char *prog_name = "freplace/get_constant";
+       const char *tgt_name = prog_name + 9; /* cut off freplace/ */
+       const char *tgt_obj_file = "./test_pkt_access.o";
+       int err = 0, tgt_fd, tgt_btf_id, link_fd = -1;
+       struct bpf_program *prog = NULL;
+       struct bpf_object *tgt_obj;
+       __u32 duration = 0, retval;
+       struct btf *btf;
+
+       prog = bpf_object__find_program_by_title(obj, prog_name);
+       if (CHECK(!prog, "find_prog", "prog %s not found\n", prog_name))
+               return -ENOENT;
+
+       err = bpf_prog_load(tgt_obj_file, BPF_PROG_TYPE_UNSPEC,
+                           &tgt_obj, &tgt_fd);
+       if (CHECK(err, "second_prog_load", "file %s err %d errno %d\n",
+                 tgt_obj_file, err, errno))
+               return err;
+
+       btf = bpf_object__btf(tgt_obj);
+       tgt_btf_id = btf__find_by_name_kind(btf, tgt_name, BTF_KIND_FUNC);
+       if (CHECK(tgt_btf_id < 0, "find_btf", "no BTF ID found for func %s\n", 
prog_name)) {
+               err = -ENOENT;
+               goto out;
+       }
+
+       DECLARE_LIBBPF_OPTS(bpf_raw_tracepoint_opts, opts,
+                           .tgt_prog_fd = tgt_fd,
+                           .tgt_btf_id = tgt_btf_id,
+                          );
+       link_fd = bpf_raw_tracepoint_open_opts(NULL, bpf_program__fd(prog), 
&opts);
+       if (CHECK(link_fd < 0, "second_link", "err %d errno %d",
+                 link_fd, errno)) {
+               err = link_fd;
+               goto out;
+       }
+
+       err = bpf_prog_test_run(tgt_fd, 1, &pkt_v6, sizeof(pkt_v6),
+                               NULL, NULL, &retval, &duration);
+       if (CHECK(err || retval, "ipv6",
+                 "err %d errno %d retval %d duration %d\n",
+                 err, errno, retval, duration))
+               goto out;
+
+       err = check_data_map(obj, 1, true);
+       if (err)
+               goto out;
+
+out:
+       if (link_fd >= 0)
+               close(link_fd);
+       bpf_object__close(tgt_obj);
+       return err;
+}
+
+static void test_func_replace_multi(void)
+{
+       const char *prog_name[] = {
+               "freplace/get_constant",
+       };
+       test_fexit_bpf2bpf_common("./freplace_get_constant.o",
+                                 "./test_pkt_access.o",
+                                 ARRAY_SIZE(prog_name),
+                                 prog_name, true, test_second_attach);
 }
 
 void test_fexit_bpf2bpf(void)
@@ -147,4 +252,5 @@ void test_fexit_bpf2bpf(void)
        test_target_yes_callees();
        test_func_replace();
        test_func_replace_verify();
+       test_func_replace_multi();
 }
diff --git a/tools/testing/selftests/bpf/progs/freplace_get_constant.c 
b/tools/testing/selftests/bpf/progs/freplace_get_constant.c
new file mode 100644
index 000000000000..8f0ecf94e533
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/freplace_get_constant.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+volatile __u64 test_get_constant = 0;
+SEC("freplace/get_constant")
+int new_get_constant(long val)
+{
+       if (val != 123)
+               return 0;
+       test_get_constant = 1;
+       return test_get_constant; /* original get_constant() returns val - 122 
*/
+}
+char _license[] SEC("license") = "GPL";

Reply via email to