Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next

Pull networking updates from David Miller:

 1) Support IPV6 RA Captive Portal Identifier, from Maciej Żenczykowski.

 2) Use bio_vec in the networking instead of custom skb_frag_t, from
    Matthew Wilcox.

 3) Make use of xmit_more in r8169 driver, from Heiner Kallweit.

 4) Add devmap_hash to xdp, from Toke Høiland-Jørgensen.

 5) Support all variants of 5750X bnxt_en chips, from Michael Chan.

 6) More RTNL avoidance work in the core and mlx5 driver, from Vlad
    Buslov.

 7) Add TCP syn cookies bpf helper, from Petar Penkov.

 8) Add 'nettest' to selftests and use it, from David Ahern.

 9) Add extack support to drop_monitor, add packet alert mode and
    support for HW drops, from Ido Schimmel.

10) Add VLAN offload to stmmac, from Jose Abreu.

11) Lots of devm_platform_ioremap_resource() conversions, from
    YueHaibing.

12) Add IONIC driver, from Shannon Nelson.

13) Several kTLS cleanups, from Jakub Kicinski.

* git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1930 commits)
  mlxsw: spectrum_buffers: Add the ability to query the CPU port's shared buffer
  mlxsw: spectrum: Register CPU port with devlink
  mlxsw: spectrum_buffers: Prevent changing CPU port's configuration
  net: ena: fix incorrect update of intr_delay_resolution
  net: ena: fix retrieval of nonadaptive interrupt moderation intervals
  net: ena: fix update of interrupt moderation register
  net: ena: remove all old adaptive rx interrupt moderation code from ena_com
  net: ena: remove ena_restore_ethtool_params() and relevant fields
  net: ena: remove old adaptive interrupt moderation code from ena_netdev
  net: ena: remove code duplication in ena_com_update_nonadaptive_moderation_interval _*()
  net: ena: enable the interrupt_moderation in driver_supported_features
  net: ena: reimplement set/get_coalesce()
  net: ena: switch to dim algorithm for rx adaptive interrupt moderation
  net: ena: add intr_moder_rx_interval to struct ena_com_dev and use it
  net: phy: adin: implement Energy Detect Powerdown mode via phy-tunable
  ethtool: implement Energy Detect Powerdown support via phy-tunable
  xen-netfront: do not assume sk_buff_head list is empty in error handling
  s390/ctcm: Delete unnecessary checks before the macro call “dev_kfree_skb”
  net: ena: don't wake up tx queue when down
  drop_monitor: Better sanitize notified packets
  ...
This commit is contained in:
Linus Torvalds
2019-09-18 12:34:53 -07:00
1711 changed files with 121345 additions and 35857 deletions

View File

@@ -39,7 +39,3 @@ libbpf.so.*
test_hashmap
test_btf_dump
xdping
test_sockopt
test_sockopt_sk
test_sockopt_multi
test_tcp_rtt

View File

@@ -17,6 +17,7 @@ LLC ?= llc
LLVM_OBJCOPY ?= llvm-objcopy
LLVM_READELF ?= llvm-readelf
BTF_PAHOLE ?= pahole
BPF_GCC ?= $(shell command -v bpf-gcc;)
CFLAGS += -g -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(BPFDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include \
-Dbpf_prog_load=bpf_prog_test_load \
-Dbpf_load_program=bpf_test_load_program
@@ -28,8 +29,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test
test_sock test_btf test_sockmap get_cgroup_id_user test_socket_cookie \
test_cgroup_storage test_select_reuseport test_section_names \
test_netcnt test_tcpnotify_user test_sock_fields test_sysctl test_hashmap \
test_btf_dump test_cgroup_attach xdping test_sockopt test_sockopt_sk \
test_sockopt_multi test_tcp_rtt
test_btf_dump test_cgroup_attach xdping
BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c)))
TEST_GEN_FILES = $(BPF_OBJ_FILES)
@@ -47,6 +47,10 @@ ifneq ($(SUBREG_CODEGEN),)
TEST_GEN_FILES += $(patsubst %.o,alu32/%.o, $(BPF_OBJ_FILES))
endif
ifneq ($(BPF_GCC),)
TEST_GEN_FILES += $(patsubst %.o,bpf_gcc/%.o, $(BPF_OBJ_FILES))
endif
# Order correspond to 'make run_tests' order
TEST_PROGS := test_kmod.sh \
test_libbpf.sh \
@@ -66,7 +70,8 @@ TEST_PROGS := test_kmod.sh \
test_tcp_check_syncookie.sh \
test_tc_tunnel.sh \
test_tc_edt.sh \
test_xdping.sh
test_xdping.sh \
test_bpftool_build.sh
TEST_PROGS_EXTENDED := with_addr.sh \
with_tunnels.sh \
@@ -105,17 +110,13 @@ $(OUTPUT)/test_socket_cookie: cgroup_helpers.c
$(OUTPUT)/test_sockmap: cgroup_helpers.c
$(OUTPUT)/test_tcpbpf_user: cgroup_helpers.c
$(OUTPUT)/test_tcpnotify_user: cgroup_helpers.c trace_helpers.c
$(OUTPUT)/test_progs: trace_helpers.c
$(OUTPUT)/test_progs: cgroup_helpers.c trace_helpers.c
$(OUTPUT)/get_cgroup_id_user: cgroup_helpers.c
$(OUTPUT)/test_cgroup_storage: cgroup_helpers.c
$(OUTPUT)/test_netcnt: cgroup_helpers.c
$(OUTPUT)/test_sock_fields: cgroup_helpers.c
$(OUTPUT)/test_sysctl: cgroup_helpers.c
$(OUTPUT)/test_cgroup_attach: cgroup_helpers.c
$(OUTPUT)/test_sockopt: cgroup_helpers.c
$(OUTPUT)/test_sockopt_sk: cgroup_helpers.c
$(OUTPUT)/test_sockopt_multi: cgroup_helpers.c
$(OUTPUT)/test_tcp_rtt: cgroup_helpers.c
.PHONY: force
@@ -141,16 +142,19 @@ endif
#
# Use '-idirafter': Don't interfere with include mechanics except where the
# build would have failed anyways.
CLANG_SYS_INCLUDES := $(shell $(CLANG) -v -E - </dev/null 2>&1 \
define get_sys_includes
$(shell $(1) -v -E - </dev/null 2>&1 \
| sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }')
endef
CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG))
BPF_CFLAGS = -I. -I./include/uapi -I../../../include/uapi \
-I$(OUTPUT)/../usr/include -D__TARGET_ARCH_$(SRCARCH)
CLANG_FLAGS = -I. -I./include/uapi -I../../../include/uapi \
$(CLANG_SYS_INCLUDES) \
-Wno-compare-distinct-pointer-types \
-D__TARGET_ARCH_$(SRCARCH)
CLANG_CFLAGS = $(CLANG_SYS_INCLUDES) \
-Wno-compare-distinct-pointer-types
$(OUTPUT)/test_l4lb_noinline.o: CLANG_FLAGS += -fno-inline
$(OUTPUT)/test_xdp_noinline.o: CLANG_FLAGS += -fno-inline
$(OUTPUT)/test_l4lb_noinline.o: BPF_CFLAGS += -fno-inline
$(OUTPUT)/test_xdp_noinline.o: BPF_CFLAGS += -fno-inline
$(OUTPUT)/test_queue_map.o: test_queue_stack_map.h
$(OUTPUT)/test_stack_map.o: test_queue_stack_map.h
@@ -167,12 +171,12 @@ BTF_LLVM_PROBE := $(shell echo "int main() { return 0; }" | \
/bin/rm -f ./llvm_btf_verify.o)
ifneq ($(BTF_LLVM_PROBE),)
CLANG_FLAGS += -g
BPF_CFLAGS += -g
else
ifneq ($(BTF_LLC_PROBE),)
ifneq ($(BTF_PAHOLE_PROBE),)
ifneq ($(BTF_OBJCOPY_PROBE),)
CLANG_FLAGS += -g
BPF_CFLAGS += -g
LLC_FLAGS += -mattr=dwarfris
DWARF2BTF = y
endif
@@ -198,7 +202,7 @@ $(ALU32_BUILD_DIR)/test_progs_32: test_progs.c $(OUTPUT)/libbpf.a\
| $(ALU32_BUILD_DIR)
$(CC) $(TEST_PROGS_CFLAGS) $(CFLAGS) \
-o $(ALU32_BUILD_DIR)/test_progs_32 \
test_progs.c test_stub.c trace_helpers.c prog_tests/*.c \
test_progs.c test_stub.c cgroup_helpers.c trace_helpers.c prog_tests/*.c \
$(OUTPUT)/libbpf.a $(LDLIBS)
$(ALU32_BUILD_DIR)/test_progs_32: $(PROG_TESTS_H)
@@ -206,8 +210,8 @@ $(ALU32_BUILD_DIR)/test_progs_32: prog_tests/*.c
$(ALU32_BUILD_DIR)/%.o: progs/%.c $(ALU32_BUILD_DIR)/test_progs_32 \
| $(ALU32_BUILD_DIR)
($(CLANG) $(CLANG_FLAGS) -O2 -target bpf -emit-llvm -c $< -o - || \
echo "clang failed") | \
($(CLANG) $(BPF_CFLAGS) $(CLANG_CFLAGS) -O2 -target bpf -emit-llvm \
-c $< -o - || echo "clang failed") | \
$(LLC) -march=bpf -mattr=+alu32 -mcpu=$(CPU) $(LLC_FLAGS) \
-filetype=obj -o $@
ifeq ($(DWARF2BTF),y)
@@ -215,10 +219,37 @@ ifeq ($(DWARF2BTF),y)
endif
endif
ifneq ($(BPF_GCC),)
GCC_SYS_INCLUDES = $(call get_sys_includes,gcc)
IS_LITTLE_ENDIAN = $(shell $(CC) -dM -E - </dev/null | \
grep 'define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__')
ifeq ($(IS_LITTLE_ENDIAN),)
MENDIAN=-mbig-endian
else
MENDIAN=-mlittle-endian
endif
BPF_GCC_CFLAGS = $(GCC_SYS_INCLUDES) $(MENDIAN)
BPF_GCC_BUILD_DIR = $(OUTPUT)/bpf_gcc
TEST_CUSTOM_PROGS += $(BPF_GCC_BUILD_DIR)/test_progs_bpf_gcc
$(BPF_GCC_BUILD_DIR):
mkdir -p $@
$(BPF_GCC_BUILD_DIR)/urandom_read: $(OUTPUT)/urandom_read | $(BPF_GCC_BUILD_DIR)
cp $< $@
$(BPF_GCC_BUILD_DIR)/test_progs_bpf_gcc: $(OUTPUT)/test_progs \
| $(BPF_GCC_BUILD_DIR)
cp $< $@
$(BPF_GCC_BUILD_DIR)/%.o: progs/%.c $(BPF_GCC_BUILD_DIR)/test_progs_bpf_gcc \
| $(BPF_GCC_BUILD_DIR)
$(BPF_GCC) $(BPF_CFLAGS) $(BPF_GCC_CFLAGS) -O2 -c $< -o $@
endif
# Have one program compiled without "-target bpf" to test whether libbpf loads
# it successfully
$(OUTPUT)/test_xdp.o: progs/test_xdp.c
($(CLANG) $(CLANG_FLAGS) -O2 -emit-llvm -c $< -o - || \
($(CLANG) $(BPF_CFLAGS) $(CLANG_CFLAGS) -O2 -emit-llvm -c $< -o - || \
echo "clang failed") | \
$(LLC) -march=bpf -mcpu=$(CPU) $(LLC_FLAGS) -filetype=obj -o $@
ifeq ($(DWARF2BTF),y)
@@ -226,8 +257,8 @@ ifeq ($(DWARF2BTF),y)
endif
$(OUTPUT)/%.o: progs/%.c
($(CLANG) $(CLANG_FLAGS) -O2 -target bpf -emit-llvm -c $< -o - || \
echo "clang failed") | \
($(CLANG) $(BPF_CFLAGS) $(CLANG_CFLAGS) -O2 -target bpf -emit-llvm \
-c $< -o - || echo "clang failed") | \
$(LLC) -march=bpf -mcpu=$(CPU) $(LLC_FLAGS) -filetype=obj -o $@
ifeq ($(DWARF2BTF),y)
$(BTF_PAHOLE) -J $@
@@ -240,18 +271,12 @@ PROG_TESTS_H := $(PROG_TESTS_DIR)/tests.h
PROG_TESTS_FILES := $(wildcard prog_tests/*.c)
test_progs.c: $(PROG_TESTS_H)
$(OUTPUT)/test_progs: CFLAGS += $(TEST_PROGS_CFLAGS)
$(OUTPUT)/test_progs: test_progs.c $(PROG_TESTS_H) $(PROG_TESTS_FILES)
$(OUTPUT)/test_progs: test_progs.c $(PROG_TESTS_FILES) | $(PROG_TESTS_H)
$(PROG_TESTS_H): $(PROG_TESTS_FILES) | $(PROG_TESTS_DIR)
$(shell ( cd prog_tests/; \
echo '/* Generated header, do not edit */'; \
echo '#ifdef DECLARE'; \
ls *.c 2> /dev/null | \
sed -e 's@\([^\.]*\)\.c@extern void test_\1(void);@'; \
echo '#endif'; \
echo '#ifdef CALL'; \
ls *.c 2> /dev/null | \
sed -e 's@\([^\.]*\)\.c@test_\1();@'; \
echo '#endif' \
sed -e 's@\([^\.]*\)\.c@DEFINE_TEST(\1)@'; \
) > $(PROG_TESTS_H))
MAP_TESTS_DIR = $(OUTPUT)/map_tests
@@ -261,7 +286,7 @@ MAP_TESTS_H := $(MAP_TESTS_DIR)/tests.h
MAP_TESTS_FILES := $(wildcard map_tests/*.c)
test_maps.c: $(MAP_TESTS_H)
$(OUTPUT)/test_maps: CFLAGS += $(TEST_MAPS_CFLAGS)
$(OUTPUT)/test_maps: test_maps.c $(MAP_TESTS_H) $(MAP_TESTS_FILES)
$(OUTPUT)/test_maps: test_maps.c $(MAP_TESTS_FILES) | $(MAP_TESTS_H)
$(MAP_TESTS_H): $(MAP_TESTS_FILES) | $(MAP_TESTS_DIR)
$(shell ( cd map_tests/; \
echo '/* Generated header, do not edit */'; \
@@ -282,7 +307,7 @@ VERIFIER_TESTS_H := $(VERIFIER_TESTS_DIR)/tests.h
VERIFIER_TEST_FILES := $(wildcard verifier/*.c)
test_verifier.c: $(VERIFIER_TESTS_H)
$(OUTPUT)/test_verifier: CFLAGS += $(TEST_VERIFIER_CFLAGS)
$(OUTPUT)/test_verifier: test_verifier.c $(VERIFIER_TESTS_H)
$(OUTPUT)/test_verifier: test_verifier.c | $(VERIFIER_TEST_FILES) $(VERIFIER_TESTS_H)
$(VERIFIER_TESTS_H): $(VERIFIER_TEST_FILES) | $(VERIFIER_TESTS_DIR)
$(shell ( cd verifier/; \
echo '/* Generated header, do not edit */'; \
@@ -292,6 +317,6 @@ $(VERIFIER_TESTS_H): $(VERIFIER_TEST_FILES) | $(VERIFIER_TESTS_DIR)
echo '#endif' \
) > $(VERIFIER_TESTS_H))
EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(ALU32_BUILD_DIR) \
EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(ALU32_BUILD_DIR) $(BPF_GCC_BUILD_DIR) \
$(VERIFIER_TESTS_H) $(PROG_TESTS_H) $(MAP_TESTS_H) \
feature

View File

@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
#ifndef __BPF_ENDIAN__
#define __BPF_ENDIAN__
@@ -29,6 +29,10 @@
# define __bpf_htonl(x) __builtin_bswap32(x)
# define __bpf_constant_ntohl(x) ___constant_swab32(x)
# define __bpf_constant_htonl(x) ___constant_swab32(x)
# define __bpf_be64_to_cpu(x) __builtin_bswap64(x)
# define __bpf_cpu_to_be64(x) __builtin_bswap64(x)
# define __bpf_constant_be64_to_cpu(x) ___constant_swab64(x)
# define __bpf_constant_cpu_to_be64(x) ___constant_swab64(x)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define __bpf_ntohs(x) (x)
# define __bpf_htons(x) (x)
@@ -38,6 +42,10 @@
# define __bpf_htonl(x) (x)
# define __bpf_constant_ntohl(x) (x)
# define __bpf_constant_htonl(x) (x)
# define __bpf_be64_to_cpu(x) (x)
# define __bpf_cpu_to_be64(x) (x)
# define __bpf_constant_be64_to_cpu(x) (x)
# define __bpf_constant_cpu_to_be64(x) (x)
#else
# error "Fix your compiler's __BYTE_ORDER__?!"
#endif
@@ -54,5 +62,11 @@
#define bpf_ntohl(x) \
(__builtin_constant_p(x) ? \
__bpf_constant_ntohl(x) : __bpf_ntohl(x))
#define bpf_cpu_to_be64(x) \
(__builtin_constant_p(x) ? \
__bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x))
#define bpf_be64_to_cpu(x) \
(__builtin_constant_p(x) ? \
__bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x))
#endif /* __BPF_ENDIAN__ */

View File

