* [PATCH net 0/2] net: dsa: b53: fix 8021q uppers on standalone ports
@ 2026-08-06 7:31 Semih Baskan
2026-08-06 7:31 ` [PATCH net 1/2] net: dsa: let drivers offload " Semih Baskan
` (2 more replies)
0 siblings, 3 replies; 19+ messages in thread
From: Semih Baskan @ 2026-08-06 7:31 UTC (permalink / raw)
To: florian.fainelli, jonas.gorski, andrew, olteanv, davem, edumazet,
kuba, pabeni
Cc: vladimir.oltean, horms, netdev, linux-kernel
Since v5.15, a standalone port on a b53 switch cannot receive its own
tagged traffic: the switch VID lookup is always active, an 8021q
upper's VID never reaches the VLAN table, and every tagged frame
resolves to an empty member set and is discarded. The common victim is
a VLAN-tagged PPPoE WAN, where the PADI goes out and the tagged PADO
never reaches the CPU.
My first attempt disabled the VLAN table while not filtering:
https://lore.kernel.org/all/20260805072641.402-1-strst.gs@gmail.com/
Jonas pointed out that this moves the ARL to shared VLAN learning and
desynchronizes the hardware table from the bridge fdb, and I withdrew
it. I then measured the alternatives on an RT-N18U (BCM53011 rev 5),
with the outbound direction of the same link as a positive control on
every run:
- With the table enabled, no ingress VID check setting delivers the
frame: VC4_NO_ING_VID_CHK, VC4_ING_VID_VIO_FWD and
VC4_ING_VID_VIO_TO_IMP all give 0, and clearing VC0_DROP_VID_MISS
changes nothing. The frame does not die at ingress admission, it
dies when forwarding resolves the VID against an empty member set.
- With the table disabled, a static fdb entry with VID 100 is lost
from the hardware ARL no matter how the driver drives the ARL
registers: keeping ARLTBL_IVL_SVL_SELECT at IVL does not preserve
it, and neither does additionally keeping the VID learning bits in
VLAN_CTRL0 set.
So on this hardware, delivering the frame and keeping VID-keyed ARL
entries are mutually exclusive unless the VID is in the table. This
series therefore programs the table, narrowed to what is actually
needed: a standalone port only needs the VIDs its 8021q uppers use,
which is one table write per upper instead of entries for all 4096
VIDs.
I tried to keep the fix inside b53, but the driver cannot solve this
alone: without NETIF_F_HW_VLAN_CTAG_FILTER the 8021q layer never calls
.ndo_vlan_rx_add_vid, so the VIDs never reach the driver, and DSA
manages that feature bit. The one existing way to get it,
ds->needs_standalone_vlan_filtering, does not work here. It was
measured insufficient, because f089652b6b16 makes .port_vlan_add skip
the hardware write while not filtering, and its other effect is one
b53 cannot take: with vlan_filtering_is_global, the forced
vlan_filtering=1 in dsa_port_reset_vlan_filtering() would flip the
whole switch into VLAN filtering when any port leaves a VLAN-unaware
bridge. hellcreek relies on exactly those semantics, so patch 1 adds a
narrower opt-in that only delivers the VIDs and leaves vlan_filtering
alone, and patch 2 uses it in b53 and programs entries that carry
standalone members, masked so bridge VLANs stay without effect while
not filtering.
Tested on the RT-N18U: the standalone upper receives 7 of 7 probe
frames with vlan_filtering staying 0, the static fdb entry with a VID
now survives a vlan_filtering toggle since the table and the ARL mode
are never touched, uppers keep working across bridge join and leave
and across a vlan_filtering toggle including on ports that were
bridged while the toggle happened, deleting an upper or bridging its
port verifiably stops delivery of that VID to the CPU, and the PPPoE
session from the original report establishes. 802.1ad uppers keep
working as software VLANs, since this switch does not parse 0x88a8,
and stacked QinQ over an offloaded upper works too.
Semih Baskan (2):
net: dsa: let drivers offload 8021q uppers on standalone ports
net: dsa: b53: offload 8021q uppers on standalone ports
drivers/net/dsa/b53/b53_common.c | 118 ++++++++++++++++++++++++++-----
include/net/dsa.h | 3 +
net/dsa/port.c | 21 ++++--
net/dsa/user.c | 4 +-
4 files changed, 120 insertions(+), 26 deletions(-)
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-06 7:31 [PATCH net 0/2] net: dsa: b53: fix 8021q uppers on standalone ports Semih Baskan @ 2026-08-06 7:31 ` Semih Baskan 2026-08-06 11:15 ` Vladimir Oltean 2026-08-06 7:31 ` [PATCH net 2/2] net: dsa: b53: " Semih Baskan 2026-08-06 8:39 ` [PATCH net 0/2] net: dsa: b53: fix " Jonas Gorski 2 siblings, 1 reply; 19+ messages in thread From: Semih Baskan @ 2026-08-06 7:31 UTC (permalink / raw) To: florian.fainelli, jonas.gorski, andrew, olteanv, davem, edumazet, kuba, pabeni Cc: vladimir.oltean, horms, netdev, linux-kernel Some switches cannot deliver a tagged frame to the CPU while its VID is absent from the VLAN table, not even with VLAN filtering turned off. b53 is one of them: its VID lookup is always active, and disabling it moves the ARL to shared VLAN learning, where ARL operations force VID 0 and the hardware table drifts away from the bridge fdb. On such hardware a standalone port can only receive the traffic of its 8021q uppers if their VIDs are programmed into the table. The existing opt-in for this class of problem, ds->needs_standalone_vlan_filtering, delivers those VIDs but does more: dsa_port_reset_vlan_filtering() also forces vlan_filtering=1 on a port that leaves a VLAN-unaware bridge. hellcreek wants exactly that. b53 must not have it, because it sets vlan_filtering_is_global, so the forced flip would turn the whole switch into a VLAN filtering device the first time any port leaves a VLAN-unaware bridge and change behaviour for every other port. Add ds->needs_standalone_vlan_offload for the narrower need. It advertises NETIF_F_HW_VLAN_CTAG_FILTER on user ports, so the 8021q layer reports upper VIDs to .port_vlan_add, and it leaves the vlan_filtering state alone. Upper offload of such a switch never depends on vlan_filtering: every VID was already delivered when the upper was created, since the feature bit is always on. dsa_port_vlan_filtering() therefore skips its ports entirely when a bridge toggles VLAN awareness. Restoring them on the way up would add VIDs that were never cleared, and clearing them on the way down would strip the driver's record of a bridged port's uppers and the feature bit, leaving a port that later leaves the bridge with uppers that cannot receive and no way to re-offload them. The conduit change path keeps its explicit teardown and restore of standalone VLANs, and now also runs it for a standalone port of such a switch while VLAN filtering is off, because that port has VLANs on the CPU port too. The Fixes tag is for backport dependency tracking: the b53 fix in the next patch needs this flag to exist. Fixes: 06cfb2df7eb0 ("net: dsa: don't advertise 'rx-vlan-filter' when not needed") Cc: stable@vger.kernel.org Signed-off-by: Semih Baskan <strst.gs@gmail.com> --- include/net/dsa.h | 3 +++ net/dsa/port.c | 21 ++++++++++++++------- net/dsa/user.c | 4 +++- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index 6f7f5c17b532..6f3a60c23d14 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -403,6 +403,9 @@ struct dsa_switch { /* Keep VLAN filtering enabled on ports not offloading any upper */ u32 needs_standalone_vlan_filtering:1; + /* Offload 8021q uppers of standalone ports even when not filtering */ + u32 needs_standalone_vlan_offload:1; + /* 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 diff --git a/net/dsa/port.c b/net/dsa/port.c index 1f5536c0dffc..23d1c5ae6934 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -831,6 +831,9 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, if (!user) continue; + if (ds->needs_standalone_vlan_offload) + continue; + err = dsa_user_manage_vlan_filtering(user, vlan_filtering); if (err) @@ -839,10 +842,12 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, } else { dp->vlan_filtering = vlan_filtering; - err = dsa_user_manage_vlan_filtering(dp->user, - vlan_filtering); - if (err) - goto restore; + if (!ds->needs_standalone_vlan_offload) { + err = dsa_user_manage_vlan_filtering(dp->user, + vlan_filtering); + if (err) + goto restore; + } } return 0; @@ -1445,10 +1450,12 @@ int dsa_port_change_conduit(struct dsa_port *dp, struct net_device *conduit, /* The port might still be VLAN filtering even if it's no longer * under a bridge, either due to ds->vlan_filtering_is_global or - * ds->needs_standalone_vlan_filtering. In turn this means VLANs - * on the CPU port. + * ds->needs_standalone_vlan_filtering, and standalone ports of a + * ds->needs_standalone_vlan_offload switch keep their VLANs without + * filtering. In turn this means VLANs on the CPU port. */ - vlan_filtering = dsa_port_is_vlan_filtering(dp); + vlan_filtering = dsa_port_is_vlan_filtering(dp) || + (ds->needs_standalone_vlan_offload && !bridge_dev); if (vlan_filtering) { err = dsa_user_manage_vlan_filtering(dev, false); if (err) { diff --git a/net/dsa/user.c b/net/dsa/user.c index 03c7af6abe18..2b1695b386ef 100644 --- a/net/dsa/user.c +++ b/net/dsa/user.c @@ -1946,6 +1946,7 @@ static int dsa_user_clear_vlan(struct net_device *vdev, int vid, void *arg) * * - If standalone (this includes software bridge, software LAG): * - if ds->needs_standalone_vlan_filtering = true, OR if + * ds->needs_standalone_vlan_offload = true, OR if * (ds->vlan_filtering_is_global = true AND there are bridges spanning * this switch chip which have vlan_filtering=1) * - the 8021q upper VLANs @@ -2718,7 +2719,8 @@ void dsa_user_setup_tagger(struct net_device *user) user->hw_features |= NETIF_F_HW_TC; if (user->needed_tailroom) user->features &= ~(NETIF_F_SG | NETIF_F_FRAGLIST); - if (ds->needs_standalone_vlan_filtering) + if (ds->needs_standalone_vlan_filtering || + ds->needs_standalone_vlan_offload) user->features |= NETIF_F_HW_VLAN_CTAG_FILTER; user->lltx = true; ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-06 7:31 ` [PATCH net 1/2] net: dsa: let drivers offload " Semih Baskan @ 2026-08-06 11:15 ` Vladimir Oltean 2026-08-06 11:44 ` Semih Baskan 0 siblings, 1 reply; 19+ messages in thread From: Vladimir Oltean @ 2026-08-06 11:15 UTC (permalink / raw) To: Semih Baskan Cc: florian.fainelli, jonas.gorski, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel On Thu, Aug 06, 2026 at 10:31:18AM +0300, Semih Baskan wrote: > Some switches cannot deliver a tagged frame to the CPU while its VID is > absent from the VLAN table, not even with VLAN filtering turned off. > b53 is one of them: its VID lookup is always active, and disabling it > moves the ARL to shared VLAN learning, where ARL operations force VID 0 > and the hardware table drifts away from the bridge fdb. On such > hardware a standalone port can only receive the traffic of its 8021q > uppers if their VIDs are programmed into the table. Then their "vlan_filtering off" implementation is broken. BTW, how is the "standalone port" behaviour different than the vlan_filtering=0 bridge port case? If as you say, the switch must have the VID in the VLAN table to send the packet to the CPU, what is different when that port is under a VLAN-unaware bridge such that this presumably does work? > The existing opt-in for this class of problem, > ds->needs_standalone_vlan_filtering, delivers those VIDs but does more: > dsa_port_reset_vlan_filtering() also forces vlan_filtering=1 on a port > that leaves a VLAN-unaware bridge. hellcreek wants exactly that. b53 > must not have it, because it sets vlan_filtering_is_global, so the > forced flip would turn the whole switch into a VLAN filtering device > the first time any port leaves a VLAN-unaware bridge and change > behaviour for every other port. If there is a problem with the vlan_filtering_is_global + needs_standalone_vlan_filtering combination, then hellcreek also suffers from it, because it does set both flags as well. > Add ds->needs_standalone_vlan_offload for the narrower need. It > advertises NETIF_F_HW_VLAN_CTAG_FILTER on user ports, so the 8021q > layer reports upper VIDs to .port_vlan_add, and it leaves the > vlan_filtering state alone. > > Upper offload of such a switch never depends on vlan_filtering: every > VID was already delivered when the upper was created, since the > feature bit is always on. dsa_port_vlan_filtering() therefore skips > its ports entirely when a bridge toggles VLAN awareness. Restoring > them on the way up would add VIDs that were never cleared, and > clearing them on the way down would strip the driver's record of a > bridged port's uppers and the feature bit, leaving a port that later > leaves the bridge with uppers that cannot receive and no way to > re-offload them. The conduit change path keeps its explicit teardown > and restore of standalone VLANs, and now also runs it for a standalone > port of such a switch while VLAN filtering is off, because that port > has VLANs on the CPU port too. I don't really understand the rest of the explanation for the "narrower need", as it relies on the false fact that hellcreek is somehow not in the same boat. Why can't standalone ports tolerate the .port_vlan_filtering() call? ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-06 11:15 ` Vladimir Oltean @ 2026-08-06 11:44 ` Semih Baskan 2026-08-06 12:43 ` Vladimir Oltean 0 siblings, 1 reply; 19+ messages in thread From: Semih Baskan @ 2026-08-06 11:44 UTC (permalink / raw) To: Vladimir Oltean Cc: florian.fainelli, jonas.gorski, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel Hi Vladimir, > Then their "vlan_filtering off" implementation is broken. In the sense that the hardware cannot forward an arbitrary tagged frame transparently while the table is active, and the table cannot be deactivated without the ARL cost from the other subthread, yes. The flag exists so the driver can compensate for exactly that. > BTW, how is the "standalone port" behaviour different than the > vlan_filtering=0 bridge port case? If as you say, the switch must have > the VID in the VLAN table to send the packet to the CPU, what is > different when that port is under a VLAN-unaware bridge such that this > presumably does work? It is not different, and it does not work. A tagged frame whose VID is not in the table dies the same way when the port is under a VLAN-unaware bridge; this hardware cannot do transparent tagged bridging since the same v5.15 change. Jonas observed the same limitation earlier in this thread from the other direction: on the chips where standalone RX still works, forwarding tagged frames between ports does not. The reason the fix scopes to standalone ports is that they have a finite, well-defined VID source: the 8021q uppers, reported through the feature bit. A VLAN-unaware bridge has no such source; making it transparent would mean programming the whole VID space, which is the several-seconds-per-toggle variant Jonas measured and rejected in the first thread. So the series fixes the reported regression, the standalone PPPoE/upper case, and does not pretend to fix transparent tagged bridging, which this hardware has not done since v5.15 either. > If there is a problem with the vlan_filtering_is_global + > needs_standalone_vlan_filtering combination, then hellcreek also suffers > from it, because it does set both flags as well. You are right, and the commit message argues this badly; I will reword it if a v2 is wanted. vlan_filtering_is_global is not the differentiator, hellcreek sets it too. The difference is what the forced vlan_filtering=1 means for each driver. For hellcreek, switch-wide VLAN awareness is the intended operating state; its standalone traffic depends on filtering being on, and hellcreek.c documents that unmanaged setups are not supported. The forced flip lands it in the state it wants. For b53, vlan_filtering=1 is a different user-visible mode for every port on the switch: untagged frames become PVID-classified against the table, egress untagging applies, unknown VIDs are dropped at ingress. Forcing that globally because one port left a VLAN-unaware bridge would change the behaviour of every other port, including members of VLAN-unaware bridges that expect transparent operation. b53 needs the VIDs delivered while vlan_filtering stays wherever the user put it, which is the narrower flag. > Why can't standalone ports tolerate the .port_vlan_filtering() call? They do tolerate and still receive it: the ds->ops->port_vlan_filtering call is unchanged, b53 sees every toggle and rebuilds its hardware state from its own records. What the flag skips is only the core's dsa_user_manage_vlan_filtering(), whose two jobs are wrong for a switch whose feature bit is permanently on. On the way to vlan_filtering=1 it replays VIDs that were never cleared, so vlan_vid_add() refcounts every upper VID twice. On the way to 0 it clears the VIDs and drops NETIF_F_HW_VLAN_CTAG_FILTER on a port that happens to be bridged at toggle time; I measured that case on the RT-N18U: after the port later leaves the bridge, its uppers stay dead until reboot, because nothing re-offloads them once the feature bit is gone. With the skip, both effects are gone and the driver derives the hardware state from the flip itself. hellcreek does not set the new flag, so its path through dsa_user_manage_vlan_filtering() is unchanged. Best regards, Semih ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-06 11:44 ` Semih Baskan @ 2026-08-06 12:43 ` Vladimir Oltean 2026-08-06 13:39 ` Semih Baskan 0 siblings, 1 reply; 19+ messages in thread From: Vladimir Oltean @ 2026-08-06 12:43 UTC (permalink / raw) To: Semih Baskan Cc: florian.fainelli, jonas.gorski, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel On Thu, Aug 06, 2026 at 02:44:44PM +0300, Semih Baskan wrote: > Hi Vladimir, > > > Then their "vlan_filtering off" implementation is broken. > > In the sense that the hardware cannot forward an arbitrary tagged frame > transparently while the table is active, and the table cannot be > deactivated without the ARL cost from the other subthread, yes. The > flag exists so the driver can compensate for exactly that. But it doesn't, at least not in a sane way. If it still only accepts those VLANs that have been added to filters by higher layers, it's not VLAN-unaware. If a solution is not found to the problem, the driver must reject operation as VLAN-unaware. > > BTW, how is the "standalone port" behaviour different than the > > vlan_filtering=0 bridge port case? If as you say, the switch must have > > the VID in the VLAN table to send the packet to the CPU, what is > > different when that port is under a VLAN-unaware bridge such that this > > presumably does work? > > It is not different, and it does not work. A tagged frame whose VID is > not in the table dies the same way when the port is under a > VLAN-unaware bridge; this hardware cannot do transparent tagged > bridging since the same v5.15 change. Jonas observed the same > limitation earlier in this thread from the other direction: on the > chips where standalone RX still works, forwarding tagged frames > between ports does not. I fail to see how commit 06cfb2df7eb0 ("net: dsa: don't advertise 'rx-vlan-filter' when not needed") could have caused a regression in VLAN-unaware bridging on your b53 switch. Only perhaps if VLAN-unaware traffic worked by coincidence. If the switch drops packets with an unmapped arbitrary VID=1234, it would do so regardless of whether 'rx-vlan-filter' is advertised or not - unless VID=1234 is not arbitrary but was programmed somehow by higher layers. Which is *not* a requirement for VLAN-unaware bridging. > > The reason the fix scopes to standalone ports is that they have a > finite, well-defined VID source: the 8021q uppers, reported through > the feature bit. A VLAN-unaware bridge has no such source; making it > transparent would mean programming the whole VID space, which is the > several-seconds-per-toggle variant Jonas measured and rejected in the > first thread. So the series fixes the reported regression, the > standalone PPPoE/upper case, and does not pretend to fix transparent > tagged bridging, which this hardware has not done since v5.15 either. > > > If there is a problem with the vlan_filtering_is_global + > > needs_standalone_vlan_filtering combination, then hellcreek also suffers > > from it, because it does set both flags as well. > > You are right, and the commit message argues this badly; I will reword > it if a v2 is wanted. vlan_filtering_is_global is not the > differentiator, hellcreek sets it too. The difference is what the > forced vlan_filtering=1 means for each driver. For hellcreek, > switch-wide VLAN awareness is the intended operating state; its > standalone traffic depends on filtering being on, and hellcreek.c > documents that unmanaged setups are not supported. The forced flip > lands it in the state it wants. For b53, vlan_filtering=1 is a > different user-visible mode for every port on the switch: untagged > frames become PVID-classified against the table, egress untagging > applies, unknown VIDs are dropped at ingress. Forcing that globally > because one port left a VLAN-unaware bridge would change the behaviour > of every other port, including members of VLAN-unaware bridges that > expect transparent operation. ..which you just said earlier that they don't work either way?! > b53 needs the VIDs delivered while vlan_filtering stays wherever the > user put it, which is the narrower flag. Sorry, but I'm not able to make any sense of this explanation. The only distinction I'm seeing is that in hellcreek, VLAN-unaware mode works, and in your b53 model it doesn't. > > Why can't standalone ports tolerate the .port_vlan_filtering() call? > > They do tolerate and still receive it: the ds->ops->port_vlan_filtering > call is unchanged, b53 sees every toggle and rebuilds its hardware > state from its own records. Ok, my mistake. > What the flag skips is only the core's > dsa_user_manage_vlan_filtering(), whose two jobs are wrong for a > switch whose feature bit is permanently on. On the way to > vlan_filtering=1 it replays VIDs that were never cleared, so > vlan_vid_add() refcounts every upper VID twice. You are really explaining here what is needed for your hack to work, not why your hack is needed. You need to skip dsa_user_manage_vlan_filtering() because you want to keep VLAN filters you need while lying to higher layers that you don't need them. Just saying that you do need them and refusing to operate otherwise is much more straightforward. > On the way to 0 it > clears the VIDs and drops NETIF_F_HW_VLAN_CTAG_FILTER on a port that > happens to be bridged at toggle time; I measured that case on the > RT-N18U: after the port later leaves the bridge, its uppers stay dead > until reboot, because nothing re-offloads them once the feature bit is > gone. With vlan_filtering/NETIF_F_HW_VLAN_CTAG_FILTER set to 0, no one *has* to reoffload the VLAN filters, because the hardware shouldn't need them. Try the VID=1234 case with 2 veth interfaces in a software VLAN-unaware bridge. > With the skip, both effects are gone and the driver derives the > hardware state from the flip itself. hellcreek does not set the new > flag, so its path through dsa_user_manage_vlan_filtering() is > unchanged. > > Best regards, > Semih ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-06 12:43 ` Vladimir Oltean @ 2026-08-06 13:39 ` Semih Baskan 2026-08-10 12:08 ` Vladimir Oltean 0 siblings, 1 reply; 19+ messages in thread From: Semih Baskan @ 2026-08-06 13:39 UTC (permalink / raw) To: Vladimir Oltean Cc: florian.fainelli, jonas.gorski, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel Hi Vladimir, > But it doesn't, at least not in a sane way. If it still only accepts > those VLANs that have been added to filters by higher layers, it's not > VLAN-unaware. If a solution is not found to the problem, the driver must > reject operation as VLAN-unaware. You are right that the port is not VLAN-unaware. It cannot be: the VID lookup on this silicon cannot be turned off without the ARL loss from the other subthread. My mistake in the previous mail was arguing around that instead of saying it. Let me first correct a history error I made, because the accurate version actually simplifies the discussion. > I fail to see how commit 06cfb2df7eb0 ("net: dsa: don't advertise > 'rx-vlan-filter' when not needed") could have caused a regression in > VLAN-unaware bridging on your b53 switch. Correct, it could not, and my sentence attributing transparent bridging to the same change was wrong. b53 has had dev->vlan_enabled = true at switch allocation since before v5.15, and b53_vlan_filtering() has never turned the table off. So arbitrary-VID transparency was already impossible in v5.14, the last working kernel of the bug report. There was no coincidence and no bridging regression: what worked in v5.14 and stopped in v5.15 is exactly one pipeline, the standalone 8021q upper. In v5.14 the feature bit was advertised unconditionally, the VIDs were delivered, and .port_vlan_add programmed them into the always-on table. 06cfb2df7eb0 stopped the delivery and f089652b6b16 stopped the programming. The series restores that v5.14 pipeline for drivers that opt in, and nothing else. That is why the Fixes tag points where it points. > ..which you just said earlier that they don't work either way?! You are right, that sentence conflated two things. Forcing vlan_filtering=1 globally would not hurt tagged transparency, which is dead either way. What it changes is what works today: untagged forwarding becomes subject to bridge VLAN semantics the user never configured, the reported vlan_filtering state of every bridge on the switch flips under the user, and b53 switches its ingress mode to VC4_ING_VID_VIO_DROP plus VC5_DROP_VTABLE_MISS chip-wide. > The only distinction I'm seeing is that in hellcreek, VLAN-unaware mode > works, and in your b53 model it doesn't. Yes, and I think the three reasons you listed in 06cfb2df7eb0's commit message describe the difference better than my commit message did. hellcreek is case 3: its hardware can be VLAN-unaware, but standalone separation depends on unique VLANs, so its flag also forces the vlan_filtering state, and that forcing is correct there. b53 after v5.14 is case 1, "the standalone ports would otherwise drop VLAN-tagged traffic", with one difference: in case 1 the VLAN awareness that causes the dropping is held on by a VLAN-aware bridge elsewhere on the switch, while on b53 it is held on by the silicon itself, permanently. The new flag registers exactly that: a driver whose ports always satisfy case 1's condition, with no bridge required. It deliberately does not force the vlan_filtering state the way needs_standalone_vlan_filtering does, because that forcing solves hellcreek's separation problem, which b53 does not have. > You need to skip dsa_user_manage_vlan_filtering() because you want to > keep VLAN filters you need while lying to higher layers that you don't > need them. I would describe it as the opposite. 'rx-vlan-filter: on' is the true statement about this hardware: it filters, always, and cannot do otherwise. What lies to higher layers is the current mainline behaviour, which reports the port as not filtering and then drops every unsubscribed VID in silicon. The flag makes the feature bit match the silicon; the skip then only stops the core from toggling a bit that describes an invariant property. > With vlan_filtering/NETIF_F_HW_VLAN_CTAG_FILTER set to 0, no one *has* > to reoffload the VLAN filters, because the hardware shouldn't need them. Agreed, in the software model no one has to. The measurement was not an argument that the software model is wrong; it shows what breaks mechanically if the flag advertises the feature permanently but the core still clears it on toggles. It is internal consistency of this approach, not a requirement I claim the model imposes. Which leaves the real question, what to do with hardware like this. I see three options. 1. Reject VLAN-unaware operation, as you suggest. Honest, but on b53 it refuses the default configuration of every deployed OpenWrt board on this platform, where the LAN bridge is vlan_filtering=0. That turns a working untagged setup into a broken one on a kernel update. 2. Force VLAN awareness, the hellcreek way. No new core code, but it flips the reported vlan_filtering state under the user, changes untagged handling switch-wide, and enables the drop modes above on every port. Whether that cost is acceptable for this user base is really a question for Jonas and Florian. 3. This series: report the filtering that the silicon actually does, restore the v5.14 delivery pipeline behind an opt-in, and change nothing else. Untagged setups keep working unchanged, VLAN-unaware bridges keep their (already partial) behaviour unchanged, and the one regression users actually reported is fixed in a way that can go to stable. I implemented 3 because it is the only one where no deployed configuration changes behaviour. If the consensus is that 1 or 2 is the right model for b53 despite the fallout, I will help make and test that on the hardware I have, but I do not think it can be the net fix for the regression. Best regards, Semih ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-06 13:39 ` Semih Baskan @ 2026-08-10 12:08 ` Vladimir Oltean 2026-08-11 6:25 ` Semih Baskan 0 siblings, 1 reply; 19+ messages in thread From: Vladimir Oltean @ 2026-08-10 12:08 UTC (permalink / raw) To: Semih Baskan Cc: florian.fainelli, jonas.gorski, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel On Thu, Aug 06, 2026 at 04:39:00PM +0300, Semih Baskan wrote: > Hi Vladimir, > > > But it doesn't, at least not in a sane way. If it still only accepts > > those VLANs that have been added to filters by higher layers, it's not > > VLAN-unaware. If a solution is not found to the problem, the driver must > > reject operation as VLAN-unaware. > > You are right that the port is not VLAN-unaware. It cannot be: the VID > lookup on this silicon cannot be turned off without the ARL loss from > the other subthread. My mistake in the previous mail was arguing around > that instead of saying it. I understand from your discussion with Jonas that with the right IMP port selection, you do get frames copied to the CPU even despite the VLAN table miss. This is more in line with the expectations of higher layers. What about VLAN-unaware bridging? Can packets with VID=100 be forwarded autonomously between two ports of a vlan_filtering=0 bridge if that VLAN is not programmed to hardware? Does the behaviour depend on silicon capabilities, or is it the same for all switches handled by the b53 driver? ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-10 12:08 ` Vladimir Oltean @ 2026-08-11 6:25 ` Semih Baskan 2026-08-11 7:44 ` Jonas Gorski 0 siblings, 1 reply; 19+ messages in thread From: Semih Baskan @ 2026-08-11 6:25 UTC (permalink / raw) To: Vladimir Oltean Cc: florian.fainelli, jonas.gorski, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel Hi Vladimir, > What about VLAN-unaware bridging? Can packets with VID=100 be forwarded > autonomously between two ports of a vlan_filtering=0 bridge if that VLAN > is not programmed to hardware? No. On every b53 switch measured so far it cannot, and it fails in the same place on all of them. The frame passes ingress admission (with filtering off the driver programs VC4_NO_ING_VID_CHK and clears VC5_DROP_VTABLE_MISS, one shared code path for every chip), then the forwarding stage resolves the egress set from the VLAN table entry for that VID. A VID that is not programmed resolves to an empty member set, so there is nothing to forward to on any port. > Does the behaviour depend on silicon capabilities, or is it the same for > all switches handled by the b53 driver? The port-to-port part has been the same on everything measured. What depends on the silicon is only whether the CPU gets a copy of the miss frame. Three chips have data across these two threads: - BCM53011 (bcm5301x, my RT-N18U): measured for the CPU direction. Every ingress-check setting (NO_ING_VID_CHK, VIO_FWD, VIO_TO_IMP, plus clearing the VC0 miss-drop bit) delivers 0 of 7; the frame dies at member-set resolution, not at admission. Whether a miss frame reaches the CPU at all depends on the IMP routing from the other subthread: with port 8 as IMP it does (indiscriminately), with the in-tree port 5 topology it never does for LAN-class ports. - BCM63268 and BCM53115: Jonas measured exactly this case there. Standalone RX works even on a table miss, so the CPU copy exists, but forwarding between ports does not. That is the case you are asking about, on two other generations of this silicon. My own measurements were CPU-directed, so for bcm5301x the two-port case is inferred from the empty member set rather than measured directly. For your question the measured answer is Jonas's, and the mechanism says it generalizes. Best regards, Semih ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-11 6:25 ` Semih Baskan @ 2026-08-11 7:44 ` Jonas Gorski 2026-08-11 9:58 ` Vladimir Oltean 0 siblings, 1 reply; 19+ messages in thread From: Jonas Gorski @ 2026-08-11 7:44 UTC (permalink / raw) To: Semih Baskan Cc: Vladimir Oltean, florian.fainelli, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel On Tue, Aug 11, 2026 at 8:25 AM Semih Baskan <strst.gs@gmail.com> wrote: > > Hi Vladimir, > > > What about VLAN-unaware bridging? Can packets with VID=100 be forwarded > > autonomously between two ports of a vlan_filtering=0 bridge if that VLAN > > is not programmed to hardware? > > No. On every b53 switch measured so far it cannot, and it fails in the > same place on all of them. The frame passes ingress admission (with > filtering off the driver programs VC4_NO_ING_VID_CHK and clears > VC5_DROP_VTABLE_MISS, one shared code path for every chip), then the > forwarding stage resolves the egress set from the VLAN table entry for > that VID. A VID that is not programmed resolves to an empty member set, > so there is nothing to forward to on any port. > > > Does the behaviour depend on silicon capabilities, or is it the same for > > all switches handled by the b53 driver? VLAN-unaware bridging does work on BCM5325 and BCM5365. The driver was originally written for this family (before upstream submission). There is a register bit that controls what happens when a VLAN-tagged frame is received for which no (valid) VLAN table entry exists. Default is drop. On BCM5325/5365, setting this bit makes the switch *forward* the frame regardless. This is why it works on those switches even with VLAN-aware mode enabled in hardware. On later generations, the bit's function changed to "redirect to CPU". Stand-alone ports still work there, but VLAN-unaware bridging does not. Everything goes to CPU, and the tag driver marks it erroneously as offloaded. But I didn't notice this until recently. Partially also because there is no kernel test for VLAN tagged forwarding on a vlan-unaware bridge, only for standalone ports. Everything saying OK with a vlan-unaware bridge made me think everything works as expected. > The port-to-port part has been the same on everything measured. What > depends on the silicon is only whether the CPU gets a copy of the miss > frame. Three chips have data across these two threads: > > - BCM53011 (bcm5301x, my RT-N18U): measured for the CPU direction. > Every ingress-check setting (NO_ING_VID_CHK, VIO_FWD, VIO_TO_IMP, > plus clearing the VC0 miss-drop bit) delivers 0 of 7; the frame dies > at member-set resolution, not at admission. Whether a miss frame > reaches the CPU at all depends on the IMP routing from the other > subthread: with port 8 as IMP it does (indiscriminately), with the > in-tree port 5 topology it never does for LAN-class ports. Only port 5 is an invalid configuration, so no wonder it breaks. The only valid configurations are port 8 or port 8 + 5, but not port 5 only. > - BCM63268 and BCM53115: Jonas measured exactly this case there. > Standalone RX works even on a table miss, so the CPU copy exists, > but forwarding between ports does not. That is the case you are > asking about, on two other generations of this silicon. Note that BCM53115 also supports a dual IMP / CPU setup, and has the same limitations, so this isn't something new to BCM5301x. The only difference is that on BCM5301x the switch is embedded and has ports 5 and 8 (and 7) hardwired to internal MACs, which led to the incorrect usage of (only) port 5 as CPU. Best Regards, Jonas ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-11 7:44 ` Jonas Gorski @ 2026-08-11 9:58 ` Vladimir Oltean 2026-08-11 13:19 ` Semih Baskan 2026-08-12 7:14 ` Jonas Gorski 0 siblings, 2 replies; 19+ messages in thread From: Vladimir Oltean @ 2026-08-11 9:58 UTC (permalink / raw) To: Jonas Gorski Cc: Semih Baskan, florian.fainelli, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel On Tue, Aug 11, 2026 at 09:44:37AM +0200, Jonas Gorski wrote: > VLAN-unaware bridging does work on BCM5325 and BCM5365. The driver was > originally written for this family (before upstream submission). > > There is a register bit that controls what happens when a VLAN-tagged > frame is received for which no (valid) VLAN table entry exists. > Default is drop. > > On BCM5325/5365, setting this bit makes the switch *forward* the frame > regardless. This is why it works on those switches even with > VLAN-aware mode enabled in hardware. > > On later generations, the bit's function changed to "redirect to CPU". > Stand-alone ports still work there, but VLAN-unaware bridging does > not. Everything goes to CPU, and the tag driver marks it erroneously > as offloaded. You need to be more specific, because I don't have a good grasp of the various vc0/vc1/vc4/vc5 bits and specifically how they interact. I *think* you are talking about bit VC5_DROP_VTABLE_MISS having different behaviours when clear, because that's the only reasonable interpretation of the code consistent with your explanation. Are we sure there is no other bit which influences "if we don't drop VTABLE misses, then what?"? Then I suppose the VC4_ING_VID_CHECK_MASK affects only what happens with VLAN membership violations (i.e. VTABLE hit, but port not in VLAN). Thus it does not influence the VC5_DROP_VTABLE_MISS=false case, correct? If customizing/unifying the behaviour on VTABLE misses is a dead end, could we consider an alternative? Some switches support having the VTABLE enabled, but ignore the 802.1Q header from incoming packets (thus, all packets get classified to the port PVID). Is there any bit which achieves this in b53? What do VC0_VID_CHK_EN and VC0_VLAN_EN do exactly? Does B53_VLAN_CTRL2 maybe have some useful hidden bits? > But I didn't notice this until recently. Partially also because there > is no kernel test for VLAN tagged forwarding on a vlan-unaware bridge, > only for standalone ports. Everything saying OK with a vlan-unaware > bridge made me think everything works as expected. Good point. tools/testing/selftests/net/forwarding/bridge_vlan_unaware.sh should definitely have a test for this condition. > > The port-to-port part has been the same on everything measured. What > > depends on the silicon is only whether the CPU gets a copy of the miss > > frame. Three chips have data across these two threads: > > > > - BCM53011 (bcm5301x, my RT-N18U): measured for the CPU direction. > > Every ingress-check setting (NO_ING_VID_CHK, VIO_FWD, VIO_TO_IMP, > > plus clearing the VC0 miss-drop bit) delivers 0 of 7; the frame dies > > at member-set resolution, not at admission. Whether a miss frame > > reaches the CPU at all depends on the IMP routing from the other > > subthread: with port 8 as IMP it does (indiscriminately), with the > > in-tree port 5 topology it never does for LAN-class ports. > > Only port 5 is an invalid configuration, so no wonder it breaks. The > only valid configurations are port 8 or port 8 + 5, but not port 5 > only. > > > - BCM63268 and BCM53115: Jonas measured exactly this case there. > > Standalone RX works even on a table miss, so the CPU copy exists, > > but forwarding between ports does not. That is the case you are > > asking about, on two other generations of this silicon. > > Note that BCM53115 also supports a dual IMP / CPU setup, and has the > same limitations, so this isn't something new to BCM5301x. The only > difference is that on BCM5301x the switch is embedded and has ports 5 > and 8 (and 7) hardwired to internal MACs, which led to the incorrect > usage of (only) port 5 as CPU. How badly broken are the configurations with only port 5 as CPU port? Is other management traffic like STP also not delivered correctly? ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-11 9:58 ` Vladimir Oltean @ 2026-08-11 13:19 ` Semih Baskan 2026-08-12 7:24 ` Jonas Gorski 2026-08-12 7:14 ` Jonas Gorski 1 sibling, 1 reply; 19+ messages in thread From: Semih Baskan @ 2026-08-11 13:19 UTC (permalink / raw) To: Vladimir Oltean Cc: Jonas Gorski, florian.fainelli, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel Hi Vladimir, > Then I suppose the VC4_ING_VID_CHECK_MASK affects only what happens with > VLAN membership violations (i.e. VTABLE hit, but port not in VLAN). Thus > it does not influence the VC5_DROP_VTABLE_MISS=false case, correct? Correct, at least on bcm5301x, and this part is measured rather than read from documentation: with VC5_DROP_VTABLE_MISS clear, all three VC4_ING_VID_CHECK settings behave identically for a VTABLE miss (0 of 7 delivered in every combination, standalone RX probes from the measurements behind the cover letter). Whatever the check field controls happens independently of the miss path. One observation for the "is there another bit" question: on my BCM53011 the running value of VLAN_CTRL5 is 0x10. That is bit 4, which the driver never writes and has no name for. I do not know what it does, and it may simply be the bootloader default, but it is a bit in exactly the register you are asking about. > If customizing/unifying the behaviour on VTABLE misses is a dead end, > could we consider an alternative? Some switches support having the > VTABLE enabled, but ignore the 802.1Q header from incoming packets > (thus, all packets get classified to the port PVID). Is there any bit > which achieves this in b53? What do VC0_VID_CHK_EN and VC0_VLAN_EN do > exactly? Does B53_VLAN_CTRL2 maybe have some useful hidden bits? I cannot answer what the bits mean from documentation, but I can answer what they do on bcm5301x, measured just now with two external endpoints on two front ports of a vlan_filtering=0 bridge: neither of the two candidate bits gives that mode. With VC0_VID_CHK_EN cleared, and then with VC0_VID_HASH_VID cleared as well, tagged VID 100 frames still deliver 0 of 7 to the far port and 0 to the CPU, exactly as at the 0xe3 default, while untagged traffic keeps working in every state and the default restores cleanly. So on this chip the 802.1Q header keeps participating in classification as long as VC0_VLAN_EN is set, and clearing those two bits under it does not change that. Clearing VC0_VLAN_EN itself is the earlier thread: it works but costs the VID-keyed ARL. I have not probed VLAN_CTRL2 for undocumented bits; on my chip it reads 0x10. > How badly broken are the configurations with only port 5 as CPU port? > Is other management traffic like STP also not delivered correctly? It splits by the port's management class, measured on the RT-N18U earlier in the thread. BPDUs ingressing switch port 0 reach the CPU, because port 0 is WAN class and its traps go to IMP1, which is port 5. Management traps from the LAN class ports 1-4 go to IMP0, which is port 8, and are lost, because GMNGCFG has no "IMP1 only" encoding: the driver's OR of the field mask programs dual IMP mode and port 8 is down. So on the in-tree topology STP is broken on the four LAN ports and working on the one WAN port. Best regards, Semih ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-11 13:19 ` Semih Baskan @ 2026-08-12 7:24 ` Jonas Gorski 2026-08-12 9:21 ` Semih Baskan 0 siblings, 1 reply; 19+ messages in thread From: Jonas Gorski @ 2026-08-12 7:24 UTC (permalink / raw) To: Semih Baskan Cc: Vladimir Oltean, florian.fainelli, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel On Tue, Aug 11, 2026 at 3:19 PM Semih Baskan <strst.gs@gmail.com> wrote: > > Hi Vladimir, > > > Then I suppose the VC4_ING_VID_CHECK_MASK affects only what happens with > > VLAN membership violations (i.e. VTABLE hit, but port not in VLAN). Thus > > it does not influence the VC5_DROP_VTABLE_MISS=false case, correct? > > Correct, at least on bcm5301x, and this part is measured rather than > read from documentation: with VC5_DROP_VTABLE_MISS clear, all three > VC4_ING_VID_CHECK settings behave identically for a VTABLE miss (0 of > 7 delivered in every combination, standalone RX probes from the > measurements behind the cover letter). Whatever the check field > controls happens independently of the miss path. > > One observation for the "is there another bit" question: on my > BCM53011 the running value of VLAN_CTRL5 is 0x10. That is bit 4, which > the driver never writes and has no name for. I do not know what it > does, and it may simply be the bootloader default, but it is a bit in > exactly the register you are asking about. Assuming you mean VLAN_CTRL2, this bit is described for BCM5325 as "When set to 1, GMRP,GVRP are checked by the VLAN's forward map" with a default of 0. Since other bits (sort of) match with their meanings, one could assume it retained it, and now defaults to 1, but there is no guarantee for that. > > > If customizing/unifying the behaviour on VTABLE misses is a dead end, > > could we consider an alternative? Some switches support having the > > VTABLE enabled, but ignore the 802.1Q header from incoming packets > > (thus, all packets get classified to the port PVID). Is there any bit > > which achieves this in b53? What do VC0_VID_CHK_EN and VC0_VLAN_EN do > > exactly? Does B53_VLAN_CTRL2 maybe have some useful hidden bits? > > I cannot answer what the bits mean from documentation, but I can answer > what they do on bcm5301x, measured just now with two external endpoints > on two front ports of a vlan_filtering=0 bridge: neither of the two > candidate bits gives that mode. With VC0_VID_CHK_EN cleared, and then > with VC0_VID_HASH_VID cleared as well, tagged VID 100 frames still > deliver 0 of 7 to the far port and 0 to the CPU, exactly as at the > 0xe3 default, while untagged traffic keeps working in every state and > the default restores cleanly. So on this chip the 802.1Q header keeps > participating in classification as long as VC0_VLAN_EN is set, and > clearing those two bits under it does not change that. Clearing > VC0_VLAN_EN itself is > the earlier thread: it works but costs the VID-keyed ARL. I have not > probed VLAN_CTRL2 for undocumented bits; on my chip it reads 0x10. > > > How badly broken are the configurations with only port 5 as CPU port? > > Is other management traffic like STP also not delivered correctly? > > It splits by the port's management class, measured on the RT-N18U > earlier in the thread. BPDUs ingressing switch port 0 reach the CPU, > because port 0 is WAN class and its traps go to IMP1, which is port 5. > Management traps from the LAN class ports 1-4 go to IMP0, which is > port 8, and are lost, because GMNGCFG has no "IMP1 only" encoding: the > driver's OR of the field mask programs dual IMP mode and port 8 is > down. So on the in-tree topology STP is broken on the four LAN ports > and working on the one WAN port. One thing you could try is to mark all ports as WAN ports. The WAN_PORT_SEL register (page 0, offset 0x26, 16 bit) has a bitmask for wan ports. It may allow delivery to IMP1, but the description of the WAN port feature is also "Select a port as a WAN port, then all that port’s traffic is forwarded to the CPU port only. The non- WAN port traffic from all other local ports does not flood to the WAN port." So it may also isolate them from each other. Also out of curiosity, can you wan port talk with non-wan talks in a bridge? Because the description implies it should not. Best regards, Jonas ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-12 7:24 ` Jonas Gorski @ 2026-08-12 9:21 ` Semih Baskan 2026-08-12 9:52 ` Jonas Gorski 0 siblings, 1 reply; 19+ messages in thread From: Semih Baskan @ 2026-08-12 9:21 UTC (permalink / raw) To: Jonas Gorski Cc: Vladimir Oltean, florian.fainelli, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel Hi Jonas, On Wed, Aug 12, 2026 at 10:24 AM Jonas Gorski <jonas.gorski@gmail.com> wrote: > > One observation for the "is there another bit" question: on my > > BCM53011 the running value of VLAN_CTRL5 is 0x10. That is bit 4, which > > the driver never writes and has no name for. I do not know what it > > does, and it may simply be the bootloader default, but it is a bit in > > exactly the register you are asking about. > > Assuming you mean VLAN_CTRL2, this bit is described for BCM5325 as > "When set to 1, GMRP,GVRP are checked by the > VLAN's forward map" with a default of 0. I did mean VLAN_CTRL5; both registers happen to read 0x10 here. Broadcom's published MDK definitions for BCM53010 [1] name both bits: VLAN_CTRL5 bit 4 is EGRESS_DIR_FRM_BYPASS_TRUNK_EN, a bypass for trunking redirection of egress directed frames, unrelated to the miss path. The same file gives DROP_VTABLE_MISS the exact text you quoted for the newer chips (drop when set, forward to IMP when clear), and no other option. For VLAN_CTRL2, bit 4 is documented as reserved on this chip; the GMRP/GVRP forward map check you quote from BCM5325 moved to bit 5 (EN_GMRP_GVRP_V_FWDMAP), which reads 0 here. So the set bit is a reserved default, not the retained BCM5325 function. The remaining VLAN_CTRL2 fields are GMRP/GVRP untag handling and a v_fwdmap bypass for the management port, so nothing in it changes ingress classification. The same file also names what b53 calls VC0_VID_CHK_EN and VC0_VID_HASH_VID: one two bit field, VLAN_LEARN_MODE (00 SVL, 11 IVL, 01 and 10 illegal settings). It selects how the ARL is hashed, not how ingress frames are classified, which explains why clearing those bits changed nothing in my measurement. (My intermediate test state cleared only bit 6, which per this description is an illegal encoding; the legal all clear SVL state behaved identically, so the conclusion stands.) And the VID to PVID rewrite bits in VLAN_CTRL0 are documented to act only on frames with VID 0, so on this chip they cannot reclassify real tagged traffic; that rules out the last candidate for a tag-blind mode here. > One thing you could try is to mark all ports as WAN ports. The > WAN_PORT_SEL register (page 0, offset 0x26, 16 bit) has a bitmask for > wan ports. I tried it today, and first read the register as is: WAN_PORT_SEL reads 0x0000 on my BCM53011, three consistent reads. The kernel driver never writes it on this generation (it uses offset 0x26 only on BCM5325, as the protected port register there), so it has been 0x0000 through every measurement I have reported in this thread. My earlier statement that BPDUs ingressing switch port 0 reach the CPU was a counter attribution error. That probe read a +7 delta on the wan netdev counter with no capture running (that image had no tcpdump), while the BPDU source was a live bridge port on another router, a device that also chatters IPv6 multicast. Today, with captures bracketing every counter, BPDU class frames are delivered on none of the ports I probed: crafted ones on lan2, on lan3 bridged and standalone, and on port 0, plus real kernel STP hellos on port 0 itself, all zero, while the same frames with a benign multicast destination deliver 10 of 10 to the CPU on every port tried. So there is no WAN/LAN asymmetry and no special port 0: with WAN_SELECT empty, everything trap classed aims at IMP0 exactly as the GMNGCFG text says, and IMP0 is down. Your description of the port-5-only breakage was right, and it is worse than I previously reported: STP delivery is dead on the WAN port too, not just the LAN ports. Then the experiment you suggested, on the live system, volatile write with a timed revert armed: WAN_PORT_SEL set to 0x000c, marking the two ports that had my test endpoints (lan2/port 2, lan3/port 3), leaving the management port alone. - No trap rescue appears: BPDUs into a WAN-marked port still deliver nothing, so the marking does not retarget the trap path at IMP1 on this topology. - Isolation is exactly as the description implies: unicast between the two WAN-marked ports through the same vlan-unaware bridge went from 7/7 to 0/7, and even plain multicast to CPU delivery on the marked ports went from 10/10 to zero, consistent with "forwarded to the CPU port only" resolving to the dead IMP0 here. - My management connection through a port I had not marked also dropped, and came back only when the timed revert fired. The effect is broader than the marked ports. > So it may also isolate them from each other. Also out of curiosity, > can you wan port talk with non-wan talks in a bridge? Because the > description implies it should not. The pair I could measure says no: the two WAN-marked ports in the same bridge stopped talking to each other entirely, and on this port 5 topology they stopped talking to the CPU too. The BCM53010 text also says port 5 can be selected as a WAN port only when IMP1 is disabled, so the CPU port itself cannot be WAN marked on a topology like mine. [1] https://github.com/Broadcom/OpenMDK/blob/master/cdk/PKG/chip/bcm53010/bcm53010_a0_defs.h Best regards, Semih ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-12 9:21 ` Semih Baskan @ 2026-08-12 9:52 ` Jonas Gorski 2026-08-12 10:21 ` Semih Baskan 0 siblings, 1 reply; 19+ messages in thread From: Jonas Gorski @ 2026-08-12 9:52 UTC (permalink / raw) To: Semih Baskan Cc: Vladimir Oltean, florian.fainelli, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel On Wed, Aug 12, 2026 at 11:21 AM Semih Baskan <strst.gs@gmail.com> wrote: > > Hi Jonas, > > On Wed, Aug 12, 2026 at 10:24 AM Jonas Gorski <jonas.gorski@gmail.com> wrote: > > > One observation for the "is there another bit" question: on my > > > BCM53011 the running value of VLAN_CTRL5 is 0x10. That is bit 4, which > > > the driver never writes and has no name for. I do not know what it > > > does, and it may simply be the bootloader default, but it is a bit in > > > exactly the register you are asking about. > > > > Assuming you mean VLAN_CTRL2, this bit is described for BCM5325 as > > "When set to 1, GMRP,GVRP are checked by the > > VLAN's forward map" with a default of 0. > > I did mean VLAN_CTRL5; both registers happen to read 0x10 here. > Broadcom's published MDK definitions for BCM53010 [1] name both bits: > > VLAN_CTRL5 bit 4 is EGRESS_DIR_FRM_BYPASS_TRUNK_EN, a bypass for > trunking redirection of egress directed frames, unrelated to the miss > path. The same file gives DROP_VTABLE_MISS the exact text you quoted > for the newer chips (drop when set, forward to IMP when clear), and no > other option. > > For VLAN_CTRL2, bit 4 is documented as reserved on this chip; the > GMRP/GVRP forward map check you quote from BCM5325 moved to bit 5 > (EN_GMRP_GVRP_V_FWDMAP), which reads 0 here. So the set bit is a > reserved default, not the retained BCM5325 function. The remaining > VLAN_CTRL2 fields are GMRP/GVRP untag handling and a v_fwdmap bypass > for the management port, so nothing in it changes ingress > classification. I copied the wrong line, bit 4 on BCM5325 is en_GMRP_GVRP_v_tagging / "When set to 1, GMRP,GVRP frames are tagged according to VLAN rule". Bit 5 is also the fwd map (I guess somewhere I did a 0-index / 1-index swap in my head), so no changes there. > The same file also names what b53 calls VC0_VID_CHK_EN and > VC0_VID_HASH_VID: one two bit field, VLAN_LEARN_MODE (00 SVL, 11 IVL, > 01 and 10 illegal settings). It selects how the ARL is hashed, not > how ingress frames are classified, which explains why clearing those > bits changed nothing in my measurement. (My intermediate test state > cleared only bit 6, which per this description is an illegal encoding; > the legal all clear SVL state behaved identically, so the conclusion > stands.) And the VID to PVID rewrite bits in VLAN_CTRL0 are documented > to act only on frames with VID 0, so on this chip they cannot reclassify > real tagged traffic; that rules out the last candidate for a tag-blind > mode here. I think the register description might be wrong here, because changing the VID to PVID for untagged packets is the default / expected behavior. The datasheet for switches I do have say it replaces it if the VID is not 0: "1= • For a single-tag frame with VID not = 0, change the VID to PVID. • For a double-tag frame with outer VID not = 0, change outer VID to PVID. 0 = No change for 1Q/ISP tag if VID is not 0." > > One thing you could try is to mark all ports as WAN ports. The > > WAN_PORT_SEL register (page 0, offset 0x26, 16 bit) has a bitmask for > > wan ports. > > I tried it today, and first read the register as is: WAN_PORT_SEL > reads 0x0000 on my BCM53011, three consistent reads. The kernel > driver never writes it on this generation (it uses offset 0x26 only > on BCM5325, as the protected port register there), so it has been > 0x0000 through every measurement I have reported in this thread. > > My earlier statement that BPDUs ingressing switch port 0 reach the CPU > was a counter attribution error. That probe read a +7 delta on the wan > netdev counter with no capture running (that image had no tcpdump), > while the BPDU source was a live bridge port on another router, a device > that also chatters IPv6 multicast. Today, with captures bracketing every > counter, BPDU class frames are delivered on none of the ports I probed: > crafted ones on lan2, on lan3 bridged and standalone, and on port 0, > plus real kernel STP hellos on port 0 itself, all zero, while the same > frames with a benign multicast destination deliver 10 of 10 to the CPU > on every port tried. So there is no WAN/LAN asymmetry and no special > port 0: with WAN_SELECT empty, everything trap classed aims at IMP0 > exactly as the GMNGCFG text says, and IMP0 is down. Your description of > the port-5-only breakage was right, and it is worse than I previously > reported: STP delivery is dead on the WAN port too, not just the LAN > ports. > > Then the experiment you suggested, on the live system, volatile write > with a timed revert armed: WAN_PORT_SEL set to 0x000c, marking the > two ports that had my test endpoints (lan2/port 2, lan3/port 3), > leaving the management port alone. > > - No trap rescue appears: BPDUs into a WAN-marked port still deliver > nothing, so the marking does not retarget the trap path at IMP1 on > this topology. > - Isolation is exactly as the description implies: unicast between > the two WAN-marked ports through the same vlan-unaware bridge went > from 7/7 to 0/7, and even plain multicast to CPU delivery on the > marked ports went from 10/10 to zero, consistent with "forwarded to > the CPU port only" resolving to the dead IMP0 here. > - My management connection through a port I had not marked also > dropped, and came back only when the timed revert fired. The > effect is broader than the marked ports. > > > So it may also isolate them from each other. Also out of curiosity, > > can you wan port talk with non-wan talks in a bridge? Because the > > description implies it should not. > > The pair I could measure says no: the two WAN-marked ports in the same > bridge stopped talking to each other entirely, and on this port 5 > topology they stopped talking to the CPU too. The BCM53010 text also > says port 5 can be selected as a WAN port only when IMP1 is disabled, so > the CPU port itself cannot be WAN marked on a topology like mine. The description of GLOBAL_CONFIG / GC_FRM_MGMT_PORT_M says that "11=Enable Dual-IMP ports(both IMP0 and IMP1) All traffic to CPU from LAN ports will be forwarded to IMP0; and All traffic from WAN ports will be forwarded to IMP1." so I had the faint hope that making all ports WAN ports makes it trap to IMP1/5 instead of IMP0/8. But if it doesn't, and additionally isolates them, then this obviously won't work, and enabling port 8 as CPU port really is the only option. Thank you for the quick confirmation. Best regards, Jonas ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-12 9:52 ` Jonas Gorski @ 2026-08-12 10:21 ` Semih Baskan 0 siblings, 0 replies; 19+ messages in thread From: Semih Baskan @ 2026-08-12 10:21 UTC (permalink / raw) To: Jonas Gorski Cc: Vladimir Oltean, florian.fainelli, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel Hi Jonas, On Wed, Aug 12, 2026 at 12:52 PM Jonas Gorski <jonas.gorski@gmail.com> wrote: > I think the register description might be wrong here, because changing > the VID to PVID for untagged packets is the default / expected > behavior. > > The datasheet for switches I do have say it replaces it if the VID is not 0: You are right, and the MDK text is wrong for this chip too. Measured just now on the BCM53011, volatile write with a timed revert: with CHANGE_1Q_VID set, tagged broadcast frames carrying a VID absent from the VLAN table, which deliver 0 of 10 across a vlan-unaware bridge with the bit clear, arrive 10 of 10 at the far port. They arrive untagged: the VID is rewritten to the PVID, the frame is classified into that VLAN, and the egress untag map strips the header. Clearing the bit returns delivery to 0 of 10, and the untagged control ran 10 of 10 in every phase. So the bit is a real ingress reclassifier with your datasheet's semantics. The original VID does not survive to the wire, so it cannot serve the 8021q upper case, as you presumed earlier. Best regards, Semih ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports 2026-08-11 9:58 ` Vladimir Oltean 2026-08-11 13:19 ` Semih Baskan @ 2026-08-12 7:14 ` Jonas Gorski 1 sibling, 0 replies; 19+ messages in thread From: Jonas Gorski @ 2026-08-12 7:14 UTC (permalink / raw) To: Vladimir Oltean Cc: Semih Baskan, florian.fainelli, andrew, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel On Tue, Aug 11, 2026 at 11:58 AM Vladimir Oltean <olteanv@gmail.com> wrote: > > On Tue, Aug 11, 2026 at 09:44:37AM +0200, Jonas Gorski wrote: > > VLAN-unaware bridging does work on BCM5325 and BCM5365. The driver was > > originally written for this family (before upstream submission). > > > > There is a register bit that controls what happens when a VLAN-tagged > > frame is received for which no (valid) VLAN table entry exists. > > Default is drop. > > > > On BCM5325/5365, setting this bit makes the switch *forward* the frame > > regardless. This is why it works on those switches even with > > VLAN-aware mode enabled in hardware. > > > > On later generations, the bit's function changed to "redirect to CPU". > > Stand-alone ports still work there, but VLAN-unaware bridging does > > not. Everything goes to CPU, and the tag driver marks it erroneously > > as offloaded. > > You need to be more specific, because I don't have a good grasp of the > various vc0/vc1/vc4/vc5 bits and specifically how they interact. I don't know that in detail either, and have to find some of this out by experimenting. > > I *think* you are talking about bit VC5_DROP_VTABLE_MISS having > different behaviours when clear, because that's the only reasonable > interpretation of the code consistent with your explanation. Are we sure > there is no other bit which influences "if we don't drop VTABLE misses, > then what?"? If there is, I haven't found it. The register description sounds like there isn't: On BCM5325/65, this bit is described as "This bit applies to ingress frames tagged with a VID not found in the VLAN table. If the DA is not found in the ARL table, this bit controls the what happens to the frame. 0 = Ingress frame with VLAN table miss is flooded to all ports. 1 = Ingress frame with VLAN table miss is dropped." On newer chips, this bit is described as "Frames with an invalid VID do not have a corresponding entry in the VLAN table. 1 = Ingress frames with invalid VID are dropped. 0 = Ingress frames with invalid VID are forwarded to the IMP port." > Then I suppose the VC4_ING_VID_CHECK_MASK affects only what happens with > VLAN membership violations (i.e. VTABLE hit, but port not in VLAN). Thus > it does not influence the VC5_DROP_VTABLE_MISS=false case, correct? Right. that's correct. > > If customizing/unifying the behaviour on VTABLE misses is a dead end, > could we consider an alternative? Some switches support having the > VTABLE enabled, but ignore the 802.1Q header from incoming packets > (thus, all packets get classified to the port PVID). Is there any bit > which achieves this in b53? What do VC0_VID_CHK_EN and VC0_VLAN_EN do > exactly? Does B53_VLAN_CTRL2 maybe have some useful hidden bits? Not to my knowledge. There is a bit to enable replacing the VID in VLAN tagged packets with the PVID (in VLAN Control 0), but presumably this would also rewrite the header. > > > But I didn't notice this until recently. Partially also because there > > is no kernel test for VLAN tagged forwarding on a vlan-unaware bridge, > > only for standalone ports. Everything saying OK with a vlan-unaware > > bridge made me think everything works as expected. > > Good point. tools/testing/selftests/net/forwarding/bridge_vlan_unaware.sh > should definitely have a test for this condition. > > > > The port-to-port part has been the same on everything measured. What > > > depends on the silicon is only whether the CPU gets a copy of the miss > > > frame. Three chips have data across these two threads: > > > > > > - BCM53011 (bcm5301x, my RT-N18U): measured for the CPU direction. > > > Every ingress-check setting (NO_ING_VID_CHK, VIO_FWD, VIO_TO_IMP, > > > plus clearing the VC0 miss-drop bit) delivers 0 of 7; the frame dies > > > at member-set resolution, not at admission. Whether a miss frame > > > reaches the CPU at all depends on the IMP routing from the other > > > subthread: with port 8 as IMP it does (indiscriminately), with the > > > in-tree port 5 topology it never does for LAN-class ports. > > > > Only port 5 is an invalid configuration, so no wonder it breaks. The > > only valid configurations are port 8 or port 8 + 5, but not port 5 > > only. > > > > > - BCM63268 and BCM53115: Jonas measured exactly this case there. > > > Standalone RX works even on a table miss, so the CPU copy exists, > > > but forwarding between ports does not. That is the case you are > > > asking about, on two other generations of this silicon. > > > > Note that BCM53115 also supports a dual IMP / CPU setup, and has the > > same limitations, so this isn't something new to BCM5301x. The only > > difference is that on BCM5301x the switch is embedded and has ports 5 > > and 8 (and 7) hardwired to internal MACs, which led to the incorrect > > usage of (only) port 5 as CPU. > > How badly broken are the configurations with only port 5 as CPU port? > Is other management traffic like STP also not delivered correctly? Yes. Anything that is supposed to be forwarded to IMP only is sent out via the main IMP / port 8, and since port 8 is disabled, it is just dropped. This presumably applies to all local multicast traffic. Anything that is flooded is fine, since the floodmasks have port 5 set. Best regards, Jonas ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH net 2/2] net: dsa: b53: offload 8021q uppers on standalone ports 2026-08-06 7:31 [PATCH net 0/2] net: dsa: b53: fix 8021q uppers on standalone ports Semih Baskan 2026-08-06 7:31 ` [PATCH net 1/2] net: dsa: let drivers offload " Semih Baskan @ 2026-08-06 7:31 ` Semih Baskan 2026-08-06 8:39 ` [PATCH net 0/2] net: dsa: b53: fix " Jonas Gorski 2 siblings, 0 replies; 19+ messages in thread From: Semih Baskan @ 2026-08-06 7:31 UTC (permalink / raw) To: florian.fainelli, jonas.gorski, andrew, olteanv, davem, edumazet, kuba, pabeni Cc: vladimir.oltean, horms, netdev, linux-kernel b53 keeps the hardware VID lookup enabled at all times: b53_switch_alloc() sets dev->vlan_enabled and nothing ever clears it. A VID that is absent from the VLAN table resolves to an empty member set, so a tagged frame carrying it is discarded instead of reaching the CPU. Disabling the lookup is not an option either, because that moves the ARL to shared VLAN learning, where ARL operations force VID 0 and the hardware table drifts away from the bridge fdb. Commit 06cfb2df7eb0 ("net: dsa: don't advertise 'rx-vlan-filter' when not needed") stopped advertising NETIF_F_HW_VLAN_CTAG_FILTER on ports that do not offload a VLAN-aware bridge, so creating an 8021q upper on a standalone port no longer reaches .ndo_vlan_rx_add_vid and the VID is never offloaded. Commit f089652b6b16 ("net: dsa: b53: do not program vlans when vlan filtering is off") then made .port_vlan_add skip the hardware write while dev->vlan_filtering is false, which it is for a standalone port. Together they leave standalone ports unable to receive their own tagged traffic. This breaks a common configuration, a VLAN-tagged WAN for a PPPoE ISP. The PADI leaves the port correctly tagged, the concentrator answers, and the switch discards the tagged PADO, so the session never establishes. Reported on an Asus RT-N18U in 2023 and still reproducible. Take the new needs_standalone_vlan_offload opt-in so DSA reports upper VIDs again, and program VLAN entries that carry a standalone port even while not filtering. Only the standalone members and the CPU port are written to such an entry. A VID used by both an 8021q upper and a bridge VLAN therefore does not gain the bridged ports as members, so bridge VLANs keep having no effect while filtering is off, which is what Documentation/networking/switchdev.rst requires and what that commit implements. The PVID register writes stay gated on vlan_filtering for the same reason. b53_configure_vlan() used to restore entries only while filtering, so restore the standalone ones there as well, otherwise the next b53_apply_config() wipes them. Bridge join and leave rewrite the entries of the moved port, because its standalone state is part of the masking decision: joining removes the port from its uppers' entries, and leaving adds it back, including uppers that were created while the port was still bridged. When the last standalone member leaves a VID, the entry is written back empty, so deleting an upper or bridging its port returns the hardware to the state it had before the upper existed. Creating an upper whose VID the hardware cannot serve now fails loudly instead of producing an interface that cannot receive: b53_vlan_prepare() rejects VIDs beyond the VLAN table size on BCM5325/BCM5365, and any tagged VLAN on BCM7278 port 7, which cannot receive tagged frames. Previously the ndo was never called, so such uppers were silently created broken. Measured on an Asus RT-N18U (BCM53011 rev 5) against a peer device. A probe over an 8021q upper on the standalone WAN port received 0 frames before and 7 of 7 after, with the outbound direction as a positive control and vlan_filtering staying 0 throughout. A static fdb entry with VID 100 survived a vlan_filtering 1->0 toggle in hardware, since dev->vlan_enabled is never touched and the ARL keeps using independent VLAN learning. The PPPoE session from the report establishes. Fixes: 06cfb2df7eb0 ("net: dsa: don't advertise 'rx-vlan-filter' when not needed") Cc: stable@vger.kernel.org Signed-off-by: Semih Baskan <strst.gs@gmail.com> --- drivers/net/dsa/b53/b53_common.c | 118 ++++++++++++++++++++++++++----- 1 file changed, 100 insertions(+), 18 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 3f5b9592794d..ba1266cd70c3 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -898,10 +898,52 @@ static bool b53_vlan_port_may_join_untagged(struct dsa_switch *ds, int port) return dp->bridge == NULL; } +static bool b53_vlan_hw_entry(struct dsa_switch *ds, const struct b53_vlan *vl, + struct b53_vlan *hw) +{ + struct b53_device *dev = ds->priv; + bool standalone = false; + struct dsa_port *dp; + unsigned int port; + + *hw = *vl; + + if (dev->vlan_filtering) + return true; + + hw->members = 0; + hw->untag = 0; + + b53_for_each_port(dev, port) { + if (!(vl->members & BIT(port))) + continue; + + dp = dsa_to_port(ds, port); + + if (!dsa_port_is_cpu(dp)) { + if (dp->bridge) + continue; + + standalone = true; + } + + hw->members |= BIT(port); + hw->untag |= vl->untag & BIT(port); + } + + if (!standalone) { + hw->members = 0; + hw->untag = 0; + } + + return standalone; +} + int b53_configure_vlan(struct dsa_switch *ds) { struct b53_device *dev = ds->priv; struct b53_vlan vl = { 0 }; + struct b53_vlan hw; struct b53_vlan *v; int i, def_vid; u16 vid; @@ -937,20 +979,23 @@ int b53_configure_vlan(struct dsa_switch *ds) } b53_set_vlan_entry(dev, def_vid, &vl); - if (dev->vlan_filtering) { - /* Upon initial call we have not set-up any VLANs, but upon - * system resume, we need to restore all VLAN entries. - */ - for (vid = def_vid + 1; vid < dev->num_vlans; vid++) { - v = &dev->vlans[vid]; + /* Upon initial call we have not set-up any VLANs, but upon + * system resume, we need to restore all VLAN entries. + */ + for (vid = def_vid + 1; vid < dev->num_vlans; vid++) { + v = &dev->vlans[vid]; - if (!v->members) - continue; + if (!v->members) + continue; - b53_set_vlan_entry(dev, vid, v); - b53_fast_age_vlan(dev, vid); - } + if (!b53_vlan_hw_entry(ds, v, &hw)) + continue; + b53_set_vlan_entry(dev, vid, &hw); + b53_fast_age_vlan(dev, vid); + } + + if (dev->vlan_filtering) { b53_for_each_port(dev, i) { if (!dsa_is_cpu_port(ds, i)) b53_write16(dev, B53_VLAN_PAGE, @@ -1720,6 +1765,7 @@ int b53_vlan_add(struct dsa_switch *ds, int port, struct b53_device *dev = ds->priv; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + struct b53_vlan hw; struct b53_vlan *vl; u16 old_pvid, new_pvid; int err; @@ -1751,13 +1797,14 @@ int b53_vlan_add(struct dsa_switch *ds, int port, else vl->untag &= ~BIT(port); - if (!dev->vlan_filtering) + if (!b53_vlan_hw_entry(ds, vl, &hw)) return 0; - b53_set_vlan_entry(dev, vlan->vid, vl); + b53_set_vlan_entry(dev, vlan->vid, &hw); b53_fast_age_vlan(dev, vlan->vid); - if (!dsa_is_cpu_port(ds, port) && new_pvid != old_pvid) { + if (dev->vlan_filtering && + !dsa_is_cpu_port(ds, port) && new_pvid != old_pvid) { b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), new_pvid); b53_fast_age_vlan(dev, old_pvid); @@ -1772,7 +1819,9 @@ int b53_vlan_del(struct dsa_switch *ds, int port, { struct b53_device *dev = ds->priv; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + struct b53_vlan hw; struct b53_vlan *vl; + bool needs_hw; u16 pvid; if (vlan->vid == 0) @@ -1782,6 +1831,8 @@ int b53_vlan_del(struct dsa_switch *ds, int port, vl = &dev->vlans[vlan->vid]; + needs_hw = b53_vlan_hw_entry(ds, vl, &hw); + vl->members &= ~BIT(port); if (pvid == vlan->vid) @@ -1791,14 +1842,18 @@ int b53_vlan_del(struct dsa_switch *ds, int port, if (untagged && !b53_vlan_port_needs_forced_tagged(ds, port)) vl->untag &= ~(BIT(port)); - if (!dev->vlan_filtering) + if (!needs_hw) return 0; - b53_set_vlan_entry(dev, vlan->vid, vl); + b53_vlan_hw_entry(ds, vl, &hw); + b53_set_vlan_entry(dev, vlan->vid, &hw); b53_fast_age_vlan(dev, vlan->vid); - b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), pvid); - b53_fast_age_vlan(dev, pvid); + if (dev->vlan_filtering) { + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), + pvid); + b53_fast_age_vlan(dev, pvid); + } return 0; } @@ -2261,6 +2316,28 @@ int b53_mdb_del(struct dsa_switch *ds, int port, } EXPORT_SYMBOL(b53_mdb_del); +static void b53_standalone_vlan_resync(struct dsa_switch *ds, int port) +{ + struct b53_device *dev = ds->priv; + struct b53_vlan hw; + struct b53_vlan *vl; + u16 vid; + + if (dev->vlan_filtering) + return; + + for (vid = b53_default_pvid(dev) + 1; vid < dev->num_vlans; vid++) { + vl = &dev->vlans[vid]; + + if (!(vl->members & BIT(port))) + continue; + + b53_vlan_hw_entry(ds, vl, &hw); + b53_set_vlan_entry(dev, vid, &hw); + b53_fast_age_vlan(dev, vid); + } +} + int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge, bool *tx_fwd_offload, struct netlink_ext_ack *extack) { @@ -2324,6 +2401,8 @@ int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge, b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan); dev->ports[port].vlan_ctl_mask = pvlan; + b53_standalone_vlan_resync(ds, port); + return 0; } EXPORT_SYMBOL(b53_br_join); @@ -2376,6 +2455,8 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge) vl->members |= BIT(port); b53_set_vlan_entry(dev, pvid, vl); } + + b53_standalone_vlan_resync(ds, port); } EXPORT_SYMBOL(b53_br_leave); @@ -3213,6 +3294,7 @@ struct b53_device *b53_switch_alloc(struct device *base, * devices. (not hardware supported) */ ds->vlan_filtering_is_global = true; + ds->needs_standalone_vlan_offload = true; mutex_init(&dev->reg_mutex); mutex_init(&dev->stats_mutex); ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH net 0/2] net: dsa: b53: fix 8021q uppers on standalone ports 2026-08-06 7:31 [PATCH net 0/2] net: dsa: b53: fix 8021q uppers on standalone ports Semih Baskan 2026-08-06 7:31 ` [PATCH net 1/2] net: dsa: let drivers offload " Semih Baskan 2026-08-06 7:31 ` [PATCH net 2/2] net: dsa: b53: " Semih Baskan @ 2026-08-06 8:39 ` Jonas Gorski 2026-08-06 11:06 ` Semih Baskan 2 siblings, 1 reply; 19+ messages in thread From: Jonas Gorski @ 2026-08-06 8:39 UTC (permalink / raw) To: Semih Baskan Cc: florian.fainelli, andrew, olteanv, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel, Rafał Miłecki Hi, On Thu, Aug 6, 2026 at 9:31 AM Semih Baskan <strst.gs@gmail.com> wrote: > > Since v5.15, a standalone port on a b53 switch cannot receive its own > tagged traffic: the switch VID lookup is always active, an 8021q > upper's VID never reaches the VLAN table, and every tagged frame > resolves to an empty member set and is discarded. The common victim is > a VLAN-tagged PPPoE WAN, where the PADI goes out and the tagged PADO > never reaches the CPU. > > My first attempt disabled the VLAN table while not filtering: > > https://lore.kernel.org/all/20260805072641.402-1-strst.gs@gmail.com/ > > Jonas pointed out that this moves the ARL to shared VLAN learning and > desynchronizes the hardware table from the bridge fdb, and I withdrew > it. I then measured the alternatives on an RT-N18U (BCM53011 rev 5), > with the outbound direction of the same link as a positive control on > every run: > > - With the table enabled, no ingress VID check setting delivers the > frame: VC4_NO_ING_VID_CHK, VC4_ING_VID_VIO_FWD and > VC4_ING_VID_VIO_TO_IMP all give 0, and clearing VC0_DROP_VID_MISS > changes nothing. The frame does not die at ingress admission, it > dies when forwarding resolves the VID against an empty member set. Note that this is working on switches other than bcm5301x (at least on bcm63268 and bcm53115), so this seems to be a bcm5301x specific issue. Unfortunately I do not have a device with such a switch. Though it only works for standalone ports, it does not allow forwarding between ports. Though this isn't the first time a bcm5310x issue showed up with packets not properly trapped to CPU. Rafal, Florian, did you ever figure out the issue? It feels like there is something missing with the CPU port configuration. Which port are you using as CPU port? I see several device trees in-tree using port 5, but according to the register definitions in OpenMDK, the only valid port for both BRCM_HDR and GLOBAL_CONFIG's FRM_MGMT_PORT is imp0 / port 8 [1]. So I now wonder if using port 5 as CPU port only appears to work (i.e. enabling the header does), but anything that is supposed to trap to CPU tries to forward to 8, which is disabled. Or does not forward at all, because the FRM_MGMT_PORT is configured to an invalid value. In addition to that, I see that b53_brcm_hdr_setup() does not clear GC_FRM_MGMT_PORT_M, so if it defaults/was programmed to anything before, it may become a wrong value. If you are using port 5 as CPU port, can you try switching to port 8 / gmac2? > - With the table disabled, a static fdb entry with VID 100 is lost > from the hardware ARL no matter how the driver drives the ARL > registers: keeping ARLTBL_IVL_SVL_SELECT at IVL does not preserve > it, and neither does additionally keeping the VID learning bits in > VLAN_CTRL0 set. ARLTBL_IVL_SVL_SELECT is only implemented on bcm5302x / bcm58xx / bcm53134 (and maybe some other newer switches), so no wonder it doesn't do anything for you (it also has some additional dependencies which aren't implemented in b53, so this is essentially dead code). [1] https://github.com/Broadcom/OpenMDK/blob/v2.11.0/cdk/PKG/chip/bcm53010/bcm53010_a0_defs.h Best regards, Jonas ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH net 0/2] net: dsa: b53: fix 8021q uppers on standalone ports 2026-08-06 8:39 ` [PATCH net 0/2] net: dsa: b53: fix " Jonas Gorski @ 2026-08-06 11:06 ` Semih Baskan 0 siblings, 0 replies; 19+ messages in thread From: Semih Baskan @ 2026-08-06 11:06 UTC (permalink / raw) To: Jonas Gorski Cc: florian.fainelli, andrew, olteanv, davem, edumazet, kuba, pabeni, vladimir.oltean, horms, netdev, linux-kernel, Rafał Miłecki Hi Jonas, > If you are using port 5 as CPU port, can you try switching to port 8 / gmac2? You are right. I tested it today on the RT-N18U and switching the CPU port to port 8 makes tagged standalone RX work on an unpatched driver, with nothing in the VLAN table. Details below. User ports attach to port 5 (gmac0) here, as in every bcm5301x device tree in-tree. I enabled port@8 (gmac2) as the only CPU port in the dts, left the driver completely stock, and rebuilt: - the board comes up with the whole management path over gmac2, so the port 8 to gmac2 path works on BCM47081, - the tagged probe that always failed on port 5 delivers 7 of 7 (outbound positive control 7 of 7, delivery attributed to eth2 by interface counters, eth0 stayed at 0), - the PPPoE session from the original report establishes. I also instrumented b53_brcm_hdr_setup() to read back GLOBAL_CONFIG, and the register documentation in OpenMDK explains the mechanism you suspected. GMNGCFG.FRM_MNGP on bcm53010 [1]: 00 = no IMP port 01 = reserved 10 = IMP0 only: all traffic to CPU from LAN and WAN ports goes to IMP0 11 = dual IMP: LAN-port CPU traffic goes to IMP0, WAN-port traffic to IMP1, and "In polar, IMP0 is Port 8 and IMP1 is Port 5." With CPU port 5 the driver ORs GC_FRM_MGMT_PORT_M, which is the field mask, so the register reads back 0xc2: FRM_MNGP=11, dual IMP. In that mode the tagged frames reach the CPU on neither IMP: I also tested an intermediate build with port@8 enabled as a second CPU port while the user ports stayed on port 5, which is what plain bcm-ns.dtsi describes since it does not disable port@7/8, and delivery still failed with the gmac2 counters at zero. With port 8 as the only CPU port the driver programs 0x82: FRM_MNGP=10, IMP0 only, and delivery works. So your no-clear observation is correct and the value it produces is worse than a stale leftover: the port 5 branch cannot program anything better, because there is no "IMP1 only" encoding, and LAN-class management traps can never arrive on port 5 on this chip. One smaller register note: BRCM_HDR_CTRL on bcm53010 does have per-port bits (bit0 port 8, bit1 port 5, bit2 port 7) [1], so the Broadcom header itself is valid on port 5. That is why tagging works there at all; the port-8-only limitation is in the IMP routing, not the header. A data point that fits the same picture: with CPU on port 5, BPDUs sent into switch port 0 do reach the CPU. Port 0 is WAN-class in the chip's management routing, so its traps go to IMP1, port 5. The trap destination depends on the port class, which is probably why this half-works and has been so confusing historically. > ARLTBL_IVL_SVL_SELECT is only implemented on bcm5302x / bcm58xx / > bcm53134 (and maybe some other newer switches), so no wonder it > doesn't do anything for you Thanks, noted. That makes the second measurement stronger rather than weaker: on this chip there is no knob at all that preserves VID-keyed ARL entries with the table disabled. One property of the port 8 setup worth knowing before anyone reads it as the fix: delivery is indiscriminate. After deleting the 8021q upper I still see the tagged frames of that VID on the CPU with tcpdump. Every unknown VID from the wire reaches the CPU, always, which is the pre-5.15 behavior with its unfiltered nature included. The series delivers only the VIDs that uppers subscribe, and stops delivering when they go away. So as I see it there are two valid fixes on different timescales. Moving bcm5301x device trees to gmac2 fixes the trap path at the root, but it changes the conduit for every board, needs per-board validation, and cannot go to stable. The series fixes the deployed port 5 topology selectively and is backportable. They do not conflict; the VLAN entries are correct and harmless under either CPU port. I am happy to help test a device tree migration on the RT-N18U if you want to pursue that separately. Also for completeness: a runtime test of your suggestion via conduit reassignment is not possible, b53 does not implement port_change_conduit, so I tested through the device tree. [1] https://github.com/Broadcom/OpenMDK/blob/v2.11.0/cdk/PKG/chip/bcm53010/bcm53010_a0_defs.h Best regards, Semih ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2026-08-12 10:21 UTC | newest] Thread overview: 19+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-06 7:31 [PATCH net 0/2] net: dsa: b53: fix 8021q uppers on standalone ports Semih Baskan 2026-08-06 7:31 ` [PATCH net 1/2] net: dsa: let drivers offload " Semih Baskan 2026-08-06 11:15 ` Vladimir Oltean 2026-08-06 11:44 ` Semih Baskan 2026-08-06 12:43 ` Vladimir Oltean 2026-08-06 13:39 ` Semih Baskan 2026-08-10 12:08 ` Vladimir Oltean 2026-08-11 6:25 ` Semih Baskan 2026-08-11 7:44 ` Jonas Gorski 2026-08-11 9:58 ` Vladimir Oltean 2026-08-11 13:19 ` Semih Baskan 2026-08-12 7:24 ` Jonas Gorski 2026-08-12 9:21 ` Semih Baskan 2026-08-12 9:52 ` Jonas Gorski 2026-08-12 10:21 ` Semih Baskan 2026-08-12 7:14 ` Jonas Gorski 2026-08-06 7:31 ` [PATCH net 2/2] net: dsa: b53: " Semih Baskan 2026-08-06 8:39 ` [PATCH net 0/2] net: dsa: b53: fix " Jonas Gorski 2026-08-06 11:06 ` Semih Baskan
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.