Blame view

net/sched/sch_dsmark.c 11.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /* net/sched/sch_dsmark.c - Differentiated Services field marker */
  
  /* Written 1998-2000 by Werner Almesberger, EPFL ICA */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
  #include <linux/module.h>
  #include <linux/init.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
6
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
  #include <linux/types.h>
  #include <linux/string.h>
  #include <linux/errno.h>
  #include <linux/skbuff.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/rtnetlink.h>
5b0ac72bc   David S. Miller   [PKT_SCHED] dsmar...
12
  #include <linux/bitops.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
  #include <net/pkt_sched.h>
  #include <net/dsfield.h>
  #include <net/inet_ecn.h>
  #include <asm/byteorder.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  /*
   * classid	class		marking
   * -------	-----		-------
   *   n/a	  0		n/a
   *   x:0	  1		use entry [0]
   *   ...	 ...		...
   *   x:y y>0	 y+1		use entry [y]
   *   ...	 ...		...
   * x:indices-1	indices		use entry [indices-1]
   *   ...	 ...		...
   *   x:y	 y+1		use entry [y & (indices-1)]
   *   ...	 ...		...
   * 0xffff	0x10000		use entry [indices-1]
   */
  
  
  #define NO_DEFAULT_INDEX	(1 << 16)
  
  struct dsmark_qdisc_data {
  	struct Qdisc		*q;
  	struct tcf_proto	*filter_list;
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
38
39
40
41
  	u8			*mask;	/* "owns" the array */
  	u8			*value;
  	u16			indices;
  	u32			default_index;	/* index range is 0...0xffff */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
  	int			set_tc_index;
  };
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
44
45
46
47
  static inline int dsmark_valid_index(struct dsmark_qdisc_data *p, u16 index)
  {
  	return (index <= p->indices && index > 0);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
  
  /* ------------------------- Class/flow operations ------------------------- */
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
50
51
  static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
  			struct Qdisc *new, struct Qdisc **old)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
53
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
55
56
  	pr_debug("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)
  ",
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
57
  		sch, p, new, old);
486b53e59   Thomas Graf   [PKT_SCHED]: make...
58
59
  
  	if (new == NULL) {
3511c9132   Changli Gao   net_sched: remove...
60
  		new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
9f9afec48   Patrick McHardy   [NET_SCHED]: Set ...
61
  					sch->handle);
486b53e59   Thomas Graf   [PKT_SCHED]: make...
62
63
64
  		if (new == NULL)
  			new = &noop_qdisc;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  	sch_tree_lock(sch);
b94c8afcb   Patrick McHardy   pkt_sched: remove...
66
67
  	*old = p->q;
  	p->q = new;
5e50da01d   Patrick McHardy   [NET_SCHED]: Fix ...
68
  	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
