From 1727a9dce6775a4ea77a611e9ea51cac1d093519 Mon Sep 17 00:00:00 2001 From: Jiong Wang Date: Mon, 11 Feb 2019 12:01:18 +0000 Subject: selftests: bpf: add "alu32" to .gitignore "alu32" is a build dir and contains various files for BPF sub-register code-gen testing. This patch tells git to ignore it. Suggested-by: Yonghong Song Reviewed-by: Jakub Kicinski Signed-off-by: Jiong Wang Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/.gitignore | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index dd093bd91aa9..e47168d1257d 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -29,3 +29,4 @@ test_netcnt test_section_names test_tcpnotify_user test_libbpf +alu32 -- cgit v1.2.3-59-g8ed1b From 4836b4637ef080c2764c44ee40ed354cdb991d79 Mon Sep 17 00:00:00 2001 From: Jiong Wang Date: Mon, 11 Feb 2019 12:01:19 +0000 Subject: selftests: bpf: extend sub-register mode compilation to all bpf object files At the moment, we only do extra sub-register mode compilation on bpf object files used by "test_progs". These object files are really loaded and executed. This patch further extends sub-register mode compilation to all bpf object files, even those without corresponding runtime tests. Because this could help testing LLVM sub-register code-gen, kernel bpf selftest has much more C testcases with reasonable size and complexity compared with LLVM testsuite which only contains unit tests. There were some file duplication inside BPF_OBJ_FILES_DUAL_COMPILE which is removed now. Reviewed-by: Jakub Kicinski Signed-off-by: Jiong Wang Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/Makefile | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index c7e1e3255448..f2c11474f762 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -36,20 +36,14 @@ BPF_OBJ_FILES = \ get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \ test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o test_xdp_vlan.o \ xdp_dummy.o test_map_in_map.o test_spin_lock.o test_map_lock.o \ - test_sock_fields_kern.o - -# Objects are built with default compilation flags and with sub-register -# code-gen enabled. -BPF_OBJ_FILES_DUAL_COMPILE = \ - test_pkt_access.o test_pkt_access.o test_xdp.o test_adjust_tail.o \ - test_l4lb.o test_l4lb_noinline.o test_xdp_noinline.o test_tcp_estats.o \ + test_pkt_access.o test_xdp.o test_adjust_tail.o test_l4lb.o \ + test_l4lb_noinline.o test_xdp_noinline.o test_tcp_estats.o \ test_obj_id.o test_pkt_md_access.o test_tracepoint.o \ - test_stacktrace_map.o test_stacktrace_map.o test_stacktrace_build_id.o \ - test_stacktrace_build_id.o test_get_stack_rawtp.o \ - test_get_stack_rawtp.o test_tracepoint.o test_sk_lookup_kern.o \ - test_queue_map.o test_stack_map.o + test_stacktrace_map.o test_stacktrace_build_id.o \ + test_get_stack_rawtp.o test_sk_lookup_kern.o test_queue_map.o \ + test_stack_map.o test_sock_fields_kern.o -TEST_GEN_FILES = $(BPF_OBJ_FILES) $(BPF_OBJ_FILES_DUAL_COMPILE) +TEST_GEN_FILES = $(BPF_OBJ_FILES) # Also test sub-register code-gen if LLVM + kernel both has eBPF v3 processor # support which is the first version to contain both ALU32 and JMP32 @@ -59,7 +53,7 @@ SUBREG_CODEGEN := $(shell echo "int cal(int a) { return a > 0; }" | \ $(LLC) -mattr=+alu32 -mcpu=probe 2>&1 | \ grep 'if w') ifneq ($(SUBREG_CODEGEN),) -TEST_GEN_FILES += $(patsubst %.o,alu32/%.o, $(BPF_OBJ_FILES_DUAL_COMPILE)) +TEST_GEN_FILES += $(patsubst %.o,alu32/%.o, $(BPF_OBJ_FILES)) endif # Order correspond to 'make run_tests' order -- cgit v1.2.3-59-g8ed1b From bd4aed0ee73ca873bef3cb3ec746dd796f03df28 Mon Sep 17 00:00:00 2001 From: Jiong Wang Date: Mon, 11 Feb 2019 12:01:20 +0000 Subject: selftests: bpf: centre kernel bpf objects under new subdir "progs" At the moment, all kernel bpf objects are listed under BPF_OBJ_FILES. Listing them manually sometimes causing patch conflict when people are adding new testcases simultaneously. It is better to centre all the related source files under a subdir "progs", then auto-generate the object file list. Suggested-by: Alexei Starovoitov Reviewed-by: Jakub Kicinski Signed-off-by: Jiong Wang Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/Makefile | 26 +- tools/testing/selftests/bpf/bpf_flow.c | 371 --------- tools/testing/selftests/bpf/connect4_prog.c | 72 -- tools/testing/selftests/bpf/connect6_prog.c | 95 --- tools/testing/selftests/bpf/dev_cgroup.c | 60 -- tools/testing/selftests/bpf/get_cgroup_id_kern.c | 40 - tools/testing/selftests/bpf/netcnt_prog.c | 77 -- tools/testing/selftests/bpf/progs/bpf_flow.c | 371 +++++++++ tools/testing/selftests/bpf/progs/connect4_prog.c | 72 ++ tools/testing/selftests/bpf/progs/connect6_prog.c | 95 +++ tools/testing/selftests/bpf/progs/dev_cgroup.c | 60 ++ .../selftests/bpf/progs/get_cgroup_id_kern.c | 40 + tools/testing/selftests/bpf/progs/netcnt_prog.c | 77 ++ .../testing/selftests/bpf/progs/sample_map_ret0.c | 34 + tools/testing/selftests/bpf/progs/sample_ret0.c | 7 + tools/testing/selftests/bpf/progs/sendmsg4_prog.c | 49 ++ tools/testing/selftests/bpf/progs/sendmsg6_prog.c | 60 ++ .../selftests/bpf/progs/socket_cookie_prog.c | 60 ++ .../selftests/bpf/progs/sockmap_parse_prog.c | 46 ++ .../selftests/bpf/progs/sockmap_tcp_msg_prog.c | 33 + .../selftests/bpf/progs/sockmap_verdict_prog.c | 73 ++ .../testing/selftests/bpf/progs/test_adjust_tail.c | 30 + tools/testing/selftests/bpf/progs/test_btf_haskv.c | 57 ++ tools/testing/selftests/bpf/progs/test_btf_nokv.c | 55 ++ .../selftests/bpf/progs/test_get_stack_rawtp.c | 102 +++ tools/testing/selftests/bpf/progs/test_l4lb.c | 473 ++++++++++++ .../selftests/bpf/progs/test_l4lb_noinline.c | 473 ++++++++++++ .../selftests/bpf/progs/test_lirc_mode2_kern.c | 26 + .../selftests/bpf/progs/test_lwt_seg6local.c | 437 +++++++++++ .../testing/selftests/bpf/progs/test_map_in_map.c | 49 ++ tools/testing/selftests/bpf/progs/test_map_lock.c | 66 ++ tools/testing/selftests/bpf/progs/test_obj_id.c | 35 + .../testing/selftests/bpf/progs/test_pkt_access.c | 65 ++ .../selftests/bpf/progs/test_pkt_md_access.c | 46 ++ tools/testing/selftests/bpf/progs/test_queue_map.c | 4 + .../bpf/progs/test_select_reuseport_kern.c | 180 +++++ .../selftests/bpf/progs/test_sk_lookup_kern.c | 180 +++++ .../selftests/bpf/progs/test_skb_cgroup_id_kern.c | 47 ++ .../selftests/bpf/progs/test_sock_fields_kern.c | 152 ++++ .../selftests/bpf/progs/test_sockhash_kern.c | 5 + .../selftests/bpf/progs/test_sockmap_kern.c | 5 + tools/testing/selftests/bpf/progs/test_spin_lock.c | 108 +++ tools/testing/selftests/bpf/progs/test_stack_map.c | 4 + .../selftests/bpf/progs/test_stacktrace_build_id.c | 76 ++ .../selftests/bpf/progs/test_stacktrace_map.c | 75 ++ .../testing/selftests/bpf/progs/test_tcp_estats.c | 258 +++++++ .../testing/selftests/bpf/progs/test_tcpbpf_kern.c | 153 ++++ .../selftests/bpf/progs/test_tcpnotify_kern.c | 95 +++ .../testing/selftests/bpf/progs/test_tracepoint.c | 26 + .../testing/selftests/bpf/progs/test_tunnel_kern.c | 713 ++++++++++++++++++ tools/testing/selftests/bpf/progs/test_xdp.c | 235 ++++++ tools/testing/selftests/bpf/progs/test_xdp_meta.c | 53 ++ .../selftests/bpf/progs/test_xdp_noinline.c | 833 +++++++++++++++++++++ .../selftests/bpf/progs/test_xdp_redirect.c | 28 + tools/testing/selftests/bpf/progs/test_xdp_vlan.c | 292 ++++++++ tools/testing/selftests/bpf/progs/xdp_dummy.c | 13 + tools/testing/selftests/bpf/sample_map_ret0.c | 34 - tools/testing/selftests/bpf/sample_ret0.c | 7 - tools/testing/selftests/bpf/sendmsg4_prog.c | 49 -- tools/testing/selftests/bpf/sendmsg6_prog.c | 60 -- tools/testing/selftests/bpf/socket_cookie_prog.c | 60 -- tools/testing/selftests/bpf/sockmap_parse_prog.c | 46 -- tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c | 33 - tools/testing/selftests/bpf/sockmap_verdict_prog.c | 73 -- tools/testing/selftests/bpf/test_adjust_tail.c | 30 - tools/testing/selftests/bpf/test_btf_haskv.c | 57 -- tools/testing/selftests/bpf/test_btf_nokv.c | 55 -- tools/testing/selftests/bpf/test_get_stack_rawtp.c | 102 --- tools/testing/selftests/bpf/test_l4lb.c | 473 ------------ tools/testing/selftests/bpf/test_l4lb_noinline.c | 473 ------------ tools/testing/selftests/bpf/test_lirc_mode2_kern.c | 26 - tools/testing/selftests/bpf/test_lwt_seg6local.c | 437 ----------- tools/testing/selftests/bpf/test_map_in_map.c | 49 -- tools/testing/selftests/bpf/test_map_lock.c | 66 -- tools/testing/selftests/bpf/test_obj_id.c | 35 - tools/testing/selftests/bpf/test_pkt_access.c | 65 -- tools/testing/selftests/bpf/test_pkt_md_access.c | 46 -- tools/testing/selftests/bpf/test_queue_map.c | 4 - .../selftests/bpf/test_select_reuseport_kern.c | 180 ----- tools/testing/selftests/bpf/test_sk_lookup_kern.c | 180 ----- .../selftests/bpf/test_skb_cgroup_id_kern.c | 47 -- .../testing/selftests/bpf/test_sock_fields_kern.c | 152 ---- tools/testing/selftests/bpf/test_sockhash_kern.c | 5 - tools/testing/selftests/bpf/test_sockmap_kern.c | 5 - tools/testing/selftests/bpf/test_spin_lock.c | 108 --- tools/testing/selftests/bpf/test_stack_map.c | 4 - .../selftests/bpf/test_stacktrace_build_id.c | 76 -- tools/testing/selftests/bpf/test_stacktrace_map.c | 75 -- tools/testing/selftests/bpf/test_tcp_estats.c | 258 ------- tools/testing/selftests/bpf/test_tcpbpf_kern.c | 153 ---- tools/testing/selftests/bpf/test_tcpnotify_kern.c | 95 --- tools/testing/selftests/bpf/test_tracepoint.c | 26 - tools/testing/selftests/bpf/test_tunnel_kern.c | 713 ------------------ tools/testing/selftests/bpf/test_xdp.c | 235 ------ tools/testing/selftests/bpf/test_xdp_meta.c | 53 -- tools/testing/selftests/bpf/test_xdp_noinline.c | 833 --------------------- tools/testing/selftests/bpf/test_xdp_redirect.c | 28 - tools/testing/selftests/bpf/test_xdp_vlan.c | 292 -------- tools/testing/selftests/bpf/xdp_dummy.c | 13 - 99 files changed, 6531 insertions(+), 6547 deletions(-) delete mode 100644 tools/testing/selftests/bpf/bpf_flow.c delete mode 100644 tools/testing/selftests/bpf/connect4_prog.c delete mode 100644 tools/testing/selftests/bpf/connect6_prog.c delete mode 100644 tools/testing/selftests/bpf/dev_cgroup.c delete mode 100644 tools/testing/selftests/bpf/get_cgroup_id_kern.c delete mode 100644 tools/testing/selftests/bpf/netcnt_prog.c create mode 100644 tools/testing/selftests/bpf/progs/bpf_flow.c create mode 100644 tools/testing/selftests/bpf/progs/connect4_prog.c create mode 100644 tools/testing/selftests/bpf/progs/connect6_prog.c create mode 100644 tools/testing/selftests/bpf/progs/dev_cgroup.c create mode 100644 tools/testing/selftests/bpf/progs/get_cgroup_id_kern.c create mode 100644 tools/testing/selftests/bpf/progs/netcnt_prog.c create mode 100644 tools/testing/selftests/bpf/progs/sample_map_ret0.c create mode 100644 tools/testing/selftests/bpf/progs/sample_ret0.c create mode 100644 tools/testing/selftests/bpf/progs/sendmsg4_prog.c create mode 100644 tools/testing/selftests/bpf/progs/sendmsg6_prog.c create mode 100644 tools/testing/selftests/bpf/progs/socket_cookie_prog.c create mode 100644 tools/testing/selftests/bpf/progs/sockmap_parse_prog.c create mode 100644 tools/testing/selftests/bpf/progs/sockmap_tcp_msg_prog.c create mode 100644 tools/testing/selftests/bpf/progs/sockmap_verdict_prog.c create mode 100644 tools/testing/selftests/bpf/progs/test_adjust_tail.c create mode 100644 tools/testing/selftests/bpf/progs/test_btf_haskv.c create mode 100644 tools/testing/selftests/bpf/progs/test_btf_nokv.c create mode 100644 tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c create mode 100644 tools/testing/selftests/bpf/progs/test_l4lb.c create mode 100644 tools/testing/selftests/bpf/progs/test_l4lb_noinline.c create mode 100644 tools/testing/selftests/bpf/progs/test_lirc_mode2_kern.c create mode 100644 tools/testing/selftests/bpf/progs/test_lwt_seg6local.c create mode 100644 tools/testing/selftests/bpf/progs/test_map_in_map.c create mode 100644 tools/testing/selftests/bpf/progs/test_map_lock.c create mode 100644 tools/testing/selftests/bpf/progs/test_obj_id.c create mode 100644 tools/testing/selftests/bpf/progs/test_pkt_access.c create mode 100644 tools/testing/selftests/bpf/progs/test_pkt_md_access.c create mode 100644 tools/testing/selftests/bpf/progs/test_queue_map.c create mode 100644 tools/testing/selftests/bpf/progs/test_select_reuseport_kern.c create mode 100644 tools/testing/selftests/bpf/progs/test_sk_lookup_kern.c create mode 100644 tools/testing/selftests/bpf/progs/test_skb_cgroup_id_kern.c create mode 100644 tools/testing/selftests/bpf/progs/test_sock_fields_kern.c create mode 100644 tools/testing/selftests/bpf/progs/test_sockhash_kern.c create mode 100644 tools/testing/selftests/bpf/progs/test_sockmap_kern.c create mode 100644 tools/testing/selftests/bpf/progs/test_spin_lock.c create mode 100644 tools/testing/selftests/bpf/progs/test_stack_map.c create mode 100644 tools/testing/selftests/bpf/progs/test_stacktrace_build_id.c create mode 100644 tools/testing/selftests/bpf/progs/test_stacktrace_map.c create mode 100644 tools/testing/selftests/bpf/progs/test_tcp_estats.c create mode 100644 tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c create mode 100644 tools/testing/selftests/bpf/progs/test_tcpnotify_kern.c create mode 100644 tools/testing/selftests/bpf/progs/test_tracepoint.c create mode 100644 tools/testing/selftests/bpf/progs/test_tunnel_kern.c create mode 100644 tools/testing/selftests/bpf/progs/test_xdp.c create mode 100644 tools/testing/selftests/bpf/progs/test_xdp_meta.c create mode 100644 tools/testing/selftests/bpf/progs/test_xdp_noinline.c create mode 100644 tools/testing/selftests/bpf/progs/test_xdp_redirect.c create mode 100644 tools/testing/selftests/bpf/progs/test_xdp_vlan.c create mode 100644 tools/testing/selftests/bpf/progs/xdp_dummy.c delete mode 100644 tools/testing/selftests/bpf/sample_map_ret0.c delete mode 100644 tools/testing/selftests/bpf/sample_ret0.c delete mode 100644 tools/testing/selftests/bpf/sendmsg4_prog.c delete mode 100644 tools/testing/selftests/bpf/sendmsg6_prog.c delete mode 100644 tools/testing/selftests/bpf/socket_cookie_prog.c delete mode 100644 tools/testing/selftests/bpf/sockmap_parse_prog.c delete mode 100644 tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c delete mode 100644 tools/testing/selftests/bpf/sockmap_verdict_prog.c delete mode 100644 tools/testing/selftests/bpf/test_adjust_tail.c delete mode 100644 tools/testing/selftests/bpf/test_btf_haskv.c delete mode 100644 tools/testing/selftests/bpf/test_btf_nokv.c delete mode 100644 tools/testing/selftests/bpf/test_get_stack_rawtp.c delete mode 100644 tools/testing/selftests/bpf/test_l4lb.c delete mode 100644 tools/testing/selftests/bpf/test_l4lb_noinline.c delete mode 100644 tools/testing/selftests/bpf/test_lirc_mode2_kern.c delete mode 100644 tools/testing/selftests/bpf/test_lwt_seg6local.c delete mode 100644 tools/testing/selftests/bpf/test_map_in_map.c delete mode 100644 tools/testing/selftests/bpf/test_map_lock.c delete mode 100644 tools/testing/selftests/bpf/test_obj_id.c delete mode 100644 tools/testing/selftests/bpf/test_pkt_access.c delete mode 100644 tools/testing/selftests/bpf/test_pkt_md_access.c delete mode 100644 tools/testing/selftests/bpf/test_queue_map.c delete mode 100644 tools/testing/selftests/bpf/test_select_reuseport_kern.c delete mode 100644 tools/testing/selftests/bpf/test_sk_lookup_kern.c delete mode 100644 tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c delete mode 100644 tools/testing/selftests/bpf/test_sock_fields_kern.c delete mode 100644 tools/testing/selftests/bpf/test_sockhash_kern.c delete mode 100644 tools/testing/selftests/bpf/test_sockmap_kern.c delete mode 100644 tools/testing/selftests/bpf/test_spin_lock.c delete mode 100644 tools/testing/selftests/bpf/test_stack_map.c delete mode 100644 tools/testing/selftests/bpf/test_stacktrace_build_id.c delete mode 100644 tools/testing/selftests/bpf/test_stacktrace_map.c delete mode 100644 tools/testing/selftests/bpf/test_tcp_estats.c delete mode 100644 tools/testing/selftests/bpf/test_tcpbpf_kern.c delete mode 100644 tools/testing/selftests/bpf/test_tcpnotify_kern.c delete mode 100644 tools/testing/selftests/bpf/test_tracepoint.c delete mode 100644 tools/testing/selftests/bpf/test_tunnel_kern.c delete mode 100644 tools/testing/selftests/bpf/test_xdp.c delete mode 100644 tools/testing/selftests/bpf/test_xdp_meta.c delete mode 100644 tools/testing/selftests/bpf/test_xdp_noinline.c delete mode 100644 tools/testing/selftests/bpf/test_xdp_redirect.c delete mode 100644 tools/testing/selftests/bpf/test_xdp_vlan.c delete mode 100644 tools/testing/selftests/bpf/xdp_dummy.c (limited to 'tools') diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index f2c11474f762..575746e63544 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -25,24 +25,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test test_socket_cookie test_cgroup_storage test_select_reuseport test_section_names \ test_netcnt test_tcpnotify_user test_sock_fields -BPF_OBJ_FILES = \ - test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ - sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o \ - test_tcpnotify_kern.o sample_map_ret0.o test_tcpbpf_kern.o \ - sockmap_tcp_msg_prog.o connect4_prog.o connect6_prog.o \ - test_btf_haskv.o test_btf_nokv.o test_sockmap_kern.o \ - test_tunnel_kern.o test_sockhash_kern.o test_lwt_seg6local.o \ - sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \ - get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \ - test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o test_xdp_vlan.o \ - xdp_dummy.o test_map_in_map.o test_spin_lock.o test_map_lock.o \ - test_pkt_access.o test_xdp.o test_adjust_tail.o test_l4lb.o \ - test_l4lb_noinline.o test_xdp_noinline.o test_tcp_estats.o \ - test_obj_id.o test_pkt_md_access.o test_tracepoint.o \ - test_stacktrace_map.o test_stacktrace_build_id.o \ - test_get_stack_rawtp.o test_sk_lookup_kern.o test_queue_map.o \ - test_stack_map.o test_sock_fields_kern.o - +BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c))) TEST_GEN_FILES = $(BPF_OBJ_FILES) # Also test sub-register code-gen if LLVM + kernel both has eBPF v3 processor @@ -184,7 +167,8 @@ $(ALU32_BUILD_DIR)/test_progs_32: test_progs.c $(ALU32_BUILD_DIR) \ $(CC) $(CFLAGS) -o $(ALU32_BUILD_DIR)/test_progs_32 $< \ trace_helpers.c $(OUTPUT)/libbpf.a $(LDLIBS) -$(ALU32_BUILD_DIR)/%.o: %.c $(ALU32_BUILD_DIR) $(ALU32_BUILD_DIR)/test_progs_32 +$(ALU32_BUILD_DIR)/%.o: progs/%.c $(ALU32_BUILD_DIR) \ + $(ALU32_BUILD_DIR)/test_progs_32 $(CLANG) $(CLANG_FLAGS) \ -O2 -target bpf -emit-llvm -c $< -o - | \ $(LLC) -march=bpf -mattr=+alu32 -mcpu=$(CPU) $(LLC_FLAGS) \ @@ -196,7 +180,7 @@ endif # Have one program compiled without "-target bpf" to test whether libbpf loads # it successfully -$(OUTPUT)/test_xdp.o: test_xdp.c +$(OUTPUT)/test_xdp.o: progs/test_xdp.c $(CLANG) $(CLANG_FLAGS) \ -O2 -emit-llvm -c $< -o - | \ $(LLC) -march=bpf -mcpu=$(CPU) $(LLC_FLAGS) -filetype=obj -o $@ @@ -204,7 +188,7 @@ ifeq ($(DWARF2BTF),y) $(BTF_PAHOLE) -J $@ endif -$(OUTPUT)/%.o: %.c +$(OUTPUT)/%.o: progs/%.c $(CLANG) $(CLANG_FLAGS) \ -O2 -target bpf -emit-llvm -c $< -o - | \ $(LLC) -march=bpf -mcpu=$(CPU) $(LLC_FLAGS) -filetype=obj -o $@ diff --git a/tools/testing/selftests/bpf/bpf_flow.c b/tools/testing/selftests/bpf/bpf_flow.c deleted file mode 100644 index 284660f5aa95..000000000000 --- a/tools/testing/selftests/bpf/bpf_flow.c +++ /dev/null @@ -1,371 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bpf_helpers.h" -#include "bpf_endian.h" - -int _version SEC("version") = 1; -#define PROG(F) SEC(#F) int bpf_func_##F - -/* These are the identifiers of the BPF programs that will be used in tail - * calls. Name is limited to 16 characters, with the terminating character and - * bpf_func_ above, we have only 6 to work with, anything after will be cropped. - */ -enum { - IP, - IPV6, - IPV6OP, /* Destination/Hop-by-Hop Options IPv6 Extension header */ - IPV6FR, /* Fragmentation IPv6 Extension Header */ - MPLS, - VLAN, -}; - -#define IP_MF 0x2000 -#define IP_OFFSET 0x1FFF -#define IP6_MF 0x0001 -#define IP6_OFFSET 0xFFF8 - -struct vlan_hdr { - __be16 h_vlan_TCI; - __be16 h_vlan_encapsulated_proto; -}; - -struct gre_hdr { - __be16 flags; - __be16 proto; -}; - -struct frag_hdr { - __u8 nexthdr; - __u8 reserved; - __be16 frag_off; - __be32 identification; -}; - -struct bpf_map_def SEC("maps") jmp_table = { - .type = BPF_MAP_TYPE_PROG_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = 8 -}; - -static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb, - __u16 hdr_size, - void *buffer) -{ - void *data_end = (void *)(long)skb->data_end; - void *data = (void *)(long)skb->data; - __u16 thoff = skb->flow_keys->thoff; - __u8 *hdr; - - /* Verifies this variable offset does not overflow */ - if (thoff > (USHRT_MAX - hdr_size)) - return NULL; - - hdr = data + thoff; - if (hdr + hdr_size <= data_end) - return hdr; - - if (bpf_skb_load_bytes(skb, thoff, buffer, hdr_size)) - return NULL; - - return buffer; -} - -/* Dispatches on ETHERTYPE */ -static __always_inline int parse_eth_proto(struct __sk_buff *skb, __be16 proto) -{ - struct bpf_flow_keys *keys = skb->flow_keys; - - keys->n_proto = proto; - switch (proto) { - case bpf_htons(ETH_P_IP): - bpf_tail_call(skb, &jmp_table, IP); - break; - case bpf_htons(ETH_P_IPV6): - bpf_tail_call(skb, &jmp_table, IPV6); - break; - case bpf_htons(ETH_P_MPLS_MC): - case bpf_htons(ETH_P_MPLS_UC): - bpf_tail_call(skb, &jmp_table, MPLS); - break; - case bpf_htons(ETH_P_8021Q): - case bpf_htons(ETH_P_8021AD): - bpf_tail_call(skb, &jmp_table, VLAN); - break; - default: - /* Protocol not supported */ - return BPF_DROP; - } - - return BPF_DROP; -} - -SEC("flow_dissector") -int _dissect(struct __sk_buff *skb) -{ - if (!skb->vlan_present) - return parse_eth_proto(skb, skb->protocol); - else - return parse_eth_proto(skb, skb->vlan_proto); -} - -/* Parses on IPPROTO_* */ -static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto) -{ - struct bpf_flow_keys *keys = skb->flow_keys; - void *data_end = (void *)(long)skb->data_end; - struct icmphdr *icmp, _icmp; - struct gre_hdr *gre, _gre; - struct ethhdr *eth, _eth; - 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); - if (!icmp) - return BPF_DROP; - return BPF_OK; - case IPPROTO_IPIP: - keys->is_encap = true; - return parse_eth_proto(skb, bpf_htons(ETH_P_IP)); - case IPPROTO_IPV6: - keys->is_encap = true; - return parse_eth_proto(skb, bpf_htons(ETH_P_IPV6)); - case IPPROTO_GRE: - gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre); - if (!gre) - return BPF_DROP; - - if (bpf_htons(gre->flags & GRE_VERSION)) - /* Only inspect standard GRE packets with version 0 */ - return BPF_OK; - - keys->thoff += sizeof(*gre); /* Step over GRE Flags and Proto */ - if (GRE_IS_CSUM(gre->flags)) - keys->thoff += 4; /* Step over chksum and Padding */ - if (GRE_IS_KEY(gre->flags)) - keys->thoff += 4; /* Step over key */ - if (GRE_IS_SEQ(gre->flags)) - keys->thoff += 4; /* Step over sequence number */ - - keys->is_encap = true; - - if (gre->proto == bpf_htons(ETH_P_TEB)) { - eth = bpf_flow_dissect_get_header(skb, sizeof(*eth), - &_eth); - if (!eth) - return BPF_DROP; - - keys->thoff += sizeof(*eth); - - return parse_eth_proto(skb, eth->h_proto); - } else { - return parse_eth_proto(skb, gre->proto); - } - case IPPROTO_TCP: - tcp = bpf_flow_dissect_get_header(skb, sizeof(*tcp), &_tcp); - if (!tcp) - return BPF_DROP; - - if (tcp->doff < 5) - return BPF_DROP; - - if ((__u8 *)tcp + (tcp->doff << 2) > data_end) - return BPF_DROP; - - keys->sport = tcp->source; - keys->dport = tcp->dest; - return BPF_OK; - case IPPROTO_UDP: - case IPPROTO_UDPLITE: - udp = bpf_flow_dissect_get_header(skb, sizeof(*udp), &_udp); - if (!udp) - return BPF_DROP; - - keys->sport = udp->source; - keys->dport = udp->dest; - return BPF_OK; - default: - return BPF_DROP; - } - - return BPF_DROP; -} - -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: - bpf_tail_call(skb, &jmp_table, IPV6OP); - break; - case IPPROTO_FRAGMENT: - bpf_tail_call(skb, &jmp_table, IPV6FR); - break; - default: - return parse_ip_proto(skb, nexthdr); - } - - return BPF_DROP; -} - -PROG(IP)(struct __sk_buff *skb) -{ - void *data_end = (void *)(long)skb->data_end; - struct bpf_flow_keys *keys = skb->flow_keys; - void *data = (void *)(long)skb->data; - struct iphdr *iph, _iph; - bool done = false; - - iph = bpf_flow_dissect_get_header(skb, sizeof(*iph), &_iph); - if (!iph) - return BPF_DROP; - - /* IP header cannot be smaller than 20 bytes */ - if (iph->ihl < 5) - return BPF_DROP; - - keys->addr_proto = ETH_P_IP; - keys->ipv4_src = iph->saddr; - keys->ipv4_dst = iph->daddr; - - keys->thoff += iph->ihl << 2; - if (data + keys->thoff > data_end) - return BPF_DROP; - - if (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET)) { - keys->is_frag = true; - if (iph->frag_off & bpf_htons(IP_OFFSET)) - /* From second fragment on, packets do not have headers - * we can parse. - */ - done = true; - else - keys->is_first_frag = true; - } - - if (done) - return BPF_OK; - - return parse_ip_proto(skb, iph->protocol); -} - -PROG(IPV6)(struct __sk_buff *skb) -{ - struct bpf_flow_keys *keys = skb->flow_keys; - struct ipv6hdr *ip6h, _ip6h; - - ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h); - if (!ip6h) - return BPF_DROP; - - keys->addr_proto = ETH_P_IPV6; - memcpy(&keys->ipv6_src, &ip6h->saddr, 2*sizeof(ip6h->saddr)); - - keys->thoff += sizeof(struct ipv6hdr); - - return parse_ipv6_proto(skb, ip6h->nexthdr); -} - -PROG(IPV6OP)(struct __sk_buff *skb) -{ - struct ipv6_opt_hdr *ip6h, _ip6h; - - ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h); - if (!ip6h) - return BPF_DROP; - - /* hlen is in 8-octets and does not include the first 8 bytes - * of the header - */ - skb->flow_keys->thoff += (1 + ip6h->hdrlen) << 3; - - return parse_ipv6_proto(skb, ip6h->nexthdr); -} - -PROG(IPV6FR)(struct __sk_buff *skb) -{ - struct bpf_flow_keys *keys = skb->flow_keys; - struct frag_hdr *fragh, _fragh; - - fragh = bpf_flow_dissect_get_header(skb, sizeof(*fragh), &_fragh); - if (!fragh) - return BPF_DROP; - - keys->thoff += sizeof(*fragh); - keys->is_frag = true; - if (!(fragh->frag_off & bpf_htons(IP6_OFFSET))) - keys->is_first_frag = true; - - return parse_ipv6_proto(skb, fragh->nexthdr); -} - -PROG(MPLS)(struct __sk_buff *skb) -{ - struct mpls_label *mpls, _mpls; - - mpls = bpf_flow_dissect_get_header(skb, sizeof(*mpls), &_mpls); - if (!mpls) - return BPF_DROP; - - return BPF_OK; -} - -PROG(VLAN)(struct __sk_buff *skb) -{ - struct bpf_flow_keys *keys = skb->flow_keys; - struct vlan_hdr *vlan, _vlan; - __be16 proto; - - /* Peek back to see if single or double-tagging */ - if (bpf_skb_load_bytes(skb, keys->thoff - sizeof(proto), &proto, - sizeof(proto))) - return BPF_DROP; - - /* Account for double-tagging */ - if (proto == bpf_htons(ETH_P_8021AD)) { - vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan); - if (!vlan) - return BPF_DROP; - - if (vlan->h_vlan_encapsulated_proto != bpf_htons(ETH_P_8021Q)) - return BPF_DROP; - - keys->thoff += sizeof(*vlan); - } - - vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan); - if (!vlan) - return BPF_DROP; - - keys->thoff += sizeof(*vlan); - /* Only allow 8021AD + 8021Q double tagging and no triple tagging.*/ - if (vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021AD) || - vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021Q)) - return BPF_DROP; - - return parse_eth_proto(skb, vlan->h_vlan_encapsulated_proto); -} - -char __license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/connect4_prog.c b/tools/testing/selftests/bpf/connect4_prog.c deleted file mode 100644 index 1fd244d35ba9..000000000000 --- a/tools/testing/selftests/bpf/connect4_prog.c +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Facebook - -#include - -#include -#include -#include -#include -#include - -#include "bpf_helpers.h" -#include "bpf_endian.h" - -#define SRC_REWRITE_IP4 0x7f000004U -#define DST_REWRITE_IP4 0x7f000001U -#define DST_REWRITE_PORT4 4444 - -int _version SEC("version") = 1; - -SEC("cgroup/connect4") -int connect_v4_prog(struct bpf_sock_addr *ctx) -{ - struct bpf_sock_tuple tuple = {}; - struct sockaddr_in sa; - struct bpf_sock *sk; - - /* Verify that new destination is available. */ - memset(&tuple.ipv4.saddr, 0, sizeof(tuple.ipv4.saddr)); - memset(&tuple.ipv4.sport, 0, sizeof(tuple.ipv4.sport)); - - tuple.ipv4.daddr = bpf_htonl(DST_REWRITE_IP4); - tuple.ipv4.dport = bpf_htons(DST_REWRITE_PORT4); - - if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM) - return 0; - else if (ctx->type == SOCK_STREAM) - sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof(tuple.ipv4), - BPF_F_CURRENT_NETNS, 0); - else - sk = bpf_sk_lookup_udp(ctx, &tuple, sizeof(tuple.ipv4), - BPF_F_CURRENT_NETNS, 0); - - if (!sk) - return 0; - - if (sk->src_ip4 != tuple.ipv4.daddr || - sk->src_port != DST_REWRITE_PORT4) { - bpf_sk_release(sk); - return 0; - } - - bpf_sk_release(sk); - - /* Rewrite destination. */ - ctx->user_ip4 = bpf_htonl(DST_REWRITE_IP4); - ctx->user_port = bpf_htons(DST_REWRITE_PORT4); - - /* Rewrite source. */ - memset(&sa, 0, sizeof(sa)); - - sa.sin_family = AF_INET; - sa.sin_port = bpf_htons(0); - sa.sin_addr.s_addr = bpf_htonl(SRC_REWRITE_IP4); - - if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) - return 0; - - return 1; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/connect6_prog.c b/tools/testing/selftests/bpf/connect6_prog.c deleted file mode 100644 index 26397ab7b3c7..000000000000 --- a/tools/testing/selftests/bpf/connect6_prog.c +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Facebook - -#include - -#include -#include -#include -#include -#include - -#include "bpf_helpers.h" -#include "bpf_endian.h" - -#define SRC_REWRITE_IP6_0 0 -#define SRC_REWRITE_IP6_1 0 -#define SRC_REWRITE_IP6_2 0 -#define SRC_REWRITE_IP6_3 6 - -#define DST_REWRITE_IP6_0 0 -#define DST_REWRITE_IP6_1 0 -#define DST_REWRITE_IP6_2 0 -#define DST_REWRITE_IP6_3 1 - -#define DST_REWRITE_PORT6 6666 - -int _version SEC("version") = 1; - -SEC("cgroup/connect6") -int connect_v6_prog(struct bpf_sock_addr *ctx) -{ - struct bpf_sock_tuple tuple = {}; - struct sockaddr_in6 sa; - struct bpf_sock *sk; - - /* Verify that new destination is available. */ - memset(&tuple.ipv6.saddr, 0, sizeof(tuple.ipv6.saddr)); - memset(&tuple.ipv6.sport, 0, sizeof(tuple.ipv6.sport)); - - tuple.ipv6.daddr[0] = bpf_htonl(DST_REWRITE_IP6_0); - tuple.ipv6.daddr[1] = bpf_htonl(DST_REWRITE_IP6_1); - tuple.ipv6.daddr[2] = bpf_htonl(DST_REWRITE_IP6_2); - tuple.ipv6.daddr[3] = bpf_htonl(DST_REWRITE_IP6_3); - - tuple.ipv6.dport = bpf_htons(DST_REWRITE_PORT6); - - if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM) - return 0; - else if (ctx->type == SOCK_STREAM) - sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof(tuple.ipv6), - BPF_F_CURRENT_NETNS, 0); - else - sk = bpf_sk_lookup_udp(ctx, &tuple, sizeof(tuple.ipv6), - BPF_F_CURRENT_NETNS, 0); - - if (!sk) - return 0; - - if (sk->src_ip6[0] != tuple.ipv6.daddr[0] || - sk->src_ip6[1] != tuple.ipv6.daddr[1] || - sk->src_ip6[2] != tuple.ipv6.daddr[2] || - sk->src_ip6[3] != tuple.ipv6.daddr[3] || - sk->src_port != DST_REWRITE_PORT6) { - bpf_sk_release(sk); - return 0; - } - - bpf_sk_release(sk); - - /* Rewrite destination. */ - ctx->user_ip6[0] = bpf_htonl(DST_REWRITE_IP6_0); - ctx->user_ip6[1] = bpf_htonl(DST_REWRITE_IP6_1); - ctx->user_ip6[2] = bpf_htonl(DST_REWRITE_IP6_2); - ctx->user_ip6[3] = bpf_htonl(DST_REWRITE_IP6_3); - - ctx->user_port = bpf_htons(DST_REWRITE_PORT6); - - /* Rewrite source. */ - memset(&sa, 0, sizeof(sa)); - - sa.sin6_family = AF_INET6; - sa.sin6_port = bpf_htons(0); - - sa.sin6_addr.s6_addr32[0] = bpf_htonl(SRC_REWRITE_IP6_0); - sa.sin6_addr.s6_addr32[1] = bpf_htonl(SRC_REWRITE_IP6_1); - sa.sin6_addr.s6_addr32[2] = bpf_htonl(SRC_REWRITE_IP6_2); - sa.sin6_addr.s6_addr32[3] = bpf_htonl(SRC_REWRITE_IP6_3); - - if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) - return 0; - - return 1; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/dev_cgroup.c b/tools/testing/selftests/bpf/dev_cgroup.c deleted file mode 100644 index ce41a3475f27..000000000000 --- a/tools/testing/selftests/bpf/dev_cgroup.c +++ /dev/null @@ -1,60 +0,0 @@ -/* Copyright (c) 2017 Facebook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ - -#include -#include -#include "bpf_helpers.h" - -SEC("cgroup/dev") -int bpf_prog1(struct bpf_cgroup_dev_ctx *ctx) -{ - short type = ctx->access_type & 0xFFFF; -#ifdef DEBUG - short access = ctx->access_type >> 16; - char fmt[] = " %d:%d \n"; - - switch (type) { - case BPF_DEVCG_DEV_BLOCK: - fmt[0] = 'b'; - break; - case BPF_DEVCG_DEV_CHAR: - fmt[0] = 'c'; - break; - default: - fmt[0] = '?'; - break; - } - - if (access & BPF_DEVCG_ACC_READ) - fmt[8] = 'r'; - - if (access & BPF_DEVCG_ACC_WRITE) - fmt[9] = 'w'; - - if (access & BPF_DEVCG_ACC_MKNOD) - fmt[10] = 'm'; - - bpf_trace_printk(fmt, sizeof(fmt), ctx->major, ctx->minor); -#endif - - /* Allow access to /dev/zero and /dev/random. - * Forbid everything else. - */ - if (ctx->major != 1 || type != BPF_DEVCG_DEV_CHAR) - return 0; - - switch (ctx->minor) { - case 5: /* 1:5 /dev/zero */ - case 9: /* 1:9 /dev/urandom */ - return 1; - } - - return 0; -} - -char _license[] SEC("license") = "GPL"; -__u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/tools/testing/selftests/bpf/get_cgroup_id_kern.c b/tools/testing/selftests/bpf/get_cgroup_id_kern.c deleted file mode 100644 index 014dba10b8a5..000000000000 --- a/tools/testing/selftests/bpf/get_cgroup_id_kern.c +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Facebook - -#include -#include "bpf_helpers.h" - -struct bpf_map_def SEC("maps") cg_ids = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u64), - .max_entries = 1, -}; - -struct bpf_map_def SEC("maps") pidmap = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = 1, -}; - -SEC("tracepoint/syscalls/sys_enter_nanosleep") -int trace(void *ctx) -{ - __u32 pid = bpf_get_current_pid_tgid(); - __u32 key = 0, *expected_pid; - __u64 *val; - - expected_pid = bpf_map_lookup_elem(&pidmap, &key); - if (!expected_pid || *expected_pid != pid) - return 0; - - val = bpf_map_lookup_elem(&cg_ids, &key); - if (val) - *val = bpf_get_current_cgroup_id(); - - return 0; -} - -char _license[] SEC("license") = "GPL"; -__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/netcnt_prog.c b/tools/testing/selftests/bpf/netcnt_prog.c deleted file mode 100644 index 9f741e69cebe..000000000000 --- a/tools/testing/selftests/bpf/netcnt_prog.c +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -#include "bpf_helpers.h" -#include "netcnt_common.h" - -#define MAX_BPS (3 * 1024 * 1024) - -#define REFRESH_TIME_NS 100000000 -#define NS_PER_SEC 1000000000 - -struct bpf_map_def SEC("maps") percpu_netcnt = { - .type = BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, - .key_size = sizeof(struct bpf_cgroup_storage_key), - .value_size = sizeof(struct percpu_net_cnt), -}; - -BPF_ANNOTATE_KV_PAIR(percpu_netcnt, struct bpf_cgroup_storage_key, - struct percpu_net_cnt); - -struct bpf_map_def SEC("maps") netcnt = { - .type = BPF_MAP_TYPE_CGROUP_STORAGE, - .key_size = sizeof(struct bpf_cgroup_storage_key), - .value_size = sizeof(struct net_cnt), -}; - -BPF_ANNOTATE_KV_PAIR(netcnt, struct bpf_cgroup_storage_key, - struct net_cnt); - -SEC("cgroup/skb") -int bpf_nextcnt(struct __sk_buff *skb) -{ - struct percpu_net_cnt *percpu_cnt; - char fmt[] = "%d %llu %llu\n"; - struct net_cnt *cnt; - __u64 ts, dt; - int ret; - - cnt = bpf_get_local_storage(&netcnt, 0); - percpu_cnt = bpf_get_local_storage(&percpu_netcnt, 0); - - percpu_cnt->packets++; - percpu_cnt->bytes += skb->len; - - if (percpu_cnt->packets > MAX_PERCPU_PACKETS) { - __sync_fetch_and_add(&cnt->packets, - percpu_cnt->packets); - percpu_cnt->packets = 0; - - __sync_fetch_and_add(&cnt->bytes, - percpu_cnt->bytes); - percpu_cnt->bytes = 0; - } - - ts = bpf_ktime_get_ns(); - dt = ts - percpu_cnt->prev_ts; - - dt *= MAX_BPS; - dt /= NS_PER_SEC; - - if (cnt->bytes + percpu_cnt->bytes - percpu_cnt->prev_bytes < dt) - ret = 1; - else - ret = 0; - - if (dt > REFRESH_TIME_NS) { - percpu_cnt->prev_ts = ts; - percpu_cnt->prev_packets = cnt->packets; - percpu_cnt->prev_bytes = cnt->bytes; - } - - return !!ret; -} - -char _license[] SEC("license") = "GPL"; -__u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/tools/testing/selftests/bpf/progs/bpf_flow.c b/tools/testing/selftests/bpf/progs/bpf_flow.c new file mode 100644 index 000000000000..284660f5aa95 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/bpf_flow.c @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; +#define PROG(F) SEC(#F) int bpf_func_##F + +/* These are the identifiers of the BPF programs that will be used in tail + * calls. Name is limited to 16 characters, with the terminating character and + * bpf_func_ above, we have only 6 to work with, anything after will be cropped. + */ +enum { + IP, + IPV6, + IPV6OP, /* Destination/Hop-by-Hop Options IPv6 Extension header */ + IPV6FR, /* Fragmentation IPv6 Extension Header */ + MPLS, + VLAN, +}; + +#define IP_MF 0x2000 +#define IP_OFFSET 0x1FFF +#define IP6_MF 0x0001 +#define IP6_OFFSET 0xFFF8 + +struct vlan_hdr { + __be16 h_vlan_TCI; + __be16 h_vlan_encapsulated_proto; +}; + +struct gre_hdr { + __be16 flags; + __be16 proto; +}; + +struct frag_hdr { + __u8 nexthdr; + __u8 reserved; + __be16 frag_off; + __be32 identification; +}; + +struct bpf_map_def SEC("maps") jmp_table = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 8 +}; + +static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb, + __u16 hdr_size, + void *buffer) +{ + void *data_end = (void *)(long)skb->data_end; + void *data = (void *)(long)skb->data; + __u16 thoff = skb->flow_keys->thoff; + __u8 *hdr; + + /* Verifies this variable offset does not overflow */ + if (thoff > (USHRT_MAX - hdr_size)) + return NULL; + + hdr = data + thoff; + if (hdr + hdr_size <= data_end) + return hdr; + + if (bpf_skb_load_bytes(skb, thoff, buffer, hdr_size)) + return NULL; + + return buffer; +} + +/* Dispatches on ETHERTYPE */ +static __always_inline int parse_eth_proto(struct __sk_buff *skb, __be16 proto) +{ + struct bpf_flow_keys *keys = skb->flow_keys; + + keys->n_proto = proto; + switch (proto) { + case bpf_htons(ETH_P_IP): + bpf_tail_call(skb, &jmp_table, IP); + break; + case bpf_htons(ETH_P_IPV6): + bpf_tail_call(skb, &jmp_table, IPV6); + break; + case bpf_htons(ETH_P_MPLS_MC): + case bpf_htons(ETH_P_MPLS_UC): + bpf_tail_call(skb, &jmp_table, MPLS); + break; + case bpf_htons(ETH_P_8021Q): + case bpf_htons(ETH_P_8021AD): + bpf_tail_call(skb, &jmp_table, VLAN); + break; + default: + /* Protocol not supported */ + return BPF_DROP; + } + + return BPF_DROP; +} + +SEC("flow_dissector") +int _dissect(struct __sk_buff *skb) +{ + if (!skb->vlan_present) + return parse_eth_proto(skb, skb->protocol); + else + return parse_eth_proto(skb, skb->vlan_proto); +} + +/* Parses on IPPROTO_* */ +static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto) +{ + struct bpf_flow_keys *keys = skb->flow_keys; + void *data_end = (void *)(long)skb->data_end; + struct icmphdr *icmp, _icmp; + struct gre_hdr *gre, _gre; + struct ethhdr *eth, _eth; + 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); + if (!icmp) + return BPF_DROP; + return BPF_OK; + case IPPROTO_IPIP: + keys->is_encap = true; + return parse_eth_proto(skb, bpf_htons(ETH_P_IP)); + case IPPROTO_IPV6: + keys->is_encap = true; + return parse_eth_proto(skb, bpf_htons(ETH_P_IPV6)); + case IPPROTO_GRE: + gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre); + if (!gre) + return BPF_DROP; + + if (bpf_htons(gre->flags & GRE_VERSION)) + /* Only inspect standard GRE packets with version 0 */ + return BPF_OK; + + keys->thoff += sizeof(*gre); /* Step over GRE Flags and Proto */ + if (GRE_IS_CSUM(gre->flags)) + keys->thoff += 4; /* Step over chksum and Padding */ + if (GRE_IS_KEY(gre->flags)) + keys->thoff += 4; /* Step over key */ + if (GRE_IS_SEQ(gre->flags)) + keys->thoff += 4; /* Step over sequence number */ + + keys->is_encap = true; + + if (gre->proto == bpf_htons(ETH_P_TEB)) { + eth = bpf_flow_dissect_get_header(skb, sizeof(*eth), + &_eth); + if (!eth) + return BPF_DROP; + + keys->thoff += sizeof(*eth); + + return parse_eth_proto(skb, eth->h_proto); + } else { + return parse_eth_proto(skb, gre->proto); + } + case IPPROTO_TCP: + tcp = bpf_flow_dissect_get_header(skb, sizeof(*tcp), &_tcp); + if (!tcp) + return BPF_DROP; + + if (tcp->doff < 5) + return BPF_DROP; + + if ((__u8 *)tcp + (tcp->doff << 2) > data_end) + return BPF_DROP; + + keys->sport = tcp->source; + keys->dport = tcp->dest; + return BPF_OK; + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + udp = bpf_flow_dissect_get_header(skb, sizeof(*udp), &_udp); + if (!udp) + return BPF_DROP; + + keys->sport = udp->source; + keys->dport = udp->dest; + return BPF_OK; + default: + return BPF_DROP; + } + + return BPF_DROP; +} + +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: + bpf_tail_call(skb, &jmp_table, IPV6OP); + break; + case IPPROTO_FRAGMENT: + bpf_tail_call(skb, &jmp_table, IPV6FR); + break; + default: + return parse_ip_proto(skb, nexthdr); + } + + return BPF_DROP; +} + +PROG(IP)(struct __sk_buff *skb) +{ + void *data_end = (void *)(long)skb->data_end; + struct bpf_flow_keys *keys = skb->flow_keys; + void *data = (void *)(long)skb->data; + struct iphdr *iph, _iph; + bool done = false; + + iph = bpf_flow_dissect_get_header(skb, sizeof(*iph), &_iph); + if (!iph) + return BPF_DROP; + + /* IP header cannot be smaller than 20 bytes */ + if (iph->ihl < 5) + return BPF_DROP; + + keys->addr_proto = ETH_P_IP; + keys->ipv4_src = iph->saddr; + keys->ipv4_dst = iph->daddr; + + keys->thoff += iph->ihl << 2; + if (data + keys->thoff > data_end) + return BPF_DROP; + + if (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET)) { + keys->is_frag = true; + if (iph->frag_off & bpf_htons(IP_OFFSET)) + /* From second fragment on, packets do not have headers + * we can parse. + */ + done = true; + else + keys->is_first_frag = true; + } + + if (done) + return BPF_OK; + + return parse_ip_proto(skb, iph->protocol); +} + +PROG(IPV6)(struct __sk_buff *skb) +{ + struct bpf_flow_keys *keys = skb->flow_keys; + struct ipv6hdr *ip6h, _ip6h; + + ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h); + if (!ip6h) + return BPF_DROP; + + keys->addr_proto = ETH_P_IPV6; + memcpy(&keys->ipv6_src, &ip6h->saddr, 2*sizeof(ip6h->saddr)); + + keys->thoff += sizeof(struct ipv6hdr); + + return parse_ipv6_proto(skb, ip6h->nexthdr); +} + +PROG(IPV6OP)(struct __sk_buff *skb) +{ + struct ipv6_opt_hdr *ip6h, _ip6h; + + ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h); + if (!ip6h) + return BPF_DROP; + + /* hlen is in 8-octets and does not include the first 8 bytes + * of the header + */ + skb->flow_keys->thoff += (1 + ip6h->hdrlen) << 3; + + return parse_ipv6_proto(skb, ip6h->nexthdr); +} + +PROG(IPV6FR)(struct __sk_buff *skb) +{ + struct bpf_flow_keys *keys = skb->flow_keys; + struct frag_hdr *fragh, _fragh; + + fragh = bpf_flow_dissect_get_header(skb, sizeof(*fragh), &_fragh); + if (!fragh) + return BPF_DROP; + + keys->thoff += sizeof(*fragh); + keys->is_frag = true; + if (!(fragh->frag_off & bpf_htons(IP6_OFFSET))) + keys->is_first_frag = true; + + return parse_ipv6_proto(skb, fragh->nexthdr); +} + +PROG(MPLS)(struct __sk_buff *skb) +{ + struct mpls_label *mpls, _mpls; + + mpls = bpf_flow_dissect_get_header(skb, sizeof(*mpls), &_mpls); + if (!mpls) + return BPF_DROP; + + return BPF_OK; +} + +PROG(VLAN)(struct __sk_buff *skb) +{ + struct bpf_flow_keys *keys = skb->flow_keys; + struct vlan_hdr *vlan, _vlan; + __be16 proto; + + /* Peek back to see if single or double-tagging */ + if (bpf_skb_load_bytes(skb, keys->thoff - sizeof(proto), &proto, + sizeof(proto))) + return BPF_DROP; + + /* Account for double-tagging */ + if (proto == bpf_htons(ETH_P_8021AD)) { + vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan); + if (!vlan) + return BPF_DROP; + + if (vlan->h_vlan_encapsulated_proto != bpf_htons(ETH_P_8021Q)) + return BPF_DROP; + + keys->thoff += sizeof(*vlan); + } + + vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan); + if (!vlan) + return BPF_DROP; + + keys->thoff += sizeof(*vlan); + /* Only allow 8021AD + 8021Q double tagging and no triple tagging.*/ + if (vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021AD) || + vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021Q)) + return BPF_DROP; + + return parse_eth_proto(skb, vlan->h_vlan_encapsulated_proto); +} + +char __license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/connect4_prog.c b/tools/testing/selftests/bpf/progs/connect4_prog.c new file mode 100644 index 000000000000..1fd244d35ba9 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/connect4_prog.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include + +#include +#include +#include +#include +#include + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define SRC_REWRITE_IP4 0x7f000004U +#define DST_REWRITE_IP4 0x7f000001U +#define DST_REWRITE_PORT4 4444 + +int _version SEC("version") = 1; + +SEC("cgroup/connect4") +int connect_v4_prog(struct bpf_sock_addr *ctx) +{ + struct bpf_sock_tuple tuple = {}; + struct sockaddr_in sa; + struct bpf_sock *sk; + + /* Verify that new destination is available. */ + memset(&tuple.ipv4.saddr, 0, sizeof(tuple.ipv4.saddr)); + memset(&tuple.ipv4.sport, 0, sizeof(tuple.ipv4.sport)); + + tuple.ipv4.daddr = bpf_htonl(DST_REWRITE_IP4); + tuple.ipv4.dport = bpf_htons(DST_REWRITE_PORT4); + + if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM) + return 0; + else if (ctx->type == SOCK_STREAM) + sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof(tuple.ipv4), + BPF_F_CURRENT_NETNS, 0); + else + sk = bpf_sk_lookup_udp(ctx, &tuple, sizeof(tuple.ipv4), + BPF_F_CURRENT_NETNS, 0); + + if (!sk) + return 0; + + if (sk->src_ip4 != tuple.ipv4.daddr || + sk->src_port != DST_REWRITE_PORT4) { + bpf_sk_release(sk); + return 0; + } + + bpf_sk_release(sk); + + /* Rewrite destination. */ + ctx->user_ip4 = bpf_htonl(DST_REWRITE_IP4); + ctx->user_port = bpf_htons(DST_REWRITE_PORT4); + + /* Rewrite source. */ + memset(&sa, 0, sizeof(sa)); + + sa.sin_family = AF_INET; + sa.sin_port = bpf_htons(0); + sa.sin_addr.s_addr = bpf_htonl(SRC_REWRITE_IP4); + + if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) + return 0; + + return 1; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/connect6_prog.c b/tools/testing/selftests/bpf/progs/connect6_prog.c new file mode 100644 index 000000000000..26397ab7b3c7 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/connect6_prog.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include + +#include +#include +#include +#include +#include + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define SRC_REWRITE_IP6_0 0 +#define SRC_REWRITE_IP6_1 0 +#define SRC_REWRITE_IP6_2 0 +#define SRC_REWRITE_IP6_3 6 + +#define DST_REWRITE_IP6_0 0 +#define DST_REWRITE_IP6_1 0 +#define DST_REWRITE_IP6_2 0 +#define DST_REWRITE_IP6_3 1 + +#define DST_REWRITE_PORT6 6666 + +int _version SEC("version") = 1; + +SEC("cgroup/connect6") +int connect_v6_prog(struct bpf_sock_addr *ctx) +{ + struct bpf_sock_tuple tuple = {}; + struct sockaddr_in6 sa; + struct bpf_sock *sk; + + /* Verify that new destination is available. */ + memset(&tuple.ipv6.saddr, 0, sizeof(tuple.ipv6.saddr)); + memset(&tuple.ipv6.sport, 0, sizeof(tuple.ipv6.sport)); + + tuple.ipv6.daddr[0] = bpf_htonl(DST_REWRITE_IP6_0); + tuple.ipv6.daddr[1] = bpf_htonl(DST_REWRITE_IP6_1); + tuple.ipv6.daddr[2] = bpf_htonl(DST_REWRITE_IP6_2); + tuple.ipv6.daddr[3] = bpf_htonl(DST_REWRITE_IP6_3); + + tuple.ipv6.dport = bpf_htons(DST_REWRITE_PORT6); + + if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM) + return 0; + else if (ctx->type == SOCK_STREAM) + sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof(tuple.ipv6), + BPF_F_CURRENT_NETNS, 0); + else + sk = bpf_sk_lookup_udp(ctx, &tuple, sizeof(tuple.ipv6), + BPF_F_CURRENT_NETNS, 0); + + if (!sk) + return 0; + + if (sk->src_ip6[0] != tuple.ipv6.daddr[0] || + sk->src_ip6[1] != tuple.ipv6.daddr[1] || + sk->src_ip6[2] != tuple.ipv6.daddr[2] || + sk->src_ip6[3] != tuple.ipv6.daddr[3] || + sk->src_port != DST_REWRITE_PORT6) { + bpf_sk_release(sk); + return 0; + } + + bpf_sk_release(sk); + + /* Rewrite destination. */ + ctx->user_ip6[0] = bpf_htonl(DST_REWRITE_IP6_0); + ctx->user_ip6[1] = bpf_htonl(DST_REWRITE_IP6_1); + ctx->user_ip6[2] = bpf_htonl(DST_REWRITE_IP6_2); + ctx->user_ip6[3] = bpf_htonl(DST_REWRITE_IP6_3); + + ctx->user_port = bpf_htons(DST_REWRITE_PORT6); + + /* Rewrite source. */ + memset(&sa, 0, sizeof(sa)); + + sa.sin6_family = AF_INET6; + sa.sin6_port = bpf_htons(0); + + sa.sin6_addr.s6_addr32[0] = bpf_htonl(SRC_REWRITE_IP6_0); + sa.sin6_addr.s6_addr32[1] = bpf_htonl(SRC_REWRITE_IP6_1); + sa.sin6_addr.s6_addr32[2] = bpf_htonl(SRC_REWRITE_IP6_2); + sa.sin6_addr.s6_addr32[3] = bpf_htonl(SRC_REWRITE_IP6_3); + + if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) + return 0; + + return 1; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/dev_cgroup.c b/tools/testing/selftests/bpf/progs/dev_cgroup.c new file mode 100644 index 000000000000..ce41a3475f27 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/dev_cgroup.c @@ -0,0 +1,60 @@ +/* Copyright (c) 2017 Facebook + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ + +#include +#include +#include "bpf_helpers.h" + +SEC("cgroup/dev") +int bpf_prog1(struct bpf_cgroup_dev_ctx *ctx) +{ + short type = ctx->access_type & 0xFFFF; +#ifdef DEBUG + short access = ctx->access_type >> 16; + char fmt[] = " %d:%d \n"; + + switch (type) { + case BPF_DEVCG_DEV_BLOCK: + fmt[0] = 'b'; + break; + case BPF_DEVCG_DEV_CHAR: + fmt[0] = 'c'; + break; + default: + fmt[0] = '?'; + break; + } + + if (access & BPF_DEVCG_ACC_READ) + fmt[8] = 'r'; + + if (access & BPF_DEVCG_ACC_WRITE) + fmt[9] = 'w'; + + if (access & BPF_DEVCG_ACC_MKNOD) + fmt[10] = 'm'; + + bpf_trace_printk(fmt, sizeof(fmt), ctx->major, ctx->minor); +#endif + + /* Allow access to /dev/zero and /dev/random. + * Forbid everything else. + */ + if (ctx->major != 1 || type != BPF_DEVCG_DEV_CHAR) + return 0; + + switch (ctx->minor) { + case 5: /* 1:5 /dev/zero */ + case 9: /* 1:9 /dev/urandom */ + return 1; + } + + return 0; +} + +char _license[] SEC("license") = "GPL"; +__u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/tools/testing/selftests/bpf/progs/get_cgroup_id_kern.c b/tools/testing/selftests/bpf/progs/get_cgroup_id_kern.c new file mode 100644 index 000000000000..014dba10b8a5 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/get_cgroup_id_kern.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include "bpf_helpers.h" + +struct bpf_map_def SEC("maps") cg_ids = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u64), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") pidmap = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 1, +}; + +SEC("tracepoint/syscalls/sys_enter_nanosleep") +int trace(void *ctx) +{ + __u32 pid = bpf_get_current_pid_tgid(); + __u32 key = 0, *expected_pid; + __u64 *val; + + expected_pid = bpf_map_lookup_elem(&pidmap, &key); + if (!expected_pid || *expected_pid != pid) + return 0; + + val = bpf_map_lookup_elem(&cg_ids, &key); + if (val) + *val = bpf_get_current_cgroup_id(); + + return 0; +} + +char _license[] SEC("license") = "GPL"; +__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/progs/netcnt_prog.c b/tools/testing/selftests/bpf/progs/netcnt_prog.c new file mode 100644 index 000000000000..9f741e69cebe --- /dev/null +++ b/tools/testing/selftests/bpf/progs/netcnt_prog.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include "bpf_helpers.h" +#include "netcnt_common.h" + +#define MAX_BPS (3 * 1024 * 1024) + +#define REFRESH_TIME_NS 100000000 +#define NS_PER_SEC 1000000000 + +struct bpf_map_def SEC("maps") percpu_netcnt = { + .type = BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, + .key_size = sizeof(struct bpf_cgroup_storage_key), + .value_size = sizeof(struct percpu_net_cnt), +}; + +BPF_ANNOTATE_KV_PAIR(percpu_netcnt, struct bpf_cgroup_storage_key, + struct percpu_net_cnt); + +struct bpf_map_def SEC("maps") netcnt = { + .type = BPF_MAP_TYPE_CGROUP_STORAGE, + .key_size = sizeof(struct bpf_cgroup_storage_key), + .value_size = sizeof(struct net_cnt), +}; + +BPF_ANNOTATE_KV_PAIR(netcnt, struct bpf_cgroup_storage_key, + struct net_cnt); + +SEC("cgroup/skb") +int bpf_nextcnt(struct __sk_buff *skb) +{ + struct percpu_net_cnt *percpu_cnt; + char fmt[] = "%d %llu %llu\n"; + struct net_cnt *cnt; + __u64 ts, dt; + int ret; + + cnt = bpf_get_local_storage(&netcnt, 0); + percpu_cnt = bpf_get_local_storage(&percpu_netcnt, 0); + + percpu_cnt->packets++; + percpu_cnt->bytes += skb->len; + + if (percpu_cnt->packets > MAX_PERCPU_PACKETS) { + __sync_fetch_and_add(&cnt->packets, + percpu_cnt->packets); + percpu_cnt->packets = 0; + + __sync_fetch_and_add(&cnt->bytes, + percpu_cnt->bytes); + percpu_cnt->bytes = 0; + } + + ts = bpf_ktime_get_ns(); + dt = ts - percpu_cnt->prev_ts; + + dt *= MAX_BPS; + dt /= NS_PER_SEC; + + if (cnt->bytes + percpu_cnt->bytes - percpu_cnt->prev_bytes < dt) + ret = 1; + else + ret = 0; + + if (dt > REFRESH_TIME_NS) { + percpu_cnt->prev_ts = ts; + percpu_cnt->prev_packets = cnt->packets; + percpu_cnt->prev_bytes = cnt->bytes; + } + + return !!ret; +} + +char _license[] SEC("license") = "GPL"; +__u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/tools/testing/selftests/bpf/progs/sample_map_ret0.c b/tools/testing/selftests/bpf/progs/sample_map_ret0.c new file mode 100644 index 000000000000..0756303676ac --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sample_map_ret0.c @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */ +#include +#include "bpf_helpers.h" + +struct bpf_map_def SEC("maps") htab = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(__u32), + .value_size = sizeof(long), + .max_entries = 2, +}; + +struct bpf_map_def SEC("maps") array = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(long), + .max_entries = 2, +}; + +/* Sample program which should always load for testing control paths. */ +SEC(".text") int func() +{ + __u64 key64 = 0; + __u32 key = 0; + long *value; + + value = bpf_map_lookup_elem(&htab, &key); + if (!value) + return 1; + value = bpf_map_lookup_elem(&array, &key64); + if (!value) + return 1; + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/sample_ret0.c b/tools/testing/selftests/bpf/progs/sample_ret0.c new file mode 100644 index 000000000000..fec99750d6ea --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sample_ret0.c @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */ + +/* Sample program which should always load for testing control paths. */ +int func() +{ + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/sendmsg4_prog.c b/tools/testing/selftests/bpf/progs/sendmsg4_prog.c new file mode 100644 index 000000000000..a91536b1c47e --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sendmsg4_prog.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include +#include + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define SRC1_IP4 0xAC100001U /* 172.16.0.1 */ +#define SRC2_IP4 0x00000000U +#define SRC_REWRITE_IP4 0x7f000004U +#define DST_IP4 0xC0A801FEU /* 192.168.1.254 */ +#define DST_REWRITE_IP4 0x7f000001U +#define DST_PORT 4040 +#define DST_REWRITE_PORT4 4444 + +int _version SEC("version") = 1; + +SEC("cgroup/sendmsg4") +int sendmsg_v4_prog(struct bpf_sock_addr *ctx) +{ + if (ctx->type != SOCK_DGRAM) + return 0; + + /* Rewrite source. */ + if (ctx->msg_src_ip4 == bpf_htonl(SRC1_IP4) || + ctx->msg_src_ip4 == bpf_htonl(SRC2_IP4)) { + ctx->msg_src_ip4 = bpf_htonl(SRC_REWRITE_IP4); + } else { + /* Unexpected source. Reject sendmsg. */ + return 0; + } + + /* Rewrite destination. */ + if ((ctx->user_ip4 >> 24) == (bpf_htonl(DST_IP4) >> 24) && + ctx->user_port == bpf_htons(DST_PORT)) { + ctx->user_ip4 = bpf_htonl(DST_REWRITE_IP4); + ctx->user_port = bpf_htons(DST_REWRITE_PORT4); + } else { + /* Unexpected source. Reject sendmsg. */ + return 0; + } + + return 1; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/sendmsg6_prog.c b/tools/testing/selftests/bpf/progs/sendmsg6_prog.c new file mode 100644 index 000000000000..5aeaa284fc47 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sendmsg6_prog.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include +#include + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define SRC_REWRITE_IP6_0 0 +#define SRC_REWRITE_IP6_1 0 +#define SRC_REWRITE_IP6_2 0 +#define SRC_REWRITE_IP6_3 6 + +#define DST_REWRITE_IP6_0 0 +#define DST_REWRITE_IP6_1 0 +#define DST_REWRITE_IP6_2 0 +#define DST_REWRITE_IP6_3 1 + +#define DST_REWRITE_PORT6 6666 + +int _version SEC("version") = 1; + +SEC("cgroup/sendmsg6") +int sendmsg_v6_prog(struct bpf_sock_addr *ctx) +{ + if (ctx->type != SOCK_DGRAM) + return 0; + + /* Rewrite source. */ + if (ctx->msg_src_ip6[3] == bpf_htonl(1) || + ctx->msg_src_ip6[3] == bpf_htonl(0)) { + ctx->msg_src_ip6[0] = bpf_htonl(SRC_REWRITE_IP6_0); + ctx->msg_src_ip6[1] = bpf_htonl(SRC_REWRITE_IP6_1); + ctx->msg_src_ip6[2] = bpf_htonl(SRC_REWRITE_IP6_2); + ctx->msg_src_ip6[3] = bpf_htonl(SRC_REWRITE_IP6_3); + } else { + /* Unexpected source. Reject sendmsg. */ + return 0; + } + + /* Rewrite destination. */ + if ((ctx->user_ip6[0] & 0xFFFF) == bpf_htons(0xFACE) && + ctx->user_ip6[0] >> 16 == bpf_htons(0xB00C)) { + ctx->user_ip6[0] = bpf_htonl(DST_REWRITE_IP6_0); + ctx->user_ip6[1] = bpf_htonl(DST_REWRITE_IP6_1); + ctx->user_ip6[2] = bpf_htonl(DST_REWRITE_IP6_2); + ctx->user_ip6[3] = bpf_htonl(DST_REWRITE_IP6_3); + + ctx->user_port = bpf_htons(DST_REWRITE_PORT6); + } else { + /* Unexpected destination. Reject sendmsg. */ + return 0; + } + + return 1; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/socket_cookie_prog.c b/tools/testing/selftests/bpf/progs/socket_cookie_prog.c new file mode 100644 index 000000000000..9ff8ac4b0bf6 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/socket_cookie_prog.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +struct bpf_map_def SEC("maps") socket_cookies = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(__u64), + .value_size = sizeof(__u32), + .max_entries = 1 << 8, +}; + +SEC("cgroup/connect6") +int set_cookie(struct bpf_sock_addr *ctx) +{ + __u32 cookie_value = 0xFF; + __u64 cookie_key; + + if (ctx->family != AF_INET6 || ctx->user_family != AF_INET6) + return 1; + + cookie_key = bpf_get_socket_cookie(ctx); + if (bpf_map_update_elem(&socket_cookies, &cookie_key, &cookie_value, 0)) + return 0; + + return 1; +} + +SEC("sockops") +int update_cookie(struct bpf_sock_ops *ctx) +{ + __u32 new_cookie_value; + __u32 *cookie_value; + __u64 cookie_key; + + if (ctx->family != AF_INET6) + return 1; + + if (ctx->op != BPF_SOCK_OPS_TCP_CONNECT_CB) + return 1; + + cookie_key = bpf_get_socket_cookie(ctx); + + cookie_value = bpf_map_lookup_elem(&socket_cookies, &cookie_key); + if (!cookie_value) + return 1; + + new_cookie_value = (ctx->local_port << 8) | *cookie_value; + bpf_map_update_elem(&socket_cookies, &cookie_key, &new_cookie_value, 0); + + return 1; +} + +int _version SEC("version") = 1; + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c b/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c new file mode 100644 index 000000000000..0f92858f6226 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c @@ -0,0 +1,46 @@ +#include +#include "bpf_helpers.h" +#include "bpf_util.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; + +#define bpf_printk(fmt, ...) \ +({ \ + char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ +}) + +SEC("sk_skb1") +int bpf_prog1(struct __sk_buff *skb) +{ + void *data_end = (void *)(long) skb->data_end; + void *data = (void *)(long) skb->data; + __u32 lport = skb->local_port; + __u32 rport = skb->remote_port; + __u8 *d = data; + __u32 len = (__u32) data_end - (__u32) data; + int err; + + if (data + 10 > data_end) { + err = bpf_skb_pull_data(skb, 10); + if (err) + return SK_DROP; + + data_end = (void *)(long)skb->data_end; + data = (void *)(long)skb->data; + if (data + 10 > data_end) + return SK_DROP; + } + + /* This write/read is a bit pointless but tests the verifier and + * strparser handler for read/write pkt data and access into sk + * fields. + */ + d = data; + d[7] = 1; + return skb->len; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/sockmap_tcp_msg_prog.c b/tools/testing/selftests/bpf/progs/sockmap_tcp_msg_prog.c new file mode 100644 index 000000000000..12a7b5c82ed6 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sockmap_tcp_msg_prog.c @@ -0,0 +1,33 @@ +#include +#include "bpf_helpers.h" +#include "bpf_util.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; + +#define bpf_printk(fmt, ...) \ +({ \ + char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ +}) + +SEC("sk_msg1") +int bpf_prog1(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + + char *d; + + if (data + 8 > data_end) + return SK_DROP; + + bpf_printk("data length %i\n", (__u64)msg->data_end - (__u64)msg->data); + d = (char *)data; + bpf_printk("hello sendmsg hook %i %i\n", d[0], d[1]); + + return SK_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/sockmap_verdict_prog.c b/tools/testing/selftests/bpf/progs/sockmap_verdict_prog.c new file mode 100644 index 000000000000..2ce7634a4012 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sockmap_verdict_prog.c @@ -0,0 +1,73 @@ +#include +#include "bpf_helpers.h" +#include "bpf_util.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; + +#define bpf_printk(fmt, ...) \ +({ \ + char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ +}) + +struct bpf_map_def SEC("maps") sock_map_rx = { + .type = BPF_MAP_TYPE_SOCKMAP, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 20, +}; + +struct bpf_map_def SEC("maps") sock_map_tx = { + .type = BPF_MAP_TYPE_SOCKMAP, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 20, +}; + +struct bpf_map_def SEC("maps") sock_map_msg = { + .type = BPF_MAP_TYPE_SOCKMAP, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 20, +}; + +struct bpf_map_def SEC("maps") sock_map_break = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 20, +}; + +SEC("sk_skb2") +int bpf_prog2(struct __sk_buff *skb) +{ + void *data_end = (void *)(long) skb->data_end; + void *data = (void *)(long) skb->data; + __u32 lport = skb->local_port; + __u32 rport = skb->remote_port; + __u8 *d = data; + __u8 sk, map; + + if (data + 8 > data_end) + return SK_DROP; + + map = d[0]; + sk = d[1]; + + d[0] = 0xd; + d[1] = 0xe; + d[2] = 0xa; + d[3] = 0xd; + d[4] = 0xb; + d[5] = 0xe; + d[6] = 0xe; + d[7] = 0xf; + + if (!map) + return bpf_sk_redirect_map(skb, &sock_map_rx, sk, 0); + return bpf_sk_redirect_map(skb, &sock_map_tx, sk, 0); +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_adjust_tail.c b/tools/testing/selftests/bpf/progs/test_adjust_tail.c new file mode 100644 index 000000000000..4cd5e860c903 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_adjust_tail.c @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018 Facebook + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ +#include +#include +#include "bpf_helpers.h" + +int _version SEC("version") = 1; + +SEC("xdp_adjust_tail") +int _xdp_adjust_tail(struct xdp_md *xdp) +{ + void *data_end = (void *)(long)xdp->data_end; + void *data = (void *)(long)xdp->data; + int offset = 0; + + if (data_end - data == 54) + offset = 256; + else + offset = 20; + if (bpf_xdp_adjust_tail(xdp, 0 - offset)) + return XDP_DROP; + return XDP_TX; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_btf_haskv.c b/tools/testing/selftests/bpf/progs/test_btf_haskv.c new file mode 100644 index 000000000000..e5c79fe0ffdb --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_btf_haskv.c @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Facebook */ +#include +#include "bpf_helpers.h" + +int _version SEC("version") = 1; + +struct ipv_counts { + unsigned int v4; + unsigned int v6; +}; + +struct bpf_map_def SEC("maps") btf_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(struct ipv_counts), + .max_entries = 4, +}; + +BPF_ANNOTATE_KV_PAIR(btf_map, int, struct ipv_counts); + +struct dummy_tracepoint_args { + unsigned long long pad; + struct sock *sock; +}; + +__attribute__((noinline)) +static int test_long_fname_2(struct dummy_tracepoint_args *arg) +{ + struct ipv_counts *counts; + int key = 0; + + if (!arg->sock) + return 0; + + counts = bpf_map_lookup_elem(&btf_map, &key); + if (!counts) + return 0; + + counts->v6++; + + return 0; +} + +__attribute__((noinline)) +static int test_long_fname_1(struct dummy_tracepoint_args *arg) +{ + return test_long_fname_2(arg); +} + +SEC("dummy_tracepoint") +int _dummy_tracepoint(struct dummy_tracepoint_args *arg) +{ + return test_long_fname_1(arg); +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_btf_nokv.c b/tools/testing/selftests/bpf/progs/test_btf_nokv.c new file mode 100644 index 000000000000..434188c37774 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_btf_nokv.c @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Facebook */ +#include +#include "bpf_helpers.h" + +int _version SEC("version") = 1; + +struct ipv_counts { + unsigned int v4; + unsigned int v6; +}; + +struct bpf_map_def SEC("maps") btf_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(struct ipv_counts), + .max_entries = 4, +}; + +struct dummy_tracepoint_args { + unsigned long long pad; + struct sock *sock; +}; + +__attribute__((noinline)) +static int test_long_fname_2(struct dummy_tracepoint_args *arg) +{ + struct ipv_counts *counts; + int key = 0; + + if (!arg->sock) + return 0; + + counts = bpf_map_lookup_elem(&btf_map, &key); + if (!counts) + return 0; + + counts->v6++; + + return 0; +} + +__attribute__((noinline)) +static int test_long_fname_1(struct dummy_tracepoint_args *arg) +{ + return test_long_fname_2(arg); +} + +SEC("dummy_tracepoint") +int _dummy_tracepoint(struct dummy_tracepoint_args *arg) +{ + return test_long_fname_1(arg); +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c b/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c new file mode 100644 index 000000000000..f6d9f238e00a --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include "bpf_helpers.h" + +/* Permit pretty deep stack traces */ +#define MAX_STACK_RAWTP 100 +struct stack_trace_t { + int pid; + int kern_stack_size; + int user_stack_size; + int user_stack_buildid_size; + __u64 kern_stack[MAX_STACK_RAWTP]; + __u64 user_stack[MAX_STACK_RAWTP]; + struct bpf_stack_build_id user_stack_buildid[MAX_STACK_RAWTP]; +}; + +struct bpf_map_def SEC("maps") perfmap = { + .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(__u32), + .max_entries = 2, +}; + +struct bpf_map_def SEC("maps") stackdata_map = { + .type = BPF_MAP_TYPE_PERCPU_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct stack_trace_t), + .max_entries = 1, +}; + +/* Allocate per-cpu space twice the needed. For the code below + * usize = bpf_get_stack(ctx, raw_data, max_len, BPF_F_USER_STACK); + * if (usize < 0) + * return 0; + * ksize = bpf_get_stack(ctx, raw_data + usize, max_len - usize, 0); + * + * If we have value_size = MAX_STACK_RAWTP * sizeof(__u64), + * verifier will complain that access "raw_data + usize" + * with size "max_len - usize" may be out of bound. + * The maximum "raw_data + usize" is "raw_data + max_len" + * and the maximum "max_len - usize" is "max_len", verifier + * concludes that the maximum buffer access range is + * "raw_data[0...max_len * 2 - 1]" and hence reject the program. + * + * Doubling the to-be-used max buffer size can fix this verifier + * issue and avoid complicated C programming massaging. + * This is an acceptable workaround since there is one entry here. + */ +struct bpf_map_def SEC("maps") rawdata_map = { + .type = BPF_MAP_TYPE_PERCPU_ARRAY, + .key_size = sizeof(__u32), + .value_size = MAX_STACK_RAWTP * sizeof(__u64) * 2, + .max_entries = 1, +}; + +SEC("tracepoint/raw_syscalls/sys_enter") +int bpf_prog1(void *ctx) +{ + int max_len, max_buildid_len, usize, ksize, total_size; + struct stack_trace_t *data; + void *raw_data; + __u32 key = 0; + + data = bpf_map_lookup_elem(&stackdata_map, &key); + if (!data) + return 0; + + max_len = MAX_STACK_RAWTP * sizeof(__u64); + max_buildid_len = MAX_STACK_RAWTP * sizeof(struct bpf_stack_build_id); + data->pid = bpf_get_current_pid_tgid(); + data->kern_stack_size = bpf_get_stack(ctx, data->kern_stack, + max_len, 0); + data->user_stack_size = bpf_get_stack(ctx, data->user_stack, max_len, + BPF_F_USER_STACK); + data->user_stack_buildid_size = bpf_get_stack( + ctx, data->user_stack_buildid, max_buildid_len, + BPF_F_USER_STACK | BPF_F_USER_BUILD_ID); + bpf_perf_event_output(ctx, &perfmap, 0, data, sizeof(*data)); + + /* write both kernel and user stacks to the same buffer */ + raw_data = bpf_map_lookup_elem(&rawdata_map, &key); + if (!raw_data) + return 0; + + usize = bpf_get_stack(ctx, raw_data, max_len, BPF_F_USER_STACK); + if (usize < 0) + return 0; + + ksize = bpf_get_stack(ctx, raw_data + usize, max_len - usize, 0); + if (ksize < 0) + return 0; + + total_size = usize + ksize; + if (total_size > 0 && total_size <= max_len) + bpf_perf_event_output(ctx, &perfmap, 0, raw_data, total_size); + + return 0; +} + +char _license[] SEC("license") = "GPL"; +__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/progs/test_l4lb.c b/tools/testing/selftests/bpf/progs/test_l4lb.c new file mode 100644 index 000000000000..1e10c9590991 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_l4lb.c @@ -0,0 +1,473 @@ +/* Copyright (c) 2017 Facebook + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "test_iptunnel_common.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; + +static inline __u32 rol32(__u32 word, unsigned int shift) +{ + return (word << shift) | (word >> ((-shift) & 31)); +} + +/* copy paste of jhash from kernel sources to make sure llvm + * can compile it into valid sequence of bpf instructions + */ +#define __jhash_mix(a, b, c) \ +{ \ + a -= c; a ^= rol32(c, 4); c += b; \ + b -= a; b ^= rol32(a, 6); a += c; \ + c -= b; c ^= rol32(b, 8); b += a; \ + a -= c; a ^= rol32(c, 16); c += b; \ + b -= a; b ^= rol32(a, 19); a += c; \ + c -= b; c ^= rol32(b, 4); b += a; \ +} + +#define __jhash_final(a, b, c) \ +{ \ + c ^= b; c -= rol32(b, 14); \ + a ^= c; a -= rol32(c, 11); \ + b ^= a; b -= rol32(a, 25); \ + c ^= b; c -= rol32(b, 16); \ + a ^= c; a -= rol32(c, 4); \ + b ^= a; b -= rol32(a, 14); \ + c ^= b; c -= rol32(b, 24); \ +} + +#define JHASH_INITVAL 0xdeadbeef + +typedef unsigned int u32; + +static inline u32 jhash(const void *key, u32 length, u32 initval) +{ + u32 a, b, c; + const unsigned char *k = key; + + a = b = c = JHASH_INITVAL + length + initval; + + while (length > 12) { + a += *(u32 *)(k); + b += *(u32 *)(k + 4); + c += *(u32 *)(k + 8); + __jhash_mix(a, b, c); + length -= 12; + k += 12; + } + switch (length) { + case 12: c += (u32)k[11]<<24; + case 11: c += (u32)k[10]<<16; + case 10: c += (u32)k[9]<<8; + case 9: c += k[8]; + case 8: b += (u32)k[7]<<24; + case 7: b += (u32)k[6]<<16; + case 6: b += (u32)k[5]<<8; + case 5: b += k[4]; + case 4: a += (u32)k[3]<<24; + case 3: a += (u32)k[2]<<16; + case 2: a += (u32)k[1]<<8; + case 1: a += k[0]; + __jhash_final(a, b, c); + case 0: /* Nothing left to add */ + break; + } + + return c; +} + +static inline u32 __jhash_nwords(u32 a, u32 b, u32 c, u32 initval) +{ + a += initval; + b += initval; + c += initval; + __jhash_final(a, b, c); + return c; +} + +static inline u32 jhash_2words(u32 a, u32 b, u32 initval) +{ + return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2)); +} + +#define PCKT_FRAGMENTED 65343 +#define IPV4_HDR_LEN_NO_OPT 20 +#define IPV4_PLUS_ICMP_HDR 28 +#define IPV6_PLUS_ICMP_HDR 48 +#define RING_SIZE 2 +#define MAX_VIPS 12 +#define MAX_REALS 5 +#define CTL_MAP_SIZE 16 +#define CH_RINGS_SIZE (MAX_VIPS * RING_SIZE) +#define F_IPV6 (1 << 0) +#define F_HASH_NO_SRC_PORT (1 << 0) +#define F_ICMP (1 << 0) +#define F_SYN_SET (1 << 1) + +struct packet_description { + union { + __be32 src; + __be32 srcv6[4]; + }; + union { + __be32 dst; + __be32 dstv6[4]; + }; + union { + __u32 ports; + __u16 port16[2]; + }; + __u8 proto; + __u8 flags; +}; + +struct ctl_value { + union { + __u64 value; + __u32 ifindex; + __u8 mac[6]; + }; +}; + +struct vip_meta { + __u32 flags; + __u32 vip_num; +}; + +struct real_definition { + union { + __be32 dst; + __be32 dstv6[4]; + }; + __u8 flags; +}; + +struct vip_stats { + __u64 bytes; + __u64 pkts; +}; + +struct eth_hdr { + unsigned char eth_dest[ETH_ALEN]; + unsigned char eth_source[ETH_ALEN]; + unsigned short eth_proto; +}; + +struct bpf_map_def SEC("maps") vip_map = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(struct vip), + .value_size = sizeof(struct vip_meta), + .max_entries = MAX_VIPS, +}; + +struct bpf_map_def SEC("maps") ch_rings = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = CH_RINGS_SIZE, +}; + +struct bpf_map_def SEC("maps") reals = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct real_definition), + .max_entries = MAX_REALS, +}; + +struct bpf_map_def SEC("maps") stats = { + .type = BPF_MAP_TYPE_PERCPU_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct vip_stats), + .max_entries = MAX_VIPS, +}; + +struct bpf_map_def SEC("maps") ctl_array = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct ctl_value), + .max_entries = CTL_MAP_SIZE, +}; + +static __always_inline __u32 get_packet_hash(struct packet_description *pckt, + bool ipv6) +{ + if (ipv6) + return jhash_2words(jhash(pckt->srcv6, 16, MAX_VIPS), + pckt->ports, CH_RINGS_SIZE); + else + return jhash_2words(pckt->src, pckt->ports, CH_RINGS_SIZE); +} + +static __always_inline bool get_packet_dst(struct real_definition **real, + struct packet_description *pckt, + struct vip_meta *vip_info, + bool is_ipv6) +{ + __u32 hash = get_packet_hash(pckt, is_ipv6) % RING_SIZE; + __u32 key = RING_SIZE * vip_info->vip_num + hash; + __u32 *real_pos; + + real_pos = bpf_map_lookup_elem(&ch_rings, &key); + if (!real_pos) + return false; + key = *real_pos; + *real = bpf_map_lookup_elem(&reals, &key); + if (!(*real)) + return false; + return true; +} + +static __always_inline int parse_icmpv6(void *data, void *data_end, __u64 off, + struct packet_description *pckt) +{ + struct icmp6hdr *icmp_hdr; + struct ipv6hdr *ip6h; + + icmp_hdr = data + off; + if (icmp_hdr + 1 > data_end) + return TC_ACT_SHOT; + if (icmp_hdr->icmp6_type != ICMPV6_PKT_TOOBIG) + return TC_ACT_OK; + off += sizeof(struct icmp6hdr); + ip6h = data + off; + if (ip6h + 1 > data_end) + return TC_ACT_SHOT; + pckt->proto = ip6h->nexthdr; + pckt->flags |= F_ICMP; + memcpy(pckt->srcv6, ip6h->daddr.s6_addr32, 16); + memcpy(pckt->dstv6, ip6h->saddr.s6_addr32, 16); + return TC_ACT_UNSPEC; +} + +static __always_inline int parse_icmp(void *data, void *data_end, __u64 off, + struct packet_description *pckt) +{ + struct icmphdr *icmp_hdr; + struct iphdr *iph; + + icmp_hdr = data + off; + if (icmp_hdr + 1 > data_end) + return TC_ACT_SHOT; + if (icmp_hdr->type != ICMP_DEST_UNREACH || + icmp_hdr->code != ICMP_FRAG_NEEDED) + return TC_ACT_OK; + off += sizeof(struct icmphdr); + iph = data + off; + if (iph + 1 > data_end) + return TC_ACT_SHOT; + if (iph->ihl != 5) + return TC_ACT_SHOT; + pckt->proto = iph->protocol; + pckt->flags |= F_ICMP; + pckt->src = iph->daddr; + pckt->dst = iph->saddr; + return TC_ACT_UNSPEC; +} + +static __always_inline bool parse_udp(void *data, __u64 off, void *data_end, + struct packet_description *pckt) +{ + struct udphdr *udp; + udp = data + off; + + if (udp + 1 > data_end) + return false; + + if (!(pckt->flags & F_ICMP)) { + pckt->port16[0] = udp->source; + pckt->port16[1] = udp->dest; + } else { + pckt->port16[0] = udp->dest; + pckt->port16[1] = udp->source; + } + return true; +} + +static __always_inline bool parse_tcp(void *data, __u64 off, void *data_end, + struct packet_description *pckt) +{ + struct tcphdr *tcp; + + tcp = data + off; + if (tcp + 1 > data_end) + return false; + + if (tcp->syn) + pckt->flags |= F_SYN_SET; + + if (!(pckt->flags & F_ICMP)) { + pckt->port16[0] = tcp->source; + pckt->port16[1] = tcp->dest; + } else { + pckt->port16[0] = tcp->dest; + pckt->port16[1] = tcp->source; + } + return true; +} + +static __always_inline int process_packet(void *data, __u64 off, void *data_end, + bool is_ipv6, struct __sk_buff *skb) +{ + void *pkt_start = (void *)(long)skb->data; + struct packet_description pckt = {}; + struct eth_hdr *eth = pkt_start; + struct bpf_tunnel_key tkey = {}; + struct vip_stats *data_stats; + struct real_definition *dst; + struct vip_meta *vip_info; + struct ctl_value *cval; + __u32 v4_intf_pos = 1; + __u32 v6_intf_pos = 2; + struct ipv6hdr *ip6h; + struct vip vip = {}; + struct iphdr *iph; + int tun_flag = 0; + __u16 pkt_bytes; + __u64 iph_len; + __u32 ifindex; + __u8 protocol; + __u32 vip_num; + int action; + + tkey.tunnel_ttl = 64; + if (is_ipv6) { + ip6h = data + off; + if (ip6h + 1 > data_end) + return TC_ACT_SHOT; + + iph_len = sizeof(struct ipv6hdr); + protocol = ip6h->nexthdr; + pckt.proto = protocol; + pkt_bytes = bpf_ntohs(ip6h->payload_len); + off += iph_len; + if (protocol == IPPROTO_FRAGMENT) { + return TC_ACT_SHOT; + } else if (protocol == IPPROTO_ICMPV6) { + action = parse_icmpv6(data, data_end, off, &pckt); + if (action >= 0) + return action; + off += IPV6_PLUS_ICMP_HDR; + } else { + memcpy(pckt.srcv6, ip6h->saddr.s6_addr32, 16); + memcpy(pckt.dstv6, ip6h->daddr.s6_addr32, 16); + } + } else { + iph = data + off; + if (iph + 1 > data_end) + return TC_ACT_SHOT; + if (iph->ihl != 5) + return TC_ACT_SHOT; + + protocol = iph->protocol; + pckt.proto = protocol; + pkt_bytes = bpf_ntohs(iph->tot_len); + off += IPV4_HDR_LEN_NO_OPT; + + if (iph->frag_off & PCKT_FRAGMENTED) + return TC_ACT_SHOT; + if (protocol == IPPROTO_ICMP) { + action = parse_icmp(data, data_end, off, &pckt); + if (action >= 0) + return action; + off += IPV4_PLUS_ICMP_HDR; + } else { + pckt.src = iph->saddr; + pckt.dst = iph->daddr; + } + } + protocol = pckt.proto; + + if (protocol == IPPROTO_TCP) { + if (!parse_tcp(data, off, data_end, &pckt)) + return TC_ACT_SHOT; + } else if (protocol == IPPROTO_UDP) { + if (!parse_udp(data, off, data_end, &pckt)) + return TC_ACT_SHOT; + } else { + return TC_ACT_SHOT; + } + + if (is_ipv6) + memcpy(vip.daddr.v6, pckt.dstv6, 16); + else + vip.daddr.v4 = pckt.dst; + + vip.dport = pckt.port16[1]; + vip.protocol = pckt.proto; + vip_info = bpf_map_lookup_elem(&vip_map, &vip); + if (!vip_info) { + vip.dport = 0; + vip_info = bpf_map_lookup_elem(&vip_map, &vip); + if (!vip_info) + return TC_ACT_SHOT; + pckt.port16[1] = 0; + } + + if (vip_info->flags & F_HASH_NO_SRC_PORT) + pckt.port16[0] = 0; + + if (!get_packet_dst(&dst, &pckt, vip_info, is_ipv6)) + return TC_ACT_SHOT; + + if (dst->flags & F_IPV6) { + cval = bpf_map_lookup_elem(&ctl_array, &v6_intf_pos); + if (!cval) + return TC_ACT_SHOT; + ifindex = cval->ifindex; + memcpy(tkey.remote_ipv6, dst->dstv6, 16); + tun_flag = BPF_F_TUNINFO_IPV6; + } else { + cval = bpf_map_lookup_elem(&ctl_array, &v4_intf_pos); + if (!cval) + return TC_ACT_SHOT; + ifindex = cval->ifindex; + tkey.remote_ipv4 = dst->dst; + } + vip_num = vip_info->vip_num; + data_stats = bpf_map_lookup_elem(&stats, &vip_num); + if (!data_stats) + return TC_ACT_SHOT; + data_stats->pkts++; + data_stats->bytes += pkt_bytes; + bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), tun_flag); + *(u32 *)eth->eth_dest = tkey.remote_ipv4; + return bpf_redirect(ifindex, 0); +} + +SEC("l4lb-demo") +int balancer_ingress(struct __sk_buff *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + struct eth_hdr *eth = data; + __u32 eth_proto; + __u32 nh_off; + + nh_off = sizeof(struct eth_hdr); + if (data + nh_off > data_end) + return TC_ACT_SHOT; + eth_proto = eth->eth_proto; + if (eth_proto == bpf_htons(ETH_P_IP)) + return process_packet(data, nh_off, data_end, false, ctx); + else if (eth_proto == bpf_htons(ETH_P_IPV6)) + return process_packet(data, nh_off, data_end, true, ctx); + else + return TC_ACT_SHOT; +} +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_l4lb_noinline.c b/tools/testing/selftests/bpf/progs/test_l4lb_noinline.c new file mode 100644 index 000000000000..ba44a14e6dc4 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_l4lb_noinline.c @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Facebook +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "test_iptunnel_common.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; + +static __u32 rol32(__u32 word, unsigned int shift) +{ + return (word << shift) | (word >> ((-shift) & 31)); +} + +/* copy paste of jhash from kernel sources to make sure llvm + * can compile it into valid sequence of bpf instructions + */ +#define __jhash_mix(a, b, c) \ +{ \ + a -= c; a ^= rol32(c, 4); c += b; \ + b -= a; b ^= rol32(a, 6); a += c; \ + c -= b; c ^= rol32(b, 8); b += a; \ + a -= c; a ^= rol32(c, 16); c += b; \ + b -= a; b ^= rol32(a, 19); a += c; \ + c -= b; c ^= rol32(b, 4); b += a; \ +} + +#define __jhash_final(a, b, c) \ +{ \ + c ^= b; c -= rol32(b, 14); \ + a ^= c; a -= rol32(c, 11); \ + b ^= a; b -= rol32(a, 25); \ + c ^= b; c -= rol32(b, 16); \ + a ^= c; a -= rol32(c, 4); \ + b ^= a; b -= rol32(a, 14); \ + c ^= b; c -= rol32(b, 24); \ +} + +#define JHASH_INITVAL 0xdeadbeef + +typedef unsigned int u32; + +static u32 jhash(const void *key, u32 length, u32 initval) +{ + u32 a, b, c; + const unsigned char *k = key; + + a = b = c = JHASH_INITVAL + length + initval; + + while (length > 12) { + a += *(u32 *)(k); + b += *(u32 *)(k + 4); + c += *(u32 *)(k + 8); + __jhash_mix(a, b, c); + length -= 12; + k += 12; + } + switch (length) { + case 12: c += (u32)k[11]<<24; + case 11: c += (u32)k[10]<<16; + case 10: c += (u32)k[9]<<8; + case 9: c += k[8]; + case 8: b += (u32)k[7]<<24; + case 7: b += (u32)k[6]<<16; + case 6: b += (u32)k[5]<<8; + case 5: b += k[4]; + case 4: a += (u32)k[3]<<24; + case 3: a += (u32)k[2]<<16; + case 2: a += (u32)k[1]<<8; + case 1: a += k[0]; + __jhash_final(a, b, c); + case 0: /* Nothing left to add */ + break; + } + + return c; +} + +static u32 __jhash_nwords(u32 a, u32 b, u32 c, u32 initval) +{ + a += initval; + b += initval; + c += initval; + __jhash_final(a, b, c); + return c; +} + +static u32 jhash_2words(u32 a, u32 b, u32 initval) +{ + return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2)); +} + +#define PCKT_FRAGMENTED 65343 +#define IPV4_HDR_LEN_NO_OPT 20 +#define IPV4_PLUS_ICMP_HDR 28 +#define IPV6_PLUS_ICMP_HDR 48 +#define RING_SIZE 2 +#define MAX_VIPS 12 +#define MAX_REALS 5 +#define CTL_MAP_SIZE 16 +#define CH_RINGS_SIZE (MAX_VIPS * RING_SIZE) +#define F_IPV6 (1 << 0) +#define F_HASH_NO_SRC_PORT (1 << 0) +#define F_ICMP (1 << 0) +#define F_SYN_SET (1 << 1) + +struct packet_description { + union { + __be32 src; + __be32 srcv6[4]; + }; + union { + __be32 dst; + __be32 dstv6[4]; + }; + union { + __u32 ports; + __u16 port16[2]; + }; + __u8 proto; + __u8 flags; +}; + +struct ctl_value { + union { + __u64 value; + __u32 ifindex; + __u8 mac[6]; + }; +}; + +struct vip_meta { + __u32 flags; + __u32 vip_num; +}; + +struct real_definition { + union { + __be32 dst; + __be32 dstv6[4]; + }; + __u8 flags; +}; + +struct vip_stats { + __u64 bytes; + __u64 pkts; +}; + +struct eth_hdr { + unsigned char eth_dest[ETH_ALEN]; + unsigned char eth_source[ETH_ALEN]; + unsigned short eth_proto; +}; + +struct bpf_map_def SEC("maps") vip_map = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(struct vip), + .value_size = sizeof(struct vip_meta), + .max_entries = MAX_VIPS, +}; + +struct bpf_map_def SEC("maps") ch_rings = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = CH_RINGS_SIZE, +}; + +struct bpf_map_def SEC("maps") reals = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct real_definition), + .max_entries = MAX_REALS, +}; + +struct bpf_map_def SEC("maps") stats = { + .type = BPF_MAP_TYPE_PERCPU_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct vip_stats), + .max_entries = MAX_VIPS, +}; + +struct bpf_map_def SEC("maps") ctl_array = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct ctl_value), + .max_entries = CTL_MAP_SIZE, +}; + +static __u32 get_packet_hash(struct packet_description *pckt, + bool ipv6) +{ + if (ipv6) + return jhash_2words(jhash(pckt->srcv6, 16, MAX_VIPS), + pckt->ports, CH_RINGS_SIZE); + else + return jhash_2words(pckt->src, pckt->ports, CH_RINGS_SIZE); +} + +static bool get_packet_dst(struct real_definition **real, + struct packet_description *pckt, + struct vip_meta *vip_info, + bool is_ipv6) +{ + __u32 hash = get_packet_hash(pckt, is_ipv6); + __u32 key = RING_SIZE * vip_info->vip_num + hash % RING_SIZE; + __u32 *real_pos; + + if (hash != 0x358459b7 /* jhash of ipv4 packet */ && + hash != 0x2f4bc6bb /* jhash of ipv6 packet */) + return 0; + + real_pos = bpf_map_lookup_elem(&ch_rings, &key); + if (!real_pos) + return false; + key = *real_pos; + *real = bpf_map_lookup_elem(&reals, &key); + if (!(*real)) + return false; + return true; +} + +static int parse_icmpv6(void *data, void *data_end, __u64 off, + struct packet_description *pckt) +{ + struct icmp6hdr *icmp_hdr; + struct ipv6hdr *ip6h; + + icmp_hdr = data + off; + if (icmp_hdr + 1 > data_end) + return TC_ACT_SHOT; + if (icmp_hdr->icmp6_type != ICMPV6_PKT_TOOBIG) + return TC_ACT_OK; + off += sizeof(struct icmp6hdr); + ip6h = data + off; + if (ip6h + 1 > data_end) + return TC_ACT_SHOT; + pckt->proto = ip6h->nexthdr; + pckt->flags |= F_ICMP; + memcpy(pckt->srcv6, ip6h->daddr.s6_addr32, 16); + memcpy(pckt->dstv6, ip6h->saddr.s6_addr32, 16); + return TC_ACT_UNSPEC; +} + +static int parse_icmp(void *data, void *data_end, __u64 off, + struct packet_description *pckt) +{ + struct icmphdr *icmp_hdr; + struct iphdr *iph; + + icmp_hdr = data + off; + if (icmp_hdr + 1 > data_end) + return TC_ACT_SHOT; + if (icmp_hdr->type != ICMP_DEST_UNREACH || + icmp_hdr->code != ICMP_FRAG_NEEDED) + return TC_ACT_OK; + off += sizeof(struct icmphdr); + iph = data + off; + if (iph + 1 > data_end) + return TC_ACT_SHOT; + if (iph->ihl != 5) + return TC_ACT_SHOT; + pckt->proto = iph->protocol; + pckt->flags |= F_ICMP; + pckt->src = iph->daddr; + pckt->dst = iph->saddr; + return TC_ACT_UNSPEC; +} + +static bool parse_udp(void *data, __u64 off, void *data_end, + struct packet_description *pckt) +{ + struct udphdr *udp; + udp = data + off; + + if (udp + 1 > data_end) + return false; + + if (!(pckt->flags & F_ICMP)) { + pckt->port16[0] = udp->source; + pckt->port16[1] = udp->dest; + } else { + pckt->port16[0] = udp->dest; + pckt->port16[1] = udp->source; + } + return true; +} + +static bool parse_tcp(void *data, __u64 off, void *data_end, + struct packet_description *pckt) +{ + struct tcphdr *tcp; + + tcp = data + off; + if (tcp + 1 > data_end) + return false; + + if (tcp->syn) + pckt->flags |= F_SYN_SET; + + if (!(pckt->flags & F_ICMP)) { + pckt->port16[0] = tcp->source; + pckt->port16[1] = tcp->dest; + } else { + pckt->port16[0] = tcp->dest; + pckt->port16[1] = tcp->source; + } + return true; +} + +static int process_packet(void *data, __u64 off, void *data_end, + bool is_ipv6, struct __sk_buff *skb) +{ + void *pkt_start = (void *)(long)skb->data; + struct packet_description pckt = {}; + struct eth_hdr *eth = pkt_start; + struct bpf_tunnel_key tkey = {}; + struct vip_stats *data_stats; + struct real_definition *dst; + struct vip_meta *vip_info; + struct ctl_value *cval; + __u32 v4_intf_pos = 1; + __u32 v6_intf_pos = 2; + struct ipv6hdr *ip6h; + struct vip vip = {}; + struct iphdr *iph; + int tun_flag = 0; + __u16 pkt_bytes; + __u64 iph_len; + __u32 ifindex; + __u8 protocol; + __u32 vip_num; + int action; + + tkey.tunnel_ttl = 64; + if (is_ipv6) { + ip6h = data + off; + if (ip6h + 1 > data_end) + return TC_ACT_SHOT; + + iph_len = sizeof(struct ipv6hdr); + protocol = ip6h->nexthdr; + pckt.proto = protocol; + pkt_bytes = bpf_ntohs(ip6h->payload_len); + off += iph_len; + if (protocol == IPPROTO_FRAGMENT) { + return TC_ACT_SHOT; + } else if (protocol == IPPROTO_ICMPV6) { + action = parse_icmpv6(data, data_end, off, &pckt); + if (action >= 0) + return action; + off += IPV6_PLUS_ICMP_HDR; + } else { + memcpy(pckt.srcv6, ip6h->saddr.s6_addr32, 16); + memcpy(pckt.dstv6, ip6h->daddr.s6_addr32, 16); + } + } else { + iph = data + off; + if (iph + 1 > data_end) + return TC_ACT_SHOT; + if (iph->ihl != 5) + return TC_ACT_SHOT; + + protocol = iph->protocol; + pckt.proto = protocol; + pkt_bytes = bpf_ntohs(iph->tot_len); + off += IPV4_HDR_LEN_NO_OPT; + + if (iph->frag_off & PCKT_FRAGMENTED) + return TC_ACT_SHOT; + if (protocol == IPPROTO_ICMP) { + action = parse_icmp(data, data_end, off, &pckt); + if (action >= 0) + return action; + off += IPV4_PLUS_ICMP_HDR; + } else { + pckt.src = iph->saddr; + pckt.dst = iph->daddr; + } + } + protocol = pckt.proto; + + if (protocol == IPPROTO_TCP) { + if (!parse_tcp(data, off, data_end, &pckt)) + return TC_ACT_SHOT; + } else if (protocol == IPPROTO_UDP) { + if (!parse_udp(data, off, data_end, &pckt)) + return TC_ACT_SHOT; + } else { + return TC_ACT_SHOT; + } + + if (is_ipv6) + memcpy(vip.daddr.v6, pckt.dstv6, 16); + else + vip.daddr.v4 = pckt.dst; + + vip.dport = pckt.port16[1]; + vip.protocol = pckt.proto; + vip_info = bpf_map_lookup_elem(&vip_map, &vip); + if (!vip_info) { + vip.dport = 0; + vip_info = bpf_map_lookup_elem(&vip_map, &vip); + if (!vip_info) + return TC_ACT_SHOT; + pckt.port16[1] = 0; + } + + if (vip_info->flags & F_HASH_NO_SRC_PORT) + pckt.port16[0] = 0; + + if (!get_packet_dst(&dst, &pckt, vip_info, is_ipv6)) + return TC_ACT_SHOT; + + if (dst->flags & F_IPV6) { + cval = bpf_map_lookup_elem(&ctl_array, &v6_intf_pos); + if (!cval) + return TC_ACT_SHOT; + ifindex = cval->ifindex; + memcpy(tkey.remote_ipv6, dst->dstv6, 16); + tun_flag = BPF_F_TUNINFO_IPV6; + } else { + cval = bpf_map_lookup_elem(&ctl_array, &v4_intf_pos); + if (!cval) + return TC_ACT_SHOT; + ifindex = cval->ifindex; + tkey.remote_ipv4 = dst->dst; + } + vip_num = vip_info->vip_num; + data_stats = bpf_map_lookup_elem(&stats, &vip_num); + if (!data_stats) + return TC_ACT_SHOT; + data_stats->pkts++; + data_stats->bytes += pkt_bytes; + bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), tun_flag); + *(u32 *)eth->eth_dest = tkey.remote_ipv4; + return bpf_redirect(ifindex, 0); +} + +SEC("l4lb-demo") +int balancer_ingress(struct __sk_buff *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + struct eth_hdr *eth = data; + __u32 eth_proto; + __u32 nh_off; + + nh_off = sizeof(struct eth_hdr); + if (data + nh_off > data_end) + return TC_ACT_SHOT; + eth_proto = eth->eth_proto; + if (eth_proto == bpf_htons(ETH_P_IP)) + return process_packet(data, nh_off, data_end, false, ctx); + else if (eth_proto == bpf_htons(ETH_P_IPV6)) + return process_packet(data, nh_off, data_end, true, ctx); + else + return TC_ACT_SHOT; +} +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_lirc_mode2_kern.c b/tools/testing/selftests/bpf/progs/test_lirc_mode2_kern.c new file mode 100644 index 000000000000..4147130cc3b7 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_lirc_mode2_kern.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +// test ir decoder +// +// Copyright (C) 2018 Sean Young + +#include +#include +#include "bpf_helpers.h" + +SEC("lirc_mode2") +int bpf_decoder(unsigned int *sample) +{ + if (LIRC_IS_PULSE(*sample)) { + unsigned int duration = LIRC_VALUE(*sample); + + if (duration & 0x10000) + bpf_rc_keydown(sample, 0x40, duration & 0xffff, 0); + if (duration & 0x20000) + bpf_rc_pointer_rel(sample, (duration >> 8) & 0xff, + duration & 0xff); + } + + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_lwt_seg6local.c b/tools/testing/selftests/bpf/progs/test_lwt_seg6local.c new file mode 100644 index 000000000000..0575751bc1bc --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_lwt_seg6local.c @@ -0,0 +1,437 @@ +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define bpf_printk(fmt, ...) \ +({ \ + char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ +}) + +/* Packet parsing state machine helpers. */ +#define cursor_advance(_cursor, _len) \ + ({ void *_tmp = _cursor; _cursor += _len; _tmp; }) + +#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 { + unsigned int ver:4; + unsigned int priority:8; + unsigned int flow_label:20; + unsigned short payload_len; + unsigned char next_header; + unsigned char hop_limit; + unsigned long long src_hi; + unsigned long long src_lo; + unsigned long long dst_hi; + unsigned long long dst_lo; +} BPF_PACKET_HEADER; + +struct ip6_addr_t { + unsigned long long hi; + unsigned long long lo; +} BPF_PACKET_HEADER; + +struct ip6_srh_t { + unsigned char nexthdr; + unsigned char hdrlen; + unsigned char type; + unsigned char segments_left; + unsigned char first_segment; + unsigned char flags; + unsigned short tag; + + struct ip6_addr_t segments[0]; +} BPF_PACKET_HEADER; + +struct sr6_tlv_t { + unsigned char type; + unsigned char len; + unsigned char value[0]; +} BPF_PACKET_HEADER; + +__attribute__((always_inline)) struct ip6_srh_t *get_srh(struct __sk_buff *skb) +{ + void *cursor, *data_end; + struct ip6_srh_t *srh; + struct ip6_t *ip; + uint8_t *ipver; + + data_end = (void *)(long)skb->data_end; + cursor = (void *)(long)skb->data; + ipver = (uint8_t *)cursor; + + if ((void *)ipver + sizeof(*ipver) > data_end) + return NULL; + + if ((*ipver >> 4) != 6) + return NULL; + + ip = cursor_advance(cursor, sizeof(*ip)); + if ((void *)ip + sizeof(*ip) > data_end) + return NULL; + + if (ip->next_header != 43) + return NULL; + + srh = cursor_advance(cursor, sizeof(*srh)); + if ((void *)srh + sizeof(*srh) > data_end) + return NULL; + + if (srh->type != 4) + return NULL; + + return srh; +} + +__attribute__((always_inline)) +int update_tlv_pad(struct __sk_buff *skb, uint32_t new_pad, + uint32_t old_pad, uint32_t pad_off) +{ + int err; + + if (new_pad != old_pad) { + err = bpf_lwt_seg6_adjust_srh(skb, pad_off, + (int) new_pad - (int) old_pad); + if (err) + return err; + } + + if (new_pad > 0) { + char pad_tlv_buf[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0}; + struct sr6_tlv_t *pad_tlv = (struct sr6_tlv_t *) pad_tlv_buf; + + pad_tlv->type = SR6_TLV_PADDING; + pad_tlv->len = new_pad - 2; + + err = bpf_lwt_seg6_store_bytes(skb, pad_off, + (void *)pad_tlv_buf, new_pad); + if (err) + return err; + } + + return 0; +} + +__attribute__((always_inline)) +int is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh, + uint32_t *tlv_off, uint32_t *pad_size, + uint32_t *pad_off) +{ + uint32_t srh_off, cur_off; + int offset_valid = 0; + int err; + + srh_off = (char *)srh - (char *)(long)skb->data; + // cur_off = end of segments, start of possible TLVs + cur_off = srh_off + sizeof(*srh) + + sizeof(struct ip6_addr_t) * (srh->first_segment + 1); + + *pad_off = 0; + + // we can only go as far as ~10 TLVs due to the BPF max stack size + #pragma clang loop unroll(full) + for (int i = 0; i < 10; i++) { + struct sr6_tlv_t tlv; + + if (cur_off == *tlv_off) + offset_valid = 1; + + if (cur_off >= srh_off + ((srh->hdrlen + 1) << 3)) + break; + + err = bpf_skb_load_bytes(skb, cur_off, &tlv, sizeof(tlv)); + if (err) + return err; + + if (tlv.type == SR6_TLV_PADDING) { + *pad_size = tlv.len + sizeof(tlv); + *pad_off = cur_off; + + if (*tlv_off == srh_off) { + *tlv_off = cur_off; + offset_valid = 1; + } + break; + + } else if (tlv.type == SR6_TLV_HMAC) { + break; + } + + cur_off += sizeof(tlv) + tlv.len; + } // we reached the padding or HMAC TLVs, or the end of the SRH + + if (*pad_off == 0) + *pad_off = cur_off; + + if (*tlv_off == -1) + *tlv_off = cur_off; + else if (!offset_valid) + return -EINVAL; + + return 0; +} + +__attribute__((always_inline)) +int add_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, uint32_t tlv_off, + struct sr6_tlv_t *itlv, uint8_t tlv_size) +{ + uint32_t srh_off = (char *)srh - (char *)(long)skb->data; + uint8_t len_remaining, new_pad; + uint32_t pad_off = 0; + uint32_t pad_size = 0; + uint32_t partial_srh_len; + int err; + + if (tlv_off != -1) + tlv_off += srh_off; + + if (itlv->type == SR6_TLV_PADDING || itlv->type == SR6_TLV_HMAC) + return -EINVAL; + + err = is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); + if (err) + return err; + + err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, sizeof(*itlv) + itlv->len); + if (err) + return err; + + err = bpf_lwt_seg6_store_bytes(skb, tlv_off, (void *)itlv, tlv_size); + if (err) + return err; + + // the following can't be moved inside update_tlv_pad because the + // bpf verifier has some issues with it + pad_off += sizeof(*itlv) + itlv->len; + partial_srh_len = pad_off - srh_off; + len_remaining = partial_srh_len % 8; + new_pad = 8 - len_remaining; + + if (new_pad == 1) // cannot pad for 1 byte only + new_pad = 9; + else if (new_pad == 8) + new_pad = 0; + + return update_tlv_pad(skb, new_pad, pad_size, pad_off); +} + +__attribute__((always_inline)) +int delete_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, + uint32_t tlv_off) +{ + uint32_t srh_off = (char *)srh - (char *)(long)skb->data; + uint8_t len_remaining, new_pad; + uint32_t partial_srh_len; + uint32_t pad_off = 0; + uint32_t pad_size = 0; + struct sr6_tlv_t tlv; + int err; + + tlv_off += srh_off; + + err = is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); + if (err) + return err; + + err = bpf_skb_load_bytes(skb, tlv_off, &tlv, sizeof(tlv)); + if (err) + return err; + + err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, -(sizeof(tlv) + tlv.len)); + if (err) + return err; + + pad_off -= sizeof(tlv) + tlv.len; + partial_srh_len = pad_off - srh_off; + len_remaining = partial_srh_len % 8; + new_pad = 8 - len_remaining; + if (new_pad == 1) // cannot pad for 1 byte only + new_pad = 9; + else if (new_pad == 8) + new_pad = 0; + + return update_tlv_pad(skb, new_pad, pad_size, pad_off); +} + +__attribute__((always_inline)) +int has_egr_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh) +{ + int tlv_offset = sizeof(struct ip6_t) + sizeof(struct ip6_srh_t) + + ((srh->first_segment + 1) << 4); + struct sr6_tlv_t tlv; + + if (bpf_skb_load_bytes(skb, tlv_offset, &tlv, sizeof(struct sr6_tlv_t))) + return 0; + + if (tlv.type == SR6_TLV_EGRESS && tlv.len == 18) { + struct ip6_addr_t egr_addr; + + if (bpf_skb_load_bytes(skb, tlv_offset + 4, &egr_addr, 16)) + return 0; + + // check if egress TLV value is correct + if (ntohll(egr_addr.hi) == 0xfd00000000000000 && + ntohll(egr_addr.lo) == 0x4) + return 1; + } + + return 0; +} + +// This function will push a SRH with segments fd00::1, fd00::2, fd00::3, +// fd00::4 +SEC("encap_srh") +int __encap_srh(struct __sk_buff *skb) +{ + unsigned long long hi = 0xfd00000000000000; + struct ip6_addr_t *seg; + struct ip6_srh_t *srh; + char srh_buf[72]; // room for 4 segments + int err; + + srh = (struct ip6_srh_t *)srh_buf; + srh->nexthdr = 0; + srh->hdrlen = 8; + srh->type = 4; + srh->segments_left = 3; + srh->first_segment = 3; + srh->flags = 0; + srh->tag = 0; + + seg = (struct ip6_addr_t *)((char *)srh + sizeof(*srh)); + + #pragma clang loop unroll(full) + for (unsigned long long lo = 0; lo < 4; lo++) { + seg->lo = htonll(4 - lo); + seg->hi = htonll(hi); + seg = (struct ip6_addr_t *)((char *)seg + sizeof(*seg)); + } + + err = bpf_lwt_push_encap(skb, 0, (void *)srh, sizeof(srh_buf)); + if (err) + return BPF_DROP; + + return BPF_REDIRECT; +} + +// Add an Egress TLV fc00::4, add the flag A, +// and apply End.X action to fc42::1 +SEC("add_egr_x") +int __add_egr_x(struct __sk_buff *skb) +{ + unsigned long long hi = 0xfc42000000000000; + unsigned long long lo = 0x1; + struct ip6_srh_t *srh = get_srh(skb); + uint8_t new_flags = SR6_FLAG_ALERT; + struct ip6_addr_t addr; + int err, offset; + + if (srh == NULL) + return BPF_DROP; + + uint8_t tlv[20] = {2, 18, 0, 0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4}; + + err = add_tlv(skb, srh, (srh->hdrlen+1) << 3, + (struct sr6_tlv_t *)&tlv, 20); + if (err) + return BPF_DROP; + + offset = sizeof(struct ip6_t) + offsetof(struct ip6_srh_t, flags); + err = bpf_lwt_seg6_store_bytes(skb, offset, + (void *)&new_flags, sizeof(new_flags)); + if (err) + return BPF_DROP; + + addr.lo = htonll(lo); + addr.hi = htonll(hi); + err = bpf_lwt_seg6_action(skb, SEG6_LOCAL_ACTION_END_X, + (void *)&addr, sizeof(addr)); + if (err) + return BPF_DROP; + return BPF_REDIRECT; +} + +// Pop the Egress TLV, reset the flags, change the tag 2442 and finally do a +// simple End action +SEC("pop_egr") +int __pop_egr(struct __sk_buff *skb) +{ + struct ip6_srh_t *srh = get_srh(skb); + uint16_t new_tag = bpf_htons(2442); + uint8_t new_flags = 0; + int err, offset; + + if (srh == NULL) + return BPF_DROP; + + if (srh->flags != SR6_FLAG_ALERT) + return BPF_DROP; + + if (srh->hdrlen != 11) // 4 segments + Egress TLV + Padding TLV + return BPF_DROP; + + if (!has_egr_tlv(skb, srh)) + return BPF_DROP; + + err = delete_tlv(skb, srh, 8 + (srh->first_segment + 1) * 16); + if (err) + return BPF_DROP; + + offset = sizeof(struct ip6_t) + offsetof(struct ip6_srh_t, flags); + if (bpf_lwt_seg6_store_bytes(skb, offset, (void *)&new_flags, + sizeof(new_flags))) + return BPF_DROP; + + offset = sizeof(struct ip6_t) + offsetof(struct ip6_srh_t, tag); + if (bpf_lwt_seg6_store_bytes(skb, offset, (void *)&new_tag, + sizeof(new_tag))) + return BPF_DROP; + + return BPF_OK; +} + +// Inspect if the Egress TLV and flag have been removed, if the tag is correct, +// then apply a End.T action to reach the last segment +SEC("inspect_t") +int __inspect_t(struct __sk_buff *skb) +{ + struct ip6_srh_t *srh = get_srh(skb); + int table = 117; + int err; + + if (srh == NULL) + return BPF_DROP; + + if (srh->flags != 0) + return BPF_DROP; + + if (srh->tag != bpf_htons(2442)) + return BPF_DROP; + + if (srh->hdrlen != 8) // 4 segments + return BPF_DROP; + + err = bpf_lwt_seg6_action(skb, SEG6_LOCAL_ACTION_END_T, + (void *)&table, sizeof(table)); + + if (err) + return BPF_DROP; + + return BPF_REDIRECT; +} + +char __license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_map_in_map.c b/tools/testing/selftests/bpf/progs/test_map_in_map.c new file mode 100644 index 000000000000..ce923e67e08e --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_map_in_map.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Facebook */ +#include +#include +#include +#include "bpf_helpers.h" + +struct bpf_map_def SEC("maps") mim_array = { + .type = BPF_MAP_TYPE_ARRAY_OF_MAPS, + .key_size = sizeof(int), + /* must be sizeof(__u32) for map in map */ + .value_size = sizeof(__u32), + .max_entries = 1, + .map_flags = 0, +}; + +struct bpf_map_def SEC("maps") mim_hash = { + .type = BPF_MAP_TYPE_HASH_OF_MAPS, + .key_size = sizeof(int), + /* must be sizeof(__u32) for map in map */ + .value_size = sizeof(__u32), + .max_entries = 1, + .map_flags = 0, +}; + +SEC("xdp_mimtest") +int xdp_mimtest0(struct xdp_md *ctx) +{ + int value = 123; + int key = 0; + void *map; + + map = bpf_map_lookup_elem(&mim_array, &key); + if (!map) + return XDP_DROP; + + bpf_map_update_elem(map, &key, &value, 0); + + map = bpf_map_lookup_elem(&mim_hash, &key); + if (!map) + return XDP_DROP; + + bpf_map_update_elem(map, &key, &value, 0); + + return XDP_PASS; +} + +int _version SEC("version") = 1; +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_map_lock.c b/tools/testing/selftests/bpf/progs/test_map_lock.c new file mode 100644 index 000000000000..af8cc68ed2f9 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_map_lock.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Facebook +#include +#include +#include "bpf_helpers.h" + +#define VAR_NUM 16 + +struct hmap_elem { + struct bpf_spin_lock lock; + int var[VAR_NUM]; +}; + +struct bpf_map_def SEC("maps") hash_map = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(int), + .value_size = sizeof(struct hmap_elem), + .max_entries = 1, +}; + +BPF_ANNOTATE_KV_PAIR(hash_map, int, struct hmap_elem); + +struct array_elem { + struct bpf_spin_lock lock; + int var[VAR_NUM]; +}; + +struct bpf_map_def SEC("maps") array_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(struct array_elem), + .max_entries = 1, +}; + +BPF_ANNOTATE_KV_PAIR(array_map, int, struct array_elem); + +SEC("map_lock_demo") +int bpf_map_lock_test(struct __sk_buff *skb) +{ + struct hmap_elem zero = {}, *val; + int rnd = bpf_get_prandom_u32(); + int key = 0, err = 1, i; + struct array_elem *q; + + val = bpf_map_lookup_elem(&hash_map, &key); + if (!val) + goto err; + /* spin_lock in hash map */ + bpf_spin_lock(&val->lock); + for (i = 0; i < VAR_NUM; i++) + val->var[i] = rnd; + bpf_spin_unlock(&val->lock); + + /* spin_lock in array */ + q = bpf_map_lookup_elem(&array_map, &key); + if (!q) + goto err; + bpf_spin_lock(&q->lock); + for (i = 0; i < VAR_NUM; i++) + q->var[i] = rnd; + bpf_spin_unlock(&q->lock); + err = 0; +err: + return err; +} +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_obj_id.c b/tools/testing/selftests/bpf/progs/test_obj_id.c new file mode 100644 index 000000000000..880d2963b472 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_obj_id.c @@ -0,0 +1,35 @@ +/* Copyright (c) 2017 Facebook + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ +#include +#include +#include +#include "bpf_helpers.h" + +/* It is a dumb bpf program such that it must have no + * issue to be loaded since testing the verifier is + * not the focus here. + */ + +int _version SEC("version") = 1; + +struct bpf_map_def SEC("maps") test_map_id = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u64), + .max_entries = 1, +}; + +SEC("test_obj_id_dummy") +int test_obj_id(struct __sk_buff *skb) +{ + __u32 key = 0; + __u64 *value; + + value = bpf_map_lookup_elem(&test_map_id, &key); + + return TC_ACT_OK; +} diff --git a/tools/testing/selftests/bpf/progs/test_pkt_access.c b/tools/testing/selftests/bpf/progs/test_pkt_access.c new file mode 100644 index 000000000000..6e11ba11709e --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_pkt_access.c @@ -0,0 +1,65 @@ +/* Copyright (c) 2017 Facebook + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define barrier() __asm__ __volatile__("": : :"memory") +int _version SEC("version") = 1; + +SEC("test1") +int process(struct __sk_buff *skb) +{ + void *data_end = (void *)(long)skb->data_end; + void *data = (void *)(long)skb->data; + struct ethhdr *eth = (struct ethhdr *)(data); + struct tcphdr *tcp = NULL; + __u8 proto = 255; + __u64 ihl_len; + + if (eth + 1 > data_end) + return TC_ACT_SHOT; + + if (eth->h_proto == bpf_htons(ETH_P_IP)) { + struct iphdr *iph = (struct iphdr *)(eth + 1); + + if (iph + 1 > data_end) + return TC_ACT_SHOT; + ihl_len = iph->ihl * 4; + proto = iph->protocol; + tcp = (struct tcphdr *)((void *)(iph) + ihl_len); + } else if (eth->h_proto == bpf_htons(ETH_P_IPV6)) { + struct ipv6hdr *ip6h = (struct ipv6hdr *)(eth + 1); + + if (ip6h + 1 > data_end) + return TC_ACT_SHOT; + ihl_len = sizeof(*ip6h); + proto = ip6h->nexthdr; + tcp = (struct tcphdr *)((void *)(ip6h) + ihl_len); + } + + if (tcp) { + if (((void *)(tcp) + 20) > data_end || proto != 6) + return TC_ACT_SHOT; + barrier(); /* to force ordering of checks */ + if (((void *)(tcp) + 18) > data_end) + return TC_ACT_SHOT; + if (tcp->urg_ptr == 123) + return TC_ACT_OK; + } + + return TC_ACT_UNSPEC; +} diff --git a/tools/testing/selftests/bpf/progs/test_pkt_md_access.c b/tools/testing/selftests/bpf/progs/test_pkt_md_access.c new file mode 100644 index 000000000000..7956302ecdf2 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_pkt_md_access.c @@ -0,0 +1,46 @@ +/* Copyright (c) 2017 Facebook + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include "bpf_helpers.h" + +int _version SEC("version") = 1; + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define TEST_FIELD(TYPE, FIELD, MASK) \ + { \ + TYPE tmp = *(volatile TYPE *)&skb->FIELD; \ + if (tmp != ((*(volatile __u32 *)&skb->FIELD) & MASK)) \ + return TC_ACT_SHOT; \ + } +#else +#define TEST_FIELD_OFFSET(a, b) ((sizeof(a) - sizeof(b)) / sizeof(b)) +#define TEST_FIELD(TYPE, FIELD, MASK) \ + { \ + TYPE tmp = *((volatile TYPE *)&skb->FIELD + \ + TEST_FIELD_OFFSET(skb->FIELD, TYPE)); \ + if (tmp != ((*(volatile __u32 *)&skb->FIELD) & MASK)) \ + return TC_ACT_SHOT; \ + } +#endif + +SEC("test1") +int process(struct __sk_buff *skb) +{ + TEST_FIELD(__u8, len, 0xFF); + TEST_FIELD(__u16, len, 0xFFFF); + TEST_FIELD(__u32, len, 0xFFFFFFFF); + TEST_FIELD(__u16, protocol, 0xFFFF); + TEST_FIELD(__u32, protocol, 0xFFFFFFFF); + TEST_FIELD(__u8, hash, 0xFF); + TEST_FIELD(__u16, hash, 0xFFFF); + TEST_FIELD(__u32, hash, 0xFFFFFFFF); + + return TC_ACT_OK; +} diff --git a/tools/testing/selftests/bpf/progs/test_queue_map.c b/tools/testing/selftests/bpf/progs/test_queue_map.c new file mode 100644 index 000000000000..87db1f9da33d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_queue_map.c @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Politecnico di Torino +#define MAP_TYPE BPF_MAP_TYPE_QUEUE +#include "test_queue_stack_map.h" diff --git a/tools/testing/selftests/bpf/progs/test_select_reuseport_kern.c b/tools/testing/selftests/bpf/progs/test_select_reuseport_kern.c new file mode 100644 index 000000000000..5b54ec637ada --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_select_reuseport_kern.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Facebook */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf_endian.h" +#include "bpf_helpers.h" +#include "test_select_reuseport_common.h" + +int _version SEC("version") = 1; + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +struct bpf_map_def SEC("maps") outer_map = { + .type = BPF_MAP_TYPE_ARRAY_OF_MAPS, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") result_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = NR_RESULTS, +}; + +struct bpf_map_def SEC("maps") tmp_index_ovr_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(int), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") linum_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") data_check_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct data_check), + .max_entries = 1, +}; + +#define GOTO_DONE(_result) ({ \ + result = (_result); \ + linum = __LINE__; \ + goto done; \ +}) + +SEC("select_by_skb_data") +int _select_by_skb_data(struct sk_reuseport_md *reuse_md) +{ + __u32 linum, index = 0, flags = 0, index_zero = 0; + __u32 *result_cnt, *linum_value; + struct data_check data_check = {}; + struct cmd *cmd, cmd_copy; + void *data, *data_end; + void *reuseport_array; + enum result result; + int *index_ovr; + int err; + + data = reuse_md->data; + data_end = reuse_md->data_end; + data_check.len = reuse_md->len; + data_check.eth_protocol = reuse_md->eth_protocol; + data_check.ip_protocol = reuse_md->ip_protocol; + data_check.hash = reuse_md->hash; + data_check.bind_inany = reuse_md->bind_inany; + if (data_check.eth_protocol == bpf_htons(ETH_P_IP)) { + if (bpf_skb_load_bytes_relative(reuse_md, + offsetof(struct iphdr, saddr), + data_check.skb_addrs, 8, + BPF_HDR_START_NET)) + GOTO_DONE(DROP_MISC); + } else { + if (bpf_skb_load_bytes_relative(reuse_md, + offsetof(struct ipv6hdr, saddr), + data_check.skb_addrs, 32, + BPF_HDR_START_NET)) + GOTO_DONE(DROP_MISC); + } + + /* + * The ip_protocol could be a compile time decision + * if the bpf_prog.o is dedicated to either TCP or + * UDP. + * + * Otherwise, reuse_md->ip_protocol or + * the protocol field in the iphdr can be used. + */ + if (data_check.ip_protocol == IPPROTO_TCP) { + struct tcphdr *th = data; + + if (th + 1 > data_end) + GOTO_DONE(DROP_MISC); + + data_check.skb_ports[0] = th->source; + data_check.skb_ports[1] = th->dest; + + if ((th->doff << 2) + sizeof(*cmd) > data_check.len) + GOTO_DONE(DROP_ERR_SKB_DATA); + if (bpf_skb_load_bytes(reuse_md, th->doff << 2, &cmd_copy, + sizeof(cmd_copy))) + GOTO_DONE(DROP_MISC); + cmd = &cmd_copy; + } else if (data_check.ip_protocol == IPPROTO_UDP) { + struct udphdr *uh = data; + + if (uh + 1 > data_end) + GOTO_DONE(DROP_MISC); + + data_check.skb_ports[0] = uh->source; + data_check.skb_ports[1] = uh->dest; + + if (sizeof(struct udphdr) + sizeof(*cmd) > data_check.len) + GOTO_DONE(DROP_ERR_SKB_DATA); + if (data + sizeof(struct udphdr) + sizeof(*cmd) > data_end) { + if (bpf_skb_load_bytes(reuse_md, sizeof(struct udphdr), + &cmd_copy, sizeof(cmd_copy))) + GOTO_DONE(DROP_MISC); + cmd = &cmd_copy; + } else { + cmd = data + sizeof(struct udphdr); + } + } else { + GOTO_DONE(DROP_MISC); + } + + reuseport_array = bpf_map_lookup_elem(&outer_map, &index_zero); + if (!reuseport_array) + GOTO_DONE(DROP_ERR_INNER_MAP); + + index = cmd->reuseport_index; + index_ovr = bpf_map_lookup_elem(&tmp_index_ovr_map, &index_zero); + if (!index_ovr) + GOTO_DONE(DROP_MISC); + + if (*index_ovr != -1) { + index = *index_ovr; + *index_ovr = -1; + } + err = bpf_sk_select_reuseport(reuse_md, reuseport_array, &index, + flags); + if (!err) + GOTO_DONE(PASS); + + if (cmd->pass_on_failure) + GOTO_DONE(PASS_ERR_SK_SELECT_REUSEPORT); + else + GOTO_DONE(DROP_ERR_SK_SELECT_REUSEPORT); + +done: + result_cnt = bpf_map_lookup_elem(&result_map, &result); + if (!result_cnt) + return SK_DROP; + + bpf_map_update_elem(&linum_map, &index_zero, &linum, BPF_ANY); + bpf_map_update_elem(&data_check_map, &index_zero, &data_check, BPF_ANY); + + (*result_cnt)++; + return result < PASS ? SK_DROP : SK_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_sk_lookup_kern.c b/tools/testing/selftests/bpf/progs/test_sk_lookup_kern.c new file mode 100644 index 000000000000..e21cd736c196 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_sk_lookup_kern.c @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +// Copyright (c) 2018 Covalent IO, Inc. http://covalent.io + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; +char _license[] SEC("license") = "GPL"; + +/* Fill 'tuple' with L3 info, and attempt to find L4. On fail, return NULL. */ +static struct bpf_sock_tuple *get_tuple(void *data, __u64 nh_off, + void *data_end, __u16 eth_proto, + bool *ipv4) +{ + struct bpf_sock_tuple *result; + __u8 proto = 0; + __u64 ihl_len; + + if (eth_proto == bpf_htons(ETH_P_IP)) { + struct iphdr *iph = (struct iphdr *)(data + nh_off); + + if (iph + 1 > data_end) + return NULL; + ihl_len = iph->ihl * 4; + proto = iph->protocol; + *ipv4 = true; + result = (struct bpf_sock_tuple *)&iph->saddr; + } else if (eth_proto == bpf_htons(ETH_P_IPV6)) { + struct ipv6hdr *ip6h = (struct ipv6hdr *)(data + nh_off); + + if (ip6h + 1 > data_end) + return NULL; + ihl_len = sizeof(*ip6h); + proto = ip6h->nexthdr; + *ipv4 = true; + result = (struct bpf_sock_tuple *)&ip6h->saddr; + } + + if (data + nh_off + ihl_len > data_end || proto != IPPROTO_TCP) + return NULL; + + return result; +} + +SEC("sk_lookup_success") +int bpf_sk_lookup_test0(struct __sk_buff *skb) +{ + void *data_end = (void *)(long)skb->data_end; + void *data = (void *)(long)skb->data; + struct ethhdr *eth = (struct ethhdr *)(data); + struct bpf_sock_tuple *tuple; + struct bpf_sock *sk; + size_t tuple_len; + bool ipv4; + + if (eth + 1 > data_end) + return TC_ACT_SHOT; + + tuple = get_tuple(data, sizeof(*eth), data_end, eth->h_proto, &ipv4); + if (!tuple || tuple + sizeof *tuple > data_end) + return TC_ACT_SHOT; + + tuple_len = ipv4 ? sizeof(tuple->ipv4) : sizeof(tuple->ipv6); + sk = bpf_sk_lookup_tcp(skb, tuple, tuple_len, BPF_F_CURRENT_NETNS, 0); + if (sk) + bpf_sk_release(sk); + return sk ? TC_ACT_OK : TC_ACT_UNSPEC; +} + +SEC("sk_lookup_success_simple") +int bpf_sk_lookup_test1(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + struct bpf_sock *sk; + + sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); + if (sk) + bpf_sk_release(sk); + return 0; +} + +SEC("fail_use_after_free") +int bpf_sk_lookup_uaf(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + struct bpf_sock *sk; + __u32 family = 0; + + sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); + if (sk) { + bpf_sk_release(sk); + family = sk->family; + } + return family; +} + +SEC("fail_modify_sk_pointer") +int bpf_sk_lookup_modptr(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + struct bpf_sock *sk; + __u32 family; + + sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); + if (sk) { + sk += 1; + bpf_sk_release(sk); + } + return 0; +} + +SEC("fail_modify_sk_or_null_pointer") +int bpf_sk_lookup_modptr_or_null(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + struct bpf_sock *sk; + __u32 family; + + sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); + sk += 1; + if (sk) + bpf_sk_release(sk); + return 0; +} + +SEC("fail_no_release") +int bpf_sk_lookup_test2(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + + bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); + return 0; +} + +SEC("fail_release_twice") +int bpf_sk_lookup_test3(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + struct bpf_sock *sk; + + sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); + bpf_sk_release(sk); + bpf_sk_release(sk); + return 0; +} + +SEC("fail_release_unchecked") +int bpf_sk_lookup_test4(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + struct bpf_sock *sk; + + sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); + bpf_sk_release(sk); + return 0; +} + +void lookup_no_release(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); +} + +SEC("fail_no_release_subcall") +int bpf_sk_lookup_test5(struct __sk_buff *skb) +{ + lookup_no_release(skb); + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/test_skb_cgroup_id_kern.c b/tools/testing/selftests/bpf/progs/test_skb_cgroup_id_kern.c new file mode 100644 index 000000000000..68cf9829f5a7 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_skb_cgroup_id_kern.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include + +#include + +#include "bpf_helpers.h" + +#define NUM_CGROUP_LEVELS 4 + +struct bpf_map_def SEC("maps") cgroup_ids = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u64), + .max_entries = NUM_CGROUP_LEVELS, +}; + +static __always_inline void log_nth_level(struct __sk_buff *skb, __u32 level) +{ + __u64 id; + + /* [1] &level passed to external function that may change it, it's + * incompatible with loop unroll. + */ + id = bpf_skb_ancestor_cgroup_id(skb, level); + bpf_map_update_elem(&cgroup_ids, &level, &id, 0); +} + +SEC("cgroup_id_logger") +int log_cgroup_id(struct __sk_buff *skb) +{ + /* Loop unroll can't be used here due to [1]. Unrolling manually. + * Number of calls should be in sync with NUM_CGROUP_LEVELS. + */ + log_nth_level(skb, 0); + log_nth_level(skb, 1); + log_nth_level(skb, 2); + log_nth_level(skb, 3); + + return TC_ACT_OK; +} + +int _version SEC("version") = 1; + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_sock_fields_kern.c b/tools/testing/selftests/bpf/progs/test_sock_fields_kern.c new file mode 100644 index 000000000000..de1a43e8f610 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_sock_fields_kern.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019 Facebook */ + +#include +#include +#include + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +enum bpf_array_idx { + SRV_IDX, + CLI_IDX, + __NR_BPF_ARRAY_IDX, +}; + +struct bpf_map_def SEC("maps") addr_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct sockaddr_in6), + .max_entries = __NR_BPF_ARRAY_IDX, +}; + +struct bpf_map_def SEC("maps") sock_result_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct bpf_sock), + .max_entries = __NR_BPF_ARRAY_IDX, +}; + +struct bpf_map_def SEC("maps") tcp_sock_result_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct bpf_tcp_sock), + .max_entries = __NR_BPF_ARRAY_IDX, +}; + +struct bpf_map_def SEC("maps") linum_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 1, +}; + +static bool is_loopback6(__u32 *a6) +{ + return !a6[0] && !a6[1] && !a6[2] && a6[3] == bpf_htonl(1); +} + +static void skcpy(struct bpf_sock *dst, + const struct bpf_sock *src) +{ + dst->bound_dev_if = src->bound_dev_if; + dst->family = src->family; + dst->type = src->type; + dst->protocol = src->protocol; + dst->mark = src->mark; + dst->priority = src->priority; + dst->src_ip4 = src->src_ip4; + dst->src_ip6[0] = src->src_ip6[0]; + dst->src_ip6[1] = src->src_ip6[1]; + dst->src_ip6[2] = src->src_ip6[2]; + dst->src_ip6[3] = src->src_ip6[3]; + dst->src_port = src->src_port; + dst->dst_ip4 = src->dst_ip4; + dst->dst_ip6[0] = src->dst_ip6[0]; + dst->dst_ip6[1] = src->dst_ip6[1]; + dst->dst_ip6[2] = src->dst_ip6[2]; + dst->dst_ip6[3] = src->dst_ip6[3]; + dst->dst_port = src->dst_port; + dst->state = src->state; +} + +static void tpcpy(struct bpf_tcp_sock *dst, + const struct bpf_tcp_sock *src) +{ + dst->snd_cwnd = src->snd_cwnd; + dst->srtt_us = src->srtt_us; + dst->rtt_min = src->rtt_min; + dst->snd_ssthresh = src->snd_ssthresh; + dst->rcv_nxt = src->rcv_nxt; + dst->snd_nxt = src->snd_nxt; + dst->snd_una = src->snd_una; + dst->mss_cache = src->mss_cache; + dst->ecn_flags = src->ecn_flags; + dst->rate_delivered = src->rate_delivered; + dst->rate_interval_us = src->rate_interval_us; + dst->packets_out = src->packets_out; + dst->retrans_out = src->retrans_out; + dst->total_retrans = src->total_retrans; + dst->segs_in = src->segs_in; + dst->data_segs_in = src->data_segs_in; + dst->segs_out = src->segs_out; + dst->data_segs_out = src->data_segs_out; + dst->lost_out = src->lost_out; + dst->sacked_out = src->sacked_out; + dst->bytes_received = src->bytes_received; + dst->bytes_acked = src->bytes_acked; +} + +#define RETURN { \ + linum = __LINE__; \ + bpf_map_update_elem(&linum_map, &idx0, &linum, 0); \ + return 1; \ +} + +SEC("cgroup_skb/egress") +int read_sock_fields(struct __sk_buff *skb) +{ + __u32 srv_idx = SRV_IDX, cli_idx = CLI_IDX, idx; + struct sockaddr_in6 *srv_sa6, *cli_sa6; + struct bpf_tcp_sock *tp, *tp_ret; + struct bpf_sock *sk, *sk_ret; + __u32 linum, idx0 = 0; + + sk = skb->sk; + if (!sk || sk->state == 10) + RETURN; + + sk = bpf_sk_fullsock(sk); + if (!sk || sk->family != AF_INET6 || sk->protocol != IPPROTO_TCP || + !is_loopback6(sk->src_ip6)) + RETURN; + + tp = bpf_tcp_sock(sk); + if (!tp) + RETURN; + + srv_sa6 = bpf_map_lookup_elem(&addr_map, &srv_idx); + cli_sa6 = bpf_map_lookup_elem(&addr_map, &cli_idx); + if (!srv_sa6 || !cli_sa6) + RETURN; + + if (sk->src_port == bpf_ntohs(srv_sa6->sin6_port)) + idx = srv_idx; + else if (sk->src_port == bpf_ntohs(cli_sa6->sin6_port)) + idx = cli_idx; + else + RETURN; + + sk_ret = bpf_map_lookup_elem(&sock_result_map, &idx); + tp_ret = bpf_map_lookup_elem(&tcp_sock_result_map, &idx); + if (!sk_ret || !tp_ret) + RETURN; + + skcpy(sk_ret, sk); + tpcpy(tp_ret, tp); + + RETURN; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_sockhash_kern.c b/tools/testing/selftests/bpf/progs/test_sockhash_kern.c new file mode 100644 index 000000000000..e6755916442a --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_sockhash_kern.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Covalent IO, Inc. http://covalent.io +#undef SOCKMAP +#define TEST_MAP_TYPE BPF_MAP_TYPE_SOCKHASH +#include "./test_sockmap_kern.h" diff --git a/tools/testing/selftests/bpf/progs/test_sockmap_kern.c b/tools/testing/selftests/bpf/progs/test_sockmap_kern.c new file mode 100644 index 000000000000..677b2ed1cc1e --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_sockmap_kern.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Covalent IO, Inc. http://covalent.io +#define SOCKMAP +#define TEST_MAP_TYPE BPF_MAP_TYPE_SOCKMAP +#include "./test_sockmap_kern.h" diff --git a/tools/testing/selftests/bpf/progs/test_spin_lock.c b/tools/testing/selftests/bpf/progs/test_spin_lock.c new file mode 100644 index 000000000000..40f904312090 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_spin_lock.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Facebook +#include +#include +#include "bpf_helpers.h" + +struct hmap_elem { + volatile int cnt; + struct bpf_spin_lock lock; + int test_padding; +}; + +struct bpf_map_def SEC("maps") hmap = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(int), + .value_size = sizeof(struct hmap_elem), + .max_entries = 1, +}; + +BPF_ANNOTATE_KV_PAIR(hmap, int, struct hmap_elem); + + +struct cls_elem { + struct bpf_spin_lock lock; + volatile int cnt; +}; + +struct bpf_map_def SEC("maps") cls_map = { + .type = BPF_MAP_TYPE_CGROUP_STORAGE, + .key_size = sizeof(struct bpf_cgroup_storage_key), + .value_size = sizeof(struct cls_elem), +}; + +BPF_ANNOTATE_KV_PAIR(cls_map, struct bpf_cgroup_storage_key, + struct cls_elem); + +struct bpf_vqueue { + struct bpf_spin_lock lock; + /* 4 byte hole */ + unsigned long long lasttime; + int credit; + unsigned int rate; +}; + +struct bpf_map_def SEC("maps") vqueue = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(struct bpf_vqueue), + .max_entries = 1, +}; + +BPF_ANNOTATE_KV_PAIR(vqueue, int, struct bpf_vqueue); +#define CREDIT_PER_NS(delta, rate) (((delta) * rate) >> 20) + +SEC("spin_lock_demo") +int bpf_sping_lock_test(struct __sk_buff *skb) +{ + volatile int credit = 0, max_credit = 100, pkt_len = 64; + struct hmap_elem zero = {}, *val; + unsigned long long curtime; + struct bpf_vqueue *q; + struct cls_elem *cls; + int key = 0; + int err = 0; + + val = bpf_map_lookup_elem(&hmap, &key); + if (!val) { + bpf_map_update_elem(&hmap, &key, &zero, 0); + val = bpf_map_lookup_elem(&hmap, &key); + if (!val) { + err = 1; + goto err; + } + } + /* spin_lock in hash map run time test */ + bpf_spin_lock(&val->lock); + if (val->cnt) + val->cnt--; + else + val->cnt++; + if (val->cnt != 0 && val->cnt != 1) + err = 1; + bpf_spin_unlock(&val->lock); + + /* spin_lock in array. virtual queue demo */ + q = bpf_map_lookup_elem(&vqueue, &key); + if (!q) + goto err; + curtime = bpf_ktime_get_ns(); + bpf_spin_lock(&q->lock); + q->credit += CREDIT_PER_NS(curtime - q->lasttime, q->rate); + q->lasttime = curtime; + if (q->credit > max_credit) + q->credit = max_credit; + q->credit -= pkt_len; + credit = q->credit; + bpf_spin_unlock(&q->lock); + + /* spin_lock in cgroup local storage */ + cls = bpf_get_local_storage(&cls_map, 0); + bpf_spin_lock(&cls->lock); + cls->cnt++; + bpf_spin_unlock(&cls->lock); + +err: + return err; +} +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_stack_map.c b/tools/testing/selftests/bpf/progs/test_stack_map.c new file mode 100644 index 000000000000..31c3880e6da0 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_stack_map.c @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Politecnico di Torino +#define MAP_TYPE BPF_MAP_TYPE_STACK +#include "test_queue_stack_map.h" diff --git a/tools/testing/selftests/bpf/progs/test_stacktrace_build_id.c b/tools/testing/selftests/bpf/progs/test_stacktrace_build_id.c new file mode 100644 index 000000000000..d86c281e957f --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_stacktrace_build_id.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include "bpf_helpers.h" + +#ifndef PERF_MAX_STACK_DEPTH +#define PERF_MAX_STACK_DEPTH 127 +#endif + +struct bpf_map_def SEC("maps") control_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") stackid_hmap = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 16384, +}; + +struct bpf_map_def SEC("maps") stackmap = { + .type = BPF_MAP_TYPE_STACK_TRACE, + .key_size = sizeof(__u32), + .value_size = sizeof(struct bpf_stack_build_id) + * PERF_MAX_STACK_DEPTH, + .max_entries = 128, + .map_flags = BPF_F_STACK_BUILD_ID, +}; + +struct bpf_map_def SEC("maps") stack_amap = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct bpf_stack_build_id) + * PERF_MAX_STACK_DEPTH, + .max_entries = 128, +}; + +/* taken from /sys/kernel/debug/tracing/events/random/urandom_read/format */ +struct random_urandom_args { + unsigned long long pad; + int got_bits; + int pool_left; + int input_left; +}; + +SEC("tracepoint/random/urandom_read") +int oncpu(struct random_urandom_args *args) +{ + __u32 max_len = sizeof(struct bpf_stack_build_id) + * PERF_MAX_STACK_DEPTH; + __u32 key = 0, val = 0, *value_p; + void *stack_p; + + value_p = bpf_map_lookup_elem(&control_map, &key); + if (value_p && *value_p) + return 0; /* skip if non-zero *value_p */ + + /* The size of stackmap and stackid_hmap should be the same */ + key = bpf_get_stackid(args, &stackmap, BPF_F_USER_STACK); + if ((int)key >= 0) { + bpf_map_update_elem(&stackid_hmap, &key, &val, 0); + stack_p = bpf_map_lookup_elem(&stack_amap, &key); + if (stack_p) + bpf_get_stack(args, stack_p, max_len, + BPF_F_USER_STACK | BPF_F_USER_BUILD_ID); + } + + return 0; +} + +char _license[] SEC("license") = "GPL"; +__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/progs/test_stacktrace_map.c b/tools/testing/selftests/bpf/progs/test_stacktrace_map.c new file mode 100644 index 000000000000..af111af7ca1a --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_stacktrace_map.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include "bpf_helpers.h" + +#ifndef PERF_MAX_STACK_DEPTH +#define PERF_MAX_STACK_DEPTH 127 +#endif + +struct bpf_map_def SEC("maps") control_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") stackid_hmap = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 16384, +}; + +struct bpf_map_def SEC("maps") stackmap = { + .type = BPF_MAP_TYPE_STACK_TRACE, + .key_size = sizeof(__u32), + .value_size = sizeof(__u64) * PERF_MAX_STACK_DEPTH, + .max_entries = 16384, +}; + +struct bpf_map_def SEC("maps") stack_amap = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u64) * PERF_MAX_STACK_DEPTH, + .max_entries = 16384, +}; + +/* taken from /sys/kernel/debug/tracing/events/sched/sched_switch/format */ +struct sched_switch_args { + unsigned long long pad; + char prev_comm[16]; + int prev_pid; + int prev_prio; + long long prev_state; + char next_comm[16]; + int next_pid; + int next_prio; +}; + +SEC("tracepoint/sched/sched_switch") +int oncpu(struct sched_switch_args *ctx) +{ + __u32 max_len = PERF_MAX_STACK_DEPTH * sizeof(__u64); + __u32 key = 0, val = 0, *value_p; + void *stack_p; + + value_p = bpf_map_lookup_elem(&control_map, &key); + if (value_p && *value_p) + return 0; /* skip if non-zero *value_p */ + + /* The size of stackmap and stackid_hmap should be the same */ + key = bpf_get_stackid(ctx, &stackmap, 0); + if ((int)key >= 0) { + bpf_map_update_elem(&stackid_hmap, &key, &val, 0); + stack_p = bpf_map_lookup_elem(&stack_amap, &key); + if (stack_p) + bpf_get_stack(ctx, stack_p, max_len, 0); + } + + return 0; +} + +char _license[] SEC("license") = "GPL"; +__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/progs/test_tcp_estats.c b/tools/testing/selftests/bpf/progs/test_tcp_estats.c new file mode 100644 index 000000000000..bee3bbecc0c4 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_tcp_estats.c @@ -0,0 +1,258 @@ +/* Copyright (c) 2017 Facebook + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ + +/* This program shows clang/llvm is able to generate code pattern + * like: + * _tcp_send_active_reset: + * 0: bf 16 00 00 00 00 00 00 r6 = r1 + * ...... + * 335: b7 01 00 00 0f 00 00 00 r1 = 15 + * 336: 05 00 48 00 00 00 00 00 goto 72 + * + * LBB0_3: + * 337: b7 01 00 00 01 00 00 00 r1 = 1 + * 338: 63 1a d0 ff 00 00 00 00 *(u32 *)(r10 - 48) = r1 + * 408: b7 01 00 00 03 00 00 00 r1 = 3 + * + * LBB0_4: + * 409: 71 a2 fe ff 00 00 00 00 r2 = *(u8 *)(r10 - 2) + * 410: bf a7 00 00 00 00 00 00 r7 = r10 + * 411: 07 07 00 00 b8 ff ff ff r7 += -72 + * 412: bf 73 00 00 00 00 00 00 r3 = r7 + * 413: 0f 13 00 00 00 00 00 00 r3 += r1 + * 414: 73 23 2d 00 00 00 00 00 *(u8 *)(r3 + 45) = r2 + * + * From the above code snippet, the code generated by the compiler + * is reasonable. The "r1" is assigned to different values in basic + * blocks "_tcp_send_active_reset" and "LBB0_3", and used in "LBB0_4". + * The verifier should be able to handle such code patterns. + */ +#include +#include +#include +#include +#include +#include "bpf_helpers.h" + +#define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;}) +#define TCP_ESTATS_MAGIC 0xBAADBEEF + +/* This test case needs "sock" and "pt_regs" data structure. + * Recursively, "sock" needs "sock_common" and "inet_sock". + * However, this is a unit test case only for + * verifier purpose without bpf program execution. + * We can safely mock much simpler data structures, basically + * only taking the necessary fields from kernel headers. + */ +typedef __u32 __bitwise __portpair; +typedef __u64 __bitwise __addrpair; + +struct sock_common { + unsigned short skc_family; + union { + __addrpair skc_addrpair; + struct { + __be32 skc_daddr; + __be32 skc_rcv_saddr; + }; + }; + union { + __portpair skc_portpair; + struct { + __be16 skc_dport; + __u16 skc_num; + }; + }; + struct in6_addr skc_v6_daddr; + struct in6_addr skc_v6_rcv_saddr; +}; + +struct sock { + struct sock_common __sk_common; +#define sk_family __sk_common.skc_family +#define sk_v6_daddr __sk_common.skc_v6_daddr +#define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr +}; + +struct inet_sock { + struct sock sk; +#define inet_daddr sk.__sk_common.skc_daddr +#define inet_dport sk.__sk_common.skc_dport + __be32 inet_saddr; + __be16 inet_sport; +}; + +struct pt_regs { + long di; +}; + +static inline struct inet_sock *inet_sk(const struct sock *sk) +{ + return (struct inet_sock *)sk; +} + +/* Define various data structures for state recording. + * Some fields are not used due to test simplification. + */ +enum tcp_estats_addrtype { + TCP_ESTATS_ADDRTYPE_IPV4 = 1, + TCP_ESTATS_ADDRTYPE_IPV6 = 2 +}; + +enum tcp_estats_event_type { + TCP_ESTATS_ESTABLISH, + TCP_ESTATS_PERIODIC, + TCP_ESTATS_TIMEOUT, + TCP_ESTATS_RETRANSMIT_TIMEOUT, + TCP_ESTATS_RETRANSMIT_OTHER, + TCP_ESTATS_SYN_RETRANSMIT, + TCP_ESTATS_SYNACK_RETRANSMIT, + TCP_ESTATS_TERM, + TCP_ESTATS_TX_RESET, + TCP_ESTATS_RX_RESET, + TCP_ESTATS_WRITE_TIMEOUT, + TCP_ESTATS_CONN_TIMEOUT, + TCP_ESTATS_ACK_LATENCY, + TCP_ESTATS_NEVENTS, +}; + +struct tcp_estats_event { + int pid; + int cpu; + unsigned long ts; + unsigned int magic; + enum tcp_estats_event_type event_type; +}; + +/* The below data structure is packed in order for + * llvm compiler to generate expected code. + */ +struct tcp_estats_conn_id { + unsigned int localaddressType; + struct { + unsigned char data[16]; + } localaddress; + struct { + unsigned char data[16]; + } remaddress; + unsigned short localport; + unsigned short remport; +} __attribute__((__packed__)); + +struct tcp_estats_basic_event { + struct tcp_estats_event event; + struct tcp_estats_conn_id conn_id; +}; + +struct bpf_map_def SEC("maps") ev_record_map = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(__u32), + .value_size = sizeof(struct tcp_estats_basic_event), + .max_entries = 1024, +}; + +struct dummy_tracepoint_args { + unsigned long long pad; + struct sock *sock; +}; + +static __always_inline void tcp_estats_ev_init(struct tcp_estats_event *event, + enum tcp_estats_event_type type) +{ + event->magic = TCP_ESTATS_MAGIC; + event->ts = bpf_ktime_get_ns(); + event->event_type = type; +} + +static __always_inline void unaligned_u32_set(unsigned char *to, __u8 *from) +{ + to[0] = _(from[0]); + to[1] = _(from[1]); + to[2] = _(from[2]); + to[3] = _(from[3]); +} + +static __always_inline void conn_id_ipv4_init(struct tcp_estats_conn_id *conn_id, + __be32 *saddr, __be32 *daddr) +{ + conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV4; + + unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr); + unaligned_u32_set(conn_id->remaddress.data, (__u8 *)daddr); +} + +static __always_inline void conn_id_ipv6_init(struct tcp_estats_conn_id *conn_id, + __be32 *saddr, __be32 *daddr) +{ + conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV6; + + unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr); + unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32), + (__u8 *)(saddr + 1)); + unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 2, + (__u8 *)(saddr + 2)); + unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 3, + (__u8 *)(saddr + 3)); + + unaligned_u32_set(conn_id->remaddress.data, + (__u8 *)(daddr)); + unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32), + (__u8 *)(daddr + 1)); + unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 2, + (__u8 *)(daddr + 2)); + unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 3, + (__u8 *)(daddr + 3)); +} + +static __always_inline void tcp_estats_conn_id_init(struct tcp_estats_conn_id *conn_id, + struct sock *sk) +{ + conn_id->localport = _(inet_sk(sk)->inet_sport); + conn_id->remport = _(inet_sk(sk)->inet_dport); + + if (_(sk->sk_family) == AF_INET6) + conn_id_ipv6_init(conn_id, + sk->sk_v6_rcv_saddr.s6_addr32, + sk->sk_v6_daddr.s6_addr32); + else + conn_id_ipv4_init(conn_id, + &inet_sk(sk)->inet_saddr, + &inet_sk(sk)->inet_daddr); +} + +static __always_inline void tcp_estats_init(struct sock *sk, + struct tcp_estats_event *event, + struct tcp_estats_conn_id *conn_id, + enum tcp_estats_event_type type) +{ + tcp_estats_ev_init(event, type); + tcp_estats_conn_id_init(conn_id, sk); +} + +static __always_inline void send_basic_event(struct sock *sk, + enum tcp_estats_event_type type) +{ + struct tcp_estats_basic_event ev; + __u32 key = bpf_get_prandom_u32(); + + memset(&ev, 0, sizeof(ev)); + tcp_estats_init(sk, &ev.event, &ev.conn_id, type); + bpf_map_update_elem(&ev_record_map, &key, &ev, BPF_ANY); +} + +SEC("dummy_tracepoint") +int _dummy_tracepoint(struct dummy_tracepoint_args *arg) +{ + if (!arg->sock) + return 0; + + send_basic_event(arg->sock, TCP_ESTATS_TX_RESET); + return 0; +} + +char _license[] SEC("license") = "GPL"; +__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c b/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c new file mode 100644 index 000000000000..74f73b33a7b0 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "bpf_endian.h" +#include "test_tcpbpf.h" + +struct bpf_map_def SEC("maps") global_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct tcpbpf_globals), + .max_entries = 4, +}; + +struct bpf_map_def SEC("maps") sockopt_results = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(int), + .max_entries = 2, +}; + +static inline void update_event_map(int event) +{ + __u32 key = 0; + struct tcpbpf_globals g, *gp; + + gp = bpf_map_lookup_elem(&global_map, &key); + if (gp == NULL) { + struct tcpbpf_globals g = {0}; + + g.event_map |= (1 << event); + bpf_map_update_elem(&global_map, &key, &g, + BPF_ANY); + } else { + g = *gp; + g.event_map |= (1 << event); + bpf_map_update_elem(&global_map, &key, &g, + BPF_ANY); + } +} + +int _version SEC("version") = 1; + +SEC("sockops") +int bpf_testcb(struct bpf_sock_ops *skops) +{ + char header[sizeof(struct ipv6hdr) + sizeof(struct tcphdr)]; + struct tcphdr *thdr; + int good_call_rv = 0; + int bad_call_rv = 0; + int save_syn = 1; + int rv = -1; + int v = 0; + int op; + + op = (int) skops->op; + + update_event_map(op); + + switch (op) { + case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: + /* Test failure to set largest cb flag (assumes not defined) */ + bad_call_rv = bpf_sock_ops_cb_flags_set(skops, 0x80); + /* Set callback */ + good_call_rv = bpf_sock_ops_cb_flags_set(skops, + BPF_SOCK_OPS_STATE_CB_FLAG); + /* Update results */ + { + __u32 key = 0; + struct tcpbpf_globals g, *gp; + + gp = bpf_map_lookup_elem(&global_map, &key); + if (!gp) + break; + g = *gp; + g.bad_cb_test_rv = bad_call_rv; + g.good_cb_test_rv = good_call_rv; + bpf_map_update_elem(&global_map, &key, &g, + BPF_ANY); + } + break; + case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: + skops->sk_txhash = 0x12345f; + v = 0xff; + rv = bpf_setsockopt(skops, SOL_IPV6, IPV6_TCLASS, &v, + sizeof(v)); + if (skops->family == AF_INET6) { + v = bpf_getsockopt(skops, IPPROTO_TCP, TCP_SAVED_SYN, + header, (sizeof(struct ipv6hdr) + + sizeof(struct tcphdr))); + if (!v) { + int offset = sizeof(struct ipv6hdr); + + thdr = (struct tcphdr *)(header + offset); + v = thdr->syn; + __u32 key = 1; + + bpf_map_update_elem(&sockopt_results, &key, &v, + BPF_ANY); + } + } + break; + case BPF_SOCK_OPS_RTO_CB: + break; + case BPF_SOCK_OPS_RETRANS_CB: + break; + case BPF_SOCK_OPS_STATE_CB: + if (skops->args[1] == BPF_TCP_CLOSE) { + __u32 key = 0; + struct tcpbpf_globals g, *gp; + + gp = bpf_map_lookup_elem(&global_map, &key); + if (!gp) + break; + g = *gp; + if (skops->args[0] == BPF_TCP_LISTEN) { + g.num_listen++; + } else { + g.total_retrans = skops->total_retrans; + g.data_segs_in = skops->data_segs_in; + g.data_segs_out = skops->data_segs_out; + g.bytes_received = skops->bytes_received; + g.bytes_acked = skops->bytes_acked; + } + bpf_map_update_elem(&global_map, &key, &g, + BPF_ANY); + } + break; + case BPF_SOCK_OPS_TCP_LISTEN_CB: + bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG); + v = bpf_setsockopt(skops, IPPROTO_TCP, TCP_SAVE_SYN, + &save_syn, sizeof(save_syn)); + /* Update global map w/ result of setsock opt */ + __u32 key = 0; + + bpf_map_update_elem(&sockopt_results, &key, &v, BPF_ANY); + break; + default: + rv = -1; + } + skops->reply = rv; + return 1; +} +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_tcpnotify_kern.c b/tools/testing/selftests/bpf/progs/test_tcpnotify_kern.c new file mode 100644 index 000000000000..edbca203ce2d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_tcpnotify_kern.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "bpf_endian.h" +#include "test_tcpnotify.h" + +struct bpf_map_def SEC("maps") global_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct tcpnotify_globals), + .max_entries = 4, +}; + +struct bpf_map_def SEC("maps") perf_event_map = { + .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(__u32), + .max_entries = 2, +}; + +int _version SEC("version") = 1; + +SEC("sockops") +int bpf_testcb(struct bpf_sock_ops *skops) +{ + int rv = -1; + int op; + + op = (int) skops->op; + + if (bpf_ntohl(skops->remote_port) != TESTPORT) { + skops->reply = -1; + return 0; + } + + switch (op) { + case BPF_SOCK_OPS_TIMEOUT_INIT: + case BPF_SOCK_OPS_RWND_INIT: + case BPF_SOCK_OPS_NEEDS_ECN: + case BPF_SOCK_OPS_BASE_RTT: + case BPF_SOCK_OPS_RTO_CB: + rv = 1; + break; + + case BPF_SOCK_OPS_TCP_CONNECT_CB: + case BPF_SOCK_OPS_TCP_LISTEN_CB: + case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: + case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: + bpf_sock_ops_cb_flags_set(skops, (BPF_SOCK_OPS_RETRANS_CB_FLAG| + BPF_SOCK_OPS_RTO_CB_FLAG)); + rv = 1; + break; + case BPF_SOCK_OPS_RETRANS_CB: { + __u32 key = 0; + struct tcpnotify_globals g, *gp; + struct tcp_notifier msg = { + .type = 0xde, + .subtype = 0xad, + .source = 0xbe, + .hash = 0xef, + }; + + rv = 1; + + /* Update results */ + gp = bpf_map_lookup_elem(&global_map, &key); + if (!gp) + break; + g = *gp; + g.total_retrans = skops->total_retrans; + g.ncalls++; + bpf_map_update_elem(&global_map, &key, &g, + BPF_ANY); + bpf_perf_event_output(skops, &perf_event_map, + BPF_F_CURRENT_CPU, + &msg, sizeof(msg)); + } + break; + default: + rv = -1; + } + skops->reply = rv; + return 1; +} +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_tracepoint.c b/tools/testing/selftests/bpf/progs/test_tracepoint.c new file mode 100644 index 000000000000..04bf084517e0 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_tracepoint.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Facebook + +#include +#include "bpf_helpers.h" + +/* taken from /sys/kernel/debug/tracing/events/sched/sched_switch/format */ +struct sched_switch_args { + unsigned long long pad; + char prev_comm[16]; + int prev_pid; + int prev_prio; + long long prev_state; + char next_comm[16]; + int next_pid; + int next_prio; +}; + +SEC("tracepoint/sched/sched_switch") +int oncpu(struct sched_switch_args *ctx) +{ + return 0; +} + +char _license[] SEC("license") = "GPL"; +__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/progs/test_tunnel_kern.c b/tools/testing/selftests/bpf/progs/test_tunnel_kern.c new file mode 100644 index 000000000000..504df69c83df --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_tunnel_kern.c @@ -0,0 +1,713 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2016 VMware + * Copyright (c) 2016 Facebook + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define ERROR(ret) do {\ + char fmt[] = "ERROR line:%d ret:%d\n";\ + bpf_trace_printk(fmt, sizeof(fmt), __LINE__, ret); \ + } while (0) + +int _version SEC("version") = 1; + +struct geneve_opt { + __be16 opt_class; + __u8 type; + __u8 length:5; + __u8 r3:1; + __u8 r2:1; + __u8 r1:1; + __u8 opt_data[8]; /* hard-coded to 8 byte */ +}; + +struct vxlan_metadata { + __u32 gbp; +}; + +SEC("gre_set_tunnel") +int _gre_set_tunnel(struct __sk_buff *skb) +{ + int ret; + struct bpf_tunnel_key key; + + __builtin_memset(&key, 0x0, sizeof(key)); + key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ + key.tunnel_id = 2; + key.tunnel_tos = 0; + key.tunnel_ttl = 64; + + ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), + BPF_F_ZERO_CSUM_TX | BPF_F_SEQ_NUMBER); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + return TC_ACT_OK; +} + +SEC("gre_get_tunnel") +int _gre_get_tunnel(struct __sk_buff *skb) +{ + int ret; + struct bpf_tunnel_key key; + char fmt[] = "key %d remote ip 0x%x\n"; + + ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + bpf_trace_printk(fmt, sizeof(fmt), key.tunnel_id, key.remote_ipv4); + return TC_ACT_OK; +} + +SEC("ip6gretap_set_tunnel") +int _ip6gretap_set_tunnel(struct __sk_buff *skb) +{ + struct bpf_tunnel_key key; + int ret; + + __builtin_memset(&key, 0x0, sizeof(key)); + key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */ + key.tunnel_id = 2; + key.tunnel_tos = 0; + key.tunnel_ttl = 64; + key.tunnel_label = 0xabcde; + + ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), + BPF_F_TUNINFO_IPV6 | BPF_F_ZERO_CSUM_TX | + BPF_F_SEQ_NUMBER); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + return TC_ACT_OK; +} + +SEC("ip6gretap_get_tunnel") +int _ip6gretap_get_tunnel(struct __sk_buff *skb) +{ + char fmt[] = "key %d remote ip6 ::%x label %x\n"; + struct bpf_tunnel_key key; + int ret; + + ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), + BPF_F_TUNINFO_IPV6); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + bpf_trace_printk(fmt, sizeof(fmt), + key.tunnel_id, key.remote_ipv6[3], key.tunnel_label); + + return TC_ACT_OK; +} + +SEC("erspan_set_tunnel") +int _erspan_set_tunnel(struct __sk_buff *skb) +{ + struct bpf_tunnel_key key; + struct erspan_metadata md; + int ret; + + __builtin_memset(&key, 0x0, sizeof(key)); + key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ + key.tunnel_id = 2; + key.tunnel_tos = 0; + key.tunnel_ttl = 64; + + ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), + BPF_F_ZERO_CSUM_TX); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + __builtin_memset(&md, 0, sizeof(md)); +#ifdef ERSPAN_V1 + md.version = 1; + md.u.index = bpf_htonl(123); +#else + __u8 direction = 1; + __u8 hwid = 7; + + md.version = 2; + md.u.md2.dir = direction; + md.u.md2.hwid = hwid & 0xf; + md.u.md2.hwid_upper = (hwid >> 4) & 0x3; +#endif + + ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md)); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + return TC_ACT_OK; +} + +SEC("erspan_get_tunnel") +int _erspan_get_tunnel(struct __sk_buff *skb) +{ + char fmt[] = "key %d remote ip 0x%x erspan version %d\n"; + struct bpf_tunnel_key key; + struct erspan_metadata md; + __u32 index; + int ret; + + ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md)); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + bpf_trace_printk(fmt, sizeof(fmt), + key.tunnel_id, key.remote_ipv4, md.version); + +#ifdef ERSPAN_V1 + char fmt2[] = "\tindex %x\n"; + + index = bpf_ntohl(md.u.index); + bpf_trace_printk(fmt2, sizeof(fmt2), index); +#else + char fmt2[] = "\tdirection %d hwid %x timestamp %u\n"; + + bpf_trace_printk(fmt2, sizeof(fmt2), + md.u.md2.dir, + (md.u.md2.hwid_upper << 4) + md.u.md2.hwid, + bpf_ntohl(md.u.md2.timestamp)); +#endif + + return TC_ACT_OK; +} + +SEC("ip4ip6erspan_set_tunnel") +int _ip4ip6erspan_set_tunnel(struct __sk_buff *skb) +{ + struct bpf_tunnel_key key; + struct erspan_metadata md; + int ret; + + __builtin_memset(&key, 0x0, sizeof(key)); + key.remote_ipv6[3] = bpf_htonl(0x11); + key.tunnel_id = 2; + key.tunnel_tos = 0; + key.tunnel_ttl = 64; + + ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), + BPF_F_TUNINFO_IPV6); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + __builtin_memset(&md, 0, sizeof(md)); + +#ifdef ERSPAN_V1 + md.u.index = bpf_htonl(123); + md.version = 1; +#else + __u8 direction = 0; + __u8 hwid = 17; + + md.version = 2; + md.u.md2.dir = direction; + md.u.md2.hwid = hwid & 0xf; + md.u.md2.hwid_upper = (hwid >> 4) & 0x3; +#endif + + ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md)); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + return TC_ACT_OK; +} + +SEC("ip4ip6erspan_get_tunnel") +int _ip4ip6erspan_get_tunnel(struct __sk_buff *skb) +{ + char fmt[] = "ip6erspan get key %d remote ip6 ::%x erspan version %d\n"; + struct bpf_tunnel_key key; + struct erspan_metadata md; + __u32 index; + int ret; + + ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), + BPF_F_TUNINFO_IPV6); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md)); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + bpf_trace_printk(fmt, sizeof(fmt), + key.tunnel_id, key.remote_ipv4, md.version); + +#ifdef ERSPAN_V1 + char fmt2[] = "\tindex %x\n"; + + index = bpf_ntohl(md.u.index); + bpf_trace_printk(fmt2, sizeof(fmt2), index); +#else + char fmt2[] = "\tdirection %d hwid %x timestamp %u\n"; + + bpf_trace_printk(fmt2, sizeof(fmt2), + md.u.md2.dir, + (md.u.md2.hwid_upper << 4) + md.u.md2.hwid, + bpf_ntohl(md.u.md2.timestamp)); +#endif + + return TC_ACT_OK; +} + +SEC("vxlan_set_tunnel") +int _vxlan_set_tunnel(struct __sk_buff *skb) +{ + int ret; + struct bpf_tunnel_key key; + struct vxlan_metadata md; + + __builtin_memset(&key, 0x0, sizeof(key)); + key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ + key.tunnel_id = 2; + key.tunnel_tos = 0; + key.tunnel_ttl = 64; + + ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), + BPF_F_ZERO_CSUM_TX); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + md.gbp = 0x800FF; /* Set VXLAN Group Policy extension */ + ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md)); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + return TC_ACT_OK; +} + +SEC("vxlan_get_tunnel") +int _vxlan_get_tunnel(struct __sk_buff *skb) +{ + int ret; + struct bpf_tunnel_key key; + struct vxlan_metadata md; + char fmt[] = "key %d remote ip 0x%x vxlan gbp 0x%x\n"; + + ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md)); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + bpf_trace_printk(fmt, sizeof(fmt), + key.tunnel_id, key.remote_ipv4, md.gbp); + + return TC_ACT_OK; +} + +SEC("ip6vxlan_set_tunnel") +int _ip6vxlan_set_tunnel(struct __sk_buff *skb) +{ + struct bpf_tunnel_key key; + int ret; + + __builtin_memset(&key, 0x0, sizeof(key)); + key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */ + key.tunnel_id = 22; + key.tunnel_tos = 0; + key.tunnel_ttl = 64; + + ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), + BPF_F_TUNINFO_IPV6); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + return TC_ACT_OK; +} + +SEC("ip6vxlan_get_tunnel") +int _ip6vxlan_get_tunnel(struct __sk_buff *skb) +{ + char fmt[] = "key %d remote ip6 ::%x label %x\n"; + struct bpf_tunnel_key key; + int ret; + + ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), + BPF_F_TUNINFO_IPV6); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + bpf_trace_printk(fmt, sizeof(fmt), + key.tunnel_id, key.remote_ipv6[3], key.tunnel_label); + + return TC_ACT_OK; +} + +SEC("geneve_set_tunnel") +int _geneve_set_tunnel(struct __sk_buff *skb) +{ + int ret, ret2; + struct bpf_tunnel_key key; + struct geneve_opt gopt; + + __builtin_memset(&key, 0x0, sizeof(key)); + key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ + key.tunnel_id = 2; + key.tunnel_tos = 0; + key.tunnel_ttl = 64; + + __builtin_memset(&gopt, 0x0, sizeof(gopt)); + gopt.opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */ + gopt.type = 0x08; + gopt.r1 = 0; + gopt.r2 = 0; + gopt.r3 = 0; + gopt.length = 2; /* 4-byte multiple */ + *(int *) &gopt.opt_data = bpf_htonl(0xdeadbeef); + + ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), + BPF_F_ZERO_CSUM_TX); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + ret = bpf_skb_set_tunnel_opt(skb, &gopt, sizeof(gopt)); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + return TC_ACT_OK; +} + +SEC("geneve_get_tunnel") +int _geneve_get_tunnel(struct __sk_buff *skb) +{ + int ret; + struct bpf_tunnel_key key; + struct geneve_opt gopt; + char fmt[] = "key %d remote ip 0x%x geneve class 0x%x\n"; + + ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + ret = bpf_skb_get_tunnel_opt(skb, &gopt, sizeof(gopt)); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + bpf_trace_printk(fmt, sizeof(fmt), + key.tunnel_id, key.remote_ipv4, gopt.opt_class); + return TC_ACT_OK; +} + +SEC("ip6geneve_set_tunnel") +int _ip6geneve_set_tunnel(struct __sk_buff *skb) +{ + struct bpf_tunnel_key key; + struct geneve_opt gopt; + int ret; + + __builtin_memset(&key, 0x0, sizeof(key)); + key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */ + key.tunnel_id = 22; + key.tunnel_tos = 0; + key.tunnel_ttl = 64; + + ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), + BPF_F_TUNINFO_IPV6); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + __builtin_memset(&gopt, 0x0, sizeof(gopt)); + gopt.opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */ + gopt.type = 0x08; + gopt.r1 = 0; + gopt.r2 = 0; + gopt.r3 = 0; + gopt.length = 2; /* 4-byte multiple */ + *(int *) &gopt.opt_data = bpf_htonl(0xfeedbeef); + + ret = bpf_skb_set_tunnel_opt(skb, &gopt, sizeof(gopt)); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + return TC_ACT_OK; +} + +SEC("ip6geneve_get_tunnel") +int _ip6geneve_get_tunnel(struct __sk_buff *skb) +{ + char fmt[] = "key %d remote ip 0x%x geneve class 0x%x\n"; + struct bpf_tunnel_key key; + struct geneve_opt gopt; + int ret; + + ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), + BPF_F_TUNINFO_IPV6); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + ret = bpf_skb_get_tunnel_opt(skb, &gopt, sizeof(gopt)); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + bpf_trace_printk(fmt, sizeof(fmt), + key.tunnel_id, key.remote_ipv4, gopt.opt_class); + + return TC_ACT_OK; +} + +SEC("ipip_set_tunnel") +int _ipip_set_tunnel(struct __sk_buff *skb) +{ + struct bpf_tunnel_key key = {}; + void *data = (void *)(long)skb->data; + struct iphdr *iph = data; + struct tcphdr *tcp = data + sizeof(*iph); + void *data_end = (void *)(long)skb->data_end; + int ret; + + /* single length check */ + if (data + sizeof(*iph) + sizeof(*tcp) > data_end) { + ERROR(1); + return TC_ACT_SHOT; + } + + key.tunnel_ttl = 64; + if (iph->protocol == IPPROTO_ICMP) { + key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ + } else { + if (iph->protocol != IPPROTO_TCP || iph->ihl != 5) + return TC_ACT_SHOT; + + if (tcp->dest == bpf_htons(5200)) + key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ + else if (tcp->dest == bpf_htons(5201)) + key.remote_ipv4 = 0xac100165; /* 172.16.1.101 */ + else + return TC_ACT_SHOT; + } + + ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + return TC_ACT_OK; +} + +SEC("ipip_get_tunnel") +int _ipip_get_tunnel(struct __sk_buff *skb) +{ + int ret; + struct bpf_tunnel_key key; + char fmt[] = "remote ip 0x%x\n"; + + ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + bpf_trace_printk(fmt, sizeof(fmt), key.remote_ipv4); + return TC_ACT_OK; +} + +SEC("ipip6_set_tunnel") +int _ipip6_set_tunnel(struct __sk_buff *skb) +{ + struct bpf_tunnel_key key = {}; + void *data = (void *)(long)skb->data; + struct iphdr *iph = data; + struct tcphdr *tcp = data + sizeof(*iph); + void *data_end = (void *)(long)skb->data_end; + int ret; + + /* single length check */ + if (data + sizeof(*iph) + sizeof(*tcp) > data_end) { + ERROR(1); + return TC_ACT_SHOT; + } + + __builtin_memset(&key, 0x0, sizeof(key)); + key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */ + key.tunnel_ttl = 64; + + ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), + BPF_F_TUNINFO_IPV6); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + return TC_ACT_OK; +} + +SEC("ipip6_get_tunnel") +int _ipip6_get_tunnel(struct __sk_buff *skb) +{ + int ret; + struct bpf_tunnel_key key; + char fmt[] = "remote ip6 %x::%x\n"; + + ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), + BPF_F_TUNINFO_IPV6); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + bpf_trace_printk(fmt, sizeof(fmt), bpf_htonl(key.remote_ipv6[0]), + bpf_htonl(key.remote_ipv6[3])); + return TC_ACT_OK; +} + +SEC("ip6ip6_set_tunnel") +int _ip6ip6_set_tunnel(struct __sk_buff *skb) +{ + struct bpf_tunnel_key key = {}; + void *data = (void *)(long)skb->data; + struct ipv6hdr *iph = data; + struct tcphdr *tcp = data + sizeof(*iph); + void *data_end = (void *)(long)skb->data_end; + int ret; + + /* single length check */ + if (data + sizeof(*iph) + sizeof(*tcp) > data_end) { + ERROR(1); + return TC_ACT_SHOT; + } + + key.remote_ipv6[0] = bpf_htonl(0x2401db00); + key.tunnel_ttl = 64; + + if (iph->nexthdr == 58 /* NEXTHDR_ICMP */) { + key.remote_ipv6[3] = bpf_htonl(1); + } else { + if (iph->nexthdr != 6 /* NEXTHDR_TCP */) { + ERROR(iph->nexthdr); + return TC_ACT_SHOT; + } + + if (tcp->dest == bpf_htons(5200)) { + key.remote_ipv6[3] = bpf_htonl(1); + } else if (tcp->dest == bpf_htons(5201)) { + key.remote_ipv6[3] = bpf_htonl(2); + } else { + ERROR(tcp->dest); + return TC_ACT_SHOT; + } + } + + ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), + BPF_F_TUNINFO_IPV6); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + return TC_ACT_OK; +} + +SEC("ip6ip6_get_tunnel") +int _ip6ip6_get_tunnel(struct __sk_buff *skb) +{ + int ret; + struct bpf_tunnel_key key; + char fmt[] = "remote ip6 %x::%x\n"; + + ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), + BPF_F_TUNINFO_IPV6); + if (ret < 0) { + ERROR(ret); + return TC_ACT_SHOT; + } + + bpf_trace_printk(fmt, sizeof(fmt), bpf_htonl(key.remote_ipv6[0]), + bpf_htonl(key.remote_ipv6[3])); + return TC_ACT_OK; +} + +SEC("xfrm_get_state") +int _xfrm_get_state(struct __sk_buff *skb) +{ + struct bpf_xfrm_state x; + char fmt[] = "reqid %d spi 0x%x remote ip 0x%x\n"; + int ret; + + ret = bpf_skb_get_xfrm_state(skb, 0, &x, sizeof(x), 0); + if (ret < 0) + return TC_ACT_OK; + + bpf_trace_printk(fmt, sizeof(fmt), x.reqid, bpf_ntohl(x.spi), + bpf_ntohl(x.remote_ipv4)); + return TC_ACT_OK; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_xdp.c b/tools/testing/selftests/bpf/progs/test_xdp.c new file mode 100644 index 000000000000..5e7df8bb5b5d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_xdp.c @@ -0,0 +1,235 @@ +/* Copyright (c) 2016,2017 Facebook + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "bpf_endian.h" +#include "test_iptunnel_common.h" + +int _version SEC("version") = 1; + +struct bpf_map_def SEC("maps") rxcnt = { + .type = BPF_MAP_TYPE_PERCPU_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u64), + .max_entries = 256, +}; + +struct bpf_map_def SEC("maps") vip2tnl = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(struct vip), + .value_size = sizeof(struct iptnl_info), + .max_entries = MAX_IPTNL_ENTRIES, +}; + +static __always_inline void count_tx(__u32 protocol) +{ + __u64 *rxcnt_count; + + rxcnt_count = bpf_map_lookup_elem(&rxcnt, &protocol); + if (rxcnt_count) + *rxcnt_count += 1; +} + +static __always_inline int get_dport(void *trans_data, void *data_end, + __u8 protocol) +{ + struct tcphdr *th; + struct udphdr *uh; + + switch (protocol) { + case IPPROTO_TCP: + th = (struct tcphdr *)trans_data; + if (th + 1 > data_end) + return -1; + return th->dest; + case IPPROTO_UDP: + uh = (struct udphdr *)trans_data; + if (uh + 1 > data_end) + return -1; + return uh->dest; + default: + return 0; + } +} + +static __always_inline void set_ethhdr(struct ethhdr *new_eth, + const struct ethhdr *old_eth, + const struct iptnl_info *tnl, + __be16 h_proto) +{ + memcpy(new_eth->h_source, old_eth->h_dest, sizeof(new_eth->h_source)); + memcpy(new_eth->h_dest, tnl->dmac, sizeof(new_eth->h_dest)); + new_eth->h_proto = h_proto; +} + +static __always_inline int handle_ipv4(struct xdp_md *xdp) +{ + void *data_end = (void *)(long)xdp->data_end; + void *data = (void *)(long)xdp->data; + struct iptnl_info *tnl; + struct ethhdr *new_eth; + struct ethhdr *old_eth; + struct iphdr *iph = data + sizeof(struct ethhdr); + __u16 *next_iph; + __u16 payload_len; + struct vip vip = {}; + int dport; + __u32 csum = 0; + int i; + + if (iph + 1 > data_end) + return XDP_DROP; + + dport = get_dport(iph + 1, data_end, iph->protocol); + if (dport == -1) + return XDP_DROP; + + vip.protocol = iph->protocol; + vip.family = AF_INET; + vip.daddr.v4 = iph->daddr; + vip.dport = dport; + payload_len = bpf_ntohs(iph->tot_len); + + tnl = bpf_map_lookup_elem(&vip2tnl, &vip); + /* It only does v4-in-v4 */ + if (!tnl || tnl->family != AF_INET) + return XDP_PASS; + + if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(struct iphdr))) + return XDP_DROP; + + data = (void *)(long)xdp->data; + data_end = (void *)(long)xdp->data_end; + + new_eth = data; + iph = data + sizeof(*new_eth); + old_eth = data + sizeof(*iph); + + if (new_eth + 1 > data_end || + old_eth + 1 > data_end || + iph + 1 > data_end) + return XDP_DROP; + + set_ethhdr(new_eth, old_eth, tnl, bpf_htons(ETH_P_IP)); + + iph->version = 4; + iph->ihl = sizeof(*iph) >> 2; + iph->frag_off = 0; + iph->protocol = IPPROTO_IPIP; + iph->check = 0; + iph->tos = 0; + iph->tot_len = bpf_htons(payload_len + sizeof(*iph)); + iph->daddr = tnl->daddr.v4; + iph->saddr = tnl->saddr.v4; + iph->ttl = 8; + + next_iph = (__u16 *)iph; +#pragma clang loop unroll(full) + for (i = 0; i < sizeof(*iph) >> 1; i++) + csum += *next_iph++; + + iph->check = ~((csum & 0xffff) + (csum >> 16)); + + count_tx(vip.protocol); + + return XDP_TX; +} + +static __always_inline int handle_ipv6(struct xdp_md *xdp) +{ + void *data_end = (void *)(long)xdp->data_end; + void *data = (void *)(long)xdp->data; + struct iptnl_info *tnl; + struct ethhdr *new_eth; + struct ethhdr *old_eth; + struct ipv6hdr *ip6h = data + sizeof(struct ethhdr); + __u16 payload_len; + struct vip vip = {}; + int dport; + + if (ip6h + 1 > data_end) + return XDP_DROP; + + dport = get_dport(ip6h + 1, data_end, ip6h->nexthdr); + if (dport == -1) + return XDP_DROP; + + vip.protocol = ip6h->nexthdr; + vip.family = AF_INET6; + memcpy(vip.daddr.v6, ip6h->daddr.s6_addr32, sizeof(vip.daddr)); + vip.dport = dport; + payload_len = ip6h->payload_len; + + tnl = bpf_map_lookup_elem(&vip2tnl, &vip); + /* It only does v6-in-v6 */ + if (!tnl || tnl->family != AF_INET6) + return XDP_PASS; + + if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(struct ipv6hdr))) + return XDP_DROP; + + data = (void *)(long)xdp->data; + data_end = (void *)(long)xdp->data_end; + + new_eth = data; + ip6h = data + sizeof(*new_eth); + old_eth = data + sizeof(*ip6h); + + if (new_eth + 1 > data_end || old_eth + 1 > data_end || + ip6h + 1 > data_end) + return XDP_DROP; + + set_ethhdr(new_eth, old_eth, tnl, bpf_htons(ETH_P_IPV6)); + + ip6h->version = 6; + ip6h->priority = 0; + memset(ip6h->flow_lbl, 0, sizeof(ip6h->flow_lbl)); + ip6h->payload_len = bpf_htons(bpf_ntohs(payload_len) + sizeof(*ip6h)); + ip6h->nexthdr = IPPROTO_IPV6; + ip6h->hop_limit = 8; + memcpy(ip6h->saddr.s6_addr32, tnl->saddr.v6, sizeof(tnl->saddr.v6)); + memcpy(ip6h->daddr.s6_addr32, tnl->daddr.v6, sizeof(tnl->daddr.v6)); + + count_tx(vip.protocol); + + return XDP_TX; +} + +SEC("xdp_tx_iptunnel") +int _xdp_tx_iptunnel(struct xdp_md *xdp) +{ + void *data_end = (void *)(long)xdp->data_end; + void *data = (void *)(long)xdp->data; + struct ethhdr *eth = data; + __u16 h_proto; + + if (eth + 1 > data_end) + return XDP_DROP; + + h_proto = eth->h_proto; + + if (h_proto == bpf_htons(ETH_P_IP)) + return handle_ipv4(xdp); + else if (h_proto == bpf_htons(ETH_P_IPV6)) + + return handle_ipv6(xdp); + else + return XDP_DROP; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_xdp_meta.c b/tools/testing/selftests/bpf/progs/test_xdp_meta.c new file mode 100644 index 000000000000..8d0182650653 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_xdp_meta.c @@ -0,0 +1,53 @@ +#include +#include +#include + +#include "bpf_helpers.h" + +#define __round_mask(x, y) ((__typeof__(x))((y) - 1)) +#define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1) +#define ctx_ptr(ctx, mem) (void *)(unsigned long)ctx->mem + +SEC("t") +int ing_cls(struct __sk_buff *ctx) +{ + __u8 *data, *data_meta, *data_end; + __u32 diff = 0; + + data_meta = ctx_ptr(ctx, data_meta); + data_end = ctx_ptr(ctx, data_end); + data = ctx_ptr(ctx, data); + + if (data + ETH_ALEN > data_end || + data_meta + round_up(ETH_ALEN, 4) > data) + return TC_ACT_SHOT; + + diff |= ((__u32 *)data_meta)[0] ^ ((__u32 *)data)[0]; + diff |= ((__u16 *)data_meta)[2] ^ ((__u16 *)data)[2]; + + return diff ? TC_ACT_SHOT : TC_ACT_OK; +} + +SEC("x") +int ing_xdp(struct xdp_md *ctx) +{ + __u8 *data, *data_meta, *data_end; + int ret; + + ret = bpf_xdp_adjust_meta(ctx, -round_up(ETH_ALEN, 4)); + if (ret < 0) + return XDP_DROP; + + data_meta = ctx_ptr(ctx, data_meta); + data_end = ctx_ptr(ctx, data_end); + data = ctx_ptr(ctx, data); + + if (data + ETH_ALEN > data_end || + data_meta + round_up(ETH_ALEN, 4) > data) + return XDP_DROP; + + __builtin_memcpy(data_meta, data, ETH_ALEN); + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_xdp_noinline.c b/tools/testing/selftests/bpf/progs/test_xdp_noinline.c new file mode 100644 index 000000000000..5e4aac74f9d0 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_xdp_noinline.c @@ -0,0 +1,833 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Facebook +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" + +#define bpf_printk(fmt, ...) \ +({ \ + char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ +}) + +static __u32 rol32(__u32 word, unsigned int shift) +{ + return (word << shift) | (word >> ((-shift) & 31)); +} + +/* copy paste of jhash from kernel sources to make sure llvm + * can compile it into valid sequence of bpf instructions + */ +#define __jhash_mix(a, b, c) \ +{ \ + a -= c; a ^= rol32(c, 4); c += b; \ + b -= a; b ^= rol32(a, 6); a += c; \ + c -= b; c ^= rol32(b, 8); b += a; \ + a -= c; a ^= rol32(c, 16); c += b; \ + b -= a; b ^= rol32(a, 19); a += c; \ + c -= b; c ^= rol32(b, 4); b += a; \ +} + +#define __jhash_final(a, b, c) \ +{ \ + c ^= b; c -= rol32(b, 14); \ + a ^= c; a -= rol32(c, 11); \ + b ^= a; b -= rol32(a, 25); \ + c ^= b; c -= rol32(b, 16); \ + a ^= c; a -= rol32(c, 4); \ + b ^= a; b -= rol32(a, 14); \ + c ^= b; c -= rol32(b, 24); \ +} + +#define JHASH_INITVAL 0xdeadbeef + +typedef unsigned int u32; + +static __attribute__ ((noinline)) +u32 jhash(const void *key, u32 length, u32 initval) +{ + u32 a, b, c; + const unsigned char *k = key; + + a = b = c = JHASH_INITVAL + length + initval; + + while (length > 12) { + a += *(u32 *)(k); + b += *(u32 *)(k + 4); + c += *(u32 *)(k + 8); + __jhash_mix(a, b, c); + length -= 12; + k += 12; + } + switch (length) { + case 12: c += (u32)k[11]<<24; + case 11: c += (u32)k[10]<<16; + case 10: c += (u32)k[9]<<8; + case 9: c += k[8]; + case 8: b += (u32)k[7]<<24; + case 7: b += (u32)k[6]<<16; + case 6: b += (u32)k[5]<<8; + case 5: b += k[4]; + case 4: a += (u32)k[3]<<24; + case 3: a += (u32)k[2]<<16; + case 2: a += (u32)k[1]<<8; + case 1: a += k[0]; + __jhash_final(a, b, c); + case 0: /* Nothing left to add */ + break; + } + + return c; +} + +static __attribute__ ((noinline)) +u32 __jhash_nwords(u32 a, u32 b, u32 c, u32 initval) +{ + a += initval; + b += initval; + c += initval; + __jhash_final(a, b, c); + return c; +} + +static __attribute__ ((noinline)) +u32 jhash_2words(u32 a, u32 b, u32 initval) +{ + return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2)); +} + +struct flow_key { + union { + __be32 src; + __be32 srcv6[4]; + }; + union { + __be32 dst; + __be32 dstv6[4]; + }; + union { + __u32 ports; + __u16 port16[2]; + }; + __u8 proto; +}; + +struct packet_description { + struct flow_key flow; + __u8 flags; +}; + +struct ctl_value { + union { + __u64 value; + __u32 ifindex; + __u8 mac[6]; + }; +}; + +struct vip_definition { + union { + __be32 vip; + __be32 vipv6[4]; + }; + __u16 port; + __u16 family; + __u8 proto; +}; + +struct vip_meta { + __u32 flags; + __u32 vip_num; +}; + +struct real_pos_lru { + __u32 pos; + __u64 atime; +}; + +struct real_definition { + union { + __be32 dst; + __be32 dstv6[4]; + }; + __u8 flags; +}; + +struct lb_stats { + __u64 v2; + __u64 v1; +}; + +struct bpf_map_def __attribute__ ((section("maps"), used)) vip_map = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(struct vip_definition), + .value_size = sizeof(struct vip_meta), + .max_entries = 512, + .map_flags = 0, +}; + +struct bpf_map_def __attribute__ ((section("maps"), used)) lru_cache = { + .type = BPF_MAP_TYPE_LRU_HASH, + .key_size = sizeof(struct flow_key), + .value_size = sizeof(struct real_pos_lru), + .max_entries = 300, + .map_flags = 1U << 1, +}; + +struct bpf_map_def __attribute__ ((section("maps"), used)) ch_rings = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 12 * 655, + .map_flags = 0, +}; + +struct bpf_map_def __attribute__ ((section("maps"), used)) reals = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct real_definition), + .max_entries = 40, + .map_flags = 0, +}; + +struct bpf_map_def __attribute__ ((section("maps"), used)) stats = { + .type = BPF_MAP_TYPE_PERCPU_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct lb_stats), + .max_entries = 515, + .map_flags = 0, +}; + +struct bpf_map_def __attribute__ ((section("maps"), used)) ctl_array = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct ctl_value), + .max_entries = 16, + .map_flags = 0, +}; + +struct eth_hdr { + unsigned char eth_dest[6]; + unsigned char eth_source[6]; + unsigned short eth_proto; +}; + +static inline __u64 calc_offset(bool is_ipv6, bool is_icmp) +{ + __u64 off = sizeof(struct eth_hdr); + if (is_ipv6) { + off += sizeof(struct ipv6hdr); + if (is_icmp) + off += sizeof(struct icmp6hdr) + sizeof(struct ipv6hdr); + } else { + off += sizeof(struct iphdr); + if (is_icmp) + off += sizeof(struct icmphdr) + sizeof(struct iphdr); + } + return off; +} + +static __attribute__ ((noinline)) +bool parse_udp(void *data, void *data_end, + bool is_ipv6, struct packet_description *pckt) +{ + + bool is_icmp = !((pckt->flags & (1 << 0)) == 0); + __u64 off = calc_offset(is_ipv6, is_icmp); + struct udphdr *udp; + udp = data + off; + + if (udp + 1 > data_end) + return 0; + if (!is_icmp) { + pckt->flow.port16[0] = udp->source; + pckt->flow.port16[1] = udp->dest; + } else { + pckt->flow.port16[0] = udp->dest; + pckt->flow.port16[1] = udp->source; + } + return 1; +} + +static __attribute__ ((noinline)) +bool parse_tcp(void *data, void *data_end, + bool is_ipv6, struct packet_description *pckt) +{ + + bool is_icmp = !((pckt->flags & (1 << 0)) == 0); + __u64 off = calc_offset(is_ipv6, is_icmp); + struct tcphdr *tcp; + + tcp = data + off; + if (tcp + 1 > data_end) + return 0; + if (tcp->syn) + pckt->flags |= (1 << 1); + if (!is_icmp) { + pckt->flow.port16[0] = tcp->source; + pckt->flow.port16[1] = tcp->dest; + } else { + pckt->flow.port16[0] = tcp->dest; + pckt->flow.port16[1] = tcp->source; + } + return 1; +} + +static __attribute__ ((noinline)) +bool encap_v6(struct xdp_md *xdp, struct ctl_value *cval, + struct packet_description *pckt, + struct real_definition *dst, __u32 pkt_bytes) +{ + struct eth_hdr *new_eth; + struct eth_hdr *old_eth; + struct ipv6hdr *ip6h; + __u32 ip_suffix; + void *data_end; + void *data; + + if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(struct ipv6hdr))) + return 0; + data = (void *)(long)xdp->data; + data_end = (void *)(long)xdp->data_end; + new_eth = data; + ip6h = data + sizeof(struct eth_hdr); + old_eth = data + sizeof(struct ipv6hdr); + if (new_eth + 1 > data_end || + old_eth + 1 > data_end || ip6h + 1 > data_end) + return 0; + memcpy(new_eth->eth_dest, cval->mac, 6); + memcpy(new_eth->eth_source, old_eth->eth_dest, 6); + new_eth->eth_proto = 56710; + ip6h->version = 6; + ip6h->priority = 0; + memset(ip6h->flow_lbl, 0, sizeof(ip6h->flow_lbl)); + + ip6h->nexthdr = IPPROTO_IPV6; + ip_suffix = pckt->flow.srcv6[3] ^ pckt->flow.port16[0]; + ip6h->payload_len = + __builtin_bswap16(pkt_bytes + sizeof(struct ipv6hdr)); + ip6h->hop_limit = 4; + + ip6h->saddr.in6_u.u6_addr32[0] = 1; + ip6h->saddr.in6_u.u6_addr32[1] = 2; + ip6h->saddr.in6_u.u6_addr32[2] = 3; + ip6h->saddr.in6_u.u6_addr32[3] = ip_suffix; + memcpy(ip6h->daddr.in6_u.u6_addr32, dst->dstv6, 16); + return 1; +} + +static __attribute__ ((noinline)) +bool encap_v4(struct xdp_md *xdp, struct ctl_value *cval, + struct packet_description *pckt, + struct real_definition *dst, __u32 pkt_bytes) +{ + + __u32 ip_suffix = __builtin_bswap16(pckt->flow.port16[0]); + struct eth_hdr *new_eth; + struct eth_hdr *old_eth; + __u16 *next_iph_u16; + struct iphdr *iph; + __u32 csum = 0; + void *data_end; + void *data; + + ip_suffix <<= 15; + ip_suffix ^= pckt->flow.src; + if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(struct iphdr))) + return 0; + data = (void *)(long)xdp->data; + data_end = (void *)(long)xdp->data_end; + new_eth = data; + iph = data + sizeof(struct eth_hdr); + old_eth = data + sizeof(struct iphdr); + if (new_eth + 1 > data_end || + old_eth + 1 > data_end || iph + 1 > data_end) + return 0; + memcpy(new_eth->eth_dest, cval->mac, 6); + memcpy(new_eth->eth_source, old_eth->eth_dest, 6); + new_eth->eth_proto = 8; + iph->version = 4; + iph->ihl = 5; + iph->frag_off = 0; + iph->protocol = IPPROTO_IPIP; + iph->check = 0; + iph->tos = 1; + iph->tot_len = __builtin_bswap16(pkt_bytes + sizeof(struct iphdr)); + /* don't update iph->daddr, since it will overwrite old eth_proto + * and multiple iterations of bpf_prog_run() will fail + */ + + iph->saddr = ((0xFFFF0000 & ip_suffix) | 4268) ^ dst->dst; + iph->ttl = 4; + + next_iph_u16 = (__u16 *) iph; +#pragma clang loop unroll(full) + for (int i = 0; i < sizeof(struct iphdr) >> 1; i++) + csum += *next_iph_u16++; + iph->check = ~((csum & 0xffff) + (csum >> 16)); + if (bpf_xdp_adjust_head(xdp, (int)sizeof(struct iphdr))) + return 0; + return 1; +} + +static __attribute__ ((noinline)) +bool decap_v6(struct xdp_md *xdp, void **data, void **data_end, bool inner_v4) +{ + struct eth_hdr *new_eth; + struct eth_hdr *old_eth; + + old_eth = *data; + new_eth = *data + sizeof(struct ipv6hdr); + memcpy(new_eth->eth_source, old_eth->eth_source, 6); + memcpy(new_eth->eth_dest, old_eth->eth_dest, 6); + if (inner_v4) + new_eth->eth_proto = 8; + else + new_eth->eth_proto = 56710; + if (bpf_xdp_adjust_head(xdp, (int)sizeof(struct ipv6hdr))) + return 0; + *data = (void *)(long)xdp->data; + *data_end = (void *)(long)xdp->data_end; + return 1; +} + +static __attribute__ ((noinline)) +bool decap_v4(struct xdp_md *xdp, void **data, void **data_end) +{ + struct eth_hdr *new_eth; + struct eth_hdr *old_eth; + + old_eth = *data; + new_eth = *data + sizeof(struct iphdr); + memcpy(new_eth->eth_source, old_eth->eth_source, 6); + memcpy(new_eth->eth_dest, old_eth->eth_dest, 6); + new_eth->eth_proto = 8; + if (bpf_xdp_adjust_head(xdp, (int)sizeof(struct iphdr))) + return 0; + *data = (void *)(long)xdp->data; + *data_end = (void *)(long)xdp->data_end; + return 1; +} + +static __attribute__ ((noinline)) +int swap_mac_and_send(void *data, void *data_end) +{ + unsigned char tmp_mac[6]; + struct eth_hdr *eth; + + eth = data; + memcpy(tmp_mac, eth->eth_source, 6); + memcpy(eth->eth_source, eth->eth_dest, 6); + memcpy(eth->eth_dest, tmp_mac, 6); + return XDP_TX; +} + +static __attribute__ ((noinline)) +int send_icmp_reply(void *data, void *data_end) +{ + struct icmphdr *icmp_hdr; + __u16 *next_iph_u16; + __u32 tmp_addr = 0; + struct iphdr *iph; + __u32 csum1 = 0; + __u32 csum = 0; + __u64 off = 0; + + if (data + sizeof(struct eth_hdr) + + sizeof(struct iphdr) + sizeof(struct icmphdr) > data_end) + return XDP_DROP; + off += sizeof(struct eth_hdr); + iph = data + off; + off += sizeof(struct iphdr); + icmp_hdr = data + off; + icmp_hdr->type = 0; + icmp_hdr->checksum += 0x0007; + iph->ttl = 4; + tmp_addr = iph->daddr; + iph->daddr = iph->saddr; + iph->saddr = tmp_addr; + iph->check = 0; + next_iph_u16 = (__u16 *) iph; +#pragma clang loop unroll(full) + for (int i = 0; i < sizeof(struct iphdr) >> 1; i++) + csum += *next_iph_u16++; + iph->check = ~((csum & 0xffff) + (csum >> 16)); + return swap_mac_and_send(data, data_end); +} + +static __attribute__ ((noinline)) +int send_icmp6_reply(void *data, void *data_end) +{ + struct icmp6hdr *icmp_hdr; + struct ipv6hdr *ip6h; + __be32 tmp_addr[4]; + __u64 off = 0; + + if (data + sizeof(struct eth_hdr) + + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr) > data_end) + return XDP_DROP; + off += sizeof(struct eth_hdr); + ip6h = data + off; + off += sizeof(struct ipv6hdr); + icmp_hdr = data + off; + icmp_hdr->icmp6_type = 129; + icmp_hdr->icmp6_cksum -= 0x0001; + ip6h->hop_limit = 4; + memcpy(tmp_addr, ip6h->saddr.in6_u.u6_addr32, 16); + memcpy(ip6h->saddr.in6_u.u6_addr32, ip6h->daddr.in6_u.u6_addr32, 16); + memcpy(ip6h->daddr.in6_u.u6_addr32, tmp_addr, 16); + return swap_mac_and_send(data, data_end); +} + +static __attribute__ ((noinline)) +int parse_icmpv6(void *data, void *data_end, __u64 off, + struct packet_description *pckt) +{ + struct icmp6hdr *icmp_hdr; + struct ipv6hdr *ip6h; + + icmp_hdr = data + off; + if (icmp_hdr + 1 > data_end) + return XDP_DROP; + if (icmp_hdr->icmp6_type == 128) + return send_icmp6_reply(data, data_end); + if (icmp_hdr->icmp6_type != 3) + return XDP_PASS; + off += sizeof(struct icmp6hdr); + ip6h = data + off; + if (ip6h + 1 > data_end) + return XDP_DROP; + pckt->flow.proto = ip6h->nexthdr; + pckt->flags |= (1 << 0); + memcpy(pckt->flow.srcv6, ip6h->daddr.in6_u.u6_addr32, 16); + memcpy(pckt->flow.dstv6, ip6h->saddr.in6_u.u6_addr32, 16); + return -1; +} + +static __attribute__ ((noinline)) +int parse_icmp(void *data, void *data_end, __u64 off, + struct packet_description *pckt) +{ + struct icmphdr *icmp_hdr; + struct iphdr *iph; + + icmp_hdr = data + off; + if (icmp_hdr + 1 > data_end) + return XDP_DROP; + if (icmp_hdr->type == 8) + return send_icmp_reply(data, data_end); + if ((icmp_hdr->type != 3) || (icmp_hdr->code != 4)) + return XDP_PASS; + off += sizeof(struct icmphdr); + iph = data + off; + if (iph + 1 > data_end) + return XDP_DROP; + if (iph->ihl != 5) + return XDP_DROP; + pckt->flow.proto = iph->protocol; + pckt->flags |= (1 << 0); + pckt->flow.src = iph->daddr; + pckt->flow.dst = iph->saddr; + return -1; +} + +static __attribute__ ((noinline)) +__u32 get_packet_hash(struct packet_description *pckt, + bool hash_16bytes) +{ + if (hash_16bytes) + return jhash_2words(jhash(pckt->flow.srcv6, 16, 12), + pckt->flow.ports, 24); + else + return jhash_2words(pckt->flow.src, pckt->flow.ports, + 24); +} + +__attribute__ ((noinline)) +static bool get_packet_dst(struct real_definition **real, + struct packet_description *pckt, + struct vip_meta *vip_info, + bool is_ipv6, void *lru_map) +{ + struct real_pos_lru new_dst_lru = { }; + bool hash_16bytes = is_ipv6; + __u32 *real_pos, hash, key; + __u64 cur_time; + + if (vip_info->flags & (1 << 2)) + hash_16bytes = 1; + if (vip_info->flags & (1 << 3)) { + pckt->flow.port16[0] = pckt->flow.port16[1]; + memset(pckt->flow.srcv6, 0, 16); + } + hash = get_packet_hash(pckt, hash_16bytes); + if (hash != 0x358459b7 /* jhash of ipv4 packet */ && + hash != 0x2f4bc6bb /* jhash of ipv6 packet */) + return 0; + key = 2 * vip_info->vip_num + hash % 2; + real_pos = bpf_map_lookup_elem(&ch_rings, &key); + if (!real_pos) + return 0; + key = *real_pos; + *real = bpf_map_lookup_elem(&reals, &key); + if (!(*real)) + return 0; + if (!(vip_info->flags & (1 << 1))) { + __u32 conn_rate_key = 512 + 2; + struct lb_stats *conn_rate_stats = + bpf_map_lookup_elem(&stats, &conn_rate_key); + + if (!conn_rate_stats) + return 1; + cur_time = bpf_ktime_get_ns(); + if ((cur_time - conn_rate_stats->v2) >> 32 > 0xffFFFF) { + conn_rate_stats->v1 = 1; + conn_rate_stats->v2 = cur_time; + } else { + conn_rate_stats->v1 += 1; + if (conn_rate_stats->v1 >= 1) + return 1; + } + if (pckt->flow.proto == IPPROTO_UDP) + new_dst_lru.atime = cur_time; + new_dst_lru.pos = key; + bpf_map_update_elem(lru_map, &pckt->flow, &new_dst_lru, 0); + } + return 1; +} + +__attribute__ ((noinline)) +static void connection_table_lookup(struct real_definition **real, + struct packet_description *pckt, + void *lru_map) +{ + + struct real_pos_lru *dst_lru; + __u64 cur_time; + __u32 key; + + dst_lru = bpf_map_lookup_elem(lru_map, &pckt->flow); + if (!dst_lru) + return; + if (pckt->flow.proto == IPPROTO_UDP) { + cur_time = bpf_ktime_get_ns(); + if (cur_time - dst_lru->atime > 300000) + return; + dst_lru->atime = cur_time; + } + key = dst_lru->pos; + *real = bpf_map_lookup_elem(&reals, &key); +} + +/* don't believe your eyes! + * below function has 6 arguments whereas bpf and llvm allow maximum of 5 + * but since it's _static_ llvm can optimize one argument away + */ +__attribute__ ((noinline)) +static int process_l3_headers_v6(struct packet_description *pckt, + __u8 *protocol, __u64 off, + __u16 *pkt_bytes, void *data, + void *data_end) +{ + struct ipv6hdr *ip6h; + __u64 iph_len; + int action; + + ip6h = data + off; + if (ip6h + 1 > data_end) + return XDP_DROP; + iph_len = sizeof(struct ipv6hdr); + *protocol = ip6h->nexthdr; + pckt->flow.proto = *protocol; + *pkt_bytes = __builtin_bswap16(ip6h->payload_len); + off += iph_len; + if (*protocol == 45) { + return XDP_DROP; + } else if (*protocol == 59) { + action = parse_icmpv6(data, data_end, off, pckt); + if (action >= 0) + return action; + } else { + memcpy(pckt->flow.srcv6, ip6h->saddr.in6_u.u6_addr32, 16); + memcpy(pckt->flow.dstv6, ip6h->daddr.in6_u.u6_addr32, 16); + } + return -1; +} + +__attribute__ ((noinline)) +static int process_l3_headers_v4(struct packet_description *pckt, + __u8 *protocol, __u64 off, + __u16 *pkt_bytes, void *data, + void *data_end) +{ + struct iphdr *iph; + __u64 iph_len; + int action; + + iph = data + off; + if (iph + 1 > data_end) + return XDP_DROP; + if (iph->ihl != 5) + return XDP_DROP; + *protocol = iph->protocol; + pckt->flow.proto = *protocol; + *pkt_bytes = __builtin_bswap16(iph->tot_len); + off += 20; + if (iph->frag_off & 65343) + return XDP_DROP; + if (*protocol == IPPROTO_ICMP) { + action = parse_icmp(data, data_end, off, pckt); + if (action >= 0) + return action; + } else { + pckt->flow.src = iph->saddr; + pckt->flow.dst = iph->daddr; + } + return -1; +} + +__attribute__ ((noinline)) +static int process_packet(void *data, __u64 off, void *data_end, + bool is_ipv6, struct xdp_md *xdp) +{ + + struct real_definition *dst = NULL; + struct packet_description pckt = { }; + struct vip_definition vip = { }; + struct lb_stats *data_stats; + struct eth_hdr *eth = data; + void *lru_map = &lru_cache; + struct vip_meta *vip_info; + __u32 lru_stats_key = 513; + __u32 mac_addr_pos = 0; + __u32 stats_key = 512; + struct ctl_value *cval; + __u16 pkt_bytes; + __u64 iph_len; + __u8 protocol; + __u32 vip_num; + int action; + + if (is_ipv6) + action = process_l3_headers_v6(&pckt, &protocol, off, + &pkt_bytes, data, data_end); + else + action = process_l3_headers_v4(&pckt, &protocol, off, + &pkt_bytes, data, data_end); + if (action >= 0) + return action; + protocol = pckt.flow.proto; + if (protocol == IPPROTO_TCP) { + if (!parse_tcp(data, data_end, is_ipv6, &pckt)) + return XDP_DROP; + } else if (protocol == IPPROTO_UDP) { + if (!parse_udp(data, data_end, is_ipv6, &pckt)) + return XDP_DROP; + } else { + return XDP_TX; + } + + if (is_ipv6) + memcpy(vip.vipv6, pckt.flow.dstv6, 16); + else + vip.vip = pckt.flow.dst; + vip.port = pckt.flow.port16[1]; + vip.proto = pckt.flow.proto; + vip_info = bpf_map_lookup_elem(&vip_map, &vip); + if (!vip_info) { + vip.port = 0; + vip_info = bpf_map_lookup_elem(&vip_map, &vip); + if (!vip_info) + return XDP_PASS; + if (!(vip_info->flags & (1 << 4))) + pckt.flow.port16[1] = 0; + } + if (data_end - data > 1400) + return XDP_DROP; + data_stats = bpf_map_lookup_elem(&stats, &stats_key); + if (!data_stats) + return XDP_DROP; + data_stats->v1 += 1; + if (!dst) { + if (vip_info->flags & (1 << 0)) + pckt.flow.port16[0] = 0; + if (!(pckt.flags & (1 << 1)) && !(vip_info->flags & (1 << 1))) + connection_table_lookup(&dst, &pckt, lru_map); + if (dst) + goto out; + if (pckt.flow.proto == IPPROTO_TCP) { + struct lb_stats *lru_stats = + bpf_map_lookup_elem(&stats, &lru_stats_key); + + if (!lru_stats) + return XDP_DROP; + if (pckt.flags & (1 << 1)) + lru_stats->v1 += 1; + else + lru_stats->v2 += 1; + } + if (!get_packet_dst(&dst, &pckt, vip_info, is_ipv6, lru_map)) + return XDP_DROP; + data_stats->v2 += 1; + } +out: + cval = bpf_map_lookup_elem(&ctl_array, &mac_addr_pos); + if (!cval) + return XDP_DROP; + if (dst->flags & (1 << 0)) { + if (!encap_v6(xdp, cval, &pckt, dst, pkt_bytes)) + return XDP_DROP; + } else { + if (!encap_v4(xdp, cval, &pckt, dst, pkt_bytes)) + return XDP_DROP; + } + vip_num = vip_info->vip_num; + data_stats = bpf_map_lookup_elem(&stats, &vip_num); + if (!data_stats) + return XDP_DROP; + data_stats->v1 += 1; + data_stats->v2 += pkt_bytes; + + data = (void *)(long)xdp->data; + data_end = (void *)(long)xdp->data_end; + if (data + 4 > data_end) + return XDP_DROP; + *(u32 *)data = dst->dst; + return XDP_DROP; +} + +__attribute__ ((section("xdp-test"), used)) +int balancer_ingress(struct xdp_md *ctx) +{ + void *data = (void *)(long)ctx->data; + void *data_end = (void *)(long)ctx->data_end; + struct eth_hdr *eth = data; + __u32 eth_proto; + __u32 nh_off; + + nh_off = sizeof(struct eth_hdr); + if (data + nh_off > data_end) + return XDP_DROP; + eth_proto = eth->eth_proto; + if (eth_proto == 8) + return process_packet(data, nh_off, data_end, 0, ctx); + else if (eth_proto == 56710) + return process_packet(data, nh_off, data_end, 1, ctx); + else + return XDP_DROP; +} + +char _license[] __attribute__ ((section("license"), used)) = "GPL"; +int _version __attribute__ ((section("version"), used)) = 1; diff --git a/tools/testing/selftests/bpf/progs/test_xdp_redirect.c b/tools/testing/selftests/bpf/progs/test_xdp_redirect.c new file mode 100644 index 000000000000..ef9e704be140 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_xdp_redirect.c @@ -0,0 +1,28 @@ +/* Copyright (c) 2017 VMware + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include +#include "bpf_helpers.h" + +int _version SEC("version") = 1; + +SEC("redirect_to_111") +int xdp_redirect_to_111(struct xdp_md *xdp) +{ + return bpf_redirect(111, 0); +} +SEC("redirect_to_222") +int xdp_redirect_to_222(struct xdp_md *xdp) +{ + return bpf_redirect(222, 0); +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_xdp_vlan.c b/tools/testing/selftests/bpf/progs/test_xdp_vlan.c new file mode 100644 index 000000000000..365a7d2d9f5c --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_xdp_vlan.c @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright(c) 2018 Jesper Dangaard Brouer. + * + * XDP/TC VLAN manipulation example + * + * GOTCHA: Remember to disable NIC hardware offloading of VLANs, + * else the VLAN tags are NOT inlined in the packet payload: + * + * # ethtool -K ixgbe2 rxvlan off + * + * Verify setting: + * # ethtool -k ixgbe2 | grep rx-vlan-offload + * rx-vlan-offload: off + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +/* linux/if_vlan.h have not exposed this as UAPI, thus mirror some here + * + * struct vlan_hdr - vlan header + * @h_vlan_TCI: priority and VLAN ID + * @h_vlan_encapsulated_proto: packet type ID or len + */ +struct _vlan_hdr { + __be16 h_vlan_TCI; + __be16 h_vlan_encapsulated_proto; +}; +#define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */ +#define VLAN_PRIO_SHIFT 13 +#define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */ +#define VLAN_TAG_PRESENT VLAN_CFI_MASK +#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */ +#define VLAN_N_VID 4096 + +struct parse_pkt { + __u16 l3_proto; + __u16 l3_offset; + __u16 vlan_outer; + __u16 vlan_inner; + __u8 vlan_outer_offset; + __u8 vlan_inner_offset; +}; + +char _license[] SEC("license") = "GPL"; + +static __always_inline +bool parse_eth_frame(struct ethhdr *eth, void *data_end, struct parse_pkt *pkt) +{ + __u16 eth_type; + __u8 offset; + + offset = sizeof(*eth); + /* Make sure packet is large enough for parsing eth + 2 VLAN headers */ + if ((void *)eth + offset + (2*sizeof(struct _vlan_hdr)) > data_end) + return false; + + eth_type = eth->h_proto; + + /* Handle outer VLAN tag */ + if (eth_type == bpf_htons(ETH_P_8021Q) + || eth_type == bpf_htons(ETH_P_8021AD)) { + struct _vlan_hdr *vlan_hdr; + + vlan_hdr = (void *)eth + offset; + pkt->vlan_outer_offset = offset; + pkt->vlan_outer = bpf_ntohs(vlan_hdr->h_vlan_TCI) + & VLAN_VID_MASK; + eth_type = vlan_hdr->h_vlan_encapsulated_proto; + offset += sizeof(*vlan_hdr); + } + + /* Handle inner (double) VLAN tag */ + if (eth_type == bpf_htons(ETH_P_8021Q) + || eth_type == bpf_htons(ETH_P_8021AD)) { + struct _vlan_hdr *vlan_hdr; + + vlan_hdr = (void *)eth + offset; + pkt->vlan_inner_offset = offset; + pkt->vlan_inner = bpf_ntohs(vlan_hdr->h_vlan_TCI) + & VLAN_VID_MASK; + eth_type = vlan_hdr->h_vlan_encapsulated_proto; + offset += sizeof(*vlan_hdr); + } + + pkt->l3_proto = bpf_ntohs(eth_type); /* Convert to host-byte-order */ + pkt->l3_offset = offset; + + return true; +} + +/* Hint, VLANs are choosen to hit network-byte-order issues */ +#define TESTVLAN 4011 /* 0xFAB */ +// #define TO_VLAN 4000 /* 0xFA0 (hint 0xOA0 = 160) */ + +SEC("xdp_drop_vlan_4011") +int xdp_prognum0(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + struct parse_pkt pkt = { 0 }; + + if (!parse_eth_frame(data, data_end, &pkt)) + return XDP_ABORTED; + + /* Drop specific VLAN ID example */ + if (pkt.vlan_outer == TESTVLAN) + return XDP_ABORTED; + /* + * Using XDP_ABORTED makes it possible to record this event, + * via tracepoint xdp:xdp_exception like: + * # perf record -a -e xdp:xdp_exception + * # perf script + */ + return XDP_PASS; +} +/* +Commands to setup VLAN on Linux to test packets gets dropped: + + export ROOTDEV=ixgbe2 + export VLANID=4011 + ip link add link $ROOTDEV name $ROOTDEV.$VLANID type vlan id $VLANID + ip link set dev $ROOTDEV.$VLANID up + + ip link set dev $ROOTDEV mtu 1508 + ip addr add 100.64.40.11/24 dev $ROOTDEV.$VLANID + +Load prog with ip tool: + + ip link set $ROOTDEV xdp off + ip link set $ROOTDEV xdp object xdp_vlan01_kern.o section xdp_drop_vlan_4011 + +*/ + +/* Changing VLAN to zero, have same practical effect as removing the VLAN. */ +#define TO_VLAN 0 + +SEC("xdp_vlan_change") +int xdp_prognum1(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + struct parse_pkt pkt = { 0 }; + + if (!parse_eth_frame(data, data_end, &pkt)) + return XDP_ABORTED; + + /* Change specific VLAN ID */ + if (pkt.vlan_outer == TESTVLAN) { + struct _vlan_hdr *vlan_hdr = data + pkt.vlan_outer_offset; + + /* Modifying VLAN, preserve top 4 bits */ + vlan_hdr->h_vlan_TCI = + bpf_htons((bpf_ntohs(vlan_hdr->h_vlan_TCI) & 0xf000) + | TO_VLAN); + } + + return XDP_PASS; +} + +/* + * Show XDP+TC can cooperate, on creating a VLAN rewriter. + * 1. Create a XDP prog that can "pop"/remove a VLAN header. + * 2. Create a TC-bpf prog that egress can add a VLAN header. + */ + +#ifndef ETH_ALEN /* Ethernet MAC address length */ +#define ETH_ALEN 6 /* bytes */ +#endif +#define VLAN_HDR_SZ 4 /* bytes */ + +SEC("xdp_vlan_remove_outer") +int xdp_prognum2(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + struct parse_pkt pkt = { 0 }; + char *dest; + + if (!parse_eth_frame(data, data_end, &pkt)) + return XDP_ABORTED; + + /* Skip packet if no outer VLAN was detected */ + if (pkt.vlan_outer_offset == 0) + return XDP_PASS; + + /* Moving Ethernet header, dest overlap with src, memmove handle this */ + dest = data; + dest+= VLAN_HDR_SZ; + /* + * Notice: Taking over vlan_hdr->h_vlan_encapsulated_proto, by + * only moving two MAC addrs (12 bytes), not overwriting last 2 bytes + */ + __builtin_memmove(dest, data, ETH_ALEN * 2); + /* Note: LLVM built-in memmove inlining require size to be constant */ + + /* Move start of packet header seen by Linux kernel stack */ + bpf_xdp_adjust_head(ctx, VLAN_HDR_SZ); + + return XDP_PASS; +} + +static __always_inline +void shift_mac_4bytes_16bit(void *data) +{ + __u16 *p = data; + + p[7] = p[5]; /* delete p[7] was vlan_hdr->h_vlan_TCI */ + p[6] = p[4]; /* delete p[6] was ethhdr->h_proto */ + p[5] = p[3]; + p[4] = p[2]; + p[3] = p[1]; + p[2] = p[0]; +} + +static __always_inline +void shift_mac_4bytes_32bit(void *data) +{ + __u32 *p = data; + + /* Assuming VLAN hdr present. The 4 bytes in p[3] that gets + * overwritten, is ethhdr->h_proto and vlan_hdr->h_vlan_TCI. + * The vlan_hdr->h_vlan_encapsulated_proto take over role as + * ethhdr->h_proto. + */ + p[3] = p[2]; + p[2] = p[1]; + p[1] = p[0]; +} + +SEC("xdp_vlan_remove_outer2") +int xdp_prognum3(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + struct ethhdr *orig_eth = data; + struct parse_pkt pkt = { 0 }; + + if (!parse_eth_frame(orig_eth, data_end, &pkt)) + return XDP_ABORTED; + + /* Skip packet if no outer VLAN was detected */ + if (pkt.vlan_outer_offset == 0) + return XDP_PASS; + + /* Simply shift down MAC addrs 4 bytes, overwrite h_proto + TCI */ + shift_mac_4bytes_32bit(data); + + /* Move start of packet header seen by Linux kernel stack */ + bpf_xdp_adjust_head(ctx, VLAN_HDR_SZ); + + return XDP_PASS; +} + +/*===================================== + * BELOW: TC-hook based ebpf programs + * ==================================== + * The TC-clsact eBPF programs (currently) need to be attach via TC commands + */ + +SEC("tc_vlan_push") +int _tc_progA(struct __sk_buff *ctx) +{ + bpf_skb_vlan_push(ctx, bpf_htons(ETH_P_8021Q), TESTVLAN); + + return TC_ACT_OK; +} +/* +Commands to setup TC to use above bpf prog: + +export ROOTDEV=ixgbe2 +export FILE=xdp_vlan01_kern.o + +# Re-attach clsact to clear/flush existing role +tc qdisc del dev $ROOTDEV clsact 2> /dev/null ;\ +tc qdisc add dev $ROOTDEV clsact + +# Attach BPF prog EGRESS +tc filter add dev $ROOTDEV egress \ + prio 1 handle 1 bpf da obj $FILE sec tc_vlan_push + +tc filter show dev $ROOTDEV egress +*/ diff --git a/tools/testing/selftests/bpf/progs/xdp_dummy.c b/tools/testing/selftests/bpf/progs/xdp_dummy.c new file mode 100644 index 000000000000..43b0ef1001ed --- /dev/null +++ b/tools/testing/selftests/bpf/progs/xdp_dummy.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define KBUILD_MODNAME "xdp_dummy" +#include +#include "bpf_helpers.h" + +SEC("xdp_dummy") +int xdp_dummy_prog(struct xdp_md *ctx) +{ + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/sample_map_ret0.c b/tools/testing/selftests/bpf/sample_map_ret0.c deleted file mode 100644 index 0756303676ac..000000000000 --- a/tools/testing/selftests/bpf/sample_map_ret0.c +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */ -#include -#include "bpf_helpers.h" - -struct bpf_map_def SEC("maps") htab = { - .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(__u32), - .value_size = sizeof(long), - .max_entries = 2, -}; - -struct bpf_map_def SEC("maps") array = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(long), - .max_entries = 2, -}; - -/* Sample program which should always load for testing control paths. */ -SEC(".text") int func() -{ - __u64 key64 = 0; - __u32 key = 0; - long *value; - - value = bpf_map_lookup_elem(&htab, &key); - if (!value) - return 1; - value = bpf_map_lookup_elem(&array, &key64); - if (!value) - return 1; - - return 0; -} diff --git a/tools/testing/selftests/bpf/sample_ret0.c b/tools/testing/selftests/bpf/sample_ret0.c deleted file mode 100644 index fec99750d6ea..000000000000 --- a/tools/testing/selftests/bpf/sample_ret0.c +++ /dev/null @@ -1,7 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */ - -/* Sample program which should always load for testing control paths. */ -int func() -{ - return 0; -} diff --git a/tools/testing/selftests/bpf/sendmsg4_prog.c b/tools/testing/selftests/bpf/sendmsg4_prog.c deleted file mode 100644 index a91536b1c47e..000000000000 --- a/tools/testing/selftests/bpf/sendmsg4_prog.c +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Facebook - -#include -#include -#include - -#include "bpf_helpers.h" -#include "bpf_endian.h" - -#define SRC1_IP4 0xAC100001U /* 172.16.0.1 */ -#define SRC2_IP4 0x00000000U -#define SRC_REWRITE_IP4 0x7f000004U -#define DST_IP4 0xC0A801FEU /* 192.168.1.254 */ -#define DST_REWRITE_IP4 0x7f000001U -#define DST_PORT 4040 -#define DST_REWRITE_PORT4 4444 - -int _version SEC("version") = 1; - -SEC("cgroup/sendmsg4") -int sendmsg_v4_prog(struct bpf_sock_addr *ctx) -{ - if (ctx->type != SOCK_DGRAM) - return 0; - - /* Rewrite source. */ - if (ctx->msg_src_ip4 == bpf_htonl(SRC1_IP4) || - ctx->msg_src_ip4 == bpf_htonl(SRC2_IP4)) { - ctx->msg_src_ip4 = bpf_htonl(SRC_REWRITE_IP4); - } else { - /* Unexpected source. Reject sendmsg. */ - return 0; - } - - /* Rewrite destination. */ - if ((ctx->user_ip4 >> 24) == (bpf_htonl(DST_IP4) >> 24) && - ctx->user_port == bpf_htons(DST_PORT)) { - ctx->user_ip4 = bpf_htonl(DST_REWRITE_IP4); - ctx->user_port = bpf_htons(DST_REWRITE_PORT4); - } else { - /* Unexpected source. Reject sendmsg. */ - return 0; - } - - return 1; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/sendmsg6_prog.c b/tools/testing/selftests/bpf/sendmsg6_prog.c deleted file mode 100644 index 5aeaa284fc47..000000000000 --- a/tools/testing/selftests/bpf/sendmsg6_prog.c +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Facebook - -#include -#include -#include - -#include "bpf_helpers.h" -#include "bpf_endian.h" - -#define SRC_REWRITE_IP6_0 0 -#define SRC_REWRITE_IP6_1 0 -#define SRC_REWRITE_IP6_2 0 -#define SRC_REWRITE_IP6_3 6 - -#define DST_REWRITE_IP6_0 0 -#define DST_REWRITE_IP6_1 0 -#define DST_REWRITE_IP6_2 0 -#define DST_REWRITE_IP6_3 1 - -#define DST_REWRITE_PORT6 6666 - -int _version SEC("version") = 1; - -SEC("cgroup/sendmsg6") -int sendmsg_v6_prog(struct bpf_sock_addr *ctx) -{ - if (ctx->type != SOCK_DGRAM) - return 0; - - /* Rewrite source. */ - if (ctx->msg_src_ip6[3] == bpf_htonl(1) || - ctx->msg_src_ip6[3] == bpf_htonl(0)) { - ctx->msg_src_ip6[0] = bpf_htonl(SRC_REWRITE_IP6_0); - ctx->msg_src_ip6[1] = bpf_htonl(SRC_REWRITE_IP6_1); - ctx->msg_src_ip6[2] = bpf_htonl(SRC_REWRITE_IP6_2); - ctx->msg_src_ip6[3] = bpf_htonl(SRC_REWRITE_IP6_3); - } else { - /* Unexpected source. Reject sendmsg. */ - return 0; - } - - /* Rewrite destination. */ - if ((ctx->user_ip6[0] & 0xFFFF) == bpf_htons(0xFACE) && - ctx->user_ip6[0] >> 16 == bpf_htons(0xB00C)) { - ctx->user_ip6[0] = bpf_htonl(DST_REWRITE_IP6_0); - ctx->user_ip6[1] = bpf_htonl(DST_REWRITE_IP6_1); - ctx->user_ip6[2] = bpf_htonl(DST_REWRITE_IP6_2); - ctx->user_ip6[3] = bpf_htonl(DST_REWRITE_IP6_3); - - ctx->user_port = bpf_htons(DST_REWRITE_PORT6); - } else { - /* Unexpected destination. Reject sendmsg. */ - return 0; - } - - return 1; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/socket_cookie_prog.c b/tools/testing/selftests/bpf/socket_cookie_prog.c deleted file mode 100644 index 9ff8ac4b0bf6..000000000000 --- a/tools/testing/selftests/bpf/socket_cookie_prog.c +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Facebook - -#include -#include - -#include "bpf_helpers.h" -#include "bpf_endian.h" - -struct bpf_map_def SEC("maps") socket_cookies = { - .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(__u64), - .value_size = sizeof(__u32), - .max_entries = 1 << 8, -}; - -SEC("cgroup/connect6") -int set_cookie(struct bpf_sock_addr *ctx) -{ - __u32 cookie_value = 0xFF; - __u64 cookie_key; - - if (ctx->family != AF_INET6 || ctx->user_family != AF_INET6) - return 1; - - cookie_key = bpf_get_socket_cookie(ctx); - if (bpf_map_update_elem(&socket_cookies, &cookie_key, &cookie_value, 0)) - return 0; - - return 1; -} - -SEC("sockops") -int update_cookie(struct bpf_sock_ops *ctx) -{ - __u32 new_cookie_value; - __u32 *cookie_value; - __u64 cookie_key; - - if (ctx->family != AF_INET6) - return 1; - - if (ctx->op != BPF_SOCK_OPS_TCP_CONNECT_CB) - return 1; - - cookie_key = bpf_get_socket_cookie(ctx); - - cookie_value = bpf_map_lookup_elem(&socket_cookies, &cookie_key); - if (!cookie_value) - return 1; - - new_cookie_value = (ctx->local_port << 8) | *cookie_value; - bpf_map_update_elem(&socket_cookies, &cookie_key, &new_cookie_value, 0); - - return 1; -} - -int _version SEC("version") = 1; - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/sockmap_parse_prog.c b/tools/testing/selftests/bpf/sockmap_parse_prog.c deleted file mode 100644 index 0f92858f6226..000000000000 --- a/tools/testing/selftests/bpf/sockmap_parse_prog.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include "bpf_helpers.h" -#include "bpf_util.h" -#include "bpf_endian.h" - -int _version SEC("version") = 1; - -#define bpf_printk(fmt, ...) \ -({ \ - char ____fmt[] = fmt; \ - bpf_trace_printk(____fmt, sizeof(____fmt), \ - ##__VA_ARGS__); \ -}) - -SEC("sk_skb1") -int bpf_prog1(struct __sk_buff *skb) -{ - void *data_end = (void *)(long) skb->data_end; - void *data = (void *)(long) skb->data; - __u32 lport = skb->local_port; - __u32 rport = skb->remote_port; - __u8 *d = data; - __u32 len = (__u32) data_end - (__u32) data; - int err; - - if (data + 10 > data_end) { - err = bpf_skb_pull_data(skb, 10); - if (err) - return SK_DROP; - - data_end = (void *)(long)skb->data_end; - data = (void *)(long)skb->data; - if (data + 10 > data_end) - return SK_DROP; - } - - /* This write/read is a bit pointless but tests the verifier and - * strparser handler for read/write pkt data and access into sk - * fields. - */ - d = data; - d[7] = 1; - return skb->len; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c b/tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c deleted file mode 100644 index 12a7b5c82ed6..000000000000 --- a/tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include "bpf_helpers.h" -#include "bpf_util.h" -#include "bpf_endian.h" - -int _version SEC("version") = 1; - -#define bpf_printk(fmt, ...) \ -({ \ - char ____fmt[] = fmt; \ - bpf_trace_printk(____fmt, sizeof(____fmt), \ - ##__VA_ARGS__); \ -}) - -SEC("sk_msg1") -int bpf_prog1(struct sk_msg_md *msg) -{ - void *data_end = (void *)(long) msg->data_end; - void *data = (void *)(long) msg->data; - - char *d; - - if (data + 8 > data_end) - return SK_DROP; - - bpf_printk("data length %i\n", (__u64)msg->data_end - (__u64)msg->data); - d = (char *)data; - bpf_printk("hello sendmsg hook %i %i\n", d[0], d[1]); - - return SK_PASS; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/sockmap_verdict_prog.c b/tools/testing/selftests/bpf/sockmap_verdict_prog.c deleted file mode 100644 index 2ce7634a4012..000000000000 --- a/tools/testing/selftests/bpf/sockmap_verdict_prog.c +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include "bpf_helpers.h" -#include "bpf_util.h" -#include "bpf_endian.h" - -int _version SEC("version") = 1; - -#define bpf_printk(fmt, ...) \ -({ \ - char ____fmt[] = fmt; \ - bpf_trace_printk(____fmt, sizeof(____fmt), \ - ##__VA_ARGS__); \ -}) - -struct bpf_map_def SEC("maps") sock_map_rx = { - .type = BPF_MAP_TYPE_SOCKMAP, - .key_size = sizeof(int), - .value_size = sizeof(int), - .max_entries = 20, -}; - -struct bpf_map_def SEC("maps") sock_map_tx = { - .type = BPF_MAP_TYPE_SOCKMAP, - .key_size = sizeof(int), - .value_size = sizeof(int), - .max_entries = 20, -}; - -struct bpf_map_def SEC("maps") sock_map_msg = { - .type = BPF_MAP_TYPE_SOCKMAP, - .key_size = sizeof(int), - .value_size = sizeof(int), - .max_entries = 20, -}; - -struct bpf_map_def SEC("maps") sock_map_break = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(int), - .value_size = sizeof(int), - .max_entries = 20, -}; - -SEC("sk_skb2") -int bpf_prog2(struct __sk_buff *skb) -{ - void *data_end = (void *)(long) skb->data_end; - void *data = (void *)(long) skb->data; - __u32 lport = skb->local_port; - __u32 rport = skb->remote_port; - __u8 *d = data; - __u8 sk, map; - - if (data + 8 > data_end) - return SK_DROP; - - map = d[0]; - sk = d[1]; - - d[0] = 0xd; - d[1] = 0xe; - d[2] = 0xa; - d[3] = 0xd; - d[4] = 0xb; - d[5] = 0xe; - d[6] = 0xe; - d[7] = 0xf; - - if (!map) - return bpf_sk_redirect_map(skb, &sock_map_rx, sk, 0); - return bpf_sk_redirect_map(skb, &sock_map_tx, sk, 0); -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_adjust_tail.c b/tools/testing/selftests/bpf/test_adjust_tail.c deleted file mode 100644 index 4cd5e860c903..000000000000 --- a/tools/testing/selftests/bpf/test_adjust_tail.c +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 - * Copyright (c) 2018 Facebook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#include -#include -#include "bpf_helpers.h" - -int _version SEC("version") = 1; - -SEC("xdp_adjust_tail") -int _xdp_adjust_tail(struct xdp_md *xdp) -{ - void *data_end = (void *)(long)xdp->data_end; - void *data = (void *)(long)xdp->data; - int offset = 0; - - if (data_end - data == 54) - offset = 256; - else - offset = 20; - if (bpf_xdp_adjust_tail(xdp, 0 - offset)) - return XDP_DROP; - return XDP_TX; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_btf_haskv.c b/tools/testing/selftests/bpf/test_btf_haskv.c deleted file mode 100644 index e5c79fe0ffdb..000000000000 --- a/tools/testing/selftests/bpf/test_btf_haskv.c +++ /dev/null @@ -1,57 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2018 Facebook */ -#include -#include "bpf_helpers.h" - -int _version SEC("version") = 1; - -struct ipv_counts { - unsigned int v4; - unsigned int v6; -}; - -struct bpf_map_def SEC("maps") btf_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(int), - .value_size = sizeof(struct ipv_counts), - .max_entries = 4, -}; - -BPF_ANNOTATE_KV_PAIR(btf_map, int, struct ipv_counts); - -struct dummy_tracepoint_args { - unsigned long long pad; - struct sock *sock; -}; - -__attribute__((noinline)) -static int test_long_fname_2(struct dummy_tracepoint_args *arg) -{ - struct ipv_counts *counts; - int key = 0; - - if (!arg->sock) - return 0; - - counts = bpf_map_lookup_elem(&btf_map, &key); - if (!counts) - return 0; - - counts->v6++; - - return 0; -} - -__attribute__((noinline)) -static int test_long_fname_1(struct dummy_tracepoint_args *arg) -{ - return test_long_fname_2(arg); -} - -SEC("dummy_tracepoint") -int _dummy_tracepoint(struct dummy_tracepoint_args *arg) -{ - return test_long_fname_1(arg); -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_btf_nokv.c b/tools/testing/selftests/bpf/test_btf_nokv.c deleted file mode 100644 index 434188c37774..000000000000 --- a/tools/testing/selftests/bpf/test_btf_nokv.c +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2018 Facebook */ -#include -#include "bpf_helpers.h" - -int _version SEC("version") = 1; - -struct ipv_counts { - unsigned int v4; - unsigned int v6; -}; - -struct bpf_map_def SEC("maps") btf_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(int), - .value_size = sizeof(struct ipv_counts), - .max_entries = 4, -}; - -struct dummy_tracepoint_args { - unsigned long long pad; - struct sock *sock; -}; - -__attribute__((noinline)) -static int test_long_fname_2(struct dummy_tracepoint_args *arg) -{ - struct ipv_counts *counts; - int key = 0; - - if (!arg->sock) - return 0; - - counts = bpf_map_lookup_elem(&btf_map, &key); - if (!counts) - return 0; - - counts->v6++; - - return 0; -} - -__attribute__((noinline)) -static int test_long_fname_1(struct dummy_tracepoint_args *arg) -{ - return test_long_fname_2(arg); -} - -SEC("dummy_tracepoint") -int _dummy_tracepoint(struct dummy_tracepoint_args *arg) -{ - return test_long_fname_1(arg); -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_get_stack_rawtp.c b/tools/testing/selftests/bpf/test_get_stack_rawtp.c deleted file mode 100644 index f6d9f238e00a..000000000000 --- a/tools/testing/selftests/bpf/test_get_stack_rawtp.c +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include "bpf_helpers.h" - -/* Permit pretty deep stack traces */ -#define MAX_STACK_RAWTP 100 -struct stack_trace_t { - int pid; - int kern_stack_size; - int user_stack_size; - int user_stack_buildid_size; - __u64 kern_stack[MAX_STACK_RAWTP]; - __u64 user_stack[MAX_STACK_RAWTP]; - struct bpf_stack_build_id user_stack_buildid[MAX_STACK_RAWTP]; -}; - -struct bpf_map_def SEC("maps") perfmap = { - .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, - .key_size = sizeof(int), - .value_size = sizeof(__u32), - .max_entries = 2, -}; - -struct bpf_map_def SEC("maps") stackdata_map = { - .type = BPF_MAP_TYPE_PERCPU_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct stack_trace_t), - .max_entries = 1, -}; - -/* Allocate per-cpu space twice the needed. For the code below - * usize = bpf_get_stack(ctx, raw_data, max_len, BPF_F_USER_STACK); - * if (usize < 0) - * return 0; - * ksize = bpf_get_stack(ctx, raw_data + usize, max_len - usize, 0); - * - * If we have value_size = MAX_STACK_RAWTP * sizeof(__u64), - * verifier will complain that access "raw_data + usize" - * with size "max_len - usize" may be out of bound. - * The maximum "raw_data + usize" is "raw_data + max_len" - * and the maximum "max_len - usize" is "max_len", verifier - * concludes that the maximum buffer access range is - * "raw_data[0...max_len * 2 - 1]" and hence reject the program. - * - * Doubling the to-be-used max buffer size can fix this verifier - * issue and avoid complicated C programming massaging. - * This is an acceptable workaround since there is one entry here. - */ -struct bpf_map_def SEC("maps") rawdata_map = { - .type = BPF_MAP_TYPE_PERCPU_ARRAY, - .key_size = sizeof(__u32), - .value_size = MAX_STACK_RAWTP * sizeof(__u64) * 2, - .max_entries = 1, -}; - -SEC("tracepoint/raw_syscalls/sys_enter") -int bpf_prog1(void *ctx) -{ - int max_len, max_buildid_len, usize, ksize, total_size; - struct stack_trace_t *data; - void *raw_data; - __u32 key = 0; - - data = bpf_map_lookup_elem(&stackdata_map, &key); - if (!data) - return 0; - - max_len = MAX_STACK_RAWTP * sizeof(__u64); - max_buildid_len = MAX_STACK_RAWTP * sizeof(struct bpf_stack_build_id); - data->pid = bpf_get_current_pid_tgid(); - data->kern_stack_size = bpf_get_stack(ctx, data->kern_stack, - max_len, 0); - data->user_stack_size = bpf_get_stack(ctx, data->user_stack, max_len, - BPF_F_USER_STACK); - data->user_stack_buildid_size = bpf_get_stack( - ctx, data->user_stack_buildid, max_buildid_len, - BPF_F_USER_STACK | BPF_F_USER_BUILD_ID); - bpf_perf_event_output(ctx, &perfmap, 0, data, sizeof(*data)); - - /* write both kernel and user stacks to the same buffer */ - raw_data = bpf_map_lookup_elem(&rawdata_map, &key); - if (!raw_data) - return 0; - - usize = bpf_get_stack(ctx, raw_data, max_len, BPF_F_USER_STACK); - if (usize < 0) - return 0; - - ksize = bpf_get_stack(ctx, raw_data + usize, max_len - usize, 0); - if (ksize < 0) - return 0; - - total_size = usize + ksize; - if (total_size > 0 && total_size <= max_len) - bpf_perf_event_output(ctx, &perfmap, 0, raw_data, total_size); - - return 0; -} - -char _license[] SEC("license") = "GPL"; -__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/test_l4lb.c b/tools/testing/selftests/bpf/test_l4lb.c deleted file mode 100644 index 1e10c9590991..000000000000 --- a/tools/testing/selftests/bpf/test_l4lb.c +++ /dev/null @@ -1,473 +0,0 @@ -/* Copyright (c) 2017 Facebook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bpf_helpers.h" -#include "test_iptunnel_common.h" -#include "bpf_endian.h" - -int _version SEC("version") = 1; - -static inline __u32 rol32(__u32 word, unsigned int shift) -{ - return (word << shift) | (word >> ((-shift) & 31)); -} - -/* copy paste of jhash from kernel sources to make sure llvm - * can compile it into valid sequence of bpf instructions - */ -#define __jhash_mix(a, b, c) \ -{ \ - a -= c; a ^= rol32(c, 4); c += b; \ - b -= a; b ^= rol32(a, 6); a += c; \ - c -= b; c ^= rol32(b, 8); b += a; \ - a -= c; a ^= rol32(c, 16); c += b; \ - b -= a; b ^= rol32(a, 19); a += c; \ - c -= b; c ^= rol32(b, 4); b += a; \ -} - -#define __jhash_final(a, b, c) \ -{ \ - c ^= b; c -= rol32(b, 14); \ - a ^= c; a -= rol32(c, 11); \ - b ^= a; b -= rol32(a, 25); \ - c ^= b; c -= rol32(b, 16); \ - a ^= c; a -= rol32(c, 4); \ - b ^= a; b -= rol32(a, 14); \ - c ^= b; c -= rol32(b, 24); \ -} - -#define JHASH_INITVAL 0xdeadbeef - -typedef unsigned int u32; - -static inline u32 jhash(const void *key, u32 length, u32 initval) -{ - u32 a, b, c; - const unsigned char *k = key; - - a = b = c = JHASH_INITVAL + length + initval; - - while (length > 12) { - a += *(u32 *)(k); - b += *(u32 *)(k + 4); - c += *(u32 *)(k + 8); - __jhash_mix(a, b, c); - length -= 12; - k += 12; - } - switch (length) { - case 12: c += (u32)k[11]<<24; - case 11: c += (u32)k[10]<<16; - case 10: c += (u32)k[9]<<8; - case 9: c += k[8]; - case 8: b += (u32)k[7]<<24; - case 7: b += (u32)k[6]<<16; - case 6: b += (u32)k[5]<<8; - case 5: b += k[4]; - case 4: a += (u32)k[3]<<24; - case 3: a += (u32)k[2]<<16; - case 2: a += (u32)k[1]<<8; - case 1: a += k[0]; - __jhash_final(a, b, c); - case 0: /* Nothing left to add */ - break; - } - - return c; -} - -static inline u32 __jhash_nwords(u32 a, u32 b, u32 c, u32 initval) -{ - a += initval; - b += initval; - c += initval; - __jhash_final(a, b, c); - return c; -} - -static inline u32 jhash_2words(u32 a, u32 b, u32 initval) -{ - return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2)); -} - -#define PCKT_FRAGMENTED 65343 -#define IPV4_HDR_LEN_NO_OPT 20 -#define IPV4_PLUS_ICMP_HDR 28 -#define IPV6_PLUS_ICMP_HDR 48 -#define RING_SIZE 2 -#define MAX_VIPS 12 -#define MAX_REALS 5 -#define CTL_MAP_SIZE 16 -#define CH_RINGS_SIZE (MAX_VIPS * RING_SIZE) -#define F_IPV6 (1 << 0) -#define F_HASH_NO_SRC_PORT (1 << 0) -#define F_ICMP (1 << 0) -#define F_SYN_SET (1 << 1) - -struct packet_description { - union { - __be32 src; - __be32 srcv6[4]; - }; - union { - __be32 dst; - __be32 dstv6[4]; - }; - union { - __u32 ports; - __u16 port16[2]; - }; - __u8 proto; - __u8 flags; -}; - -struct ctl_value { - union { - __u64 value; - __u32 ifindex; - __u8 mac[6]; - }; -}; - -struct vip_meta { - __u32 flags; - __u32 vip_num; -}; - -struct real_definition { - union { - __be32 dst; - __be32 dstv6[4]; - }; - __u8 flags; -}; - -struct vip_stats { - __u64 bytes; - __u64 pkts; -}; - -struct eth_hdr { - unsigned char eth_dest[ETH_ALEN]; - unsigned char eth_source[ETH_ALEN]; - unsigned short eth_proto; -}; - -struct bpf_map_def SEC("maps") vip_map = { - .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(struct vip), - .value_size = sizeof(struct vip_meta), - .max_entries = MAX_VIPS, -}; - -struct bpf_map_def SEC("maps") ch_rings = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = CH_RINGS_SIZE, -}; - -struct bpf_map_def SEC("maps") reals = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct real_definition), - .max_entries = MAX_REALS, -}; - -struct bpf_map_def SEC("maps") stats = { - .type = BPF_MAP_TYPE_PERCPU_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct vip_stats), - .max_entries = MAX_VIPS, -}; - -struct bpf_map_def SEC("maps") ctl_array = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct ctl_value), - .max_entries = CTL_MAP_SIZE, -}; - -static __always_inline __u32 get_packet_hash(struct packet_description *pckt, - bool ipv6) -{ - if (ipv6) - return jhash_2words(jhash(pckt->srcv6, 16, MAX_VIPS), - pckt->ports, CH_RINGS_SIZE); - else - return jhash_2words(pckt->src, pckt->ports, CH_RINGS_SIZE); -} - -static __always_inline bool get_packet_dst(struct real_definition **real, - struct packet_description *pckt, - struct vip_meta *vip_info, - bool is_ipv6) -{ - __u32 hash = get_packet_hash(pckt, is_ipv6) % RING_SIZE; - __u32 key = RING_SIZE * vip_info->vip_num + hash; - __u32 *real_pos; - - real_pos = bpf_map_lookup_elem(&ch_rings, &key); - if (!real_pos) - return false; - key = *real_pos; - *real = bpf_map_lookup_elem(&reals, &key); - if (!(*real)) - return false; - return true; -} - -static __always_inline int parse_icmpv6(void *data, void *data_end, __u64 off, - struct packet_description *pckt) -{ - struct icmp6hdr *icmp_hdr; - struct ipv6hdr *ip6h; - - icmp_hdr = data + off; - if (icmp_hdr + 1 > data_end) - return TC_ACT_SHOT; - if (icmp_hdr->icmp6_type != ICMPV6_PKT_TOOBIG) - return TC_ACT_OK; - off += sizeof(struct icmp6hdr); - ip6h = data + off; - if (ip6h + 1 > data_end) - return TC_ACT_SHOT; - pckt->proto = ip6h->nexthdr; - pckt->flags |= F_ICMP; - memcpy(pckt->srcv6, ip6h->daddr.s6_addr32, 16); - memcpy(pckt->dstv6, ip6h->saddr.s6_addr32, 16); - return TC_ACT_UNSPEC; -} - -static __always_inline int parse_icmp(void *data, void *data_end, __u64 off, - struct packet_description *pckt) -{ - struct icmphdr *icmp_hdr; - struct iphdr *iph; - - icmp_hdr = data + off; - if (icmp_hdr + 1 > data_end) - return TC_ACT_SHOT; - if (icmp_hdr->type != ICMP_DEST_UNREACH || - icmp_hdr->code != ICMP_FRAG_NEEDED) - return TC_ACT_OK; - off += sizeof(struct icmphdr); - iph = data + off; - if (iph + 1 > data_end) - return TC_ACT_SHOT; - if (iph->ihl != 5) - return TC_ACT_SHOT; - pckt->proto = iph->protocol; - pckt->flags |= F_ICMP; - pckt->src = iph->daddr; - pckt->dst = iph->saddr; - return TC_ACT_UNSPEC; -} - -static __always_inline bool parse_udp(void *data, __u64 off, void *data_end, - struct packet_description *pckt) -{ - struct udphdr *udp; - udp = data + off; - - if (udp + 1 > data_end) - return false; - - if (!(pckt->flags & F_ICMP)) { - pckt->port16[0] = udp->source; - pckt->port16[1] = udp->dest; - } else { - pckt->port16[0] = udp->dest; - pckt->port16[1] = udp->source; - } - return true; -} - -static __always_inline bool parse_tcp(void *data, __u64 off, void *data_end, - struct packet_description *pckt) -{ - struct tcphdr *tcp; - - tcp = data + off; - if (tcp + 1 > data_end) - return false; - - if (tcp->syn) - pckt->flags |= F_SYN_SET; - - if (!(pckt->flags & F_ICMP)) { - pckt->port16[0] = tcp->source; - pckt->port16[1] = tcp->dest; - } else { - pckt->port16[0] = tcp->dest; - pckt->port16[1] = tcp->source; - } - return true; -} - -static __always_inline int process_packet(void *data, __u64 off, void *data_end, - bool is_ipv6, struct __sk_buff *skb) -{ - void *pkt_start = (void *)(long)skb->data; - struct packet_description pckt = {}; - struct eth_hdr *eth = pkt_start; - struct bpf_tunnel_key tkey = {}; - struct vip_stats *data_stats; - struct real_definition *dst; - struct vip_meta *vip_info; - struct ctl_value *cval; - __u32 v4_intf_pos = 1; - __u32 v6_intf_pos = 2; - struct ipv6hdr *ip6h; - struct vip vip = {}; - struct iphdr *iph; - int tun_flag = 0; - __u16 pkt_bytes; - __u64 iph_len; - __u32 ifindex; - __u8 protocol; - __u32 vip_num; - int action; - - tkey.tunnel_ttl = 64; - if (is_ipv6) { - ip6h = data + off; - if (ip6h + 1 > data_end) - return TC_ACT_SHOT; - - iph_len = sizeof(struct ipv6hdr); - protocol = ip6h->nexthdr; - pckt.proto = protocol; - pkt_bytes = bpf_ntohs(ip6h->payload_len); - off += iph_len; - if (protocol == IPPROTO_FRAGMENT) { - return TC_ACT_SHOT; - } else if (protocol == IPPROTO_ICMPV6) { - action = parse_icmpv6(data, data_end, off, &pckt); - if (action >= 0) - return action; - off += IPV6_PLUS_ICMP_HDR; - } else { - memcpy(pckt.srcv6, ip6h->saddr.s6_addr32, 16); - memcpy(pckt.dstv6, ip6h->daddr.s6_addr32, 16); - } - } else { - iph = data + off; - if (iph + 1 > data_end) - return TC_ACT_SHOT; - if (iph->ihl != 5) - return TC_ACT_SHOT; - - protocol = iph->protocol; - pckt.proto = protocol; - pkt_bytes = bpf_ntohs(iph->tot_len); - off += IPV4_HDR_LEN_NO_OPT; - - if (iph->frag_off & PCKT_FRAGMENTED) - return TC_ACT_SHOT; - if (protocol == IPPROTO_ICMP) { - action = parse_icmp(data, data_end, off, &pckt); - if (action >= 0) - return action; - off += IPV4_PLUS_ICMP_HDR; - } else { - pckt.src = iph->saddr; - pckt.dst = iph->daddr; - } - } - protocol = pckt.proto; - - if (protocol == IPPROTO_TCP) { - if (!parse_tcp(data, off, data_end, &pckt)) - return TC_ACT_SHOT; - } else if (protocol == IPPROTO_UDP) { - if (!parse_udp(data, off, data_end, &pckt)) - return TC_ACT_SHOT; - } else { - return TC_ACT_SHOT; - } - - if (is_ipv6) - memcpy(vip.daddr.v6, pckt.dstv6, 16); - else - vip.daddr.v4 = pckt.dst; - - vip.dport = pckt.port16[1]; - vip.protocol = pckt.proto; - vip_info = bpf_map_lookup_elem(&vip_map, &vip); - if (!vip_info) { - vip.dport = 0; - vip_info = bpf_map_lookup_elem(&vip_map, &vip); - if (!vip_info) - return TC_ACT_SHOT; - pckt.port16[1] = 0; - } - - if (vip_info->flags & F_HASH_NO_SRC_PORT) - pckt.port16[0] = 0; - - if (!get_packet_dst(&dst, &pckt, vip_info, is_ipv6)) - return TC_ACT_SHOT; - - if (dst->flags & F_IPV6) { - cval = bpf_map_lookup_elem(&ctl_array, &v6_intf_pos); - if (!cval) - return TC_ACT_SHOT; - ifindex = cval->ifindex; - memcpy(tkey.remote_ipv6, dst->dstv6, 16); - tun_flag = BPF_F_TUNINFO_IPV6; - } else { - cval = bpf_map_lookup_elem(&ctl_array, &v4_intf_pos); - if (!cval) - return TC_ACT_SHOT; - ifindex = cval->ifindex; - tkey.remote_ipv4 = dst->dst; - } - vip_num = vip_info->vip_num; - data_stats = bpf_map_lookup_elem(&stats, &vip_num); - if (!data_stats) - return TC_ACT_SHOT; - data_stats->pkts++; - data_stats->bytes += pkt_bytes; - bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), tun_flag); - *(u32 *)eth->eth_dest = tkey.remote_ipv4; - return bpf_redirect(ifindex, 0); -} - -SEC("l4lb-demo") -int balancer_ingress(struct __sk_buff *ctx) -{ - void *data_end = (void *)(long)ctx->data_end; - void *data = (void *)(long)ctx->data; - struct eth_hdr *eth = data; - __u32 eth_proto; - __u32 nh_off; - - nh_off = sizeof(struct eth_hdr); - if (data + nh_off > data_end) - return TC_ACT_SHOT; - eth_proto = eth->eth_proto; - if (eth_proto == bpf_htons(ETH_P_IP)) - return process_packet(data, nh_off, data_end, false, ctx); - else if (eth_proto == bpf_htons(ETH_P_IPV6)) - return process_packet(data, nh_off, data_end, true, ctx); - else - return TC_ACT_SHOT; -} -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_l4lb_noinline.c b/tools/testing/selftests/bpf/test_l4lb_noinline.c deleted file mode 100644 index ba44a14e6dc4..000000000000 --- a/tools/testing/selftests/bpf/test_l4lb_noinline.c +++ /dev/null @@ -1,473 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2017 Facebook -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bpf_helpers.h" -#include "test_iptunnel_common.h" -#include "bpf_endian.h" - -int _version SEC("version") = 1; - -static __u32 rol32(__u32 word, unsigned int shift) -{ - return (word << shift) | (word >> ((-shift) & 31)); -} - -/* copy paste of jhash from kernel sources to make sure llvm - * can compile it into valid sequence of bpf instructions - */ -#define __jhash_mix(a, b, c) \ -{ \ - a -= c; a ^= rol32(c, 4); c += b; \ - b -= a; b ^= rol32(a, 6); a += c; \ - c -= b; c ^= rol32(b, 8); b += a; \ - a -= c; a ^= rol32(c, 16); c += b; \ - b -= a; b ^= rol32(a, 19); a += c; \ - c -= b; c ^= rol32(b, 4); b += a; \ -} - -#define __jhash_final(a, b, c) \ -{ \ - c ^= b; c -= rol32(b, 14); \ - a ^= c; a -= rol32(c, 11); \ - b ^= a; b -= rol32(a, 25); \ - c ^= b; c -= rol32(b, 16); \ - a ^= c; a -= rol32(c, 4); \ - b ^= a; b -= rol32(a, 14); \ - c ^= b; c -= rol32(b, 24); \ -} - -#define JHASH_INITVAL 0xdeadbeef - -typedef unsigned int u32; - -static u32 jhash(const void *key, u32 length, u32 initval) -{ - u32 a, b, c; - const unsigned char *k = key; - - a = b = c = JHASH_INITVAL + length + initval; - - while (length > 12) { - a += *(u32 *)(k); - b += *(u32 *)(k + 4); - c += *(u32 *)(k + 8); - __jhash_mix(a, b, c); - length -= 12; - k += 12; - } - switch (length) { - case 12: c += (u32)k[11]<<24; - case 11: c += (u32)k[10]<<16; - case 10: c += (u32)k[9]<<8; - case 9: c += k[8]; - case 8: b += (u32)k[7]<<24; - case 7: b += (u32)k[6]<<16; - case 6: b += (u32)k[5]<<8; - case 5: b += k[4]; - case 4: a += (u32)k[3]<<24; - case 3: a += (u32)k[2]<<16; - case 2: a += (u32)k[1]<<8; - case 1: a += k[0]; - __jhash_final(a, b, c); - case 0: /* Nothing left to add */ - break; - } - - return c; -} - -static u32 __jhash_nwords(u32 a, u32 b, u32 c, u32 initval) -{ - a += initval; - b += initval; - c += initval; - __jhash_final(a, b, c); - return c; -} - -static u32 jhash_2words(u32 a, u32 b, u32 initval) -{ - return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2)); -} - -#define PCKT_FRAGMENTED 65343 -#define IPV4_HDR_LEN_NO_OPT 20 -#define IPV4_PLUS_ICMP_HDR 28 -#define IPV6_PLUS_ICMP_HDR 48 -#define RING_SIZE 2 -#define MAX_VIPS 12 -#define MAX_REALS 5 -#define CTL_MAP_SIZE 16 -#define CH_RINGS_SIZE (MAX_VIPS * RING_SIZE) -#define F_IPV6 (1 << 0) -#define F_HASH_NO_SRC_PORT (1 << 0) -#define F_ICMP (1 << 0) -#define F_SYN_SET (1 << 1) - -struct packet_description { - union { - __be32 src; - __be32 srcv6[4]; - }; - union { - __be32 dst; - __be32 dstv6[4]; - }; - union { - __u32 ports; - __u16 port16[2]; - }; - __u8 proto; - __u8 flags; -}; - -struct ctl_value { - union { - __u64 value; - __u32 ifindex; - __u8 mac[6]; - }; -}; - -struct vip_meta { - __u32 flags; - __u32 vip_num; -}; - -struct real_definition { - union { - __be32 dst; - __be32 dstv6[4]; - }; - __u8 flags; -}; - -struct vip_stats { - __u64 bytes; - __u64 pkts; -}; - -struct eth_hdr { - unsigned char eth_dest[ETH_ALEN]; - unsigned char eth_source[ETH_ALEN]; - unsigned short eth_proto; -}; - -struct bpf_map_def SEC("maps") vip_map = { - .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(struct vip), - .value_size = sizeof(struct vip_meta), - .max_entries = MAX_VIPS, -}; - -struct bpf_map_def SEC("maps") ch_rings = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = CH_RINGS_SIZE, -}; - -struct bpf_map_def SEC("maps") reals = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct real_definition), - .max_entries = MAX_REALS, -}; - -struct bpf_map_def SEC("maps") stats = { - .type = BPF_MAP_TYPE_PERCPU_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct vip_stats), - .max_entries = MAX_VIPS, -}; - -struct bpf_map_def SEC("maps") ctl_array = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct ctl_value), - .max_entries = CTL_MAP_SIZE, -}; - -static __u32 get_packet_hash(struct packet_description *pckt, - bool ipv6) -{ - if (ipv6) - return jhash_2words(jhash(pckt->srcv6, 16, MAX_VIPS), - pckt->ports, CH_RINGS_SIZE); - else - return jhash_2words(pckt->src, pckt->ports, CH_RINGS_SIZE); -} - -static bool get_packet_dst(struct real_definition **real, - struct packet_description *pckt, - struct vip_meta *vip_info, - bool is_ipv6) -{ - __u32 hash = get_packet_hash(pckt, is_ipv6); - __u32 key = RING_SIZE * vip_info->vip_num + hash % RING_SIZE; - __u32 *real_pos; - - if (hash != 0x358459b7 /* jhash of ipv4 packet */ && - hash != 0x2f4bc6bb /* jhash of ipv6 packet */) - return 0; - - real_pos = bpf_map_lookup_elem(&ch_rings, &key); - if (!real_pos) - return false; - key = *real_pos; - *real = bpf_map_lookup_elem(&reals, &key); - if (!(*real)) - return false; - return true; -} - -static int parse_icmpv6(void *data, void *data_end, __u64 off, - struct packet_description *pckt) -{ - struct icmp6hdr *icmp_hdr; - struct ipv6hdr *ip6h; - - icmp_hdr = data + off; - if (icmp_hdr + 1 > data_end) - return TC_ACT_SHOT; - if (icmp_hdr->icmp6_type != ICMPV6_PKT_TOOBIG) - return TC_ACT_OK; - off += sizeof(struct icmp6hdr); - ip6h = data + off; - if (ip6h + 1 > data_end) - return TC_ACT_SHOT; - pckt->proto = ip6h->nexthdr; - pckt->flags |= F_ICMP; - memcpy(pckt->srcv6, ip6h->daddr.s6_addr32, 16); - memcpy(pckt->dstv6, ip6h->saddr.s6_addr32, 16); - return TC_ACT_UNSPEC; -} - -static int parse_icmp(void *data, void *data_end, __u64 off, - struct packet_description *pckt) -{ - struct icmphdr *icmp_hdr; - struct iphdr *iph; - - icmp_hdr = data + off; - if (icmp_hdr + 1 > data_end) - return TC_ACT_SHOT; - if (icmp_hdr->type != ICMP_DEST_UNREACH || - icmp_hdr->code != ICMP_FRAG_NEEDED) - return TC_ACT_OK; - off += sizeof(struct icmphdr); - iph = data + off; - if (iph + 1 > data_end) - return TC_ACT_SHOT; - if (iph->ihl != 5) - return TC_ACT_SHOT; - pckt->proto = iph->protocol; - pckt->flags |= F_ICMP; - pckt->src = iph->daddr; - pckt->dst = iph->saddr; - return TC_ACT_UNSPEC; -} - -static bool parse_udp(void *data, __u64 off, void *data_end, - struct packet_description *pckt) -{ - struct udphdr *udp; - udp = data + off; - - if (udp + 1 > data_end) - return false; - - if (!(pckt->flags & F_ICMP)) { - pckt->port16[0] = udp->source; - pckt->port16[1] = udp->dest; - } else { - pckt->port16[0] = udp->dest; - pckt->port16[1] = udp->source; - } - return true; -} - -static bool parse_tcp(void *data, __u64 off, void *data_end, - struct packet_description *pckt) -{ - struct tcphdr *tcp; - - tcp = data + off; - if (tcp + 1 > data_end) - return false; - - if (tcp->syn) - pckt->flags |= F_SYN_SET; - - if (!(pckt->flags & F_ICMP)) { - pckt->port16[0] = tcp->source; - pckt->port16[1] = tcp->dest; - } else { - pckt->port16[0] = tcp->dest; - pckt->port16[1] = tcp->source; - } - return true; -} - -static int process_packet(void *data, __u64 off, void *data_end, - bool is_ipv6, struct __sk_buff *skb) -{ - void *pkt_start = (void *)(long)skb->data; - struct packet_description pckt = {}; - struct eth_hdr *eth = pkt_start; - struct bpf_tunnel_key tkey = {}; - struct vip_stats *data_stats; - struct real_definition *dst; - struct vip_meta *vip_info; - struct ctl_value *cval; - __u32 v4_intf_pos = 1; - __u32 v6_intf_pos = 2; - struct ipv6hdr *ip6h; - struct vip vip = {}; - struct iphdr *iph; - int tun_flag = 0; - __u16 pkt_bytes; - __u64 iph_len; - __u32 ifindex; - __u8 protocol; - __u32 vip_num; - int action; - - tkey.tunnel_ttl = 64; - if (is_ipv6) { - ip6h = data + off; - if (ip6h + 1 > data_end) - return TC_ACT_SHOT; - - iph_len = sizeof(struct ipv6hdr); - protocol = ip6h->nexthdr; - pckt.proto = protocol; - pkt_bytes = bpf_ntohs(ip6h->payload_len); - off += iph_len; - if (protocol == IPPROTO_FRAGMENT) { - return TC_ACT_SHOT; - } else if (protocol == IPPROTO_ICMPV6) { - action = parse_icmpv6(data, data_end, off, &pckt); - if (action >= 0) - return action; - off += IPV6_PLUS_ICMP_HDR; - } else { - memcpy(pckt.srcv6, ip6h->saddr.s6_addr32, 16); - memcpy(pckt.dstv6, ip6h->daddr.s6_addr32, 16); - } - } else { - iph = data + off; - if (iph + 1 > data_end) - return TC_ACT_SHOT; - if (iph->ihl != 5) - return TC_ACT_SHOT; - - protocol = iph->protocol; - pckt.proto = protocol; - pkt_bytes = bpf_ntohs(iph->tot_len); - off += IPV4_HDR_LEN_NO_OPT; - - if (iph->frag_off & PCKT_FRAGMENTED) - return TC_ACT_SHOT; - if (protocol == IPPROTO_ICMP) { - action = parse_icmp(data, data_end, off, &pckt); - if (action >= 0) - return action; - off += IPV4_PLUS_ICMP_HDR; - } else { - pckt.src = iph->saddr; - pckt.dst = iph->daddr; - } - } - protocol = pckt.proto; - - if (protocol == IPPROTO_TCP) { - if (!parse_tcp(data, off, data_end, &pckt)) - return TC_ACT_SHOT; - } else if (protocol == IPPROTO_UDP) { - if (!parse_udp(data, off, data_end, &pckt)) - return TC_ACT_SHOT; - } else { - return TC_ACT_SHOT; - } - - if (is_ipv6) - memcpy(vip.daddr.v6, pckt.dstv6, 16); - else - vip.daddr.v4 = pckt.dst; - - vip.dport = pckt.port16[1]; - vip.protocol = pckt.proto; - vip_info = bpf_map_lookup_elem(&vip_map, &vip); - if (!vip_info) { - vip.dport = 0; - vip_info = bpf_map_lookup_elem(&vip_map, &vip); - if (!vip_info) - return TC_ACT_SHOT; - pckt.port16[1] = 0; - } - - if (vip_info->flags & F_HASH_NO_SRC_PORT) - pckt.port16[0] = 0; - - if (!get_packet_dst(&dst, &pckt, vip_info, is_ipv6)) - return TC_ACT_SHOT; - - if (dst->flags & F_IPV6) { - cval = bpf_map_lookup_elem(&ctl_array, &v6_intf_pos); - if (!cval) - return TC_ACT_SHOT; - ifindex = cval->ifindex; - memcpy(tkey.remote_ipv6, dst->dstv6, 16); - tun_flag = BPF_F_TUNINFO_IPV6; - } else { - cval = bpf_map_lookup_elem(&ctl_array, &v4_intf_pos); - if (!cval) - return TC_ACT_SHOT; - ifindex = cval->ifindex; - tkey.remote_ipv4 = dst->dst; - } - vip_num = vip_info->vip_num; - data_stats = bpf_map_lookup_elem(&stats, &vip_num); - if (!data_stats) - return TC_ACT_SHOT; - data_stats->pkts++; - data_stats->bytes += pkt_bytes; - bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), tun_flag); - *(u32 *)eth->eth_dest = tkey.remote_ipv4; - return bpf_redirect(ifindex, 0); -} - -SEC("l4lb-demo") -int balancer_ingress(struct __sk_buff *ctx) -{ - void *data_end = (void *)(long)ctx->data_end; - void *data = (void *)(long)ctx->data; - struct eth_hdr *eth = data; - __u32 eth_proto; - __u32 nh_off; - - nh_off = sizeof(struct eth_hdr); - if (data + nh_off > data_end) - return TC_ACT_SHOT; - eth_proto = eth->eth_proto; - if (eth_proto == bpf_htons(ETH_P_IP)) - return process_packet(data, nh_off, data_end, false, ctx); - else if (eth_proto == bpf_htons(ETH_P_IPV6)) - return process_packet(data, nh_off, data_end, true, ctx); - else - return TC_ACT_SHOT; -} -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_lirc_mode2_kern.c b/tools/testing/selftests/bpf/test_lirc_mode2_kern.c deleted file mode 100644 index 4147130cc3b7..000000000000 --- a/tools/testing/selftests/bpf/test_lirc_mode2_kern.c +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// test ir decoder -// -// Copyright (C) 2018 Sean Young - -#include -#include -#include "bpf_helpers.h" - -SEC("lirc_mode2") -int bpf_decoder(unsigned int *sample) -{ - if (LIRC_IS_PULSE(*sample)) { - unsigned int duration = LIRC_VALUE(*sample); - - if (duration & 0x10000) - bpf_rc_keydown(sample, 0x40, duration & 0xffff, 0); - if (duration & 0x20000) - bpf_rc_pointer_rel(sample, (duration >> 8) & 0xff, - duration & 0xff); - } - - return 0; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_lwt_seg6local.c b/tools/testing/selftests/bpf/test_lwt_seg6local.c deleted file mode 100644 index 0575751bc1bc..000000000000 --- a/tools/testing/selftests/bpf/test_lwt_seg6local.c +++ /dev/null @@ -1,437 +0,0 @@ -#include -#include -#include -#include -#include -#include "bpf_helpers.h" -#include "bpf_endian.h" - -#define bpf_printk(fmt, ...) \ -({ \ - char ____fmt[] = fmt; \ - bpf_trace_printk(____fmt, sizeof(____fmt), \ - ##__VA_ARGS__); \ -}) - -/* Packet parsing state machine helpers. */ -#define cursor_advance(_cursor, _len) \ - ({ void *_tmp = _cursor; _cursor += _len; _tmp; }) - -#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 { - unsigned int ver:4; - unsigned int priority:8; - unsigned int flow_label:20; - unsigned short payload_len; - unsigned char next_header; - unsigned char hop_limit; - unsigned long long src_hi; - unsigned long long src_lo; - unsigned long long dst_hi; - unsigned long long dst_lo; -} BPF_PACKET_HEADER; - -struct ip6_addr_t { - unsigned long long hi; - unsigned long long lo; -} BPF_PACKET_HEADER; - -struct ip6_srh_t { - unsigned char nexthdr; - unsigned char hdrlen; - unsigned char type; - unsigned char segments_left; - unsigned char first_segment; - unsigned char flags; - unsigned short tag; - - struct ip6_addr_t segments[0]; -} BPF_PACKET_HEADER; - -struct sr6_tlv_t { - unsigned char type; - unsigned char len; - unsigned char value[0]; -} BPF_PACKET_HEADER; - -__attribute__((always_inline)) struct ip6_srh_t *get_srh(struct __sk_buff *skb) -{ - void *cursor, *data_end; - struct ip6_srh_t *srh; - struct ip6_t *ip; - uint8_t *ipver; - - data_end = (void *)(long)skb->data_end; - cursor = (void *)(long)skb->data; - ipver = (uint8_t *)cursor; - - if ((void *)ipver + sizeof(*ipver) > data_end) - return NULL; - - if ((*ipver >> 4) != 6) - return NULL; - - ip = cursor_advance(cursor, sizeof(*ip)); - if ((void *)ip + sizeof(*ip) > data_end) - return NULL; - - if (ip->next_header != 43) - return NULL; - - srh = cursor_advance(cursor, sizeof(*srh)); - if ((void *)srh + sizeof(*srh) > data_end) - return NULL; - - if (srh->type != 4) - return NULL; - - return srh; -} - -__attribute__((always_inline)) -int update_tlv_pad(struct __sk_buff *skb, uint32_t new_pad, - uint32_t old_pad, uint32_t pad_off) -{ - int err; - - if (new_pad != old_pad) { - err = bpf_lwt_seg6_adjust_srh(skb, pad_off, - (int) new_pad - (int) old_pad); - if (err) - return err; - } - - if (new_pad > 0) { - char pad_tlv_buf[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0}; - struct sr6_tlv_t *pad_tlv = (struct sr6_tlv_t *) pad_tlv_buf; - - pad_tlv->type = SR6_TLV_PADDING; - pad_tlv->len = new_pad - 2; - - err = bpf_lwt_seg6_store_bytes(skb, pad_off, - (void *)pad_tlv_buf, new_pad); - if (err) - return err; - } - - return 0; -} - -__attribute__((always_inline)) -int is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh, - uint32_t *tlv_off, uint32_t *pad_size, - uint32_t *pad_off) -{ - uint32_t srh_off, cur_off; - int offset_valid = 0; - int err; - - srh_off = (char *)srh - (char *)(long)skb->data; - // cur_off = end of segments, start of possible TLVs - cur_off = srh_off + sizeof(*srh) + - sizeof(struct ip6_addr_t) * (srh->first_segment + 1); - - *pad_off = 0; - - // we can only go as far as ~10 TLVs due to the BPF max stack size - #pragma clang loop unroll(full) - for (int i = 0; i < 10; i++) { - struct sr6_tlv_t tlv; - - if (cur_off == *tlv_off) - offset_valid = 1; - - if (cur_off >= srh_off + ((srh->hdrlen + 1) << 3)) - break; - - err = bpf_skb_load_bytes(skb, cur_off, &tlv, sizeof(tlv)); - if (err) - return err; - - if (tlv.type == SR6_TLV_PADDING) { - *pad_size = tlv.len + sizeof(tlv); - *pad_off = cur_off; - - if (*tlv_off == srh_off) { - *tlv_off = cur_off; - offset_valid = 1; - } - break; - - } else if (tlv.type == SR6_TLV_HMAC) { - break; - } - - cur_off += sizeof(tlv) + tlv.len; - } // we reached the padding or HMAC TLVs, or the end of the SRH - - if (*pad_off == 0) - *pad_off = cur_off; - - if (*tlv_off == -1) - *tlv_off = cur_off; - else if (!offset_valid) - return -EINVAL; - - return 0; -} - -__attribute__((always_inline)) -int add_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, uint32_t tlv_off, - struct sr6_tlv_t *itlv, uint8_t tlv_size) -{ - uint32_t srh_off = (char *)srh - (char *)(long)skb->data; - uint8_t len_remaining, new_pad; - uint32_t pad_off = 0; - uint32_t pad_size = 0; - uint32_t partial_srh_len; - int err; - - if (tlv_off != -1) - tlv_off += srh_off; - - if (itlv->type == SR6_TLV_PADDING || itlv->type == SR6_TLV_HMAC) - return -EINVAL; - - err = is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); - if (err) - return err; - - err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, sizeof(*itlv) + itlv->len); - if (err) - return err; - - err = bpf_lwt_seg6_store_bytes(skb, tlv_off, (void *)itlv, tlv_size); - if (err) - return err; - - // the following can't be moved inside update_tlv_pad because the - // bpf verifier has some issues with it - pad_off += sizeof(*itlv) + itlv->len; - partial_srh_len = pad_off - srh_off; - len_remaining = partial_srh_len % 8; - new_pad = 8 - len_remaining; - - if (new_pad == 1) // cannot pad for 1 byte only - new_pad = 9; - else if (new_pad == 8) - new_pad = 0; - - return update_tlv_pad(skb, new_pad, pad_size, pad_off); -} - -__attribute__((always_inline)) -int delete_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, - uint32_t tlv_off) -{ - uint32_t srh_off = (char *)srh - (char *)(long)skb->data; - uint8_t len_remaining, new_pad; - uint32_t partial_srh_len; - uint32_t pad_off = 0; - uint32_t pad_size = 0; - struct sr6_tlv_t tlv; - int err; - - tlv_off += srh_off; - - err = is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off); - if (err) - return err; - - err = bpf_skb_load_bytes(skb, tlv_off, &tlv, sizeof(tlv)); - if (err) - return err; - - err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, -(sizeof(tlv) + tlv.len)); - if (err) - return err; - - pad_off -= sizeof(tlv) + tlv.len; - partial_srh_len = pad_off - srh_off; - len_remaining = partial_srh_len % 8; - new_pad = 8 - len_remaining; - if (new_pad == 1) // cannot pad for 1 byte only - new_pad = 9; - else if (new_pad == 8) - new_pad = 0; - - return update_tlv_pad(skb, new_pad, pad_size, pad_off); -} - -__attribute__((always_inline)) -int has_egr_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh) -{ - int tlv_offset = sizeof(struct ip6_t) + sizeof(struct ip6_srh_t) + - ((srh->first_segment + 1) << 4); - struct sr6_tlv_t tlv; - - if (bpf_skb_load_bytes(skb, tlv_offset, &tlv, sizeof(struct sr6_tlv_t))) - return 0; - - if (tlv.type == SR6_TLV_EGRESS && tlv.len == 18) { - struct ip6_addr_t egr_addr; - - if (bpf_skb_load_bytes(skb, tlv_offset + 4, &egr_addr, 16)) - return 0; - - // check if egress TLV value is correct - if (ntohll(egr_addr.hi) == 0xfd00000000000000 && - ntohll(egr_addr.lo) == 0x4) - return 1; - } - - return 0; -} - -// This function will push a SRH with segments fd00::1, fd00::2, fd00::3, -// fd00::4 -SEC("encap_srh") -int __encap_srh(struct __sk_buff *skb) -{ - unsigned long long hi = 0xfd00000000000000; - struct ip6_addr_t *seg; - struct ip6_srh_t *srh; - char srh_buf[72]; // room for 4 segments - int err; - - srh = (struct ip6_srh_t *)srh_buf; - srh->nexthdr = 0; - srh->hdrlen = 8; - srh->type = 4; - srh->segments_left = 3; - srh->first_segment = 3; - srh->flags = 0; - srh->tag = 0; - - seg = (struct ip6_addr_t *)((char *)srh + sizeof(*srh)); - - #pragma clang loop unroll(full) - for (unsigned long long lo = 0; lo < 4; lo++) { - seg->lo = htonll(4 - lo); - seg->hi = htonll(hi); - seg = (struct ip6_addr_t *)((char *)seg + sizeof(*seg)); - } - - err = bpf_lwt_push_encap(skb, 0, (void *)srh, sizeof(srh_buf)); - if (err) - return BPF_DROP; - - return BPF_REDIRECT; -} - -// Add an Egress TLV fc00::4, add the flag A, -// and apply End.X action to fc42::1 -SEC("add_egr_x") -int __add_egr_x(struct __sk_buff *skb) -{ - unsigned long long hi = 0xfc42000000000000; - unsigned long long lo = 0x1; - struct ip6_srh_t *srh = get_srh(skb); - uint8_t new_flags = SR6_FLAG_ALERT; - struct ip6_addr_t addr; - int err, offset; - - if (srh == NULL) - return BPF_DROP; - - uint8_t tlv[20] = {2, 18, 0, 0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4}; - - err = add_tlv(skb, srh, (srh->hdrlen+1) << 3, - (struct sr6_tlv_t *)&tlv, 20); - if (err) - return BPF_DROP; - - offset = sizeof(struct ip6_t) + offsetof(struct ip6_srh_t, flags); - err = bpf_lwt_seg6_store_bytes(skb, offset, - (void *)&new_flags, sizeof(new_flags)); - if (err) - return BPF_DROP; - - addr.lo = htonll(lo); - addr.hi = htonll(hi); - err = bpf_lwt_seg6_action(skb, SEG6_LOCAL_ACTION_END_X, - (void *)&addr, sizeof(addr)); - if (err) - return BPF_DROP; - return BPF_REDIRECT; -} - -// Pop the Egress TLV, reset the flags, change the tag 2442 and finally do a -// simple End action -SEC("pop_egr") -int __pop_egr(struct __sk_buff *skb) -{ - struct ip6_srh_t *srh = get_srh(skb); - uint16_t new_tag = bpf_htons(2442); - uint8_t new_flags = 0; - int err, offset; - - if (srh == NULL) - return BPF_DROP; - - if (srh->flags != SR6_FLAG_ALERT) - return BPF_DROP; - - if (srh->hdrlen != 11) // 4 segments + Egress TLV + Padding TLV - return BPF_DROP; - - if (!has_egr_tlv(skb, srh)) - return BPF_DROP; - - err = delete_tlv(skb, srh, 8 + (srh->first_segment + 1) * 16); - if (err) - return BPF_DROP; - - offset = sizeof(struct ip6_t) + offsetof(struct ip6_srh_t, flags); - if (bpf_lwt_seg6_store_bytes(skb, offset, (void *)&new_flags, - sizeof(new_flags))) - return BPF_DROP; - - offset = sizeof(struct ip6_t) + offsetof(struct ip6_srh_t, tag); - if (bpf_lwt_seg6_store_bytes(skb, offset, (void *)&new_tag, - sizeof(new_tag))) - return BPF_DROP; - - return BPF_OK; -} - -// Inspect if the Egress TLV and flag have been removed, if the tag is correct, -// then apply a End.T action to reach the last segment -SEC("inspect_t") -int __inspect_t(struct __sk_buff *skb) -{ - struct ip6_srh_t *srh = get_srh(skb); - int table = 117; - int err; - - if (srh == NULL) - return BPF_DROP; - - if (srh->flags != 0) - return BPF_DROP; - - if (srh->tag != bpf_htons(2442)) - return BPF_DROP; - - if (srh->hdrlen != 8) // 4 segments - return BPF_DROP; - - err = bpf_lwt_seg6_action(skb, SEG6_LOCAL_ACTION_END_T, - (void *)&table, sizeof(table)); - - if (err) - return BPF_DROP; - - return BPF_REDIRECT; -} - -char __license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_map_in_map.c b/tools/testing/selftests/bpf/test_map_in_map.c deleted file mode 100644 index ce923e67e08e..000000000000 --- a/tools/testing/selftests/bpf/test_map_in_map.c +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2018 Facebook */ -#include -#include -#include -#include "bpf_helpers.h" - -struct bpf_map_def SEC("maps") mim_array = { - .type = BPF_MAP_TYPE_ARRAY_OF_MAPS, - .key_size = sizeof(int), - /* must be sizeof(__u32) for map in map */ - .value_size = sizeof(__u32), - .max_entries = 1, - .map_flags = 0, -}; - -struct bpf_map_def SEC("maps") mim_hash = { - .type = BPF_MAP_TYPE_HASH_OF_MAPS, - .key_size = sizeof(int), - /* must be sizeof(__u32) for map in map */ - .value_size = sizeof(__u32), - .max_entries = 1, - .map_flags = 0, -}; - -SEC("xdp_mimtest") -int xdp_mimtest0(struct xdp_md *ctx) -{ - int value = 123; - int key = 0; - void *map; - - map = bpf_map_lookup_elem(&mim_array, &key); - if (!map) - return XDP_DROP; - - bpf_map_update_elem(map, &key, &value, 0); - - map = bpf_map_lookup_elem(&mim_hash, &key); - if (!map) - return XDP_DROP; - - bpf_map_update_elem(map, &key, &value, 0); - - return XDP_PASS; -} - -int _version SEC("version") = 1; -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_map_lock.c b/tools/testing/selftests/bpf/test_map_lock.c deleted file mode 100644 index af8cc68ed2f9..000000000000 --- a/tools/testing/selftests/bpf/test_map_lock.c +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2019 Facebook -#include -#include -#include "bpf_helpers.h" - -#define VAR_NUM 16 - -struct hmap_elem { - struct bpf_spin_lock lock; - int var[VAR_NUM]; -}; - -struct bpf_map_def SEC("maps") hash_map = { - .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(int), - .value_size = sizeof(struct hmap_elem), - .max_entries = 1, -}; - -BPF_ANNOTATE_KV_PAIR(hash_map, int, struct hmap_elem); - -struct array_elem { - struct bpf_spin_lock lock; - int var[VAR_NUM]; -}; - -struct bpf_map_def SEC("maps") array_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(int), - .value_size = sizeof(struct array_elem), - .max_entries = 1, -}; - -BPF_ANNOTATE_KV_PAIR(array_map, int, struct array_elem); - -SEC("map_lock_demo") -int bpf_map_lock_test(struct __sk_buff *skb) -{ - struct hmap_elem zero = {}, *val; - int rnd = bpf_get_prandom_u32(); - int key = 0, err = 1, i; - struct array_elem *q; - - val = bpf_map_lookup_elem(&hash_map, &key); - if (!val) - goto err; - /* spin_lock in hash map */ - bpf_spin_lock(&val->lock); - for (i = 0; i < VAR_NUM; i++) - val->var[i] = rnd; - bpf_spin_unlock(&val->lock); - - /* spin_lock in array */ - q = bpf_map_lookup_elem(&array_map, &key); - if (!q) - goto err; - bpf_spin_lock(&q->lock); - for (i = 0; i < VAR_NUM; i++) - q->var[i] = rnd; - bpf_spin_unlock(&q->lock); - err = 0; -err: - return err; -} -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_obj_id.c b/tools/testing/selftests/bpf/test_obj_id.c deleted file mode 100644 index 880d2963b472..000000000000 --- a/tools/testing/selftests/bpf/test_obj_id.c +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (c) 2017 Facebook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#include -#include -#include -#include "bpf_helpers.h" - -/* It is a dumb bpf program such that it must have no - * issue to be loaded since testing the verifier is - * not the focus here. - */ - -int _version SEC("version") = 1; - -struct bpf_map_def SEC("maps") test_map_id = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u64), - .max_entries = 1, -}; - -SEC("test_obj_id_dummy") -int test_obj_id(struct __sk_buff *skb) -{ - __u32 key = 0; - __u64 *value; - - value = bpf_map_lookup_elem(&test_map_id, &key); - - return TC_ACT_OK; -} diff --git a/tools/testing/selftests/bpf/test_pkt_access.c b/tools/testing/selftests/bpf/test_pkt_access.c deleted file mode 100644 index 6e11ba11709e..000000000000 --- a/tools/testing/selftests/bpf/test_pkt_access.c +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (c) 2017 Facebook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bpf_helpers.h" -#include "bpf_endian.h" - -#define barrier() __asm__ __volatile__("": : :"memory") -int _version SEC("version") = 1; - -SEC("test1") -int process(struct __sk_buff *skb) -{ - void *data_end = (void *)(long)skb->data_end; - void *data = (void *)(long)skb->data; - struct ethhdr *eth = (struct ethhdr *)(data); - struct tcphdr *tcp = NULL; - __u8 proto = 255; - __u64 ihl_len; - - if (eth + 1 > data_end) - return TC_ACT_SHOT; - - if (eth->h_proto == bpf_htons(ETH_P_IP)) { - struct iphdr *iph = (struct iphdr *)(eth + 1); - - if (iph + 1 > data_end) - return TC_ACT_SHOT; - ihl_len = iph->ihl * 4; - proto = iph->protocol; - tcp = (struct tcphdr *)((void *)(iph) + ihl_len); - } else if (eth->h_proto == bpf_htons(ETH_P_IPV6)) { - struct ipv6hdr *ip6h = (struct ipv6hdr *)(eth + 1); - - if (ip6h + 1 > data_end) - return TC_ACT_SHOT; - ihl_len = sizeof(*ip6h); - proto = ip6h->nexthdr; - tcp = (struct tcphdr *)((void *)(ip6h) + ihl_len); - } - - if (tcp) { - if (((void *)(tcp) + 20) > data_end || proto != 6) - return TC_ACT_SHOT; - barrier(); /* to force ordering of checks */ - if (((void *)(tcp) + 18) > data_end) - return TC_ACT_SHOT; - if (tcp->urg_ptr == 123) - return TC_ACT_OK; - } - - return TC_ACT_UNSPEC; -} diff --git a/tools/testing/selftests/bpf/test_pkt_md_access.c b/tools/testing/selftests/bpf/test_pkt_md_access.c deleted file mode 100644 index 7956302ecdf2..000000000000 --- a/tools/testing/selftests/bpf/test_pkt_md_access.c +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2017 Facebook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include "bpf_helpers.h" - -int _version SEC("version") = 1; - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define TEST_FIELD(TYPE, FIELD, MASK) \ - { \ - TYPE tmp = *(volatile TYPE *)&skb->FIELD; \ - if (tmp != ((*(volatile __u32 *)&skb->FIELD) & MASK)) \ - return TC_ACT_SHOT; \ - } -#else -#define TEST_FIELD_OFFSET(a, b) ((sizeof(a) - sizeof(b)) / sizeof(b)) -#define TEST_FIELD(TYPE, FIELD, MASK) \ - { \ - TYPE tmp = *((volatile TYPE *)&skb->FIELD + \ - TEST_FIELD_OFFSET(skb->FIELD, TYPE)); \ - if (tmp != ((*(volatile __u32 *)&skb->FIELD) & MASK)) \ - return TC_ACT_SHOT; \ - } -#endif - -SEC("test1") -int process(struct __sk_buff *skb) -{ - TEST_FIELD(__u8, len, 0xFF); - TEST_FIELD(__u16, len, 0xFFFF); - TEST_FIELD(__u32, len, 0xFFFFFFFF); - TEST_FIELD(__u16, protocol, 0xFFFF); - TEST_FIELD(__u32, protocol, 0xFFFFFFFF); - TEST_FIELD(__u8, hash, 0xFF); - TEST_FIELD(__u16, hash, 0xFFFF); - TEST_FIELD(__u32, hash, 0xFFFFFFFF); - - return TC_ACT_OK; -} diff --git a/tools/testing/selftests/bpf/test_queue_map.c b/tools/testing/selftests/bpf/test_queue_map.c deleted file mode 100644 index 87db1f9da33d..000000000000 --- a/tools/testing/selftests/bpf/test_queue_map.c +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Politecnico di Torino -#define MAP_TYPE BPF_MAP_TYPE_QUEUE -#include "test_queue_stack_map.h" diff --git a/tools/testing/selftests/bpf/test_select_reuseport_kern.c b/tools/testing/selftests/bpf/test_select_reuseport_kern.c deleted file mode 100644 index 5b54ec637ada..000000000000 --- a/tools/testing/selftests/bpf/test_select_reuseport_kern.c +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2018 Facebook */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bpf_endian.h" -#include "bpf_helpers.h" -#include "test_select_reuseport_common.h" - -int _version SEC("version") = 1; - -#ifndef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -#endif - -struct bpf_map_def SEC("maps") outer_map = { - .type = BPF_MAP_TYPE_ARRAY_OF_MAPS, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = 1, -}; - -struct bpf_map_def SEC("maps") result_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = NR_RESULTS, -}; - -struct bpf_map_def SEC("maps") tmp_index_ovr_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(int), - .max_entries = 1, -}; - -struct bpf_map_def SEC("maps") linum_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = 1, -}; - -struct bpf_map_def SEC("maps") data_check_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct data_check), - .max_entries = 1, -}; - -#define GOTO_DONE(_result) ({ \ - result = (_result); \ - linum = __LINE__; \ - goto done; \ -}) - -SEC("select_by_skb_data") -int _select_by_skb_data(struct sk_reuseport_md *reuse_md) -{ - __u32 linum, index = 0, flags = 0, index_zero = 0; - __u32 *result_cnt, *linum_value; - struct data_check data_check = {}; - struct cmd *cmd, cmd_copy; - void *data, *data_end; - void *reuseport_array; - enum result result; - int *index_ovr; - int err; - - data = reuse_md->data; - data_end = reuse_md->data_end; - data_check.len = reuse_md->len; - data_check.eth_protocol = reuse_md->eth_protocol; - data_check.ip_protocol = reuse_md->ip_protocol; - data_check.hash = reuse_md->hash; - data_check.bind_inany = reuse_md->bind_inany; - if (data_check.eth_protocol == bpf_htons(ETH_P_IP)) { - if (bpf_skb_load_bytes_relative(reuse_md, - offsetof(struct iphdr, saddr), - data_check.skb_addrs, 8, - BPF_HDR_START_NET)) - GOTO_DONE(DROP_MISC); - } else { - if (bpf_skb_load_bytes_relative(reuse_md, - offsetof(struct ipv6hdr, saddr), - data_check.skb_addrs, 32, - BPF_HDR_START_NET)) - GOTO_DONE(DROP_MISC); - } - - /* - * The ip_protocol could be a compile time decision - * if the bpf_prog.o is dedicated to either TCP or - * UDP. - * - * Otherwise, reuse_md->ip_protocol or - * the protocol field in the iphdr can be used. - */ - if (data_check.ip_protocol == IPPROTO_TCP) { - struct tcphdr *th = data; - - if (th + 1 > data_end) - GOTO_DONE(DROP_MISC); - - data_check.skb_ports[0] = th->source; - data_check.skb_ports[1] = th->dest; - - if ((th->doff << 2) + sizeof(*cmd) > data_check.len) - GOTO_DONE(DROP_ERR_SKB_DATA); - if (bpf_skb_load_bytes(reuse_md, th->doff << 2, &cmd_copy, - sizeof(cmd_copy))) - GOTO_DONE(DROP_MISC); - cmd = &cmd_copy; - } else if (data_check.ip_protocol == IPPROTO_UDP) { - struct udphdr *uh = data; - - if (uh + 1 > data_end) - GOTO_DONE(DROP_MISC); - - data_check.skb_ports[0] = uh->source; - data_check.skb_ports[1] = uh->dest; - - if (sizeof(struct udphdr) + sizeof(*cmd) > data_check.len) - GOTO_DONE(DROP_ERR_SKB_DATA); - if (data + sizeof(struct udphdr) + sizeof(*cmd) > data_end) { - if (bpf_skb_load_bytes(reuse_md, sizeof(struct udphdr), - &cmd_copy, sizeof(cmd_copy))) - GOTO_DONE(DROP_MISC); - cmd = &cmd_copy; - } else { - cmd = data + sizeof(struct udphdr); - } - } else { - GOTO_DONE(DROP_MISC); - } - - reuseport_array = bpf_map_lookup_elem(&outer_map, &index_zero); - if (!reuseport_array) - GOTO_DONE(DROP_ERR_INNER_MAP); - - index = cmd->reuseport_index; - index_ovr = bpf_map_lookup_elem(&tmp_index_ovr_map, &index_zero); - if (!index_ovr) - GOTO_DONE(DROP_MISC); - - if (*index_ovr != -1) { - index = *index_ovr; - *index_ovr = -1; - } - err = bpf_sk_select_reuseport(reuse_md, reuseport_array, &index, - flags); - if (!err) - GOTO_DONE(PASS); - - if (cmd->pass_on_failure) - GOTO_DONE(PASS_ERR_SK_SELECT_REUSEPORT); - else - GOTO_DONE(DROP_ERR_SK_SELECT_REUSEPORT); - -done: - result_cnt = bpf_map_lookup_elem(&result_map, &result); - if (!result_cnt) - return SK_DROP; - - bpf_map_update_elem(&linum_map, &index_zero, &linum, BPF_ANY); - bpf_map_update_elem(&data_check_map, &index_zero, &data_check, BPF_ANY); - - (*result_cnt)++; - return result < PASS ? SK_DROP : SK_PASS; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_sk_lookup_kern.c b/tools/testing/selftests/bpf/test_sk_lookup_kern.c deleted file mode 100644 index e21cd736c196..000000000000 --- a/tools/testing/selftests/bpf/test_sk_lookup_kern.c +++ /dev/null @@ -1,180 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// Copyright (c) 2018 Covalent IO, Inc. http://covalent.io - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bpf_helpers.h" -#include "bpf_endian.h" - -int _version SEC("version") = 1; -char _license[] SEC("license") = "GPL"; - -/* Fill 'tuple' with L3 info, and attempt to find L4. On fail, return NULL. */ -static struct bpf_sock_tuple *get_tuple(void *data, __u64 nh_off, - void *data_end, __u16 eth_proto, - bool *ipv4) -{ - struct bpf_sock_tuple *result; - __u8 proto = 0; - __u64 ihl_len; - - if (eth_proto == bpf_htons(ETH_P_IP)) { - struct iphdr *iph = (struct iphdr *)(data + nh_off); - - if (iph + 1 > data_end) - return NULL; - ihl_len = iph->ihl * 4; - proto = iph->protocol; - *ipv4 = true; - result = (struct bpf_sock_tuple *)&iph->saddr; - } else if (eth_proto == bpf_htons(ETH_P_IPV6)) { - struct ipv6hdr *ip6h = (struct ipv6hdr *)(data + nh_off); - - if (ip6h + 1 > data_end) - return NULL; - ihl_len = sizeof(*ip6h); - proto = ip6h->nexthdr; - *ipv4 = true; - result = (struct bpf_sock_tuple *)&ip6h->saddr; - } - - if (data + nh_off + ihl_len > data_end || proto != IPPROTO_TCP) - return NULL; - - return result; -} - -SEC("sk_lookup_success") -int bpf_sk_lookup_test0(struct __sk_buff *skb) -{ - void *data_end = (void *)(long)skb->data_end; - void *data = (void *)(long)skb->data; - struct ethhdr *eth = (struct ethhdr *)(data); - struct bpf_sock_tuple *tuple; - struct bpf_sock *sk; - size_t tuple_len; - bool ipv4; - - if (eth + 1 > data_end) - return TC_ACT_SHOT; - - tuple = get_tuple(data, sizeof(*eth), data_end, eth->h_proto, &ipv4); - if (!tuple || tuple + sizeof *tuple > data_end) - return TC_ACT_SHOT; - - tuple_len = ipv4 ? sizeof(tuple->ipv4) : sizeof(tuple->ipv6); - sk = bpf_sk_lookup_tcp(skb, tuple, tuple_len, BPF_F_CURRENT_NETNS, 0); - if (sk) - bpf_sk_release(sk); - return sk ? TC_ACT_OK : TC_ACT_UNSPEC; -} - -SEC("sk_lookup_success_simple") -int bpf_sk_lookup_test1(struct __sk_buff *skb) -{ - struct bpf_sock_tuple tuple = {}; - struct bpf_sock *sk; - - sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); - if (sk) - bpf_sk_release(sk); - return 0; -} - -SEC("fail_use_after_free") -int bpf_sk_lookup_uaf(struct __sk_buff *skb) -{ - struct bpf_sock_tuple tuple = {}; - struct bpf_sock *sk; - __u32 family = 0; - - sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); - if (sk) { - bpf_sk_release(sk); - family = sk->family; - } - return family; -} - -SEC("fail_modify_sk_pointer") -int bpf_sk_lookup_modptr(struct __sk_buff *skb) -{ - struct bpf_sock_tuple tuple = {}; - struct bpf_sock *sk; - __u32 family; - - sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); - if (sk) { - sk += 1; - bpf_sk_release(sk); - } - return 0; -} - -SEC("fail_modify_sk_or_null_pointer") -int bpf_sk_lookup_modptr_or_null(struct __sk_buff *skb) -{ - struct bpf_sock_tuple tuple = {}; - struct bpf_sock *sk; - __u32 family; - - sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); - sk += 1; - if (sk) - bpf_sk_release(sk); - return 0; -} - -SEC("fail_no_release") -int bpf_sk_lookup_test2(struct __sk_buff *skb) -{ - struct bpf_sock_tuple tuple = {}; - - bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); - return 0; -} - -SEC("fail_release_twice") -int bpf_sk_lookup_test3(struct __sk_buff *skb) -{ - struct bpf_sock_tuple tuple = {}; - struct bpf_sock *sk; - - sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); - bpf_sk_release(sk); - bpf_sk_release(sk); - return 0; -} - -SEC("fail_release_unchecked") -int bpf_sk_lookup_test4(struct __sk_buff *skb) -{ - struct bpf_sock_tuple tuple = {}; - struct bpf_sock *sk; - - sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); - bpf_sk_release(sk); - return 0; -} - -void lookup_no_release(struct __sk_buff *skb) -{ - struct bpf_sock_tuple tuple = {}; - bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); -} - -SEC("fail_no_release_subcall") -int bpf_sk_lookup_test5(struct __sk_buff *skb) -{ - lookup_no_release(skb); - return 0; -} diff --git a/tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c b/tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c deleted file mode 100644 index 68cf9829f5a7..000000000000 --- a/tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Facebook - -#include -#include - -#include - -#include "bpf_helpers.h" - -#define NUM_CGROUP_LEVELS 4 - -struct bpf_map_def SEC("maps") cgroup_ids = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u64), - .max_entries = NUM_CGROUP_LEVELS, -}; - -static __always_inline void log_nth_level(struct __sk_buff *skb, __u32 level) -{ - __u64 id; - - /* [1] &level passed to external function that may change it, it's - * incompatible with loop unroll. - */ - id = bpf_skb_ancestor_cgroup_id(skb, level); - bpf_map_update_elem(&cgroup_ids, &level, &id, 0); -} - -SEC("cgroup_id_logger") -int log_cgroup_id(struct __sk_buff *skb) -{ - /* Loop unroll can't be used here due to [1]. Unrolling manually. - * Number of calls should be in sync with NUM_CGROUP_LEVELS. - */ - log_nth_level(skb, 0); - log_nth_level(skb, 1); - log_nth_level(skb, 2); - log_nth_level(skb, 3); - - return TC_ACT_OK; -} - -int _version SEC("version") = 1; - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_sock_fields_kern.c b/tools/testing/selftests/bpf/test_sock_fields_kern.c deleted file mode 100644 index de1a43e8f610..000000000000 --- a/tools/testing/selftests/bpf/test_sock_fields_kern.c +++ /dev/null @@ -1,152 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2019 Facebook */ - -#include -#include -#include - -#include "bpf_helpers.h" -#include "bpf_endian.h" - -enum bpf_array_idx { - SRV_IDX, - CLI_IDX, - __NR_BPF_ARRAY_IDX, -}; - -struct bpf_map_def SEC("maps") addr_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct sockaddr_in6), - .max_entries = __NR_BPF_ARRAY_IDX, -}; - -struct bpf_map_def SEC("maps") sock_result_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct bpf_sock), - .max_entries = __NR_BPF_ARRAY_IDX, -}; - -struct bpf_map_def SEC("maps") tcp_sock_result_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct bpf_tcp_sock), - .max_entries = __NR_BPF_ARRAY_IDX, -}; - -struct bpf_map_def SEC("maps") linum_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = 1, -}; - -static bool is_loopback6(__u32 *a6) -{ - return !a6[0] && !a6[1] && !a6[2] && a6[3] == bpf_htonl(1); -} - -static void skcpy(struct bpf_sock *dst, - const struct bpf_sock *src) -{ - dst->bound_dev_if = src->bound_dev_if; - dst->family = src->family; - dst->type = src->type; - dst->protocol = src->protocol; - dst->mark = src->mark; - dst->priority = src->priority; - dst->src_ip4 = src->src_ip4; - dst->src_ip6[0] = src->src_ip6[0]; - dst->src_ip6[1] = src->src_ip6[1]; - dst->src_ip6[2] = src->src_ip6[2]; - dst->src_ip6[3] = src->src_ip6[3]; - dst->src_port = src->src_port; - dst->dst_ip4 = src->dst_ip4; - dst->dst_ip6[0] = src->dst_ip6[0]; - dst->dst_ip6[1] = src->dst_ip6[1]; - dst->dst_ip6[2] = src->dst_ip6[2]; - dst->dst_ip6[3] = src->dst_ip6[3]; - dst->dst_port = src->dst_port; - dst->state = src->state; -} - -static void tpcpy(struct bpf_tcp_sock *dst, - const struct bpf_tcp_sock *src) -{ - dst->snd_cwnd = src->snd_cwnd; - dst->srtt_us = src->srtt_us; - dst->rtt_min = src->rtt_min; - dst->snd_ssthresh = src->snd_ssthresh; - dst->rcv_nxt = src->rcv_nxt; - dst->snd_nxt = src->snd_nxt; - dst->snd_una = src->snd_una; - dst->mss_cache = src->mss_cache; - dst->ecn_flags = src->ecn_flags; - dst->rate_delivered = src->rate_delivered; - dst->rate_interval_us = src->rate_interval_us; - dst->packets_out = src->packets_out; - dst->retrans_out = src->retrans_out; - dst->total_retrans = src->total_retrans; - dst->segs_in = src->segs_in; - dst->data_segs_in = src->data_segs_in; - dst->segs_out = src->segs_out; - dst->data_segs_out = src->data_segs_out; - dst->lost_out = src->lost_out; - dst->sacked_out = src->sacked_out; - dst->bytes_received = src->bytes_received; - dst->bytes_acked = src->bytes_acked; -} - -#define RETURN { \ - linum = __LINE__; \ - bpf_map_update_elem(&linum_map, &idx0, &linum, 0); \ - return 1; \ -} - -SEC("cgroup_skb/egress") -int read_sock_fields(struct __sk_buff *skb) -{ - __u32 srv_idx = SRV_IDX, cli_idx = CLI_IDX, idx; - struct sockaddr_in6 *srv_sa6, *cli_sa6; - struct bpf_tcp_sock *tp, *tp_ret; - struct bpf_sock *sk, *sk_ret; - __u32 linum, idx0 = 0; - - sk = skb->sk; - if (!sk || sk->state == 10) - RETURN; - - sk = bpf_sk_fullsock(sk); - if (!sk || sk->family != AF_INET6 || sk->protocol != IPPROTO_TCP || - !is_loopback6(sk->src_ip6)) - RETURN; - - tp = bpf_tcp_sock(sk); - if (!tp) - RETURN; - - srv_sa6 = bpf_map_lookup_elem(&addr_map, &srv_idx); - cli_sa6 = bpf_map_lookup_elem(&addr_map, &cli_idx); - if (!srv_sa6 || !cli_sa6) - RETURN; - - if (sk->src_port == bpf_ntohs(srv_sa6->sin6_port)) - idx = srv_idx; - else if (sk->src_port == bpf_ntohs(cli_sa6->sin6_port)) - idx = cli_idx; - else - RETURN; - - sk_ret = bpf_map_lookup_elem(&sock_result_map, &idx); - tp_ret = bpf_map_lookup_elem(&tcp_sock_result_map, &idx); - if (!sk_ret || !tp_ret) - RETURN; - - skcpy(sk_ret, sk); - tpcpy(tp_ret, tp); - - RETURN; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_sockhash_kern.c b/tools/testing/selftests/bpf/test_sockhash_kern.c deleted file mode 100644 index e6755916442a..000000000000 --- a/tools/testing/selftests/bpf/test_sockhash_kern.c +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Covalent IO, Inc. http://covalent.io -#undef SOCKMAP -#define TEST_MAP_TYPE BPF_MAP_TYPE_SOCKHASH -#include "./test_sockmap_kern.h" diff --git a/tools/testing/selftests/bpf/test_sockmap_kern.c b/tools/testing/selftests/bpf/test_sockmap_kern.c deleted file mode 100644 index 677b2ed1cc1e..000000000000 --- a/tools/testing/selftests/bpf/test_sockmap_kern.c +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Covalent IO, Inc. http://covalent.io -#define SOCKMAP -#define TEST_MAP_TYPE BPF_MAP_TYPE_SOCKMAP -#include "./test_sockmap_kern.h" diff --git a/tools/testing/selftests/bpf/test_spin_lock.c b/tools/testing/selftests/bpf/test_spin_lock.c deleted file mode 100644 index 40f904312090..000000000000 --- a/tools/testing/selftests/bpf/test_spin_lock.c +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2019 Facebook -#include -#include -#include "bpf_helpers.h" - -struct hmap_elem { - volatile int cnt; - struct bpf_spin_lock lock; - int test_padding; -}; - -struct bpf_map_def SEC("maps") hmap = { - .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(int), - .value_size = sizeof(struct hmap_elem), - .max_entries = 1, -}; - -BPF_ANNOTATE_KV_PAIR(hmap, int, struct hmap_elem); - - -struct cls_elem { - struct bpf_spin_lock lock; - volatile int cnt; -}; - -struct bpf_map_def SEC("maps") cls_map = { - .type = BPF_MAP_TYPE_CGROUP_STORAGE, - .key_size = sizeof(struct bpf_cgroup_storage_key), - .value_size = sizeof(struct cls_elem), -}; - -BPF_ANNOTATE_KV_PAIR(cls_map, struct bpf_cgroup_storage_key, - struct cls_elem); - -struct bpf_vqueue { - struct bpf_spin_lock lock; - /* 4 byte hole */ - unsigned long long lasttime; - int credit; - unsigned int rate; -}; - -struct bpf_map_def SEC("maps") vqueue = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(int), - .value_size = sizeof(struct bpf_vqueue), - .max_entries = 1, -}; - -BPF_ANNOTATE_KV_PAIR(vqueue, int, struct bpf_vqueue); -#define CREDIT_PER_NS(delta, rate) (((delta) * rate) >> 20) - -SEC("spin_lock_demo") -int bpf_sping_lock_test(struct __sk_buff *skb) -{ - volatile int credit = 0, max_credit = 100, pkt_len = 64; - struct hmap_elem zero = {}, *val; - unsigned long long curtime; - struct bpf_vqueue *q; - struct cls_elem *cls; - int key = 0; - int err = 0; - - val = bpf_map_lookup_elem(&hmap, &key); - if (!val) { - bpf_map_update_elem(&hmap, &key, &zero, 0); - val = bpf_map_lookup_elem(&hmap, &key); - if (!val) { - err = 1; - goto err; - } - } - /* spin_lock in hash map run time test */ - bpf_spin_lock(&val->lock); - if (val->cnt) - val->cnt--; - else - val->cnt++; - if (val->cnt != 0 && val->cnt != 1) - err = 1; - bpf_spin_unlock(&val->lock); - - /* spin_lock in array. virtual queue demo */ - q = bpf_map_lookup_elem(&vqueue, &key); - if (!q) - goto err; - curtime = bpf_ktime_get_ns(); - bpf_spin_lock(&q->lock); - q->credit += CREDIT_PER_NS(curtime - q->lasttime, q->rate); - q->lasttime = curtime; - if (q->credit > max_credit) - q->credit = max_credit; - q->credit -= pkt_len; - credit = q->credit; - bpf_spin_unlock(&q->lock); - - /* spin_lock in cgroup local storage */ - cls = bpf_get_local_storage(&cls_map, 0); - bpf_spin_lock(&cls->lock); - cls->cnt++; - bpf_spin_unlock(&cls->lock); - -err: - return err; -} -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_stack_map.c b/tools/testing/selftests/bpf/test_stack_map.c deleted file mode 100644 index 31c3880e6da0..000000000000 --- a/tools/testing/selftests/bpf/test_stack_map.c +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Politecnico di Torino -#define MAP_TYPE BPF_MAP_TYPE_STACK -#include "test_queue_stack_map.h" diff --git a/tools/testing/selftests/bpf/test_stacktrace_build_id.c b/tools/testing/selftests/bpf/test_stacktrace_build_id.c deleted file mode 100644 index d86c281e957f..000000000000 --- a/tools/testing/selftests/bpf/test_stacktrace_build_id.c +++ /dev/null @@ -1,76 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Facebook - -#include -#include "bpf_helpers.h" - -#ifndef PERF_MAX_STACK_DEPTH -#define PERF_MAX_STACK_DEPTH 127 -#endif - -struct bpf_map_def SEC("maps") control_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = 1, -}; - -struct bpf_map_def SEC("maps") stackid_hmap = { - .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = 16384, -}; - -struct bpf_map_def SEC("maps") stackmap = { - .type = BPF_MAP_TYPE_STACK_TRACE, - .key_size = sizeof(__u32), - .value_size = sizeof(struct bpf_stack_build_id) - * PERF_MAX_STACK_DEPTH, - .max_entries = 128, - .map_flags = BPF_F_STACK_BUILD_ID, -}; - -struct bpf_map_def SEC("maps") stack_amap = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct bpf_stack_build_id) - * PERF_MAX_STACK_DEPTH, - .max_entries = 128, -}; - -/* taken from /sys/kernel/debug/tracing/events/random/urandom_read/format */ -struct random_urandom_args { - unsigned long long pad; - int got_bits; - int pool_left; - int input_left; -}; - -SEC("tracepoint/random/urandom_read") -int oncpu(struct random_urandom_args *args) -{ - __u32 max_len = sizeof(struct bpf_stack_build_id) - * PERF_MAX_STACK_DEPTH; - __u32 key = 0, val = 0, *value_p; - void *stack_p; - - value_p = bpf_map_lookup_elem(&control_map, &key); - if (value_p && *value_p) - return 0; /* skip if non-zero *value_p */ - - /* The size of stackmap and stackid_hmap should be the same */ - key = bpf_get_stackid(args, &stackmap, BPF_F_USER_STACK); - if ((int)key >= 0) { - bpf_map_update_elem(&stackid_hmap, &key, &val, 0); - stack_p = bpf_map_lookup_elem(&stack_amap, &key); - if (stack_p) - bpf_get_stack(args, stack_p, max_len, - BPF_F_USER_STACK | BPF_F_USER_BUILD_ID); - } - - return 0; -} - -char _license[] SEC("license") = "GPL"; -__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/test_stacktrace_map.c b/tools/testing/selftests/bpf/test_stacktrace_map.c deleted file mode 100644 index af111af7ca1a..000000000000 --- a/tools/testing/selftests/bpf/test_stacktrace_map.c +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018 Facebook - -#include -#include "bpf_helpers.h" - -#ifndef PERF_MAX_STACK_DEPTH -#define PERF_MAX_STACK_DEPTH 127 -#endif - -struct bpf_map_def SEC("maps") control_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = 1, -}; - -struct bpf_map_def SEC("maps") stackid_hmap = { - .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = 16384, -}; - -struct bpf_map_def SEC("maps") stackmap = { - .type = BPF_MAP_TYPE_STACK_TRACE, - .key_size = sizeof(__u32), - .value_size = sizeof(__u64) * PERF_MAX_STACK_DEPTH, - .max_entries = 16384, -}; - -struct bpf_map_def SEC("maps") stack_amap = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u64) * PERF_MAX_STACK_DEPTH, - .max_entries = 16384, -}; - -/* taken from /sys/kernel/debug/tracing/events/sched/sched_switch/format */ -struct sched_switch_args { - unsigned long long pad; - char prev_comm[16]; - int prev_pid; - int prev_prio; - long long prev_state; - char next_comm[16]; - int next_pid; - int next_prio; -}; - -SEC("tracepoint/sched/sched_switch") -int oncpu(struct sched_switch_args *ctx) -{ - __u32 max_len = PERF_MAX_STACK_DEPTH * sizeof(__u64); - __u32 key = 0, val = 0, *value_p; - void *stack_p; - - value_p = bpf_map_lookup_elem(&control_map, &key); - if (value_p && *value_p) - return 0; /* skip if non-zero *value_p */ - - /* The size of stackmap and stackid_hmap should be the same */ - key = bpf_get_stackid(ctx, &stackmap, 0); - if ((int)key >= 0) { - bpf_map_update_elem(&stackid_hmap, &key, &val, 0); - stack_p = bpf_map_lookup_elem(&stack_amap, &key); - if (stack_p) - bpf_get_stack(ctx, stack_p, max_len, 0); - } - - return 0; -} - -char _license[] SEC("license") = "GPL"; -__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/test_tcp_estats.c b/tools/testing/selftests/bpf/test_tcp_estats.c deleted file mode 100644 index bee3bbecc0c4..000000000000 --- a/tools/testing/selftests/bpf/test_tcp_estats.c +++ /dev/null @@ -1,258 +0,0 @@ -/* Copyright (c) 2017 Facebook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ - -/* This program shows clang/llvm is able to generate code pattern - * like: - * _tcp_send_active_reset: - * 0: bf 16 00 00 00 00 00 00 r6 = r1 - * ...... - * 335: b7 01 00 00 0f 00 00 00 r1 = 15 - * 336: 05 00 48 00 00 00 00 00 goto 72 - * - * LBB0_3: - * 337: b7 01 00 00 01 00 00 00 r1 = 1 - * 338: 63 1a d0 ff 00 00 00 00 *(u32 *)(r10 - 48) = r1 - * 408: b7 01 00 00 03 00 00 00 r1 = 3 - * - * LBB0_4: - * 409: 71 a2 fe ff 00 00 00 00 r2 = *(u8 *)(r10 - 2) - * 410: bf a7 00 00 00 00 00 00 r7 = r10 - * 411: 07 07 00 00 b8 ff ff ff r7 += -72 - * 412: bf 73 00 00 00 00 00 00 r3 = r7 - * 413: 0f 13 00 00 00 00 00 00 r3 += r1 - * 414: 73 23 2d 00 00 00 00 00 *(u8 *)(r3 + 45) = r2 - * - * From the above code snippet, the code generated by the compiler - * is reasonable. The "r1" is assigned to different values in basic - * blocks "_tcp_send_active_reset" and "LBB0_3", and used in "LBB0_4". - * The verifier should be able to handle such code patterns. - */ -#include -#include -#include -#include -#include -#include "bpf_helpers.h" - -#define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;}) -#define TCP_ESTATS_MAGIC 0xBAADBEEF - -/* This test case needs "sock" and "pt_regs" data structure. - * Recursively, "sock" needs "sock_common" and "inet_sock". - * However, this is a unit test case only for - * verifier purpose without bpf program execution. - * We can safely mock much simpler data structures, basically - * only taking the necessary fields from kernel headers. - */ -typedef __u32 __bitwise __portpair; -typedef __u64 __bitwise __addrpair; - -struct sock_common { - unsigned short skc_family; - union { - __addrpair skc_addrpair; - struct { - __be32 skc_daddr; - __be32 skc_rcv_saddr; - }; - }; - union { - __portpair skc_portpair; - struct { - __be16 skc_dport; - __u16 skc_num; - }; - }; - struct in6_addr skc_v6_daddr; - struct in6_addr skc_v6_rcv_saddr; -}; - -struct sock { - struct sock_common __sk_common; -#define sk_family __sk_common.skc_family -#define sk_v6_daddr __sk_common.skc_v6_daddr -#define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr -}; - -struct inet_sock { - struct sock sk; -#define inet_daddr sk.__sk_common.skc_daddr -#define inet_dport sk.__sk_common.skc_dport - __be32 inet_saddr; - __be16 inet_sport; -}; - -struct pt_regs { - long di; -}; - -static inline struct inet_sock *inet_sk(const struct sock *sk) -{ - return (struct inet_sock *)sk; -} - -/* Define various data structures for state recording. - * Some fields are not used due to test simplification. - */ -enum tcp_estats_addrtype { - TCP_ESTATS_ADDRTYPE_IPV4 = 1, - TCP_ESTATS_ADDRTYPE_IPV6 = 2 -}; - -enum tcp_estats_event_type { - TCP_ESTATS_ESTABLISH, - TCP_ESTATS_PERIODIC, - TCP_ESTATS_TIMEOUT, - TCP_ESTATS_RETRANSMIT_TIMEOUT, - TCP_ESTATS_RETRANSMIT_OTHER, - TCP_ESTATS_SYN_RETRANSMIT, - TCP_ESTATS_SYNACK_RETRANSMIT, - TCP_ESTATS_TERM, - TCP_ESTATS_TX_RESET, - TCP_ESTATS_RX_RESET, - TCP_ESTATS_WRITE_TIMEOUT, - TCP_ESTATS_CONN_TIMEOUT, - TCP_ESTATS_ACK_LATENCY, - TCP_ESTATS_NEVENTS, -}; - -struct tcp_estats_event { - int pid; - int cpu; - unsigned long ts; - unsigned int magic; - enum tcp_estats_event_type event_type; -}; - -/* The below data structure is packed in order for - * llvm compiler to generate expected code. - */ -struct tcp_estats_conn_id { - unsigned int localaddressType; - struct { - unsigned char data[16]; - } localaddress; - struct { - unsigned char data[16]; - } remaddress; - unsigned short localport; - unsigned short remport; -} __attribute__((__packed__)); - -struct tcp_estats_basic_event { - struct tcp_estats_event event; - struct tcp_estats_conn_id conn_id; -}; - -struct bpf_map_def SEC("maps") ev_record_map = { - .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(__u32), - .value_size = sizeof(struct tcp_estats_basic_event), - .max_entries = 1024, -}; - -struct dummy_tracepoint_args { - unsigned long long pad; - struct sock *sock; -}; - -static __always_inline void tcp_estats_ev_init(struct tcp_estats_event *event, - enum tcp_estats_event_type type) -{ - event->magic = TCP_ESTATS_MAGIC; - event->ts = bpf_ktime_get_ns(); - event->event_type = type; -} - -static __always_inline void unaligned_u32_set(unsigned char *to, __u8 *from) -{ - to[0] = _(from[0]); - to[1] = _(from[1]); - to[2] = _(from[2]); - to[3] = _(from[3]); -} - -static __always_inline void conn_id_ipv4_init(struct tcp_estats_conn_id *conn_id, - __be32 *saddr, __be32 *daddr) -{ - conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV4; - - unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr); - unaligned_u32_set(conn_id->remaddress.data, (__u8 *)daddr); -} - -static __always_inline void conn_id_ipv6_init(struct tcp_estats_conn_id *conn_id, - __be32 *saddr, __be32 *daddr) -{ - conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV6; - - unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr); - unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32), - (__u8 *)(saddr + 1)); - unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 2, - (__u8 *)(saddr + 2)); - unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 3, - (__u8 *)(saddr + 3)); - - unaligned_u32_set(conn_id->remaddress.data, - (__u8 *)(daddr)); - unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32), - (__u8 *)(daddr + 1)); - unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 2, - (__u8 *)(daddr + 2)); - unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 3, - (__u8 *)(daddr + 3)); -} - -static __always_inline void tcp_estats_conn_id_init(struct tcp_estats_conn_id *conn_id, - struct sock *sk) -{ - conn_id->localport = _(inet_sk(sk)->inet_sport); - conn_id->remport = _(inet_sk(sk)->inet_dport); - - if (_(sk->sk_family) == AF_INET6) - conn_id_ipv6_init(conn_id, - sk->sk_v6_rcv_saddr.s6_addr32, - sk->sk_v6_daddr.s6_addr32); - else - conn_id_ipv4_init(conn_id, - &inet_sk(sk)->inet_saddr, - &inet_sk(sk)->inet_daddr); -} - -static __always_inline void tcp_estats_init(struct sock *sk, - struct tcp_estats_event *event, - struct tcp_estats_conn_id *conn_id, - enum tcp_estats_event_type type) -{ - tcp_estats_ev_init(event, type); - tcp_estats_conn_id_init(conn_id, sk); -} - -static __always_inline void send_basic_event(struct sock *sk, - enum tcp_estats_event_type type) -{ - struct tcp_estats_basic_event ev; - __u32 key = bpf_get_prandom_u32(); - - memset(&ev, 0, sizeof(ev)); - tcp_estats_init(sk, &ev.event, &ev.conn_id, type); - bpf_map_update_elem(&ev_record_map, &key, &ev, BPF_ANY); -} - -SEC("dummy_tracepoint") -int _dummy_tracepoint(struct dummy_tracepoint_args *arg) -{ - if (!arg->sock) - return 0; - - send_basic_event(arg->sock, TCP_ESTATS_TX_RESET); - return 0; -} - -char _license[] SEC("license") = "GPL"; -__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/test_tcpbpf_kern.c b/tools/testing/selftests/bpf/test_tcpbpf_kern.c deleted file mode 100644 index 74f73b33a7b0..000000000000 --- a/tools/testing/selftests/bpf/test_tcpbpf_kern.c +++ /dev/null @@ -1,153 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bpf_helpers.h" -#include "bpf_endian.h" -#include "test_tcpbpf.h" - -struct bpf_map_def SEC("maps") global_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct tcpbpf_globals), - .max_entries = 4, -}; - -struct bpf_map_def SEC("maps") sockopt_results = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(int), - .max_entries = 2, -}; - -static inline void update_event_map(int event) -{ - __u32 key = 0; - struct tcpbpf_globals g, *gp; - - gp = bpf_map_lookup_elem(&global_map, &key); - if (gp == NULL) { - struct tcpbpf_globals g = {0}; - - g.event_map |= (1 << event); - bpf_map_update_elem(&global_map, &key, &g, - BPF_ANY); - } else { - g = *gp; - g.event_map |= (1 << event); - bpf_map_update_elem(&global_map, &key, &g, - BPF_ANY); - } -} - -int _version SEC("version") = 1; - -SEC("sockops") -int bpf_testcb(struct bpf_sock_ops *skops) -{ - char header[sizeof(struct ipv6hdr) + sizeof(struct tcphdr)]; - struct tcphdr *thdr; - int good_call_rv = 0; - int bad_call_rv = 0; - int save_syn = 1; - int rv = -1; - int v = 0; - int op; - - op = (int) skops->op; - - update_event_map(op); - - switch (op) { - case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: - /* Test failure to set largest cb flag (assumes not defined) */ - bad_call_rv = bpf_sock_ops_cb_flags_set(skops, 0x80); - /* Set callback */ - good_call_rv = bpf_sock_ops_cb_flags_set(skops, - BPF_SOCK_OPS_STATE_CB_FLAG); - /* Update results */ - { - __u32 key = 0; - struct tcpbpf_globals g, *gp; - - gp = bpf_map_lookup_elem(&global_map, &key); - if (!gp) - break; - g = *gp; - g.bad_cb_test_rv = bad_call_rv; - g.good_cb_test_rv = good_call_rv; - bpf_map_update_elem(&global_map, &key, &g, - BPF_ANY); - } - break; - case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: - skops->sk_txhash = 0x12345f; - v = 0xff; - rv = bpf_setsockopt(skops, SOL_IPV6, IPV6_TCLASS, &v, - sizeof(v)); - if (skops->family == AF_INET6) { - v = bpf_getsockopt(skops, IPPROTO_TCP, TCP_SAVED_SYN, - header, (sizeof(struct ipv6hdr) + - sizeof(struct tcphdr))); - if (!v) { - int offset = sizeof(struct ipv6hdr); - - thdr = (struct tcphdr *)(header + offset); - v = thdr->syn; - __u32 key = 1; - - bpf_map_update_elem(&sockopt_results, &key, &v, - BPF_ANY); - } - } - break; - case BPF_SOCK_OPS_RTO_CB: - break; - case BPF_SOCK_OPS_RETRANS_CB: - break; - case BPF_SOCK_OPS_STATE_CB: - if (skops->args[1] == BPF_TCP_CLOSE) { - __u32 key = 0; - struct tcpbpf_globals g, *gp; - - gp = bpf_map_lookup_elem(&global_map, &key); - if (!gp) - break; - g = *gp; - if (skops->args[0] == BPF_TCP_LISTEN) { - g.num_listen++; - } else { - g.total_retrans = skops->total_retrans; - g.data_segs_in = skops->data_segs_in; - g.data_segs_out = skops->data_segs_out; - g.bytes_received = skops->bytes_received; - g.bytes_acked = skops->bytes_acked; - } - bpf_map_update_elem(&global_map, &key, &g, - BPF_ANY); - } - break; - case BPF_SOCK_OPS_TCP_LISTEN_CB: - bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG); - v = bpf_setsockopt(skops, IPPROTO_TCP, TCP_SAVE_SYN, - &save_syn, sizeof(save_syn)); - /* Update global map w/ result of setsock opt */ - __u32 key = 0; - - bpf_map_update_elem(&sockopt_results, &key, &v, BPF_ANY); - break; - default: - rv = -1; - } - skops->reply = rv; - return 1; -} -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_tcpnotify_kern.c b/tools/testing/selftests/bpf/test_tcpnotify_kern.c deleted file mode 100644 index edbca203ce2d..000000000000 --- a/tools/testing/selftests/bpf/test_tcpnotify_kern.c +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bpf_helpers.h" -#include "bpf_endian.h" -#include "test_tcpnotify.h" - -struct bpf_map_def SEC("maps") global_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct tcpnotify_globals), - .max_entries = 4, -}; - -struct bpf_map_def SEC("maps") perf_event_map = { - .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, - .key_size = sizeof(int), - .value_size = sizeof(__u32), - .max_entries = 2, -}; - -int _version SEC("version") = 1; - -SEC("sockops") -int bpf_testcb(struct bpf_sock_ops *skops) -{ - int rv = -1; - int op; - - op = (int) skops->op; - - if (bpf_ntohl(skops->remote_port) != TESTPORT) { - skops->reply = -1; - return 0; - } - - switch (op) { - case BPF_SOCK_OPS_TIMEOUT_INIT: - case BPF_SOCK_OPS_RWND_INIT: - case BPF_SOCK_OPS_NEEDS_ECN: - case BPF_SOCK_OPS_BASE_RTT: - case BPF_SOCK_OPS_RTO_CB: - rv = 1; - break; - - case BPF_SOCK_OPS_TCP_CONNECT_CB: - case BPF_SOCK_OPS_TCP_LISTEN_CB: - case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: - case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: - bpf_sock_ops_cb_flags_set(skops, (BPF_SOCK_OPS_RETRANS_CB_FLAG| - BPF_SOCK_OPS_RTO_CB_FLAG)); - rv = 1; - break; - case BPF_SOCK_OPS_RETRANS_CB: { - __u32 key = 0; - struct tcpnotify_globals g, *gp; - struct tcp_notifier msg = { - .type = 0xde, - .subtype = 0xad, - .source = 0xbe, - .hash = 0xef, - }; - - rv = 1; - - /* Update results */ - gp = bpf_map_lookup_elem(&global_map, &key); - if (!gp) - break; - g = *gp; - g.total_retrans = skops->total_retrans; - g.ncalls++; - bpf_map_update_elem(&global_map, &key, &g, - BPF_ANY); - bpf_perf_event_output(skops, &perf_event_map, - BPF_F_CURRENT_CPU, - &msg, sizeof(msg)); - } - break; - default: - rv = -1; - } - skops->reply = rv; - return 1; -} -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_tracepoint.c b/tools/testing/selftests/bpf/test_tracepoint.c deleted file mode 100644 index 04bf084517e0..000000000000 --- a/tools/testing/selftests/bpf/test_tracepoint.c +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2017 Facebook - -#include -#include "bpf_helpers.h" - -/* taken from /sys/kernel/debug/tracing/events/sched/sched_switch/format */ -struct sched_switch_args { - unsigned long long pad; - char prev_comm[16]; - int prev_pid; - int prev_prio; - long long prev_state; - char next_comm[16]; - int next_pid; - int next_prio; -}; - -SEC("tracepoint/sched/sched_switch") -int oncpu(struct sched_switch_args *ctx) -{ - return 0; -} - -char _license[] SEC("license") = "GPL"; -__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/test_tunnel_kern.c b/tools/testing/selftests/bpf/test_tunnel_kern.c deleted file mode 100644 index 504df69c83df..000000000000 --- a/tools/testing/selftests/bpf/test_tunnel_kern.c +++ /dev/null @@ -1,713 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2016 VMware - * Copyright (c) 2016 Facebook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bpf_helpers.h" -#include "bpf_endian.h" - -#define ERROR(ret) do {\ - char fmt[] = "ERROR line:%d ret:%d\n";\ - bpf_trace_printk(fmt, sizeof(fmt), __LINE__, ret); \ - } while (0) - -int _version SEC("version") = 1; - -struct geneve_opt { - __be16 opt_class; - __u8 type; - __u8 length:5; - __u8 r3:1; - __u8 r2:1; - __u8 r1:1; - __u8 opt_data[8]; /* hard-coded to 8 byte */ -}; - -struct vxlan_metadata { - __u32 gbp; -}; - -SEC("gre_set_tunnel") -int _gre_set_tunnel(struct __sk_buff *skb) -{ - int ret; - struct bpf_tunnel_key key; - - __builtin_memset(&key, 0x0, sizeof(key)); - key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ - key.tunnel_id = 2; - key.tunnel_tos = 0; - key.tunnel_ttl = 64; - - ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), - BPF_F_ZERO_CSUM_TX | BPF_F_SEQ_NUMBER); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - return TC_ACT_OK; -} - -SEC("gre_get_tunnel") -int _gre_get_tunnel(struct __sk_buff *skb) -{ - int ret; - struct bpf_tunnel_key key; - char fmt[] = "key %d remote ip 0x%x\n"; - - ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - bpf_trace_printk(fmt, sizeof(fmt), key.tunnel_id, key.remote_ipv4); - return TC_ACT_OK; -} - -SEC("ip6gretap_set_tunnel") -int _ip6gretap_set_tunnel(struct __sk_buff *skb) -{ - struct bpf_tunnel_key key; - int ret; - - __builtin_memset(&key, 0x0, sizeof(key)); - key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */ - key.tunnel_id = 2; - key.tunnel_tos = 0; - key.tunnel_ttl = 64; - key.tunnel_label = 0xabcde; - - ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), - BPF_F_TUNINFO_IPV6 | BPF_F_ZERO_CSUM_TX | - BPF_F_SEQ_NUMBER); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - return TC_ACT_OK; -} - -SEC("ip6gretap_get_tunnel") -int _ip6gretap_get_tunnel(struct __sk_buff *skb) -{ - char fmt[] = "key %d remote ip6 ::%x label %x\n"; - struct bpf_tunnel_key key; - int ret; - - ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), - BPF_F_TUNINFO_IPV6); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - bpf_trace_printk(fmt, sizeof(fmt), - key.tunnel_id, key.remote_ipv6[3], key.tunnel_label); - - return TC_ACT_OK; -} - -SEC("erspan_set_tunnel") -int _erspan_set_tunnel(struct __sk_buff *skb) -{ - struct bpf_tunnel_key key; - struct erspan_metadata md; - int ret; - - __builtin_memset(&key, 0x0, sizeof(key)); - key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ - key.tunnel_id = 2; - key.tunnel_tos = 0; - key.tunnel_ttl = 64; - - ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), - BPF_F_ZERO_CSUM_TX); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - __builtin_memset(&md, 0, sizeof(md)); -#ifdef ERSPAN_V1 - md.version = 1; - md.u.index = bpf_htonl(123); -#else - __u8 direction = 1; - __u8 hwid = 7; - - md.version = 2; - md.u.md2.dir = direction; - md.u.md2.hwid = hwid & 0xf; - md.u.md2.hwid_upper = (hwid >> 4) & 0x3; -#endif - - ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md)); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - return TC_ACT_OK; -} - -SEC("erspan_get_tunnel") -int _erspan_get_tunnel(struct __sk_buff *skb) -{ - char fmt[] = "key %d remote ip 0x%x erspan version %d\n"; - struct bpf_tunnel_key key; - struct erspan_metadata md; - __u32 index; - int ret; - - ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md)); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - bpf_trace_printk(fmt, sizeof(fmt), - key.tunnel_id, key.remote_ipv4, md.version); - -#ifdef ERSPAN_V1 - char fmt2[] = "\tindex %x\n"; - - index = bpf_ntohl(md.u.index); - bpf_trace_printk(fmt2, sizeof(fmt2), index); -#else - char fmt2[] = "\tdirection %d hwid %x timestamp %u\n"; - - bpf_trace_printk(fmt2, sizeof(fmt2), - md.u.md2.dir, - (md.u.md2.hwid_upper << 4) + md.u.md2.hwid, - bpf_ntohl(md.u.md2.timestamp)); -#endif - - return TC_ACT_OK; -} - -SEC("ip4ip6erspan_set_tunnel") -int _ip4ip6erspan_set_tunnel(struct __sk_buff *skb) -{ - struct bpf_tunnel_key key; - struct erspan_metadata md; - int ret; - - __builtin_memset(&key, 0x0, sizeof(key)); - key.remote_ipv6[3] = bpf_htonl(0x11); - key.tunnel_id = 2; - key.tunnel_tos = 0; - key.tunnel_ttl = 64; - - ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), - BPF_F_TUNINFO_IPV6); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - __builtin_memset(&md, 0, sizeof(md)); - -#ifdef ERSPAN_V1 - md.u.index = bpf_htonl(123); - md.version = 1; -#else - __u8 direction = 0; - __u8 hwid = 17; - - md.version = 2; - md.u.md2.dir = direction; - md.u.md2.hwid = hwid & 0xf; - md.u.md2.hwid_upper = (hwid >> 4) & 0x3; -#endif - - ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md)); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - return TC_ACT_OK; -} - -SEC("ip4ip6erspan_get_tunnel") -int _ip4ip6erspan_get_tunnel(struct __sk_buff *skb) -{ - char fmt[] = "ip6erspan get key %d remote ip6 ::%x erspan version %d\n"; - struct bpf_tunnel_key key; - struct erspan_metadata md; - __u32 index; - int ret; - - ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), - BPF_F_TUNINFO_IPV6); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md)); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - bpf_trace_printk(fmt, sizeof(fmt), - key.tunnel_id, key.remote_ipv4, md.version); - -#ifdef ERSPAN_V1 - char fmt2[] = "\tindex %x\n"; - - index = bpf_ntohl(md.u.index); - bpf_trace_printk(fmt2, sizeof(fmt2), index); -#else - char fmt2[] = "\tdirection %d hwid %x timestamp %u\n"; - - bpf_trace_printk(fmt2, sizeof(fmt2), - md.u.md2.dir, - (md.u.md2.hwid_upper << 4) + md.u.md2.hwid, - bpf_ntohl(md.u.md2.timestamp)); -#endif - - return TC_ACT_OK; -} - -SEC("vxlan_set_tunnel") -int _vxlan_set_tunnel(struct __sk_buff *skb) -{ - int ret; - struct bpf_tunnel_key key; - struct vxlan_metadata md; - - __builtin_memset(&key, 0x0, sizeof(key)); - key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ - key.tunnel_id = 2; - key.tunnel_tos = 0; - key.tunnel_ttl = 64; - - ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), - BPF_F_ZERO_CSUM_TX); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - md.gbp = 0x800FF; /* Set VXLAN Group Policy extension */ - ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md)); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - return TC_ACT_OK; -} - -SEC("vxlan_get_tunnel") -int _vxlan_get_tunnel(struct __sk_buff *skb) -{ - int ret; - struct bpf_tunnel_key key; - struct vxlan_metadata md; - char fmt[] = "key %d remote ip 0x%x vxlan gbp 0x%x\n"; - - ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md)); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - bpf_trace_printk(fmt, sizeof(fmt), - key.tunnel_id, key.remote_ipv4, md.gbp); - - return TC_ACT_OK; -} - -SEC("ip6vxlan_set_tunnel") -int _ip6vxlan_set_tunnel(struct __sk_buff *skb) -{ - struct bpf_tunnel_key key; - int ret; - - __builtin_memset(&key, 0x0, sizeof(key)); - key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */ - key.tunnel_id = 22; - key.tunnel_tos = 0; - key.tunnel_ttl = 64; - - ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), - BPF_F_TUNINFO_IPV6); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - return TC_ACT_OK; -} - -SEC("ip6vxlan_get_tunnel") -int _ip6vxlan_get_tunnel(struct __sk_buff *skb) -{ - char fmt[] = "key %d remote ip6 ::%x label %x\n"; - struct bpf_tunnel_key key; - int ret; - - ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), - BPF_F_TUNINFO_IPV6); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - bpf_trace_printk(fmt, sizeof(fmt), - key.tunnel_id, key.remote_ipv6[3], key.tunnel_label); - - return TC_ACT_OK; -} - -SEC("geneve_set_tunnel") -int _geneve_set_tunnel(struct __sk_buff *skb) -{ - int ret, ret2; - struct bpf_tunnel_key key; - struct geneve_opt gopt; - - __builtin_memset(&key, 0x0, sizeof(key)); - key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ - key.tunnel_id = 2; - key.tunnel_tos = 0; - key.tunnel_ttl = 64; - - __builtin_memset(&gopt, 0x0, sizeof(gopt)); - gopt.opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */ - gopt.type = 0x08; - gopt.r1 = 0; - gopt.r2 = 0; - gopt.r3 = 0; - gopt.length = 2; /* 4-byte multiple */ - *(int *) &gopt.opt_data = bpf_htonl(0xdeadbeef); - - ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), - BPF_F_ZERO_CSUM_TX); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - ret = bpf_skb_set_tunnel_opt(skb, &gopt, sizeof(gopt)); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - return TC_ACT_OK; -} - -SEC("geneve_get_tunnel") -int _geneve_get_tunnel(struct __sk_buff *skb) -{ - int ret; - struct bpf_tunnel_key key; - struct geneve_opt gopt; - char fmt[] = "key %d remote ip 0x%x geneve class 0x%x\n"; - - ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - ret = bpf_skb_get_tunnel_opt(skb, &gopt, sizeof(gopt)); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - bpf_trace_printk(fmt, sizeof(fmt), - key.tunnel_id, key.remote_ipv4, gopt.opt_class); - return TC_ACT_OK; -} - -SEC("ip6geneve_set_tunnel") -int _ip6geneve_set_tunnel(struct __sk_buff *skb) -{ - struct bpf_tunnel_key key; - struct geneve_opt gopt; - int ret; - - __builtin_memset(&key, 0x0, sizeof(key)); - key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */ - key.tunnel_id = 22; - key.tunnel_tos = 0; - key.tunnel_ttl = 64; - - ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), - BPF_F_TUNINFO_IPV6); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - __builtin_memset(&gopt, 0x0, sizeof(gopt)); - gopt.opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */ - gopt.type = 0x08; - gopt.r1 = 0; - gopt.r2 = 0; - gopt.r3 = 0; - gopt.length = 2; /* 4-byte multiple */ - *(int *) &gopt.opt_data = bpf_htonl(0xfeedbeef); - - ret = bpf_skb_set_tunnel_opt(skb, &gopt, sizeof(gopt)); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - return TC_ACT_OK; -} - -SEC("ip6geneve_get_tunnel") -int _ip6geneve_get_tunnel(struct __sk_buff *skb) -{ - char fmt[] = "key %d remote ip 0x%x geneve class 0x%x\n"; - struct bpf_tunnel_key key; - struct geneve_opt gopt; - int ret; - - ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), - BPF_F_TUNINFO_IPV6); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - ret = bpf_skb_get_tunnel_opt(skb, &gopt, sizeof(gopt)); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - bpf_trace_printk(fmt, sizeof(fmt), - key.tunnel_id, key.remote_ipv4, gopt.opt_class); - - return TC_ACT_OK; -} - -SEC("ipip_set_tunnel") -int _ipip_set_tunnel(struct __sk_buff *skb) -{ - struct bpf_tunnel_key key = {}; - void *data = (void *)(long)skb->data; - struct iphdr *iph = data; - struct tcphdr *tcp = data + sizeof(*iph); - void *data_end = (void *)(long)skb->data_end; - int ret; - - /* single length check */ - if (data + sizeof(*iph) + sizeof(*tcp) > data_end) { - ERROR(1); - return TC_ACT_SHOT; - } - - key.tunnel_ttl = 64; - if (iph->protocol == IPPROTO_ICMP) { - key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ - } else { - if (iph->protocol != IPPROTO_TCP || iph->ihl != 5) - return TC_ACT_SHOT; - - if (tcp->dest == bpf_htons(5200)) - key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ - else if (tcp->dest == bpf_htons(5201)) - key.remote_ipv4 = 0xac100165; /* 172.16.1.101 */ - else - return TC_ACT_SHOT; - } - - ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - return TC_ACT_OK; -} - -SEC("ipip_get_tunnel") -int _ipip_get_tunnel(struct __sk_buff *skb) -{ - int ret; - struct bpf_tunnel_key key; - char fmt[] = "remote ip 0x%x\n"; - - ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - bpf_trace_printk(fmt, sizeof(fmt), key.remote_ipv4); - return TC_ACT_OK; -} - -SEC("ipip6_set_tunnel") -int _ipip6_set_tunnel(struct __sk_buff *skb) -{ - struct bpf_tunnel_key key = {}; - void *data = (void *)(long)skb->data; - struct iphdr *iph = data; - struct tcphdr *tcp = data + sizeof(*iph); - void *data_end = (void *)(long)skb->data_end; - int ret; - - /* single length check */ - if (data + sizeof(*iph) + sizeof(*tcp) > data_end) { - ERROR(1); - return TC_ACT_SHOT; - } - - __builtin_memset(&key, 0x0, sizeof(key)); - key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */ - key.tunnel_ttl = 64; - - ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), - BPF_F_TUNINFO_IPV6); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - return TC_ACT_OK; -} - -SEC("ipip6_get_tunnel") -int _ipip6_get_tunnel(struct __sk_buff *skb) -{ - int ret; - struct bpf_tunnel_key key; - char fmt[] = "remote ip6 %x::%x\n"; - - ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), - BPF_F_TUNINFO_IPV6); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - bpf_trace_printk(fmt, sizeof(fmt), bpf_htonl(key.remote_ipv6[0]), - bpf_htonl(key.remote_ipv6[3])); - return TC_ACT_OK; -} - -SEC("ip6ip6_set_tunnel") -int _ip6ip6_set_tunnel(struct __sk_buff *skb) -{ - struct bpf_tunnel_key key = {}; - void *data = (void *)(long)skb->data; - struct ipv6hdr *iph = data; - struct tcphdr *tcp = data + sizeof(*iph); - void *data_end = (void *)(long)skb->data_end; - int ret; - - /* single length check */ - if (data + sizeof(*iph) + sizeof(*tcp) > data_end) { - ERROR(1); - return TC_ACT_SHOT; - } - - key.remote_ipv6[0] = bpf_htonl(0x2401db00); - key.tunnel_ttl = 64; - - if (iph->nexthdr == 58 /* NEXTHDR_ICMP */) { - key.remote_ipv6[3] = bpf_htonl(1); - } else { - if (iph->nexthdr != 6 /* NEXTHDR_TCP */) { - ERROR(iph->nexthdr); - return TC_ACT_SHOT; - } - - if (tcp->dest == bpf_htons(5200)) { - key.remote_ipv6[3] = bpf_htonl(1); - } else if (tcp->dest == bpf_htons(5201)) { - key.remote_ipv6[3] = bpf_htonl(2); - } else { - ERROR(tcp->dest); - return TC_ACT_SHOT; - } - } - - ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), - BPF_F_TUNINFO_IPV6); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - return TC_ACT_OK; -} - -SEC("ip6ip6_get_tunnel") -int _ip6ip6_get_tunnel(struct __sk_buff *skb) -{ - int ret; - struct bpf_tunnel_key key; - char fmt[] = "remote ip6 %x::%x\n"; - - ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), - BPF_F_TUNINFO_IPV6); - if (ret < 0) { - ERROR(ret); - return TC_ACT_SHOT; - } - - bpf_trace_printk(fmt, sizeof(fmt), bpf_htonl(key.remote_ipv6[0]), - bpf_htonl(key.remote_ipv6[3])); - return TC_ACT_OK; -} - -SEC("xfrm_get_state") -int _xfrm_get_state(struct __sk_buff *skb) -{ - struct bpf_xfrm_state x; - char fmt[] = "reqid %d spi 0x%x remote ip 0x%x\n"; - int ret; - - ret = bpf_skb_get_xfrm_state(skb, 0, &x, sizeof(x), 0); - if (ret < 0) - return TC_ACT_OK; - - bpf_trace_printk(fmt, sizeof(fmt), x.reqid, bpf_ntohl(x.spi), - bpf_ntohl(x.remote_ipv4)); - return TC_ACT_OK; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_xdp.c b/tools/testing/selftests/bpf/test_xdp.c deleted file mode 100644 index 5e7df8bb5b5d..000000000000 --- a/tools/testing/selftests/bpf/test_xdp.c +++ /dev/null @@ -1,235 +0,0 @@ -/* Copyright (c) 2016,2017 Facebook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bpf_helpers.h" -#include "bpf_endian.h" -#include "test_iptunnel_common.h" - -int _version SEC("version") = 1; - -struct bpf_map_def SEC("maps") rxcnt = { - .type = BPF_MAP_TYPE_PERCPU_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u64), - .max_entries = 256, -}; - -struct bpf_map_def SEC("maps") vip2tnl = { - .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(struct vip), - .value_size = sizeof(struct iptnl_info), - .max_entries = MAX_IPTNL_ENTRIES, -}; - -static __always_inline void count_tx(__u32 protocol) -{ - __u64 *rxcnt_count; - - rxcnt_count = bpf_map_lookup_elem(&rxcnt, &protocol); - if (rxcnt_count) - *rxcnt_count += 1; -} - -static __always_inline int get_dport(void *trans_data, void *data_end, - __u8 protocol) -{ - struct tcphdr *th; - struct udphdr *uh; - - switch (protocol) { - case IPPROTO_TCP: - th = (struct tcphdr *)trans_data; - if (th + 1 > data_end) - return -1; - return th->dest; - case IPPROTO_UDP: - uh = (struct udphdr *)trans_data; - if (uh + 1 > data_end) - return -1; - return uh->dest; - default: - return 0; - } -} - -static __always_inline void set_ethhdr(struct ethhdr *new_eth, - const struct ethhdr *old_eth, - const struct iptnl_info *tnl, - __be16 h_proto) -{ - memcpy(new_eth->h_source, old_eth->h_dest, sizeof(new_eth->h_source)); - memcpy(new_eth->h_dest, tnl->dmac, sizeof(new_eth->h_dest)); - new_eth->h_proto = h_proto; -} - -static __always_inline int handle_ipv4(struct xdp_md *xdp) -{ - void *data_end = (void *)(long)xdp->data_end; - void *data = (void *)(long)xdp->data; - struct iptnl_info *tnl; - struct ethhdr *new_eth; - struct ethhdr *old_eth; - struct iphdr *iph = data + sizeof(struct ethhdr); - __u16 *next_iph; - __u16 payload_len; - struct vip vip = {}; - int dport; - __u32 csum = 0; - int i; - - if (iph + 1 > data_end) - return XDP_DROP; - - dport = get_dport(iph + 1, data_end, iph->protocol); - if (dport == -1) - return XDP_DROP; - - vip.protocol = iph->protocol; - vip.family = AF_INET; - vip.daddr.v4 = iph->daddr; - vip.dport = dport; - payload_len = bpf_ntohs(iph->tot_len); - - tnl = bpf_map_lookup_elem(&vip2tnl, &vip); - /* It only does v4-in-v4 */ - if (!tnl || tnl->family != AF_INET) - return XDP_PASS; - - if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(struct iphdr))) - return XDP_DROP; - - data = (void *)(long)xdp->data; - data_end = (void *)(long)xdp->data_end; - - new_eth = data; - iph = data + sizeof(*new_eth); - old_eth = data + sizeof(*iph); - - if (new_eth + 1 > data_end || - old_eth + 1 > data_end || - iph + 1 > data_end) - return XDP_DROP; - - set_ethhdr(new_eth, old_eth, tnl, bpf_htons(ETH_P_IP)); - - iph->version = 4; - iph->ihl = sizeof(*iph) >> 2; - iph->frag_off = 0; - iph->protocol = IPPROTO_IPIP; - iph->check = 0; - iph->tos = 0; - iph->tot_len = bpf_htons(payload_len + sizeof(*iph)); - iph->daddr = tnl->daddr.v4; - iph->saddr = tnl->saddr.v4; - iph->ttl = 8; - - next_iph = (__u16 *)iph; -#pragma clang loop unroll(full) - for (i = 0; i < sizeof(*iph) >> 1; i++) - csum += *next_iph++; - - iph->check = ~((csum & 0xffff) + (csum >> 16)); - - count_tx(vip.protocol); - - return XDP_TX; -} - -static __always_inline int handle_ipv6(struct xdp_md *xdp) -{ - void *data_end = (void *)(long)xdp->data_end; - void *data = (void *)(long)xdp->data; - struct iptnl_info *tnl; - struct ethhdr *new_eth; - struct ethhdr *old_eth; - struct ipv6hdr *ip6h = data + sizeof(struct ethhdr); - __u16 payload_len; - struct vip vip = {}; - int dport; - - if (ip6h + 1 > data_end) - return XDP_DROP; - - dport = get_dport(ip6h + 1, data_end, ip6h->nexthdr); - if (dport == -1) - return XDP_DROP; - - vip.protocol = ip6h->nexthdr; - vip.family = AF_INET6; - memcpy(vip.daddr.v6, ip6h->daddr.s6_addr32, sizeof(vip.daddr)); - vip.dport = dport; - payload_len = ip6h->payload_len; - - tnl = bpf_map_lookup_elem(&vip2tnl, &vip); - /* It only does v6-in-v6 */ - if (!tnl || tnl->family != AF_INET6) - return XDP_PASS; - - if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(struct ipv6hdr))) - return XDP_DROP; - - data = (void *)(long)xdp->data; - data_end = (void *)(long)xdp->data_end; - - new_eth = data; - ip6h = data + sizeof(*new_eth); - old_eth = data + sizeof(*ip6h); - - if (new_eth + 1 > data_end || old_eth + 1 > data_end || - ip6h + 1 > data_end) - return XDP_DROP; - - set_ethhdr(new_eth, old_eth, tnl, bpf_htons(ETH_P_IPV6)); - - ip6h->version = 6; - ip6h->priority = 0; - memset(ip6h->flow_lbl, 0, sizeof(ip6h->flow_lbl)); - ip6h->payload_len = bpf_htons(bpf_ntohs(payload_len) + sizeof(*ip6h)); - ip6h->nexthdr = IPPROTO_IPV6; - ip6h->hop_limit = 8; - memcpy(ip6h->saddr.s6_addr32, tnl->saddr.v6, sizeof(tnl->saddr.v6)); - memcpy(ip6h->daddr.s6_addr32, tnl->daddr.v6, sizeof(tnl->daddr.v6)); - - count_tx(vip.protocol); - - return XDP_TX; -} - -SEC("xdp_tx_iptunnel") -int _xdp_tx_iptunnel(struct xdp_md *xdp) -{ - void *data_end = (void *)(long)xdp->data_end; - void *data = (void *)(long)xdp->data; - struct ethhdr *eth = data; - __u16 h_proto; - - if (eth + 1 > data_end) - return XDP_DROP; - - h_proto = eth->h_proto; - - if (h_proto == bpf_htons(ETH_P_IP)) - return handle_ipv4(xdp); - else if (h_proto == bpf_htons(ETH_P_IPV6)) - - return handle_ipv6(xdp); - else - return XDP_DROP; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_xdp_meta.c b/tools/testing/selftests/bpf/test_xdp_meta.c deleted file mode 100644 index 8d0182650653..000000000000 --- a/tools/testing/selftests/bpf/test_xdp_meta.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include - -#include "bpf_helpers.h" - -#define __round_mask(x, y) ((__typeof__(x))((y) - 1)) -#define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1) -#define ctx_ptr(ctx, mem) (void *)(unsigned long)ctx->mem - -SEC("t") -int ing_cls(struct __sk_buff *ctx) -{ - __u8 *data, *data_meta, *data_end; - __u32 diff = 0; - - data_meta = ctx_ptr(ctx, data_meta); - data_end = ctx_ptr(ctx, data_end); - data = ctx_ptr(ctx, data); - - if (data + ETH_ALEN > data_end || - data_meta + round_up(ETH_ALEN, 4) > data) - return TC_ACT_SHOT; - - diff |= ((__u32 *)data_meta)[0] ^ ((__u32 *)data)[0]; - diff |= ((__u16 *)data_meta)[2] ^ ((__u16 *)data)[2]; - - return diff ? TC_ACT_SHOT : TC_ACT_OK; -} - -SEC("x") -int ing_xdp(struct xdp_md *ctx) -{ - __u8 *data, *data_meta, *data_end; - int ret; - - ret = bpf_xdp_adjust_meta(ctx, -round_up(ETH_ALEN, 4)); - if (ret < 0) - return XDP_DROP; - - data_meta = ctx_ptr(ctx, data_meta); - data_end = ctx_ptr(ctx, data_end); - data = ctx_ptr(ctx, data); - - if (data + ETH_ALEN > data_end || - data_meta + round_up(ETH_ALEN, 4) > data) - return XDP_DROP; - - __builtin_memcpy(data_meta, data, ETH_ALEN); - return XDP_PASS; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_xdp_noinline.c b/tools/testing/selftests/bpf/test_xdp_noinline.c deleted file mode 100644 index 5e4aac74f9d0..000000000000 --- a/tools/testing/selftests/bpf/test_xdp_noinline.c +++ /dev/null @@ -1,833 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2017 Facebook -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bpf_helpers.h" - -#define bpf_printk(fmt, ...) \ -({ \ - char ____fmt[] = fmt; \ - bpf_trace_printk(____fmt, sizeof(____fmt), \ - ##__VA_ARGS__); \ -}) - -static __u32 rol32(__u32 word, unsigned int shift) -{ - return (word << shift) | (word >> ((-shift) & 31)); -} - -/* copy paste of jhash from kernel sources to make sure llvm - * can compile it into valid sequence of bpf instructions - */ -#define __jhash_mix(a, b, c) \ -{ \ - a -= c; a ^= rol32(c, 4); c += b; \ - b -= a; b ^= rol32(a, 6); a += c; \ - c -= b; c ^= rol32(b, 8); b += a; \ - a -= c; a ^= rol32(c, 16); c += b; \ - b -= a; b ^= rol32(a, 19); a += c; \ - c -= b; c ^= rol32(b, 4); b += a; \ -} - -#define __jhash_final(a, b, c) \ -{ \ - c ^= b; c -= rol32(b, 14); \ - a ^= c; a -= rol32(c, 11); \ - b ^= a; b -= rol32(a, 25); \ - c ^= b; c -= rol32(b, 16); \ - a ^= c; a -= rol32(c, 4); \ - b ^= a; b -= rol32(a, 14); \ - c ^= b; c -= rol32(b, 24); \ -} - -#define JHASH_INITVAL 0xdeadbeef - -typedef unsigned int u32; - -static __attribute__ ((noinline)) -u32 jhash(const void *key, u32 length, u32 initval) -{ - u32 a, b, c; - const unsigned char *k = key; - - a = b = c = JHASH_INITVAL + length + initval; - - while (length > 12) { - a += *(u32 *)(k); - b += *(u32 *)(k + 4); - c += *(u32 *)(k + 8); - __jhash_mix(a, b, c); - length -= 12; - k += 12; - } - switch (length) { - case 12: c += (u32)k[11]<<24; - case 11: c += (u32)k[10]<<16; - case 10: c += (u32)k[9]<<8; - case 9: c += k[8]; - case 8: b += (u32)k[7]<<24; - case 7: b += (u32)k[6]<<16; - case 6: b += (u32)k[5]<<8; - case 5: b += k[4]; - case 4: a += (u32)k[3]<<24; - case 3: a += (u32)k[2]<<16; - case 2: a += (u32)k[1]<<8; - case 1: a += k[0]; - __jhash_final(a, b, c); - case 0: /* Nothing left to add */ - break; - } - - return c; -} - -static __attribute__ ((noinline)) -u32 __jhash_nwords(u32 a, u32 b, u32 c, u32 initval) -{ - a += initval; - b += initval; - c += initval; - __jhash_final(a, b, c); - return c; -} - -static __attribute__ ((noinline)) -u32 jhash_2words(u32 a, u32 b, u32 initval) -{ - return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2)); -} - -struct flow_key { - union { - __be32 src; - __be32 srcv6[4]; - }; - union { - __be32 dst; - __be32 dstv6[4]; - }; - union { - __u32 ports; - __u16 port16[2]; - }; - __u8 proto; -}; - -struct packet_description { - struct flow_key flow; - __u8 flags; -}; - -struct ctl_value { - union { - __u64 value; - __u32 ifindex; - __u8 mac[6]; - }; -}; - -struct vip_definition { - union { - __be32 vip; - __be32 vipv6[4]; - }; - __u16 port; - __u16 family; - __u8 proto; -}; - -struct vip_meta { - __u32 flags; - __u32 vip_num; -}; - -struct real_pos_lru { - __u32 pos; - __u64 atime; -}; - -struct real_definition { - union { - __be32 dst; - __be32 dstv6[4]; - }; - __u8 flags; -}; - -struct lb_stats { - __u64 v2; - __u64 v1; -}; - -struct bpf_map_def __attribute__ ((section("maps"), used)) vip_map = { - .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(struct vip_definition), - .value_size = sizeof(struct vip_meta), - .max_entries = 512, - .map_flags = 0, -}; - -struct bpf_map_def __attribute__ ((section("maps"), used)) lru_cache = { - .type = BPF_MAP_TYPE_LRU_HASH, - .key_size = sizeof(struct flow_key), - .value_size = sizeof(struct real_pos_lru), - .max_entries = 300, - .map_flags = 1U << 1, -}; - -struct bpf_map_def __attribute__ ((section("maps"), used)) ch_rings = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = 12 * 655, - .map_flags = 0, -}; - -struct bpf_map_def __attribute__ ((section("maps"), used)) reals = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct real_definition), - .max_entries = 40, - .map_flags = 0, -}; - -struct bpf_map_def __attribute__ ((section("maps"), used)) stats = { - .type = BPF_MAP_TYPE_PERCPU_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct lb_stats), - .max_entries = 515, - .map_flags = 0, -}; - -struct bpf_map_def __attribute__ ((section("maps"), used)) ctl_array = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(struct ctl_value), - .max_entries = 16, - .map_flags = 0, -}; - -struct eth_hdr { - unsigned char eth_dest[6]; - unsigned char eth_source[6]; - unsigned short eth_proto; -}; - -static inline __u64 calc_offset(bool is_ipv6, bool is_icmp) -{ - __u64 off = sizeof(struct eth_hdr); - if (is_ipv6) { - off += sizeof(struct ipv6hdr); - if (is_icmp) - off += sizeof(struct icmp6hdr) + sizeof(struct ipv6hdr); - } else { - off += sizeof(struct iphdr); - if (is_icmp) - off += sizeof(struct icmphdr) + sizeof(struct iphdr); - } - return off; -} - -static __attribute__ ((noinline)) -bool parse_udp(void *data, void *data_end, - bool is_ipv6, struct packet_description *pckt) -{ - - bool is_icmp = !((pckt->flags & (1 << 0)) == 0); - __u64 off = calc_offset(is_ipv6, is_icmp); - struct udphdr *udp; - udp = data + off; - - if (udp + 1 > data_end) - return 0; - if (!is_icmp) { - pckt->flow.port16[0] = udp->source; - pckt->flow.port16[1] = udp->dest; - } else { - pckt->flow.port16[0] = udp->dest; - pckt->flow.port16[1] = udp->source; - } - return 1; -} - -static __attribute__ ((noinline)) -bool parse_tcp(void *data, void *data_end, - bool is_ipv6, struct packet_description *pckt) -{ - - bool is_icmp = !((pckt->flags & (1 << 0)) == 0); - __u64 off = calc_offset(is_ipv6, is_icmp); - struct tcphdr *tcp; - - tcp = data + off; - if (tcp + 1 > data_end) - return 0; - if (tcp->syn) - pckt->flags |= (1 << 1); - if (!is_icmp) { - pckt->flow.port16[0] = tcp->source; - pckt->flow.port16[1] = tcp->dest; - } else { - pckt->flow.port16[0] = tcp->dest; - pckt->flow.port16[1] = tcp->source; - } - return 1; -} - -static __attribute__ ((noinline)) -bool encap_v6(struct xdp_md *xdp, struct ctl_value *cval, - struct packet_description *pckt, - struct real_definition *dst, __u32 pkt_bytes) -{ - struct eth_hdr *new_eth; - struct eth_hdr *old_eth; - struct ipv6hdr *ip6h; - __u32 ip_suffix; - void *data_end; - void *data; - - if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(struct ipv6hdr))) - return 0; - data = (void *)(long)xdp->data; - data_end = (void *)(long)xdp->data_end; - new_eth = data; - ip6h = data + sizeof(struct eth_hdr); - old_eth = data + sizeof(struct ipv6hdr); - if (new_eth + 1 > data_end || - old_eth + 1 > data_end || ip6h + 1 > data_end) - return 0; - memcpy(new_eth->eth_dest, cval->mac, 6); - memcpy(new_eth->eth_source, old_eth->eth_dest, 6); - new_eth->eth_proto = 56710; - ip6h->version = 6; - ip6h->priority = 0; - memset(ip6h->flow_lbl, 0, sizeof(ip6h->flow_lbl)); - - ip6h->nexthdr = IPPROTO_IPV6; - ip_suffix = pckt->flow.srcv6[3] ^ pckt->flow.port16[0]; - ip6h->payload_len = - __builtin_bswap16(pkt_bytes + sizeof(struct ipv6hdr)); - ip6h->hop_limit = 4; - - ip6h->saddr.in6_u.u6_addr32[0] = 1; - ip6h->saddr.in6_u.u6_addr32[1] = 2; - ip6h->saddr.in6_u.u6_addr32[2] = 3; - ip6h->saddr.in6_u.u6_addr32[3] = ip_suffix; - memcpy(ip6h->daddr.in6_u.u6_addr32, dst->dstv6, 16); - return 1; -} - -static __attribute__ ((noinline)) -bool encap_v4(struct xdp_md *xdp, struct ctl_value *cval, - struct packet_description *pckt, - struct real_definition *dst, __u32 pkt_bytes) -{ - - __u32 ip_suffix = __builtin_bswap16(pckt->flow.port16[0]); - struct eth_hdr *new_eth; - struct eth_hdr *old_eth; - __u16 *next_iph_u16; - struct iphdr *iph; - __u32 csum = 0; - void *data_end; - void *data; - - ip_suffix <<= 15; - ip_suffix ^= pckt->flow.src; - if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(struct iphdr))) - return 0; - data = (void *)(long)xdp->data; - data_end = (void *)(long)xdp->data_end; - new_eth = data; - iph = data + sizeof(struct eth_hdr); - old_eth = data + sizeof(struct iphdr); - if (new_eth + 1 > data_end || - old_eth + 1 > data_end || iph + 1 > data_end) - return 0; - memcpy(new_eth->eth_dest, cval->mac, 6); - memcpy(new_eth->eth_source, old_eth->eth_dest, 6); - new_eth->eth_proto = 8; - iph->version = 4; - iph->ihl = 5; - iph->frag_off = 0; - iph->protocol = IPPROTO_IPIP; - iph->check = 0; - iph->tos = 1; - iph->tot_len = __builtin_bswap16(pkt_bytes + sizeof(struct iphdr)); - /* don't update iph->daddr, since it will overwrite old eth_proto - * and multiple iterations of bpf_prog_run() will fail - */ - - iph->saddr = ((0xFFFF0000 & ip_suffix) | 4268) ^ dst->dst; - iph->ttl = 4; - - next_iph_u16 = (__u16 *) iph; -#pragma clang loop unroll(full) - for (int i = 0; i < sizeof(struct iphdr) >> 1; i++) - csum += *next_iph_u16++; - iph->check = ~((csum & 0xffff) + (csum >> 16)); - if (bpf_xdp_adjust_head(xdp, (int)sizeof(struct iphdr))) - return 0; - return 1; -} - -static __attribute__ ((noinline)) -bool decap_v6(struct xdp_md *xdp, void **data, void **data_end, bool inner_v4) -{ - struct eth_hdr *new_eth; - struct eth_hdr *old_eth; - - old_eth = *data; - new_eth = *data + sizeof(struct ipv6hdr); - memcpy(new_eth->eth_source, old_eth->eth_source, 6); - memcpy(new_eth->eth_dest, old_eth->eth_dest, 6); - if (inner_v4) - new_eth->eth_proto = 8; - else - new_eth->eth_proto = 56710; - if (bpf_xdp_adjust_head(xdp, (int)sizeof(struct ipv6hdr))) - return 0; - *data = (void *)(long)xdp->data; - *data_end = (void *)(long)xdp->data_end; - return 1; -} - -static __attribute__ ((noinline)) -bool decap_v4(struct xdp_md *xdp, void **data, void **data_end) -{ - struct eth_hdr *new_eth; - struct eth_hdr *old_eth; - - old_eth = *data; - new_eth = *data + sizeof(struct iphdr); - memcpy(new_eth->eth_source, old_eth->eth_source, 6); - memcpy(new_eth->eth_dest, old_eth->eth_dest, 6); - new_eth->eth_proto = 8; - if (bpf_xdp_adjust_head(xdp, (int)sizeof(struct iphdr))) - return 0; - *data = (void *)(long)xdp->data; - *data_end = (void *)(long)xdp->data_end; - return 1; -} - -static __attribute__ ((noinline)) -int swap_mac_and_send(void *data, void *data_end) -{ - unsigned char tmp_mac[6]; - struct eth_hdr *eth; - - eth = data; - memcpy(tmp_mac, eth->eth_source, 6); - memcpy(eth->eth_source, eth->eth_dest, 6); - memcpy(eth->eth_dest, tmp_mac, 6); - return XDP_TX; -} - -static __attribute__ ((noinline)) -int send_icmp_reply(void *data, void *data_end) -{ - struct icmphdr *icmp_hdr; - __u16 *next_iph_u16; - __u32 tmp_addr = 0; - struct iphdr *iph; - __u32 csum1 = 0; - __u32 csum = 0; - __u64 off = 0; - - if (data + sizeof(struct eth_hdr) - + sizeof(struct iphdr) + sizeof(struct icmphdr) > data_end) - return XDP_DROP; - off += sizeof(struct eth_hdr); - iph = data + off; - off += sizeof(struct iphdr); - icmp_hdr = data + off; - icmp_hdr->type = 0; - icmp_hdr->checksum += 0x0007; - iph->ttl = 4; - tmp_addr = iph->daddr; - iph->daddr = iph->saddr; - iph->saddr = tmp_addr; - iph->check = 0; - next_iph_u16 = (__u16 *) iph; -#pragma clang loop unroll(full) - for (int i = 0; i < sizeof(struct iphdr) >> 1; i++) - csum += *next_iph_u16++; - iph->check = ~((csum & 0xffff) + (csum >> 16)); - return swap_mac_and_send(data, data_end); -} - -static __attribute__ ((noinline)) -int send_icmp6_reply(void *data, void *data_end) -{ - struct icmp6hdr *icmp_hdr; - struct ipv6hdr *ip6h; - __be32 tmp_addr[4]; - __u64 off = 0; - - if (data + sizeof(struct eth_hdr) - + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr) > data_end) - return XDP_DROP; - off += sizeof(struct eth_hdr); - ip6h = data + off; - off += sizeof(struct ipv6hdr); - icmp_hdr = data + off; - icmp_hdr->icmp6_type = 129; - icmp_hdr->icmp6_cksum -= 0x0001; - ip6h->hop_limit = 4; - memcpy(tmp_addr, ip6h->saddr.in6_u.u6_addr32, 16); - memcpy(ip6h->saddr.in6_u.u6_addr32, ip6h->daddr.in6_u.u6_addr32, 16); - memcpy(ip6h->daddr.in6_u.u6_addr32, tmp_addr, 16); - return swap_mac_and_send(data, data_end); -} - -static __attribute__ ((noinline)) -int parse_icmpv6(void *data, void *data_end, __u64 off, - struct packet_description *pckt) -{ - struct icmp6hdr *icmp_hdr; - struct ipv6hdr *ip6h; - - icmp_hdr = data + off; - if (icmp_hdr + 1 > data_end) - return XDP_DROP; - if (icmp_hdr->icmp6_type == 128) - return send_icmp6_reply(data, data_end); - if (icmp_hdr->icmp6_type != 3) - return XDP_PASS; - off += sizeof(struct icmp6hdr); - ip6h = data + off; - if (ip6h + 1 > data_end) - return XDP_DROP; - pckt->flow.proto = ip6h->nexthdr; - pckt->flags |= (1 << 0); - memcpy(pckt->flow.srcv6, ip6h->daddr.in6_u.u6_addr32, 16); - memcpy(pckt->flow.dstv6, ip6h->saddr.in6_u.u6_addr32, 16); - return -1; -} - -static __attribute__ ((noinline)) -int parse_icmp(void *data, void *data_end, __u64 off, - struct packet_description *pckt) -{ - struct icmphdr *icmp_hdr; - struct iphdr *iph; - - icmp_hdr = data + off; - if (icmp_hdr + 1 > data_end) - return XDP_DROP; - if (icmp_hdr->type == 8) - return send_icmp_reply(data, data_end); - if ((icmp_hdr->type != 3) || (icmp_hdr->code != 4)) - return XDP_PASS; - off += sizeof(struct icmphdr); - iph = data + off; - if (iph + 1 > data_end) - return XDP_DROP; - if (iph->ihl != 5) - return XDP_DROP; - pckt->flow.proto = iph->protocol; - pckt->flags |= (1 << 0); - pckt->flow.src = iph->daddr; - pckt->flow.dst = iph->saddr; - return -1; -} - -static __attribute__ ((noinline)) -__u32 get_packet_hash(struct packet_description *pckt, - bool hash_16bytes) -{ - if (hash_16bytes) - return jhash_2words(jhash(pckt->flow.srcv6, 16, 12), - pckt->flow.ports, 24); - else - return jhash_2words(pckt->flow.src, pckt->flow.ports, - 24); -} - -__attribute__ ((noinline)) -static bool get_packet_dst(struct real_definition **real, - struct packet_description *pckt, - struct vip_meta *vip_info, - bool is_ipv6, void *lru_map) -{ - struct real_pos_lru new_dst_lru = { }; - bool hash_16bytes = is_ipv6; - __u32 *real_pos, hash, key; - __u64 cur_time; - - if (vip_info->flags & (1 << 2)) - hash_16bytes = 1; - if (vip_info->flags & (1 << 3)) { - pckt->flow.port16[0] = pckt->flow.port16[1]; - memset(pckt->flow.srcv6, 0, 16); - } - hash = get_packet_hash(pckt, hash_16bytes); - if (hash != 0x358459b7 /* jhash of ipv4 packet */ && - hash != 0x2f4bc6bb /* jhash of ipv6 packet */) - return 0; - key = 2 * vip_info->vip_num + hash % 2; - real_pos = bpf_map_lookup_elem(&ch_rings, &key); - if (!real_pos) - return 0; - key = *real_pos; - *real = bpf_map_lookup_elem(&reals, &key); - if (!(*real)) - return 0; - if (!(vip_info->flags & (1 << 1))) { - __u32 conn_rate_key = 512 + 2; - struct lb_stats *conn_rate_stats = - bpf_map_lookup_elem(&stats, &conn_rate_key); - - if (!conn_rate_stats) - return 1; - cur_time = bpf_ktime_get_ns(); - if ((cur_time - conn_rate_stats->v2) >> 32 > 0xffFFFF) { - conn_rate_stats->v1 = 1; - conn_rate_stats->v2 = cur_time; - } else { - conn_rate_stats->v1 += 1; - if (conn_rate_stats->v1 >= 1) - return 1; - } - if (pckt->flow.proto == IPPROTO_UDP) - new_dst_lru.atime = cur_time; - new_dst_lru.pos = key; - bpf_map_update_elem(lru_map, &pckt->flow, &new_dst_lru, 0); - } - return 1; -} - -__attribute__ ((noinline)) -static void connection_table_lookup(struct real_definition **real, - struct packet_description *pckt, - void *lru_map) -{ - - struct real_pos_lru *dst_lru; - __u64 cur_time; - __u32 key; - - dst_lru = bpf_map_lookup_elem(lru_map, &pckt->flow); - if (!dst_lru) - return; - if (pckt->flow.proto == IPPROTO_UDP) { - cur_time = bpf_ktime_get_ns(); - if (cur_time - dst_lru->atime > 300000) - return; - dst_lru->atime = cur_time; - } - key = dst_lru->pos; - *real = bpf_map_lookup_elem(&reals, &key); -} - -/* don't believe your eyes! - * below function has 6 arguments whereas bpf and llvm allow maximum of 5 - * but since it's _static_ llvm can optimize one argument away - */ -__attribute__ ((noinline)) -static int process_l3_headers_v6(struct packet_description *pckt, - __u8 *protocol, __u64 off, - __u16 *pkt_bytes, void *data, - void *data_end) -{ - struct ipv6hdr *ip6h; - __u64 iph_len; - int action; - - ip6h = data + off; - if (ip6h + 1 > data_end) - return XDP_DROP; - iph_len = sizeof(struct ipv6hdr); - *protocol = ip6h->nexthdr; - pckt->flow.proto = *protocol; - *pkt_bytes = __builtin_bswap16(ip6h->payload_len); - off += iph_len; - if (*protocol == 45) { - return XDP_DROP; - } else if (*protocol == 59) { - action = parse_icmpv6(data, data_end, off, pckt); - if (action >= 0) - return action; - } else { - memcpy(pckt->flow.srcv6, ip6h->saddr.in6_u.u6_addr32, 16); - memcpy(pckt->flow.dstv6, ip6h->daddr.in6_u.u6_addr32, 16); - } - return -1; -} - -__attribute__ ((noinline)) -static int process_l3_headers_v4(struct packet_description *pckt, - __u8 *protocol, __u64 off, - __u16 *pkt_bytes, void *data, - void *data_end) -{ - struct iphdr *iph; - __u64 iph_len; - int action; - - iph = data + off; - if (iph + 1 > data_end) - return XDP_DROP; - if (iph->ihl != 5) - return XDP_DROP; - *protocol = iph->protocol; - pckt->flow.proto = *protocol; - *pkt_bytes = __builtin_bswap16(iph->tot_len); - off += 20; - if (iph->frag_off & 65343) - return XDP_DROP; - if (*protocol == IPPROTO_ICMP) { - action = parse_icmp(data, data_end, off, pckt); - if (action >= 0) - return action; - } else { - pckt->flow.src = iph->saddr; - pckt->flow.dst = iph->daddr; - } - return -1; -} - -__attribute__ ((noinline)) -static int process_packet(void *data, __u64 off, void *data_end, - bool is_ipv6, struct xdp_md *xdp) -{ - - struct real_definition *dst = NULL; - struct packet_description pckt = { }; - struct vip_definition vip = { }; - struct lb_stats *data_stats; - struct eth_hdr *eth = data; - void *lru_map = &lru_cache; - struct vip_meta *vip_info; - __u32 lru_stats_key = 513; - __u32 mac_addr_pos = 0; - __u32 stats_key = 512; - struct ctl_value *cval; - __u16 pkt_bytes; - __u64 iph_len; - __u8 protocol; - __u32 vip_num; - int action; - - if (is_ipv6) - action = process_l3_headers_v6(&pckt, &protocol, off, - &pkt_bytes, data, data_end); - else - action = process_l3_headers_v4(&pckt, &protocol, off, - &pkt_bytes, data, data_end); - if (action >= 0) - return action; - protocol = pckt.flow.proto; - if (protocol == IPPROTO_TCP) { - if (!parse_tcp(data, data_end, is_ipv6, &pckt)) - return XDP_DROP; - } else if (protocol == IPPROTO_UDP) { - if (!parse_udp(data, data_end, is_ipv6, &pckt)) - return XDP_DROP; - } else { - return XDP_TX; - } - - if (is_ipv6) - memcpy(vip.vipv6, pckt.flow.dstv6, 16); - else - vip.vip = pckt.flow.dst; - vip.port = pckt.flow.port16[1]; - vip.proto = pckt.flow.proto; - vip_info = bpf_map_lookup_elem(&vip_map, &vip); - if (!vip_info) { - vip.port = 0; - vip_info = bpf_map_lookup_elem(&vip_map, &vip); - if (!vip_info) - return XDP_PASS; - if (!(vip_info->flags & (1 << 4))) - pckt.flow.port16[1] = 0; - } - if (data_end - data > 1400) - return XDP_DROP; - data_stats = bpf_map_lookup_elem(&stats, &stats_key); - if (!data_stats) - return XDP_DROP; - data_stats->v1 += 1; - if (!dst) { - if (vip_info->flags & (1 << 0)) - pckt.flow.port16[0] = 0; - if (!(pckt.flags & (1 << 1)) && !(vip_info->flags & (1 << 1))) - connection_table_lookup(&dst, &pckt, lru_map); - if (dst) - goto out; - if (pckt.flow.proto == IPPROTO_TCP) { - struct lb_stats *lru_stats = - bpf_map_lookup_elem(&stats, &lru_stats_key); - - if (!lru_stats) - return XDP_DROP; - if (pckt.flags & (1 << 1)) - lru_stats->v1 += 1; - else - lru_stats->v2 += 1; - } - if (!get_packet_dst(&dst, &pckt, vip_info, is_ipv6, lru_map)) - return XDP_DROP; - data_stats->v2 += 1; - } -out: - cval = bpf_map_lookup_elem(&ctl_array, &mac_addr_pos); - if (!cval) - return XDP_DROP; - if (dst->flags & (1 << 0)) { - if (!encap_v6(xdp, cval, &pckt, dst, pkt_bytes)) - return XDP_DROP; - } else { - if (!encap_v4(xdp, cval, &pckt, dst, pkt_bytes)) - return XDP_DROP; - } - vip_num = vip_info->vip_num; - data_stats = bpf_map_lookup_elem(&stats, &vip_num); - if (!data_stats) - return XDP_DROP; - data_stats->v1 += 1; - data_stats->v2 += pkt_bytes; - - data = (void *)(long)xdp->data; - data_end = (void *)(long)xdp->data_end; - if (data + 4 > data_end) - return XDP_DROP; - *(u32 *)data = dst->dst; - return XDP_DROP; -} - -__attribute__ ((section("xdp-test"), used)) -int balancer_ingress(struct xdp_md *ctx) -{ - void *data = (void *)(long)ctx->data; - void *data_end = (void *)(long)ctx->data_end; - struct eth_hdr *eth = data; - __u32 eth_proto; - __u32 nh_off; - - nh_off = sizeof(struct eth_hdr); - if (data + nh_off > data_end) - return XDP_DROP; - eth_proto = eth->eth_proto; - if (eth_proto == 8) - return process_packet(data, nh_off, data_end, 0, ctx); - else if (eth_proto == 56710) - return process_packet(data, nh_off, data_end, 1, ctx); - else - return XDP_DROP; -} - -char _license[] __attribute__ ((section("license"), used)) = "GPL"; -int _version __attribute__ ((section("version"), used)) = 1; diff --git a/tools/testing/selftests/bpf/test_xdp_redirect.c b/tools/testing/selftests/bpf/test_xdp_redirect.c deleted file mode 100644 index ef9e704be140..000000000000 --- a/tools/testing/selftests/bpf/test_xdp_redirect.c +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (c) 2017 VMware - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#include -#include "bpf_helpers.h" - -int _version SEC("version") = 1; - -SEC("redirect_to_111") -int xdp_redirect_to_111(struct xdp_md *xdp) -{ - return bpf_redirect(111, 0); -} -SEC("redirect_to_222") -int xdp_redirect_to_222(struct xdp_md *xdp) -{ - return bpf_redirect(222, 0); -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_xdp_vlan.c b/tools/testing/selftests/bpf/test_xdp_vlan.c deleted file mode 100644 index 365a7d2d9f5c..000000000000 --- a/tools/testing/selftests/bpf/test_xdp_vlan.c +++ /dev/null @@ -1,292 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 - * Copyright(c) 2018 Jesper Dangaard Brouer. - * - * XDP/TC VLAN manipulation example - * - * GOTCHA: Remember to disable NIC hardware offloading of VLANs, - * else the VLAN tags are NOT inlined in the packet payload: - * - * # ethtool -K ixgbe2 rxvlan off - * - * Verify setting: - * # ethtool -k ixgbe2 | grep rx-vlan-offload - * rx-vlan-offload: off - * - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bpf_helpers.h" -#include "bpf_endian.h" - -/* linux/if_vlan.h have not exposed this as UAPI, thus mirror some here - * - * struct vlan_hdr - vlan header - * @h_vlan_TCI: priority and VLAN ID - * @h_vlan_encapsulated_proto: packet type ID or len - */ -struct _vlan_hdr { - __be16 h_vlan_TCI; - __be16 h_vlan_encapsulated_proto; -}; -#define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */ -#define VLAN_PRIO_SHIFT 13 -#define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */ -#define VLAN_TAG_PRESENT VLAN_CFI_MASK -#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */ -#define VLAN_N_VID 4096 - -struct parse_pkt { - __u16 l3_proto; - __u16 l3_offset; - __u16 vlan_outer; - __u16 vlan_inner; - __u8 vlan_outer_offset; - __u8 vlan_inner_offset; -}; - -char _license[] SEC("license") = "GPL"; - -static __always_inline -bool parse_eth_frame(struct ethhdr *eth, void *data_end, struct parse_pkt *pkt) -{ - __u16 eth_type; - __u8 offset; - - offset = sizeof(*eth); - /* Make sure packet is large enough for parsing eth + 2 VLAN headers */ - if ((void *)eth + offset + (2*sizeof(struct _vlan_hdr)) > data_end) - return false; - - eth_type = eth->h_proto; - - /* Handle outer VLAN tag */ - if (eth_type == bpf_htons(ETH_P_8021Q) - || eth_type == bpf_htons(ETH_P_8021AD)) { - struct _vlan_hdr *vlan_hdr; - - vlan_hdr = (void *)eth + offset; - pkt->vlan_outer_offset = offset; - pkt->vlan_outer = bpf_ntohs(vlan_hdr->h_vlan_TCI) - & VLAN_VID_MASK; - eth_type = vlan_hdr->h_vlan_encapsulated_proto; - offset += sizeof(*vlan_hdr); - } - - /* Handle inner (double) VLAN tag */ - if (eth_type == bpf_htons(ETH_P_8021Q) - || eth_type == bpf_htons(ETH_P_8021AD)) { - struct _vlan_hdr *vlan_hdr; - - vlan_hdr = (void *)eth + offset; - pkt->vlan_inner_offset = offset; - pkt->vlan_inner = bpf_ntohs(vlan_hdr->h_vlan_TCI) - & VLAN_VID_MASK; - eth_type = vlan_hdr->h_vlan_encapsulated_proto; - offset += sizeof(*vlan_hdr); - } - - pkt->l3_proto = bpf_ntohs(eth_type); /* Convert to host-byte-order */ - pkt->l3_offset = offset; - - return true; -} - -/* Hint, VLANs are choosen to hit network-byte-order issues */ -#define TESTVLAN 4011 /* 0xFAB */ -// #define TO_VLAN 4000 /* 0xFA0 (hint 0xOA0 = 160) */ - -SEC("xdp_drop_vlan_4011") -int xdp_prognum0(struct xdp_md *ctx) -{ - void *data_end = (void *)(long)ctx->data_end; - void *data = (void *)(long)ctx->data; - struct parse_pkt pkt = { 0 }; - - if (!parse_eth_frame(data, data_end, &pkt)) - return XDP_ABORTED; - - /* Drop specific VLAN ID example */ - if (pkt.vlan_outer == TESTVLAN) - return XDP_ABORTED; - /* - * Using XDP_ABORTED makes it possible to record this event, - * via tracepoint xdp:xdp_exception like: - * # perf record -a -e xdp:xdp_exception - * # perf script - */ - return XDP_PASS; -} -/* -Commands to setup VLAN on Linux to test packets gets dropped: - - export ROOTDEV=ixgbe2 - export VLANID=4011 - ip link add link $ROOTDEV name $ROOTDEV.$VLANID type vlan id $VLANID - ip link set dev $ROOTDEV.$VLANID up - - ip link set dev $ROOTDEV mtu 1508 - ip addr add 100.64.40.11/24 dev $ROOTDEV.$VLANID - -Load prog with ip tool: - - ip link set $ROOTDEV xdp off - ip link set $ROOTDEV xdp object xdp_vlan01_kern.o section xdp_drop_vlan_4011 - -*/ - -/* Changing VLAN to zero, have same practical effect as removing the VLAN. */ -#define TO_VLAN 0 - -SEC("xdp_vlan_change") -int xdp_prognum1(struct xdp_md *ctx) -{ - void *data_end = (void *)(long)ctx->data_end; - void *data = (void *)(long)ctx->data; - struct parse_pkt pkt = { 0 }; - - if (!parse_eth_frame(data, data_end, &pkt)) - return XDP_ABORTED; - - /* Change specific VLAN ID */ - if (pkt.vlan_outer == TESTVLAN) { - struct _vlan_hdr *vlan_hdr = data + pkt.vlan_outer_offset; - - /* Modifying VLAN, preserve top 4 bits */ - vlan_hdr->h_vlan_TCI = - bpf_htons((bpf_ntohs(vlan_hdr->h_vlan_TCI) & 0xf000) - | TO_VLAN); - } - - return XDP_PASS; -} - -/* - * Show XDP+TC can cooperate, on creating a VLAN rewriter. - * 1. Create a XDP prog that can "pop"/remove a VLAN header. - * 2. Create a TC-bpf prog that egress can add a VLAN header. - */ - -#ifndef ETH_ALEN /* Ethernet MAC address length */ -#define ETH_ALEN 6 /* bytes */ -#endif -#define VLAN_HDR_SZ 4 /* bytes */ - -SEC("xdp_vlan_remove_outer") -int xdp_prognum2(struct xdp_md *ctx) -{ - void *data_end = (void *)(long)ctx->data_end; - void *data = (void *)(long)ctx->data; - struct parse_pkt pkt = { 0 }; - char *dest; - - if (!parse_eth_frame(data, data_end, &pkt)) - return XDP_ABORTED; - - /* Skip packet if no outer VLAN was detected */ - if (pkt.vlan_outer_offset == 0) - return XDP_PASS; - - /* Moving Ethernet header, dest overlap with src, memmove handle this */ - dest = data; - dest+= VLAN_HDR_SZ; - /* - * Notice: Taking over vlan_hdr->h_vlan_encapsulated_proto, by - * only moving two MAC addrs (12 bytes), not overwriting last 2 bytes - */ - __builtin_memmove(dest, data, ETH_ALEN * 2); - /* Note: LLVM built-in memmove inlining require size to be constant */ - - /* Move start of packet header seen by Linux kernel stack */ - bpf_xdp_adjust_head(ctx, VLAN_HDR_SZ); - - return XDP_PASS; -} - -static __always_inline -void shift_mac_4bytes_16bit(void *data) -{ - __u16 *p = data; - - p[7] = p[5]; /* delete p[7] was vlan_hdr->h_vlan_TCI */ - p[6] = p[4]; /* delete p[6] was ethhdr->h_proto */ - p[5] = p[3]; - p[4] = p[2]; - p[3] = p[1]; - p[2] = p[0]; -} - -static __always_inline -void shift_mac_4bytes_32bit(void *data) -{ - __u32 *p = data; - - /* Assuming VLAN hdr present. The 4 bytes in p[3] that gets - * overwritten, is ethhdr->h_proto and vlan_hdr->h_vlan_TCI. - * The vlan_hdr->h_vlan_encapsulated_proto take over role as - * ethhdr->h_proto. - */ - p[3] = p[2]; - p[2] = p[1]; - p[1] = p[0]; -} - -SEC("xdp_vlan_remove_outer2") -int xdp_prognum3(struct xdp_md *ctx) -{ - void *data_end = (void *)(long)ctx->data_end; - void *data = (void *)(long)ctx->data; - struct ethhdr *orig_eth = data; - struct parse_pkt pkt = { 0 }; - - if (!parse_eth_frame(orig_eth, data_end, &pkt)) - return XDP_ABORTED; - - /* Skip packet if no outer VLAN was detected */ - if (pkt.vlan_outer_offset == 0) - return XDP_PASS; - - /* Simply shift down MAC addrs 4 bytes, overwrite h_proto + TCI */ - shift_mac_4bytes_32bit(data); - - /* Move start of packet header seen by Linux kernel stack */ - bpf_xdp_adjust_head(ctx, VLAN_HDR_SZ); - - return XDP_PASS; -} - -/*===================================== - * BELOW: TC-hook based ebpf programs - * ==================================== - * The TC-clsact eBPF programs (currently) need to be attach via TC commands - */ - -SEC("tc_vlan_push") -int _tc_progA(struct __sk_buff *ctx) -{ - bpf_skb_vlan_push(ctx, bpf_htons(ETH_P_8021Q), TESTVLAN); - - return TC_ACT_OK; -} -/* -Commands to setup TC to use above bpf prog: - -export ROOTDEV=ixgbe2 -export FILE=xdp_vlan01_kern.o - -# Re-attach clsact to clear/flush existing role -tc qdisc del dev $ROOTDEV clsact 2> /dev/null ;\ -tc qdisc add dev $ROOTDEV clsact - -# Attach BPF prog EGRESS -tc filter add dev $ROOTDEV egress \ - prio 1 handle 1 bpf da obj $FILE sec tc_vlan_push - -tc filter show dev $ROOTDEV egress -*/ diff --git a/tools/testing/selftests/bpf/xdp_dummy.c b/tools/testing/selftests/bpf/xdp_dummy.c deleted file mode 100644 index 43b0ef1001ed..000000000000 --- a/tools/testing/selftests/bpf/xdp_dummy.c +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#define KBUILD_MODNAME "xdp_dummy" -#include -#include "bpf_helpers.h" - -SEC("xdp_dummy") -int xdp_dummy_prog(struct xdp_md *ctx) -{ - return XDP_PASS; -} - -char _license[] SEC("license") = "GPL"; -- cgit v1.2.3-59-g8ed1b From 64e39ee2c84bd8eac1bd3ea370c4ada5163befac Mon Sep 17 00:00:00 2001 From: Jiong Wang Date: Mon, 11 Feb 2019 12:01:21 +0000 Subject: selftests: bpf: relax sub-register mode compilation criteria Sub-register mode compilation was enabled only when there are eBPF "v3" processor supports at both compilation time inside LLVM and runtime inside kernel. Given separation betwen build and test server could be often, this patch removes the runtime support criteria. Suggested-by: Alexei Starovoitov Signed-off-by: Jiong Wang Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 575746e63544..c3edf47da05d 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -28,12 +28,11 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c))) TEST_GEN_FILES = $(BPF_OBJ_FILES) -# Also test sub-register code-gen if LLVM + kernel both has eBPF v3 processor -# support which is the first version to contain both ALU32 and JMP32 -# instructions. +# Also test sub-register code-gen if LLVM has eBPF v3 processor support which +# contains both ALU32 and JMP32 instructions. SUBREG_CODEGEN := $(shell echo "int cal(int a) { return a > 0; }" | \ $(CLANG) -target bpf -O2 -emit-llvm -S -x c - -o - | \ - $(LLC) -mattr=+alu32 -mcpu=probe 2>&1 | \ + $(LLC) -mattr=+alu32 -mcpu=v3 2>&1 | \ grep 'if w') ifneq ($(SUBREG_CODEGEN),) TEST_GEN_FILES += $(patsubst %.o,alu32/%.o, $(BPF_OBJ_FILES)) -- cgit v1.2.3-59-g8ed1b