11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Spanning tree protocol; timer-related code 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux ethernet bridge 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Authors: 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Lennert Buytenhek <buytenh@gnu.org> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/times.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "br_private.h" 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "br_private_stp.h" 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* called under bridge lock */ 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int br_is_designated_for_some_port(const struct net_bridge *br) 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_bridge_port *p; 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(p, &br->port_list, list) { 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p->state != BR_STATE_DISABLED && 279d6f229fc45b6ac268020c0c8eff29e94bb34381YOSHIFUJI Hideaki !memcmp(&p->designated_bridge, &br->bridge_id, 8)) 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void br_hello_timer_expired(unsigned long arg) 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_bridge *br = (struct net_bridge *)arg; 379d6f229fc45b6ac268020c0c8eff29e94bb34381YOSHIFUJI Hideaki 3828a16c97963d3bc36a2c192859f6d8025ef2967astephen hemminger br_debug(br, "hello timer expired\n"); 39e3efe08e9a2c24232711dc573bf2decd2d93e335Stephen Hemminger spin_lock(&br->lock); 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (br->dev->flags & IFF_UP) { 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br_config_bpdu_generation(br); 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 439a834b87c5544c347fd788cd9d4eb276402ab54aStephen Hemminger mod_timer(&br->hello_timer, round_jiffies(jiffies + br->hello_time)); 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45e3efe08e9a2c24232711dc573bf2decd2d93e335Stephen Hemminger spin_unlock(&br->lock); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void br_message_age_timer_expired(unsigned long arg) 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_bridge_port *p = (struct net_bridge_port *) arg; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_bridge *br = p->br; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const bridge_id *id = &p->designated_bridge; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int was_root; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p->state == BR_STATE_DISABLED) 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5828a16c97963d3bc36a2c192859f6d8025ef2967astephen hemminger br_info(br, "port %u(%s) neighbor %.2x%.2x.%pM lost\n", 5995c961747284a6b83a5e2d81240e214b0fa3464dEric Dumazet (unsigned int) p->port_no, p->dev->name, 6028a16c97963d3bc36a2c192859f6d8025ef2967astephen hemminger id->prio[0], id->prio[1], &id->addr); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * According to the spec, the message age timer cannot be 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * running when we are the root bridge. So.. this was_root 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * check is redundant. I'm leaving it in for now, though. 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 67e3efe08e9a2c24232711dc573bf2decd2d93e335Stephen Hemminger spin_lock(&br->lock); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p->state == BR_STATE_DISABLED) 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto unlock; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds was_root = br_is_root_bridge(br); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br_become_designated_port(p); 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br_configuration_update(br); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br_port_state_selection(br); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (br_is_root_bridge(br) && !was_root) 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br_become_root_bridge(br); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock: 78e3efe08e9a2c24232711dc573bf2decd2d93e335Stephen Hemminger spin_unlock(&br->lock); 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void br_forward_delay_timer_expired(unsigned long arg) 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_bridge_port *p = (struct net_bridge_port *) arg; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_bridge *br = p->br; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8628a16c97963d3bc36a2c192859f6d8025ef2967astephen hemminger br_debug(br, "port %u(%s) forward delay timer\n", 8795c961747284a6b83a5e2d81240e214b0fa3464dEric Dumazet (unsigned int) p->port_no, p->dev->name); 88e3efe08e9a2c24232711dc573bf2decd2d93e335Stephen Hemminger spin_lock(&br->lock); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p->state == BR_STATE_LISTENING) { 90775dd692bd34f9201ed2aa775a0edcba4f973f3eFlorian Fainelli br_set_state(p, BR_STATE_LEARNING); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer(&p->forward_delay_timer, 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds jiffies + br->forward_delay); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (p->state == BR_STATE_LEARNING) { 94775dd692bd34f9201ed2aa775a0edcba4f973f3eFlorian Fainelli br_set_state(p, BR_STATE_FORWARDING); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (br_is_designated_for_some_port(br)) 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br_topology_change_detection(br); 971faa4356a3bd89ea11fb92752d897cff3a20ec0estephen hemminger netif_carrier_on(br->dev); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br_log_state(p); 1004ecb961c8b474ebef5aff55f715c7875e69dd57bstephen hemminger br_ifinfo_notify(RTM_NEWLINK, p); 101e3efe08e9a2c24232711dc573bf2decd2d93e335Stephen Hemminger spin_unlock(&br->lock); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void br_tcn_timer_expired(unsigned long arg) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_bridge *br = (struct net_bridge *) arg; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10828a16c97963d3bc36a2c192859f6d8025ef2967astephen hemminger br_debug(br, "tcn timer expired\n"); 109e3efe08e9a2c24232711dc573bf2decd2d93e335Stephen Hemminger spin_lock(&br->lock); 11083401eb4990ff6af55aeed8f49681558544192e6stephen hemminger if (!br_is_root_bridge(br) && (br->dev->flags & IFF_UP)) { 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br_transmit_tcn(br); 1129d6f229fc45b6ac268020c0c8eff29e94bb34381YOSHIFUJI Hideaki 11331a5b837c2e0d282f36d06a2b96f16d97464fd68tanxiaojun mod_timer(&br->tcn_timer, jiffies + br->bridge_hello_time); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 115e3efe08e9a2c24232711dc573bf2decd2d93e335Stephen Hemminger spin_unlock(&br->lock); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void br_topology_change_timer_expired(unsigned long arg) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_bridge *br = (struct net_bridge *) arg; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12228a16c97963d3bc36a2c192859f6d8025ef2967astephen hemminger br_debug(br, "topo change timer expired\n"); 123e3efe08e9a2c24232711dc573bf2decd2d93e335Stephen Hemminger spin_lock(&br->lock); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br->topology_change_detected = 0; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br->topology_change = 0; 126e3efe08e9a2c24232711dc573bf2decd2d93e335Stephen Hemminger spin_unlock(&br->lock); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void br_hold_timer_expired(unsigned long arg) 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_bridge_port *p = (struct net_bridge_port *) arg; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13328a16c97963d3bc36a2c192859f6d8025ef2967astephen hemminger br_debug(p->br, "port %u(%s) hold timer expired\n", 13495c961747284a6b83a5e2d81240e214b0fa3464dEric Dumazet (unsigned int) p->port_no, p->dev->name); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 136e3efe08e9a2c24232711dc573bf2decd2d93e335Stephen Hemminger spin_lock(&p->br->lock); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p->config_pending) 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br_transmit_config(p); 139e3efe08e9a2c24232711dc573bf2decd2d93e335Stephen Hemminger spin_unlock(&p->br->lock); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid br_stp_timer_init(struct net_bridge *br) 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 144a95fcacdc33fa12836c306deb085ef3e68bca15aStephen Hemminger setup_timer(&br->hello_timer, br_hello_timer_expired, 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long) br); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 147a95fcacdc33fa12836c306deb085ef3e68bca15aStephen Hemminger setup_timer(&br->tcn_timer, br_tcn_timer_expired, 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long) br); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 150a95fcacdc33fa12836c306deb085ef3e68bca15aStephen Hemminger setup_timer(&br->topology_change_timer, 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br_topology_change_timer_expired, 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long) br); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 154a95fcacdc33fa12836c306deb085ef3e68bca15aStephen Hemminger setup_timer(&br->gc_timer, br_fdb_cleanup, (unsigned long) br); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid br_stp_port_timer_init(struct net_bridge_port *p) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 159a95fcacdc33fa12836c306deb085ef3e68bca15aStephen Hemminger setup_timer(&p->message_age_timer, br_message_age_timer_expired, 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long) p); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 162a95fcacdc33fa12836c306deb085ef3e68bca15aStephen Hemminger setup_timer(&p->forward_delay_timer, br_forward_delay_timer_expired, 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long) p); 1649d6f229fc45b6ac268020c0c8eff29e94bb34381YOSHIFUJI Hideaki 165a95fcacdc33fa12836c306deb085ef3e68bca15aStephen Hemminger setup_timer(&p->hold_timer, br_hold_timer_expired, 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long) p); 1679d6f229fc45b6ac268020c0c8eff29e94bb34381YOSHIFUJI Hideaki} 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Report ticks left (in USER_HZ) used for API */ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned long br_timer_value(const struct timer_list *timer) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return timer_pending(timer) 173a399a8053164ec8bcb06fed52be9941a26ecde11Eric Dumazet ? jiffies_delta_to_clock_t(timer->expires - jiffies) : 0; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 175