diff options
-rw-r--r-- | include/net/cls_cgroup.h | 63 | ||||
-rw-r--r-- | include/net/sock.h | 10 | ||||
-rw-r--r-- | net/core/sock.c | 18 | ||||
-rw-r--r-- | net/sched/cls_cgroup.c | 50 | ||||
-rw-r--r-- | net/socket.c | 9 |
5 files changed, 133 insertions, 17 deletions
diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h new file mode 100644 index 000000000000..ef2df1475b51 --- /dev/null +++ b/include/net/cls_cgroup.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * cls_cgroup.h Control Group Classifier | ||
3 | * | ||
4 | * Authors: Thomas Graf <tgraf@suug.ch> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the Free | ||
8 | * Software Foundation; either version 2 of the License, or (at your option) | ||
9 | * any later version. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #ifndef _NET_CLS_CGROUP_H | ||
14 | #define _NET_CLS_CGROUP_H | ||
15 | |||
16 | #include <linux/cgroup.h> | ||
17 | #include <linux/hardirq.h> | ||
18 | #include <linux/rcupdate.h> | ||
19 | |||
20 | #ifdef CONFIG_CGROUPS | ||
21 | struct cgroup_cls_state | ||
22 | { | ||
23 | struct cgroup_subsys_state css; | ||
24 | u32 classid; | ||
25 | }; | ||
26 | |||
27 | #ifdef CONFIG_NET_CLS_CGROUP | ||
28 | static inline u32 task_cls_classid(struct task_struct *p) | ||
29 | { | ||
30 | if (in_interrupt()) | ||
31 | return 0; | ||
32 | |||
33 | return container_of(task_subsys_state(p, net_cls_subsys_id), | ||
34 | struct cgroup_cls_state, css).classid; | ||
35 | } | ||
36 | #else | ||
37 | extern int net_cls_subsys_id; | ||
38 | |||
39 | static inline u32 task_cls_classid(struct task_struct *p) | ||
40 | { | ||
41 | int id; | ||
42 | u32 classid; | ||
43 | |||
44 | if (in_interrupt()) | ||
45 | return 0; | ||
46 | |||
47 | rcu_read_lock(); | ||
48 | id = rcu_dereference(net_cls_subsys_id); | ||
49 | if (id >= 0) | ||
50 | classid = container_of(task_subsys_state(p, id), | ||
51 | struct cgroup_cls_state, css)->classid; | ||
52 | rcu_read_unlock(); | ||
53 | |||
54 | return classid; | ||
55 | } | ||
56 | #endif | ||
57 | #else | ||
58 | static inline u32 task_cls_classid(struct task_struct *p) | ||
59 | { | ||
60 | return 0; | ||
61 | } | ||
62 | #endif | ||
63 | #endif /* _NET_CLS_CGROUP_H */ | ||
diff --git a/include/net/sock.h b/include/net/sock.h index 5697caf8cc76..d24f382cb712 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -312,7 +312,7 @@ struct sock { | |||
312 | void *sk_security; | 312 | void *sk_security; |
313 | #endif | 313 | #endif |
314 | __u32 sk_mark; | 314 | __u32 sk_mark; |
315 | /* XXX 4 bytes hole on 64 bit */ | 315 | u32 sk_classid; |
316 | void (*sk_state_change)(struct sock *sk); | 316 | void (*sk_state_change)(struct sock *sk); |
317 | void (*sk_data_ready)(struct sock *sk, int bytes); | 317 | void (*sk_data_ready)(struct sock *sk, int bytes); |
318 | void (*sk_write_space)(struct sock *sk); | 318 | void (*sk_write_space)(struct sock *sk); |
@@ -1074,6 +1074,14 @@ extern void *sock_kmalloc(struct sock *sk, int size, | |||
1074 | extern void sock_kfree_s(struct sock *sk, void *mem, int size); | 1074 | extern void sock_kfree_s(struct sock *sk, void *mem, int size); |
1075 | extern void sk_send_sigurg(struct sock *sk); | 1075 | extern void sk_send_sigurg(struct sock *sk); |
1076 | 1076 | ||
1077 | #ifdef CONFIG_CGROUPS | ||
1078 | extern void sock_update_classid(struct sock *sk); | ||
1079 | #else | ||
1080 | static inline void sock_update_classid(struct sock *sk) | ||
1081 | { | ||
1082 | } | ||
1083 | #endif | ||
1084 | |||
1077 | /* | 1085 | /* |
1078 | * Functions to fill in entries in struct proto_ops when a protocol | 1086 | * Functions to fill in entries in struct proto_ops when a protocol |
1079 | * does not implement a particular function. | 1087 | * does not implement a particular function. |
diff --git a/net/core/sock.c b/net/core/sock.c index bf88a167c8f2..a05ae7f9771e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -123,6 +123,7 @@ | |||
123 | #include <linux/net_tstamp.h> | 123 | #include <linux/net_tstamp.h> |
124 | #include <net/xfrm.h> | 124 | #include <net/xfrm.h> |
125 | #include <linux/ipsec.h> | 125 | #include <linux/ipsec.h> |
126 | #include <net/cls_cgroup.h> | ||
126 | 127 | ||
127 | #include <linux/filter.h> | 128 | #include <linux/filter.h> |
128 | 129 | ||
@@ -217,6 +218,11 @@ __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX; | |||
217 | int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512); | 218 | int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512); |
218 | EXPORT_SYMBOL(sysctl_optmem_max); | 219 | EXPORT_SYMBOL(sysctl_optmem_max); |
219 | 220 | ||
221 | #if defined(CONFIG_CGROUPS) && !defined(CONFIG_NET_CLS_CGROUP) | ||
222 | int net_cls_subsys_id = -1; | ||
223 | EXPORT_SYMBOL_GPL(net_cls_subsys_id); | ||
224 | #endif | ||
225 | |||
220 | static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) | 226 | static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) |
221 | { | 227 | { |
222 | struct timeval tv; | 228 | struct timeval tv; |
@@ -1050,6 +1056,16 @@ static void sk_prot_free(struct proto *prot, struct sock *sk) | |||
1050 | module_put(owner); | 1056 | module_put(owner); |
1051 | } | 1057 | } |
1052 | 1058 | ||
1059 | #ifdef CONFIG_CGROUPS | ||
1060 | void sock_update_classid(struct sock *sk) | ||
1061 | { | ||
1062 | u32 classid = task_cls_classid(current); | ||
1063 | |||
1064 | if (classid && classid != sk->sk_classid) | ||
1065 | sk->sk_classid = classid; | ||
1066 | } | ||
1067 | #endif | ||
1068 | |||
1053 | /** | 1069 | /** |
1054 | * sk_alloc - All socket objects are allocated here | 1070 | * sk_alloc - All socket objects are allocated here |
1055 | * @net: the applicable net namespace | 1071 | * @net: the applicable net namespace |
@@ -1073,6 +1089,8 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, | |||
1073 | sock_lock_init(sk); | 1089 | sock_lock_init(sk); |
1074 | sock_net_set(sk, get_net(net)); | 1090 | sock_net_set(sk, get_net(net)); |
1075 | atomic_set(&sk->sk_wmem_alloc, 1); | 1091 | atomic_set(&sk->sk_wmem_alloc, 1); |
1092 | |||
1093 | sock_update_classid(sk); | ||
1076 | } | 1094 | } |
1077 | 1095 | ||
1078 | return sk; | 1096 | return sk; |
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index 221180384fd7..78ef2c5e130b 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c | |||
@@ -16,14 +16,11 @@ | |||
16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
17 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
18 | #include <linux/cgroup.h> | 18 | #include <linux/cgroup.h> |
19 | #include <linux/rcupdate.h> | ||
19 | #include <net/rtnetlink.h> | 20 | #include <net/rtnetlink.h> |
20 | #include <net/pkt_cls.h> | 21 | #include <net/pkt_cls.h> |
21 | 22 | #include <net/sock.h> | |
22 | struct cgroup_cls_state | 23 | #include <net/cls_cgroup.h> |
23 | { | ||
24 | struct cgroup_subsys_state css; | ||
25 | u32 classid; | ||
26 | }; | ||
27 | 24 | ||
28 | static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, | 25 | static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, |
29 | struct cgroup *cgrp); | 26 | struct cgroup *cgrp); |
@@ -112,6 +109,10 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp, | |||
112 | struct cls_cgroup_head *head = tp->root; | 109 | struct cls_cgroup_head *head = tp->root; |
113 | u32 classid; | 110 | u32 classid; |
114 | 111 | ||
112 | rcu_read_lock(); | ||
113 | classid = task_cls_state(current)->classid; | ||
114 | rcu_read_unlock(); | ||
115 | |||
115 | /* | 116 | /* |
116 | * Due to the nature of the classifier it is required to ignore all | 117 | * Due to the nature of the classifier it is required to ignore all |
117 | * packets originating from softirq context as accessing `current' | 118 | * packets originating from softirq context as accessing `current' |
@@ -122,12 +123,12 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp, | |||
122 | * calls by looking at the number of nested bh disable calls because | 123 | * calls by looking at the number of nested bh disable calls because |
123 | * softirqs always disables bh. | 124 | * softirqs always disables bh. |
124 | */ | 125 | */ |
125 | if (softirq_count() != SOFTIRQ_OFFSET) | 126 | if (softirq_count() != SOFTIRQ_OFFSET) { |
126 | return -1; | 127 | /* If there is an sk_classid we'll use that. */ |
127 | 128 | if (!skb->sk) | |
128 | rcu_read_lock(); | 129 | return -1; |
129 | classid = task_cls_state(current)->classid; | 130 | classid = skb->sk->sk_classid; |
130 | rcu_read_unlock(); | 131 | } |
131 | 132 | ||
132 | if (!classid) | 133 | if (!classid) |
133 | return -1; | 134 | return -1; |
@@ -289,18 +290,35 @@ static struct tcf_proto_ops cls_cgroup_ops __read_mostly = { | |||
289 | 290 | ||
290 | static int __init init_cgroup_cls(void) | 291 | static int __init init_cgroup_cls(void) |
291 | { | 292 | { |
292 | int ret = register_tcf_proto_ops(&cls_cgroup_ops); | 293 | int ret; |
293 | if (ret) | 294 | |
294 | return ret; | ||
295 | ret = cgroup_load_subsys(&net_cls_subsys); | 295 | ret = cgroup_load_subsys(&net_cls_subsys); |
296 | if (ret) | 296 | if (ret) |
297 | unregister_tcf_proto_ops(&cls_cgroup_ops); | 297 | goto out; |
298 | |||
299 | #ifndef CONFIG_NET_CLS_CGROUP | ||
300 | /* We can't use rcu_assign_pointer because this is an int. */ | ||
301 | smp_wmb(); | ||
302 | net_cls_subsys_id = net_cls_subsys.subsys_id; | ||
303 | #endif | ||
304 | |||
305 | ret = register_tcf_proto_ops(&cls_cgroup_ops); | ||
306 | if (ret) | ||
307 | cgroup_unload_subsys(&net_cls_subsys); | ||
308 | |||
309 | out: | ||
298 | return ret; | 310 | return ret; |
299 | } | 311 | } |
300 | 312 | ||
301 | static void __exit exit_cgroup_cls(void) | 313 | static void __exit exit_cgroup_cls(void) |
302 | { | 314 | { |
303 | unregister_tcf_proto_ops(&cls_cgroup_ops); | 315 | unregister_tcf_proto_ops(&cls_cgroup_ops); |
316 | |||
317 | #ifndef CONFIG_NET_CLS_CGROUP | ||
318 | net_cls_subsys_id = -1; | ||
319 | synchronize_rcu(); | ||
320 | #endif | ||
321 | |||
304 | cgroup_unload_subsys(&net_cls_subsys); | 322 | cgroup_unload_subsys(&net_cls_subsys); |
305 | } | 323 | } |
306 | 324 | ||
diff --git a/net/socket.c b/net/socket.c index f9f7d0872cac..367d5477d00f 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -94,6 +94,7 @@ | |||
94 | 94 | ||
95 | #include <net/compat.h> | 95 | #include <net/compat.h> |
96 | #include <net/wext.h> | 96 | #include <net/wext.h> |
97 | #include <net/cls_cgroup.h> | ||
97 | 98 | ||
98 | #include <net/sock.h> | 99 | #include <net/sock.h> |
99 | #include <linux/netfilter.h> | 100 | #include <linux/netfilter.h> |
@@ -558,6 +559,8 @@ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
558 | struct sock_iocb *si = kiocb_to_siocb(iocb); | 559 | struct sock_iocb *si = kiocb_to_siocb(iocb); |
559 | int err; | 560 | int err; |
560 | 561 | ||
562 | sock_update_classid(sock->sk); | ||
563 | |||
561 | si->sock = sock; | 564 | si->sock = sock; |
562 | si->scm = NULL; | 565 | si->scm = NULL; |
563 | si->msg = msg; | 566 | si->msg = msg; |
@@ -684,6 +687,8 @@ static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock, | |||
684 | { | 687 | { |
685 | struct sock_iocb *si = kiocb_to_siocb(iocb); | 688 | struct sock_iocb *si = kiocb_to_siocb(iocb); |
686 | 689 | ||
690 | sock_update_classid(sock->sk); | ||
691 | |||
687 | si->sock = sock; | 692 | si->sock = sock; |
688 | si->scm = NULL; | 693 | si->scm = NULL; |
689 | si->msg = msg; | 694 | si->msg = msg; |
@@ -777,6 +782,8 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos, | |||
777 | if (unlikely(!sock->ops->splice_read)) | 782 | if (unlikely(!sock->ops->splice_read)) |
778 | return -EINVAL; | 783 | return -EINVAL; |
779 | 784 | ||
785 | sock_update_classid(sock->sk); | ||
786 | |||
780 | return sock->ops->splice_read(sock, ppos, pipe, len, flags); | 787 | return sock->ops->splice_read(sock, ppos, pipe, len, flags); |
781 | } | 788 | } |
782 | 789 | ||
@@ -3069,6 +3076,8 @@ int kernel_setsockopt(struct socket *sock, int level, int optname, | |||
3069 | int kernel_sendpage(struct socket *sock, struct page *page, int offset, | 3076 | int kernel_sendpage(struct socket *sock, struct page *page, int offset, |
3070 | size_t size, int flags) | 3077 | size_t size, int flags) |
3071 | { | 3078 | { |
3079 | sock_update_classid(sock->sk); | ||
3080 | |||
3072 | if (sock->ops->sendpage) | 3081 | if (sock->ops->sendpage) |
3073 | return sock->ops->sendpage(sock, page, offset, size, flags); | 3082 | return sock->ops->sendpage(sock, page, offset, size, flags); |
3074 | 3083 | ||