diff options
Diffstat (limited to 'tools/testing')
55 files changed, 2119 insertions, 348 deletions
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index d8df5c9b5b2f..fb5ce43e28b3 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile | |||
| @@ -280,4 +280,5 @@ $(OUTPUT)/verifier/tests.h: $(VERIFIER_TESTS_DIR) $(VERIFIER_TEST_FILES) | |||
| 280 | ) > $(VERIFIER_TESTS_H)) | 280 | ) > $(VERIFIER_TESTS_H)) |
| 281 | 281 | ||
| 282 | EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(ALU32_BUILD_DIR) \ | 282 | EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(ALU32_BUILD_DIR) \ |
| 283 | $(VERIFIER_TESTS_H) $(PROG_TESTS_H) $(MAP_TESTS_H) | 283 | $(VERIFIER_TESTS_H) $(PROG_TESTS_H) $(MAP_TESTS_H) \ |
| 284 | feature | ||
diff --git a/tools/testing/selftests/bpf/bpf_endian.h b/tools/testing/selftests/bpf/bpf_endian.h index b25595ea4a78..05f036df8a4c 100644 --- a/tools/testing/selftests/bpf/bpf_endian.h +++ b/tools/testing/selftests/bpf/bpf_endian.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #ifndef __BPF_ENDIAN__ | 2 | #ifndef __BPF_ENDIAN__ |
| 3 | #define __BPF_ENDIAN__ | 3 | #define __BPF_ENDIAN__ |
| 4 | 4 | ||
| 5 | #include <linux/stddef.h> | ||
| 5 | #include <linux/swab.h> | 6 | #include <linux/swab.h> |
| 6 | 7 | ||
| 7 | /* LLVM's BPF target selects the endianness of the CPU | 8 | /* LLVM's BPF target selects the endianness of the CPU |
diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index e6d243b7cd74..1a5b1accf091 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h | |||
| @@ -31,7 +31,7 @@ static int (*bpf_map_pop_elem)(void *map, void *value) = | |||
| 31 | (void *) BPF_FUNC_map_pop_elem; | 31 | (void *) BPF_FUNC_map_pop_elem; |
| 32 | static int (*bpf_map_peek_elem)(void *map, void *value) = | 32 | static int (*bpf_map_peek_elem)(void *map, void *value) = |
| 33 | (void *) BPF_FUNC_map_peek_elem; | 33 | (void *) BPF_FUNC_map_peek_elem; |
| 34 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = | 34 | static int (*bpf_probe_read)(void *dst, int size, const void *unsafe_ptr) = |
| 35 | (void *) BPF_FUNC_probe_read; | 35 | (void *) BPF_FUNC_probe_read; |
| 36 | static unsigned long long (*bpf_ktime_get_ns)(void) = | 36 | static unsigned long long (*bpf_ktime_get_ns)(void) = |
| 37 | (void *) BPF_FUNC_ktime_get_ns; | 37 | (void *) BPF_FUNC_ktime_get_ns; |
| @@ -62,7 +62,7 @@ static int (*bpf_perf_event_output)(void *ctx, void *map, | |||
| 62 | (void *) BPF_FUNC_perf_event_output; | 62 | (void *) BPF_FUNC_perf_event_output; |
| 63 | static int (*bpf_get_stackid)(void *ctx, void *map, int flags) = | 63 | static int (*bpf_get_stackid)(void *ctx, void *map, int flags) = |
| 64 | (void *) BPF_FUNC_get_stackid; | 64 | (void *) BPF_FUNC_get_stackid; |
| 65 | static int (*bpf_probe_write_user)(void *dst, void *src, int size) = | 65 | static int (*bpf_probe_write_user)(void *dst, const void *src, int size) = |
| 66 | (void *) BPF_FUNC_probe_write_user; | 66 | (void *) BPF_FUNC_probe_write_user; |
| 67 | static int (*bpf_current_task_under_cgroup)(void *map, int index) = | 67 | static int (*bpf_current_task_under_cgroup)(void *map, int index) = |
| 68 | (void *) BPF_FUNC_current_task_under_cgroup; | 68 | (void *) BPF_FUNC_current_task_under_cgroup; |
diff --git a/tools/testing/selftests/bpf/bpf_util.h b/tools/testing/selftests/bpf/bpf_util.h index a29206ebbd13..ec219f84e041 100644 --- a/tools/testing/selftests/bpf/bpf_util.h +++ b/tools/testing/selftests/bpf/bpf_util.h | |||
| @@ -6,44 +6,17 @@ | |||
| 6 | #include <stdlib.h> | 6 | #include <stdlib.h> |
| 7 | #include <string.h> | 7 | #include <string.h> |
| 8 | #include <errno.h> | 8 | #include <errno.h> |
| 9 | #include <libbpf.h> /* libbpf_num_possible_cpus */ | ||
| 9 | 10 | ||
| 10 | static inline unsigned int bpf_num_possible_cpus(void) | 11 | static inline unsigned int bpf_num_possible_cpus(void) |
| 11 | { | 12 | { |
| 12 | static const char *fcpu = "/sys/devices/system/cpu/possible"; | 13 | int possible_cpus = libbpf_num_possible_cpus(); |
| 13 | unsigned int start, end, possible_cpus = 0; | ||
| 14 | char buff[128]; | ||
| 15 | FILE *fp; | ||
| 16 | int len, n, i, j = 0; | ||
| 17 | 14 | ||
| 18 | fp = fopen(fcpu, "r"); | 15 | if (possible_cpus < 0) { |
| 19 | if (!fp) { | 16 | printf("Failed to get # of possible cpus: '%s'!\n", |
| 20 | printf("Failed to open %s: '%s'!\n", fcpu, strerror(errno)); | 17 | strerror(-possible_cpus)); |
| 21 | exit(1); | 18 | exit(1); |
| 22 | } | 19 | } |
| 23 | |||
| 24 | if (!fgets(buff, sizeof(buff), fp)) { | ||
| 25 | printf("Failed to read %s!\n", fcpu); | ||
| 26 | exit(1); | ||
| 27 | } | ||
| 28 | |||
| 29 | len = strlen(buff); | ||
| 30 | for (i = 0; i <= len; i++) { | ||
| 31 | if (buff[i] == ',' || buff[i] == '\0') { | ||
| 32 | buff[i] = '\0'; | ||
| 33 | n = sscanf(&buff[j], "%u-%u", &start, &end); | ||
| 34 | if (n <= 0) { | ||
| 35 | printf("Failed to retrieve # possible CPUs!\n"); | ||
| 36 | exit(1); | ||
| 37 | } else if (n == 1) { | ||
| 38 | end = start; | ||
| 39 | } | ||
| 40 | possible_cpus += end - start + 1; | ||
| 41 | j = i + 1; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | fclose(fp); | ||
| 46 | |||
| 47 | return possible_cpus; | 20 | return possible_cpus; |
| 48 | } | 21 | } |
| 49 | 22 | ||
diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c index 0d89f0396be4..e95c33e333a4 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.c +++ b/tools/testing/selftests/bpf/cgroup_helpers.c | |||
| @@ -47,7 +47,7 @@ int enable_all_controllers(char *cgroup_path) | |||
| 47 | char buf[PATH_MAX]; | 47 | char buf[PATH_MAX]; |
| 48 | char *c, *c2; | 48 | char *c, *c2; |
| 49 | int fd, cfd; | 49 | int fd, cfd; |
| 50 | size_t len; | 50 | ssize_t len; |
| 51 | 51 | ||
| 52 | snprintf(path, sizeof(path), "%s/cgroup.controllers", cgroup_path); | 52 | snprintf(path, sizeof(path), "%s/cgroup.controllers", cgroup_path); |
| 53 | fd = open(path, O_RDONLY); | 53 | fd = open(path, O_RDONLY); |
diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c b/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c index c0091137074b..e1b55261526f 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c | |||
| @@ -5,7 +5,7 @@ static int libbpf_debug_print(enum libbpf_print_level level, | |||
| 5 | const char *format, va_list args) | 5 | const char *format, va_list args) |
| 6 | { | 6 | { |
| 7 | if (level != LIBBPF_DEBUG) | 7 | if (level != LIBBPF_DEBUG) |
| 8 | return 0; | 8 | return vfprintf(stderr, format, args); |
| 9 | 9 | ||
| 10 | if (!strstr(format, "verifier log")) | 10 | if (!strstr(format, "verifier log")) |
| 11 | return 0; | 11 | return 0; |
| @@ -32,24 +32,69 @@ static int check_load(const char *file, enum bpf_prog_type type) | |||
| 32 | 32 | ||
| 33 | void test_bpf_verif_scale(void) | 33 | void test_bpf_verif_scale(void) |
| 34 | { | 34 | { |
| 35 | const char *scale[] = { | 35 | const char *sched_cls[] = { |
| 36 | "./test_verif_scale1.o", "./test_verif_scale2.o", "./test_verif_scale3.o" | 36 | "./test_verif_scale1.o", "./test_verif_scale2.o", "./test_verif_scale3.o", |
| 37 | }; | 37 | }; |
| 38 | const char *pyperf[] = { | 38 | const char *raw_tp[] = { |
| 39 | "./pyperf50.o", "./pyperf100.o", "./pyperf180.o" | 39 | /* full unroll by llvm */ |
| 40 | "./pyperf50.o", "./pyperf100.o", "./pyperf180.o", | ||
| 41 | |||
| 42 | /* partial unroll. llvm will unroll loop ~150 times. | ||
| 43 | * C loop count -> 600. | ||
| 44 | * Asm loop count -> 4. | ||
| 45 | * 16k insns in loop body. | ||
| 46 | * Total of 5 such loops. Total program size ~82k insns. | ||
| 47 | */ | ||
| 48 | "./pyperf600.o", | ||
| 49 | |||
| 50 | /* no unroll at all. | ||
| 51 | * C loop count -> 600. | ||
| 52 | * ASM loop count -> 600. | ||
| 53 | * ~110 insns in loop body. | ||
| 54 | * Total of 5 such loops. Total program size ~1500 insns. | ||
| 55 | */ | ||
| 56 | "./pyperf600_nounroll.o", | ||
| 57 | |||
| 58 | "./loop1.o", "./loop2.o", | ||
| 59 | |||
| 60 | /* partial unroll. 19k insn in a loop. | ||
| 61 | * Total program size 20.8k insn. | ||
| 62 | * ~350k processed_insns | ||
| 63 | */ | ||
| 64 | "./strobemeta.o", | ||
| 65 | |||
| 66 | /* no unroll, tiny loops */ | ||
| 67 | "./strobemeta_nounroll1.o", | ||
| 68 | "./strobemeta_nounroll2.o", | ||
| 69 | }; | ||
| 70 | const char *cg_sysctl[] = { | ||
| 71 | "./test_sysctl_loop1.o", "./test_sysctl_loop2.o", | ||
| 40 | }; | 72 | }; |
| 41 | int err, i; | 73 | int err, i; |
| 42 | 74 | ||
| 43 | if (verifier_stats) | 75 | if (verifier_stats) |
| 44 | libbpf_set_print(libbpf_debug_print); | 76 | libbpf_set_print(libbpf_debug_print); |
| 45 | 77 | ||
| 46 | for (i = 0; i < ARRAY_SIZE(scale); i++) { | 78 | err = check_load("./loop3.o", BPF_PROG_TYPE_RAW_TRACEPOINT); |
| 47 | err = check_load(scale[i], BPF_PROG_TYPE_SCHED_CLS); | 79 | printf("test_scale:loop3:%s\n", err ? (error_cnt--, "OK") : "FAIL"); |
| 48 | printf("test_scale:%s:%s\n", scale[i], err ? "FAIL" : "OK"); | 80 | |
| 81 | for (i = 0; i < ARRAY_SIZE(sched_cls); i++) { | ||
| 82 | err = check_load(sched_cls[i], BPF_PROG_TYPE_SCHED_CLS); | ||
| 83 | printf("test_scale:%s:%s\n", sched_cls[i], err ? "FAIL" : "OK"); | ||
| 49 | } | 84 | } |
| 50 | 85 | ||
| 51 | for (i = 0; i < ARRAY_SIZE(pyperf); i++) { | 86 | for (i = 0; i < ARRAY_SIZE(raw_tp); i++) { |
| 52 | err = check_load(pyperf[i], BPF_PROG_TYPE_RAW_TRACEPOINT); | 87 | err = check_load(raw_tp[i], BPF_PROG_TYPE_RAW_TRACEPOINT); |
| 53 | printf("test_scale:%s:%s\n", pyperf[i], err ? "FAIL" : "OK"); | 88 | printf("test_scale:%s:%s\n", raw_tp[i], err ? "FAIL" : "OK"); |
| 54 | } | 89 | } |
| 90 | |||
| 91 | for (i = 0; i < ARRAY_SIZE(cg_sysctl); i++) { | ||
| 92 | err = check_load(cg_sysctl[i], BPF_PROG_TYPE_CGROUP_SYSCTL); | ||
| 93 | printf("test_scale:%s:%s\n", cg_sysctl[i], err ? "FAIL" : "OK"); | ||
| 94 | } | ||
| 95 | err = check_load("./test_xdp_loop.o", BPF_PROG_TYPE_XDP); | ||
| 96 | printf("test_scale:test_xdp_loop:%s\n", err ? "FAIL" : "OK"); | ||
| 97 | |||
| 98 | err = check_load("./test_seg6_loop.o", BPF_PROG_TYPE_LWT_SEG6LOCAL); | ||
| 99 | printf("test_scale:test_seg6_loop:%s\n", err ? "FAIL" : "OK"); | ||
| 55 | } | 100 | } |
diff --git a/tools/testing/selftests/bpf/progs/bpf_flow.c b/tools/testing/selftests/bpf/progs/bpf_flow.c index 81ad9a0b29d0..849f42e548b5 100644 --- a/tools/testing/selftests/bpf/progs/bpf_flow.c +++ b/tools/testing/selftests/bpf/progs/bpf_flow.c | |||
| @@ -57,17 +57,25 @@ struct frag_hdr { | |||
| 57 | __be32 identification; | 57 | __be32 identification; |
| 58 | }; | 58 | }; |
| 59 | 59 | ||
| 60 | struct bpf_map_def SEC("maps") jmp_table = { | 60 | struct { |
| 61 | __u32 type; | ||
| 62 | __u32 max_entries; | ||
| 63 | __u32 key_size; | ||
| 64 | __u32 value_size; | ||
| 65 | } jmp_table SEC(".maps") = { | ||
| 61 | .type = BPF_MAP_TYPE_PROG_ARRAY, | 66 | .type = BPF_MAP_TYPE_PROG_ARRAY, |
| 67 | .max_entries = 8, | ||
| 62 | .key_size = sizeof(__u32), | 68 | .key_size = sizeof(__u32), |
| 63 | .value_size = sizeof(__u32), | 69 | .value_size = sizeof(__u32), |
| 64 | .max_entries = 8 | ||
| 65 | }; | 70 | }; |
| 66 | 71 | ||
| 67 | struct bpf_map_def SEC("maps") last_dissection = { | 72 | struct { |
| 73 | __u32 type; | ||
| 74 | __u32 max_entries; | ||
| 75 | __u32 *key; | ||
| 76 | struct bpf_flow_keys *value; | ||
| 77 | } last_dissection SEC(".maps") = { | ||
| 68 | .type = BPF_MAP_TYPE_ARRAY, | 78 | .type = BPF_MAP_TYPE_ARRAY, |
| 69 | .key_size = sizeof(__u32), | ||
| 70 | .value_size = sizeof(struct bpf_flow_keys), | ||
| 71 | .max_entries = 1, | 79 | .max_entries = 1, |
| 72 | }; | 80 | }; |
| 73 | 81 | ||
diff --git a/tools/testing/selftests/bpf/progs/loop1.c b/tools/testing/selftests/bpf/progs/loop1.c new file mode 100644 index 000000000000..dea395af9ea9 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/loop1.c | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (c) 2019 Facebook | ||
| 3 | #include <linux/sched.h> | ||
| 4 | #include <linux/ptrace.h> | ||
| 5 | #include <stdint.h> | ||
| 6 | #include <stddef.h> | ||
| 7 | #include <stdbool.h> | ||
| 8 | #include <linux/bpf.h> | ||
| 9 | #include "bpf_helpers.h" | ||
| 10 | |||
| 11 | char _license[] SEC("license") = "GPL"; | ||
| 12 | |||
| 13 | SEC("raw_tracepoint/kfree_skb") | ||
| 14 | int nested_loops(volatile struct pt_regs* ctx) | ||
| 15 | { | ||
| 16 | int i, j, sum = 0, m; | ||
| 17 | |||
| 18 | for (j = 0; j < 300; j++) | ||
| 19 | for (i = 0; i < j; i++) { | ||
| 20 | if (j & 1) | ||
| 21 | m = ctx->rax; | ||
| 22 | else | ||
| 23 | m = j; | ||
| 24 | sum += i * m; | ||
| 25 | } | ||
| 26 | |||
| 27 | return sum; | ||
| 28 | } | ||
diff --git a/tools/testing/selftests/bpf/progs/loop2.c b/tools/testing/selftests/bpf/progs/loop2.c new file mode 100644 index 000000000000..0637bd8e8bcf --- /dev/null +++ b/tools/testing/selftests/bpf/progs/loop2.c | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (c) 2019 Facebook | ||
| 3 | #include <linux/sched.h> | ||
| 4 | #include <linux/ptrace.h> | ||
| 5 | #include <stdint.h> | ||
| 6 | #include <stddef.h> | ||
| 7 | #include <stdbool.h> | ||
| 8 | #include <linux/bpf.h> | ||
| 9 | #include "bpf_helpers.h" | ||
| 10 | |||
| 11 | char _license[] SEC("license") = "GPL"; | ||
| 12 | |||
| 13 | SEC("raw_tracepoint/consume_skb") | ||
| 14 | int while_true(volatile struct pt_regs* ctx) | ||
| 15 | { | ||
| 16 | int i = 0; | ||
| 17 | |||
| 18 | while (true) { | ||
| 19 | if (ctx->rax & 1) | ||
| 20 | i += 3; | ||
| 21 | else | ||
| 22 | i += 7; | ||
| 23 | if (i > 40) | ||
| 24 | break; | ||
| 25 | } | ||
| 26 | |||
| 27 | return i; | ||
| 28 | } | ||
diff --git a/tools/testing/selftests/bpf/progs/loop3.c b/tools/testing/selftests/bpf/progs/loop3.c new file mode 100644 index 000000000000..30a0f6cba080 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/loop3.c | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (c) 2019 Facebook | ||
| 3 | #include <linux/sched.h> | ||
| 4 | #include <linux/ptrace.h> | ||
| 5 | #include <stdint.h> | ||
| 6 | #include <stddef.h> | ||
| 7 | #include <stdbool.h> | ||
| 8 | #include <linux/bpf.h> | ||
| 9 | #include "bpf_helpers.h" | ||
| 10 | |||
| 11 | char _license[] SEC("license") = "GPL"; | ||
| 12 | |||
| 13 | SEC("raw_tracepoint/consume_skb") | ||
| 14 | int while_true(volatile struct pt_regs* ctx) | ||
| 15 | { | ||
| 16 | __u64 i = 0, sum = 0; | ||
| 17 | do { | ||
| 18 | i++; | ||
| 19 | sum += ctx->rax; | ||
| 20 | } while (i < 0x100000000ULL); | ||
| 21 | return sum; | ||
| 22 | } | ||
diff --git a/tools/testing/selftests/bpf/progs/netcnt_prog.c b/tools/testing/selftests/bpf/progs/netcnt_prog.c index 9f741e69cebe..a25c82a5b7c8 100644 --- a/tools/testing/selftests/bpf/progs/netcnt_prog.c +++ b/tools/testing/selftests/bpf/progs/netcnt_prog.c | |||
| @@ -10,24 +10,22 @@ | |||
| 10 | #define REFRESH_TIME_NS 100000000 | 10 | #define REFRESH_TIME_NS 100000000 |
| 11 | #define NS_PER_SEC 1000000000 | 11 | #define NS_PER_SEC 1000000000 |
| 12 | 12 | ||
| 13 | struct bpf_map_def SEC("maps") percpu_netcnt = { | 13 | struct { |
| 14 | __u32 type; | ||
| 15 | struct bpf_cgroup_storage_key *key; | ||
| 16 | struct percpu_net_cnt *value; | ||
| 17 | } percpu_netcnt SEC(".maps") = { | ||
| 14 | .type = BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, | 18 | .type = BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, |
| 15 | .key_size = sizeof(struct bpf_cgroup_storage_key), | ||
| 16 | .value_size = sizeof(struct percpu_net_cnt), | ||
| 17 | }; | 19 | }; |
| 18 | 20 | ||
| 19 | BPF_ANNOTATE_KV_PAIR(percpu_netcnt, struct bpf_cgroup_storage_key, | 21 | struct { |
| 20 | struct percpu_net_cnt); | 22 | __u32 type; |
| 21 | 23 | struct bpf_cgroup_storage_key *key; | |
| 22 | struct bpf_map_def SEC("maps") netcnt = { | 24 | struct net_cnt *value; |
| 25 | } netcnt SEC(".maps") = { | ||
| 23 | .type = BPF_MAP_TYPE_CGROUP_STORAGE, | 26 | .type = BPF_MAP_TYPE_CGROUP_STORAGE, |
| 24 | .key_size = sizeof(struct bpf_cgroup_storage_key), | ||
| 25 | .value_size = sizeof(struct net_cnt), | ||
| 26 | }; | 27 | }; |
| 27 | 28 | ||
| 28 | BPF_ANNOTATE_KV_PAIR(netcnt, struct bpf_cgroup_storage_key, | ||
| 29 | struct net_cnt); | ||
| 30 | |||
| 31 | SEC("cgroup/skb") | 29 | SEC("cgroup/skb") |
| 32 | int bpf_nextcnt(struct __sk_buff *skb) | 30 | int bpf_nextcnt(struct __sk_buff *skb) |
| 33 | { | 31 | { |
diff --git a/tools/testing/selftests/bpf/progs/pyperf.h b/tools/testing/selftests/bpf/progs/pyperf.h index 0cc5e4ee90bd..6b0781391be5 100644 --- a/tools/testing/selftests/bpf/progs/pyperf.h +++ b/tools/testing/selftests/bpf/progs/pyperf.h | |||
| @@ -220,7 +220,11 @@ static inline __attribute__((__always_inline__)) int __on_event(struct pt_regs * | |||
| 220 | int32_t* symbol_counter = bpf_map_lookup_elem(&symbolmap, &sym); | 220 | int32_t* symbol_counter = bpf_map_lookup_elem(&symbolmap, &sym); |
| 221 | if (symbol_counter == NULL) | 221 | if (symbol_counter == NULL) |
| 222 | return 0; | 222 | return 0; |
| 223 | #pragma unroll | 223 | #ifdef NO_UNROLL |
| 224 | #pragma clang loop unroll(disable) | ||
| 225 | #else | ||
| 226 | #pragma clang loop unroll(full) | ||
| 227 | #endif | ||
| 224 | /* Unwind python stack */ | 228 | /* Unwind python stack */ |
| 225 | for (int i = 0; i < STACK_MAX_LEN; ++i) { | 229 | for (int i = 0; i < STACK_MAX_LEN; ++i) { |
| 226 | if (frame_ptr && get_frame_data(frame_ptr, pidData, &frame, &sym)) { | 230 | if (frame_ptr && get_frame_data(frame_ptr, pidData, &frame, &sym)) { |
diff --git a/tools/testing/selftests/bpf/progs/pyperf600.c b/tools/testing/selftests/bpf/progs/pyperf600.c new file mode 100644 index 000000000000..cb49b89e37cd --- /dev/null +++ b/tools/testing/selftests/bpf/progs/pyperf600.c | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (c) 2019 Facebook | ||
| 3 | #define STACK_MAX_LEN 600 | ||
| 4 | /* clang will not unroll the loop 600 times. | ||
| 5 | * Instead it will unroll it to the amount it deemed | ||
| 6 | * appropriate, but the loop will still execute 600 times. | ||
| 7 | * Total program size is around 90k insns | ||
| 8 | */ | ||
| 9 | #include "pyperf.h" | ||
diff --git a/tools/testing/selftests/bpf/progs/pyperf600_nounroll.c b/tools/testing/selftests/bpf/progs/pyperf600_nounroll.c new file mode 100644 index 000000000000..6beff7502f4d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/pyperf600_nounroll.c | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (c) 2019 Facebook | ||
| 3 | #define STACK_MAX_LEN 600 | ||
| 4 | #define NO_UNROLL | ||
| 5 | /* clang will not unroll at all. | ||
| 6 | * Total program size is around 2k insns | ||
| 7 | */ | ||
| 8 | #include "pyperf.h" | ||
diff --git a/tools/testing/selftests/bpf/progs/socket_cookie_prog.c b/tools/testing/selftests/bpf/progs/socket_cookie_prog.c index 9ff8ac4b0bf6..6aabb681fb9a 100644 --- a/tools/testing/selftests/bpf/progs/socket_cookie_prog.c +++ b/tools/testing/selftests/bpf/progs/socket_cookie_prog.c | |||
| @@ -7,25 +7,36 @@ | |||
| 7 | #include "bpf_helpers.h" | 7 | #include "bpf_helpers.h" |
| 8 | #include "bpf_endian.h" | 8 | #include "bpf_endian.h" |
| 9 | 9 | ||
| 10 | struct bpf_map_def SEC("maps") socket_cookies = { | 10 | struct socket_cookie { |
| 11 | .type = BPF_MAP_TYPE_HASH, | 11 | __u64 cookie_key; |
| 12 | .key_size = sizeof(__u64), | 12 | __u32 cookie_value; |
| 13 | .value_size = sizeof(__u32), | 13 | }; |
| 14 | .max_entries = 1 << 8, | 14 | |
| 15 | struct { | ||
| 16 | __u32 type; | ||
| 17 | __u32 map_flags; | ||
| 18 | int *key; | ||
| 19 | struct socket_cookie *value; | ||
| 20 | } socket_cookies SEC(".maps") = { | ||
| 21 | .type = BPF_MAP_TYPE_SK_STORAGE, | ||
| 22 | .map_flags = BPF_F_NO_PREALLOC, | ||
| 15 | }; | 23 | }; |
| 16 | 24 | ||
| 17 | SEC("cgroup/connect6") | 25 | SEC("cgroup/connect6") |
| 18 | int set_cookie(struct bpf_sock_addr *ctx) | 26 | int set_cookie(struct bpf_sock_addr *ctx) |
| 19 | { | 27 | { |
| 20 | __u32 cookie_value = 0xFF; | 28 | struct socket_cookie *p; |
| 21 | __u64 cookie_key; | ||
| 22 | 29 | ||
| 23 | if (ctx->family != AF_INET6 || ctx->user_family != AF_INET6) | 30 | if (ctx->family != AF_INET6 || ctx->user_family != AF_INET6) |
| 24 | return 1; | 31 | return 1; |
| 25 | 32 | ||
| 26 | cookie_key = bpf_get_socket_cookie(ctx); | 33 | p = bpf_sk_storage_get(&socket_cookies, ctx->sk, 0, |
| 27 | if (bpf_map_update_elem(&socket_cookies, &cookie_key, &cookie_value, 0)) | 34 | BPF_SK_STORAGE_GET_F_CREATE); |
| 28 | return 0; | 35 | if (!p) |
| 36 | return 1; | ||
| 37 | |||
| 38 | p->cookie_value = 0xFF; | ||
| 39 | p->cookie_key = bpf_get_socket_cookie(ctx); | ||
| 29 | 40 | ||
| 30 | return 1; | 41 | return 1; |
| 31 | } | 42 | } |
| @@ -33,9 +44,8 @@ int set_cookie(struct bpf_sock_addr *ctx) | |||
| 33 | SEC("sockops") | 44 | SEC("sockops") |
| 34 | int update_cookie(struct bpf_sock_ops *ctx) | 45 | int update_cookie(struct bpf_sock_ops *ctx) |
| 35 | { | 46 | { |
| 36 | __u32 new_cookie_value; | 47 | struct bpf_sock *sk; |
| 37 | __u32 *cookie_value; | 48 | struct socket_cookie *p; |
| 38 | __u64 cookie_key; | ||
| 39 | 49 | ||
| 40 | if (ctx->family != AF_INET6) | 50 | if (ctx->family != AF_INET6) |
| 41 | return 1; | 51 | return 1; |
| @@ -43,14 +53,17 @@ int update_cookie(struct bpf_sock_ops *ctx) | |||
| 43 | if (ctx->op != BPF_SOCK_OPS_TCP_CONNECT_CB) | 53 | if (ctx->op != BPF_SOCK_OPS_TCP_CONNECT_CB) |
| 44 | return 1; | 54 | return 1; |
| 45 | 55 | ||
| 46 | cookie_key = bpf_get_socket_cookie(ctx); | 56 | if (!ctx->sk) |
| 57 | return 1; | ||
| 58 | |||
| 59 | p = bpf_sk_storage_get(&socket_cookies, ctx->sk, 0, 0); | ||
| 60 | if (!p) | ||
| 61 | return 1; | ||
| 47 | 62 | ||
| 48 | cookie_value = bpf_map_lookup_elem(&socket_cookies, &cookie_key); | 63 | if (p->cookie_key != bpf_get_socket_cookie(ctx)) |
| 49 | if (!cookie_value) | ||
| 50 | return 1; | 64 | return 1; |
| 51 | 65 | ||
| 52 | new_cookie_value = (ctx->local_port << 8) | *cookie_value; | 66 | p->cookie_value = (ctx->local_port << 8) | p->cookie_value; |
| 53 | bpf_map_update_elem(&socket_cookies, &cookie_key, &new_cookie_value, 0); | ||
| 54 | 67 | ||
| 55 | return 1; | 68 | return 1; |
| 56 | } | 69 | } |
diff --git a/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c b/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c index ed3e4a551c57..9390e0244259 100644 --- a/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c +++ b/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | #include <linux/bpf.h> | 1 | #include <linux/bpf.h> |
| 2 | #include "bpf_helpers.h" | 2 | #include "bpf_helpers.h" |
| 3 | #include "bpf_util.h" | ||
| 4 | #include "bpf_endian.h" | 3 | #include "bpf_endian.h" |
| 5 | 4 | ||
| 6 | int _version SEC("version") = 1; | 5 | int _version SEC("version") = 1; |
diff --git a/tools/testing/selftests/bpf/progs/sockmap_tcp_msg_prog.c b/tools/testing/selftests/bpf/progs/sockmap_tcp_msg_prog.c index 65fbfdb6cd3a..e80484d98a1a 100644 --- a/tools/testing/selftests/bpf/progs/sockmap_tcp_msg_prog.c +++ b/tools/testing/selftests/bpf/progs/sockmap_tcp_msg_prog.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #include <linux/bpf.h> | 1 | #include <linux/bpf.h> |
| 2 | |||
| 2 | #include "bpf_helpers.h" | 3 | #include "bpf_helpers.h" |
| 3 | #include "bpf_util.h" | ||
| 4 | #include "bpf_endian.h" | 4 | #include "bpf_endian.h" |
| 5 | 5 | ||
| 6 | int _version SEC("version") = 1; | 6 | int _version SEC("version") = 1; |
diff --git a/tools/testing/selftests/bpf/progs/sockmap_verdict_prog.c b/tools/testing/selftests/bpf/progs/sockmap_verdict_prog.c index bdc22be46f2e..d85c874ef25e 100644 --- a/tools/testing/selftests/bpf/progs/sockmap_verdict_prog.c +++ b/tools/testing/selftests/bpf/progs/sockmap_verdict_prog.c | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | #include <linux/bpf.h> | 1 | #include <linux/bpf.h> |
| 2 | #include "bpf_helpers.h" | 2 | #include "bpf_helpers.h" |
| 3 | #include "bpf_util.h" | ||
| 4 | #include "bpf_endian.h" | 3 | #include "bpf_endian.h" |
| 5 | 4 | ||
| 6 | int _version SEC("version") = 1; | 5 | int _version SEC("version") = 1; |
diff --git a/tools/testing/selftests/bpf/progs/strobemeta.c b/tools/testing/selftests/bpf/progs/strobemeta.c new file mode 100644 index 000000000000..d3df3d86f092 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/strobemeta.c | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | ||
| 2 | // Copyright (c) 2019 Facebook | ||
| 3 | |||
| 4 | #define STROBE_MAX_INTS 2 | ||
| 5 | #define STROBE_MAX_STRS 25 | ||
| 6 | #define STROBE_MAX_MAPS 100 | ||
| 7 | #define STROBE_MAX_MAP_ENTRIES 20 | ||
| 8 | /* full unroll by llvm #undef NO_UNROLL */ | ||
| 9 | #include "strobemeta.h" | ||
| 10 | |||
diff --git a/tools/testing/selftests/bpf/progs/strobemeta.h b/tools/testing/selftests/bpf/progs/strobemeta.h new file mode 100644 index 000000000000..1ff73f60a3e4 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/strobemeta.h | |||
| @@ -0,0 +1,528 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (c) 2019 Facebook | ||
| 3 | |||
| 4 | #include <stdint.h> | ||
| 5 | #include <stddef.h> | ||
| 6 | #include <stdbool.h> | ||
| 7 | #include <linux/bpf.h> | ||
| 8 | #include <linux/ptrace.h> | ||
| 9 | #include <linux/sched.h> | ||
| 10 | #include <linux/types.h> | ||
| 11 | #include "bpf_helpers.h" | ||
| 12 | |||
| 13 | typedef uint32_t pid_t; | ||
| 14 | struct task_struct {}; | ||
| 15 | |||
| 16 | #define TASK_COMM_LEN 16 | ||
| 17 | #define PERF_MAX_STACK_DEPTH 127 | ||
| 18 | |||
| 19 | #define STROBE_TYPE_INVALID 0 | ||
| 20 | #define STROBE_TYPE_INT 1 | ||
| 21 | #define STROBE_TYPE_STR 2 | ||
| 22 | #define STROBE_TYPE_MAP 3 | ||
| 23 | |||
| 24 | #define STACK_TABLE_EPOCH_SHIFT 20 | ||
| 25 | #define STROBE_MAX_STR_LEN 1 | ||
| 26 | #define STROBE_MAX_CFGS 32 | ||
| 27 | #define STROBE_MAX_PAYLOAD \ | ||
| 28 | (STROBE_MAX_STRS * STROBE_MAX_STR_LEN + \ | ||
| 29 | STROBE_MAX_MAPS * (1 + STROBE_MAX_MAP_ENTRIES * 2) * STROBE_MAX_STR_LEN) | ||
| 30 | |||
| 31 | struct strobe_value_header { | ||
| 32 | /* | ||
| 33 | * meaning depends on type: | ||
| 34 | * 1. int: 0, if value not set, 1 otherwise | ||
| 35 | * 2. str: 1 always, whether value is set or not is determined by ptr | ||
| 36 | * 3. map: 1 always, pointer points to additional struct with number | ||
| 37 | * of entries (up to STROBE_MAX_MAP_ENTRIES) | ||
| 38 | */ | ||
| 39 | uint16_t len; | ||
| 40 | /* | ||
| 41 | * _reserved might be used for some future fields/flags, but we always | ||
| 42 | * want to keep strobe_value_header to be 8 bytes, so BPF can read 16 | ||
| 43 | * bytes in one go and get both header and value | ||
| 44 | */ | ||
| 45 | uint8_t _reserved[6]; | ||
| 46 | }; | ||
| 47 | |||
| 48 | /* | ||
| 49 | * strobe_value_generic is used from BPF probe only, but needs to be a union | ||
| 50 | * of strobe_value_int/strobe_value_str/strobe_value_map | ||
| 51 | */ | ||
| 52 | struct strobe_value_generic { | ||
| 53 | struct strobe_value_header header; | ||
| 54 | union { | ||
| 55 | int64_t val; | ||
| 56 | void *ptr; | ||
| 57 | }; | ||
| 58 | }; | ||
| 59 | |||
| 60 | struct strobe_value_int { | ||
| 61 | struct strobe_value_header header; | ||
| 62 | int64_t value; | ||
| 63 | }; | ||
| 64 | |||
| 65 | struct strobe_value_str { | ||
| 66 | struct strobe_value_header header; | ||
| 67 | const char* value; | ||
| 68 | }; | ||
| 69 | |||
| 70 | struct strobe_value_map { | ||
| 71 | struct strobe_value_header header; | ||
| 72 | const struct strobe_map_raw* value; | ||
| 73 | }; | ||
| 74 | |||
| 75 | struct strobe_map_entry { | ||
| 76 | const char* key; | ||
| 77 | const char* val; | ||
| 78 | }; | ||
| 79 | |||
| 80 | /* | ||
| 81 | * Map of C-string key/value pairs with fixed maximum capacity. Each map has | ||
| 82 | * corresponding int64 ID, which application can use (or ignore) in whatever | ||
| 83 | * way appropriate. Map is "write-only", there is no way to get data out of | ||
| 84 | * map. Map is intended to be used to provide metadata for profilers and is | ||
| 85 | * not to be used for internal in-app communication. All methods are | ||
| 86 | * thread-safe. | ||
| 87 | */ | ||
| 88 | struct strobe_map_raw { | ||
| 89 | /* | ||
| 90 | * general purpose unique ID that's up to application to decide | ||
| 91 | * whether and how to use; for request metadata use case id is unique | ||
| 92 | * request ID that's used to match metadata with stack traces on | ||
| 93 | * Strobelight backend side | ||
| 94 | */ | ||
| 95 | int64_t id; | ||
| 96 | /* number of used entries in map */ | ||
| 97 | int64_t cnt; | ||
| 98 | /* | ||
| 99 | * having volatile doesn't change anything on BPF side, but clang | ||
| 100 | * emits warnings for passing `volatile const char *` into | ||
| 101 | * bpf_probe_read_str that expects just `const char *` | ||
| 102 | */ | ||
| 103 | const char* tag; | ||
| 104 | /* | ||
| 105 | * key/value entries, each consisting of 2 pointers to key and value | ||
| 106 | * C strings | ||
| 107 | */ | ||
| 108 | struct strobe_map_entry entries[STROBE_MAX_MAP_ENTRIES]; | ||
| 109 | }; | ||
| 110 | |||
| 111 | /* Following values define supported values of TLS mode */ | ||
| 112 | #define TLS_NOT_SET -1 | ||
| 113 | #define TLS_LOCAL_EXEC 0 | ||
| 114 | #define TLS_IMM_EXEC 1 | ||
| 115 | #define TLS_GENERAL_DYN 2 | ||
| 116 | |||
| 117 | /* | ||
| 118 | * structure that universally represents TLS location (both for static | ||
| 119 | * executables and shared libraries) | ||
| 120 | */ | ||
| 121 | struct strobe_value_loc { | ||
| 122 | /* | ||
| 123 | * tls_mode defines what TLS mode was used for particular metavariable: | ||
| 124 | * - -1 (TLS_NOT_SET) - no metavariable; | ||
| 125 | * - 0 (TLS_LOCAL_EXEC) - Local Executable mode; | ||
| 126 | * - 1 (TLS_IMM_EXEC) - Immediate Executable mode; | ||
| 127 | * - 2 (TLS_GENERAL_DYN) - General Dynamic mode; | ||
| 128 | * Local Dynamic mode is not yet supported, because never seen in | ||
| 129 | * practice. Mode defines how offset field is interpreted. See | ||
| 130 | * calc_location() in below for details. | ||
| 131 | */ | ||
| 132 | int64_t tls_mode; | ||
| 133 | /* | ||
| 134 | * TLS_LOCAL_EXEC: offset from thread pointer (fs:0 for x86-64, | ||
| 135 | * tpidr_el0 for aarch64). | ||
| 136 | * TLS_IMM_EXEC: absolute address of GOT entry containing offset | ||
| 137 | * from thread pointer; | ||
| 138 | * TLS_GENERAL_DYN: absolute addres of double GOT entry | ||
| 139 | * containing tls_index_t struct; | ||
| 140 | */ | ||
| 141 | int64_t offset; | ||
| 142 | }; | ||
| 143 | |||
| 144 | struct strobemeta_cfg { | ||
| 145 | int64_t req_meta_idx; | ||
| 146 | struct strobe_value_loc int_locs[STROBE_MAX_INTS]; | ||
| 147 | struct strobe_value_loc str_locs[STROBE_MAX_STRS]; | ||
| 148 | struct strobe_value_loc map_locs[STROBE_MAX_MAPS]; | ||
| 149 | }; | ||
| 150 | |||
| 151 | struct strobe_map_descr { | ||
| 152 | uint64_t id; | ||
| 153 | int16_t tag_len; | ||
| 154 | /* | ||
| 155 | * cnt <0 - map value isn't set; | ||
| 156 | * 0 - map has id set, but no key/value entries | ||
| 157 | */ | ||
| 158 | int16_t cnt; | ||
| 159 | /* | ||
| 160 | * both key_lens[i] and val_lens[i] should be >0 for present key/value | ||
| 161 | * entry | ||
| 162 | */ | ||
| 163 | uint16_t key_lens[STROBE_MAX_MAP_ENTRIES]; | ||
| 164 | uint16_t val_lens[STROBE_MAX_MAP_ENTRIES]; | ||
| 165 | }; | ||
| 166 | |||
| 167 | struct strobemeta_payload { | ||
| 168 | /* req_id has valid request ID, if req_meta_valid == 1 */ | ||
| 169 | int64_t req_id; | ||
| 170 | uint8_t req_meta_valid; | ||
| 171 | /* | ||
| 172 | * mask has Nth bit set to 1, if Nth metavar was present and | ||
| 173 | * successfully read | ||
| 174 | */ | ||
| 175 | uint64_t int_vals_set_mask; | ||
| 176 | int64_t int_vals[STROBE_MAX_INTS]; | ||
| 177 | /* len is >0 for present values */ | ||
| 178 | uint16_t str_lens[STROBE_MAX_STRS]; | ||
| 179 | /* if map_descrs[i].cnt == -1, metavar is not present/set */ | ||
| 180 | struct strobe_map_descr map_descrs[STROBE_MAX_MAPS]; | ||
| 181 | /* | ||
| 182 | * payload has compactly packed values of str and map variables in the | ||
| 183 | * form: strval1\0strval2\0map1key1\0map1val1\0map2key1\0map2val1\0 | ||
| 184 | * (and so on); str_lens[i], key_lens[i] and val_lens[i] determines | ||
| 185 | * value length | ||
| 186 | */ | ||
| 187 | char payload[STROBE_MAX_PAYLOAD]; | ||
| 188 | }; | ||
| 189 | |||
| 190 | struct strobelight_bpf_sample { | ||
| 191 | uint64_t ktime; | ||
| 192 | char comm[TASK_COMM_LEN]; | ||
| 193 | pid_t pid; | ||
| 194 | int user_stack_id; | ||
| 195 | int kernel_stack_id; | ||
| 196 | int has_meta; | ||
| 197 | struct strobemeta_payload metadata; | ||
| 198 | /* | ||
| 199 | * makes it possible to pass (<real payload size> + 1) as data size to | ||
| 200 | * perf_submit() to avoid perf_submit's paranoia about passing zero as | ||
| 201 | * size, as it deduces that <real payload size> might be | ||
| 202 | * **theoretically** zero | ||
| 203 | */ | ||
| 204 | char dummy_safeguard; | ||
| 205 | }; | ||
| 206 | |||
| 207 | struct bpf_map_def SEC("maps") samples = { | ||
| 208 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, | ||
| 209 | .key_size = sizeof(int), | ||
| 210 | .value_size = sizeof(int), | ||
| 211 | .max_entries = 32, | ||
| 212 | }; | ||
| 213 | |||
| 214 | struct bpf_map_def SEC("maps") stacks_0 = { | ||
| 215 | .type = BPF_MAP_TYPE_STACK_TRACE, | ||
| 216 | .key_size = sizeof(uint32_t), | ||
| 217 | .value_size = sizeof(uint64_t) * PERF_MAX_STACK_DEPTH, | ||
| 218 | .max_entries = 16, | ||
| 219 | }; | ||
| 220 | |||
| 221 | struct bpf_map_def SEC("maps") stacks_1 = { | ||
| 222 | .type = BPF_MAP_TYPE_STACK_TRACE, | ||
| 223 | .key_size = sizeof(uint32_t), | ||
| 224 | .value_size = sizeof(uint64_t) * PERF_MAX_STACK_DEPTH, | ||
| 225 | .max_entries = 16, | ||
| 226 | }; | ||
| 227 | |||
| 228 | struct bpf_map_def SEC("maps") sample_heap = { | ||
| 229 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, | ||
| 230 | .key_size = sizeof(uint32_t), | ||
| 231 | .value_size = sizeof(struct strobelight_bpf_sample), | ||
| 232 | .max_entries = 1, | ||
| 233 | }; | ||
| 234 | |||
| 235 | struct bpf_map_def SEC("maps") strobemeta_cfgs = { | ||
| 236 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, | ||
| 237 | .key_size = sizeof(pid_t), | ||
| 238 | .value_size = sizeof(struct strobemeta_cfg), | ||
| 239 | .max_entries = STROBE_MAX_CFGS, | ||
| 240 | }; | ||
| 241 | |||
| 242 | /* Type for the dtv. */ | ||
| 243 | /* https://github.com/lattera/glibc/blob/master/nptl/sysdeps/x86_64/tls.h#L34 */ | ||
| 244 | typedef union dtv { | ||
| 245 | size_t counter; | ||
| 246 | struct { | ||
| 247 | void* val; | ||
| 248 | bool is_static; | ||
| 249 | } pointer; | ||
| 250 | } dtv_t; | ||
| 251 | |||
| 252 | /* Partial definition for tcbhead_t */ | ||
| 253 | /* https://github.com/bminor/glibc/blob/master/sysdeps/x86_64/nptl/tls.h#L42 */ | ||
| 254 | struct tcbhead { | ||
| 255 | void* tcb; | ||
| 256 | dtv_t* dtv; | ||
| 257 | }; | ||
| 258 | |||
| 259 | /* | ||
| 260 | * TLS module/offset information for shared library case. | ||
| 261 | * For x86-64, this is mapped onto two entries in GOT. | ||
| 262 | * For aarch64, this is pointed to by second GOT entry. | ||
| 263 | */ | ||
| 264 | struct tls_index { | ||
| 265 | uint64_t module; | ||
| 266 | uint64_t offset; | ||
| 267 | }; | ||
| 268 | |||
| 269 | static inline __attribute__((always_inline)) | ||
| 270 | void *calc_location(struct strobe_value_loc *loc, void *tls_base) | ||
| 271 | { | ||
| 272 | /* | ||
| 273 | * tls_mode value is: | ||
| 274 | * - -1 (TLS_NOT_SET), if no metavar is present; | ||
| 275 | * - 0 (TLS_LOCAL_EXEC), if metavar uses Local Executable mode of TLS | ||
| 276 | * (offset from fs:0 for x86-64 or tpidr_el0 for aarch64); | ||
| 277 | * - 1 (TLS_IMM_EXEC), if metavar uses Immediate Executable mode of TLS; | ||
| 278 | * - 2 (TLS_GENERAL_DYN), if metavar uses General Dynamic mode of TLS; | ||
| 279 | * This schema allows to use something like: | ||
| 280 | * (tls_mode + 1) * (tls_base + offset) | ||
| 281 | * to get NULL for "no metavar" location, or correct pointer for local | ||
| 282 | * executable mode without doing extra ifs. | ||
| 283 | */ | ||
| 284 | if (loc->tls_mode <= TLS_LOCAL_EXEC) { | ||
| 285 | /* static executable is simple, we just have offset from | ||
| 286 | * tls_base */ | ||
| 287 | void *addr = tls_base + loc->offset; | ||
| 288 | /* multiply by (tls_mode + 1) to get NULL, if we have no | ||
| 289 | * metavar in this slot */ | ||
| 290 | return (void *)((loc->tls_mode + 1) * (int64_t)addr); | ||
| 291 | } | ||
| 292 | /* | ||
| 293 | * Other modes are more complicated, we need to jump through few hoops. | ||
| 294 | * | ||
| 295 | * For immediate executable mode (currently supported only for aarch64): | ||
| 296 | * - loc->offset is pointing to a GOT entry containing fixed offset | ||
| 297 | * relative to tls_base; | ||
| 298 | * | ||
| 299 | * For general dynamic mode: | ||
| 300 | * - loc->offset is pointing to a beginning of double GOT entries; | ||
| 301 | * - (for aarch64 only) second entry points to tls_index_t struct; | ||
| 302 | * - (for x86-64 only) two GOT entries are already tls_index_t; | ||
| 303 | * - tls_index_t->module is used to find start of TLS section in | ||
| 304 | * which variable resides; | ||
| 305 | * - tls_index_t->offset provides offset within that TLS section, | ||
| 306 | * pointing to value of variable. | ||
| 307 | */ | ||
| 308 | struct tls_index tls_index; | ||
| 309 | dtv_t *dtv; | ||
| 310 | void *tls_ptr; | ||
| 311 | |||
| 312 | bpf_probe_read(&tls_index, sizeof(struct tls_index), | ||
| 313 | (void *)loc->offset); | ||
| 314 | /* valid module index is always positive */ | ||
| 315 | if (tls_index.module > 0) { | ||
| 316 | /* dtv = ((struct tcbhead *)tls_base)->dtv[tls_index.module] */ | ||
| 317 | bpf_probe_read(&dtv, sizeof(dtv), | ||
| 318 | &((struct tcbhead *)tls_base)->dtv); | ||
| 319 | dtv += tls_index.module; | ||
| 320 | } else { | ||
| 321 | dtv = NULL; | ||
| 322 | } | ||
| 323 | bpf_probe_read(&tls_ptr, sizeof(void *), dtv); | ||
| 324 | /* if pointer has (void *)-1 value, then TLS wasn't initialized yet */ | ||
| 325 | return tls_ptr && tls_ptr != (void *)-1 | ||
| 326 | ? tls_ptr + tls_index.offset | ||
| 327 | : NULL; | ||
| 328 | } | ||
| 329 | |||
| 330 | static inline __attribute__((always_inline)) | ||
| 331 | void read_int_var(struct strobemeta_cfg *cfg, size_t idx, void *tls_base, | ||
| 332 | struct strobe_value_generic *value, | ||
| 333 | struct strobemeta_payload *data) | ||
| 334 | { | ||
| 335 | void *location = calc_location(&cfg->int_locs[idx], tls_base); | ||
| 336 | if (!location) | ||
| 337 | return; | ||
| 338 | |||
| 339 | bpf_probe_read(value, sizeof(struct strobe_value_generic), location); | ||
| 340 | data->int_vals[idx] = value->val; | ||
| 341 | if (value->header.len) | ||
| 342 | data->int_vals_set_mask |= (1 << idx); | ||
| 343 | } | ||
| 344 | |||
| 345 | static inline __attribute__((always_inline)) | ||
| 346 | uint64_t read_str_var(struct strobemeta_cfg* cfg, size_t idx, void *tls_base, | ||
| 347 | struct strobe_value_generic *value, | ||
| 348 | struct strobemeta_payload *data, void *payload) | ||
| 349 | { | ||
| 350 | void *location; | ||
| 351 | uint32_t len; | ||
| 352 | |||
| 353 | data->str_lens[idx] = 0; | ||
| 354 | location = calc_location(&cfg->str_locs[idx], tls_base); | ||
| 355 | if (!location) | ||
| 356 | return 0; | ||
| 357 | |||
| 358 | bpf_probe_read(value, sizeof(struct strobe_value_generic), location); | ||
| 359 | len = bpf_probe_read_str(payload, STROBE_MAX_STR_LEN, value->ptr); | ||
| 360 | /* | ||
| 361 | * if bpf_probe_read_str returns error (<0), due to casting to | ||
| 362 | * unsinged int, it will become big number, so next check is | ||
| 363 | * sufficient to check for errors AND prove to BPF verifier, that | ||
| 364 | * bpf_probe_read_str won't return anything bigger than | ||
| 365 | * STROBE_MAX_STR_LEN | ||
| 366 | */ | ||
| 367 | if (len > STROBE_MAX_STR_LEN) | ||
| 368 | return 0; | ||
| 369 | |||
| 370 | data->str_lens[idx] = len; | ||
| 371 | return len; | ||
| 372 | } | ||
| 373 | |||
| 374 | static inline __attribute__((always_inline)) | ||
| 375 | void *read_map_var(struct strobemeta_cfg *cfg, size_t idx, void *tls_base, | ||
| 376 | struct strobe_value_generic *value, | ||
| 377 | struct strobemeta_payload* data, void *payload) | ||
| 378 | { | ||
| 379 | struct strobe_map_descr* descr = &data->map_descrs[idx]; | ||
| 380 | struct strobe_map_raw map; | ||
| 381 | void *location; | ||
| 382 | uint32_t len; | ||
| 383 | int i; | ||
| 384 | |||
| 385 | descr->tag_len = 0; /* presume no tag is set */ | ||
| 386 | descr->cnt = -1; /* presume no value is set */ | ||
| 387 | |||
| 388 | location = calc_location(&cfg->map_locs[idx], tls_base); | ||
| 389 | if (!location) | ||
| 390 | return payload; | ||
| 391 | |||
| 392 | bpf_probe_read(value, sizeof(struct strobe_value_generic), location); | ||
| 393 | if (bpf_probe_read(&map, sizeof(struct strobe_map_raw), value->ptr)) | ||
| 394 | return payload; | ||
| 395 | |||
| 396 | descr->id = map.id; | ||
| 397 | descr->cnt = map.cnt; | ||
| 398 | if (cfg->req_meta_idx == idx) { | ||
| 399 | data->req_id = map.id; | ||
| 400 | data->req_meta_valid = 1; | ||
| 401 | } | ||
| 402 | |||
| 403 | len = bpf_probe_read_str(payload, STROBE_MAX_STR_LEN, map.tag); | ||
| 404 | if (len <= STROBE_MAX_STR_LEN) { | ||
| 405 | descr->tag_len = len; | ||
| 406 | payload += len; | ||
| 407 | } | ||
| 408 | |||
| 409 | #ifdef NO_UNROLL | ||
| 410 | #pragma clang loop unroll(disable) | ||
| 411 | #else | ||
| 412 | #pragma unroll | ||
| 413 | #endif | ||
| 414 | for (int i = 0; i < STROBE_MAX_MAP_ENTRIES && i < map.cnt; ++i) { | ||
| 415 | descr->key_lens[i] = 0; | ||
| 416 | len = bpf_probe_read_str(payload, STROBE_MAX_STR_LEN, | ||
| 417 | map.entries[i].key); | ||
| 418 | if (len <= STROBE_MAX_STR_LEN) { | ||
| 419 | descr->key_lens[i] = len; | ||
| 420 | payload += len; | ||
| 421 | } | ||
| 422 | descr->val_lens[i] = 0; | ||
| 423 | len = bpf_probe_read_str(payload, STROBE_MAX_STR_LEN, | ||
| 424 | map.entries[i].val); | ||
| 425 | if (len <= STROBE_MAX_STR_LEN) { | ||
| 426 | descr->val_lens[i] = len; | ||
| 427 | payload += len; | ||
| 428 | } | ||
| 429 | } | ||
| 430 | |||
| 431 | return payload; | ||
| 432 | } | ||
| 433 | |||
| 434 | /* | ||
| 435 | * read_strobe_meta returns NULL, if no metadata was read; otherwise returns | ||
| 436 | * pointer to *right after* payload ends | ||
| 437 | */ | ||
| 438 | static inline __attribute__((always_inline)) | ||
| 439 | void *read_strobe_meta(struct task_struct* task, | ||
| 440 | struct strobemeta_payload* data) { | ||
| 441 | pid_t pid = bpf_get_current_pid_tgid() >> 32; | ||
| 442 | struct strobe_value_generic value = {0}; | ||
| 443 | struct strobemeta_cfg *cfg; | ||
| 444 | void *tls_base, *payload; | ||
| 445 | |||
| 446 | cfg = bpf_map_lookup_elem(&strobemeta_cfgs, &pid); | ||
| 447 | if (!cfg) | ||
| 448 | return NULL; | ||
| 449 | |||
| 450 | data->int_vals_set_mask = 0; | ||
| 451 | data->req_meta_valid = 0; | ||
| 452 | payload = data->payload; | ||
| 453 | /* | ||
| 454 | * we don't have struct task_struct definition, it should be: | ||
| 455 | * tls_base = (void *)task->thread.fsbase; | ||
| 456 | */ | ||
| 457 | tls_base = (void *)task; | ||
| 458 | |||
| 459 | #ifdef NO_UNROLL | ||
| 460 | #pragma clang loop unroll(disable) | ||
| 461 | #else | ||
| 462 | #pragma unroll | ||
| 463 | #endif | ||
| 464 | for (int i = 0; i < STROBE_MAX_INTS; ++i) { | ||
| 465 | read_int_var(cfg, i, tls_base, &value, data); | ||
| 466 | } | ||
| 467 | #ifdef NO_UNROLL | ||
| 468 | #pragma clang loop unroll(disable) | ||
| 469 | #else | ||
| 470 | #pragma unroll | ||
| 471 | #endif | ||
| 472 | for (int i = 0; i < STROBE_MAX_STRS; ++i) { | ||
| 473 | payload += read_str_var(cfg, i, tls_base, &value, data, payload); | ||
| 474 | } | ||
| 475 | #ifdef NO_UNROLL | ||
| 476 | #pragma clang loop unroll(disable) | ||
| 477 | #else | ||
| 478 | #pragma unroll | ||
| 479 | #endif | ||
| 480 | for (int i = 0; i < STROBE_MAX_MAPS; ++i) { | ||
| 481 | payload = read_map_var(cfg, i, tls_base, &value, data, payload); | ||
| 482 | } | ||
| 483 | /* | ||
| 484 | * return pointer right after end of payload, so it's possible to | ||
| 485 | * calculate exact amount of useful data that needs to be sent | ||
| 486 | */ | ||
| 487 | return payload; | ||
| 488 | } | ||
| 489 | |||
| 490 | SEC("raw_tracepoint/kfree_skb") | ||
| 491 | int on_event(struct pt_regs *ctx) { | ||
| 492 | pid_t pid = bpf_get_current_pid_tgid() >> 32; | ||
| 493 | struct strobelight_bpf_sample* sample; | ||
| 494 | struct task_struct *task; | ||
| 495 | uint32_t zero = 0; | ||
| 496 | uint64_t ktime_ns; | ||
| 497 | void *sample_end; | ||
| 498 | |||
| 499 | sample = bpf_map_lookup_elem(&sample_heap, &zero); | ||
| 500 | if (!sample) | ||
| 501 | return 0; /* this will never happen */ | ||
| 502 | |||
| 503 | sample->pid = pid; | ||
| 504 | bpf_get_current_comm(&sample->comm, TASK_COMM_LEN); | ||
| 505 | ktime_ns = bpf_ktime_get_ns(); | ||
| 506 | sample->ktime = ktime_ns; | ||
| 507 | |||
| 508 | task = (struct task_struct *)bpf_get_current_task(); | ||
| 509 | sample_end = read_strobe_meta(task, &sample->metadata); | ||
| 510 | sample->has_meta = sample_end != NULL; | ||
| 511 | sample_end = sample_end ? : &sample->metadata; | ||
| 512 | |||
| 513 | if ((ktime_ns >> STACK_TABLE_EPOCH_SHIFT) & 1) { | ||
| 514 | sample->kernel_stack_id = bpf_get_stackid(ctx, &stacks_1, 0); | ||
| 515 | sample->user_stack_id = bpf_get_stackid(ctx, &stacks_1, BPF_F_USER_STACK); | ||
| 516 | } else { | ||
| 517 | sample->kernel_stack_id = bpf_get_stackid(ctx, &stacks_0, 0); | ||
| 518 | sample->user_stack_id = bpf_get_stackid(ctx, &stacks_0, BPF_F_USER_STACK); | ||
| 519 | } | ||
| 520 | |||
| 521 | uint64_t sample_size = sample_end - (void *)sample; | ||
| 522 | /* should always be true */ | ||
| 523 | if (sample_size < sizeof(struct strobelight_bpf_sample)) | ||
| 524 | bpf_perf_event_output(ctx, &samples, 0, sample, 1 + sample_size); | ||
| 525 | return 0; | ||
| 526 | } | ||
| 527 | |||
| 528 | char _license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/progs/strobemeta_nounroll1.c b/tools/testing/selftests/bpf/progs/strobemeta_nounroll1.c new file mode 100644 index 000000000000..f0a1669e11d6 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/strobemeta_nounroll1.c | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | ||
| 2 | // Copyright (c) 2019 Facebook | ||
| 3 | |||
| 4 | #define STROBE_MAX_INTS 2 | ||
| 5 | #define STROBE_MAX_STRS 25 | ||
| 6 | #define STROBE_MAX_MAPS 13 | ||
| 7 | #define STROBE_MAX_MAP_ENTRIES 20 | ||
| 8 | #define NO_UNROLL | ||
| 9 | #include "strobemeta.h" | ||
diff --git a/tools/testing/selftests/bpf/progs/strobemeta_nounroll2.c b/tools/testing/selftests/bpf/progs/strobemeta_nounroll2.c new file mode 100644 index 000000000000..4291a7d642e7 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/strobemeta_nounroll2.c | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | ||
| 2 | // Copyright (c) 2019 Facebook | ||
| 3 | |||
| 4 | #define STROBE_MAX_INTS 2 | ||
| 5 | #define STROBE_MAX_STRS 25 | ||
| 6 | #define STROBE_MAX_MAPS 30 | ||
| 7 | #define STROBE_MAX_MAP_ENTRIES 20 | ||
| 8 | #define NO_UNROLL | ||
| 9 | #include "strobemeta.h" | ||
diff --git a/tools/testing/selftests/bpf/progs/test_btf_newkv.c b/tools/testing/selftests/bpf/progs/test_btf_newkv.c new file mode 100644 index 000000000000..28c16bb583b6 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_btf_newkv.c | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* Copyright (c) 2018 Facebook */ | ||
| 3 | #include <linux/bpf.h> | ||
| 4 | #include "bpf_helpers.h" | ||
| 5 | |||
| 6 | int _version SEC("version") = 1; | ||
| 7 | |||
| 8 | struct ipv_counts { | ||
| 9 | unsigned int v4; | ||
| 10 | unsigned int v6; | ||
| 11 | }; | ||
| 12 | |||
| 13 | /* just to validate we can handle maps in multiple sections */ | ||
| 14 | struct bpf_map_def SEC("maps") btf_map_legacy = { | ||
| 15 | .type = BPF_MAP_TYPE_ARRAY, | ||
| 16 | .key_size = sizeof(int), | ||
| 17 | .value_size = sizeof(long long), | ||
| 18 | .max_entries = 4, | ||
| 19 | }; | ||
| 20 | |||
| 21 | BPF_ANNOTATE_KV_PAIR(btf_map_legacy, int, struct ipv_counts); | ||
| 22 | |||
| 23 | struct { | ||
| 24 | int *key; | ||
| 25 | struct ipv_counts *value; | ||
| 26 | unsigned int type; | ||
| 27 | unsigned int max_entries; | ||
| 28 | } btf_map SEC(".maps") = { | ||
| 29 | .type = BPF_MAP_TYPE_ARRAY, | ||
| 30 | .max_entries = 4, | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct dummy_tracepoint_args { | ||
| 34 | unsigned long long pad; | ||
| 35 | struct sock *sock; | ||
| 36 | }; | ||
| 37 | |||
| 38 | __attribute__((noinline)) | ||
| 39 | static int test_long_fname_2(struct dummy_tracepoint_args *arg) | ||
| 40 | { | ||
| 41 | struct ipv_counts *counts; | ||
| 42 | int key = 0; | ||
| 43 | |||
| 44 | if (!arg->sock) | ||
| 45 | return 0; | ||
| 46 | |||
| 47 | counts = bpf_map_lookup_elem(&btf_map, &key); | ||
| 48 | if (!counts) | ||
| 49 | return 0; | ||
| 50 | |||
| 51 | counts->v6++; | ||
| 52 | |||
| 53 | /* just verify we can reference both maps */ | ||
| 54 | counts = bpf_map_lookup_elem(&btf_map_legacy, &key); | ||
| 55 | if (!counts) | ||
| 56 | return 0; | ||
| 57 | |||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | __attribute__((noinline)) | ||
| 62 | static int test_long_fname_1(struct dummy_tracepoint_args *arg) | ||
| 63 | { | ||
| 64 | return test_long_fname_2(arg); | ||
| 65 | } | ||
| 66 | |||
| 67 | SEC("dummy_tracepoint") | ||
| 68 | int _dummy_tracepoint(struct dummy_tracepoint_args *arg) | ||
| 69 | { | ||
| 70 | return test_long_fname_1(arg); | ||
| 71 | } | ||
| 72 | |||
| 73 | char _license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c b/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c index f6d9f238e00a..aaa6ec250e15 100644 --- a/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c +++ b/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c | |||
| @@ -15,17 +15,25 @@ struct stack_trace_t { | |||
| 15 | struct bpf_stack_build_id user_stack_buildid[MAX_STACK_RAWTP]; | 15 | struct bpf_stack_build_id user_stack_buildid[MAX_STACK_RAWTP]; |
| 16 | }; | 16 | }; |
| 17 | 17 | ||
| 18 | struct bpf_map_def SEC("maps") perfmap = { | 18 | struct { |
| 19 | __u32 type; | ||
| 20 | __u32 max_entries; | ||
| 21 | __u32 key_size; | ||
| 22 | __u32 value_size; | ||
| 23 | } perfmap SEC(".maps") = { | ||
| 19 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, | 24 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, |
| 25 | .max_entries = 2, | ||
| 20 | .key_size = sizeof(int), | 26 | .key_size = sizeof(int), |
| 21 | .value_size = sizeof(__u32), | 27 | .value_size = sizeof(__u32), |
| 22 | .max_entries = 2, | ||
| 23 | }; | 28 | }; |
| 24 | 29 | ||
| 25 | struct bpf_map_def SEC("maps") stackdata_map = { | 30 | struct { |
| 31 | __u32 type; | ||
| 32 | __u32 max_entries; | ||
| 33 | __u32 *key; | ||
| 34 | struct stack_trace_t *value; | ||
| 35 | } stackdata_map SEC(".maps") = { | ||
| 26 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, | 36 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, |
| 27 | .key_size = sizeof(__u32), | ||
| 28 | .value_size = sizeof(struct stack_trace_t), | ||
| 29 | .max_entries = 1, | 37 | .max_entries = 1, |
| 30 | }; | 38 | }; |
| 31 | 39 | ||
| @@ -47,10 +55,13 @@ struct bpf_map_def SEC("maps") stackdata_map = { | |||
| 47 | * issue and avoid complicated C programming massaging. | 55 | * issue and avoid complicated C programming massaging. |
| 48 | * This is an acceptable workaround since there is one entry here. | 56 | * This is an acceptable workaround since there is one entry here. |
| 49 | */ | 57 | */ |
| 50 | struct bpf_map_def SEC("maps") rawdata_map = { | 58 | struct { |
| 59 | __u32 type; | ||
| 60 | __u32 max_entries; | ||
| 61 | __u32 *key; | ||
| 62 | __u64 (*value)[2 * MAX_STACK_RAWTP]; | ||
| 63 | } rawdata_map SEC(".maps") = { | ||
| 51 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, | 64 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, |
| 52 | .key_size = sizeof(__u32), | ||
| 53 | .value_size = MAX_STACK_RAWTP * sizeof(__u64) * 2, | ||
| 54 | .max_entries = 1, | 65 | .max_entries = 1, |
| 55 | }; | 66 | }; |
| 56 | 67 | ||
diff --git a/tools/testing/selftests/bpf/progs/test_global_data.c b/tools/testing/selftests/bpf/progs/test_global_data.c index 5ab14e941980..866cc7ddbe43 100644 --- a/tools/testing/selftests/bpf/progs/test_global_data.c +++ b/tools/testing/selftests/bpf/progs/test_global_data.c | |||
| @@ -7,17 +7,23 @@ | |||
| 7 | 7 | ||
| 8 | #include "bpf_helpers.h" | 8 | #include "bpf_helpers.h" |
| 9 | 9 | ||
| 10 | struct bpf_map_def SEC("maps") result_number = { | 10 | struct { |
| 11 | __u32 type; | ||
| 12 | __u32 max_entries; | ||
| 13 | __u32 *key; | ||
| 14 | __u64 *value; | ||
| 15 | } result_number SEC(".maps") = { | ||
| 11 | .type = BPF_MAP_TYPE_ARRAY, | 16 | .type = BPF_MAP_TYPE_ARRAY, |
| 12 | .key_size = sizeof(__u32), | ||
| 13 | .value_size = sizeof(__u64), | ||
| 14 | .max_entries = 11, | 17 | .max_entries = 11, |
| 15 | }; | 18 | }; |
| 16 | 19 | ||
| 17 | struct bpf_map_def SEC("maps") result_string = { | 20 | struct { |
| 21 | __u32 type; | ||
| 22 | __u32 max_entries; | ||
| 23 | __u32 *key; | ||
| 24 | const char (*value)[32]; | ||
| 25 | } result_string SEC(".maps") = { | ||
| 18 | .type = BPF_MAP_TYPE_ARRAY, | 26 | .type = BPF_MAP_TYPE_ARRAY, |
| 19 | .key_size = sizeof(__u32), | ||
| 20 | .value_size = 32, | ||
| 21 | .max_entries = 5, | 27 | .max_entries = 5, |
| 22 | }; | 28 | }; |
| 23 | 29 | ||
| @@ -27,10 +33,13 @@ struct foo { | |||
| 27 | __u64 c; | 33 | __u64 c; |
| 28 | }; | 34 | }; |
| 29 | 35 | ||
| 30 | struct bpf_map_def SEC("maps") result_struct = { | 36 | struct { |
| 37 | __u32 type; | ||
| 38 | __u32 max_entries; | ||
| 39 | __u32 *key; | ||
| 40 | struct foo *value; | ||
| 41 | } result_struct SEC(".maps") = { | ||
| 31 | .type = BPF_MAP_TYPE_ARRAY, | 42 | .type = BPF_MAP_TYPE_ARRAY, |
| 32 | .key_size = sizeof(__u32), | ||
| 33 | .value_size = sizeof(struct foo), | ||
| 34 | .max_entries = 5, | 43 | .max_entries = 5, |
| 35 | }; | 44 | }; |
| 36 | 45 | ||
diff --git a/tools/testing/selftests/bpf/progs/test_l4lb.c b/tools/testing/selftests/bpf/progs/test_l4lb.c index 1e10c9590991..848cbb90f581 100644 --- a/tools/testing/selftests/bpf/progs/test_l4lb.c +++ b/tools/testing/selftests/bpf/progs/test_l4lb.c | |||
| @@ -169,38 +169,53 @@ struct eth_hdr { | |||
| 169 | unsigned short eth_proto; | 169 | unsigned short eth_proto; |
| 170 | }; | 170 | }; |
| 171 | 171 | ||
| 172 | struct bpf_map_def SEC("maps") vip_map = { | 172 | struct { |
| 173 | __u32 type; | ||
| 174 | __u32 max_entries; | ||
| 175 | struct vip *key; | ||
| 176 | struct vip_meta *value; | ||
| 177 | } vip_map SEC(".maps") = { | ||
| 173 | .type = BPF_MAP_TYPE_HASH, | 178 | .type = BPF_MAP_TYPE_HASH, |
| 174 | .key_size = sizeof(struct vip), | ||
| 175 | .value_size = sizeof(struct vip_meta), | ||
| 176 | .max_entries = MAX_VIPS, | 179 | .max_entries = MAX_VIPS, |
| 177 | }; | 180 | }; |
| 178 | 181 | ||
| 179 | struct bpf_map_def SEC("maps") ch_rings = { | 182 | struct { |
| 183 | __u32 type; | ||
| 184 | __u32 max_entries; | ||
| 185 | __u32 *key; | ||
| 186 | __u32 *value; | ||
| 187 | } ch_rings SEC(".maps") = { | ||
| 180 | .type = BPF_MAP_TYPE_ARRAY, | 188 | .type = BPF_MAP_TYPE_ARRAY, |
| 181 | .key_size = sizeof(__u32), | ||
| 182 | .value_size = sizeof(__u32), | ||
| 183 | .max_entries = CH_RINGS_SIZE, | 189 | .max_entries = CH_RINGS_SIZE, |
| 184 | }; | 190 | }; |
| 185 | 191 | ||
| 186 | struct bpf_map_def SEC("maps") reals = { | 192 | struct { |
| 193 | __u32 type; | ||
| 194 | __u32 max_entries; | ||
| 195 | __u32 *key; | ||
| 196 | struct real_definition *value; | ||
| 197 | } reals SEC(".maps") = { | ||
| 187 | .type = BPF_MAP_TYPE_ARRAY, | 198 | .type = BPF_MAP_TYPE_ARRAY, |
| 188 | .key_size = sizeof(__u32), | ||
| 189 | .value_size = sizeof(struct real_definition), | ||
| 190 | .max_entries = MAX_REALS, | 199 | .max_entries = MAX_REALS, |
| 191 | }; | 200 | }; |
| 192 | 201 | ||
| 193 | struct bpf_map_def SEC("maps") stats = { | 202 | struct { |
| 203 | __u32 type; | ||
| 204 | __u32 max_entries; | ||
| 205 | __u32 *key; | ||
| 206 | struct vip_stats *value; | ||
| 207 | } stats SEC(".maps") = { | ||
| 194 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, | 208 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, |
| 195 | .key_size = sizeof(__u32), | ||
| 196 | .value_size = sizeof(struct vip_stats), | ||
| 197 | .max_entries = MAX_VIPS, | 209 | .max_entries = MAX_VIPS, |
| 198 | }; | 210 | }; |
| 199 | 211 | ||
| 200 | struct bpf_map_def SEC("maps") ctl_array = { | 212 | struct { |
| 213 | __u32 type; | ||
| 214 | __u32 max_entries; | ||
| 215 | __u32 *key; | ||
| 216 | struct ctl_value *value; | ||
| 217 | } ctl_array SEC(".maps") = { | ||
| 201 | .type = BPF_MAP_TYPE_ARRAY, | 218 | .type = BPF_MAP_TYPE_ARRAY, |
| 202 | .key_size = sizeof(__u32), | ||
| 203 | .value_size = sizeof(struct ctl_value), | ||
| 204 | .max_entries = CTL_MAP_SIZE, | 219 | .max_entries = CTL_MAP_SIZE, |
| 205 | }; | 220 | }; |
| 206 | 221 | ||
diff --git a/tools/testing/selftests/bpf/progs/test_l4lb_noinline.c b/tools/testing/selftests/bpf/progs/test_l4lb_noinline.c index ba44a14e6dc4..c63ecf3ca573 100644 --- a/tools/testing/selftests/bpf/progs/test_l4lb_noinline.c +++ b/tools/testing/selftests/bpf/progs/test_l4lb_noinline.c | |||
| @@ -165,38 +165,53 @@ struct eth_hdr { | |||
| 165 | unsigned short eth_proto; | 165 | unsigned short eth_proto; |
| 166 | }; | 166 | }; |
| 167 | 167 | ||
| 168 | struct bpf_map_def SEC("maps") vip_map = { | 168 | struct { |
| 169 | __u32 type; | ||
| 170 | __u32 max_entries; | ||
| 171 | struct vip *key; | ||
| 172 | struct vip_meta *value; | ||
| 173 | } vip_map SEC(".maps") = { | ||
| 169 | .type = BPF_MAP_TYPE_HASH, | 174 | .type = BPF_MAP_TYPE_HASH, |
| 170 | .key_size = sizeof(struct vip), | ||
| 171 | .value_size = sizeof(struct vip_meta), | ||
| 172 | .max_entries = MAX_VIPS, | 175 | .max_entries = MAX_VIPS, |
| 173 | }; | 176 | }; |
| 174 | 177 | ||
| 175 | struct bpf_map_def SEC("maps") ch_rings = { | 178 | struct { |
| 179 | __u32 type; | ||
| 180 | __u32 max_entries; | ||
| 181 | __u32 *key; | ||
| 182 | __u32 *value; | ||
| 183 | } ch_rings SEC(".maps") = { | ||
| 176 | .type = BPF_MAP_TYPE_ARRAY, | 184 | .type = BPF_MAP_TYPE_ARRAY, |
| 177 | .key_size = sizeof(__u32), | ||
| 178 | .value_size = sizeof(__u32), | ||
| 179 | .max_entries = CH_RINGS_SIZE, | 185 | .max_entries = CH_RINGS_SIZE, |
| 180 | }; | 186 | }; |
| 181 | 187 | ||
| 182 | struct bpf_map_def SEC("maps") reals = { | 188 | struct { |
| 189 | __u32 type; | ||
| 190 | __u32 max_entries; | ||
| 191 | __u32 *key; | ||
| 192 | struct real_definition *value; | ||
| 193 | } reals SEC(".maps") = { | ||
| 183 | .type = BPF_MAP_TYPE_ARRAY, | 194 | .type = BPF_MAP_TYPE_ARRAY, |
| 184 | .key_size = sizeof(__u32), | ||
| 185 | .value_size = sizeof(struct real_definition), | ||
| 186 | .max_entries = MAX_REALS, | 195 | .max_entries = MAX_REALS, |
| 187 | }; | 196 | }; |
| 188 | 197 | ||
| 189 | struct bpf_map_def SEC("maps") stats = { | 198 | struct { |
| 199 | __u32 type; | ||
| 200 | __u32 max_entries; | ||
| 201 | __u32 *key; | ||
| 202 | struct vip_stats *value; | ||
| 203 | } stats SEC(".maps") = { | ||
| 190 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, | 204 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, |
| 191 | .key_size = sizeof(__u32), | ||
| 192 | .value_size = sizeof(struct vip_stats), | ||
| 193 | .max_entries = MAX_VIPS, | 205 | .max_entries = MAX_VIPS, |
| 194 | }; | 206 | }; |
| 195 | 207 | ||
| 196 | struct bpf_map_def SEC("maps") ctl_array = { | 208 | struct { |
| 209 | __u32 type; | ||
| 210 | __u32 max_entries; | ||
| 211 | __u32 *key; | ||
| 212 | struct ctl_value *value; | ||
| 213 | } ctl_array SEC(".maps") = { | ||
| 197 | .type = BPF_MAP_TYPE_ARRAY, | 214 | .type = BPF_MAP_TYPE_ARRAY, |
| 198 | .key_size = sizeof(__u32), | ||
| 199 | .value_size = sizeof(struct ctl_value), | ||
| 200 | .max_entries = CTL_MAP_SIZE, | 215 | .max_entries = CTL_MAP_SIZE, |
| 201 | }; | 216 | }; |
| 202 | 217 | ||
diff --git a/tools/testing/selftests/bpf/progs/test_map_lock.c b/tools/testing/selftests/bpf/progs/test_map_lock.c index af8cc68ed2f9..40d9c2853393 100644 --- a/tools/testing/selftests/bpf/progs/test_map_lock.c +++ b/tools/testing/selftests/bpf/progs/test_map_lock.c | |||
| @@ -11,29 +11,31 @@ struct hmap_elem { | |||
| 11 | int var[VAR_NUM]; | 11 | int var[VAR_NUM]; |
| 12 | }; | 12 | }; |
| 13 | 13 | ||
| 14 | struct bpf_map_def SEC("maps") hash_map = { | 14 | struct { |
| 15 | __u32 type; | ||
| 16 | __u32 max_entries; | ||
| 17 | __u32 *key; | ||
| 18 | struct hmap_elem *value; | ||
| 19 | } hash_map SEC(".maps") = { | ||
| 15 | .type = BPF_MAP_TYPE_HASH, | 20 | .type = BPF_MAP_TYPE_HASH, |
| 16 | .key_size = sizeof(int), | ||
| 17 | .value_size = sizeof(struct hmap_elem), | ||
| 18 | .max_entries = 1, | 21 | .max_entries = 1, |
| 19 | }; | 22 | }; |
| 20 | 23 | ||
| 21 | BPF_ANNOTATE_KV_PAIR(hash_map, int, struct hmap_elem); | ||
| 22 | |||
| 23 | struct array_elem { | 24 | struct array_elem { |
| 24 | struct bpf_spin_lock lock; | 25 | struct bpf_spin_lock lock; |
| 25 | int var[VAR_NUM]; | 26 | int var[VAR_NUM]; |
| 26 | }; | 27 | }; |
| 27 | 28 | ||
| 28 | struct bpf_map_def SEC("maps") array_map = { | 29 | struct { |
| 30 | __u32 type; | ||
| 31 | __u32 max_entries; | ||
| 32 | int *key; | ||
| 33 | struct array_elem *value; | ||
| 34 | } array_map SEC(".maps") = { | ||
| 29 | .type = BPF_MAP_TYPE_ARRAY, | 35 | .type = BPF_MAP_TYPE_ARRAY, |
| 30 | .key_size = sizeof(int), | ||
| 31 | .value_size = sizeof(struct array_elem), | ||
| 32 | .max_entries = 1, | 36 | .max_entries = 1, |
| 33 | }; | 37 | }; |
| 34 | 38 | ||
| 35 | BPF_ANNOTATE_KV_PAIR(array_map, int, struct array_elem); | ||
| 36 | |||
| 37 | SEC("map_lock_demo") | 39 | SEC("map_lock_demo") |
| 38 | int bpf_map_lock_test(struct __sk_buff *skb) | 40 | int bpf_map_lock_test(struct __sk_buff *skb) |
| 39 | { | 41 | { |
diff --git a/tools/testing/selftests/bpf/progs/test_seg6_loop.c b/tools/testing/selftests/bpf/progs/test_seg6_loop.c new file mode 100644 index 000000000000..463964d79f73 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_seg6_loop.c | |||
| @@ -0,0 +1,261 @@ | |||
| 1 | #include <stddef.h> | ||
| 2 | #include <inttypes.h> | ||
| 3 | #include <errno.h> | ||
| 4 | #include <linux/seg6_local.h> | ||
| 5 | #include <linux/bpf.h> | ||
| 6 | #include "bpf_helpers.h" | ||
| 7 | #include "bpf_endian.h" | ||
| 8 | |||
| 9 | /* Packet parsing state machine helpers. */ | ||
| 10 | #define cursor_advance(_cursor, _len) \ | ||
| 11 | ({ void *_tmp = _cursor; _cursor += _len; _tmp; }) | ||
| 12 | |||
| 13 | #define SR6_FLAG_ALERT (1 << 4) | ||
| 14 | |||
| 15 | #define htonll(x) ((bpf_htonl(1)) == 1 ? (x) : ((uint64_t)bpf_htonl((x) & \ | ||
| 16 | 0xFFFFFFFF) << 32) | bpf_htonl((x) >> 32)) | ||
| 17 | #define ntohll(x) ((bpf_ntohl(1)) == 1 ? (x) : ((uint64_t)bpf_ntohl((x) & \ | ||
| 18 | 0xFFFFFFFF) << 32) | bpf_ntohl((x) >> 32)) | ||
| 19 | #define BPF_PACKET_HEADER __attribute__((packed)) | ||
| 20 | |||
| 21 | struct ip6_t { | ||
| 22 | unsigned int ver:4; | ||
| 23 | unsigned int priority:8; | ||
| 24 | unsigned int flow_label:20; | ||
| 25 | unsigned short payload_len; | ||
| 26 | unsigned char next_header; | ||
| 27 | unsigned char hop_limit; | ||
| 28 | unsigned long long src_hi; | ||
| 29 | unsigned long long src_lo; | ||
| 30 | unsigned long long dst_hi; | ||
| 31 | unsigned long long dst_lo; | ||
| 32 | } BPF_PACKET_HEADER; | ||
| 33 | |||
| 34 | struct ip6_addr_t { | ||
| 35 | unsigned long long hi; | ||
| 36 | unsigned long long lo; | ||
| 37 | } BPF_PACKET_HEADER; | ||
| 38 | |||
| 39 | struct ip6_srh_t { | ||
| 40 | unsigned char nexthdr; | ||
| 41 | unsigned char hdrlen; | ||
| 42 | unsigned char type; | ||
| 43 | unsigned char segments_left; | ||
| 44 | unsigned char first_segment; | ||
| 45 | unsigned char flags; | ||
| 46 | unsigned short tag; | ||
| 47 | |||
| 48 | struct ip6_addr_t segments[0]; | ||
| 49 | } BPF_PACKET_HEADER; | ||
| 50 | |||
| 51 | struct sr6_tlv_t { | ||
| 52 | unsigned char type; | ||
| 53 | unsigned char len; | ||
| 54 | unsigned char value[0]; | ||
| 55 | } BPF_PACKET_HEADER; | ||
| 56 | |||
| 57 | static __attribute__((always_inline)) struct ip6_srh_t *get_srh(struct __sk_buff *skb) | ||
| 58 | { | ||
| 59 | void *cursor, *data_end; | ||
| 60 | struct ip6_srh_t *srh; | ||
| 61 | struct ip6_t *ip; | ||
| 62 | uint8_t *ipver; | ||
| 63 | |||
| 64 | data_end = (void *)(long)skb->data_end; | ||
| 65 | cursor = (void *)(long)skb->data; | ||
| 66 | ipver = (uint8_t *)cursor; | ||
| 67 | |||
| 68 | if ((void *)ipver + sizeof(*ipver) > data_end) | ||
| 69 | return NULL; | ||
| 70 | |||
| 71 | if ((*ipver >> 4) != 6) | ||
| 72 | return NULL; | ||
| 73 | |||
| 74 | ip = cursor_advance(cursor, sizeof(*ip)); | ||
| 75 | if ((void *)ip + sizeof(*ip) > data_end) | ||
| 76 | return NULL; | ||
| 77 | |||
| 78 | if (ip->next_header != 43) | ||
| 79 | return NULL; | ||
| 80 | |||
| 81 | srh = cursor_advance(cursor, sizeof(*srh)); | ||
| 82 | if ((void *)srh + sizeof(*srh) > data_end) | ||
| 83 | return NULL; | ||
| 84 | |||
| 85 | if (srh->type != 4) | ||
| 86 | return NULL; | ||
| 87 | |||
| 88 | return srh; | ||
| 89 | } | ||
| 90 | |||
| 91 | static __attribute__((always_inline)) | ||
| 92 | int update_tlv_pad(struct __sk_buff *skb, uint32_t new_pad, | ||
| 93 | uint32_t old_pad, uint32_t pad_off) | ||
| 94 | { | ||
| 95 | int err; | ||
| 96 | |||
| 97 | if (new_pad != old_pad) { | ||
| 98 | err = bpf_lwt_seg6_adjust_srh(skb, pad_off, | ||
| 99 | (int) new_pad - (int) old_pad); | ||
| 100 | if (err) | ||
| 101 | return err; | ||
| 102 | } | ||
| 103 | |||
| 104 | if (new_pad > 0) { | ||
| 105 | char pad_tlv_buf[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 106 | 0, 0, 0}; | ||
| 107 | struct sr6_tlv_t *pad_tlv = (struct sr6_tlv_t *) pad_tlv_buf; | ||
| 108 | |||
| 109 | pad_tlv->type = SR6_TLV_PADDING; | ||
| 110 | pad_tlv->len = new_pad - 2; | ||
| 111 | |||
| 112 | err = bpf_lwt_seg6_store_bytes(skb, pad_off, | ||
| 113 | (void *)pad_tlv_buf, new_pad); | ||
| 114 | if (err) | ||
| 115 | return err; | ||
| 116 | } | ||
| 117 | |||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | static __attribute__((always_inline)) | ||
| 122 | int is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh, | ||
| 123 | uint32_t *tlv_off, uint32_t *pad_size, | ||
| 124 | uint32_t *pad_off) | ||
| 125 | { | ||
| 126 | uint32_t srh_off, cur_off; | ||
| 127 | int offset_valid = 0; | ||
| 128 | int err; | ||
| 129 | |||
| 130 | srh_off = (char *)srh - (char *)(long)skb->data; | ||
| 131 | // cur_off = end of segments, start of possible TLVs | ||
| 132 | cur_off = srh_off + sizeof(*srh) + | ||
| 133 | sizeof(struct ip6_addr_t) * (srh->first_segment + 1); | ||
| 134 | |||
| 135 | *pad_off = 0; | ||
| 136 | |||
| 137 | // we can only go as far as ~10 TLVs due to the BPF max stack size | ||
| 138 | #pragma clang loop unroll(disable) | ||
| 139 | for (int i = 0; i < 100; i++) { | ||
| 140 | struct sr6_tlv_t tlv; | ||
| 141 | |||
| 142 | if (cur_off == *tlv_off) | ||
| 143 | offset_valid = 1; | ||
| 144 | |||
| 145 | if (cur_off >= srh_off + ((srh->hdrlen + 1) << 3)) | ||
| 146 | break; | ||
| 147 | |||
| 148 | err = bpf_skb_load_bytes(skb, cur_off, &tlv, sizeof(tlv)); | ||
| 149 | if (err) | ||
| 150 | return err; | ||
| 151 | |||
| 152 | if (tlv.type == SR6_TLV_PADDING) { | ||
| 153 | *pad_size = tlv.len + sizeof(tlv); | ||
| 154 | *pad_off = cur_off; | ||
| 155 | |||
| 156 | if (*tlv_off == srh_off) { | ||
| 157 | *tlv_off = cur_off; | ||
| 158 | offset_valid = 1; | ||
| 159 | } | ||
| 160 | break; | ||
| 161 | |||
| 162 | } else if (tlv.type == SR6_TLV_HMAC) { | ||
| 163 | break; | ||
| 164 | } | ||
| 165 | |||
| 166 | cur_off += sizeof(tlv) + tlv.len; | ||
| 167 | } // we reached the padding or HMAC TLVs, or the end of the SRH | ||
| 168 | |||
| 169 | if (*pad_off == 0) | ||
| 170 | *pad_off = cur_off; | ||
| 171 | |||
| 172 | if (*tlv_off == -1) | ||
| 173 | *tlv_off = cur_off; | ||
| 174 | else if (!offset_valid) | ||
| 175 | return -EINVAL; | ||
| 176 | |||
| 177 | return 0; | ||
| 178 | } | ||
| 179 | |||
| 180 | static __attribute__((always_inline)) | ||
| 181 | int add_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, uint32_t tlv_off, | ||
| 182 | struct sr6_tlv_t *itlv, uint8_t tlv_size) | ||
| 183 | { | ||
| 184 | uint32_t srh_off = (char *)srh - (char *)(long)skb->data; | ||
| 185 | uint8_t len_remaining, new_pad; | ||
| 186 | uint32_t pad_off = 0; | ||
| 187 | uint32_t pad_size = 0; | ||
| 188 | uint32_t partial_srh_len; | ||
| 189 | int err; | ||
| 190 | |||
| 191 | if (tlv_off != -1) | ||
| 192 | tlv_off += srh_off; | ||
| 193 | |||
| 194 | if (itlv->type == SR6_TLV_PADDING || itlv->type == SR6_TLV_HMAC) | ||
| 195 | return -EINVAL; | ||
| 196 | |||
| 197 | err = is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); | ||
| 198 | if (err) | ||
| 199 | return err; | ||
| 200 | |||
| 201 | err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, sizeof(*itlv) + itlv->len); | ||
| 202 | if (err) | ||
| 203 | return err; | ||
| 204 | |||
| 205 | err = bpf_lwt_seg6_store_bytes(skb, tlv_off, (void *)itlv, tlv_size); | ||
| 206 | if (err) | ||
| 207 | return err; | ||
| 208 | |||
| 209 | // the following can't be moved inside update_tlv_pad because the | ||
| 210 | // bpf verifier has some issues with it | ||
| 211 | pad_off += sizeof(*itlv) + itlv->len; | ||
| 212 | partial_srh_len = pad_off - srh_off; | ||
| 213 | len_remaining = partial_srh_len % 8; | ||
| 214 | new_pad = 8 - len_remaining; | ||
| 215 | |||
| 216 | if (new_pad == 1) // cannot pad for 1 byte only | ||
| 217 | new_pad = 9; | ||
| 218 | else if (new_pad == 8) | ||
| 219 | new_pad = 0; | ||
| 220 | |||
| 221 | return update_tlv_pad(skb, new_pad, pad_size, pad_off); | ||
| 222 | } | ||
| 223 | |||
| 224 | // Add an Egress TLV fc00::4, add the flag A, | ||
| 225 | // and apply End.X action to fc42::1 | ||
| 226 | SEC("lwt_seg6local") | ||
| 227 | int __add_egr_x(struct __sk_buff *skb) | ||
| 228 | { | ||
| 229 | unsigned long long hi = 0xfc42000000000000; | ||
| 230 | unsigned long long lo = 0x1; | ||
| 231 | struct ip6_srh_t *srh = get_srh(skb); | ||
| 232 | uint8_t new_flags = SR6_FLAG_ALERT; | ||
| 233 | struct ip6_addr_t addr; | ||
| 234 | int err, offset; | ||
| 235 | |||
| 236 | if (srh == NULL) | ||
| 237 | return BPF_DROP; | ||
| 238 | |||
| 239 | uint8_t tlv[20] = {2, 18, 0, 0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||
| 240 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4}; | ||
| 241 | |||
| 242 | err = add_tlv(skb, srh, (srh->hdrlen+1) << 3, | ||
| 243 | (struct sr6_tlv_t *)&tlv, 20); | ||
| 244 | if (err) | ||
| 245 | return BPF_DROP; | ||
| 246 | |||
| 247 | offset = sizeof(struct ip6_t) + offsetof(struct ip6_srh_t, flags); | ||
| 248 | err = bpf_lwt_seg6_store_bytes(skb, offset, | ||
| 249 | (void *)&new_flags, sizeof(new_flags)); | ||
| 250 | if (err) | ||
| 251 | return BPF_DROP; | ||
| 252 | |||
| 253 | addr.lo = htonll(lo); | ||
| 254 | addr.hi = htonll(hi); | ||
| 255 | err = bpf_lwt_seg6_action(skb, SEG6_LOCAL_ACTION_END_X, | ||
| 256 | (void *)&addr, sizeof(addr)); | ||
| 257 | if (err) | ||
| 258 | return BPF_DROP; | ||
| 259 | return BPF_REDIRECT; | ||
| 260 | } | ||
| 261 | char __license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/progs/test_select_reuseport_kern.c b/tools/testing/selftests/bpf/progs/test_select_reuseport_kern.c index 5b54ec637ada..435a9527733e 100644 --- a/tools/testing/selftests/bpf/progs/test_select_reuseport_kern.c +++ b/tools/testing/selftests/bpf/progs/test_select_reuseport_kern.c | |||
| @@ -21,38 +21,55 @@ int _version SEC("version") = 1; | |||
| 21 | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) | 21 | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) |
| 22 | #endif | 22 | #endif |
| 23 | 23 | ||
| 24 | struct bpf_map_def SEC("maps") outer_map = { | 24 | struct { |
| 25 | __u32 type; | ||
| 26 | __u32 max_entries; | ||
| 27 | __u32 key_size; | ||
| 28 | __u32 value_size; | ||
| 29 | } outer_map SEC(".maps") = { | ||
| 25 | .type = BPF_MAP_TYPE_ARRAY_OF_MAPS, | 30 | .type = BPF_MAP_TYPE_ARRAY_OF_MAPS, |
| 31 | .max_entries = 1, | ||
| 26 | .key_size = sizeof(__u32), | 32 | .key_size = sizeof(__u32), |
| 27 | .value_size = sizeof(__u32), | 33 | .value_size = sizeof(__u32), |
| 28 | .max_entries = 1, | ||
| 29 | }; | 34 | }; |
| 30 | 35 | ||
| 31 | struct bpf_map_def SEC("maps") result_map = { | 36 | struct { |
| 37 | __u32 type; | ||
| 38 | __u32 max_entries; | ||
| 39 | __u32 *key; | ||
| 40 | __u32 *value; | ||
| 41 | } result_map SEC(".maps") = { | ||
| 32 | .type = BPF_MAP_TYPE_ARRAY, | 42 | .type = BPF_MAP_TYPE_ARRAY, |
| 33 | .key_size = sizeof(__u32), | ||
| 34 | .value_size = sizeof(__u32), | ||
| 35 | .max_entries = NR_RESULTS, | 43 | .max_entries = NR_RESULTS, |
| 36 | }; | 44 | }; |
| 37 | 45 | ||
| 38 | struct bpf_map_def SEC("maps") tmp_index_ovr_map = { | 46 | struct { |
| 47 | __u32 type; | ||
| 48 | __u32 max_entries; | ||
| 49 | __u32 *key; | ||
| 50 | int *value; | ||
| 51 | } tmp_index_ovr_map SEC(".maps") = { | ||
| 39 | .type = BPF_MAP_TYPE_ARRAY, | 52 | .type = BPF_MAP_TYPE_ARRAY, |
| 40 | .key_size = sizeof(__u32), | ||
| 41 | .value_size = sizeof(int), | ||
| 42 | .max_entries = 1, | 53 | .max_entries = 1, |
| 43 | }; | 54 | }; |
| 44 | 55 | ||
| 45 | struct bpf_map_def SEC("maps") linum_map = { | 56 | struct { |
| 57 | __u32 type; | ||
| 58 | __u32 max_entries; | ||
| 59 | __u32 *key; | ||
| 60 | __u32 *value; | ||
| 61 | } linum_map SEC(".maps") = { | ||
| 46 | .type = BPF_MAP_TYPE_ARRAY, | 62 | .type = BPF_MAP_TYPE_ARRAY, |
| 47 | .key_size = sizeof(__u32), | ||
| 48 | .value_size = sizeof(__u32), | ||
| 49 | .max_entries = 1, | 63 | .max_entries = 1, |
| 50 | }; | 64 | }; |
| 51 | 65 | ||
| 52 | struct bpf_map_def SEC("maps") data_check_map = { | 66 | struct { |
| 67 | __u32 type; | ||
| 68 | __u32 max_entries; | ||
| 69 | __u32 *key; | ||
| 70 | struct data_check *value; | ||
| 71 | } data_check_map SEC(".maps") = { | ||
| 53 | .type = BPF_MAP_TYPE_ARRAY, | 72 | .type = BPF_MAP_TYPE_ARRAY, |
| 54 | .key_size = sizeof(__u32), | ||
| 55 | .value_size = sizeof(struct data_check), | ||
| 56 | .max_entries = 1, | 73 | .max_entries = 1, |
| 57 | }; | 74 | }; |
| 58 | 75 | ||
diff --git a/tools/testing/selftests/bpf/progs/test_send_signal_kern.c b/tools/testing/selftests/bpf/progs/test_send_signal_kern.c index 45a1a1a2c345..6ac68be5d68b 100644 --- a/tools/testing/selftests/bpf/progs/test_send_signal_kern.c +++ b/tools/testing/selftests/bpf/progs/test_send_signal_kern.c | |||
| @@ -4,24 +4,26 @@ | |||
| 4 | #include <linux/version.h> | 4 | #include <linux/version.h> |
| 5 | #include "bpf_helpers.h" | 5 | #include "bpf_helpers.h" |
| 6 | 6 | ||
| 7 | struct bpf_map_def SEC("maps") info_map = { | 7 | struct { |
| 8 | __u32 type; | ||
| 9 | __u32 max_entries; | ||
| 10 | __u32 *key; | ||
| 11 | __u64 *value; | ||
| 12 | } info_map SEC(".maps") = { | ||
| 8 | .type = BPF_MAP_TYPE_ARRAY, | 13 | .type = BPF_MAP_TYPE_ARRAY, |
| 9 | .key_size = sizeof(__u32), | ||
| 10 | .value_size = sizeof(__u64), | ||
| 11 | .max_entries = 1, | 14 | .max_entries = 1, |
| 12 | }; | 15 | }; |
| 13 | 16 | ||
| 14 | BPF_ANNOTATE_KV_PAIR(info_map, __u32, __u64); | 17 | struct { |
| 15 | 18 | __u32 type; | |
| 16 | struct bpf_map_def SEC("maps") status_map = { | 19 | __u32 max_entries; |
| 20 | __u32 *key; | ||
| 21 | __u64 *value; | ||
| 22 | } status_map SEC(".maps") = { | ||
| 17 | .type = BPF_MAP_TYPE_ARRAY, | 23 | .type = BPF_MAP_TYPE_ARRAY, |
| 18 | .key_size = sizeof(__u32), | ||
| 19 | .value_size = sizeof(__u64), | ||
| 20 | .max_entries = 1, | 24 | .max_entries = 1, |
| 21 | }; | 25 | }; |
| 22 | 26 | ||
| 23 | BPF_ANNOTATE_KV_PAIR(status_map, __u32, __u64); | ||
| 24 | |||
| 25 | SEC("send_signal_demo") | 27 | SEC("send_signal_demo") |
| 26 | int bpf_send_signal_test(void *ctx) | 28 | int bpf_send_signal_test(void *ctx) |
| 27 | { | 29 | { |
diff --git a/tools/testing/selftests/bpf/progs/test_sock_fields_kern.c b/tools/testing/selftests/bpf/progs/test_sock_fields_kern.c index 1c39e4ccb7f1..c3d383d650cb 100644 --- a/tools/testing/selftests/bpf/progs/test_sock_fields_kern.c +++ b/tools/testing/selftests/bpf/progs/test_sock_fields_kern.c | |||
| @@ -27,31 +27,43 @@ enum bpf_linum_array_idx { | |||
| 27 | __NR_BPF_LINUM_ARRAY_IDX, | 27 | __NR_BPF_LINUM_ARRAY_IDX, |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | struct bpf_map_def SEC("maps") addr_map = { | 30 | struct { |
| 31 | __u32 type; | ||
| 32 | __u32 max_entries; | ||
| 33 | __u32 *key; | ||
| 34 | struct sockaddr_in6 *value; | ||
| 35 | } addr_map SEC(".maps") = { | ||
| 31 | .type = BPF_MAP_TYPE_ARRAY, | 36 | .type = BPF_MAP_TYPE_ARRAY, |
| 32 | .key_size = sizeof(__u32), | ||
| 33 | .value_size = sizeof(struct sockaddr_in6), | ||
| 34 | .max_entries = __NR_BPF_ADDR_ARRAY_IDX, | 37 | .max_entries = __NR_BPF_ADDR_ARRAY_IDX, |
| 35 | }; | 38 | }; |
| 36 | 39 | ||
| 37 | struct bpf_map_def SEC("maps") sock_result_map = { | 40 | struct { |
| 41 | __u32 type; | ||
| 42 | __u32 max_entries; | ||
| 43 | __u32 *key; | ||
| 44 | struct bpf_sock *value; | ||
| 45 | } sock_result_map SEC(".maps") = { | ||
| 38 | .type = BPF_MAP_TYPE_ARRAY, | 46 | .type = BPF_MAP_TYPE_ARRAY, |
| 39 | .key_size = sizeof(__u32), | ||
| 40 | .value_size = sizeof(struct bpf_sock), | ||
| 41 | .max_entries = __NR_BPF_RESULT_ARRAY_IDX, | 47 | .max_entries = __NR_BPF_RESULT_ARRAY_IDX, |
| 42 | }; | 48 | }; |
| 43 | 49 | ||
| 44 | struct bpf_map_def SEC("maps") tcp_sock_result_map = { | 50 | struct { |
| 51 | __u32 type; | ||
| 52 | __u32 max_entries; | ||
| 53 | __u32 *key; | ||
| 54 | struct bpf_tcp_sock *value; | ||
| 55 | } tcp_sock_result_map SEC(".maps") = { | ||
| 45 | .type = BPF_MAP_TYPE_ARRAY, | 56 | .type = BPF_MAP_TYPE_ARRAY, |
| 46 | .key_size = sizeof(__u32), | ||
| 47 | .value_size = sizeof(struct bpf_tcp_sock), | ||
| 48 | .max_entries = __NR_BPF_RESULT_ARRAY_IDX, | 57 | .max_entries = __NR_BPF_RESULT_ARRAY_IDX, |
| 49 | }; | 58 | }; |
| 50 | 59 | ||
| 51 | struct bpf_map_def SEC("maps") linum_map = { | 60 | struct { |
| 61 | __u32 type; | ||
| 62 | __u32 max_entries; | ||
| 63 | __u32 *key; | ||
| 64 | __u32 *value; | ||
| 65 | } linum_map SEC(".maps") = { | ||
| 52 | .type = BPF_MAP_TYPE_ARRAY, | 66 | .type = BPF_MAP_TYPE_ARRAY, |
| 53 | .key_size = sizeof(__u32), | ||
| 54 | .value_size = sizeof(__u32), | ||
| 55 | .max_entries = __NR_BPF_LINUM_ARRAY_IDX, | 67 | .max_entries = __NR_BPF_LINUM_ARRAY_IDX, |
| 56 | }; | 68 | }; |
| 57 | 69 | ||
| @@ -60,26 +72,26 @@ struct bpf_spinlock_cnt { | |||
| 60 | __u32 cnt; | 72 | __u32 cnt; |
| 61 | }; | 73 | }; |
| 62 | 74 | ||
| 63 | struct bpf_map_def SEC("maps") sk_pkt_out_cnt = { | 75 | struct { |
| 76 | __u32 type; | ||
| 77 | __u32 map_flags; | ||
| 78 | int *key; | ||
| 79 | struct bpf_spinlock_cnt *value; | ||
| 80 | } sk_pkt_out_cnt SEC(".maps") = { | ||
| 64 | .type = BPF_MAP_TYPE_SK_STORAGE, | 81 | .type = BPF_MAP_TYPE_SK_STORAGE, |
| 65 | .key_size = sizeof(int), | ||
| 66 | .value_size = sizeof(struct bpf_spinlock_cnt), | ||
| 67 | .max_entries = 0, | ||
| 68 | .map_flags = BPF_F_NO_PREALLOC, | 82 | .map_flags = BPF_F_NO_PREALLOC, |
| 69 | }; | 83 | }; |
| 70 | 84 | ||
| 71 | BPF_ANNOTATE_KV_PAIR(sk_pkt_out_cnt, int, struct bpf_spinlock_cnt); | 85 | struct { |
| 72 | 86 | __u32 type; | |
| 73 | struct bpf_map_def SEC("maps") sk_pkt_out_cnt10 = { | 87 | __u32 map_flags; |
| 88 | int *key; | ||
| 89 | struct bpf_spinlock_cnt *value; | ||
| 90 | } sk_pkt_out_cnt10 SEC(".maps") = { | ||
| 74 | .type = BPF_MAP_TYPE_SK_STORAGE, | 91 | .type = BPF_MAP_TYPE_SK_STORAGE, |
| 75 | .key_size = sizeof(int), | ||
| 76 | .value_size = sizeof(struct bpf_spinlock_cnt), | ||
| 77 | .max_entries = 0, | ||
| 78 | .map_flags = BPF_F_NO_PREALLOC, | 92 | .map_flags = BPF_F_NO_PREALLOC, |
| 79 | }; | 93 | }; |
| 80 | 94 | ||
| 81 | BPF_ANNOTATE_KV_PAIR(sk_pkt_out_cnt10, int, struct bpf_spinlock_cnt); | ||
| 82 | |||
| 83 | static bool is_loopback6(__u32 *a6) | 95 | static bool is_loopback6(__u32 *a6) |
| 84 | { | 96 | { |
| 85 | return !a6[0] && !a6[1] && !a6[2] && a6[3] == bpf_htonl(1); | 97 | return !a6[0] && !a6[1] && !a6[2] && a6[3] == bpf_htonl(1); |
diff --git a/tools/testing/selftests/bpf/progs/test_spin_lock.c b/tools/testing/selftests/bpf/progs/test_spin_lock.c index 40f904312090..0a77ae36d981 100644 --- a/tools/testing/selftests/bpf/progs/test_spin_lock.c +++ b/tools/testing/selftests/bpf/progs/test_spin_lock.c | |||
| @@ -10,30 +10,29 @@ struct hmap_elem { | |||
| 10 | int test_padding; | 10 | int test_padding; |
| 11 | }; | 11 | }; |
| 12 | 12 | ||
| 13 | struct bpf_map_def SEC("maps") hmap = { | 13 | struct { |
| 14 | __u32 type; | ||
| 15 | __u32 max_entries; | ||
| 16 | int *key; | ||
| 17 | struct hmap_elem *value; | ||
| 18 | } hmap SEC(".maps") = { | ||
| 14 | .type = BPF_MAP_TYPE_HASH, | 19 | .type = BPF_MAP_TYPE_HASH, |
| 15 | .key_size = sizeof(int), | ||
| 16 | .value_size = sizeof(struct hmap_elem), | ||
| 17 | .max_entries = 1, | 20 | .max_entries = 1, |
| 18 | }; | 21 | }; |
| 19 | 22 | ||
| 20 | BPF_ANNOTATE_KV_PAIR(hmap, int, struct hmap_elem); | ||
| 21 | |||
| 22 | |||
| 23 | struct cls_elem { | 23 | struct cls_elem { |
| 24 | struct bpf_spin_lock lock; | 24 | struct bpf_spin_lock lock; |
| 25 | volatile int cnt; | 25 | volatile int cnt; |
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | struct bpf_map_def SEC("maps") cls_map = { | 28 | struct { |
| 29 | __u32 type; | ||
| 30 | struct bpf_cgroup_storage_key *key; | ||
| 31 | struct cls_elem *value; | ||
| 32 | } cls_map SEC(".maps") = { | ||
| 29 | .type = BPF_MAP_TYPE_CGROUP_STORAGE, | 33 | .type = BPF_MAP_TYPE_CGROUP_STORAGE, |
| 30 | .key_size = sizeof(struct bpf_cgroup_storage_key), | ||
| 31 | .value_size = sizeof(struct cls_elem), | ||
| 32 | }; | 34 | }; |
| 33 | 35 | ||
| 34 | BPF_ANNOTATE_KV_PAIR(cls_map, struct bpf_cgroup_storage_key, | ||
| 35 | struct cls_elem); | ||
| 36 | |||
| 37 | struct bpf_vqueue { | 36 | struct bpf_vqueue { |
| 38 | struct bpf_spin_lock lock; | 37 | struct bpf_spin_lock lock; |
| 39 | /* 4 byte hole */ | 38 | /* 4 byte hole */ |
| @@ -42,14 +41,16 @@ struct bpf_vqueue { | |||
| 42 | unsigned int rate; | 41 | unsigned int rate; |
| 43 | }; | 42 | }; |
| 44 | 43 | ||
| 45 | struct bpf_map_def SEC("maps") vqueue = { | 44 | struct { |
| 45 | __u32 type; | ||
| 46 | __u32 max_entries; | ||
| 47 | int *key; | ||
| 48 | struct bpf_vqueue *value; | ||
| 49 | } vqueue SEC(".maps") = { | ||
| 46 | .type = BPF_MAP_TYPE_ARRAY, | 50 | .type = BPF_MAP_TYPE_ARRAY, |
| 47 | .key_size = sizeof(int), | ||
| 48 | .value_size = sizeof(struct bpf_vqueue), | ||
| 49 | .max_entries = 1, | 51 | .max_entries = 1, |
| 50 | }; | 52 | }; |
| 51 | 53 | ||
| 52 | BPF_ANNOTATE_KV_PAIR(vqueue, int, struct bpf_vqueue); | ||
| 53 | #define CREDIT_PER_NS(delta, rate) (((delta) * rate) >> 20) | 54 | #define CREDIT_PER_NS(delta, rate) (((delta) * rate) >> 20) |
| 54 | 55 | ||
| 55 | SEC("spin_lock_demo") | 56 | SEC("spin_lock_demo") |
diff --git a/tools/testing/selftests/bpf/progs/test_stacktrace_build_id.c b/tools/testing/selftests/bpf/progs/test_stacktrace_build_id.c index d86c281e957f..fcf2280bb60c 100644 --- a/tools/testing/selftests/bpf/progs/test_stacktrace_build_id.c +++ b/tools/testing/selftests/bpf/progs/test_stacktrace_build_id.c | |||
| @@ -8,34 +8,50 @@ | |||
| 8 | #define PERF_MAX_STACK_DEPTH 127 | 8 | #define PERF_MAX_STACK_DEPTH 127 |
| 9 | #endif | 9 | #endif |
| 10 | 10 | ||
| 11 | struct bpf_map_def SEC("maps") control_map = { | 11 | struct { |
| 12 | __u32 type; | ||
| 13 | __u32 max_entries; | ||
| 14 | __u32 *key; | ||
| 15 | __u32 *value; | ||
| 16 | } control_map SEC(".maps") = { | ||
| 12 | .type = BPF_MAP_TYPE_ARRAY, | 17 | .type = BPF_MAP_TYPE_ARRAY, |
| 13 | .key_size = sizeof(__u32), | ||
| 14 | .value_size = sizeof(__u32), | ||
| 15 | .max_entries = 1, | 18 | .max_entries = 1, |
| 16 | }; | 19 | }; |
| 17 | 20 | ||
| 18 | struct bpf_map_def SEC("maps") stackid_hmap = { | 21 | struct { |
| 22 | __u32 type; | ||
| 23 | __u32 max_entries; | ||
| 24 | __u32 *key; | ||
| 25 | __u32 *value; | ||
| 26 | } stackid_hmap SEC(".maps") = { | ||
| 19 | .type = BPF_MAP_TYPE_HASH, | 27 | .type = BPF_MAP_TYPE_HASH, |
| 20 | .key_size = sizeof(__u32), | ||
| 21 | .value_size = sizeof(__u32), | ||
| 22 | .max_entries = 16384, | 28 | .max_entries = 16384, |
| 23 | }; | 29 | }; |
| 24 | 30 | ||
| 25 | struct bpf_map_def SEC("maps") stackmap = { | 31 | typedef struct bpf_stack_build_id stack_trace_t[PERF_MAX_STACK_DEPTH]; |
| 32 | |||
| 33 | struct { | ||
| 34 | __u32 type; | ||
| 35 | __u32 max_entries; | ||
| 36 | __u32 map_flags; | ||
| 37 | __u32 key_size; | ||
| 38 | __u32 value_size; | ||
| 39 | } stackmap SEC(".maps") = { | ||
| 26 | .type = BPF_MAP_TYPE_STACK_TRACE, | 40 | .type = BPF_MAP_TYPE_STACK_TRACE, |
| 27 | .key_size = sizeof(__u32), | ||
| 28 | .value_size = sizeof(struct bpf_stack_build_id) | ||
| 29 | * PERF_MAX_STACK_DEPTH, | ||
| 30 | .max_entries = 128, | 41 | .max_entries = 128, |
| 31 | .map_flags = BPF_F_STACK_BUILD_ID, | 42 | .map_flags = BPF_F_STACK_BUILD_ID, |
| 43 | .key_size = sizeof(__u32), | ||
| 44 | .value_size = sizeof(stack_trace_t), | ||
| 32 | }; | 45 | }; |
| 33 | 46 | ||
| 34 | struct bpf_map_def SEC("maps") stack_amap = { | 47 | struct { |
| 48 | __u32 type; | ||
| 49 | __u32 max_entries; | ||
| 50 | __u32 *key; | ||
| 51 | /* there seems to be a bug in kernel not handling typedef properly */ | ||
| 52 | struct bpf_stack_build_id (*value)[PERF_MAX_STACK_DEPTH]; | ||
| 53 | } stack_amap SEC(".maps") = { | ||
| 35 | .type = BPF_MAP_TYPE_ARRAY, | 54 | .type = BPF_MAP_TYPE_ARRAY, |
| 36 | .key_size = sizeof(__u32), | ||
| 37 | .value_size = sizeof(struct bpf_stack_build_id) | ||
| 38 | * PERF_MAX_STACK_DEPTH, | ||
| 39 | .max_entries = 128, | 55 | .max_entries = 128, |
| 40 | }; | 56 | }; |
| 41 | 57 | ||
diff --git a/tools/testing/selftests/bpf/progs/test_stacktrace_map.c b/tools/testing/selftests/bpf/progs/test_stacktrace_map.c index af111af7ca1a..7ad09adbf648 100644 --- a/tools/testing/selftests/bpf/progs/test_stacktrace_map.c +++ b/tools/testing/selftests/bpf/progs/test_stacktrace_map.c | |||
| @@ -8,31 +8,47 @@ | |||
| 8 | #define PERF_MAX_STACK_DEPTH 127 | 8 | #define PERF_MAX_STACK_DEPTH 127 |
| 9 | #endif | 9 | #endif |
| 10 | 10 | ||
| 11 | struct bpf_map_def SEC("maps") control_map = { | 11 | struct { |
| 12 | __u32 type; | ||
| 13 | __u32 max_entries; | ||
| 14 | __u32 *key; | ||
| 15 | __u32 *value; | ||
| 16 | } control_map SEC(".maps") = { | ||
| 12 | .type = BPF_MAP_TYPE_ARRAY, | 17 | .type = BPF_MAP_TYPE_ARRAY, |
| 13 | .key_size = sizeof(__u32), | ||
| 14 | .value_size = sizeof(__u32), | ||
| 15 | .max_entries = 1, | 18 | .max_entries = 1, |
| 16 | }; | 19 | }; |
| 17 | 20 | ||
| 18 | struct bpf_map_def SEC("maps") stackid_hmap = { | 21 | struct { |
| 22 | __u32 type; | ||
| 23 | __u32 max_entries; | ||
| 24 | __u32 *key; | ||
| 25 | __u32 *value; | ||
| 26 | } stackid_hmap SEC(".maps") = { | ||
| 19 | .type = BPF_MAP_TYPE_HASH, | 27 | .type = BPF_MAP_TYPE_HASH, |
| 20 | .key_size = sizeof(__u32), | ||
| 21 | .value_size = sizeof(__u32), | ||
| 22 | .max_entries = 16384, | 28 | .max_entries = 16384, |
| 23 | }; | 29 | }; |
| 24 | 30 | ||
| 25 | struct bpf_map_def SEC("maps") stackmap = { | 31 | typedef __u64 stack_trace_t[PERF_MAX_STACK_DEPTH]; |
| 32 | |||
| 33 | struct { | ||
| 34 | __u32 type; | ||
| 35 | __u32 max_entries; | ||
| 36 | __u32 key_size; | ||
| 37 | __u32 value_size; | ||
| 38 | } stackmap SEC(".maps") = { | ||
| 26 | .type = BPF_MAP_TYPE_STACK_TRACE, | 39 | .type = BPF_MAP_TYPE_STACK_TRACE, |
| 27 | .key_size = sizeof(__u32), | ||
| 28 | .value_size = sizeof(__u64) * PERF_MAX_STACK_DEPTH, | ||
| 29 | .max_entries = 16384, | 40 | .max_entries = 16384, |
| 41 | .key_size = sizeof(__u32), | ||
| 42 | .value_size = sizeof(stack_trace_t), | ||
| 30 | }; | 43 | }; |
| 31 | 44 | ||
| 32 | struct bpf_map_def SEC("maps") stack_amap = { | 45 | struct { |
| 46 | __u32 type; | ||
| 47 | __u32 max_entries; | ||
| 48 | __u32 *key; | ||
| 49 | __u64 (*value)[PERF_MAX_STACK_DEPTH]; | ||
| 50 | } stack_amap SEC(".maps") = { | ||
| 33 | .type = BPF_MAP_TYPE_ARRAY, | 51 | .type = BPF_MAP_TYPE_ARRAY, |
| 34 | .key_size = sizeof(__u32), | ||
| 35 | .value_size = sizeof(__u64) * PERF_MAX_STACK_DEPTH, | ||
| 36 | .max_entries = 16384, | 52 | .max_entries = 16384, |
| 37 | }; | 53 | }; |
| 38 | 54 | ||
diff --git a/tools/testing/selftests/bpf/progs/test_sysctl_loop1.c b/tools/testing/selftests/bpf/progs/test_sysctl_loop1.c new file mode 100644 index 000000000000..608a06871572 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_sysctl_loop1.c | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (c) 2019 Facebook | ||
| 3 | |||
| 4 | #include <stdint.h> | ||
| 5 | #include <string.h> | ||
| 6 | |||
| 7 | #include <linux/stddef.h> | ||
| 8 | #include <linux/bpf.h> | ||
| 9 | |||
| 10 | #include "bpf_helpers.h" | ||
| 11 | |||
| 12 | #ifndef ARRAY_SIZE | ||
| 13 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
| 14 | #endif | ||
| 15 | |||
| 16 | /* tcp_mem sysctl has only 3 ints, but this test is doing TCP_MEM_LOOPS */ | ||
| 17 | #define TCP_MEM_LOOPS 28 /* because 30 doesn't fit into 512 bytes of stack */ | ||
| 18 | #define MAX_ULONG_STR_LEN 7 | ||
| 19 | #define MAX_VALUE_STR_LEN (TCP_MEM_LOOPS * MAX_ULONG_STR_LEN) | ||
| 20 | |||
| 21 | static __always_inline int is_tcp_mem(struct bpf_sysctl *ctx) | ||
| 22 | { | ||
| 23 | volatile char tcp_mem_name[] = "net/ipv4/tcp_mem/very_very_very_very_long_pointless_string"; | ||
| 24 | unsigned char i; | ||
| 25 | char name[64]; | ||
| 26 | int ret; | ||
| 27 | |||
| 28 | memset(name, 0, sizeof(name)); | ||
| 29 | ret = bpf_sysctl_get_name(ctx, name, sizeof(name), 0); | ||
| 30 | if (ret < 0 || ret != sizeof(tcp_mem_name) - 1) | ||
| 31 | return 0; | ||
| 32 | |||
| 33 | #pragma clang loop unroll(disable) | ||
| 34 | for (i = 0; i < sizeof(tcp_mem_name); ++i) | ||
| 35 | if (name[i] != tcp_mem_name[i]) | ||
| 36 | return 0; | ||
| 37 | |||
| 38 | return 1; | ||
| 39 | } | ||
| 40 | |||
| 41 | SEC("cgroup/sysctl") | ||
| 42 | int sysctl_tcp_mem(struct bpf_sysctl *ctx) | ||
| 43 | { | ||
| 44 | unsigned long tcp_mem[TCP_MEM_LOOPS] = {}; | ||
| 45 | char value[MAX_VALUE_STR_LEN]; | ||
| 46 | unsigned char i, off = 0; | ||
| 47 | int ret; | ||
| 48 | |||
| 49 | if (ctx->write) | ||
| 50 | return 0; | ||
| 51 | |||
| 52 | if (!is_tcp_mem(ctx)) | ||
| 53 | return 0; | ||
| 54 | |||
| 55 | ret = bpf_sysctl_get_current_value(ctx, value, MAX_VALUE_STR_LEN); | ||
| 56 | if (ret < 0 || ret >= MAX_VALUE_STR_LEN) | ||
| 57 | return 0; | ||
| 58 | |||
| 59 | #pragma clang loop unroll(disable) | ||
| 60 | for (i = 0; i < ARRAY_SIZE(tcp_mem); ++i) { | ||
| 61 | ret = bpf_strtoul(value + off, MAX_ULONG_STR_LEN, 0, | ||
| 62 | tcp_mem + i); | ||
| 63 | if (ret <= 0 || ret > MAX_ULONG_STR_LEN) | ||
| 64 | return 0; | ||
| 65 | off += ret & MAX_ULONG_STR_LEN; | ||
| 66 | } | ||
| 67 | |||
| 68 | return tcp_mem[0] < tcp_mem[1] && tcp_mem[1] < tcp_mem[2]; | ||
| 69 | } | ||
| 70 | |||
| 71 | char _license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/progs/test_sysctl_loop2.c b/tools/testing/selftests/bpf/progs/test_sysctl_loop2.c new file mode 100644 index 000000000000..cb201cbe11e7 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_sysctl_loop2.c | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (c) 2019 Facebook | ||
| 3 | |||
| 4 | #include <stdint.h> | ||
| 5 | #include <string.h> | ||
| 6 | |||
| 7 | #include <linux/stddef.h> | ||
| 8 | #include <linux/bpf.h> | ||
| 9 | |||
| 10 | #include "bpf_helpers.h" | ||
| 11 | |||
| 12 | #ifndef ARRAY_SIZE | ||
| 13 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
| 14 | #endif | ||
| 15 | |||
| 16 | /* tcp_mem sysctl has only 3 ints, but this test is doing TCP_MEM_LOOPS */ | ||
| 17 | #define TCP_MEM_LOOPS 20 /* because 30 doesn't fit into 512 bytes of stack */ | ||
| 18 | #define MAX_ULONG_STR_LEN 7 | ||
| 19 | #define MAX_VALUE_STR_LEN (TCP_MEM_LOOPS * MAX_ULONG_STR_LEN) | ||
| 20 | |||
| 21 | static __attribute__((noinline)) int is_tcp_mem(struct bpf_sysctl *ctx) | ||
| 22 | { | ||
| 23 | volatile char tcp_mem_name[] = "net/ipv4/tcp_mem/very_very_very_very_long_pointless_string_to_stress_byte_loop"; | ||
| 24 | unsigned char i; | ||
| 25 | char name[64]; | ||
| 26 | int ret; | ||
| 27 | |||
| 28 | memset(name, 0, sizeof(name)); | ||
| 29 | ret = bpf_sysctl_get_name(ctx, name, sizeof(name), 0); | ||
| 30 | if (ret < 0 || ret != sizeof(tcp_mem_name) - 1) | ||
| 31 | return 0; | ||
| 32 | |||
| 33 | #pragma clang loop unroll(disable) | ||
| 34 | for (i = 0; i < sizeof(tcp_mem_name); ++i) | ||
| 35 | if (name[i] != tcp_mem_name[i]) | ||
| 36 | return 0; | ||
| 37 | |||
| 38 | return 1; | ||
| 39 | } | ||
| 40 | |||
| 41 | |||
| 42 | SEC("cgroup/sysctl") | ||
| 43 | int sysctl_tcp_mem(struct bpf_sysctl *ctx) | ||
| 44 | { | ||
| 45 | unsigned long tcp_mem[TCP_MEM_LOOPS] = {}; | ||
| 46 | char value[MAX_VALUE_STR_LEN]; | ||
| 47 | unsigned char i, off = 0; | ||
| 48 | int ret; | ||
| 49 | |||
| 50 | if (ctx->write) | ||
| 51 | return 0; | ||
| 52 | |||
| 53 | if (!is_tcp_mem(ctx)) | ||
| 54 | return 0; | ||
| 55 | |||
| 56 | ret = bpf_sysctl_get_current_value(ctx, value, MAX_VALUE_STR_LEN); | ||
| 57 | if (ret < 0 || ret >= MAX_VALUE_STR_LEN) | ||
| 58 | return 0; | ||
| 59 | |||
| 60 | #pragma clang loop unroll(disable) | ||
| 61 | for (i = 0; i < ARRAY_SIZE(tcp_mem); ++i) { | ||
| 62 | ret = bpf_strtoul(value + off, MAX_ULONG_STR_LEN, 0, | ||
| 63 | tcp_mem + i); | ||
| 64 | if (ret <= 0 || ret > MAX_ULONG_STR_LEN) | ||
| 65 | return 0; | ||
| 66 | off += ret & MAX_ULONG_STR_LEN; | ||
| 67 | } | ||
| 68 | |||
| 69 | return tcp_mem[0] < tcp_mem[1] && tcp_mem[1] < tcp_mem[2]; | ||
| 70 | } | ||
| 71 | |||
| 72 | char _license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/progs/test_sysctl_prog.c b/tools/testing/selftests/bpf/progs/test_sysctl_prog.c index a295cad805d7..5cbbff416998 100644 --- a/tools/testing/selftests/bpf/progs/test_sysctl_prog.c +++ b/tools/testing/selftests/bpf/progs/test_sysctl_prog.c | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include <linux/bpf.h> | 8 | #include <linux/bpf.h> |
| 9 | 9 | ||
| 10 | #include "bpf_helpers.h" | 10 | #include "bpf_helpers.h" |
| 11 | #include "bpf_util.h" | ||
| 12 | 11 | ||
| 13 | /* Max supported length of a string with unsigned long in base 10 (pow2 - 1). */ | 12 | /* Max supported length of a string with unsigned long in base 10 (pow2 - 1). */ |
| 14 | #define MAX_ULONG_STR_LEN 0xF | 13 | #define MAX_ULONG_STR_LEN 0xF |
| @@ -16,6 +15,10 @@ | |||
| 16 | /* Max supported length of sysctl value string (pow2). */ | 15 | /* Max supported length of sysctl value string (pow2). */ |
| 17 | #define MAX_VALUE_STR_LEN 0x40 | 16 | #define MAX_VALUE_STR_LEN 0x40 |
| 18 | 17 | ||
| 18 | #ifndef ARRAY_SIZE | ||
| 19 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
| 20 | #endif | ||
| 21 | |||
| 19 | static __always_inline int is_tcp_mem(struct bpf_sysctl *ctx) | 22 | static __always_inline int is_tcp_mem(struct bpf_sysctl *ctx) |
| 20 | { | 23 | { |
| 21 | char tcp_mem_name[] = "net/ipv4/tcp_mem"; | 24 | char tcp_mem_name[] = "net/ipv4/tcp_mem"; |
diff --git a/tools/testing/selftests/bpf/progs/test_tcp_estats.c b/tools/testing/selftests/bpf/progs/test_tcp_estats.c index bee3bbecc0c4..df98f7e32832 100644 --- a/tools/testing/selftests/bpf/progs/test_tcp_estats.c +++ b/tools/testing/selftests/bpf/progs/test_tcp_estats.c | |||
| @@ -148,10 +148,13 @@ struct tcp_estats_basic_event { | |||
| 148 | struct tcp_estats_conn_id conn_id; | 148 | struct tcp_estats_conn_id conn_id; |
| 149 | }; | 149 | }; |
| 150 | 150 | ||
| 151 | struct bpf_map_def SEC("maps") ev_record_map = { | 151 | struct { |
| 152 | __u32 type; | ||
| 153 | __u32 max_entries; | ||
| 154 | __u32 *key; | ||
| 155 | struct tcp_estats_basic_event *value; | ||
| 156 | } ev_record_map SEC(".maps") = { | ||
| 152 | .type = BPF_MAP_TYPE_HASH, | 157 | .type = BPF_MAP_TYPE_HASH, |
| 153 | .key_size = sizeof(__u32), | ||
| 154 | .value_size = sizeof(struct tcp_estats_basic_event), | ||
| 155 | .max_entries = 1024, | 158 | .max_entries = 1024, |
| 156 | }; | 159 | }; |
| 157 | 160 | ||
diff --git a/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c b/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c index c7c3240e0dd4..38e10c9fd996 100644 --- a/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c +++ b/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c | |||
| @@ -14,17 +14,23 @@ | |||
| 14 | #include "bpf_endian.h" | 14 | #include "bpf_endian.h" |
| 15 | #include "test_tcpbpf.h" | 15 | #include "test_tcpbpf.h" |
| 16 | 16 | ||
| 17 | struct bpf_map_def SEC("maps") global_map = { | 17 | struct { |
| 18 | __u32 type; | ||
| 19 | __u32 max_entries; | ||
| 20 | __u32 *key; | ||
| 21 | struct tcpbpf_globals *value; | ||
| 22 | } global_map SEC(".maps") = { | ||
| 18 | .type = BPF_MAP_TYPE_ARRAY, | 23 | .type = BPF_MAP_TYPE_ARRAY, |
| 19 | .key_size = sizeof(__u32), | ||
| 20 | .value_size = sizeof(struct tcpbpf_globals), | ||
| 21 | .max_entries = 4, | 24 | .max_entries = 4, |
| 22 | }; | 25 | }; |
| 23 | 26 | ||
| 24 | struct bpf_map_def SEC("maps") sockopt_results = { | 27 | struct { |
| 28 | __u32 type; | ||
| 29 | __u32 max_entries; | ||
| 30 | __u32 *key; | ||
| 31 | int *value; | ||
| 32 | } sockopt_results SEC(".maps") = { | ||
| 25 | .type = BPF_MAP_TYPE_ARRAY, | 33 | .type = BPF_MAP_TYPE_ARRAY, |
| 26 | .key_size = sizeof(__u32), | ||
| 27 | .value_size = sizeof(int), | ||
| 28 | .max_entries = 2, | 34 | .max_entries = 2, |
| 29 | }; | 35 | }; |
| 30 | 36 | ||
diff --git a/tools/testing/selftests/bpf/progs/test_tcpnotify_kern.c b/tools/testing/selftests/bpf/progs/test_tcpnotify_kern.c index ec6db6e64c41..d073d37d4e27 100644 --- a/tools/testing/selftests/bpf/progs/test_tcpnotify_kern.c +++ b/tools/testing/selftests/bpf/progs/test_tcpnotify_kern.c | |||
| @@ -14,18 +14,26 @@ | |||
| 14 | #include "bpf_endian.h" | 14 | #include "bpf_endian.h" |
| 15 | #include "test_tcpnotify.h" | 15 | #include "test_tcpnotify.h" |
| 16 | 16 | ||
| 17 | struct bpf_map_def SEC("maps") global_map = { | 17 | struct { |
| 18 | __u32 type; | ||
| 19 | __u32 max_entries; | ||
| 20 | __u32 *key; | ||
| 21 | struct tcpnotify_globals *value; | ||
| 22 | } global_map SEC(".maps") = { | ||
| 18 | .type = BPF_MAP_TYPE_ARRAY, | 23 | .type = BPF_MAP_TYPE_ARRAY, |
| 19 | .key_size = sizeof(__u32), | ||
| 20 | .value_size = sizeof(struct tcpnotify_globals), | ||
| 21 | .max_entries = 4, | 24 | .max_entries = 4, |
| 22 | }; | 25 | }; |
| 23 | 26 | ||
| 24 | struct bpf_map_def SEC("maps") perf_event_map = { | 27 | struct { |
| 28 | __u32 type; | ||
| 29 | __u32 max_entries; | ||
| 30 | __u32 key_size; | ||
| 31 | __u32 value_size; | ||
| 32 | } perf_event_map SEC(".maps") = { | ||
| 25 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, | 33 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, |
| 34 | .max_entries = 2, | ||
| 26 | .key_size = sizeof(int), | 35 | .key_size = sizeof(int), |
| 27 | .value_size = sizeof(__u32), | 36 | .value_size = sizeof(__u32), |
| 28 | .max_entries = 2, | ||
| 29 | }; | 37 | }; |
| 30 | 38 | ||
| 31 | int _version SEC("version") = 1; | 39 | int _version SEC("version") = 1; |
diff --git a/tools/testing/selftests/bpf/progs/test_xdp.c b/tools/testing/selftests/bpf/progs/test_xdp.c index 5e7df8bb5b5d..ec3d2c1c8cf9 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp.c +++ b/tools/testing/selftests/bpf/progs/test_xdp.c | |||
| @@ -22,17 +22,23 @@ | |||
| 22 | 22 | ||
| 23 | int _version SEC("version") = 1; | 23 | int _version SEC("version") = 1; |
| 24 | 24 | ||
| 25 | struct bpf_map_def SEC("maps") rxcnt = { | 25 | struct { |
| 26 | __u32 type; | ||
| 27 | __u32 max_entries; | ||
| 28 | __u32 *key; | ||
| 29 | __u64 *value; | ||
| 30 | } rxcnt SEC(".maps") = { | ||
| 26 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, | 31 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, |
| 27 | .key_size = sizeof(__u32), | ||
| 28 | .value_size = sizeof(__u64), | ||
| 29 | .max_entries = 256, | 32 | .max_entries = 256, |
| 30 | }; | 33 | }; |
| 31 | 34 | ||
| 32 | struct bpf_map_def SEC("maps") vip2tnl = { | 35 | struct { |
| 36 | __u32 type; | ||
| 37 | __u32 max_entries; | ||
| 38 | struct vip *key; | ||
| 39 | struct iptnl_info *value; | ||
| 40 | } vip2tnl SEC(".maps") = { | ||
| 33 | .type = BPF_MAP_TYPE_HASH, | 41 | .type = BPF_MAP_TYPE_HASH, |
| 34 | .key_size = sizeof(struct vip), | ||
| 35 | .value_size = sizeof(struct iptnl_info), | ||
| 36 | .max_entries = MAX_IPTNL_ENTRIES, | 42 | .max_entries = MAX_IPTNL_ENTRIES, |
| 37 | }; | 43 | }; |
| 38 | 44 | ||
diff --git a/tools/testing/selftests/bpf/progs/test_xdp_loop.c b/tools/testing/selftests/bpf/progs/test_xdp_loop.c new file mode 100644 index 000000000000..7fa4677df22e --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_xdp_loop.c | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (c) 2019 Facebook | ||
| 3 | #include <stddef.h> | ||
| 4 | #include <string.h> | ||
| 5 | #include <linux/bpf.h> | ||
| 6 | #include <linux/if_ether.h> | ||
| 7 | #include <linux/if_packet.h> | ||
| 8 | #include <linux/ip.h> | ||
| 9 | #include <linux/ipv6.h> | ||
| 10 | #include <linux/in.h> | ||
| 11 | #include <linux/udp.h> | ||
| 12 | #include <linux/tcp.h> | ||
| 13 | #include <linux/pkt_cls.h> | ||
| 14 | #include <sys/socket.h> | ||
| 15 | #include "bpf_helpers.h" | ||
| 16 | #include "bpf_endian.h" | ||
| 17 | #include "test_iptunnel_common.h" | ||
| 18 | |||
| 19 | int _version SEC("version") = 1; | ||
| 20 | |||
| 21 | struct bpf_map_def SEC("maps") rxcnt = { | ||
| 22 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, | ||
| 23 | .key_size = sizeof(__u32), | ||
| 24 | .value_size = sizeof(__u64), | ||
| 25 | .max_entries = 256, | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct bpf_map_def SEC("maps") vip2tnl = { | ||
| 29 | .type = BPF_MAP_TYPE_HASH, | ||
| 30 | .key_size = sizeof(struct vip), | ||
| 31 | .value_size = sizeof(struct iptnl_info), | ||
| 32 | .max_entries = MAX_IPTNL_ENTRIES, | ||
| 33 | }; | ||
| 34 | |||
| 35 | static __always_inline void count_tx(__u32 protocol) | ||
| 36 | { | ||
| 37 | __u64 *rxcnt_count; | ||
| 38 | |||
| 39 | rxcnt_count = bpf_map_lookup_elem(&rxcnt, &protocol); | ||
| 40 | if (rxcnt_count) | ||
| 41 | *rxcnt_count += 1; | ||
| 42 | } | ||
| 43 | |||
| 44 | static __always_inline int get_dport(void *trans_data, void *data_end, | ||
| 45 | __u8 protocol) | ||
| 46 | { | ||
| 47 | struct tcphdr *th; | ||
| 48 | struct udphdr *uh; | ||
| 49 | |||
| 50 | switch (protocol) { | ||
| 51 | case IPPROTO_TCP: | ||
| 52 | th = (struct tcphdr *)trans_data; | ||
| 53 | if (th + 1 > data_end) | ||
| 54 | return -1; | ||
| 55 | return th->dest; | ||
| 56 | case IPPROTO_UDP: | ||
| 57 | uh = (struct udphdr *)trans_data; | ||
| 58 | if (uh + 1 > data_end) | ||
| 59 | return -1; | ||
| 60 | return uh->dest; | ||
| 61 | default: | ||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | static __always_inline void set_ethhdr(struct ethhdr *new_eth, | ||
| 67 | const struct ethhdr *old_eth, | ||
| 68 | const struct iptnl_info *tnl, | ||
| 69 | __be16 h_proto) | ||
| 70 | { | ||
| 71 | memcpy(new_eth->h_source, old_eth->h_dest, sizeof(new_eth->h_source)); | ||
| 72 | memcpy(new_eth->h_dest, tnl->dmac, sizeof(new_eth->h_dest)); | ||
| 73 | new_eth->h_proto = h_proto; | ||
| 74 | } | ||
| 75 | |||
| 76 | static __always_inline int handle_ipv4(struct xdp_md *xdp) | ||
| 77 | { | ||
| 78 | void *data_end = (void *)(long)xdp->data_end; | ||
| 79 | void *data = (void *)(long)xdp->data; | ||
| 80 | struct iptnl_info *tnl; | ||
| 81 | struct ethhdr *new_eth; | ||
| 82 | struct ethhdr *old_eth; | ||
| 83 | struct iphdr *iph = data + sizeof(struct ethhdr); | ||
| 84 | __u16 *next_iph; | ||
| 85 | __u16 payload_len; | ||
| 86 | struct vip vip = {}; | ||
| 87 | int dport; | ||
| 88 | __u32 csum = 0; | ||
| 89 | int i; | ||
| 90 | |||
| 91 | if (iph + 1 > data_end) | ||
| 92 | return XDP_DROP; | ||
| 93 | |||
| 94 | dport = get_dport(iph + 1, data_end, iph->protocol); | ||
| 95 | if (dport == -1) | ||
| 96 | return XDP_DROP; | ||
| 97 | |||
| 98 | vip.protocol = iph->protocol; | ||
| 99 | vip.family = AF_INET; | ||
| 100 | vip.daddr.v4 = iph->daddr; | ||
| 101 | vip.dport = dport; | ||
| 102 | payload_len = bpf_ntohs(iph->tot_len); | ||
| 103 | |||
| 104 | tnl = bpf_map_lookup_elem(&vip2tnl, &vip); | ||
| 105 | /* It only does v4-in-v4 */ | ||
| 106 | if (!tnl || tnl->family != AF_INET) | ||
| 107 | return XDP_PASS; | ||
| 108 | |||
| 109 | if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(struct iphdr))) | ||
| 110 | return XDP_DROP; | ||
| 111 | |||
| 112 | data = (void *)(long)xdp->data; | ||
| 113 | data_end = (void *)(long)xdp->data_end; | ||
| 114 | |||
| 115 | new_eth = data; | ||
| 116 | iph = data + sizeof(*new_eth); | ||
| 117 | old_eth = data + sizeof(*iph); | ||
| 118 | |||
| 119 | if (new_eth + 1 > data_end || | ||
| 120 | old_eth + 1 > data_end || | ||
| 121 | iph + 1 > data_end) | ||
| 122 | return XDP_DROP; | ||
| 123 | |||
| 124 | set_ethhdr(new_eth, old_eth, tnl, bpf_htons(ETH_P_IP)); | ||
| 125 | |||
| 126 | iph->version = 4; | ||
| 127 | iph->ihl = sizeof(*iph) >> 2; | ||
| 128 | iph->frag_off = 0; | ||
| 129 | iph->protocol = IPPROTO_IPIP; | ||
| 130 | iph->check = 0; | ||
| 131 | iph->tos = 0; | ||
| 132 | iph->tot_len = bpf_htons(payload_len + sizeof(*iph)); | ||
| 133 | iph->daddr = tnl->daddr.v4; | ||
| 134 | iph->saddr = tnl->saddr.v4; | ||
| 135 | iph->ttl = 8; | ||
| 136 | |||
| 137 | next_iph = (__u16 *)iph; | ||
| 138 | #pragma clang loop unroll(disable) | ||
| 139 | for (i = 0; i < sizeof(*iph) >> 1; i++) | ||
| 140 | csum += *next_iph++; | ||
| 141 | |||
| 142 | iph->check = ~((csum & 0xffff) + (csum >> 16)); | ||
| 143 | |||
| 144 | count_tx(vip.protocol); | ||
| 145 | |||
| 146 | return XDP_TX; | ||
| 147 | } | ||
| 148 | |||
| 149 | static __always_inline int handle_ipv6(struct xdp_md *xdp) | ||
| 150 | { | ||
| 151 | void *data_end = (void *)(long)xdp->data_end; | ||
| 152 | void *data = (void *)(long)xdp->data; | ||
| 153 | struct iptnl_info *tnl; | ||
| 154 | struct ethhdr *new_eth; | ||
| 155 | struct ethhdr *old_eth; | ||
| 156 | struct ipv6hdr *ip6h = data + sizeof(struct ethhdr); | ||
| 157 | __u16 payload_len; | ||
| 158 | struct vip vip = {}; | ||
| 159 | int dport; | ||
| 160 | |||
| 161 | if (ip6h + 1 > data_end) | ||
| 162 | return XDP_DROP; | ||
| 163 | |||
| 164 | dport = get_dport(ip6h + 1, data_end, ip6h->nexthdr); | ||
| 165 | if (dport == -1) | ||
| 166 | return XDP_DROP; | ||
| 167 | |||
| 168 | vip.protocol = ip6h->nexthdr; | ||
| 169 | vip.family = AF_INET6; | ||
| 170 | memcpy(vip.daddr.v6, ip6h->daddr.s6_addr32, sizeof(vip.daddr)); | ||
| 171 | vip.dport = dport; | ||
| 172 | payload_len = ip6h->payload_len; | ||
| 173 | |||
| 174 | tnl = bpf_map_lookup_elem(&vip2tnl, &vip); | ||
| 175 | /* It only does v6-in-v6 */ | ||
| 176 | if (!tnl || tnl->family != AF_INET6) | ||
| 177 | return XDP_PASS; | ||
| 178 | |||
| 179 | if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(struct ipv6hdr))) | ||
| 180 | return XDP_DROP; | ||
| 181 | |||
| 182 | data = (void *)(long)xdp->data; | ||
| 183 | data_end = (void *)(long)xdp->data_end; | ||
| 184 | |||
| 185 | new_eth = data; | ||
| 186 | ip6h = data + sizeof(*new_eth); | ||
| 187 | old_eth = data + sizeof(*ip6h); | ||
| 188 | |||
| 189 | if (new_eth + 1 > data_end || old_eth + 1 > data_end || | ||
| 190 | ip6h + 1 > data_end) | ||
| 191 | return XDP_DROP; | ||
| 192 | |||
| 193 | set_ethhdr(new_eth, old_eth, tnl, bpf_htons(ETH_P_IPV6)); | ||
| 194 | |||
| 195 | ip6h->version = 6; | ||
| 196 | ip6h->priority = 0; | ||
| 197 | memset(ip6h->flow_lbl, 0, sizeof(ip6h->flow_lbl)); | ||
| 198 | ip6h->payload_len = bpf_htons(bpf_ntohs(payload_len) + sizeof(*ip6h)); | ||
| 199 | ip6h->nexthdr = IPPROTO_IPV6; | ||
| 200 | ip6h->hop_limit = 8; | ||
| 201 | memcpy(ip6h->saddr.s6_addr32, tnl->saddr.v6, sizeof(tnl->saddr.v6)); | ||
| 202 | memcpy(ip6h->daddr.s6_addr32, tnl->daddr.v6, sizeof(tnl->daddr.v6)); | ||
| 203 | |||
| 204 | count_tx(vip.protocol); | ||
| 205 | |||
| 206 | return XDP_TX; | ||
| 207 | } | ||
| 208 | |||
| 209 | SEC("xdp_tx_iptunnel") | ||
| 210 | int _xdp_tx_iptunnel(struct xdp_md *xdp) | ||
| 211 | { | ||
| 212 | void *data_end = (void *)(long)xdp->data_end; | ||
| 213 | void *data = (void *)(long)xdp->data; | ||
| 214 | struct ethhdr *eth = data; | ||
| 215 | __u16 h_proto; | ||
| 216 | |||
| 217 | if (eth + 1 > data_end) | ||
| 218 | return XDP_DROP; | ||
| 219 | |||
| 220 | h_proto = eth->h_proto; | ||
| 221 | |||
| 222 | if (h_proto == bpf_htons(ETH_P_IP)) | ||
| 223 | return handle_ipv4(xdp); | ||
| 224 | else if (h_proto == bpf_htons(ETH_P_IPV6)) | ||
| 225 | |||
| 226 | return handle_ipv6(xdp); | ||
| 227 | else | ||
| 228 | return XDP_DROP; | ||
| 229 | } | ||
| 230 | |||
| 231 | char _license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/progs/test_xdp_noinline.c b/tools/testing/selftests/bpf/progs/test_xdp_noinline.c index 4fe6aaad22a4..d2eddb5553d1 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_noinline.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_noinline.c | |||
| @@ -163,52 +163,66 @@ struct lb_stats { | |||
| 163 | __u64 v1; | 163 | __u64 v1; |
| 164 | }; | 164 | }; |
| 165 | 165 | ||
| 166 | struct bpf_map_def __attribute__ ((section("maps"), used)) vip_map = { | 166 | struct { |
| 167 | __u32 type; | ||
| 168 | __u32 max_entries; | ||
| 169 | struct vip_definition *key; | ||
| 170 | struct vip_meta *value; | ||
| 171 | } vip_map SEC(".maps") = { | ||
| 167 | .type = BPF_MAP_TYPE_HASH, | 172 | .type = BPF_MAP_TYPE_HASH, |
| 168 | .key_size = sizeof(struct vip_definition), | ||
| 169 | .value_size = sizeof(struct vip_meta), | ||
| 170 | .max_entries = 512, | 173 | .max_entries = 512, |
| 171 | .map_flags = 0, | ||
| 172 | }; | 174 | }; |
| 173 | 175 | ||
| 174 | struct bpf_map_def __attribute__ ((section("maps"), used)) lru_cache = { | 176 | struct { |
| 177 | __u32 type; | ||
| 178 | __u32 max_entries; | ||
| 179 | __u32 map_flags; | ||
| 180 | struct flow_key *key; | ||
| 181 | struct real_pos_lru *value; | ||
| 182 | } lru_cache SEC(".maps") = { | ||
| 175 | .type = BPF_MAP_TYPE_LRU_HASH, | 183 | .type = BPF_MAP_TYPE_LRU_HASH, |
| 176 | .key_size = sizeof(struct flow_key), | ||
| 177 | .value_size = sizeof(struct real_pos_lru), | ||
| 178 | .max_entries = 300, | 184 | .max_entries = 300, |
| 179 | .map_flags = 1U << 1, | 185 | .map_flags = 1U << 1, |
| 180 | }; | 186 | }; |
| 181 | 187 | ||
| 182 | struct bpf_map_def __attribute__ ((section("maps"), used)) ch_rings = { | 188 | struct { |
| 189 | __u32 type; | ||
| 190 | __u32 max_entries; | ||
| 191 | __u32 *key; | ||
| 192 | __u32 *value; | ||
| 193 | } ch_rings SEC(".maps") = { | ||
| 183 | .type = BPF_MAP_TYPE_ARRAY, | 194 | .type = BPF_MAP_TYPE_ARRAY, |
| 184 | .key_size = sizeof(__u32), | ||
| 185 | .value_size = sizeof(__u32), | ||
| 186 | .max_entries = 12 * 655, | 195 | .max_entries = 12 * 655, |
| 187 | .map_flags = 0, | ||
| 188 | }; | 196 | }; |
| 189 | 197 | ||
| 190 | struct bpf_map_def __attribute__ ((section("maps"), used)) reals = { | 198 | struct { |
| 199 | __u32 type; | ||
| 200 | __u32 max_entries; | ||
| 201 | __u32 *key; | ||
| 202 | struct real_definition *value; | ||
| 203 | } reals SEC(".maps") = { | ||
| 191 | .type = BPF_MAP_TYPE_ARRAY, | 204 | .type = BPF_MAP_TYPE_ARRAY, |
| 192 | .key_size = sizeof(__u32), | ||
| 193 | .value_size = sizeof(struct real_definition), | ||
| 194 | .max_entries = 40, | 205 | .max_entries = 40, |
| 195 | .map_flags = 0, | ||
| 196 | }; | 206 | }; |
| 197 | 207 | ||
| 198 | struct bpf_map_def __attribute__ ((section("maps"), used)) stats = { | 208 | struct { |
| 209 | __u32 type; | ||
| 210 | __u32 max_entries; | ||
| 211 | __u32 *key; | ||
| 212 | struct lb_stats *value; | ||
| 213 | } stats SEC(".maps") = { | ||
| 199 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, | 214 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, |
| 200 | .key_size = sizeof(__u32), | ||
| 201 | .value_size = sizeof(struct lb_stats), | ||
| 202 | .max_entries = 515, | 215 | .max_entries = 515, |
| 203 | .map_flags = 0, | ||
| 204 | }; | 216 | }; |
| 205 | 217 | ||
| 206 | struct bpf_map_def __attribute__ ((section("maps"), used)) ctl_array = { | 218 | struct { |
| 219 | __u32 type; | ||
| 220 | __u32 max_entries; | ||
| 221 | __u32 *key; | ||
| 222 | struct ctl_value *value; | ||
| 223 | } ctl_array SEC(".maps") = { | ||
| 207 | .type = BPF_MAP_TYPE_ARRAY, | 224 | .type = BPF_MAP_TYPE_ARRAY, |
| 208 | .key_size = sizeof(__u32), | ||
| 209 | .value_size = sizeof(struct ctl_value), | ||
| 210 | .max_entries = 16, | 225 | .max_entries = 16, |
| 211 | .map_flags = 0, | ||
| 212 | }; | 226 | }; |
| 213 | 227 | ||
| 214 | struct eth_hdr { | 228 | struct eth_hdr { |
diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c index 289daf54dec4..8351cb5f4a20 100644 --- a/tools/testing/selftests/bpf/test_btf.c +++ b/tools/testing/selftests/bpf/test_btf.c | |||
| @@ -4016,13 +4016,9 @@ struct btf_file_test { | |||
| 4016 | }; | 4016 | }; |
| 4017 | 4017 | ||
| 4018 | static struct btf_file_test file_tests[] = { | 4018 | static struct btf_file_test file_tests[] = { |
| 4019 | { | 4019 | { .file = "test_btf_haskv.o", }, |
| 4020 | .file = "test_btf_haskv.o", | 4020 | { .file = "test_btf_newkv.o", }, |
| 4021 | }, | 4021 | { .file = "test_btf_nokv.o", .btf_kv_notfound = true, }, |
| 4022 | { | ||
| 4023 | .file = "test_btf_nokv.o", | ||
| 4024 | .btf_kv_notfound = true, | ||
| 4025 | }, | ||
| 4026 | }; | 4022 | }; |
| 4027 | 4023 | ||
| 4028 | static int do_test_file(unsigned int test_num) | 4024 | static int do_test_file(unsigned int test_num) |
diff --git a/tools/testing/selftests/bpf/test_select_reuseport.c b/tools/testing/selftests/bpf/test_select_reuseport.c index 75646d9b34aa..7566c13eb51a 100644 --- a/tools/testing/selftests/bpf/test_select_reuseport.c +++ b/tools/testing/selftests/bpf/test_select_reuseport.c | |||
| @@ -523,6 +523,58 @@ static void test_pass_on_err(int type, sa_family_t family) | |||
| 523 | printf("OK\n"); | 523 | printf("OK\n"); |
| 524 | } | 524 | } |
| 525 | 525 | ||
| 526 | static void test_detach_bpf(int type, sa_family_t family) | ||
| 527 | { | ||
| 528 | #ifdef SO_DETACH_REUSEPORT_BPF | ||
| 529 | __u32 nr_run_before = 0, nr_run_after = 0, tmp, i; | ||
| 530 | struct epoll_event ev; | ||
| 531 | int cli_fd, err, nev; | ||
| 532 | struct cmd cmd = {}; | ||
| 533 | int optvalue = 0; | ||
| 534 | |||
| 535 | printf("%s: ", __func__); | ||
| 536 | err = setsockopt(sk_fds[0], SOL_SOCKET, SO_DETACH_REUSEPORT_BPF, | ||
| 537 | &optvalue, sizeof(optvalue)); | ||
| 538 | CHECK(err == -1, "setsockopt(SO_DETACH_REUSEPORT_BPF)", | ||
| 539 | "err:%d errno:%d\n", err, errno); | ||
| 540 | |||
| 541 | err = setsockopt(sk_fds[1], SOL_SOCKET, SO_DETACH_REUSEPORT_BPF, | ||
| 542 | &optvalue, sizeof(optvalue)); | ||
| 543 | CHECK(err == 0 || errno != ENOENT, "setsockopt(SO_DETACH_REUSEPORT_BPF)", | ||
| 544 | "err:%d errno:%d\n", err, errno); | ||
| 545 | |||
| 546 | for (i = 0; i < NR_RESULTS; i++) { | ||
| 547 | err = bpf_map_lookup_elem(result_map, &i, &tmp); | ||
| 548 | CHECK(err == -1, "lookup_elem(result_map)", | ||
| 549 | "i:%u err:%d errno:%d\n", i, err, errno); | ||
| 550 | nr_run_before += tmp; | ||
| 551 | } | ||
| 552 | |||
| 553 | cli_fd = send_data(type, family, &cmd, sizeof(cmd), PASS); | ||
| 554 | nev = epoll_wait(epfd, &ev, 1, 5); | ||
| 555 | CHECK(nev <= 0, "nev <= 0", | ||
| 556 | "nev:%d expected:1 type:%d family:%d data:(0, 0)\n", | ||
| 557 | nev, type, family); | ||
| 558 | |||
| 559 | for (i = 0; i < NR_RESULTS; i++) { | ||
| 560 | err = bpf_map_lookup_elem(result_map, &i, &tmp); | ||
| 561 | CHECK(err == -1, "lookup_elem(result_map)", | ||
| 562 | "i:%u err:%d errno:%d\n", i, err, errno); | ||
| 563 | nr_run_after += tmp; | ||
| 564 | } | ||
| 565 | |||
| 566 | CHECK(nr_run_before != nr_run_after, | ||
| 567 | "nr_run_before != nr_run_after", | ||
| 568 | "nr_run_before:%u nr_run_after:%u\n", | ||
| 569 | nr_run_before, nr_run_after); | ||
| 570 | |||
| 571 | printf("OK\n"); | ||
| 572 | close(cli_fd); | ||
| 573 | #else | ||
| 574 | printf("%s: SKIP\n", __func__); | ||
| 575 | #endif | ||
| 576 | } | ||
| 577 | |||
| 526 | static void prepare_sk_fds(int type, sa_family_t family, bool inany) | 578 | static void prepare_sk_fds(int type, sa_family_t family, bool inany) |
| 527 | { | 579 | { |
| 528 | const int first = REUSEPORT_ARRAY_SIZE - 1; | 580 | const int first = REUSEPORT_ARRAY_SIZE - 1; |
| @@ -664,6 +716,8 @@ static void test_all(void) | |||
| 664 | test_pass(type, family); | 716 | test_pass(type, family); |
| 665 | test_syncookie(type, family); | 717 | test_syncookie(type, family); |
| 666 | test_pass_on_err(type, family); | 718 | test_pass_on_err(type, family); |
| 719 | /* Must be the last test */ | ||
| 720 | test_detach_bpf(type, family); | ||
| 667 | 721 | ||
| 668 | cleanup_per_test(); | 722 | cleanup_per_test(); |
| 669 | printf("\n"); | 723 | printf("\n"); |
diff --git a/tools/testing/selftests/bpf/test_socket_cookie.c b/tools/testing/selftests/bpf/test_socket_cookie.c index cac8ee57a013..15653b0e26eb 100644 --- a/tools/testing/selftests/bpf/test_socket_cookie.c +++ b/tools/testing/selftests/bpf/test_socket_cookie.c | |||
| @@ -18,6 +18,11 @@ | |||
| 18 | #define CG_PATH "/foo" | 18 | #define CG_PATH "/foo" |
| 19 | #define SOCKET_COOKIE_PROG "./socket_cookie_prog.o" | 19 | #define SOCKET_COOKIE_PROG "./socket_cookie_prog.o" |
| 20 | 20 | ||
| 21 | struct socket_cookie { | ||
| 22 | __u64 cookie_key; | ||
| 23 | __u32 cookie_value; | ||
| 24 | }; | ||
| 25 | |||
| 21 | static int start_server(void) | 26 | static int start_server(void) |
| 22 | { | 27 | { |
| 23 | struct sockaddr_in6 addr; | 28 | struct sockaddr_in6 addr; |
| @@ -89,8 +94,7 @@ static int validate_map(struct bpf_map *map, int client_fd) | |||
| 89 | __u32 cookie_expected_value; | 94 | __u32 cookie_expected_value; |
| 90 | struct sockaddr_in6 addr; | 95 | struct sockaddr_in6 addr; |
| 91 | socklen_t len = sizeof(addr); | 96 | socklen_t len = sizeof(addr); |
| 92 | __u32 cookie_value; | 97 | struct socket_cookie val; |
| 93 | __u64 cookie_key; | ||
| 94 | int err = 0; | 98 | int err = 0; |
| 95 | int map_fd; | 99 | int map_fd; |
| 96 | 100 | ||
| @@ -101,17 +105,7 @@ static int validate_map(struct bpf_map *map, int client_fd) | |||
| 101 | 105 | ||
| 102 | map_fd = bpf_map__fd(map); | 106 | map_fd = bpf_map__fd(map); |
| 103 | 107 | ||
| 104 | err = bpf_map_get_next_key(map_fd, NULL, &cookie_key); | 108 | err = bpf_map_lookup_elem(map_fd, &client_fd, &val); |
| 105 | if (err) { | ||
| 106 | log_err("Can't get cookie key from map"); | ||
| 107 | goto out; | ||
| 108 | } | ||
| 109 | |||
| 110 | err = bpf_map_lookup_elem(map_fd, &cookie_key, &cookie_value); | ||
| 111 | if (err) { | ||
| 112 | log_err("Can't get cookie value from map"); | ||
| 113 | goto out; | ||
| 114 | } | ||
| 115 | 109 | ||
| 116 | err = getsockname(client_fd, (struct sockaddr *)&addr, &len); | 110 | err = getsockname(client_fd, (struct sockaddr *)&addr, &len); |
| 117 | if (err) { | 111 | if (err) { |
| @@ -120,8 +114,8 @@ static int validate_map(struct bpf_map *map, int client_fd) | |||
| 120 | } | 114 | } |
| 121 | 115 | ||
| 122 | cookie_expected_value = (ntohs(addr.sin6_port) << 8) | 0xFF; | 116 | cookie_expected_value = (ntohs(addr.sin6_port) << 8) | 0xFF; |
| 123 | if (cookie_value != cookie_expected_value) { | 117 | if (val.cookie_value != cookie_expected_value) { |
| 124 | log_err("Unexpected value in map: %x != %x", cookie_value, | 118 | log_err("Unexpected value in map: %x != %x", val.cookie_value, |
| 125 | cookie_expected_value); | 119 | cookie_expected_value); |
| 126 | goto err; | 120 | goto err; |
| 127 | } | 121 | } |
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 6cb307201958..c5514daf8865 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c | |||
| @@ -234,10 +234,10 @@ static void bpf_fill_scale1(struct bpf_test *self) | |||
| 234 | insn[i++] = BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, | 234 | insn[i++] = BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, |
| 235 | -8 * (k % 64 + 1)); | 235 | -8 * (k % 64 + 1)); |
| 236 | } | 236 | } |
| 237 | /* every jump adds 1 step to insn_processed, so to stay exactly | 237 | /* is_state_visited() doesn't allocate state for pruning for every jump. |
| 238 | * within 1m limit add MAX_TEST_INSNS - MAX_JMP_SEQ - 1 MOVs and 1 EXIT | 238 | * Hence multiply jmps by 4 to accommodate that heuristic |
| 239 | */ | 239 | */ |
| 240 | while (i < MAX_TEST_INSNS - MAX_JMP_SEQ - 1) | 240 | while (i < MAX_TEST_INSNS - MAX_JMP_SEQ * 4) |
| 241 | insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 42); | 241 | insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 42); |
| 242 | insn[i] = BPF_EXIT_INSN(); | 242 | insn[i] = BPF_EXIT_INSN(); |
| 243 | self->prog_len = i + 1; | 243 | self->prog_len = i + 1; |
| @@ -266,10 +266,7 @@ static void bpf_fill_scale2(struct bpf_test *self) | |||
| 266 | insn[i++] = BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, | 266 | insn[i++] = BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, |
| 267 | -8 * (k % (64 - 4 * FUNC_NEST) + 1)); | 267 | -8 * (k % (64 - 4 * FUNC_NEST) + 1)); |
| 268 | } | 268 | } |
| 269 | /* every jump adds 1 step to insn_processed, so to stay exactly | 269 | while (i < MAX_TEST_INSNS - MAX_JMP_SEQ * 4) |
| 270 | * within 1m limit add MAX_TEST_INSNS - MAX_JMP_SEQ - 1 MOVs and 1 EXIT | ||
| 271 | */ | ||
| 272 | while (i < MAX_TEST_INSNS - MAX_JMP_SEQ - 1) | ||
| 273 | insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 42); | 270 | insn[i++] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 42); |
| 274 | insn[i] = BPF_EXIT_INSN(); | 271 | insn[i] = BPF_EXIT_INSN(); |
| 275 | self->prog_len = i + 1; | 272 | self->prog_len = i + 1; |
diff --git a/tools/testing/selftests/bpf/verifier/calls.c b/tools/testing/selftests/bpf/verifier/calls.c index 9093a8f64dc6..2d752c4f8d9d 100644 --- a/tools/testing/selftests/bpf/verifier/calls.c +++ b/tools/testing/selftests/bpf/verifier/calls.c | |||
| @@ -215,9 +215,11 @@ | |||
| 215 | BPF_MOV64_IMM(BPF_REG_0, 3), | 215 | BPF_MOV64_IMM(BPF_REG_0, 3), |
| 216 | BPF_JMP_IMM(BPF_JA, 0, 0, -6), | 216 | BPF_JMP_IMM(BPF_JA, 0, 0, -6), |
| 217 | }, | 217 | }, |
| 218 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 218 | .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, |
| 219 | .errstr = "back-edge from insn", | 219 | .errstr_unpriv = "back-edge from insn", |
| 220 | .result = REJECT, | 220 | .result_unpriv = REJECT, |
| 221 | .result = ACCEPT, | ||
| 222 | .retval = 1, | ||
| 221 | }, | 223 | }, |
| 222 | { | 224 | { |
| 223 | "calls: conditional call 4", | 225 | "calls: conditional call 4", |
| @@ -250,22 +252,24 @@ | |||
| 250 | BPF_MOV64_IMM(BPF_REG_0, 3), | 252 | BPF_MOV64_IMM(BPF_REG_0, 3), |
| 251 | BPF_EXIT_INSN(), | 253 | BPF_EXIT_INSN(), |
| 252 | }, | 254 | }, |
| 253 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 255 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| 254 | .errstr = "back-edge from insn", | 256 | .result = ACCEPT, |
| 255 | .result = REJECT, | 257 | .retval = 1, |
| 256 | }, | 258 | }, |
| 257 | { | 259 | { |
| 258 | "calls: conditional call 6", | 260 | "calls: conditional call 6", |
| 259 | .insns = { | 261 | .insns = { |
| 262 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
| 263 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
| 260 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), | 264 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), |
| 261 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, -2), | 265 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, -3), |
| 262 | BPF_EXIT_INSN(), | 266 | BPF_EXIT_INSN(), |
| 263 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | 267 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, |
| 264 | offsetof(struct __sk_buff, mark)), | 268 | offsetof(struct __sk_buff, mark)), |
| 265 | BPF_EXIT_INSN(), | 269 | BPF_EXIT_INSN(), |
| 266 | }, | 270 | }, |
| 267 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 271 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| 268 | .errstr = "back-edge from insn", | 272 | .errstr = "infinite loop detected", |
| 269 | .result = REJECT, | 273 | .result = REJECT, |
| 270 | }, | 274 | }, |
| 271 | { | 275 | { |
diff --git a/tools/testing/selftests/bpf/verifier/cfg.c b/tools/testing/selftests/bpf/verifier/cfg.c index 349c0862fb4c..4eb76ed739ce 100644 --- a/tools/testing/selftests/bpf/verifier/cfg.c +++ b/tools/testing/selftests/bpf/verifier/cfg.c | |||
| @@ -41,7 +41,8 @@ | |||
| 41 | BPF_JMP_IMM(BPF_JA, 0, 0, -1), | 41 | BPF_JMP_IMM(BPF_JA, 0, 0, -1), |
| 42 | BPF_EXIT_INSN(), | 42 | BPF_EXIT_INSN(), |
| 43 | }, | 43 | }, |
| 44 | .errstr = "back-edge", | 44 | .errstr = "unreachable insn 1", |
| 45 | .errstr_unpriv = "back-edge", | ||
| 45 | .result = REJECT, | 46 | .result = REJECT, |
| 46 | }, | 47 | }, |
| 47 | { | 48 | { |
| @@ -53,18 +54,20 @@ | |||
| 53 | BPF_JMP_IMM(BPF_JA, 0, 0, -4), | 54 | BPF_JMP_IMM(BPF_JA, 0, 0, -4), |
| 54 | BPF_EXIT_INSN(), | 55 | BPF_EXIT_INSN(), |
| 55 | }, | 56 | }, |
| 56 | .errstr = "back-edge", | 57 | .errstr = "unreachable insn 4", |
| 58 | .errstr_unpriv = "back-edge", | ||
| 57 | .result = REJECT, | 59 | .result = REJECT, |
| 58 | }, | 60 | }, |
| 59 | { | 61 | { |
| 60 | "conditional loop", | 62 | "conditional loop", |
| 61 | .insns = { | 63 | .insns = { |
| 62 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | 64 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), |
| 63 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), | 65 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), |
| 64 | BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), | 66 | BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), |
| 65 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, -3), | 67 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, -3), |
| 66 | BPF_EXIT_INSN(), | 68 | BPF_EXIT_INSN(), |
| 67 | }, | 69 | }, |
| 68 | .errstr = "back-edge", | 70 | .errstr = "infinite loop detected", |
| 71 | .errstr_unpriv = "back-edge", | ||
| 69 | .result = REJECT, | 72 | .result = REJECT, |
| 70 | }, | 73 | }, |
diff --git a/tools/testing/selftests/bpf/verifier/direct_packet_access.c b/tools/testing/selftests/bpf/verifier/direct_packet_access.c index d5c596fdc4b9..2c5fbe7bcd27 100644 --- a/tools/testing/selftests/bpf/verifier/direct_packet_access.c +++ b/tools/testing/selftests/bpf/verifier/direct_packet_access.c | |||
| @@ -511,7 +511,8 @@ | |||
| 511 | offsetof(struct __sk_buff, data)), | 511 | offsetof(struct __sk_buff, data)), |
| 512 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | 512 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, |
| 513 | offsetof(struct __sk_buff, data_end)), | 513 | offsetof(struct __sk_buff, data_end)), |
| 514 | BPF_MOV64_IMM(BPF_REG_0, 0xffffffff), | 514 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, |
| 515 | offsetof(struct __sk_buff, mark)), | ||
| 515 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), | 516 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), |
| 516 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), | 517 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), |
| 517 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffff), | 518 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffff), |
diff --git a/tools/testing/selftests/bpf/verifier/helper_access_var_len.c b/tools/testing/selftests/bpf/verifier/helper_access_var_len.c index 1f39d845c64f..67ab12410050 100644 --- a/tools/testing/selftests/bpf/verifier/helper_access_var_len.c +++ b/tools/testing/selftests/bpf/verifier/helper_access_var_len.c | |||
| @@ -29,9 +29,9 @@ | |||
| 29 | { | 29 | { |
| 30 | "helper access to variable memory: stack, bitwise AND, zero included", | 30 | "helper access to variable memory: stack, bitwise AND, zero included", |
| 31 | .insns = { | 31 | .insns = { |
| 32 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), | ||
| 32 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | 33 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| 33 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), | 34 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), |
| 34 | BPF_MOV64_IMM(BPF_REG_2, 16), | ||
| 35 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), | 35 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), |
| 36 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), | 36 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), |
| 37 | BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 64), | 37 | BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 64), |
| @@ -46,9 +46,9 @@ | |||
| 46 | { | 46 | { |
| 47 | "helper access to variable memory: stack, bitwise AND + JMP, wrong max", | 47 | "helper access to variable memory: stack, bitwise AND + JMP, wrong max", |
| 48 | .insns = { | 48 | .insns = { |
| 49 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), | ||
| 49 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | 50 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| 50 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), | 51 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), |
| 51 | BPF_MOV64_IMM(BPF_REG_2, 16), | ||
| 52 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), | 52 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), |
| 53 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), | 53 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), |
| 54 | BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 65), | 54 | BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 65), |
| @@ -122,9 +122,9 @@ | |||
| 122 | { | 122 | { |
| 123 | "helper access to variable memory: stack, JMP, bounds + offset", | 123 | "helper access to variable memory: stack, JMP, bounds + offset", |
| 124 | .insns = { | 124 | .insns = { |
| 125 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), | ||
| 125 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | 126 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| 126 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), | 127 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), |
| 127 | BPF_MOV64_IMM(BPF_REG_2, 16), | ||
| 128 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), | 128 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), |
| 129 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), | 129 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), |
| 130 | BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 64, 5), | 130 | BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 64, 5), |
| @@ -143,9 +143,9 @@ | |||
| 143 | { | 143 | { |
| 144 | "helper access to variable memory: stack, JMP, wrong max", | 144 | "helper access to variable memory: stack, JMP, wrong max", |
| 145 | .insns = { | 145 | .insns = { |
| 146 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), | ||
| 146 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | 147 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| 147 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), | 148 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), |
| 148 | BPF_MOV64_IMM(BPF_REG_2, 16), | ||
| 149 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), | 149 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), |
| 150 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), | 150 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), |
| 151 | BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 65, 4), | 151 | BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 65, 4), |
| @@ -163,9 +163,9 @@ | |||
| 163 | { | 163 | { |
| 164 | "helper access to variable memory: stack, JMP, no max check", | 164 | "helper access to variable memory: stack, JMP, no max check", |
| 165 | .insns = { | 165 | .insns = { |
| 166 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), | ||
| 166 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | 167 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| 167 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), | 168 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), |
| 168 | BPF_MOV64_IMM(BPF_REG_2, 16), | ||
| 169 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), | 169 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), |
| 170 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), | 170 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), |
| 171 | BPF_MOV64_IMM(BPF_REG_4, 0), | 171 | BPF_MOV64_IMM(BPF_REG_4, 0), |
| @@ -183,9 +183,9 @@ | |||
| 183 | { | 183 | { |
| 184 | "helper access to variable memory: stack, JMP, no min check", | 184 | "helper access to variable memory: stack, JMP, no min check", |
| 185 | .insns = { | 185 | .insns = { |
| 186 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), | ||
| 186 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | 187 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| 187 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), | 188 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), |
| 188 | BPF_MOV64_IMM(BPF_REG_2, 16), | ||
| 189 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), | 189 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), |
| 190 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), | 190 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), |
| 191 | BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 64, 3), | 191 | BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 64, 3), |
| @@ -201,9 +201,9 @@ | |||
| 201 | { | 201 | { |
| 202 | "helper access to variable memory: stack, JMP (signed), no min check", | 202 | "helper access to variable memory: stack, JMP (signed), no min check", |
| 203 | .insns = { | 203 | .insns = { |
| 204 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), | ||
| 204 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | 205 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| 205 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), | 206 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), |
| 206 | BPF_MOV64_IMM(BPF_REG_2, 16), | ||
| 207 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), | 207 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, -128), |
| 208 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), | 208 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -128), |
| 209 | BPF_JMP_IMM(BPF_JSGT, BPF_REG_2, 64, 3), | 209 | BPF_JMP_IMM(BPF_JSGT, BPF_REG_2, 64, 3), |
| @@ -244,6 +244,7 @@ | |||
| 244 | { | 244 | { |
| 245 | "helper access to variable memory: map, JMP, wrong max", | 245 | "helper access to variable memory: map, JMP, wrong max", |
| 246 | .insns = { | 246 | .insns = { |
| 247 | BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 8), | ||
| 247 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 248 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| 248 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | 249 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| 249 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | 250 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), |
| @@ -251,7 +252,7 @@ | |||
| 251 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 252 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
| 252 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 10), | 253 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 10), |
| 253 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | 254 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
| 254 | BPF_MOV64_IMM(BPF_REG_2, sizeof(struct test_val)), | 255 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_6), |
| 255 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -128), | 256 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -128), |
| 256 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -128), | 257 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -128), |
| 257 | BPF_JMP_IMM(BPF_JSGT, BPF_REG_2, sizeof(struct test_val) + 1, 4), | 258 | BPF_JMP_IMM(BPF_JSGT, BPF_REG_2, sizeof(struct test_val) + 1, 4), |
| @@ -262,7 +263,7 @@ | |||
| 262 | BPF_MOV64_IMM(BPF_REG_0, 0), | 263 | BPF_MOV64_IMM(BPF_REG_0, 0), |
| 263 | BPF_EXIT_INSN(), | 264 | BPF_EXIT_INSN(), |
| 264 | }, | 265 | }, |
| 265 | .fixup_map_hash_48b = { 3 }, | 266 | .fixup_map_hash_48b = { 4 }, |
| 266 | .errstr = "invalid access to map value, value_size=48 off=0 size=49", | 267 | .errstr = "invalid access to map value, value_size=48 off=0 size=49", |
| 267 | .result = REJECT, | 268 | .result = REJECT, |
| 268 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 269 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| @@ -296,6 +297,7 @@ | |||
| 296 | { | 297 | { |
| 297 | "helper access to variable memory: map adjusted, JMP, wrong max", | 298 | "helper access to variable memory: map adjusted, JMP, wrong max", |
| 298 | .insns = { | 299 | .insns = { |
| 300 | BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 8), | ||
| 299 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 301 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
| 300 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | 302 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
| 301 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | 303 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), |
| @@ -304,7 +306,7 @@ | |||
| 304 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 11), | 306 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 11), |
| 305 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | 307 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
| 306 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 20), | 308 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 20), |
| 307 | BPF_MOV64_IMM(BPF_REG_2, sizeof(struct test_val)), | 309 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_6), |
| 308 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -128), | 310 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -128), |
| 309 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -128), | 311 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -128), |
| 310 | BPF_JMP_IMM(BPF_JSGT, BPF_REG_2, sizeof(struct test_val) - 19, 4), | 312 | BPF_JMP_IMM(BPF_JSGT, BPF_REG_2, sizeof(struct test_val) - 19, 4), |
| @@ -315,7 +317,7 @@ | |||
| 315 | BPF_MOV64_IMM(BPF_REG_0, 0), | 317 | BPF_MOV64_IMM(BPF_REG_0, 0), |
| 316 | BPF_EXIT_INSN(), | 318 | BPF_EXIT_INSN(), |
| 317 | }, | 319 | }, |
| 318 | .fixup_map_hash_48b = { 3 }, | 320 | .fixup_map_hash_48b = { 4 }, |
| 319 | .errstr = "R1 min value is outside of the array range", | 321 | .errstr = "R1 min value is outside of the array range", |
| 320 | .result = REJECT, | 322 | .result = REJECT, |
| 321 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 323 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
| @@ -337,8 +339,8 @@ | |||
| 337 | { | 339 | { |
| 338 | "helper access to variable memory: size > 0 not allowed on NULL (ARG_PTR_TO_MEM_OR_NULL)", | 340 | "helper access to variable memory: size > 0 not allowed on NULL (ARG_PTR_TO_MEM_OR_NULL)", |
| 339 | .insns = { | 341 | .insns = { |
| 342 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), | ||
| 340 | BPF_MOV64_IMM(BPF_REG_1, 0), | 343 | BPF_MOV64_IMM(BPF_REG_1, 0), |
| 341 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
| 342 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -128), | 344 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -128), |
| 343 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -128), | 345 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -128), |
| 344 | BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 64), | 346 | BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 64), |
| @@ -562,6 +564,7 @@ | |||
| 562 | { | 564 | { |
| 563 | "helper access to variable memory: 8 bytes leak", | 565 | "helper access to variable memory: 8 bytes leak", |
| 564 | .insns = { | 566 | .insns = { |
| 567 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), | ||
| 565 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | 568 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
| 566 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), | 569 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -64), |
| 567 | BPF_MOV64_IMM(BPF_REG_0, 0), | 570 | BPF_MOV64_IMM(BPF_REG_0, 0), |
| @@ -572,7 +575,6 @@ | |||
| 572 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -24), | 575 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -24), |
| 573 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -16), | 576 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -16), |
| 574 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), | 577 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), |
| 575 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
| 576 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -128), | 578 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -128), |
| 577 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -128), | 579 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -128), |
| 578 | BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 63), | 580 | BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 63), |
diff --git a/tools/testing/selftests/bpf/verifier/loops1.c b/tools/testing/selftests/bpf/verifier/loops1.c new file mode 100644 index 000000000000..5e980a5ab69d --- /dev/null +++ b/tools/testing/selftests/bpf/verifier/loops1.c | |||
| @@ -0,0 +1,161 @@ | |||
| 1 | { | ||
| 2 | "bounded loop, count to 4", | ||
| 3 | .insns = { | ||
| 4 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 5 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 6 | BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 4, -2), | ||
| 7 | BPF_EXIT_INSN(), | ||
| 8 | }, | ||
| 9 | .result = ACCEPT, | ||
| 10 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 11 | .retval = 4, | ||
| 12 | }, | ||
| 13 | { | ||
| 14 | "bounded loop, count to 20", | ||
| 15 | .insns = { | ||
| 16 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 17 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 3), | ||
| 18 | BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 20, -2), | ||
| 19 | BPF_EXIT_INSN(), | ||
| 20 | }, | ||
| 21 | .result = ACCEPT, | ||
| 22 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 23 | }, | ||
| 24 | { | ||
| 25 | "bounded loop, count from positive unknown to 4", | ||
| 26 | .insns = { | ||
| 27 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32), | ||
| 28 | BPF_JMP_IMM(BPF_JSLT, BPF_REG_0, 0, 2), | ||
| 29 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 30 | BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 4, -2), | ||
| 31 | BPF_EXIT_INSN(), | ||
| 32 | }, | ||
| 33 | .result = ACCEPT, | ||
| 34 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 35 | .retval = 4, | ||
| 36 | }, | ||
| 37 | { | ||
| 38 | "bounded loop, count from totally unknown to 4", | ||
| 39 | .insns = { | ||
| 40 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32), | ||
| 41 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 42 | BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 4, -2), | ||
| 43 | BPF_EXIT_INSN(), | ||
| 44 | }, | ||
| 45 | .result = ACCEPT, | ||
| 46 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 47 | }, | ||
| 48 | { | ||
| 49 | "bounded loop, count to 4 with equality", | ||
| 50 | .insns = { | ||
| 51 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 52 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 53 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 4, -2), | ||
| 54 | BPF_EXIT_INSN(), | ||
| 55 | }, | ||
| 56 | .result = ACCEPT, | ||
| 57 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 58 | }, | ||
| 59 | { | ||
| 60 | "bounded loop, start in the middle", | ||
| 61 | .insns = { | ||
| 62 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 63 | BPF_JMP_A(1), | ||
| 64 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 65 | BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 4, -2), | ||
| 66 | BPF_EXIT_INSN(), | ||
| 67 | }, | ||
| 68 | .result = REJECT, | ||
| 69 | .errstr = "back-edge", | ||
| 70 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 71 | .retval = 4, | ||
| 72 | }, | ||
| 73 | { | ||
| 74 | "bounded loop containing a forward jump", | ||
| 75 | .insns = { | ||
| 76 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 77 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 78 | BPF_JMP_REG(BPF_JEQ, BPF_REG_0, BPF_REG_0, 0), | ||
| 79 | BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 4, -3), | ||
| 80 | BPF_EXIT_INSN(), | ||
| 81 | }, | ||
| 82 | .result = ACCEPT, | ||
| 83 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 84 | .retval = 4, | ||
| 85 | }, | ||
| 86 | { | ||
| 87 | "bounded loop that jumps out rather than in", | ||
| 88 | .insns = { | ||
| 89 | BPF_MOV64_IMM(BPF_REG_6, 0), | ||
| 90 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1), | ||
| 91 | BPF_JMP_IMM(BPF_JGT, BPF_REG_6, 10000, 2), | ||
| 92 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32), | ||
| 93 | BPF_JMP_A(-4), | ||
| 94 | BPF_EXIT_INSN(), | ||
| 95 | }, | ||
| 96 | .result = ACCEPT, | ||
| 97 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 98 | }, | ||
| 99 | { | ||
| 100 | "infinite loop after a conditional jump", | ||
| 101 | .insns = { | ||
| 102 | BPF_MOV64_IMM(BPF_REG_0, 5), | ||
| 103 | BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 4, 2), | ||
| 104 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 105 | BPF_JMP_A(-2), | ||
| 106 | BPF_EXIT_INSN(), | ||
| 107 | }, | ||
| 108 | .result = REJECT, | ||
| 109 | .errstr = "program is too large", | ||
| 110 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 111 | }, | ||
| 112 | { | ||
| 113 | "bounded recursion", | ||
| 114 | .insns = { | ||
| 115 | BPF_MOV64_IMM(BPF_REG_1, 0), | ||
| 116 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), | ||
| 117 | BPF_EXIT_INSN(), | ||
| 118 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1), | ||
| 119 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
| 120 | BPF_JMP_IMM(BPF_JLT, BPF_REG_1, 4, 1), | ||
| 121 | BPF_EXIT_INSN(), | ||
| 122 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, -5), | ||
| 123 | BPF_EXIT_INSN(), | ||
| 124 | }, | ||
| 125 | .result = REJECT, | ||
| 126 | .errstr = "back-edge", | ||
| 127 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 128 | }, | ||
| 129 | { | ||
| 130 | "infinite loop in two jumps", | ||
| 131 | .insns = { | ||
| 132 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 133 | BPF_JMP_A(0), | ||
| 134 | BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 4, -2), | ||
| 135 | BPF_EXIT_INSN(), | ||
| 136 | }, | ||
| 137 | .result = REJECT, | ||
| 138 | .errstr = "loop detected", | ||
| 139 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 140 | }, | ||
| 141 | { | ||
| 142 | "infinite loop: three-jump trick", | ||
| 143 | .insns = { | ||
| 144 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 145 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 146 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), | ||
| 147 | BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 2, 1), | ||
| 148 | BPF_EXIT_INSN(), | ||
| 149 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 150 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), | ||
| 151 | BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 2, 1), | ||
| 152 | BPF_EXIT_INSN(), | ||
| 153 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 154 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), | ||
| 155 | BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 2, -11), | ||
| 156 | BPF_EXIT_INSN(), | ||
| 157 | }, | ||
| 158 | .result = REJECT, | ||
| 159 | .errstr = "loop detected", | ||
| 160 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 161 | }, | ||
diff --git a/tools/testing/selftests/bpf/verifier/prevent_map_lookup.c b/tools/testing/selftests/bpf/verifier/prevent_map_lookup.c index bbdba990fefb..da7a4b37cb98 100644 --- a/tools/testing/selftests/bpf/verifier/prevent_map_lookup.c +++ b/tools/testing/selftests/bpf/verifier/prevent_map_lookup.c | |||
| @@ -29,21 +29,6 @@ | |||
| 29 | .prog_type = BPF_PROG_TYPE_SOCK_OPS, | 29 | .prog_type = BPF_PROG_TYPE_SOCK_OPS, |
| 30 | }, | 30 | }, |
| 31 | { | 31 | { |
| 32 | "prevent map lookup in xskmap", | ||
| 33 | .insns = { | ||
| 34 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
| 35 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
| 36 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
| 37 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
| 38 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), | ||
| 39 | BPF_EXIT_INSN(), | ||
| 40 | }, | ||
| 41 | .fixup_map_xskmap = { 3 }, | ||
| 42 | .result = REJECT, | ||
| 43 | .errstr = "cannot pass map_type 17 into func bpf_map_lookup_elem", | ||
| 44 | .prog_type = BPF_PROG_TYPE_XDP, | ||
| 45 | }, | ||
| 46 | { | ||
| 47 | "prevent map lookup in stack trace", | 32 | "prevent map lookup in stack trace", |
| 48 | .insns = { | 33 | .insns = { |
| 49 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | 34 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
diff --git a/tools/testing/selftests/bpf/verifier/sock.c b/tools/testing/selftests/bpf/verifier/sock.c index b31cd2cf50d0..9ed192e14f5f 100644 --- a/tools/testing/selftests/bpf/verifier/sock.c +++ b/tools/testing/selftests/bpf/verifier/sock.c | |||
| @@ -498,3 +498,21 @@ | |||
| 498 | .result = REJECT, | 498 | .result = REJECT, |
| 499 | .errstr = "cannot pass map_type 24 into func bpf_map_lookup_elem", | 499 | .errstr = "cannot pass map_type 24 into func bpf_map_lookup_elem", |
| 500 | }, | 500 | }, |
| 501 | { | ||
| 502 | "bpf_map_lookup_elem(xskmap, &key); xs->queue_id", | ||
| 503 | .insns = { | ||
| 504 | BPF_ST_MEM(BPF_W, BPF_REG_10, -8, 0), | ||
| 505 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
| 506 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
| 507 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
| 508 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
| 509 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | ||
| 510 | BPF_EXIT_INSN(), | ||
| 511 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, offsetof(struct bpf_xdp_sock, queue_id)), | ||
| 512 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
| 513 | BPF_EXIT_INSN(), | ||
| 514 | }, | ||
| 515 | .fixup_map_xskmap = { 3 }, | ||
| 516 | .prog_type = BPF_PROG_TYPE_XDP, | ||
| 517 | .result = ACCEPT, | ||
| 518 | }, | ||
