0001
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
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
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
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
0109 bpf_link__destroy(links[last_cg]);
0110 links[last_cg] = NULL;
0111
0112 ping_and_check(cg_nr - 1, 0);
0113
0114
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
0129 bpf_link__destroy(links[last_cg]);
0130 links[last_cg] = NULL;
0131
0132
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
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
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
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
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
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
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
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
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
0208 ping_and_check(0, cg_nr);
0209
0210
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
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
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
0235 ping_and_check(0, cg_nr - 1);
0236
0237
0238 cleanup_cgroup_environment();
0239
0240
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 }