@@ -1,12 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __BPF_HELPERS_H
#define __BPF_HELPERS_H
/* helper macro to place programs, maps, license in
* different sections in elf_bpf file. Section names
* are interpreted by elf_bpf loader
*/
#define SEC(NAME) __attribute__((section(NAME), used))
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
#ifndef __BPF_HELPERS__
#define __BPF_HELPERS__
#define __uint(name, val) int (*name)[val]
#define __type(name, val) val *name
@@ -19,6 +13,14 @@
##__VA_ARGS__); \
})
#ifdef __clang__
/* helper macro to place programs, maps, license in
* different sections in elf_bpf file. Section names
* are interpreted by elf_bpf loader
*/
#define SEC(NAME) __attribute__((section(NAME), used))
/* helper functions called from eBPF programs written in C */
static void *(*bpf_map_lookup_elem)(void *map, const void *key) =
(void *) BPF_FUNC_map_lookup_elem;
@@ -228,6 +230,9 @@ static void *(*bpf_sk_storage_get)(void *map, struct bpf_sock *sk,
static int (*bpf_sk_storage_delete)(void *map, struct bpf_sock *sk) =
(void *)BPF_FUNC_sk_storage_delete;
static int (*bpf_send_signal)(unsigned sig) = (void *)BPF_FUNC_send_signal;
static long long (*bpf_tcp_gen_syncookie)(struct bpf_sock *sk, void *ip,
int ip_len, void *tcp, int tcp_len) =
(void *) BPF_FUNC_tcp_gen_syncookie;
/* llvm builtin functions that eBPF C program may use to
* emit BPF_LD_ABS and BPF_LD_IND instructions
@@ -253,6 +258,12 @@ struct bpf_map_def {
unsigned int numa_node;
};
#else
#include <bpf-helpers.h>
#endif
#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val) \
struct ____btf_map_##name { \
type_key key; \
@@ -501,4 +512,24 @@ struct pt_regs;
(void *)(PT_REGS_FP(ctx) + sizeof(ip))); })
#endif
/*
* BPF_CORE_READ abstracts away bpf_probe_read() call and captures offset
* relocation for source address using __builtin_preserve_access_index()
* built-in, provided by Clang.
*
* __builtin_preserve_access_index() takes as an argument an expression of
* taking an address of a field within struct/union. It makes compiler emit
* a relocation, which records BTF type ID describing root struct/union and an
* accessor string which describes exact embedded field that was used to take
* an address. See detailed description of this relocation format and
* semantics in comments to struct bpf_offset_reloc in libbpf_internal.h.
*
* This relocation allows libbpf to adjust BPF instruction to use correct
* actual field offset, based on target kernel BTF type that matches original
* (local) BTF, used to record relocation.
*/
#define BPF_CORE_READ(dst, src) \
bpf_probe_read((dst), sizeof(*(src)), \
__builtin_preserve_access_index(src))
#endif

View File

@@ -48,16 +48,17 @@ void test_bpf_obj_id(void)
/* test_obj_id.o is a dumb prog. It should never fail
* to load.
*/
if (err)
error_cnt++;
assert(!err);
if (CHECK_FAIL(err))
continue;
/* Insert a magic value to the map */
map_fds[i] = bpf_find_map(__func__, objs[i], "test_map_id");
assert(map_fds[i] >= 0);
if (CHECK_FAIL(map_fds[i] < 0))
goto done;
err = bpf_map_update_elem(map_fds[i], &array_key,
&array_magic_value, 0);
assert(!err);
if (CHECK_FAIL(err))
goto done;
/* Check getting map info */
info_len = sizeof(struct bpf_map_info) * 2;
@@ -96,9 +97,11 @@ void test_bpf_obj_id(void)
prog_infos[i].map_ids = ptr_to_u64(map_ids + i);
prog_infos[i].nr_map_ids = 2;
err = clock_gettime(CLOCK_REALTIME, &real_time_ts);
assert(!err);
if (CHECK_FAIL(err))
goto done;
err = clock_gettime(CLOCK_BOOTTIME, &boot_time_ts);
assert(!err);
if (CHECK_FAIL(err))
goto done;
err = bpf_obj_get_info_by_fd(prog_fds[i], &prog_infos[i],
&info_len);
load_time = (real_time_ts.tv_sec - boot_time_ts.tv_sec)
@@ -106,8 +109,8 @@ void test_bpf_obj_id(void)
if (CHECK(err ||
prog_infos[i].type != BPF_PROG_TYPE_SOCKET_FILTER ||
info_len != sizeof(struct bpf_prog_info) ||
(jit_enabled && !prog_infos[i].jited_prog_len) ||
(jit_enabled &&
(env.jit_enabled && !prog_infos[i].jited_prog_len) ||
(env.jit_enabled &&
!memcmp(jited_insns, zeros, sizeof(zeros))) ||
!prog_infos[i].xlated_prog_len ||
!memcmp(xlated_insns, zeros, sizeof(zeros)) ||
@@ -121,7 +124,7 @@ void test_bpf_obj_id(void)
err, errno, i,
prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER,
info_len, sizeof(struct bpf_prog_info),
jit_enabled,
env.jit_enabled,
prog_infos[i].jited_prog_len,
prog_infos[i].xlated_prog_len,
!!memcmp(jited_insns, zeros, sizeof(zeros)),
@@ -224,7 +227,8 @@ void test_bpf_obj_id(void)
nr_id_found++;
err = bpf_map_lookup_elem(map_fd, &array_key, &array_value);
assert(!err);
if (CHECK_FAIL(err))
goto done;
err = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len);
CHECK(err || info_len != sizeof(struct bpf_map_info) ||

View File

@@ -4,12 +4,15 @@
static int libbpf_debug_print(enum libbpf_print_level level,
const char *format, va_list args)
{
if (level != LIBBPF_DEBUG)
return vfprintf(stderr, format, args);
if (level != LIBBPF_DEBUG) {
vprintf(format, args);
return 0;
}
if (!strstr(format, "verifier log"))
return 0;
return vfprintf(stderr, "%s", args);
vprintf("%s", args);
return 0;
}
static int check_load(const char *file, enum bpf_prog_type type)
@@ -25,19 +28,28 @@ static int check_load(const char *file, enum bpf_prog_type type)
attr.prog_flags = BPF_F_TEST_RND_HI32;
err = bpf_prog_load_xattr(&attr, &obj, &prog_fd);
bpf_object__close(obj);
if (err)
error_cnt++;
return err;
}
struct scale_test_def {
const char *file;
enum bpf_prog_type attach_type;
bool fails;
};
void test_bpf_verif_scale(void)
{
const char *sched_cls[] = {
"./test_verif_scale1.o", "./test_verif_scale2.o", "./test_verif_scale3.o",
};
const char *raw_tp[] = {
struct scale_test_def tests[] = {
{ "loop3.o", BPF_PROG_TYPE_RAW_TRACEPOINT, true /* fails */ },
{ "test_verif_scale1.o", BPF_PROG_TYPE_SCHED_CLS },
{ "test_verif_scale2.o", BPF_PROG_TYPE_SCHED_CLS },
{ "test_verif_scale3.o", BPF_PROG_TYPE_SCHED_CLS },
/* full unroll by llvm */
"./pyperf50.o", "./pyperf100.o", "./pyperf180.o",
{ "pyperf50.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
{ "pyperf100.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
{ "pyperf180.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
/* partial unroll. llvm will unroll loop ~150 times.
* C loop count -> 600.
@@ -45,7 +57,7 @@ void test_bpf_verif_scale(void)
* 16k insns in loop body.
* Total of 5 such loops. Total program size ~82k insns.
*/
"./pyperf600.o",
{ "pyperf600.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
/* no unroll at all.
* C loop count -> 600.
@@ -53,48 +65,47 @@ void test_bpf_verif_scale(void)
* ~110 insns in loop body.
* Total of 5 such loops. Total program size ~1500 insns.
*/
"./pyperf600_nounroll.o",
{ "pyperf600_nounroll.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
"./loop1.o", "./loop2.o",
{ "loop1.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
{ "loop2.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
{ "loop4.o", BPF_PROG_TYPE_SCHED_CLS },
{ "loop5.o", BPF_PROG_TYPE_SCHED_CLS },
/* partial unroll. 19k insn in a loop.
* Total program size 20.8k insn.
* ~350k processed_insns
*/
"./strobemeta.o",
{ "strobemeta.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
/* no unroll, tiny loops */
"./strobemeta_nounroll1.o",
"./strobemeta_nounroll2.o",
};
const char *cg_sysctl[] = {
"./test_sysctl_loop1.o", "./test_sysctl_loop2.o",
{ "strobemeta_nounroll1.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
{ "strobemeta_nounroll2.o", BPF_PROG_TYPE_RAW_TRACEPOINT },
{ "test_sysctl_loop1.o", BPF_PROG_TYPE_CGROUP_SYSCTL },
{ "test_sysctl_loop2.o", BPF_PROG_TYPE_CGROUP_SYSCTL },
{ "test_xdp_loop.o", BPF_PROG_TYPE_XDP },
{ "test_seg6_loop.o", BPF_PROG_TYPE_LWT_SEG6LOCAL },
};
libbpf_print_fn_t old_print_fn = NULL;
int err, i;
if (verifier_stats)
libbpf_set_print(libbpf_debug_print);
err = check_load("./loop3.o", BPF_PROG_TYPE_RAW_TRACEPOINT);
printf("test_scale:loop3:%s\n", err ? (error_cnt--, "OK") : "FAIL");
for (i = 0; i < ARRAY_SIZE(sched_cls); i++) {
err = check_load(sched_cls[i], BPF_PROG_TYPE_SCHED_CLS);
printf("test_scale:%s:%s\n", sched_cls[i], err ? "FAIL" : "OK");
if (env.verifier_stats) {
test__force_log();
old_print_fn = libbpf_set_print(libbpf_debug_print);
}
for (i = 0; i < ARRAY_SIZE(raw_tp); i++) {
err = check_load(raw_tp[i], BPF_PROG_TYPE_RAW_TRACEPOINT);
printf("test_scale:%s:%s\n", raw_tp[i], err ? "FAIL" : "OK");
for (i = 0; i < ARRAY_SIZE(tests); i++) {
const struct scale_test_def *test = &tests[i];
if (!test__start_subtest(test->file))
continue;
err = check_load(test->file, test->attach_type);
CHECK_FAIL(err && !test->fails);
}
for (i = 0; i < ARRAY_SIZE(cg_sysctl); i++) {
err = check_load(cg_sysctl[i], BPF_PROG_TYPE_CGROUP_SYSCTL);
printf("test_scale:%s:%s\n", cg_sysctl[i], err ? "FAIL" : "OK");
}
err = check_load("./test_xdp_loop.o", BPF_PROG_TYPE_XDP);
printf("test_scale:test_xdp_loop:%s\n", err ? "FAIL" : "OK");
err = check_load("./test_seg6_loop.o", BPF_PROG_TYPE_LWT_SEG6LOCAL);
printf("test_scale:test_seg6_loop:%s\n", err ? "FAIL" : "OK");
if (env.verifier_stats)
libbpf_set_print(old_print_fn);
}

View File

@@ -0,0 +1,385 @@
// SPDX-License-Identifier: GPL-2.0
#include <test_progs.h>
#include "progs/core_reloc_types.h"
#define STRUCT_TO_CHAR_PTR(struct_name) (const char *)&(struct struct_name)
#define FLAVORS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
.a = 42, \
.b = 0xc001, \
.c = 0xbeef, \
}
#define FLAVORS_CASE_COMMON(name) \
.case_name = #name, \
.bpf_obj_file = "test_core_reloc_flavors.o", \
.btf_src_file = "btf__core_reloc_" #name ".o" \
#define FLAVORS_CASE(name) { \
FLAVORS_CASE_COMMON(name), \
.input = FLAVORS_DATA(core_reloc_##name), \
.input_len = sizeof(struct core_reloc_##name), \
.output = FLAVORS_DATA(core_reloc_flavors), \
.output_len = sizeof(struct core_reloc_flavors), \
}
#define FLAVORS_ERR_CASE(name) { \
FLAVORS_CASE_COMMON(name), \
.fails = true, \
}
#define NESTING_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
.a = { .a = { .a = 42 } }, \
.b = { .b = { .b = 0xc001 } }, \
}
#define NESTING_CASE_COMMON(name) \
.case_name = #name, \
.bpf_obj_file = "test_core_reloc_nesting.o", \
.btf_src_file = "btf__core_reloc_" #name ".o"
#define NESTING_CASE(name) { \
NESTING_CASE_COMMON(name), \
.input = NESTING_DATA(core_reloc_##name), \
.input_len = sizeof(struct core_reloc_##name), \
.output = NESTING_DATA(core_reloc_nesting), \
.output_len = sizeof(struct core_reloc_nesting) \
}
#define NESTING_ERR_CASE(name) { \
NESTING_CASE_COMMON(name), \
.fails = true, \
}
#define ARRAYS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
.a = { [2] = 1 }, \
.b = { [1] = { [2] = { [3] = 2 } } }, \
.c = { [1] = { .c = 3 } }, \
.d = { [0] = { [0] = { .d = 4 } } }, \
}
#define ARRAYS_CASE_COMMON(name) \
.case_name = #name, \
.bpf_obj_file = "test_core_reloc_arrays.o", \
.btf_src_file = "btf__core_reloc_" #name ".o"
#define ARRAYS_CASE(name) { \
ARRAYS_CASE_COMMON(name), \
.input = ARRAYS_DATA(core_reloc_##name), \
.input_len = sizeof(struct core_reloc_##name), \
.output = STRUCT_TO_CHAR_PTR(core_reloc_arrays_output) { \
.a2 = 1, \
.b123 = 2, \
.c1c = 3, \
.d00d = 4, \
}, \
.output_len = sizeof(struct core_reloc_arrays_output) \
}
#define ARRAYS_ERR_CASE(name) { \
ARRAYS_CASE_COMMON(name), \
.fails = true, \
}
#define PRIMITIVES_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
.a = 1, \
.b = 2, \
.c = 3, \
.d = (void *)4, \
.f = (void *)5, \
}
#define PRIMITIVES_CASE_COMMON(name) \
.case_name = #name, \
.bpf_obj_file = "test_core_reloc_primitives.o", \
.btf_src_file = "btf__core_reloc_" #name ".o"
#define PRIMITIVES_CASE(name) { \
PRIMITIVES_CASE_COMMON(name), \
.input = PRIMITIVES_DATA(core_reloc_##name), \
.input_len = sizeof(struct core_reloc_##name), \
.output = PRIMITIVES_DATA(core_reloc_primitives), \
.output_len = sizeof(struct core_reloc_primitives), \
}
#define PRIMITIVES_ERR_CASE(name) { \
PRIMITIVES_CASE_COMMON(name), \
.fails = true, \
}
#define MODS_CASE(name) { \
.case_name = #name, \
.bpf_obj_file = "test_core_reloc_mods.o", \
.btf_src_file = "btf__core_reloc_" #name ".o", \
.input = STRUCT_TO_CHAR_PTR(core_reloc_##name) { \
.a = 1, \
.b = 2, \
.c = (void *)3, \
.d = (void *)4, \
.e = { [2] = 5 }, \
.f = { [1] = 6 }, \
.g = { .x = 7 }, \
.h = { .y = 8 }, \
}, \
.input_len = sizeof(struct core_reloc_##name), \
.output = STRUCT_TO_CHAR_PTR(core_reloc_mods_output) { \
.a = 1, .b = 2, .c = 3, .d = 4, \
.e = 5, .f = 6, .g = 7, .h = 8, \
}, \
.output_len = sizeof(struct core_reloc_mods_output), \
}
#define PTR_AS_ARR_CASE(name) { \
.case_name = #name, \
.bpf_obj_file = "test_core_reloc_ptr_as_arr.o", \
.btf_src_file = "btf__core_reloc_" #name ".o", \
.input = (const char *)&(struct core_reloc_##name []){ \
{ .a = 1 }, \
{ .a = 2 }, \
{ .a = 3 }, \
}, \
.input_len = 3 * sizeof(struct core_reloc_##name), \
.output = STRUCT_TO_CHAR_PTR(core_reloc_ptr_as_arr) { \
.a = 3, \
}, \
.output_len = sizeof(struct core_reloc_ptr_as_arr), \
}
#define INTS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
.u8_field = 1, \
.s8_field = 2, \
.u16_field = 3, \
.s16_field = 4, \
.u32_field = 5, \
.s32_field = 6, \
.u64_field = 7, \
.s64_field = 8, \
}
#define INTS_CASE_COMMON(name) \
.case_name = #name, \
.bpf_obj_file = "test_core_reloc_ints.o", \
.btf_src_file = "btf__core_reloc_" #name ".o"
#define INTS_CASE(name) { \
INTS_CASE_COMMON(name), \
.input = INTS_DATA(core_reloc_##name), \
.input_len = sizeof(struct core_reloc_##name), \
.output = INTS_DATA(core_reloc_ints), \
.output_len = sizeof(struct core_reloc_ints), \
}
#define INTS_ERR_CASE(name) { \
INTS_CASE_COMMON(name), \
.fails = true, \
}
struct core_reloc_test_case {
const char *case_name;
const char *bpf_obj_file;
const char *btf_src_file;
const char *input;
int input_len;
const char *output;
int output_len;
bool fails;
};
static struct core_reloc_test_case test_cases[] = {
/* validate we can find kernel image and use its BTF for relocs */
{
.case_name = "kernel",
.bpf_obj_file = "test_core_reloc_kernel.o",
.btf_src_file = NULL, /* load from /lib/modules/$(uname -r) */
.input = "",
.input_len = 0,
.output = "\1", /* true */
.output_len = 1,
},
/* validate BPF program can use multiple flavors to match against
* single target BTF type
*/
FLAVORS_CASE(flavors),
FLAVORS_ERR_CASE(flavors__err_wrong_name),
/* various struct/enum nesting and resolution scenarios */
NESTING_CASE(nesting),
NESTING_CASE(nesting___anon_embed),
NESTING_CASE(nesting___struct_union_mixup),
NESTING_CASE(nesting___extra_nesting),
NESTING_CASE(nesting___dup_compat_types),
NESTING_ERR_CASE(nesting___err_missing_field),
NESTING_ERR_CASE(nesting___err_array_field),
NESTING_ERR_CASE(nesting___err_missing_container),
NESTING_ERR_CASE(nesting___err_nonstruct_container),
NESTING_ERR_CASE(nesting___err_array_container),
NESTING_ERR_CASE(nesting___err_dup_incompat_types),
NESTING_ERR_CASE(nesting___err_partial_match_dups),
NESTING_ERR_CASE(nesting___err_too_deep),
/* various array access relocation scenarios */
ARRAYS_CASE(arrays),
ARRAYS_CASE(arrays___diff_arr_dim),
ARRAYS_CASE(arrays___diff_arr_val_sz),
ARRAYS_ERR_CASE(arrays___err_too_small),
ARRAYS_ERR_CASE(arrays___err_too_shallow),
ARRAYS_ERR_CASE(arrays___err_non_array),
ARRAYS_ERR_CASE(arrays___err_wrong_val_type1),
ARRAYS_ERR_CASE(arrays___err_wrong_val_type2),
/* enum/ptr/int handling scenarios */
PRIMITIVES_CASE(primitives),
PRIMITIVES_CASE(primitives___diff_enum_def),
PRIMITIVES_CASE(primitives___diff_func_proto),
PRIMITIVES_CASE(primitives___diff_ptr_type),
PRIMITIVES_ERR_CASE(primitives___err_non_enum),
PRIMITIVES_ERR_CASE(primitives___err_non_int),
PRIMITIVES_ERR_CASE(primitives___err_non_ptr),
/* const/volatile/restrict and typedefs scenarios */
MODS_CASE(mods),
MODS_CASE(mods___mod_swap),
MODS_CASE(mods___typedefs),
/* handling "ptr is an array" semantics */
PTR_AS_ARR_CASE(ptr_as_arr),
PTR_AS_ARR_CASE(ptr_as_arr___diff_sz),
/* int signedness/sizing/bitfield handling */
INTS_CASE(ints),
INTS_CASE(ints___bool),
INTS_CASE(ints___reverse_sign),
INTS_ERR_CASE(ints___err_bitfield),
INTS_ERR_CASE(ints___err_wrong_sz_8),
INTS_ERR_CASE(ints___err_wrong_sz_16),
INTS_ERR_CASE(ints___err_wrong_sz_32),
INTS_ERR_CASE(ints___err_wrong_sz_64),
/* validate edge cases of capturing relocations */
{
.case_name = "misc",
.bpf_obj_file = "test_core_reloc_misc.o",
.btf_src_file = "btf__core_reloc_misc.o",
.input = (const char *)&(struct core_reloc_misc_extensible[]){
{ .a = 1 },
{ .a = 2 }, /* not read */
{ .a = 3 },
},
.input_len = 4 * sizeof(int),
.output = STRUCT_TO_CHAR_PTR(core_reloc_misc_output) {
.a = 1,
.b = 1,
.c = 0, /* BUG in clang, should be 3 */
},
.output_len = sizeof(struct core_reloc_misc_output),
},
};
struct data {
char in[256];
char out[256];
};
void test_core_reloc(void)
{
const char *probe_name = "raw_tracepoint/sys_enter";
struct bpf_object_load_attr load_attr = {};
struct core_reloc_test_case *test_case;
int err, duration = 0, i, equal;
struct bpf_link *link = NULL;
struct bpf_map *data_map;
struct bpf_program *prog;
struct bpf_object *obj;
const int zero = 0;
struct data data;
for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
test_case = &test_cases[i];
if (!test__start_subtest(test_case->case_name))
continue;
obj = bpf_object__open(test_case->bpf_obj_file);
if (CHECK(IS_ERR_OR_NULL(obj), "obj_open",
"failed to open '%s': %ld\n",
test_case->bpf_obj_file, PTR_ERR(obj)))
continue;
prog = bpf_object__find_program_by_title(obj, probe_name);
if (CHECK(!prog, "find_probe",
"prog '%s' not found\n", probe_name))
goto cleanup;
bpf_program__set_type(prog, BPF_PROG_TYPE_RAW_TRACEPOINT);
load_attr.obj = obj;
load_attr.log_level = 0;
load_attr.target_btf_path = test_case->btf_src_file;
err = bpf_object__load_xattr(&load_attr);
if (test_case->fails) {
CHECK(!err, "obj_load_fail",
"should fail to load prog '%s'\n", probe_name);
goto cleanup;
} else {
if (CHECK(err, "obj_load",
"failed to load prog '%s': %d\n",
probe_name, err))
goto cleanup;
}
link = bpf_program__attach_raw_tracepoint(prog, "sys_enter");
if (CHECK(IS_ERR(link), "attach_raw_tp", "err %ld\n",
PTR_ERR(link)))
goto cleanup;
data_map = bpf_object__find_map_by_name(obj, "test_cor.bss");
if (CHECK(!data_map, "find_data_map", "data map not found\n"))
goto cleanup;
memset(&data, 0, sizeof(data));
memcpy(data.in, test_case->input, test_case->input_len);
err = bpf_map_update_elem(bpf_map__fd(data_map),
&zero, &data, 0);
if (CHECK(err, "update_data_map",
"failed to update .data map: %d\n", err))
goto cleanup;
/* trigger test run */
usleep(1);
err = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, &data);
if (CHECK(err, "get_result",
"failed to get output data: %d\n", err))
goto cleanup;
equal = memcmp(data.out, test_case->output,
test_case->output_len) == 0;
if (CHECK(!equal, "check_result",
"input/output data don't match\n")) {
int j;
for (j = 0; j < test_case->input_len; j++) {
printf("input byte #%d: 0x%02hhx\n",
j, test_case->input[j]);
}
for (j = 0; j < test_case->output_len; j++) {
printf("output byte #%d: EXP 0x%02hhx GOT 0x%02hhx\n",
j, test_case->output[j], data.out[j]);
}
goto cleanup;
}
cleanup:
if (!IS_ERR_OR_NULL(link)) {
bpf_link__destroy(link);
link = NULL;
}
bpf_object__close(obj);
}
}

View File

@@ -5,6 +5,10 @@
#include <linux/if_tun.h>
#include <sys/uio.h>
#ifndef IP_MF
#define IP_MF 0x2000
#endif
#define CHECK_FLOW_KEYS(desc, got, expected) \
CHECK_ATTR(memcmp(&got, &expected, sizeof(got)) != 0, \
desc, \
@@ -16,6 +20,7 @@
"is_encap=%u/%u " \
"ip_proto=0x%x/0x%x " \
"n_proto=0x%x/0x%x " \
"flow_label=0x%x/0x%x " \
"sport=%u/%u " \
"dport=%u/%u\n", \
got.nhoff, expected.nhoff, \
@@ -26,6 +31,7 @@
got.is_encap, expected.is_encap, \
got.ip_proto, expected.ip_proto, \
got.n_proto, expected.n_proto, \
got.flow_label, expected.flow_label, \
got.sport, expected.sport, \
got.dport, expected.dport)
@@ -35,6 +41,13 @@ struct ipv4_pkt {
struct tcphdr tcp;
} __packed;
struct ipip_pkt {
struct ethhdr eth;
struct iphdr iph;
struct iphdr iph_inner;
struct tcphdr tcp;
} __packed;
struct svlan_ipv4_pkt {
struct ethhdr eth;
__u16 vlan_tci;
@@ -49,6 +62,18 @@ struct ipv6_pkt {
struct tcphdr tcp;
} __packed;
struct ipv6_frag_pkt {
struct ethhdr eth;
struct ipv6hdr iph;
struct frag_hdr {
__u8 nexthdr;
__u8 reserved;
__be16 frag_off;
__be32 identification;
} ipf;
struct tcphdr tcp;
} __packed;
struct dvlan_ipv6_pkt {
struct ethhdr eth;
__u16 vlan_tci;
@@ -64,10 +89,13 @@ struct test {
union {
struct ipv4_pkt ipv4;
struct svlan_ipv4_pkt svlan_ipv4;
struct ipip_pkt ipip;
struct ipv6_pkt ipv6;
struct ipv6_frag_pkt ipv6_frag;
struct dvlan_ipv6_pkt dvlan_ipv6;
} pkt;
struct bpf_flow_keys keys;
__u32 flags;
};
#define VLAN_HLEN 4
@@ -81,6 +109,8 @@ struct test tests[] = {
.iph.protocol = IPPROTO_TCP,
.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
.tcp.doff = 5,
.tcp.source = 80,
.tcp.dest = 8080,
},
.keys = {
.nhoff = ETH_HLEN,
@@ -88,6 +118,8 @@ struct test tests[] = {
.addr_proto = ETH_P_IP,
.ip_proto = IPPROTO_TCP,
.n_proto = __bpf_constant_htons(ETH_P_IP),
.sport = 80,
.dport = 8080,
},
},
{
@@ -97,6 +129,8 @@ struct test tests[] = {
.iph.nexthdr = IPPROTO_TCP,
.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
.tcp.doff = 5,
.tcp.source = 80,
.tcp.dest = 8080,
},
.keys = {
.nhoff = ETH_HLEN,
@@ -104,6 +138,8 @@ struct test tests[] = {
.addr_proto = ETH_P_IPV6,
.ip_proto = IPPROTO_TCP,
.n_proto = __bpf_constant_htons(ETH_P_IPV6),
.sport = 80,
.dport = 8080,
},
},
{
@@ -115,6 +151,8 @@ struct test tests[] = {
.iph.protocol = IPPROTO_TCP,
.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
.tcp.doff = 5,
.tcp.source = 80,
.tcp.dest = 8080,
},
.keys = {
.nhoff = ETH_HLEN + VLAN_HLEN,
@@ -122,6 +160,8 @@ struct test tests[] = {
.addr_proto = ETH_P_IP,
.ip_proto = IPPROTO_TCP,
.n_proto = __bpf_constant_htons(ETH_P_IP),
.sport = 80,
.dport = 8080,
},
},
{
@@ -133,6 +173,8 @@ struct test tests[] = {
.iph.nexthdr = IPPROTO_TCP,
.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
.tcp.doff = 5,
.tcp.source = 80,
.tcp.dest = 8080,
},
.keys = {
.nhoff = ETH_HLEN + VLAN_HLEN * 2,
@@ -141,8 +183,205 @@ struct test tests[] = {
.addr_proto = ETH_P_IPV6,
.ip_proto = IPPROTO_TCP,
.n_proto = __bpf_constant_htons(ETH_P_IPV6),
.sport = 80,
.dport = 8080,
},
},
{
.name = "ipv4-frag",
.pkt.ipv4 = {
.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
.iph.ihl = 5,
.iph.protocol = IPPROTO_TCP,
.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
.iph.frag_off = __bpf_constant_htons(IP_MF),
.tcp.doff = 5,
.tcp.source = 80,
.tcp.dest = 8080,
},
.keys = {
.flags = BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG,
.nhoff = ETH_HLEN,
.thoff = ETH_HLEN + sizeof(struct iphdr),
.addr_proto = ETH_P_IP,
.ip_proto = IPPROTO_TCP,
.n_proto = __bpf_constant_htons(ETH_P_IP),
.is_frag = true,
.is_first_frag = true,
.sport = 80,
.dport = 8080,
},
.flags = BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG,
},
{
.name = "ipv4-no-frag",
.pkt.ipv4 = {
.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
.iph.ihl = 5,
.iph.protocol = IPPROTO_TCP,
.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
.iph.frag_off = __bpf_constant_htons(IP_MF),
.tcp.doff = 5,
.tcp.source = 80,
.tcp.dest = 8080,
},
.keys = {
.nhoff = ETH_HLEN,
.thoff = ETH_HLEN + sizeof(struct iphdr),
.addr_proto = ETH_P_IP,
.ip_proto = IPPROTO_TCP,
.n_proto = __bpf_constant_htons(ETH_P_IP),
.is_frag = true,
.is_first_frag = true,
},
},
{
.name = "ipv6-frag",
.pkt.ipv6_frag = {
.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
.iph.nexthdr = IPPROTO_FRAGMENT,
.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
.ipf.nexthdr = IPPROTO_TCP,
.tcp.doff = 5,
.tcp.source = 80,
.tcp.dest = 8080,
},
.keys = {
.flags = BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG,
.nhoff = ETH_HLEN,
.thoff = ETH_HLEN + sizeof(struct ipv6hdr) +
sizeof(struct frag_hdr),
.addr_proto = ETH_P_IPV6,
.ip_proto = IPPROTO_TCP,
.n_proto = __bpf_constant_htons(ETH_P_IPV6),
.is_frag = true,
.is_first_frag = true,
.sport = 80,
.dport = 8080,
},
.flags = BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG,
},
{
.name = "ipv6-no-frag",
.pkt.ipv6_frag = {
.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
.iph.nexthdr = IPPROTO_FRAGMENT,
.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
.ipf.nexthdr = IPPROTO_TCP,
.tcp.doff = 5,
.tcp.source = 80,
.tcp.dest = 8080,
},
.keys = {
.nhoff = ETH_HLEN,
.thoff = ETH_HLEN + sizeof(struct ipv6hdr) +
sizeof(struct frag_hdr),
.addr_proto = ETH_P_IPV6,
.ip_proto = IPPROTO_TCP,
.n_proto = __bpf_constant_htons(ETH_P_IPV6),
.is_frag = true,
.is_first_frag = true,
},
},
{
.name = "ipv6-flow-label",
.pkt.ipv6 = {
.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
.iph.nexthdr = IPPROTO_TCP,
.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
.iph.flow_lbl = { 0xb, 0xee, 0xef },
.tcp.doff = 5,
.tcp.source = 80,
.tcp.dest = 8080,
},
.keys = {
.nhoff = ETH_HLEN,
.thoff = ETH_HLEN + sizeof(struct ipv6hdr),
.addr_proto = ETH_P_IPV6,
.ip_proto = IPPROTO_TCP,
.n_proto = __bpf_constant_htons(ETH_P_IPV6),
.sport = 80,
.dport = 8080,
.flow_label = __bpf_constant_htonl(0xbeeef),
},
},
{
.name = "ipv6-no-flow-label",
.pkt.ipv6 = {
.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
.iph.nexthdr = IPPROTO_TCP,
.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
.iph.flow_lbl = { 0xb, 0xee, 0xef },
.tcp.doff = 5,
.tcp.source = 80,
.tcp.dest = 8080,
},
.keys = {
.flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL,
.nhoff = ETH_HLEN,
.thoff = ETH_HLEN + sizeof(struct ipv6hdr),
.addr_proto = ETH_P_IPV6,
.ip_proto = IPPROTO_TCP,
.n_proto = __bpf_constant_htons(ETH_P_IPV6),
.flow_label = __bpf_constant_htonl(0xbeeef),
},
.flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL,
},
{
.name = "ipip-encap",
.pkt.ipip = {
.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
.iph.ihl = 5,
.iph.protocol = IPPROTO_IPIP,
.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
.iph_inner.ihl = 5,
.iph_inner.protocol = IPPROTO_TCP,
.iph_inner.tot_len =
__bpf_constant_htons(MAGIC_BYTES) -
sizeof(struct iphdr),
.tcp.doff = 5,
.tcp.source = 80,
.tcp.dest = 8080,
},
.keys = {
.nhoff = ETH_HLEN,
.thoff = ETH_HLEN + sizeof(struct iphdr) +
sizeof(struct iphdr),
.addr_proto = ETH_P_IP,
.ip_proto = IPPROTO_TCP,
.n_proto = __bpf_constant_htons(ETH_P_IP),
.is_encap = true,
.sport = 80,
.dport = 8080,
},
},
{
.name = "ipip-no-encap",
.pkt.ipip = {
.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
.iph.ihl = 5,
.iph.protocol = IPPROTO_IPIP,
.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
.iph_inner.ihl = 5,
.iph_inner.protocol = IPPROTO_TCP,
.iph_inner.tot_len =
__bpf_constant_htons(MAGIC_BYTES) -
sizeof(struct iphdr),
.tcp.doff = 5,
.tcp.source = 80,
.tcp.dest = 8080,
},
.keys = {
.flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP,
.nhoff = ETH_HLEN,
.thoff = ETH_HLEN + sizeof(struct iphdr),
.addr_proto = ETH_P_IP,
.ip_proto = IPPROTO_IPIP,
.n_proto = __bpf_constant_htons(ETH_P_IP),
.is_encap = true,
},
.flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP,
},
};
static int create_tap(const char *ifname)
@@ -212,10 +451,8 @@ void test_flow_dissector(void)
err = bpf_flow_load(&obj, "./bpf_flow.o", "flow_dissector",
"jmp_table", "last_dissection", &prog_fd, &keys_fd);
if (err) {
error_cnt++;
if (CHECK_FAIL(err))
return;
}
for (i = 0; i < ARRAY_SIZE(tests); i++) {
struct bpf_flow_keys flow_keys;
@@ -225,6 +462,13 @@ void test_flow_dissector(void)
.data_size_in = sizeof(tests[i].pkt),
.data_out = &flow_keys,
};
static struct bpf_flow_keys ctx = {};
if (tests[i].flags) {
tattr.ctx_in = &ctx;
tattr.ctx_size_in = sizeof(ctx);
ctx.flags = tests[i].flags;
}
err = bpf_prog_test_run_xattr(&tattr);
CHECK_ATTR(tattr.data_size_out != sizeof(flow_keys) ||
@@ -251,9 +495,20 @@ void test_flow_dissector(void)
CHECK(err, "ifup", "err %d errno %d\n", err, errno);
for (i = 0; i < ARRAY_SIZE(tests); i++) {
struct bpf_flow_keys flow_keys = {};
/* Keep in sync with 'flags' from eth_get_headlen. */
__u32 eth_get_headlen_flags =
BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG;
struct bpf_prog_test_run_attr tattr = {};
__u32 key = 0;
struct bpf_flow_keys flow_keys = {};
__u32 key = (__u32)(tests[i].keys.sport) << 16 |
tests[i].keys.dport;
/* For skb-less case we can't pass input flags; run
* only the tests that have a matching set of flags.
*/
if (tests[i].flags != eth_get_headlen_flags)
continue;
err = tx_tap(tap_fd, &tests[i].pkt, sizeof(tests[i].pkt));
CHECK(err < 0, "tx_tap", "err %d errno %d\n", err, errno);
@@ -263,6 +518,9 @@ void test_flow_dissector(void)
CHECK_ATTR(err, tests[i].name, "skb-less err %d\n", err);
CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);
err = bpf_map_delete_elem(keys_fd, &key);
CHECK_ATTR(err, tests[i].name, "bpf_map_delete_elem %d\n", err);
}
bpf_prog_detach(prog_fd, BPF_FLOW_DISSECTOR);

View File

@@ -1,8 +1,15 @@
// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
#include <pthread.h>
#include <sched.h>
#include <sys/socket.h>
#include <test_progs.h>
#define MAX_CNT_RAWTP 10ull
#define MAX_STACK_RAWTP 100
static int duration = 0;
struct get_stack_trace_t {
int pid;
int kern_stack_size;
@@ -13,7 +20,7 @@ struct get_stack_trace_t {
struct bpf_stack_build_id user_stack_buildid[MAX_STACK_RAWTP];
};
static int get_stack_print_output(void *data, int size)
static void get_stack_print_output(void *ctx, int cpu, void *data, __u32 size)
{
bool good_kern_stack = false, good_user_stack = false;
const char *nonjit_func = "___bpf_prog_run";
@@ -34,7 +41,7 @@ static int get_stack_print_output(void *data, int size)
* just assume it is good if the stack is not empty.
* This could be improved in the future.
*/
if (jit_enabled) {
if (env.jit_enabled) {
found = num_stack > 0;
} else {
for (i = 0; i < num_stack; i++) {
@@ -51,7 +58,7 @@ static int get_stack_print_output(void *data, int size)
}
} else {
num_stack = e->kern_stack_size / sizeof(__u64);
if (jit_enabled) {
if (env.jit_enabled) {
good_kern_stack = num_stack > 0;
} else {
for (i = 0; i < num_stack; i++) {
@@ -65,75 +72,73 @@ static int get_stack_print_output(void *data, int size)
if (e->user_stack_size > 0 && e->user_stack_buildid_size > 0)
good_user_stack = true;
}
if (!good_kern_stack || !good_user_stack)
return LIBBPF_PERF_EVENT_ERROR;
if (cnt == MAX_CNT_RAWTP)
return LIBBPF_PERF_EVENT_DONE;
return LIBBPF_PERF_EVENT_CONT;
if (!good_kern_stack)
CHECK(!good_kern_stack, "kern_stack", "corrupted kernel stack\n");
if (!good_user_stack)
CHECK(!good_user_stack, "user_stack", "corrupted user stack\n");
}
void test_get_stack_raw_tp(void)
{
const char *file = "./test_get_stack_rawtp.o";
int i, efd, err, prog_fd, pmu_fd, perfmap_fd;
struct perf_event_attr attr = {};
const char *prog_name = "raw_tracepoint/sys_enter";
int i, err, prog_fd, exp_cnt = MAX_CNT_RAWTP;
struct perf_buffer_opts pb_opts = {};
struct perf_buffer *pb = NULL;
struct bpf_link *link = NULL;
struct timespec tv = {0, 10};
__u32 key = 0, duration = 0;
struct bpf_program *prog;
struct bpf_object *obj;
struct bpf_map *map;
cpu_set_t cpu_set;
err = bpf_prog_load(file, BPF_PROG_TYPE_RAW_TRACEPOINT, &obj, &prog_fd);
if (CHECK(err, "prog_load raw tp", "err %d errno %d\n", err, errno))
return;
efd = bpf_raw_tracepoint_open("sys_enter", prog_fd);
if (CHECK(efd < 0, "raw_tp_open", "err %d errno %d\n", efd, errno))
prog = bpf_object__find_program_by_title(obj, prog_name);
if (CHECK(!prog, "find_probe", "prog '%s' not found\n", prog_name))
goto close_prog;
perfmap_fd = bpf_find_map(__func__, obj, "perfmap");
if (CHECK(perfmap_fd < 0, "bpf_find_map", "err %d errno %d\n",
perfmap_fd, errno))
map = bpf_object__find_map_by_name(obj, "perfmap");
if (CHECK(!map, "bpf_find_map", "not found\n"))
goto close_prog;
err = load_kallsyms();
if (CHECK(err < 0, "load_kallsyms", "err %d errno %d\n", err, errno))
goto close_prog;
attr.sample_type = PERF_SAMPLE_RAW;
attr.type = PERF_TYPE_SOFTWARE;
attr.config = PERF_COUNT_SW_BPF_OUTPUT;
pmu_fd = syscall(__NR_perf_event_open, &attr, getpid()/*pid*/, -1/*cpu*/,
-1/*group_fd*/, 0);
if (CHECK(pmu_fd < 0, "perf_event_open", "err %d errno %d\n", pmu_fd,
errno))
CPU_ZERO(&cpu_set);
CPU_SET(0, &cpu_set);
err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
if (CHECK(err, "set_affinity", "err %d, errno %d\n", err, errno))
goto close_prog;
err = bpf_map_update_elem(perfmap_fd, &key, &pmu_fd, BPF_ANY);
if (CHECK(err < 0, "bpf_map_update_elem", "err %d errno %d\n", err,
errno))
link = bpf_program__attach_raw_tracepoint(prog, "sys_enter");
if (CHECK(IS_ERR(link), "attach_raw_tp", "err %ld\n", PTR_ERR(link)))
goto close_prog;
err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0);
if (CHECK(err < 0, "ioctl PERF_EVENT_IOC_ENABLE", "err %d errno %d\n",
err, errno))
goto close_prog;
err = perf_event_mmap(pmu_fd);
if (CHECK(err < 0, "perf_event_mmap", "err %d errno %d\n", err, errno))
pb_opts.sample_cb = get_stack_print_output;
pb = perf_buffer__new(bpf_map__fd(map), 8, &pb_opts);
if (CHECK(IS_ERR(pb), "perf_buf__new", "err %ld\n", PTR_ERR(pb)))
goto close_prog;
/* trigger some syscall action */
for (i = 0; i < MAX_CNT_RAWTP; i++)
nanosleep(&tv, NULL);
err = perf_event_poller(pmu_fd, get_stack_print_output);
if (CHECK(err < 0, "perf_event_poller", "err %d errno %d\n", err, errno))
goto close_prog;
while (exp_cnt > 0) {
err = perf_buffer__poll(pb, 100);
if (err < 0 && CHECK(err < 0, "pb__poll", "err %d\n", err))
goto close_prog;
exp_cnt -= err;
}
goto close_prog_noerr;
close_prog:
error_cnt++;
close_prog_noerr:
if (!IS_ERR_OR_NULL(link))
bpf_link__destroy(link);
if (!IS_ERR_OR_NULL(pb))
perf_buffer__free(pb);
bpf_object__close(obj);
}

View File

@@ -7,10 +7,8 @@ static void test_global_data_number(struct bpf_object *obj, __u32 duration)
uint64_t num;
map_fd = bpf_find_map(__func__, obj, "result_number");
if (map_fd < 0) {
error_cnt++;
if (CHECK_FAIL(map_fd < 0))
return;
}
struct {
char *name;
@@ -44,10 +42,8 @@ static void test_global_data_string(struct bpf_object *obj, __u32 duration)
char str[32];
map_fd = bpf_find_map(__func__, obj, "result_string");
if (map_fd < 0) {
error_cnt++;
if (CHECK_FAIL(map_fd < 0))
return;
}
struct {
char *name;
@@ -81,10 +77,8 @@ static void test_global_data_struct(struct bpf_object *obj, __u32 duration)
struct foo val;
map_fd = bpf_find_map(__func__, obj, "result_struct");
if (map_fd < 0) {
error_cnt++;
if (CHECK_FAIL(map_fd < 0))
return;
}
struct {
char *name;
@@ -112,16 +106,12 @@ static void test_global_data_rdonly(struct bpf_object *obj, __u32 duration)
__u8 *buff;
map = bpf_object__find_map_by_name(obj, "test_glo.rodata");
if (!map || !bpf_map__is_internal(map)) {
error_cnt++;
if (CHECK_FAIL(!map || !bpf_map__is_internal(map)))
return;
}
map_fd = bpf_map__fd(map);
if (map_fd < 0) {
error_cnt++;
if (CHECK_FAIL(map_fd < 0))
return;
}
buff = malloc(bpf_map__def(map)->value_size);
if (buff)

View File

@@ -30,10 +30,8 @@ static void test_l4lb(const char *file)
u32 *magic = (u32 *)buf;
err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
if (err) {
error_cnt++;
if (CHECK_FAIL(err))
return;
}
map_fd = bpf_find_map(__func__, obj, "vip_map");
if (map_fd < 0)
@@ -72,10 +70,9 @@ static void test_l4lb(const char *file)
bytes += stats[i].bytes;
pkts += stats[i].pkts;
}
if (bytes != MAGIC_BYTES * NUM_ITER * 2 || pkts != NUM_ITER * 2) {
error_cnt++;
if (CHECK_FAIL(bytes != MAGIC_BYTES * NUM_ITER * 2 ||
pkts != NUM_ITER * 2))
printf("test_l4lb:FAIL:stats %lld %lld\n", bytes, pkts);
}
out:
bpf_object__close(obj);
}

View File

@@ -8,14 +8,12 @@ static void *parallel_map_access(void *arg)
for (i = 0; i < 10000; i++) {
err = bpf_map_lookup_elem_flags(map_fd, &key, vars, BPF_F_LOCK);
if (err) {
if (CHECK_FAIL(err)) {
printf("lookup failed\n");
error_cnt++;
goto out;
}
if (vars[0] != 0) {
if (CHECK_FAIL(vars[0] != 0)) {
printf("lookup #%d var[0]=%d\n", i, vars[0]);
error_cnt++;
goto out;
}
rnd = vars[1];
@@ -24,7 +22,7 @@ static void *parallel_map_access(void *arg)
continue;
printf("lookup #%d var[1]=%d var[%d]=%d\n",
i, rnd, j, vars[j]);
error_cnt++;
CHECK_FAIL(vars[j] != rnd);
goto out;
}
}
@@ -42,34 +40,36 @@ void test_map_lock(void)
void *ret;
err = bpf_prog_load(file, BPF_PROG_TYPE_CGROUP_SKB, &obj, &prog_fd);
if (err) {
if (CHECK_FAIL(err)) {
printf("test_map_lock:bpf_prog_load errno %d\n", errno);
goto close_prog;
}
map_fd[0] = bpf_find_map(__func__, obj, "hash_map");
if (map_fd[0] < 0)
if (CHECK_FAIL(map_fd[0] < 0))
goto close_prog;
map_fd[1] = bpf_find_map(__func__, obj, "array_map");
if (map_fd[1] < 0)
if (CHECK_FAIL(map_fd[1] < 0))
goto close_prog;
bpf_map_update_elem(map_fd[0], &key, vars, BPF_F_LOCK);
for (i = 0; i < 4; i++)
assert(pthread_create(&thread_id[i], NULL,
&spin_lock_thread, &prog_fd) == 0);
if (CHECK_FAIL(pthread_create(&thread_id[i], NULL,
&spin_lock_thread, &prog_fd)))
goto close_prog;
for (i = 4; i < 6; i++)
assert(pthread_create(&thread_id[i], NULL,
&parallel_map_access, &map_fd[i - 4]) == 0);
if (CHECK_FAIL(pthread_create(&thread_id[i], NULL,
&parallel_map_access,
&map_fd[i - 4])))
goto close_prog;
for (i = 0; i < 4; i++)
assert(pthread_join(thread_id[i], &ret) == 0 &&
ret == (void *)&prog_fd);
if (CHECK_FAIL(pthread_join(thread_id[i], &ret) ||
ret != (void *)&prog_fd))
goto close_prog;
for (i = 4; i < 6; i++)
assert(pthread_join(thread_id[i], &ret) == 0 &&
ret == (void *)&map_fd[i - 4]);
goto close_prog_noerr;
if (CHECK_FAIL(pthread_join(thread_id[i], &ret) ||
ret != (void *)&map_fd[i - 4]))
goto close_prog;
close_prog:
error_cnt++;
close_prog_noerr:
bpf_object__close(obj);
}

View File

@@ -9,10 +9,8 @@ void test_pkt_access(void)
int err, prog_fd;
err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
if (err) {
error_cnt++;
if (CHECK_FAIL(err))
return;
}
err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4),
NULL, NULL, &retval, &duration);

View File

@@ -9,10 +9,8 @@ void test_pkt_md_access(void)
int err, prog_fd;
err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
if (err) {
error_cnt++;
if (CHECK_FAIL(err))
return;
}
err = bpf_prog_test_run(prog_fd, 10, &pkt_v4, sizeof(pkt_v4),
NULL, NULL, &retval, &duration);

View File

@@ -27,10 +27,8 @@ static void test_queue_stack_map_by_type(int type)
return;
err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
if (err) {
error_cnt++;
if (CHECK_FAIL(err))
return;
}
map_in_fd = bpf_find_map(__func__, obj, "map_in");
if (map_in_fd < 0)
@@ -43,10 +41,8 @@ static void test_queue_stack_map_by_type(int type)
/* Push 32 elements to the input map */
for (i = 0; i < MAP_SIZE; i++) {
err = bpf_map_update_elem(map_in_fd, NULL, &vals[i], 0);
if (err) {
error_cnt++;
if (CHECK_FAIL(err))
goto out;
}
}
/* The eBPF program pushes iph.saddr in the output map,

View File

@@ -1,15 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#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;
return vfprintf(stderr, format, args);
}
void test_reference_tracking(void)
{
const char *file = "./test_sk_lookup_kern.o";
@@ -19,10 +10,8 @@ void test_reference_tracking(void)
int err = 0;
obj = bpf_object__open(file);
if (IS_ERR(obj)) {
error_cnt++;
if (CHECK_FAIL(IS_ERR(obj)))
return;
}
bpf_object__for_each_program(prog, obj) {
const char *title;
@@ -36,9 +25,11 @@ void test_reference_tracking(void)
/* Expect verifier failure if test name has 'fail' */
if (strstr(title, "fail") != NULL) {
libbpf_set_print(NULL);
libbpf_print_fn_t old_print_fn;
old_print_fn = libbpf_set_print(NULL);
err = !bpf_program__load(prog, "GPL", 0);
libbpf_set_print(libbpf_debug_print);
libbpf_set_print(old_print_fn);
} else {
err = bpf_program__load(prog, "GPL", 0);
}

View File

@@ -8,7 +8,7 @@ static void sigusr1_handler(int signum)
sigusr1_received++;
}
static int test_send_signal_common(struct perf_event_attr *attr,
static void test_send_signal_common(struct perf_event_attr *attr,
int prog_type,
const char *test_name)
{
@@ -23,13 +23,13 @@ static int test_send_signal_common(struct perf_event_attr *attr,
if (CHECK(pipe(pipe_c2p), test_name,
"pipe pipe_c2p error: %s\n", strerror(errno)))
goto no_fork_done;
return;
if (CHECK(pipe(pipe_p2c), test_name,
"pipe pipe_p2c error: %s\n", strerror(errno))) {
close(pipe_c2p[0]);
close(pipe_c2p[1]);
goto no_fork_done;
return;
}
pid = fork();
@@ -38,7 +38,7 @@ static int test_send_signal_common(struct perf_event_attr *attr,
close(pipe_c2p[1]);
close(pipe_p2c[0]);
close(pipe_p2c[1]);
goto no_fork_done;
return;
}
if (pid == 0) {
@@ -125,7 +125,7 @@ static int test_send_signal_common(struct perf_event_attr *attr,
goto disable_pmu;
}
err = CHECK(buf[0] != '2', test_name, "incorrect result\n");
CHECK(buf[0] != '2', test_name, "incorrect result\n");
/* notify child safe to exit */
write(pipe_p2c[1], buf, 1);
@@ -138,11 +138,9 @@ prog_load_failure:
close(pipe_c2p[0]);
close(pipe_p2c[1]);
wait(NULL);
no_fork_done:
return err;
}
static int test_send_signal_tracepoint(void)
static void test_send_signal_tracepoint(void)
{
const char *id_path = "/sys/kernel/debug/tracing/events/syscalls/sys_enter_nanosleep/id";
struct perf_event_attr attr = {
@@ -159,21 +157,21 @@ static int test_send_signal_tracepoint(void)
if (CHECK(efd < 0, "tracepoint",
"open syscalls/sys_enter_nanosleep/id failure: %s\n",
strerror(errno)))
return -1;
return;
bytes = read(efd, buf, sizeof(buf));
close(efd);
if (CHECK(bytes <= 0 || bytes >= sizeof(buf), "tracepoint",
"read syscalls/sys_enter_nanosleep/id failure: %s\n",
strerror(errno)))
return -1;
return;
attr.config = strtol(buf, NULL, 0);
return test_send_signal_common(&attr, BPF_PROG_TYPE_TRACEPOINT, "tracepoint");
test_send_signal_common(&attr, BPF_PROG_TYPE_TRACEPOINT, "tracepoint");
}
static int test_send_signal_perf(void)
static void test_send_signal_perf(void)
{
struct perf_event_attr attr = {
.sample_period = 1,
@@ -181,11 +179,11 @@ static int test_send_signal_perf(void)
.config = PERF_COUNT_SW_CPU_CLOCK,
};
return test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT,
"perf_sw_event");
test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT,
"perf_sw_event");
}
static int test_send_signal_nmi(void)
static void test_send_signal_nmi(void)
{
struct perf_event_attr attr = {
.sample_freq = 50,
@@ -203,27 +201,25 @@ static int test_send_signal_nmi(void)
if (pmu_fd == -1) {
if (errno == ENOENT) {
printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
__func__);
return 0;
__func__);
test__skip();
return;
}
/* Let the test fail with a more informative message */
} else {
close(pmu_fd);
}
return test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT,
"perf_hw_event");
test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT,
"perf_hw_event");
}
void test_send_signal(void)
{
int ret = 0;
ret |= test_send_signal_tracepoint();
ret |= test_send_signal_perf();
ret |= test_send_signal_nmi();
if (!ret)
printf("test_send_signal:OK\n");
else
printf("test_send_signal:FAIL\n");
if (test__start_subtest("send_signal_tracepoint"))
test_send_signal_tracepoint();
if (test__start_subtest("send_signal_perf"))
test_send_signal_perf();
if (test__start_subtest("send_signal_nmi"))
test_send_signal_nmi();
}

View File

@@ -1,22 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/filter.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "bpf_rlimit.h"
#include "bpf_util.h"
#include <test_progs.h>
#include "cgroup_helpers.h"
#define CG_PATH "/sockopt"
static char bpf_log_buf[4096];
static bool verbose;
@@ -983,39 +968,18 @@ close_prog_fd:
return ret;
}
int main(int args, char **argv)
void test_sockopt(void)
{
int err = EXIT_FAILURE, error_cnt = 0;
int cgroup_fd, i;
if (setup_cgroup_environment())
goto cleanup_obj;
cgroup_fd = create_and_get_cgroup(CG_PATH);
if (cgroup_fd < 0)
goto cleanup_cgroup_env;
if (join_cgroup(CG_PATH))
goto cleanup_cgroup;
cgroup_fd = test__join_cgroup("/sockopt");
if (CHECK_FAIL(cgroup_fd < 0))
return;
for (i = 0; i < ARRAY_SIZE(tests); i++) {
int err = run_test(cgroup_fd, &tests[i]);
if (err)
error_cnt++;
printf("#%d %s: %s\n", i, err ? "FAIL" : "PASS",
tests[i].descr);
test__start_subtest(tests[i].descr);
CHECK_FAIL(run_test(cgroup_fd, &tests[i]));
}
printf("Summary: %ld PASSED, %d FAILED\n",
ARRAY_SIZE(tests) - error_cnt, error_cnt);
err = error_cnt ? EXIT_FAILURE : EXIT_SUCCESS;
cleanup_cgroup:
close(cgroup_fd);
cleanup_cgroup_env:
cleanup_cgroup_environment();
cleanup_obj:
return err;
}

View File

@@ -0,0 +1,235 @@
// SPDX-License-Identifier: GPL-2.0
#include <test_progs.h>
#include "cgroup_helpers.h"
#define SOL_CUSTOM 0xdeadbeef
#define CUSTOM_INHERIT1 0
#define CUSTOM_INHERIT2 1
#define CUSTOM_LISTENER 2
static int connect_to_server(int server_fd)
{
struct sockaddr_storage addr;
socklen_t len = sizeof(addr);
int fd;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
log_err("Failed to create client socket");
return -1;
}
if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) {
log_err("Failed to get server addr");
goto out;
}
if (connect(fd, (const struct sockaddr *)&addr, len) < 0) {
log_err("Fail to connect to server");
goto out;
}
return fd;
out:
close(fd);
return -1;
}
static int verify_sockopt(int fd, int optname, const char *msg, char expected)
{
socklen_t optlen = 1;
char buf = 0;
int err;
err = getsockopt(fd, SOL_CUSTOM, optname, &buf, &optlen);
if (err) {
log_err("%s: failed to call getsockopt", msg);
return 1;
}
printf("%s %d: got=0x%x ? expected=0x%x\n", msg, optname, buf, expected);
if (buf != expected) {
log_err("%s: unexpected getsockopt value %d != %d", msg,
buf, expected);
return 1;
}
return 0;
}
static pthread_mutex_t server_started_mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t server_started = PTHREAD_COND_INITIALIZER;
static void *server_thread(void *arg)
{
struct sockaddr_storage addr;
socklen_t len = sizeof(addr);
int fd = *(int *)arg;
int client_fd;
int err = 0;
err = listen(fd, 1);
pthread_mutex_lock(&server_started_mtx);
pthread_cond_signal(&server_started);
pthread_mutex_unlock(&server_started_mtx);
if (CHECK_FAIL(err < 0)) {
perror("Failed to listed on socket");
return NULL;
}
err += verify_sockopt(fd, CUSTOM_INHERIT1, "listen", 1);
err += verify_sockopt(fd, CUSTOM_INHERIT2, "listen", 1);
err += verify_sockopt(fd, CUSTOM_LISTENER, "listen", 1);
client_fd = accept(fd, (struct sockaddr *)&addr, &len);
if (CHECK_FAIL(client_fd < 0)) {
perror("Failed to accept client");
return NULL;
}
err += verify_sockopt(client_fd, CUSTOM_INHERIT1, "accept", 1);
err += verify_sockopt(client_fd, CUSTOM_INHERIT2, "accept", 1);
err += verify_sockopt(client_fd, CUSTOM_LISTENER, "accept", 0);
close(client_fd);
return (void *)(long)err;
}
static int start_server(void)
{
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
};
char buf;
int err;
int fd;
int i;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
log_err("Failed to create server socket");
return -1;
}
for (i = CUSTOM_INHERIT1; i <= CUSTOM_LISTENER; i++) {
buf = 0x01;
err = setsockopt(fd, SOL_CUSTOM, i, &buf, 1);
if (err) {
log_err("Failed to call setsockopt(%d)", i);
close(fd);
return -1;
}
}
if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) {
log_err("Failed to bind socket");
close(fd);
return -1;
}
return fd;
}
static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title)
{
enum bpf_attach_type attach_type;
enum bpf_prog_type prog_type;
struct bpf_program *prog;
int err;
err = libbpf_prog_type_by_name(title, &prog_type, &attach_type);
if (err) {
log_err("Failed to deduct types for %s BPF program", title);
return -1;
}
prog = bpf_object__find_program_by_title(obj, title);
if (!prog) {
log_err("Failed to find %s BPF program", title);
return -1;
}
err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd,
attach_type, 0);
if (err) {
log_err("Failed to attach %s BPF program", title);
return -1;
}
return 0;
}
static void run_test(int cgroup_fd)
{
struct bpf_prog_load_attr attr = {
.file = "./sockopt_inherit.o",
};
int server_fd = -1, client_fd;
struct bpf_object *obj;
void *server_err;
pthread_t tid;
int ignored;
int err;
err = bpf_prog_load_xattr(&attr, &obj, &ignored);
if (CHECK_FAIL(err))
return;
err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt");
if (CHECK_FAIL(err))
goto close_bpf_object;
err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt");
if (CHECK_FAIL(err))
goto close_bpf_object;
server_fd = start_server();
if (CHECK_FAIL(server_fd < 0))
goto close_bpf_object;
if (CHECK_FAIL(pthread_create(&tid, NULL, server_thread,
(void *)&server_fd)))
goto close_bpf_object;
pthread_mutex_lock(&server_started_mtx);
pthread_cond_wait(&server_started, &server_started_mtx);
pthread_mutex_unlock(&server_started_mtx);
client_fd = connect_to_server(server_fd);
if (CHECK_FAIL(client_fd < 0))
goto close_server_fd;
CHECK_FAIL(verify_sockopt(client_fd, CUSTOM_INHERIT1, "connect", 0));
CHECK_FAIL(verify_sockopt(client_fd, CUSTOM_INHERIT2, "connect", 0));
CHECK_FAIL(verify_sockopt(client_fd, CUSTOM_LISTENER, "connect", 0));
pthread_join(tid, &server_err);
err = (int)(long)server_err;
CHECK_FAIL(err);
close(client_fd);
close_server_fd:
close(server_fd);
close_bpf_object:
bpf_object__close(obj);
}
void test_sockopt_inherit(void)
{
int cgroup_fd;
cgroup_fd = test__join_cgroup("/sockopt_inherit");
if (CHECK_FAIL(cgroup_fd < 0))
return;
run_test(cgroup_fd);
close(cgroup_fd);
}

View File

@@ -1,19 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#include <error.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/filter.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "bpf_rlimit.h"
#include "bpf_util.h"
#include <test_progs.h>
#include "cgroup_helpers.h"
static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title)
@@ -308,7 +294,7 @@ detach:
return err;
}
int main(int argc, char **argv)
void test_sockopt_multi(void)
{
struct bpf_prog_load_attr attr = {
.file = "./sockopt_multi.o",
@@ -319,56 +305,28 @@ int main(int argc, char **argv)
int err = -1;
int ignored;
if (setup_cgroup_environment()) {
log_err("Failed to setup cgroup environment\n");
cg_parent = test__join_cgroup("/parent");
if (CHECK_FAIL(cg_parent < 0))
goto out;
}
cg_parent = create_and_get_cgroup("/parent");
if (cg_parent < 0) {
log_err("Failed to create cgroup /parent\n");
cg_child = test__join_cgroup("/parent/child");
if (CHECK_FAIL(cg_child < 0))
goto out;
}
cg_child = create_and_get_cgroup("/parent/child");
if (cg_child < 0) {
log_err("Failed to create cgroup /parent/child\n");
goto out;
}
if (join_cgroup("/parent/child")) {
log_err("Failed to join cgroup /parent/child\n");
goto out;
}
err = bpf_prog_load_xattr(&attr, &obj, &ignored);
if (err) {
log_err("Failed to load BPF object");
if (CHECK_FAIL(err))
goto out;
}
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0) {
log_err("Failed to create socket");
if (CHECK_FAIL(sock_fd < 0))
goto out;
}
if (run_getsockopt_test(obj, cg_parent, cg_child, sock_fd))
err = -1;
printf("test_sockopt_multi: getsockopt %s\n",
err ? "FAILED" : "PASSED");
if (run_setsockopt_test(obj, cg_parent, cg_child, sock_fd))
err = -1;
printf("test_sockopt_multi: setsockopt %s\n",
err ? "FAILED" : "PASSED");
CHECK_FAIL(run_getsockopt_test(obj, cg_parent, cg_child, sock_fd));
CHECK_FAIL(run_setsockopt_test(obj, cg_parent, cg_child, sock_fd));
out:
close(sock_fd);
bpf_object__close(obj);
close(cg_child);
close(cg_parent);
printf("test_sockopt_multi: %s\n", err ? "FAILED" : "PASSED");
return err ? EXIT_FAILURE : EXIT_SUCCESS;
}

View File

@@ -1,22 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/filter.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "bpf_rlimit.h"
#include "bpf_util.h"
#include <test_progs.h>
#include "cgroup_helpers.h"
#define CG_PATH "/sockopt"
#define SOL_CUSTOM 0xdeadbeef
static int getsetsockopt(void)
@@ -25,6 +10,7 @@ static int getsetsockopt(void)
union {
char u8[4];
__u32 u32;
char cc[16]; /* TCP_CA_NAME_MAX */
} buf = {};
socklen_t optlen;
@@ -115,6 +101,29 @@ static int getsetsockopt(void)
goto err;
}
/* TCP_CONGESTION can extend the string */
strcpy(buf.cc, "nv");
err = setsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, strlen("nv"));
if (err) {
log_err("Failed to call setsockopt(TCP_CONGESTION)");
goto err;
}
optlen = sizeof(buf.cc);
err = getsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, &optlen);
if (err) {
log_err("Failed to call getsockopt(TCP_CONGESTION)");
goto err;
}
if (strcmp(buf.cc, "cubic") != 0) {
log_err("Unexpected getsockopt(TCP_CONGESTION) %s != %s",
buf.cc, "cubic");
goto err;
}
close(fd);
return 0;
err:
@@ -151,7 +160,7 @@ static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title)
return 0;
}
static int run_test(int cgroup_fd)
static void run_test(int cgroup_fd)
{
struct bpf_prog_load_attr attr = {
.file = "./sockopt_sk.o",
@@ -161,51 +170,31 @@ static int run_test(int cgroup_fd)
int err;
err = bpf_prog_load_xattr(&attr, &obj, &ignored);
if (err) {
log_err("Failed to load BPF object");
return -1;
}
if (CHECK_FAIL(err))
return;
err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt");
if (err)
if (CHECK_FAIL(err))
goto close_bpf_object;
err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt");
if (err)
if (CHECK_FAIL(err))
goto close_bpf_object;
err = getsetsockopt();
CHECK_FAIL(getsetsockopt());
close_bpf_object:
bpf_object__close(obj);
return err;
}
int main(int args, char **argv)
void test_sockopt_sk(void)
{
int cgroup_fd;
int err = EXIT_SUCCESS;
if (setup_cgroup_environment())
goto cleanup_obj;
cgroup_fd = test__join_cgroup("/sockopt_sk");
if (CHECK_FAIL(cgroup_fd < 0))
return;
cgroup_fd = create_and_get_cgroup(CG_PATH);
if (cgroup_fd < 0)
goto cleanup_cgroup_env;
if (join_cgroup(CG_PATH))
goto cleanup_cgroup;
if (run_test(cgroup_fd))
err = EXIT_FAILURE;
printf("test_sockopt_sk: %s\n",
err == EXIT_SUCCESS ? "PASSED" : "FAILED");
cleanup_cgroup:
run_test(cgroup_fd);
close(cgroup_fd);
cleanup_cgroup_env:
cleanup_cgroup_environment();
cleanup_obj:
return err;
}

View File

@@ -11,19 +11,19 @@ void test_spinlock(void)
void *ret;
err = bpf_prog_load(file, BPF_PROG_TYPE_CGROUP_SKB, &obj, &prog_fd);
if (err) {
if (CHECK_FAIL(err)) {
printf("test_spin_lock:bpf_prog_load errno %d\n", errno);
goto close_prog;
}
for (i = 0; i < 4; i++)
assert(pthread_create(&thread_id[i], NULL,
&spin_lock_thread, &prog_fd) == 0);
if (CHECK_FAIL(pthread_create(&thread_id[i], NULL,
&spin_lock_thread, &prog_fd)))
goto close_prog;
for (i = 0; i < 4; i++)
assert(pthread_join(thread_id[i], &ret) == 0 &&
ret == (void *)&prog_fd);
goto close_prog_noerr;
if (CHECK_FAIL(pthread_join(thread_id[i], &ret) ||
ret != (void *)&prog_fd))
goto close_prog;
close_prog:
error_cnt++;
close_prog_noerr:
bpf_object__close(obj);
}

View File

@@ -51,9 +51,10 @@ retry:
"err %d errno %d\n", err, errno))
goto disable_pmu;
assert(system("dd if=/dev/urandom of=/dev/zero count=4 2> /dev/null")
== 0);
assert(system("./urandom_read") == 0);
if (CHECK_FAIL(system("dd if=/dev/urandom of=/dev/zero count=4 2> /dev/null")))
goto disable_pmu;
if (CHECK_FAIL(system("./urandom_read")))
goto disable_pmu;
/* disable stack trace collection */
key = 0;
val = 1;

