Blame view

net/sched/cls_fw.c 9.18 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   * net/sched/cls_fw.c	Classifier mapping ipchains' fwmark to traffic class.
   *
   *		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:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   *
   * Changes:
   * Karlis Peisenieks <karlis@mt.lv> : 990415 : fw_walk off by one
   * Karlis Peisenieks <karlis@mt.lv> : 990415 : fw_delete killed all the filter (and kernel).
   * Alex <alex@pilotsoft.com> : 2004xxyy: Added Action extension
   *
   * JHS: We should remove the CONFIG_NET_CLS_IND from here
   * eventually when the meta match extension is made available
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
21
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
  #include <linux/types.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <linux/errno.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  #include <linux/skbuff.h>
0ba480538   Patrick McHardy   [NET_SCHED]: Remo...
27
  #include <net/netlink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
  #include <net/act_api.h>
  #include <net/pkt_cls.h>
d37d8ac17   Eric Dumazet   net: sched: use n...
30
  #define HTSIZE 256
c5c13fafd   Thomas Graf   [PKT_SCHED]: impr...
31

cc7ec456f   Eric Dumazet   net_sched: cleanups
32
  struct fw_head {
d37d8ac17   Eric Dumazet   net: sched: use n...
33
  	u32			mask;
e35a8ee59   John Fastabend   net: sched: fw us...
34
35
  	struct fw_filter __rcu	*ht[HTSIZE];
  	struct rcu_head		rcu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  };
cc7ec456f   Eric Dumazet   net_sched: cleanups
37
  struct fw_filter {
e35a8ee59   John Fastabend   net: sched: fw us...
38
  	struct fw_filter __rcu	*next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  	u32			id;
  	struct tcf_result	res;
  #ifdef CONFIG_NET_CLS_IND
2519a602c   WANG Cong   net_sched: optimi...
42
  	int			ifindex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
  #endif /* CONFIG_NET_CLS_IND */
  	struct tcf_exts		exts;
e35a8ee59   John Fastabend   net: sched: fw us...
45
46
  	struct tcf_proto	*tp;
  	struct rcu_head		rcu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  };
d37d8ac17   Eric Dumazet   net: sched: use n...
48
  static u32 fw_hash(u32 handle)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  {
d37d8ac17   Eric Dumazet   net: sched: use n...
50
51
52
  	handle ^= (handle >> 16);
  	handle ^= (handle >> 8);
  	return handle % HTSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  }
