Loading...
1// SPDX-License-Identifier: GPL-2.0-only
2
3/*
4 * Copyright 2020 Google LLC.
5 */
6
7#include <test_progs.h>
8#include <cgroup_helpers.h>
9#include <network_helpers.h>
10
11#include "progs/cg_storage_multi.h"
12
13#include "cg_storage_multi_egress_only.skel.h"
14#include "cg_storage_multi_isolated.skel.h"
15#include "cg_storage_multi_shared.skel.h"
16
17#define PARENT_CGROUP "/cgroup_storage"
18#define CHILD_CGROUP "/cgroup_storage/child"
19
20static int duration;
21
22static bool assert_storage(struct bpf_map *map, const void *key,
23 struct cgroup_value *expected)
24{
25 struct cgroup_value value;
26 int map_fd;
27
28 map_fd = bpf_map__fd(map);
29
30 if (CHECK(bpf_map_lookup_elem(map_fd, key, &value) < 0,
31 "map-lookup", "errno %d", errno))
32 return true;
33 if (CHECK(memcmp(&value, expected, sizeof(struct cgroup_value)),
34 "assert-storage", "storages differ"))
35 return true;
36
37 return false;
38}
39
40static bool assert_storage_noexist(struct bpf_map *map, const void *key)
41{
42 struct cgroup_value value;
43 int map_fd;
44
45 map_fd = bpf_map__fd(map);
46
47 if (CHECK(bpf_map_lookup_elem(map_fd, key, &value) == 0,
48 "map-lookup", "succeeded, expected ENOENT"))
49 return true;
50 if (CHECK(errno != ENOENT,
51 "map-lookup", "errno %d, expected ENOENT", errno))
52 return true;
53
54 return false;
55}
56
57static bool connect_send(const char *cgroup_path)
58{
59 int server_fd = -1, client_fd = -1;
60 char message[] = "message";
61 bool res = true;
62
63 if (join_cgroup(cgroup_path))
64 goto out_clean;
65
66 server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0);
67 if (server_fd < 0)
68 goto out_clean;
69
70 client_fd = connect_to_fd(server_fd, 0);
71 if (client_fd < 0)
72 goto out_clean;
73
74 if (send(client_fd, &message, sizeof(message), 0) < 0)
75 goto out_clean;
76
77 if (read(server_fd, &message, sizeof(message)) < 0)
78 goto out_clean;
79
80 res = false;
81
82out_clean:
83 close(client_fd);
84 close(server_fd);
85 return res;
86}
87
88static void test_egress_only(int parent_cgroup_fd, int child_cgroup_fd)
89{
90 struct cg_storage_multi_egress_only *obj;
91 struct cgroup_value expected_cgroup_value;
92 struct bpf_cgroup_storage_key key;
93 struct bpf_link *parent_link = NULL, *child_link = NULL;
94 bool err;
95
96 key.attach_type = BPF_CGROUP_INET_EGRESS;
97
98 obj = cg_storage_multi_egress_only__open_and_load();
99 if (CHECK(!obj, "skel-load", "errno %d", errno))
100 return;
101
102 /* Attach to parent cgroup, trigger packet from child.
103 * Assert that there is only one run and in that run the storage is
104 * parent cgroup's storage.
105 * Also assert that child cgroup's storage does not exist
106 */
107 parent_link = bpf_program__attach_cgroup(obj->progs.egress,
108 parent_cgroup_fd);
109 if (!ASSERT_OK_PTR(parent_link, "parent-cg-attach"))
110 goto close_bpf_object;
111 err = connect_send(CHILD_CGROUP);
112 if (CHECK(err, "first-connect-send", "errno %d", errno))
113 goto close_bpf_object;
114 if (CHECK(obj->bss->invocations != 1,
115 "first-invoke", "invocations=%d", obj->bss->invocations))
116 goto close_bpf_object;
117 key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
118 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
119 if (assert_storage(obj->maps.cgroup_storage,
120 &key, &expected_cgroup_value))
121 goto close_bpf_object;
122 key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
123 if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
124 goto close_bpf_object;
125
126 /* Attach to parent and child cgroup, trigger packet from child.
127 * Assert that there are two additional runs, one that run with parent
128 * cgroup's storage and one with child cgroup's storage.
129 */
130 child_link = bpf_program__attach_cgroup(obj->progs.egress,
131 child_cgroup_fd);
132 if (!ASSERT_OK_PTR(child_link, "child-cg-attach"))
133 goto close_bpf_object;
134 err = connect_send(CHILD_CGROUP);
135 if (CHECK(err, "second-connect-send", "errno %d", errno))
136 goto close_bpf_object;
137 if (CHECK(obj->bss->invocations != 3,
138 "second-invoke", "invocations=%d", obj->bss->invocations))
139 goto close_bpf_object;
140 key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
141 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
142 if (assert_storage(obj->maps.cgroup_storage,
143 &key, &expected_cgroup_value))
144 goto close_bpf_object;
145 key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
146 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
147 if (assert_storage(obj->maps.cgroup_storage,
148 &key, &expected_cgroup_value))
149 goto close_bpf_object;
150
151close_bpf_object:
152 bpf_link__destroy(parent_link);
153 bpf_link__destroy(child_link);
154
155 cg_storage_multi_egress_only__destroy(obj);
156}
157
158static void test_isolated(int parent_cgroup_fd, int child_cgroup_fd)
159{
160 struct cg_storage_multi_isolated *obj;
161 struct cgroup_value expected_cgroup_value;
162 struct bpf_cgroup_storage_key key;
163 struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
164 struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
165 struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
166 bool err;
167
168 obj = cg_storage_multi_isolated__open_and_load();
169 if (CHECK(!obj, "skel-load", "errno %d", errno))
170 return;
171
172 /* Attach to parent cgroup, trigger packet from child.
173 * Assert that there is three runs, two with parent cgroup egress and
174 * one with parent cgroup ingress, stored in separate parent storages.
175 * Also assert that child cgroup's storages does not exist
176 */
177 parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
178 parent_cgroup_fd);
179 if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
180 goto close_bpf_object;
181 parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
182 parent_cgroup_fd);
183 if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
184 goto close_bpf_object;
185 parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
186 parent_cgroup_fd);
187 if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
188 goto close_bpf_object;
189 err = connect_send(CHILD_CGROUP);
190 if (CHECK(err, "first-connect-send", "errno %d", errno))
191 goto close_bpf_object;
192 if (CHECK(obj->bss->invocations != 3,
193 "first-invoke", "invocations=%d", obj->bss->invocations))
194 goto close_bpf_object;
195 key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
196 key.attach_type = BPF_CGROUP_INET_EGRESS;
197 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
198 if (assert_storage(obj->maps.cgroup_storage,
199 &key, &expected_cgroup_value))
200 goto close_bpf_object;
201 key.attach_type = BPF_CGROUP_INET_INGRESS;
202 expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
203 if (assert_storage(obj->maps.cgroup_storage,
204 &key, &expected_cgroup_value))
205 goto close_bpf_object;
206 key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
207 key.attach_type = BPF_CGROUP_INET_EGRESS;
208 if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
209 goto close_bpf_object;
210 key.attach_type = BPF_CGROUP_INET_INGRESS;
211 if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
212 goto close_bpf_object;
213
214 /* Attach to parent and child cgroup, trigger packet from child.
215 * Assert that there is six additional runs, parent cgroup egresses and
216 * ingress, child cgroup egresses and ingress.
217 * Assert that egress and ingress storages are separate.
218 */
219 child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
220 child_cgroup_fd);
221 if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
222 goto close_bpf_object;
223 child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
224 child_cgroup_fd);
225 if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
226 goto close_bpf_object;
227 child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
228 child_cgroup_fd);
229 if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
230 goto close_bpf_object;
231 err = connect_send(CHILD_CGROUP);
232 if (CHECK(err, "second-connect-send", "errno %d", errno))
233 goto close_bpf_object;
234 if (CHECK(obj->bss->invocations != 9,
235 "second-invoke", "invocations=%d", obj->bss->invocations))
236 goto close_bpf_object;
237 key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
238 key.attach_type = BPF_CGROUP_INET_EGRESS;
239 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 4 };
240 if (assert_storage(obj->maps.cgroup_storage,
241 &key, &expected_cgroup_value))
242 goto close_bpf_object;
243 key.attach_type = BPF_CGROUP_INET_INGRESS;
244 expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 2 };
245 if (assert_storage(obj->maps.cgroup_storage,
246 &key, &expected_cgroup_value))
247 goto close_bpf_object;
248 key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
249 key.attach_type = BPF_CGROUP_INET_EGRESS;
250 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
251 if (assert_storage(obj->maps.cgroup_storage,
252 &key, &expected_cgroup_value))
253 goto close_bpf_object;
254 key.attach_type = BPF_CGROUP_INET_INGRESS;
255 expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
256 if (assert_storage(obj->maps.cgroup_storage,
257 &key, &expected_cgroup_value))
258 goto close_bpf_object;
259
260close_bpf_object:
261 bpf_link__destroy(parent_egress1_link);
262 bpf_link__destroy(parent_egress2_link);
263 bpf_link__destroy(parent_ingress_link);
264 bpf_link__destroy(child_egress1_link);
265 bpf_link__destroy(child_egress2_link);
266 bpf_link__destroy(child_ingress_link);
267
268 cg_storage_multi_isolated__destroy(obj);
269}
270
271static void test_shared(int parent_cgroup_fd, int child_cgroup_fd)
272{
273 struct cg_storage_multi_shared *obj;
274 struct cgroup_value expected_cgroup_value;
275 __u64 key;
276 struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
277 struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
278 struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
279 bool err;
280
281 obj = cg_storage_multi_shared__open_and_load();
282 if (CHECK(!obj, "skel-load", "errno %d", errno))
283 return;
284
285 /* Attach to parent cgroup, trigger packet from child.
286 * Assert that there is three runs, two with parent cgroup egress and
287 * one with parent cgroup ingress.
288 * Also assert that child cgroup's storage does not exist
289 */
290 parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
291 parent_cgroup_fd);
292 if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
293 goto close_bpf_object;
294 parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
295 parent_cgroup_fd);
296 if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
297 goto close_bpf_object;
298 parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
299 parent_cgroup_fd);
300 if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
301 goto close_bpf_object;
302 err = connect_send(CHILD_CGROUP);
303 if (CHECK(err, "first-connect-send", "errno %d", errno))
304 goto close_bpf_object;
305 if (CHECK(obj->bss->invocations != 3,
306 "first-invoke", "invocations=%d", obj->bss->invocations))
307 goto close_bpf_object;
308 key = get_cgroup_id(PARENT_CGROUP);
309 expected_cgroup_value = (struct cgroup_value) {
310 .egress_pkts = 2,
311 .ingress_pkts = 1,
312 };
313 if (assert_storage(obj->maps.cgroup_storage,
314 &key, &expected_cgroup_value))
315 goto close_bpf_object;
316 key = get_cgroup_id(CHILD_CGROUP);
317 if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
318 goto close_bpf_object;
319
320 /* Attach to parent and child cgroup, trigger packet from child.
321 * Assert that there is six additional runs, parent cgroup egresses and
322 * ingress, child cgroup egresses and ingress.
323 */
324 child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
325 child_cgroup_fd);
326 if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
327 goto close_bpf_object;
328 child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
329 child_cgroup_fd);
330 if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
331 goto close_bpf_object;
332 child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
333 child_cgroup_fd);
334 if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
335 goto close_bpf_object;
336 err = connect_send(CHILD_CGROUP);
337 if (CHECK(err, "second-connect-send", "errno %d", errno))
338 goto close_bpf_object;
339 if (CHECK(obj->bss->invocations != 9,
340 "second-invoke", "invocations=%d", obj->bss->invocations))
341 goto close_bpf_object;
342 key = get_cgroup_id(PARENT_CGROUP);
343 expected_cgroup_value = (struct cgroup_value) {
344 .egress_pkts = 4,
345 .ingress_pkts = 2,
346 };
347 if (assert_storage(obj->maps.cgroup_storage,
348 &key, &expected_cgroup_value))
349 goto close_bpf_object;
350 key = get_cgroup_id(CHILD_CGROUP);
351 expected_cgroup_value = (struct cgroup_value) {
352 .egress_pkts = 2,
353 .ingress_pkts = 1,
354 };
355 if (assert_storage(obj->maps.cgroup_storage,
356 &key, &expected_cgroup_value))
357 goto close_bpf_object;
358
359close_bpf_object:
360 bpf_link__destroy(parent_egress1_link);
361 bpf_link__destroy(parent_egress2_link);
362 bpf_link__destroy(parent_ingress_link);
363 bpf_link__destroy(child_egress1_link);
364 bpf_link__destroy(child_egress2_link);
365 bpf_link__destroy(child_ingress_link);
366
367 cg_storage_multi_shared__destroy(obj);
368}
369
370void serial_test_cg_storage_multi(void)
371{
372 int parent_cgroup_fd = -1, child_cgroup_fd = -1;
373
374 parent_cgroup_fd = test__join_cgroup(PARENT_CGROUP);
375 if (CHECK(parent_cgroup_fd < 0, "cg-create-parent", "errno %d", errno))
376 goto close_cgroup_fd;
377 child_cgroup_fd = create_and_get_cgroup(CHILD_CGROUP);
378 if (CHECK(child_cgroup_fd < 0, "cg-create-child", "errno %d", errno))
379 goto close_cgroup_fd;
380
381 if (test__start_subtest("egress_only"))
382 test_egress_only(parent_cgroup_fd, child_cgroup_fd);
383
384 if (test__start_subtest("isolated"))
385 test_isolated(parent_cgroup_fd, child_cgroup_fd);
386
387 if (test__start_subtest("shared"))
388 test_shared(parent_cgroup_fd, child_cgroup_fd);
389
390close_cgroup_fd:
391 close(child_cgroup_fd);
392 close(parent_cgroup_fd);
393}
1// SPDX-License-Identifier: GPL-2.0-only
2
3/*
4 * Copyright 2020 Google LLC.
5 */
6
7#include <test_progs.h>
8#include <cgroup_helpers.h>
9#include <network_helpers.h>
10
11#include "progs/cg_storage_multi.h"
12
13#include "cg_storage_multi_egress_only.skel.h"
14#include "cg_storage_multi_isolated.skel.h"
15#include "cg_storage_multi_shared.skel.h"
16
17#define PARENT_CGROUP "/cgroup_storage"
18#define CHILD_CGROUP "/cgroup_storage/child"
19
20static int duration;
21
22static bool assert_storage(struct bpf_map *map, const void *key,
23 struct cgroup_value *expected)
24{
25 struct cgroup_value value;
26 int map_fd;
27
28 map_fd = bpf_map__fd(map);
29
30 if (CHECK(bpf_map_lookup_elem(map_fd, key, &value) < 0,
31 "map-lookup", "errno %d", errno))
32 return true;
33 if (CHECK(memcmp(&value, expected, sizeof(struct cgroup_value)),
34 "assert-storage", "storages differ"))
35 return true;
36
37 return false;
38}
39
40static bool assert_storage_noexist(struct bpf_map *map, const void *key)
41{
42 struct cgroup_value value;
43 int map_fd;
44
45 map_fd = bpf_map__fd(map);
46
47 if (CHECK(bpf_map_lookup_elem(map_fd, key, &value) == 0,
48 "map-lookup", "succeeded, expected ENOENT"))
49 return true;
50 if (CHECK(errno != ENOENT,
51 "map-lookup", "errno %d, expected ENOENT", errno))
52 return true;
53
54 return false;
55}
56
57static bool connect_send(const char *cgroup_path)
58{
59 bool res = true;
60 int server_fd = -1, client_fd = -1;
61
62 if (join_cgroup(cgroup_path))
63 goto out_clean;
64
65 server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0);
66 if (server_fd < 0)
67 goto out_clean;
68
69 client_fd = connect_to_fd(server_fd, 0);
70 if (client_fd < 0)
71 goto out_clean;
72
73 if (send(client_fd, "message", strlen("message"), 0) < 0)
74 goto out_clean;
75
76 res = false;
77
78out_clean:
79 close(client_fd);
80 close(server_fd);
81 return res;
82}
83
84static void test_egress_only(int parent_cgroup_fd, int child_cgroup_fd)
85{
86 struct cg_storage_multi_egress_only *obj;
87 struct cgroup_value expected_cgroup_value;
88 struct bpf_cgroup_storage_key key;
89 struct bpf_link *parent_link = NULL, *child_link = NULL;
90 bool err;
91
92 key.attach_type = BPF_CGROUP_INET_EGRESS;
93
94 obj = cg_storage_multi_egress_only__open_and_load();
95 if (CHECK(!obj, "skel-load", "errno %d", errno))
96 return;
97
98 /* Attach to parent cgroup, trigger packet from child.
99 * Assert that there is only one run and in that run the storage is
100 * parent cgroup's storage.
101 * Also assert that child cgroup's storage does not exist
102 */
103 parent_link = bpf_program__attach_cgroup(obj->progs.egress,
104 parent_cgroup_fd);
105 if (!ASSERT_OK_PTR(parent_link, "parent-cg-attach"))
106 goto close_bpf_object;
107 err = connect_send(CHILD_CGROUP);
108 if (CHECK(err, "first-connect-send", "errno %d", errno))
109 goto close_bpf_object;
110 if (CHECK(obj->bss->invocations != 1,
111 "first-invoke", "invocations=%d", obj->bss->invocations))
112 goto close_bpf_object;
113 key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
114 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
115 if (assert_storage(obj->maps.cgroup_storage,
116 &key, &expected_cgroup_value))
117 goto close_bpf_object;
118 key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
119 if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
120 goto close_bpf_object;
121
122 /* Attach to parent and child cgroup, trigger packet from child.
123 * Assert that there are two additional runs, one that run with parent
124 * cgroup's storage and one with child cgroup's storage.
125 */
126 child_link = bpf_program__attach_cgroup(obj->progs.egress,
127 child_cgroup_fd);
128 if (!ASSERT_OK_PTR(child_link, "child-cg-attach"))
129 goto close_bpf_object;
130 err = connect_send(CHILD_CGROUP);
131 if (CHECK(err, "second-connect-send", "errno %d", errno))
132 goto close_bpf_object;
133 if (CHECK(obj->bss->invocations != 3,
134 "second-invoke", "invocations=%d", obj->bss->invocations))
135 goto close_bpf_object;
136 key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
137 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
138 if (assert_storage(obj->maps.cgroup_storage,
139 &key, &expected_cgroup_value))
140 goto close_bpf_object;
141 key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
142 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
143 if (assert_storage(obj->maps.cgroup_storage,
144 &key, &expected_cgroup_value))
145 goto close_bpf_object;
146
147close_bpf_object:
148 bpf_link__destroy(parent_link);
149 bpf_link__destroy(child_link);
150
151 cg_storage_multi_egress_only__destroy(obj);
152}
153
154static void test_isolated(int parent_cgroup_fd, int child_cgroup_fd)
155{
156 struct cg_storage_multi_isolated *obj;
157 struct cgroup_value expected_cgroup_value;
158 struct bpf_cgroup_storage_key key;
159 struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
160 struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
161 struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
162 bool err;
163
164 obj = cg_storage_multi_isolated__open_and_load();
165 if (CHECK(!obj, "skel-load", "errno %d", errno))
166 return;
167
168 /* Attach to parent cgroup, trigger packet from child.
169 * Assert that there is three runs, two with parent cgroup egress and
170 * one with parent cgroup ingress, stored in separate parent storages.
171 * Also assert that child cgroup's storages does not exist
172 */
173 parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
174 parent_cgroup_fd);
175 if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
176 goto close_bpf_object;
177 parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
178 parent_cgroup_fd);
179 if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
180 goto close_bpf_object;
181 parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
182 parent_cgroup_fd);
183 if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
184 goto close_bpf_object;
185 err = connect_send(CHILD_CGROUP);
186 if (CHECK(err, "first-connect-send", "errno %d", errno))
187 goto close_bpf_object;
188 if (CHECK(obj->bss->invocations != 3,
189 "first-invoke", "invocations=%d", obj->bss->invocations))
190 goto close_bpf_object;
191 key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
192 key.attach_type = BPF_CGROUP_INET_EGRESS;
193 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
194 if (assert_storage(obj->maps.cgroup_storage,
195 &key, &expected_cgroup_value))
196 goto close_bpf_object;
197 key.attach_type = BPF_CGROUP_INET_INGRESS;
198 expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
199 if (assert_storage(obj->maps.cgroup_storage,
200 &key, &expected_cgroup_value))
201 goto close_bpf_object;
202 key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
203 key.attach_type = BPF_CGROUP_INET_EGRESS;
204 if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
205 goto close_bpf_object;
206 key.attach_type = BPF_CGROUP_INET_INGRESS;
207 if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
208 goto close_bpf_object;
209
210 /* Attach to parent and child cgroup, trigger packet from child.
211 * Assert that there is six additional runs, parent cgroup egresses and
212 * ingress, child cgroup egresses and ingress.
213 * Assert that egree and ingress storages are separate.
214 */
215 child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
216 child_cgroup_fd);
217 if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
218 goto close_bpf_object;
219 child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
220 child_cgroup_fd);
221 if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
222 goto close_bpf_object;
223 child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
224 child_cgroup_fd);
225 if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
226 goto close_bpf_object;
227 err = connect_send(CHILD_CGROUP);
228 if (CHECK(err, "second-connect-send", "errno %d", errno))
229 goto close_bpf_object;
230 if (CHECK(obj->bss->invocations != 9,
231 "second-invoke", "invocations=%d", obj->bss->invocations))
232 goto close_bpf_object;
233 key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
234 key.attach_type = BPF_CGROUP_INET_EGRESS;
235 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 4 };
236 if (assert_storage(obj->maps.cgroup_storage,
237 &key, &expected_cgroup_value))
238 goto close_bpf_object;
239 key.attach_type = BPF_CGROUP_INET_INGRESS;
240 expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 2 };
241 if (assert_storage(obj->maps.cgroup_storage,
242 &key, &expected_cgroup_value))
243 goto close_bpf_object;
244 key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
245 key.attach_type = BPF_CGROUP_INET_EGRESS;
246 expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
247 if (assert_storage(obj->maps.cgroup_storage,
248 &key, &expected_cgroup_value))
249 goto close_bpf_object;
250 key.attach_type = BPF_CGROUP_INET_INGRESS;
251 expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
252 if (assert_storage(obj->maps.cgroup_storage,
253 &key, &expected_cgroup_value))
254 goto close_bpf_object;
255
256close_bpf_object:
257 bpf_link__destroy(parent_egress1_link);
258 bpf_link__destroy(parent_egress2_link);
259 bpf_link__destroy(parent_ingress_link);
260 bpf_link__destroy(child_egress1_link);
261 bpf_link__destroy(child_egress2_link);
262 bpf_link__destroy(child_ingress_link);
263
264 cg_storage_multi_isolated__destroy(obj);
265}
266
267static void test_shared(int parent_cgroup_fd, int child_cgroup_fd)
268{
269 struct cg_storage_multi_shared *obj;
270 struct cgroup_value expected_cgroup_value;
271 __u64 key;
272 struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
273 struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
274 struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
275 bool err;
276
277 obj = cg_storage_multi_shared__open_and_load();
278 if (CHECK(!obj, "skel-load", "errno %d", errno))
279 return;
280
281 /* Attach to parent cgroup, trigger packet from child.
282 * Assert that there is three runs, two with parent cgroup egress and
283 * one with parent cgroup ingress.
284 * Also assert that child cgroup's storage does not exist
285 */
286 parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
287 parent_cgroup_fd);
288 if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
289 goto close_bpf_object;
290 parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
291 parent_cgroup_fd);
292 if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
293 goto close_bpf_object;
294 parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
295 parent_cgroup_fd);
296 if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
297 goto close_bpf_object;
298 err = connect_send(CHILD_CGROUP);
299 if (CHECK(err, "first-connect-send", "errno %d", errno))
300 goto close_bpf_object;
301 if (CHECK(obj->bss->invocations != 3,
302 "first-invoke", "invocations=%d", obj->bss->invocations))
303 goto close_bpf_object;
304 key = get_cgroup_id(PARENT_CGROUP);
305 expected_cgroup_value = (struct cgroup_value) {
306 .egress_pkts = 2,
307 .ingress_pkts = 1,
308 };
309 if (assert_storage(obj->maps.cgroup_storage,
310 &key, &expected_cgroup_value))
311 goto close_bpf_object;
312 key = get_cgroup_id(CHILD_CGROUP);
313 if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
314 goto close_bpf_object;
315
316 /* Attach to parent and child cgroup, trigger packet from child.
317 * Assert that there is six additional runs, parent cgroup egresses and
318 * ingress, child cgroup egresses and ingress.
319 */
320 child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
321 child_cgroup_fd);
322 if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
323 goto close_bpf_object;
324 child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
325 child_cgroup_fd);
326 if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
327 goto close_bpf_object;
328 child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
329 child_cgroup_fd);
330 if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
331 goto close_bpf_object;
332 err = connect_send(CHILD_CGROUP);
333 if (CHECK(err, "second-connect-send", "errno %d", errno))
334 goto close_bpf_object;
335 if (CHECK(obj->bss->invocations != 9,
336 "second-invoke", "invocations=%d", obj->bss->invocations))
337 goto close_bpf_object;
338 key = get_cgroup_id(PARENT_CGROUP);
339 expected_cgroup_value = (struct cgroup_value) {
340 .egress_pkts = 4,
341 .ingress_pkts = 2,
342 };
343 if (assert_storage(obj->maps.cgroup_storage,
344 &key, &expected_cgroup_value))
345 goto close_bpf_object;
346 key = get_cgroup_id(CHILD_CGROUP);
347 expected_cgroup_value = (struct cgroup_value) {
348 .egress_pkts = 2,
349 .ingress_pkts = 1,
350 };
351 if (assert_storage(obj->maps.cgroup_storage,
352 &key, &expected_cgroup_value))
353 goto close_bpf_object;
354
355close_bpf_object:
356 bpf_link__destroy(parent_egress1_link);
357 bpf_link__destroy(parent_egress2_link);
358 bpf_link__destroy(parent_ingress_link);
359 bpf_link__destroy(child_egress1_link);
360 bpf_link__destroy(child_egress2_link);
361 bpf_link__destroy(child_ingress_link);
362
363 cg_storage_multi_shared__destroy(obj);
364}
365
366void serial_test_cg_storage_multi(void)
367{
368 int parent_cgroup_fd = -1, child_cgroup_fd = -1;
369
370 parent_cgroup_fd = test__join_cgroup(PARENT_CGROUP);
371 if (CHECK(parent_cgroup_fd < 0, "cg-create-parent", "errno %d", errno))
372 goto close_cgroup_fd;
373 child_cgroup_fd = create_and_get_cgroup(CHILD_CGROUP);
374 if (CHECK(child_cgroup_fd < 0, "cg-create-child", "errno %d", errno))
375 goto close_cgroup_fd;
376
377 if (test__start_subtest("egress_only"))
378 test_egress_only(parent_cgroup_fd, child_cgroup_fd);
379
380 if (test__start_subtest("isolated"))
381 test_isolated(parent_cgroup_fd, child_cgroup_fd);
382
383 if (test__start_subtest("shared"))
384 test_shared(parent_cgroup_fd, child_cgroup_fd);
385
386close_cgroup_fd:
387 close(child_cgroup_fd);
388 close(parent_cgroup_fd);
389}