2005-04-17 02:20:36 +04:00
/*
* Spanning tree protocol ; timer - related code
* Linux ethernet bridge
*
* Authors :
* Lennert Buytenhek < buytenh @ gnu . org >
*
* 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 .
*/
# include <linux/kernel.h>
# include <linux/times.h>
# include "br_private.h"
# include "br_private_stp.h"
/* called under bridge lock */
static int br_is_designated_for_some_port ( const struct net_bridge * br )
{
struct net_bridge_port * p ;
list_for_each_entry ( p , & br - > port_list , list ) {
if ( p - > state ! = BR_STATE_DISABLED & &
2007-02-09 17:24:35 +03:00
! memcmp ( & p - > designated_bridge , & br - > bridge_id , 8 ) )
2005-04-17 02:20:36 +04:00
return 1 ;
}
return 0 ;
}
static void br_hello_timer_expired ( unsigned long arg )
{
struct net_bridge * br = ( struct net_bridge * ) arg ;
2007-02-09 17:24:35 +03:00
2005-04-17 02:20:36 +04:00
pr_debug ( " %s: hello timer expired \n " , br - > dev - > name ) ;
2006-03-21 09:56:25 +03:00
spin_lock ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
if ( br - > dev - > flags & IFF_UP ) {
br_config_bpdu_generation ( br ) ;
2007-05-31 12:21:39 +04:00
mod_timer ( & br - > hello_timer , round_jiffies ( jiffies + br - > hello_time ) ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-21 09:56:25 +03:00
spin_unlock ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
}
static void br_message_age_timer_expired ( unsigned long arg )
{
struct net_bridge_port * p = ( struct net_bridge_port * ) arg ;
struct net_bridge * br = p - > br ;
const bridge_id * id = & p - > designated_bridge ;
int was_root ;
if ( p - > state = = BR_STATE_DISABLED )
return ;
2007-02-09 17:24:35 +03:00
2005-04-17 02:20:36 +04:00
pr_info ( " %s: neighbor %.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x lost on port %d(%s) \n " ,
2007-02-09 17:24:35 +03:00
br - > dev - > name ,
id - > prio [ 0 ] , id - > prio [ 1 ] ,
id - > addr [ 0 ] , id - > addr [ 1 ] , id - > addr [ 2 ] ,
2005-04-17 02:20:36 +04:00
id - > addr [ 3 ] , id - > addr [ 4 ] , id - > addr [ 5 ] ,
p - > port_no , p - > dev - > name ) ;
/*
* According to the spec , the message age timer cannot be
* running when we are the root bridge . So . . this was_root
* check is redundant . I ' m leaving it in for now , though .
*/
2006-03-21 09:56:25 +03:00
spin_lock ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
if ( p - > state = = BR_STATE_DISABLED )
goto unlock ;
was_root = br_is_root_bridge ( br ) ;
br_become_designated_port ( p ) ;
br_configuration_update ( br ) ;
br_port_state_selection ( br ) ;
if ( br_is_root_bridge ( br ) & & ! was_root )
br_become_root_bridge ( br ) ;
unlock :
2006-03-21 09:56:25 +03:00
spin_unlock ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
}
static void br_forward_delay_timer_expired ( unsigned long arg )
{
struct net_bridge_port * p = ( struct net_bridge_port * ) arg ;
struct net_bridge * br = p - > br ;
pr_debug ( " %s: %d(%s) forward delay timer \n " ,
br - > dev - > name , p - > port_no , p - > dev - > name ) ;
2006-03-21 09:56:25 +03:00
spin_lock ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
if ( p - > state = = BR_STATE_LISTENING ) {
p - > state = BR_STATE_LEARNING ;
mod_timer ( & p - > forward_delay_timer ,
jiffies + br - > forward_delay ) ;
} else if ( p - > state = = BR_STATE_LEARNING ) {
p - > state = BR_STATE_FORWARDING ;
if ( br_is_designated_for_some_port ( br ) )
br_topology_change_detection ( br ) ;
}
br_log_state ( p ) ;
2006-03-21 09:56:25 +03:00
spin_unlock ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
}
static void br_tcn_timer_expired ( unsigned long arg )
{
struct net_bridge * br = ( struct net_bridge * ) arg ;
pr_debug ( " %s: tcn timer expired \n " , br - > dev - > name ) ;
2006-03-21 09:56:25 +03:00
spin_lock ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
if ( br - > dev - > flags & IFF_UP ) {
br_transmit_tcn ( br ) ;
2007-02-09 17:24:35 +03:00
2005-04-17 02:20:36 +04:00
mod_timer ( & br - > tcn_timer , jiffies + br - > bridge_hello_time ) ;
}
2006-03-21 09:56:25 +03:00
spin_unlock ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
}
static void br_topology_change_timer_expired ( unsigned long arg )
{
struct net_bridge * br = ( struct net_bridge * ) arg ;
pr_debug ( " %s: topo change timer expired \n " , br - > dev - > name ) ;
2006-03-21 09:56:25 +03:00
spin_lock ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
br - > topology_change_detected = 0 ;
br - > topology_change = 0 ;
2006-03-21 09:56:25 +03:00
spin_unlock ( & br - > lock ) ;
2005-04-17 02:20:36 +04:00
}
static void br_hold_timer_expired ( unsigned long arg )
{
struct net_bridge_port * p = ( struct net_bridge_port * ) arg ;
2007-02-09 17:24:35 +03:00
pr_debug ( " %s: %d(%s) hold timer expired \n " ,
2005-04-17 02:20:36 +04:00
p - > br - > dev - > name , p - > port_no , p - > dev - > name ) ;
2006-03-21 09:56:25 +03:00
spin_lock ( & p - > br - > lock ) ;
2005-04-17 02:20:36 +04:00
if ( p - > config_pending )
br_transmit_config ( p ) ;
2006-03-21 09:56:25 +03:00
spin_unlock ( & p - > br - > lock ) ;
2005-04-17 02:20:36 +04:00
}
void br_stp_timer_init ( struct net_bridge * br )
{
2006-03-21 09:56:38 +03:00
setup_timer ( & br - > hello_timer , br_hello_timer_expired ,
2005-04-17 02:20:36 +04:00
( unsigned long ) br ) ;
2006-03-21 09:56:38 +03:00
setup_timer ( & br - > tcn_timer , br_tcn_timer_expired ,
2005-04-17 02:20:36 +04:00
( unsigned long ) br ) ;
2006-03-21 09:56:38 +03:00
setup_timer ( & br - > topology_change_timer ,
2005-04-17 02:20:36 +04:00
br_topology_change_timer_expired ,
( unsigned long ) br ) ;
2006-03-21 09:56:38 +03:00
setup_timer ( & br - > gc_timer , br_fdb_cleanup , ( unsigned long ) br ) ;
2005-04-17 02:20:36 +04:00
}
void br_stp_port_timer_init ( struct net_bridge_port * p )
{
2006-03-21 09:56:38 +03:00
setup_timer ( & p - > message_age_timer , br_message_age_timer_expired ,
2005-04-17 02:20:36 +04:00
( unsigned long ) p ) ;
2006-03-21 09:56:38 +03:00
setup_timer ( & p - > forward_delay_timer , br_forward_delay_timer_expired ,
2005-04-17 02:20:36 +04:00
( unsigned long ) p ) ;
2007-02-09 17:24:35 +03:00
2006-03-21 09:56:38 +03:00
setup_timer ( & p - > hold_timer , br_hold_timer_expired ,
2005-04-17 02:20:36 +04:00
( unsigned long ) p ) ;
2007-02-09 17:24:35 +03:00
}
2005-04-17 02:20:36 +04:00
/* Report ticks left (in USER_HZ) used for API */
unsigned long br_timer_value ( const struct timer_list * timer )
{
return timer_pending ( timer )
? jiffies_to_clock_t ( timer - > expires - jiffies ) : 0 ;
}