xref: /openbmc/linux/net/core/netclassid_cgroup.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2fe1217c4SDaniel Borkmann /*
3fe1217c4SDaniel Borkmann  * net/core/netclassid_cgroup.c	Classid Cgroupfs Handling
4fe1217c4SDaniel Borkmann  *
5fe1217c4SDaniel Borkmann  * Authors:	Thomas Graf <tgraf@suug.ch>
6fe1217c4SDaniel Borkmann  */
7fe1217c4SDaniel Borkmann 
8fe1217c4SDaniel Borkmann #include <linux/slab.h>
9fe1217c4SDaniel Borkmann #include <linux/cgroup.h>
10fe1217c4SDaniel Borkmann #include <linux/fdtable.h>
11f719ff9bSIngo Molnar #include <linux/sched/task.h>
12f719ff9bSIngo Molnar 
13fe1217c4SDaniel Borkmann #include <net/cls_cgroup.h>
14fe1217c4SDaniel Borkmann #include <net/sock.h>
15fe1217c4SDaniel Borkmann 
css_cls_state(struct cgroup_subsys_state * css)16fe1217c4SDaniel Borkmann static inline struct cgroup_cls_state *css_cls_state(struct cgroup_subsys_state *css)
17fe1217c4SDaniel Borkmann {
18fe1217c4SDaniel Borkmann 	return css ? container_of(css, struct cgroup_cls_state, css) : NULL;
19fe1217c4SDaniel Borkmann }
20fe1217c4SDaniel Borkmann 
task_cls_state(struct task_struct * p)21fe1217c4SDaniel Borkmann struct cgroup_cls_state *task_cls_state(struct task_struct *p)
22fe1217c4SDaniel Borkmann {
23cc9f4daaSKonstantin Khlebnikov 	return css_cls_state(task_css_check(p, net_cls_cgrp_id,
24cc9f4daaSKonstantin Khlebnikov 					    rcu_read_lock_bh_held()));
25fe1217c4SDaniel Borkmann }
26fe1217c4SDaniel Borkmann EXPORT_SYMBOL_GPL(task_cls_state);
27fe1217c4SDaniel Borkmann 
28fe1217c4SDaniel Borkmann static struct cgroup_subsys_state *
cgrp_css_alloc(struct cgroup_subsys_state * parent_css)29fe1217c4SDaniel Borkmann cgrp_css_alloc(struct cgroup_subsys_state *parent_css)
30fe1217c4SDaniel Borkmann {
31fe1217c4SDaniel Borkmann 	struct cgroup_cls_state *cs;
32fe1217c4SDaniel Borkmann 
33fe1217c4SDaniel Borkmann 	cs = kzalloc(sizeof(*cs), GFP_KERNEL);
34fe1217c4SDaniel Borkmann 	if (!cs)
35fe1217c4SDaniel Borkmann 		return ERR_PTR(-ENOMEM);
36fe1217c4SDaniel Borkmann 
37fe1217c4SDaniel Borkmann 	return &cs->css;
38fe1217c4SDaniel Borkmann }
39fe1217c4SDaniel Borkmann 
cgrp_css_online(struct cgroup_subsys_state * css)40fe1217c4SDaniel Borkmann static int cgrp_css_online(struct cgroup_subsys_state *css)
41fe1217c4SDaniel Borkmann {
42fe1217c4SDaniel Borkmann 	struct cgroup_cls_state *cs = css_cls_state(css);
435c9d535bSTejun Heo 	struct cgroup_cls_state *parent = css_cls_state(css->parent);
44fe1217c4SDaniel Borkmann 
45fe1217c4SDaniel Borkmann 	if (parent)
46fe1217c4SDaniel Borkmann 		cs->classid = parent->classid;
47fe1217c4SDaniel Borkmann 
48fe1217c4SDaniel Borkmann 	return 0;
49fe1217c4SDaniel Borkmann }
50fe1217c4SDaniel Borkmann 
cgrp_css_free(struct cgroup_subsys_state * css)51fe1217c4SDaniel Borkmann static void cgrp_css_free(struct cgroup_subsys_state *css)
52fe1217c4SDaniel Borkmann {
53fe1217c4SDaniel Borkmann 	kfree(css_cls_state(css));
54fe1217c4SDaniel Borkmann }
55fe1217c4SDaniel Borkmann 
56018d26fcSDmitry Yakunin /*
57018d26fcSDmitry Yakunin  * To avoid freezing of sockets creation for tasks with big number of threads
58018d26fcSDmitry Yakunin  * and opened sockets lets release file_lock every 1000 iterated descriptors.
59018d26fcSDmitry Yakunin  * New sockets will already have been created with new classid.
60018d26fcSDmitry Yakunin  */
61018d26fcSDmitry Yakunin 
62018d26fcSDmitry Yakunin struct update_classid_context {
63018d26fcSDmitry Yakunin 	u32 classid;
64018d26fcSDmitry Yakunin 	unsigned int batch;
65018d26fcSDmitry Yakunin };
66018d26fcSDmitry Yakunin 
67018d26fcSDmitry Yakunin #define UPDATE_CLASSID_BATCH 1000
68018d26fcSDmitry Yakunin 
update_classid_sock(const void * v,struct file * file,unsigned int n)69*3177d7bbSXin Gao static int update_classid_sock(const void *v, struct file *file, unsigned int n)
70fe1217c4SDaniel Borkmann {
71018d26fcSDmitry Yakunin 	struct update_classid_context *ctx = (void *)v;
72dba4a925SFlorent Revest 	struct socket *sock = sock_from_file(file);
73fe1217c4SDaniel Borkmann 
748520e224SDaniel Borkmann 	if (sock)
75018d26fcSDmitry Yakunin 		sock_cgroup_set_classid(&sock->sk->sk_cgrp_data, ctx->classid);
76018d26fcSDmitry Yakunin 	if (--ctx->batch == 0) {
77018d26fcSDmitry Yakunin 		ctx->batch = UPDATE_CLASSID_BATCH;
78018d26fcSDmitry Yakunin 		return n + 1;
79018d26fcSDmitry Yakunin 	}
80fe1217c4SDaniel Borkmann 	return 0;
81fe1217c4SDaniel Borkmann }
82fe1217c4SDaniel Borkmann 
update_classid_task(struct task_struct * p,u32 classid)83018d26fcSDmitry Yakunin static void update_classid_task(struct task_struct *p, u32 classid)
84018d26fcSDmitry Yakunin {
85018d26fcSDmitry Yakunin 	struct update_classid_context ctx = {
86018d26fcSDmitry Yakunin 		.classid = classid,
87018d26fcSDmitry Yakunin 		.batch = UPDATE_CLASSID_BATCH
88018d26fcSDmitry Yakunin 	};
89018d26fcSDmitry Yakunin 	unsigned int fd = 0;
90018d26fcSDmitry Yakunin 
91018d26fcSDmitry Yakunin 	do {
92018d26fcSDmitry Yakunin 		task_lock(p);
93018d26fcSDmitry Yakunin 		fd = iterate_fd(p->files, fd, update_classid_sock, &ctx);
94018d26fcSDmitry Yakunin 		task_unlock(p);
95018d26fcSDmitry Yakunin 		cond_resched();
96018d26fcSDmitry Yakunin 	} while (fd);
97018d26fcSDmitry Yakunin }
98018d26fcSDmitry Yakunin 
cgrp_attach(struct cgroup_taskset * tset)990b98f0c0STejun Heo static void cgrp_attach(struct cgroup_taskset *tset)
100fe1217c4SDaniel Borkmann {
1010b98f0c0STejun Heo 	struct cgroup_subsys_state *css;
102a05d4fd9STejun Heo 	struct task_struct *p;
1030b98f0c0STejun Heo 
104a05d4fd9STejun Heo 	cgroup_taskset_for_each(p, css, tset) {
105018d26fcSDmitry Yakunin 		update_classid_task(p, css_cls_state(css)->classid);
106a05d4fd9STejun Heo 	}
107fe1217c4SDaniel Borkmann }
108fe1217c4SDaniel Borkmann 
read_classid(struct cgroup_subsys_state * css,struct cftype * cft)109fe1217c4SDaniel Borkmann static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft)
110fe1217c4SDaniel Borkmann {
111fe1217c4SDaniel Borkmann 	return css_cls_state(css)->classid;
112fe1217c4SDaniel Borkmann }
113fe1217c4SDaniel Borkmann 
write_classid(struct cgroup_subsys_state * css,struct cftype * cft,u64 value)114fe1217c4SDaniel Borkmann static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft,
115fe1217c4SDaniel Borkmann 			 u64 value)
116fe1217c4SDaniel Borkmann {
1173b13758fSNina Schiff 	struct cgroup_cls_state *cs = css_cls_state(css);
118a05d4fd9STejun Heo 	struct css_task_iter it;
119a05d4fd9STejun Heo 	struct task_struct *p;
120fe1217c4SDaniel Borkmann 
1213b13758fSNina Schiff 	cs->classid = (u32)value;
1223b13758fSNina Schiff 
123bc2fb7edSTejun Heo 	css_task_iter_start(css, 0, &it);
124526f3d96SJiri Slaby 	while ((p = css_task_iter_next(&it)))
125018d26fcSDmitry Yakunin 		update_classid_task(p, cs->classid);
126a05d4fd9STejun Heo 	css_task_iter_end(&it);
127a05d4fd9STejun Heo 
128fe1217c4SDaniel Borkmann 	return 0;
129fe1217c4SDaniel Borkmann }
130fe1217c4SDaniel Borkmann 
131fe1217c4SDaniel Borkmann static struct cftype ss_files[] = {
132fe1217c4SDaniel Borkmann 	{
133fe1217c4SDaniel Borkmann 		.name		= "classid",
134fe1217c4SDaniel Borkmann 		.read_u64	= read_classid,
135fe1217c4SDaniel Borkmann 		.write_u64	= write_classid,
136fe1217c4SDaniel Borkmann 	},
137fe1217c4SDaniel Borkmann 	{ }	/* terminate */
138fe1217c4SDaniel Borkmann };
139fe1217c4SDaniel Borkmann 
140073219e9STejun Heo struct cgroup_subsys net_cls_cgrp_subsys = {
141fe1217c4SDaniel Borkmann 	.css_alloc		= cgrp_css_alloc,
142fe1217c4SDaniel Borkmann 	.css_online		= cgrp_css_online,
143fe1217c4SDaniel Borkmann 	.css_free		= cgrp_css_free,
144fe1217c4SDaniel Borkmann 	.attach			= cgrp_attach,
1455577964eSTejun Heo 	.legacy_cftypes		= ss_files,
146fe1217c4SDaniel Borkmann };
147