View File

@@ -82,9 +82,10 @@ retry:
"err %d errno %d\n", err, errno))
goto disable_pmu;
assert(system("dd if=/dev/urandom of=/dev/zero count=4 2> /dev/null")
== 0);
assert(system("taskset 0x1 ./urandom_read 100000") == 0);
if (CHECK_FAIL(system("dd if=/dev/urandom of=/dev/zero count=4 2> /dev/null")))
goto disable_pmu;
if (CHECK_FAIL(system("taskset 0x1 ./urandom_read 100000")))
goto disable_pmu;
/* disable stack trace collection */
key = 0;
val = 1;

View File

@@ -26,19 +26,19 @@ void test_stacktrace_map(void)
/* find map fds */
control_map_fd = bpf_find_map(__func__, obj, "control_map");
if (control_map_fd < 0)
if (CHECK_FAIL(control_map_fd < 0))
goto disable_pmu;
stackid_hmap_fd = bpf_find_map(__func__, obj, "stackid_hmap");
if (stackid_hmap_fd < 0)
if (CHECK_FAIL(stackid_hmap_fd < 0))
goto disable_pmu;
stackmap_fd = bpf_find_map(__func__, obj, "stackmap");
if (stackmap_fd < 0)
if (CHECK_FAIL(stackmap_fd < 0))
goto disable_pmu;
stack_amap_fd = bpf_find_map(__func__, obj, "stack_amap");
if (stack_amap_fd < 0)
if (CHECK_FAIL(stack_amap_fd < 0))
goto disable_pmu;
/* give some time for bpf program run */
@@ -55,23 +55,20 @@ void test_stacktrace_map(void)
err = compare_map_keys(stackid_hmap_fd, stackmap_fd);
if (CHECK(err, "compare_map_keys stackid_hmap vs. stackmap",
"err %d errno %d\n", err, errno))
goto disable_pmu_noerr;
goto disable_pmu;
err = compare_map_keys(stackmap_fd, stackid_hmap_fd);
if (CHECK(err, "compare_map_keys stackmap vs. stackid_hmap",
"err %d errno %d\n", err, errno))
goto disable_pmu_noerr;
goto disable_pmu;
stack_trace_len = PERF_MAX_STACK_DEPTH * sizeof(__u64);
err = compare_stack_ips(stackmap_fd, stack_amap_fd, stack_trace_len);
if (CHECK(err, "compare_stack_ips stackmap vs. stack_amap",
"err %d errno %d\n", err, errno))
goto disable_pmu_noerr;
goto disable_pmu;
goto disable_pmu_noerr;
disable_pmu:
error_cnt++;
disable_pmu_noerr:
bpf_link__destroy(link);
close_prog:
bpf_object__close(obj);

