mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-29 07:34:06 +08:00
Merge branch 'Dynamic-toggling-of-vlan_filtering-for-SJA1105-DSA'
Vladimir Oltean says: ==================== Dynamic toggling of vlan_filtering for SJA1105 DSA This patchset addresses a limitation in dsa_8021q where this sequence of commands was causing the switch to stop forwarding traffic: ip link add name br0 type bridge vlan_filtering 0 ip link set dev swp2 master br0 echo 1 > /sys/class/net/br0/bridge/vlan_filtering echo 0 > /sys/class/net/br0/bridge/vlan_filtering The issue has to do with the VLAN table manipulations that dsa_8021q does without notifying the bridge layer. The solution is to always restore the VLANs that the bridge knows about, when disabling tagging. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
b0274eb0d7
@ -1281,6 +1281,8 @@ int br_vlan_get_info(const struct net_device *dev, u16 vid,
|
||||
|
||||
p_vinfo->vid = vid;
|
||||
p_vinfo->flags = v->flags;
|
||||
if (vid == br_get_pvid(vg))
|
||||
p_vinfo->flags |= BRIDGE_VLAN_INFO_PVID;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(br_vlan_get_info);
|
||||
|
@ -91,6 +91,79 @@ int dsa_8021q_rx_source_port(u16 vid)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dsa_8021q_rx_source_port);
|
||||
|
||||
static int dsa_8021q_restore_pvid(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct bridge_vlan_info vinfo;
|
||||
struct net_device *slave;
|
||||
u16 pvid;
|
||||
int err;
|
||||
|
||||
if (!dsa_is_user_port(ds, port))
|
||||
return 0;
|
||||
|
||||
slave = ds->ports[port].slave;
|
||||
|
||||
err = br_vlan_get_pvid(slave, &pvid);
|
||||
if (err < 0)
|
||||
/* There is no pvid on the bridge for this port, which is
|
||||
* perfectly valid. Nothing to restore, bye-bye!
|
||||
*/
|
||||
return 0;
|
||||
|
||||
err = br_vlan_get_info(slave, pvid, &vinfo);
|
||||
if (err < 0) {
|
||||
dev_err(ds->dev, "Couldn't determine PVID attributes\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return dsa_port_vid_add(&ds->ports[port], pvid, vinfo.flags);
|
||||
}
|
||||
|
||||
/* If @enabled is true, installs @vid with @flags into the switch port's HW
|
||||
* filter.
|
||||
* If @enabled is false, deletes @vid (ignores @flags) from the port. Had the
|
||||
* user explicitly configured this @vid through the bridge core, then the @vid
|
||||
* is installed again, but this time with the flags from the bridge layer.
|
||||
*/
|
||||
static int dsa_8021q_vid_apply(struct dsa_switch *ds, int port, u16 vid,
|
||||
u16 flags, bool enabled)
|
||||
{
|
||||
struct dsa_port *dp = &ds->ports[port];
|
||||
struct bridge_vlan_info vinfo;
|
||||
int err;
|
||||
|
||||
if (enabled)
|
||||
return dsa_port_vid_add(dp, vid, flags);
|
||||
|
||||
err = dsa_port_vid_del(dp, vid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Nothing to restore from the bridge for a non-user port.
|
||||
* The CPU port VLANs are restored implicitly with the user ports,
|
||||
* similar to how the bridge does in dsa_slave_vlan_add and
|
||||
* dsa_slave_vlan_del.
|
||||
*/
|
||||
if (!dsa_is_user_port(ds, port))
|
||||
return 0;
|
||||
|
||||
err = br_vlan_get_info(dp->slave, vid, &vinfo);
|
||||
/* Couldn't determine bridge attributes for this vid,
|
||||
* it means the bridge had not configured it.
|
||||
*/
|
||||
if (err < 0)
|
||||
return 0;
|
||||
|
||||
/* Restore the VID from the bridge */
|
||||
err = dsa_port_vid_add(dp, vid, vinfo.flags);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
vinfo.flags &= ~BRIDGE_VLAN_INFO_PVID;
|
||||
|
||||
return dsa_port_vid_add(dp->cpu_dp, vid, vinfo.flags);
|
||||
}
|
||||
|
||||
/* RX VLAN tagging (left) and TX VLAN tagging (right) setup shown for a single
|
||||
* front-panel switch port (here swp0).
|
||||
*
|
||||
@ -146,8 +219,6 @@ EXPORT_SYMBOL_GPL(dsa_8021q_rx_source_port);
|
||||
int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
|
||||
{
|
||||
int upstream = dsa_upstream_port(ds, port);
|
||||
struct dsa_port *dp = &ds->ports[port];
|
||||
struct dsa_port *upstream_dp = &ds->ports[upstream];
|
||||
u16 rx_vid = dsa_8021q_rx_vid(ds, port);
|
||||
u16 tx_vid = dsa_8021q_tx_vid(ds, port);
|
||||
int i, err;
|
||||
@ -164,7 +235,6 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
|
||||
* restrictions, so there are no concerns about leaking traffic.
|
||||
*/
|
||||
for (i = 0; i < ds->num_ports; i++) {
|
||||
struct dsa_port *other_dp = &ds->ports[i];
|
||||
u16 flags;
|
||||
|
||||
if (i == upstream)
|
||||
@ -177,10 +247,7 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
|
||||
/* The RX VID is a regular VLAN on all others */
|
||||
flags = BRIDGE_VLAN_INFO_UNTAGGED;
|
||||
|
||||
if (enabled)
|
||||
err = dsa_port_vid_add(other_dp, rx_vid, flags);
|
||||
else
|
||||
err = dsa_port_vid_del(other_dp, rx_vid);
|
||||
err = dsa_8021q_vid_apply(ds, i, rx_vid, flags, enabled);
|
||||
if (err) {
|
||||
dev_err(ds->dev, "Failed to apply RX VID %d to port %d: %d\n",
|
||||
rx_vid, port, err);
|
||||
@ -191,10 +258,7 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
|
||||
/* CPU port needs to see this port's RX VID
|
||||
* as tagged egress.
|
||||
*/
|
||||
if (enabled)
|
||||
err = dsa_port_vid_add(upstream_dp, rx_vid, 0);
|
||||
else
|
||||
err = dsa_port_vid_del(upstream_dp, rx_vid);
|
||||
err = dsa_8021q_vid_apply(ds, upstream, rx_vid, 0, enabled);
|
||||
if (err) {
|
||||
dev_err(ds->dev, "Failed to apply RX VID %d to port %d: %d\n",
|
||||
rx_vid, port, err);
|
||||
@ -202,26 +266,24 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
|
||||
}
|
||||
|
||||
/* Finally apply the TX VID on this port and on the CPU port */
|
||||
if (enabled)
|
||||
err = dsa_port_vid_add(dp, tx_vid, BRIDGE_VLAN_INFO_UNTAGGED);
|
||||
else
|
||||
err = dsa_port_vid_del(dp, tx_vid);
|
||||
err = dsa_8021q_vid_apply(ds, port, tx_vid, BRIDGE_VLAN_INFO_UNTAGGED,
|
||||
enabled);
|
||||
if (err) {
|
||||
dev_err(ds->dev, "Failed to apply TX VID %d on port %d: %d\n",
|
||||
tx_vid, port, err);
|
||||
return err;
|
||||
}
|
||||
if (enabled)
|
||||
err = dsa_port_vid_add(upstream_dp, tx_vid, 0);
|
||||
else
|
||||
err = dsa_port_vid_del(upstream_dp, tx_vid);
|
||||
err = dsa_8021q_vid_apply(ds, upstream, tx_vid, 0, enabled);
|
||||
if (err) {
|
||||
dev_err(ds->dev, "Failed to apply TX VID %d on port %d: %d\n",
|
||||
tx_vid, upstream, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (!enabled)
|
||||
err = dsa_8021q_restore_pvid(ds, port);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dsa_port_setup_8021q_tagging);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user