From nobody Fri Oct 2 01:54:33 2026 Received: from mail-wm1-f49.google.com (mail-wm1-f49.google.com [209.85.128.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0E3713DAAD2 for ; Thu, 6 Aug 2026 07:31:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786001496; cv=none; b=rIX5X5aRVMC+AZjMWgvE9HaQmucdsf1vwJpjur1x87WWTDKHG7SuhkDmWAM5wTQCDUZRMF9+Wji8+5UbTQHfZ/ty0Hz+Svzyq6fuD49OOiZ1cna1cp77MmORM/1RsD+iB51BeIzeMZW4INbfXtWsNJDAx6LiF55qmHkcOmtgWqI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786001496; c=relaxed/simple; bh=BRPYXCecTDnjSVaChCQSCTURDJvYwheTIwAy5EhtNRA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XH7Bhpuy/3zy/guGJrWcYgHMu7B07XWKrZXokY9gfNeyp9jdO7KuUL4kbrMdEATA/gUsngzvCyZazurQcQI9Qlu9areDpUjUU8/xTKuUp7cRBVk13B/44zJy2dpjvoirJMl7OmkwwtsXDcP5HQ4b16yOrc5R1ubEBa0kd2ZR9ug= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=BWf67QTT; arc=none smtp.client-ip=209.85.128.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BWf67QTT" Received: by mail-wm1-f49.google.com with SMTP id 5b1f17b1804b1-4954dff6536so13021955e9.0 for ; Thu, 06 Aug 2026 00:31:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786001491; x=1786606291; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:from:to:cc:subject:date :message-id:reply-to:content-type; bh=D0kLjzVMGQP2GDl+xLrm6TwqzVKVcj9RXEl6sHzZBCM=; b=BWf67QTTdBXK/Y8T9eWKpD5IrHAPsnyZP/ZN0hxF+idpTy5mCiDRjVvU2VB0kstIQR IY2girq6LocI8gtKVF1IlMHf6lKACgEgjEMdLfYjSNWzFnC4oMF+DSDq3bsFcHNIv0/l 0o+lLHHA4j5rvdJqdOwQQBvE2YHEvmmKS1vNrQLnfqsrCCoFp1jP8hBZ98CC00o0N90F /Tm8v1p+M2SnF71DT4ZiVdFbynveGiyMhmcBsPzesJ5jvZGHixewNuDvKMdpTVItm3vC jBjNSMafEW1Zo2IfH86HiH+PMbZUC550KDhY4Gyqulqs1Lr5XtL2oeDvlDFWsjD7DtfH oZ/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786001491; x=1786606291; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=D0kLjzVMGQP2GDl+xLrm6TwqzVKVcj9RXEl6sHzZBCM=; b=dqRUeI/L8ySE9BdqvSP20F8SYb4QpyKawCpHr4smMo9ZpoajOR7ZieeWOSEUSmAbhc ibZuSWtBKfc21SunBneNUXcvcJW5ZeLmmAcFXMbsOx/yO4b6TKPUJe9vc60BfXWrQj01 uOKl9fqtQ//yQKw9CifENH3uRbGCjQrvUlJjFSNIG3gvG31xMz3eMQUm5VkDRnL32sfu 69HPHrEVrY8udT2Ma9/Dpp/o9BXoBIxjaB2j/NxSSC9OPPbSnr4OQVTWNKYe4QdXQMAU 0D7uia4Xkf4mtqm+fkTylLR4ZVtfhOHzAEypxt58Abx2+FaVoXzVx8ISNStCksNIZUF3 D1jg== X-Forwarded-Encrypted: i=1; AHgh+Rr4pwlWhjGvWhc44cwp01GrsgqV87XXeN9ZqEu2QOvnKCMiXk7uyFG989c99xkkjskjErlaHtAh6zO7KRo=@vger.kernel.org X-Gm-Message-State: AOJu0YyrmUhKSaQ22UXpIg829uyUhxsaxEj9lsxyE3IZBE8UVkkzcoP9 FqBtWIcdyypuDFri5G9/G4cOnZbUXn4SvJZsvHZiby03eFoWLyKYMjeK X-Gm-Gg: AR+sD10jyftl/qXOt/PZLOhzdHNmO2nc8GyatG+GAD9TwxEDQMhWH/Wix01UffC3DQ7 20Gw99RhGpH3F6hwIaaYFvnkSl1YDjlPxwJqOjXQ6I+FH7ukLju5ilJuILwTFgAc6MawuOvLXxu d/0/yoePe6++nfpLfnw1XUFsUHfRaoU/ZIy4NEz4XGPr7/tRLlAhy1oGK2BOZ/+JcXigZw2xz+A XplZwZ7JMfOo54OhLUg03ZckBzkhM4cCcEVQB8Ufdvx4VJam7vCW/KzTEICuO01Vo97kuyUwJea kXGwqfEaab5v3xnQ5SgNBiaYiuir+l10q8W1VuEttmX5vQ8gdUrCJaX0YUp4nPyTf9Gi1OvFaEw gWm0QWbWXMNmuYTgYYY6GSzBWMEm7TkQt3F8JjbYic0mNuFe1aLiuFHti6czrpPt2C7Rift2kYJ 6AXPuhBtVzUzzgSQUUpCbVdRW9K37vQ8k+/oOzBNo8li7lS0tQ7xikLcEDK7178b6jQ1WSJkQwn Q== X-Received: by 2002:a05:600c:a206:b0:495:48d7:f178 with SMTP id 5b1f17b1804b1-4994e7ccadbmr109314435e9.11.1786001490746; Thu, 06 Aug 2026 00:31:30 -0700 (PDT) Received: from SVR.localdomain ([86.106.74.249]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4994e52d819sm79075085e9.1.2026.08.06.00.31.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Aug 2026 00:31:30 -0700 (PDT) Sender: Semih Baskan From: Semih Baskan To: florian.fainelli@broadcom.com, jonas.gorski@gmail.com, andrew@lunn.ch, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com Cc: vladimir.oltean@nxp.com, horms@kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports Date: Thu, 6 Aug 2026 10:31:18 +0300 Message-ID: <20260806073119.387-2-strst.gs@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260806073119.387-1-strst.gs@gmail.com> References: <20260806073119.387-1-strst.gs@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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=3D1 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 n= eeded") Cc: stable@vger.kernel.org Signed-off-by: Semih Baskan --- 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; =20 + /* 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=3D0. 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 v= lan_filtering, if (!user) continue; =20 + if (ds->needs_standalone_vlan_offload) + continue; + err =3D 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 =3D vlan_filtering; =20 - err =3D dsa_user_manage_vlan_filtering(dp->user, - vlan_filtering); - if (err) - goto restore; + if (!ds->needs_standalone_vlan_offload) { + err =3D dsa_user_manage_vlan_filtering(dp->user, + vlan_filtering); + if (err) + goto restore; + } } =20 return 0; @@ -1445,10 +1450,12 @@ int dsa_port_change_conduit(struct dsa_port *dp, st= ruct net_device *conduit, =20 /* 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 =3D dsa_port_is_vlan_filtering(dp); + vlan_filtering =3D dsa_port_is_vlan_filtering(dp) || + (ds->needs_standalone_vlan_offload && !bridge_dev); if (vlan_filtering) { err =3D 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 *vde= v, int vid, void *arg) * * - If standalone (this includes software bridge, software LAG): * - if ds->needs_standalone_vlan_filtering =3D true, OR if + * ds->needs_standalone_vlan_offload =3D true, OR if * (ds->vlan_filtering_is_global =3D true AND there are bridges span= ning * this switch chip which have vlan_filtering=3D1) * - the 8021q upper VLANs @@ -2718,7 +2719,8 @@ void dsa_user_setup_tagger(struct net_device *user) user->hw_features |=3D NETIF_F_HW_TC; if (user->needed_tailroom) user->features &=3D ~(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 |=3D NETIF_F_HW_VLAN_CTAG_FILTER; =20 user->lltx =3D true; From nobody Fri Oct 2 01:54:33 2026 Received: from mail-wm1-f49.google.com (mail-wm1-f49.google.com [209.85.128.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1CAB825B2F4 for ; Thu, 6 Aug 2026 07:31:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786001501; cv=none; b=atn2EXITm6z6NOO8bny3chTPGWHX8TcH56p3UwZZLIV56Z/Kc0jVGSgA3mHyLUQwYOmBu++8oURKc3qDh4wiSb8C5/QzlftcAr3a1fTPwORgo3DDjzv5Oy8lyu92HQSuOEC0tImSTDQSOajA8E+gMCmFpXjoLWPxs++W5PhYXig= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786001501; c=relaxed/simple; bh=WJigues5/Zq//oA8yEj8xZ7mbFeDzXspYLRD/AhetSQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=P6BhWmxH1fmGa5R3uFweFjScsJlxj6sp/I3rqOyNK2D/PBJseOkU++r/YpaGDhMKyG3snJv2Y30PArOR7g0AIEp4i8s40wS93cl3sIPmJqjsPZSFoH5WEi5AVDkYat/Ague7UND5PuQYzUDb1Pk6ugD6Hj2GNxGwCe56Nt407Cg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=h+IT+WPv; arc=none smtp.client-ip=209.85.128.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="h+IT+WPv" Received: by mail-wm1-f49.google.com with SMTP id 5b1f17b1804b1-490cf322ed0so14543115e9.1 for ; Thu, 06 Aug 2026 00:31:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786001494; x=1786606294; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:from:to:cc:subject:date :message-id:reply-to:content-type; bh=uDqsWTzMDLL3yPNgURcpCw3SFq7morA76M8ptW4qhcg=; b=h+IT+WPvNsuwJ+crYFIV7Pz0nganmmtizLw4MIPYyQBDPQ33GYNiTuc4vBNLTbNQwb 76/CPaiITobzc7xWkSB2IwGqk2yq4bHUoCBw9q03U6mhmJ9E0dPDk5+HCgvnKVH7879l 0Oag2jjUXkgrYAmHddWxWKfsgqHtM16r8NIo9XZbTCV9MIEKo9CWv0b/58ROfbfkMWvc GTeFduTDal+bIH3FfSstLNc+QP4zC5U8g12dWMAZjdxKIaUYYcH4aXtMP9RDLBXEFw0g gZT4bCh8PaY5bnGG1Wm3Ha1A1NYLGs658Zx53E/I2NFxXuaogd0F3K/qlEEoZ+YvZcCj RUzw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786001494; x=1786606294; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=uDqsWTzMDLL3yPNgURcpCw3SFq7morA76M8ptW4qhcg=; b=IPewr48xAREZtgLpzAIiJvTEEXLghnxvtShdWeNP8tjasWjRSGAEe51IfO6GJLd39Y evXLOCfRyODGTexH3FwUNg5ONWyzzJws7GL5R/c3x14+/cYLjfncP2sxGSfwV7UvC+vL oplutPo5/VoEJdl88ATnxh1Ld6OhslKQ8TR4L10GoodfEP95RMhzmvWdYpSjGVOlbrxy YDnH7LwTT97hR++1ZTTwiUuthXC6e36CVAOjA0vwwx1KHuAl+12nozL+JfJZhg7pgTPp CEZB5fahcH6BPKhDTP6ruO9XwfL7uTW0bSESUKmNomCgberTuoh+jNYilxmMphVROIcX YS9g== X-Forwarded-Encrypted: i=1; AHgh+RpPo3VGldZ9vg3Mk7z9K0bwG0xmk2/bisDC90RdQ+j3A8AMIAeztH7LBNsq3yr7Mz7nduB33x1qBS43gas=@vger.kernel.org X-Gm-Message-State: AOJu0Yzr0YkYQ66CBpgT1+EzcY9hnwZT8d0iGwKyXNuvBEM+S08kSqvQ Z6DPaFeYGu6SZSkLFgRfKC0qT1ipYK0ul8cotIox1s2Z3az56SUH0Hmh X-Gm-Gg: AR+sD12hq/FTjSSRi/076kvvQ3+3sX0COLiHSwyUtUiJzGR/2f+St1oByLOGujHTZzh Np6eWgJqbUI6aiAq3oeBCuJWk9bAjL5nQJ1KFIEcKBD59ufbvHx1tEaQERtUlx36IMCwBfqOtUY 0yEF+ngNJB6IcQ74i+gIqkCazo0W7rWn7XoDqErkNL4rD1YR5espuOV2UBx8E5afJFdrJIjNd4b I7Mn265WDPQcjJ1jTQsWllZsVHMo0qI9liyM4tBzm77ex09nDPfLz0cQfPnl3a1ioYgUNJrGB9E RePBS1OvPcb0RKrbqrbfepMMgppAhBUJIdDRN10zgg/rzI4bluozainwNRNIBteg+ApxU+pKis9 U4zusko3BLLudU7/JtA1SlNqowj6G9InPd6aZTFcUvAoiD6sG5wqd+NOv34fCfge9fUqGLywYVN zTW8rWrWlOvq6Jc308pYanMQL66I4mZPKIRshYNraSDRSOm1V7PYuKZXcEh76s3w== X-Received: by 2002:a05:600d:4448:20b0:495:5e3d:15e1 with SMTP id 5b1f17b1804b1-4994e7d21fdmr145198385e9.16.1786001493858; Thu, 06 Aug 2026 00:31:33 -0700 (PDT) Received: from SVR.localdomain ([86.106.74.249]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4994e52d819sm79075085e9.1.2026.08.06.00.31.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Aug 2026 00:31:32 -0700 (PDT) Sender: Semih Baskan From: Semih Baskan To: florian.fainelli@broadcom.com, jonas.gorski@gmail.com, andrew@lunn.ch, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com Cc: vladimir.oltean@nxp.com, horms@kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net 2/2] net: dsa: b53: offload 8021q uppers on standalone ports Date: Thu, 6 Aug 2026 10:31:19 +0300 Message-ID: <20260806073119.387-3-strst.gs@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260806073119.387-1-strst.gs@gmail.com> References: <20260806073119.387-1-strst.gs@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 n= eeded") Cc: stable@vger.kernel.org Signed-off-by: Semih Baskan --- 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_com= mon.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 ds= a_switch *ds, int port) return dp->bridge =3D=3D NULL; } =20 +static bool b53_vlan_hw_entry(struct dsa_switch *ds, const struct b53_vlan= *vl, + struct b53_vlan *hw) +{ + struct b53_device *dev =3D ds->priv; + bool standalone =3D false; + struct dsa_port *dp; + unsigned int port; + + *hw =3D *vl; + + if (dev->vlan_filtering) + return true; + + hw->members =3D 0; + hw->untag =3D 0; + + b53_for_each_port(dev, port) { + if (!(vl->members & BIT(port))) + continue; + + dp =3D dsa_to_port(ds, port); + + if (!dsa_port_is_cpu(dp)) { + if (dp->bridge) + continue; + + standalone =3D true; + } + + hw->members |=3D BIT(port); + hw->untag |=3D vl->untag & BIT(port); + } + + if (!standalone) { + hw->members =3D 0; + hw->untag =3D 0; + } + + return standalone; +} + int b53_configure_vlan(struct dsa_switch *ds) { struct b53_device *dev =3D ds->priv; struct b53_vlan vl =3D { 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); =20 - 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 =3D def_vid + 1; vid < dev->num_vlans; vid++) { - v =3D &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 =3D def_vid + 1; vid < dev->num_vlans; vid++) { + v =3D &dev->vlans[vid]; =20 - if (!v->members) - continue; + if (!v->members) + continue; =20 - b53_set_vlan_entry(dev, vid, v); - b53_fast_age_vlan(dev, vid); - } + if (!b53_vlan_hw_entry(ds, v, &hw)) + continue; =20 + 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 =3D ds->priv; bool untagged =3D vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; bool pvid =3D 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 &=3D ~BIT(port); =20 - if (!dev->vlan_filtering) + if (!b53_vlan_hw_entry(ds, vl, &hw)) return 0; =20 - b53_set_vlan_entry(dev, vlan->vid, vl); + b53_set_vlan_entry(dev, vlan->vid, &hw); b53_fast_age_vlan(dev, vlan->vid); =20 - if (!dsa_is_cpu_port(ds, port) && new_pvid !=3D old_pvid) { + if (dev->vlan_filtering && + !dsa_is_cpu_port(ds, port) && new_pvid !=3D 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 =3D ds->priv; bool untagged =3D vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + struct b53_vlan hw; struct b53_vlan *vl; + bool needs_hw; u16 pvid; =20 if (vlan->vid =3D=3D 0) @@ -1782,6 +1831,8 @@ int b53_vlan_del(struct dsa_switch *ds, int port, =20 vl =3D &dev->vlans[vlan->vid]; =20 + needs_hw =3D b53_vlan_hw_entry(ds, vl, &hw); + vl->members &=3D ~BIT(port); =20 if (pvid =3D=3D 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 &=3D ~(BIT(port)); =20 - if (!dev->vlan_filtering) + if (!needs_hw) return 0; =20 - 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); =20 - 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); + } =20 return 0; } @@ -2261,6 +2316,28 @@ int b53_mdb_del(struct dsa_switch *ds, int port, } EXPORT_SYMBOL(b53_mdb_del); =20 +static void b53_standalone_vlan_resync(struct dsa_switch *ds, int port) +{ + struct b53_device *dev =3D ds->priv; + struct b53_vlan hw; + struct b53_vlan *vl; + u16 vid; + + if (dev->vlan_filtering) + return; + + for (vid =3D b53_default_pvid(dev) + 1; vid < dev->num_vlans; vid++) { + vl =3D &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, stru= ct dsa_bridge bridge, b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan); dev->ports[port].vlan_ctl_mask =3D pvlan; =20 + 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, st= ruct dsa_bridge bridge) vl->members |=3D BIT(port); b53_set_vlan_entry(dev, pvid, vl); } + + b53_standalone_vlan_resync(ds, port); } EXPORT_SYMBOL(b53_br_leave); =20 @@ -3213,6 +3294,7 @@ struct b53_device *b53_switch_alloc(struct device *ba= se, * devices. (not hardware supported) */ ds->vlan_filtering_is_global =3D true; + ds->needs_standalone_vlan_offload =3D true; =20 mutex_init(&dev->reg_mutex); mutex_init(&dev->stats_mutex);