dc7f9f6e8   Eric Dumazet   net: sched: const...
54
  static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
  			  struct tcf_result *res)
  {
e35a8ee59   John Fastabend   net: sched: fw us...
57
  	struct fw_head *head = rcu_dereference_bh(tp->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
  	struct fw_filter *f;
  	int r;
5c804bfdc   Patrick McHardy   [NET_SCHED]: cls_...
60
  	u32 id = skb->mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  
  	if (head != NULL) {
5c804bfdc   Patrick McHardy   [NET_SCHED]: cls_...
63
  		id &= head->mask;
e35a8ee59   John Fastabend   net: sched: fw us...
64
65
66
  
  		for (f = rcu_dereference_bh(head->ht[fw_hash(id)]); f;
  		     f = rcu_dereference_bh(f->next)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
  			if (f->id == id) {
  				*res = f->res;
  #ifdef CONFIG_NET_CLS_IND
2519a602c   WANG Cong   net_sched: optimi...
70
  				if (!tcf_match_indev(skb, f->ifindex))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
75
76
77
78
79
80
81
  					continue;
  #endif /* CONFIG_NET_CLS_IND */
  				r = tcf_exts_exec(skb, &f->exts, res);
  				if (r < 0)
  					continue;
  
  				return r;
  			}
  		}
  	} else {
  		/* old method */
cc7ec456f   Eric Dumazet   net_sched: cleanups
82
83
  		if (id && (TC_H_MAJ(id) == 0 ||
  			   !(TC_H_MAJ(id ^ tp->q->handle)))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
89
90
91
92
93
94
  			res->classid = id;
  			res->class = 0;
  			return 0;
  		}
  	}
  
  	return -1;
  }
  
  static unsigned long fw_get(struct tcf_proto *tp, u32 handle)
  {
e35a8ee59   John Fastabend   net: sched: fw us...
95
  	struct fw_head *head = rtnl_dereference(tp->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
  	struct fw_filter *f;
  
  	if (head == NULL)
  		return 0;
e35a8ee59   John Fastabend   net: sched: fw us...
100
101
  	f = rtnl_dereference(head->ht[fw_hash(handle)]);
  	for (; f; f = rtnl_dereference(f->next)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
  		if (f->id == handle)
  			return (unsigned long)f;
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
  static int fw_init(struct tcf_proto *tp)
  {
  	return 0;
  }
e35a8ee59   John Fastabend   net: sched: fw us...
111
  static void fw_delete_filter(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  {
e35a8ee59   John Fastabend   net: sched: fw us...
113
  	struct fw_filter *f = container_of(head, struct fw_filter, rcu);
e35a8ee59   John Fastabend   net: sched: fw us...
114

18d0264f6   WANG Cong   net_sched: remove...
115
  	tcf_exts_destroy(&f->exts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
  	kfree(f);
  }
  
  static void fw_destroy(struct tcf_proto *tp)
  {
e35a8ee59   John Fastabend   net: sched: fw us...
121
  	struct fw_head *head = rtnl_dereference(tp->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
126
  	struct fw_filter *f;
  	int h;
  
  	if (head == NULL)
  		return;
cc7ec456f   Eric Dumazet   net_sched: cleanups
127
  	for (h = 0; h < HTSIZE; h++) {
e35a8ee59   John Fastabend   net: sched: fw us...
128
129
130
  		while ((f = rtnl_dereference(head->ht[h])) != NULL) {
  			RCU_INIT_POINTER(head->ht[h],
  					 rtnl_dereference(f->next));
18cdb37eb   John Fastabend   net: sched: do no...
131
  			tcf_unbind_filter(tp, &f->res);
e35a8ee59   John Fastabend   net: sched: fw us...
132
  			call_rcu(&f->rcu, fw_delete_filter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
  		}
  	}
e35a8ee59   John Fastabend   net: sched: fw us...
135
136
  	RCU_INIT_POINTER(tp->root, NULL);
  	kfree_rcu(head, rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
  }
  
  static int fw_delete(struct tcf_proto *tp, unsigned long arg)
  {
e35a8ee59   John Fastabend   net: sched: fw us...
141
  	struct fw_head *head = rtnl_dereference(tp->root);
cc7ec456f   Eric Dumazet   net_sched: cleanups
142
  	struct fw_filter *f = (struct fw_filter *)arg;
e35a8ee59   John Fastabend   net: sched: fw us...
143
144
  	struct fw_filter __rcu **fp;
  	struct fw_filter *pfp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
  
  	if (head == NULL || f == NULL)
  		goto out;
e35a8ee59   John Fastabend   net: sched: fw us...
148
149
150
151
152
153
  	fp = &head->ht[fw_hash(f->id)];
  
  	for (pfp = rtnl_dereference(*fp); pfp;
  	     fp = &pfp->next, pfp = rtnl_dereference(*fp)) {
  		if (pfp == f) {
  			RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
18cdb37eb   John Fastabend   net: sched: do no...
154
  			tcf_unbind_filter(tp, &f->res);
e35a8ee59   John Fastabend   net: sched: fw us...
155
  			call_rcu(&f->rcu, fw_delete_filter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
159
160
161
  			return 0;
  		}
  	}
  out:
  	return -EINVAL;
  }
6fa8c0144   Patrick McHardy   [NET_SCHED]: Use ...
162
163
164
165
166
  static const struct nla_policy fw_policy[TCA_FW_MAX + 1] = {
  	[TCA_FW_CLASSID]	= { .type = NLA_U32 },
  	[TCA_FW_INDEV]		= { .type = NLA_STRING, .len = IFNAMSIZ },
  	[TCA_FW_MASK]		= { .type = NLA_U32 },
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  static int
c1b52739e   Benjamin LaHaise   pkt_sched: namesp...
168
  fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f,
2f7ef2f87   Cong Wang   sched, cls: check...
169
  	struct nlattr **tb, struct nlattr **tca, unsigned long base, bool ovr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  {
e35a8ee59   John Fastabend   net: sched: fw us...
171
  	struct fw_head *head = rtnl_dereference(tp->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  	struct tcf_exts e;
b4e9b520c   Patrick McHardy   [NET_SCHED]: Add ...
173
  	u32 mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  	int err;
5da57f422   WANG Cong   net_sched: cls: r...
175
  	tcf_exts_init(&e, TCA_FW_ACT, TCA_FW_POLICE);
2f7ef2f87   Cong Wang   sched, cls: check...
176
  	err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
  	if (err < 0)
  		return err;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
179
  	if (tb[TCA_FW_CLASSID]) {
1587bac49   Patrick McHardy   [NET_SCHED]: Use ...
180
  		f->res.classid = nla_get_u32(tb[TCA_FW_CLASSID]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
  		tcf_bind_filter(tp, &f->res, base);
  	}
  
  #ifdef CONFIG_NET_CLS_IND
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
185
  	if (tb[TCA_FW_INDEV]) {
2519a602c   WANG Cong   net_sched: optimi...
186
187
  		int ret;
  		ret = tcf_change_indev(net, tb[TCA_FW_INDEV]);
722e47d79   Wei Yongjun   net_sched: fix er...
188
189
  		if (ret < 0) {
  			err = ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
  			goto errout;
722e47d79   Wei Yongjun   net_sched: fix er...
191
  		}
2519a602c   WANG Cong   net_sched: optimi...
192
  		f->ifindex = ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  	}
  #endif /* CONFIG_NET_CLS_IND */
cb95ec626   Wei Yongjun   pkt_sched: fix er...
195
  	err = -EINVAL;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
196
  	if (tb[TCA_FW_MASK]) {
1587bac49   Patrick McHardy   [NET_SCHED]: Use ...
197
  		mask = nla_get_u32(tb[TCA_FW_MASK]);
b4e9b520c   Patrick McHardy   [NET_SCHED]: Add ...
198
199
200
201
  		if (mask != head->mask)
  			goto errout;
  	} else if (head->mask != 0xFFFFFFFF)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
  	tcf_exts_change(tp, &f->exts, &e);
  
  	return 0;
  errout:
18d0264f6   WANG Cong   net_sched: remove...
206
  	tcf_exts_destroy(&e);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
  	return err;
  }
c1b52739e   Benjamin LaHaise   pkt_sched: namesp...
209
  static int fw_change(struct net *net, struct sk_buff *in_skb,
af4c6641f   Eric W. Biederman   net sched: Pass t...
210
  		     struct tcf_proto *tp, unsigned long base,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  		     u32 handle,
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
212
  		     struct nlattr **tca,
2f7ef2f87   Cong Wang   sched, cls: check...
213
  		     unsigned long *arg, bool ovr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  {
e35a8ee59   John Fastabend   net: sched: fw us...
215
  	struct fw_head *head = rtnl_dereference(tp->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  	struct fw_filter *f = (struct fw_filter *) *arg;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
217
218
  	struct nlattr *opt = tca[TCA_OPTIONS];
  	struct nlattr *tb[TCA_FW_MAX + 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
  	int err;
  
  	if (!opt)
  		return handle ? -EINVAL : 0;
6fa8c0144   Patrick McHardy   [NET_SCHED]: Use ...
223
  	err = nla_parse_nested(tb, TCA_FW_MAX, opt, fw_policy);
cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
224
225
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226

e35a8ee59   John Fastabend   net: sched: fw us...
227
228
229
  	if (f) {
  		struct fw_filter *pfp, *fnew;
  		struct fw_filter __rcu **fp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
  		if (f->id != handle && handle)
  			return -EINVAL;
e35a8ee59   John Fastabend   net: sched: fw us...
232
233
234
235
236
237
238
239
240
241
242
  
  		fnew = kzalloc(sizeof(struct fw_filter), GFP_KERNEL);
  		if (!fnew)
  			return -ENOBUFS;
  
  		fnew->id = f->id;
  		fnew->res = f->res;
  #ifdef CONFIG_NET_CLS_IND
  		fnew->ifindex = f->ifindex;
  #endif /* CONFIG_NET_CLS_IND */
  		fnew->tp = f->tp;
e1f93eb06   John Fastabend   net: sched: cls_f...
243
  		tcf_exts_init(&fnew->exts, TCA_FW_ACT, TCA_FW_POLICE);
e35a8ee59   John Fastabend   net: sched: fw us...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  		err = fw_change_attrs(net, tp, fnew, tb, tca, base, ovr);
  		if (err < 0) {
  			kfree(fnew);
  			return err;
  		}
  
  		fp = &head->ht[fw_hash(fnew->id)];
  		for (pfp = rtnl_dereference(*fp); pfp;
  		     fp = &pfp->next, pfp = rtnl_dereference(*fp))
  			if (pfp == f)
  				break;
  
  		RCU_INIT_POINTER(fnew->next, rtnl_dereference(pfp->next));
  		rcu_assign_pointer(*fp, fnew);
18cdb37eb   John Fastabend   net: sched: do no...
258
  		tcf_unbind_filter(tp, &f->res);
e35a8ee59   John Fastabend   net: sched: fw us...
259
260
261
262
  		call_rcu(&f->rcu, fw_delete_filter);
  
  		*arg = (unsigned long)fnew;
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
267
268
  	}
  
  	if (!handle)
  		return -EINVAL;
  
  	if (head == NULL) {
b4e9b520c   Patrick McHardy   [NET_SCHED]: Add ...
269
  		u32 mask = 0xFFFFFFFF;
6fa8c0144   Patrick McHardy   [NET_SCHED]: Use ...
270
  		if (tb[TCA_FW_MASK])
1587bac49   Patrick McHardy   [NET_SCHED]: Use ...
271
  			mask = nla_get_u32(tb[TCA_FW_MASK]);
b4e9b520c   Patrick McHardy   [NET_SCHED]: Add ...
272

0da974f4f   Panagiotis Issaris   [NET]: Conversion...
273
  		head = kzalloc(sizeof(struct fw_head), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
  		if (head == NULL)
  			return -ENOBUFS;
b4e9b520c   Patrick McHardy   [NET_SCHED]: Add ...
276
  		head->mask = mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277

e35a8ee59   John Fastabend   net: sched: fw us...
278
  		rcu_assign_pointer(tp->root, head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  	}
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
280
  	f = kzalloc(sizeof(struct fw_filter), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
  	if (f == NULL)
  		return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283

5da57f422   WANG Cong   net_sched: cls: r...
284
  	tcf_exts_init(&f->exts, TCA_FW_ACT, TCA_FW_POLICE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  	f->id = handle;
e35a8ee59   John Fastabend   net: sched: fw us...
286
  	f->tp = tp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287

2f7ef2f87   Cong Wang   sched, cls: check...
288
  	err = fw_change_attrs(net, tp, f, tb, tca, base, ovr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
  	if (err < 0)
  		goto errout;
e35a8ee59   John Fastabend   net: sched: fw us...
291
292
  	RCU_INIT_POINTER(f->next, head->ht[fw_hash(handle)]);
  	rcu_assign_pointer(head->ht[fw_hash(handle)], f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
295
296
297
  
  	*arg = (unsigned long)f;
  	return 0;
  
  errout:
a51482bde   Jesper Juhl   [NET]: kfree cleanup
298
  	kfree(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
302
303
  	return err;
  }
  
  static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
  {
e35a8ee59   John Fastabend   net: sched: fw us...
304
  	struct fw_head *head = rtnl_dereference(tp->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
309
310
311
  	int h;
  
  	if (head == NULL)
  		arg->stop = 1;
  
  	if (arg->stop)
  		return;
c5c13fafd   Thomas Graf   [PKT_SCHED]: impr...
312
  	for (h = 0; h < HTSIZE; h++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  		struct fw_filter *f;
e35a8ee59   John Fastabend   net: sched: fw us...
314
315
  		for (f = rtnl_dereference(head->ht[h]); f;
  		     f = rtnl_dereference(f->next)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
320
321
322
323
324
325
326
327
  			if (arg->count < arg->skip) {
  				arg->count++;
  				continue;
  			}
  			if (arg->fn(tp, (unsigned long)f, arg) < 0) {
  				arg->stop = 1;
  				return;
  			}
  			arg->count++;
  		}
  	}
  }
832d1d5bf   WANG Cong   net_sched: add st...
328
  static int fw_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
  		   struct sk_buff *skb, struct tcmsg *t)
  {
e35a8ee59   John Fastabend   net: sched: fw us...
331
  	struct fw_head *head = rtnl_dereference(tp->root);
cc7ec456f   Eric Dumazet   net_sched: cleanups
332
  	struct fw_filter *f = (struct fw_filter *)fh;
4b3550ef5   Patrick McHardy   [NET_SCHED]: Use ...
333
  	struct nlattr *nest;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
338
339
340
341
  
  	if (f == NULL)
  		return skb->len;
  
  	t->tcm_handle = f->id;
  
  	if (!f->res.classid && !tcf_exts_is_available(&f->exts))
  		return skb->len;
4b3550ef5   Patrick McHardy   [NET_SCHED]: Use ...
342
343
344
  	nest = nla_nest_start(skb, TCA_OPTIONS);
  	if (nest == NULL)
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345

1b34ec43c   David S. Miller   pkt_sched: Stop u...
346
347
348
  	if (f->res.classid &&
  	    nla_put_u32(skb, TCA_FW_CLASSID, f->res.classid))
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  #ifdef CONFIG_NET_CLS_IND
2519a602c   WANG Cong   net_sched: optimi...
350
351
352
353
354
355
  	if (f->ifindex) {
  		struct net_device *dev;
  		dev = __dev_get_by_index(net, f->ifindex);
  		if (dev && nla_put_string(skb, TCA_FW_INDEV, dev->name))
  			goto nla_put_failure;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  #endif /* CONFIG_NET_CLS_IND */
1b34ec43c   David S. Miller   pkt_sched: Stop u...
357
358
359
  	if (head->mask != 0xFFFFFFFF &&
  	    nla_put_u32(skb, TCA_FW_MASK, head->mask))
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360

5da57f422   WANG Cong   net_sched: cls: r...
361
  	if (tcf_exts_dump(skb, &f->exts) < 0)
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
362
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363

4b3550ef5   Patrick McHardy   [NET_SCHED]: Use ...
364
  	nla_nest_end(skb, nest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365

5da57f422   WANG Cong   net_sched: cls: r...
366
  	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
367
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
  
  	return skb->len;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
370
  nla_put_failure:
6ea3b446b   Jiri Pirko   net: sched: cls: ...
371
  	nla_nest_cancel(skb, nest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
  	return -1;
  }
2eb9d75c7   Patrick McHardy   [NET_SCHED]: mark...
374
  static struct tcf_proto_ops cls_fw_ops __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
378
379
  	.kind		=	"fw",
  	.classify	=	fw_classify,
  	.init		=	fw_init,
  	.destroy	=	fw_destroy,
  	.get		=	fw_get,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
384
385
386
387
388
389
390
  	.change		=	fw_change,
  	.delete		=	fw_delete,
  	.walk		=	fw_walk,
  	.dump		=	fw_dump,
  	.owner		=	THIS_MODULE,
  };
  
  static int __init init_fw(void)
  {
  	return register_tcf_proto_ops(&cls_fw_ops);
  }
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
391
  static void __exit exit_fw(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
396
397
398
  {
  	unregister_tcf_proto_ops(&cls_fw_ops);
  }
  
  module_init(init_fw)
  module_exit(exit_fw)
  MODULE_LICENSE("GPL");