diff options
Diffstat (limited to 'tools/testing/selftests/bpf/test_btf.c')
-rw-r--r-- | tools/testing/selftests/bpf/test_btf.c | 332 |
1 files changed, 329 insertions, 3 deletions
diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c index e0eeee5c8c04..8fd3a16fea4d 100644 --- a/tools/testing/selftests/bpf/test_btf.c +++ b/tools/testing/selftests/bpf/test_btf.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/btf.h> | 5 | #include <linux/btf.h> |
6 | #include <linux/err.h> | 6 | #include <linux/err.h> |
7 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
8 | #include <linux/filter.h> | ||
8 | #include <bpf/bpf.h> | 9 | #include <bpf/bpf.h> |
9 | #include <sys/resource.h> | 10 | #include <sys/resource.h> |
10 | #include <libelf.h> | 11 | #include <libelf.h> |
@@ -22,9 +23,13 @@ | |||
22 | #include "bpf_rlimit.h" | 23 | #include "bpf_rlimit.h" |
23 | #include "bpf_util.h" | 24 | #include "bpf_util.h" |
24 | 25 | ||
26 | #define MAX_INSNS 512 | ||
27 | #define MAX_SUBPROGS 16 | ||
28 | |||
25 | static uint32_t pass_cnt; | 29 | static uint32_t pass_cnt; |
26 | static uint32_t error_cnt; | 30 | static uint32_t error_cnt; |
27 | static uint32_t skip_cnt; | 31 | static uint32_t skip_cnt; |
32 | static bool jit_enabled; | ||
28 | 33 | ||
29 | #define CHECK(condition, format...) ({ \ | 34 | #define CHECK(condition, format...) ({ \ |
30 | int __ret = !!(condition); \ | 35 | int __ret = !!(condition); \ |
@@ -60,6 +65,24 @@ static int __base_pr(const char *format, ...) | |||
60 | return err; | 65 | return err; |
61 | } | 66 | } |
62 | 67 | ||
68 | static bool is_jit_enabled(void) | ||
69 | { | ||
70 | const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable"; | ||
71 | bool enabled = false; | ||
72 | int sysctl_fd; | ||
73 | |||
74 | sysctl_fd = open(jit_sysctl, 0, O_RDONLY); | ||
75 | if (sysctl_fd != -1) { | ||
76 | char tmpc; | ||
77 | |||
78 | if (read(sysctl_fd, &tmpc, sizeof(tmpc)) == 1) | ||
79 | enabled = (tmpc != '0'); | ||
80 | close(sysctl_fd); | ||
81 | } | ||
82 | |||
83 | return enabled; | ||
84 | } | ||
85 | |||
63 | #define BTF_INFO_ENC(kind, root, vlen) \ | 86 | #define BTF_INFO_ENC(kind, root, vlen) \ |
64 | ((!!(root) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN)) | 87 | ((!!(root) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN)) |
65 | 88 | ||
@@ -115,6 +138,7 @@ static struct args { | |||
115 | bool get_info_test; | 138 | bool get_info_test; |
116 | bool pprint_test; | 139 | bool pprint_test; |
117 | bool always_log; | 140 | bool always_log; |
141 | bool func_type_test; | ||
118 | } args; | 142 | } args; |
119 | 143 | ||
120 | static char btf_log_buf[BTF_LOG_BUF_SIZE]; | 144 | static char btf_log_buf[BTF_LOG_BUF_SIZE]; |
@@ -2947,16 +2971,310 @@ static int test_pprint(void) | |||
2947 | return err; | 2971 | return err; |
2948 | } | 2972 | } |
2949 | 2973 | ||
2974 | static struct btf_func_type_test { | ||
2975 | const char *descr; | ||
2976 | const char *str_sec; | ||
2977 | __u32 raw_types[MAX_NR_RAW_TYPES]; | ||
2978 | __u32 str_sec_size; | ||
2979 | struct bpf_insn insns[MAX_INSNS]; | ||
2980 | __u32 prog_type; | ||
2981 | __u32 func_info[MAX_SUBPROGS][2]; | ||
2982 | __u32 func_info_rec_size; | ||
2983 | __u32 func_info_cnt; | ||
2984 | bool expected_prog_load_failure; | ||
2985 | } func_type_test[] = { | ||
2986 | { | ||
2987 | .descr = "func_type (main func + one sub)", | ||
2988 | .raw_types = { | ||
2989 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
2990 | BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4), /* [2] */ | ||
2991 | BTF_FUNC_PROTO_ENC(1, 2), /* [3] */ | ||
2992 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1), | ||
2993 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2), | ||
2994 | BTF_FUNC_PROTO_ENC(1, 2), /* [4] */ | ||
2995 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2), | ||
2996 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1), | ||
2997 | BTF_FUNC_ENC(NAME_TBD, 3), /* [5] */ | ||
2998 | BTF_FUNC_ENC(NAME_TBD, 4), /* [6] */ | ||
2999 | BTF_END_RAW, | ||
3000 | }, | ||
3001 | .str_sec = "\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB", | ||
3002 | .str_sec_size = sizeof("\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB"), | ||
3003 | .insns = { | ||
3004 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), | ||
3005 | BPF_MOV64_IMM(BPF_REG_0, 1), | ||
3006 | BPF_EXIT_INSN(), | ||
3007 | BPF_MOV64_IMM(BPF_REG_0, 2), | ||
3008 | BPF_EXIT_INSN(), | ||
3009 | }, | ||
3010 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
3011 | .func_info = { {0, 5}, {3, 6} }, | ||
3012 | .func_info_rec_size = 8, | ||
3013 | .func_info_cnt = 2, | ||
3014 | }, | ||
3015 | |||
3016 | { | ||
3017 | .descr = "func_type (Incorrect func_info_rec_size)", | ||
3018 | .raw_types = { | ||
3019 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
3020 | BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4), /* [2] */ | ||
3021 | BTF_FUNC_PROTO_ENC(1, 2), /* [3] */ | ||
3022 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1), | ||
3023 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2), | ||
3024 | BTF_FUNC_PROTO_ENC(1, 2), /* [4] */ | ||
3025 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2), | ||
3026 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1), | ||
3027 | BTF_FUNC_ENC(NAME_TBD, 3), /* [5] */ | ||
3028 | BTF_FUNC_ENC(NAME_TBD, 4), /* [6] */ | ||
3029 | BTF_END_RAW, | ||
3030 | }, | ||
3031 | .str_sec = "\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB", | ||
3032 | .str_sec_size = sizeof("\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB"), | ||
3033 | .insns = { | ||
3034 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), | ||
3035 | BPF_MOV64_IMM(BPF_REG_0, 1), | ||
3036 | BPF_EXIT_INSN(), | ||
3037 | BPF_MOV64_IMM(BPF_REG_0, 2), | ||
3038 | BPF_EXIT_INSN(), | ||
3039 | }, | ||
3040 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
3041 | .func_info = { {0, 5}, {3, 6} }, | ||
3042 | .func_info_rec_size = 4, | ||
3043 | .func_info_cnt = 2, | ||
3044 | .expected_prog_load_failure = true, | ||
3045 | }, | ||
3046 | |||
3047 | { | ||
3048 | .descr = "func_type (Incorrect func_info_cnt)", | ||
3049 | .raw_types = { | ||
3050 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
3051 | BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4), /* [2] */ | ||
3052 | BTF_FUNC_PROTO_ENC(1, 2), /* [3] */ | ||
3053 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1), | ||
3054 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2), | ||
3055 | BTF_FUNC_PROTO_ENC(1, 2), /* [4] */ | ||
3056 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2), | ||
3057 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1), | ||
3058 | BTF_FUNC_ENC(NAME_TBD, 3), /* [5] */ | ||
3059 | BTF_FUNC_ENC(NAME_TBD, 4), /* [6] */ | ||
3060 | BTF_END_RAW, | ||
3061 | }, | ||
3062 | .str_sec = "\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB", | ||
3063 | .str_sec_size = sizeof("\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB"), | ||
3064 | .insns = { | ||
3065 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), | ||
3066 | BPF_MOV64_IMM(BPF_REG_0, 1), | ||
3067 | BPF_EXIT_INSN(), | ||
3068 | BPF_MOV64_IMM(BPF_REG_0, 2), | ||
3069 | BPF_EXIT_INSN(), | ||
3070 | }, | ||
3071 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
3072 | .func_info = { {0, 5}, {3, 6} }, | ||
3073 | .func_info_rec_size = 8, | ||
3074 | .func_info_cnt = 1, | ||
3075 | .expected_prog_load_failure = true, | ||
3076 | }, | ||
3077 | |||
3078 | { | ||
3079 | .descr = "func_type (Incorrect bpf_func_info.insn_offset)", | ||
3080 | .raw_types = { | ||
3081 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
3082 | BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4), /* [2] */ | ||
3083 | BTF_FUNC_PROTO_ENC(1, 2), /* [3] */ | ||
3084 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1), | ||
3085 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2), | ||
3086 | BTF_FUNC_PROTO_ENC(1, 2), /* [4] */ | ||
3087 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2), | ||
3088 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1), | ||
3089 | BTF_FUNC_ENC(NAME_TBD, 3), /* [5] */ | ||
3090 | BTF_FUNC_ENC(NAME_TBD, 4), /* [6] */ | ||
3091 | BTF_END_RAW, | ||
3092 | }, | ||
3093 | .str_sec = "\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB", | ||
3094 | .str_sec_size = sizeof("\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB"), | ||
3095 | .insns = { | ||
3096 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), | ||
3097 | BPF_MOV64_IMM(BPF_REG_0, 1), | ||
3098 | BPF_EXIT_INSN(), | ||
3099 | BPF_MOV64_IMM(BPF_REG_0, 2), | ||
3100 | BPF_EXIT_INSN(), | ||
3101 | }, | ||
3102 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
3103 | .func_info = { {0, 5}, {2, 6} }, | ||
3104 | .func_info_rec_size = 8, | ||
3105 | .func_info_cnt = 2, | ||
3106 | .expected_prog_load_failure = true, | ||
3107 | }, | ||
3108 | |||
3109 | }; | ||
3110 | |||
3111 | static size_t probe_prog_length(const struct bpf_insn *fp) | ||
3112 | { | ||
3113 | size_t len; | ||
3114 | |||
3115 | for (len = MAX_INSNS - 1; len > 0; --len) | ||
3116 | if (fp[len].code != 0 || fp[len].imm != 0) | ||
3117 | break; | ||
3118 | return len + 1; | ||
3119 | } | ||
3120 | |||
3121 | static int do_test_func_type(int test_num) | ||
3122 | { | ||
3123 | const struct btf_func_type_test *test = &func_type_test[test_num]; | ||
3124 | unsigned int raw_btf_size, info_len, rec_size; | ||
3125 | int i, btf_fd = -1, prog_fd = -1, err = 0; | ||
3126 | struct bpf_load_program_attr attr = {}; | ||
3127 | void *raw_btf, *func_info = NULL; | ||
3128 | struct bpf_prog_info info = {}; | ||
3129 | struct bpf_func_info *finfo; | ||
3130 | |||
3131 | fprintf(stderr, "%s......", test->descr); | ||
3132 | raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types, | ||
3133 | test->str_sec, test->str_sec_size, | ||
3134 | &raw_btf_size); | ||
3135 | |||
3136 | if (!raw_btf) | ||
3137 | return -1; | ||
3138 | |||
3139 | *btf_log_buf = '\0'; | ||
3140 | btf_fd = bpf_load_btf(raw_btf, raw_btf_size, | ||
3141 | btf_log_buf, BTF_LOG_BUF_SIZE, | ||
3142 | args.always_log); | ||
3143 | free(raw_btf); | ||
3144 | |||
3145 | if (CHECK(btf_fd == -1, "invalid btf_fd errno:%d", errno)) { | ||
3146 | err = -1; | ||
3147 | goto done; | ||
3148 | } | ||
3149 | |||
3150 | if (*btf_log_buf && args.always_log) | ||
3151 | fprintf(stderr, "\n%s", btf_log_buf); | ||
3152 | |||
3153 | attr.prog_type = test->prog_type; | ||
3154 | attr.insns = test->insns; | ||
3155 | attr.insns_cnt = probe_prog_length(attr.insns); | ||
3156 | attr.license = "GPL"; | ||
3157 | attr.prog_btf_fd = btf_fd; | ||
3158 | attr.func_info_rec_size = test->func_info_rec_size; | ||
3159 | attr.func_info_cnt = test->func_info_cnt; | ||
3160 | attr.func_info = test->func_info; | ||
3161 | |||
3162 | *btf_log_buf = '\0'; | ||
3163 | prog_fd = bpf_load_program_xattr(&attr, btf_log_buf, | ||
3164 | BTF_LOG_BUF_SIZE); | ||
3165 | if (test->expected_prog_load_failure && prog_fd == -1) { | ||
3166 | err = 0; | ||
3167 | goto done; | ||
3168 | } | ||
3169 | if (CHECK(prog_fd == -1, "invalid prog_id errno:%d", errno)) { | ||
3170 | fprintf(stderr, "%s\n", btf_log_buf); | ||
3171 | err = -1; | ||
3172 | goto done; | ||
3173 | } | ||
3174 | if (!jit_enabled) { | ||
3175 | skip_cnt++; | ||
3176 | fprintf(stderr, "SKIPPED, please enable sysctl bpf_jit_enable\n"); | ||
3177 | err = 0; | ||
3178 | goto done; | ||
3179 | } | ||
3180 | |||
3181 | /* get necessary lens */ | ||
3182 | info_len = sizeof(struct bpf_prog_info); | ||
3183 | err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); | ||
3184 | if (CHECK(err == -1, "invalid get info (1st) errno:%d", errno)) { | ||
3185 | fprintf(stderr, "%s\n", btf_log_buf); | ||
3186 | err = -1; | ||
3187 | goto done; | ||
3188 | } | ||
3189 | if (CHECK(info.func_info_cnt != 2, | ||
3190 | "incorrect info.func_info_cnt (1st) %d\n", | ||
3191 | info.func_info_cnt)) { | ||
3192 | err = -1; | ||
3193 | goto done; | ||
3194 | } | ||
3195 | rec_size = info.func_info_rec_size; | ||
3196 | if (CHECK(rec_size < 4, | ||
3197 | "incorrect info.func_info_rec_size (1st) %d\n", rec_size)) { | ||
3198 | err = -1; | ||
3199 | goto done; | ||
3200 | } | ||
3201 | |||
3202 | func_info = malloc(info.func_info_cnt * rec_size); | ||
3203 | if (CHECK(!func_info, "out of memeory")) { | ||
3204 | err = -1; | ||
3205 | goto done; | ||
3206 | } | ||
3207 | |||
3208 | /* reset info to only retrieve func_info related data */ | ||
3209 | memset(&info, 0, sizeof(info)); | ||
3210 | info.func_info_cnt = 2; | ||
3211 | info.func_info_rec_size = rec_size; | ||
3212 | info.func_info = ptr_to_u64(func_info); | ||
3213 | err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); | ||
3214 | if (CHECK(err == -1, "invalid get info (2nd) errno:%d", errno)) { | ||
3215 | fprintf(stderr, "%s\n", btf_log_buf); | ||
3216 | err = -1; | ||
3217 | goto done; | ||
3218 | } | ||
3219 | if (CHECK(info.func_info_cnt != 2, | ||
3220 | "incorrect info.func_info_cnt (2nd) %d\n", | ||
3221 | info.func_info_cnt)) { | ||
3222 | err = -1; | ||
3223 | goto done; | ||
3224 | } | ||
3225 | if (CHECK(info.func_info_rec_size != rec_size, | ||
3226 | "incorrect info.func_info_rec_size (2nd) %d\n", | ||
3227 | info.func_info_rec_size)) { | ||
3228 | err = -1; | ||
3229 | goto done; | ||
3230 | } | ||
3231 | |||
3232 | finfo = func_info; | ||
3233 | for (i = 0; i < 2; i++) { | ||
3234 | if (CHECK(finfo->type_id != test->func_info[i][1], | ||
3235 | "incorrect func_type %u expected %u", | ||
3236 | finfo->type_id, test->func_info[i][1])) { | ||
3237 | err = -1; | ||
3238 | goto done; | ||
3239 | } | ||
3240 | finfo = (void *)finfo + rec_size; | ||
3241 | } | ||
3242 | |||
3243 | done: | ||
3244 | if (*btf_log_buf && (err || args.always_log)) | ||
3245 | fprintf(stderr, "\n%s", btf_log_buf); | ||
3246 | |||
3247 | if (btf_fd != -1) | ||
3248 | close(btf_fd); | ||
3249 | if (prog_fd != -1) | ||
3250 | close(prog_fd); | ||
3251 | free(func_info); | ||
3252 | return err; | ||
3253 | } | ||
3254 | |||
3255 | static int test_func_type(void) | ||
3256 | { | ||
3257 | unsigned int i; | ||
3258 | int err = 0; | ||
3259 | |||
3260 | for (i = 0; i < ARRAY_SIZE(func_type_test); i++) | ||
3261 | err |= count_result(do_test_func_type(i)); | ||
3262 | |||
3263 | return err; | ||
3264 | } | ||
3265 | |||
2950 | static void usage(const char *cmd) | 3266 | static void usage(const char *cmd) |
2951 | { | 3267 | { |
2952 | fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] | [-g test_num (1 - %zu)] | [-f test_num (1 - %zu)] | [-p]]\n", | 3268 | fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] |" |
3269 | " [-g test_num (1 - %zu)] |" | ||
3270 | " [-f test_num (1 - %zu)] | [-p] | [-k] ]\n", | ||
2953 | cmd, ARRAY_SIZE(raw_tests), ARRAY_SIZE(get_info_tests), | 3271 | cmd, ARRAY_SIZE(raw_tests), ARRAY_SIZE(get_info_tests), |
2954 | ARRAY_SIZE(file_tests)); | 3272 | ARRAY_SIZE(file_tests)); |
2955 | } | 3273 | } |
2956 | 3274 | ||
2957 | static int parse_args(int argc, char **argv) | 3275 | static int parse_args(int argc, char **argv) |
2958 | { | 3276 | { |
2959 | const char *optstr = "lpf:r:g:"; | 3277 | const char *optstr = "lpkf:r:g:"; |
2960 | int opt; | 3278 | int opt; |
2961 | 3279 | ||
2962 | while ((opt = getopt(argc, argv, optstr)) != -1) { | 3280 | while ((opt = getopt(argc, argv, optstr)) != -1) { |
@@ -2979,6 +3297,9 @@ static int parse_args(int argc, char **argv) | |||
2979 | case 'p': | 3297 | case 'p': |
2980 | args.pprint_test = true; | 3298 | args.pprint_test = true; |
2981 | break; | 3299 | break; |
3300 | case 'k': | ||
3301 | args.func_type_test = true; | ||
3302 | break; | ||
2982 | case 'h': | 3303 | case 'h': |
2983 | usage(argv[0]); | 3304 | usage(argv[0]); |
2984 | exit(0); | 3305 | exit(0); |
@@ -3032,6 +3353,8 @@ int main(int argc, char **argv) | |||
3032 | if (args.always_log) | 3353 | if (args.always_log) |
3033 | libbpf_set_print(__base_pr, __base_pr, __base_pr); | 3354 | libbpf_set_print(__base_pr, __base_pr, __base_pr); |
3034 | 3355 | ||
3356 | jit_enabled = is_jit_enabled(); | ||
3357 | |||
3035 | if (args.raw_test) | 3358 | if (args.raw_test) |
3036 | err |= test_raw(); | 3359 | err |= test_raw(); |
3037 | 3360 | ||
@@ -3044,8 +3367,11 @@ int main(int argc, char **argv) | |||
3044 | if (args.pprint_test) | 3367 | if (args.pprint_test) |
3045 | err |= test_pprint(); | 3368 | err |= test_pprint(); |
3046 | 3369 | ||
3370 | if (args.func_type_test) | ||
3371 | err |= test_func_type(); | ||
3372 | |||
3047 | if (args.raw_test || args.get_info_test || args.file_test || | 3373 | if (args.raw_test || args.get_info_test || args.file_test || |
3048 | args.pprint_test) | 3374 | args.pprint_test || args.func_type_test) |
3049 | goto done; | 3375 | goto done; |
3050 | 3376 | ||
3051 | err |= test_raw(); | 3377 | err |= test_raw(); |