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

Reply via email to