Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 #include <test_progs.h>
0004 #include "cgroup_helpers.h"
0005 #include "testing_helpers.h"
0006 #include "test_cgroup_link.skel.h"
0007 
0008 static __u32 duration = 0;
0009 #define PING_CMD    "ping -q -c1 -w1 127.0.0.1 > /dev/null"
0010 
0011 static struct test_cgroup_link *skel = NULL;
0012 
0013 int ping_and_check(int exp_calls, int exp_alt_calls)
0014 {
0015     skel->bss->calls = 0;
0016     skel->bss->alt_calls = 0;
0017     CHECK_FAIL(system(PING_CMD));
0018     if (CHECK(skel->bss->calls != exp_calls, "call_cnt",
0019           "exp %d, got %d\n", exp_calls, skel->bss->calls))
0020         return -EINVAL;
0021     if (CHECK(skel->bss->alt_calls != exp_alt_calls, "alt_call_cnt",
0022           "exp %d, got %d\n", exp_alt_calls, skel->bss->alt_calls))
0023         return -EINVAL;
0024     return 0;
0025 }
0026 
0027 void serial_test_cgroup_link(void)
0028 {
0029     struct {
0030         const char *path;
0031         int fd;
0032     } cgs[] = {
0033         { "/cg1" },
0034         { "/cg1/cg2" },
0035         { "/cg1/cg2/cg3" },
0036         { "/cg1/cg2/cg3/cg4" },
0037     };
0038     int last_cg = ARRAY_SIZE(cgs) - 1, cg_nr = ARRAY_SIZE(cgs);
0039     DECLARE_LIBBPF_OPTS(bpf_link_update_opts, link_upd_opts);
0040     struct bpf_link *links[ARRAY_SIZE(cgs)] = {}, *tmp_link;
0041     __u32 prog_ids[ARRAY_SIZE(cgs)], prog_cnt = 0, attach_flags, prog_id;
0042     struct bpf_link_info info;
0043     int i = 0, err, prog_fd;
0044     bool detach_legacy = false;
0045 
0046     skel = test_cgroup_link__open_and_load();
0047     if (CHECK(!skel, "skel_open_load", "failed to open/load skeleton\n"))
0048         return;
0049     prog_fd = bpf_program__fd(skel->progs.egress);
0050 
0051     err = setup_cgroup_environment();
0052     if (CHECK(err, "cg_init", "failed: %d\n", err))
0053         goto cleanup;
0054 
0055     for (i = 0; i < cg_nr; i++) {
0056         cgs[i].fd = create_and_get_cgroup(cgs[i].path);
0057         if (!ASSERT_GE(cgs[i].fd, 0, "cg_create"))
0058             goto cleanup;
0059     }
0060 
0061     err = join_cgroup(cgs[last_cg].path);
0062     if (CHECK(err, "cg_join", "fail: %d\n", err))
0063         goto cleanup;
0064 
0065     for (i = 0; i < cg_nr; i++) {
0066         links[i] = bpf_program__attach_cgroup(skel->progs.egress,
0067                               cgs[i].fd);
0068         if (!ASSERT_OK_PTR(links[i], "cg_attach"))
0069             goto cleanup;
0070     }
0071 
0072     ping_and_check(cg_nr, 0);
0073 
0074     /* query the number of effective progs and attach flags in root cg */
0075     err = bpf_prog_query(cgs[0].fd, BPF_CGROUP_INET_EGRESS,
0076                  BPF_F_QUERY_EFFECTIVE, &attach_flags, NULL,
0077                  &prog_cnt);
0078     CHECK_FAIL(err);
0079     CHECK_FAIL(attach_flags != BPF_F_ALLOW_MULTI);
0080     if (CHECK(prog_cnt != 1, "effect_cnt", "exp %d, got %d\n", 1, prog_cnt))
0081         goto cleanup;
0082 
0083     /* query the number of effective progs in last cg */
0084     err = bpf_prog_query(cgs[last_cg].fd, BPF_CGROUP_INET_EGRESS,
0085                  BPF_F_QUERY_EFFECTIVE, NULL, NULL,
0086                  &prog_cnt);
0087     CHECK_FAIL(err);
0088     CHECK_FAIL(attach_flags != BPF_F_ALLOW_MULTI);
0089     if (CHECK(prog_cnt != cg_nr, "effect_cnt", "exp %d, got %d\n",
0090           cg_nr, prog_cnt))
0091         goto cleanup;
0092 
0093     /* query the effective prog IDs in last cg */
0094     err = bpf_prog_query(cgs[last_cg].fd, BPF_CGROUP_INET_EGRESS,
0095                  BPF_F_QUERY_EFFECTIVE, &attach_flags,
0096                  prog_ids, &prog_cnt);
0097     CHECK_FAIL(err);
0098     CHECK_FAIL(attach_flags != BPF_F_ALLOW_MULTI);
0099     if (CHECK(prog_cnt != cg_nr, "effect_cnt", "exp %d, got %d\n",
0100           cg_nr, prog_cnt))
0101         goto cleanup;
0102     for (i = 1; i < prog_cnt; i++) {
0103         CHECK(prog_ids[i - 1] != prog_ids[i], "prog_id_check",
0104               "idx %d, prev id %d, cur id %d\n",
0105               i, prog_ids[i - 1], prog_ids[i]);
0106     }
0107 
0108     /* detach bottom program and ping again */
0109     bpf_link__destroy(links[last_cg]);
0110     links[last_cg] = NULL;
0111 
0112     ping_and_check(cg_nr - 1, 0);
0113 
0114     /* mix in with non link-based multi-attachments */
0115     err = bpf_prog_attach(prog_fd, cgs[last_cg].fd,
0116                   BPF_CGROUP_INET_EGRESS, BPF_F_ALLOW_MULTI);
0117     if (CHECK(err, "cg_attach_legacy", "errno=%d\n", errno))
0118         goto cleanup;
0119     detach_legacy = true;
0120 
0121     links[last_cg] = bpf_program__attach_cgroup(skel->progs.egress,
0122                             cgs[last_cg].fd);
0123     if (!ASSERT_OK_PTR(links[last_cg], "cg_attach"))
0124         goto cleanup;
0125 
0126     ping_and_check(cg_nr + 1, 0);
0127 
0128     /* detach link */
0129     bpf_link__destroy(links[last_cg]);
0130     links[last_cg] = NULL;
0131 
0132     /* detach legacy */
0133     err = bpf_prog_detach2(prog_fd, cgs[last_cg].fd, BPF_CGROUP_INET_EGRESS);
0134     if (CHECK(err, "cg_detach_legacy", "errno=%d\n", errno))
0135         goto cleanup;
0136     detach_legacy = false;
0137 
0138     /* attach legacy exclusive prog attachment */
0139     err = bpf_prog_attach(prog_fd, cgs[last_cg].fd,
0140                   BPF_CGROUP_INET_EGRESS, 0);
0141     if (CHECK(err, "cg_attach_exclusive", "errno=%d\n", errno))
0142         goto cleanup;
0143     detach_legacy = true;
0144 
0145     /* attempt to mix in with multi-attach bpf_link */
0146     tmp_link = bpf_program__attach_cgroup(skel->progs.egress,
0147                           cgs[last_cg].fd);
0148     if (!ASSERT_ERR_PTR(tmp_link, "cg_attach_fail")) {
0149         bpf_link__destroy(tmp_link);
0150         goto cleanup;
0151     }
0152 
0153     ping_and_check(cg_nr, 0);
0154 
0155     /* detach */
0156     err = bpf_prog_detach2(prog_fd, cgs[last_cg].fd, BPF_CGROUP_INET_EGRESS);
0157     if (CHECK(err, "cg_detach_legacy", "errno=%d\n", errno))
0158         goto cleanup;
0159     detach_legacy = false;
0160 
0161     ping_and_check(cg_nr - 1, 0);
0162 
0163     /* attach back link-based one */
0164     links[last_cg] = bpf_program__attach_cgroup(skel->progs.egress,
0165                             cgs[last_cg].fd);
0166     if (!ASSERT_OK_PTR(links[last_cg], "cg_attach"))
0167         goto cleanup;
0168 
0169     ping_and_check(cg_nr, 0);
0170 
0171     /* check legacy exclusive prog can't be attached */
0172     err = bpf_prog_attach(prog_fd, cgs[last_cg].fd,
0173                   BPF_CGROUP_INET_EGRESS, 0);
0174     if (CHECK(!err, "cg_attach_exclusive", "unexpected success")) {
0175         bpf_prog_detach2(prog_fd, cgs[last_cg].fd, BPF_CGROUP_INET_EGRESS);
0176         goto cleanup;
0177     }
0178 
0179     /* replace BPF programs inside their links for all but first link */
0180     for (i = 1; i < cg_nr; i++) {
0181         err = bpf_link__update_program(links[i], skel->progs.egress_alt);
0182         if (CHECK(err, "prog_upd", "link #%d\n", i))
0183             goto cleanup;
0184     }
0185 
0186     ping_and_check(1, cg_nr - 1);
0187 
0188     /* Attempt program update with wrong expected BPF program */
0189     link_upd_opts.old_prog_fd = bpf_program__fd(skel->progs.egress_alt);
0190     link_upd_opts.flags = BPF_F_REPLACE;
0191     err = bpf_link_update(bpf_link__fd(links[0]),
0192                   bpf_program__fd(skel->progs.egress_alt),
0193                   &link_upd_opts);
0194     if (CHECK(err == 0 || errno != EPERM, "prog_cmpxchg1",
0195           "unexpectedly succeeded, err %d, errno %d\n", err, -errno))
0196         goto cleanup;
0197 
0198     /* Compare-exchange single link program from egress to egress_alt */
0199     link_upd_opts.old_prog_fd = bpf_program__fd(skel->progs.egress);
0200     link_upd_opts.flags = BPF_F_REPLACE;
0201     err = bpf_link_update(bpf_link__fd(links[0]),
0202                   bpf_program__fd(skel->progs.egress_alt),
0203                   &link_upd_opts);
0204     if (CHECK(err, "prog_cmpxchg2", "errno %d\n", -errno))
0205         goto cleanup;
0206 
0207     /* ping */
0208     ping_and_check(0, cg_nr);
0209 
0210     /* close cgroup FDs before detaching links */
0211     for (i = 0; i < cg_nr; i++) {
0212         if (cgs[i].fd > 0) {
0213             close(cgs[i].fd);
0214             cgs[i].fd = -1;
0215         }
0216     }
0217 
0218     /* BPF programs should still get called */
0219     ping_and_check(0, cg_nr);
0220 
0221     prog_id = link_info_prog_id(links[0], &info);
0222     CHECK(prog_id == 0, "link_info", "failed\n");
0223     CHECK(info.cgroup.cgroup_id == 0, "cgroup_id", "unexpected %llu\n", info.cgroup.cgroup_id);
0224 
0225     err = bpf_link__detach(links[0]);
0226     if (CHECK(err, "link_detach", "failed %d\n", err))
0227         goto cleanup;
0228 
0229     /* cgroup_id should be zero in link_info */
0230     prog_id = link_info_prog_id(links[0], &info);
0231     CHECK(prog_id == 0, "link_info", "failed\n");
0232     CHECK(info.cgroup.cgroup_id != 0, "cgroup_id", "unexpected %llu\n", info.cgroup.cgroup_id);
0233 
0234     /* First BPF program shouldn't be called anymore */
0235     ping_and_check(0, cg_nr - 1);
0236 
0237     /* leave cgroup and remove them, don't detach programs */
0238     cleanup_cgroup_environment();
0239 
0240     /* BPF programs should have been auto-detached */
0241     ping_and_check(0, 0);
0242 
0243 cleanup:
0244     if (detach_legacy)
0245         bpf_prog_detach2(prog_fd, cgs[last_cg].fd,
0246                  BPF_CGROUP_INET_EGRESS);
0247 
0248     for (i = 0; i < cg_nr; i++) {
0249         bpf_link__destroy(links[i]);
0250     }
0251     test_cgroup_link__destroy(skel);
0252 
0253     for (i = 0; i < cg_nr; i++) {
0254         if (cgs[i].fd > 0)
0255             close(cgs[i].fd);
0256     }
0257     cleanup_cgroup_environment();
0258 }