diff options
Diffstat (limited to 'net/sched/cls_cgroup.c')
| -rw-r--r-- | net/sched/cls_cgroup.c | 145 |
1 files changed, 37 insertions, 108 deletions
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index 91a3db4a76f..cacf01bd04f 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c @@ -10,102 +10,29 @@ */ #include <linux/module.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/errno.h> +#include <linux/slab.h> #include <linux/skbuff.h> -#include <linux/cgroup.h> +#include <linux/rcupdate.h> #include <net/rtnetlink.h> #include <net/pkt_cls.h> +#include <net/sock.h> +#include <net/cls_cgroup.h> -struct cgroup_cls_state -{ - struct cgroup_subsys_state css; - u32 classid; -}; - -static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp) -{ - return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id), - struct cgroup_cls_state, css); -} - -static inline struct cgroup_cls_state *task_cls_state(struct task_struct *p) -{ - return container_of(task_subsys_state(p, net_cls_subsys_id), - struct cgroup_cls_state, css); -} - -static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, - struct cgroup *cgrp) -{ - struct cgroup_cls_state *cs; - - if (!(cs = kzalloc(sizeof(*cs), GFP_KERNEL))) - return ERR_PTR(-ENOMEM); - - if (cgrp->parent) - cs->classid = cgrp_cls_state(cgrp->parent)->classid; - - return &cs->css; -} - -static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp) -{ - kfree(cgrp_cls_state(cgrp)); -} - -static u64 read_classid(struct cgroup *cgrp, struct cftype *cft) -{ - return cgrp_cls_state(cgrp)->classid; -} - -static int write_classid(struct cgroup *cgrp, struct cftype *cft, u64 value) -{ - if (!cgroup_lock_live_group(cgrp)) - return -ENODEV; - - cgrp_cls_state(cgrp)->classid = (u32) value; - - cgroup_unlock(); - - return 0; -} - -static struct cftype ss_files[] = { - { - .name = "classid", - .read_u64 = read_classid, - .write_u64 = write_classid, - }, -}; - -static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp) -{ - return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files)); -} - -struct cgroup_subsys net_cls_subsys = { - .name = "net_cls", - .create = cgrp_create, - .destroy = cgrp_destroy, - .populate = cgrp_populate, - .subsys_id = net_cls_subsys_id, -}; - -struct cls_cgroup_head -{ +struct cls_cgroup_head { u32 handle; struct tcf_exts exts; struct tcf_ematch_tree ematches; }; -static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp, +static int cls_cgroup_classify(struct sk_buff *skb, const struct tcf_proto *tp, struct tcf_result *res) { struct cls_cgroup_head *head = tp->root; - struct cgroup_cls_state *cs; - int ret = 0; + u32 classid; + + rcu_read_lock(); + classid = task_cls_state(current)->classid; + rcu_read_unlock(); /* * Due to the nature of the classifier it is required to ignore all @@ -117,21 +44,22 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp, * calls by looking at the number of nested bh disable calls because * softirqs always disables bh. */ - if (softirq_count() != SOFTIRQ_OFFSET) - return -1; + if (in_serving_softirq()) { + /* If there is an sk_classid we'll use that. */ + if (!skb->sk) + return -1; + classid = skb->sk->sk_classid; + } - rcu_read_lock(); - cs = task_cls_state(current); - if (cs->classid && tcf_em_tree_match(skb, &head->ematches, NULL)) { - res->classid = cs->classid; - res->class = 0; - ret = tcf_exts_exec(skb, &head->exts, res); - } else - ret = -1; + if (!classid) + return -1; - rcu_read_unlock(); + if (!tcf_em_tree_match(skb, &head->ematches, NULL)) + return -1; - return ret; + res->classid = classid; + res->class = 0; + return tcf_exts_exec(skb, &head->exts, res); } static unsigned long cls_cgroup_get(struct tcf_proto *tp, u32 handle) @@ -148,25 +76,24 @@ static int cls_cgroup_init(struct tcf_proto *tp) return 0; } -static const struct tcf_ext_map cgroup_ext_map = { - .action = TCA_CGROUP_ACT, - .police = TCA_CGROUP_POLICE, -}; - static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = { [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, }; -static int cls_cgroup_change(struct tcf_proto *tp, unsigned long base, +static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, + struct tcf_proto *tp, unsigned long base, u32 handle, struct nlattr **tca, - unsigned long *arg) + unsigned long *arg, bool ovr) { - struct nlattr *tb[TCA_CGROUP_MAX+1]; + struct nlattr *tb[TCA_CGROUP_MAX + 1]; struct cls_cgroup_head *head = tp->root; struct tcf_ematch_tree t; struct tcf_exts e; int err; + if (!tca[TCA_OPTIONS]) + return -EINVAL; + if (head == NULL) { if (!handle) return -EINVAL; @@ -175,6 +102,7 @@ static int cls_cgroup_change(struct tcf_proto *tp, unsigned long base, if (head == NULL) return -ENOBUFS; + tcf_exts_init(&head->exts, TCA_CGROUP_ACT, TCA_CGROUP_POLICE); head->handle = handle; tcf_tree_lock(tp); @@ -190,7 +118,8 @@ static int cls_cgroup_change(struct tcf_proto *tp, unsigned long base, if (err < 0) return err; - err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &cgroup_ext_map); + tcf_exts_init(&e, TCA_CGROUP_ACT, TCA_CGROUP_POLICE); + err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr); if (err < 0) return err; @@ -235,7 +164,7 @@ skip: arg->count++; } -static int cls_cgroup_dump(struct tcf_proto *tp, unsigned long fh, +static int cls_cgroup_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { struct cls_cgroup_head *head = tp->root; @@ -248,13 +177,13 @@ static int cls_cgroup_dump(struct tcf_proto *tp, unsigned long fh, if (nest == NULL) goto nla_put_failure; - if (tcf_exts_dump(skb, &head->exts, &cgroup_ext_map) < 0 || + if (tcf_exts_dump(skb, &head->exts) < 0 || tcf_em_tree_dump(skb, &head->ematches, TCA_CGROUP_EMATCHES) < 0) goto nla_put_failure; nla_nest_end(skb, nest); - if (tcf_exts_dump_stats(skb, &head->exts, &cgroup_ext_map) < 0) + if (tcf_exts_dump_stats(skb, &head->exts) < 0) goto nla_put_failure; return skb->len; |
