Skip to content

Commit 09115c3

Browse files
author
Martin KaFai Lau
committed
Merge branch 'bpf: Expand bpf_cgrp_storage to support cgroup1 non-attach case'
Yafang Shao says: ==================== In the current cgroup1 environment, associating operations between a cgroup and applications in a BPF program requires storing a mapping of cgroup_id to application either in a hash map or maintaining it in userspace. However, by enabling bpf_cgrp_storage for cgroup1, it becomes possible to conveniently store application-specific information in cgroup-local storage and utilize it within BPF programs. Furthermore, enabling this feature for cgroup1 involves minor modifications for the non-attach case, streamlining the process. However, when it comes to enabling this functionality for the cgroup1 attach case, it presents challenges. Therefore, the decision is to focus on enabling it solely for the cgroup1 non-attach case at present. If attempting to attach to a cgroup1 fd, the operation will simply fail with the error code -EBADF. Changes: - RFC -> v1: - Collect acked-by - Avoid unnecessary is_cgroup1 check (Yonghong) - Keep the code patterns consistent (Yonghong) ==================== Signed-off-by: Martin KaFai Lau <[email protected]>
2 parents 1720c42 + a2c6380 commit 09115c3

File tree

7 files changed

+298
-50
lines changed

7 files changed

+298
-50
lines changed

kernel/bpf/bpf_cgrp_storage.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ static void *bpf_cgrp_storage_lookup_elem(struct bpf_map *map, void *key)
8282
int fd;
8383

8484
fd = *(int *)key;
85-
cgroup = cgroup_get_from_fd(fd);
85+
cgroup = cgroup_v1v2_get_from_fd(fd);
8686
if (IS_ERR(cgroup))
8787
return ERR_CAST(cgroup);
8888

@@ -101,7 +101,7 @@ static long bpf_cgrp_storage_update_elem(struct bpf_map *map, void *key,
101101
int fd;
102102

103103
fd = *(int *)key;
104-
cgroup = cgroup_get_from_fd(fd);
104+
cgroup = cgroup_v1v2_get_from_fd(fd);
105105
if (IS_ERR(cgroup))
106106
return PTR_ERR(cgroup);
107107

@@ -131,7 +131,7 @@ static long bpf_cgrp_storage_delete_elem(struct bpf_map *map, void *key)
131131
int err, fd;
132132

133133
fd = *(int *)key;
134-
cgroup = cgroup_get_from_fd(fd);
134+
cgroup = cgroup_v1v2_get_from_fd(fd);
135135
if (IS_ERR(cgroup))
136136
return PTR_ERR(cgroup);
137137

tools/testing/selftests/bpf/cgroup_helpers.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,3 +689,19 @@ int get_cgroup1_hierarchy_id(const char *subsys_name)
689689
fclose(file);
690690
return found ? id : -1;
691691
}
692+
693+
/**
694+
* open_classid() - Open a cgroupv1 net_cls classid
695+
*
696+
* This function expects the cgroup work dir to be already created, as we
697+
* open it here.
698+
*
699+
* On success, it returns the file descriptor. On failure it returns -1.
700+
*/
701+
int open_classid(void)
702+
{
703+
char cgroup_workdir[PATH_MAX + 1];
704+
705+
format_classid_path(cgroup_workdir);
706+
return open(cgroup_workdir, O_RDONLY);
707+
}

tools/testing/selftests/bpf/cgroup_helpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ void cleanup_cgroup_environment(void);
3333
int set_classid(void);
3434
int join_classid(void);
3535
unsigned long long get_classid_cgroup_id(void);
36+
int open_classid(void);
3637

3738
int setup_classid_environment(void);
3839
void cleanup_classid_environment(void);

tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ struct socket_cookie {
1919
__u64 cookie_value;
2020
};
2121

