Commit 8e9e678e authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: dsa: move reset of VLAN filtering to dsa_port_switchdev_unsync_attrs

In dsa_port_switchdev_unsync_attrs() there is a comment that resetting
the VLAN filtering isn't done where it is expected. And since commit
108dc874 ("net: dsa: Avoid cross-chip syncing of VLAN filtering"),
there is no reason to handle this in switch.c either.

Therefore, move the logic to port.c, and adapt it slightly to the data
structures and naming conventions from there.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cc4bdef2
...@@ -242,6 +242,59 @@ void dsa_port_disable(struct dsa_port *dp) ...@@ -242,6 +242,59 @@ void dsa_port_disable(struct dsa_port *dp)
rtnl_unlock(); rtnl_unlock();
} }
static void dsa_port_reset_vlan_filtering(struct dsa_port *dp,
struct dsa_bridge bridge)
{
struct netlink_ext_ack extack = {0};
bool change_vlan_filtering = false;
struct dsa_switch *ds = dp->ds;
bool vlan_filtering;
int err;
if (ds->needs_standalone_vlan_filtering &&
!br_vlan_enabled(bridge.dev)) {
change_vlan_filtering = true;
vlan_filtering = true;
} else if (!ds->needs_standalone_vlan_filtering &&
br_vlan_enabled(bridge.dev)) {
change_vlan_filtering = true;
vlan_filtering = false;
}
/* If the bridge was vlan_filtering, the bridge core doesn't trigger an
* event for changing vlan_filtering setting upon slave ports leaving
* it. That is a good thing, because that lets us handle it and also
* handle the case where the switch's vlan_filtering setting is global
* (not per port). When that happens, the correct moment to trigger the
* vlan_filtering callback is only when the last port leaves the last
* VLAN-aware bridge.
*/
if (change_vlan_filtering && ds->vlan_filtering_is_global) {
dsa_switch_for_each_port(dp, ds) {
struct net_device *br = dsa_port_bridge_dev_get(dp);
if (br && br_vlan_enabled(br)) {
change_vlan_filtering = false;
break;
}
}
}
if (!change_vlan_filtering)
return;
err = dsa_port_vlan_filtering(dp, vlan_filtering, &extack);
if (extack._msg) {
dev_err(ds->dev, "port %d: %s\n", dp->index,
extack._msg);
}
if (err && err != -EOPNOTSUPP) {
dev_err(ds->dev,
"port %d failed to reset VLAN filtering to %d: %pe\n",
dp->index, vlan_filtering, ERR_PTR(err));
}
}
static int dsa_port_inherit_brport_flags(struct dsa_port *dp, static int dsa_port_inherit_brport_flags(struct dsa_port *dp,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
...@@ -313,7 +366,8 @@ static int dsa_port_switchdev_sync_attrs(struct dsa_port *dp, ...@@ -313,7 +366,8 @@ static int dsa_port_switchdev_sync_attrs(struct dsa_port *dp,
return 0; return 0;
} }
static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp) static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp,
struct dsa_bridge bridge)
{ {
/* Configure the port for standalone mode (no address learning, /* Configure the port for standalone mode (no address learning,
* flood everything). * flood everything).
...@@ -333,7 +387,7 @@ static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp) ...@@ -333,7 +387,7 @@ static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp)
*/ */
dsa_port_set_state_now(dp, BR_STATE_FORWARDING, true); dsa_port_set_state_now(dp, BR_STATE_FORWARDING, true);
/* VLAN filtering is handled by dsa_switch_bridge_leave */ dsa_port_reset_vlan_filtering(dp, bridge);
/* Ageing time may be global to the switch chip, so don't change it /* Ageing time may be global to the switch chip, so don't change it
* here because we have no good reason (or value) to change it to. * here because we have no good reason (or value) to change it to.
...@@ -501,7 +555,7 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) ...@@ -501,7 +555,7 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
"port %d failed to notify DSA_NOTIFIER_BRIDGE_LEAVE: %pe\n", "port %d failed to notify DSA_NOTIFIER_BRIDGE_LEAVE: %pe\n",
dp->index, ERR_PTR(err)); dp->index, ERR_PTR(err));
dsa_port_switchdev_unsync_attrs(dp); dsa_port_switchdev_unsync_attrs(dp, info.bridge);
} }
int dsa_port_lag_change(struct dsa_port *dp, int dsa_port_lag_change(struct dsa_port *dp,
......
...@@ -115,62 +115,10 @@ static int dsa_switch_bridge_join(struct dsa_switch *ds, ...@@ -115,62 +115,10 @@ static int dsa_switch_bridge_join(struct dsa_switch *ds,
return 0; return 0;
} }
static int dsa_switch_sync_vlan_filtering(struct dsa_switch *ds,
struct dsa_notifier_bridge_info *info)
{
struct netlink_ext_ack extack = {0};
bool change_vlan_filtering = false;
bool vlan_filtering;
struct dsa_port *dp;
int err;
if (ds->needs_standalone_vlan_filtering &&
!br_vlan_enabled(info->bridge.dev)) {
change_vlan_filtering = true;
vlan_filtering = true;
} else if (!ds->needs_standalone_vlan_filtering &&
br_vlan_enabled(info->bridge.dev)) {
change_vlan_filtering = true;
vlan_filtering = false;
}
/* If the bridge was vlan_filtering, the bridge core doesn't trigger an
* event for changing vlan_filtering setting upon slave ports leaving
* it. That is a good thing, because that lets us handle it and also
* handle the case where the switch's vlan_filtering setting is global
* (not per port). When that happens, the correct moment to trigger the
* vlan_filtering callback is only when the last port leaves the last
* VLAN-aware bridge.
*/
if (change_vlan_filtering && ds->vlan_filtering_is_global) {
dsa_switch_for_each_port(dp, ds) {
struct net_device *br = dsa_port_bridge_dev_get(dp);
if (br && br_vlan_enabled(br)) {
change_vlan_filtering = false;
break;
}
}
}
if (change_vlan_filtering) {
err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
vlan_filtering, &extack);
if (extack._msg)
dev_err(ds->dev, "port %d: %s\n", info->port,
extack._msg);
if (err && err != -EOPNOTSUPP)
return err;
}
return 0;
}
static int dsa_switch_bridge_leave(struct dsa_switch *ds, static int dsa_switch_bridge_leave(struct dsa_switch *ds,
struct dsa_notifier_bridge_info *info) struct dsa_notifier_bridge_info *info)
{ {
struct dsa_switch_tree *dst = ds->dst; struct dsa_switch_tree *dst = ds->dst;
int err;
if (dst->index == info->tree_index && ds->index == info->sw_index && if (dst->index == info->tree_index && ds->index == info->sw_index &&
ds->ops->port_bridge_leave) ds->ops->port_bridge_leave)
...@@ -182,12 +130,6 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds, ...@@ -182,12 +130,6 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
info->sw_index, info->port, info->sw_index, info->port,
info->bridge); info->bridge);
if (ds->dst->index == info->tree_index && ds->index == info->sw_index) {
err = dsa_switch_sync_vlan_filtering(ds, info);
if (err)
return err;
}
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment