2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-11-12 02:16:48 +04:00
/*
2012-06-19 09:54:09 +04:00
* drivers / net / team / team_mode_activebackup . c - Active - backup mode for team
2011-11-12 02:16:48 +04:00
* Copyright ( c ) 2011 Jiri Pirko < jpirko @ redhat . com >
*/
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/netdevice.h>
# include <net/rtnetlink.h>
# include <linux/if_team.h>
struct ab_priv {
struct team_port __rcu * active_port ;
2013-02-01 12:17:26 +04:00
struct team_option_inst_info * ap_opt_inst_info ;
2011-11-12 02:16:48 +04:00
} ;
static struct ab_priv * ab_priv ( struct team * team )
{
return ( struct ab_priv * ) & team - > mode_priv ;
}
static rx_handler_result_t ab_receive ( struct team * team , struct team_port * port ,
struct sk_buff * skb ) {
struct team_port * active_port ;
active_port = rcu_dereference ( ab_priv ( team ) - > active_port ) ;
if ( active_port ! = port )
return RX_HANDLER_EXACT ;
return RX_HANDLER_ANOTHER ;
}
static bool ab_transmit ( struct team * team , struct sk_buff * skb )
{
struct team_port * active_port ;
2012-06-19 09:54:21 +04:00
active_port = rcu_dereference_bh ( ab_priv ( team ) - > active_port ) ;
2011-11-12 02:16:48 +04:00
if ( unlikely ( ! active_port ) )
goto drop ;
2012-07-17 09:22:36 +04:00
if ( team_dev_queue_xmit ( team , active_port , skb ) )
2011-11-12 02:16:48 +04:00
return false ;
return true ;
drop :
dev_kfree_skb_any ( skb ) ;
return false ;
}
static void ab_port_leave ( struct team * team , struct team_port * port )
{
2013-02-01 12:17:26 +04:00
if ( ab_priv ( team ) - > active_port = = port ) {
2011-11-23 11:09:32 +04:00
RCU_INIT_POINTER ( ab_priv ( team ) - > active_port , NULL ) ;
2013-02-01 12:17:26 +04:00
team_option_inst_set_change ( ab_priv ( team ) - > ap_opt_inst_info ) ;
}
}
static int ab_active_port_init ( struct team * team ,
struct team_option_inst_info * info )
{
ab_priv ( team ) - > ap_opt_inst_info = info ;
return 0 ;
2011-11-12 02:16:48 +04:00
}
2012-04-10 09:15:42 +04:00
static int ab_active_port_get ( struct team * team , struct team_gsetter_ctx * ctx )
2011-11-12 02:16:48 +04:00
{
2012-06-20 12:39:39 +04:00
struct team_port * active_port ;
active_port = rcu_dereference_protected ( ab_priv ( team ) - > active_port ,
lockdep_is_held ( & team - > lock ) ) ;
if ( active_port )
ctx - > data . u32_val = active_port - > dev - > ifindex ;
2012-04-10 09:15:42 +04:00
else
ctx - > data . u32_val = 0 ;
2011-11-12 02:16:48 +04:00
return 0 ;
}
2012-04-10 09:15:42 +04:00
static int ab_active_port_set ( struct team * team , struct team_gsetter_ctx * ctx )
2011-11-12 02:16:48 +04:00
{
struct team_port * port ;
2012-04-10 09:15:45 +04:00
list_for_each_entry ( port , & team - > port_list , list ) {
2012-04-10 09:15:42 +04:00
if ( port - > dev - > ifindex = = ctx - > data . u32_val ) {
2011-11-12 02:16:48 +04:00
rcu_assign_pointer ( ab_priv ( team ) - > active_port , port ) ;
return 0 ;
}
}
return - ENOENT ;
}
2011-11-16 15:09:09 +04:00
static const struct team_option ab_options [ ] = {
2011-11-12 02:16:48 +04:00
{
. name = " activeport " ,
. type = TEAM_OPTION_TYPE_U32 ,
2013-02-01 12:17:26 +04:00
. init = ab_active_port_init ,
2011-11-12 02:16:48 +04:00
. getter = ab_active_port_get ,
. setter = ab_active_port_set ,
} ,
} ;
2012-04-10 09:15:46 +04:00
static int ab_init ( struct team * team )
2011-11-12 02:16:48 +04:00
{
2011-11-16 15:09:09 +04:00
return team_options_register ( team , ab_options , ARRAY_SIZE ( ab_options ) ) ;
2011-11-12 02:16:48 +04:00
}
2012-04-10 09:15:46 +04:00
static void ab_exit ( struct team * team )
2011-11-12 02:16:48 +04:00
{
team_options_unregister ( team , ab_options , ARRAY_SIZE ( ab_options ) ) ;
}
static const struct team_mode_ops ab_mode_ops = {
. init = ab_init ,
. exit = ab_exit ,
. receive = ab_receive ,
. transmit = ab_transmit ,
. port_leave = ab_port_leave ,
} ;
2012-06-19 09:54:03 +04:00
static const struct team_mode ab_mode = {
2011-11-12 02:16:48 +04:00
. kind = " activebackup " ,
. owner = THIS_MODULE ,
. priv_size = sizeof ( struct ab_priv ) ,
. ops = & ab_mode_ops ,
2015-12-03 14:12:13 +03:00
. lag_tx_type = NETDEV_LAG_TX_TYPE_ACTIVEBACKUP ,
2011-11-12 02:16:48 +04:00
} ;
static int __init ab_init_module ( void )
{
return team_mode_register ( & ab_mode ) ;
}
static void __exit ab_cleanup_module ( void )
{
team_mode_unregister ( & ab_mode ) ;
}
module_init ( ab_init_module ) ;
module_exit ( ab_cleanup_module ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Jiri Pirko <jpirko@redhat.com> " ) ;
MODULE_DESCRIPTION ( " Active-backup mode for team " ) ;
2017-06-01 10:37:02 +03:00
MODULE_ALIAS_TEAM_MODE ( " activebackup " ) ;