mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-22 06:57:57 +00:00
122 lines
4.4 KiB
Diff
122 lines
4.4 KiB
Diff
|
From 54a0ed0df49609f4e3f098f8943e38e389dc2e15 Mon Sep 17 00:00:00 2001
|
||
|
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||
|
Date: Tue, 12 May 2020 20:20:25 +0300
|
||
|
Subject: net: dsa: provide an option for drivers to always receive bridge
|
||
|
VLANs
|
||
|
|
||
|
DSA assumes that a bridge which has vlan filtering disabled is not
|
||
|
vlan aware, and ignores all vlan configuration. However, the kernel
|
||
|
software bridge code allows configuration in this state.
|
||
|
|
||
|
This causes the kernel's idea of the bridge vlan state and the
|
||
|
hardware state to disagree, so "bridge vlan show" indicates a correct
|
||
|
configuration but the hardware lacks all configuration. Even worse,
|
||
|
enabling vlan filtering on a DSA bridge immediately blocks all traffic
|
||
|
which, given the output of "bridge vlan show", is very confusing.
|
||
|
|
||
|
Provide an option that drivers can set to indicate they want to receive
|
||
|
vlan configuration even when vlan filtering is disabled. At the very
|
||
|
least, this is safe for Marvell DSA bridges, which do not look up
|
||
|
ingress traffic in the VTU if the port is in 8021Q disabled state. It is
|
||
|
also safe for the Ocelot switch family. Whether this change is suitable
|
||
|
for all DSA bridges is not known.
|
||
|
|
||
|
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||
|
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>
|
||
|
---
|
||
|
include/net/dsa.h | 7 +++++++
|
||
|
net/dsa/dsa_priv.h | 1 +
|
||
|
net/dsa/port.c | 14 ++++++++++++++
|
||
|
net/dsa/slave.c | 8 ++++----
|
||
|
4 files changed, 26 insertions(+), 4 deletions(-)
|
||
|
|
||
|
--- a/include/net/dsa.h
|
||
|
+++ b/include/net/dsa.h
|
||
|
@@ -270,6 +270,13 @@ struct dsa_switch {
|
||
|
*/
|
||
|
bool vlan_filtering_is_global;
|
||
|
|
||
|
+ /* Pass .port_vlan_add and .port_vlan_del to drivers even for bridges
|
||
|
+ * that have vlan_filtering=0. All drivers should ideally set this (and
|
||
|
+ * then the option would get removed), but it is unknown whether this
|
||
|
+ * would break things or not.
|
||
|
+ */
|
||
|
+ bool configure_vlan_while_not_filtering;
|
||
|
+
|
||
|
/* In case vlan_filtering_is_global is set, the VLAN awareness state
|
||
|
* should be retrieved from here and not from the per-port settings.
|
||
|
*/
|
||
|
--- a/net/dsa/dsa_priv.h
|
||
|
+++ b/net/dsa/dsa_priv.h
|
||
|
@@ -136,6 +136,7 @@ int dsa_port_bridge_join(struct dsa_port
|
||
|
void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
|
||
|
int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
|
||
|
struct switchdev_trans *trans);
|
||
|
+bool dsa_port_skip_vlan_configuration(struct dsa_port *dp);
|
||
|
int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
|
||
|
struct switchdev_trans *trans);
|
||
|
int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
|
||
|
--- a/net/dsa/port.c
|
||
|
+++ b/net/dsa/port.c
|
||
|
@@ -238,6 +238,20 @@ int dsa_port_vlan_filtering(struct dsa_p
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/* This enforces legacy behavior for switch drivers which assume they can't
|
||
|
+ * receive VLAN configuration when enslaved to a bridge with vlan_filtering=0
|
||
|
+ */
|
||
|
+bool dsa_port_skip_vlan_configuration(struct dsa_port *dp)
|
||
|
+{
|
||
|
+ struct dsa_switch *ds = dp->ds;
|
||
|
+
|
||
|
+ if (!dp->bridge_dev)
|
||
|
+ return false;
|
||
|
+
|
||
|
+ return (!ds->configure_vlan_while_not_filtering &&
|
||
|
+ !br_vlan_enabled(dp->bridge_dev));
|
||
|
+}
|
||
|
+
|
||
|
int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
|
||
|
struct switchdev_trans *trans)
|
||
|
{
|
||
|
--- a/net/dsa/slave.c
|
||
|
+++ b/net/dsa/slave.c
|
||
|
@@ -319,7 +319,7 @@ static int dsa_slave_vlan_add(struct net
|
||
|
if (obj->orig_dev != dev)
|
||
|
return -EOPNOTSUPP;
|
||
|
|
||
|
- if (dp->bridge_dev && !br_vlan_enabled(dp->bridge_dev))
|
||
|
+ if (dsa_port_skip_vlan_configuration(dp))
|
||
|
return 0;
|
||
|
|
||
|
vlan = *SWITCHDEV_OBJ_PORT_VLAN(obj);
|
||
|
@@ -386,7 +386,7 @@ static int dsa_slave_vlan_del(struct net
|
||
|
if (obj->orig_dev != dev)
|
||
|
return -EOPNOTSUPP;
|
||
|
|
||
|
- if (dp->bridge_dev && !br_vlan_enabled(dp->bridge_dev))
|
||
|
+ if (dsa_port_skip_vlan_configuration(dp))
|
||
|
return 0;
|
||
|
|
||
|
/* Do not deprogram the CPU port as it may be shared with other user
|
||
|
@@ -1118,7 +1118,7 @@ static int dsa_slave_vlan_rx_add_vid(str
|
||
|
* need to emulate the switchdev prepare + commit phase.
|
||
|
*/
|
||
|
if (dp->bridge_dev) {
|
||
|
- if (!br_vlan_enabled(dp->bridge_dev))
|
||
|
+ if (dsa_port_skip_vlan_configuration(dp))
|
||
|
return 0;
|
||
|
|
||
|
/* br_vlan_get_info() returns -EINVAL or -ENOENT if the
|
||
|
@@ -1152,7 +1152,7 @@ static int dsa_slave_vlan_rx_kill_vid(st
|
||
|
* need to emulate the switchdev prepare + commit phase.
|
||
|
*/
|
||
|
if (dp->bridge_dev) {
|
||
|
- if (!br_vlan_enabled(dp->bridge_dev))
|
||
|
+ if (dsa_port_skip_vlan_configuration(dp))
|
||
|
return 0;
|
||
|
|
||
|
/* br_vlan_get_info() returns -EINVAL or -ENOENT if the
|