diff options
Diffstat (limited to 'tools/testing/selftests/bpf/prog_tests')
8 files changed, 394 insertions, 21 deletions
diff --git a/tools/testing/selftests/bpf/prog_tests/attach_probe.c b/tools/testing/selftests/bpf/prog_tests/attach_probe.c index 4f50d32c4abb..a83111a32d4a 100644 --- a/tools/testing/selftests/bpf/prog_tests/attach_probe.c +++ b/tools/testing/selftests/bpf/prog_tests/attach_probe.c @@ -50,7 +50,7 @@ void test_attach_probe(void) const int kprobe_idx = 0, kretprobe_idx = 1; const int uprobe_idx = 2, uretprobe_idx = 3; const char *obj_name = "attach_probe"; - LIBBPF_OPTS(bpf_object_open_opts, open_opts, + DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, .object_name = obj_name, .relaxed_maps = true, ); @@ -99,11 +99,6 @@ void test_attach_probe(void) "prog '%s' not found\n", uretprobe_name)) goto cleanup; - bpf_program__set_kprobe(kprobe_prog); - bpf_program__set_kprobe(kretprobe_prog); - bpf_program__set_kprobe(uprobe_prog); - bpf_program__set_kprobe(uretprobe_prog); - /* create maps && load programs */ err = bpf_object__load(obj); if (CHECK(err, "obj_load", "err %d\n", err)) diff --git a/tools/testing/selftests/bpf/prog_tests/core_reloc.c b/tools/testing/selftests/bpf/prog_tests/core_reloc.c index 21a0dff66241..09dfa75fe948 100644 --- a/tools/testing/selftests/bpf/prog_tests/core_reloc.c +++ b/tools/testing/selftests/bpf/prog_tests/core_reloc.c @@ -174,6 +174,21 @@ .fails = true, \ } +#define EXISTENCE_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \ + .a = 42, \ +} + +#define EXISTENCE_CASE_COMMON(name) \ + .case_name = #name, \ + .bpf_obj_file = "test_core_reloc_existence.o", \ + .btf_src_file = "btf__core_reloc_" #name ".o", \ + .relaxed_core_relocs = true \ + +#define EXISTENCE_ERR_CASE(name) { \ + EXISTENCE_CASE_COMMON(name), \ + .fails = true, \ +} + struct core_reloc_test_case { const char *case_name; const char *bpf_obj_file; @@ -183,6 +198,7 @@ struct core_reloc_test_case { const char *output; int output_len; bool fails; + bool relaxed_core_relocs; }; static struct core_reloc_test_case test_cases[] = { @@ -195,8 +211,8 @@ static struct core_reloc_test_case test_cases[] = { .input_len = 0, .output = STRUCT_TO_CHAR_PTR(core_reloc_kernel_output) { .valid = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, - .comm = "test_progs\0\0\0\0\0", - .comm_len = 11, + .comm = "test_progs", + .comm_len = sizeof("test_progs"), }, .output_len = sizeof(struct core_reloc_kernel_output), }, @@ -283,6 +299,59 @@ static struct core_reloc_test_case test_cases[] = { }, .output_len = sizeof(struct core_reloc_misc_output), }, + + /* validate field existence checks */ + { + EXISTENCE_CASE_COMMON(existence), + .input = STRUCT_TO_CHAR_PTR(core_reloc_existence) { + .a = 1, + .b = 2, + .c = 3, + .arr = { 4 }, + .s = { .x = 5 }, + }, + .input_len = sizeof(struct core_reloc_existence), + .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) { + .a_exists = 1, + .b_exists = 1, + .c_exists = 1, + .arr_exists = 1, + .s_exists = 1, + .a_value = 1, + .b_value = 2, + .c_value = 3, + .arr_value = 4, + .s_value = 5, + }, + .output_len = sizeof(struct core_reloc_existence_output), + }, + { + EXISTENCE_CASE_COMMON(existence___minimal), + .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___minimal) { + .a = 42, + }, + .input_len = sizeof(struct core_reloc_existence), + .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) { + .a_exists = 1, + .b_exists = 0, + .c_exists = 0, + .arr_exists = 0, + .s_exists = 0, + .a_value = 42, + .b_value = 0xff000002u, + .c_value = 0xff000003u, + .arr_value = 0xff000004u, + .s_value = 0xff000005u, + }, + .output_len = sizeof(struct core_reloc_existence_output), + }, + + EXISTENCE_ERR_CASE(existence__err_int_sz), + EXISTENCE_ERR_CASE(existence__err_int_type), + EXISTENCE_ERR_CASE(existence__err_int_kind), + EXISTENCE_ERR_CASE(existence__err_arr_kind), + EXISTENCE_ERR_CASE(existence__err_arr_value_type), + EXISTENCE_ERR_CASE(existence__err_struct_type), }; struct data { @@ -305,11 +374,14 @@ void test_core_reloc(void) for (i = 0; i < ARRAY_SIZE(test_cases); i++) { test_case = &test_cases[i]; - if (!test__start_subtest(test_case->case_name)) continue; - obj = bpf_object__open(test_case->bpf_obj_file); + DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, + .relaxed_core_relocs = test_case->relaxed_core_relocs, + ); + + obj = bpf_object__open_file(test_case->bpf_obj_file, &opts); if (CHECK(IS_ERR_OR_NULL(obj), "obj_open", "failed to open '%s': %ld\n", test_case->bpf_obj_file, PTR_ERR(obj))) @@ -319,7 +391,6 @@ void test_core_reloc(void) if (CHECK(!prog, "find_probe", "prog '%s' not found\n", probe_name)) goto cleanup; - bpf_program__set_type(prog, BPF_PROG_TYPE_RAW_TRACEPOINT); load_attr.obj = obj; load_attr.log_level = 0; diff --git a/tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c b/tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c index 777faffc4639..1f51ba66b98b 100644 --- a/tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c +++ b/tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c @@ -91,12 +91,18 @@ out_close: void test_flow_dissector_reattach(void) { - int init_net, err; + int init_net, self_net, err; + + self_net = open("/proc/self/ns/net", O_RDONLY); + if (CHECK_FAIL(self_net < 0)) { + perror("open(/proc/self/ns/net"); + return; + } init_net = open("/proc/1/ns/net", O_RDONLY); if (CHECK_FAIL(init_net < 0)) { perror("open(/proc/1/ns/net)"); - return; + goto out_close; } err = setns(init_net, CLONE_NEWNET); @@ -108,7 +114,7 @@ void test_flow_dissector_reattach(void) if (is_attached(init_net)) { test__skip(); printf("Can't test with flow dissector attached to init_net\n"); - return; + goto out_setns; } /* First run tests in root network namespace */ @@ -118,10 +124,17 @@ void test_flow_dissector_reattach(void) err = unshare(CLONE_NEWNET); if (CHECK_FAIL(err)) { perror("unshare(CLONE_NEWNET)"); - goto out_close; + goto out_setns; } do_flow_dissector_reattach(); +out_setns: + /* Move back to netns we started in. */ + err = setns(self_net, CLONE_NEWNET); + if (CHECK_FAIL(err)) + perror("setns(/proc/self/ns/net)"); + out_close: close(init_net); + close(self_net); } diff --git a/tools/testing/selftests/bpf/prog_tests/kfree_skb.c b/tools/testing/selftests/bpf/prog_tests/kfree_skb.c new file mode 100644 index 000000000000..430b50de1583 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/kfree_skb.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <test_progs.h> + +static void on_sample(void *ctx, int cpu, void *data, __u32 size) +{ + int ifindex = *(int *)data, duration = 0; + struct ipv6_packet *pkt_v6 = data + 4; + + if (ifindex != 1) + /* spurious kfree_skb not on loopback device */ + return; + if (CHECK(size != 76, "check_size", "size %u != 76\n", size)) + return; + if (CHECK(pkt_v6->eth.h_proto != 0xdd86, "check_eth", + "h_proto %x\n", pkt_v6->eth.h_proto)) + return; + if (CHECK(pkt_v6->iph.nexthdr != 6, "check_ip", + "iph.nexthdr %x\n", pkt_v6->iph.nexthdr)) + return; + if (CHECK(pkt_v6->tcp.doff != 5, "check_tcp", + "tcp.doff %x\n", pkt_v6->tcp.doff)) + return; + + *(bool *)ctx = true; +} + +void test_kfree_skb(void) +{ + struct bpf_prog_load_attr attr = { + .file = "./kfree_skb.o", + }; + + struct bpf_object *obj, *obj2 = NULL; + struct perf_buffer_opts pb_opts = {}; + struct perf_buffer *pb = NULL; + struct bpf_link *link = NULL; + struct bpf_map *perf_buf_map; + struct bpf_program *prog; + __u32 duration, retval; + int err, pkt_fd, kfree_skb_fd; + bool passed = false; + + err = bpf_prog_load("./test_pkt_access.o", BPF_PROG_TYPE_SCHED_CLS, &obj, &pkt_fd); + if (CHECK(err, "prog_load sched cls", "err %d errno %d\n", err, errno)) + return; + + err = bpf_prog_load_xattr(&attr, &obj2, &kfree_skb_fd); + if (CHECK(err, "prog_load raw tp", "err %d errno %d\n", err, errno)) + goto close_prog; + + prog = bpf_object__find_program_by_title(obj2, "tp_btf/kfree_skb"); + if (CHECK(!prog, "find_prog", "prog kfree_skb not found\n")) + goto close_prog; + link = bpf_program__attach_raw_tracepoint(prog, NULL); + if (CHECK(IS_ERR(link), "attach_raw_tp", "err %ld\n", PTR_ERR(link))) + goto close_prog; + + perf_buf_map = bpf_object__find_map_by_name(obj2, "perf_buf_map"); + if (CHECK(!perf_buf_map, "find_perf_buf_map", "not found\n")) + goto close_prog; + + /* set up perf buffer */ + pb_opts.sample_cb = on_sample; + pb_opts.ctx = &passed; + pb = perf_buffer__new(bpf_map__fd(perf_buf_map), 1, &pb_opts); + if (CHECK(IS_ERR(pb), "perf_buf__new", "err %ld\n", PTR_ERR(pb))) + goto close_prog; + + err = bpf_prog_test_run(pkt_fd, 1, &pkt_v6, sizeof(pkt_v6), + NULL, NULL, &retval, &duration); + CHECK(err || retval, "ipv6", + "err %d errno %d retval %d duration %d\n", + err, errno, retval, duration); + + /* read perf buffer */ + err = perf_buffer__poll(pb, 100); + if (CHECK(err < 0, "perf_buffer__poll", "err %d\n", err)) + goto close_prog; + /* make sure kfree_skb program was triggered + * and it sent expected skb into ring buffer + */ + CHECK_FAIL(!passed); +close_prog: + perf_buffer__free(pb); + if (!IS_ERR_OR_NULL(link)) + bpf_link__destroy(link); + bpf_object__close(obj); + bpf_object__close(obj2); +} diff --git a/tools/testing/selftests/bpf/prog_tests/rdonly_maps.c b/tools/testing/selftests/bpf/prog_tests/rdonly_maps.c index 9bf9de0aaeea..d90acc13d1ec 100644 --- a/tools/testing/selftests/bpf/prog_tests/rdonly_maps.c +++ b/tools/testing/selftests/bpf/prog_tests/rdonly_maps.c @@ -36,10 +36,6 @@ void test_rdonly_maps(void) if (CHECK(IS_ERR(obj), "obj_open", "err %ld\n", PTR_ERR(obj))) return; - bpf_object__for_each_program(prog, obj) { - bpf_program__set_raw_tracepoint(prog); - } - err = bpf_object__load(obj); if (CHECK(err, "obj_load", "err %d errno %d\n", err, errno)) goto cleanup; diff --git a/tools/testing/selftests/bpf/prog_tests/reference_tracking.c b/tools/testing/selftests/bpf/prog_tests/reference_tracking.c index 86cee820d4d3..fc0d7f4f02cf 100644 --- a/tools/testing/selftests/bpf/prog_tests/reference_tracking.c +++ b/tools/testing/selftests/bpf/prog_tests/reference_tracking.c @@ -5,7 +5,7 @@ void test_reference_tracking(void) { const char *file = "test_sk_lookup_kern.o"; const char *obj_name = "ref_track"; - LIBBPF_OPTS(bpf_object_open_opts, open_opts, + DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, .object_name = obj_name, .relaxed_maps = true, ); @@ -31,7 +31,8 @@ void test_reference_tracking(void) if (strstr(title, ".text") != NULL) continue; - bpf_program__set_type(prog, BPF_PROG_TYPE_SCHED_CLS); + if (!test__start_subtest(title)) + continue; /* Expect verifier failure if test name has 'fail' */ if (strstr(title, "fail") != NULL) { diff --git a/tools/testing/selftests/bpf/prog_tests/section_names.c b/tools/testing/selftests/bpf/prog_tests/section_names.c new file mode 100644 index 000000000000..9d9351dc2ded --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/section_names.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook +#include <test_progs.h> + +static int duration = 0; + +struct sec_name_test { + const char sec_name[32]; + struct { + int rc; + enum bpf_prog_type prog_type; + enum bpf_attach_type expected_attach_type; + } expected_load; + struct { + int rc; + enum bpf_attach_type attach_type; + } expected_attach; +}; + +static struct sec_name_test tests[] = { + {"InvAliD", {-ESRCH, 0, 0}, {-EINVAL, 0} }, + {"cgroup", {-ESRCH, 0, 0}, {-EINVAL, 0} }, + {"socket", {0, BPF_PROG_TYPE_SOCKET_FILTER, 0}, {-EINVAL, 0} }, + {"kprobe/", {0, BPF_PROG_TYPE_KPROBE, 0}, {-EINVAL, 0} }, + {"uprobe/", {0, BPF_PROG_TYPE_KPROBE, 0}, {-EINVAL, 0} }, + {"kretprobe/", {0, BPF_PROG_TYPE_KPROBE, 0}, {-EINVAL, 0} }, + {"uretprobe/", {0, BPF_PROG_TYPE_KPROBE, 0}, {-EINVAL, 0} }, + {"classifier", {0, BPF_PROG_TYPE_SCHED_CLS, 0}, {-EINVAL, 0} }, + {"action", {0, BPF_PROG_TYPE_SCHED_ACT, 0}, {-EINVAL, 0} }, + {"tracepoint/", {0, BPF_PROG_TYPE_TRACEPOINT, 0}, {-EINVAL, 0} }, + {"tp/", {0, BPF_PROG_TYPE_TRACEPOINT, 0}, {-EINVAL, 0} }, + { + "raw_tracepoint/", + {0, BPF_PROG_TYPE_RAW_TRACEPOINT, 0}, + {-EINVAL, 0}, + }, + {"raw_tp/", {0, BPF_PROG_TYPE_RAW_TRACEPOINT, 0}, {-EINVAL, 0} }, + {"xdp", {0, BPF_PROG_TYPE_XDP, 0}, {-EINVAL, 0} }, + {"perf_event", {0, BPF_PROG_TYPE_PERF_EVENT, 0}, {-EINVAL, 0} }, + {"lwt_in", {0, BPF_PROG_TYPE_LWT_IN, 0}, {-EINVAL, 0} }, + {"lwt_out", {0, BPF_PROG_TYPE_LWT_OUT, 0}, {-EINVAL, 0} }, + {"lwt_xmit", {0, BPF_PROG_TYPE_LWT_XMIT, 0}, {-EINVAL, 0} }, + {"lwt_seg6local", {0, BPF_PROG_TYPE_LWT_SEG6LOCAL, 0}, {-EINVAL, 0} }, + { + "cgroup_skb/ingress", + {0, BPF_PROG_TYPE_CGROUP_SKB, 0}, + {0, BPF_CGROUP_INET_INGRESS}, + }, + { + "cgroup_skb/egress", + {0, BPF_PROG_TYPE_CGROUP_SKB, 0}, + {0, BPF_CGROUP_INET_EGRESS}, + }, + {"cgroup/skb", {0, BPF_PROG_TYPE_CGROUP_SKB, 0}, {-EINVAL, 0} }, + { + "cgroup/sock", + {0, BPF_PROG_TYPE_CGROUP_SOCK, 0}, + {0, BPF_CGROUP_INET_SOCK_CREATE}, + }, + { + "cgroup/post_bind4", + {0, BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET4_POST_BIND}, + {0, BPF_CGROUP_INET4_POST_BIND}, + }, + { + "cgroup/post_bind6", + {0, BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET6_POST_BIND}, + {0, BPF_CGROUP_INET6_POST_BIND}, + }, + { + "cgroup/dev", + {0, BPF_PROG_TYPE_CGROUP_DEVICE, 0}, + {0, BPF_CGROUP_DEVICE}, + }, + {"sockops", {0, BPF_PROG_TYPE_SOCK_OPS, 0}, {0, BPF_CGROUP_SOCK_OPS} }, + { + "sk_skb/stream_parser", + {0, BPF_PROG_TYPE_SK_SKB, 0}, + {0, BPF_SK_SKB_STREAM_PARSER}, + }, + { + "sk_skb/stream_verdict", + {0, BPF_PROG_TYPE_SK_SKB, 0}, + {0, BPF_SK_SKB_STREAM_VERDICT}, + }, + {"sk_skb", {0, BPF_PROG_TYPE_SK_SKB, 0}, {-EINVAL, 0} }, + {"sk_msg", {0, BPF_PROG_TYPE_SK_MSG, 0}, {0, BPF_SK_MSG_VERDICT} }, + {"lirc_mode2", {0, BPF_PROG_TYPE_LIRC_MODE2, 0}, {0, BPF_LIRC_MODE2} }, + { + "flow_dissector", + {0, BPF_PROG_TYPE_FLOW_DISSECTOR, 0}, + {0, BPF_FLOW_DISSECTOR}, + }, + { + "cgroup/bind4", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_BIND}, + {0, BPF_CGROUP_INET4_BIND}, + }, + { + "cgroup/bind6", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_BIND}, + {0, BPF_CGROUP_INET6_BIND}, + }, + { + "cgroup/connect4", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_CONNECT}, + {0, BPF_CGROUP_INET4_CONNECT}, + }, + { + "cgroup/connect6", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_CONNECT}, + {0, BPF_CGROUP_INET6_CONNECT}, + }, + { + "cgroup/sendmsg4", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_SENDMSG}, + {0, BPF_CGROUP_UDP4_SENDMSG}, + }, + { + "cgroup/sendmsg6", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_SENDMSG}, + {0, BPF_CGROUP_UDP6_SENDMSG}, + }, + { + "cgroup/recvmsg4", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_RECVMSG}, + {0, BPF_CGROUP_UDP4_RECVMSG}, + }, + { + "cgroup/recvmsg6", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_RECVMSG}, + {0, BPF_CGROUP_UDP6_RECVMSG}, + }, + { + "cgroup/sysctl", + {0, BPF_PROG_TYPE_CGROUP_SYSCTL, BPF_CGROUP_SYSCTL}, + {0, BPF_CGROUP_SYSCTL}, + }, + { + "cgroup/getsockopt", + {0, BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_CGROUP_GETSOCKOPT}, + {0, BPF_CGROUP_GETSOCKOPT}, + }, + { + "cgroup/setsockopt", + {0, BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_CGROUP_SETSOCKOPT}, + {0, BPF_CGROUP_SETSOCKOPT}, + }, +}; + +static void test_prog_type_by_name(const struct sec_name_test *test) +{ + enum bpf_attach_type expected_attach_type; + enum bpf_prog_type prog_type; + int rc; + + rc = libbpf_prog_type_by_name(test->sec_name, &prog_type, + &expected_attach_type); + + CHECK(rc != test->expected_load.rc, "check_code", + "prog: unexpected rc=%d for %s", rc, test->sec_name); + + if (rc) + return; + + CHECK(prog_type != test->expected_load.prog_type, "check_prog_type", + "prog: unexpected prog_type=%d for %s", + prog_type, test->sec_name); + + CHECK(expected_attach_type != test->expected_load.expected_attach_type, + "check_attach_type", "prog: unexpected expected_attach_type=%d for %s", + expected_attach_type, test->sec_name); +} + +static void test_attach_type_by_name(const struct sec_name_test *test) +{ + enum bpf_attach_type attach_type; + int rc; + + rc = libbpf_attach_type_by_name(test->sec_name, &attach_type); + + CHECK(rc != test->expected_attach.rc, "check_ret", + "attach: unexpected rc=%d for %s", rc, test->sec_name); + + if (rc) + return; + + CHECK(attach_type != test->expected_attach.attach_type, + "check_attach_type", "attach: unexpected attach_type=%d for %s", + attach_type, test->sec_name); +} + +void test_section_names(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) { + struct sec_name_test *test = &tests[i]; + + test_prog_type_by_name(test); + test_attach_type_by_name(test); + } +} diff --git a/tools/testing/selftests/bpf/prog_tests/skb_ctx.c b/tools/testing/selftests/bpf/prog_tests/skb_ctx.c index e95baa32e277..a2eb8db8dafb 100644 --- a/tools/testing/selftests/bpf/prog_tests/skb_ctx.c +++ b/tools/testing/selftests/bpf/prog_tests/skb_ctx.c @@ -10,6 +10,7 @@ void test_skb_ctx(void) .cb[3] = 4, .cb[4] = 5, .priority = 6, + .tstamp = 7, }; struct bpf_prog_test_run_attr tattr = { .data_in = &pkt_v4, @@ -86,4 +87,8 @@ void test_skb_ctx(void) "ctx_out_priority", "skb->priority == %d, expected %d\n", skb.priority, 7); + CHECK_ATTR(skb.tstamp != 8, + "ctx_out_tstamp", + "skb->tstamp == %lld, expected %d\n", + skb.tstamp, 8); } |