diff options
-rw-r--r-- | net/sched/sch_dsmark.c | 174 |
1 files changed, 88 insertions, 86 deletions
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index ac0efeae312e..13e0e7b3856b 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | 33 | ||
34 | #define PRIV(sch) qdisc_priv(sch) | 34 | #define PRIV(sch) ((struct dsmark_qdisc_data *) qdisc_priv(sch)) |
35 | 35 | ||
36 | 36 | ||
37 | /* | 37 | /* |
@@ -55,10 +55,10 @@ | |||
55 | struct dsmark_qdisc_data { | 55 | struct dsmark_qdisc_data { |
56 | struct Qdisc *q; | 56 | struct Qdisc *q; |
57 | struct tcf_proto *filter_list; | 57 | struct tcf_proto *filter_list; |
58 | __u8 *mask; /* "owns" the array */ | 58 | u8 *mask; /* "owns" the array */ |
59 | __u8 *value; | 59 | u8 *value; |
60 | __u16 indices; | 60 | u16 indices; |
61 | __u32 default_index; /* index range is 0...0xffff */ | 61 | u32 default_index; /* index range is 0...0xffff */ |
62 | int set_tc_index; | 62 | int set_tc_index; |
63 | }; | 63 | }; |
64 | 64 | ||
@@ -80,14 +80,13 @@ static inline int dsmark_valid_index(struct dsmark_qdisc_data *p, u16 index) | |||
80 | 80 | ||
81 | /* ------------------------- Class/flow operations ------------------------- */ | 81 | /* ------------------------- Class/flow operations ------------------------- */ |
82 | 82 | ||
83 | 83 | static int dsmark_graft(struct Qdisc *sch, unsigned long arg, | |
84 | static int dsmark_graft(struct Qdisc *sch,unsigned long arg, | 84 | struct Qdisc *new, struct Qdisc **old) |
85 | struct Qdisc *new,struct Qdisc **old) | ||
86 | { | 85 | { |
87 | struct dsmark_qdisc_data *p = PRIV(sch); | 86 | struct dsmark_qdisc_data *p = PRIV(sch); |
88 | 87 | ||
89 | DPRINTK("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n",sch,p,new, | 88 | DPRINTK("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n", |
90 | old); | 89 | sch, p, new, old); |
91 | 90 | ||
92 | if (new == NULL) { | 91 | if (new == NULL) { |
93 | new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); | 92 | new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); |
@@ -96,44 +95,37 @@ static int dsmark_graft(struct Qdisc *sch,unsigned long arg, | |||
96 | } | 95 | } |
97 | 96 | ||
98 | sch_tree_lock(sch); | 97 | sch_tree_lock(sch); |
99 | *old = xchg(&p->q,new); | 98 | *old = xchg(&p->q, new); |
100 | if (*old) | 99 | qdisc_reset(*old); |
101 | qdisc_reset(*old); | ||
102 | sch->q.qlen = 0; | 100 | sch->q.qlen = 0; |
103 | sch_tree_unlock(sch); /* @@@ move up ? */ | 101 | sch_tree_unlock(sch); |
102 | |||
104 | return 0; | 103 | return 0; |
105 | } | 104 | } |
106 | 105 | ||
107 | |||
108 | static struct Qdisc *dsmark_leaf(struct Qdisc *sch, unsigned long arg) | 106 | static struct Qdisc *dsmark_leaf(struct Qdisc *sch, unsigned long arg) |
109 | { | 107 | { |
110 | struct dsmark_qdisc_data *p = PRIV(sch); | 108 | return PRIV(sch)->q; |
111 | |||
112 | return p->q; | ||
113 | } | 109 | } |
114 | 110 | ||
115 | 111 | static unsigned long dsmark_get(struct Qdisc *sch, u32 classid) | |
116 | static unsigned long dsmark_get(struct Qdisc *sch,u32 classid) | ||
117 | { | 112 | { |
118 | struct dsmark_qdisc_data *p __attribute__((unused)) = PRIV(sch); | 113 | DPRINTK("dsmark_get(sch %p,[qdisc %p],classid %x)\n", |
114 | sch, PRIV(sch), classid); | ||
119 | 115 | ||
120 | DPRINTK("dsmark_get(sch %p,[qdisc %p],classid %x)\n",sch,p,classid); | 116 | return TC_H_MIN(classid) + 1; |
121 | return TC_H_MIN(classid)+1; | ||
122 | } | 117 | } |
123 | 118 | ||
124 | |||
125 | static unsigned long dsmark_bind_filter(struct Qdisc *sch, | 119 | static unsigned long dsmark_bind_filter(struct Qdisc *sch, |
126 | unsigned long parent, u32 classid) | 120 | unsigned long parent, u32 classid) |
127 | { | 121 | { |
128 | return dsmark_get(sch,classid); | 122 | return dsmark_get(sch, classid); |
129 | } | 123 | } |
130 | 124 | ||
131 | |||
132 | static void dsmark_put(struct Qdisc *sch, unsigned long cl) | 125 | static void dsmark_put(struct Qdisc *sch, unsigned long cl) |
133 | { | 126 | { |
134 | } | 127 | } |
135 | 128 | ||
136 | |||
137 | static int dsmark_change(struct Qdisc *sch, u32 classid, u32 parent, | 129 | static int dsmark_change(struct Qdisc *sch, u32 classid, u32 parent, |
138 | struct rtattr **tca, unsigned long *arg) | 130 | struct rtattr **tca, unsigned long *arg) |
139 | { | 131 | { |
@@ -169,26 +161,29 @@ rtattr_failure: | |||
169 | return err; | 161 | return err; |
170 | } | 162 | } |
171 | 163 | ||
172 | static int dsmark_delete(struct Qdisc *sch,unsigned long arg) | 164 | static int dsmark_delete(struct Qdisc *sch, unsigned long arg) |
173 | { | 165 | { |
174 | struct dsmark_qdisc_data *p = PRIV(sch); | 166 | struct dsmark_qdisc_data *p = PRIV(sch); |
175 | 167 | ||
176 | if (!arg || arg > p->indices) | 168 | if (!dsmark_valid_index(p, arg)) |
177 | return -EINVAL; | 169 | return -EINVAL; |
170 | |||
178 | p->mask[arg-1] = 0xff; | 171 | p->mask[arg-1] = 0xff; |
179 | p->value[arg-1] = 0; | 172 | p->value[arg-1] = 0; |
173 | |||
180 | return 0; | 174 | return 0; |
181 | } | 175 | } |
182 | 176 | ||
183 | |||
184 | static void dsmark_walk(struct Qdisc *sch,struct qdisc_walker *walker) | 177 | static void dsmark_walk(struct Qdisc *sch,struct qdisc_walker *walker) |
185 | { | 178 | { |
186 | struct dsmark_qdisc_data *p = PRIV(sch); | 179 | struct dsmark_qdisc_data *p = PRIV(sch); |
187 | int i; | 180 | int i; |
188 | 181 | ||
189 | DPRINTK("dsmark_walk(sch %p,[qdisc %p],walker %p)\n",sch,p,walker); | 182 | DPRINTK("dsmark_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); |
183 | |||
190 | if (walker->stop) | 184 | if (walker->stop) |
191 | return; | 185 | return; |
186 | |||
192 | for (i = 0; i < p->indices; i++) { | 187 | for (i = 0; i < p->indices; i++) { |
193 | if (p->mask[i] == 0xff && !p->value[i]) | 188 | if (p->mask[i] == 0xff && !p->value[i]) |
194 | goto ignore; | 189 | goto ignore; |
@@ -203,26 +198,20 @@ ignore: | |||
203 | } | 198 | } |
204 | } | 199 | } |
205 | 200 | ||
206 | |||
207 | static struct tcf_proto **dsmark_find_tcf(struct Qdisc *sch,unsigned long cl) | 201 | static struct tcf_proto **dsmark_find_tcf(struct Qdisc *sch,unsigned long cl) |
208 | { | 202 | { |
209 | struct dsmark_qdisc_data *p = PRIV(sch); | 203 | return &PRIV(sch)->filter_list; |
210 | |||
211 | return &p->filter_list; | ||
212 | } | 204 | } |
213 | 205 | ||
214 | |||
215 | /* --------------------------- Qdisc operations ---------------------------- */ | 206 | /* --------------------------- Qdisc operations ---------------------------- */ |
216 | 207 | ||
217 | |||
218 | static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch) | 208 | static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch) |
219 | { | 209 | { |
220 | struct dsmark_qdisc_data *p = PRIV(sch); | 210 | struct dsmark_qdisc_data *p = PRIV(sch); |
221 | struct tcf_result res; | 211 | int err; |
222 | int result; | 212 | |
223 | int ret = NET_XMIT_POLICED; | 213 | D2PRINTK("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); |
224 | 214 | ||
225 | D2PRINTK("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p); | ||
226 | if (p->set_tc_index) { | 215 | if (p->set_tc_index) { |
227 | /* FIXME: Safe with non-linear skbs? --RR */ | 216 | /* FIXME: Safe with non-linear skbs? --RR */ |
228 | switch (skb->protocol) { | 217 | switch (skb->protocol) { |
@@ -239,17 +228,21 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch) | |||
239 | break; | 228 | break; |
240 | }; | 229 | }; |
241 | } | 230 | } |
242 | result = TC_POLICE_OK; /* be nice to gcc */ | 231 | |
243 | if (TC_H_MAJ(skb->priority) == sch->handle) { | 232 | if (TC_H_MAJ(skb->priority) == sch->handle) |
244 | skb->tc_index = TC_H_MIN(skb->priority); | 233 | skb->tc_index = TC_H_MIN(skb->priority); |
245 | } else { | 234 | else { |
246 | result = tc_classify(skb,p->filter_list,&res); | 235 | struct tcf_result res; |
247 | D2PRINTK("result %d class 0x%04x\n",result,res.classid); | 236 | int result = tc_classify(skb, p->filter_list, &res); |
237 | |||
238 | D2PRINTK("result %d class 0x%04x\n", result, res.classid); | ||
239 | |||
248 | switch (result) { | 240 | switch (result) { |
249 | #ifdef CONFIG_NET_CLS_POLICE | 241 | #ifdef CONFIG_NET_CLS_POLICE |
250 | case TC_POLICE_SHOT: | 242 | case TC_POLICE_SHOT: |
251 | kfree_skb(skb); | 243 | kfree_skb(skb); |
252 | break; | 244 | sch->qstats.drops++; |
245 | return NET_XMIT_POLICED; | ||
253 | #if 0 | 246 | #if 0 |
254 | case TC_POLICE_RECLASSIFY: | 247 | case TC_POLICE_RECLASSIFY: |
255 | /* FIXME: what to do here ??? */ | 248 | /* FIXME: what to do here ??? */ |
@@ -266,43 +259,45 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch) | |||
266 | break; | 259 | break; |
267 | }; | 260 | }; |
268 | } | 261 | } |
269 | if ( | ||
270 | #ifdef CONFIG_NET_CLS_POLICE | ||
271 | result == TC_POLICE_SHOT || | ||
272 | #endif | ||
273 | 262 | ||
274 | ((ret = p->q->enqueue(skb,p->q)) != 0)) { | 263 | err = p->q->enqueue(skb,p->q); |
264 | if (err != NET_XMIT_SUCCESS) { | ||
275 | sch->qstats.drops++; | 265 | sch->qstats.drops++; |
276 | return ret; | 266 | return err; |
277 | } | 267 | } |
268 | |||
278 | sch->bstats.bytes += skb->len; | 269 | sch->bstats.bytes += skb->len; |
279 | sch->bstats.packets++; | 270 | sch->bstats.packets++; |
280 | sch->q.qlen++; | 271 | sch->q.qlen++; |
281 | return ret; | ||
282 | } | ||
283 | 272 | ||
273 | return NET_XMIT_SUCCESS; | ||
274 | } | ||
284 | 275 | ||
285 | static struct sk_buff *dsmark_dequeue(struct Qdisc *sch) | 276 | static struct sk_buff *dsmark_dequeue(struct Qdisc *sch) |
286 | { | 277 | { |
287 | struct dsmark_qdisc_data *p = PRIV(sch); | 278 | struct dsmark_qdisc_data *p = PRIV(sch); |
288 | struct sk_buff *skb; | 279 | struct sk_buff *skb; |
289 | int index; | 280 | u32 index; |
281 | |||
282 | D2PRINTK("dsmark_dequeue(sch %p,[qdisc %p])\n", sch, p); | ||
290 | 283 | ||
291 | D2PRINTK("dsmark_dequeue(sch %p,[qdisc %p])\n",sch,p); | ||
292 | skb = p->q->ops->dequeue(p->q); | 284 | skb = p->q->ops->dequeue(p->q); |
293 | if (!skb) | 285 | if (skb == NULL) |
294 | return NULL; | 286 | return NULL; |
287 | |||
295 | sch->q.qlen--; | 288 | sch->q.qlen--; |
296 | index = skb->tc_index & (p->indices-1); | 289 | |
297 | D2PRINTK("index %d->%d\n",skb->tc_index,index); | 290 | index = skb->tc_index & (p->indices - 1); |
291 | D2PRINTK("index %d->%d\n", skb->tc_index, index); | ||
292 | |||
298 | switch (skb->protocol) { | 293 | switch (skb->protocol) { |
299 | case __constant_htons(ETH_P_IP): | 294 | case __constant_htons(ETH_P_IP): |
300 | ipv4_change_dsfield(skb->nh.iph, | 295 | ipv4_change_dsfield(skb->nh.iph, p->mask[index], |
301 | p->mask[index],p->value[index]); | 296 | p->value[index]); |
302 | break; | 297 | break; |
303 | case __constant_htons(ETH_P_IPV6): | 298 | case __constant_htons(ETH_P_IPV6): |
304 | ipv6_change_dsfield(skb->nh.ipv6h, | 299 | ipv6_change_dsfield(skb->nh.ipv6h, p->mask[index], |
305 | p->mask[index],p->value[index]); | 300 | p->value[index]); |
306 | break; | 301 | break; |
307 | default: | 302 | default: |
308 | /* | 303 | /* |
@@ -316,41 +311,46 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch) | |||
316 | htons(skb->protocol)); | 311 | htons(skb->protocol)); |
317 | break; | 312 | break; |
318 | }; | 313 | }; |
314 | |||
319 | return skb; | 315 | return skb; |
320 | } | 316 | } |
321 | 317 | ||
322 | |||
323 | static int dsmark_requeue(struct sk_buff *skb,struct Qdisc *sch) | 318 | static int dsmark_requeue(struct sk_buff *skb,struct Qdisc *sch) |
324 | { | 319 | { |
325 | int ret; | ||
326 | struct dsmark_qdisc_data *p = PRIV(sch); | 320 | struct dsmark_qdisc_data *p = PRIV(sch); |
321 | int err; | ||
327 | 322 | ||
328 | D2PRINTK("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p); | 323 | D2PRINTK("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); |
329 | if ((ret = p->q->ops->requeue(skb, p->q)) == 0) { | 324 | |
330 | sch->q.qlen++; | 325 | err = p->q->ops->requeue(skb, p->q); |
331 | sch->qstats.requeues++; | 326 | if (err != NET_XMIT_SUCCESS) { |
332 | return 0; | 327 | sch->qstats.drops++; |
328 | return err; | ||
333 | } | 329 | } |
334 | sch->qstats.drops++; | ||
335 | return ret; | ||
336 | } | ||
337 | 330 | ||
331 | sch->q.qlen++; | ||
332 | sch->qstats.requeues++; | ||
333 | |||
334 | return NET_XMIT_SUCCESS; | ||
335 | } | ||
338 | 336 | ||
339 | static unsigned int dsmark_drop(struct Qdisc *sch) | 337 | static unsigned int dsmark_drop(struct Qdisc *sch) |
340 | { | 338 | { |
341 | struct dsmark_qdisc_data *p = PRIV(sch); | 339 | struct dsmark_qdisc_data *p = PRIV(sch); |
342 | unsigned int len; | 340 | unsigned int len; |
343 | 341 | ||
344 | DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n",sch,p); | 342 | DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n", sch, p); |
345 | if (!p->q->ops->drop) | 343 | |
346 | return 0; | 344 | if (p->q->ops->drop == NULL) |
347 | if (!(len = p->q->ops->drop(p->q))) | ||
348 | return 0; | 345 | return 0; |
349 | sch->q.qlen--; | 346 | |
347 | len = p->q->ops->drop(p->q); | ||
348 | if (len) | ||
349 | sch->q.qlen--; | ||
350 | |||
350 | return len; | 351 | return len; |
351 | } | 352 | } |
352 | 353 | ||
353 | |||
354 | static int dsmark_init(struct Qdisc *sch, struct rtattr *opt) | 354 | static int dsmark_init(struct Qdisc *sch, struct rtattr *opt) |
355 | { | 355 | { |
356 | struct dsmark_qdisc_data *p = PRIV(sch); | 356 | struct dsmark_qdisc_data *p = PRIV(sch); |
@@ -400,33 +400,32 @@ rtattr_failure: | |||
400 | return err; | 400 | return err; |
401 | } | 401 | } |
402 | 402 | ||
403 | |||
404 | static void dsmark_reset(struct Qdisc *sch) | 403 | static void dsmark_reset(struct Qdisc *sch) |
405 | { | 404 | { |
406 | struct dsmark_qdisc_data *p = PRIV(sch); | 405 | struct dsmark_qdisc_data *p = PRIV(sch); |
407 | 406 | ||
408 | DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n",sch,p); | 407 | DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n", sch, p); |
409 | qdisc_reset(p->q); | 408 | qdisc_reset(p->q); |
410 | sch->q.qlen = 0; | 409 | sch->q.qlen = 0; |
411 | } | 410 | } |
412 | 411 | ||
413 | |||
414 | static void dsmark_destroy(struct Qdisc *sch) | 412 | static void dsmark_destroy(struct Qdisc *sch) |
415 | { | 413 | { |
416 | struct dsmark_qdisc_data *p = PRIV(sch); | 414 | struct dsmark_qdisc_data *p = PRIV(sch); |
417 | struct tcf_proto *tp; | 415 | struct tcf_proto *tp; |
418 | 416 | ||
419 | DPRINTK("dsmark_destroy(sch %p,[qdisc %p])\n",sch,p); | 417 | DPRINTK("dsmark_destroy(sch %p,[qdisc %p])\n", sch, p); |
418 | |||
420 | while (p->filter_list) { | 419 | while (p->filter_list) { |
421 | tp = p->filter_list; | 420 | tp = p->filter_list; |
422 | p->filter_list = tp->next; | 421 | p->filter_list = tp->next; |
423 | tcf_destroy(tp); | 422 | tcf_destroy(tp); |
424 | } | 423 | } |
424 | |||
425 | qdisc_destroy(p->q); | 425 | qdisc_destroy(p->q); |
426 | kfree(p->mask); | 426 | kfree(p->mask); |
427 | } | 427 | } |
428 | 428 | ||
429 | |||
430 | static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl, | 429 | static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl, |
431 | struct sk_buff *skb, struct tcmsg *tcm) | 430 | struct sk_buff *skb, struct tcmsg *tcm) |
432 | { | 431 | { |
@@ -505,10 +504,13 @@ static int __init dsmark_module_init(void) | |||
505 | { | 504 | { |
506 | return register_qdisc(&dsmark_qdisc_ops); | 505 | return register_qdisc(&dsmark_qdisc_ops); |
507 | } | 506 | } |
507 | |||
508 | static void __exit dsmark_module_exit(void) | 508 | static void __exit dsmark_module_exit(void) |
509 | { | 509 | { |
510 | unregister_qdisc(&dsmark_qdisc_ops); | 510 | unregister_qdisc(&dsmark_qdisc_ops); |
511 | } | 511 | } |
512 | |||
512 | module_init(dsmark_module_init) | 513 | module_init(dsmark_module_init) |
513 | module_exit(dsmark_module_exit) | 514 | module_exit(dsmark_module_exit) |
515 | |||
514 | MODULE_LICENSE("GPL"); | 516 | MODULE_LICENSE("GPL"); |