Blame view

net/sched/cls_basic.c 6.45 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
  /*
   * net/sched/cls_basic.c	Basic Packet Classifier.
   *
   *		This program is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
   *		as published by the Free Software Foundation; either version
   *		2 of the License, or (at your option) any later version.
   *
   * Authors:	Thomas Graf <tgraf@suug.ch>
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
12
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
  #include <linux/types.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
  #include <linux/errno.h>
  #include <linux/rtnetlink.h>
  #include <linux/skbuff.h>
dc5fc579b   Arnaldo Carvalho de Melo   [NETLINK]: Use nl...
19
  #include <net/netlink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  #include <net/act_api.h>
  #include <net/pkt_cls.h>
cc7ec456f   Eric Dumazet   net_sched: cleanups
22
  struct basic_head {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
  	u32			hgenerator;
  	struct list_head	flist;
  };
cc7ec456f   Eric Dumazet   net_sched: cleanups
26
  struct basic_filter {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
32
  	u32			handle;
  	struct tcf_exts		exts;
  	struct tcf_ematch_tree	ematches;
  	struct tcf_result	res;
  	struct list_head	link;
  };
5239008b0   Patrick McHardy   [NET_SCHED]: Cons...
33
  static const struct tcf_ext_map basic_ext_map = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
  	.action = TCA_BASIC_ACT,
  	.police = TCA_BASIC_POLICE
  };
dc7f9f6e8   Eric Dumazet   net: sched: const...
37
  static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  			  struct tcf_result *res)
  {
  	int r;
  	struct basic_head *head = (struct basic_head *) tp->root;
  	struct basic_filter *f;
  
  	list_for_each_entry(f, &head->flist, link) {
  		if (!tcf_em_tree_match(skb, &f->ematches, NULL))
  			continue;
  		*res = f->res;
  		r = tcf_exts_exec(skb, &f->exts, res);
  		if (r < 0)
  			continue;
  		return r;
  	}
  	return -1;
  }
  
  static unsigned long basic_get(struct tcf_proto *tp, u32 handle)
  {
  	unsigned long l = 0UL;
  	struct basic_head *head = (struct basic_head *) tp->root;
  	struct basic_filter *f;
  
  	if (head == NULL)
  		return 0UL;
  
  	list_for_each_entry(f, &head->flist, link)
  		if (f->handle == handle)
  			l = (unsigned long) f;
  
  	return l;
  }
  
  static void basic_put(struct tcf_proto *tp, unsigned long f)
  {
  }
  
  static int basic_init(struct tcf_proto *tp)
  {
d3fa76ee6   Patrick McHardy   [NET_SCHED]: cls_...
78
79
80
81
82
83
84
  	struct basic_head *head;
  
  	head = kzalloc(sizeof(*head), GFP_KERNEL);
  	if (head == NULL)
  		return -ENOBUFS;
  	INIT_LIST_HEAD(&head->flist);
  	tp->root = head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
  	return 0;
  }
cc7ec456f   Eric Dumazet   net_sched: cleanups
87
  static void basic_delete_filter(struct tcf_proto *tp, struct basic_filter *f)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
92
93
94
95
96
  {
  	tcf_unbind_filter(tp, &f->res);
  	tcf_exts_destroy(tp, &f->exts);
  	tcf_em_tree_destroy(tp, &f->ematches);
  	kfree(f);
  }
  
  static void basic_destroy(struct tcf_proto *tp)
  {
47a1a1d4b   Patrick McHardy   pkt_sched: remove...
97
  	struct basic_head *head = tp->root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  	struct basic_filter *f, *n;
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
99

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
  	list_for_each_entry_safe(f, n, &head->flist, link) {
  		list_del(&f->link);
  		basic_delete_filter(tp, f);
  	}
31ba548f9   Patrick McHardy   [NET_SCHED]: cls_...
104
  	kfree(head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  }
  
  static int basic_delete(struct tcf_proto *tp, unsigned long arg)
  {
  	struct basic_head *head = (struct basic_head *) tp->root;
  	struct basic_filter *t, *f = (struct basic_filter *) arg;
  
  	list_for_each_entry(t, &head->flist, link)
  		if (t == f) {
  			tcf_tree_lock(tp);
  			list_del(&t->link);
  			tcf_tree_unlock(tp);
  			basic_delete_filter(tp, t);
  			return 0;
  		}
  
  	return -ENOENT;
  }
6fa8c0144   Patrick McHardy   [NET_SCHED]: Use ...
123
124
125
126
  static const struct nla_policy basic_policy[TCA_BASIC_MAX + 1] = {
  	[TCA_BASIC_CLASSID]	= { .type = NLA_U32 },
  	[TCA_BASIC_EMATCHES]	= { .type = NLA_NESTED },
  };
cc7ec456f   Eric Dumazet   net_sched: cleanups
127
128
129
  static int basic_set_parms(struct tcf_proto *tp, struct basic_filter *f,
  			   unsigned long base, struct nlattr **tb,
  			   struct nlattr *est)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
132
133
  {
  	int err = -EINVAL;
  	struct tcf_exts e;
  	struct tcf_ematch_tree t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
  	err = tcf_exts_validate(tp, tb, est, &e, &basic_ext_map);
  	if (err < 0)
  		return err;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
137
  	err = tcf_em_tree_validate(tp, tb[TCA_BASIC_EMATCHES], &t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
  	if (err < 0)
  		goto errout;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
140
  	if (tb[TCA_BASIC_CLASSID]) {
1587bac49   Patrick McHardy   [NET_SCHED]: Use ...
141
  		f->res.classid = nla_get_u32(tb[TCA_BASIC_CLASSID]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
146
147
148
149
150
151
152
153
154
  		tcf_bind_filter(tp, &f->res, base);
  	}
  
  	tcf_exts_change(tp, &f->exts, &e);
  	tcf_em_tree_change(tp, &f->ematches, &t);
  
  	return 0;
  errout:
  	tcf_exts_destroy(tp, &e);
  	return err;
  }
  
  static int basic_change(struct tcf_proto *tp, unsigned long base, u32 handle,
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
155
  			struct nlattr **tca, unsigned long *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  {
cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
157
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  	struct basic_head *head = (struct basic_head *) tp->root;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
159
  	struct nlattr *tb[TCA_BASIC_MAX + 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  	struct basic_filter *f = (struct basic_filter *) *arg;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
161
  	if (tca[TCA_OPTIONS] == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  		return -EINVAL;
6fa8c0144   Patrick McHardy   [NET_SCHED]: Use ...
163
164
  	err = nla_parse_nested(tb, TCA_BASIC_MAX, tca[TCA_OPTIONS],
  			       basic_policy);
cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
165
166
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
  
  	if (f != NULL) {
  		if (handle && f->handle != handle)
  			return -EINVAL;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
171
  		return basic_set_parms(tp, f, base, tb, tca[TCA_RATE]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
  	}
  
  	err = -ENOBUFS;
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
175
  	f = kzalloc(sizeof(*f), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
  	if (f == NULL)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
180
181
182
  
  	err = -EINVAL;
  	if (handle)
  		f->handle = handle;
  	else {
658270a0a   Kim Nordlund   [PKT_SCHED] cls_b...
183
  		unsigned int i = 0x80000000;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
  		do {
  			if (++head->hgenerator == 0x7FFFFFFF)
  				head->hgenerator = 1;
  		} while (--i > 0 && basic_get(tp, head->hgenerator));
  
  		if (i <= 0) {
cc7ec456f   Eric Dumazet   net_sched: cleanups
190
191
  			pr_err("Insufficient number of handles
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
196
  			goto errout;
  		}
  
  		f->handle = head->hgenerator;
  	}
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
197
  	err = basic_set_parms(tp, f, base, tb, tca[TCA_RATE]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  	if (err < 0)
  		goto errout;
  
  	tcf_tree_lock(tp);
  	list_add(&f->link, &head->flist);
  	tcf_tree_unlock(tp);
  	*arg = (unsigned long) f;
  
  	return 0;
  errout:
  	if (*arg == 0UL && f)
  		kfree(f);
  
  	return err;
  }
  
  static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg)
  {
  	struct basic_head *head = (struct basic_head *) tp->root;
  	struct basic_filter *f;
  
  	list_for_each_entry(f, &head->flist, link) {
  		if (arg->count < arg->skip)
  			goto skip;
  
  		if (arg->fn(tp, (unsigned long) f, arg) < 0) {
  			arg->stop = 1;
  			break;
  		}
  skip:
  		arg->count++;
  	}
  }
  
  static int basic_dump(struct tcf_proto *tp, unsigned long fh,
  		      struct sk_buff *skb, struct tcmsg *t)
  {
  	struct basic_filter *f = (struct basic_filter *) fh;
4b3550ef5   Patrick McHardy   [NET_SCHED]: Use ...
236
  	struct nlattr *nest;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
241
  
  	if (f == NULL)
  		return skb->len;
  
  	t->tcm_handle = f->handle;
4b3550ef5   Patrick McHardy   [NET_SCHED]: Use ...
242
243
244
  	nest = nla_nest_start(skb, TCA_OPTIONS);
  	if (nest == NULL)
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245

e1e284a4b   Thomas Graf   [PKT_SCHED]: Dump...
246
  	if (f->res.classid)
24beeab53   Patrick McHardy   [NET_SCHED]: Use ...
247
  		NLA_PUT_U32(skb, TCA_BASIC_CLASSID, f->res.classid);
e1e284a4b   Thomas Graf   [PKT_SCHED]: Dump...
248

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
  	if (tcf_exts_dump(skb, &f->exts, &basic_ext_map) < 0 ||
  	    tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0)
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
251
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252

4b3550ef5   Patrick McHardy   [NET_SCHED]: Use ...
253
  	nla_nest_end(skb, nest);
4c46ee525   stephen hemminger   classifier: repor...
254
255
256
  
  	if (tcf_exts_dump_stats(skb, &f->exts, &basic_ext_map) < 0)
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  	return skb->len;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
258
  nla_put_failure:
4b3550ef5   Patrick McHardy   [NET_SCHED]: Use ...
259
  	nla_nest_cancel(skb, nest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
  	return -1;
  }
2eb9d75c7   Patrick McHardy   [NET_SCHED]: mark...
262
  static struct tcf_proto_ops cls_basic_ops __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  	.kind		=	"basic",
  	.classify	=	basic_classify,
  	.init		=	basic_init,
  	.destroy	=	basic_destroy,
  	.get		=	basic_get,
  	.put		=	basic_put,
  	.change		=	basic_change,
  	.delete		=	basic_delete,
  	.walk		=	basic_walk,
  	.dump		=	basic_dump,
  	.owner		=	THIS_MODULE,
  };
  
  static int __init init_basic(void)
  {
  	return register_tcf_proto_ops(&cls_basic_ops);
  }
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
280
  static void __exit exit_basic(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
284
285
286
287
  {
  	unregister_tcf_proto_ops(&cls_basic_ops);
  }
  
  module_init(init_basic)
  module_exit(exit_basic)
  MODULE_LICENSE("GPL");