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