Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Add selftests allowing cgroup prog pre-ordering

Add a few selftests with cgroup prog pre-ordering.

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/r/20250224230121.283601-1-yonghong.song@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Yonghong Song and committed by
Alexei Starovoitov
2222aa1c 4b82b181

+169
+128
tools/testing/selftests/bpf/prog_tests/cgroup_preorder.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ 3 + #include <test_progs.h> 4 + #include "cgroup_helpers.h" 5 + #include "cgroup_preorder.skel.h" 6 + 7 + static int run_getsockopt_test(int cg_parent, int cg_child, int sock_fd, bool all_preorder) 8 + { 9 + LIBBPF_OPTS(bpf_prog_attach_opts, opts); 10 + enum bpf_attach_type prog_c_atype, prog_c2_atype, prog_p_atype, prog_p2_atype; 11 + int prog_c_fd, prog_c2_fd, prog_p_fd, prog_p2_fd; 12 + struct cgroup_preorder *skel = NULL; 13 + struct bpf_program *prog; 14 + __u8 *result, buf; 15 + socklen_t optlen; 16 + int err = 0; 17 + 18 + skel = cgroup_preorder__open_and_load(); 19 + if (!ASSERT_OK_PTR(skel, "cgroup_preorder__open_and_load")) 20 + return 0; 21 + 22 + buf = 0x00; 23 + err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); 24 + if (!ASSERT_OK(err, "setsockopt")) 25 + goto close_skel; 26 + 27 + opts.flags = BPF_F_ALLOW_MULTI; 28 + if (all_preorder) 29 + opts.flags |= BPF_F_PREORDER; 30 + prog = skel->progs.child; 31 + prog_c_fd = bpf_program__fd(prog); 32 + prog_c_atype = bpf_program__expected_attach_type(prog); 33 + err = bpf_prog_attach_opts(prog_c_fd, cg_child, prog_c_atype, &opts); 34 + if (!ASSERT_OK(err, "bpf_prog_attach_opts-child")) 35 + goto close_skel; 36 + 37 + opts.flags = BPF_F_ALLOW_MULTI | BPF_F_PREORDER; 38 + prog = skel->progs.child_2; 39 + prog_c2_fd = bpf_program__fd(prog); 40 + prog_c2_atype = bpf_program__expected_attach_type(prog); 41 + err = bpf_prog_attach_opts(prog_c2_fd, cg_child, prog_c2_atype, &opts); 42 + if (!ASSERT_OK(err, "bpf_prog_attach_opts-child_2")) 43 + goto detach_child; 44 + 45 + optlen = 1; 46 + err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 47 + if (!ASSERT_OK(err, "getsockopt")) 48 + goto detach_child_2; 49 + 50 + result = skel->bss->result; 51 + if (all_preorder) 52 + ASSERT_TRUE(result[0] == 1 && result[1] == 2, "child only"); 53 + else 54 + ASSERT_TRUE(result[0] == 2 && result[1] == 1, "child only"); 55 + 56 + skel->bss->idx = 0; 57 + memset(result, 0, 4); 58 + 59 + opts.flags = BPF_F_ALLOW_MULTI; 60 + if (all_preorder) 61 + opts.flags |= BPF_F_PREORDER; 62 + prog = skel->progs.parent; 63 + prog_p_fd = bpf_program__fd(prog); 64 + prog_p_atype = bpf_program__expected_attach_type(prog); 65 + err = bpf_prog_attach_opts(prog_p_fd, cg_parent, prog_p_atype, &opts); 66 + if (!ASSERT_OK(err, "bpf_prog_attach_opts-parent")) 67 + goto detach_child_2; 68 + 69 + opts.flags = BPF_F_ALLOW_MULTI | BPF_F_PREORDER; 70 + prog = skel->progs.parent_2; 71 + prog_p2_fd = bpf_program__fd(prog); 72 + prog_p2_atype = bpf_program__expected_attach_type(prog); 73 + err = bpf_prog_attach_opts(prog_p2_fd, cg_parent, prog_p2_atype, &opts); 74 + if (!ASSERT_OK(err, "bpf_prog_attach_opts-parent_2")) 75 + goto detach_parent; 76 + 77 + err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); 78 + if (!ASSERT_OK(err, "getsockopt")) 79 + goto detach_parent_2; 80 + 81 + if (all_preorder) 82 + ASSERT_TRUE(result[0] == 3 && result[1] == 4 && result[2] == 1 && result[3] == 2, 83 + "parent and child"); 84 + else 85 + ASSERT_TRUE(result[0] == 4 && result[1] == 2 && result[2] == 1 && result[3] == 3, 86 + "parent and child"); 87 + 88 + detach_parent_2: 89 + ASSERT_OK(bpf_prog_detach2(prog_p2_fd, cg_parent, prog_p2_atype), 90 + "bpf_prog_detach2-parent_2"); 91 + detach_parent: 92 + ASSERT_OK(bpf_prog_detach2(prog_p_fd, cg_parent, prog_p_atype), 93 + "bpf_prog_detach2-parent"); 94 + detach_child_2: 95 + ASSERT_OK(bpf_prog_detach2(prog_c2_fd, cg_child, prog_c2_atype), 96 + "bpf_prog_detach2-child_2"); 97 + detach_child: 98 + ASSERT_OK(bpf_prog_detach2(prog_c_fd, cg_child, prog_c_atype), 99 + "bpf_prog_detach2-child"); 100 + close_skel: 101 + cgroup_preorder__destroy(skel); 102 + return err; 103 + } 104 + 105 + void test_cgroup_preorder(void) 106 + { 107 + int cg_parent = -1, cg_child = -1, sock_fd = -1; 108 + 109 + cg_parent = test__join_cgroup("/parent"); 110 + if (!ASSERT_GE(cg_parent, 0, "join_cgroup /parent")) 111 + goto out; 112 + 113 + cg_child = test__join_cgroup("/parent/child"); 114 + if (!ASSERT_GE(cg_child, 0, "join_cgroup /parent/child")) 115 + goto out; 116 + 117 + sock_fd = socket(AF_INET, SOCK_STREAM, 0); 118 + if (!ASSERT_GE(sock_fd, 0, "socket")) 119 + goto out; 120 + 121 + ASSERT_OK(run_getsockopt_test(cg_parent, cg_child, sock_fd, false), "getsockopt_test_1"); 122 + ASSERT_OK(run_getsockopt_test(cg_parent, cg_child, sock_fd, true), "getsockopt_test_2"); 123 + 124 + out: 125 + close(sock_fd); 126 + close(cg_child); 127 + close(cg_parent); 128 + }
+41
tools/testing/selftests/bpf/progs/cgroup_preorder.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ 3 + #include <vmlinux.h> 4 + #include <bpf/bpf_helpers.h> 5 + 6 + char _license[] SEC("license") = "GPL"; 7 + 8 + unsigned int idx; 9 + __u8 result[4]; 10 + 11 + SEC("cgroup/getsockopt") 12 + int child(struct bpf_sockopt *ctx) 13 + { 14 + if (idx < 4) 15 + result[idx++] = 1; 16 + return 1; 17 + } 18 + 19 + SEC("cgroup/getsockopt") 20 + int child_2(struct bpf_sockopt *ctx) 21 + { 22 + if (idx < 4) 23 + result[idx++] = 2; 24 + return 1; 25 + } 26 + 27 + SEC("cgroup/getsockopt") 28 + int parent(struct bpf_sockopt *ctx) 29 + { 30 + if (idx < 4) 31 + result[idx++] = 3; 32 + return 1; 33 + } 34 + 35 + SEC("cgroup/getsockopt") 36 + int parent_2(struct bpf_sockopt *ctx) 37 + { 38 + if (idx < 4) 39 + result[idx++] = 4; 40 + return 1; 41 + }