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 
assert_storage(struct bpf_map * map,const void * key,struct cgroup_value * expected)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 
assert_storage_noexist(struct bpf_map * map,const void * key)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 
connect_send(const char * cgroup_path)57d4a89c1eSYiFei Zhu static bool connect_send(const char *cgroup_path)
58d4a89c1eSYiFei Zhu {
59d4a89c1eSYiFei Zhu 	int server_fd = -1, client_fd = -1;
60*5af607a8SYiFei Zhu 	char message[] = "message";
61*5af607a8SYiFei Zhu 	bool res = true;
62d4a89c1eSYiFei Zhu 
63d4a89c1eSYiFei Zhu 	if (join_cgroup(cgroup_path))
64d4a89c1eSYiFei Zhu 		goto out_clean;
65d4a89c1eSYiFei Zhu 
66d4a89c1eSYiFei Zhu 	server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0);
67d4a89c1eSYiFei Zhu 	if (server_fd < 0)
68d4a89c1eSYiFei Zhu 		goto out_clean;
69d4a89c1eSYiFei Zhu 
70d4a89c1eSYiFei Zhu 	client_fd = connect_to_fd(server_fd, 0);
71d4a89c1eSYiFei Zhu 	if (client_fd < 0)
72d4a89c1eSYiFei Zhu 		goto out_clean;
73d4a89c1eSYiFei Zhu 
74*5af607a8SYiFei Zhu 	if (send(client_fd, &message, sizeof(message), 0) < 0)
75*5af607a8SYiFei Zhu 		goto out_clean;
76*5af607a8SYiFei Zhu 
77*5af607a8SYiFei Zhu 	if (read(server_fd, &message, sizeof(message)) < 0)
78d4a89c1eSYiFei Zhu 		goto out_clean;
79d4a89c1eSYiFei Zhu 
80d4a89c1eSYiFei Zhu 	res = false;
81d4a89c1eSYiFei Zhu 
82d4a89c1eSYiFei Zhu out_clean:
83d4a89c1eSYiFei Zhu 	close(client_fd);
84d4a89c1eSYiFei Zhu 	close(server_fd);
85d4a89c1eSYiFei Zhu 	return res;
86d4a89c1eSYiFei Zhu }
87d4a89c1eSYiFei Zhu 
test_egress_only(int parent_cgroup_fd,int child_cgroup_fd)88d4a89c1eSYiFei Zhu static void test_egress_only(int parent_cgroup_fd, int child_cgroup_fd)
89d4a89c1eSYiFei Zhu {
90d4a89c1eSYiFei Zhu 	struct cg_storage_multi_egress_only *obj;
919e5bd1f7SYiFei Zhu 	struct cgroup_value expected_cgroup_value;
923573f384SYiFei Zhu 	struct bpf_cgroup_storage_key key;
93d4a89c1eSYiFei Zhu 	struct bpf_link *parent_link = NULL, *child_link = NULL;
94d4a89c1eSYiFei Zhu 	bool err;
95d4a89c1eSYiFei Zhu 
963573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
973573f384SYiFei Zhu 
98d4a89c1eSYiFei Zhu 	obj = cg_storage_multi_egress_only__open_and_load();
99d4a89c1eSYiFei Zhu 	if (CHECK(!obj, "skel-load", "errno %d", errno))
100d4a89c1eSYiFei Zhu 		return;
101d4a89c1eSYiFei Zhu 
102d4a89c1eSYiFei Zhu 	/* Attach to parent cgroup, trigger packet from child.
103d4a89c1eSYiFei Zhu 	 * Assert that there is only one run and in that run the storage is
104d4a89c1eSYiFei Zhu 	 * parent cgroup's storage.
105d4a89c1eSYiFei Zhu 	 * Also assert that child cgroup's storage does not exist
106d4a89c1eSYiFei Zhu 	 */
107d4a89c1eSYiFei Zhu 	parent_link = bpf_program__attach_cgroup(obj->progs.egress,
108d4a89c1eSYiFei Zhu 						 parent_cgroup_fd);
109bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_link, "parent-cg-attach"))
110d4a89c1eSYiFei Zhu 		goto close_bpf_object;
111d4a89c1eSYiFei Zhu 	err = connect_send(CHILD_CGROUP);
112d4a89c1eSYiFei Zhu 	if (CHECK(err, "first-connect-send", "errno %d", errno))
113d4a89c1eSYiFei Zhu 		goto close_bpf_object;
114d4a89c1eSYiFei Zhu 	if (CHECK(obj->bss->invocations != 1,
115d4a89c1eSYiFei Zhu 		  "first-invoke", "invocations=%d", obj->bss->invocations))
116d4a89c1eSYiFei Zhu 		goto close_bpf_object;
1173573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
1189e5bd1f7SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
1199e5bd1f7SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
1203573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
121d4a89c1eSYiFei Zhu 		goto close_bpf_object;
1223573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
1233573f384SYiFei Zhu 	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
124d4a89c1eSYiFei Zhu 		goto close_bpf_object;
125d4a89c1eSYiFei Zhu 
126d4a89c1eSYiFei Zhu 	/* Attach to parent and child cgroup, trigger packet from child.
127d4a89c1eSYiFei Zhu 	 * Assert that there are two additional runs, one that run with parent
128d4a89c1eSYiFei Zhu 	 * cgroup's storage and one with child cgroup's storage.
129d4a89c1eSYiFei Zhu 	 */
130d4a89c1eSYiFei Zhu 	child_link = bpf_program__attach_cgroup(obj->progs.egress,
131d4a89c1eSYiFei Zhu 						child_cgroup_fd);
132bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_link, "child-cg-attach"))
133d4a89c1eSYiFei Zhu 		goto close_bpf_object;
134d4a89c1eSYiFei Zhu 	err = connect_send(CHILD_CGROUP);
135d4a89c1eSYiFei Zhu 	if (CHECK(err, "second-connect-send", "errno %d", errno))
136d4a89c1eSYiFei Zhu 		goto close_bpf_object;
137d4a89c1eSYiFei Zhu 	if (CHECK(obj->bss->invocations != 3,
138d4a89c1eSYiFei Zhu 		  "second-invoke", "invocations=%d", obj->bss->invocations))
139d4a89c1eSYiFei Zhu 		goto close_bpf_object;
1403573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
1419e5bd1f7SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
1429e5bd1f7SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
1433573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
144d4a89c1eSYiFei Zhu 		goto close_bpf_object;
1453573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
1469e5bd1f7SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
1479e5bd1f7SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
1483573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
149d4a89c1eSYiFei Zhu 		goto close_bpf_object;
150d4a89c1eSYiFei Zhu 
151d4a89c1eSYiFei Zhu close_bpf_object:
152d4a89c1eSYiFei Zhu 	bpf_link__destroy(parent_link);
153d4a89c1eSYiFei Zhu 	bpf_link__destroy(child_link);
154d4a89c1eSYiFei Zhu 
155d4a89c1eSYiFei Zhu 	cg_storage_multi_egress_only__destroy(obj);
156d4a89c1eSYiFei Zhu }
157d4a89c1eSYiFei Zhu 
test_isolated(int parent_cgroup_fd,int child_cgroup_fd)1583573f384SYiFei Zhu static void test_isolated(int parent_cgroup_fd, int child_cgroup_fd)
1599e5bd1f7SYiFei Zhu {
1603573f384SYiFei Zhu 	struct cg_storage_multi_isolated *obj;
1613573f384SYiFei Zhu 	struct cgroup_value expected_cgroup_value;
1623573f384SYiFei Zhu 	struct bpf_cgroup_storage_key key;
1633573f384SYiFei Zhu 	struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
1643573f384SYiFei Zhu 	struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
1653573f384SYiFei Zhu 	struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
1663573f384SYiFei Zhu 	bool err;
1679e5bd1f7SYiFei Zhu 
1683573f384SYiFei Zhu 	obj = cg_storage_multi_isolated__open_and_load();
1693573f384SYiFei Zhu 	if (CHECK(!obj, "skel-load", "errno %d", errno))
1703573f384SYiFei Zhu 		return;
1713573f384SYiFei Zhu 
1723573f384SYiFei Zhu 	/* Attach to parent cgroup, trigger packet from child.
1733573f384SYiFei Zhu 	 * Assert that there is three runs, two with parent cgroup egress and
1743573f384SYiFei Zhu 	 * one with parent cgroup ingress, stored in separate parent storages.
1753573f384SYiFei Zhu 	 * Also assert that child cgroup's storages does not exist
1769e5bd1f7SYiFei Zhu 	 */
1773573f384SYiFei Zhu 	parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
1783573f384SYiFei Zhu 							 parent_cgroup_fd);
179bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
1803573f384SYiFei Zhu 		goto close_bpf_object;
1813573f384SYiFei Zhu 	parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
1823573f384SYiFei Zhu 							 parent_cgroup_fd);
183bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
1843573f384SYiFei Zhu 		goto close_bpf_object;
1853573f384SYiFei Zhu 	parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
1863573f384SYiFei Zhu 							 parent_cgroup_fd);
187bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
1883573f384SYiFei Zhu 		goto close_bpf_object;
1893573f384SYiFei Zhu 	err = connect_send(CHILD_CGROUP);
1903573f384SYiFei Zhu 	if (CHECK(err, "first-connect-send", "errno %d", errno))
1913573f384SYiFei Zhu 		goto close_bpf_object;
1923573f384SYiFei Zhu 	if (CHECK(obj->bss->invocations != 3,
1933573f384SYiFei Zhu 		  "first-invoke", "invocations=%d", obj->bss->invocations))
1943573f384SYiFei Zhu 		goto close_bpf_object;
1953573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
1963573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
1973573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
1983573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
1993573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2003573f384SYiFei Zhu 		goto close_bpf_object;
2013573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_INGRESS;
2023573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
2033573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2043573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2053573f384SYiFei Zhu 		goto close_bpf_object;
2063573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
2073573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
2083573f384SYiFei Zhu 	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
2093573f384SYiFei Zhu 		goto close_bpf_object;
2103573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_INGRESS;
2113573f384SYiFei Zhu 	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
2123573f384SYiFei Zhu 		goto close_bpf_object;
2139e5bd1f7SYiFei Zhu 
2143573f384SYiFei Zhu 	/* Attach to parent and child cgroup, trigger packet from child.
2153573f384SYiFei Zhu 	 * Assert that there is six additional runs, parent cgroup egresses and
2163573f384SYiFei Zhu 	 * ingress, child cgroup egresses and ingress.
2173573f384SYiFei Zhu 	 * Assert that egree and ingress storages are separate.
2183573f384SYiFei Zhu 	 */
2193573f384SYiFei Zhu 	child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
2203573f384SYiFei Zhu 							child_cgroup_fd);
221bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
2223573f384SYiFei Zhu 		goto close_bpf_object;
2233573f384SYiFei Zhu 	child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
2243573f384SYiFei Zhu 							child_cgroup_fd);
225bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
2263573f384SYiFei Zhu 		goto close_bpf_object;
2273573f384SYiFei Zhu 	child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
2283573f384SYiFei Zhu 							child_cgroup_fd);
229bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
2303573f384SYiFei Zhu 		goto close_bpf_object;
2313573f384SYiFei Zhu 	err = connect_send(CHILD_CGROUP);
2323573f384SYiFei Zhu 	if (CHECK(err, "second-connect-send", "errno %d", errno))
2333573f384SYiFei Zhu 		goto close_bpf_object;
2343573f384SYiFei Zhu 	if (CHECK(obj->bss->invocations != 9,
2353573f384SYiFei Zhu 		  "second-invoke", "invocations=%d", obj->bss->invocations))
2363573f384SYiFei Zhu 		goto close_bpf_object;
2373573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
2383573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
2393573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 4 };
2403573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2413573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2423573f384SYiFei Zhu 		goto close_bpf_object;
2433573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_INGRESS;
2443573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 2 };
2453573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2463573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2473573f384SYiFei Zhu 		goto close_bpf_object;
2483573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
2493573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
2503573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
2513573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2523573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2533573f384SYiFei Zhu 		goto close_bpf_object;
2543573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_INGRESS;
2553573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
2563573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2573573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2583573f384SYiFei Zhu 		goto close_bpf_object;
2593573f384SYiFei Zhu 
2603573f384SYiFei Zhu close_bpf_object:
2613573f384SYiFei Zhu 	bpf_link__destroy(parent_egress1_link);
2623573f384SYiFei Zhu 	bpf_link__destroy(parent_egress2_link);
2633573f384SYiFei Zhu 	bpf_link__destroy(parent_ingress_link);
2643573f384SYiFei Zhu 	bpf_link__destroy(child_egress1_link);
2653573f384SYiFei Zhu 	bpf_link__destroy(child_egress2_link);
2663573f384SYiFei Zhu 	bpf_link__destroy(child_ingress_link);
2673573f384SYiFei Zhu 
2683573f384SYiFei Zhu 	cg_storage_multi_isolated__destroy(obj);
2693573f384SYiFei Zhu }
2703573f384SYiFei Zhu 
test_shared(int parent_cgroup_fd,int child_cgroup_fd)2713573f384SYiFei Zhu static void test_shared(int parent_cgroup_fd, int child_cgroup_fd)
2723573f384SYiFei Zhu {
2733573f384SYiFei Zhu 	struct cg_storage_multi_shared *obj;
2743573f384SYiFei Zhu 	struct cgroup_value expected_cgroup_value;
2753573f384SYiFei Zhu 	__u64 key;
2763573f384SYiFei Zhu 	struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
2773573f384SYiFei Zhu 	struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
2783573f384SYiFei Zhu 	struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
2793573f384SYiFei Zhu 	bool err;
2803573f384SYiFei Zhu 
2813573f384SYiFei Zhu 	obj = cg_storage_multi_shared__open_and_load();
2823573f384SYiFei Zhu 	if (CHECK(!obj, "skel-load", "errno %d", errno))
2833573f384SYiFei Zhu 		return;
2843573f384SYiFei Zhu 
2853573f384SYiFei Zhu 	/* Attach to parent cgroup, trigger packet from child.
2863573f384SYiFei Zhu 	 * Assert that there is three runs, two with parent cgroup egress and
2873573f384SYiFei Zhu 	 * one with parent cgroup ingress.
2883573f384SYiFei Zhu 	 * Also assert that child cgroup's storage does not exist
2893573f384SYiFei Zhu 	 */
2903573f384SYiFei Zhu 	parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
2913573f384SYiFei Zhu 							 parent_cgroup_fd);
292bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
2933573f384SYiFei Zhu 		goto close_bpf_object;
2943573f384SYiFei Zhu 	parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
2953573f384SYiFei Zhu 							 parent_cgroup_fd);
296bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
2973573f384SYiFei Zhu 		goto close_bpf_object;
2983573f384SYiFei Zhu 	parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
2993573f384SYiFei Zhu 							 parent_cgroup_fd);
300bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
3013573f384SYiFei Zhu 		goto close_bpf_object;
3023573f384SYiFei Zhu 	err = connect_send(CHILD_CGROUP);
3033573f384SYiFei Zhu 	if (CHECK(err, "first-connect-send", "errno %d", errno))
3043573f384SYiFei Zhu 		goto close_bpf_object;
3053573f384SYiFei Zhu 	if (CHECK(obj->bss->invocations != 3,
3063573f384SYiFei Zhu 		  "first-invoke", "invocations=%d", obj->bss->invocations))
3073573f384SYiFei Zhu 		goto close_bpf_object;
3083573f384SYiFei Zhu 	key = get_cgroup_id(PARENT_CGROUP);
3093573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) {
3103573f384SYiFei Zhu 		.egress_pkts = 2,
3113573f384SYiFei Zhu 		.ingress_pkts = 1,
3123573f384SYiFei Zhu 	};
3133573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
3143573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
3153573f384SYiFei Zhu 		goto close_bpf_object;
3163573f384SYiFei Zhu 	key = get_cgroup_id(CHILD_CGROUP);
3173573f384SYiFei Zhu 	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
3183573f384SYiFei Zhu 		goto close_bpf_object;
3193573f384SYiFei Zhu 
3203573f384SYiFei Zhu 	/* Attach to parent and child cgroup, trigger packet from child.
3213573f384SYiFei Zhu 	 * Assert that there is six additional runs, parent cgroup egresses and
3223573f384SYiFei Zhu 	 * ingress, child cgroup egresses and ingress.
3233573f384SYiFei Zhu 	 */
3243573f384SYiFei Zhu 	child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
3253573f384SYiFei Zhu 							child_cgroup_fd);
326bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
3273573f384SYiFei Zhu 		goto close_bpf_object;
3283573f384SYiFei Zhu 	child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
3293573f384SYiFei Zhu 							child_cgroup_fd);
330bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
3313573f384SYiFei Zhu 		goto close_bpf_object;
3323573f384SYiFei Zhu 	child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
3333573f384SYiFei Zhu 							child_cgroup_fd);
334bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
3353573f384SYiFei Zhu 		goto close_bpf_object;
3363573f384SYiFei Zhu 	err = connect_send(CHILD_CGROUP);
3373573f384SYiFei Zhu 	if (CHECK(err, "second-connect-send", "errno %d", errno))
3383573f384SYiFei Zhu 		goto close_bpf_object;
3393573f384SYiFei Zhu 	if (CHECK(obj->bss->invocations != 9,
3403573f384SYiFei Zhu 		  "second-invoke", "invocations=%d", obj->bss->invocations))
3413573f384SYiFei Zhu 		goto close_bpf_object;
3423573f384SYiFei Zhu 	key = get_cgroup_id(PARENT_CGROUP);
3433573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) {
3443573f384SYiFei Zhu 		.egress_pkts = 4,
3453573f384SYiFei Zhu 		.ingress_pkts = 2,
3463573f384SYiFei Zhu 	};
3473573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
3483573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
3493573f384SYiFei Zhu 		goto close_bpf_object;
3503573f384SYiFei Zhu 	key = get_cgroup_id(CHILD_CGROUP);
3513573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) {
3523573f384SYiFei Zhu 		.egress_pkts = 2,
3533573f384SYiFei Zhu 		.ingress_pkts = 1,
3543573f384SYiFei Zhu 	};
3553573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
3563573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
3573573f384SYiFei Zhu 		goto close_bpf_object;
3583573f384SYiFei Zhu 
3593573f384SYiFei Zhu close_bpf_object:
3603573f384SYiFei Zhu 	bpf_link__destroy(parent_egress1_link);
3613573f384SYiFei Zhu 	bpf_link__destroy(parent_egress2_link);
3623573f384SYiFei Zhu 	bpf_link__destroy(parent_ingress_link);
3633573f384SYiFei Zhu 	bpf_link__destroy(child_egress1_link);
3643573f384SYiFei Zhu 	bpf_link__destroy(child_egress2_link);
3653573f384SYiFei Zhu 	bpf_link__destroy(child_ingress_link);
3663573f384SYiFei Zhu 
3673573f384SYiFei Zhu 	cg_storage_multi_shared__destroy(obj);
3689e5bd1f7SYiFei Zhu }
3699e5bd1f7SYiFei Zhu 
serial_test_cg_storage_multi(void)370d3f7b166SYucong Sun void serial_test_cg_storage_multi(void)
371d4a89c1eSYiFei Zhu {
372d4a89c1eSYiFei Zhu 	int parent_cgroup_fd = -1, child_cgroup_fd = -1;
373d4a89c1eSYiFei Zhu 
374d4a89c1eSYiFei Zhu 	parent_cgroup_fd = test__join_cgroup(PARENT_CGROUP);
375d4a89c1eSYiFei Zhu 	if (CHECK(parent_cgroup_fd < 0, "cg-create-parent", "errno %d", errno))
376d4a89c1eSYiFei Zhu 		goto close_cgroup_fd;
377d4a89c1eSYiFei Zhu 	child_cgroup_fd = create_and_get_cgroup(CHILD_CGROUP);
378d4a89c1eSYiFei Zhu 	if (CHECK(child_cgroup_fd < 0, "cg-create-child", "errno %d", errno))
379d4a89c1eSYiFei Zhu 		goto close_cgroup_fd;
380d4a89c1eSYiFei Zhu 
381d4a89c1eSYiFei Zhu 	if (test__start_subtest("egress_only"))
382d4a89c1eSYiFei Zhu 		test_egress_only(parent_cgroup_fd, child_cgroup_fd);
383d4a89c1eSYiFei Zhu 
3843573f384SYiFei Zhu 	if (test__start_subtest("isolated"))
3853573f384SYiFei Zhu 		test_isolated(parent_cgroup_fd, child_cgroup_fd);
3863573f384SYiFei Zhu 
3873573f384SYiFei Zhu 	if (test__start_subtest("shared"))
3883573f384SYiFei Zhu 		test_shared(parent_cgroup_fd, child_cgroup_fd);
3899e5bd1f7SYiFei Zhu 
390d4a89c1eSYiFei Zhu close_cgroup_fd:
391d4a89c1eSYiFei Zhu 	close(child_cgroup_fd);
392d4a89c1eSYiFei Zhu 	close(parent_cgroup_fd);
393d4a89c1eSYiFei Zhu }
394