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:
@@ -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);
|
||||
}
|
Reference in New Issue
Block a user