View File

@@ -26,15 +26,15 @@ void test_stacktrace_map_raw_tp(void)
/* find map fds */
control_map_fd = bpf_find_map(__func__, obj, "control_map");
if (control_map_fd < 0)
if (CHECK_FAIL(control_map_fd < 0))
goto close_prog;
stackid_hmap_fd = bpf_find_map(__func__, obj, "stackid_hmap");
if (stackid_hmap_fd < 0)
if (CHECK_FAIL(stackid_hmap_fd < 0))
goto close_prog;
stackmap_fd = bpf_find_map(__func__, obj, "stackmap");
if (stackmap_fd < 0)
if (CHECK_FAIL(stackmap_fd < 0))
goto close_prog;
/* give some time for bpf program run */
@@ -58,10 +58,7 @@ void test_stacktrace_map_raw_tp(void)
"err %d errno %d\n", err, errno))
goto close_prog;
goto close_prog_noerr;
close_prog:
error_cnt++;
close_prog_noerr:
if (!IS_ERR_OR_NULL(link))
bpf_link__destroy(link);
bpf_object__close(obj);

View File

@@ -70,9 +70,6 @@ void test_task_fd_query_rawtp(void)
if (CHECK(!err, "check_results", "fd_type %d len %u\n", fd_type, len))
goto close_prog;
goto close_prog_noerr;
close_prog:
error_cnt++;
close_prog_noerr:
bpf_object__close(obj);
}

