2013-10-18 17:43:34 +02:00
/*
* drivers / net / bond / bond_options . c - bonding options
* Copyright ( c ) 2013 Jiri Pirko < jiri @ resnulli . us >
2013-12-12 14:09:55 -08:00
* Copyright ( c ) 2013 Scott Feldman < sfeldma @ cumulusnetworks . com >
2013-10-18 17:43:34 +02: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 .
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/errno.h>
# include <linux/if.h>
2013-10-18 17:43:35 +02:00
# include <linux/netdevice.h>
# include <linux/rwlock.h>
# include <linux/rcupdate.h>
2013-10-18 17:43:34 +02:00
# include "bonding.h"
static bool bond_mode_is_valid ( int mode )
{
int i ;
for ( i = 0 ; bond_mode_tbl [ i ] . modename ; i + + ) ;
return mode > = 0 & & mode < i ;
}
int bond_option_mode_set ( struct bonding * bond , int mode )
{
if ( ! bond_mode_is_valid ( mode ) ) {
pr_err ( " invalid mode value %d. \n " , mode ) ;
return - EINVAL ;
}
if ( bond - > dev - > flags & IFF_UP ) {
pr_err ( " %s: unable to update mode because interface is up. \n " ,
bond - > dev - > name ) ;
return - EPERM ;
}
if ( bond_has_slaves ( bond ) ) {
pr_err ( " %s: unable to update mode because bond has slaves. \n " ,
bond - > dev - > name ) ;
return - EPERM ;
}
bonding: disable arp and enable mii monitoring when bond change to no uses arp mode
Because the ARP monitoring is not support for 802.3ad, but I still
could change the mode to 802.3ad from ab mode while ARP monitoring
is running, it is incorrect.
So add a check for 802.3ad in bonding_store_mode to fix the problem,
and make a new macro BOND_NO_USES_ARP() to simplify the code.
v2: according to the Dan Williams's suggestion, bond mode is the most
important bond option, it should override any of the other sub-options.
So when the mode is changed, the conficting values should be cleared
or reset, otherwise the user has to duplicate more operations to modify
the logic. I disable the arp and enable mii monitoring when the bond mode
is changed to AB, TB and 8023AD if the arp interval is true.
v3: according to the Nik's suggestion, the default value of miimon should need
a name, there is several place to use it, and the bond_store_arp_interval()
could use micro BOND_NO_USES_ARP to make the code more simpify.
Suggested-by: Dan Williams <dcbw@redhat.com>
Suggested-by: Nikolay Aleksandrov <nikolay@redhat.com>
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
Reviewed-by: Nikolay Aleksandrov <nikolay@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-11-22 22:28:43 +08:00
if ( BOND_NO_USES_ARP ( mode ) & & bond - > params . arp_interval ) {
pr_info ( " %s: %s mode is incompatible with arp monitoring, start mii monitoring \n " ,
bond - > dev - > name , bond_mode_tbl [ mode ] . modename ) ;
/* disable arp monitoring */
bond - > params . arp_interval = 0 ;
/* set miimon to default value */
bond - > params . miimon = BOND_DEFAULT_MIIMON ;
pr_info ( " %s: Setting MII monitoring interval to %d. \n " ,
bond - > dev - > name , bond - > params . miimon ) ;
2013-10-18 17:43:34 +02:00
}
/* don't cache arp_validate between modes */
bond - > params . arp_validate = BOND_ARP_VALIDATE_NONE ;
bond - > params . mode = mode ;
return 0 ;
}
2013-10-18 17:43:35 +02:00
2013-10-18 17:43:37 +02:00
static struct net_device * __bond_option_active_slave_get ( struct bonding * bond ,
struct slave * slave )
{
return USES_PRIMARY ( bond - > params . mode ) & & slave ? slave - > dev : NULL ;
}
struct net_device * bond_option_active_slave_get_rcu ( struct bonding * bond )
{
struct slave * slave = rcu_dereference ( bond - > curr_active_slave ) ;
return __bond_option_active_slave_get ( bond , slave ) ;
}
struct net_device * bond_option_active_slave_get ( struct bonding * bond )
{
return __bond_option_active_slave_get ( bond , bond - > curr_active_slave ) ;
}
2013-10-18 17:43:35 +02:00
int bond_option_active_slave_set ( struct bonding * bond ,
struct net_device * slave_dev )
{
int ret = 0 ;
if ( slave_dev ) {
if ( ! netif_is_bond_slave ( slave_dev ) ) {
pr_err ( " Device %s is not bonding slave. \n " ,
slave_dev - > name ) ;
return - EINVAL ;
}
if ( bond - > dev ! = netdev_master_upper_dev_get ( slave_dev ) ) {
pr_err ( " %s: Device %s is not our slave. \n " ,
bond - > dev - > name , slave_dev - > name ) ;
return - EINVAL ;
}
}
if ( ! USES_PRIMARY ( bond - > params . mode ) ) {
pr_err ( " %s: Unable to change active slave; %s is in mode %d \n " ,
bond - > dev - > name , bond - > dev - > name , bond - > params . mode ) ;
return - EINVAL ;
}
block_netpoll_tx ( ) ;
read_lock ( & bond - > lock ) ;
write_lock_bh ( & bond - > curr_slave_lock ) ;
/* check to see if we are clearing active */
if ( ! slave_dev ) {
pr_info ( " %s: Clearing current active slave. \n " ,
bond - > dev - > name ) ;
rcu_assign_pointer ( bond - > curr_active_slave , NULL ) ;
bond_select_active_slave ( bond ) ;
} else {
struct slave * old_active = bond - > curr_active_slave ;
struct slave * new_active = bond_slave_get_rtnl ( slave_dev ) ;
BUG_ON ( ! new_active ) ;
if ( new_active = = old_active ) {
/* do nothing */
pr_info ( " %s: %s is already the current active slave. \n " ,
bond - > dev - > name , new_active - > dev - > name ) ;
} else {
if ( old_active & & ( new_active - > link = = BOND_LINK_UP ) & &
IS_UP ( new_active - > dev ) ) {
pr_info ( " %s: Setting %s as active slave. \n " ,
bond - > dev - > name , new_active - > dev - > name ) ;
bond_change_active_slave ( bond , new_active ) ;
} else {
pr_err ( " %s: Could not set %s as active slave; either %s is down or the link is down. \n " ,
bond - > dev - > name , new_active - > dev - > name ,
new_active - > dev - > name ) ;
ret = - EINVAL ;
}
}
}
write_unlock_bh ( & bond - > curr_slave_lock ) ;
read_unlock ( & bond - > lock ) ;
unblock_netpoll_tx ( ) ;
return ret ;
}
2013-12-12 14:09:55 -08:00
int bond_option_miimon_set ( struct bonding * bond , int miimon )
{
if ( miimon < 0 ) {
pr_err ( " %s: Invalid miimon value %d not in range %d-%d; rejected. \n " ,
bond - > dev - > name , miimon , 0 , INT_MAX ) ;
return - EINVAL ;
}
pr_info ( " %s: Setting MII monitoring interval to %d. \n " ,
bond - > dev - > name , miimon ) ;
bond - > params . miimon = miimon ;
if ( bond - > params . updelay )
pr_info ( " %s: Note: Updating updelay (to %d) since it is a multiple of the miimon value. \n " ,
bond - > dev - > name ,
bond - > params . updelay * bond - > params . miimon ) ;
if ( bond - > params . downdelay )
pr_info ( " %s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value. \n " ,
bond - > dev - > name ,
bond - > params . downdelay * bond - > params . miimon ) ;
if ( miimon & & bond - > params . arp_interval ) {
pr_info ( " %s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring... \n " ,
bond - > dev - > name ) ;
bond - > params . arp_interval = 0 ;
if ( bond - > params . arp_validate )
bond - > params . arp_validate = BOND_ARP_VALIDATE_NONE ;
}
if ( bond - > dev - > flags & IFF_UP ) {
/* If the interface is up, we may need to fire off
* the MII timer . If the interface is down , the
* timer will get fired off when the open function
* is called .
*/
if ( ! miimon ) {
cancel_delayed_work_sync ( & bond - > mii_work ) ;
} else {
cancel_delayed_work_sync ( & bond - > arp_work ) ;
queue_delayed_work ( bond - > wq , & bond - > mii_work , 0 ) ;
}
}
return 0 ;
}