22+
static bool is_cgroup1;
23+
static int target_hid;
24+
25+
#define CGROUP_MODE_SET(skel) \
26+
{ \
27+
skel->bss->is_cgroup1 = is_cgroup1; \
28+
skel->bss->target_hid = target_hid; \
29+
}
30+
31+
static void cgroup_mode_value_init(bool cgroup, int hid)
32+
{
33+
is_cgroup1 = cgroup;
34+
target_hid = hid;
35+
}
36+
2237
static void test_tp_btf(int cgroup_fd)
2338
{
2439
struct cgrp_ls_tp_btf *skel;
@@ -29,6 +44,8 @@ static void test_tp_btf(int cgroup_fd)
2944
if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
3045
return;
3146

47+
CGROUP_MODE_SET(skel);
48+
3249
/* populate a value in map_b */
3350
err = bpf_map_update_elem(bpf_map__fd(skel->maps.map_b), &cgroup_fd, &val1, BPF_ANY);
3451
if (!ASSERT_OK(err, "map_update_elem"))
@@ -130,6 +147,8 @@ static void test_recursion(int cgroup_fd)
130147
if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
131148
return;
132149

150+
CGROUP_MODE_SET(skel);
151+
133152
err = cgrp_ls_recursion__attach(skel);
134153
if (!ASSERT_OK(err, "skel_attach"))
135154
goto out;
@@ -165,6 +184,8 @@ static void test_cgroup_iter_sleepable(int cgroup_fd, __u64 cgroup_id)
165184
if (!ASSERT_OK_PTR(skel, "skel_open"))
166185
return;
167186

187+
CGROUP_MODE_SET(skel);
188+
168189
bpf_program__set_autoload(skel->progs.cgroup_iter, true);
169190
err = cgrp_ls_sleepable__load(skel);
170191
if (!ASSERT_OK(err, "skel_load"))
@@ -202,6 +223,7 @@ static void test_yes_rcu_lock(__u64 cgroup_id)
202223
if (!ASSERT_OK_PTR(skel, "skel_open"))
203224
return;
204225

226+
CGROUP_MODE_SET(skel);
205227
skel->bss->target_pid = syscall(SYS_gettid);
206228

207229
bpf_program__set_autoload(skel->progs.yes_rcu_lock, true);
@@ -229,14 +251,34 @@ static void test_no_rcu_lock(void)
229251
if (!ASSERT_OK_PTR(skel, "skel_open"))
230252
return;
231253

254+
CGROUP_MODE_SET(skel);
255+
232256
bpf_program__set_autoload(skel->progs.no_rcu_lock, true);
233257
err = cgrp_ls_sleepable__load(skel);
234258
ASSERT_ERR(err, "skel_load");
235259

236260
cgrp_ls_sleepable__destroy(skel);
237261
}
238262

239-
void test_cgrp_local_storage(void)
263+
static void test_cgrp1_no_rcu_lock(void)
264+
{
265+
struct cgrp_ls_sleepable *skel;
266+
int err;
267+
268+
skel = cgrp_ls_sleepable__open();
269+
if (!ASSERT_OK_PTR(skel, "skel_open"))
270+
return;
271+
272+
CGROUP_MODE_SET(skel);
273+
274+
bpf_program__set_autoload(skel->progs.cgrp1_no_rcu_lock, true);
275+
err = cgrp_ls_sleepable__load(skel);
276+
ASSERT_OK(err, "skel_load");
277+
278+
cgrp_ls_sleepable__destroy(skel);
279+
}
280+
281+
static void cgrp2_local_storage(void)
240282
{
241283
__u64 cgroup_id;
242284
int cgroup_fd;
@@ -245,6 +287,8 @@ void test_cgrp_local_storage(void)
245287
if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /cgrp_local_storage"))
246288
return;
247289

290+
cgroup_mode_value_init(0, -1);
291+
248292
cgroup_id = get_cgroup_id("/cgrp_local_storage");
249293
if (test__start_subtest("tp_btf"))
250294
test_tp_btf(cgroup_fd);
@@ -263,3 +307,55 @@ void test_cgrp_local_storage(void)
263307

264308
close(cgroup_fd);
265309
}
310+
311+
static void cgrp1_local_storage(void)
312+
{
313+
int cgrp1_fd, cgrp1_hid, cgrp1_id, err;
314+
315+
/* Setup cgroup1 hierarchy */
316+
err = setup_classid_environment();
317+
if (!ASSERT_OK(err, "setup_classid_environment"))
318+
return;
319+
320+
err = join_classid();
321+
if (!ASSERT_OK(err, "join_cgroup1"))
322+
goto cleanup;
323+
324+
cgrp1_fd = open_classid();
325+
if (!ASSERT_GE(cgrp1_fd, 0, "cgroup1 fd"))
326+
goto cleanup;
327+
328+
cgrp1_id = get_classid_cgroup_id();
329+
if (!ASSERT_GE(cgrp1_id, 0, "cgroup1 id"))
330+
goto close_fd;
331+
332+
cgrp1_hid = get_cgroup1_hierarchy_id("net_cls");
333+
if (!ASSERT_GE(cgrp1_hid, 0, "cgroup1 hid"))
334+
goto close_fd;
335+
336+
cgroup_mode_value_init(1, cgrp1_hid);
337+
338+
if (test__start_subtest("cgrp1_tp_btf"))
339+
test_tp_btf(cgrp1_fd);
340+
if (test__start_subtest("cgrp1_recursion"))
341+
test_recursion(cgrp1_fd);
342+
if (test__start_subtest("cgrp1_negative"))
343+
test_negative();
344+
if (test__start_subtest("cgrp1_iter_sleepable"))
345+
test_cgroup_iter_sleepable(cgrp1_fd, cgrp1_id);
346+
if (test__start_subtest("cgrp1_yes_rcu_lock"))
347+
test_yes_rcu_lock(cgrp1_id);
348+
if (test__start_subtest("cgrp1_no_rcu_lock"))
349+
test_cgrp1_no_rcu_lock();
350+
351+
close_fd:
352+
close(cgrp1_fd);
353+
cleanup:
354+
cleanup_classid_environment();
355+
}
356+
357+
void test_cgrp_local_storage(void)
358+
{
359+
cgrp2_local_storage();
360+
cgrp1_local_storage();
361+
}

tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,50 +21,100 @@ struct {
2121
__type(value, long);
2222
} map_b SEC(".maps");
2323

24+
int target_hid = 0;
25+
bool is_cgroup1 = 0;
26+
27+
struct cgroup *bpf_task_get_cgroup1(struct task_struct *task, int hierarchy_id) __ksym;
28+
void bpf_cgroup_release(struct cgroup *cgrp) __ksym;
29+
30+
static void __on_lookup(struct cgroup *cgrp)
31+
{
32+
bpf_cgrp_storage_delete(&map_a, cgrp);
33+
bpf_cgrp_storage_delete(&map_b, cgrp);
34+
}
35+
2436
SEC("fentry/bpf_local_storage_lookup")
2537
int BPF_PROG(on_lookup)
2638
{
2739
struct task_struct *task = bpf_get_current_task_btf();
40+
struct cgroup *cgrp;
41+
42+
if (is_cgroup1) {
43+
cgrp = bpf_task_get_cgroup1(task, target_hid);
44+
if (!cgrp)
45+
return 0;
2846

29-
bpf_cgrp_storage_delete(&map_a, task->cgroups->dfl_cgrp);
30-
bpf_cgrp_storage_delete(&map_b, task->cgroups->dfl_cgrp);
47+
__on_lookup(cgrp);
48+
bpf_cgroup_release(cgrp);
49+
return 0;
50+
}
51+
52+
__on_lookup(task->cgroups->dfl_cgrp);
3153
return 0;
3254
}
3355

34-
SEC("fentry/bpf_local_storage_update")
35-
int BPF_PROG(on_update)
56+
static void __on_update(struct cgroup *cgrp)
3657
{
37-
struct task_struct *task = bpf_get_current_task_btf();
3858
long *ptr;
3959

40-
ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0,
41-
BPF_LOCAL_STORAGE_GET_F_CREATE);
60+
ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE);
4261
if (ptr)
4362
*ptr += 1;
4463

45-
ptr = bpf_cgrp_storage_get(&map_b, task->cgroups->dfl_cgrp, 0,
46-
BPF_LOCAL_STORAGE_GET_F_CREATE);
64+
ptr = bpf_cgrp_storage_get(&map_b, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE);
4765
if (ptr)
4866
*ptr += 1;
67+
}
4968

69+
SEC("fentry/bpf_local_storage_update")
70+
int BPF_PROG(on_update)
71+
{
72+
struct task_struct *task = bpf_get_current_task_btf();
73+
struct cgroup *cgrp;
74+
75+
if (is_cgroup1) {
76+
cgrp = bpf_task_get_cgroup1(task, target_hid);
77+
if (!cgrp)
78+
return 0;
79+
80+
__on_update(cgrp);
81+
bpf_cgroup_release(cgrp);
82+
return 0;
83+
}
84+
85+
__on_update(task->cgroups->dfl_cgrp);
5086
return 0;
5187
}
5288

53-
SEC("tp_btf/sys_enter")
54-
int BPF_PROG(on_enter, struct pt_regs *regs, long id)
89+
static void __on_enter(struct pt_regs *regs, long id, struct cgroup *cgrp)
5590
{
56-
struct task_struct *task;
5791
long *ptr;
5892

59-
task = bpf_get_current_task_btf();
60-
ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0,
61-
BPF_LOCAL_STORAGE_GET_F_CREATE);
93+
ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE);
6294
if (ptr)
6395
*ptr = 200;
6496

65-
ptr = bpf_cgrp_storage_get(&map_b, task->cgroups->dfl_cgrp, 0,
66-
BPF_LOCAL_STORAGE_GET_F_CREATE);
97+
ptr = bpf_cgrp_storage_get(&map_b, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE);
6798
if (ptr)
6899
*ptr = 100;
100+
}
101+
102+
SEC("tp_btf/sys_enter")
103+
int BPF_PROG(on_enter, struct pt_regs *regs, long id)
104+
{
105+
struct task_struct *task = bpf_get_current_task_btf();
106+
struct cgroup *cgrp;
107+
108+
if (is_cgroup1) {
109+
cgrp = bpf_task_get_cgroup1(task, target_hid);
110+
if (!cgrp)
111+
return 0;
112+
113+
__on_enter(regs, id, cgrp);
114+
bpf_cgroup_release(cgrp);
115+
return 0;
116+
}
117+
118+
__on_enter(regs, id, task->cgroups->dfl_cgrp);
69119
return 0;
70120
}

0 commit comments

Comments
 (0)