lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <5b5d8034f0fe7f95b04087ea01fc43acec2db942.camel@microchip.com>
Date:   Tue, 26 Jul 2022 15:10:24 +0000
From:   <Arun.Ramadoss@...rochip.com>
To:     <vladimir.oltean@....com>
CC:     <claudiu.manoil@....com>, <UNGLinuxDriver@...rochip.com>,
        <alexandre.belloni@...tlin.com>, <vivien.didelot@...il.com>,
        <andrew@...n.ch>, <idosch@...dia.com>, <linux@...pel-privat.de>,
        <petrm@...dia.com>, <f.fainelli@...il.com>, <hauke@...ke-m.de>,
        <martin.blumenstingl@...glemail.com>, <xiaoliang.yang_1@....com>,
        <kuba@...nel.org>, <pabeni@...hat.com>, <edumazet@...gle.com>,
        <netdev@...r.kernel.org>, <Woojung.Huh@...rochip.com>,
        <davem@...emloft.net>
Subject: Re: [RFC PATCH net-next 3/3] net: dsa: never skip VLAN configuration

Hi Vladimir,
On Mon, 2022-07-18 at 16:24 +0000, Vladimir Oltean wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you
> know the content is safe
> 
> Hi Arun,
> 
> On Mon, Jul 18, 2022 at 02:34:33PM +0000, Arun.Ramadoss@...rochip.com
>  wrote:
> > Hi Vladimir,
> > There was a mistake in our testing on the latest code base of net-
> > next.
> > Today we tried in the latest net-next and following are the
> > observation.
> > 
> > Scenario 1: Before applying the patch
> > ------------------------------
> > ip link set dev br0 type bridge vlan_filtering 0
> > 
> > bridge vlan add vid 10 dev lan1 pvid untagged
> > bridge vlan add vid 10 dev lan2 pvid untagged
> 
> "bridge vlan add" on lan2 was never part of the test instructions.
> 
> > 
> > We got warning skipping configuration of VLAN and
> > ksz_port_vlan_add()
> > is not called.
> > 
> > Packet is received in Host2 when transmitted from Host1. So there
> > is no
> > breakage in the forwarding.
> 
> Nonetheless it's good to know that the control scenario behaves as
> expected, i.e. the VLANs are skipped while VLAN-unaware (and
> therefore,
> the port hardware PVID remains what it was).
> 
> > Scenario 2: After applying the patch
> > ----------------------------
> > ip link set dev br0 type bridge vlan_filtering 0
> > 
> > bridge vlan add vid 10 dev lan1 pvid untagged
> > 
> > --> Packet is not received in the Host2
> 
> The problem is exactly here. The driver should pass packets at this
> stage.
> This is because the bridge is still VLAN-unaware, despite its VLAN-
> aware
> pvid VLAN having been changed from 1 (vlan_default_pvid) to 10.
> 
> > bridge vlan add vid 10 dev lan2 pvid untagged
> > 
> > --> packet is received in the Host2
> 
> This only goes to prove that the VLAN in which the switch processes
> traffic while VLAN-unaware is the PVID of the port. So when the PVID
> on
> the ingress and egress ports matches, forwarding is naturally
> restored.
> 
> > bridge vlan del vid 10 dev lan1
> > 
> > --> packet is received in the Host2
> > 
> > bridge vlan del vid 10 dev lan2
> > 
> > --> packet is received in the Host2
> > 
> >  * Let us know, do we need to test anything further on this.
> 
> Yes, now you need to go fix the driver :) Please read the comments
> from
> this patch and the series in general (including cover letter), they
> point to similar issues in other drivers and to commits which have
> solved them. I need the ksz driver to work properly before I can
> delete
> the configure_vlan_while_not_filtering workaround. Generally
> speaking,
> the PVID needs to be committed to hardware based on a smarter logic,
> see
> this for example (and all the places from which it is called):
> 
> static int mv88e6xxx_port_commit_pvid(struct mv88e6xxx_chip *chip,
> int port)
> {
>         struct dsa_port *dp = dsa_to_port(chip->ds, port);
>         struct net_device *br = dsa_port_bridge_dev_get(dp);
>         struct mv88e6xxx_port *p = &chip->ports[port];
>         u16 pvid = MV88E6XXX_VID_STANDALONE; // Dedicated PVID for
> standalone mode
>         bool drop_untagged = false;
>         int err;
> 
>         if (br) {
>                 if (br_vlan_enabled(br)) {
>                         pvid = p->bridge_pvid.vid; // PVID is
> inherited from bridge only if the bridge is *currently* VLAN-aware
>                         drop_untagged = !p->bridge_pvid.valid;
>                 } else {
>                         pvid = MV88E6XXX_VID_BRIDGED; // Dedicated
> PVID for VLAN-unaware bridging
>                 }
>         }
> 
>         err = mv88e6xxx_port_set_pvid(chip, port, pvid);
>         if (err)
>                 return err;
> 
>         return mv88e6xxx_port_drop_untagged(chip, port,
> drop_untagged);
> }
> 
> Additionally, DaveM has just merged some DSA documentation updates
> which
> I think are very relevant to this discussion. See the new "Address
> databases"
> chapter for a review of how things are supposed to actually work when
> done carefully:
> 
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/tree/Documentation/networking/dsa/dsa.rst#n730
> 
> Thanks!
I tried to update the ksz code and tested after applying this patch
series. Following are the observation,

