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

net: dsa: sja1105: update existing VLANs from the bridge VLAN list

When running this sequence of operations:

ip link add br0 type bridge vlan_filtering 1
ip link set swp4 master br0
bridge vlan add dev swp4 vid 1

We observe the traffic sent on swp4 is still untagged, even though the
bridge has overwritten the existing VLAN entry:

port    vlan ids
swp4     1 PVID

br0      1 PVID Egress Untagged

This happens because we didn't consider that the 'bridge vlan add'
command just overwrites VLANs like it's nothing. We treat the 'vid 1
pvid untagged' and the 'vid 1' as two separate VLANs, and the first
still has precedence when calling sja1105_build_vlan_table. Obviously
there is a disagreement regarding semantics, and we end up doing
something unexpected from the PoV of the bridge.

Let's actually consider an "existing VLAN" to be one which is on the
same port, and has the same VLAN ID, as one we already have, and update
it if it has different flags than we do.

The first blamed commit is the one introducing the bug, the second one
is the latest on top of which the bugfix still applies.

Fixes: ec5ae610 ("net: dsa: sja1105: save/restore VLANs using a delta commit method")
Fixes: 5899ee36 ("net: dsa: tag_8021q: add a context structure")
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ed040abc
...@@ -2816,12 +2816,23 @@ static int sja1105_vlan_add_one(struct dsa_switch *ds, int port, u16 vid, ...@@ -2816,12 +2816,23 @@ static int sja1105_vlan_add_one(struct dsa_switch *ds, int port, u16 vid,
bool pvid = flags & BRIDGE_VLAN_INFO_PVID; bool pvid = flags & BRIDGE_VLAN_INFO_PVID;
struct sja1105_bridge_vlan *v; struct sja1105_bridge_vlan *v;
list_for_each_entry(v, vlan_list, list) list_for_each_entry(v, vlan_list, list) {
if (v->port == port && v->vid == vid && if (v->port == port && v->vid == vid) {
v->untagged == untagged && v->pvid == pvid)
/* Already added */ /* Already added */
if (v->untagged == untagged && v->pvid == pvid)
/* Nothing changed */
return 0; return 0;
/* It's the same VLAN, but some of the flags changed
* and the user did not bother to delete it first.
* Update it and trigger sja1105_build_vlan_table.
*/
v->untagged = untagged;
v->pvid = pvid;
return 1;
}
}
v = kzalloc(sizeof(*v), GFP_KERNEL); v = kzalloc(sizeof(*v), GFP_KERNEL);
if (!v) { if (!v) {
dev_err(ds->dev, "Out of memory while storing VLAN\n"); dev_err(ds->dev, "Out of memory while storing VLAN\n");
......
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