tests: refactor bpf test

The aim of this change is to introduce an ability to perform multiple
checks for a specific bpf command.  In order to achieve so, all the
related data is stored in check descriptor, and test_bpf iterates over
it.  There are also some provisions made in regard to future changes
(specifically, the way bpf_attr_data union is defined).

* tests/bpf.c (print_bpf_attr): New function, a wrapper around
struct bpf_check.printer.
(test_bpf_): Rename to...
(test_bpf): ...this.  Replace arguments with struct bpf_check pointer.
Iterate over possible attribute variants. Account for changes in
attribute initialisation routine: provide a pointer to locally defined
union bpf_attr_data and perform memcpy afterwards. Initialise memory
from data each time before a bpf call.
(TEST_BPF, DEF_*, init_*, print_*): Remove.
(init_BPF_PROG_LOAD_attr, print_BPF_PROG_LOAD_attr,
init_BPF_OBJ_PIN_attr): New functions.
(license, pathname): New variables.
(BPF_MAP_CREATE_checks, BPF_MAP_LOOKUP_ELEM_checks,
BPF_MAP_UPDATE_ELEM_checks, BPF_MAP_DELETE_ELEM_checks,
BPF_MAP_GET_NEXT_KEY_checks, BPF_PROG_LOAD_checks, BPF_OBJ_PIN_checks,
BPF_PROG_ATTACH_checks, BPF_PROG_DETACH_checks,
BPF_PROG_TEST_RUN_checks, BPF_PROG_GET_NEXT_ID_checks,
BPF_PROG_GET_FD_BY_ID_checks, BPF_MAP_GET_FD_BY_ID_checks,
BPF_OBJ_GET_INFO_BY_FD_checks): New arrays.
(BPF_OBJ_GET_checks, BPF_MAP_GET_NEXT_ID_checks): New macros.
(CHK): New macro, a shorthand for initialising array of struct bpf_check.
(main): New static constant checks, iterate over checks and run test_bpf
with each element.

Co-Authored-by: Dmitry V. Levin <ldv@altlinux.org>
This commit is contained in:
Eugene Syromyatnikov 2018-03-21 19:10:15 +01:00 committed by Dmitry V. Levin
parent 82120681e3
commit 737762cb85

View File

