Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: Add test for multiple attachments of freplace program

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

Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Link: https://lore.kernel.org/bpf/160138355497.48470.17568077161540217107.stgit@toke.dk

authored by

Toke Høiland-Jørgensen and committed by
Alexei Starovoitov
f6429476 a5359091

+139 -32
+124 -32
tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c
··· 2 2 /* Copyright (c) 2019 Facebook */ 3 3 #include <test_progs.h> 4 4 #include <network_helpers.h> 5 + #include <bpf/btf.h> 6 + 7 + typedef int (*test_cb)(struct bpf_object *obj); 8 + 9 + static int check_data_map(struct bpf_object *obj, int prog_cnt, bool reset) 10 + { 11 + struct bpf_map *data_map = NULL, *map; 12 + __u64 *result = NULL; 13 + const int zero = 0; 14 + __u32 duration = 0; 15 + int ret = -1, i; 16 + 17 + result = malloc((prog_cnt + 32 /* spare */) * sizeof(__u64)); 18 + if (CHECK(!result, "alloc_memory", "failed to alloc memory")) 19 + return -ENOMEM; 20 + 21 + bpf_object__for_each_map(map, obj) 22 + if (bpf_map__is_internal(map)) { 23 + data_map = map; 24 + break; 25 + } 26 + if (CHECK(!data_map, "find_data_map", "data map not found\n")) 27 + goto out; 28 + 29 + ret = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result); 30 + if (CHECK(ret, "get_result", 31 + "failed to get output data: %d\n", ret)) 32 + goto out; 33 + 34 + for (i = 0; i < prog_cnt; i++) { 35 + if (CHECK(result[i] != 1, "result", 36 + "fexit_bpf2bpf result[%d] failed err %llu\n", 37 + i, result[i])) 38 + goto out; 39 + result[i] = 0; 40 + } 41 + if (reset) { 42 + ret = bpf_map_update_elem(bpf_map__fd(data_map), &zero, result, 0); 43 + if (CHECK(ret, "reset_result", "failed to reset result\n")) 44 + goto out; 45 + } 46 + 47 + ret = 0; 48 + out: 49 + free(result); 50 + return ret; 51 + } 5 52 6 53 static void test_fexit_bpf2bpf_common(const char *obj_file, 7 54 const char *target_obj_file, 8 55 int prog_cnt, 9 56 const char **prog_name, 10 - bool run_prog) 57 + bool run_prog, 58 + test_cb cb) 11 59 { 12 - struct bpf_object *obj = NULL, *pkt_obj; 13 - int err, pkt_fd, i; 14 - struct bpf_link **link = NULL; 60 + struct bpf_object *obj = NULL, *tgt_obj; 15 61 struct bpf_program **prog = NULL; 62 + struct bpf_link **link = NULL; 16 63 __u32 duration = 0, retval; 17 - struct bpf_map *data_map; 18 - const int zero = 0; 19 - __u64 *result = NULL; 64 + int err, tgt_fd, i; 20 65 21 66 err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC, 22 - &pkt_obj, &pkt_fd); 67 + &tgt_obj, &tgt_fd); 23 68 if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n", 24 69 target_obj_file, err, errno)) 25 70 return; 26 71 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, 27 - .attach_prog_fd = pkt_fd, 72 + .attach_prog_fd = tgt_fd, 28 73 ); 29 74 30 75 link = calloc(sizeof(struct bpf_link *), prog_cnt); 31 76 prog = calloc(sizeof(struct bpf_program *), prog_cnt); 32 - result = malloc((prog_cnt + 32 /* spare */) * sizeof(__u64)); 33 - if (CHECK(!link || !prog || !result, "alloc_memory", 34 - "failed to alloc memory")) 77 + if (CHECK(!link || !prog, "alloc_memory", "failed to alloc memory")) 35 78 goto close_prog; 36 79 37 80 obj = bpf_object__open_file(obj_file, &opts); ··· 96 53 goto close_prog; 97 54 } 98 55 56 + if (cb) { 57 + err = cb(obj); 58 + if (err) 59 + goto close_prog; 60 + } 61 + 99 62 if (!run_prog) 100 63 goto close_prog; 101 64 102 - data_map = bpf_object__find_map_by_name(obj, "fexit_bp.bss"); 103 - if (CHECK(!data_map, "find_data_map", "data map not found\n")) 104 - goto close_prog; 105 - 106 - err = bpf_prog_test_run(pkt_fd, 1, &pkt_v6, sizeof(pkt_v6), 65 + err = bpf_prog_test_run(tgt_fd, 1, &pkt_v6, sizeof(pkt_v6), 107 66 NULL, NULL, &retval, &duration); 108 67 CHECK(err || retval, "ipv6", 109 68 "err %d errno %d retval %d duration %d\n", 110 69 err, errno, retval, duration); 111 70 112 - err = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result); 113 - if (CHECK(err, "get_result", 114 - "failed to get output data: %d\n", err)) 71 + if (check_data_map(obj, prog_cnt, false)) 115 72 goto close_prog; 116 - 117 - for (i = 0; i < prog_cnt; i++) 118 - if (CHECK(result[i] != 1, "result", "fexit_bpf2bpf failed err %llu\n", 119 - result[i])) 120 - goto close_prog; 121 73 122 74 close_prog: 123 75 for (i = 0; i < prog_cnt; i++) ··· 120 82 bpf_link__destroy(link[i]); 121 83 if (!IS_ERR_OR_NULL(obj)) 122 84 bpf_object__close(obj); 123 - bpf_object__close(pkt_obj); 85 + bpf_object__close(tgt_obj); 124 86 free(link); 125 87 free(prog); 126 - free(result); 127 88 } 128 89 129 90 static void test_target_no_callees(void) ··· 133 96 test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.o", 134 97 "./test_pkt_md_access.o", 135 98 ARRAY_SIZE(prog_name), 136 - prog_name, true); 99 + prog_name, true, NULL); 137 100 } 138 101 139 102 static void test_target_yes_callees(void) ··· 147 110 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o", 148 111 "./test_pkt_access.o", 149 112 ARRAY_SIZE(prog_name), 150 - prog_name, true); 113 + prog_name, true, NULL); 151 114 } 152 115 153 116 static void test_func_replace(void) ··· 165 128 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o", 166 129 "./test_pkt_access.o", 167 130 ARRAY_SIZE(prog_name), 168 - prog_name, true); 131 + prog_name, true, NULL); 169 132 } 170 133 171 134 static void test_func_replace_verify(void) ··· 176 139 test_fexit_bpf2bpf_common("./freplace_connect4.o", 177 140 "./connect4_prog.o", 178 141 ARRAY_SIZE(prog_name), 179 - prog_name, false); 142 + prog_name, false, NULL); 143 + } 144 + 145 + static int test_second_attach(struct bpf_object *obj) 146 + { 147 + const char *prog_name = "freplace/get_constant"; 148 + const char *tgt_name = prog_name + 9; /* cut off freplace/ */ 149 + const char *tgt_obj_file = "./test_pkt_access.o"; 150 + struct bpf_program *prog = NULL; 151 + struct bpf_object *tgt_obj; 152 + __u32 duration = 0, retval; 153 + struct bpf_link *link; 154 + int err = 0, tgt_fd; 155 + 156 + prog = bpf_object__find_program_by_title(obj, prog_name); 157 + if (CHECK(!prog, "find_prog", "prog %s not found\n", prog_name)) 158 + return -ENOENT; 159 + 160 + err = bpf_prog_load(tgt_obj_file, BPF_PROG_TYPE_UNSPEC, 161 + &tgt_obj, &tgt_fd); 162 + if (CHECK(err, "second_prog_load", "file %s err %d errno %d\n", 163 + tgt_obj_file, err, errno)) 164 + return err; 165 + 166 + link = bpf_program__attach_freplace(prog, tgt_fd, tgt_name); 167 + if (CHECK(IS_ERR(link), "second_link", "failed to attach second link prog_fd %d tgt_fd %d\n", bpf_program__fd(prog), tgt_fd)) 168 + goto out; 169 + 170 + err = bpf_prog_test_run(tgt_fd, 1, &pkt_v6, sizeof(pkt_v6), 171 + NULL, NULL, &retval, &duration); 172 + if (CHECK(err || retval, "ipv6", 173 + "err %d errno %d retval %d duration %d\n", 174 + err, errno, retval, duration)) 175 + goto out; 176 + 177 + err = check_data_map(obj, 1, true); 178 + if (err) 179 + goto out; 180 + 181 + out: 182 + bpf_link__destroy(link); 183 + bpf_object__close(tgt_obj); 184 + return err; 185 + } 186 + 187 + static void test_func_replace_multi(void) 188 + { 189 + const char *prog_name[] = { 190 + "freplace/get_constant", 191 + }; 192 + test_fexit_bpf2bpf_common("./freplace_get_constant.o", 193 + "./test_pkt_access.o", 194 + ARRAY_SIZE(prog_name), 195 + prog_name, true, test_second_attach); 180 196 } 181 197 182 198 static void test_func_sockmap_update(void) ··· 240 150 test_fexit_bpf2bpf_common("./freplace_cls_redirect.o", 241 151 "./test_cls_redirect.o", 242 152 ARRAY_SIZE(prog_name), 243 - prog_name, false); 153 + prog_name, false, NULL); 244 154 } 245 155 246 156 static void test_obj_load_failure_common(const char *obj_file, ··· 312 222 test_func_replace_return_code(); 313 223 if (test__start_subtest("func_map_prog_compatibility")) 314 224 test_func_map_prog_compatibility(); 225 + if (test__start_subtest("func_replace_multi")) 226 + test_func_replace_multi(); 315 227 }
+15
tools/testing/selftests/bpf/progs/freplace_get_constant.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/bpf.h> 3 + #include <bpf/bpf_helpers.h> 4 + #include <bpf/bpf_endian.h> 5 + 6 + volatile __u64 test_get_constant = 0; 7 + SEC("freplace/get_constant") 8 + int new_get_constant(long val) 9 + { 10 + if (val != 123) 11 + return 0; 12 + test_get_constant = 1; 13 + return test_get_constant; /* original get_constant() returns val - 122 */ 14 + } 15 + char _license[] SEC("license") = "GPL";