summaryrefslogtreecommitdiff
path: root/net/dsa/dsa2.c
diff options
context:
space:
mode:
authorVladimir Oltean <vladimir.oltean@nxp.com>2022-02-15 20:02:18 +0300
committerDavid S. Miller <davem@davemloft.net>2022-02-16 14:21:05 +0300
commit164f861bd40ccc3ed10a59ee72437b93670a525a (patch)
treed846755802b21a9b1cbf774f89ad193b0e475ee5 /net/dsa/dsa2.c
parent134ef2388e7f3271d13223decdb5e45b0f84489f (diff)
downloadlinux-164f861bd40ccc3ed10a59ee72437b93670a525a.tar.xz
net: dsa: offload bridge port VLANs on foreign interfaces
DSA now explicitly handles VLANs installed with the 'self' flag on the bridge as host VLANs, instead of just replicating every bridge port VLAN also on the CPU port and never deleting it, which is what it did before. However, this leaves a corner case uncovered, as explained by Tobias Waldekranz: https://patchwork.kernel.org/project/netdevbpf/patch/20220209213044.2353153-6-vladimir.oltean@nxp.com/#24735260 Forwarding towards a bridge port VLAN installed on a bridge port foreign to DSA (separate NIC, Wi-Fi AP) used to work by virtue of the fact that DSA itself needed to have at least one port in that VLAN (therefore, it also had the CPU port in said VLAN). However, now that the CPU port may not be member of all VLANs that user ports are members of, we need to ensure this isn't the case if software forwarding to a foreign interface is required. The solution is to treat bridge port VLANs on standalone interfaces in the exact same way as host VLANs. From DSA's perspective, there is no difference between local termination and software forwarding; packets in that VLAN must reach the CPU in both cases. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa/dsa2.c')
-rw-r--r--net/dsa/dsa2.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 1df8c2356463..408b79a28cd4 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -565,6 +565,7 @@ static void dsa_port_teardown(struct dsa_port *dp)
struct dsa_switch *ds = dp->ds;
struct dsa_mac_addr *a, *tmp;
struct net_device *slave;
+ struct dsa_vlan *v, *n;
if (!dp->setup)
return;
@@ -605,6 +606,11 @@ static void dsa_port_teardown(struct dsa_port *dp)
kfree(a);
}
+ list_for_each_entry_safe(v, n, &dp->vlans, list) {
+ list_del(&v->list);
+ kfree(v);
+ }
+
dp->setup = false;
}