View File

@@ -62,14 +62,9 @@ static void test_task_fd_query_tp_core(const char *probe_name,
fd_type, buf))
goto close_pmu;
close(pmu_fd);
goto close_prog_noerr;
close_pmu:
close(pmu_fd);
close_prog:
error_cnt++;
close_prog_noerr:
bpf_object__close(obj);
}

View File

@@ -10,10 +10,8 @@ void test_tcp_estats(void)
err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd);
CHECK(err, "", "err %d errno %d\n", err, errno);
if (err) {
error_cnt++;
if (err)
return;
}
bpf_object__close(obj);
}

View File

@@ -1,23 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <error.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <linux/filter.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "bpf_rlimit.h"
#include "bpf_util.h"
#include <test_progs.h>
#include "cgroup_helpers.h"
#define CG_PATH "/tcp_rtt"
struct tcp_rtt_storage {
__u32 invoked;
__u32 dsack_dups;
@@ -30,8 +14,32 @@ static void send_byte(int fd)
{
char b = 0x55;
if (write(fd, &b, sizeof(b)) != 1)
error(1, errno, "Failed to send single byte");
if (CHECK_FAIL(write(fd, &b, sizeof(b)) != 1))
perror("Failed to send single byte");
}
static int wait_for_ack(int fd, int retries)
{
struct tcp_info info;
socklen_t optlen;
int i, err;
for (i = 0; i < retries; i++) {
optlen = sizeof(info);
err = getsockopt(fd, SOL_TCP, TCP_INFO, &info, &optlen);
if (err < 0) {
log_err("Failed to lookup TCP stats");
return err;
}
if (info.tcpi_unacked == 0)
return 0;
usleep(10);
}
log_err("Did not receive ACK");
return -1;
}
static int verify_sk(int map_fd, int client_fd, const char *msg, __u32 invoked,
@@ -41,8 +49,10 @@ static int verify_sk(int map_fd, int client_fd, const char *msg, __u32 invoked,
int err = 0;
struct tcp_rtt_storage val;
if (bpf_map_lookup_elem(map_fd, &client_fd, &val) < 0)
error(1, errno, "Failed to read socket storage");
if (CHECK_FAIL(bpf_map_lookup_elem(map_fd, &client_fd, &val) < 0)) {
perror("Failed to read socket storage");
return -1;
}
if (val.invoked != invoked) {
log_err("%s: unexpected bpf_tcp_sock.invoked %d != %d",
@@ -149,6 +159,11 @@ static int run_test(int cgroup_fd, int server_fd)
/*icsk_retransmits=*/0);
send_byte(client_fd);
if (wait_for_ack(client_fd, 100) < 0) {
err = -1;
goto close_client_fd;
}
err += verify_sk(map_fd, client_fd, "first payload byte",
/*invoked=*/2,
@@ -157,6 +172,7 @@ static int run_test(int cgroup_fd, int server_fd)
/*delivered_ce=*/0,
/*icsk_retransmits=*/0);
close_client_fd:
close(client_fd);
close_bpf_object:
@@ -194,61 +210,47 @@ static void *server_thread(void *arg)
int fd = *(int *)arg;
int client_fd;
if (listen(fd, 1) < 0)
error(1, errno, "Failed to listed on socket");
if (CHECK_FAIL(listen(fd, 1)) < 0) {
perror("Failed to listed on socket");
return NULL;
}
client_fd = accept(fd, (struct sockaddr *)&addr, &len);
if (client_fd < 0)
error(1, errno, "Failed to accept client");
if (CHECK_FAIL(client_fd < 0)) {
perror("Failed to accept client");
return NULL;
}
/* Wait for the next connection (that never arrives)
* to keep this thread alive to prevent calling
* close() on client_fd.
*/
if (accept(fd, (struct sockaddr *)&addr, &len) >= 0)
error(1, errno, "Unexpected success in second accept");
if (CHECK_FAIL(accept(fd, (struct sockaddr *)&addr, &len) >= 0)) {
perror("Unexpected success in second accept");
return NULL;
}
close(client_fd);
return NULL;
}
int main(int args, char **argv)
void test_tcp_rtt(void)
{
int server_fd, cgroup_fd;
int err = EXIT_SUCCESS;
pthread_t tid;
if (setup_cgroup_environment())
goto cleanup_obj;
cgroup_fd = create_and_get_cgroup(CG_PATH);
if (cgroup_fd < 0)
goto cleanup_cgroup_env;
if (join_cgroup(CG_PATH))
goto cleanup_cgroup;
cgroup_fd = test__join_cgroup("/tcp_rtt");
if (CHECK_FAIL(cgroup_fd < 0))
return;
server_fd = start_server();
if (server_fd < 0) {
err = EXIT_FAILURE;
goto cleanup_cgroup;
}
if (CHECK_FAIL(server_fd < 0))
goto close_cgroup_fd;
pthread_create(&tid, NULL, server_thread, (void *)&server_fd);
if (run_test(cgroup_fd, server_fd))
err = EXIT_FAILURE;
CHECK_FAIL(run_test(cgroup_fd, server_fd));
close(server_fd);
printf("test_sockopt_sk: %s\n",
err == EXIT_SUCCESS ? "PASSED" : "FAILED");
cleanup_cgroup:
close_cgroup_fd:
close(cgroup_fd);
cleanup_cgroup_env:
cleanup_cgroup_environment();
cleanup_obj:
return err;
}

View File

@@ -16,10 +16,8 @@ void test_xdp(void)
int err, prog_fd, map_fd;
err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
if (err) {
error_cnt++;
if (CHECK_FAIL(err))
return;
}
map_fd = bpf_find_map(__func__, obj, "vip2tnl");
if (map_fd < 0)

View File

@@ -10,10 +10,8 @@ void test_xdp_adjust_tail(void)
int err, prog_fd;
err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
if (err) {
error_cnt++;
if (CHECK_FAIL(err))
return;
}
err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
buf, &size, &retval, &duration);

View File

@@ -31,10 +31,8 @@ void test_xdp_noinline(void)
u32 *magic = (u32 *)buf;
err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
if (err) {
error_cnt++;
if (CHECK_FAIL(err))
return;
}
map_fd = bpf_find_map(__func__, obj, "vip_map");
if (map_fd < 0)
@@ -73,9 +71,10 @@ void test_xdp_noinline(void)
bytes += stats[i].bytes;
pkts += stats[i].pkts;
}
if (bytes != MAGIC_BYTES * NUM_ITER * 2 || pkts != NUM_ITER * 2) {
error_cnt++;
printf("test_xdp_noinline:FAIL:stats %lld %lld\n", bytes, pkts);
if (CHECK_FAIL(bytes != MAGIC_BYTES * NUM_ITER * 2 ||
pkts != NUM_ITER * 2)) {
printf("test_xdp_noinline:FAIL:stats %lld %lld\n",
bytes, pkts);
}
out:
bpf_object__close(obj);

View File

@@ -65,8 +65,8 @@ struct {
} jmp_table SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 1);
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, __u32);
__type(value, struct bpf_flow_keys);
} last_dissection SEC(".maps");
@@ -74,15 +74,20 @@ struct {
static __always_inline int export_flow_keys(struct bpf_flow_keys *keys,
int ret)
{
struct bpf_flow_keys *val;
__u32 key = 0;
__u32 key = (__u32)(keys->sport) << 16 | keys->dport;
struct bpf_flow_keys val;
val = bpf_map_lookup_elem(&last_dissection, &key);
if (val)
memcpy(val, keys, sizeof(*val));
memcpy(&val, keys, sizeof(val));
bpf_map_update_elem(&last_dissection, &key, &val, BPF_ANY);
return ret;
}
#define IPV6_FLOWLABEL_MASK __bpf_constant_htonl(0x000FFFFF)
static inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr)
{
return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK;
}
static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb,
__u16 hdr_size,
void *buffer)
@@ -153,7 +158,6 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
struct tcphdr *tcp, _tcp;
struct udphdr *udp, _udp;
keys->ip_proto = proto;
switch (proto) {
case IPPROTO_ICMP:
icmp = bpf_flow_dissect_get_header(skb, sizeof(*icmp), &_icmp);
@@ -162,9 +166,15 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
return export_flow_keys(keys, BPF_OK);
case IPPROTO_IPIP:
keys->is_encap = true;
if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP)
return export_flow_keys(keys, BPF_OK);
return parse_eth_proto(skb, bpf_htons(ETH_P_IP));
case IPPROTO_IPV6:
keys->is_encap = true;
if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP)
return export_flow_keys(keys, BPF_OK);
return parse_eth_proto(skb, bpf_htons(ETH_P_IPV6));
case IPPROTO_GRE:
gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre);
@@ -184,6 +194,8 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
keys->thoff += 4; /* Step over sequence number */
keys->is_encap = true;
if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP)
return export_flow_keys(keys, BPF_OK);
if (gre->proto == bpf_htons(ETH_P_TEB)) {
eth = bpf_flow_dissect_get_header(skb, sizeof(*eth),
@@ -231,7 +243,6 @@ static __always_inline int parse_ipv6_proto(struct __sk_buff *skb, __u8 nexthdr)
{
struct bpf_flow_keys *keys = skb->flow_keys;
keys->ip_proto = nexthdr;
switch (nexthdr) {
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
@@ -266,6 +277,7 @@ PROG(IP)(struct __sk_buff *skb)
keys->addr_proto = ETH_P_IP;
keys->ipv4_src = iph->saddr;
keys->ipv4_dst = iph->daddr;
keys->ip_proto = iph->protocol;
keys->thoff += iph->ihl << 2;
if (data + keys->thoff > data_end)
@@ -273,13 +285,20 @@ PROG(IP)(struct __sk_buff *skb)
if (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET)) {
keys->is_frag = true;
if (iph->frag_off & bpf_htons(IP_OFFSET))
if (iph->frag_off & bpf_htons(IP_OFFSET)) {
/* From second fragment on, packets do not have headers
* we can parse.
*/
done = true;
else
} else {
keys->is_first_frag = true;
/* No need to parse fragmented packet unless
* explicitly asked for.
*/
if (!(keys->flags &
BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG))
done = true;
}
}
if (done)
@@ -301,6 +320,11 @@ PROG(IPV6)(struct __sk_buff *skb)
memcpy(&keys->ipv6_src, &ip6h->saddr, 2*sizeof(ip6h->saddr));
keys->thoff += sizeof(struct ipv6hdr);
keys->ip_proto = ip6h->nexthdr;
keys->flow_label = ip6_flowlabel(ip6h);
if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)
return export_flow_keys(keys, BPF_OK);
return parse_ipv6_proto(skb, ip6h->nexthdr);
}
@@ -317,7 +341,8 @@ PROG(IPV6OP)(struct __sk_buff *skb)
/* hlen is in 8-octets and does not include the first 8 bytes
* of the header
*/
skb->flow_keys->thoff += (1 + ip6h->hdrlen) << 3;
keys->thoff += (1 + ip6h->hdrlen) << 3;
keys->ip_proto = ip6h->nexthdr;
return parse_ipv6_proto(skb, ip6h->nexthdr);
}
@@ -333,9 +358,18 @@ PROG(IPV6FR)(struct __sk_buff *skb)
keys->thoff += sizeof(*fragh);
keys->is_frag = true;
if (!(fragh->frag_off & bpf_htons(IP6_OFFSET)))
keys->ip_proto = fragh->nexthdr;
if (!(fragh->frag_off & bpf_htons(IP6_OFFSET))) {
keys->is_first_frag = true;
/* No need to parse fragmented packet unless
* explicitly asked for.
*/
if (!(keys->flags & BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG))
return export_flow_keys(keys, BPF_OK);
}
return parse_ipv6_proto(skb, fragh->nexthdr);
}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_arrays x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_arrays___diff_arr_dim x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_arrays___diff_arr_val_sz x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_arrays___err_non_array x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_arrays___err_too_shallow x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_arrays___err_too_small x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_arrays___err_wrong_val_type1 x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_arrays___err_wrong_val_type2 x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_flavors x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_flavors__err_wrong_name x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_ints x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_ints___bool x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_ints___err_bitfield x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_ints___err_wrong_sz_16 x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_ints___err_wrong_sz_32 x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_ints___err_wrong_sz_64 x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_ints___err_wrong_sz_8 x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_ints___reverse_sign x) {}

