1d4a89c1eSYiFei Zhu // SPDX-License-Identifier: GPL-2.0-only
2d4a89c1eSYiFei Zhu 
3d4a89c1eSYiFei Zhu /*
4d4a89c1eSYiFei Zhu  * Copyright 2020 Google LLC.
5d4a89c1eSYiFei Zhu  */
6d4a89c1eSYiFei Zhu 
7d4a89c1eSYiFei Zhu #include <test_progs.h>
8d4a89c1eSYiFei Zhu #include <cgroup_helpers.h>
9d4a89c1eSYiFei Zhu #include <network_helpers.h>
10d4a89c1eSYiFei Zhu 
119e5bd1f7SYiFei Zhu #include "progs/cg_storage_multi.h"
129e5bd1f7SYiFei Zhu 
13d4a89c1eSYiFei Zhu #include "cg_storage_multi_egress_only.skel.h"
143573f384SYiFei Zhu #include "cg_storage_multi_isolated.skel.h"
153573f384SYiFei Zhu #include "cg_storage_multi_shared.skel.h"
16d4a89c1eSYiFei Zhu 
17d4a89c1eSYiFei Zhu #define PARENT_CGROUP "/cgroup_storage"
18d4a89c1eSYiFei Zhu #define CHILD_CGROUP "/cgroup_storage/child"
19d4a89c1eSYiFei Zhu 
20d4a89c1eSYiFei Zhu static int duration;
21d4a89c1eSYiFei Zhu 
223573f384SYiFei Zhu static bool assert_storage(struct bpf_map *map, const void *key,
239e5bd1f7SYiFei Zhu 			   struct cgroup_value *expected)
24d4a89c1eSYiFei Zhu {
259e5bd1f7SYiFei Zhu 	struct cgroup_value value;
26d4a89c1eSYiFei Zhu 	int map_fd;
27d4a89c1eSYiFei Zhu 
28d4a89c1eSYiFei Zhu 	map_fd = bpf_map__fd(map);
29d4a89c1eSYiFei Zhu 
303573f384SYiFei Zhu 	if (CHECK(bpf_map_lookup_elem(map_fd, key, &value) < 0,
31d4a89c1eSYiFei Zhu 		  "map-lookup", "errno %d", errno))
32d4a89c1eSYiFei Zhu 		return true;
339e5bd1f7SYiFei Zhu 	if (CHECK(memcmp(&value, expected, sizeof(struct cgroup_value)),
349e5bd1f7SYiFei Zhu 		  "assert-storage", "storages differ"))
35d4a89c1eSYiFei Zhu 		return true;
36d4a89c1eSYiFei Zhu 
37d4a89c1eSYiFei Zhu 	return false;
38d4a89c1eSYiFei Zhu }
39d4a89c1eSYiFei Zhu 
403573f384SYiFei Zhu static bool assert_storage_noexist(struct bpf_map *map, const void *key)
41d4a89c1eSYiFei Zhu {
429e5bd1f7SYiFei Zhu 	struct cgroup_value value;
43d4a89c1eSYiFei Zhu 	int map_fd;
44d4a89c1eSYiFei Zhu 
45d4a89c1eSYiFei Zhu 	map_fd = bpf_map__fd(map);
46d4a89c1eSYiFei Zhu 
473573f384SYiFei Zhu 	if (CHECK(bpf_map_lookup_elem(map_fd, key, &value) == 0,
48d4a89c1eSYiFei Zhu 		  "map-lookup", "succeeded, expected ENOENT"))
49d4a89c1eSYiFei Zhu 		return true;
50d4a89c1eSYiFei Zhu 	if (CHECK(errno != ENOENT,
51d4a89c1eSYiFei Zhu 		  "map-lookup", "errno %d, expected ENOENT", errno))
52d4a89c1eSYiFei Zhu 		return true;
53d4a89c1eSYiFei Zhu 
54d4a89c1eSYiFei Zhu 	return false;
55d4a89c1eSYiFei Zhu }
56d4a89c1eSYiFei Zhu 
57d4a89c1eSYiFei Zhu static bool connect_send(const char *cgroup_path)
58d4a89c1eSYiFei Zhu {
59d4a89c1eSYiFei Zhu 	bool res = true;
60d4a89c1eSYiFei Zhu 	int server_fd = -1, client_fd = -1;
61d4a89c1eSYiFei Zhu 
62d4a89c1eSYiFei Zhu 	if (join_cgroup(cgroup_path))
63d4a89c1eSYiFei Zhu 		goto out_clean;
64d4a89c1eSYiFei Zhu 
65d4a89c1eSYiFei Zhu 	server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0);
66d4a89c1eSYiFei Zhu 	if (server_fd < 0)
67d4a89c1eSYiFei Zhu 		goto out_clean;
68d4a89c1eSYiFei Zhu 
69d4a89c1eSYiFei Zhu 	client_fd = connect_to_fd(server_fd, 0);
70d4a89c1eSYiFei Zhu 	if (client_fd < 0)
71d4a89c1eSYiFei Zhu 		goto out_clean;
72d4a89c1eSYiFei Zhu 
73d4a89c1eSYiFei Zhu 	if (send(client_fd, "message", strlen("message"), 0) < 0)
74d4a89c1eSYiFei Zhu 		goto out_clean;
75d4a89c1eSYiFei Zhu 
76d4a89c1eSYiFei Zhu 	res = false;
77d4a89c1eSYiFei Zhu 
78d4a89c1eSYiFei Zhu out_clean:
79d4a89c1eSYiFei Zhu 	close(client_fd);
80d4a89c1eSYiFei Zhu 	close(server_fd);
81d4a89c1eSYiFei Zhu 	return res;
82d4a89c1eSYiFei Zhu }
83d4a89c1eSYiFei Zhu 
84d4a89c1eSYiFei Zhu static void test_egress_only(int parent_cgroup_fd, int child_cgroup_fd)
85d4a89c1eSYiFei Zhu {
86d4a89c1eSYiFei Zhu 	struct cg_storage_multi_egress_only *obj;
879e5bd1f7SYiFei Zhu 	struct cgroup_value expected_cgroup_value;
883573f384SYiFei Zhu 	struct bpf_cgroup_storage_key key;
89d4a89c1eSYiFei Zhu 	struct bpf_link *parent_link = NULL, *child_link = NULL;
90d4a89c1eSYiFei Zhu 	bool err;
91d4a89c1eSYiFei Zhu 
923573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
933573f384SYiFei Zhu 
94d4a89c1eSYiFei Zhu 	obj = cg_storage_multi_egress_only__open_and_load();
95d4a89c1eSYiFei Zhu 	if (CHECK(!obj, "skel-load", "errno %d", errno))
96d4a89c1eSYiFei Zhu 		return;
97d4a89c1eSYiFei Zhu 
98d4a89c1eSYiFei Zhu 	/* Attach to parent cgroup, trigger packet from child.
99d4a89c1eSYiFei Zhu 	 * Assert that there is only one run and in that run the storage is
100d4a89c1eSYiFei Zhu 	 * parent cgroup's storage.
101d4a89c1eSYiFei Zhu 	 * Also assert that child cgroup's storage does not exist
102d4a89c1eSYiFei Zhu 	 */
103d4a89c1eSYiFei Zhu 	parent_link = bpf_program__attach_cgroup(obj->progs.egress,
104d4a89c1eSYiFei Zhu 						 parent_cgroup_fd);
105bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_link, "parent-cg-attach"))
106d4a89c1eSYiFei Zhu 		goto close_bpf_object;
107d4a89c1eSYiFei Zhu 	err = connect_send(CHILD_CGROUP);
108d4a89c1eSYiFei Zhu 	if (CHECK(err, "first-connect-send", "errno %d", errno))
109d4a89c1eSYiFei Zhu 		goto close_bpf_object;
110d4a89c1eSYiFei Zhu 	if (CHECK(obj->bss->invocations != 1,
111d4a89c1eSYiFei Zhu 		  "first-invoke", "invocations=%d", obj->bss->invocations))
112d4a89c1eSYiFei Zhu 		goto close_bpf_object;
1133573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
1149e5bd1f7SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
1159e5bd1f7SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
1163573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
117d4a89c1eSYiFei Zhu 		goto close_bpf_object;
1183573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
1193573f384SYiFei Zhu 	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
120d4a89c1eSYiFei Zhu 		goto close_bpf_object;
121d4a89c1eSYiFei Zhu 
122d4a89c1eSYiFei Zhu 	/* Attach to parent and child cgroup, trigger packet from child.
123d4a89c1eSYiFei Zhu 	 * Assert that there are two additional runs, one that run with parent
124d4a89c1eSYiFei Zhu 	 * cgroup's storage and one with child cgroup's storage.
125d4a89c1eSYiFei Zhu 	 */
126d4a89c1eSYiFei Zhu 	child_link = bpf_program__attach_cgroup(obj->progs.egress,
127d4a89c1eSYiFei Zhu 						child_cgroup_fd);
128bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_link, "child-cg-attach"))
129d4a89c1eSYiFei Zhu 		goto close_bpf_object;
130d4a89c1eSYiFei Zhu 	err = connect_send(CHILD_CGROUP);
131d4a89c1eSYiFei Zhu 	if (CHECK(err, "second-connect-send", "errno %d", errno))
132d4a89c1eSYiFei Zhu 		goto close_bpf_object;
133d4a89c1eSYiFei Zhu 	if (CHECK(obj->bss->invocations != 3,
134d4a89c1eSYiFei Zhu 		  "second-invoke", "invocations=%d", obj->bss->invocations))
135d4a89c1eSYiFei Zhu 		goto close_bpf_object;
1363573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
1379e5bd1f7SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
1389e5bd1f7SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
1393573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
140d4a89c1eSYiFei Zhu 		goto close_bpf_object;
1413573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
1429e5bd1f7SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
1439e5bd1f7SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
1443573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
145d4a89c1eSYiFei Zhu 		goto close_bpf_object;
146d4a89c1eSYiFei Zhu 
147d4a89c1eSYiFei Zhu close_bpf_object:
148d4a89c1eSYiFei Zhu 	bpf_link__destroy(parent_link);
149d4a89c1eSYiFei Zhu 	bpf_link__destroy(child_link);
150d4a89c1eSYiFei Zhu 
151d4a89c1eSYiFei Zhu 	cg_storage_multi_egress_only__destroy(obj);
152d4a89c1eSYiFei Zhu }
153d4a89c1eSYiFei Zhu 
1543573f384SYiFei Zhu static void test_isolated(int parent_cgroup_fd, int child_cgroup_fd)
1559e5bd1f7SYiFei Zhu {
1563573f384SYiFei Zhu 	struct cg_storage_multi_isolated *obj;
1573573f384SYiFei Zhu 	struct cgroup_value expected_cgroup_value;
1583573f384SYiFei Zhu 	struct bpf_cgroup_storage_key key;
1593573f384SYiFei Zhu 	struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
1603573f384SYiFei Zhu 	struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
1613573f384SYiFei Zhu 	struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
1623573f384SYiFei Zhu 	bool err;
1639e5bd1f7SYiFei Zhu 
1643573f384SYiFei Zhu 	obj = cg_storage_multi_isolated__open_and_load();
1653573f384SYiFei Zhu 	if (CHECK(!obj, "skel-load", "errno %d", errno))
1663573f384SYiFei Zhu 		return;
1673573f384SYiFei Zhu 
1683573f384SYiFei Zhu 	/* Attach to parent cgroup, trigger packet from child.
1693573f384SYiFei Zhu 	 * Assert that there is three runs, two with parent cgroup egress and
1703573f384SYiFei Zhu 	 * one with parent cgroup ingress, stored in separate parent storages.
1713573f384SYiFei Zhu 	 * Also assert that child cgroup's storages does not exist
1729e5bd1f7SYiFei Zhu 	 */
1733573f384SYiFei Zhu 	parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
1743573f384SYiFei Zhu 							 parent_cgroup_fd);
175bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
1763573f384SYiFei Zhu 		goto close_bpf_object;
1773573f384SYiFei Zhu 	parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
1783573f384SYiFei Zhu 							 parent_cgroup_fd);
179bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
1803573f384SYiFei Zhu 		goto close_bpf_object;
1813573f384SYiFei Zhu 	parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
1823573f384SYiFei Zhu 							 parent_cgroup_fd);
183bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
1843573f384SYiFei Zhu 		goto close_bpf_object;
1853573f384SYiFei Zhu 	err = connect_send(CHILD_CGROUP);
1863573f384SYiFei Zhu 	if (CHECK(err, "first-connect-send", "errno %d", errno))
1873573f384SYiFei Zhu 		goto close_bpf_object;
1883573f384SYiFei Zhu 	if (CHECK(obj->bss->invocations != 3,
1893573f384SYiFei Zhu 		  "first-invoke", "invocations=%d", obj->bss->invocations))
1903573f384SYiFei Zhu 		goto close_bpf_object;
1913573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
1923573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
1933573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
1943573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
1953573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
1963573f384SYiFei Zhu 		goto close_bpf_object;
1973573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_INGRESS;
1983573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
1993573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2003573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2013573f384SYiFei Zhu 		goto close_bpf_object;
2023573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
2033573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
2043573f384SYiFei Zhu 	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
2053573f384SYiFei Zhu 		goto close_bpf_object;
2063573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_INGRESS;
2073573f384SYiFei Zhu 	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
2083573f384SYiFei Zhu 		goto close_bpf_object;
2099e5bd1f7SYiFei Zhu 
2103573f384SYiFei Zhu 	/* Attach to parent and child cgroup, trigger packet from child.
2113573f384SYiFei Zhu 	 * Assert that there is six additional runs, parent cgroup egresses and
2123573f384SYiFei Zhu 	 * ingress, child cgroup egresses and ingress.
2133573f384SYiFei Zhu 	 * Assert that egree and ingress storages are separate.
2143573f384SYiFei Zhu 	 */
2153573f384SYiFei Zhu 	child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
2163573f384SYiFei Zhu 							child_cgroup_fd);
217bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
2183573f384SYiFei Zhu 		goto close_bpf_object;
2193573f384SYiFei Zhu 	child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
2203573f384SYiFei Zhu 							child_cgroup_fd);
221bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
2223573f384SYiFei Zhu 		goto close_bpf_object;
2233573f384SYiFei Zhu 	child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
2243573f384SYiFei Zhu 							child_cgroup_fd);
225bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
2263573f384SYiFei Zhu 		goto close_bpf_object;
2273573f384SYiFei Zhu 	err = connect_send(CHILD_CGROUP);
2283573f384SYiFei Zhu 	if (CHECK(err, "second-connect-send", "errno %d", errno))
2293573f384SYiFei Zhu 		goto close_bpf_object;
2303573f384SYiFei Zhu 	if (CHECK(obj->bss->invocations != 9,
2313573f384SYiFei Zhu 		  "second-invoke", "invocations=%d", obj->bss->invocations))
2323573f384SYiFei Zhu 		goto close_bpf_object;
2333573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
2343573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
2353573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 4 };
2363573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2373573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2383573f384SYiFei Zhu 		goto close_bpf_object;
2393573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_INGRESS;
2403573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 2 };
2413573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2423573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2433573f384SYiFei Zhu 		goto close_bpf_object;
2443573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
2453573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
2463573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
2473573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2483573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2493573f384SYiFei Zhu 		goto close_bpf_object;
2503573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_INGRESS;
2513573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
2523573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2533573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2543573f384SYiFei Zhu 		goto close_bpf_object;
2553573f384SYiFei Zhu 
2563573f384SYiFei Zhu close_bpf_object:
2573573f384SYiFei Zhu 	bpf_link__destroy(parent_egress1_link);
2583573f384SYiFei Zhu 	bpf_link__destroy(parent_egress2_link);
2593573f384SYiFei Zhu 	bpf_link__destroy(parent_ingress_link);
2603573f384SYiFei Zhu 	bpf_link__destroy(child_egress1_link);
2613573f384SYiFei Zhu 	bpf_link__destroy(child_egress2_link);
2623573f384SYiFei Zhu 	bpf_link__destroy(child_ingress_link);
2633573f384SYiFei Zhu 
2643573f384SYiFei Zhu 	cg_storage_multi_isolated__destroy(obj);
2653573f384SYiFei Zhu }
2663573f384SYiFei Zhu 
2673573f384SYiFei Zhu static void test_shared(int parent_cgroup_fd, int child_cgroup_fd)
2683573f384SYiFei Zhu {
2693573f384SYiFei Zhu 	struct cg_storage_multi_shared *obj;
2703573f384SYiFei Zhu 	struct cgroup_value expected_cgroup_value;
2713573f384SYiFei Zhu 	__u64 key;
2723573f384SYiFei Zhu 	struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
2733573f384SYiFei Zhu 	struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
2743573f384SYiFei Zhu 	struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
2753573f384SYiFei Zhu 	bool err;
2763573f384SYiFei Zhu 
2773573f384SYiFei Zhu 	obj = cg_storage_multi_shared__open_and_load();
2783573f384SYiFei Zhu 	if (CHECK(!obj, "skel-load", "errno %d", errno))
2793573f384SYiFei Zhu 		return;
2803573f384SYiFei Zhu 
2813573f384SYiFei Zhu 	/* Attach to parent cgroup, trigger packet from child.
2823573f384SYiFei Zhu 	 * Assert that there is three runs, two with parent cgroup egress and
2833573f384SYiFei Zhu 	 * one with parent cgroup ingress.
2843573f384SYiFei Zhu 	 * Also assert that child cgroup's storage does not exist
2853573f384SYiFei Zhu 	 */
2863573f384SYiFei Zhu 	parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
2873573f384SYiFei Zhu 							 parent_cgroup_fd);
288bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
2893573f384SYiFei Zhu 		goto close_bpf_object;
2903573f384SYiFei Zhu 	parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
2913573f384SYiFei Zhu 							 parent_cgroup_fd);
292bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
2933573f384SYiFei Zhu 		goto close_bpf_object;
2943573f384SYiFei Zhu 	parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
2953573f384SYiFei Zhu 							 parent_cgroup_fd);
296bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
2973573f384SYiFei Zhu 		goto close_bpf_object;
2983573f384SYiFei Zhu 	err = connect_send(CHILD_CGROUP);
2993573f384SYiFei Zhu 	if (CHECK(err, "first-connect-send", "errno %d", errno))
3003573f384SYiFei Zhu 		goto close_bpf_object;
3013573f384SYiFei Zhu 	if (CHECK(obj->bss->invocations != 3,
3023573f384SYiFei Zhu 		  "first-invoke", "invocations=%d", obj->bss->invocations))
3033573f384SYiFei Zhu 		goto close_bpf_object;
3043573f384SYiFei Zhu 	key = get_cgroup_id(PARENT_CGROUP);
3053573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) {
3063573f384SYiFei Zhu 		.egress_pkts = 2,
3073573f384SYiFei Zhu 		.ingress_pkts = 1,
3083573f384SYiFei Zhu 	};
3093573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
3103573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
3113573f384SYiFei Zhu 		goto close_bpf_object;
3123573f384SYiFei Zhu 	key = get_cgroup_id(CHILD_CGROUP);
3133573f384SYiFei Zhu 	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
3143573f384SYiFei Zhu 		goto close_bpf_object;
3153573f384SYiFei Zhu 
3163573f384SYiFei Zhu 	/* Attach to parent and child cgroup, trigger packet from child.
3173573f384SYiFei Zhu 	 * Assert that there is six additional runs, parent cgroup egresses and
3183573f384SYiFei Zhu 	 * ingress, child cgroup egresses and ingress.
3193573f384SYiFei Zhu 	 */
3203573f384SYiFei Zhu 	child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
3213573f384SYiFei Zhu 							child_cgroup_fd);
322bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
3233573f384SYiFei Zhu 		goto close_bpf_object;
3243573f384SYiFei Zhu 	child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
3253573f384SYiFei Zhu 							child_cgroup_fd);
326bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
3273573f384SYiFei Zhu 		goto close_bpf_object;
3283573f384SYiFei Zhu 	child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
3293573f384SYiFei Zhu 							child_cgroup_fd);
330bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
3313573f384SYiFei Zhu 		goto close_bpf_object;
3323573f384SYiFei Zhu 	err = connect_send(CHILD_CGROUP);
3333573f384SYiFei Zhu 	if (CHECK(err, "second-connect-send", "errno %d", errno))
3343573f384SYiFei Zhu 		goto close_bpf_object;
3353573f384SYiFei Zhu 	if (CHECK(obj->bss->invocations != 9,
3363573f384SYiFei Zhu 		  "second-invoke", "invocations=%d", obj->bss->invocations))
3373573f384SYiFei Zhu 		goto close_bpf_object;
3383573f384SYiFei Zhu 	key = get_cgroup_id(PARENT_CGROUP);
3393573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) {
3403573f384SYiFei Zhu 		.egress_pkts = 4,
3413573f384SYiFei Zhu 		.ingress_pkts = 2,
3423573f384SYiFei Zhu 	};
3433573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
3443573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
3453573f384SYiFei Zhu 		goto close_bpf_object;
3463573f384SYiFei Zhu 	key = get_cgroup_id(CHILD_CGROUP);
3473573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) {
3483573f384SYiFei Zhu 		.egress_pkts = 2,
3493573f384SYiFei Zhu 		.ingress_pkts = 1,
3503573f384SYiFei Zhu 	};
3513573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
3523573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
3533573f384SYiFei Zhu 		goto close_bpf_object;
3543573f384SYiFei Zhu 
3553573f384SYiFei Zhu close_bpf_object:
3563573f384SYiFei Zhu 	bpf_link__destroy(parent_egress1_link);
3573573f384SYiFei Zhu 	bpf_link__destroy(parent_egress2_link);
3583573f384SYiFei Zhu 	bpf_link__destroy(parent_ingress_link);
3593573f384SYiFei Zhu 	bpf_link__destroy(child_egress1_link);
3603573f384SYiFei Zhu 	bpf_link__destroy(child_egress2_link);
3613573f384SYiFei Zhu 	bpf_link__destroy(child_ingress_link);
3623573f384SYiFei Zhu 
3633573f384SYiFei Zhu 	cg_storage_multi_shared__destroy(obj);
3649e5bd1f7SYiFei Zhu }
3659e5bd1f7SYiFei Zhu 
366*d3f7b166SYucong Sun void serial_test_cg_storage_multi(void)
367d4a89c1eSYiFei Zhu {
368d4a89c1eSYiFei Zhu 	int parent_cgroup_fd = -1, child_cgroup_fd = -1;
369d4a89c1eSYiFei Zhu 
370d4a89c1eSYiFei Zhu 	parent_cgroup_fd = test__join_cgroup(PARENT_CGROUP);
371d4a89c1eSYiFei Zhu 	if (CHECK(parent_cgroup_fd < 0, "cg-create-parent", "errno %d", errno))
372d4a89c1eSYiFei Zhu 		goto close_cgroup_fd;
373d4a89c1eSYiFei Zhu 	child_cgroup_fd = create_and_get_cgroup(CHILD_CGROUP);
374d4a89c1eSYiFei Zhu 	if (CHECK(child_cgroup_fd < 0, "cg-create-child", "errno %d", errno))
375d4a89c1eSYiFei Zhu 		goto close_cgroup_fd;
376d4a89c1eSYiFei Zhu 
377d4a89c1eSYiFei Zhu 	if (test__start_subtest("egress_only"))
378d4a89c1eSYiFei Zhu 		test_egress_only(parent_cgroup_fd, child_cgroup_fd);
379d4a89c1eSYiFei Zhu 
3803573f384SYiFei Zhu 	if (test__start_subtest("isolated"))
3813573f384SYiFei Zhu 		test_isolated(parent_cgroup_fd, child_cgroup_fd);
3823573f384SYiFei Zhu 
3833573f384SYiFei Zhu 	if (test__start_subtest("shared"))
3843573f384SYiFei Zhu 		test_shared(parent_cgroup_fd, child_cgroup_fd);
3859e5bd1f7SYiFei Zhu 
386d4a89c1eSYiFei Zhu close_cgroup_fd:
387d4a89c1eSYiFei Zhu 	close(child_cgroup_fd);
388d4a89c1eSYiFei Zhu 	close(parent_cgroup_fd);
389d4a89c1eSYiFei Zhu }
390