Dmitry V. Levin
3e8b3ccd98
* tests/bpf.c (DEF_BPF_INIT_FIRST): New macro. (init_BPF_MAP_CREATE_first, init_BPF_MAP_LOOKUP_ELEM_first, init_BPF_PROG_LOAD_first, init_BPF_OBJ_PIN_first, init_BPF_PROG_ATTACH_first, init_BPF_PROG_TEST_RUN_first, init_BPF_PROG_GET_NEXT_ID_first, init_BPF_OBJ_GET_INFO_BY_FD_first): Use it.
753 lines
21 KiB
C
753 lines
21 KiB
C
/*
|
|
* Check bpf syscall decoding.
|
|
*
|
|
* Copyright (c) 2015-2017 Dmitry V. Levin <ldv@altlinux.org>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "tests.h"
|
|
#include <asm/unistd.h>
|
|
|
|
#if defined __NR_bpf \
|
|
&& (defined HAVE_UNION_BPF_ATTR_ATTACH_FLAGS \
|
|
|| defined HAVE_UNION_BPF_ATTR_BPF_FD \
|
|
|| defined HAVE_UNION_BPF_ATTR_FLAGS \
|
|
|| defined HAVE_UNION_BPF_ATTR_INFO_INFO \
|
|
|| defined HAVE_UNION_BPF_ATTR_NEXT_ID \
|
|
|| defined HAVE_UNION_BPF_ATTR_NUMA_NODE \
|
|
|| defined HAVE_UNION_BPF_ATTR_PROG_FLAGS \
|
|
|| defined HAVE_UNION_BPF_ATTR_TEST_DURATION)
|
|
|
|
# include <stddef.h>
|
|
# include <stdio.h>
|
|
# include <stdint.h>
|
|
# include <string.h>
|
|
# include <unistd.h>
|
|
# include <linux/bpf.h>
|
|
# include "print_fields.h"
|
|
|
|
static const kernel_ulong_t long_bits = (kernel_ulong_t) 0xfacefeed00000000ULL;
|
|
static const char *errstr;
|
|
static unsigned int sizeof_attr = sizeof(union bpf_attr);
|
|
static unsigned int page_size;
|
|
static unsigned long end_of_page;
|
|
|
|
static long
|
|
sys_bpf(kernel_ulong_t cmd, kernel_ulong_t attr, kernel_ulong_t size)
|
|
{
|
|
long rc = syscall(__NR_bpf, cmd, attr, size);
|
|
errstr = sprintrc(rc);
|
|
return rc;
|
|
}
|
|
|
|
# if VERBOSE
|
|
# define print_extra_data(addr_, size_) print_quoted_hex((addr_), (size_))
|
|
# else
|
|
# define print_extra_data(addr_, size_) printf("...")
|
|
#endif
|
|
|
|
# define TEST_BPF_(cmd_, cmd_str_, \
|
|
init_first_, print_first_, \
|
|
init_attr_, print_attr_) \
|
|
do { \
|
|
/* zero addr */ \
|
|
sys_bpf(cmd_, 0, long_bits | sizeof(union bpf_attr)); \
|
|
printf("bpf(%s, NULL, %u) = %s\n", \
|
|
cmd_str_, sizeof_attr, errstr); \
|
|
\
|
|
/* zero size */ \
|
|
unsigned long addr = end_of_page - sizeof_attr; \
|
|
sys_bpf(cmd_, addr, long_bits); \
|
|
printf("bpf(%s, %#lx, 0) = %s\n", \
|
|
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); \
|
|
\
|
|
/* efault after the first field */ \
|
|
sys_bpf(cmd_, addr, offset + 1); \
|
|
printf("bpf(%s, %#lx, %u) = %s\n", \
|
|
cmd_str_, addr, offset + 1, errstr); \
|
|
\
|
|
/* the relevant part of union bpf_attr */ \
|
|
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); \
|
|
\
|
|
/* short read of the relevant part of union bpf_attr */ \
|
|
sys_bpf(cmd_, addr + 1, offset); \
|
|
printf("bpf(%s, %#lx, %u) = %s\n", \
|
|
cmd_str_, addr + 1, offset, errstr); \
|
|
\
|
|
if (offset < sizeof_attr) { \
|
|
/* short read of the whole union bpf_attr */ \
|
|
memmove((void *) end_of_page - sizeof_attr + 1, \
|
|
(void *) addr, offset); \
|
|
addr = end_of_page - sizeof_attr + 1; \
|
|
memset((void *) addr + offset, 0, \
|
|
sizeof_attr - offset - 1); \
|
|
sys_bpf(cmd_, addr, sizeof_attr); \
|
|
printf("bpf(%s, %#lx, %u) = %s\n", \
|
|
cmd_str_, addr, sizeof_attr, errstr); \
|
|
\
|
|
/* the whole union bpf_attr */ \
|
|
memmove((void *) end_of_page - sizeof_attr, \
|
|
(void *) addr, 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); \
|
|
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); \
|
|
printf(", "); \
|
|
print_extra_data((void *) addr + offset, \
|
|
sizeof_attr - offset); \
|
|
printf("}, %u) = %s\n", sizeof_attr, errstr); \
|
|
} \
|
|
\
|
|
/* short read of the whole page */ \
|
|
memmove((void *) end_of_page - page_size + 1, \
|
|
(void *) addr, offset); \
|
|
addr = end_of_page - page_size + 1; \
|
|
memset((void *) addr + offset, 0, \
|
|
page_size - offset - 1); \
|
|
sys_bpf(cmd_, addr, page_size); \
|
|
printf("bpf(%s, %#lx, %u) = %s\n", \
|
|
cmd_str_, addr, page_size, errstr); \
|
|
\
|
|
/* the whole page */ \
|
|
memmove((void *) end_of_page - page_size, \
|
|
(void *) addr, 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); \
|
|
printf("}, %u) = %s\n", page_size, errstr); \
|
|
\
|
|
/* non-zero bytes after the whole union bpf_attr */ \
|
|
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); \
|
|
printf(", "); \
|
|
print_extra_data((void *) addr + offset, \
|
|
page_size - offset); \
|
|
printf("}, %u) = %s\n", page_size, errstr); \
|
|
\
|
|
/* more than a page */ \
|
|
sys_bpf(cmd_, addr, page_size + 1); \
|
|
printf("bpf(%s, %#lx, %u) = %s\n", \
|
|
cmd_str_, addr, page_size + 1, errstr); \
|
|
} while (0) \
|
|
/* End of TEST_BPF_ definition. */
|
|
|
|
# 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. */
|
|
|
|
#define DEF_BPF_INIT_FIRST(cmd_, field_, value_) \
|
|
static unsigned int \
|
|
init_ ## cmd_ ## _first(const unsigned long eop) \
|
|
{ \
|
|
static const union bpf_attr 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. */
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE
|
|
|
|
DEF_BPF_INIT_FIRST(BPF_MAP_CREATE, map_type, 2)
|
|
|
|
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 unsigned int
|
|
init_BPF_MAP_CREATE_attr(const unsigned long eop)
|
|
{
|
|
static const union bpf_attr 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(union bpf_attr, 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");
|
|
}
|
|
|
|
# endif /* HAVE_UNION_BPF_ATTR_NUMA_NODE */
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_FLAGS
|
|
|
|
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 union bpf_attr attr = {
|
|
.map_fd = -1,
|
|
.key = 0xdeadbeef,
|
|
.value = 0xbadc0ded
|
|
};
|
|
static const unsigned int offset =
|
|
offsetofend(union bpf_attr, 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 union bpf_attr attr = {
|
|
.map_fd = -1,
|
|
.key = 0xdeadbeef,
|
|
.value = 0xbadc0ded,
|
|
.flags = 2
|
|
};
|
|
static const unsigned int offset =
|
|
offsetofend(union bpf_attr, 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 union bpf_attr attr = {
|
|
.map_fd = -1,
|
|
.key = 0xdeadbeef
|
|
};
|
|
static const unsigned int offset =
|
|
offsetofend(union bpf_attr, 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 union bpf_attr attr = {
|
|
.map_fd = -1,
|
|
.key = 0xdeadbeef,
|
|
.next_key = 0xbadc0ded
|
|
};
|
|
static const unsigned int offset =
|
|
offsetofend(union bpf_attr, 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");
|
|
}
|
|
|
|
# endif /* HAVE_UNION_BPF_ATTR_FLAGS */
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_PROG_FLAGS
|
|
|
|
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, log_level=0, log_size=0, log_buf=0"
|
|
", kern_version=0, prog_flags=0");
|
|
}
|
|
|
|
static const struct bpf_insn insns[] = {
|
|
{ .code = BPF_JMP | BPF_EXIT }
|
|
};
|
|
static char log_buf[4096];
|
|
|
|
static unsigned int
|
|
init_BPF_PROG_LOAD_attr(const unsigned long eop)
|
|
{
|
|
const union bpf_attr 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(union bpf_attr, prog_flags);
|
|
const unsigned long addr = eop - offset;
|
|
|
|
memcpy((void *) addr, &attr, offset);
|
|
return offset;
|
|
}
|
|
|
|
static void
|
|
print_BPF_PROG_LOAD_attr(const 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"
|
|
", kern_version=%u, prog_flags=BPF_F_STRICT_ALIGNMENT",
|
|
(unsigned int) ARRAY_SIZE(insns), insns,
|
|
log_buf, 0xcafef00d);
|
|
}
|
|
|
|
# endif /* HAVE_UNION_BPF_ATTR_PROG_FLAGS */
|
|
|
|
/*
|
|
* bpf() syscall and its first six commands were introduced in Linux kernel
|
|
* 3.18. Some additional commands were added afterwards, so we need to take
|
|
* precautions to make sure the tests compile.
|
|
*
|
|
* BPF_OBJ_PIN and BPF_OBJ_GET commands appear in kernel 4.4.
|
|
*/
|
|
# ifdef HAVE_UNION_BPF_ATTR_BPF_FD
|
|
|
|
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 union bpf_attr attr = {
|
|
.pathname = (uintptr_t) "/sys/fs/bpf/foo/bar",
|
|
.bpf_fd = -1
|
|
};
|
|
static const unsigned int offset =
|
|
offsetofend(union bpf_attr, 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
|
|
|
|
# endif /* HAVE_UNION_BPF_ATTR_BPF_FD */
|
|
|
|
/* BPF_PROG_ATTACH and BPF_PROG_DETACH commands appear in kernel 4.10. */
|
|
# ifdef HAVE_UNION_BPF_ATTR_ATTACH_FLAGS
|
|
|
|
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 union bpf_attr attr = {
|
|
.target_fd = -1,
|
|
.attach_bpf_fd = -2,
|
|
.attach_type = 2,
|
|
.attach_flags = 1
|
|
};
|
|
static const unsigned int offset =
|
|
offsetofend(union bpf_attr, 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 union bpf_attr attr = {
|
|
.target_fd = -1,
|
|
.attach_type = 2
|
|
};
|
|
static const unsigned int offset =
|
|
offsetofend(union bpf_attr, 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");
|
|
}
|
|
|
|
# endif /* HAVE_UNION_BPF_ATTR_ATTACH_FLAGS */
|
|
|
|
/* BPF_PROG_TEST_RUN command appears in kernel 4.12. */
|
|
# ifdef HAVE_UNION_BPF_ATTR_TEST_DURATION
|
|
|
|
DEF_BPF_INIT_FIRST(BPF_PROG_TEST_RUN, test.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 union bpf_attr sample_BPF_PROG_TEST_RUN_attr = {
|
|
.test = {
|
|
.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 unsigned int
|
|
init_BPF_PROG_TEST_RUN_attr(const unsigned long eop)
|
|
{
|
|
static const unsigned int offset =
|
|
offsetofend(union bpf_attr, test);
|
|
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)
|
|
{
|
|
PRINT_FIELD_D("test={", sample_BPF_PROG_TEST_RUN_attr.test, prog_fd);
|
|
PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, retval);
|
|
PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_size_in);
|
|
PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_size_out);
|
|
PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_in);
|
|
PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_out);
|
|
PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, repeat);
|
|
PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, duration);
|
|
printf("}");
|
|
}
|
|
|
|
# endif /* HAVE_UNION_BPF_ATTR_TEST_DURATION */
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_NEXT_ID
|
|
|
|
DEF_BPF_INIT_FIRST(BPF_PROG_GET_NEXT_ID, start_id, 0xdeadbeef)
|
|
|
|
static void
|
|
print_BPF_PROG_GET_NEXT_ID_first(const unsigned long addr)
|
|
{
|
|
printf("start_id=%u, next_id=0", 0xdeadbeef);
|
|
}
|
|
|
|
static unsigned int
|
|
init_BPF_PROG_GET_NEXT_ID_attr(const unsigned long eop)
|
|
{
|
|
static const union bpf_attr attr = {
|
|
.start_id = 0xbadc0ded,
|
|
.next_id = 0xcafef00d
|
|
};
|
|
static const unsigned int offset =
|
|
offsetofend(union bpf_attr, next_id);
|
|
const unsigned long addr = eop - offset;
|
|
|
|
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);
|
|
}
|
|
|
|
# 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
|
|
|
|
# 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 void
|
|
print_BPF_PROG_GET_FD_BY_ID_first(const unsigned long addr)
|
|
{
|
|
printf("prog_id=%u, next_id=0", 0xdeadbeef);
|
|
}
|
|
|
|
static void
|
|
print_BPF_PROG_GET_FD_BY_ID_attr(const unsigned long addr)
|
|
{
|
|
printf("prog_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
|
|
}
|
|
|
|
# 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 void
|
|
print_BPF_MAP_GET_FD_BY_ID_first(const unsigned long addr)
|
|
{
|
|
printf("map_id=%u, next_id=0", 0xdeadbeef);
|
|
}
|
|
|
|
static void
|
|
print_BPF_MAP_GET_FD_BY_ID_attr(const unsigned long addr)
|
|
{
|
|
printf("map_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
|
|
}
|
|
|
|
# endif /* HAVE_UNION_BPF_ATTR_NEXT_ID */
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_INFO_INFO
|
|
|
|
DEF_BPF_INIT_FIRST(BPF_OBJ_GET_INFO_BY_FD, info.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 union bpf_attr sample_BPF_OBJ_GET_INFO_BY_FD_attr = {
|
|
.info = {
|
|
.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(union bpf_attr, 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.info, bpf_fd);
|
|
PRINT_FIELD_U(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, info_len);
|
|
PRINT_FIELD_X(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, info);
|
|
printf("}");
|
|
}
|
|
|
|
# endif /* HAVE_UNION_BPF_ATTR_INFO_INFO */
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
page_size = get_page_size();
|
|
end_of_page = (unsigned long) tail_alloc(1) + 1;
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE
|
|
TEST_BPF(BPF_MAP_CREATE);
|
|
# endif
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_FLAGS
|
|
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);
|
|
# endif
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_PROG_FLAGS
|
|
TEST_BPF(BPF_PROG_LOAD);
|
|
# endif
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_BPF_FD
|
|
TEST_BPF(BPF_OBJ_PIN);
|
|
TEST_BPF(BPF_OBJ_GET);
|
|
# endif
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_ATTACH_FLAGS
|
|
TEST_BPF(BPF_PROG_ATTACH);
|
|
TEST_BPF(BPF_PROG_DETACH);
|
|
# endif
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_TEST_DURATION
|
|
TEST_BPF(BPF_PROG_TEST_RUN);
|
|
# endif
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_NEXT_ID
|
|
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);
|
|
# endif
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_INFO_INFO
|
|
TEST_BPF(BPF_OBJ_GET_INFO_BY_FD);
|
|
# endif
|
|
|
|
sys_bpf(0xfacefeed, end_of_page, 40);
|
|
printf("bpf(0xfacefeed /* BPF_??? */, %#lx, 40) = %s\n",
|
|
end_of_page, errstr);
|
|
|
|
puts("+++ exited with 0 +++");
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
SKIP_MAIN_UNDEFINED("__NR_bpf && HAVE_UNION_BPF_ATTR_*")
|
|
|
|
#endif
|