View File

@@ -0,0 +1,5 @@
#include "core_reloc_types.h"
void f1(struct core_reloc_misc___a x) {}
void f2(struct core_reloc_misc___b x) {}
void f3(struct core_reloc_misc_extensible x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_mods x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_mods___mod_swap x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_mods___typedefs x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_nesting x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___anon_embed x) {}

View File

@@ -0,0 +1,5 @@
#include "core_reloc_types.h"
void f1(struct core_reloc_nesting___dup_compat_types x) {}
void f2(struct core_reloc_nesting___dup_compat_types__2 x) {}
void f3(struct core_reloc_nesting___dup_compat_types__3 x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___err_array_container x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___err_array_field x) {}

View File

@@ -0,0 +1,4 @@
#include "core_reloc_types.h"
void f1(struct core_reloc_nesting___err_dup_incompat_types__1 x) {}
void f2(struct core_reloc_nesting___err_dup_incompat_types__2 x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___err_missing_container x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___err_missing_field x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___err_nonstruct_container x) {}

View File

@@ -0,0 +1,4 @@
#include "core_reloc_types.h"
void f1(struct core_reloc_nesting___err_partial_match_dups__a x) {}
void f2(struct core_reloc_nesting___err_partial_match_dups__b x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___err_too_deep x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___extra_nesting x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___struct_union_mixup x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_primitives x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_primitives___diff_enum_def x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_primitives___diff_func_proto x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_primitives___diff_ptr_type x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_primitives___err_non_enum x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_primitives___err_non_int x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_primitives___err_non_ptr x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_ptr_as_arr x) {}

View File

@@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_ptr_as_arr___diff_sz x) {}

View File

