mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 15:11:31 +00:00
net: dsa: targeted MTU notifiers should only match on one port
dsa_slave_change_mtu() calls dsa_port_mtu_change() twice: - it sends a cross-chip notifier with the MTU of the CPU port which is used to update the DSA links. - it sends one targeted MTU notifier which is supposed to only match the user port on which we are changing the MTU. The "propagate_upstream" variable is used here to bypass the cross-chip notifier system from switch.c But due to a mistake, the second, targeted notifier matches not only on the user port, but also on the DSA link which is a member of the same switch, if that exists. And because the DSA links of the entire dst were programmed in a previous round to the largest_mtu via a "propagate_upstream == true" notification, then the dsa_port_mtu_change(propagate_upstream == false) call that is immediately upcoming will break the MTU on the one DSA link which is chip-wise local to the dp whose MTU is changing right now. Example given this daisy chain topology: sw0p0 sw0p1 sw0p2 sw0p3 sw0p4 [ cpu ] [ user ] [ user ] [ dsa ] [ user ] [ x ] [ ] [ ] [ x ] [ ] | +---------+ | sw1p0 sw1p1 sw1p2 sw1p3 sw1p4 [ user ] [ user ] [ user ] [ dsa ] [ dsa ] [ ] [ ] [ ] [ ] [ x ] ip link set sw0p1 mtu 9000 ip link set sw1p1 mtu 9000 # at this stage, sw0p1 and sw1p1 can talk # to one another using jumbo frames ip link set sw0p2 mtu 1500 # this programs the sw0p3 DSA link first to # the largest_mtu of 9000, then reprograms it to # 1500 with the "propagate_upstream == false" # notifier, breaking communication between # sw0p1 and sw1p1 To escape from this situation, make the targeted match really match on a single port - the user port, and rename the "propagate_upstream" variable to "targeted_match" to clarify the intention and avoid future issues. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
4e4ab79500
commit
88faba20e2
@ -84,7 +84,7 @@ struct dsa_notifier_vlan_info {
|
||||
|
||||
/* DSA_NOTIFIER_MTU */
|
||||
struct dsa_notifier_mtu_info {
|
||||
bool propagate_upstream;
|
||||
bool targeted_match;
|
||||
int sw_index;
|
||||
int port;
|
||||
int mtu;
|
||||
@ -200,7 +200,7 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
|
||||
bool dsa_port_skip_vlan_configuration(struct dsa_port *dp);
|
||||
int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock);
|
||||
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,
|
||||
bool propagate_upstream);
|
||||
bool targeted_match);
|
||||
int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
|
||||
u16 vid);
|
||||
int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
|
||||
|
@ -567,11 +567,11 @@ int dsa_port_mrouter(struct dsa_port *dp, bool mrouter,
|
||||
}
|
||||
|
||||
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,
|
||||
bool propagate_upstream)
|
||||
bool targeted_match)
|
||||
{
|
||||
struct dsa_notifier_mtu_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.propagate_upstream = propagate_upstream,
|
||||
.targeted_match = targeted_match,
|
||||
.port = dp->index,
|
||||
.mtu = new_mtu,
|
||||
};
|
||||
|
@ -1586,14 +1586,15 @@ int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
|
||||
goto out_master_failed;
|
||||
|
||||
/* We only need to propagate the MTU of the CPU port to
|
||||
* upstream switches.
|
||||
* upstream switches, so create a non-targeted notifier which
|
||||
* updates all switches.
|
||||
*/
|
||||
err = dsa_port_mtu_change(cpu_dp, cpu_mtu, true);
|
||||
err = dsa_port_mtu_change(cpu_dp, cpu_mtu, false);
|
||||
if (err)
|
||||
goto out_cpu_failed;
|
||||
}
|
||||
|
||||
err = dsa_port_mtu_change(dp, new_mtu, false);
|
||||
err = dsa_port_mtu_change(dp, new_mtu, true);
|
||||
if (err)
|
||||
goto out_port_failed;
|
||||
|
||||
@ -1607,7 +1608,7 @@ out_port_failed:
|
||||
if (new_master_mtu != old_master_mtu)
|
||||
dsa_port_mtu_change(cpu_dp, old_master_mtu -
|
||||
dsa_tag_protocol_overhead(cpu_dp->tag_ops),
|
||||
true);
|
||||
false);
|
||||
out_cpu_failed:
|
||||
if (new_master_mtu != old_master_mtu)
|
||||
dev_set_mtu(master, old_master_mtu);
|
||||
|
@ -52,10 +52,13 @@ static int dsa_switch_ageing_time(struct dsa_switch *ds,
|
||||
static bool dsa_switch_mtu_match(struct dsa_switch *ds, int port,
|
||||
struct dsa_notifier_mtu_info *info)
|
||||
{
|
||||
if (ds->index == info->sw_index)
|
||||
return (port == info->port) || dsa_is_dsa_port(ds, port);
|
||||
if (ds->index == info->sw_index && port == info->port)
|
||||
return true;
|
||||
|
||||
if (!info->propagate_upstream)
|
||||
/* Do not propagate to other switches in the tree if the notifier was
|
||||
* targeted for a single switch.
|
||||
*/
|
||||
if (info->targeted_match)
|
||||
return false;
|
||||
|
||||
if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
|
||||
|
Loading…
Reference in New Issue
Block a user