2005-04-17 02:20:36 +04:00
/*
* net / sched / sch_fifo . c The simplest FIFO queue .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
* Authors : Alexey Kuznetsov , < kuznet @ ms2 . inr . ac . ru >
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/skbuff.h>
# include <net/pkt_sched.h>
/* 1 band FIFO pseudo-"scheduler" */
struct fifo_sched_data
{
2005-06-19 09:58:00 +04:00
u32 limit ;
2005-04-17 02:20:36 +04:00
} ;
2005-06-19 09:58:00 +04:00
static int bfifo_enqueue ( struct sk_buff * skb , struct Qdisc * sch )
2005-04-17 02:20:36 +04:00
{
struct fifo_sched_data * q = qdisc_priv ( sch ) ;
2008-07-20 11:08:27 +04:00
if ( likely ( sch - > qstats . backlog + qdisc_pkt_len ( skb ) < = q - > limit ) )
2005-06-19 09:57:42 +04:00
return qdisc_enqueue_tail ( skb , sch ) ;
2005-04-17 02:20:36 +04:00
2005-06-19 09:57:42 +04:00
return qdisc_reshape_fail ( skb , sch ) ;
2005-04-17 02:20:36 +04:00
}
2005-06-19 09:58:00 +04:00
static int pfifo_enqueue ( struct sk_buff * skb , struct Qdisc * sch )
2005-04-17 02:20:36 +04:00
{
struct fifo_sched_data * q = qdisc_priv ( sch ) ;
2005-06-19 09:57:42 +04:00
if ( likely ( skb_queue_len ( & sch - > q ) < q - > limit ) )
return qdisc_enqueue_tail ( skb , sch ) ;
2005-04-17 02:20:36 +04:00
2005-06-19 09:57:42 +04:00
return qdisc_reshape_fail ( skb , sch ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-23 09:11:17 +03:00
static int fifo_init ( struct Qdisc * sch , struct nlattr * opt )
2005-04-17 02:20:36 +04:00
{
struct fifo_sched_data * q = qdisc_priv ( sch ) ;
if ( opt = = NULL ) {
2008-07-09 04:06:30 +04:00
u32 limit = qdisc_dev ( sch ) - > tx_queue_len ? : 1 ;
2005-04-17 02:20:36 +04:00
if ( sch - > ops = = & bfifo_qdisc_ops )
2008-07-09 04:06:30 +04:00
limit * = qdisc_dev ( sch ) - > mtu ;
2005-06-19 09:58:00 +04:00
q - > limit = limit ;
2005-04-17 02:20:36 +04:00
} else {
2008-01-23 09:11:17 +03:00
struct tc_fifo_qopt * ctl = nla_data ( opt ) ;
2005-06-19 09:58:00 +04:00
2008-01-23 09:11:17 +03:00
if ( nla_len ( opt ) < sizeof ( * ctl ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2005-06-19 09:58:00 +04:00
2005-04-17 02:20:36 +04:00
q - > limit = ctl - > limit ;
}
2005-06-19 09:58:00 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int fifo_dump ( struct Qdisc * sch , struct sk_buff * skb )
{
struct fifo_sched_data * q = qdisc_priv ( sch ) ;
2005-06-19 09:58:00 +04:00
struct tc_fifo_qopt opt = { . limit = q - > limit } ;
2005-04-17 02:20:36 +04:00
2008-01-23 09:11:17 +03:00
NLA_PUT ( skb , TCA_OPTIONS , sizeof ( opt ) , & opt ) ;
2005-04-17 02:20:36 +04:00
return skb - > len ;
2008-01-23 09:11:17 +03:00
nla_put_failure :
2005-04-17 02:20:36 +04:00
return - 1 ;
}
2007-11-14 12:44:41 +03:00
struct Qdisc_ops pfifo_qdisc_ops __read_mostly = {
2005-04-17 02:20:36 +04:00
. id = " pfifo " ,
. priv_size = sizeof ( struct fifo_sched_data ) ,
. enqueue = pfifo_enqueue ,
2005-06-19 09:57:42 +04:00
. dequeue = qdisc_dequeue_head ,
2008-10-31 10:44:18 +03:00
. peek = qdisc_peek_head ,
2005-06-19 09:57:42 +04:00
. drop = qdisc_queue_drop ,
2005-04-17 02:20:36 +04:00
. init = fifo_init ,
2005-06-19 09:57:42 +04:00
. reset = qdisc_reset_queue ,
2005-04-17 02:20:36 +04:00
. change = fifo_init ,
. dump = fifo_dump ,
. owner = THIS_MODULE ,
} ;
2008-01-23 09:10:23 +03:00
EXPORT_SYMBOL ( pfifo_qdisc_ops ) ;
2005-04-17 02:20:36 +04:00
2007-11-14 12:44:41 +03:00
struct Qdisc_ops bfifo_qdisc_ops __read_mostly = {
2005-04-17 02:20:36 +04:00
. id = " bfifo " ,
. priv_size = sizeof ( struct fifo_sched_data ) ,
. enqueue = bfifo_enqueue ,
2005-06-19 09:57:42 +04:00
. dequeue = qdisc_dequeue_head ,
2008-10-31 10:44:18 +03:00
. peek = qdisc_peek_head ,
2005-06-19 09:57:42 +04:00
. drop = qdisc_queue_drop ,
2005-04-17 02:20:36 +04:00
. init = fifo_init ,
2005-06-19 09:57:42 +04:00
. reset = qdisc_reset_queue ,
2005-04-17 02:20:36 +04:00
. change = fifo_init ,
. dump = fifo_dump ,
. owner = THIS_MODULE ,
} ;
EXPORT_SYMBOL ( bfifo_qdisc_ops ) ;
2008-07-06 10:40:21 +04:00
/* Pass size change message down to embedded FIFO */
int fifo_set_limit ( struct Qdisc * q , unsigned int limit )
{
struct nlattr * nla ;
int ret = - ENOMEM ;
/* Hack to avoid sending change message to non-FIFO */
if ( strncmp ( q - > ops - > id + 1 , " fifo " , 4 ) ! = 0 )
return 0 ;
nla = kmalloc ( nla_attr_size ( sizeof ( struct tc_fifo_qopt ) ) , GFP_KERNEL ) ;
if ( nla ) {
nla - > nla_type = RTM_NEWQDISC ;
nla - > nla_len = nla_attr_size ( sizeof ( struct tc_fifo_qopt ) ) ;
( ( struct tc_fifo_qopt * ) nla_data ( nla ) ) - > limit = limit ;
ret = q - > ops - > change ( q , nla ) ;
kfree ( nla ) ;
}
return ret ;
}
EXPORT_SYMBOL ( fifo_set_limit ) ;
struct Qdisc * fifo_create_dflt ( struct Qdisc * sch , struct Qdisc_ops * ops ,
unsigned int limit )
{
struct Qdisc * q ;
int err = - ENOMEM ;
2008-07-09 04:06:30 +04:00
q = qdisc_create_dflt ( qdisc_dev ( sch ) , sch - > dev_queue ,
2008-07-09 03:55:56 +04:00
ops , TC_H_MAKE ( sch - > handle , 1 ) ) ;
2008-07-06 10:40:21 +04:00
if ( q ) {
err = fifo_set_limit ( q , limit ) ;
if ( err < 0 ) {
qdisc_destroy ( q ) ;
q = NULL ;
}
}
return q ? : ERR_PTR ( err ) ;
}
EXPORT_SYMBOL ( fifo_create_dflt ) ;