Blame view

net/sched/cls_fw.c 9.71 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
  /*
   * net/sched/cls_fw.c	Classifier mapping ipchains' fwmark to traffic class.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
10
   * 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
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
13
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
  #include <linux/types.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include <linux/errno.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include <linux/skbuff.h>
0ba480538   Patrick McHardy   [NET_SCHED]: Remo...
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>
1abf27202   Jiri Pirko   net: sched: tcind...
22
  #include <net/sch_generic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

d37d8ac17   Eric Dumazet   net: sched: use n...
24
  #define HTSIZE 256
c5c13fafd   Thomas Graf   [PKT_SCHED]: impr...
25

cc7ec456f   Eric Dumazet   net_sched: cleanups
26
  struct fw_head {
d37d8ac17   Eric Dumazet   net: sched: use n...
27
  	u32			mask;
e35a8ee59   John Fastabend   net: sched: fw us...
28
29
  	struct fw_filter __rcu	*ht[HTSIZE];
  	struct rcu_head		rcu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  };
cc7ec456f   Eric Dumazet   net_sched: cleanups
31
  struct fw_filter {
e35a8ee59   John Fastabend   net: sched: fw us...
32
  	struct fw_filter __rcu	*next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
  	u32			id;
  	struct tcf_result	res;
2519a602c   WANG Cong   net_sched: optimi...
35
  	int			ifindex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  	struct tcf_exts		exts;
e35a8ee59   John Fastabend   net: sched: fw us...
37
  	struct tcf_proto	*tp;
aaa908ffb   Cong Wang   net_sched: switch...
38
  	struct rcu_work		rwork;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  };
d37d8ac17   Eric Dumazet   net: sched: use n...
40
  static u32 fw_hash(u32 handle)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  {
d37d8ac17   Eric Dumazet   net: sched: use n...
42
43
44
  	handle ^= (handle >> 16);
  	handle ^= (handle >> 8);
  	return handle % HTSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  }
dc7f9f6e8   Eric Dumazet   net: sched: const...
46
  static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp,
5a7a5555a   Jamal Hadi Salim   net sched: stylis...
47
  		       struct tcf_result *res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  {
e35a8ee59   John Fastabend   net: sched: fw us...
49
  	struct fw_head *head = rcu_dereference_bh(tp->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
  	struct fw_filter *f;
  	int r;
5c804bfdc   Patrick McHardy   [NET_SCHED]: cls_...
52
  	u32 id = skb->mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
  
  	if (head != NULL) {
5c804bfdc   Patrick McHardy   [NET_SCHED]: cls_...
55
  		id &= head->mask;
e35a8ee59   John Fastabend   net: sched: fw us...
56
57
58
  
  		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
59
60
  			if (f->id == id) {
  				*res = f->res;
2519a602c   WANG Cong   net_sched: optimi...
61
  				if (!tcf_match_indev(skb, f->ifindex))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  					continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
67
68
69
70
  				r = tcf_exts_exec(skb, &f->exts, res);
  				if (r < 0)
  					continue;
  
  				return r;
  			}
  		}
  	} else {
1abf27202   Jiri Pirko   net: sched: tcind...
71
  		struct Qdisc *q = tcf_block_q(tp->chain->block);
d8aecb101   WANG Cong   net: revert "net_...
72
  		/* Old method: classify the packet using its skb mark. */
cc7ec456f   Eric Dumazet   net_sched: cleanups
73
  		if (id && (TC_H_MAJ(id) == 0 ||
1abf27202   Jiri Pirko   net: sched: tcind...
74
  			   !(TC_H_MAJ(id ^ q->handle)))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
79
80
81
82
  			res->classid = id;
  			res->class = 0;
  			return 0;
  		}
  	}
  
  	return -1;
  }
