diff options
Diffstat (limited to 'net/sched/cls_basic.c')
-rw-r--r-- | net/sched/cls_basic.c | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c index 6a5dce8baf19..4a57fec6f306 100644 --- a/net/sched/cls_basic.c +++ b/net/sched/cls_basic.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/rtnetlink.h> | 18 | #include <linux/rtnetlink.h> |
19 | #include <linux/skbuff.h> | 19 | #include <linux/skbuff.h> |
20 | #include <linux/idr.h> | 20 | #include <linux/idr.h> |
21 | #include <linux/percpu.h> | ||
21 | #include <net/netlink.h> | 22 | #include <net/netlink.h> |
22 | #include <net/act_api.h> | 23 | #include <net/act_api.h> |
23 | #include <net/pkt_cls.h> | 24 | #include <net/pkt_cls.h> |
@@ -35,6 +36,7 @@ struct basic_filter { | |||
35 | struct tcf_result res; | 36 | struct tcf_result res; |
36 | struct tcf_proto *tp; | 37 | struct tcf_proto *tp; |
37 | struct list_head link; | 38 | struct list_head link; |
39 | struct tc_basic_pcnt __percpu *pf; | ||
38 | struct rcu_work rwork; | 40 | struct rcu_work rwork; |
39 | }; | 41 | }; |
40 | 42 | ||
@@ -46,8 +48,10 @@ static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp, | |||
46 | struct basic_filter *f; | 48 | struct basic_filter *f; |
47 | 49 | ||
48 | list_for_each_entry_rcu(f, &head->flist, link) { | 50 | list_for_each_entry_rcu(f, &head->flist, link) { |
51 | __this_cpu_inc(f->pf->rcnt); | ||
49 | if (!tcf_em_tree_match(skb, &f->ematches, NULL)) | 52 | if (!tcf_em_tree_match(skb, &f->ematches, NULL)) |
50 | continue; | 53 | continue; |
54 | __this_cpu_inc(f->pf->rhit); | ||
51 | *res = f->res; | 55 | *res = f->res; |
52 | r = tcf_exts_exec(skb, &f->exts, res); | 56 | r = tcf_exts_exec(skb, &f->exts, res); |
53 | if (r < 0) | 57 | if (r < 0) |
@@ -89,6 +93,7 @@ static void __basic_delete_filter(struct basic_filter *f) | |||
89 | tcf_exts_destroy(&f->exts); | 93 | tcf_exts_destroy(&f->exts); |
90 | tcf_em_tree_destroy(&f->ematches); | 94 | tcf_em_tree_destroy(&f->ematches); |
91 | tcf_exts_put_net(&f->exts); | 95 | tcf_exts_put_net(&f->exts); |
96 | free_percpu(f->pf); | ||
92 | kfree(f); | 97 | kfree(f); |
93 | } | 98 | } |
94 | 99 | ||
@@ -208,6 +213,11 @@ static int basic_change(struct net *net, struct sk_buff *in_skb, | |||
208 | if (err) | 213 | if (err) |
209 | goto errout; | 214 | goto errout; |
210 | fnew->handle = handle; | 215 | fnew->handle = handle; |
216 | fnew->pf = alloc_percpu(struct tc_basic_pcnt); | ||
217 | if (!fnew->pf) { | ||
218 | err = -ENOMEM; | ||
219 | goto errout; | ||
220 | } | ||
211 | 221 | ||
212 | err = basic_set_parms(net, tp, fnew, base, tb, tca[TCA_RATE], ovr, | 222 | err = basic_set_parms(net, tp, fnew, base, tb, tca[TCA_RATE], ovr, |
213 | extack); | 223 | extack); |
@@ -231,6 +241,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb, | |||
231 | 241 | ||
232 | return 0; | 242 | return 0; |
233 | errout: | 243 | errout: |
244 | free_percpu(fnew->pf); | ||
234 | tcf_exts_destroy(&fnew->exts); | 245 | tcf_exts_destroy(&fnew->exts); |
235 | kfree(fnew); | 246 | kfree(fnew); |
236 | return err; | 247 | return err; |
@@ -265,8 +276,10 @@ static void basic_bind_class(void *fh, u32 classid, unsigned long cl) | |||
265 | static int basic_dump(struct net *net, struct tcf_proto *tp, void *fh, | 276 | static int basic_dump(struct net *net, struct tcf_proto *tp, void *fh, |
266 | struct sk_buff *skb, struct tcmsg *t) | 277 | struct sk_buff *skb, struct tcmsg *t) |
267 | { | 278 | { |
279 | struct tc_basic_pcnt gpf = {}; | ||
268 | struct basic_filter *f = fh; | 280 | struct basic_filter *f = fh; |
269 | struct nlattr *nest; | 281 | struct nlattr *nest; |
282 | int cpu; | ||
270 | 283 | ||
271 | if (f == NULL) | 284 | if (f == NULL) |
272 | return skb->len; | 285 | return skb->len; |
@@ -281,6 +294,18 @@ static int basic_dump(struct net *net, struct tcf_proto *tp, void *fh, | |||
281 | nla_put_u32(skb, TCA_BASIC_CLASSID, f->res.classid)) | 294 | nla_put_u32(skb, TCA_BASIC_CLASSID, f->res.classid)) |
282 | goto nla_put_failure; | 295 | goto nla_put_failure; |
283 | 296 | ||
297 | for_each_possible_cpu(cpu) { | ||
298 | struct tc_basic_pcnt *pf = per_cpu_ptr(f->pf, cpu); | ||
299 | |||
300 | gpf.rcnt += pf->rcnt; | ||
301 | gpf.rhit += pf->rhit; | ||
302 | } | ||
303 | |||
304 | if (nla_put_64bit(skb, TCA_BASIC_PCNT, | ||
305 | sizeof(struct tc_basic_pcnt), | ||
306 | &gpf, TCA_BASIC_PAD)) | ||
307 | goto nla_put_failure; | ||
308 | |||
284 | if (tcf_exts_dump(skb, &f->exts) < 0 || | 309 | if (tcf_exts_dump(skb, &f->exts) < 0 || |
285 | tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0) | 310 | tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0) |
286 | goto nla_put_failure; | 311 | goto nla_put_failure; |