Merge branch 'parisc-4.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[deliverable/linux.git] / net / sched / sch_dsmark.c
CommitLineData
1da177e4
LT
1/* net/sched/sch_dsmark.c - Differentiated Services field marker */
2
3/* Written 1998-2000 by Werner Almesberger, EPFL ICA */
4
5
1da177e4
LT
6#include <linux/module.h>
7#include <linux/init.h>
5a0e3ad6 8#include <linux/slab.h>
1da177e4
LT
9#include <linux/types.h>
10#include <linux/string.h>
11#include <linux/errno.h>
12#include <linux/skbuff.h>
1da177e4 13#include <linux/rtnetlink.h>
5b0ac72b 14#include <linux/bitops.h>
1da177e4
LT
15#include <net/pkt_sched.h>
16#include <net/dsfield.h>
17#include <net/inet_ecn.h>
18#include <asm/byteorder.h>
19
1da177e4
LT
20/*
21 * classid class marking
22 * ------- ----- -------
23 * n/a 0 n/a
24 * x:0 1 use entry [0]
25 * ... ... ...
26 * x:y y>0 y+1 use entry [y]
27 * ... ... ...
28 * x:indices-1 indices use entry [indices-1]
29 * ... ... ...
30 * x:y y+1 use entry [y & (indices-1)]
31 * ... ... ...
32 * 0xffff 0x10000 use entry [indices-1]
33 */
34
35
36#define NO_DEFAULT_INDEX (1 << 16)
37
47bbbb30
ED
38struct mask_value {
39 u8 mask;
40 u8 value;
41};
42
1da177e4
LT
43struct dsmark_qdisc_data {
44 struct Qdisc *q;
25d8c0d5 45 struct tcf_proto __rcu *filter_list;
47bbbb30 46 struct mask_value *mv;
af0d1141 47 u16 indices;
47bbbb30 48 u8 set_tc_index;
af0d1141 49 u32 default_index; /* index range is 0...0xffff */
47bbbb30
ED
50#define DSMARK_EMBEDDED_SZ 16
51 struct mask_value embedded[DSMARK_EMBEDDED_SZ];
1da177e4
LT
52};
53
758cc43c
TG
54static inline int dsmark_valid_index(struct dsmark_qdisc_data *p, u16 index)
55{
17569fae 56 return index <= p->indices && index > 0;
758cc43c 57}
1da177e4
LT
58
59/* ------------------------- Class/flow operations ------------------------- */
60
af0d1141
TG
61static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
62 struct Qdisc *new, struct Qdisc **old)
1da177e4 63{
81da99ed 64 struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4 65
c76f2a2c
YY
66 pr_debug("%s(sch %p,[qdisc %p],new %p,old %p)\n",
67 __func__, sch, p, new, old);
486b53e5
TG
68
69 if (new == NULL) {
3511c913 70 new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
9f9afec4 71 sch->handle);
486b53e5
TG
72 if (new == NULL)
73 new = &noop_qdisc;
74 }
75
1da177e4 76 sch_tree_lock(sch);
b94c8afc
PM
77 *old = p->q;
78 p->q = new;
5e50da01 79 qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
af0d1141 80 qdisc_reset(*old);
af0d1141
TG
81 sch_tree_unlock(sch);
82
10297b99 83 return 0;
1da177e4
LT
84}
85
1da177e4
LT
86static struct Qdisc *dsmark_leaf(struct Qdisc *sch, unsigned long arg)
87{
81da99ed
SH
88 struct dsmark_qdisc_data *p = qdisc_priv(sch);
89 return p->q;
1da177e4
LT
90}
91
af0d1141 92static unsigned long dsmark_get(struct Qdisc *sch, u32 classid)
1da177e4 93{
c76f2a2c
YY
94 pr_debug("%s(sch %p,[qdisc %p],classid %x)\n",
95 __func__, sch, qdisc_priv(sch), classid);
1da177e4 96
af0d1141 97 return TC_H_MIN(classid) + 1;
1da177e4
LT
98}
99
1da177e4 100static unsigned long dsmark_bind_filter(struct Qdisc *sch,
af0d1141 101 unsigned long parent, u32 classid)
1da177e4 102{
af0d1141 103 return dsmark_get(sch, classid);
1da177e4
LT
104}
105
1da177e4
LT
106static void dsmark_put(struct Qdisc *sch, unsigned long cl)
107{
108}
109
27a3421e
PM
110static const struct nla_policy dsmark_policy[TCA_DSMARK_MAX + 1] = {
111 [TCA_DSMARK_INDICES] = { .type = NLA_U16 },
112 [TCA_DSMARK_DEFAULT_INDEX] = { .type = NLA_U16 },
113 [TCA_DSMARK_SET_TC_INDEX] = { .type = NLA_FLAG },
114 [TCA_DSMARK_MASK] = { .type = NLA_U8 },
115 [TCA_DSMARK_VALUE] = { .type = NLA_U8 },
116};
117
1da177e4 118static int dsmark_change(struct Qdisc *sch, u32 classid, u32 parent,
1e90474c 119 struct nlattr **tca, unsigned long *arg)
1da177e4 120{
81da99ed 121 struct dsmark_qdisc_data *p = qdisc_priv(sch);
1e90474c
PM
122 struct nlattr *opt = tca[TCA_OPTIONS];
123 struct nlattr *tb[TCA_DSMARK_MAX + 1];
758cc43c 124 int err = -EINVAL;
1da177e4 125
c76f2a2c
YY
126 pr_debug("%s(sch %p,[qdisc %p],classid %x,parent %x), arg 0x%lx\n",
127 __func__, sch, p, classid, parent, *arg);
758cc43c
TG
128
129 if (!dsmark_valid_index(p, *arg)) {
130 err = -ENOENT;
1e90474c 131 goto errout;
1da177e4 132 }
1da177e4 133
cee63723 134 if (!opt)
1e90474c 135 goto errout;
758cc43c 136
27a3421e 137 err = nla_parse_nested(tb, TCA_DSMARK_MAX, opt, dsmark_policy);
cee63723 138 if (err < 0)
27a3421e 139 goto errout;
cee63723 140
27a3421e 141 if (tb[TCA_DSMARK_VALUE])
47bbbb30 142 p->mv[*arg - 1].value = nla_get_u8(tb[TCA_DSMARK_VALUE]);
10297b99 143
1e90474c 144 if (tb[TCA_DSMARK_MASK])
47bbbb30 145 p->mv[*arg - 1].mask = nla_get_u8(tb[TCA_DSMARK_MASK]);
758cc43c
TG
146
147 err = 0;
148
1e90474c 149errout:
758cc43c
TG
150 return err;
151}
1da177e4 152
af0d1141 153static int dsmark_delete(struct Qdisc *sch, unsigned long arg)
1da177e4 154{
81da99ed 155 struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4 156
af0d1141 157 if (!dsmark_valid_index(p, arg))
1da177e4 158 return -EINVAL;
10297b99 159
47bbbb30
ED
160 p->mv[arg - 1].mask = 0xff;
161 p->mv[arg - 1].value = 0;
af0d1141 162
1da177e4
LT
163 return 0;
164}
165
9d127fbd 166static void dsmark_walk(struct Qdisc *sch, struct qdisc_walker *walker)
1da177e4 167{
81da99ed 168 struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4
LT
169 int i;
170
c76f2a2c
YY
171 pr_debug("%s(sch %p,[qdisc %p],walker %p)\n",
172 __func__, sch, p, walker);
af0d1141 173
1da177e4
LT
174 if (walker->stop)
175 return;
af0d1141 176
1da177e4 177 for (i = 0; i < p->indices; i++) {
47bbbb30 178 if (p->mv[i].mask == 0xff && !p->mv[i].value)
0451eb07 179 goto ignore;
1da177e4 180 if (walker->count >= walker->skip) {
cc7ec456 181 if (walker->fn(sch, i + 1, walker) < 0) {
1da177e4
LT
182 walker->stop = 1;
183 break;
184 }
185 }
10297b99 186ignore:
0451eb07 187 walker->count++;
10297b99 188 }
1da177e4
LT
189}
190
25d8c0d5
JF
191static inline struct tcf_proto __rcu **dsmark_find_tcf(struct Qdisc *sch,
192 unsigned long cl)
1da177e4 193{
81da99ed
SH
194 struct dsmark_qdisc_data *p = qdisc_priv(sch);
195 return &p->filter_list;
1da177e4
LT
196}
197
1da177e4
LT
198/* --------------------------- Qdisc operations ---------------------------- */
199
9d127fbd 200static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
1da177e4 201{
81da99ed 202 struct dsmark_qdisc_data *p = qdisc_priv(sch);
af0d1141
TG
203 int err;
204
c76f2a2c 205 pr_debug("%s(skb %p,sch %p,[qdisc %p])\n", __func__, skb, sch, p);
1da177e4 206
1da177e4 207 if (p->set_tc_index) {
d8b9605d 208 switch (tc_skb_protocol(skb)) {
60678040 209 case htons(ETH_P_IP):
9d127fbd
SH
210 if (skb_cow_head(skb, sizeof(struct iphdr)))
211 goto drop;
4c30719f 212
9d127fbd
SH
213 skb->tc_index = ipv4_get_dsfield(ip_hdr(skb))
214 & ~INET_ECN_MASK;
215 break;
4c30719f 216
60678040 217 case htons(ETH_P_IPV6):
9d127fbd
SH
218 if (skb_cow_head(skb, sizeof(struct ipv6hdr)))
219 goto drop;
4c30719f 220
9d127fbd
SH
221 skb->tc_index = ipv6_get_dsfield(ipv6_hdr(skb))
222 & ~INET_ECN_MASK;
223 break;
224 default:
225 skb->tc_index = 0;
226 break;
3ff50b79 227 }
1da177e4 228 }
af0d1141
TG
229
230 if (TC_H_MAJ(skb->priority) == sch->handle)
1da177e4 231 skb->tc_index = TC_H_MIN(skb->priority);
af0d1141
TG
232 else {
233 struct tcf_result res;
25d8c0d5 234 struct tcf_proto *fl = rcu_dereference_bh(p->filter_list);
3b3ae880 235 int result = tc_classify(skb, fl, &res, false);
af0d1141 236
81da99ed 237 pr_debug("result %d class 0x%04x\n", result, res.classid);
af0d1141 238
1da177e4 239 switch (result) {
f6853e2d
PM
240#ifdef CONFIG_NET_CLS_ACT
241 case TC_ACT_QUEUED:
242 case TC_ACT_STOLEN:
243 kfree_skb(skb);
378a2f09 244 return NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
4c30719f 245
f6853e2d 246 case TC_ACT_SHOT:
4c30719f 247 goto drop;
1da177e4 248#endif
c3bc7cff 249 case TC_ACT_OK:
f6853e2d
PM
250 skb->tc_index = TC_H_MIN(res.classid);
251 break;
4c30719f 252
f6853e2d
PM
253 default:
254 if (p->default_index != NO_DEFAULT_INDEX)
255 skb->tc_index = p->default_index;
256 break;
3ff50b79 257 }
1da177e4 258 }
1da177e4 259
5f86173b 260 err = qdisc_enqueue(skb, p->q);
af0d1141 261 if (err != NET_XMIT_SUCCESS) {
378a2f09 262 if (net_xmit_drop_count(err))
25331d6c 263 qdisc_qstats_drop(sch);
af0d1141 264 return err;
1da177e4 265 }
af0d1141 266
1da177e4 267 sch->q.qlen++;
1da177e4 268
af0d1141 269 return NET_XMIT_SUCCESS;
4c30719f
SH
270
271drop:
17045755 272 qdisc_drop(skb, sch);
c27f339a 273 return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
af0d1141 274}
1da177e4
LT
275
276static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
277{
81da99ed 278 struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4 279 struct sk_buff *skb;
af0d1141
TG
280 u32 index;
281
c76f2a2c 282 pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p);
1da177e4 283
1da177e4 284 skb = p->q->ops->dequeue(p->q);
af0d1141 285 if (skb == NULL)
1da177e4 286 return NULL;
af0d1141 287
9190b3b3 288 qdisc_bstats_update(sch, skb);
1da177e4 289 sch->q.qlen--;
af0d1141
TG
290
291 index = skb->tc_index & (p->indices - 1);
81da99ed 292 pr_debug("index %d->%d\n", skb->tc_index, index);
af0d1141 293
d8b9605d 294 switch (tc_skb_protocol(skb)) {
60678040 295 case htons(ETH_P_IP):
47bbbb30
ED
296 ipv4_change_dsfield(ip_hdr(skb), p->mv[index].mask,
297 p->mv[index].value);
1da177e4 298 break;
60678040 299 case htons(ETH_P_IPV6):
47bbbb30
ED
300 ipv6_change_dsfield(ipv6_hdr(skb), p->mv[index].mask,
301 p->mv[index].value);
1da177e4 302 break;
9d127fbd
SH
303 default:
304 /*
305 * Only complain if a change was actually attempted.
306 * This way, we can send non-IP traffic through dsmark
307 * and don't need yet another qdisc as a bypass.
308 */
47bbbb30 309 if (p->mv[index].mask != 0xff || p->mv[index].value)
c76f2a2c 310 pr_warn("%s: unsupported protocol %d\n",
d8b9605d 311 __func__, ntohs(tc_skb_protocol(skb)));
9d127fbd 312 break;
3ff50b79 313 }
af0d1141 314
1da177e4
LT
315 return skb;
316}
317
8e3af978
JP
318static struct sk_buff *dsmark_peek(struct Qdisc *sch)
319{
320 struct dsmark_qdisc_data *p = qdisc_priv(sch);
321
c76f2a2c 322 pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p);
8e3af978
JP
323
324 return p->q->ops->peek(p->q);
325}
326
1da177e4
LT
327static unsigned int dsmark_drop(struct Qdisc *sch)
328{
81da99ed 329 struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4 330 unsigned int len;
10297b99 331
c76f2a2c 332 pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p);
af0d1141
TG
333
334 if (p->q->ops->drop == NULL)
1da177e4 335 return 0;
af0d1141
TG
336
337 len = p->q->ops->drop(p->q);
338 if (len)
339 sch->q.qlen--;
340
1da177e4
LT
341 return len;
342}
343
1e90474c 344static int dsmark_init(struct Qdisc *sch, struct nlattr *opt)
1da177e4 345{
81da99ed 346 struct dsmark_qdisc_data *p = qdisc_priv(sch);
1e90474c 347 struct nlattr *tb[TCA_DSMARK_MAX + 1];
758cc43c
TG
348 int err = -EINVAL;
349 u32 default_index = NO_DEFAULT_INDEX;
350 u16 indices;
47bbbb30 351 int i;
758cc43c 352
c76f2a2c 353 pr_debug("%s(sch %p,[qdisc %p],opt %p)\n", __func__, sch, p, opt);
758cc43c 354
cee63723
PM
355 if (!opt)
356 goto errout;
357
27a3421e 358 err = nla_parse_nested(tb, TCA_DSMARK_MAX, opt, dsmark_policy);
cee63723 359 if (err < 0)
758cc43c
TG
360 goto errout;
361
cee63723 362 err = -EINVAL;
1e90474c 363 indices = nla_get_u16(tb[TCA_DSMARK_INDICES]);
5b0ac72b
DM
364
365 if (hweight32(indices) != 1)
758cc43c
TG
366 goto errout;
367
27a3421e 368 if (tb[TCA_DSMARK_DEFAULT_INDEX])
1e90474c 369 default_index = nla_get_u16(tb[TCA_DSMARK_DEFAULT_INDEX]);
758cc43c 370
47bbbb30
ED
371 if (indices <= DSMARK_EMBEDDED_SZ)
372 p->mv = p->embedded;
373 else
374 p->mv = kmalloc_array(indices, sizeof(*p->mv), GFP_KERNEL);
375 if (!p->mv) {
758cc43c
TG
376 err = -ENOMEM;
377 goto errout;
1da177e4 378 }
47bbbb30
ED
379 for (i = 0; i < indices; i++) {
380 p->mv[i].mask = 0xff;
381 p->mv[i].value = 0;
382 }
758cc43c
TG
383 p->indices = indices;
384 p->default_index = default_index;
1e90474c 385 p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]);
758cc43c 386
3511c913 387 p->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, sch->handle);
758cc43c 388 if (p->q == NULL)
1da177e4 389 p->q = &noop_qdisc;
758cc43c 390
c76f2a2c 391 pr_debug("%s: qdisc %p\n", __func__, p->q);
758cc43c
TG
392
393 err = 0;
394errout:
758cc43c 395 return err;
1da177e4
LT
396}
397
1da177e4
LT
398static void dsmark_reset(struct Qdisc *sch)
399{
81da99ed 400 struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4 401
c76f2a2c 402 pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p);
1da177e4
LT
403 qdisc_reset(p->q);
404 sch->q.qlen = 0;
405}
406
1da177e4
LT
407static void dsmark_destroy(struct Qdisc *sch)
408{
81da99ed 409 struct dsmark_qdisc_data *p = qdisc_priv(sch);
1da177e4 410
c76f2a2c 411 pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p);
af0d1141 412
ff31ab56 413 tcf_destroy_chain(&p->filter_list);
1da177e4 414 qdisc_destroy(p->q);
47bbbb30
ED
415 if (p->mv != p->embedded)
416 kfree(p->mv);
1da177e4
LT
417}
418
1da177e4 419static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl,
02f23f09 420 struct sk_buff *skb, struct tcmsg *tcm)
1da177e4 421{
81da99ed 422 struct dsmark_qdisc_data *p = qdisc_priv(sch);
1e90474c 423 struct nlattr *opts = NULL;
1da177e4 424
c76f2a2c 425 pr_debug("%s(sch %p,[qdisc %p],class %ld\n", __func__, sch, p, cl);
02f23f09
TG
426
427 if (!dsmark_valid_index(p, cl))
1da177e4 428 return -EINVAL;
02f23f09 429
cc7ec456 430 tcm->tcm_handle = TC_H_MAKE(TC_H_MAJ(sch->handle), cl - 1);
cdc7f8e3 431 tcm->tcm_info = p->q->handle;
02f23f09 432
1e90474c
PM
433 opts = nla_nest_start(skb, TCA_OPTIONS);
434 if (opts == NULL)
435 goto nla_put_failure;
47bbbb30
ED
436 if (nla_put_u8(skb, TCA_DSMARK_MASK, p->mv[cl - 1].mask) ||
437 nla_put_u8(skb, TCA_DSMARK_VALUE, p->mv[cl - 1].value))
1b34ec43 438 goto nla_put_failure;
02f23f09 439
1e90474c 440 return nla_nest_end(skb, opts);
1da177e4 441
1e90474c 442nla_put_failure:
bc3ed28c
TG
443 nla_nest_cancel(skb, opts);
444 return -EMSGSIZE;
1da177e4
LT
445}
446
447static int dsmark_dump(struct Qdisc *sch, struct sk_buff *skb)
448{
81da99ed 449 struct dsmark_qdisc_data *p = qdisc_priv(sch);
1e90474c 450 struct nlattr *opts = NULL;
1da177e4 451
1e90474c
PM
452 opts = nla_nest_start(skb, TCA_OPTIONS);
453 if (opts == NULL)
454 goto nla_put_failure;
1b34ec43
DM
455 if (nla_put_u16(skb, TCA_DSMARK_INDICES, p->indices))
456 goto nla_put_failure;
02f23f09 457
1b34ec43
DM
458 if (p->default_index != NO_DEFAULT_INDEX &&
459 nla_put_u16(skb, TCA_DSMARK_DEFAULT_INDEX, p->default_index))
460 goto nla_put_failure;
1da177e4 461
1b34ec43
DM
462 if (p->set_tc_index &&
463 nla_put_flag(skb, TCA_DSMARK_SET_TC_INDEX))
464 goto nla_put_failure;
02f23f09 465
1e90474c 466 return nla_nest_end(skb, opts);
1da177e4 467
1e90474c 468nla_put_failure:
bc3ed28c
TG
469 nla_nest_cancel(skb, opts);
470 return -EMSGSIZE;
1da177e4
LT
471}
472
20fea08b 473static const struct Qdisc_class_ops dsmark_class_ops = {
1da177e4
LT
474 .graft = dsmark_graft,
475 .leaf = dsmark_leaf,
476 .get = dsmark_get,
477 .put = dsmark_put,
478 .change = dsmark_change,
479 .delete = dsmark_delete,
480 .walk = dsmark_walk,
481 .tcf_chain = dsmark_find_tcf,
482 .bind_tcf = dsmark_bind_filter,
483 .unbind_tcf = dsmark_put,
484 .dump = dsmark_dump_class,
485};
486
20fea08b 487static struct Qdisc_ops dsmark_qdisc_ops __read_mostly = {
1da177e4
LT
488 .next = NULL,
489 .cl_ops = &dsmark_class_ops,
490 .id = "dsmark",
491 .priv_size = sizeof(struct dsmark_qdisc_data),
492 .enqueue = dsmark_enqueue,
493 .dequeue = dsmark_dequeue,
8e3af978 494 .peek = dsmark_peek,
1da177e4
LT
495 .drop = dsmark_drop,
496 .init = dsmark_init,
497 .reset = dsmark_reset,
498 .destroy = dsmark_destroy,
499 .change = NULL,
500 .dump = dsmark_dump,
501 .owner = THIS_MODULE,
502};
503
504static int __init dsmark_module_init(void)
505{
506 return register_qdisc(&dsmark_qdisc_ops);
507}
af0d1141 508
10297b99 509static void __exit dsmark_module_exit(void)
1da177e4
LT
510{
511 unregister_qdisc(&dsmark_qdisc_ops);
512}
af0d1141 513
1da177e4
LT
514module_init(dsmark_module_init)
515module_exit(dsmark_module_exit)
af0d1141 516
1da177e4 517MODULE_LICENSE("GPL");
This page took 1.246362 seconds and 5 git commands to generate.