Scenario 1: bridge_vlan_unaware default pvid = 1
---------------------------------
ip link set dev br0 type bridge vlan_filtering 0

--> packet is received in the Host 2                       

bridge vlan add vid 10 dev lan1 pvid untagged

--> packet is received in the Host 2

bridge vlan add vid 10 dev lan2 pvid untagged

--> packet is received in the Host 2

bridge vlan del vid 10 dev lan1

--> packet is received in the Host 2

bridge vlan del vid 10 dev lan2

--> packet is received in the Host2

Scenario 2: bridge_vlan_unaware default pvid other than 1
---------------------------------
ip link set dev br0 type bridge vlan_filtering 0

--> packet is not received in the Host 2. Only after enabling the
vlan_filtering and bridge vlan add packets are receiving.

ip link set dev br0 type bridge vlan_filtering 1
bridge vlan add vid 10 dev lan2 pvid untagged   

In summary, only for pvid 1 below patch is working. Initially I tried
with pvid 0, 21, 4095, it were not working, only for pvid 1 it is
working. Kindly suggest whether any changes to be done in patch or
testing methodology.

Updated code patch
------------------
diff --git a/drivers/net/dsa/microchip/ksz8.h
b/drivers/net/dsa/microchip/ksz8.h
index 42c50cc4d853..e8e1590a78c0 100644
--- a/drivers/net/dsa/microchip/ksz8.h
+++ b/drivers/net/dsa/microchip/ksz8.h
@@ -43,6 +43,7 @@ int ksz8_port_vlan_add(struct ksz_device *dev, int
port,
 		       struct netlink_ext_ack *extack);
 int ksz8_port_vlan_del(struct ksz_device *dev, int port,
 		       const struct switchdev_obj_port_vlan *vlan);
+void ksz8_port_enable_pvid(struct ksz_device *dev, int port, bool
state);
 int ksz8_port_mirror_add(struct ksz_device *dev, int port,
 			 struct dsa_mall_mirror_tc_entry *mirror,
 			 bool ingress, struct netlink_ext_ack *extack);
diff --git a/drivers/net/dsa/microchip/ksz8795.c
b/drivers/net/dsa/microchip/ksz8795.c
index c79a5128235f..4f4e26001957 100644
--- a/drivers/net/dsa/microchip/ksz8795.c
+++ b/drivers/net/dsa/microchip/ksz8795.c
@@ -952,7 +952,7 @@ int ksz8_port_vlan_filtering(struct ksz_device
*dev, int port, bool flag,
 	return 0;
 }
 
