Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
Daniel Borkmann says: ==================== pull-request: bpf-next 2019-04-12 The following pull-request contains BPF updates for your *net-next* tree. The main changes are: 1) Improve BPF verifier scalability for large programs through two optimizations: i) remove verifier states that are not useful in pruning, ii) stop walking parentage chain once first LIVE_READ is seen. Combined gives approx 20x speedup. Increase limits for accepting large programs under root, and add various stress tests, from Alexei. 2) Implement global data support in BPF. This enables static global variables for .data, .rodata and .bss sections to be properly handled which allows for more natural program development. This also opens up the possibility to optimize program workflow by compiling ELFs only once and later only rewriting section data before reload, from Daniel and with test cases and libbpf refactoring from Joe. 3) Add config option to generate BTF type info for vmlinux as part of the kernel build process. DWARF debug info is converted via pahole to BTF. Latter relies on libbpf and makes use of BTF deduplication algorithm which results in 100x savings compared to DWARF data. Resulting .BTF section is typically about 2MB in size, from Andrii. 4) Add BPF verifier support for stack access with variable offset from helpers and add various test cases along with it, from Andrey. 5) Extend bpf_skb_adjust_room() growth BPF helper to mark inner MAC header so that L2 encapsulation can be used for tc tunnels, from Alan. 6) Add support for input __sk_buff context in BPF_PROG_TEST_RUN so that users can define a subset of allowed __sk_buff fields that get fed into the test program, from Stanislav. 7) Add bpf fs multi-dimensional array tests for BTF test suite and fix up various UBSAN warnings in bpftool, from Yonghong. 8) Generate a pkg-config file for libbpf, from Luca. 9) Dump program's BTF id in bpftool, from Prashant. 10) libbpf fix to use smaller BPF log buffer size for AF_XDP's XDP program, from Magnus. 11) kallsyms related fixes for the case when symbols are not present in BPF selftests and samples, from Daniel ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -209,7 +209,7 @@ ifeq ($(DWARF2BTF),y)
|
||||
endif
|
||||
|
||||
PROG_TESTS_H := $(OUTPUT)/prog_tests/tests.h
|
||||
$(OUTPUT)/test_progs: $(PROG_TESTS_H)
|
||||
test_progs.c: $(PROG_TESTS_H)
|
||||
$(OUTPUT)/test_progs: CFLAGS += $(TEST_PROGS_CFLAGS)
|
||||
$(OUTPUT)/test_progs: prog_tests/*.c
|
||||
|
||||
@@ -232,7 +232,7 @@ $(PROG_TESTS_H): $(PROG_TESTS_DIR) $(PROG_TESTS_FILES)
|
||||
) > $(PROG_TESTS_H))
|
||||
|
||||
VERIFIER_TESTS_H := $(OUTPUT)/verifier/tests.h
|
||||
$(OUTPUT)/test_verifier: $(VERIFIER_TESTS_H)
|
||||
test_verifier.c: $(VERIFIER_TESTS_H)
|
||||
$(OUTPUT)/test_verifier: CFLAGS += $(TEST_VERIFIER_CFLAGS)
|
||||
|
||||
VERIFIER_TESTS_DIR = $(OUTPUT)/verifier
|
||||
|
@@ -9,14 +9,14 @@
|
||||
#define SEC(NAME) __attribute__((section(NAME), used))
|
||||
|
||||
/* helper functions called from eBPF programs written in C */
|
||||
static void *(*bpf_map_lookup_elem)(void *map, void *key) =
|
||||
static void *(*bpf_map_lookup_elem)(void *map, const void *key) =
|
||||
(void *) BPF_FUNC_map_lookup_elem;
|
||||
static int (*bpf_map_update_elem)(void *map, void *key, void *value,
|
||||
static int (*bpf_map_update_elem)(void *map, const void *key, const void *value,
|
||||
unsigned long long flags) =
|
||||
(void *) BPF_FUNC_map_update_elem;
|
||||
static int (*bpf_map_delete_elem)(void *map, void *key) =
|
||||
static int (*bpf_map_delete_elem)(void *map, const void *key) =
|
||||
(void *) BPF_FUNC_map_delete_elem;
|
||||
static int (*bpf_map_push_elem)(void *map, void *value,
|
||||
static int (*bpf_map_push_elem)(void *map, const void *value,
|
||||
unsigned long long flags) =
|
||||
(void *) BPF_FUNC_map_push_elem;
|
||||
static int (*bpf_map_pop_elem)(void *map, void *value) =
|
||||
|
@@ -25,3 +25,11 @@ CONFIG_XDP_SOCKETS=y
|
||||
CONFIG_FTRACE_SYSCALLS=y
|
||||
CONFIG_IPV6_TUNNEL=y
|
||||
CONFIG_IPV6_GRE=y
|
||||
CONFIG_NET_FOU=m
|
||||
CONFIG_NET_FOU_IP_TUNNELS=y
|
||||
CONFIG_IPV6_FOU=m
|
||||
CONFIG_IPV6_FOU_TUNNEL=m
|
||||
CONFIG_MPLS=y
|
||||
CONFIG_NET_MPLS_GSO=m
|
||||
CONFIG_MPLS_ROUTING=m
|
||||
CONFIG_MPLS_IPTUNNEL=m
|
||||
|
@@ -52,7 +52,7 @@ static void detach_program(void)
|
||||
sprintf(command, "rm -r %s", cfg_pin_path);
|
||||
ret = system(command);
|
||||
if (ret)
|
||||
error(1, errno, command);
|
||||
error(1, errno, "%s", command);
|
||||
}
|
||||
|
||||
static void parse_opts(int argc, char **argv)
|
||||
|
@@ -73,7 +73,7 @@ void test_bpf_obj_id(void)
|
||||
info_len != sizeof(struct bpf_map_info) ||
|
||||
strcmp((char *)map_infos[i].name, expected_map_name),
|
||||
"get-map-info(fd)",
|
||||
"err %d errno %d type %d(%d) info_len %u(%Zu) key_size %u value_size %u max_entries %u map_flags %X name %s(%s)\n",
|
||||
"err %d errno %d type %d(%d) info_len %u(%zu) key_size %u value_size %u max_entries %u map_flags %X name %s(%s)\n",
|
||||
err, errno,
|
||||
map_infos[i].type, BPF_MAP_TYPE_ARRAY,
|
||||
info_len, sizeof(struct bpf_map_info),
|
||||
@@ -117,7 +117,7 @@ void test_bpf_obj_id(void)
|
||||
*(int *)(long)prog_infos[i].map_ids != map_infos[i].id ||
|
||||
strcmp((char *)prog_infos[i].name, expected_prog_name),
|
||||
"get-prog-info(fd)",
|
||||
"err %d errno %d i %d type %d(%d) info_len %u(%Zu) jit_enabled %d jited_prog_len %u xlated_prog_len %u jited_prog %d xlated_prog %d load_time %lu(%lu) uid %u(%u) nr_map_ids %u(%u) map_id %u(%u) name %s(%s)\n",
|
||||
"err %d errno %d i %d type %d(%d) info_len %u(%zu) jit_enabled %d jited_prog_len %u xlated_prog_len %u jited_prog %d xlated_prog %d load_time %lu(%lu) uid %u(%u) nr_map_ids %u(%u) map_id %u(%u) name %s(%s)\n",
|
||||
err, errno, i,
|
||||
prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER,
|
||||
info_len, sizeof(struct bpf_prog_info),
|
||||
@@ -185,7 +185,7 @@ void test_bpf_obj_id(void)
|
||||
memcmp(&prog_info, &prog_infos[i], info_len) ||
|
||||
*(int *)(long)prog_info.map_ids != saved_map_id,
|
||||
"get-prog-info(next_id->fd)",
|
||||
"err %d errno %d info_len %u(%Zu) memcmp %d map_id %u(%u)\n",
|
||||
"err %d errno %d info_len %u(%zu) memcmp %d map_id %u(%u)\n",
|
||||
err, errno, info_len, sizeof(struct bpf_prog_info),
|
||||
memcmp(&prog_info, &prog_infos[i], info_len),
|
||||
*(int *)(long)prog_info.map_ids, saved_map_id);
|
||||
@@ -231,7 +231,7 @@ void test_bpf_obj_id(void)
|
||||
memcmp(&map_info, &map_infos[i], info_len) ||
|
||||
array_value != array_magic_value,
|
||||
"check get-map-info(next_id->fd)",
|
||||
"err %d errno %d info_len %u(%Zu) memcmp %d array_value %llu(%llu)\n",
|
||||
"err %d errno %d info_len %u(%zu) memcmp %d array_value %llu(%llu)\n",
|
||||
err, errno, info_len, sizeof(struct bpf_map_info),
|
||||
memcmp(&map_info, &map_infos[i], info_len),
|
||||
array_value, array_magic_value);
|
||||
|
49
tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c
Normal file
49
tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c
Normal file
@@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
#include <test_progs.h>
|
||||
static int libbpf_debug_print(enum libbpf_print_level level,
|
||||
const char *format, va_list args)
|
||||
{
|
||||
if (level != LIBBPF_DEBUG)
|
||||
return 0;
|
||||
|
||||
if (!strstr(format, "verifier log"))
|
||||
return 0;
|
||||
return vfprintf(stderr, "%s", args);
|
||||
}
|
||||
|
||||
static int check_load(const char *file)
|
||||
{
|
||||
struct bpf_prog_load_attr attr;
|
||||
struct bpf_object *obj;
|
||||
int err, prog_fd;
|
||||
|
||||
memset(&attr, 0, sizeof(struct bpf_prog_load_attr));
|
||||
attr.file = file;
|
||||
attr.prog_type = BPF_PROG_TYPE_SCHED_CLS;
|
||||
attr.log_level = 4;
|
||||
err = bpf_prog_load_xattr(&attr, &obj, &prog_fd);
|
||||
bpf_object__close(obj);
|
||||
if (err)
|
||||
error_cnt++;
|
||||
return err;
|
||||
}
|
||||
|
||||
void test_bpf_verif_scale(void)
|
||||
{
|
||||
const char *file1 = "./test_verif_scale1.o";
|
||||
const char *file2 = "./test_verif_scale2.o";
|
||||
const char *file3 = "./test_verif_scale3.o";
|
||||
int err;
|
||||
|
||||
if (verifier_stats)
|
||||
libbpf_set_print(libbpf_debug_print);
|
||||
|
||||
err = check_load(file1);
|
||||
err |= check_load(file2);
|
||||
err |= check_load(file3);
|
||||
if (!err)
|
||||
printf("test_verif_scale:OK\n");
|
||||
else
|
||||
printf("test_verif_scale:FAIL\n");
|
||||
}
|
@@ -39,7 +39,7 @@ static int get_stack_print_output(void *data, int size)
|
||||
} else {
|
||||
for (i = 0; i < num_stack; i++) {
|
||||
ks = ksym_search(raw_data[i]);
|
||||
if (strcmp(ks->name, nonjit_func) == 0) {
|
||||
if (ks && (strcmp(ks->name, nonjit_func) == 0)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ static int get_stack_print_output(void *data, int size)
|
||||
} else {
|
||||
for (i = 0; i < num_stack; i++) {
|
||||
ks = ksym_search(e->kern_stack[i]);
|
||||
if (strcmp(ks->name, nonjit_func) == 0) {
|
||||
if (ks && (strcmp(ks->name, nonjit_func) == 0)) {
|
||||
good_kern_stack = true;
|
||||
break;
|
||||
}
|
||||
|
157
tools/testing/selftests/bpf/prog_tests/global_data.c
Normal file
157
tools/testing/selftests/bpf/prog_tests/global_data.c
Normal file
@@ -0,0 +1,157 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <test_progs.h>
|
||||
|
||||
static void test_global_data_number(struct bpf_object *obj, __u32 duration)
|
||||
{
|
||||
int i, err, map_fd;
|
||||
uint64_t num;
|
||||
|
||||
map_fd = bpf_find_map(__func__, obj, "result_number");
|
||||
if (map_fd < 0) {
|
||||
error_cnt++;
|
||||
return;
|
||||
}
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
uint32_t key;
|
||||
uint64_t num;
|
||||
} tests[] = {
|
||||
{ "relocate .bss reference", 0, 0 },
|
||||
{ "relocate .data reference", 1, 42 },
|
||||
{ "relocate .rodata reference", 2, 24 },
|
||||
{ "relocate .bss reference", 3, 0 },
|
||||
{ "relocate .data reference", 4, 0xffeeff },
|
||||
{ "relocate .rodata reference", 5, 0xabab },
|
||||
{ "relocate .bss reference", 6, 1234 },
|
||||
{ "relocate .bss reference", 7, 0 },
|
||||
{ "relocate .rodata reference", 8, 0xab },
|
||||
{ "relocate .rodata reference", 9, 0x1111111111111111 },
|
||||
{ "relocate .rodata reference", 10, ~0 },
|
||||
};
|
||||
|
||||
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
|
||||
err = bpf_map_lookup_elem(map_fd, &tests[i].key, &num);
|
||||
CHECK(err || num != tests[i].num, tests[i].name,
|
||||
"err %d result %lx expected %lx\n",
|
||||
err, num, tests[i].num);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_global_data_string(struct bpf_object *obj, __u32 duration)
|
||||
{
|
||||
int i, err, map_fd;
|
||||
char str[32];
|
||||
|
||||
map_fd = bpf_find_map(__func__, obj, "result_string");
|
||||
if (map_fd < 0) {
|
||||
error_cnt++;
|
||||
return;
|
||||
}
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
uint32_t key;
|
||||
char str[32];
|
||||
} tests[] = {
|
||||
{ "relocate .rodata reference", 0, "abcdefghijklmnopqrstuvwxyz" },
|
||||
{ "relocate .data reference", 1, "abcdefghijklmnopqrstuvwxyz" },
|
||||
{ "relocate .bss reference", 2, "" },
|
||||
{ "relocate .data reference", 3, "abcdexghijklmnopqrstuvwxyz" },
|
||||
{ "relocate .bss reference", 4, "\0\0hello" },
|
||||
};
|
||||
|
||||
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
|
||||
err = bpf_map_lookup_elem(map_fd, &tests[i].key, str);
|
||||
CHECK(err || memcmp(str, tests[i].str, sizeof(str)),
|
||||
tests[i].name, "err %d result \'%s\' expected \'%s\'\n",
|
||||
err, str, tests[i].str);
|
||||
}
|
||||
}
|
||||
|
||||
struct foo {
|
||||
__u8 a;
|
||||
__u32 b;
|
||||
__u64 c;
|
||||
};
|
||||
|
||||
static void test_global_data_struct(struct bpf_object *obj, __u32 duration)
|
||||
{
|
||||
int i, err, map_fd;
|
||||
struct foo val;
|
||||
|
||||
map_fd = bpf_find_map(__func__, obj, "result_struct");
|
||||
if (map_fd < 0) {
|
||||
error_cnt++;
|
||||
return;
|
||||
}
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
uint32_t key;
|
||||
struct foo val;
|
||||
} tests[] = {
|
||||
{ "relocate .rodata reference", 0, { 42, 0xfefeefef, 0x1111111111111111ULL, } },
|
||||
{ "relocate .bss reference", 1, { } },
|
||||
{ "relocate .rodata reference", 2, { } },
|
||||
{ "relocate .data reference", 3, { 41, 0xeeeeefef, 0x2111111111111111ULL, } },
|
||||
};
|
||||
|
||||
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
|
||||
err = bpf_map_lookup_elem(map_fd, &tests[i].key, &val);
|
||||
CHECK(err || memcmp(&val, &tests[i].val, sizeof(val)),
|
||||
tests[i].name, "err %d result { %u, %u, %llu } expected { %u, %u, %llu }\n",
|
||||
err, val.a, val.b, val.c, tests[i].val.a, tests[i].val.b, tests[i].val.c);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_global_data_rdonly(struct bpf_object *obj, __u32 duration)
|
||||
{
|
||||
int err = -ENOMEM, map_fd, zero = 0;
|
||||
struct bpf_map *map;
|
||||
__u8 *buff;
|
||||
|
||||
map = bpf_object__find_map_by_name(obj, "test_glo.rodata");
|
||||
if (!map || !bpf_map__is_internal(map)) {
|
||||
error_cnt++;
|
||||
return;
|
||||
}
|
||||
|
||||
map_fd = bpf_map__fd(map);
|
||||
if (map_fd < 0) {
|
||||
error_cnt++;
|
||||
return;
|
||||
}
|
||||
|
||||
buff = malloc(bpf_map__def(map)->value_size);
|
||||
if (buff)
|
||||
err = bpf_map_update_elem(map_fd, &zero, buff, 0);
|
||||
free(buff);
|
||||
CHECK(!err || errno != EPERM, "test .rodata read-only map",
|
||||
"err %d errno %d\n", err, errno);
|
||||
}
|
||||
|
||||
void test_global_data(void)
|
||||
{
|
||||
const char *file = "./test_global_data.o";
|
||||
__u32 duration = 0, retval;
|
||||
struct bpf_object *obj;
|
||||
int err, prog_fd;
|
||||
|
||||
err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
|
||||
if (CHECK(err, "load program", "error %d loading %s\n", err, file))
|
||||
return;
|
||||
|
||||
err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
|
||||
NULL, NULL, &retval, &duration);
|
||||
CHECK(err || retval, "pass global data run",
|
||||
"err %d errno %d retval %d duration %d\n",
|
||||
err, errno, retval, duration);
|
||||
|
||||
test_global_data_number(obj, duration);
|
||||
test_global_data_string(obj, duration);
|
||||
test_global_data_struct(obj, duration);
|
||||
test_global_data_rdonly(obj, duration);
|
||||
|
||||
bpf_object__close(obj);
|
||||
}
|
89
tools/testing/selftests/bpf/prog_tests/skb_ctx.c
Normal file
89
tools/testing/selftests/bpf/prog_tests/skb_ctx.c
Normal file
@@ -0,0 +1,89 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <test_progs.h>
|
||||
|
||||
void test_skb_ctx(void)
|
||||
{
|
||||
struct __sk_buff skb = {
|
||||
.cb[0] = 1,
|
||||
.cb[1] = 2,
|
||||
.cb[2] = 3,
|
||||
.cb[3] = 4,
|
||||
.cb[4] = 5,
|
||||
.priority = 6,
|
||||
};
|
||||
struct bpf_prog_test_run_attr tattr = {
|
||||
.data_in = &pkt_v4,
|
||||
.data_size_in = sizeof(pkt_v4),
|
||||
.ctx_in = &skb,
|
||||
.ctx_size_in = sizeof(skb),
|
||||
.ctx_out = &skb,
|
||||
.ctx_size_out = sizeof(skb),
|
||||
};
|
||||
struct bpf_object *obj;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
err = bpf_prog_load("./test_skb_ctx.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
|
||||
&tattr.prog_fd);
|
||||
if (CHECK_ATTR(err, "load", "err %d errno %d\n", err, errno))
|
||||
return;
|
||||
|
||||
/* ctx_in != NULL, ctx_size_in == 0 */
|
||||
|
||||
tattr.ctx_size_in = 0;
|
||||
err = bpf_prog_test_run_xattr(&tattr);
|
||||
CHECK_ATTR(err == 0, "ctx_size_in", "err %d errno %d\n", err, errno);
|
||||
tattr.ctx_size_in = sizeof(skb);
|
||||
|
||||
/* ctx_out != NULL, ctx_size_out == 0 */
|
||||
|
||||
tattr.ctx_size_out = 0;
|
||||
err = bpf_prog_test_run_xattr(&tattr);
|
||||
CHECK_ATTR(err == 0, "ctx_size_out", "err %d errno %d\n", err, errno);
|
||||
tattr.ctx_size_out = sizeof(skb);
|
||||
|
||||
/* non-zero [len, tc_index] fields should be rejected*/
|
||||
|
||||
skb.len = 1;
|
||||
err = bpf_prog_test_run_xattr(&tattr);
|
||||
CHECK_ATTR(err == 0, "len", "err %d errno %d\n", err, errno);
|
||||
skb.len = 0;
|
||||
|
||||
skb.tc_index = 1;
|
||||
err = bpf_prog_test_run_xattr(&tattr);
|
||||
CHECK_ATTR(err == 0, "tc_index", "err %d errno %d\n", err, errno);
|
||||
skb.tc_index = 0;
|
||||
|
||||
/* non-zero [hash, sk] fields should be rejected */
|
||||
|
||||
skb.hash = 1;
|
||||
err = bpf_prog_test_run_xattr(&tattr);
|
||||
CHECK_ATTR(err == 0, "hash", "err %d errno %d\n", err, errno);
|
||||
skb.hash = 0;
|
||||
|
||||
skb.sk = (struct bpf_sock *)1;
|
||||
err = bpf_prog_test_run_xattr(&tattr);
|
||||
CHECK_ATTR(err == 0, "sk", "err %d errno %d\n", err, errno);
|
||||
skb.sk = 0;
|
||||
|
||||
err = bpf_prog_test_run_xattr(&tattr);
|
||||
CHECK_ATTR(err != 0 || tattr.retval,
|
||||
"run",
|
||||
"err %d errno %d retval %d\n",
|
||||
err, errno, tattr.retval);
|
||||
|
||||
CHECK_ATTR(tattr.ctx_size_out != sizeof(skb),
|
||||
"ctx_size_out",
|
||||
"incorrect output size, want %lu have %u\n",
|
||||
sizeof(skb), tattr.ctx_size_out);
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
CHECK_ATTR(skb.cb[i] != i + 2,
|
||||
"ctx_out_cb",
|
||||
"skb->cb[i] == %d, expected %d\n",
|
||||
skb.cb[i], i + 2);
|
||||
CHECK_ATTR(skb.priority != 7,
|
||||
"ctx_out_priority",
|
||||
"skb->priority == %d, expected %d\n",
|
||||
skb.priority, 7);
|
||||
}
|
106
tools/testing/selftests/bpf/progs/test_global_data.c
Normal file
106
tools/testing/selftests/bpf/progs/test_global_data.c
Normal file
@@ -0,0 +1,106 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Isovalent, Inc.
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
struct bpf_map_def SEC("maps") result_number = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(__u64),
|
||||
.max_entries = 11,
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") result_string = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = 32,
|
||||
.max_entries = 5,
|
||||
};
|
||||
|
||||
struct foo {
|
||||
__u8 a;
|
||||
__u32 b;
|
||||
__u64 c;
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") result_struct = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(struct foo),
|
||||
.max_entries = 5,
|
||||
};
|
||||
|
||||
/* Relocation tests for __u64s. */
|
||||
static __u64 num0;
|
||||
static __u64 num1 = 42;
|
||||
static const __u64 num2 = 24;
|
||||
static __u64 num3 = 0;
|
||||
static __u64 num4 = 0xffeeff;
|
||||
static const __u64 num5 = 0xabab;
|
||||
static const __u64 num6 = 0xab;
|
||||
|
||||
/* Relocation tests for strings. */
|
||||
static const char str0[32] = "abcdefghijklmnopqrstuvwxyz";
|
||||
static char str1[32] = "abcdefghijklmnopqrstuvwxyz";
|
||||
static char str2[32];
|
||||
|
||||
/* Relocation tests for structs. */
|
||||
static const struct foo struct0 = {
|
||||
.a = 42,
|
||||
.b = 0xfefeefef,
|
||||
.c = 0x1111111111111111ULL,
|
||||
};
|
||||
static struct foo struct1;
|
||||
static const struct foo struct2;
|
||||
static struct foo struct3 = {
|
||||
.a = 41,
|
||||
.b = 0xeeeeefef,
|
||||
.c = 0x2111111111111111ULL,
|
||||
};
|
||||
|
||||
#define test_reloc(map, num, var) \
|
||||
do { \
|
||||
__u32 key = num; \
|
||||
bpf_map_update_elem(&result_##map, &key, var, 0); \
|
||||
} while (0)
|
||||
|
||||
SEC("static_data_load")
|
||||
int load_static_data(struct __sk_buff *skb)
|
||||
{
|
||||
static const __u64 bar = ~0;
|
||||
|
||||
test_reloc(number, 0, &num0);
|
||||
test_reloc(number, 1, &num1);
|
||||
test_reloc(number, 2, &num2);
|
||||
test_reloc(number, 3, &num3);
|
||||
test_reloc(number, 4, &num4);
|
||||
test_reloc(number, 5, &num5);
|
||||
num4 = 1234;
|
||||
test_reloc(number, 6, &num4);
|
||||
test_reloc(number, 7, &num0);
|
||||
test_reloc(number, 8, &num6);
|
||||
|
||||
test_reloc(string, 0, str0);
|
||||
test_reloc(string, 1, str1);
|
||||
test_reloc(string, 2, str2);
|
||||
str1[5] = 'x';
|
||||
test_reloc(string, 3, str1);
|
||||
__builtin_memcpy(&str2[2], "hello", sizeof("hello"));
|
||||
test_reloc(string, 4, str2);
|
||||
|
||||
test_reloc(struct, 0, &struct0);
|
||||
test_reloc(struct, 1, &struct1);
|
||||
test_reloc(struct, 2, &struct2);
|
||||
test_reloc(struct, 3, &struct3);
|
||||
|
||||
test_reloc(number, 9, &struct0.c);
|
||||
test_reloc(number, 10, &bar);
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
70
tools/testing/selftests/bpf/progs/test_jhash.h
Normal file
70
tools/testing/selftests/bpf/progs/test_jhash.h
Normal file
@@ -0,0 +1,70 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
|
||||
typedef unsigned int u32;
|
||||
|
||||
static __attribute__((always_inline)) u32 rol32(u32 word, unsigned int shift)
|
||||
{
|
||||
return (word << shift) | (word >> ((-shift) & 31));
|
||||
}
|
||||
|
||||
#define __jhash_mix(a, b, c) \
|
||||
{ \
|
||||
a -= c; a ^= rol32(c, 4); c += b; \
|
||||
b -= a; b ^= rol32(a, 6); a += c; \
|
||||
c -= b; c ^= rol32(b, 8); b += a; \
|
||||
a -= c; a ^= rol32(c, 16); c += b; \
|
||||
b -= a; b ^= rol32(a, 19); a += c; \
|
||||
c -= b; c ^= rol32(b, 4); b += a; \
|
||||
}
|
||||
|
||||
#define __jhash_final(a, b, c) \
|
||||
{ \
|
||||
c ^= b; c -= rol32(b, 14); \
|
||||
a ^= c; a -= rol32(c, 11); \
|
||||
b ^= a; b -= rol32(a, 25); \
|
||||
c ^= b; c -= rol32(b, 16); \
|
||||
a ^= c; a -= rol32(c, 4); \
|
||||
b ^= a; b -= rol32(a, 14); \
|
||||
c ^= b; c -= rol32(b, 24); \
|
||||
}
|
||||
|
||||
#define JHASH_INITVAL 0xdeadbeef
|
||||
|
||||
static ATTR
|
||||
u32 jhash(const void *key, u32 length, u32 initval)
|
||||
{
|
||||
u32 a, b, c;
|
||||
const unsigned char *k = key;
|
||||
|
||||
a = b = c = JHASH_INITVAL + length + initval;
|
||||
|
||||
while (length > 12) {
|
||||
a += *(volatile u32 *)(k);
|
||||
b += *(volatile u32 *)(k + 4);
|
||||
c += *(volatile u32 *)(k + 8);
|
||||
__jhash_mix(a, b, c);
|
||||
length -= 12;
|
||||
k += 12;
|
||||
}
|
||||
switch (length) {
|
||||
case 12: c += (u32)k[11]<<24;
|
||||
case 11: c += (u32)k[10]<<16;
|
||||
case 10: c += (u32)k[9]<<8;
|
||||
case 9: c += k[8];
|
||||
case 8: b += (u32)k[7]<<24;
|
||||
case 7: b += (u32)k[6]<<16;
|
||||
case 6: b += (u32)k[5]<<8;
|
||||
case 5: b += k[4];
|
||||
case 4: a += (u32)k[3]<<24;
|
||||
case 3: a += (u32)k[2]<<16;
|
||||
case 2: a += (u32)k[1]<<8;
|
||||
case 1: a += k[0];
|
||||
c ^= a;
|
||||
__jhash_final(a, b, c);
|
||||
case 0: /* Nothing left to add */
|
||||
break;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
21
tools/testing/selftests/bpf/progs/test_skb_ctx.c
Normal file
21
tools/testing/selftests/bpf/progs/test_skb_ctx.c
Normal file
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
SEC("skb_ctx")
|
||||
int process(struct __sk_buff *skb)
|
||||
{
|
||||
#pragma clang loop unroll(full)
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (skb->cb[i] != i + 1)
|
||||
return 1;
|
||||
skb->cb[i]++;
|
||||
}
|
||||
skb->priority++;
|
||||
|
||||
return 0;
|
||||
}
|
@@ -11,7 +11,9 @@
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/mpls.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
@@ -20,16 +22,36 @@
|
||||
|
||||
static const int cfg_port = 8000;
|
||||
|
||||
struct grev4hdr {
|
||||
struct iphdr ip;
|
||||
static const int cfg_udp_src = 20000;
|
||||
|
||||
#define UDP_PORT 5555
|
||||
#define MPLS_OVER_UDP_PORT 6635
|
||||
#define ETH_OVER_UDP_PORT 7777
|
||||
|
||||
/* MPLS label 1000 with S bit (last label) set and ttl of 255. */
|
||||
static const __u32 mpls_label = __bpf_constant_htonl(1000 << 12 |
|
||||
MPLS_LS_S_MASK | 0xff);
|
||||
|
||||
struct gre_hdr {
|
||||
__be16 flags;
|
||||
__be16 protocol;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct grev6hdr {
|
||||
union l4hdr {
|
||||
struct udphdr udp;
|
||||
struct gre_hdr gre;
|
||||
};
|
||||
|
||||
struct v4hdr {
|
||||
struct iphdr ip;
|
||||
union l4hdr l4hdr;
|
||||
__u8 pad[16]; /* enough space for L2 header */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct v6hdr {
|
||||
struct ipv6hdr ip;
|
||||
__be16 flags;
|
||||
__be16 protocol;
|
||||
union l4hdr l4hdr;
|
||||
__u8 pad[16]; /* enough space for L2 header */
|
||||
} __attribute__((packed));
|
||||
|
||||
static __always_inline void set_ipv4_csum(struct iphdr *iph)
|
||||
@@ -47,13 +69,15 @@ static __always_inline void set_ipv4_csum(struct iphdr *iph)
|
||||
iph->check = ~((csum & 0xffff) + (csum >> 16));
|
||||
}
|
||||
|
||||
static __always_inline int encap_ipv4(struct __sk_buff *skb, bool with_gre)
|
||||
static __always_inline int encap_ipv4(struct __sk_buff *skb, __u8 encap_proto,
|
||||
__u16 l2_proto)
|
||||
{
|
||||
struct grev4hdr h_outer;
|
||||
__u16 udp_dst = UDP_PORT;
|
||||
struct iphdr iph_inner;
|
||||
struct v4hdr h_outer;
|
||||
struct tcphdr tcph;
|
||||
int olen, l2_len;
|
||||
__u64 flags;
|
||||
int olen;
|
||||
|
||||
if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner,
|
||||
sizeof(iph_inner)) < 0)
|
||||
@@ -70,13 +94,58 @@ static __always_inline int encap_ipv4(struct __sk_buff *skb, bool with_gre)
|
||||
if (tcph.dest != __bpf_constant_htons(cfg_port))
|
||||
return TC_ACT_OK;
|
||||
|
||||
olen = sizeof(h_outer.ip);
|
||||
l2_len = 0;
|
||||
|
||||
flags = BPF_F_ADJ_ROOM_FIXED_GSO | BPF_F_ADJ_ROOM_ENCAP_L3_IPV4;
|
||||
if (with_gre) {
|
||||
flags |= BPF_F_ADJ_ROOM_ENCAP_L4_GRE;
|
||||
olen = sizeof(h_outer);
|
||||
} else {
|
||||
olen = sizeof(h_outer.ip);
|
||||
|
||||
switch (l2_proto) {
|
||||
case ETH_P_MPLS_UC:
|
||||
l2_len = sizeof(mpls_label);
|
||||
udp_dst = MPLS_OVER_UDP_PORT;
|
||||
break;
|
||||
case ETH_P_TEB:
|
||||
l2_len = ETH_HLEN;
|
||||
udp_dst = ETH_OVER_UDP_PORT;
|
||||
break;
|
||||
}
|
||||
flags |= BPF_F_ADJ_ROOM_ENCAP_L2(l2_len);
|
||||
|
||||
switch (encap_proto) {
|
||||
case IPPROTO_GRE:
|
||||
flags |= BPF_F_ADJ_ROOM_ENCAP_L4_GRE;
|
||||
olen += sizeof(h_outer.l4hdr.gre);
|
||||
h_outer.l4hdr.gre.protocol = bpf_htons(l2_proto);
|
||||
h_outer.l4hdr.gre.flags = 0;
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
flags |= BPF_F_ADJ_ROOM_ENCAP_L4_UDP;
|
||||
olen += sizeof(h_outer.l4hdr.udp);
|
||||
h_outer.l4hdr.udp.source = __bpf_constant_htons(cfg_udp_src);
|
||||
h_outer.l4hdr.udp.dest = bpf_htons(udp_dst);
|
||||
h_outer.l4hdr.udp.check = 0;
|
||||
h_outer.l4hdr.udp.len = bpf_htons(bpf_ntohs(iph_inner.tot_len) +
|
||||
sizeof(h_outer.l4hdr.udp) +
|
||||
l2_len);
|
||||
break;
|
||||
case IPPROTO_IPIP:
|
||||
break;
|
||||
default:
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
/* add L2 encap (if specified) */
|
||||
switch (l2_proto) {
|
||||
case ETH_P_MPLS_UC:
|
||||
*((__u32 *)((__u8 *)&h_outer + olen)) = mpls_label;
|
||||
break;
|
||||
case ETH_P_TEB:
|
||||
if (bpf_skb_load_bytes(skb, 0, (__u8 *)&h_outer + olen,
|
||||
ETH_HLEN))
|
||||
return TC_ACT_SHOT;
|
||||
break;
|
||||
}
|
||||
olen += l2_len;
|
||||
|
||||
/* add room between mac and network header */
|
||||
if (bpf_skb_adjust_room(skb, olen, BPF_ADJ_ROOM_MAC, flags))
|
||||
@@ -85,16 +154,10 @@ static __always_inline int encap_ipv4(struct __sk_buff *skb, bool with_gre)
|
||||
/* prepare new outer network header */
|
||||
h_outer.ip = iph_inner;
|
||||
h_outer.ip.tot_len = bpf_htons(olen +
|
||||
bpf_htons(h_outer.ip.tot_len));
|
||||
if (with_gre) {
|
||||
h_outer.ip.protocol = IPPROTO_GRE;
|
||||
h_outer.protocol = bpf_htons(ETH_P_IP);
|
||||
h_outer.flags = 0;
|
||||
} else {
|
||||
h_outer.ip.protocol = IPPROTO_IPIP;
|
||||
}
|
||||
bpf_ntohs(h_outer.ip.tot_len));
|
||||
h_outer.ip.protocol = encap_proto;
|
||||
|
||||
set_ipv4_csum((void *)&h_outer.ip);
|
||||
set_ipv4_csum(&h_outer.ip);
|
||||
|
||||
/* store new outer network header */
|
||||
if (bpf_skb_store_bytes(skb, ETH_HLEN, &h_outer, olen,
|
||||
@@ -104,13 +167,16 @@ static __always_inline int encap_ipv4(struct __sk_buff *skb, bool with_gre)
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
static __always_inline int encap_ipv6(struct __sk_buff *skb, bool with_gre)
|
||||
static __always_inline int encap_ipv6(struct __sk_buff *skb, __u8 encap_proto,
|
||||
__u16 l2_proto)
|
||||
{
|
||||
__u16 udp_dst = UDP_PORT;
|
||||
struct ipv6hdr iph_inner;
|
||||
struct grev6hdr h_outer;
|
||||
struct v6hdr h_outer;
|
||||
struct tcphdr tcph;
|
||||
int olen, l2_len;
|
||||
__u16 tot_len;
|
||||
__u64 flags;
|
||||
int olen;
|
||||
|
||||
if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner,
|
||||
sizeof(iph_inner)) < 0)
|
||||
@@ -124,14 +190,58 @@ static __always_inline int encap_ipv6(struct __sk_buff *skb, bool with_gre)
|
||||
if (tcph.dest != __bpf_constant_htons(cfg_port))
|
||||
return TC_ACT_OK;
|
||||
|
||||
olen = sizeof(h_outer.ip);
|
||||
l2_len = 0;
|
||||
|
||||
flags = BPF_F_ADJ_ROOM_FIXED_GSO | BPF_F_ADJ_ROOM_ENCAP_L3_IPV6;
|
||||
if (with_gre) {
|
||||
|
||||
switch (l2_proto) {
|
||||
case ETH_P_MPLS_UC:
|
||||
l2_len = sizeof(mpls_label);
|
||||
udp_dst = MPLS_OVER_UDP_PORT;
|
||||
break;
|
||||
case ETH_P_TEB:
|
||||
l2_len = ETH_HLEN;
|
||||
udp_dst = ETH_OVER_UDP_PORT;
|
||||
break;
|
||||
}
|
||||
flags |= BPF_F_ADJ_ROOM_ENCAP_L2(l2_len);
|
||||
|
||||
switch (encap_proto) {
|
||||
case IPPROTO_GRE:
|
||||
flags |= BPF_F_ADJ_ROOM_ENCAP_L4_GRE;
|
||||
olen = sizeof(h_outer);
|
||||
} else {
|
||||
olen = sizeof(h_outer.ip);
|
||||
olen += sizeof(h_outer.l4hdr.gre);
|
||||
h_outer.l4hdr.gre.protocol = bpf_htons(l2_proto);
|
||||
h_outer.l4hdr.gre.flags = 0;
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
flags |= BPF_F_ADJ_ROOM_ENCAP_L4_UDP;
|
||||
olen += sizeof(h_outer.l4hdr.udp);
|
||||
h_outer.l4hdr.udp.source = __bpf_constant_htons(cfg_udp_src);
|
||||
h_outer.l4hdr.udp.dest = bpf_htons(udp_dst);
|
||||
tot_len = bpf_ntohs(iph_inner.payload_len) + sizeof(iph_inner) +
|
||||
sizeof(h_outer.l4hdr.udp);
|
||||
h_outer.l4hdr.udp.check = 0;
|
||||
h_outer.l4hdr.udp.len = bpf_htons(tot_len);
|
||||
break;
|
||||
case IPPROTO_IPV6:
|
||||
break;
|
||||
default:
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
/* add L2 encap (if specified) */
|
||||
switch (l2_proto) {
|
||||
case ETH_P_MPLS_UC:
|
||||
*((__u32 *)((__u8 *)&h_outer + olen)) = mpls_label;
|
||||
break;
|
||||
case ETH_P_TEB:
|
||||
if (bpf_skb_load_bytes(skb, 0, (__u8 *)&h_outer + olen,
|
||||
ETH_HLEN))
|
||||
return TC_ACT_SHOT;
|
||||
break;
|
||||
}
|
||||
olen += l2_len;
|
||||
|
||||
/* add room between mac and network header */
|
||||
if (bpf_skb_adjust_room(skb, olen, BPF_ADJ_ROOM_MAC, flags))
|
||||
@@ -141,13 +251,8 @@ static __always_inline int encap_ipv6(struct __sk_buff *skb, bool with_gre)
|
||||
h_outer.ip = iph_inner;
|
||||
h_outer.ip.payload_len = bpf_htons(olen +
|
||||
bpf_ntohs(h_outer.ip.payload_len));
|
||||
if (with_gre) {
|
||||
h_outer.ip.nexthdr = IPPROTO_GRE;
|
||||
h_outer.protocol = bpf_htons(ETH_P_IPV6);
|
||||
h_outer.flags = 0;
|
||||
} else {
|
||||
h_outer.ip.nexthdr = IPPROTO_IPV6;
|
||||
}
|
||||
|
||||
h_outer.ip.nexthdr = encap_proto;
|
||||
|
||||
/* store new outer network header */
|
||||
if (bpf_skb_store_bytes(skb, ETH_HLEN, &h_outer, olen,
|
||||
@@ -157,54 +262,168 @@ static __always_inline int encap_ipv6(struct __sk_buff *skb, bool with_gre)
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_ipip")
|
||||
int __encap_ipip(struct __sk_buff *skb)
|
||||
SEC("encap_ipip_none")
|
||||
int __encap_ipip_none(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
|
||||
return encap_ipv4(skb, false);
|
||||
return encap_ipv4(skb, IPPROTO_IPIP, ETH_P_IP);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_gre")
|
||||
int __encap_gre(struct __sk_buff *skb)
|
||||
SEC("encap_gre_none")
|
||||
int __encap_gre_none(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
|
||||
return encap_ipv4(skb, true);
|
||||
return encap_ipv4(skb, IPPROTO_GRE, ETH_P_IP);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_ip6tnl")
|
||||
int __encap_ip6tnl(struct __sk_buff *skb)
|
||||
SEC("encap_gre_mpls")
|
||||
int __encap_gre_mpls(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
|
||||
return encap_ipv6(skb, false);
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
|
||||
return encap_ipv4(skb, IPPROTO_GRE, ETH_P_MPLS_UC);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_ip6gre")
|
||||
int __encap_ip6gre(struct __sk_buff *skb)
|
||||
SEC("encap_gre_eth")
|
||||
int __encap_gre_eth(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
|
||||
return encap_ipv4(skb, IPPROTO_GRE, ETH_P_TEB);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_udp_none")
|
||||
int __encap_udp_none(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
|
||||
return encap_ipv4(skb, IPPROTO_UDP, ETH_P_IP);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_udp_mpls")
|
||||
int __encap_udp_mpls(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
|
||||
return encap_ipv4(skb, IPPROTO_UDP, ETH_P_MPLS_UC);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_udp_eth")
|
||||
int __encap_udp_eth(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IP))
|
||||
return encap_ipv4(skb, IPPROTO_UDP, ETH_P_TEB);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_ip6tnl_none")
|
||||
int __encap_ip6tnl_none(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
|
||||
return encap_ipv6(skb, true);
|
||||
return encap_ipv6(skb, IPPROTO_IPV6, ETH_P_IPV6);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_ip6gre_none")
|
||||
int __encap_ip6gre_none(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
|
||||
return encap_ipv6(skb, IPPROTO_GRE, ETH_P_IPV6);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_ip6gre_mpls")
|
||||
int __encap_ip6gre_mpls(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
|
||||
return encap_ipv6(skb, IPPROTO_GRE, ETH_P_MPLS_UC);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_ip6gre_eth")
|
||||
int __encap_ip6gre_eth(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
|
||||
return encap_ipv6(skb, IPPROTO_GRE, ETH_P_TEB);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_ip6udp_none")
|
||||
int __encap_ip6udp_none(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
|
||||
return encap_ipv6(skb, IPPROTO_UDP, ETH_P_IPV6);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_ip6udp_mpls")
|
||||
int __encap_ip6udp_mpls(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
|
||||
return encap_ipv6(skb, IPPROTO_UDP, ETH_P_MPLS_UC);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("encap_ip6udp_eth")
|
||||
int __encap_ip6udp_eth(struct __sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6))
|
||||
return encap_ipv6(skb, IPPROTO_UDP, ETH_P_TEB);
|
||||
else
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
static int decap_internal(struct __sk_buff *skb, int off, int len, char proto)
|
||||
{
|
||||
char buf[sizeof(struct grev6hdr)];
|
||||
int olen;
|
||||
char buf[sizeof(struct v6hdr)];
|
||||
struct gre_hdr greh;
|
||||
struct udphdr udph;
|
||||
int olen = len;
|
||||
|
||||
switch (proto) {
|
||||
case IPPROTO_IPIP:
|
||||
case IPPROTO_IPV6:
|
||||
olen = len;
|
||||
break;
|
||||
case IPPROTO_GRE:
|
||||
olen = len + 4 /* gre hdr */;
|
||||
olen += sizeof(struct gre_hdr);
|
||||
if (bpf_skb_load_bytes(skb, off + len, &greh, sizeof(greh)) < 0)
|
||||
return TC_ACT_OK;
|
||||
switch (bpf_ntohs(greh.protocol)) {
|
||||
case ETH_P_MPLS_UC:
|
||||
olen += sizeof(mpls_label);
|
||||
break;
|
||||
case ETH_P_TEB:
|
||||
olen += ETH_HLEN;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
olen += sizeof(struct udphdr);
|
||||
if (bpf_skb_load_bytes(skb, off + len, &udph, sizeof(udph)) < 0)
|
||||
return TC_ACT_OK;
|
||||
switch (bpf_ntohs(udph.dest)) {
|
||||
case MPLS_OVER_UDP_PORT:
|
||||
olen += sizeof(mpls_label);
|
||||
break;
|
||||
case ETH_OVER_UDP_PORT:
|
||||
olen += ETH_HLEN;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return TC_ACT_OK;
|
||||
|
30
tools/testing/selftests/bpf/progs/test_verif_scale1.c
Normal file
30
tools/testing/selftests/bpf/progs/test_verif_scale1.c
Normal file
@@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
#include <linux/bpf.h>
|
||||
#include "bpf_helpers.h"
|
||||
#define ATTR __attribute__((noinline))
|
||||
#include "test_jhash.h"
|
||||
|
||||
SEC("scale90_noinline")
|
||||
int balancer_ingress(struct __sk_buff *ctx)
|
||||
{
|
||||
void *data_end = (void *)(long)ctx->data_end;
|
||||
void *data = (void *)(long)ctx->data;
|
||||
void *ptr;
|
||||
int ret = 0, nh_off, i = 0;
|
||||
|
||||
nh_off = 14;
|
||||
|
||||
/* pragma unroll doesn't work on large loops */
|
||||
|
||||
#define C do { \
|
||||
ptr = data + i; \
|
||||
if (ptr + nh_off > data_end) \
|
||||
break; \
|
||||
ctx->tc_index = jhash(ptr, nh_off, ctx->cb[0] + i++); \
|
||||
} while (0);
|
||||
#define C30 C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;
|
||||
C30;C30;C30; /* 90 calls */
|
||||
return 0;
|
||||
}
|
||||
char _license[] SEC("license") = "GPL";
|
30
tools/testing/selftests/bpf/progs/test_verif_scale2.c
Normal file
30
tools/testing/selftests/bpf/progs/test_verif_scale2.c
Normal file
@@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
#include <linux/bpf.h>
|
||||
#include "bpf_helpers.h"
|
||||
#define ATTR __attribute__((always_inline))
|
||||
#include "test_jhash.h"
|
||||
|
||||
SEC("scale90_inline")
|
||||
int balancer_ingress(struct __sk_buff *ctx)
|
||||
{
|
||||
void *data_end = (void *)(long)ctx->data_end;
|
||||
void *data = (void *)(long)ctx->data;
|
||||
void *ptr;
|
||||
int ret = 0, nh_off, i = 0;
|
||||
|
||||
nh_off = 14;
|
||||
|
||||
/* pragma unroll doesn't work on large loops */
|
||||
|
||||
#define C do { \
|
||||
ptr = data + i; \
|
||||
if (ptr + nh_off > data_end) \
|
||||
break; \
|
||||
ctx->tc_index = jhash(ptr, nh_off, ctx->cb[0] + i++); \
|
||||
} while (0);
|
||||
#define C30 C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;
|
||||
C30;C30;C30; /* 90 calls */
|
||||
return 0;
|
||||
}
|
||||
char _license[] SEC("license") = "GPL";
|
30
tools/testing/selftests/bpf/progs/test_verif_scale3.c
Normal file
30
tools/testing/selftests/bpf/progs/test_verif_scale3.c
Normal file
@@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
#include <linux/bpf.h>
|
||||
#include "bpf_helpers.h"
|
||||
#define ATTR __attribute__((noinline))
|
||||
#include "test_jhash.h"
|
||||
|
||||
SEC("scale90_noinline32")
|
||||
int balancer_ingress(struct __sk_buff *ctx)
|
||||
{
|
||||
void *data_end = (void *)(long)ctx->data_end;
|
||||
void *data = (void *)(long)ctx->data;
|
||||
void *ptr;
|
||||
int ret = 0, nh_off, i = 0;
|
||||
|
||||
nh_off = 32;
|
||||
|
||||
/* pragma unroll doesn't work on large loops */
|
||||
|
||||
#define C do { \
|
||||
ptr = data + i; \
|
||||
if (ptr + nh_off > data_end) \
|
||||
break; \
|
||||
ctx->tc_index = jhash(ptr, nh_off, ctx->cb[0] + i++); \
|
||||
} while (0);
|
||||
#define C30 C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;
|
||||
C30;C30;C30; /* 90 calls */
|
||||
return 0;
|
||||
}
|
||||
char _license[] SEC("license") = "GPL";
|
@@ -85,6 +85,11 @@ static int __base_pr(enum libbpf_print_level level __attribute__((unused)),
|
||||
#define BTF_UNION_ENC(name, nr_elems, sz) \
|
||||
BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_UNION, 0, nr_elems), sz)
|
||||
|
||||
#define BTF_VAR_ENC(name, type, linkage) \
|
||||
BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), type), (linkage)
|
||||
#define BTF_VAR_SECINFO_ENC(type, offset, size) \
|
||||
(type), (offset), (size)
|
||||
|
||||
#define BTF_MEMBER_ENC(name, type, bits_offset) \
|
||||
(name), (type), (bits_offset)
|
||||
#define BTF_ENUM_ENC(name, val) (name), (val)
|
||||
@@ -291,7 +296,6 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.value_type_id = 3,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "struct test #3 Invalid member offset",
|
||||
.raw_types = {
|
||||
@@ -319,7 +323,664 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid member bits_offset",
|
||||
},
|
||||
|
||||
/*
|
||||
* struct A {
|
||||
* unsigned long long m;
|
||||
* int n;
|
||||
* char o;
|
||||
* [3 bytes hole]
|
||||
* int p[8];
|
||||
* };
|
||||
*/
|
||||
{
|
||||
.descr = "global data test #1",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* unsigned long long */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */
|
||||
/* char */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 8, 1), /* [3] */
|
||||
/* int[8] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 8), /* [4] */
|
||||
/* struct A { */ /* [5] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 4), 48),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* unsigned long long m;*/
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 64),/* int n; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 3, 96),/* char o; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 4, 128),/* int p[8] */
|
||||
/* } */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0m\0n\0o\0p",
|
||||
.str_sec_size = sizeof("\0A\0m\0n\0o\0p"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "struct_test1_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 48,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 5,
|
||||
.max_entries = 4,
|
||||
},
|
||||
/*
|
||||
* struct A {
|
||||
* unsigned long long m;
|
||||
* int n;
|
||||
* char o;
|
||||
* [3 bytes hole]
|
||||
* int p[8];
|
||||
* };
|
||||
* static struct A t; <- in .bss
|
||||
*/
|
||||
{
|
||||
.descr = "global data test #2",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* unsigned long long */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */
|
||||
/* char */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 8, 1), /* [3] */
|
||||
/* int[8] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 8), /* [4] */
|
||||
/* struct A { */ /* [5] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 4), 48),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* unsigned long long m;*/
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 64),/* int n; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 3, 96),/* char o; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 4, 128),/* int p[8] */
|
||||
/* } */
|
||||
/* static struct A t */
|
||||
BTF_VAR_ENC(NAME_TBD, 5, 0), /* [6] */
|
||||
/* .bss section */ /* [7] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 48),
|
||||
BTF_VAR_SECINFO_ENC(6, 0, 48),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0m\0n\0o\0p\0t\0.bss",
|
||||
.str_sec_size = sizeof("\0A\0m\0n\0o\0p\0t\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 48,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 7,
|
||||
.max_entries = 1,
|
||||
},
|
||||
{
|
||||
.descr = "global data test #3",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* static int t */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [2] */
|
||||
/* .bss section */ /* [3] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(2, 0, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0t\0.bss",
|
||||
.str_sec_size = sizeof("\0t\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 3,
|
||||
.max_entries = 1,
|
||||
},
|
||||
{
|
||||
.descr = "global data test #4, unsupported linkage",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* static int t */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 2), /* [2] */
|
||||
/* .bss section */ /* [3] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(2, 0, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0t\0.bss",
|
||||
.str_sec_size = sizeof("\0t\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 3,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Linkage not supported",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #5, invalid var type",
|
||||
.raw_types = {
|
||||
/* static void t */
|
||||
BTF_VAR_ENC(NAME_TBD, 0, 0), /* [1] */
|
||||
/* .bss section */ /* [2] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(1, 0, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0t\0.bss",
|
||||
.str_sec_size = sizeof("\0t\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 2,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid type_id",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #6, invalid var type (fwd type)",
|
||||
.raw_types = {
|
||||
/* union A */
|
||||
BTF_TYPE_ENC(NAME_TBD,
|
||||
BTF_INFO_ENC(BTF_KIND_FWD, 1, 0), 0), /* [1] */
|
||||
/* static union A t */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [2] */
|
||||
/* .bss section */ /* [3] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(2, 0, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0t\0.bss",
|
||||
.str_sec_size = sizeof("\0A\0t\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 2,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid type",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #7, invalid var type (fwd type)",
|
||||
.raw_types = {
|
||||
/* union A */
|
||||
BTF_TYPE_ENC(NAME_TBD,
|
||||
BTF_INFO_ENC(BTF_KIND_FWD, 1, 0), 0), /* [1] */
|
||||
/* static union A t */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [2] */
|
||||
/* .bss section */ /* [3] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(1, 0, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0t\0.bss",
|
||||
.str_sec_size = sizeof("\0A\0t\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 2,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid type",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #8, invalid var size",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* unsigned long long */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */
|
||||
/* char */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 8, 1), /* [3] */
|
||||
/* int[8] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 8), /* [4] */
|
||||
/* struct A { */ /* [5] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 4), 48),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* unsigned long long m;*/
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 64),/* int n; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 3, 96),/* char o; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 4, 128),/* int p[8] */
|
||||
/* } */
|
||||
/* static struct A t */
|
||||
BTF_VAR_ENC(NAME_TBD, 5, 0), /* [6] */
|
||||
/* .bss section */ /* [7] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 48),
|
||||
BTF_VAR_SECINFO_ENC(6, 0, 47),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0m\0n\0o\0p\0t\0.bss",
|
||||
.str_sec_size = sizeof("\0A\0m\0n\0o\0p\0t\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 48,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 7,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid size",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #9, invalid var size",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* unsigned long long */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */
|
||||
/* char */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 8, 1), /* [3] */
|
||||
/* int[8] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 8), /* [4] */
|
||||
/* struct A { */ /* [5] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 4), 48),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* unsigned long long m;*/
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 64),/* int n; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 3, 96),/* char o; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 4, 128),/* int p[8] */
|
||||
/* } */
|
||||
/* static struct A t */
|
||||
BTF_VAR_ENC(NAME_TBD, 5, 0), /* [6] */
|
||||
/* .bss section */ /* [7] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 46),
|
||||
BTF_VAR_SECINFO_ENC(6, 0, 48),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0m\0n\0o\0p\0t\0.bss",
|
||||
.str_sec_size = sizeof("\0A\0m\0n\0o\0p\0t\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 48,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 7,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid size",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #10, invalid var size",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* unsigned long long */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */
|
||||
/* char */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 8, 1), /* [3] */
|
||||
/* int[8] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 8), /* [4] */
|
||||
/* struct A { */ /* [5] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 4), 48),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* unsigned long long m;*/
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 64),/* int n; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 3, 96),/* char o; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 4, 128),/* int p[8] */
|
||||
/* } */
|
||||
/* static struct A t */
|
||||
BTF_VAR_ENC(NAME_TBD, 5, 0), /* [6] */
|
||||
/* .bss section */ /* [7] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 46),
|
||||
BTF_VAR_SECINFO_ENC(6, 0, 46),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0m\0n\0o\0p\0t\0.bss",
|
||||
.str_sec_size = sizeof("\0A\0m\0n\0o\0p\0t\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 48,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 7,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid size",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #11, multiple section members",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* unsigned long long */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */
|
||||
/* char */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 8, 1), /* [3] */
|
||||
/* int[8] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 8), /* [4] */
|
||||
/* struct A { */ /* [5] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 4), 48),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* unsigned long long m;*/
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 64),/* int n; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 3, 96),/* char o; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 4, 128),/* int p[8] */
|
||||
/* } */
|
||||
/* static struct A t */
|
||||
BTF_VAR_ENC(NAME_TBD, 5, 0), /* [6] */
|
||||
/* static int u */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [7] */
|
||||
/* .bss section */ /* [8] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 2), 62),
|
||||
BTF_VAR_SECINFO_ENC(6, 10, 48),
|
||||
BTF_VAR_SECINFO_ENC(7, 58, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0m\0n\0o\0p\0t\0u\0.bss",
|
||||
.str_sec_size = sizeof("\0A\0m\0n\0o\0p\0t\0u\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 62,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 8,
|
||||
.max_entries = 1,
|
||||
},
|
||||
{
|
||||
.descr = "global data test #12, invalid offset",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* unsigned long long */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */
|
||||
/* char */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 8, 1), /* [3] */
|
||||
/* int[8] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 8), /* [4] */
|
||||
/* struct A { */ /* [5] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 4), 48),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* unsigned long long m;*/
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 64),/* int n; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 3, 96),/* char o; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 4, 128),/* int p[8] */
|
||||
/* } */
|
||||
/* static struct A t */
|
||||
BTF_VAR_ENC(NAME_TBD, 5, 0), /* [6] */
|
||||
/* static int u */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [7] */
|
||||
/* .bss section */ /* [8] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 2), 62),
|
||||
BTF_VAR_SECINFO_ENC(6, 10, 48),
|
||||
BTF_VAR_SECINFO_ENC(7, 60, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0m\0n\0o\0p\0t\0u\0.bss",
|
||||
.str_sec_size = sizeof("\0A\0m\0n\0o\0p\0t\0u\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 62,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 8,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid offset+size",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #13, invalid offset",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* unsigned long long */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */
|
||||
/* char */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 8, 1), /* [3] */
|
||||
/* int[8] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 8), /* [4] */
|
||||
/* struct A { */ /* [5] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 4), 48),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* unsigned long long m;*/
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 64),/* int n; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 3, 96),/* char o; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 4, 128),/* int p[8] */
|
||||
/* } */
|
||||
/* static struct A t */
|
||||
BTF_VAR_ENC(NAME_TBD, 5, 0), /* [6] */
|
||||
/* static int u */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [7] */
|
||||
/* .bss section */ /* [8] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 2), 62),
|
||||
BTF_VAR_SECINFO_ENC(6, 10, 48),
|
||||
BTF_VAR_SECINFO_ENC(7, 12, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0m\0n\0o\0p\0t\0u\0.bss",
|
||||
.str_sec_size = sizeof("\0A\0m\0n\0o\0p\0t\0u\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 62,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 8,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid offset",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #14, invalid offset",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* unsigned long long */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */
|
||||
/* char */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 8, 1), /* [3] */
|
||||
/* int[8] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 8), /* [4] */
|
||||
/* struct A { */ /* [5] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 4), 48),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* unsigned long long m;*/
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 64),/* int n; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 3, 96),/* char o; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 4, 128),/* int p[8] */
|
||||
/* } */
|
||||
/* static struct A t */
|
||||
BTF_VAR_ENC(NAME_TBD, 5, 0), /* [6] */
|
||||
/* static int u */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [7] */
|
||||
/* .bss section */ /* [8] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 2), 62),
|
||||
BTF_VAR_SECINFO_ENC(7, 58, 4),
|
||||
BTF_VAR_SECINFO_ENC(6, 10, 48),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0m\0n\0o\0p\0t\0u\0.bss",
|
||||
.str_sec_size = sizeof("\0A\0m\0n\0o\0p\0t\0u\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 62,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 8,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid offset",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #15, not var kind",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [2] */
|
||||
/* .bss section */ /* [3] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(1, 0, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0t\0.bss",
|
||||
.str_sec_size = sizeof("\0A\0t\0.bss"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 3,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Not a VAR kind member",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #16, invalid var referencing sec",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_VAR_ENC(NAME_TBD, 5, 0), /* [2] */
|
||||
BTF_VAR_ENC(NAME_TBD, 2, 0), /* [3] */
|
||||
/* a section */ /* [4] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(3, 0, 4),
|
||||
/* a section */ /* [5] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(6, 0, 4),
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [6] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0t\0s\0a\0a",
|
||||
.str_sec_size = sizeof("\0A\0t\0s\0a\0a"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 4,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid type_id",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #17, invalid var referencing var",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [2] */
|
||||
BTF_VAR_ENC(NAME_TBD, 2, 0), /* [3] */
|
||||
/* a section */ /* [4] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(3, 0, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0t\0s\0a\0a",
|
||||
.str_sec_size = sizeof("\0A\0t\0s\0a\0a"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 4,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid type_id",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #18, invalid var loop",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_VAR_ENC(NAME_TBD, 2, 0), /* [2] */
|
||||
/* .bss section */ /* [3] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(2, 0, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0t\0aaa",
|
||||
.str_sec_size = sizeof("\0A\0t\0aaa"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 4,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid type_id",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #19, invalid var referencing var",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_VAR_ENC(NAME_TBD, 3, 0), /* [2] */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [3] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0t\0s\0a\0a",
|
||||
.str_sec_size = sizeof("\0A\0t\0s\0a\0a"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 4,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid type_id",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #20, invalid ptr referencing var",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* PTR type_id=3 */ /* [2] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 3),
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [3] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0t\0s\0a\0a",
|
||||
.str_sec_size = sizeof("\0A\0t\0s\0a\0a"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 4,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid type_id",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #21, var included in struct",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* struct A { */ /* [2] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), sizeof(int) * 2),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int m; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 3, 32),/* VAR type_id=3; */
|
||||
/* } */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [3] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0t\0s\0a\0a",
|
||||
.str_sec_size = sizeof("\0A\0t\0s\0a\0a"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 4,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid member",
|
||||
},
|
||||
{
|
||||
.descr = "global data test #22, array of var",
|
||||
.raw_types = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ARRAY_ENC(3, 1, 4), /* [2] */
|
||||
BTF_VAR_ENC(NAME_TBD, 1, 0), /* [3] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0A\0t\0s\0a\0a",
|
||||
.str_sec_size = sizeof("\0A\0t\0s\0a\0a"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = ".bss",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 4,
|
||||
.key_type_id = 0,
|
||||
.value_type_id = 4,
|
||||
.max_entries = 1,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid elem",
|
||||
},
|
||||
/* Test member exceeds the size of struct.
|
||||
*
|
||||
* struct A {
|
||||
@@ -3677,6 +4338,7 @@ struct pprint_mapv {
|
||||
} aenum;
|
||||
uint32_t ui32b;
|
||||
uint32_t bits2c:2;
|
||||
uint8_t si8_4[2][2];
|
||||
};
|
||||
|
||||
#ifdef __SIZEOF_INT128__
|
||||
@@ -3729,7 +4391,7 @@ static struct btf_raw_test pprint_test_template[] = {
|
||||
BTF_ENUM_ENC(NAME_TBD, 2),
|
||||
BTF_ENUM_ENC(NAME_TBD, 3),
|
||||
/* struct pprint_mapv */ /* [16] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 10), 40),
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 11), 40),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 11, 0), /* uint32_t ui32 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 10, 32), /* uint16_t ui16 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 12, 64), /* int32_t si32 */
|
||||
@@ -3740,9 +4402,12 @@ static struct btf_raw_test pprint_test_template[] = {
|
||||
BTF_MEMBER_ENC(NAME_TBD, 15, 192), /* aenum */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 11, 224), /* uint32_t ui32b */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 6, 256), /* bits2c */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 17, 264), /* si8_4 */
|
||||
BTF_TYPE_ARRAY_ENC(18, 1, 2), /* [17] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 2), /* [18] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c"),
|
||||
BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c\0si8_4"),
|
||||
.key_size = sizeof(unsigned int),
|
||||
.value_size = sizeof(struct pprint_mapv),
|
||||
.key_type_id = 3, /* unsigned int */
|
||||
@@ -3791,7 +4456,7 @@ static struct btf_raw_test pprint_test_template[] = {
|
||||
BTF_ENUM_ENC(NAME_TBD, 2),
|
||||
BTF_ENUM_ENC(NAME_TBD, 3),
|
||||
/* struct pprint_mapv */ /* [16] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 10), 40),
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 11), 40),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 0)), /* uint32_t ui32 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 10, BTF_MEMBER_OFFSET(0, 32)), /* uint16_t ui16 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 12, BTF_MEMBER_OFFSET(0, 64)), /* int32_t si32 */
|
||||
@@ -3802,9 +4467,12 @@ static struct btf_raw_test pprint_test_template[] = {
|
||||
BTF_MEMBER_ENC(NAME_TBD, 15, BTF_MEMBER_OFFSET(0, 192)), /* aenum */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 224)), /* uint32_t ui32b */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 256)), /* bits2c */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 17, 264), /* si8_4 */
|
||||
BTF_TYPE_ARRAY_ENC(18, 1, 2), /* [17] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 2), /* [18] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c"),
|
||||
BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c\0si8_4"),
|
||||
.key_size = sizeof(unsigned int),
|
||||
.value_size = sizeof(struct pprint_mapv),
|
||||
.key_type_id = 3, /* unsigned int */
|
||||
@@ -3855,7 +4523,7 @@ static struct btf_raw_test pprint_test_template[] = {
|
||||
BTF_ENUM_ENC(NAME_TBD, 2),
|
||||
BTF_ENUM_ENC(NAME_TBD, 3),
|
||||
/* struct pprint_mapv */ /* [16] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 10), 40),
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 11), 40),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 0)), /* uint32_t ui32 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 10, BTF_MEMBER_OFFSET(0, 32)), /* uint16_t ui16 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 12, BTF_MEMBER_OFFSET(0, 64)), /* int32_t si32 */
|
||||
@@ -3866,13 +4534,16 @@ static struct btf_raw_test pprint_test_template[] = {
|
||||
BTF_MEMBER_ENC(NAME_TBD, 15, BTF_MEMBER_OFFSET(0, 192)), /* aenum */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 224)), /* uint32_t ui32b */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 17, BTF_MEMBER_OFFSET(2, 256)), /* bits2c */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 20, BTF_MEMBER_OFFSET(0, 264)), /* si8_4 */
|
||||
/* typedef unsigned int ___int */ /* [17] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 18),
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_VOLATILE, 0, 0), 6), /* [18] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 15), /* [19] */
|
||||
BTF_TYPE_ARRAY_ENC(21, 1, 2), /* [20] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 2), /* [21] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c\0___int"),
|
||||
BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c\0___int\0si8_4"),
|
||||
.key_size = sizeof(unsigned int),
|
||||
.value_size = sizeof(struct pprint_mapv),
|
||||
.key_type_id = 3, /* unsigned int */
|
||||
@@ -4007,6 +4678,10 @@ static void set_pprint_mapv(enum pprint_mapv_kind_t mapv_kind,
|
||||
v->aenum = i & 0x03;
|
||||
v->ui32b = 4;
|
||||
v->bits2c = 1;
|
||||
v->si8_4[0][0] = (cpu + i) & 0xff;
|
||||
v->si8_4[0][1] = (cpu + i + 1) & 0xff;
|
||||
v->si8_4[1][0] = (cpu + i + 2) & 0xff;
|
||||
v->si8_4[1][1] = (cpu + i + 3) & 0xff;
|
||||
v = (void *)v + rounded_value_size;
|
||||
}
|
||||
}
|
||||
@@ -4040,7 +4715,7 @@ ssize_t get_pprint_expected_line(enum pprint_mapv_kind_t mapv_kind,
|
||||
nexpected_line = snprintf(expected_line, line_size,
|
||||
"%s%u: {%u,0,%d,0x%x,0x%x,0x%x,"
|
||||
"{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s,"
|
||||
"%u,0x%x}\n",
|
||||
"%u,0x%x,[[%d,%d],[%d,%d]]}\n",
|
||||
percpu_map ? "\tcpu" : "",
|
||||
percpu_map ? cpu : next_key,
|
||||
v->ui32, v->si32,
|
||||
@@ -4054,7 +4729,9 @@ ssize_t get_pprint_expected_line(enum pprint_mapv_kind_t mapv_kind,
|
||||
v->ui8a[6], v->ui8a[7],
|
||||
pprint_enum_str[v->aenum],
|
||||
v->ui32b,
|
||||
v->bits2c);
|
||||
v->bits2c,
|
||||
v->si8_4[0][0], v->si8_4[0][1],
|
||||
v->si8_4[1][0], v->si8_4[1][1]);
|
||||
}
|
||||
|
||||
#ifdef __SIZEOF_INT128__
|
||||
|
@@ -9,6 +9,7 @@
|
||||
|
||||
int error_cnt, pass_cnt;
|
||||
bool jit_enabled;
|
||||
bool verifier_stats = false;
|
||||
|
||||
struct ipv4_packet pkt_v4 = {
|
||||
.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
|
||||
@@ -162,12 +163,15 @@ void *spin_lock_thread(void *arg)
|
||||
#include <prog_tests/tests.h>
|
||||
#undef DECLARE
|
||||
|
||||
int main(void)
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
srand(time(NULL));
|
||||
|
||||
jit_enabled = is_jit_enabled();
|
||||
|
||||
if (ac == 2 && strcmp(av[1], "-s") == 0)
|
||||
verifier_stats = true;
|
||||
|
||||
#define CALL
|
||||
#include <prog_tests/tests.h>
|
||||
#undef CALL
|
||||
|
@@ -40,6 +40,7 @@ typedef __u16 __sum16;
|
||||
|
||||
extern int error_cnt, pass_cnt;
|
||||
extern bool jit_enabled;
|
||||
extern bool verifier_stats;
|
||||
|
||||
#define MAGIC_BYTES 123
|
||||
|
||||
|
@@ -15,6 +15,12 @@ readonly ns2_v4=192.168.1.2
|
||||
readonly ns1_v6=fd::1
|
||||
readonly ns2_v6=fd::2
|
||||
|
||||
# Must match port used by bpf program
|
||||
readonly udpport=5555
|
||||
# MPLSoverUDP
|
||||
readonly mplsudpport=6635
|
||||
readonly mplsproto=137
|
||||
|
||||
readonly infile="$(mktemp)"
|
||||
readonly outfile="$(mktemp)"
|
||||
|
||||
@@ -38,8 +44,8 @@ setup() {
|
||||
# clamp route to reserve room for tunnel headers
|
||||
ip -netns "${ns1}" -4 route flush table main
|
||||
ip -netns "${ns1}" -6 route flush table main
|
||||
ip -netns "${ns1}" -4 route add "${ns2_v4}" mtu 1476 dev veth1
|
||||
ip -netns "${ns1}" -6 route add "${ns2_v6}" mtu 1456 dev veth1
|
||||
ip -netns "${ns1}" -4 route add "${ns2_v4}" mtu 1458 dev veth1
|
||||
ip -netns "${ns1}" -6 route add "${ns2_v6}" mtu 1438 dev veth1
|
||||
|
||||
sleep 1
|
||||
|
||||
@@ -86,30 +92,44 @@ set -e
|
||||
# no arguments: automated test, run all
|
||||
if [[ "$#" -eq "0" ]]; then
|
||||
echo "ipip"
|
||||
$0 ipv4 ipip 100
|
||||
$0 ipv4 ipip none 100
|
||||
|
||||
echo "ip6ip6"
|
||||
$0 ipv6 ip6tnl 100
|
||||
$0 ipv6 ip6tnl none 100
|
||||
|
||||
echo "ip gre"
|
||||
$0 ipv4 gre 100
|
||||
for mac in none mpls eth ; do
|
||||
echo "ip gre $mac"
|
||||
$0 ipv4 gre $mac 100
|
||||
|
||||
echo "ip6 gre"
|
||||
$0 ipv6 ip6gre 100
|
||||
echo "ip6 gre $mac"
|
||||
$0 ipv6 ip6gre $mac 100
|
||||
|
||||
echo "ip gre gso"
|
||||
$0 ipv4 gre 2000
|
||||
echo "ip gre $mac gso"
|
||||
$0 ipv4 gre $mac 2000
|
||||
|
||||
echo "ip6 gre gso"
|
||||
$0 ipv6 ip6gre 2000
|
||||
echo "ip6 gre $mac gso"
|
||||
$0 ipv6 ip6gre $mac 2000
|
||||
|
||||
echo "ip udp $mac"
|
||||
$0 ipv4 udp $mac 100
|
||||
|
||||
echo "ip6 udp $mac"
|
||||
$0 ipv6 ip6udp $mac 100
|
||||
|
||||
echo "ip udp $mac gso"
|
||||
$0 ipv4 udp $mac 2000
|
||||
|
||||
echo "ip6 udp $mac gso"
|
||||
$0 ipv6 ip6udp $mac 2000
|
||||
done
|
||||
|
||||
echo "OK. All tests passed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$#" -ne "3" ]]; then
|
||||
if [[ "$#" -ne "4" ]]; then
|
||||
echo "Usage: $0"
|
||||
echo " or: $0 <ipv4|ipv6> <tuntype> <data_len>"
|
||||
echo " or: $0 <ipv4|ipv6> <tuntype> <none|mpls|eth> <data_len>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -117,12 +137,24 @@ case "$1" in
|
||||
"ipv4")
|
||||
readonly addr1="${ns1_v4}"
|
||||
readonly addr2="${ns2_v4}"
|
||||
readonly netcat_opt=-4
|
||||
readonly ipproto=4
|
||||
readonly netcat_opt=-${ipproto}
|
||||
readonly foumod=fou
|
||||
readonly foutype=ipip
|
||||
readonly fouproto=4
|
||||
readonly fouproto_mpls=${mplsproto}
|
||||
readonly gretaptype=gretap
|
||||
;;
|
||||
"ipv6")
|
||||
readonly addr1="${ns1_v6}"
|
||||
readonly addr2="${ns2_v6}"
|
||||
readonly netcat_opt=-6
|
||||
readonly ipproto=6
|
||||
readonly netcat_opt=-${ipproto}
|
||||
readonly foumod=fou6
|
||||
readonly foutype=ip6tnl
|
||||
readonly fouproto="41 -6"
|
||||
readonly fouproto_mpls="${mplsproto} -6"
|
||||
readonly gretaptype=ip6gretap
|
||||
;;
|
||||
*)
|
||||
echo "unknown arg: $1"
|
||||
@@ -131,9 +163,10 @@ case "$1" in
|
||||
esac
|
||||
|
||||
readonly tuntype=$2
|
||||
readonly datalen=$3
|
||||
readonly mac=$3
|
||||
readonly datalen=$4
|
||||
|
||||
echo "encap ${addr1} to ${addr2}, type ${tuntype}, len ${datalen}"
|
||||
echo "encap ${addr1} to ${addr2}, type ${tuntype}, mac ${mac} len ${datalen}"
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
@@ -150,16 +183,63 @@ verify_data
|
||||
ip netns exec "${ns1}" tc qdisc add dev veth1 clsact
|
||||
ip netns exec "${ns1}" tc filter add dev veth1 egress \
|
||||
bpf direct-action object-file ./test_tc_tunnel.o \
|
||||
section "encap_${tuntype}"
|
||||
section "encap_${tuntype}_${mac}"
|
||||
echo "test bpf encap without decap (expect failure)"
|
||||
server_listen
|
||||
! client_connect
|
||||
|
||||
if [[ "$tuntype" =~ "udp" ]]; then
|
||||
# Set up fou tunnel.
|
||||
ttype="${foutype}"
|
||||
targs="encap fou encap-sport auto encap-dport $udpport"
|
||||
# fou may be a module; allow this to fail.
|
||||
modprobe "${foumod}" ||true
|
||||
if [[ "$mac" == "mpls" ]]; then
|
||||
dport=${mplsudpport}
|
||||
dproto=${fouproto_mpls}
|
||||
tmode="mode any ttl 255"
|
||||
else
|
||||
dport=${udpport}
|
||||
dproto=${fouproto}
|
||||
fi
|
||||
ip netns exec "${ns2}" ip fou add port $dport ipproto ${dproto}
|
||||
targs="encap fou encap-sport auto encap-dport $dport"
|
||||
elif [[ "$tuntype" =~ "gre" && "$mac" == "eth" ]]; then
|
||||
ttype=$gretaptype
|
||||
else
|
||||
ttype=$tuntype
|
||||
targs=""
|
||||
fi
|
||||
|
||||
# serverside, insert decap module
|
||||
# server is still running
|
||||
# client can connect again
|
||||
ip netns exec "${ns2}" ip link add dev testtun0 type "${tuntype}" \
|
||||
remote "${addr1}" local "${addr2}"
|
||||
ip netns exec "${ns2}" ip link add name testtun0 type "${ttype}" \
|
||||
${tmode} remote "${addr1}" local "${addr2}" $targs
|
||||
|
||||
expect_tun_fail=0
|
||||
|
||||
if [[ "$tuntype" == "ip6udp" && "$mac" == "mpls" ]]; then
|
||||
# No support for MPLS IPv6 fou tunnel; expect failure.
|
||||
expect_tun_fail=1
|
||||
elif [[ "$tuntype" =~ "udp" && "$mac" == "eth" ]]; then
|
||||
# No support for TEB fou tunnel; expect failure.
|
||||
expect_tun_fail=1
|
||||
elif [[ "$tuntype" =~ "gre" && "$mac" == "eth" ]]; then
|
||||
# Share ethernet address between tunnel/veth2 so L2 decap works.
|
||||
ethaddr=$(ip netns exec "${ns2}" ip link show veth2 | \
|
||||
awk '/ether/ { print $2 }')
|
||||
ip netns exec "${ns2}" ip link set testtun0 address $ethaddr
|
||||
elif [[ "$mac" == "mpls" ]]; then
|
||||
modprobe mpls_iptunnel ||true
|
||||
modprobe mpls_gso ||true
|
||||
ip netns exec "${ns2}" sysctl -qw net.mpls.platform_labels=65536
|
||||
ip netns exec "${ns2}" ip -f mpls route add 1000 dev lo
|
||||
ip netns exec "${ns2}" ip link set lo up
|
||||
ip netns exec "${ns2}" sysctl -qw net.mpls.conf.testtun0.input=1
|
||||
ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.lo.rp_filter=0
|
||||
fi
|
||||
|
||||
# Because packets are decapped by the tunnel they arrive on testtun0 from
|
||||
# the IP stack perspective. Ensure reverse path filtering is disabled
|
||||
# otherwise we drop the TCP SYN as arriving on testtun0 instead of the
|
||||
@@ -169,16 +249,22 @@ ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.all.rp_filter=0
|
||||
# selected as the max of the "all" and device-specific values.
|
||||
ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.testtun0.rp_filter=0
|
||||
ip netns exec "${ns2}" ip link set dev testtun0 up
|
||||
echo "test bpf encap with tunnel device decap"
|
||||
client_connect
|
||||
verify_data
|
||||
if [[ "$expect_tun_fail" == 1 ]]; then
|
||||
# This tunnel mode is not supported, so we expect failure.
|
||||
echo "test bpf encap with tunnel device decap (expect failure)"
|
||||
! client_connect
|
||||
else
|
||||
echo "test bpf encap with tunnel device decap"
|
||||
client_connect
|
||||
verify_data
|
||||
server_listen
|
||||
fi
|
||||
|
||||
# serverside, use BPF for decap
|
||||
ip netns exec "${ns2}" ip link del dev testtun0
|
||||
ip netns exec "${ns2}" tc qdisc add dev veth2 clsact
|
||||
ip netns exec "${ns2}" tc filter add dev veth2 ingress \
|
||||
bpf direct-action object-file ./test_tc_tunnel.o section decap
|
||||
server_listen
|
||||
echo "test bpf encap with bpf decap"
|
||||
client_connect
|
||||
verify_data
|
||||
|
@@ -50,8 +50,9 @@
|
||||
#include "../../../include/linux/filter.h"
|
||||
|
||||
#define MAX_INSNS BPF_MAXINSNS
|
||||
#define MAX_TEST_INSNS 1000000
|
||||
#define MAX_FIXUPS 8
|
||||
#define MAX_NR_MAPS 14
|
||||
#define MAX_NR_MAPS 16
|
||||
#define MAX_TEST_RUNS 8
|
||||
#define POINTER_VALUE 0xcafe4all
|
||||
#define TEST_DATA_LEN 64
|
||||
@@ -66,6 +67,7 @@ static int skips;
|
||||
struct bpf_test {
|
||||
const char *descr;
|
||||
struct bpf_insn insns[MAX_INSNS];
|
||||
struct bpf_insn *fill_insns;
|
||||
int fixup_map_hash_8b[MAX_FIXUPS];
|
||||
int fixup_map_hash_48b[MAX_FIXUPS];
|
||||
int fixup_map_hash_16b[MAX_FIXUPS];
|
||||
@@ -80,9 +82,13 @@ struct bpf_test {
|
||||
int fixup_cgroup_storage[MAX_FIXUPS];
|
||||
int fixup_percpu_cgroup_storage[MAX_FIXUPS];
|
||||
int fixup_map_spin_lock[MAX_FIXUPS];
|
||||
int fixup_map_array_ro[MAX_FIXUPS];
|
||||
int fixup_map_array_wo[MAX_FIXUPS];
|
||||
int fixup_map_array_small[MAX_FIXUPS];
|
||||
const char *errstr;
|
||||
const char *errstr_unpriv;
|
||||
uint32_t retval, retval_unpriv, insn_processed;
|
||||
int prog_len;
|
||||
enum {
|
||||
UNDEF,
|
||||
ACCEPT,
|
||||
@@ -119,10 +125,11 @@ struct other_val {
|
||||
|
||||
static void bpf_fill_ld_abs_vlan_push_pop(struct bpf_test *self)
|
||||
{
|
||||
/* test: {skb->data[0], vlan_push} x 68 + {skb->data[0], vlan_pop} x 68 */
|
||||
/* test: {skb->data[0], vlan_push} x 51 + {skb->data[0], vlan_pop} x 51 */
|
||||
#define PUSH_CNT 51
|
||||
unsigned int len = BPF_MAXINSNS;
|
||||
struct bpf_insn *insn = self->insns;
|
||||
/* jump range is limited to 16 bit. PUSH_CNT of ld_abs needs room */
|
||||
unsigned int len = (1 << 15) - PUSH_CNT * 2 * 5 * 6;
|
||||
struct bpf_insn *insn = self->fill_insns;
|
||||
int i = 0, j, k = 0;
|
||||
|
||||
insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1);
|
||||
@@ -156,12 +163,14 @@ loop:
|
||||
for (; i < len - 1; i++)
|
||||
insn[i] = BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 0xbef);
|
||||
insn[len - 1] = BPF_EXIT_INSN();
|
||||
self->prog_len = len;
|
||||
}
|
||||
|
||||
static void bpf_fill_jump_around_ld_abs(struct bpf_test *self)
|
||||
{
|
||||
struct bpf_insn *insn = self->insns;
|
||||
unsigned int len = BPF_MAXINSNS;
|
||||
struct bpf_insn *insn = self->fill_insns;
|
||||
/* jump range is limited to 16 bit. every ld_abs is replaced by 6 insns */
|
||||
unsigned int len = (1 << 15) / 6;
|
||||
int i = 0;
|
||||
|
||||
insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1);
|
||||
@@ -171,11 +180,12 @@ static void bpf_fill_jump_around_ld_abs(struct bpf_test *self)
|
||||
while (i < len - 1)
|
||||
insn[i++] = BPF_LD_ABS(BPF_B, 1);
|
||||
insn[i] = BPF_EXIT_INSN();
|
||||
self->prog_len = i + 1;
|
||||
}
|
||||
|
||||
static void bpf_fill_rand_ld_dw(struct bpf_test *self)
|
||||
{
|
||||
struct bpf_insn *insn = self->insns;
|
||||
struct bpf_insn *insn = self->fill_insns;
|
||||
uint64_t res = 0;
|
||||
int i = 0;
|
||||
|
||||
@@ -193,6 +203,7 @@ static void bpf_fill_rand_ld_dw(struct bpf_test *self)
|
||||
insn[i++] = BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 32);
|
||||
insn[i++] = BPF_ALU64_REG(BPF_XOR, BPF_REG_0, BPF_REG_1);
|
||||
insn[i] = BPF_EXIT_INSN();
|
||||
self->prog_len = i + 1;
|
||||
res ^= (res >> 32);
|
||||
self->retval = (uint32_t)res;
|
||||
}
|
||||
@@ -277,13 +288,15 @@ static bool skip_unsupported_map(enum bpf_map_type map_type)
|
||||
return false;
|
||||
}
|
||||
|
||||
static int create_map(uint32_t type, uint32_t size_key,
|
||||
uint32_t size_value, uint32_t max_elem)
|
||||
static int __create_map(uint32_t type, uint32_t size_key,
|
||||
uint32_t size_value, uint32_t max_elem,
|
||||
uint32_t extra_flags)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = bpf_create_map(type, size_key, size_value, max_elem,
|
||||
type == BPF_MAP_TYPE_HASH ? BPF_F_NO_PREALLOC : 0);
|
||||
(type == BPF_MAP_TYPE_HASH ?
|
||||
BPF_F_NO_PREALLOC : 0) | extra_flags);
|
||||
if (fd < 0) {
|
||||
if (skip_unsupported_map(type))
|
||||
return -1;
|
||||
@@ -293,6 +306,12 @@ static int create_map(uint32_t type, uint32_t size_key,
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int create_map(uint32_t type, uint32_t size_key,
|
||||
uint32_t size_value, uint32_t max_elem)
|
||||
{
|
||||
return __create_map(type, size_key, size_value, max_elem, 0);
|
||||
}
|
||||
|
||||
static void update_map(int fd, int index)
|
||||
{
|
||||
struct test_val value = {
|
||||
@@ -519,9 +538,14 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type,
|
||||
int *fixup_cgroup_storage = test->fixup_cgroup_storage;
|
||||
int *fixup_percpu_cgroup_storage = test->fixup_percpu_cgroup_storage;
|
||||
int *fixup_map_spin_lock = test->fixup_map_spin_lock;
|
||||
int *fixup_map_array_ro = test->fixup_map_array_ro;
|
||||
int *fixup_map_array_wo = test->fixup_map_array_wo;
|
||||
int *fixup_map_array_small = test->fixup_map_array_small;
|
||||
|
||||
if (test->fill_helper)
|
||||
if (test->fill_helper) {
|
||||
test->fill_insns = calloc(MAX_TEST_INSNS, sizeof(struct bpf_insn));
|
||||
test->fill_helper(test);
|
||||
}
|
||||
|
||||
/* Allocating HTs with 1 elem is fine here, since we only test
|
||||
* for verifier and not do a runtime lookup, so the only thing
|
||||
@@ -642,6 +666,35 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type,
|
||||
fixup_map_spin_lock++;
|
||||
} while (*fixup_map_spin_lock);
|
||||
}
|
||||
if (*fixup_map_array_ro) {
|
||||
map_fds[14] = __create_map(BPF_MAP_TYPE_ARRAY, sizeof(int),
|
||||
sizeof(struct test_val), 1,
|
||||
BPF_F_RDONLY_PROG);
|
||||
update_map(map_fds[14], 0);
|
||||
do {
|
||||
prog[*fixup_map_array_ro].imm = map_fds[14];
|
||||
fixup_map_array_ro++;
|
||||
} while (*fixup_map_array_ro);
|
||||
}
|
||||
if (*fixup_map_array_wo) {
|
||||
map_fds[15] = __create_map(BPF_MAP_TYPE_ARRAY, sizeof(int),
|
||||
sizeof(struct test_val), 1,
|
||||
BPF_F_WRONLY_PROG);
|
||||
update_map(map_fds[15], 0);
|
||||
do {
|
||||
prog[*fixup_map_array_wo].imm = map_fds[15];
|
||||
fixup_map_array_wo++;
|
||||
} while (*fixup_map_array_wo);
|
||||
}
|
||||
if (*fixup_map_array_small) {
|
||||
map_fds[16] = __create_map(BPF_MAP_TYPE_ARRAY, sizeof(int),
|
||||
1, 1, 0);
|
||||
update_map(map_fds[16], 0);
|
||||
do {
|
||||
prog[*fixup_map_array_small].imm = map_fds[16];
|
||||
fixup_map_array_small++;
|
||||
} while (*fixup_map_array_small);
|
||||
}
|
||||
}
|
||||
|
||||
static int set_admin(bool admin)
|
||||
@@ -718,12 +771,17 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
|
||||
prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
|
||||
fixup_skips = skips;
|
||||
do_test_fixup(test, prog_type, prog, map_fds);
|
||||
if (test->fill_insns) {
|
||||
prog = test->fill_insns;
|
||||
prog_len = test->prog_len;
|
||||
} else {
|
||||
prog_len = probe_filter_length(prog);
|
||||
}
|
||||
/* If there were some map skips during fixup due to missing bpf
|
||||
* features, skip this test.
|
||||
*/
|
||||
if (fixup_skips != skips)
|
||||
return;
|
||||
prog_len = probe_filter_length(prog);
|
||||
|
||||
pflags = 0;
|
||||
if (test->flags & F_LOAD_WITH_STRICT_ALIGNMENT)
|
||||
@@ -731,7 +789,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
|
||||
if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS)
|
||||
pflags |= BPF_F_ANY_ALIGNMENT;
|
||||
fd_prog = bpf_verify_program(prog_type, prog, prog_len, pflags,
|
||||
"GPL", 0, bpf_vlog, sizeof(bpf_vlog), 1);
|
||||
"GPL", 0, bpf_vlog, sizeof(bpf_vlog), 4);
|
||||
if (fd_prog < 0 && !bpf_probe_prog_type(prog_type, 0)) {
|
||||
printf("SKIP (unsupported program type %d)\n", prog_type);
|
||||
skips++;
|
||||
@@ -830,6 +888,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
|
||||
goto fail_log;
|
||||
}
|
||||
close_fds:
|
||||
if (test->fill_insns)
|
||||
free(test->fill_insns);
|
||||
close(fd_prog);
|
||||
for (i = 0; i < MAX_NR_MAPS; i++)
|
||||
close(map_fds[i]);
|
||||
|
@@ -52,6 +52,10 @@ struct ksym *ksym_search(long key)
|
||||
int start = 0, end = sym_cnt;
|
||||
int result;
|
||||
|
||||
/* kallsyms not loaded. return NULL */
|
||||
if (sym_cnt <= 0)
|
||||
return NULL;
|
||||
|
||||
while (start < end) {
|
||||
size_t mid = start + (end - start) / 2;
|
||||
|
||||
|
@@ -217,3 +217,162 @@
|
||||
.result = REJECT,
|
||||
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
|
||||
},
|
||||
{
|
||||
"valid read map access into a read-only array 1",
|
||||
.insns = {
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
|
||||
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_ro = { 3 },
|
||||
.result = ACCEPT,
|
||||
.retval = 28,
|
||||
},
|
||||
{
|
||||
"valid read map access into a read-only array 2",
|
||||
.insns = {
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
|
||||
BPF_MOV64_IMM(BPF_REG_2, 4),
|
||||
BPF_MOV64_IMM(BPF_REG_3, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_4, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_5, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_csum_diff),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
.fixup_map_array_ro = { 3 },
|
||||
.result = ACCEPT,
|
||||
.retval = -29,
|
||||
},
|
||||
{
|
||||
"invalid write map access into a read-only array 1",
|
||||
.insns = {
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 42),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_ro = { 3 },
|
||||
.result = REJECT,
|
||||
.errstr = "write into map forbidden",
|
||||
},
|
||||
{
|
||||
"invalid write map access into a read-only array 2",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
|
||||
BPF_MOV64_IMM(BPF_REG_2, 0),
|
||||
BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
|
||||
BPF_MOV64_IMM(BPF_REG_4, 8),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_skb_load_bytes),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
.fixup_map_array_ro = { 4 },
|
||||
.result = REJECT,
|
||||
.errstr = "write into map forbidden",
|
||||
},
|
||||
{
|
||||
"valid write map access into a write-only array 1",
|
||||
.insns = {
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 42),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_wo = { 3 },
|
||||
.result = ACCEPT,
|
||||
.retval = 1,
|
||||
},
|
||||
{
|
||||
"valid write map access into a write-only array 2",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
|
||||
BPF_MOV64_IMM(BPF_REG_2, 0),
|
||||
BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
|
||||
BPF_MOV64_IMM(BPF_REG_4, 8),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_skb_load_bytes),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
.fixup_map_array_wo = { 4 },
|
||||
.result = ACCEPT,
|
||||
.retval = 0,
|
||||
},
|
||||
{
|
||||
"invalid read map access into a write-only array 1",
|
||||
.insns = {
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
|
||||
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_wo = { 3 },
|
||||
.result = REJECT,
|
||||
.errstr = "read from map forbidden",
|
||||
},
|
||||
{
|
||||
"invalid read map access into a write-only array 2",
|
||||
.insns = {
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
|
||||
BPF_MOV64_IMM(BPF_REG_2, 4),
|
||||
BPF_MOV64_IMM(BPF_REG_3, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_4, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_5, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_csum_diff),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
.fixup_map_array_wo = { 3 },
|
||||
.result = REJECT,
|
||||
.errstr = "read from map forbidden",
|
||||
},
|
||||
|
@@ -705,7 +705,6 @@
|
||||
.errstr = "invalid bpf_context access",
|
||||
.result = REJECT,
|
||||
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
|
||||
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
|
||||
},
|
||||
{
|
||||
"check cb access: half, wrong type",
|
||||
|
347
tools/testing/selftests/bpf/verifier/direct_value_access.c
Normal file
347
tools/testing/selftests/bpf/verifier/direct_value_access.c
Normal file
@@ -0,0 +1,347 @@
|
||||
{
|
||||
"direct map access, write test 1",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 0),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 4242),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = ACCEPT,
|
||||
.retval = 1,
|
||||
},
|
||||
{
|
||||
"direct map access, write test 2",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 4242),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = ACCEPT,
|
||||
.retval = 1,
|
||||
},
|
||||
{
|
||||
"direct map access, write test 3",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 4242),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = ACCEPT,
|
||||
.retval = 1,
|
||||
},
|
||||
{
|
||||
"direct map access, write test 4",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 40),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 4242),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = ACCEPT,
|
||||
.retval = 1,
|
||||
},
|
||||
{
|
||||
"direct map access, write test 5",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 32),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 4242),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = ACCEPT,
|
||||
.retval = 1,
|
||||
},
|
||||
{
|
||||
"direct map access, write test 6",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 40),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, 4, 4242),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "R1 min value is outside of the array range",
|
||||
},
|
||||
{
|
||||
"direct map access, write test 7",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, -1),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, 4, 4242),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "direct value offset of 4294967295 is not allowed",
|
||||
},
|
||||
{
|
||||
"direct map access, write test 8",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 1),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, -1, 4242),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = ACCEPT,
|
||||
.retval = 1,
|
||||
},
|
||||
{
|
||||
"direct map access, write test 9",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 48),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 4242),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value pointer",
|
||||
},
|
||||
{
|
||||
"direct map access, write test 10",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 47),
|
||||
BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 4),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = ACCEPT,
|
||||
.retval = 1,
|
||||
},
|
||||
{
|
||||
"direct map access, write test 11",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 48),
|
||||
BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 4),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value pointer",
|
||||
},
|
||||
{
|
||||
"direct map access, write test 12",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, (1<<29)),
|
||||
BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 4),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "direct value offset of 536870912 is not allowed",
|
||||
},
|
||||
{
|
||||
"direct map access, write test 13",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, (1<<29)-1),
|
||||
BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 4),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value pointer, value_size=48 off=536870911",
|
||||
},
|
||||
{
|
||||
"direct map access, write test 14",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 47),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_2, 0, 46),
|
||||
BPF_ST_MEM(BPF_H, BPF_REG_2, 0, 0xffff),
|
||||
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1, 3 },
|
||||
.result = ACCEPT,
|
||||
.retval = 0xff,
|
||||
},
|
||||
{
|
||||
"direct map access, write test 15",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 46),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_2, 0, 46),
|
||||
BPF_ST_MEM(BPF_H, BPF_REG_2, 0, 0xffff),
|
||||
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1, 3 },
|
||||
.result = ACCEPT,
|
||||
.retval = 0xffff,
|
||||
},
|
||||
{
|
||||
"direct map access, write test 16",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 46),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_2, 0, 47),
|
||||
BPF_ST_MEM(BPF_H, BPF_REG_2, 0, 0xffff),
|
||||
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1, 3 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=48 off=47 size=2",
|
||||
},
|
||||
{
|
||||
"direct map access, write test 17",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 46),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_2, 0, 46),
|
||||
BPF_ST_MEM(BPF_H, BPF_REG_2, 1, 0xffff),
|
||||
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1, 3 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=48 off=47 size=2",
|
||||
},
|
||||
{
|
||||
"direct map access, write test 18",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 0),
|
||||
BPF_ST_MEM(BPF_H, BPF_REG_1, 0, 42),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_small = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "R1 min value is outside of the array range",
|
||||
},
|
||||
{
|
||||
"direct map access, write test 19",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 0),
|
||||
BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_small = { 1 },
|
||||
.result = ACCEPT,
|
||||
.retval = 1,
|
||||
},
|
||||
{
|
||||
"direct map access, write test 20",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 1),
|
||||
BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_small = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value pointer",
|
||||
},
|
||||
{
|
||||
"direct map access, invalid insn test 1",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_VALUE, 0, 1, 0, 47),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid bpf_ld_imm64 insn",
|
||||
},
|
||||
{
|
||||
"direct map access, invalid insn test 2",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_VALUE, 1, 0, 0, 47),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "BPF_LD_IMM64 uses reserved fields",
|
||||
},
|
||||
{
|
||||
"direct map access, invalid insn test 3",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_VALUE, ~0, 0, 0, 47),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "BPF_LD_IMM64 uses reserved fields",
|
||||
},
|
||||
{
|
||||
"direct map access, invalid insn test 4",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_VALUE, 0, ~0, 0, 47),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid bpf_ld_imm64 insn",
|
||||
},
|
||||
{
|
||||
"direct map access, invalid insn test 5",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_VALUE, ~0, ~0, 0, 47),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid bpf_ld_imm64 insn",
|
||||
},
|
||||
{
|
||||
"direct map access, invalid insn test 6",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_FD, ~0, 0, 0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "BPF_LD_IMM64 uses reserved fields",
|
||||
},
|
||||
{
|
||||
"direct map access, invalid insn test 7",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_FD, 0, ~0, 0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid bpf_ld_imm64 insn",
|
||||
},
|
||||
{
|
||||
"direct map access, invalid insn test 8",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_FD, ~0, ~0, 0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid bpf_ld_imm64 insn",
|
||||
},
|
||||
{
|
||||
"direct map access, invalid insn test 9",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_FD, 0, 0, 0, 47),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_array_48b = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "unrecognized bpf_ld_imm64 insn",
|
||||
},
|
@@ -34,3 +34,12 @@
|
||||
.result = ACCEPT,
|
||||
.retval = 5,
|
||||
},
|
||||
{
|
||||
"ld_dw: xor semi-random 64 bit imms, test 5",
|
||||
.insns = { },
|
||||
.data = { },
|
||||
.fill_helper = bpf_fill_rand_ld_dw,
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
.result = ACCEPT,
|
||||
.retval = 1000000 - 6,
|
||||
},
|
||||
|
@@ -40,7 +40,35 @@
|
||||
.prog_type = BPF_PROG_TYPE_LWT_IN,
|
||||
},
|
||||
{
|
||||
"indirect variable-offset stack access",
|
||||
"indirect variable-offset stack access, unbounded",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_2, 6),
|
||||
BPF_MOV64_IMM(BPF_REG_3, 28),
|
||||
/* Fill the top 16 bytes of the stack. */
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
/* Get an unknown value. */
|
||||
BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_1, offsetof(struct bpf_sock_ops,
|
||||
bytes_received)),
|
||||
/* Check the lower bound but don't check the upper one. */
|
||||
BPF_JMP_IMM(BPF_JSLT, BPF_REG_4, 0, 4),
|
||||
/* Point the lower bound to initialized stack. Offset is now in range
|
||||
* from fp-16 to fp+0x7fffffffffffffef, i.e. max value is unbounded.
|
||||
*/
|
||||
BPF_ALU64_IMM(BPF_SUB, BPF_REG_4, 16),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_10),
|
||||
BPF_MOV64_IMM(BPF_REG_5, 8),
|
||||
/* Dereference it indirectly. */
|
||||
BPF_EMIT_CALL(BPF_FUNC_getsockopt),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "R4 unbounded indirect variable offset stack access",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_SOCK_OPS,
|
||||
},
|
||||
{
|
||||
"indirect variable-offset stack access, max out of bound",
|
||||
.insns = {
|
||||
/* Fill the top 8 bytes of the stack */
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
@@ -60,7 +88,161 @@
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_hash_8b = { 5 },
|
||||
.errstr = "variable stack read R2",
|
||||
.errstr = "R2 max value is outside of stack bound",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_LWT_IN,
|
||||
},
|
||||
{
|
||||
"indirect variable-offset stack access, min out of bound",
|
||||
.insns = {
|
||||
/* Fill the top 8 bytes of the stack */
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
/* Get an unknown value */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
|
||||
/* Make it small and 4-byte aligned */
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
|
||||
BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 516),
|
||||
/* add it to fp. We now have either fp-516 or fp-512, but
|
||||
* we don't know which
|
||||
*/
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
|
||||
/* dereference it indirectly */
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_hash_8b = { 5 },
|
||||
.errstr = "R2 min value is outside of stack bound",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_LWT_IN,
|
||||
},
|
||||
{
|
||||
"indirect variable-offset stack access, max_off+size > max_initialized",
|
||||
.insns = {
|
||||
/* Fill only the second from top 8 bytes of the stack. */
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
|
||||
/* Get an unknown value. */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
|
||||
/* Make it small and 4-byte aligned. */
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
|
||||
BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
|
||||
/* Add it to fp. We now have either fp-12 or fp-16, but we don't know
|
||||
* which. fp-12 size 8 is partially uninitialized stack.
|
||||
*/
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
|
||||
/* Dereference it indirectly. */
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_hash_8b = { 5 },
|
||||
.errstr = "invalid indirect read from stack var_off",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_LWT_IN,
|
||||
},
|
||||
{
|
||||
"indirect variable-offset stack access, min_off < min_initialized",
|
||||
.insns = {
|
||||
/* Fill only the top 8 bytes of the stack. */
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
/* Get an unknown value */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
|
||||
/* Make it small and 4-byte aligned. */
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
|
||||
BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
|
||||
/* Add it to fp. We now have either fp-12 or fp-16, but we don't know
|
||||
* which. fp-16 size 8 is partially uninitialized stack.
|
||||
*/
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
|
||||
/* Dereference it indirectly. */
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_hash_8b = { 5 },
|
||||
.errstr = "invalid indirect read from stack var_off",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_LWT_IN,
|
||||
},
|
||||
{
|
||||
"indirect variable-offset stack access, priv vs unpriv",
|
||||
.insns = {
|
||||
/* Fill the top 16 bytes of the stack. */
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
/* Get an unknown value. */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
|
||||
/* Make it small and 4-byte aligned. */
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
|
||||
BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
|
||||
/* Add it to fp. We now have either fp-12 or fp-16, we don't know
|
||||
* which, but either way it points to initialized stack.
|
||||
*/
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
|
||||
/* Dereference it indirectly. */
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_hash_8b = { 6 },
|
||||
.errstr_unpriv = "R2 stack pointer arithmetic goes out of range, prohibited for !root",
|
||||
.result_unpriv = REJECT,
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
|
||||
},
|
||||
{
|
||||
"indirect variable-offset stack access, uninitialized",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_2, 6),
|
||||
BPF_MOV64_IMM(BPF_REG_3, 28),
|
||||
/* Fill the top 16 bytes of the stack. */
|
||||
BPF_ST_MEM(BPF_W, BPF_REG_10, -16, 0),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
/* Get an unknown value. */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, 0),
|
||||
/* Make it small and 4-byte aligned. */
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_4, 4),
|
||||
BPF_ALU64_IMM(BPF_SUB, BPF_REG_4, 16),
|
||||
/* Add it to fp. We now have either fp-12 or fp-16, we don't know
|
||||
* which, but either way it points to initialized stack.
|
||||
*/
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_10),
|
||||
BPF_MOV64_IMM(BPF_REG_5, 8),
|
||||
/* Dereference it indirectly. */
|
||||
BPF_EMIT_CALL(BPF_FUNC_getsockopt),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid indirect read from stack var_off",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_SOCK_OPS,
|
||||
},
|
||||
{
|
||||
"indirect variable-offset stack access, ok",
|
||||
.insns = {
|
||||
/* Fill the top 16 bytes of the stack. */
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
/* Get an unknown value. */
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
|
||||
/* Make it small and 4-byte aligned. */
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
|
||||
BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
|
||||
/* Add it to fp. We now have either fp-12 or fp-16, we don't know
|
||||
* which, but either way it points to initialized stack.
|
||||
*/
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
|
||||
/* Dereference it indirectly. */
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_hash_8b = { 6 },
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_LWT_IN,
|
||||
},
|
||||
|
Reference in New Issue
Block a user