@ -78,6 +78,22 @@ union bpf_attr_data {
char char_data[256];
};
struct bpf_attr_check {
union bpf_attr_data data;
size_t size;
const char *str;
void (*init_fn)(struct bpf_attr_check *check);
void (*print_fn)(const struct bpf_attr_check *check,
unsigned long addr);
};
struct bpf_check {
kernel_ulong_t cmd;
const char *cmd_str;
const struct bpf_attr_check *checks;
size_t count;
};
static const kernel_ulong_t long_bits = (kernel_ulong_t) 0xfacefeed00000000ULL;
static const char *errstr;
static unsigned int sizeof_attr = sizeof(union bpf_attr_data);
@ -103,77 +119,78 @@ sys_bpf(kernel_ulong_t cmd, kernel_ulong_t attr, kernel_ulong_t size)
#endif
static void
test_bpf_(kernel_ulong_t cmd, const char *cmd_str,
unsigned int (*init_first)(const unsigned long eop),
void (*print_first)(const unsigned long eop),
unsigned int (*init_attr)(const unsigned long eop),
void (*print_attr)(const unsigned long eop))
print_bpf_attr(const struct bpf_attr_check *check, unsigned long addr)
{
if (check->print_fn)
check->print_fn(check, addr);
else
printf("%s", check->str);
}
static void
test_bpf(const struct bpf_check *cmd_check)
{
const struct bpf_attr_check *check = 0;
const union bpf_attr_data *data = 0;
unsigned int offset = 0;
/* zero addr */
sys_bpf(cmd, 0, long_bits | sizeof(union bpf_attr_data));
sys_bpf(cmd_check->cmd, 0, long_bits | sizeof(union bpf_attr_data));
printf("bpf(%s, NULL, %u) = %s\n",
cmd_str, sizeof_attr, errstr);
cmd_check->cmd_str, sizeof_attr, errstr);
/* zero size */
unsigned long addr = end_of_page - sizeof_attr;
sys_bpf(cmd, addr, long_bits);
sys_bpf(cmd_check->cmd, addr, long_bits);
printf("bpf(%s, %#lx, 0) = %s\n",
cmd_str, addr, errstr);
cmd_check->cmd_str, addr, errstr);
/* the first field only */
unsigned int offset = init_first(end_of_page);
addr = end_of_page - offset;
sys_bpf(cmd, addr, offset);
printf("bpf(%s, {", cmd_str);
print_first(addr);
printf("}, %u) = %s\n", offset, errstr);
for (size_t i = 0; i < cmd_check->count; i++) {
check = &cmd_check->checks[i];
if (check->init_fn)
check->init_fn((struct bpf_attr_check *) check);
data = &check->data;
offset = check->size;
/* efault after the first field */
sys_bpf(cmd, addr, offset + 1);
printf("bpf(%s, %#lx, %u) = %s\n",
cmd_str, addr, offset + 1, errstr);
addr = end_of_page - offset;
memcpy((void *) addr, data, offset);
/* the relevant part of bpf_attr_data */
offset = init_attr(end_of_page);
addr = end_of_page - offset;
sys_bpf(cmd, addr, offset);
printf("bpf(%s, {", cmd_str);
print_attr(addr);
printf("}, %u) = %s\n", offset, errstr);
/* starting piece of bpf_attr_data */
sys_bpf(cmd_check->cmd, addr, offset);
printf("bpf(%s, {", cmd_check->cmd_str);
print_bpf_attr(check, addr);
printf("}, %u) = %s\n", offset, errstr);
/* short read of the relevant part of bpf_attr_data */
sys_bpf(cmd, addr + 1, offset);
printf("bpf(%s, %#lx, %u) = %s\n",
cmd_str, addr + 1, offset, errstr);
/* short read of the starting piece */
sys_bpf(cmd_check->cmd, addr + 1, offset);
printf("bpf(%s, %#lx, %u) = %s\n",
cmd_check->cmd_str, addr + 1, offset, errstr);
}
if (offset < sizeof_attr) {
/* short read of the whole bpf_attr_data */
memmove((void *) end_of_page - sizeof_attr + 1,
(void *) addr, offset);
memcpy((void *) end_of_page - sizeof_attr + 1, data, offset);
addr = end_of_page - sizeof_attr + 1;
memset((void *) addr + offset, 0,
sizeof_attr - offset - 1);
sys_bpf(cmd, addr, sizeof_attr);
memset((void *) addr + offset, 0, sizeof_attr - offset - 1);
sys_bpf(cmd_check->cmd, addr, sizeof_attr);
printf("bpf(%s, %#lx, %u) = %s\n",
cmd_str, addr, sizeof_attr, errstr);
cmd_check->cmd_str, addr, sizeof_attr, errstr);
/* the whole bpf_attr_data */
memmove((void *) end_of_page - sizeof_attr,
(void *) addr, offset);
memcpy((void *) end_of_page - sizeof_attr, data, offset);
addr = end_of_page - sizeof_attr;
memset((void *) addr + offset, 0,
sizeof_attr - offset);
sys_bpf(cmd, addr, sizeof_attr);
printf("bpf(%s, {", cmd_str);
print_attr(addr);
memset((void *) addr + offset, 0, sizeof_attr - offset);
sys_bpf(cmd_check->cmd, addr, sizeof_attr);
printf("bpf(%s, {", cmd_check->cmd_str);
print_bpf_attr(check, addr);
printf("}, %u) = %s\n", sizeof_attr, errstr);
/* non-zero bytes after the relevant part */
fill_memory_ex((void *) addr + offset,
sizeof_attr - offset, '0', 10);
sys_bpf(cmd, addr, sizeof_attr);
printf("bpf(%s, {", cmd_str);
print_attr(addr);
sys_bpf(cmd_check->cmd, addr, sizeof_attr);
printf("bpf(%s, {", cmd_check->cmd_str);
print_bpf_attr(check, addr);
printf(", ");
print_extra_data((char *) addr, offset,
sizeof_attr - offset);
@ -181,532 +198,379 @@ test_bpf_(kernel_ulong_t cmd, const char *cmd_str,
}
/* short read of the whole page */
memmove((void *) end_of_page - page_size + 1,
(void *) addr, offset);
memcpy((void *) end_of_page - page_size + 1, data, offset);
addr = end_of_page - page_size + 1;
memset((void *) addr + offset, 0,
page_size - offset - 1);
sys_bpf(cmd, addr, page_size);
memset((void *) addr + offset, 0, page_size - offset - 1);
sys_bpf(cmd_check->cmd, addr, page_size);
printf("bpf(%s, %#lx, %u) = %s\n",
cmd_str, addr, page_size, errstr);
cmd_check->cmd_str, addr, page_size, errstr);
/* the whole page */
memmove((void *) end_of_page - page_size,
(void *) addr, offset);
memcpy((void *) end_of_page - page_size, data, offset);
addr = end_of_page - page_size;
memset((void *) addr + offset, 0, page_size - offset);
sys_bpf(cmd, addr, page_size);
printf("bpf(%s, {", cmd_str);
print_attr(addr);
sys_bpf(cmd_check->cmd, addr, page_size);
printf("bpf(%s, {", cmd_check->cmd_str);
print_bpf_attr(check, addr);
printf("}, %u) = %s\n", page_size, errstr);
/* non-zero bytes after the whole bpf_attr_data */
fill_memory_ex((void *) addr + offset,
page_size - offset, '0', 10);
sys_bpf(cmd, addr, page_size);
printf("bpf(%s, {", cmd_str);
print_attr(addr);
sys_bpf(cmd_check->cmd, addr, page_size);
printf("bpf(%s, {", cmd_check->cmd_str);
print_bpf_attr(check, addr);
printf(", ");
print_extra_data((char *) addr, offset,
page_size - offset);
printf("}, %u) = %s\n", page_size, errstr);
/* more than a page */
sys_bpf(cmd, addr, page_size + 1);
sys_bpf(cmd_check->cmd, addr, page_size + 1);
printf("bpf(%s, %#lx, %u) = %s\n",
cmd_str, addr, page_size + 1, errstr);
cmd_check->cmd_str, addr, page_size + 1, errstr);
}
#define TEST_BPF(cmd_) \
test_bpf_((cmd_), #cmd_, \
init_ ## cmd_ ## _first, print_ ## cmd_ ## _first, \
init_ ## cmd_ ## _attr, print_ ## cmd_ ## _attr) \
/* End of TEST_BPF definition. */
static const struct bpf_attr_check BPF_MAP_CREATE_checks[] = {
{
.data = { .BPF_MAP_CREATE_data = { .map_type = 2 } },
.size = offsetofend(struct BPF_MAP_CREATE_struct, map_type),
.str = "map_type=BPF_MAP_TYPE_ARRAY, key_size=0, value_size=0"
", max_entries=0, map_flags=0, inner_map_fd=0"
},
{
.data = { .BPF_MAP_CREATE_data = {
.map_type = 1,
.key_size = 4,
.value_size = 8,
.max_entries = 256,
.map_flags = 7,
.inner_map_fd = -1,
.numa_node = 42
} },
.size = offsetofend(struct BPF_MAP_CREATE_struct, numa_node),
.str = "map_type=BPF_MAP_TYPE_HASH, key_size=4"
", value_size=8, max_entries=256"
", map_flags=BPF_F_NO_PREALLOC|BPF_F_NO_COMMON_LRU"
"|BPF_F_NUMA_NODE, inner_map_fd=-1, numa_node=42"
}
};
#define DEF_BPF_INIT_FIRST(cmd_, field_, value_) \
static unsigned int \
init_ ## cmd_ ## _first(const unsigned long eop) \
{ \
static const struct cmd_ ## _struct attr = { \
.field_ = value_ \
}; \
static const unsigned int offset = sizeof(attr.field_); \
const unsigned long addr = eop - offset; \
\
memcpy((void *) addr, &attr.field_, offset); \
return offset; \
} \
/* End of DEF_INIT_FIRST definition. */
static const struct bpf_attr_check BPF_MAP_LOOKUP_ELEM_checks[] = {
{
.data = { .BPF_MAP_LOOKUP_ELEM_data = { .map_fd = -1 } },
.size = offsetofend(struct BPF_MAP_LOOKUP_ELEM_struct, map_fd),
.str = "map_fd=-1, key=0, value=0"
},
{
.data = { .BPF_MAP_LOOKUP_ELEM_data = {
.map_fd = -1,
.key = 0xdeadbeef,
.value = 0xbadc0ded
} },
.size = offsetofend(struct BPF_MAP_LOOKUP_ELEM_struct, value),
.str = "map_fd=-1, key=0xdeadbeef, value=0xbadc0ded"
}
};
DEF_BPF_INIT_FIRST(BPF_MAP_CREATE, map_type, 2)
static const struct bpf_attr_check BPF_MAP_UPDATE_ELEM_checks[] = {
{
.data = { .BPF_MAP_UPDATE_ELEM_data = { .map_fd = -1 } },
.size = offsetofend(struct BPF_MAP_UPDATE_ELEM_struct, map_fd),
.str = "map_fd=-1, key=0, value=0, flags=BPF_ANY"
},
{
.data = { .BPF_MAP_UPDATE_ELEM_data = {
.map_fd = -1,
.key = 0xdeadbeef,
.value = 0xbadc0ded,
.flags = 2
} },
.size = offsetofend(struct BPF_MAP_UPDATE_ELEM_struct, flags),
.str = "map_fd=-1, key=0xdeadbeef, value=0xbadc0ded"
", flags=BPF_EXIST"
}
};
static void
print_BPF_MAP_CREATE_first(const unsigned long addr)
{
printf("map_type=BPF_MAP_TYPE_ARRAY, key_size=0, value_size=0"
", max_entries=0, map_flags=0, inner_map_fd=0");
}
static const struct bpf_attr_check BPF_MAP_DELETE_ELEM_checks[] = {
{
.data = { .BPF_MAP_DELETE_ELEM_data = { .map_fd = -1 } },
.size = offsetofend(struct BPF_MAP_DELETE_ELEM_struct, map_fd),
.str = "map_fd=-1, key=0"
},
{
.data = { .BPF_MAP_DELETE_ELEM_data = {
.map_fd = -1,
.key = 0xdeadbeef
} },
.size = offsetofend(struct BPF_MAP_DELETE_ELEM_struct, key),
.str = "map_fd=-1, key=0xdeadbeef"
}
};
static unsigned int
init_BPF_MAP_CREATE_attr(const unsigned long eop)
{
static const struct BPF_MAP_CREATE_struct attr = {
.map_type = 1,
.key_size = 4,
.value_size = 8,
.max_entries = 256,
.map_flags = 7,
.inner_map_fd = -1,
.numa_node = 42
};
static const unsigned int offset =
offsetofend(struct BPF_MAP_CREATE_struct, numa_node);
const unsigned long addr = eop - offset;
memcpy((void *) addr, &attr, offset);
return offset;
}
static void
print_BPF_MAP_CREATE_attr(const unsigned long addr)
{
printf("map_type=BPF_MAP_TYPE_HASH, key_size=4"
", value_size=8, max_entries=256"
", map_flags=BPF_F_NO_PREALLOC|BPF_F_NO_COMMON_LRU"
"|BPF_F_NUMA_NODE, inner_map_fd=-1, numa_node=42");
}
DEF_BPF_INIT_FIRST(BPF_MAP_LOOKUP_ELEM, map_fd, -1)
static void
print_BPF_MAP_LOOKUP_ELEM_first(const unsigned long addr)
{
printf("map_fd=-1, key=0, value=0");
}
static unsigned int
init_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long eop)
{
static const struct BPF_MAP_LOOKUP_ELEM_struct attr = {
.map_fd = -1,
.key = 0xdeadbeef,
.value = 0xbadc0ded
};
static const unsigned int offset =
offsetofend(struct BPF_MAP_LOOKUP_ELEM_struct, value);
const unsigned long addr = eop - offset;
memcpy((void *) addr, &attr, offset);
return offset;
}
static void
print_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long addr)
{
printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded");
}
#define init_BPF_MAP_UPDATE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first
static void
print_BPF_MAP_UPDATE_ELEM_first(const unsigned long addr)
{
printf("map_fd=-1, key=0, value=0, flags=BPF_ANY");
}
static unsigned int
init_BPF_MAP_UPDATE_ELEM_attr(const unsigned long eop)
{
static const struct BPF_MAP_UPDATE_ELEM_struct attr = {
.map_fd = -1,
.key = 0xdeadbeef,
.value = 0xbadc0ded,
.flags = 2
};
static const unsigned int offset =
offsetofend(struct BPF_MAP_UPDATE_ELEM_struct, flags);
const unsigned long addr = eop - offset;
memcpy((void *) addr, &attr, offset);
return offset;
}
static void
print_BPF_MAP_UPDATE_ELEM_attr(const unsigned long addr)
{
printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded, flags=BPF_EXIST");
}
#define init_BPF_MAP_DELETE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first
static void
print_BPF_MAP_DELETE_ELEM_first(const unsigned long addr)
{
printf("map_fd=-1, key=0");
}
static unsigned int
init_BPF_MAP_DELETE_ELEM_attr(const unsigned long eop)
{
static const struct BPF_MAP_DELETE_ELEM_struct attr = {
.map_fd = -1,
.key = 0xdeadbeef
};
static const unsigned int offset =
offsetofend(struct BPF_MAP_DELETE_ELEM_struct, key);
const unsigned long addr = eop - offset;
memcpy((void *) addr, &attr, offset);
return offset;
}
static void
print_BPF_MAP_DELETE_ELEM_attr(const unsigned long addr)
{
printf("map_fd=-1, key=0xdeadbeef");
}
#define init_BPF_MAP_GET_NEXT_KEY_first init_BPF_MAP_LOOKUP_ELEM_first
static void
print_BPF_MAP_GET_NEXT_KEY_first(const unsigned long addr)
{
printf("map_fd=-1, key=0, next_key=0");
}
static unsigned int
init_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long eop)
{
static const struct BPF_MAP_GET_NEXT_KEY_struct attr = {
.map_fd = -1,
.key = 0xdeadbeef,
.next_key = 0xbadc0ded
};
static const unsigned int offset =
offsetofend(struct BPF_MAP_GET_NEXT_KEY_struct, next_key);
const unsigned long addr = eop - offset;
memcpy((void *) addr, &attr, offset);
return offset;
}
static void
print_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long addr)
{
printf("map_fd=-1, key=0xdeadbeef, next_key=0xbadc0ded");
}
DEF_BPF_INIT_FIRST(BPF_PROG_LOAD, prog_type, 1)
static void
print_BPF_PROG_LOAD_first(const unsigned long addr)
{
printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=0, insns=0"
", license=NULL");
}
static const struct bpf_attr_check BPF_MAP_GET_NEXT_KEY_checks[] = {
{
.data = { .BPF_MAP_GET_NEXT_KEY_data = { .map_fd = -1 } },
.size = offsetofend(struct BPF_MAP_GET_NEXT_KEY_struct, map_fd),
.str = "map_fd=-1, key=0, next_key=0"
},
{
.data = { .BPF_MAP_GET_NEXT_KEY_data = {
.map_fd = -1,
.key = 0xdeadbeef,
.next_key = 0xbadc0ded
} },
.size = offsetofend(struct BPF_MAP_GET_NEXT_KEY_struct, next_key),
.str = "map_fd=-1, key=0xdeadbeef, next_key=0xbadc0ded"
}
};
static const struct bpf_insn insns[] = {
{ .code = 0x95 }
};
static const char license[] = "GPL";
static char log_buf[4096];
static const char pathname[] = "/sys/fs/bpf/foo/bar";
static unsigned int
init_BPF_PROG_LOAD_attr(const unsigned long eop)
static void
init_BPF_PROG_LOAD_attr(struct bpf_attr_check *check)
{
const struct BPF_PROG_LOAD_struct attr = {
.prog_type = 1,
.insn_cnt = ARRAY_SIZE(insns),
.insns = (uintptr_t) insns,
.license = (uintptr_t) "GPL",
.log_level = 42,
.log_size = sizeof(log_buf),
.log_buf = (uintptr_t) log_buf,
.kern_version = 0xcafef00d,
.prog_flags = 1
};
static const unsigned int offset =
offsetofend(struct BPF_PROG_LOAD_struct, prog_flags);
const unsigned long addr = eop - offset;
memcpy((void *) addr, &attr, offset);
return offset;
struct BPF_PROG_LOAD_struct *attr = &check->data.BPF_PROG_LOAD_data;
attr->insns = (uintptr_t) insns;
attr->license = (uintptr_t) license;
attr->log_buf = (uintptr_t) log_buf;
}
static void
print_BPF_PROG_LOAD_attr(const unsigned long addr)
print_BPF_PROG_LOAD_attr(const struct bpf_attr_check *check, unsigned long addr)
{
printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=%u, insns=%p"
", license=\"GPL\", log_level=42, log_size=4096, log_buf=%p"
", license=\"%s\", log_level=42, log_size=4096, log_buf=%p"
", kern_version=KERNEL_VERSION(51966, 240, 13)"
", prog_flags=BPF_F_STRICT_ALIGNMENT",
(unsigned int) ARRAY_SIZE(insns), insns,
log_buf);
license, log_buf);
}
DEF_BPF_INIT_FIRST(BPF_OBJ_PIN, pathname, 0)
static void
print_BPF_OBJ_PIN_first(const unsigned long addr)
{
printf("pathname=NULL, bpf_fd=0");
}
static unsigned int
init_BPF_OBJ_PIN_attr(const unsigned long eop)
{
const struct BPF_OBJ_PIN_struct attr = {
.pathname = (uintptr_t) "/sys/fs/bpf/foo/bar",
.bpf_fd = -1
};
static const unsigned int offset =
offsetofend(struct BPF_OBJ_PIN_struct, bpf_fd);
const unsigned long addr = eop - offset;
memcpy((void *) addr, &attr, offset);
return offset;
}
static void
print_BPF_OBJ_PIN_attr(const unsigned long addr)
{
printf("pathname=\"/sys/fs/bpf/foo/bar\", bpf_fd=-1");
}
#define init_BPF_OBJ_GET_first init_BPF_OBJ_PIN_first
#define print_BPF_OBJ_GET_first print_BPF_OBJ_PIN_first
#define init_BPF_OBJ_GET_attr init_BPF_OBJ_PIN_attr
#define print_BPF_OBJ_GET_attr print_BPF_OBJ_PIN_attr
DEF_BPF_INIT_FIRST(BPF_PROG_ATTACH, target_fd, -1)
static void
print_BPF_PROG_ATTACH_first(const unsigned long addr)
{
printf("target_fd=-1, attach_bpf_fd=0"
", attach_type=BPF_CGROUP_INET_INGRESS, attach_flags=0");
}
static unsigned int
init_BPF_PROG_ATTACH_attr(const unsigned long eop)
{
static const struct BPF_PROG_ATTACH_struct attr = {
.target_fd = -1,
.attach_bpf_fd = -2,
.attach_type = 2,
.attach_flags = 1
};
static const unsigned int offset =
offsetofend(struct BPF_PROG_ATTACH_struct, attach_flags);
const unsigned long addr = eop - offset;
memcpy((void *) addr, &attr, offset);
return offset;
}
static void
print_BPF_PROG_ATTACH_attr(const unsigned long addr)
{
printf("target_fd=-1, attach_bpf_fd=-2"
", attach_type=BPF_CGROUP_INET_SOCK_CREATE"
", attach_flags=BPF_F_ALLOW_OVERRIDE");
}
#define init_BPF_PROG_DETACH_first init_BPF_PROG_ATTACH_first
static unsigned int
init_BPF_PROG_DETACH_attr(const unsigned long eop)
{
static const struct BPF_PROG_DETACH_struct attr = {
.target_fd = -1,
.attach_type = 2
};
static const unsigned int offset =
offsetofend(struct BPF_PROG_DETACH_struct, attach_type);
const unsigned long addr = eop - offset;
memcpy((void *) addr, &attr, offset);
return offset;
}
static void
print_BPF_PROG_DETACH_first(const unsigned long addr)
{
printf("target_fd=-1, attach_type=BPF_CGROUP_INET_INGRESS");
}
static void
print_BPF_PROG_DETACH_attr(const unsigned long addr)
{
printf("target_fd=-1, attach_type=BPF_CGROUP_INET_SOCK_CREATE");
}
DEF_BPF_INIT_FIRST(BPF_PROG_TEST_RUN, prog_fd, -1)
static void
print_BPF_PROG_TEST_RUN_first(const unsigned long addr)
{
printf("test={prog_fd=-1, retval=0, data_size_in=0, data_size_out=0"
", data_in=0, data_out=0, repeat=0, duration=0}");
}
static const struct BPF_PROG_TEST_RUN_struct sample_BPF_PROG_TEST_RUN_attr = {
.prog_fd = -1,
.retval = 0xfac1fed2,
.data_size_in = 0xfac3fed4,
.data_size_out = 0xfac5fed6,
.data_in = (uint64_t) 0xfacef11dbadc2ded,
.data_out = (uint64_t) 0xfacef33dbadc4ded,
.repeat = 0xfac7fed8,
.duration = 0xfac9feda
static struct bpf_attr_check BPF_PROG_LOAD_checks[] = {
{
.data = { .BPF_PROG_LOAD_data = { .prog_type = 1 } },
.size = offsetofend(struct BPF_PROG_LOAD_struct, prog_type),
.str = "prog_type=BPF_PROG_TYPE_SOCKET_FILTER"
", insn_cnt=0, insns=0, license=NULL"
},
{
.data = { .BPF_PROG_LOAD_data = {
.prog_type = 1,
.insn_cnt = ARRAY_SIZE(insns),
.log_level = 42,
.log_size = sizeof(log_buf),
.kern_version = 0xcafef00d,
.prog_flags = 1
} },
.size = offsetofend(struct BPF_PROG_LOAD_struct, prog_flags),
.init_fn = init_BPF_PROG_LOAD_attr,
.print_fn = print_BPF_PROG_LOAD_attr
}
};
static unsigned int
init_BPF_PROG_TEST_RUN_attr(const unsigned long eop)
{
static const unsigned int offset =
offsetofend(struct BPF_PROG_TEST_RUN_struct, duration);
const unsigned long addr = eop - offset;
memcpy((void *) addr, &sample_BPF_PROG_TEST_RUN_attr, offset);
return offset;
}
static void
print_BPF_PROG_TEST_RUN_attr(const unsigned long addr)
init_BPF_OBJ_PIN_attr(struct bpf_attr_check *check)
{
PRINT_FIELD_D("test={", sample_BPF_PROG_TEST_RUN_attr, prog_fd);
PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, retval);
PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, data_size_in);
PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, data_size_out);
PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr, data_in);
PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr, data_out);
PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, repeat);
PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr, duration);
printf("}");
struct BPF_OBJ_PIN_struct *attr = &check->data.BPF_OBJ_PIN_data;
attr->pathname = (uintptr_t) pathname;
}
DEF_BPF_INIT_FIRST(BPF_PROG_GET_NEXT_ID, start_id, 0xdeadbeef)
static struct bpf_attr_check BPF_OBJ_PIN_checks[] = {
{
.data = { .BPF_OBJ_PIN_data = { .pathname = 0 } },
.size = offsetofend(struct BPF_OBJ_PIN_struct, pathname),
.str = "pathname=NULL, bpf_fd=0"
},
{
.data = { .BPF_OBJ_PIN_data = { .bpf_fd = -1 } },
.size = offsetofend(struct BPF_OBJ_PIN_struct, bpf_fd),
.init_fn = init_BPF_OBJ_PIN_attr,
.str = "pathname=\"/sys/fs/bpf/foo/bar\", bpf_fd=-1"
}
};
static void
print_BPF_PROG_GET_NEXT_ID_first(const unsigned long addr)
{
printf("start_id=%u, next_id=0", 0xdeadbeef);
}
#define BPF_OBJ_GET_checks BPF_OBJ_PIN_checks
static unsigned int
init_BPF_PROG_GET_NEXT_ID_attr(const unsigned long eop)
{
static const struct BPF_PROG_GET_NEXT_ID_struct attr = {
.start_id = 0xbadc0ded,
.next_id = 0xcafef00d
};
static const unsigned int offset =
offsetofend(struct BPF_PROG_GET_NEXT_ID_struct, next_id);
const unsigned long addr = eop - offset;
static const struct bpf_attr_check BPF_PROG_ATTACH_checks[] = {
{
.data = { .BPF_PROG_ATTACH_data = { .target_fd = -1 } },
.size = offsetofend(struct BPF_PROG_ATTACH_struct, target_fd),
.str = "target_fd=-1, attach_bpf_fd=0"
", attach_type=BPF_CGROUP_INET_INGRESS, attach_flags=0"
},
{
.data = { .BPF_PROG_ATTACH_data = {
.target_fd = -1,
.attach_bpf_fd = -2,
.attach_type = 2,
.attach_flags = 1
} },
.size = offsetofend(struct BPF_PROG_ATTACH_struct, attach_flags),
.str = "target_fd=-1, attach_bpf_fd=-2"
", attach_type=BPF_CGROUP_INET_SOCK_CREATE"
", attach_flags=BPF_F_ALLOW_OVERRIDE"
}
};
memcpy((void *) addr, &attr, offset);
return offset;
}
static void
print_BPF_PROG_GET_NEXT_ID_attr(const unsigned long addr)
{
printf("start_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
}
static const struct bpf_attr_check BPF_PROG_DETACH_checks[] = {
{
.data = { .BPF_PROG_DETACH_data = { .target_fd = -1 } },
.size = offsetofend(struct BPF_PROG_DETACH_struct, target_fd),
.str = "target_fd=-1, attach_type=BPF_CGROUP_INET_INGRESS"
},
{
.data = { .BPF_PROG_DETACH_data = {
.target_fd = -1,
.attach_type = 2
} },
.size = offsetofend(struct BPF_PROG_DETACH_struct, attach_type),
.str = "target_fd=-1, attach_type=BPF_CGROUP_INET_SOCK_CREATE"
}
};
#define init_BPF_MAP_GET_NEXT_ID_first init_BPF_PROG_GET_NEXT_ID_first
#define print_BPF_MAP_GET_NEXT_ID_first print_BPF_PROG_GET_NEXT_ID_first
#define init_BPF_MAP_GET_NEXT_ID_attr init_BPF_PROG_GET_NEXT_ID_attr
#define print_BPF_MAP_GET_NEXT_ID_attr print_BPF_PROG_GET_NEXT_ID_attr
static const struct bpf_attr_check BPF_PROG_TEST_RUN_checks[] = {
{
.data = { .BPF_PROG_TEST_RUN_data = { .prog_fd = -1 } },
.size = offsetofend(struct BPF_PROG_TEST_RUN_struct, prog_fd),
.str = "test={prog_fd=-1, retval=0, data_size_in=0"
", data_size_out=0, data_in=0, data_out=0"
", repeat=0, duration=0}"
},
{
.data = { .BPF_PROG_TEST_RUN_data = {
.prog_fd = -1,
.retval = 0xfac1fed2,
.data_size_in = 0xfac3fed4,
.data_size_out = 0xfac5fed6,
.data_in = (uint64_t) 0xfacef11dbadc2dedULL,
.data_out = (uint64_t) 0xfacef33dbadc4dedULL,
.repeat = 0xfac7fed8,
.duration = 0xfac9feda
} },
.size = offsetofend(struct BPF_PROG_TEST_RUN_struct, duration),
.str = "test={prog_fd=-1, retval=4207017682"
", data_size_in=4207148756, data_size_out=4207279830"
", data_in=0xfacef11dbadc2ded"
", data_out=0xfacef33dbadc4ded"
", repeat=4207410904, duration=4207541978}"
}
};
#define init_BPF_PROG_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first
#define init_BPF_PROG_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr
static const struct bpf_attr_check BPF_PROG_GET_NEXT_ID_checks[] = {
{
.data = { .BPF_PROG_GET_NEXT_ID_data = {
.start_id = 0xdeadbeef
} },
.size = offsetofend(struct BPF_PROG_GET_NEXT_ID_struct, start_id),
.str = "start_id=3735928559, next_id=0"
},
{
.data = { .BPF_PROG_GET_NEXT_ID_data = {
.start_id = 0xbadc0ded,
.next_id = 0xcafef00d
} },
.size = offsetofend(struct BPF_PROG_GET_NEXT_ID_struct, next_id),
.str = "start_id=3134983661, next_id=3405705229"
}
};
static void
print_BPF_PROG_GET_FD_BY_ID_first(const unsigned long addr)
{
printf("prog_id=%u, next_id=0", 0xdeadbeef);
}
#define BPF_MAP_GET_NEXT_ID_checks BPF_PROG_GET_NEXT_ID_checks
static void
print_BPF_PROG_GET_FD_BY_ID_attr(const unsigned long addr)
{
printf("prog_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
}
static const struct bpf_attr_check BPF_PROG_GET_FD_BY_ID_checks[] = {
{
.data = { .BPF_PROG_GET_FD_BY_ID_data = {
.prog_id = 0xdeadbeef
} },
.size = offsetofend(struct BPF_PROG_GET_FD_BY_ID_struct, prog_id),
.str = "prog_id=3735928559, next_id=0"
},
{
.data = { .BPF_PROG_GET_FD_BY_ID_data = {
.prog_id = 0xbadc0ded,
.next_id = 0xcafef00d
} },
.size = offsetofend(struct BPF_PROG_GET_FD_BY_ID_struct, next_id),
.str = "prog_id=3134983661, next_id=3405705229"
}
};
#define init_BPF_MAP_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first
#define init_BPF_MAP_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr
static const struct bpf_attr_check BPF_MAP_GET_FD_BY_ID_checks[] = {
{
.data = { .BPF_MAP_GET_FD_BY_ID_data = {
.map_id = 0xdeadbeef
} },
.size = offsetofend(struct BPF_MAP_GET_FD_BY_ID_struct, map_id),
.str = "map_id=3735928559, next_id=0"
},
{
.data = { .BPF_MAP_GET_FD_BY_ID_data = {
.map_id = 0xbadc0ded,
.next_id = 0xcafef00d
} },
.size = offsetofend(struct BPF_MAP_GET_FD_BY_ID_struct, next_id),
.str = "map_id=3134983661, next_id=3405705229"
}
};
static void
print_BPF_MAP_GET_FD_BY_ID_first(const unsigned long addr)
{
printf("map_id=%u, next_id=0", 0xdeadbeef);
}
static const struct bpf_attr_check BPF_OBJ_GET_INFO_BY_FD_checks[] = {
{
.data = { .BPF_OBJ_GET_INFO_BY_FD_data = { .bpf_fd = -1 } },
.size = offsetofend(struct BPF_OBJ_GET_INFO_BY_FD_struct, bpf_fd),
.str = "info={bpf_fd=-1, info_len=0, info=0}"
},
{
.data = { .BPF_OBJ_GET_INFO_BY_FD_data = {
.bpf_fd = -1,
.info_len = 0xdeadbeef,
.info = (uint64_t) 0xfacefeedbadc0dedULL
} },
.size = offsetofend(struct BPF_OBJ_GET_INFO_BY_FD_struct, info),
.str = "info={bpf_fd=-1, info_len=3735928559"
", info=0xfacefeedbadc0ded}"
}
};
static void
print_BPF_MAP_GET_FD_BY_ID_attr(const unsigned long addr)
{
printf("map_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
}
DEF_BPF_INIT_FIRST(BPF_OBJ_GET_INFO_BY_FD, bpf_fd, -1)
static void
print_BPF_OBJ_GET_INFO_BY_FD_first(const unsigned long addr)
{
printf("info={bpf_fd=-1, info_len=0, info=0}");
}
static const struct BPF_OBJ_GET_INFO_BY_FD_struct
sample_BPF_OBJ_GET_INFO_BY_FD_attr = {
.bpf_fd = -1,
.info_len = 0xdeadbeef,
.info = (uint64_t) 0xfacefeedbadc0ded
};
static unsigned int
init_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long eop)
{
static const unsigned int offset =
offsetofend(struct BPF_OBJ_GET_INFO_BY_FD_struct, info);
const unsigned long addr = eop - offset;
memcpy((void *) addr, &sample_BPF_OBJ_GET_INFO_BY_FD_attr, offset);
return offset;
}
static void
print_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long addr)
{
PRINT_FIELD_D("info={", sample_BPF_OBJ_GET_INFO_BY_FD_attr, bpf_fd);
PRINT_FIELD_U(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr, info_len);
PRINT_FIELD_X(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr, info);
printf("}");
}
#define CHK(cmd_) \
{ \
cmd_, #cmd_, \
cmd_##_checks, ARRAY_SIZE(cmd_##_checks), \
} \
/* End of CHK definition */
int
main(void)
{
static const struct bpf_check checks[] = {
CHK(BPF_MAP_CREATE),
CHK(BPF_MAP_LOOKUP_ELEM),
CHK(BPF_MAP_UPDATE_ELEM),
CHK(BPF_MAP_DELETE_ELEM),
CHK(BPF_MAP_GET_NEXT_KEY),
CHK(BPF_PROG_LOAD),
CHK(BPF_OBJ_PIN),
CHK(BPF_OBJ_GET),
CHK(BPF_PROG_ATTACH),
CHK(BPF_PROG_DETACH),
CHK(BPF_PROG_TEST_RUN),
CHK(BPF_PROG_GET_NEXT_ID),
CHK(BPF_MAP_GET_NEXT_ID),
CHK(BPF_PROG_GET_FD_BY_ID),
CHK(BPF_MAP_GET_FD_BY_ID),
CHK(BPF_OBJ_GET_INFO_BY_FD),
};
page_size = get_page_size();
end_of_page = (unsigned long) tail_alloc(1) + 1;
TEST_BPF(BPF_MAP_CREATE);
TEST_BPF(BPF_MAP_LOOKUP_ELEM);
TEST_BPF(BPF_MAP_UPDATE_ELEM);
TEST_BPF(BPF_MAP_DELETE_ELEM);
TEST_BPF(BPF_MAP_GET_NEXT_KEY);
TEST_BPF(BPF_PROG_LOAD);
TEST_BPF(BPF_OBJ_PIN);
TEST_BPF(BPF_OBJ_GET);
TEST_BPF(BPF_PROG_ATTACH);
TEST_BPF(BPF_PROG_DETACH);
TEST_BPF(BPF_PROG_TEST_RUN);
TEST_BPF(BPF_PROG_GET_NEXT_ID);
TEST_BPF(BPF_MAP_GET_NEXT_ID);
TEST_BPF(BPF_PROG_GET_FD_BY_ID);
TEST_BPF(BPF_MAP_GET_FD_BY_ID);
TEST_BPF(BPF_OBJ_GET_INFO_BY_FD);
for (size_t i = 0; i < ARRAY_SIZE(checks); i++)
test_bpf(checks + i);
sys_bpf(0xfacefeed, 0, (kernel_ulong_t) 0xfacefeedbadc0dedULL);
printf("bpf(0xfacefeed /* BPF_??? */, NULL, %u) = %s\n",