8113c0956   WANG Cong   net_sched: use vo...
83
  static void *fw_get(struct tcf_proto *tp, u32 handle)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  {
e35a8ee59   John Fastabend   net: sched: fw us...
85
  	struct fw_head *head = rtnl_dereference(tp->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
  	struct fw_filter *f;
  
  	if (head == NULL)
8113c0956   WANG Cong   net_sched: use vo...
89
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90

e35a8ee59   John Fastabend   net: sched: fw us...
91
92
  	f = rtnl_dereference(head->ht[fw_hash(handle)]);
  	for (; f; f = rtnl_dereference(f->next)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  		if (f->id == handle)
8113c0956   WANG Cong   net_sched: use vo...
94
  			return f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  	}
8113c0956   WANG Cong   net_sched: use vo...
96
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
  static int fw_init(struct tcf_proto *tp)
  {
d8aecb101   WANG Cong   net: revert "net_...
100
101
102
  	/* We don't allocate fw_head here, because in the old method
  	 * we don't need it at all.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
  	return 0;
  }
d5f984f5a   Cong Wang   cls_fw: use tcf_e...
105
106
107
108
109
110
  static void __fw_delete_filter(struct fw_filter *f)
  {
  	tcf_exts_destroy(&f->exts);
  	tcf_exts_put_net(&f->exts);
  	kfree(f);
  }
e071dff2a   Cong Wang   net_sched: use tc...
111
  static void fw_delete_filter_work(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  {
aaa908ffb   Cong Wang   net_sched: switch...
113
114
115
  	struct fw_filter *f = container_of(to_rcu_work(work),
  					   struct fw_filter,
  					   rwork);
e071dff2a   Cong Wang   net_sched: use tc...
116
  	rtnl_lock();
d5f984f5a   Cong Wang   cls_fw: use tcf_e...
117
  	__fw_delete_filter(f);
e071dff2a   Cong Wang   net_sched: use tc...
118
119
  	rtnl_unlock();
  }
12db03b65   Vlad Buslov   net: sched: exten...
120
121
  static void fw_destroy(struct tcf_proto *tp, bool rtnl_held,
  		       struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  {
e35a8ee59   John Fastabend   net: sched: fw us...
123
  	struct fw_head *head = rtnl_dereference(tp->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
  	struct fw_filter *f;
  	int h;
  
  	if (head == NULL)
763dbf632   WANG Cong   net_sched: move t...
128
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129

cc7ec456f   Eric Dumazet   net_sched: cleanups
130
  	for (h = 0; h < HTSIZE; h++) {
e35a8ee59   John Fastabend   net: sched: fw us...
131
132
133
  		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...
134
  			tcf_unbind_filter(tp, &f->res);
d5f984f5a   Cong Wang   cls_fw: use tcf_e...
135
  			if (tcf_exts_get_net(&f->exts))
aaa908ffb   Cong Wang   net_sched: switch...
136
  				tcf_queue_work(&f->rwork, fw_delete_filter_work);
d5f984f5a   Cong Wang   cls_fw: use tcf_e...
137
138
  			else
  				__fw_delete_filter(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
  		}
  	}
e35a8ee59   John Fastabend   net: sched: fw us...
141
  	kfree_rcu(head, rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  }
571acf210   Alexander Aring   net: sched: cls: ...
143
  static int fw_delete(struct tcf_proto *tp, void *arg, bool *last,
12db03b65   Vlad Buslov   net: sched: exten...
144
  		     bool rtnl_held, struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  {
e35a8ee59   John Fastabend   net: sched: fw us...
146
  	struct fw_head *head = rtnl_dereference(tp->root);
8113c0956   WANG Cong   net_sched: use vo...
147
  	struct fw_filter *f = arg;
e35a8ee59   John Fastabend   net: sched: fw us...
148
149
  	struct fw_filter __rcu **fp;
  	struct fw_filter *pfp;
763dbf632   WANG Cong   net_sched: move t...
150
151
  	int ret = -EINVAL;
  	int h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
  
  	if (head == NULL || f == NULL)
  		goto out;
e35a8ee59   John Fastabend   net: sched: fw us...
155
156
157
158
159
160
  	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...
161
  			tcf_unbind_filter(tp, &f->res);
d5f984f5a   Cong Wang   cls_fw: use tcf_e...
162
  			tcf_exts_get_net(&f->exts);
aaa908ffb   Cong Wang   net_sched: switch...
163
  			tcf_queue_work(&f->rwork, fw_delete_filter_work);
763dbf632   WANG Cong   net_sched: move t...
164
165
  			ret = 0;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
  		}
  	}
763dbf632   WANG Cong   net_sched: move t...
168
169
170
171
172
173
174
175
  
  	*last = true;
  	for (h = 0; h < HTSIZE; h++) {
  		if (rcu_access_pointer(head->ht[h])) {
  			*last = false;
  			break;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
  out:
763dbf632   WANG Cong   net_sched: move t...
177
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  }
6fa8c0144   Patrick McHardy   [NET_SCHED]: Use ...
179
180
181
182
183
  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 },
  };
1e5003af3   Jiri Pirko   net: sched: cls_f...
184
185
  static int fw_set_parms(struct net *net, struct tcf_proto *tp,
  			struct fw_filter *f, struct nlattr **tb,
50a561900   Alexander Aring   net: sched: cls: ...
186
187
  			struct nlattr **tca, unsigned long base, bool ovr,
  			struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  {
e35a8ee59   John Fastabend   net: sched: fw us...
189
  	struct fw_head *head = rtnl_dereference(tp->root);
b4e9b520c   Patrick McHardy   [NET_SCHED]: Add ...
190
  	u32 mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  	int err;
50a561900   Alexander Aring   net: sched: cls: ...
192
  	err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &f->exts, ovr,
ec6743a10   Vlad Buslov   net: sched: track...
193
  				true, extack);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
  	if (err < 0)
  		return err;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
196
  	if (tb[TCA_FW_CLASSID]) {
1587bac49   Patrick McHardy   [NET_SCHED]: Use ...
197
  		f->res.classid = nla_get_u32(tb[TCA_FW_CLASSID]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
  		tcf_bind_filter(tp, &f->res, base);
  	}
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
200
  	if (tb[TCA_FW_INDEV]) {
2519a602c   WANG Cong   net_sched: optimi...
201
  		int ret;
1057c55f6   Alexander Aring   net: sched: cls: ...
202
  		ret = tcf_change_indev(net, tb[TCA_FW_INDEV], extack);
94611bff6   Jiri Pirko   net: sched: cls_f...
203
204
  		if (ret < 0)
  			return ret;
2519a602c   WANG Cong   net_sched: optimi...
205
  		f->ifindex = ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207

cb95ec626   Wei Yongjun   pkt_sched: fix er...
208
  	err = -EINVAL;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
209
  	if (tb[TCA_FW_MASK]) {
1587bac49   Patrick McHardy   [NET_SCHED]: Use ...
210
  		mask = nla_get_u32(tb[TCA_FW_MASK]);
b4e9b520c   Patrick McHardy   [NET_SCHED]: Add ...
211
  		if (mask != head->mask)
94611bff6   Jiri Pirko   net: sched: cls_f...
212
  			return err;
b4e9b520c   Patrick McHardy   [NET_SCHED]: Add ...
213
  	} else if (head->mask != 0xFFFFFFFF)
94611bff6   Jiri Pirko   net: sched: cls_f...
214
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  }
c1b52739e   Benjamin LaHaise   pkt_sched: namesp...
218
  static int fw_change(struct net *net, struct sk_buff *in_skb,
af4c6641f   Eric W. Biederman   net sched: Pass t...
219
  		     struct tcf_proto *tp, unsigned long base,
8113c0956   WANG Cong   net_sched: use vo...
220
  		     u32 handle, struct nlattr **tca, void **arg,
12db03b65   Vlad Buslov   net: sched: exten...
221
222
  		     bool ovr, bool rtnl_held,
  		     struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  {
e35a8ee59   John Fastabend   net: sched: fw us...
224
  	struct fw_head *head = rtnl_dereference(tp->root);
8113c0956   WANG Cong   net_sched: use vo...
225
  	struct fw_filter *f = *arg;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
226
227
  	struct nlattr *opt = tca[TCA_OPTIONS];
  	struct nlattr *tb[TCA_FW_MAX + 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
  	int err;
  
  	if (!opt)
d8aecb101   WANG Cong   net: revert "net_...
231
  		return handle ? -EINVAL : 0; /* Succeed if it is old method. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232

8cb081746   Johannes Berg   netlink: make val...
233
234
  	err = nla_parse_nested_deprecated(tb, TCA_FW_MAX, opt, fw_policy,
  					  NULL);
cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
235
236
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237

e35a8ee59   John Fastabend   net: sched: fw us...
238
239
240
  	if (f) {
  		struct fw_filter *pfp, *fnew;
  		struct fw_filter __rcu **fp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
  		if (f->id != handle && handle)
  			return -EINVAL;
e35a8ee59   John Fastabend   net: sched: fw us...
243
244
245
246
247
248
249
  
  		fnew = kzalloc(sizeof(struct fw_filter), GFP_KERNEL);
  		if (!fnew)
  			return -ENOBUFS;
  
  		fnew->id = f->id;
  		fnew->res = f->res;
e35a8ee59   John Fastabend   net: sched: fw us...
250
  		fnew->ifindex = f->ifindex;
e35a8ee59   John Fastabend   net: sched: fw us...
251
  		fnew->tp = f->tp;
14215108a   Cong Wang   net_sched: initia...
252
253
  		err = tcf_exts_init(&fnew->exts, net, TCA_FW_ACT,
  				    TCA_FW_POLICE);
b9a24bb76   WANG Cong   net_sched: proper...
254
255
256
257
  		if (err < 0) {
  			kfree(fnew);
  			return err;
  		}
e1f93eb06   John Fastabend   net: sched: cls_f...
258

50a561900   Alexander Aring   net: sched: cls: ...
259
  		err = fw_set_parms(net, tp, fnew, tb, tca, base, ovr, extack);
e35a8ee59   John Fastabend   net: sched: fw us...
260
  		if (err < 0) {
b9a24bb76   WANG Cong   net_sched: proper...
261
  			tcf_exts_destroy(&fnew->exts);
e35a8ee59   John Fastabend   net: sched: fw us...
262
263
264
265
266
267
268
269
270
271
272
273
  			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...
274
  		tcf_unbind_filter(tp, &f->res);
d5f984f5a   Cong Wang   cls_fw: use tcf_e...
275
  		tcf_exts_get_net(&f->exts);
aaa908ffb   Cong Wang   net_sched: switch...
276
  		tcf_queue_work(&f->rwork, fw_delete_filter_work);
e35a8ee59   John Fastabend   net: sched: fw us...
277

8113c0956   WANG Cong   net_sched: use vo...
278
  		*arg = fnew;
e35a8ee59   John Fastabend   net: sched: fw us...
279
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
  	}
  
  	if (!handle)
  		return -EINVAL;
d8aecb101   WANG Cong   net: revert "net_...
284
285
  	if (!head) {
  		u32 mask = 0xFFFFFFFF;
6fa8c0144   Patrick McHardy   [NET_SCHED]: Use ...
286
  		if (tb[TCA_FW_MASK])
d8aecb101   WANG Cong   net: revert "net_...
287
288
289
290
291
292
293
294
  			mask = nla_get_u32(tb[TCA_FW_MASK]);
  
  		head = kzalloc(sizeof(*head), GFP_KERNEL);
  		if (!head)
  			return -ENOBUFS;
  		head->mask = mask;
  
  		rcu_assign_pointer(tp->root, head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  	}
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
296
  	f = kzalloc(sizeof(struct fw_filter), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
  	if (f == NULL)
  		return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299

14215108a   Cong Wang   net_sched: initia...
300
  	err = tcf_exts_init(&f->exts, net, TCA_FW_ACT, TCA_FW_POLICE);
b9a24bb76   WANG Cong   net_sched: proper...
301
302
  	if (err < 0)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  	f->id = handle;
e35a8ee59   John Fastabend   net: sched: fw us...
304
  	f->tp = tp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305

50a561900   Alexander Aring   net: sched: cls: ...
306
  	err = fw_set_parms(net, tp, f, tb, tca, base, ovr, extack);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
  	if (err < 0)
  		goto errout;
e35a8ee59   John Fastabend   net: sched: fw us...
309
310
  	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
311

8113c0956   WANG Cong   net_sched: use vo...
312
  	*arg = f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
315
  	return 0;
  
  errout:
b9a24bb76   WANG Cong   net_sched: proper...
316
  	tcf_exts_destroy(&f->exts);
a51482bde   Jesper Juhl   [NET]: kfree cleanup
317
  	kfree(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
  	return err;
  }
12db03b65   Vlad Buslov   net: sched: exten...
320
321
  static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg,
  		    bool rtnl_held)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
  {
e35a8ee59   John Fastabend   net: sched: fw us...
323
  	struct fw_head *head = rtnl_dereference(tp->root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  	int h;
1d9978757   Vlad Buslov   Revert "net: sche...
325
326
327
328
  	if (head == NULL)
  		arg->stop = 1;
  
  	if (arg->stop)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  		return;
c5c13fafd   Thomas Graf   [PKT_SCHED]: impr...
330
  	for (h = 0; h < HTSIZE; h++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  		struct fw_filter *f;
e35a8ee59   John Fastabend   net: sched: fw us...
332
333
  		for (f = rtnl_dereference(head->ht[h]); f;
  		     f = rtnl_dereference(f->next)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
  			if (arg->count < arg->skip) {
  				arg->count++;
  				continue;
  			}
8113c0956   WANG Cong   net_sched: use vo...
338
  			if (arg->fn(tp, f, arg) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
343
344
345
  				arg->stop = 1;
  				return;
  			}
  			arg->count++;
  		}
  	}
  }
8113c0956   WANG Cong   net_sched: use vo...
346
  static int fw_dump(struct net *net, struct tcf_proto *tp, void *fh,
12db03b65   Vlad Buslov   net: sched: exten...
347
  		   struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
  {
e35a8ee59   John Fastabend   net: sched: fw us...
349
  	struct fw_head *head = rtnl_dereference(tp->root);
8113c0956   WANG Cong   net_sched: use vo...
350
  	struct fw_filter *f = fh;
4b3550ef5   Patrick McHardy   [NET_SCHED]: Use ...
351
  	struct nlattr *nest;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
356
  
  	if (f == NULL)
  		return skb->len;
  
  	t->tcm_handle = f->id;
6fc6d06e5   Jiri Pirko   net: sched: remov...
357
  	if (!f->res.classid && !tcf_exts_has_actions(&f->exts))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  		return skb->len;
ae0be8de9   Michal Kubecek   netlink: make nla...
359
  	nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
4b3550ef5   Patrick McHardy   [NET_SCHED]: Use ...
360
361
  	if (nest == NULL)
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362

1b34ec43c   David S. Miller   pkt_sched: Stop u...
363
364
365
  	if (f->res.classid &&
  	    nla_put_u32(skb, TCA_FW_CLASSID, f->res.classid))
  		goto nla_put_failure;
2519a602c   WANG Cong   net_sched: optimi...
366
367
368
369
370
371
  	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;
  	}
1b34ec43c   David S. Miller   pkt_sched: Stop u...
372
373
374
  	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
375

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

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

5da57f422   WANG Cong   net_sched: cls: r...
381
  	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
382
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
  
  	return skb->len;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
385
  nla_put_failure:
6ea3b446b   Jiri Pirko   net: sched: cls: ...
386
  	nla_nest_cancel(skb, nest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
  	return -1;
  }
2e24cd755   Cong Wang   net_sched: fix op...
389
390
  static void fw_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
  			  unsigned long base)
07d79fc7d   Cong Wang   net_sched: add re...
391
392
  {
  	struct fw_filter *f = fh;
2e24cd755   Cong Wang   net_sched: fix op...
393
394
395
396
397
398
  	if (f && f->res.classid == classid) {
  		if (cl)
  			__tcf_bind_filter(q, &f->res, base);
  		else
  			__tcf_unbind_filter(q, &f->res);
  	}
07d79fc7d   Cong Wang   net_sched: add re...
399
  }
2eb9d75c7   Patrick McHardy   [NET_SCHED]: mark...
400
  static struct tcf_proto_ops cls_fw_ops __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
402
403
404
405
  	.kind		=	"fw",
  	.classify	=	fw_classify,
  	.init		=	fw_init,
  	.destroy	=	fw_destroy,
  	.get		=	fw_get,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
  	.change		=	fw_change,
  	.delete		=	fw_delete,
  	.walk		=	fw_walk,
  	.dump		=	fw_dump,
07d79fc7d   Cong Wang   net_sched: add re...
410
  	.bind_class	=	fw_bind_class,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
416
417
  	.owner		=	THIS_MODULE,
  };
  
  static int __init init_fw(void)
  {
  	return register_tcf_proto_ops(&cls_fw_ops);
  }
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
418
  static void __exit exit_fw(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
421
422
423
424
425
  {
  	unregister_tcf_proto_ops(&cls_fw_ops);
  }
  
  module_init(init_fw)
  module_exit(exit_fw)
  MODULE_LICENSE("GPL");