0001
0002
0003
0004
0005
0006
0007 #include <test_progs.h>
0008 #include <cgroup_helpers.h>
0009 #include <network_helpers.h>
0010
0011 #include "progs/cg_storage_multi.h"
0012
0013 #include "cg_storage_multi_egress_only.skel.h"
0014 #include "cg_storage_multi_isolated.skel.h"
0015 #include "cg_storage_multi_shared.skel.h"
0016
0017 #define PARENT_CGROUP "/cgroup_storage"
0018 #define CHILD_CGROUP "/cgroup_storage/child"
0019
0020 static int duration;
0021
0022 static bool assert_storage(struct bpf_map *map, const void *key,
0023 struct cgroup_value *expected)
0024 {
0025 struct cgroup_value value;
0026 int map_fd;
0027
0028 map_fd = bpf_map__fd(map);
0029
0030 if (CHECK(bpf_map_lookup_elem(map_fd, key, &value) < 0,
0031 "map-lookup", "errno %d", errno))
0032 return true;
0033 if (CHECK(memcmp(&value, expected, sizeof(struct cgroup_value)),
0034 "assert-storage", "storages differ"))
0035 return true;
0036
0037 return false;
0038 }
0039
0040 static bool assert_storage_noexist(struct bpf_map *map, const void *key)
0041 {
0042 struct cgroup_value value;
0043 int map_fd;
0044
0045 map_fd = bpf_map__fd(map);
0046
0047 if (CHECK(bpf_map_lookup_elem(map_fd, key, &value) == 0,
0048 "map-lookup", "succeeded, expected ENOENT"))
0049 return true;
0050 if (CHECK(errno != ENOENT,
0051 "map-lookup", "errno %d, expected ENOENT", errno))
0052 return true;
0053
0054 return false;
0055 }
0056
0057 static bool connect_send(const char *cgroup_path)
0058 {
0059 bool res = true;
0060 int server_fd = -1, client_fd = -1;
0061
0062 if (join_cgroup(cgroup_path))
0063 goto out_clean;
0064
0065 server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0);
0066 if (server_fd < 0)
0067 goto out_clean;
0068
0069 client_fd = connect_to_fd(server_fd, 0);
0070 if (client_fd < 0)
0071 goto out_clean;
0072
0073 if (send(client_fd, "message", strlen("message"), 0) < 0)
0074 goto out_clean;
0075
0076 res = false;
0077
0078 out_clean:
0079 close(client_fd);
0080 close(server_fd);
0081 return res;
0082 }
0083
0084 static void test_egress_only(int parent_cgroup_fd, int child_cgroup_fd)
0085 {
0086 struct cg_storage_multi_egress_only *obj;
0087 struct cgroup_value expected_cgroup_value;
0088 struct bpf_cgroup_storage_key key;
0089 struct bpf_link *parent_link = NULL, *child_link = NULL;
0090 bool err;
0091
0092 key.attach_type = BPF_CGROUP_INET_EGRESS;
0093
0094 obj = cg_storage_multi_egress_only__open_and_load();
0095 if (CHECK(!obj, "skel-load", "errno %d", errno))
0096 return;
0097
0098
0099
0100
0101
0102
0103 parent_link = bpf_program__attach_cgroup(obj->progs.egress,
0104 parent_cgroup_fd);
0105 if (!ASSERT_OK_PTR(parent_link, "parent-cg-attach"))
0106 goto close_bpf_object;
0107 err = connect_send(CHILD_CGROUP);
0108 if (CHECK(err, "first-connect-send", "errno %d", errno))
0109 goto close_bpf_object;
0110 if (CHECK(obj->bss->invocations != 1,
0111 "first-invoke", "invocations=%d", obj->bss->invocations))
0112 goto close_bpf_object;
0113 key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
0114 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
0115 if (assert_storage(obj->maps.cgroup_storage,
0116 &key, &expected_cgroup_value))
0117 goto close_bpf_object;
0118 key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
0119 if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
0120 goto close_bpf_object;
0121
0122
0123
0124
0125
0126 child_link = bpf_program__attach_cgroup(obj->progs.egress,
0127 child_cgroup_fd);
0128 if (!ASSERT_OK_PTR(child_link, "child-cg-attach"))
0129 goto close_bpf_object;
0130 err = connect_send(CHILD_CGROUP);
0131 if (CHECK(err, "second-connect-send", "errno %d", errno))
0132 goto close_bpf_object;
0133 if (CHECK(obj->bss->invocations != 3,
0134 "second-invoke", "invocations=%d", obj->bss->invocations))
0135 goto close_bpf_object;
0136 key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
0137 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
0138 if (assert_storage(obj->maps.cgroup_storage,
0139 &key, &expected_cgroup_value))
0140 goto close_bpf_object;
0141 key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
0142 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
0143 if (assert_storage(obj->maps.cgroup_storage,
0144 &key, &expected_cgroup_value))
0145 goto close_bpf_object;
0146
0147 close_bpf_object:
0148 bpf_link__destroy(parent_link);
0149 bpf_link__destroy(child_link);
0150
0151 cg_storage_multi_egress_only__destroy(obj);
0152 }
0153
0154 static void test_isolated(int parent_cgroup_fd, int child_cgroup_fd)
0155 {
0156 struct cg_storage_multi_isolated *obj;
0157 struct cgroup_value expected_cgroup_value;
0158 struct bpf_cgroup_storage_key key;
0159 struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
0160 struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
0161 struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
0162 bool err;
0163
0164 obj = cg_storage_multi_isolated__open_and_load();
0165 if (CHECK(!obj, "skel-load", "errno %d", errno))
0166 return;
0167
0168
0169
0170
0171
0172
0173 parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
0174 parent_cgroup_fd);
0175 if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
0176 goto close_bpf_object;
0177 parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
0178 parent_cgroup_fd);
0179 if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
0180 goto close_bpf_object;
0181 parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
0182 parent_cgroup_fd);
0183 if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
0184 goto close_bpf_object;
0185 err = connect_send(CHILD_CGROUP);
0186 if (CHECK(err, "first-connect-send", "errno %d", errno))
0187 goto close_bpf_object;
0188 if (CHECK(obj->bss->invocations != 3,
0189 "first-invoke", "invocations=%d", obj->bss->invocations))
0190 goto close_bpf_object;
0191 key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
0192 key.attach_type = BPF_CGROUP_INET_EGRESS;
0193 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
0194 if (assert_storage(obj->maps.cgroup_storage,
0195 &key, &expected_cgroup_value))
0196 goto close_bpf_object;
0197 key.attach_type = BPF_CGROUP_INET_INGRESS;
0198 expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
0199 if (assert_storage(obj->maps.cgroup_storage,
0200 &key, &expected_cgroup_value))
0201 goto close_bpf_object;
0202 key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
0203 key.attach_type = BPF_CGROUP_INET_EGRESS;
0204 if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
0205 goto close_bpf_object;
0206 key.attach_type = BPF_CGROUP_INET_INGRESS;
0207 if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
0208 goto close_bpf_object;
0209
0210
0211
0212
0213
0214
0215 child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
0216 child_cgroup_fd);
0217 if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
0218 goto close_bpf_object;
0219 child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
0220 child_cgroup_fd);
0221 if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
0222 goto close_bpf_object;
0223 child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
0224 child_cgroup_fd);
0225 if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
0226 goto close_bpf_object;
0227 err = connect_send(CHILD_CGROUP);
0228 if (CHECK(err, "second-connect-send", "errno %d", errno))
0229 goto close_bpf_object;
0230 if (CHECK(obj->bss->invocations != 9,
0231 "second-invoke", "invocations=%d", obj->bss->invocations))
0232 goto close_bpf_object;
0233 key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
0234 key.attach_type = BPF_CGROUP_INET_EGRESS;
0235 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 4 };
0236 if (assert_storage(obj->maps.cgroup_storage,
0237 &key, &expected_cgroup_value))
0238 goto close_bpf_object;
0239 key.attach_type = BPF_CGROUP_INET_INGRESS;
0240 expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 2 };
0241 if (assert_storage(obj->maps.cgroup_storage,
0242 &key, &expected_cgroup_value))
0243 goto close_bpf_object;
0244 key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
0245 key.attach_type = BPF_CGROUP_INET_EGRESS;
0246 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
0247 if (assert_storage(obj->maps.cgroup_storage,
0248 &key, &expected_cgroup_value))
0249 goto close_bpf_object;
0250 key.attach_type = BPF_CGROUP_INET_INGRESS;
0251 expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
0252 if (assert_storage(obj->maps.cgroup_storage,
0253 &key, &expected_cgroup_value))
0254 goto close_bpf_object;
0255
0256 close_bpf_object:
0257 bpf_link__destroy(parent_egress1_link);
0258 bpf_link__destroy(parent_egress2_link);
0259 bpf_link__destroy(parent_ingress_link);
0260 bpf_link__destroy(child_egress1_link);
0261 bpf_link__destroy(child_egress2_link);
0262 bpf_link__destroy(child_ingress_link);
0263
0264 cg_storage_multi_isolated__destroy(obj);
0265 }
0266
0267 static void test_shared(int parent_cgroup_fd, int child_cgroup_fd)
0268 {
0269 struct cg_storage_multi_shared *obj;
0270 struct cgroup_value expected_cgroup_value;
0271 __u64 key;
0272 struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
0273 struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
0274 struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
0275 bool err;
0276
0277 obj = cg_storage_multi_shared__open_and_load();
0278 if (CHECK(!obj, "skel-load", "errno %d", errno))
0279 return;
0280
0281
0282
0283
0284
0285
0286 parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
0287 parent_cgroup_fd);
0288 if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
0289 goto close_bpf_object;
0290 parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
0291 parent_cgroup_fd);
0292 if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
0293 goto close_bpf_object;
0294 parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
0295 parent_cgroup_fd);
0296 if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
0297 goto close_bpf_object;
0298 err = connect_send(CHILD_CGROUP);
0299 if (CHECK(err, "first-connect-send", "errno %d", errno))
0300 goto close_bpf_object;
0301 if (CHECK(obj->bss->invocations != 3,
0302 "first-invoke", "invocations=%d", obj->bss->invocations))
0303 goto close_bpf_object;
0304 key = get_cgroup_id(PARENT_CGROUP);
0305 expected_cgroup_value = (struct cgroup_value) {
0306 .egress_pkts = 2,
0307 .ingress_pkts = 1,
0308 };
0309 if (assert_storage(obj->maps.cgroup_storage,
0310 &key, &expected_cgroup_value))
0311 goto close_bpf_object;
0312 key = get_cgroup_id(CHILD_CGROUP);
0313 if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
0314 goto close_bpf_object;
0315
0316
0317
0318
0319
0320 child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
0321 child_cgroup_fd);
0322 if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
0323 goto close_bpf_object;
0324 child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
0325 child_cgroup_fd);
0326 if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
0327 goto close_bpf_object;
0328 child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
0329 child_cgroup_fd);
0330 if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
0331 goto close_bpf_object;
0332 err = connect_send(CHILD_CGROUP);
0333 if (CHECK(err, "second-connect-send", "errno %d", errno))
0334 goto close_bpf_object;
0335 if (CHECK(obj->bss->invocations != 9,
0336 "second-invoke", "invocations=%d", obj->bss->invocations))
0337 goto close_bpf_object;
0338 key = get_cgroup_id(PARENT_CGROUP);
0339 expected_cgroup_value = (struct cgroup_value) {
0340 .egress_pkts = 4,
0341 .ingress_pkts = 2,
0342 };
0343 if (assert_storage(obj->maps.cgroup_storage,
0344 &key, &expected_cgroup_value))
0345 goto close_bpf_object;
0346 key = get_cgroup_id(CHILD_CGROUP);
0347 expected_cgroup_value = (struct cgroup_value) {
0348 .egress_pkts = 2,
0349 .ingress_pkts = 1,
0350 };
0351 if (assert_storage(obj->maps.cgroup_storage,
0352 &key, &expected_cgroup_value))
0353 goto close_bpf_object;
0354
0355 close_bpf_object:
0356 bpf_link__destroy(parent_egress1_link);
0357 bpf_link__destroy(parent_egress2_link);
0358 bpf_link__destroy(parent_ingress_link);
0359 bpf_link__destroy(child_egress1_link);
0360 bpf_link__destroy(child_egress2_link);
0361 bpf_link__destroy(child_ingress_link);
0362
0363 cg_storage_multi_shared__destroy(obj);
0364 }
0365
0366 void serial_test_cg_storage_multi(void)
0367 {
0368 int parent_cgroup_fd = -1, child_cgroup_fd = -1;
0369
0370 parent_cgroup_fd = test__join_cgroup(PARENT_CGROUP);
0371 if (CHECK(parent_cgroup_fd < 0, "cg-create-parent", "errno %d", errno))
0372 goto close_cgroup_fd;
0373 child_cgroup_fd = create_and_get_cgroup(CHILD_CGROUP);
0374 if (CHECK(child_cgroup_fd < 0, "cg-create-child", "errno %d", errno))
0375 goto close_cgroup_fd;
0376
0377 if (test__start_subtest("egress_only"))
0378 test_egress_only(parent_cgroup_fd, child_cgroup_fd);
0379
0380 if (test__start_subtest("isolated"))
0381 test_isolated(parent_cgroup_fd, child_cgroup_fd);
0382
0383 if (test__start_subtest("shared"))
0384 test_shared(parent_cgroup_fd, child_cgroup_fd);
0385
0386 close_cgroup_fd:
0387 close(child_cgroup_fd);
0388 close(parent_cgroup_fd);
0389 }