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