Skip to content

Commit 54a0ed0

Browse files
Russell Kingdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 26831d7 commit 54a0ed0

File tree

4 files changed

+26
-4
lines changed

4 files changed

+26
-4
lines changed

include/net/dsa.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,13 @@ struct dsa_switch {
282282
*/
283283
bool vlan_filtering_is_global;
284284

285+
/* Pass .port_vlan_add and .port_vlan_del to drivers even for bridges
286+
* that have vlan_filtering=0. All drivers should ideally set this (and
287+
* then the option would get removed), but it is unknown whether this
288+
* would break things or not.
289+
*/
290+
bool configure_vlan_while_not_filtering;
291+
285292
/* In case vlan_filtering_is_global is set, the VLAN awareness state
286293
* should be retrieved from here and not from the per-port settings.
287294
*/

net/dsa/dsa_priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br);
138138
void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
139139
int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
140140
struct switchdev_trans *trans);
141+
bool dsa_port_skip_vlan_configuration(struct dsa_port *dp);
141142
int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
142143
struct switchdev_trans *trans);
143144
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,

net/dsa/port.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,20 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
257257
return 0;
258258
}
259259

260+
/* This enforces legacy behavior for switch drivers which assume they can't
261+
* receive VLAN configuration when enslaved to a bridge with vlan_filtering=0
262+
*/
263+
bool dsa_port_skip_vlan_configuration(struct dsa_port *dp)
264+
{
265+
struct dsa_switch *ds = dp->ds;
266+
267+
if (!dp->bridge_dev)
268+
return false;
269+
270+
return (!ds->configure_vlan_while_not_filtering &&
271+
!br_vlan_enabled(dp->bridge_dev));
272+
}
273+
260274
int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
261275
struct switchdev_trans *trans)
262276
{

net/dsa/slave.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ static int dsa_slave_vlan_add(struct net_device *dev,
314314
if (obj->orig_dev != dev)
315315
return -EOPNOTSUPP;
316316

317-
if (dp->bridge_dev && !br_vlan_enabled(dp->bridge_dev))
317+
if (dsa_port_skip_vlan_configuration(dp))
318318
return 0;
319319

320320
vlan = *SWITCHDEV_OBJ_PORT_VLAN(obj);
@@ -381,7 +381,7 @@ static int dsa_slave_vlan_del(struct net_device *dev,
381381
if (obj->orig_dev != dev)
382382
return -EOPNOTSUPP;
383383

384-
if (dp->bridge_dev && !br_vlan_enabled(dp->bridge_dev))
384+
if (dsa_port_skip_vlan_configuration(dp))
385385
return 0;
386386

387387
/* Do not deprogram the CPU port as it may be shared with other user
@@ -1240,7 +1240,7 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
12401240
* need to emulate the switchdev prepare + commit phase.
12411241
*/
12421242
if (dp->bridge_dev) {
1243-
if (!br_vlan_enabled(dp->bridge_dev))
1243+
if (dsa_port_skip_vlan_configuration(dp))
12441244
return 0;
12451245

12461246
/* br_vlan_get_info() returns -EINVAL or -ENOENT if the
@@ -1274,7 +1274,7 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
12741274
* need to emulate the switchdev prepare + commit phase.
12751275
*/
12761276
if (dp->bridge_dev) {
1277-
if (!br_vlan_enabled(dp->bridge_dev))
1277+
if (dsa_port_skip_vlan_configuration(dp))
12781278
return 0;
12791279

12801280
/* br_vlan_get_info() returns -EINVAL or -ENOENT if the

0 commit comments

Comments
 (0)