2005-04-17 02:20:36 +04:00
/* net/sched/sch_dsmark.c - Differentiated Services field marker */
/* Written 1998-2000 by Werner Almesberger, EPFL ICA */
# include <linux/module.h>
# include <linux/init.h>
# include <linux/types.h>
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/skbuff.h>
# include <linux/rtnetlink.h>
2008-01-21 13:21:45 +03:00
# include <linux/bitops.h>
2005-04-17 02:20:36 +04:00
# include <net/pkt_sched.h>
# include <net/dsfield.h>
# include <net/inet_ecn.h>
# include <asm/byteorder.h>
/*
* 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 ;
2005-06-19 09:53:29 +04:00
u8 * mask ; /* "owns" the array */
u8 * value ;
u16 indices ;
u32 default_index ; /* index range is 0...0xffff */
2005-04-17 02:20:36 +04:00
int set_tc_index ;
} ;
2005-06-19 09:52:54 +04:00
static inline int dsmark_valid_index ( struct dsmark_qdisc_data * p , u16 index )
{
return ( index < = p - > indices & & index > 0 ) ;
}
2005-04-17 02:20:36 +04:00
/* ------------------------- Class/flow operations ------------------------- */
2005-06-19 09:53:29 +04:00
static int dsmark_graft ( struct Qdisc * sch , unsigned long arg ,
struct Qdisc * new , struct Qdisc * * old )
2005-04-17 02:20:36 +04:00
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
2005-04-17 02:20:36 +04:00
2008-01-21 11:50:09 +03:00
pr_debug ( " dsmark_graft(sch %p,[qdisc %p],new %p,old %p) \n " ,
2005-06-19 09:53:29 +04:00
sch , p , new , old ) ;
2005-06-01 02:16:52 +04:00
if ( new = = NULL ) {
2008-07-09 04:06:30 +04:00
new = qdisc_create_dflt ( qdisc_dev ( sch ) , sch - > dev_queue ,
2008-07-09 03:55:56 +04:00
& pfifo_qdisc_ops ,
2006-11-30 04:35:18 +03:00
sch - > handle ) ;
2005-06-01 02:16:52 +04:00
if ( new = = NULL )
new = & noop_qdisc ;
}
2005-04-17 02:20:36 +04:00
sch_tree_lock ( sch ) ;
2008-11-20 15:11:36 +03:00
* old = p - > q ;
p - > q = new ;
2006-11-30 04:36:20 +03:00
qdisc_tree_decrease_qlen ( * old , ( * old ) - > q . qlen ) ;
2005-06-19 09:53:29 +04:00
qdisc_reset ( * old ) ;
sch_tree_unlock ( sch ) ;
2007-02-09 17:25:16 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static struct Qdisc * dsmark_leaf ( struct Qdisc * sch , unsigned long arg )
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
return p - > q ;
2005-04-17 02:20:36 +04:00
}
2005-06-19 09:53:29 +04:00
static unsigned long dsmark_get ( struct Qdisc * sch , u32 classid )
2005-04-17 02:20:36 +04:00
{
2008-01-21 11:50:09 +03:00
pr_debug ( " dsmark_get(sch %p,[qdisc %p],classid %x) \n " ,
sch , qdisc_priv ( sch ) , classid ) ;
2005-04-17 02:20:36 +04:00
2005-06-19 09:53:29 +04:00
return TC_H_MIN ( classid ) + 1 ;
2005-04-17 02:20:36 +04:00
}
static unsigned long dsmark_bind_filter ( struct Qdisc * sch ,
2005-06-19 09:53:29 +04:00
unsigned long parent , u32 classid )
2005-04-17 02:20:36 +04:00
{
2005-06-19 09:53:29 +04:00
return dsmark_get ( sch , classid ) ;
2005-04-17 02:20:36 +04:00
}
static void dsmark_put ( struct Qdisc * sch , unsigned long cl )
{
}
2008-01-24 07:35:39 +03:00
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 } ,
} ;
2005-04-17 02:20:36 +04:00
static int dsmark_change ( struct Qdisc * sch , u32 classid , u32 parent ,
2008-01-23 09:11:17 +03:00
struct nlattr * * tca , unsigned long * arg )
2005-04-17 02:20:36 +04:00
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
2008-01-23 09:11:17 +03:00
struct nlattr * opt = tca [ TCA_OPTIONS ] ;
struct nlattr * tb [ TCA_DSMARK_MAX + 1 ] ;
2005-06-19 09:52:54 +04:00
int err = - EINVAL ;
u8 mask = 0 ;
2005-04-17 02:20:36 +04:00
2008-01-21 11:50:09 +03:00
pr_debug ( " dsmark_change(sch %p,[qdisc %p],classid %x,parent %x), "
2005-06-19 09:52:54 +04:00
" arg 0x%lx \n " , sch , p , classid , parent , * arg ) ;
if ( ! dsmark_valid_index ( p , * arg ) ) {
err = - ENOENT ;
2008-01-23 09:11:17 +03:00
goto errout ;
2005-04-17 02:20:36 +04:00
}
2008-01-24 07:33:32 +03:00
if ( ! opt )
2008-01-23 09:11:17 +03:00
goto errout ;
2005-06-19 09:52:54 +04:00
2008-01-24 07:35:39 +03:00
err = nla_parse_nested ( tb , TCA_DSMARK_MAX , opt , dsmark_policy ) ;
2008-01-24 07:33:32 +03:00
if ( err < 0 )
2008-01-24 07:35:39 +03:00
goto errout ;
2008-01-24 07:33:32 +03:00
2008-01-24 07:35:39 +03:00
if ( tb [ TCA_DSMARK_MASK ] )
2008-01-23 09:11:17 +03:00
mask = nla_get_u8 ( tb [ TCA_DSMARK_MASK ] ) ;
2008-01-24 07:35:39 +03:00
if ( tb [ TCA_DSMARK_VALUE ] )
2008-01-23 09:11:17 +03:00
p - > value [ * arg - 1 ] = nla_get_u8 ( tb [ TCA_DSMARK_VALUE ] ) ;
2007-02-09 17:25:16 +03:00
2008-01-23 09:11:17 +03:00
if ( tb [ TCA_DSMARK_MASK ] )
2005-06-19 09:52:54 +04:00
p - > mask [ * arg - 1 ] = mask ;
err = 0 ;
2008-01-23 09:11:17 +03:00
errout :
2005-06-19 09:52:54 +04:00
return err ;
}
2005-04-17 02:20:36 +04:00
2005-06-19 09:53:29 +04:00
static int dsmark_delete ( struct Qdisc * sch , unsigned long arg )
2005-04-17 02:20:36 +04:00
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
2005-04-17 02:20:36 +04:00
2005-06-19 09:53:29 +04:00
if ( ! dsmark_valid_index ( p , arg ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-02-09 17:25:16 +03:00
2005-04-17 02:20:36 +04:00
p - > mask [ arg - 1 ] = 0xff ;
p - > value [ arg - 1 ] = 0 ;
2005-06-19 09:53:29 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-01-21 13:24:21 +03:00
static void dsmark_walk ( struct Qdisc * sch , struct qdisc_walker * walker )
2005-04-17 02:20:36 +04:00
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
2005-04-17 02:20:36 +04:00
int i ;
2008-01-21 11:50:09 +03:00
pr_debug ( " dsmark_walk(sch %p,[qdisc %p],walker %p) \n " , sch , p , walker ) ;
2005-06-19 09:53:29 +04:00
2005-04-17 02:20:36 +04:00
if ( walker - > stop )
return ;
2005-06-19 09:53:29 +04:00
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < p - > indices ; i + + ) {
if ( p - > mask [ i ] = = 0xff & & ! p - > value [ i ] )
2005-06-01 02:15:58 +04:00
goto ignore ;
2005-04-17 02:20:36 +04:00
if ( walker - > count > = walker - > skip ) {
if ( walker - > fn ( sch , i + 1 , walker ) < 0 ) {
walker - > stop = 1 ;
break ;
}
}
2007-02-09 17:25:16 +03:00
ignore :
2005-06-01 02:15:58 +04:00
walker - > count + + ;
2007-02-09 17:25:16 +03:00
}
2005-04-17 02:20:36 +04:00
}
2008-01-21 13:24:21 +03:00
static inline struct tcf_proto * * dsmark_find_tcf ( struct Qdisc * sch ,
unsigned long cl )
2005-04-17 02:20:36 +04:00
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
return & p - > filter_list ;
2005-04-17 02:20:36 +04:00
}
/* --------------------------- Qdisc operations ---------------------------- */
2008-01-21 13:24:21 +03:00
static int dsmark_enqueue ( struct sk_buff * skb , struct Qdisc * sch )
2005-04-17 02:20:36 +04:00
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
2005-06-19 09:53:29 +04:00
int err ;
2008-01-21 11:50:09 +03:00
pr_debug ( " dsmark_enqueue(skb %p,sch %p,[qdisc %p]) \n " , skb , sch , p ) ;
2005-04-17 02:20:36 +04:00
if ( p - > set_tc_index ) {
switch ( skb - > protocol ) {
2008-09-21 09:20:49 +04:00
case htons ( ETH_P_IP ) :
2008-01-21 13:24:21 +03:00
if ( skb_cow_head ( skb , sizeof ( struct iphdr ) ) )
goto drop ;
2008-01-21 13:23:49 +03:00
2008-01-21 13:24:21 +03:00
skb - > tc_index = ipv4_get_dsfield ( ip_hdr ( skb ) )
& ~ INET_ECN_MASK ;
break ;
2008-01-21 13:23:49 +03:00
2008-09-21 09:20:49 +04:00
case htons ( ETH_P_IPV6 ) :
2008-01-21 13:24:21 +03:00
if ( skb_cow_head ( skb , sizeof ( struct ipv6hdr ) ) )
goto drop ;
2008-01-21 13:23:49 +03:00
2008-01-21 13:24:21 +03:00
skb - > tc_index = ipv6_get_dsfield ( ipv6_hdr ( skb ) )
& ~ INET_ECN_MASK ;
break ;
default :
skb - > tc_index = 0 ;
break ;
2007-04-21 04:09:22 +04:00
}
2005-04-17 02:20:36 +04:00
}
2005-06-19 09:53:29 +04:00
if ( TC_H_MAJ ( skb - > priority ) = = sch - > handle )
2005-04-17 02:20:36 +04:00
skb - > tc_index = TC_H_MIN ( skb - > priority ) ;
2005-06-19 09:53:29 +04:00
else {
struct tcf_result res ;
int result = tc_classify ( skb , p - > filter_list , & res ) ;
2008-01-21 11:50:09 +03:00
pr_debug ( " result %d class 0x%04x \n " , result , res . classid ) ;
2005-06-19 09:53:29 +04:00
2005-04-17 02:20:36 +04:00
switch ( result ) {
2007-07-15 11:02:10 +04:00
# ifdef CONFIG_NET_CLS_ACT
case TC_ACT_QUEUED :
case TC_ACT_STOLEN :
kfree_skb ( skb ) ;
2008-08-05 09:31:03 +04:00
return NET_XMIT_SUCCESS | __NET_XMIT_STOLEN ;
2008-01-21 13:23:49 +03:00
2007-07-15 11:02:10 +04:00
case TC_ACT_SHOT :
2008-01-21 13:23:49 +03:00
goto drop ;
2005-04-17 02:20:36 +04:00
# endif
2007-07-15 11:03:05 +04:00
case TC_ACT_OK :
2007-07-15 11:02:10 +04:00
skb - > tc_index = TC_H_MIN ( res . classid ) ;
break ;
2008-01-21 13:23:49 +03:00
2007-07-15 11:02:10 +04:00
default :
if ( p - > default_index ! = NO_DEFAULT_INDEX )
skb - > tc_index = p - > default_index ;
break ;
2007-04-21 04:09:22 +04:00
}
2005-04-17 02:20:36 +04:00
}
2008-07-20 11:08:04 +04:00
err = qdisc_enqueue ( skb , p - > q ) ;
2005-06-19 09:53:29 +04:00
if ( err ! = NET_XMIT_SUCCESS ) {
2008-08-05 09:31:03 +04:00
if ( net_xmit_drop_count ( err ) )
sch - > qstats . drops + + ;
2005-06-19 09:53:29 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
2005-06-19 09:53:29 +04:00
2008-07-20 11:08:27 +04:00
sch - > bstats . bytes + = qdisc_pkt_len ( skb ) ;
2005-04-17 02:20:36 +04:00
sch - > bstats . packets + + ;
sch - > q . qlen + + ;
2005-06-19 09:53:29 +04:00
return NET_XMIT_SUCCESS ;
2008-01-21 13:23:49 +03:00
drop :
kfree_skb ( skb ) ;
sch - > qstats . drops + + ;
2008-08-05 09:39:11 +04:00
return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS ;
2005-06-19 09:53:29 +04:00
}
2005-04-17 02:20:36 +04:00
static struct sk_buff * dsmark_dequeue ( struct Qdisc * sch )
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
2005-04-17 02:20:36 +04:00
struct sk_buff * skb ;
2005-06-19 09:53:29 +04:00
u32 index ;
2008-01-21 11:50:09 +03:00
pr_debug ( " dsmark_dequeue(sch %p,[qdisc %p]) \n " , sch , p ) ;
2005-04-17 02:20:36 +04:00
skb = p - > q - > ops - > dequeue ( p - > q ) ;
2005-06-19 09:53:29 +04:00
if ( skb = = NULL )
2005-04-17 02:20:36 +04:00
return NULL ;
2005-06-19 09:53:29 +04:00
2005-04-17 02:20:36 +04:00
sch - > q . qlen - - ;
2005-06-19 09:53:29 +04:00
index = skb - > tc_index & ( p - > indices - 1 ) ;
2008-01-21 11:50:09 +03:00
pr_debug ( " index %d->%d \n " , skb - > tc_index , index ) ;
2005-06-19 09:53:29 +04:00
2005-04-17 02:20:36 +04:00
switch ( skb - > protocol ) {
2008-09-21 09:20:49 +04:00
case htons ( ETH_P_IP ) :
2008-01-21 13:24:21 +03:00
ipv4_change_dsfield ( ip_hdr ( skb ) , p - > mask [ index ] ,
p - > value [ index ] ) ;
2005-04-17 02:20:36 +04:00
break ;
2008-09-21 09:20:49 +04:00
case htons ( ETH_P_IPV6 ) :
2008-01-21 13:24:21 +03:00
ipv6_change_dsfield ( ipv6_hdr ( skb ) , p - > mask [ index ] ,
p - > value [ index ] ) ;
2005-04-17 02:20:36 +04:00
break ;
2008-01-21 13:24:21 +03:00
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 ] )
printk ( KERN_WARNING
" dsmark_dequeue: unsupported protocol %d \n " ,
ntohs ( skb - > protocol ) ) ;
break ;
2007-04-21 04:09:22 +04:00
}
2005-06-19 09:53:29 +04:00
2005-04-17 02:20:36 +04:00
return skb ;
}
2008-10-31 10:45:55 +03:00
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]) \n " , sch , p ) ;
return p - > q - > ops - > peek ( p - > q ) ;
}
2005-04-17 02:20:36 +04:00
static unsigned int dsmark_drop ( struct Qdisc * sch )
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
2005-04-17 02:20:36 +04:00
unsigned int len ;
2007-02-09 17:25:16 +03:00
2008-01-21 11:50:09 +03:00
pr_debug ( " dsmark_reset(sch %p,[qdisc %p]) \n " , sch , p ) ;
2005-06-19 09:53:29 +04:00
if ( p - > q - > ops - > drop = = NULL )
2005-04-17 02:20:36 +04:00
return 0 ;
2005-06-19 09:53:29 +04:00
len = p - > q - > ops - > drop ( p - > q ) ;
if ( len )
sch - > q . qlen - - ;
2005-04-17 02:20:36 +04:00
return len ;
}
2008-01-23 09:11:17 +03:00
static int dsmark_init ( struct Qdisc * sch , struct nlattr * opt )
2005-04-17 02:20:36 +04:00
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
2008-01-23 09:11:17 +03:00
struct nlattr * tb [ TCA_DSMARK_MAX + 1 ] ;
2005-06-19 09:52:54 +04:00
int err = - EINVAL ;
u32 default_index = NO_DEFAULT_INDEX ;
u16 indices ;
u8 * mask ;
2008-01-21 11:50:09 +03:00
pr_debug ( " dsmark_init(sch %p,[qdisc %p],opt %p) \n " , sch , p , opt ) ;
2005-06-19 09:52:54 +04:00
2008-01-24 07:33:32 +03:00
if ( ! opt )
goto errout ;
2008-01-24 07:35:39 +03:00
err = nla_parse_nested ( tb , TCA_DSMARK_MAX , opt , dsmark_policy ) ;
2008-01-24 07:33:32 +03:00
if ( err < 0 )
2005-06-19 09:52:54 +04:00
goto errout ;
2008-01-24 07:33:32 +03:00
err = - EINVAL ;
2008-01-23 09:11:17 +03:00
indices = nla_get_u16 ( tb [ TCA_DSMARK_INDICES ] ) ;
2008-01-21 13:21:45 +03:00
if ( hweight32 ( indices ) ! = 1 )
2005-06-19 09:52:54 +04:00
goto errout ;
2008-01-24 07:35:39 +03:00
if ( tb [ TCA_DSMARK_DEFAULT_INDEX ] )
2008-01-23 09:11:17 +03:00
default_index = nla_get_u16 ( tb [ TCA_DSMARK_DEFAULT_INDEX ] ) ;
2005-06-19 09:52:54 +04:00
mask = kmalloc ( indices * 2 , GFP_KERNEL ) ;
if ( mask = = NULL ) {
err = - ENOMEM ;
goto errout ;
2005-04-17 02:20:36 +04:00
}
2005-06-19 09:52:54 +04:00
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 ;
2008-01-23 09:11:17 +03:00
p - > set_tc_index = nla_get_flag ( tb [ TCA_DSMARK_SET_TC_INDEX ] ) ;
2005-06-19 09:52:54 +04:00
2008-07-09 04:06:30 +04:00
p - > q = qdisc_create_dflt ( qdisc_dev ( sch ) , sch - > dev_queue ,
2008-07-09 03:55:56 +04:00
& pfifo_qdisc_ops , sch - > handle ) ;
2005-06-19 09:52:54 +04:00
if ( p - > q = = NULL )
2005-04-17 02:20:36 +04:00
p - > q = & noop_qdisc ;
2005-06-19 09:52:54 +04:00
2008-01-21 11:50:09 +03:00
pr_debug ( " dsmark_init: qdisc %p \n " , p - > q ) ;
2005-06-19 09:52:54 +04:00
err = 0 ;
errout :
return err ;
2005-04-17 02:20:36 +04:00
}
static void dsmark_reset ( struct Qdisc * sch )
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
2005-04-17 02:20:36 +04:00
2008-01-21 11:50:09 +03:00
pr_debug ( " dsmark_reset(sch %p,[qdisc %p]) \n " , sch , p ) ;
2005-04-17 02:20:36 +04:00
qdisc_reset ( p - > q ) ;
sch - > q . qlen = 0 ;
}
static void dsmark_destroy ( struct Qdisc * sch )
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
2005-04-17 02:20:36 +04:00
2008-01-21 11:50:09 +03:00
pr_debug ( " dsmark_destroy(sch %p,[qdisc %p]) \n " , sch , p ) ;
2005-06-19 09:53:29 +04:00
2008-07-02 06:52:38 +04:00
tcf_destroy_chain ( & p - > filter_list ) ;
2005-04-17 02:20:36 +04:00
qdisc_destroy ( p - > q ) ;
kfree ( p - > mask ) ;
}
static int dsmark_dump_class ( struct Qdisc * sch , unsigned long cl ,
2005-06-19 09:53:12 +04:00
struct sk_buff * skb , struct tcmsg * tcm )
2005-04-17 02:20:36 +04:00
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
2008-01-23 09:11:17 +03:00
struct nlattr * opts = NULL ;
2005-04-17 02:20:36 +04:00
2008-01-21 11:50:09 +03:00
pr_debug ( " dsmark_dump_class(sch %p,[qdisc %p],class %ld \n " , sch , p , cl ) ;
2005-06-19 09:53:12 +04:00
if ( ! dsmark_valid_index ( p , cl ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2005-06-19 09:53:12 +04:00
tcm - > tcm_handle = TC_H_MAKE ( TC_H_MAJ ( sch - > handle ) , cl - 1 ) ;
2006-03-21 06:01:06 +03:00
tcm - > tcm_info = p - > q - > handle ;
2005-06-19 09:53:12 +04:00
2008-01-23 09:11:17 +03:00
opts = nla_nest_start ( skb , TCA_OPTIONS ) ;
if ( opts = = NULL )
goto nla_put_failure ;
NLA_PUT_U8 ( skb , TCA_DSMARK_MASK , p - > mask [ cl - 1 ] ) ;
NLA_PUT_U8 ( skb , TCA_DSMARK_VALUE , p - > value [ cl - 1 ] ) ;
2005-06-19 09:53:12 +04:00
2008-01-23 09:11:17 +03:00
return nla_nest_end ( skb , opts ) ;
2005-04-17 02:20:36 +04:00
2008-01-23 09:11:17 +03:00
nla_put_failure :
2008-06-04 03:36:54 +04:00
nla_nest_cancel ( skb , opts ) ;
return - EMSGSIZE ;
2005-04-17 02:20:36 +04:00
}
static int dsmark_dump ( struct Qdisc * sch , struct sk_buff * skb )
{
2008-01-21 11:50:09 +03:00
struct dsmark_qdisc_data * p = qdisc_priv ( sch ) ;
2008-01-23 09:11:17 +03:00
struct nlattr * opts = NULL ;
2005-04-17 02:20:36 +04:00
2008-01-23 09:11:17 +03:00
opts = nla_nest_start ( skb , TCA_OPTIONS ) ;
if ( opts = = NULL )
goto nla_put_failure ;
NLA_PUT_U16 ( skb , TCA_DSMARK_INDICES , p - > indices ) ;
2005-06-19 09:53:12 +04:00
if ( p - > default_index ! = NO_DEFAULT_INDEX )
2008-01-23 09:11:17 +03:00
NLA_PUT_U16 ( skb , TCA_DSMARK_DEFAULT_INDEX , p - > default_index ) ;
2005-04-17 02:20:36 +04:00
if ( p - > set_tc_index )
2008-01-23 09:11:17 +03:00
NLA_PUT_FLAG ( skb , TCA_DSMARK_SET_TC_INDEX ) ;
2005-06-19 09:53:12 +04:00
2008-01-23 09:11:17 +03:00
return nla_nest_end ( skb , opts ) ;
2005-04-17 02:20:36 +04:00
2008-01-23 09:11:17 +03:00
nla_put_failure :
2008-06-04 03:36:54 +04:00
nla_nest_cancel ( skb , opts ) ;
return - EMSGSIZE ;
2005-04-17 02:20:36 +04:00
}
2007-11-14 12:44:41 +03:00
static const struct Qdisc_class_ops dsmark_class_ops = {
2005-04-17 02:20:36 +04:00
. 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 ,
} ;
2007-11-14 12:44:41 +03:00
static struct Qdisc_ops dsmark_qdisc_ops __read_mostly = {
2005-04-17 02:20:36 +04:00
. next = NULL ,
. cl_ops = & dsmark_class_ops ,
. id = " dsmark " ,
. priv_size = sizeof ( struct dsmark_qdisc_data ) ,
. enqueue = dsmark_enqueue ,
. dequeue = dsmark_dequeue ,
2008-10-31 10:45:55 +03:00
. peek = dsmark_peek ,
2005-04-17 02:20:36 +04:00
. 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 ) ;
}
2005-06-19 09:53:29 +04:00
2007-02-09 17:25:16 +03:00
static void __exit dsmark_module_exit ( void )
2005-04-17 02:20:36 +04:00
{
unregister_qdisc ( & dsmark_qdisc_ops ) ;
}
2005-06-19 09:53:29 +04:00
2005-04-17 02:20:36 +04:00
module_init ( dsmark_module_init )
module_exit ( dsmark_module_exit )
2005-06-19 09:53:29 +04:00
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;