-static void ksz8_port_enable_pvid(struct ksz_device *dev, int port,
bool state)
+void ksz8_port_enable_pvid(struct ksz_device *dev, int port, bool
state)
 {
 	if (ksz_is_ksz88x3(dev)) {
 		ksz_cfg(dev, REG_SW_INSERT_SRC_PVID,
@@ -968,8 +968,8 @@ int ksz8_port_vlan_add(struct ksz_device *dev, int
port,
 {
 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
 	struct ksz_port *p = &dev->ports[port];
-	u16 data, new_pvid = 0;
 	u8 fid, member, valid;
+	u16 data;
 
 	if (ksz_is_ksz88x3(dev))
 		return -ENOTSUPP;
@@ -1016,36 +1016,18 @@ int ksz8_port_vlan_add(struct ksz_device *dev,
int port,
 	ksz8_to_vlan(dev, fid, member, valid, &data);
 	ksz8_w_vlan_table(dev, vlan->vid, data);
 
-	/* change PVID */
-	if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
-		new_pvid = vlan->vid;
-
-	if (new_pvid) {
-		u16 vid;
-
-		ksz_pread16(dev, port, REG_PORT_CTRL_VID, &vid);
-		vid &= ~VLAN_VID_MASK;
-		vid |= new_pvid;
-		ksz_pwrite16(dev, port, REG_PORT_CTRL_VID, vid);
-
-		ksz8_port_enable_pvid(dev, port, true);
-	}
-
 	return 0;
 }
 
 int ksz8_port_vlan_del(struct ksz_device *dev, int port,
 		       const struct switchdev_obj_port_vlan *vlan)
 {
-	u16 data, pvid;
+	u16 data;
 	u8 fid, member, valid;
 
 	if (ksz_is_ksz88x3(dev))
 		return -ENOTSUPP;
 
-	ksz_pread16(dev, port, REG_PORT_CTRL_VID, &pvid);
-	pvid = pvid & 0xFFF;
-
 	ksz8_r_vlan_table(dev, vlan->vid, &data);
 	ksz8_from_vlan(dev, data, &fid, &member, &valid);
 
@@ -1060,9 +1042,6 @@ int ksz8_port_vlan_del(struct ksz_device *dev,
int port,
 	ksz8_to_vlan(dev, fid, member, valid, &data);
 	ksz8_w_vlan_table(dev, vlan->vid, data);
 
-	if (pvid == vlan->vid)
-		ksz8_port_enable_pvid(dev, port, false);
-
 	return 0;
 }
 
diff --git a/drivers/net/dsa/microchip/ksz9477.c
b/drivers/net/dsa/microchip/ksz9477.c
index 4b14d80d27ed..6a39d6893142 100644
--- a/drivers/net/dsa/microchip/ksz9477.c
+++ b/drivers/net/dsa/microchip/ksz9477.c
@@ -354,6 +354,12 @@ void ksz9477_flush_dyn_mac_table(struct ksz_device
*dev, int port)
 	}
 }
 
+void ksz9477_port_drop_untagged(struct ksz_device *dev, int port, bool
state)
+{
+	ksz_port_cfg(dev, port, REG_PORT_MRI_MAC_CTRL,
PORT_DROP_NON_VLAN,
+		     state);
+}
+
 int ksz9477_port_vlan_filtering(struct ksz_device *dev, int port,
 				bool flag, struct netlink_ext_ack
*extack)
 {
@@ -399,10 +405,6 @@ int ksz9477_port_vlan_add(struct ksz_device *dev,
int port,
 		return err;
 	}
 
-	/* change PVID */
-	if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
-		ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, vlan-
>vid);
-
 	return 0;
 }
 
@@ -411,10 +413,6 @@ int ksz9477_port_vlan_del(struct ksz_device *dev,
int port,
 {
 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
 	u32 vlan_table[3];
-	u16 pvid;
-
-	ksz_pread16(dev, port, REG_PORT_DEFAULT_VID, &pvid);
-	pvid = pvid & 0xFFF;
 
 	if (ksz9477_get_vlan_table(dev, vlan->vid, vlan_table)) {
 		dev_dbg(dev->dev, "Failed to get vlan table\n");
@@ -423,9 +421,6 @@ int ksz9477_port_vlan_del(struct ksz_device *dev,
int port,
 
 	vlan_table[2] &= ~BIT(port);
 
-	if (pvid == vlan->vid)
-		pvid = 1;
-
 	if (untagged)
 		vlan_table[1] &= ~BIT(port);
 
@@ -434,8 +429,6 @@ int ksz9477_port_vlan_del(struct ksz_device *dev,
int port,
 		return -ETIMEDOUT;
 	}
 
-	ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, pvid);
-
 	return 0;
 }
 
diff --git a/drivers/net/dsa/microchip/ksz9477.h
b/drivers/net/dsa/microchip/ksz9477.h
index cd278b307b3c..005c510ee6c2 100644
--- a/drivers/net/dsa/microchip/ksz9477.h
+++ b/drivers/net/dsa/microchip/ksz9477.h
@@ -30,6 +30,7 @@ int ksz9477_port_vlan_add(struct ksz_device *dev, int
port,
 			  struct netlink_ext_ack *extack);
 int ksz9477_port_vlan_del(struct ksz_device *dev, int port,
 			  const struct switchdev_obj_port_vlan *vlan);
+void ksz9477_port_drop_untagged(struct ksz_device *dev, int port, bool
state);
 int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
 			    struct dsa_mall_mirror_tc_entry *mirror,
 			    bool ingress, struct netlink_ext_ack
*extack);
diff --git a/drivers/net/dsa/microchip/ksz_common.c
b/drivers/net/dsa/microchip/ksz_common.c
index ed7d137cba99..8711be6155e6 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -14,6 +14,7 @@
 #include <linux/phy.h>
 #include <linux/etherdevice.h>
 #include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
 #include <linux/of_device.h>
 #include <linux/of_net.h>
 #include <linux/micrel_phy.h>
@@ -160,6 +161,7 @@ static const struct ksz_dev_ops ksz8_dev_ops = {
 	.vlan_filtering = ksz8_port_vlan_filtering,
 	.vlan_add = ksz8_port_vlan_add,
 	.vlan_del = ksz8_port_vlan_del,
+	.drop_untagged = ksz8_port_enable_pvid,
 	.mirror_add = ksz8_port_mirror_add,
 	.mirror_del = ksz8_port_mirror_del,
 	.get_caps = ksz8_get_caps,
@@ -186,6 +188,7 @@ static const struct ksz_dev_ops ksz9477_dev_ops = {
 	.vlan_filtering = ksz9477_port_vlan_filtering,
 	.vlan_add = ksz9477_port_vlan_add,
 	.vlan_del = ksz9477_port_vlan_del,
+	.drop_untagged = ksz9477_port_drop_untagged,
 	.mirror_add = ksz9477_port_mirror_add,
 	.mirror_del = ksz9477_port_mirror_del,
 	.get_caps = ksz9477_get_caps,
@@ -219,6 +222,7 @@ static const struct ksz_dev_ops lan937x_dev_ops = {
 	.vlan_filtering = ksz9477_port_vlan_filtering,
 	.vlan_add = ksz9477_port_vlan_add,
 	.vlan_del = ksz9477_port_vlan_del,
+	.drop_untagged = ksz9477_port_drop_untagged,
 	.mirror_add = ksz9477_port_mirror_add,
 	.mirror_del = ksz9477_port_mirror_del,
 	.get_caps = lan937x_phylink_get_caps,
@@ -258,6 +262,7 @@ static const u16 ksz8795_regs[] = {
 	[S_MULTICAST_CTRL]		= 0x04,
 	[P_XMII_CTRL_0]			= 0x06,
 	[P_XMII_CTRL_1]			= 0x56,
+	[P_DEFAULT_PVID]		= 0x03,
 };
 
 static const u32 ksz8795_masks[] = {
@@ -330,6 +335,7 @@ static const u16 ksz8863_regs[] = {
 	[S_START_CTRL]			= 0x01,
 	[S_BROADCAST_CTRL]		= 0x06,
 	[S_MULTICAST_CTRL]		= 0x04,
+	[P_DEFAULT_PVID]		= 0x03,
 };
 
 static const u32 ksz8863_masks[] = {
@@ -372,6 +378,7 @@ static const u16 ksz9477_regs[] = {
 	[S_MULTICAST_CTRL]		= 0x0331,
 	[P_XMII_CTRL_0]			= 0x0300,
 	[P_XMII_CTRL_1]			= 0x0301,
+	[P_DEFAULT_PVID]		= 0x0000,
 };
 
 static const u32 ksz9477_masks[] = {
@@ -1333,38 +1340,120 @@ static enum dsa_tag_protocol
ksz_get_tag_protocol(struct dsa_switch *ds,
 	return proto;
 }
 
+static void ksz_get_pvid(struct ksz_device *dev, int port, u16 *pvid)
+{
+	const u16 *regs = dev->info->regs;
+	u16 val;
+
+	ksz_pread16(dev, port, regs[P_DEFAULT_PVID], &val);
+
+	*pvid = val & VLAN_VID_MASK;
+}
+
+static void ksz_set_pvid(struct ksz_device *dev, int port, u16 pvid)
+{
+	const u16 *regs = dev->info->regs;
+
+	ksz_prmw16(dev, port, regs[P_DEFAULT_PVID], VLAN_VID_MASK,
pvid);
+}
+
+static int ksz_commit_pvid(struct dsa_switch *ds, int port)
+{
+	struct dsa_port *dp = dsa_to_port(ds, port);
+	struct net_device *br = dsa_port_bridge_dev_get(dp);
+	struct ksz_device *dev = ds->priv;
+	bool drop_untagged = false;
+	struct ksz_port *p;
+	u16 pvid = 1;       /* bridge vlan unaware pvid */
+
+	p = &dev->ports[port];
+
+	if (br && br_vlan_enabled(br)) {
+		pvid = p->bridge_pvid.vid;
+		drop_untagged = !p->bridge_pvid.valid;
+	}
+
+	ksz_set_pvid(dev, port, pvid);
+
+	if (dev->dev_ops->drop_untagged)
+		dev->dev_ops->drop_untagged(dev, port, drop_untagged);
+
+	return 0;
+}
+
 static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port,
 				   bool flag, struct netlink_ext_ack
*extack)
 {
 	struct ksz_device *dev = ds->priv;
+	int ret;
 
 	if (!dev->dev_ops->vlan_filtering)
 		return -EOPNOTSUPP;
 
-	return dev->dev_ops->vlan_filtering(dev, port, flag, extack);
+	ret = dev->dev_ops->vlan_filtering(dev, port, flag, extack);
+	if (ret)
+		return ret;
+
+	return ksz_commit_pvid(ds, port);
 }
 
 static int ksz_port_vlan_add(struct dsa_switch *ds, int port,
 			     const struct switchdev_obj_port_vlan
*vlan,
 			     struct netlink_ext_ack *extack)
 {
+	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
 	struct ksz_device *dev = ds->priv;
+	struct ksz_port *p;
+	int ret;
+
+	p = &dev->ports[port];
 
 	if (!dev->dev_ops->vlan_add)
 		return -EOPNOTSUPP;
 
-	return dev->dev_ops->vlan_add(dev, port, vlan, extack);
+	ret = dev->dev_ops->vlan_add(dev, port, vlan, extack);
+	if (ret)
+		return ret;
+
+	if (pvid) {
+		p->bridge_pvid.vid = vlan->vid;
+		p->bridge_pvid.valid = true;
+	} else if (vlan->vid && p->bridge_pvid.vid == vlan->vid) {
+		/* The old pvid was reinstalled as a non-pvid VLAN */
+		p->bridge_pvid.valid = false;
+	}
+
+	return ksz_commit_pvid(ds, port);
 }
 
 static int ksz_port_vlan_del(struct dsa_switch *ds, int port,
 			     const struct switchdev_obj_port_vlan
*vlan)
 {
 	struct ksz_device *dev = ds->priv;
+	struct ksz_port *p;
+	u16 pvid;
+	int ret;
+
+	p = &dev->ports[port];
 
 	if (!dev->dev_ops->vlan_del)
 		return -EOPNOTSUPP;
 
-	return dev->dev_ops->vlan_del(dev, port, vlan);
+	ksz_get_pvid(dev, port, &pvid);
+
+	ret = dev->dev_ops->vlan_del(dev, port, vlan);
+	if (ret)
+		return ret;
+
+	if (vlan->vid == pvid) {
+		p->bridge_pvid.valid = false;
+
+		ret = ksz_commit_pvid(ds, port);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
 }
 
 static int ksz_port_mirror_add(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/microchip/ksz_common.h
b/drivers/net/dsa/microchip/ksz_common.h
index 764ada3a0f42..c583cda6cc3d 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -63,6 +63,11 @@ struct ksz_chip_data {
 	bool internal_phy[KSZ_MAX_NUM_PORTS];
 };
 
+struct ksz_vlan {
+	u16	vid;
+	bool	valid;
+};
+
 struct ksz_port {
 	bool remove_tag;		/* Remove Tag flag set, for
ksz8795 only */
 	int stp_state;
@@ -81,6 +86,7 @@ struct ksz_port {
 	u16 max_frame;
 	u32 rgmii_tx_val;
 	u32 rgmii_rx_val;
+	struct ksz_vlan bridge_pvid;
 };
 
 struct ksz_device {
@@ -175,6 +181,7 @@ enum ksz_regs {
 	S_MULTICAST_CTRL,
 	P_XMII_CTRL_0,
 	P_XMII_CTRL_1,
+	P_DEFAULT_PVID,
 };
 
 enum ksz_masks {
@@ -272,6 +279,7 @@ struct ksz_dev_ops {
 			 struct netlink_ext_ack *extack);
 	int  (*vlan_del)(struct ksz_device *dev, int port,
 			 const struct switchdev_obj_port_vlan *vlan);
+	void (*drop_untagged)(struct ksz_device *dev, int port, bool
untagged);
 	int (*mirror_add)(struct ksz_device *dev, int port,
 			  struct dsa_mall_mirror_tc_entry *mirror,
 			  bool ingress, struct netlink_ext_ack
*extack);
@@ -434,6 +442,14 @@ static inline void ksz_prmw8(struct ksz_device
*dev, int port, int offset,
 			   mask, val);
 }
 
+static inline void ksz_prmw16(struct ksz_device *dev, int port, int
offset,
+			      u16 mask, u16 val)
+{
+	regmap_update_bits(dev->regmap[1],
+			   dev->dev_ops->get_port_addr(port, offset),
+			   mask, val);
+}
+
 static inline void ksz_regmap_lock(void *__mtx)
 {
 	struct mutex *mtx = __mtx;
-- 
2.36.1
                                

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