2005-04-17 02:20:36 +04:00
/*
2014-11-05 22:51:51 +03:00
* net / sched / act_gact . c Generic actions
2005-04-17 02:20:36 +04:00
*
* 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>
netns: make struct pernet_operations::id unsigned int
Make struct pernet_operations::id unsigned.
There are 2 reasons to do so:
1)
This field is really an index into an zero based array and
thus is unsigned entity. Using negative value is out-of-bound
access by definition.
2)
On x86_64 unsigned 32-bit data which are mixed with pointers
via array indexing or offsets added or subtracted to pointers
are preffered to signed 32-bit data.
"int" being used as an array index needs to be sign-extended
to 64-bit before being used.
void f(long *p, int i)
{
g(p[i]);
}
roughly translates to
movsx rsi, esi
mov rdi, [rsi+...]
call g
MOVSX is 3 byte instruction which isn't necessary if the variable is
unsigned because x86_64 is zero extending by default.
Now, there is net_generic() function which, you guessed it right, uses
"int" as an array index:
static inline void *net_generic(const struct net *net, int id)
{
...
ptr = ng->ptr[id - 1];
...
}
And this function is used a lot, so those sign extensions add up.
Patch snipes ~1730 bytes on allyesconfig kernel (without all junk
messing with code generation):
add/remove: 0/0 grow/shrink: 70/598 up/down: 396/-2126 (-1730)
Unfortunately some functions actually grow bigger.
This is a semmingly random artefact of code generation with register
allocator being used differently. gcc decides that some variable
needs to live in new r8+ registers and every access now requires REX
prefix. Or it is shifted into r12, so [r12+0] addressing mode has to be
used which is longer than [r8]
However, overall balance is in negative direction:
add/remove: 0/0 grow/shrink: 70/598 up/down: 396/-2126 (-1730)
function old new delta
nfsd4_lock 3886 3959 +73
tipc_link_build_proto_msg 1096 1140 +44
mac80211_hwsim_new_radio 2776 2808 +32
tipc_mon_rcv 1032 1058 +26
svcauth_gss_legacy_init 1413 1429 +16
tipc_bcbase_select_primary 379 392 +13
nfsd4_exchange_id 1247 1260 +13
nfsd4_setclientid_confirm 782 793 +11
...
put_client_renew_locked 494 480 -14
ip_set_sockfn_get 730 716 -14
geneve_sock_add 829 813 -16
nfsd4_sequence_done 721 703 -18
nlmclnt_lookup_host 708 686 -22
nfsd4_lockt 1085 1063 -22
nfs_get_client 1077 1050 -27
tcf_bpf_init 1106 1076 -30
nfsd4_encode_fattr 5997 5930 -67
Total: Before=154856051, After=154854321, chg -0.00%
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-11-17 04:58:21 +03:00
static unsigned int gact_net_id ;
2016-07-26 02:09:41 +03:00
static struct tc_action_ops act_gact_ops ;
2016-02-23 02:57:53 +03:00
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
{
2015-07-06 15:18:05 +03:00
smp_rmb ( ) ; /* coupled with smp_wmb() in tcf_gact_init() */
if ( prandom_u32 ( ) % 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
{
2015-07-06 15:18:06 +03:00
u32 pack = atomic_inc_return ( & gact - > packets ) ;
2015-07-06 15:18:05 +03:00
smp_rmb ( ) ; /* coupled with smp_wmb() in tcf_gact_init() */
2015-07-06 15:18:06 +03:00
if ( pack % 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 ,
2016-07-26 02:09:41 +03:00
struct nlattr * est , struct tc_action * * a ,
2013-01-14 09:15:39 +04:00
int ovr , int bind )
2005-04-17 02:20:36 +04:00
{
2016-02-23 02:57:53 +03:00
struct tc_action_net * tn = net_generic ( net , gact_net_id ) ;
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 ;
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 ;
2017-04-12 15:34:07 +03:00
err = nla_parse_nested ( tb , TCA_GACT_MAX , nla , gact_policy , NULL ) ;
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
2017-08-30 09:31:59 +03:00
if ( ! tcf_idr_check ( tn , parm - > index , a , bind ) ) {
ret = tcf_idr_create ( tn , parm - > index , est , a ,
& act_gact_ops , bind , true ) ;
2014-02-12 05:07:31 +04:00
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
ret = ACT_P_CREATED ;
} else {
2013-12-23 17:02:11 +04:00
if ( bind ) /* dont override defaults */
return 0 ;
2017-08-30 09:31:59 +03:00
tcf_idr_release ( * a , bind ) ;
2013-12-23 17:02:11 +04:00
if ( ! ovr )
2005-04-17 02:20:36 +04:00
return - EEXIST ;
}
2016-07-26 02:09:41 +03:00
gact = to_gact ( * a ) ;
2006-08-22 10:54:55 +04:00
2015-07-06 15:18:08 +03:00
ASSERT_RTNL ( ) ;
2006-08-22 10:54:55 +04:00
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 ;
2015-07-06 15:18:05 +03:00
gact - > tcfg_pval = max_t ( u16 , 1 , p_parm - > pval ) ;
/* Make sure tcfg_pval is written before tcfg_ptype
* coupled with smp_rmb ( ) in gact_net_rand ( ) & gact_determ ( )
*/
smp_wmb ( ) ;
2006-08-22 10:54:55 +04:00
gact - > tcfg_ptype = p_parm - > ptype ;
2005-04-17 02:20:36 +04:00
}
# endif
if ( ret = = ACT_P_CREATED )
2017-08-30 09:31:59 +03:00
tcf_idr_insert ( tn , * a ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
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
{
2016-07-26 02:09:41 +03:00
struct tcf_gact * gact = to_gact ( a ) ;
2015-07-06 15:18:08 +03:00
int action = READ_ONCE ( gact - > tcf_action ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_GACT_PROB
2015-07-06 15:18:07 +03:00
{
u32 ptype = READ_ONCE ( gact - > tcfg_ptype ) ;
if ( ptype )
action = gact_rand [ ptype ] ( gact ) ;
}
2005-04-17 02:20:36 +04:00
# endif
2015-07-06 15:18:08 +03:00
bstats_cpu_update ( this_cpu_ptr ( gact - > common . cpu_bstats ) , skb ) ;
2005-04-17 02:20:36 +04:00
if ( action = = TC_ACT_SHOT )
2015-07-06 15:18:08 +03:00
qstats_drop_inc ( this_cpu_ptr ( gact - > common . cpu_qstats ) ) ;
tcf_lastuse_update ( & gact - > tcf_tm ) ;
2005-04-17 02:20:36 +04:00
return action ;
}
2016-05-13 15:55:36 +03:00
static void tcf_gact_stats_update ( struct tc_action * a , u64 bytes , u32 packets ,
u64 lastuse )
{
2016-07-26 02:09:41 +03:00
struct tcf_gact * gact = to_gact ( a ) ;
2016-05-13 15:55:36 +03:00
int action = READ_ONCE ( gact - > tcf_action ) ;
struct tcf_t * tm = & gact - > tcf_tm ;
2016-09-18 15:45:33 +03:00
_bstats_cpu_update ( this_cpu_ptr ( gact - > common . cpu_bstats ) , bytes ,
packets ) ;
2016-05-13 15:55:36 +03:00
if ( action = = TC_ACT_SHOT )
this_cpu_ptr ( gact - > common . cpu_qstats ) - > drops + = packets ;
2017-12-26 08:48:51 +03:00
tm - > lastuse = max_t ( u64 , tm - > lastuse , lastuse ) ;
2016-05-13 15:55:36 +03:00
}
2016-06-05 17:41:32 +03: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 ) ;
2016-07-26 02:09:41 +03:00
struct tcf_gact * gact = to_gact ( a ) ;
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
2016-06-06 13:32:55 +03:00
tcf_tm_dump ( & t , & gact - > tcf_tm ) ;
2016-04-26 11:06:18 +03:00
if ( nla_put_64bit ( skb , TCA_GACT_TM , sizeof ( t ) , & t , TCA_GACT_PAD ) )
2012-03-29 13:11:39 +04:00
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 ;
}
2016-02-23 02:57:53 +03:00
static int tcf_gact_walker ( struct net * net , struct sk_buff * skb ,
struct netlink_callback * cb , int type ,
2016-07-26 02:09:41 +03:00
const struct tc_action_ops * ops )
2016-02-23 02:57:53 +03:00
{
struct tc_action_net * tn = net_generic ( net , gact_net_id ) ;
2016-07-26 02:09:41 +03:00
return tcf_generic_walker ( tn , skb , cb , type , ops ) ;
2016-02-23 02:57:53 +03:00
}
2016-07-26 02:09:41 +03:00
static int tcf_gact_search ( struct net * net , struct tc_action * * a , u32 index )
2016-02-23 02:57:53 +03:00
{
struct tc_action_net * tn = net_generic ( net , gact_net_id ) ;
2017-08-30 09:31:59 +03:00
return tcf_idr_search ( tn , a , index ) ;
2016-02-23 02:57:53 +03:00
}
2005-04-17 02:20:36 +04:00
static struct tc_action_ops act_gact_ops = {
. kind = " gact " ,
. type = TCA_ACT_GACT ,
. owner = THIS_MODULE ,
. act = tcf_gact ,
2016-05-13 15:55:36 +03:00
. stats_update = tcf_gact_stats_update ,
2005-04-17 02:20:36 +04:00
. dump = tcf_gact_dump ,
. init = tcf_gact_init ,
2016-02-23 02:57:53 +03:00
. walk = tcf_gact_walker ,
. lookup = tcf_gact_search ,
2016-07-26 02:09:41 +03:00
. size = sizeof ( struct tcf_gact ) ,
2016-02-23 02:57:53 +03:00
} ;
static __net_init int gact_init_net ( struct net * net )
{
struct tc_action_net * tn = net_generic ( net , gact_net_id ) ;
2017-11-07 00:47:18 +03:00
return tc_action_net_init ( tn , & act_gact_ops ) ;
2016-02-23 02:57:53 +03:00
}
static void __net_exit gact_exit_net ( struct net * net )
{
struct tc_action_net * tn = net_generic ( net , gact_net_id ) ;
tc_action_net_exit ( tn ) ;
}
static struct pernet_operations gact_net_ops = {
. init = gact_init_net ,
. exit = gact_exit_net ,
. id = & gact_net_id ,
. size = sizeof ( struct tc_action_net ) ,
2005-04-17 02:20:36 +04:00
} ;
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
2016-02-23 02:57:53 +03:00
return tcf_register_action ( & act_gact_ops , & gact_net_ops ) ;
2005-04-17 02:20:36 +04:00
}
2006-08-22 10:54:55 +04:00
static void __exit gact_cleanup_module ( void )
2005-04-17 02:20:36 +04:00
{
2016-02-23 02:57:53 +03:00
tcf_unregister_action ( & act_gact_ops , & gact_net_ops ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( gact_init_module ) ;
module_exit ( gact_cleanup_module ) ;