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);
105d4a89c1eSYiFei Zhu 	if (CHECK(IS_ERR(parent_link), "parent-cg-attach",
106d4a89c1eSYiFei Zhu 		  "err %ld", PTR_ERR(parent_link)))
107d4a89c1eSYiFei Zhu 		goto close_bpf_object;
108d4a89c1eSYiFei Zhu 	err = connect_send(CHILD_CGROUP);
109d4a89c1eSYiFei Zhu 	if (CHECK(err, "first-connect-send", "errno %d", errno))
110d4a89c1eSYiFei Zhu 		goto close_bpf_object;
111d4a89c1eSYiFei Zhu 	if (CHECK(obj->bss->invocations != 1,
112d4a89c1eSYiFei Zhu 		  "first-invoke", "invocations=%d", obj->bss->invocations))
113d4a89c1eSYiFei Zhu 		goto close_bpf_object;
1143573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
1159e5bd1f7SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
1169e5bd1f7SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
1173573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
118d4a89c1eSYiFei Zhu 		goto close_bpf_object;
1193573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
1203573f384SYiFei Zhu 	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
121d4a89c1eSYiFei Zhu 		goto close_bpf_object;
122d4a89c1eSYiFei Zhu 
123d4a89c1eSYiFei Zhu 	/* Attach to parent and child cgroup, trigger packet from child.
124d4a89c1eSYiFei Zhu 	 * Assert that there are two additional runs, one that run with parent
125d4a89c1eSYiFei Zhu 	 * cgroup's storage and one with child cgroup's storage.
126d4a89c1eSYiFei Zhu 	 */
127d4a89c1eSYiFei Zhu 	child_link = bpf_program__attach_cgroup(obj->progs.egress,
128d4a89c1eSYiFei Zhu 						child_cgroup_fd);
129d4a89c1eSYiFei Zhu 	if (CHECK(IS_ERR(child_link), "child-cg-attach",
130d4a89c1eSYiFei Zhu 		  "err %ld", PTR_ERR(child_link)))
131d4a89c1eSYiFei Zhu 		goto close_bpf_object;
132d4a89c1eSYiFei Zhu 	err = connect_send(CHILD_CGROUP);
133d4a89c1eSYiFei Zhu 	if (CHECK(err, "second-connect-send", "errno %d", errno))
134d4a89c1eSYiFei Zhu 		goto close_bpf_object;
135d4a89c1eSYiFei Zhu 	if (CHECK(obj->bss->invocations != 3,
136d4a89c1eSYiFei Zhu 		  "second-invoke", "invocations=%d", obj->bss->invocations))
137d4a89c1eSYiFei Zhu 		goto close_bpf_object;
1383573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
1399e5bd1f7SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
1409e5bd1f7SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
1413573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
142d4a89c1eSYiFei Zhu 		goto close_bpf_object;
1433573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
1449e5bd1f7SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
1459e5bd1f7SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
1463573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
147d4a89c1eSYiFei Zhu 		goto close_bpf_object;
148d4a89c1eSYiFei Zhu 
149d4a89c1eSYiFei Zhu close_bpf_object:
150d4a89c1eSYiFei Zhu 	bpf_link__destroy(parent_link);
151d4a89c1eSYiFei Zhu 	bpf_link__destroy(child_link);
152d4a89c1eSYiFei Zhu 
153d4a89c1eSYiFei Zhu 	cg_storage_multi_egress_only__destroy(obj);
154d4a89c1eSYiFei Zhu }
155d4a89c1eSYiFei Zhu 
1563573f384SYiFei Zhu static void test_isolated(int parent_cgroup_fd, int child_cgroup_fd)
1579e5bd1f7SYiFei Zhu {
1583573f384SYiFei Zhu 	struct cg_storage_multi_isolated *obj;
1593573f384SYiFei Zhu 	struct cgroup_value expected_cgroup_value;
1603573f384SYiFei Zhu 	struct bpf_cgroup_storage_key key;
1613573f384SYiFei Zhu 	struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
1623573f384SYiFei Zhu 	struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
1633573f384SYiFei Zhu 	struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
1643573f384SYiFei Zhu 	bool err;
1659e5bd1f7SYiFei Zhu 
1663573f384SYiFei Zhu 	obj = cg_storage_multi_isolated__open_and_load();
1673573f384SYiFei Zhu 	if (CHECK(!obj, "skel-load", "errno %d", errno))
1683573f384SYiFei Zhu 		return;
1693573f384SYiFei Zhu 
1703573f384SYiFei Zhu 	/* Attach to parent cgroup, trigger packet from child.
1713573f384SYiFei Zhu 	 * Assert that there is three runs, two with parent cgroup egress and
1723573f384SYiFei Zhu 	 * one with parent cgroup ingress, stored in separate parent storages.
1733573f384SYiFei Zhu 	 * Also assert that child cgroup's storages does not exist
1749e5bd1f7SYiFei Zhu 	 */
1753573f384SYiFei Zhu 	parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
1763573f384SYiFei Zhu 							 parent_cgroup_fd);
1773573f384SYiFei Zhu 	if (CHECK(IS_ERR(parent_egress1_link), "parent-egress1-cg-attach",
1783573f384SYiFei Zhu 		  "err %ld", PTR_ERR(parent_egress1_link)))
1793573f384SYiFei Zhu 		goto close_bpf_object;
1803573f384SYiFei Zhu 	parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
1813573f384SYiFei Zhu 							 parent_cgroup_fd);
1823573f384SYiFei Zhu 	if (CHECK(IS_ERR(parent_egress2_link), "parent-egress2-cg-attach",
1833573f384SYiFei Zhu 		  "err %ld", PTR_ERR(parent_egress2_link)))
1843573f384SYiFei Zhu 		goto close_bpf_object;
1853573f384SYiFei Zhu 	parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
1863573f384SYiFei Zhu 							 parent_cgroup_fd);
1873573f384SYiFei Zhu 	if (CHECK(IS_ERR(parent_ingress_link), "parent-ingress-cg-attach",
1883573f384SYiFei Zhu 		  "err %ld", PTR_ERR(parent_ingress_link)))
1893573f384SYiFei Zhu 		goto close_bpf_object;
1903573f384SYiFei Zhu 	err = connect_send(CHILD_CGROUP);
1913573f384SYiFei Zhu 	if (CHECK(err, "first-connect-send", "errno %d", errno))
1923573f384SYiFei Zhu 		goto close_bpf_object;
1933573f384SYiFei Zhu 	if (CHECK(obj->bss->invocations != 3,
1943573f384SYiFei Zhu 		  "first-invoke", "invocations=%d", obj->bss->invocations))
1953573f384SYiFei Zhu 		goto close_bpf_object;
1963573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
1973573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
1983573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
1993573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2003573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2013573f384SYiFei Zhu 		goto close_bpf_object;
2023573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_INGRESS;
2033573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
2043573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2053573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2063573f384SYiFei Zhu 		goto close_bpf_object;
2073573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
2083573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
2093573f384SYiFei Zhu 	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
2103573f384SYiFei Zhu 		goto close_bpf_object;
2113573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_INGRESS;
2123573f384SYiFei Zhu 	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
2133573f384SYiFei Zhu 		goto close_bpf_object;
2149e5bd1f7SYiFei Zhu 
2153573f384SYiFei Zhu 	/* Attach to parent and child cgroup, trigger packet from child.
2163573f384SYiFei Zhu 	 * Assert that there is six additional runs, parent cgroup egresses and
2173573f384SYiFei Zhu 	 * ingress, child cgroup egresses and ingress.
2183573f384SYiFei Zhu 	 * Assert that egree and ingress storages are separate.
2193573f384SYiFei Zhu 	 */
2203573f384SYiFei Zhu 	child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
2213573f384SYiFei Zhu 							child_cgroup_fd);
2223573f384SYiFei Zhu 	if (CHECK(IS_ERR(child_egress1_link), "child-egress1-cg-attach",
2233573f384SYiFei Zhu 		  "err %ld", PTR_ERR(child_egress1_link)))
2243573f384SYiFei Zhu 		goto close_bpf_object;
2253573f384SYiFei Zhu 	child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
2263573f384SYiFei Zhu 							child_cgroup_fd);
2273573f384SYiFei Zhu 	if (CHECK(IS_ERR(child_egress2_link), "child-egress2-cg-attach",
2283573f384SYiFei Zhu 		  "err %ld", PTR_ERR(child_egress2_link)))
2293573f384SYiFei Zhu 		goto close_bpf_object;
2303573f384SYiFei Zhu 	child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
2313573f384SYiFei Zhu 							child_cgroup_fd);
2323573f384SYiFei Zhu 	if (CHECK(IS_ERR(child_ingress_link), "child-ingress-cg-attach",
2333573f384SYiFei Zhu 		  "err %ld", PTR_ERR(child_ingress_link)))
2343573f384SYiFei Zhu 		goto close_bpf_object;
2353573f384SYiFei Zhu 	err = connect_send(CHILD_CGROUP);
2363573f384SYiFei Zhu 	if (CHECK(err, "second-connect-send", "errno %d", errno))
2373573f384SYiFei Zhu 		goto close_bpf_object;
2383573f384SYiFei Zhu 	if (CHECK(obj->bss->invocations != 9,
2393573f384SYiFei Zhu 		  "second-invoke", "invocations=%d", obj->bss->invocations))
2403573f384SYiFei Zhu 		goto close_bpf_object;
2413573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
2423573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
2433573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 4 };
2443573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2453573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2463573f384SYiFei Zhu 		goto close_bpf_object;
2473573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_INGRESS;
2483573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 2 };
2493573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2503573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2513573f384SYiFei Zhu 		goto close_bpf_object;
2523573f384SYiFei Zhu 	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
2533573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_EGRESS;
2543573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
2553573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2563573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2573573f384SYiFei Zhu 		goto close_bpf_object;
2583573f384SYiFei Zhu 	key.attach_type = BPF_CGROUP_INET_INGRESS;
2593573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
2603573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
2613573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
2623573f384SYiFei Zhu 		goto close_bpf_object;
2633573f384SYiFei Zhu 
2643573f384SYiFei Zhu close_bpf_object:
2653573f384SYiFei Zhu 	bpf_link__destroy(parent_egress1_link);
2663573f384SYiFei Zhu 	bpf_link__destroy(parent_egress2_link);
2673573f384SYiFei Zhu 	bpf_link__destroy(parent_ingress_link);
2683573f384SYiFei Zhu 	bpf_link__destroy(child_egress1_link);
2693573f384SYiFei Zhu 	bpf_link__destroy(child_egress2_link);
2703573f384SYiFei Zhu 	bpf_link__destroy(child_ingress_link);
2713573f384SYiFei Zhu 
2723573f384SYiFei Zhu 	cg_storage_multi_isolated__destroy(obj);
2733573f384SYiFei Zhu }
2743573f384SYiFei Zhu 
2753573f384SYiFei Zhu static void test_shared(int parent_cgroup_fd, int child_cgroup_fd)
2763573f384SYiFei Zhu {
2773573f384SYiFei Zhu 	struct cg_storage_multi_shared *obj;
2783573f384SYiFei Zhu 	struct cgroup_value expected_cgroup_value;
2793573f384SYiFei Zhu 	__u64 key;
2803573f384SYiFei Zhu 	struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
2813573f384SYiFei Zhu 	struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
2823573f384SYiFei Zhu 	struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
2833573f384SYiFei Zhu 	bool err;
2843573f384SYiFei Zhu 
2853573f384SYiFei Zhu 	obj = cg_storage_multi_shared__open_and_load();
2863573f384SYiFei Zhu 	if (CHECK(!obj, "skel-load", "errno %d", errno))
2873573f384SYiFei Zhu 		return;
2883573f384SYiFei Zhu 
2893573f384SYiFei Zhu 	/* Attach to parent cgroup, trigger packet from child.
2903573f384SYiFei Zhu 	 * Assert that there is three runs, two with parent cgroup egress and
2913573f384SYiFei Zhu 	 * one with parent cgroup ingress.
2923573f384SYiFei Zhu 	 * Also assert that child cgroup's storage does not exist
2933573f384SYiFei Zhu 	 */
2943573f384SYiFei Zhu 	parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
2953573f384SYiFei Zhu 							 parent_cgroup_fd);
2963573f384SYiFei Zhu 	if (CHECK(IS_ERR(parent_egress1_link), "parent-egress1-cg-attach",
2973573f384SYiFei Zhu 		  "err %ld", PTR_ERR(parent_egress1_link)))
2983573f384SYiFei Zhu 		goto close_bpf_object;
2993573f384SYiFei Zhu 	parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
3003573f384SYiFei Zhu 							 parent_cgroup_fd);
3013573f384SYiFei Zhu 	if (CHECK(IS_ERR(parent_egress2_link), "parent-egress2-cg-attach",
3023573f384SYiFei Zhu 		  "err %ld", PTR_ERR(parent_egress2_link)))
3033573f384SYiFei Zhu 		goto close_bpf_object;
3043573f384SYiFei Zhu 	parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
3053573f384SYiFei Zhu 							 parent_cgroup_fd);
3063573f384SYiFei Zhu 	if (CHECK(IS_ERR(parent_ingress_link), "parent-ingress-cg-attach",
3073573f384SYiFei Zhu 		  "err %ld", PTR_ERR(parent_ingress_link)))
3083573f384SYiFei Zhu 		goto close_bpf_object;
3093573f384SYiFei Zhu 	err = connect_send(CHILD_CGROUP);
3103573f384SYiFei Zhu 	if (CHECK(err, "first-connect-send", "errno %d", errno))
3113573f384SYiFei Zhu 		goto close_bpf_object;
3123573f384SYiFei Zhu 	if (CHECK(obj->bss->invocations != 3,
3133573f384SYiFei Zhu 		  "first-invoke", "invocations=%d", obj->bss->invocations))
3143573f384SYiFei Zhu 		goto close_bpf_object;
3153573f384SYiFei Zhu 	key = get_cgroup_id(PARENT_CGROUP);
3163573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) {
3173573f384SYiFei Zhu 		.egress_pkts = 2,
3183573f384SYiFei Zhu 		.ingress_pkts = 1,
3193573f384SYiFei Zhu 	};
3203573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
3213573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
3223573f384SYiFei Zhu 		goto close_bpf_object;
3233573f384SYiFei Zhu 	key = get_cgroup_id(CHILD_CGROUP);
3243573f384SYiFei Zhu 	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
3253573f384SYiFei Zhu 		goto close_bpf_object;
3263573f384SYiFei Zhu 
3273573f384SYiFei Zhu 	/* Attach to parent and child cgroup, trigger packet from child.
3283573f384SYiFei Zhu 	 * Assert that there is six additional runs, parent cgroup egresses and
3293573f384SYiFei Zhu 	 * ingress, child cgroup egresses and ingress.
3303573f384SYiFei Zhu 	 */
3313573f384SYiFei Zhu 	child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
3323573f384SYiFei Zhu 							child_cgroup_fd);
3333573f384SYiFei Zhu 	if (CHECK(IS_ERR(child_egress1_link), "child-egress1-cg-attach",
3343573f384SYiFei Zhu 		  "err %ld", PTR_ERR(child_egress1_link)))
3353573f384SYiFei Zhu 		goto close_bpf_object;
3363573f384SYiFei Zhu 	child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
3373573f384SYiFei Zhu 							child_cgroup_fd);
3383573f384SYiFei Zhu 	if (CHECK(IS_ERR(child_egress2_link), "child-egress2-cg-attach",
3393573f384SYiFei Zhu 		  "err %ld", PTR_ERR(child_egress2_link)))
3403573f384SYiFei Zhu 		goto close_bpf_object;
3413573f384SYiFei Zhu 	child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
3423573f384SYiFei Zhu 							child_cgroup_fd);
3433573f384SYiFei Zhu 	if (CHECK(IS_ERR(child_ingress_link), "child-ingress-cg-attach",
3443573f384SYiFei Zhu 		  "err %ld", PTR_ERR(child_ingress_link)))
3453573f384SYiFei Zhu 		goto close_bpf_object;
3463573f384SYiFei Zhu 	err = connect_send(CHILD_CGROUP);
3473573f384SYiFei Zhu 	if (CHECK(err, "second-connect-send", "errno %d", errno))
3483573f384SYiFei Zhu 		goto close_bpf_object;
3493573f384SYiFei Zhu 	if (CHECK(obj->bss->invocations != 9,
3503573f384SYiFei Zhu 		  "second-invoke", "invocations=%d", obj->bss->invocations))
3513573f384SYiFei Zhu 		goto close_bpf_object;
3523573f384SYiFei Zhu 	key = get_cgroup_id(PARENT_CGROUP);
3533573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) {
3543573f384SYiFei Zhu 		.egress_pkts = 4,
3553573f384SYiFei Zhu 		.ingress_pkts = 2,
3563573f384SYiFei Zhu 	};
3573573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
3583573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
3593573f384SYiFei Zhu 		goto close_bpf_object;
3603573f384SYiFei Zhu 	key = get_cgroup_id(CHILD_CGROUP);
3613573f384SYiFei Zhu 	expected_cgroup_value = (struct cgroup_value) {
3623573f384SYiFei Zhu 		.egress_pkts = 2,
3633573f384SYiFei Zhu 		.ingress_pkts = 1,
3643573f384SYiFei Zhu 	};
3653573f384SYiFei Zhu 	if (assert_storage(obj->maps.cgroup_storage,
3663573f384SYiFei Zhu 			   &key, &expected_cgroup_value))
3673573f384SYiFei Zhu 		goto close_bpf_object;
3683573f384SYiFei Zhu 
3693573f384SYiFei Zhu close_bpf_object:
3703573f384SYiFei Zhu 	bpf_link__destroy(parent_egress1_link);
3713573f384SYiFei Zhu 	bpf_link__destroy(parent_egress2_link);
3723573f384SYiFei Zhu 	bpf_link__destroy(parent_ingress_link);
3733573f384SYiFei Zhu 	bpf_link__destroy(child_egress1_link);
3743573f384SYiFei Zhu 	bpf_link__destroy(child_egress2_link);
3753573f384SYiFei Zhu 	bpf_link__destroy(child_ingress_link);
3763573f384SYiFei Zhu 
3773573f384SYiFei Zhu 	cg_storage_multi_shared__destroy(obj);
3789e5bd1f7SYiFei Zhu }
3799e5bd1f7SYiFei Zhu 
380d4a89c1eSYiFei Zhu void test_cg_storage_multi(void)
381d4a89c1eSYiFei Zhu {
382d4a89c1eSYiFei Zhu 	int parent_cgroup_fd = -1, child_cgroup_fd = -1;
383d4a89c1eSYiFei Zhu 
384d4a89c1eSYiFei Zhu 	parent_cgroup_fd = test__join_cgroup(PARENT_CGROUP);
385d4a89c1eSYiFei Zhu 	if (CHECK(parent_cgroup_fd < 0, "cg-create-parent", "errno %d", errno))
386d4a89c1eSYiFei Zhu 		goto close_cgroup_fd;
387d4a89c1eSYiFei Zhu 	child_cgroup_fd = create_and_get_cgroup(CHILD_CGROUP);
388d4a89c1eSYiFei Zhu 	if (CHECK(child_cgroup_fd < 0, "cg-create-child", "errno %d", errno))
389d4a89c1eSYiFei Zhu 		goto close_cgroup_fd;
390d4a89c1eSYiFei Zhu 
391d4a89c1eSYiFei Zhu 	if (test__start_subtest("egress_only"))
392d4a89c1eSYiFei Zhu 		test_egress_only(parent_cgroup_fd, child_cgroup_fd);
393d4a89c1eSYiFei Zhu 
3943573f384SYiFei Zhu 	if (test__start_subtest("isolated"))
3953573f384SYiFei Zhu 		test_isolated(parent_cgroup_fd, child_cgroup_fd);
3963573f384SYiFei Zhu 
3973573f384SYiFei Zhu 	if (test__start_subtest("shared"))
3983573f384SYiFei Zhu 		test_shared(parent_cgroup_fd, child_cgroup_fd);
3999e5bd1f7SYiFei Zhu 
400d4a89c1eSYiFei Zhu close_cgroup_fd:
401d4a89c1eSYiFei Zhu 	close(child_cgroup_fd);
402d4a89c1eSYiFei Zhu 	close(parent_cgroup_fd);
403d4a89c1eSYiFei Zhu }
404