diff options
Diffstat (limited to 'net/sched/cls_cgroup.c')
| -rw-r--r-- | net/sched/cls_cgroup.c | 75 |
1 files changed, 56 insertions, 19 deletions
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index e4877ca6727c..78ef2c5e130b 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c | |||
| @@ -10,20 +10,37 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/slab.h> | ||
| 13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 14 | #include <linux/string.h> | 15 | #include <linux/string.h> |
| 15 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
| 16 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
| 17 | #include <linux/cgroup.h> | 18 | #include <linux/cgroup.h> |
| 19 | #include <linux/rcupdate.h> | ||
| 18 | #include <net/rtnetlink.h> | 20 | #include <net/rtnetlink.h> |
| 19 | #include <net/pkt_cls.h> | 21 | #include <net/pkt_cls.h> |
| 22 | #include <net/sock.h> | ||
| 23 | #include <net/cls_cgroup.h> | ||
| 20 | 24 | ||
| 21 | struct cgroup_cls_state | 25 | static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, |
| 22 | { | 26 | struct cgroup *cgrp); |
| 23 | struct cgroup_subsys_state css; | 27 | static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp); |
| 24 | u32 classid; | 28 | static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp); |
| 29 | |||
| 30 | struct cgroup_subsys net_cls_subsys = { | ||
| 31 | .name = "net_cls", | ||
| 32 | .create = cgrp_create, | ||
| 33 | .destroy = cgrp_destroy, | ||
| 34 | .populate = cgrp_populate, | ||
| 35 | #ifdef CONFIG_NET_CLS_CGROUP | ||
| 36 | .subsys_id = net_cls_subsys_id, | ||
| 37 | #else | ||
| 38 | #define net_cls_subsys_id net_cls_subsys.subsys_id | ||
| 39 | #endif | ||
| 40 | .module = THIS_MODULE, | ||
| 25 | }; | 41 | }; |
| 26 | 42 | ||
| 43 | |||
| 27 | static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp) | 44 | static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp) |
| 28 | { | 45 | { |
| 29 | return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id), | 46 | return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id), |
| @@ -79,14 +96,6 @@ static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp) | |||
| 79 | return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files)); | 96 | return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files)); |
| 80 | } | 97 | } |
| 81 | 98 | ||
| 82 | struct cgroup_subsys net_cls_subsys = { | ||
| 83 | .name = "net_cls", | ||
| 84 | .create = cgrp_create, | ||
| 85 | .destroy = cgrp_destroy, | ||
| 86 | .populate = cgrp_populate, | ||
| 87 | .subsys_id = net_cls_subsys_id, | ||
| 88 | }; | ||
| 89 | |||
| 90 | struct cls_cgroup_head | 99 | struct cls_cgroup_head |
| 91 | { | 100 | { |
| 92 | u32 handle; | 101 | u32 handle; |
| @@ -100,6 +109,10 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp, | |||
| 100 | struct cls_cgroup_head *head = tp->root; | 109 | struct cls_cgroup_head *head = tp->root; |
| 101 | u32 classid; | 110 | u32 classid; |
| 102 | 111 | ||
| 112 | rcu_read_lock(); | ||
| 113 | classid = task_cls_state(current)->classid; | ||
| 114 | rcu_read_unlock(); | ||
| 115 | |||
| 103 | /* | 116 | /* |
| 104 | * 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 |
| 105 | * packets originating from softirq context as accessing `current' | 118 | * packets originating from softirq context as accessing `current' |
| @@ -110,12 +123,12 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp, | |||
| 110 | * 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 |
| 111 | * softirqs always disables bh. | 124 | * softirqs always disables bh. |
| 112 | */ | 125 | */ |
| 113 | if (softirq_count() != SOFTIRQ_OFFSET) | 126 | if (softirq_count() != SOFTIRQ_OFFSET) { |
| 114 | return -1; | 127 | /* If there is an sk_classid we'll use that. */ |
| 115 | 128 | if (!skb->sk) | |
| 116 | rcu_read_lock(); | 129 | return -1; |
| 117 | classid = task_cls_state(current)->classid; | 130 | classid = skb->sk->sk_classid; |
| 118 | rcu_read_unlock(); | 131 | } |
| 119 | 132 | ||
| 120 | if (!classid) | 133 | if (!classid) |
| 121 | return -1; | 134 | return -1; |
| @@ -277,12 +290,36 @@ static struct tcf_proto_ops cls_cgroup_ops __read_mostly = { | |||
| 277 | 290 | ||
| 278 | static int __init init_cgroup_cls(void) | 291 | static int __init init_cgroup_cls(void) |
| 279 | { | 292 | { |
| 280 | return register_tcf_proto_ops(&cls_cgroup_ops); | 293 | int ret; |
| 294 | |||
| 295 | ret = cgroup_load_subsys(&net_cls_subsys); | ||
| 296 | if (ret) | ||
| 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: | ||
| 310 | return ret; | ||
| 281 | } | 311 | } |
| 282 | 312 | ||
| 283 | static void __exit exit_cgroup_cls(void) | 313 | static void __exit exit_cgroup_cls(void) |
| 284 | { | 314 | { |
| 285 | 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 | |||
| 322 | cgroup_unload_subsys(&net_cls_subsys); | ||
| 286 | } | 323 | } |
| 287 | 324 | ||
| 288 | module_init(init_cgroup_cls); | 325 | module_init(init_cgroup_cls); |
