File Index
Files and directories
Sign in
FILE

br_stp_timer.c

File preview with syntax highlighting.

linux-6.19.14/net/bridge/br_stp_timer.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *	Spanning tree protocol; timer-related code
  4 *	Linux ethernet bridge
  5 *
  6 *	Authors:
  7 *	Lennert Buytenhek		<buytenh@gnu.org>
  8 */
  9
 10#include <linux/kernel.h>
 11#include <linux/times.h>
 12
 13#include "br_private.h"
 14#include "br_private_stp.h"
 15
 16/* called under bridge lock */
 17static int br_is_designated_for_some_port(const struct net_bridge *br)
 18{
 19	struct net_bridge_port *p;
 20
 21	list_for_each_entry(p, &br->port_list, list) {
 22		if (p->state != BR_STATE_DISABLED &&
 23		    !memcmp(&p->designated_bridge, &br->bridge_id, 8))
 24			return 1;
 25	}
 26
 27	return 0;
 28}
 29
 30static void br_hello_timer_expired(struct timer_list *t)
 31{
 32	struct net_bridge *br = timer_container_of(br, t, hello_timer);
 33
 34	br_debug(br, "hello timer expired\n");
 35	spin_lock(&br->lock);
 36	if (br->dev->flags & IFF_UP) {
 37		br_config_bpdu_generation(br);
 38
 39		if (br->stp_enabled == BR_KERNEL_STP)
 40			mod_timer(&br->hello_timer,
 41				  round_jiffies(jiffies + br->hello_time));
 42	}
 43	spin_unlock(&br->lock);
 44}
 45
 46static void br_message_age_timer_expired(struct timer_list *t)
 47{
 48	struct net_bridge_port *p = timer_container_of(p, t,
 49						       message_age_timer);
 50	struct net_bridge *br = p->br;
 51	const bridge_id *id = &p->designated_bridge;
 52	int was_root;
 53
 54	if (p->state == BR_STATE_DISABLED)
 55		return;
 56
 57	br_info(br, "port %u(%s) neighbor %.2x%.2x.%pM lost\n",
 58		(unsigned int) p->port_no, p->dev->name,
 59		id->prio[0], id->prio[1], &id->addr);
 60
 61	/*
 62	 * According to the spec, the message age timer cannot be
 63	 * running when we are the root bridge. So..  this was_root
 64	 * check is redundant. I'm leaving it in for now, though.
 65	 */
 66	spin_lock(&br->lock);
 67	if (p->state == BR_STATE_DISABLED)
 68		goto unlock;
 69	was_root = br_is_root_bridge(br);
 70
 71	br_become_designated_port(p);
 72	br_configuration_update(br);
 73	br_port_state_selection(br);
 74	if (br_is_root_bridge(br) && !was_root)
 75		br_become_root_bridge(br);
 76 unlock:
 77	spin_unlock(&br->lock);
 78}
 79
 80static void br_forward_delay_timer_expired(struct timer_list *t)
 81{
 82	struct net_bridge_port *p = timer_container_of(p, t,
 83						       forward_delay_timer);
 84	struct net_bridge *br = p->br;
 85
 86	br_debug(br, "port %u(%s) forward delay timer\n",
 87		 (unsigned int) p->port_no, p->dev->name);
 88	spin_lock(&br->lock);
 89	if (p->state == BR_STATE_LISTENING) {
 90		br_set_state(p, BR_STATE_LEARNING);
 91		mod_timer(&p->forward_delay_timer,
 92			  jiffies + br->forward_delay);
 93	} else if (p->state == BR_STATE_LEARNING) {
 94		br_set_state(p, BR_STATE_FORWARDING);
 95		if (br_is_designated_for_some_port(br))
 96			br_topology_change_detection(br);
 97		netif_carrier_on(br->dev);
 98	}
 99	rcu_read_lock();
100	br_ifinfo_notify(RTM_NEWLINK, NULL, p);
101	rcu_read_unlock();
102	spin_unlock(&br->lock);
103}
104
105static void br_tcn_timer_expired(struct timer_list *t)
106{
107	struct net_bridge *br = timer_container_of(br, t, tcn_timer);
108
109	br_debug(br, "tcn timer expired\n");
110	spin_lock(&br->lock);
111	if (!br_is_root_bridge(br) && (br->dev->flags & IFF_UP)) {
112		br_transmit_tcn(br);
113
114		mod_timer(&br->tcn_timer, jiffies + br->bridge_hello_time);
115	}
116	spin_unlock(&br->lock);
117}
118
119static void br_topology_change_timer_expired(struct timer_list *t)
120{
121	struct net_bridge *br = timer_container_of(br, t,
122						   topology_change_timer);
123
124	br_debug(br, "topo change timer expired\n");
125	spin_lock(&br->lock);
126	br->topology_change_detected = 0;
127	__br_set_topology_change(br, 0);
128	spin_unlock(&br->lock);
129}
130
131static void br_hold_timer_expired(struct timer_list *t)
132{
133	struct net_bridge_port *p = timer_container_of(p, t, hold_timer);
134
135	br_debug(p->br, "port %u(%s) hold timer expired\n",
136		 (unsigned int) p->port_no, p->dev->name);
137
138	spin_lock(&p->br->lock);
139	if (p->config_pending)
140		br_transmit_config(p);
141	spin_unlock(&p->br->lock);
142}
143
144void br_stp_timer_init(struct net_bridge *br)
145{
146	timer_setup(&br->hello_timer, br_hello_timer_expired, 0);
147	timer_setup(&br->tcn_timer, br_tcn_timer_expired, 0);
148	timer_setup(&br->topology_change_timer,
149		    br_topology_change_timer_expired, 0);
150}
151
152void br_stp_port_timer_init(struct net_bridge_port *p)
153{
154	timer_setup(&p->message_age_timer, br_message_age_timer_expired, 0);
155	timer_setup(&p->forward_delay_timer, br_forward_delay_timer_expired, 0);
156	timer_setup(&p->hold_timer, br_hold_timer_expired, 0);
157}
158
159/* Report ticks left (in USER_HZ) used for API */
160unsigned long br_timer_value(const struct timer_list *timer)
161{
162	return timer_pending(timer)
163		? jiffies_delta_to_clock_t(timer->expires - jiffies) : 0;
164}
~/ Read-only file preview.