69
  	qdisc_reset(*old);
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
70
  	sch_tree_unlock(sch);
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
71
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
  static struct Qdisc *dsmark_leaf(struct Qdisc *sch, unsigned long arg)
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
75
76
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
  	return p->q;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  }
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
78
  static unsigned long dsmark_get(struct Qdisc *sch, u32 classid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
80
81
82
  	pr_debug("dsmark_get(sch %p,[qdisc %p],classid %x)
  ",
  		sch, qdisc_priv(sch), classid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83

af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
84
  	return TC_H_MIN(classid) + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
  static unsigned long dsmark_bind_filter(struct Qdisc *sch,
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
87
  					unsigned long parent, u32 classid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
  {
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
89
  	return dsmark_get(sch, classid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
  static void dsmark_put(struct Qdisc *sch, unsigned long cl)
  {
  }
27a3421e4   Patrick McHardy   [NET_SCHED]: Use ...
94
95
96
97
98
99
100
  static const struct nla_policy dsmark_policy[TCA_DSMARK_MAX + 1] = {
  	[TCA_DSMARK_INDICES]		= { .type = NLA_U16 },
  	[TCA_DSMARK_DEFAULT_INDEX]	= { .type = NLA_U16 },
  	[TCA_DSMARK_SET_TC_INDEX]	= { .type = NLA_FLAG },
  	[TCA_DSMARK_MASK]		= { .type = NLA_U8 },
  	[TCA_DSMARK_VALUE]		= { .type = NLA_U8 },
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  static int dsmark_change(struct Qdisc *sch, u32 classid, u32 parent,
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
102
  			 struct nlattr **tca, unsigned long *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
104
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
105
106
  	struct nlattr *opt = tca[TCA_OPTIONS];
  	struct nlattr *tb[TCA_DSMARK_MAX + 1];
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
107
108
  	int err = -EINVAL;
  	u8 mask = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109

81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
110
  	pr_debug("dsmark_change(sch %p,[qdisc %p],classid %x,parent %x),"
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
111
112
113
114
115
  		"arg 0x%lx
  ", sch, p, classid, parent, *arg);
  
  	if (!dsmark_valid_index(p, *arg)) {
  		err = -ENOENT;
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
116
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118

cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
119
  	if (!opt)
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
120
  		goto errout;
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
121

27a3421e4   Patrick McHardy   [NET_SCHED]: Use ...
122
  	err = nla_parse_nested(tb, TCA_DSMARK_MAX, opt, dsmark_policy);
cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
123
  	if (err < 0)
27a3421e4   Patrick McHardy   [NET_SCHED]: Use ...
124
  		goto errout;
cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
125

27a3421e4   Patrick McHardy   [NET_SCHED]: Use ...
126
  	if (tb[TCA_DSMARK_MASK])
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
127
  		mask = nla_get_u8(tb[TCA_DSMARK_MASK]);
27a3421e4   Patrick McHardy   [NET_SCHED]: Use ...
128
129
  
  	if (tb[TCA_DSMARK_VALUE])
cc7ec456f   Eric Dumazet   net_sched: cleanups
130
  		p->value[*arg - 1] = nla_get_u8(tb[TCA_DSMARK_VALUE]);
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
131

1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
132
  	if (tb[TCA_DSMARK_MASK])
cc7ec456f   Eric Dumazet   net_sched: cleanups
133
  		p->mask[*arg - 1] = mask;
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
134
135
  
  	err = 0;
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
136
  errout:
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
137
138
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139

af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
140
  static int dsmark_delete(struct Qdisc *sch, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
142
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143

af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
144
  	if (!dsmark_valid_index(p, arg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  		return -EINVAL;
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
146

cc7ec456f   Eric Dumazet   net_sched: cleanups
147
148
  	p->mask[arg - 1] = 0xff;
  	p->value[arg - 1] = 0;
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
149

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
  	return 0;
  }
9d127fbdd   Stephen Hemminger   [PKT_SCHED] dsmar...
152
  static void dsmark_walk(struct Qdisc *sch, struct qdisc_walker *walker)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
154
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  	int i;
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
156
157
  	pr_debug("dsmark_walk(sch %p,[qdisc %p],walker %p)
  ", sch, p, walker);
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
158

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
  	if (walker->stop)
  		return;
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
161

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
  	for (i = 0; i < p->indices; i++) {
  		if (p->mask[i] == 0xff && !p->value[i])
0451eb074   Thomas Graf   [PKT_SCHED]: Fix ...
164
  			goto ignore;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  		if (walker->count >= walker->skip) {
cc7ec456f   Eric Dumazet   net_sched: cleanups
166
  			if (walker->fn(sch, i + 1, walker) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
  				walker->stop = 1;
  				break;
  			}
  		}
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
171
  ignore:
0451eb074   Thomas Graf   [PKT_SCHED]: Fix ...
172
  		walker->count++;
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
173
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  }
9d127fbdd   Stephen Hemminger   [PKT_SCHED] dsmar...
175
176
  static inline struct tcf_proto **dsmark_find_tcf(struct Qdisc *sch,
  						 unsigned long cl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
178
179
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
  	return &p->filter_list;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  /* --------------------------- Qdisc operations ---------------------------- */
9d127fbdd   Stephen Hemminger   [PKT_SCHED] dsmar...
182
  static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
184
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
185
  	int err;
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
186
187
  	pr_debug("dsmark_enqueue(skb %p,sch %p,[qdisc %p])
  ", skb, sch, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  	if (p->set_tc_index) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
  		switch (skb->protocol) {
606780404   Arnaldo Carvalho de Melo   net: Use hton[sl]...
191
  		case htons(ETH_P_IP):
9d127fbdd   Stephen Hemminger   [PKT_SCHED] dsmar...
192
193
  			if (skb_cow_head(skb, sizeof(struct iphdr)))
  				goto drop;
4c30719f4   Stephen Hemminger   [PKT_SCHED] dsmar...
194

9d127fbdd   Stephen Hemminger   [PKT_SCHED] dsmar...
195
196
197
  			skb->tc_index = ipv4_get_dsfield(ip_hdr(skb))
  				& ~INET_ECN_MASK;
  			break;
4c30719f4   Stephen Hemminger   [PKT_SCHED] dsmar...
198

606780404   Arnaldo Carvalho de Melo   net: Use hton[sl]...
199
  		case htons(ETH_P_IPV6):
9d127fbdd   Stephen Hemminger   [PKT_SCHED] dsmar...
200
201
  			if (skb_cow_head(skb, sizeof(struct ipv6hdr)))
  				goto drop;
4c30719f4   Stephen Hemminger   [PKT_SCHED] dsmar...
202

9d127fbdd   Stephen Hemminger   [PKT_SCHED] dsmar...
203
204
205
206
207
208
  			skb->tc_index = ipv6_get_dsfield(ipv6_hdr(skb))
  				& ~INET_ECN_MASK;
  			break;
  		default:
  			skb->tc_index = 0;
  			break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
209
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  	}
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
211
212
  
  	if (TC_H_MAJ(skb->priority) == sch->handle)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  		skb->tc_index = TC_H_MIN(skb->priority);
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
214
215
216
  	else {
  		struct tcf_result res;
  		int result = tc_classify(skb, p->filter_list, &res);
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
217
218
  		pr_debug("result %d class 0x%04x
  ", result, res.classid);
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
219

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
  		switch (result) {
f6853e2df   Patrick McHardy   [NET_SCHED]: sch_...
221
222
223
224
  #ifdef CONFIG_NET_CLS_ACT
  		case TC_ACT_QUEUED:
  		case TC_ACT_STOLEN:
  			kfree_skb(skb);
378a2f090   Jarek Poplawski   net_sched: Add qd...
225
  			return NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
4c30719f4   Stephen Hemminger   [PKT_SCHED] dsmar...
226

f6853e2df   Patrick McHardy   [NET_SCHED]: sch_...
227
  		case TC_ACT_SHOT:
4c30719f4   Stephen Hemminger   [PKT_SCHED] dsmar...
228
  			goto drop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  #endif
c3bc7cff8   Patrick McHardy   [NET_SCHED]: Kill...
230
  		case TC_ACT_OK:
f6853e2df   Patrick McHardy   [NET_SCHED]: sch_...
231
232
  			skb->tc_index = TC_H_MIN(res.classid);
  			break;
4c30719f4   Stephen Hemminger   [PKT_SCHED] dsmar...
233

f6853e2df   Patrick McHardy   [NET_SCHED]: sch_...
234
235
236
237
  		default:
  			if (p->default_index != NO_DEFAULT_INDEX)
  				skb->tc_index = p->default_index;
  			break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
238
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240

5f86173bd   Jussi Kivilinna   net_sched: Add qd...
241
  	err = qdisc_enqueue(skb, p->q);
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
242
  	if (err != NET_XMIT_SUCCESS) {
378a2f090   Jarek Poplawski   net_sched: Add qd...
243
244
  		if (net_xmit_drop_count(err))
  			sch->qstats.drops++;
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
245
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  	}
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
247

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  	sch->q.qlen++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249

af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
250
  	return NET_XMIT_SUCCESS;
4c30719f4   Stephen Hemminger   [PKT_SCHED] dsmar...
251
252
253
254
  
  drop:
  	kfree_skb(skb);
  	sch->qstats.drops++;
c27f339af   Jarek Poplawski   net_sched: Add qd...
255
  	return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
256
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
  
  static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
260
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  	struct sk_buff *skb;
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
262
  	u32 index;
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
263
264
  	pr_debug("dsmark_dequeue(sch %p,[qdisc %p])
  ", sch, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  	skb = p->q->ops->dequeue(p->q);
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
267
  	if (skb == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  		return NULL;
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
269

9190b3b32   Eric Dumazet   net_sched: accura...
270
  	qdisc_bstats_update(sch, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  	sch->q.qlen--;
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
272
273
  
  	index = skb->tc_index & (p->indices - 1);
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
274
275
  	pr_debug("index %d->%d
  ", skb->tc_index, index);
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
276

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  	switch (skb->protocol) {
606780404   Arnaldo Carvalho de Melo   net: Use hton[sl]...
278
  	case htons(ETH_P_IP):
9d127fbdd   Stephen Hemminger   [PKT_SCHED] dsmar...
279
280
  		ipv4_change_dsfield(ip_hdr(skb), p->mask[index],
  				    p->value[index]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  			break;
606780404   Arnaldo Carvalho de Melo   net: Use hton[sl]...
282
  	case htons(ETH_P_IPV6):
9d127fbdd   Stephen Hemminger   [PKT_SCHED] dsmar...
283
284
  		ipv6_change_dsfield(ipv6_hdr(skb), p->mask[index],
  				    p->value[index]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  			break;
9d127fbdd   Stephen Hemminger   [PKT_SCHED] dsmar...
286
287
288
289
290
291
292
  	default:
  		/*
  		 * Only complain if a change was actually attempted.
  		 * This way, we can send non-IP traffic through dsmark
  		 * and don't need yet another qdisc as a bypass.
  		 */
  		if (p->mask[index] != 0xff || p->value[index])
cc7ec456f   Eric Dumazet   net_sched: cleanups
293
294
295
  			pr_warning("dsmark_dequeue: unsupported protocol %d
  ",
  				   ntohs(skb->protocol));
9d127fbdd   Stephen Hemminger   [PKT_SCHED] dsmar...
296
  		break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
297
  	}
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
298

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
  	return skb;
  }
8e3af9789   Jarek Poplawski   pkt_sched: Add qd...
301
302
303
304
305
306
307
308
309
  static struct sk_buff *dsmark_peek(struct Qdisc *sch)
  {
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
  
  	pr_debug("dsmark_peek(sch %p,[qdisc %p])
  ", sch, p);
  
  	return p->q->ops->peek(p->q);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
  static unsigned int dsmark_drop(struct Qdisc *sch)
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
312
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  	unsigned int len;
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
314

81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
315
316
  	pr_debug("dsmark_reset(sch %p,[qdisc %p])
  ", sch, p);
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
317
318
  
  	if (p->q->ops->drop == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  		return 0;
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
320
321
322
323
  
  	len = p->q->ops->drop(p->q);
  	if (len)
  		sch->q.qlen--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
  	return len;
  }
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
326
  static int dsmark_init(struct Qdisc *sch, struct nlattr *opt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
328
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
329
  	struct nlattr *tb[TCA_DSMARK_MAX + 1];
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
330
331
332
333
  	int err = -EINVAL;
  	u32 default_index = NO_DEFAULT_INDEX;
  	u16 indices;
  	u8 *mask;
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
334
335
  	pr_debug("dsmark_init(sch %p,[qdisc %p],opt %p)
  ", sch, p, opt);
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
336

cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
337
338
  	if (!opt)
  		goto errout;
27a3421e4   Patrick McHardy   [NET_SCHED]: Use ...
339
  	err = nla_parse_nested(tb, TCA_DSMARK_MAX, opt, dsmark_policy);
cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
340
  	if (err < 0)
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
341
  		goto errout;
cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
342
  	err = -EINVAL;
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
343
  	indices = nla_get_u16(tb[TCA_DSMARK_INDICES]);
5b0ac72bc   David S. Miller   [PKT_SCHED] dsmar...
344
345
  
  	if (hweight32(indices) != 1)
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
346
  		goto errout;
27a3421e4   Patrick McHardy   [NET_SCHED]: Use ...
347
  	if (tb[TCA_DSMARK_DEFAULT_INDEX])
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
348
  		default_index = nla_get_u16(tb[TCA_DSMARK_DEFAULT_INDEX]);
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
349
350
351
352
353
  
  	mask = kmalloc(indices * 2, GFP_KERNEL);
  	if (mask == NULL) {
  		err = -ENOMEM;
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  	}
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
355
356
357
358
359
360
361
362
363
  
  	p->mask = mask;
  	memset(p->mask, 0xff, indices);
  
  	p->value = p->mask + indices;
  	memset(p->value, 0, indices);
  
  	p->indices = indices;
  	p->default_index = default_index;
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
364
  	p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]);
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
365

3511c9132   Changli Gao   net_sched: remove...
366
  	p->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, sch->handle);
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
367
  	if (p->q == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  		p->q = &noop_qdisc;
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
369

81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
370
371
  	pr_debug("dsmark_init: qdisc %p
  ", p->q);
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
372
373
374
  
  	err = 0;
  errout:
758cc43c6   Thomas Graf   [PKT_SCHED]: Fix ...
375
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
  static void dsmark_reset(struct Qdisc *sch)
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
379
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380

81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
381
382
  	pr_debug("dsmark_reset(sch %p,[qdisc %p])
  ", sch, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
385
  	qdisc_reset(p->q);
  	sch->q.qlen = 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
  static void dsmark_destroy(struct Qdisc *sch)
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
388
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389

81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
390
391
  	pr_debug("dsmark_destroy(sch %p,[qdisc %p])
  ", sch, p);
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
392

ff31ab56c   Patrick McHardy   net-sched: change...
393
  	tcf_destroy_chain(&p->filter_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
  	qdisc_destroy(p->q);
  	kfree(p->mask);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
  static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl,
02f23f095   Thomas Graf   [PKT_SCHED]: Make...
398
  			     struct sk_buff *skb, struct tcmsg *tcm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
400
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
401
  	struct nlattr *opts = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402

81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
403
404
  	pr_debug("dsmark_dump_class(sch %p,[qdisc %p],class %ld
  ", sch, p, cl);
02f23f095   Thomas Graf   [PKT_SCHED]: Make...
405
406
  
  	if (!dsmark_valid_index(p, cl))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  		return -EINVAL;
02f23f095   Thomas Graf   [PKT_SCHED]: Make...
408

cc7ec456f   Eric Dumazet   net_sched: cleanups
409
  	tcm->tcm_handle = TC_H_MAKE(TC_H_MAJ(sch->handle), cl - 1);
cdc7f8e36   Patrick McHardy   [PKT_SCHED]: Dump...
410
  	tcm->tcm_info = p->q->handle;
02f23f095   Thomas Graf   [PKT_SCHED]: Make...
411

1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
412
413
414
  	opts = nla_nest_start(skb, TCA_OPTIONS);
  	if (opts == NULL)
  		goto nla_put_failure;
cc7ec456f   Eric Dumazet   net_sched: cleanups
415
416
  	NLA_PUT_U8(skb, TCA_DSMARK_MASK, p->mask[cl - 1]);
  	NLA_PUT_U8(skb, TCA_DSMARK_VALUE, p->value[cl - 1]);
02f23f095   Thomas Graf   [PKT_SCHED]: Make...
417

1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
418
  	return nla_nest_end(skb, opts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419

1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
420
  nla_put_failure:
bc3ed28ca   Thomas Graf   netlink: Improve ...
421
422
  	nla_nest_cancel(skb, opts);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
  }
  
  static int dsmark_dump(struct Qdisc *sch, struct sk_buff *skb)
  {
81da99ed7   Stephen Hemminger   [PKT_SCHED] dsmar...
427
  	struct dsmark_qdisc_data *p = qdisc_priv(sch);
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
428
  	struct nlattr *opts = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429

1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
430
431
432
433
  	opts = nla_nest_start(skb, TCA_OPTIONS);
  	if (opts == NULL)
  		goto nla_put_failure;
  	NLA_PUT_U16(skb, TCA_DSMARK_INDICES, p->indices);
02f23f095   Thomas Graf   [PKT_SCHED]: Make...
434
435
  
  	if (p->default_index != NO_DEFAULT_INDEX)
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
436
  		NLA_PUT_U16(skb, TCA_DSMARK_DEFAULT_INDEX, p->default_index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
  	if (p->set_tc_index)
1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
439
  		NLA_PUT_FLAG(skb, TCA_DSMARK_SET_TC_INDEX);
02f23f095   Thomas Graf   [PKT_SCHED]: Make...
440

1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
441
  	return nla_nest_end(skb, opts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442

1e90474c3   Patrick McHardy   [NET_SCHED]: Conv...
443
  nla_put_failure:
bc3ed28ca   Thomas Graf   netlink: Improve ...
444
445
  	nla_nest_cancel(skb, opts);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  }
20fea08b5   Eric Dumazet   [NET]: Move Qdisc...
447
  static const struct Qdisc_class_ops dsmark_class_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
452
453
454
455
456
457
458
459
  	.graft		=	dsmark_graft,
  	.leaf		=	dsmark_leaf,
  	.get		=	dsmark_get,
  	.put		=	dsmark_put,
  	.change		=	dsmark_change,
  	.delete		=	dsmark_delete,
  	.walk		=	dsmark_walk,
  	.tcf_chain	=	dsmark_find_tcf,
  	.bind_tcf	=	dsmark_bind_filter,
  	.unbind_tcf	=	dsmark_put,
  	.dump		=	dsmark_dump_class,
  };
20fea08b5   Eric Dumazet   [NET]: Move Qdisc...
460
  static struct Qdisc_ops dsmark_qdisc_ops __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
  	.next		=	NULL,
  	.cl_ops		=	&dsmark_class_ops,
  	.id		=	"dsmark",
  	.priv_size	=	sizeof(struct dsmark_qdisc_data),
  	.enqueue	=	dsmark_enqueue,
  	.dequeue	=	dsmark_dequeue,
8e3af9789   Jarek Poplawski   pkt_sched: Add qd...
467
  	.peek		=	dsmark_peek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
470
471
472
473
474
475
476
477
478
479
480
  	.drop		=	dsmark_drop,
  	.init		=	dsmark_init,
  	.reset		=	dsmark_reset,
  	.destroy	=	dsmark_destroy,
  	.change		=	NULL,
  	.dump		=	dsmark_dump,
  	.owner		=	THIS_MODULE,
  };
  
  static int __init dsmark_module_init(void)
  {
  	return register_qdisc(&dsmark_qdisc_ops);
  }
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
481

10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
482
  static void __exit dsmark_module_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
  {
  	unregister_qdisc(&dsmark_qdisc_ops);
  }
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
486

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
  module_init(dsmark_module_init)
  module_exit(dsmark_module_exit)
af0d11417   Thomas Graf   [PKT_SCHED]: Logi...
489

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
  MODULE_LICENSE("GPL");