@@ -0,0 +1,667 @@
#include <stdint.h>
#include <stdbool.h>
/*
* FLAVORS
*/
struct core_reloc_flavors {
int a;
int b;
int c;
};
/* this is not a flavor, as it doesn't have triple underscore */
struct core_reloc_flavors__err_wrong_name {
int a;
int b;
int c;
};
/*
* NESTING
*/
/* original set up, used to record relocations in BPF program */
struct core_reloc_nesting_substruct {
int a;
};
union core_reloc_nesting_subunion {
int b;
};
struct core_reloc_nesting {
union {
struct core_reloc_nesting_substruct a;
} a;
struct {
union core_reloc_nesting_subunion b;
} b;
};
/* inlined anonymous struct/union instead of named structs in original */
struct core_reloc_nesting___anon_embed {
int __just_for_padding;
union {
struct {
int a;
} a;
} a;
struct {
union {
int b;
} b;
} b;
};
/* different mix of nested structs/unions than in original */
struct core_reloc_nesting___struct_union_mixup {
int __a;
struct {
int __a;
union {
char __a;
int a;
} a;
} a;
int __b;
union {
int __b;
union {
char __b;
int b;
} b;
} b;
};
/* extra anon structs/unions, but still valid a.a.a and b.b.b accessors */
struct core_reloc_nesting___extra_nesting {
int __padding;
struct {
struct {
struct {
struct {
union {
int a;
} a;
};
};
} a;
int __some_more;
struct {
union {
union {
union {
struct {
int b;
};
} b;
};
} b;
};
};
};
/* three flavors of same struct with different structure but same layout for
* a.a.a and b.b.b, thus successfully resolved and relocatable */
struct core_reloc_nesting___dup_compat_types {
char __just_for_padding;
/* 3 more bytes of padding */
struct {
struct {
int a; /* offset 4 */
} a;
} a;
long long __more_padding;
struct {
struct {
int b; /* offset 16 */
} b;
} b;
};
struct core_reloc_nesting___dup_compat_types__2 {
int __aligned_padding;
struct {
int __trickier_noop[0];
struct {
char __some_more_noops[0];
int a; /* offset 4 */
} a;
} a;
int __more_padding;
struct {
struct {
struct {
int __critical_padding;
int b; /* offset 16 */
} b;
int __does_not_matter;
};
} b;
int __more_irrelevant_stuff;
};
struct core_reloc_nesting___dup_compat_types__3 {
char __correct_padding[4];
struct {
struct {
int a; /* offset 4 */
} a;
} a;
/* 8 byte padding due to next struct's alignment */
struct {
struct {
int b;
} b;
} b __attribute__((aligned(16)));
};
/* b.b.b field is missing */
struct core_reloc_nesting___err_missing_field {
struct {
struct {
int a;
} a;
} a;
struct {
struct {
int x;
} b;
} b;
};
/* b.b.b field is an array of integers instead of plain int */
struct core_reloc_nesting___err_array_field {
struct {
struct {
int a;
} a;
} a;
struct {
struct {
int b[1];
} b;
} b;
};
/* middle b container is missing */
struct core_reloc_nesting___err_missing_container {
struct {
struct {
int a;
} a;
} a;
struct {
int x;
} b;
};
/* middle b container is referenced through pointer instead of being embedded */
struct core_reloc_nesting___err_nonstruct_container {
struct {
struct {
int a;
} a;
} a;
struct {
struct {
int b;
} *b;
} b;
};
/* middle b container is an array of structs instead of plain struct */
struct core_reloc_nesting___err_array_container {
struct {
struct {
int a;
} a;
} a;
struct {
struct {
int b;
} b[1];
} b;
};
/* two flavors of same struct with incompatible layout for b.b.b */
struct core_reloc_nesting___err_dup_incompat_types__1 {
struct {
struct {
int a; /* offset 0 */
} a;
} a;
struct {
struct {
int b; /* offset 4 */
} b;
} b;
};
struct core_reloc_nesting___err_dup_incompat_types__2 {
struct {
struct {
int a; /* offset 0 */
} a;
} a;
int __extra_padding;
struct {
struct {
int b; /* offset 8 (!) */
} b;
} b;
};
/* two flavors of same struct having one of a.a.a and b.b.b, but not both */
struct core_reloc_nesting___err_partial_match_dups__a {
struct {
struct {
int a;
} a;
} a;
};
struct core_reloc_nesting___err_partial_match_dups__b {
struct {
struct {
int b;
} b;
} b;
};
struct core_reloc_nesting___err_too_deep {
struct {
struct {
int a;
} a;
} a;
/* 65 levels of nestedness for b.b.b */
struct {
struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
/* this one is one too much */
struct {
int b;
};
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
} b;
} b;
};
/*
* ARRAYS
*/
struct core_reloc_arrays_output {
int a2;
char b123;
int c1c;
int d00d;
};
struct core_reloc_arrays_substruct {
int c;
int d;
};
struct core_reloc_arrays {
int a[5];
char b[2][3][4];
struct core_reloc_arrays_substruct c[3];
struct core_reloc_arrays_substruct d[1][2];
};
/* bigger array dimensions */
struct core_reloc_arrays___diff_arr_dim {
int a[7];
char b[3][4][5];
struct core_reloc_arrays_substruct c[4];
struct core_reloc_arrays_substruct d[2][3];
};
/* different size of array's value (struct) */
struct core_reloc_arrays___diff_arr_val_sz {
int a[5];
char b[2][3][4];
struct {
int __padding1;
int c;
int __padding2;
} c[3];
struct {
int __padding1;
int d;
int __padding2;
} d[1][2];
};
struct core_reloc_arrays___err_too_small {
int a[2]; /* this one is too small */
char b[2][3][4];
struct core_reloc_arrays_substruct c[3];
struct core_reloc_arrays_substruct d[1][2];
};
struct core_reloc_arrays___err_too_shallow {
int a[5];
char b[2][3]; /* this one lacks one dimension */
struct core_reloc_arrays_substruct c[3];
struct core_reloc_arrays_substruct d[1][2];
};
struct core_reloc_arrays___err_non_array {
int a; /* not an array */
char b[2][3][4];
struct core_reloc_arrays_substruct c[3];
struct core_reloc_arrays_substruct d[1][2];
};
struct core_reloc_arrays___err_wrong_val_type1 {
char a[5]; /* char instead of int */
char b[2][3][4];
struct core_reloc_arrays_substruct c[3];
struct core_reloc_arrays_substruct d[1][2];
};
struct core_reloc_arrays___err_wrong_val_type2 {
int a[5];
char b[2][3][4];
int c[3]; /* value is not a struct */
struct core_reloc_arrays_substruct d[1][2];
};
/*
* PRIMITIVES
*/
enum core_reloc_primitives_enum {
A = 0,
B = 1,
};
struct core_reloc_primitives {
char a;
int b;
enum core_reloc_primitives_enum c;
void *d;
int (*f)(const char *);
};
struct core_reloc_primitives___diff_enum_def {
char a;
int b;
void *d;
int (*f)(const char *);
enum {
X = 100,
Y = 200,
} c; /* inline enum def with differing set of values */
};
struct core_reloc_primitives___diff_func_proto {
void (*f)(int); /* incompatible function prototype */
void *d;
enum core_reloc_primitives_enum c;
int b;
char a;
};
struct core_reloc_primitives___diff_ptr_type {
const char * const d; /* different pointee type + modifiers */
char a;
int b;
enum core_reloc_primitives_enum c;
int (*f)(const char *);
};
struct core_reloc_primitives___err_non_enum {
char a[1];
int b;
int c; /* int instead of enum */
void *d;
int (*f)(const char *);
};
struct core_reloc_primitives___err_non_int {
char a[1];
int *b; /* ptr instead of int */
enum core_reloc_primitives_enum c;
void *d;
int (*f)(const char *);
};
struct core_reloc_primitives___err_non_ptr {
char a[1];
int b;
enum core_reloc_primitives_enum c;
int d; /* int instead of ptr */
int (*f)(const char *);
};
/*
* MODS
*/
struct core_reloc_mods_output {
int a, b, c, d, e, f, g, h;
};
typedef const int int_t;
typedef const char *char_ptr_t;
typedef const int arr_t[7];
struct core_reloc_mods_substruct {
int x;
int y;
};
typedef struct {
int x;
int y;
} core_reloc_mods_substruct_t;
struct core_reloc_mods {
int a;
int_t b;
char *c;
char_ptr_t d;
int e[3];
arr_t f;
struct core_reloc_mods_substruct g;
core_reloc_mods_substruct_t h;
};
/* a/b, c/d, e/f, and g/h pairs are swapped */
struct core_reloc_mods___mod_swap {
int b;
int_t a;
char *d;
char_ptr_t c;
int f[3];
arr_t e;
struct {
int y;
int x;
} h;
core_reloc_mods_substruct_t g;
};
typedef int int1_t;
typedef int1_t int2_t;
typedef int2_t int3_t;
typedef int arr1_t[5];
typedef arr1_t arr2_t;
typedef arr2_t arr3_t;
typedef arr3_t arr4_t;
typedef const char * const volatile fancy_char_ptr_t;
typedef core_reloc_mods_substruct_t core_reloc_mods_substruct_tt;
/* we need more typedefs */
struct core_reloc_mods___typedefs {
core_reloc_mods_substruct_tt g;
core_reloc_mods_substruct_tt h;
arr4_t f;
arr4_t e;
fancy_char_ptr_t d;
fancy_char_ptr_t c;
int3_t b;
int3_t a;
};
/*
* PTR_AS_ARR
*/
struct core_reloc_ptr_as_arr {
int a;
};
struct core_reloc_ptr_as_arr___diff_sz {
int :32; /* padding */
char __some_more_padding;
int a;
};
/*
* INTS
*/
struct core_reloc_ints {
uint8_t u8_field;
int8_t s8_field;
uint16_t u16_field;
int16_t s16_field;
uint32_t u32_field;
int32_t s32_field;
uint64_t u64_field;
int64_t s64_field;
};
/* signed/unsigned types swap */
struct core_reloc_ints___reverse_sign {
int8_t u8_field;
uint8_t s8_field;
int16_t u16_field;
uint16_t s16_field;
int32_t u32_field;
uint32_t s32_field;
int64_t u64_field;
uint64_t s64_field;
};
struct core_reloc_ints___bool {
bool u8_field; /* bool instead of uint8 */
int8_t s8_field;
uint16_t u16_field;
int16_t s16_field;
uint32_t u32_field;
int32_t s32_field;
uint64_t u64_field;
int64_t s64_field;
};
struct core_reloc_ints___err_bitfield {
uint8_t u8_field;
int8_t s8_field;
uint16_t u16_field;
int16_t s16_field;
uint32_t u32_field: 32; /* bitfields are not supported */
int32_t s32_field;
uint64_t u64_field;
int64_t s64_field;
};
struct core_reloc_ints___err_wrong_sz_8 {
uint16_t u8_field; /* not 8-bit anymore */
int16_t s8_field; /* not 8-bit anymore */
uint16_t u16_field;
int16_t s16_field;
uint32_t u32_field;
int32_t s32_field;
uint64_t u64_field;
int64_t s64_field;
};
struct core_reloc_ints___err_wrong_sz_16 {
uint8_t u8_field;
int8_t s8_field;
uint32_t u16_field; /* not 16-bit anymore */
int32_t s16_field; /* not 16-bit anymore */
uint32_t u32_field;
int32_t s32_field;
uint64_t u64_field;
int64_t s64_field;
};
struct core_reloc_ints___err_wrong_sz_32 {
uint8_t u8_field;
int8_t s8_field;
uint16_t u16_field;
int16_t s16_field;
uint64_t u32_field; /* not 32-bit anymore */
int64_t s32_field; /* not 32-bit anymore */
uint64_t u64_field;
int64_t s64_field;
};
struct core_reloc_ints___err_wrong_sz_64 {
uint8_t u8_field;
int8_t s8_field;
uint16_t u16_field;
int16_t s16_field;
uint32_t u32_field;
int32_t s32_field;
uint32_t u64_field; /* not 64-bit anymore */
int32_t s64_field; /* not 64-bit anymore */
};
/*
* MISC
*/
struct core_reloc_misc_output {
int a, b, c;
};
struct core_reloc_misc___a {
int a1;
int a2;
};
struct core_reloc_misc___b {
int b1;
int b2;
};
/* this one extends core_reloc_misc_extensible struct from BPF prog */
struct core_reloc_misc_extensible {
int a;
int b;
int c;
int d;
};

View File

@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/bpf.h>
#include "bpf_helpers.h"
char _license[] SEC("license") = "GPL";
SEC("socket")
int combinations(volatile struct __sk_buff* skb)
{
int ret = 0, i;
#pragma nounroll
for (i = 0; i < 20; i++)
if (skb->len)
ret |= 1 << i;
return ret;
}

View File

@@ -0,0 +1,32 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/bpf.h>
#include "bpf_helpers.h"
#define barrier() __asm__ __volatile__("": : :"memory")
char _license[] SEC("license") = "GPL";
SEC("socket")
int while_true(volatile struct __sk_buff* skb)
{
int i = 0;
while (1) {
if (skb->len)
i += 3;
else
i += 7;
if (i == 9)
break;
barrier();
if (i == 10)
break;
barrier();
if (i == 13)
break;
barrier();
if (i == 14)
break;
}
return i;
}

View File

@@ -0,0 +1,97 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include "bpf_helpers.h"
char _license[] SEC("license") = "GPL";
__u32 _version SEC("version") = 1;
#define SOL_CUSTOM 0xdeadbeef
#define CUSTOM_INHERIT1 0
#define CUSTOM_INHERIT2 1
#define CUSTOM_LISTENER 2
struct sockopt_inherit {
__u8 val;
};
struct {
__uint(type, BPF_MAP_TYPE_SK_STORAGE);
__uint(map_flags, BPF_F_NO_PREALLOC | BPF_F_CLONE);
__type(key, int);
__type(value, struct sockopt_inherit);
} cloned1_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_SK_STORAGE);
__uint(map_flags, BPF_F_NO_PREALLOC | BPF_F_CLONE);
__type(key, int);
__type(value, struct sockopt_inherit);
} cloned2_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_SK_STORAGE);
__uint(map_flags, BPF_F_NO_PREALLOC);
__type(key, int);
__type(value, struct sockopt_inherit);
} listener_only_map SEC(".maps");
static __inline struct sockopt_inherit *get_storage(struct bpf_sockopt *ctx)
{
if (ctx->optname == CUSTOM_INHERIT1)
return bpf_sk_storage_get(&cloned1_map, ctx->sk, 0,
BPF_SK_STORAGE_GET_F_CREATE);
else if (ctx->optname == CUSTOM_INHERIT2)
return bpf_sk_storage_get(&cloned2_map, ctx->sk, 0,
BPF_SK_STORAGE_GET_F_CREATE);
else
return bpf_sk_storage_get(&listener_only_map, ctx->sk, 0,
BPF_SK_STORAGE_GET_F_CREATE);
}
SEC("cgroup/getsockopt")
int _getsockopt(struct bpf_sockopt *ctx)
{
__u8 *optval_end = ctx->optval_end;
struct sockopt_inherit *storage;
__u8 *optval = ctx->optval;
if (ctx->level != SOL_CUSTOM)
return 1; /* only interested in SOL_CUSTOM */
if (optval + 1 > optval_end)
return 0; /* EPERM, bounds check */
storage = get_storage(ctx);
if (!storage)
return 0; /* EPERM, couldn't get sk storage */
ctx->retval = 0; /* Reset system call return value to zero */
optval[0] = storage->val;
ctx->optlen = 1;
return 1;
}
SEC("cgroup/setsockopt")
int _setsockopt(struct bpf_sockopt *ctx)
{
__u8 *optval_end = ctx->optval_end;
struct sockopt_inherit *storage;
__u8 *optval = ctx->optval;
if (ctx->level != SOL_CUSTOM)
return 1; /* only interested in SOL_CUSTOM */
if (optval + 1 > optval_end)
return 0; /* EPERM, bounds check */
storage = get_storage(ctx);
if (!storage)
return 0; /* EPERM, couldn't get sk storage */
storage->val = optval[0];
ctx->optlen = -1;
return 1;
}

View File

@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <string.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <linux/bpf.h>
#include "bpf_helpers.h"
@@ -42,6 +44,14 @@ int _getsockopt(struct bpf_sockopt *ctx)
return 1;
}
if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION) {
/* Not interested in SOL_TCP:TCP_CONGESTION;
* let next BPF program in the cgroup chain or kernel
* handle it.
*/
return 1;
}
if (ctx->level != SOL_CUSTOM)
return 0; /* EPERM, deny everything except custom level */
@@ -91,6 +101,18 @@ int _setsockopt(struct bpf_sockopt *ctx)
return 1;
}
if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION) {
/* Always use cubic */
if (optval + 5 > optval_end)
return 0; /* EPERM, bounds check */
memcpy(optval, "cubic", 5);
ctx->optlen = 5;
return 1;
}
if (ctx->level != SOL_CUSTOM)
return 0; /* EPERM, deny everything except custom level */

View File

@@ -0,0 +1,55 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/bpf.h>
#include <stdint.h>
#include "bpf_helpers.h"
char _license[] SEC("license") = "GPL";
static volatile struct data {
char in[256];
char out[256];
} data;
struct core_reloc_arrays_output {
int a2;
char b123;
int c1c;
int d00d;
};
struct core_reloc_arrays_substruct {
int c;
int d;
};
struct core_reloc_arrays {
int a[5];
char b[2][3][4];
struct core_reloc_arrays_substruct c[3];
struct core_reloc_arrays_substruct d[1][2];
};
SEC("raw_tracepoint/sys_enter")
int test_core_arrays(void *ctx)
{
struct core_reloc_arrays *in = (void *)&data.in;
struct core_reloc_arrays_output *out = (void *)&data.out;
/* in->a[2] */
if (BPF_CORE_READ(&out->a2, &in->a[2]))
return 1;
/* in->b[1][2][3] */
if (BPF_CORE_READ(&out->b123, &in->b[1][2][3]))
return 1;
/* in->c[1].c */
if (BPF_CORE_READ(&out->c1c, &in->c[1].c))
return 1;
/* in->d[0][0].d */
if (BPF_CORE_READ(&out->d00d, &in->d[0][0].d))
return 1;
return 0;
}

View File

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/bpf.h>
#include <stdint.h>
#include "bpf_helpers.h"
char _license[] SEC("license") = "GPL";
static volatile struct data {
char in[256];
char out[256];
} data;
struct core_reloc_flavors {
int a;
int b;
int c;
};
/* local flavor with reversed layout */
struct core_reloc_flavors___reversed {
int c;
int b;
int a;
};
/* local flavor with nested/overlapping layout */
struct core_reloc_flavors___weird {
struct {
int b;
};
/* a and c overlap in local flavor, but this should still work
* correctly with target original flavor
*/
union {
int a;
int c;
};
};
SEC("raw_tracepoint/sys_enter")
int test_core_flavors(void *ctx)
{
struct core_reloc_flavors *in_orig = (void *)&data.in;
struct core_reloc_flavors___reversed *in_rev = (void *)&data.in;
struct core_reloc_flavors___weird *in_weird = (void *)&data.in;
struct core_reloc_flavors *out = (void *)&data.out;
/* read a using weird layout */
if (BPF_CORE_READ(&out->a, &in_weird->a))
return 1;
/* read b using reversed layout */
if (BPF_CORE_READ(&out->b, &in_rev->b))
return 1;
/* read c using original layout */
if (BPF_CORE_READ(&out->c, &in_orig->c))
return 1;
return 0;
}

View File

@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/bpf.h>
#include <stdint.h>
#include "bpf_helpers.h"
char _license[] SEC("license") = "GPL";
static volatile struct data {
char in[256];
char out[256];
} data;
struct core_reloc_ints {
uint8_t u8_field;
int8_t s8_field;
uint16_t u16_field;
int16_t s16_field;
uint32_t u32_field;
int32_t s32_field;
uint64_t u64_field;
int64_t s64_field;
};
SEC("raw_tracepoint/sys_enter")
int test_core_ints(void *ctx)
{
struct core_reloc_ints *in = (void *)&data.in;
struct core_reloc_ints *out = (void *)&data.out;
if (BPF_CORE_READ(&out->u8_field, &in->u8_field) ||
BPF_CORE_READ(&out->s8_field, &in->s8_field) ||
BPF_CORE_READ(&out->u16_field, &in->u16_field) ||
BPF_CORE_READ(&out->s16_field, &in->s16_field) ||
BPF_CORE_READ(&out->u32_field, &in->u32_field) ||
BPF_CORE_READ(&out->s32_field, &in->s32_field) ||
BPF_CORE_READ(&out->u64_field, &in->u64_field) ||
BPF_CORE_READ(&out->s64_field, &in->s64_field))
return 1;
return 0;
}

View File

