From: Daniel Wagner <[email protected]> Add yet another cgroup controller for setting a socket option. Obvisouly this should be part of either net_cls or net_prio controller. Consider this only a discussion starter patch.
This patch is for net-next, but it should also apply cleanly to Linus' tree. --- include/linux/cgroup_subsys.h | 6 ++ include/net/sock_cgroup.h | 81 +++++++++++++++++++++ net/Kconfig | 6 ++ net/core/Makefile | 1 + net/core/sock.c | 15 ++++ net/core/sock_cgroup.c | 165 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 274 insertions(+) create mode 100644 include/net/sock_cgroup.h create mode 100644 net/core/sock_cgroup.c diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index dfae957..891a994 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -78,3 +78,9 @@ SUBSYS(hugetlb) #endif /* */ + +#ifdef CONFIG_SOCKCG +SUBSYS(net_sock) +#endif + +/* */ diff --git a/include/net/sock_cgroup.h b/include/net/sock_cgroup.h new file mode 100644 index 0000000..4cdf670 --- /dev/null +++ b/include/net/sock_cgroup.h @@ -0,0 +1,81 @@ +/* + * sock_cgroup.h Socket Control Group + * + * + * Authors: Daniel Wagner <[email protected]> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#ifndef _SOCK_CGROUP_H +#define _SOCK_CGROUP_H +#include <linux/cgroup.h> +#include <linux/hardirq.h> +#include <linux/rcupdate.h> + +#ifdef CONFIG_CGROUPS + +struct sockcg { + struct cgroup_subsys_state css; + __u32 mark; +}; + +#if IS_MODULE(CONFIG_SOCKCG) +extern int net_sock_subsys_id; +#endif + +extern void sock_update_sockcg(struct sock *sk, struct task_struct *task); + +#if IS_BUILTIN(CONFIG_SOCKCG) + +static inline __u32 sockcg_mark_from_task(struct task_struct *p) +{ + struct sockcg *skcg; + __u32 mark; + + rcu_read_lock(); + skcg = container_of(task_subsys_state(p, net_sock_subsys_id), + struct sockcg, css); + mark = skcg->mark; + rcu_read_unlock(); + return mark; +} + +#elif IS_MODULE(CONFIG_SOCKCG) + +static inline __u32 sockcg_mark_from_task(struct task_struct *p) +{ + struct sockcg *skcg; + int subsys_id; + __u32 mark = 0; + + rcu_read_lock(); + subsys_id = rcu_dereference_index_check(net_sock_subsys_id, + rcu_read_lock_held()); + if (subsys_id >= 0) { + skcg = container_of(task_subsys_state(p, subsys_id), + struct sockcg, css); + mark = skcg->mark; + } + rcu_read_unlock(); + return mark; +} + +#else + +static inline __u32 sockcg_mark_from_task(struct task_struct *p) +{ + return 0; +} + +#endif /* CONFIG_SOCKCG */ + +#else /* !CONFIG_CGROUP */ +#define sock_update_sockcg(sk) +#endif /* CONFIG_CGROUP */ + +#endif /* _SOCK_CGROUP_H */ diff --git a/net/Kconfig b/net/Kconfig index 245831b..6d478f0 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -240,6 +240,12 @@ config NETPRIO_CGROUP Cgroup subsystem for use in assigning processes to network priorities on a per-interface basis +config SOCKCG + tristate "Socket cgroup" + depends on CGROUPS + ---help--- + Cgroup subsystem for accounting and limiting socket based resources + config BQL boolean depends on SYSFS diff --git a/net/core/Makefile b/net/core/Makefile index 674641b..df0d27b 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_TRACEPOINTS) += net-traces.o obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o obj-$(CONFIG_NETPRIO_CGROUP) += netprio_cgroup.o +obj-$(CONFIG_SOCKCG) += sock_cgroup.o diff --git a/net/core/sock.c b/net/core/sock.c index 8f67ced..c08c70e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -130,6 +130,7 @@ #include <linux/ipsec.h> #include <net/cls_cgroup.h> #include <net/netprio_cgroup.h> +#include <net/sock_cgroup.h> #include <linux/filter.h> @@ -335,6 +336,10 @@ EXPORT_SYMBOL_GPL(net_cls_subsys_id); int net_prio_subsys_id = -1; EXPORT_SYMBOL_GPL(net_prio_subsys_id); #endif +#if !defined(CONFIG_SOCKCG) +int net_sock_subsys_id = -1; +EXPORT_SYMBOL_GPL(net_sock_subsys_id); +#endif #endif static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) @@ -1243,6 +1248,15 @@ void sock_update_netprioidx(struct sock *sk, struct task_struct *task) sk->sk_cgrp_prioidx = task_netprioidx(task); } EXPORT_SYMBOL_GPL(sock_update_netprioidx); + +void sock_update_sockcg(struct sock *sk, struct task_struct *task) +{ + if (in_interrupt()) + return; + + sk->sk_mark = sockcg_mark_from_task(current); +} +EXPORT_SYMBOL_GPL(sock_update_sockcg); #endif /** @@ -1271,6 +1285,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, sock_update_classid(sk); sock_update_netprioidx(sk, current); + sock_update_sockcg(sk, current); } return sk; diff --git a/net/core/sock_cgroup.c b/net/core/sock_cgroup.c new file mode 100644 index 0000000..f724e0f --- /dev/null +++ b/net/core/sock_cgroup.c @@ -0,0 +1,165 @@ +/* + * net/core/sockcg.c Socket Control Group + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Daniel Wagner <[email protected]> + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/skbuff.h> +#include <linux/cgroup.h> +#include <linux/rcupdate.h> +#include <linux/atomic.h> +#include <linux/fdtable.h> +#include <net/rtnetlink.h> +#include <net/pkt_cls.h> +#include <net/sock.h> +#include <net/sock_cgroup.h> + +static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp); +static void cgrp_destroy(struct cgroup *cgrp); + +static inline struct sockcg *cgrp_sock_state(struct cgroup *cgrp) +{ + return container_of(cgroup_subsys_state(cgrp, net_sock_subsys_id), + struct sockcg, css); +} + +static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp) +{ + struct sockcg *skcg; + + skcg = kzalloc(sizeof(*skcg), GFP_KERNEL); + if (!skcg) + return ERR_PTR(-ENOMEM); + + return &skcg->css; +} + +static void cgrp_destroy(struct cgroup *cgrp) +{ + struct sockcg *skcg; + + skcg = cgrp_sock_state(cgrp); + kfree(skcg); +} + +static u64 read_mark(struct cgroup *cgrp, struct cftype *cft) +{ + return cgrp_sock_state(cgrp)->mark; +} + +static int write_mark(struct cgroup *cgrp, struct cftype *cft, u64 val) +{ + cgrp_sock_state(cgrp)->mark = (u32)val; + + return 0; +} + +void cgrp_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) +{ + struct task_struct *p; + char *tmp = kzalloc(sizeof(char) * PATH_MAX, GFP_KERNEL); + + if (!tmp) { + pr_warn("Unable to attach cgrp due to alloc failure!\n"); + return; + } + + cgroup_taskset_for_each(p, cgrp, tset) { + unsigned int fd; + struct fdtable *fdt; + struct files_struct *files; + + task_lock(p); + files = p->files; + if (!files) { + task_unlock(p); + continue; + } + + rcu_read_lock(); + fdt = files_fdtable(files); + for (fd = 0; fd < fdt->max_fds; fd++) { + char *path; + struct file *file; + struct socket *sock; + unsigned long s; + int rv, err = 0; + + file = fcheck_files(files, fd); + if (!file) + continue; + + path = d_path(&file->f_path, tmp, PAGE_SIZE); + rv = sscanf(path, "socket:[%lu]", &s); + if (rv <= 0) + continue; + + sock = sock_from_file(file, &err); + if (!err) + sock_update_sockcg(sock->sk, p); + } + rcu_read_unlock(); + task_unlock(p); + } + kfree(tmp); +} + +static struct cftype ss_files[] = { + { + .name = "mark", + .read_u64 = read_mark, + .write_u64 = write_mark, + }, +}; + +struct cgroup_subsys net_sock_subsys = { + .name = "net_sock", + .create = cgrp_create, + .destroy = cgrp_destroy, + .attach = cgrp_attach, +#ifdef CONFIG_SOCKCG + .subsys_id = net_sock_subsys_id, +#endif + .base_cftypes = ss_files, + .module = THIS_MODULE +}; + +static int __init init_sockcg(void) +{ + int ret; + + ret = cgroup_load_subsys(&net_sock_subsys); + if (ret) + goto out; +#ifndef CONFIG_SOCKCG + smp_wmb(); + net_sock_subsys_id = net_sock_subsys.subsys_id; +#endif + +out: + return ret; +} + +static void __exit exit_sockcg(void) +{ + cgroup_unload_subsys(&net_sock_subsys); + +#ifndef CONFIG_SOCKCG + net_sock_subsys_id = -1; + synchronize_rcu(); +#endif +} + +module_init(init_sockcg); +module_exit(exit_sockcg); +MODULE_LICENSE("GPL v2"); -- 1.7.12.rc1.16.g05a20c8 _______________________________________________ connman mailing list [email protected] http://lists.connman.net/listinfo/connman
