mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-03 03:16:43 +07:00
Merge branch 'bridge-fast-ageing-on-topology-change'
Vivien Didelot says: ==================== net: bridge: fast ageing on topology change 802.1D [1] specifies that the bridges in a network must use a short value to age out dynamic entries in the Filtering Database for a period, once a topology change has been communicated by the root bridge. This patchset fixes this for the in-kernel STP implementation. Once the topology change flag is set in a net_bridge instance, the ageing time value is shorten to twice the forward delay used by the topology. When the topology change flag is cleared, the ageing time configured for the bridge is restored. To accomplish that, a new bridge_ageing_time member is added to the net_bridge structure, to store the user configured bridge ageing time. Two helpers are added to offload the ageing time and set the topology change flag in the net_bridge instance. Then the required logic is added in the topology change helper if in-kernel STP is used. This has been tested on the following topology: +--------------+ | root bridge | | 1 2 3 4 | +--+--+--+--+--+ | | | | +--------+ | | | +------| laptop | | | | +--------+ +--+--+--+-----+ | 1 2 3 | | slave bridge | +--------------+ When unplugging/replugging the laptop, the slave bridge (under test) gets the topology change flag sent by the root bridge, and fast ageing is triggered on the bridges. Once the topology change timer of the root bridge expires, the topology change flag is cleared and the configured ageing time is restored on the bridges. A similar test has been done between two bridges under test. When changing the forward delay of the root bridge with: # echo 3000 > /sys/class/net/br0/bridge/forward_delay the ageing time correctly changes on both bridges from 300s to 60s while the TOPOLOGY_CHANGE flag is present. [1] "8.3.5 Notifying topology changes", http://profesores.elo.utfsm.cl/~agv/elo309/doc/802.1D-1998.pdf No change since RFC: https://lkml.org/lkml/2016/10/19/828 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c280b48266
@ -409,7 +409,7 @@ void br_dev_setup(struct net_device *dev)
|
||||
br->bridge_max_age = br->max_age = 20 * HZ;
|
||||
br->bridge_hello_time = br->hello_time = 2 * HZ;
|
||||
br->bridge_forward_delay = br->forward_delay = 15 * HZ;
|
||||
br->ageing_time = BR_DEFAULT_AGEING_TIME;
|
||||
br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME;
|
||||
dev->max_mtu = ETH_MAX_MTU;
|
||||
|
||||
br_netfilter_rtable_init(br);
|
||||
|
@ -300,10 +300,11 @@ struct net_bridge
|
||||
unsigned long max_age;
|
||||
unsigned long hello_time;
|
||||
unsigned long forward_delay;
|
||||
unsigned long bridge_max_age;
|
||||
unsigned long ageing_time;
|
||||
unsigned long bridge_max_age;
|
||||
unsigned long bridge_hello_time;
|
||||
unsigned long bridge_forward_delay;
|
||||
unsigned long bridge_ageing_time;
|
||||
|
||||
u8 group_addr[ETH_ALEN];
|
||||
bool group_addr_set;
|
||||
@ -999,6 +1000,7 @@ void __br_set_forward_delay(struct net_bridge *br, unsigned long t);
|
||||
int br_set_forward_delay(struct net_bridge *br, unsigned long x);
|
||||
int br_set_hello_time(struct net_bridge *br, unsigned long x);
|
||||
int br_set_max_age(struct net_bridge *br, unsigned long x);
|
||||
int __set_ageing_time(struct net_device *dev, unsigned long t);
|
||||
int br_set_ageing_time(struct net_bridge *br, clock_t ageing_time);
|
||||
|
||||
|
||||
|
@ -61,6 +61,7 @@ void br_received_tcn_bpdu(struct net_bridge_port *p);
|
||||
void br_transmit_config(struct net_bridge_port *p);
|
||||
void br_transmit_tcn(struct net_bridge *br);
|
||||
void br_topology_change_detection(struct net_bridge *br);
|
||||
void __br_set_topology_change(struct net_bridge *br, unsigned char val);
|
||||
|
||||
/* br_stp_bpdu.c */
|
||||
void br_send_config_bpdu(struct net_bridge_port *, struct br_config_bpdu *);
|
||||
|
@ -234,7 +234,7 @@ static void br_record_config_timeout_values(struct net_bridge *br,
|
||||
br->max_age = bpdu->max_age;
|
||||
br->hello_time = bpdu->hello_time;
|
||||
br->forward_delay = bpdu->forward_delay;
|
||||
br->topology_change = bpdu->topology_change;
|
||||
__br_set_topology_change(br, bpdu->topology_change);
|
||||
}
|
||||
|
||||
/* called under bridge lock */
|
||||
@ -344,7 +344,7 @@ void br_topology_change_detection(struct net_bridge *br)
|
||||
isroot ? "propagating" : "sending tcn bpdu");
|
||||
|
||||
if (isroot) {
|
||||
br->topology_change = 1;
|
||||
__br_set_topology_change(br, 1);
|
||||
mod_timer(&br->topology_change_timer, jiffies
|
||||
+ br->bridge_forward_delay + br->bridge_max_age);
|
||||
} else if (!br->topology_change_detected) {
|
||||
@ -562,6 +562,24 @@ int br_set_max_age(struct net_bridge *br, unsigned long val)
|
||||
|
||||
}
|
||||
|
||||
/* called under bridge lock */
|
||||
int __set_ageing_time(struct net_device *dev, unsigned long t)
|
||||
{
|
||||
struct switchdev_attr attr = {
|
||||
.orig_dev = dev,
|
||||
.id = SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME,
|
||||
.flags = SWITCHDEV_F_SKIP_EOPNOTSUPP | SWITCHDEV_F_DEFER,
|
||||
.u.ageing_time = jiffies_to_clock_t(t),
|
||||
};
|
||||
int err;
|
||||
|
||||
err = switchdev_port_attr_set(dev, &attr);
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set time interval that dynamic forwarding entries live
|
||||
* For pure software bridge, allow values outside the 802.1
|
||||
* standard specification for special cases:
|
||||
@ -572,25 +590,52 @@ int br_set_max_age(struct net_bridge *br, unsigned long val)
|
||||
*/
|
||||
int br_set_ageing_time(struct net_bridge *br, clock_t ageing_time)
|
||||
{
|
||||
struct switchdev_attr attr = {
|
||||
.orig_dev = br->dev,
|
||||
.id = SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME,
|
||||
.flags = SWITCHDEV_F_SKIP_EOPNOTSUPP,
|
||||
.u.ageing_time = ageing_time,
|
||||
};
|
||||
unsigned long t = clock_t_to_jiffies(ageing_time);
|
||||
int err;
|
||||
|
||||
err = switchdev_port_attr_set(br->dev, &attr);
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
err = __set_ageing_time(br->dev, t);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
spin_lock_bh(&br->lock);
|
||||
br->bridge_ageing_time = t;
|
||||
br->ageing_time = t;
|
||||
spin_unlock_bh(&br->lock);
|
||||
|
||||
mod_timer(&br->gc_timer, jiffies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called under bridge lock */
|
||||
void __br_set_topology_change(struct net_bridge *br, unsigned char val)
|
||||
{
|
||||
unsigned long t;
|
||||
int err;
|
||||
|
||||
if (br->stp_enabled == BR_KERNEL_STP && br->topology_change != val) {
|
||||
/* On topology change, set the bridge ageing time to twice the
|
||||
* forward delay. Otherwise, restore its default ageing time.
|
||||
*/
|
||||
|
||||
if (val) {
|
||||
t = 2 * br->forward_delay;
|
||||
br_debug(br, "decreasing ageing time to %lu\n", t);
|
||||
} else {
|
||||
t = br->bridge_ageing_time;
|
||||
br_debug(br, "restoring ageing time to %lu\n", t);
|
||||
}
|
||||
|
||||
err = __set_ageing_time(br->dev, t);
|
||||
if (err)
|
||||
br_warn(br, "error offloading ageing time\n");
|
||||
else
|
||||
br->ageing_time = t;
|
||||
}
|
||||
|
||||
br->topology_change = val;
|
||||
}
|
||||
|
||||
void __br_set_forward_delay(struct net_bridge *br, unsigned long t)
|
||||
{
|
||||
br->bridge_forward_delay = t;
|
||||
|
@ -36,12 +36,6 @@ static inline port_id br_make_port_id(__u8 priority, __u16 port_no)
|
||||
/* called under bridge lock */
|
||||
void br_init_port(struct net_bridge_port *p)
|
||||
{
|
||||
struct switchdev_attr attr = {
|
||||
.orig_dev = p->dev,
|
||||
.id = SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME,
|
||||
.flags = SWITCHDEV_F_SKIP_EOPNOTSUPP | SWITCHDEV_F_DEFER,
|
||||
.u.ageing_time = jiffies_to_clock_t(p->br->ageing_time),
|
||||
};
|
||||
int err;
|
||||
|
||||
p->port_id = br_make_port_id(p->priority, p->port_no);
|
||||
@ -50,9 +44,9 @@ void br_init_port(struct net_bridge_port *p)
|
||||
p->topology_change_ack = 0;
|
||||
p->config_pending = 0;
|
||||
|
||||
err = switchdev_port_attr_set(p->dev, &attr);
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
netdev_err(p->dev, "failed to set HW ageing time\n");
|
||||
err = __set_ageing_time(p->dev, p->br->ageing_time);
|
||||
if (err)
|
||||
netdev_err(p->dev, "failed to offload ageing time\n");
|
||||
}
|
||||
|
||||
/* NO locks held */
|
||||
@ -87,7 +81,7 @@ void br_stp_disable_bridge(struct net_bridge *br)
|
||||
|
||||
}
|
||||
|
||||
br->topology_change = 0;
|
||||
__br_set_topology_change(br, 0);
|
||||
br->topology_change_detected = 0;
|
||||
spin_unlock_bh(&br->lock);
|
||||
|
||||
|
@ -125,7 +125,7 @@ static void br_topology_change_timer_expired(unsigned long arg)
|
||||
br_debug(br, "topo change timer expired\n");
|
||||
spin_lock(&br->lock);
|
||||
br->topology_change_detected = 0;
|
||||
br->topology_change = 0;
|
||||
__br_set_topology_change(br, 0);
|
||||
spin_unlock(&br->lock);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user