@@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/bpf.h>
#include <stdint.h>
#include "bpf_helpers.h"
char _license[] SEC("license") = "GPL";
static volatile struct data {
char in[256];
char out[256];
} data;
struct task_struct {
int pid;
int tgid;
};
SEC("raw_tracepoint/sys_enter")
int test_core_kernel(void *ctx)
{
struct task_struct *task = (void *)bpf_get_current_task();
uint64_t pid_tgid = bpf_get_current_pid_tgid();
int pid, tgid;
if (BPF_CORE_READ(&pid, &task->pid) ||
BPF_CORE_READ(&tgid, &task->tgid))
return 1;
/* validate pid + tgid matches */
data.out[0] = (((uint64_t)pid << 32) | tgid) == pid_tgid;
return 0;
}

View File

@@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/bpf.h>
#include <stdint.h>
#include "bpf_helpers.h"
char _license[] SEC("license") = "GPL";
static volatile struct data {
char in[256];
char out[256];
} data;
struct core_reloc_misc_output {
int a, b, c;
};
struct core_reloc_misc___a {
int a1;
int a2;
};
struct core_reloc_misc___b {
int b1;
int b2;
};
/* fixed two first members, can be extended with new fields */
struct core_reloc_misc_extensible {
int a;
int b;
};
SEC("raw_tracepoint/sys_enter")
int test_core_misc(void *ctx)
{
struct core_reloc_misc___a *in_a = (void *)&data.in;
struct core_reloc_misc___b *in_b = (void *)&data.in;
struct core_reloc_misc_extensible *in_ext = (void *)&data.in;
struct core_reloc_misc_output *out = (void *)&data.out;
/* record two different relocations with the same accessor string */
if (BPF_CORE_READ(&out->a, &in_a->a1) || /* accessor: 0:0 */
BPF_CORE_READ(&out->b, &in_b->b1)) /* accessor: 0:0 */
return 1;
/* Validate relocations capture array-only accesses for structs with
* fixed header, but with potentially extendable tail. This will read
* first 4 bytes of 2nd element of in_ext array of potentially
* variably sized struct core_reloc_misc_extensible. */
if (BPF_CORE_READ(&out->c, &in_ext[2])) /* accessor: 2 */
return 1;
return 0;
}

View File

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/bpf.h>
#include <stdint.h>
#include "bpf_helpers.h"
char _license[] SEC("license") = "GPL";
static volatile struct data {
char in[256];
char out[256];
} data;
struct core_reloc_mods_output {
int a, b, c, d, e, f, g, h;
};
typedef const int int_t;
typedef const char *char_ptr_t;
typedef const int arr_t[7];
struct core_reloc_mods_substruct {
int x;
int y;
};
typedef struct {
int x;
int y;
} core_reloc_mods_substruct_t;
struct core_reloc_mods {
int a;
int_t b;
char *c;
char_ptr_t d;
int e[3];
arr_t f;
struct core_reloc_mods_substruct g;
core_reloc_mods_substruct_t h;
};
SEC("raw_tracepoint/sys_enter")
int test_core_mods(void *ctx)
{
struct core_reloc_mods *in = (void *)&data.in;
struct core_reloc_mods_output *out = (void *)&data.out;
if (BPF_CORE_READ(&out->a, &in->a) ||
BPF_CORE_READ(&out->b, &in->b) ||
BPF_CORE_READ(&out->c, &in->c) ||
BPF_CORE_READ(&out->d, &in->d) ||
BPF_CORE_READ(&out->e, &in->e[2]) ||
BPF_CORE_READ(&out->f, &in->f[1]) ||
BPF_CORE_READ(&out->g, &in->g.x) ||
BPF_CORE_READ(&out->h, &in->h.y))
return 1;
return 0;
}

View File

@@ -0,0 +1,46 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/bpf.h>
#include <stdint.h>
#include "bpf_helpers.h"
char _license[] SEC("license") = "GPL";
static volatile struct data {
char in[256];
char out[256];
} data;
struct core_reloc_nesting_substruct {
int a;
};
union core_reloc_nesting_subunion {
int b;
};
/* int a.a.a and b.b.b accesses */
struct core_reloc_nesting {
union {
struct core_reloc_nesting_substruct a;
} a;
struct {
union core_reloc_nesting_subunion b;
} b;
};
SEC("raw_tracepoint/sys_enter")
int test_core_nesting(void *ctx)
{
struct core_reloc_nesting *in = (void *)&data.in;
struct core_reloc_nesting *out = (void *)&data.out;
if (BPF_CORE_READ(&out->a.a.a, &in->a.a.a))
return 1;
if (BPF_CORE_READ(&out->b.b.b, &in->b.b.b))
return 1;
return 0;
}

View File

@@ -0,0 +1,43 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/bpf.h>
#include <stdint.h>
#include "bpf_helpers.h"
char _license[] SEC("license") = "GPL";
static volatile struct data {
char in[256];
char out[256];
} data;
enum core_reloc_primitives_enum {
A = 0,
B = 1,
};
struct core_reloc_primitives {
char a;
int b;
enum core_reloc_primitives_enum c;
void *d;
int (*f)(const char *);
};
SEC("raw_tracepoint/sys_enter")
int test_core_primitives(void *ctx)
{
struct core_reloc_primitives *in = (void *)&data.in;
struct core_reloc_primitives *out = (void *)&data.out;
if (BPF_CORE_READ(&out->a, &in->a) ||
BPF_CORE_READ(&out->b, &in->b) ||
BPF_CORE_READ(&out->c, &in->c) ||
BPF_CORE_READ(&out->d, &in->d) ||
BPF_CORE_READ(&out->f, &in->f))
return 1;
return 0;
}

View File

@@ -0,0 +1,30 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/bpf.h>
#include <stdint.h>
#include "bpf_helpers.h"
char _license[] SEC("license") = "GPL";
static volatile struct data {
char in[256];
char out[256];
} data;
struct core_reloc_ptr_as_arr {
int a;
};
SEC("raw_tracepoint/sys_enter")
int test_core_ptr_as_arr(void *ctx)
{
struct core_reloc_ptr_as_arr *in = (void *)&data.in;
struct core_reloc_ptr_as_arr *out = (void *)&data.out;
if (BPF_CORE_READ(&out->a, &in[2].a))
return 1;
return 0;
}

View File

@@ -55,7 +55,7 @@ struct {
__type(value, raw_stack_trace_t);
} rawdata_map SEC(".maps");
SEC("tracepoint/raw_syscalls/sys_enter")
SEC("raw_tracepoint/sys_enter")
int bpf_prog1(void *ctx)
{
int max_len, max_buildid_len, usize, ksize, total_size;

View File

@@ -12,10 +12,6 @@
#define SR6_FLAG_ALERT (1 << 4)
#define htonll(x) ((bpf_htonl(1)) == 1 ? (x) : ((uint64_t)bpf_htonl((x) & \
0xFFFFFFFF) << 32) | bpf_htonl((x) >> 32))
#define ntohll(x) ((bpf_ntohl(1)) == 1 ? (x) : ((uint64_t)bpf_ntohl((x) & \
0xFFFFFFFF) << 32) | bpf_ntohl((x) >> 32))
#define BPF_PACKET_HEADER __attribute__((packed))
struct ip6_t {
@@ -276,8 +272,8 @@ int has_egr_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh)
return 0;
// check if egress TLV value is correct
if (ntohll(egr_addr.hi) == 0xfd00000000000000 &&
ntohll(egr_addr.lo) == 0x4)
if (bpf_be64_to_cpu(egr_addr.hi) == 0xfd00000000000000 &&
bpf_be64_to_cpu(egr_addr.lo) == 0x4)
return 1;
}
@@ -308,8 +304,8 @@ int __encap_srh(struct __sk_buff *skb)
#pragma clang loop unroll(full)
for (unsigned long long lo = 0; lo < 4; lo++) {
seg->lo = htonll(4 - lo);
seg->hi = htonll(hi);
seg->lo = bpf_cpu_to_be64(4 - lo);
seg->hi = bpf_cpu_to_be64(hi);
seg = (struct ip6_addr_t *)((char *)seg + sizeof(*seg));
}
@@ -349,8 +345,8 @@ int __add_egr_x(struct __sk_buff *skb)
if (err)
return BPF_DROP;
addr.lo = htonll(lo);
addr.hi = htonll(hi);
addr.lo = bpf_cpu_to_be64(lo);
addr.hi = bpf_cpu_to_be64(hi);
err = bpf_lwt_seg6_action(skb, SEG6_LOCAL_ACTION_END_X,
(void *)&addr, sizeof(addr));
if (err)

View File

@@ -12,10 +12,6 @@
#define SR6_FLAG_ALERT (1 << 4)
#define htonll(x) ((bpf_htonl(1)) == 1 ? (x) : ((uint64_t)bpf_htonl((x) & \
0xFFFFFFFF) << 32) | bpf_htonl((x) >> 32))
#define ntohll(x) ((bpf_ntohl(1)) == 1 ? (x) : ((uint64_t)bpf_ntohl((x) & \
0xFFFFFFFF) << 32) | bpf_ntohl((x) >> 32))
#define BPF_PACKET_HEADER __attribute__((packed))
struct ip6_t {
@@ -251,8 +247,8 @@ int __add_egr_x(struct __sk_buff *skb)
if (err)
return BPF_DROP;
addr.lo = htonll(lo);
addr.hi = htonll(hi);
addr.lo = bpf_cpu_to_be64(lo);
addr.hi = bpf_cpu_to_be64(hi);
err = bpf_lwt_seg6_action(skb, SEG6_LOCAL_ACTION_END_X,
(void *)&addr, sizeof(addr));
if (err)

View File

@@ -2,6 +2,7 @@
#include <stdint.h>
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/stddef.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/pkt_cls.h>

View File

@@ -19,10 +19,29 @@
struct bpf_map_def SEC("maps") results = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(__u64),
.max_entries = 1,
.value_size = sizeof(__u32),
.max_entries = 3,
};
static __always_inline __s64 gen_syncookie(void *data_end, struct bpf_sock *sk,
void *iph, __u32 ip_size,
struct tcphdr *tcph)
{
__u32 thlen = tcph->doff * 4;
if (tcph->syn && !tcph->ack) {
// packet should only have an MSS option
if (thlen != 24)
return 0;
if ((void *)tcph + thlen > data_end)
return 0;
return bpf_tcp_gen_syncookie(sk, iph, ip_size, tcph, thlen);
}
return 0;
}
static __always_inline void check_syncookie(void *ctx, void *data,
void *data_end)
{
@@ -33,8 +52,10 @@ static __always_inline void check_syncookie(void *ctx, void *data,
struct ipv6hdr *ipv6h;
struct tcphdr *tcph;
int ret;
__u32 key_mss = 2;
__u32 key_gen = 1;
__u32 key = 0;
__u64 value = 1;
__s64 seq_mss;
ethh = data;
if (ethh + 1 > data_end)
@@ -66,6 +87,9 @@ static __always_inline void check_syncookie(void *ctx, void *data,
if (sk->state != BPF_TCP_LISTEN)
goto release;
seq_mss = gen_syncookie(data_end, sk, ipv4h, sizeof(*ipv4h),
tcph);
ret = bpf_tcp_check_syncookie(sk, ipv4h, sizeof(*ipv4h),
tcph, sizeof(*tcph));
break;
@@ -95,6 +119,9 @@ static __always_inline void check_syncookie(void *ctx, void *data,
if (sk->state != BPF_TCP_LISTEN)
goto release;
seq_mss = gen_syncookie(data_end, sk, ipv6h, sizeof(*ipv6h),
tcph);
ret = bpf_tcp_check_syncookie(sk, ipv6h, sizeof(*ipv6h),
tcph, sizeof(*tcph));
break;
@@ -103,8 +130,19 @@ static __always_inline void check_syncookie(void *ctx, void *data,
return;
}
if (ret == 0)
bpf_map_update_elem(&results, &key, &value, 0);
if (seq_mss > 0) {
__u32 cookie = (__u32)seq_mss;
__u32 mss = seq_mss >> 32;
bpf_map_update_elem(&results, &key_gen, &cookie, 0);
bpf_map_update_elem(&results, &key_mss, &mss, 0);
}
if (ret == 0) {
__u32 cookie = bpf_ntohl(tcph->ack_seq) - 1;
bpf_map_update_elem(&results, &key, &cookie, 0);
}
release:
bpf_sk_release(sk);

View File

@@ -0,0 +1,143 @@
#!/bin/bash
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
ERROR=0
TMPDIR=
# If one build fails, continue but return non-0 on exit.
return_value() {
if [ -d "$TMPDIR" ] ; then
rm -rf -- $TMPDIR
fi
exit $ERROR
}
trap return_value EXIT
case $1 in
-h|--help)
echo -e "$0 [-j <n>]"
echo -e "\tTest the different ways of building bpftool."
echo -e ""
echo -e "\tOptions:"
echo -e "\t\t-j <n>:\tPass -j flag to 'make'."
exit
;;
esac
J=$*
# Assume script is located under tools/testing/selftests/bpf/. We want to start
# build attempts from the top of kernel repository.
SCRIPT_REL_PATH=$(realpath --relative-to=$PWD $0)
SCRIPT_REL_DIR=$(dirname $SCRIPT_REL_PATH)
KDIR_ROOT_DIR=$(realpath $PWD/$SCRIPT_REL_DIR/../../../../)
cd $KDIR_ROOT_DIR
check() {
local dir=$(realpath $1)
echo -n "binary: "
# Returns non-null if file is found (and "false" is run)
find $dir -type f -executable -name bpftool -print -exec false {} + && \
ERROR=1 && printf "FAILURE: Did not find bpftool\n"
}
make_and_clean() {
echo -e "\$PWD: $PWD"
echo -e "command: make -s $* >/dev/null"
make $J -s $* >/dev/null
if [ $? -ne 0 ] ; then
ERROR=1
fi
if [ $# -ge 1 ] ; then
check ${@: -1}
else
check .
fi
(
if [ $# -ge 1 ] ; then
cd ${@: -1}
fi
make -s clean
)
echo
}
make_with_tmpdir() {
local ARGS
TMPDIR=$(mktemp -d)
if [ $# -ge 2 ] ; then
ARGS=${@:1:(($# - 1))}
fi
echo -e "\$PWD: $PWD"
echo -e "command: make -s $ARGS ${@: -1}=$TMPDIR/ >/dev/null"
make $J -s $ARGS ${@: -1}=$TMPDIR/ >/dev/null
if [ $? -ne 0 ] ; then
ERROR=1
fi
check $TMPDIR
rm -rf -- $TMPDIR
echo
}
echo "Trying to build bpftool"
echo -e "... through kbuild\n"
if [ -f ".config" ] ; then
make_and_clean tools/bpf
## $OUTPUT is overwritten in kbuild Makefile, and thus cannot be passed
## down from toplevel Makefile to bpftool's Makefile.
# make_with_tmpdir tools/bpf OUTPUT
echo -e "skip: make tools/bpf OUTPUT=<dir> (not supported)\n"
make_with_tmpdir tools/bpf O
else
echo -e "skip: make tools/bpf (no .config found)\n"
echo -e "skip: make tools/bpf OUTPUT=<dir> (not supported)\n"
echo -e "skip: make tools/bpf O=<dir> (no .config found)\n"
fi
echo -e "... from kernel source tree\n"
make_and_clean -C tools/bpf/bpftool
make_with_tmpdir -C tools/bpf/bpftool OUTPUT
make_with_tmpdir -C tools/bpf/bpftool O
echo -e "... from tools/\n"
cd tools/
make_and_clean bpf
## In tools/bpf/Makefile, function "descend" is called and passes $(O) and
## $(OUTPUT). We would like $(OUTPUT) to have "bpf/bpftool/" appended before
## calling bpftool's Makefile, but this is not the case as the "descend"
## function focuses on $(O)/$(subdir). However, in the present case, updating
## $(O) to have $(OUTPUT) recomputed from it in bpftool's Makefile does not
## work, because $(O) is not defined from command line and $(OUTPUT) is not
## updated in tools/scripts/Makefile.include.
##
## Workarounds would require to a) edit "descend" or use an alternative way to
## call bpftool's Makefile, b) modify the conditions to update $(OUTPUT) and
## other variables in tools/scripts/Makefile.include (at the risk of breaking
## the build of other tools), or c) append manually the "bpf/bpftool" suffix to
## $(OUTPUT) in bpf's Makefile, which may break if targets for other directories
## use "descend" in the future.
# make_with_tmpdir bpf OUTPUT
echo -e "skip: make bpf OUTPUT=<dir> (not supported)\n"
make_with_tmpdir bpf O
echo -e "... from bpftool's dir\n"
cd bpf/bpftool
make_and_clean
make_with_tmpdir OUTPUT
make_with_tmpdir O

View File

@@ -508,6 +508,21 @@ static void test_devmap(unsigned int task, void *data)
close(fd);
}
static void test_devmap_hash(unsigned int task, void *data)
{
int fd;
__u32 key, value;
fd = bpf_create_map(BPF_MAP_TYPE_DEVMAP_HASH, sizeof(key), sizeof(value),
2, 0);
if (fd < 0) {
printf("Failed to create devmap_hash '%s'!\n", strerror(errno));
exit(1);
}
close(fd);
}
static void test_queuemap(unsigned int task, void *data)
{
const int MAP_SIZE = 32;
@@ -1684,6 +1699,7 @@ static void run_all_tests(void)
test_arraymap_percpu_many_keys();
test_devmap(0, NULL);
test_devmap_hash(0, NULL);
test_sockmap(0, NULL);
test_map_large();

View File

@@ -1353,7 +1353,7 @@ try:
bpftool_prog_list_wait(expected=1)
ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
fail(ifnameB != simB1['ifname'], "program not bound to originial device")
fail(ifnameB != simB1['ifname'], "program not bound to original device")
simB1.remove()
bpftool_prog_list_wait(expected=1)

Some files were not shown because too many files have changed in this diff Show More