1 /* net/sched/sch_dsmark.c - Differentiated Services field marker */
3 /* Written 1998-2000 by Werner Almesberger, EPFL ICA */
6 #include <linux/config.h>
7 #include <linux/module.h>
8 #include <linux/types.h>
9 #include <linux/skbuff.h>
10 #include <linux/netdevice.h> /* for pkt_sched */
11 #include <linux/rtnetlink.h>
12 #include <net/pkt_sched.h>
13 #include <net/dsfield.h>
14 #include <asm/byteorder.h>
18 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
20 #define DPRINTK(format,args...)
24 #define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args)
26 #define D2PRINTK(format,args...)
30 #define PRIV(sch) ((struct dsmark_qdisc_data *) (sch)->data)
34 * classid class marking
35 * ------- ----- -------
39 * x:y y>0 y+1 use entry [y]
41 * x:indices-1 indices use entry [indices-1]
45 struct dsmark_qdisc_data
{
47 struct tcf_proto
*filter_list
;
48 __u8
*mask
; /* "owns" the array */
56 /* ------------------------- Class/flow operations ------------------------- */
59 static int dsmark_graft(struct Qdisc
*sch
,unsigned long arg
,
60 struct Qdisc
*new,struct Qdisc
**old
)
62 struct dsmark_qdisc_data
*p
= PRIV(sch
);
64 DPRINTK("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n",sch
,p
,new,
69 *old
= xchg(&p
->q
,new);
72 sch_tree_unlock(sch
); /* @@@ move up ? */
77 static struct Qdisc
*dsmark_leaf(struct Qdisc
*sch
, unsigned long arg
)
83 static unsigned long dsmark_get(struct Qdisc
*sch
,u32 classid
)
85 struct dsmark_qdisc_data
*p
__attribute__((unused
)) = PRIV(sch
);
87 DPRINTK("dsmark_get(sch %p,[qdisc %p],classid %x)\n",sch
,p
,classid
);
88 return TC_H_MIN(classid
)+1;
92 static unsigned long dsmark_bind_filter(struct Qdisc
*sch
,
93 unsigned long parent
, u32 classid
)
95 return dsmark_get(sch
,classid
);
99 static void dsmark_put(struct Qdisc
*sch
, unsigned long cl
)
104 static int dsmark_change(struct Qdisc
*sch
, u32 classid
, u32 parent
,
105 struct rtattr
**tca
, unsigned long *arg
)
107 struct dsmark_qdisc_data
*p
= PRIV(sch
);
108 struct rtattr
*opt
= tca
[TCA_OPTIONS
-1];
109 struct rtattr
*tb
[TCA_DSMARK_MAX
];
111 DPRINTK("dsmark_change(sch %p,[qdisc %p],classid %x,parent %x),"
112 "arg 0x%lx\n",sch
,p
,classid
,parent
,*arg
);
113 if (*arg
> p
->indices
)
115 if (!opt
|| rtattr_parse(tb
, TCA_DSMARK_MAX
, RTA_DATA(opt
),
118 if (tb
[TCA_DSMARK_MASK
-1]) {
119 if (!RTA_PAYLOAD(tb
[TCA_DSMARK_MASK
-1]))
121 p
->mask
[*arg
-1] = *(__u8
*) RTA_DATA(tb
[TCA_DSMARK_MASK
-1]);
123 if (tb
[TCA_DSMARK_VALUE
-1]) {
124 if (!RTA_PAYLOAD(tb
[TCA_DSMARK_VALUE
-1]))
126 p
->value
[*arg
-1] = *(__u8
*) RTA_DATA(tb
[TCA_DSMARK_VALUE
-1]);
132 static int dsmark_delete(struct Qdisc
*sch
,unsigned long arg
)
134 struct dsmark_qdisc_data
*p
= PRIV(sch
);
136 if (!arg
|| arg
> p
->indices
)
138 p
->mask
[arg
-1] = 0xff;
144 static void dsmark_walk(struct Qdisc
*sch
,struct qdisc_walker
*walker
)
146 struct dsmark_qdisc_data
*p
= PRIV(sch
);
149 DPRINTK("dsmark_walk(sch %p,[qdisc %p],walker %p)\n",sch
,p
,walker
);
152 for (i
= 0; i
< p
->indices
; i
++) {
153 if (p
->mask
[i
] == 0xff && !p
->value
[i
])
155 if (walker
->count
>= walker
->skip
) {
156 if (walker
->fn(sch
, i
+1, walker
) < 0) {
166 static struct tcf_proto
**dsmark_find_tcf(struct Qdisc
*sch
,unsigned long cl
)
168 struct dsmark_qdisc_data
*p
= PRIV(sch
);
170 return &p
->filter_list
;
174 /* --------------------------- Qdisc operations ---------------------------- */
177 static int dsmark_enqueue(struct sk_buff
*skb
,struct Qdisc
*sch
)
179 struct dsmark_qdisc_data
*p
= PRIV(sch
);
180 struct tcf_result res
;
184 D2PRINTK("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n",skb
,sch
,p
);
185 if (p
->set_tc_index
) {
186 switch (skb
->protocol
) {
187 case __constant_htons(ETH_P_IP
):
188 skb
->tc_index
= ipv4_get_dsfield(skb
->nh
.iph
);
190 case __constant_htons(ETH_P_IPV6
):
191 skb
->tc_index
= ipv6_get_dsfield(skb
->nh
.ipv6h
);
198 result
= TC_POLICE_OK
; /* be nice to gcc */
199 if (TC_H_MAJ(skb
->priority
) == sch
->handle
) {
200 skb
->tc_index
= TC_H_MIN(skb
->priority
);
202 result
= tc_classify(skb
,p
->filter_list
,&res
);
203 D2PRINTK("result %d class 0x%04x\n",result
,res
.classid
);
205 #ifdef CONFIG_NET_CLS_POLICE
210 case TC_POLICE_RECLASSIFY
:
211 /* FIXME: what to do here ??? */
215 skb
->tc_index
= TC_H_MIN(res
.classid
);
217 case TC_POLICE_UNSPEC
:
220 if (p
->default_index
)
221 skb
->tc_index
= p
->default_index
;
226 #ifdef CONFIG_NET_CLS_POLICE
227 result
== TC_POLICE_SHOT
||
230 ((ret
= p
->q
->enqueue(skb
,p
->q
)) != 0)) {
234 sch
->stats
.bytes
+= skb
->len
;
235 sch
->stats
.packets
++;
241 static struct sk_buff
*dsmark_dequeue(struct Qdisc
*sch
)
243 struct dsmark_qdisc_data
*p
= PRIV(sch
);
247 D2PRINTK("dsmark_dequeue(sch %p,[qdisc %p])\n",sch
,p
);
248 skb
= p
->q
->ops
->dequeue(p
->q
);
252 index
= skb
->tc_index
& (p
->indices
-1);
253 D2PRINTK("index %d->%d\n",skb
->tc_index
,index
);
254 switch (skb
->protocol
) {
255 case __constant_htons(ETH_P_IP
):
256 ipv4_change_dsfield(skb
->nh
.iph
,
257 p
->mask
[index
],p
->value
[index
]);
259 case __constant_htons(ETH_P_IPV6
):
260 ipv6_change_dsfield(skb
->nh
.ipv6h
,
261 p
->mask
[index
],p
->value
[index
]);
265 * Only complain if a change was actually attempted.
266 * This way, we can send non-IP traffic through dsmark
267 * and don't need yet another qdisc as a bypass.
269 if (p
->mask
[index
] != 0xff || p
->value
[index
])
270 printk(KERN_WARNING
"dsmark_dequeue: "
271 "unsupported protocol %d\n",
272 htons(skb
->protocol
));
279 static int dsmark_requeue(struct sk_buff
*skb
,struct Qdisc
*sch
)
282 struct dsmark_qdisc_data
*p
= PRIV(sch
);
284 D2PRINTK("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n",skb
,sch
,p
);
285 if ((ret
= p
->q
->ops
->requeue(skb
, p
->q
)) == 0) {
294 static int dsmark_drop(struct Qdisc
*sch
)
296 struct dsmark_qdisc_data
*p
= PRIV(sch
);
298 DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n",sch
,p
);
299 if (!p
->q
->ops
->drop
)
301 if (!p
->q
->ops
->drop(p
->q
))
308 int dsmark_init(struct Qdisc
*sch
,struct rtattr
*opt
)
310 struct dsmark_qdisc_data
*p
= PRIV(sch
);
311 struct rtattr
*tb
[TCA_DSMARK_MAX
];
314 DPRINTK("dsmark_init(sch %p,[qdisc %p],opt %p)\n",sch
,p
,opt
);
315 if (rtattr_parse(tb
,TCA_DSMARK_MAX
,RTA_DATA(opt
),RTA_PAYLOAD(opt
)) < 0 ||
316 !tb
[TCA_DSMARK_INDICES
-1] ||
317 RTA_PAYLOAD(tb
[TCA_DSMARK_INDICES
-1]) < sizeof(__u16
))
319 memset(p
,0,sizeof(*p
));
320 p
->filter_list
= NULL
;
321 p
->indices
= *(__u16
*) RTA_DATA(tb
[TCA_DSMARK_INDICES
-1]);
324 for (tmp
= p
->indices
; tmp
!= 1; tmp
>>= 1) {
328 p
->default_index
= 0;
329 if (tb
[TCA_DSMARK_DEFAULT_INDEX
-1]) {
330 if (RTA_PAYLOAD(tb
[TCA_DSMARK_DEFAULT_INDEX
-1]) < sizeof(__u16
))
333 *(__u16
*) RTA_DATA(tb
[TCA_DSMARK_DEFAULT_INDEX
-1]);
334 if (!p
->default_index
|| p
->default_index
>= p
->indices
)
337 p
->set_tc_index
= !!tb
[TCA_DSMARK_SET_TC_INDEX
-1];
338 p
->mask
= kmalloc(p
->indices
*2,GFP_KERNEL
);
341 p
->value
= p
->mask
+p
->indices
;
342 memset(p
->mask
,0xff,p
->indices
);
343 memset(p
->value
,0,p
->indices
);
344 if (!(p
->q
= qdisc_create_dflt(sch
->dev
, &pfifo_qdisc_ops
)))
346 DPRINTK("dsmark_init: qdisc %p\n",&p
->q
);
352 static void dsmark_reset(struct Qdisc
*sch
)
354 struct dsmark_qdisc_data
*p
= PRIV(sch
);
356 DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n",sch
,p
);
362 static void dsmark_destroy(struct Qdisc
*sch
)
364 struct dsmark_qdisc_data
*p
= PRIV(sch
);
365 struct tcf_proto
*tp
;
367 DPRINTK("dsmark_destroy(sch %p,[qdisc %p])\n",sch
,p
);
368 while (p
->filter_list
) {
370 p
->filter_list
= tp
->next
;
371 tp
->ops
->destroy(tp
);
380 #ifdef CONFIG_RTNETLINK
382 static int dsmark_dump_class(struct Qdisc
*sch
, unsigned long cl
,
383 struct sk_buff
*skb
, struct tcmsg
*tcm
)
385 struct dsmark_qdisc_data
*p
= PRIV(sch
);
386 unsigned char *b
= skb
->tail
;
389 DPRINTK("dsmark_dump_class(sch %p,[qdisc %p],class %ld\n",sch
,p
,cl
);
390 if (!cl
|| cl
> p
->indices
)
392 tcm
->tcm_handle
= TC_H_MAKE(TC_H_MAJ(sch
->handle
),cl
-1);
393 rta
= (struct rtattr
*) b
;
394 RTA_PUT(skb
,TCA_OPTIONS
,0,NULL
);
395 RTA_PUT(skb
,TCA_DSMARK_MASK
,1,&p
->mask
[cl
-1]);
396 RTA_PUT(skb
,TCA_DSMARK_VALUE
,1,&p
->value
[cl
-1]);
397 rta
->rta_len
= skb
->tail
-b
;
401 skb_trim(skb
,b
-skb
->data
);
405 static int dsmark_dump(struct Qdisc
*sch
, struct sk_buff
*skb
)
407 struct dsmark_qdisc_data
*p
= PRIV(sch
);
408 unsigned char *b
= skb
->tail
;
411 rta
= (struct rtattr
*) b
;
412 RTA_PUT(skb
,TCA_OPTIONS
,0,NULL
);
413 RTA_PUT(skb
,TCA_DSMARK_INDICES
,sizeof(__u16
),&p
->indices
);
414 if (p
->default_index
)
415 RTA_PUT(skb
,TCA_DSMARK_DEFAULT_INDEX
, sizeof(__u16
),
418 RTA_PUT(skb
, TCA_DSMARK_SET_TC_INDEX
, 0, NULL
);
419 rta
->rta_len
= skb
->tail
-b
;
423 skb_trim(skb
,b
-skb
->data
);
430 static struct Qdisc_class_ops dsmark_class_ops
=
432 dsmark_graft
, /* graft */
433 dsmark_leaf
, /* leaf */
434 dsmark_get
, /* get */
435 dsmark_put
, /* put */
436 dsmark_change
, /* change */
437 dsmark_delete
, /* delete */
438 dsmark_walk
, /* walk */
440 dsmark_find_tcf
, /* tcf_chain */
441 dsmark_bind_filter
, /* bind_tcf */
442 dsmark_put
, /* unbind_tcf */
444 #ifdef CONFIG_RTNETLINK
445 dsmark_dump_class
, /* dump */
449 struct Qdisc_ops dsmark_qdisc_ops
=
452 &dsmark_class_ops
, /* cl_ops */
454 sizeof(struct dsmark_qdisc_data
),
456 dsmark_enqueue
, /* enqueue */
457 dsmark_dequeue
, /* dequeue */
458 dsmark_requeue
, /* requeue */
459 dsmark_drop
, /* drop */
461 dsmark_init
, /* init */
462 dsmark_reset
, /* reset */
463 dsmark_destroy
, /* destroy */
466 #ifdef CONFIG_RTNETLINK
467 dsmark_dump
/* dump */
472 int init_module(void)
474 return register_qdisc(&dsmark_qdisc_ops
);
478 void cleanup_module(void)
480 unregister_qdisc(&dsmark_qdisc_ops
);