2005-04-17 02:20:36 +04:00
/*
* net / sched / gact . c Generic actions
*
* 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 .
*
* copyright Jamal Hadi Salim ( 2002 - 4 )
*
*/
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/skbuff.h>
# include <linux/rtnetlink.h>
# include <linux/module.h>
# include <linux/init.h>
2007-03-26 10:06:12 +04:00
# include <net/netlink.h>
2005-04-17 02:20:36 +04:00
# include <net/pkt_sched.h>
# include <linux/tc_act/tc_gact.h>
# include <net/tc_act/tc_gact.h>
2006-08-22 10:54:55 +04:00
# define GACT_TAB_MASK 15
static struct tcf_common * tcf_gact_ht [ GACT_TAB_MASK + 1 ] ;
static u32 gact_idx_gen ;
2005-04-17 02:20:36 +04:00
static DEFINE_RWLOCK ( gact_lock ) ;
2006-08-22 10:54:55 +04:00
static struct tcf_hashinfo gact_hash_info = {
. htab = tcf_gact_ht ,
. hmask = GACT_TAB_MASK ,
. lock = & gact_lock ,
} ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_GACT_PROB
2006-08-22 10:54:55 +04:00
static int gact_net_rand ( struct tcf_gact * gact )
2005-04-17 02:20:36 +04:00
{
2006-12-02 07:21:44 +03:00
if ( ! gact - > tcfg_pval | | net_random ( ) % gact - > tcfg_pval )
2006-08-22 10:54:55 +04:00
return gact - > tcf_action ;
return gact - > tcfg_paction ;
2005-04-17 02:20:36 +04:00
}
2006-08-22 10:54:55 +04:00
static int gact_determ ( struct tcf_gact * gact )
2005-04-17 02:20:36 +04:00
{
2006-12-02 07:21:44 +03:00
if ( ! gact - > tcfg_pval | | gact - > tcf_bstats . packets % gact - > tcfg_pval )
2006-08-22 10:54:55 +04:00
return gact - > tcf_action ;
return gact - > tcfg_paction ;
2005-04-17 02:20:36 +04:00
}
2006-08-22 10:54:55 +04:00
typedef int ( * g_rand ) ( struct tcf_gact * gact ) ;
2011-01-19 22:26:56 +03:00
static g_rand gact_rand [ MAX_RAND ] = { NULL , gact_net_rand , gact_determ } ;
2006-08-22 10:54:55 +04:00
# endif /* CONFIG_GACT_PROB */
2005-04-17 02:20:36 +04:00
2008-01-24 07:36:30 +03:00
static const struct nla_policy gact_policy [ TCA_GACT_MAX + 1 ] = {
[ TCA_GACT_PARMS ] = { . len = sizeof ( struct tc_gact ) } ,
[ TCA_GACT_PROB ] = { . len = sizeof ( struct tc_gact_p ) } ,
} ;
2013-01-14 09:15:39 +04:00
static int tcf_gact_init ( struct net * net , struct nlattr * nla ,
struct nlattr * est , struct tc_action * a ,
int ovr , int bind )
2005-04-17 02:20:36 +04:00
{
2008-01-23 09:11:50 +03:00
struct nlattr * tb [ TCA_GACT_MAX + 1 ] ;
2005-04-17 02:20:36 +04:00
struct tc_gact * parm ;
2006-08-22 10:54:55 +04:00
struct tcf_gact * gact ;
struct tcf_common * pc ;
2005-04-17 02:20:36 +04:00
int ret = 0 ;
2008-01-24 07:33:32 +03:00
int err ;
2012-08-03 14:57:52 +04:00
# ifdef CONFIG_GACT_PROB
struct tc_gact_p * p_parm = NULL ;
# endif
2005-04-17 02:20:36 +04:00
2008-01-24 07:33:32 +03:00
if ( nla = = NULL )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2008-01-24 07:36:30 +03:00
err = nla_parse_nested ( tb , TCA_GACT_MAX , nla , gact_policy ) ;
2008-01-24 07:33:32 +03:00
if ( err < 0 )
return err ;
2008-01-24 07:36:30 +03:00
if ( tb [ TCA_GACT_PARMS ] = = NULL )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2008-01-23 09:11:50 +03:00
parm = nla_data ( tb [ TCA_GACT_PARMS ] ) ;
2005-04-17 02:20:36 +04:00
2008-01-24 07:36:30 +03:00
# ifndef CONFIG_GACT_PROB
2008-01-23 09:11:50 +03:00
if ( tb [ TCA_GACT_PROB ] ! = NULL )
2005-04-17 02:20:36 +04:00
return - EOPNOTSUPP ;
2012-08-03 14:57:52 +04:00
# else
if ( tb [ TCA_GACT_PROB ] ) {
p_parm = nla_data ( tb [ TCA_GACT_PROB ] ) ;
if ( p_parm - > ptype > = MAX_RAND )
return - EINVAL ;
}
2005-04-17 02:20:36 +04:00
# endif
2006-08-22 10:54:55 +04:00
pc = tcf_hash_check ( parm - > index , a , bind , & gact_hash_info ) ;
if ( ! pc ) {
pc = tcf_hash_create ( parm - > index , est , a , sizeof ( * gact ) ,
bind , & gact_idx_gen , & gact_hash_info ) ;
2008-11-26 08:12:32 +03:00
if ( IS_ERR ( pc ) )
2011-01-19 22:26:56 +03:00
return PTR_ERR ( pc ) ;
2005-04-17 02:20:36 +04:00
ret = ACT_P_CREATED ;
} else {
if ( ! ovr ) {
2006-08-22 10:54:55 +04:00
tcf_hash_release ( pc , bind , & gact_hash_info ) ;
2005-04-17 02:20:36 +04:00
return - EEXIST ;
}
}
2006-08-22 10:54:55 +04:00
gact = to_gact ( pc ) ;
spin_lock_bh ( & gact - > tcf_lock ) ;
gact - > tcf_action = parm - > action ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_GACT_PROB
2012-08-03 14:57:52 +04:00
if ( p_parm ) {
2006-08-22 10:54:55 +04:00
gact - > tcfg_paction = p_parm - > paction ;
gact - > tcfg_pval = p_parm - > pval ;
gact - > tcfg_ptype = p_parm - > ptype ;
2005-04-17 02:20:36 +04:00
}
# endif
2006-08-22 10:54:55 +04:00
spin_unlock_bh ( & gact - > tcf_lock ) ;
2005-04-17 02:20:36 +04:00
if ( ret = = ACT_P_CREATED )
2006-08-22 10:54:55 +04:00
tcf_hash_insert ( pc , & gact_hash_info ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2006-08-22 10:54:55 +04:00
static int tcf_gact_cleanup ( struct tc_action * a , int bind )
2005-04-17 02:20:36 +04:00
{
2006-08-22 10:54:55 +04:00
struct tcf_gact * gact = a - > priv ;
2005-04-17 02:20:36 +04:00
2006-08-22 10:54:55 +04:00
if ( gact )
return tcf_hash_release ( & gact - > common , bind , & gact_hash_info ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-07-06 03:25:42 +04:00
static int tcf_gact ( struct sk_buff * skb , const struct tc_action * a ,
struct tcf_result * res )
2005-04-17 02:20:36 +04:00
{
2006-08-22 10:54:55 +04:00
struct tcf_gact * gact = a - > priv ;
2005-04-17 02:20:36 +04:00
int action = TC_ACT_SHOT ;
2006-08-22 10:54:55 +04:00
spin_lock ( & gact - > tcf_lock ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_GACT_PROB
2012-08-03 14:57:52 +04:00
if ( gact - > tcfg_ptype )
2006-08-22 10:54:55 +04:00
action = gact_rand [ gact - > tcfg_ptype ] ( gact ) ;
2005-04-17 02:20:36 +04:00
else
2006-08-22 10:54:55 +04:00
action = gact - > tcf_action ;
2005-04-17 02:20:36 +04:00
# else
2006-08-22 10:54:55 +04:00
action = gact - > tcf_action ;
2005-04-17 02:20:36 +04:00
# endif
2008-07-20 11:08:27 +04:00
gact - > tcf_bstats . bytes + = qdisc_pkt_len ( skb ) ;
2006-08-22 10:54:55 +04:00
gact - > tcf_bstats . packets + + ;
2005-04-17 02:20:36 +04:00
if ( action = = TC_ACT_SHOT )
2006-08-22 10:54:55 +04:00
gact - > tcf_qstats . drops + + ;
gact - > tcf_tm . lastuse = jiffies ;
spin_unlock ( & gact - > tcf_lock ) ;
2005-04-17 02:20:36 +04:00
return action ;
}
2006-08-22 10:54:55 +04:00
static int tcf_gact_dump ( struct sk_buff * skb , struct tc_action * a , int bind , int ref )
2005-04-17 02:20:36 +04:00
{
2007-04-20 07:29:13 +04:00
unsigned char * b = skb_tail_pointer ( skb ) ;
2006-08-22 10:54:55 +04:00
struct tcf_gact * gact = a - > priv ;
2010-08-17 00:04:22 +04:00
struct tc_gact opt = {
. index = gact - > tcf_index ,
. refcnt = gact - > tcf_refcnt - ref ,
. bindcnt = gact - > tcf_bindcnt - bind ,
. action = gact - > tcf_action ,
} ;
2005-04-17 02:20:36 +04:00
struct tcf_t t ;
2012-03-29 13:11:39 +04:00
if ( nla_put ( skb , TCA_GACT_PARMS , sizeof ( opt ) , & opt ) )
goto nla_put_failure ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_GACT_PROB
2006-08-22 10:54:55 +04:00
if ( gact - > tcfg_ptype ) {
2010-08-17 00:04:22 +04:00
struct tc_gact_p p_opt = {
. paction = gact - > tcfg_paction ,
. pval = gact - > tcfg_pval ,
. ptype = gact - > tcfg_ptype ,
} ;
2012-03-29 13:11:39 +04:00
if ( nla_put ( skb , TCA_GACT_PROB , sizeof ( p_opt ) , & p_opt ) )
goto nla_put_failure ;
2005-04-17 02:20:36 +04:00
}
# endif
2006-08-22 10:54:55 +04:00
t . install = jiffies_to_clock_t ( jiffies - gact - > tcf_tm . install ) ;
t . lastuse = jiffies_to_clock_t ( jiffies - gact - > tcf_tm . lastuse ) ;
t . expires = jiffies_to_clock_t ( gact - > tcf_tm . expires ) ;
2012-03-29 13:11:39 +04:00
if ( nla_put ( skb , TCA_GACT_TM , sizeof ( t ) , & t ) )
goto nla_put_failure ;
2005-04-17 02:20:36 +04:00
return skb - > len ;
2008-01-23 09:11:50 +03:00
nla_put_failure :
2007-03-26 10:06:12 +04:00
nlmsg_trim ( skb , b ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
static struct tc_action_ops act_gact_ops = {
. kind = " gact " ,
2006-08-22 10:54:55 +04:00
. hinfo = & gact_hash_info ,
2005-04-17 02:20:36 +04:00
. type = TCA_ACT_GACT ,
. capab = TCA_CAP_NONE ,
. owner = THIS_MODULE ,
. act = tcf_gact ,
. dump = tcf_gact_dump ,
. cleanup = tcf_gact_cleanup ,
. lookup = tcf_hash_search ,
. init = tcf_gact_init ,
. walk = tcf_generic_walker
} ;
MODULE_AUTHOR ( " Jamal Hadi Salim(2002-4) " ) ;
MODULE_DESCRIPTION ( " Generic Classifier actions " ) ;
MODULE_LICENSE ( " GPL " ) ;
2006-08-22 10:54:55 +04:00
static int __init gact_init_module ( void )
2005-04-17 02:20:36 +04:00
{
# ifdef CONFIG_GACT_PROB
2011-01-19 22:26:56 +03:00
pr_info ( " GACT probability on \n " ) ;
2005-04-17 02:20:36 +04:00
# else
2011-01-19 22:26:56 +03:00
pr_info ( " GACT probability NOT on \n " ) ;
2005-04-17 02:20:36 +04:00
# endif
return tcf_register_action ( & act_gact_ops ) ;
}
2006-08-22 10:54:55 +04:00
static void __exit gact_cleanup_module ( void )
2005-04-17 02:20:36 +04:00
{
tcf_unregister_action ( & act_gact_ops ) ;
}
module_init ( gact_init_module ) ;
module_exit ( gact_cleanup_module ) ;