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 | ||
