aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Pirko <jiri@mellanox.com>2016-07-21 06:03:11 -0400
committerDavid S. Miller <davem@davemloft.net>2016-07-25 02:11:59 -0400
commitbf3994d2ed310813da28362d87bfe9f0e1c3e37f (patch)
tree5c7becf58d38f2ce5bac1fb702fb013ec4279858
parentded821c8d3793efe00195dd7ab633f6412dd8ae0 (diff)
net/sched: introduce Match-all classifier
The matchall classifier matches every packet and allows the user to apply actions on it. This filter is very useful in usecases where every packet should be matched, for example, packet mirroring (SPAN) can be setup very easily using that filter. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: Yotam Gigi <yotamg@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/uapi/linux/pkt_cls.h11
-rw-r--r--net/sched/Kconfig10
-rw-r--r--net/sched/Makefile1
-rw-r--r--net/sched/cls_matchall.c248
4 files changed, 270 insertions, 0 deletions
diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index 5702e933dc07..a32494887e01 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -433,6 +433,17 @@ enum {
433 433
434#define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) 434#define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1)
435 435
436/* Match-all classifier */
437
438enum {
439 TCA_MATCHALL_UNSPEC,
440 TCA_MATCHALL_CLASSID,
441 TCA_MATCHALL_ACT,
442 __TCA_MATCHALL_MAX,
443};
444
445#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1)
446
436/* Extended Matches */ 447/* Extended Matches */
437 448
438struct tcf_ematch_tree_hdr { 449struct tcf_ematch_tree_hdr {
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index b148302bbaf2..ccf931b3b94c 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -494,6 +494,16 @@ config NET_CLS_FLOWER
494 To compile this code as a module, choose M here: the module will 494 To compile this code as a module, choose M here: the module will
495 be called cls_flower. 495 be called cls_flower.
496 496
497config NET_CLS_MATCHALL
498 tristate "Match-all classifier"
499 select NET_CLS
500 ---help---
501 If you say Y here, you will be able to classify packets based on
502 nothing. Every packet will match.
503
504 To compile this code as a module, choose M here: the module will
505 be called cls_matchall.
506
497config NET_EMATCH 507config NET_EMATCH
498 bool "Extended Matches" 508 bool "Extended Matches"
499 select NET_CLS 509 select NET_CLS
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 84bddb373517..ae088a5a9d95 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_NET_CLS_FLOW) += cls_flow.o
60obj-$(CONFIG_NET_CLS_CGROUP) += cls_cgroup.o 60obj-$(CONFIG_NET_CLS_CGROUP) += cls_cgroup.o
61obj-$(CONFIG_NET_CLS_BPF) += cls_bpf.o 61obj-$(CONFIG_NET_CLS_BPF) += cls_bpf.o
62obj-$(CONFIG_NET_CLS_FLOWER) += cls_flower.o 62obj-$(CONFIG_NET_CLS_FLOWER) += cls_flower.o
63obj-$(CONFIG_NET_CLS_MATCHALL) += cls_matchall.o
63obj-$(CONFIG_NET_EMATCH) += ematch.o 64obj-$(CONFIG_NET_EMATCH) += ematch.o
64obj-$(CONFIG_NET_EMATCH_CMP) += em_cmp.o 65obj-$(CONFIG_NET_EMATCH_CMP) += em_cmp.o
65obj-$(CONFIG_NET_EMATCH_NBYTE) += em_nbyte.o 66obj-$(CONFIG_NET_EMATCH_NBYTE) += em_nbyte.o
diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c
new file mode 100644
index 000000000000..8a6b4de7a99a
--- /dev/null
+++ b/net/sched/cls_matchall.c
@@ -0,0 +1,248 @@
1/*
2 * net/sched/cls_matchll.c Match-all classifier
3 *
4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/module.h>
15
16#include <net/sch_generic.h>
17#include <net/pkt_cls.h>
18
19struct cls_mall_filter {
20 struct tcf_exts exts;
21 struct tcf_result res;
22 u32 handle;
23 struct rcu_head rcu;
24};
25
26struct cls_mall_head {
27 struct cls_mall_filter *filter;
28 struct rcu_head rcu;
29};
30
31static int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp,
32 struct tcf_result *res)
33{
34 struct cls_mall_head *head = rcu_dereference_bh(tp->root);
35 struct cls_mall_filter *f = head->filter;
36
37 return tcf_exts_exec(skb, &f->exts, res);
38}
39
40static int mall_init(struct tcf_proto *tp)
41{
42 struct cls_mall_head *head;
43
44 head = kzalloc(sizeof(*head), GFP_KERNEL);
45 if (!head)
46 return -ENOBUFS;
47
48 rcu_assign_pointer(tp->root, head);
49
50 return 0;
51}
52
53static void mall_destroy_filter(struct rcu_head *head)
54{
55 struct cls_mall_filter *f = container_of(head, struct cls_mall_filter, rcu);
56
57 tcf_exts_destroy(&f->exts);
58 kfree(f);
59}
60
61static bool mall_destroy(struct tcf_proto *tp, bool force)
62{
63 struct cls_mall_head *head = rtnl_dereference(tp->root);
64
65 if (!force && head->filter)
66 return false;
67
68 if (head->filter)
69 call_rcu(&head->filter->rcu, mall_destroy_filter);
70 RCU_INIT_POINTER(tp->root, NULL);
71 kfree_rcu(head, rcu);
72 return true;
73}
74
75static unsigned long mall_get(struct tcf_proto *tp, u32 handle)
76{
77 struct cls_mall_head *head = rtnl_dereference(tp->root);
78 struct cls_mall_filter *f = head->filter;
79
80 if (f && f->handle == handle)
81 return (unsigned long) f;
82 return 0;
83}
84
85static const struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = {
86 [TCA_MATCHALL_UNSPEC] = { .type = NLA_UNSPEC },
87 [TCA_MATCHALL_CLASSID] = { .type = NLA_U32 },
88};
89
90static int mall_set_parms(struct net *net, struct tcf_proto *tp,
91 struct cls_mall_filter *f,
92 unsigned long base, struct nlattr **tb,
93 struct nlattr *est, bool ovr)
94{
95 struct tcf_exts e;
96 int err;
97
98 tcf_exts_init(&e, TCA_MATCHALL_ACT, 0);
99 err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
100 if (err < 0)
101 return err;
102
103 if (tb[TCA_MATCHALL_CLASSID]) {
104 f->res.classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
105 tcf_bind_filter(tp, &f->res, base);
106 }
107
108 tcf_exts_change(tp, &f->exts, &e);
109
110 return 0;
111}
112
113static int mall_change(struct net *net, struct sk_buff *in_skb,
114 struct tcf_proto *tp, unsigned long base,
115 u32 handle, struct nlattr **tca,
116 unsigned long *arg, bool ovr)
117{
118 struct cls_mall_head *head = rtnl_dereference(tp->root);
119 struct cls_mall_filter *fold = (struct cls_mall_filter *) *arg;
120 struct cls_mall_filter *f;
121 struct nlattr *tb[TCA_MATCHALL_MAX + 1];
122 int err;
123
124 if (!tca[TCA_OPTIONS])
125 return -EINVAL;
126
127 if (head->filter)
128 return -EBUSY;
129
130 if (fold)
131 return -EINVAL;
132
133 err = nla_parse_nested(tb, TCA_MATCHALL_MAX,
134 tca[TCA_OPTIONS], mall_policy);
135 if (err < 0)
136 return err;
137
138 f = kzalloc(sizeof(*f), GFP_KERNEL);
139 if (!f)
140 return -ENOBUFS;
141
142 tcf_exts_init(&f->exts, TCA_MATCHALL_ACT, 0);
143
144 if (!handle)
145 handle = 1;
146 f->handle = handle;
147
148 err = mall_set_parms(net, tp, f, base, tb, tca[TCA_RATE], ovr);
149 if (err)
150 goto errout;
151
152 *arg = (unsigned long) f;
153 rcu_assign_pointer(head->filter, f);
154
155 return 0;
156
157errout:
158 kfree(f);
159 return err;
160}
161
162static int mall_delete(struct tcf_proto *tp, unsigned long arg)
163{
164 struct cls_mall_head *head = rtnl_dereference(tp->root);
165 struct cls_mall_filter *f = (struct cls_mall_filter *) arg;
166
167 RCU_INIT_POINTER(head->filter, NULL);
168 tcf_unbind_filter(tp, &f->res);
169 call_rcu(&f->rcu, mall_destroy_filter);
170 return 0;
171}
172
173static void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg)
174{
175 struct cls_mall_head *head = rtnl_dereference(tp->root);
176 struct cls_mall_filter *f = head->filter;
177
178 if (arg->count < arg->skip)
179 goto skip;
180 if (arg->fn(tp, (unsigned long) f, arg) < 0)
181 arg->stop = 1;
182skip:
183 arg->count++;
184}
185
186static int mall_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
187 struct sk_buff *skb, struct tcmsg *t)
188{
189 struct cls_mall_filter *f = (struct cls_mall_filter *) fh;
190 struct nlattr *nest;
191
192 if (!f)
193 return skb->len;
194
195 t->tcm_handle = f->handle;
196
197 nest = nla_nest_start(skb, TCA_OPTIONS);
198 if (!nest)
199 goto nla_put_failure;
200
201 if (f->res.classid &&
202 nla_put_u32(skb, TCA_MATCHALL_CLASSID, f->res.classid))
203 goto nla_put_failure;
204
205 if (tcf_exts_dump(skb, &f->exts))
206 goto nla_put_failure;
207
208 nla_nest_end(skb, nest);
209
210 if (tcf_exts_dump_stats(skb, &f->exts) < 0)
211 goto nla_put_failure;
212
213 return skb->len;
214
215nla_put_failure:
216 nla_nest_cancel(skb, nest);
217 return -1;
218}
219
220static struct tcf_proto_ops cls_mall_ops __read_mostly = {
221 .kind = "matchall",
222 .classify = mall_classify,
223 .init = mall_init,
224 .destroy = mall_destroy,
225 .get = mall_get,
226 .change = mall_change,
227 .delete = mall_delete,
228 .walk = mall_walk,
229 .dump = mall_dump,
230 .owner = THIS_MODULE,
231};
232
233static int __init cls_mall_init(void)
234{
235 return register_tcf_proto_ops(&cls_mall_ops);
236}
237
238static void __exit cls_mall_exit(void)
239{
240 unregister_tcf_proto_ops(&cls_mall_ops);
241}
242
243module_init(cls_mall_init);
244module_exit(cls_mall_exit);
245
246MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
247MODULE_DESCRIPTION("Match-all classifier");
248MODULE_LICENSE("GPL v2");