Thread (17 messages) flat view 17 messages, 3 authors, 2021-11-19

Re: [RFC PATCH net-next 6/6] net: dsa: eliminate dsa_switch_ops :: port_bridge_tx_fwd_{,un}offload

From: Alvin Šipraga <hidden>
Date: 2021-11-11 13:23:24

On 10/26/21 18:26, Vladimir Oltean wrote:
We don't really need new switch API for these, and with new switches
which intend to add support for this feature, it will become cumbersome
to maintain.

Simply pass a boolean argument to ->port_bridge_join which the driver
must set to true if it implements the TX forwarding offload feature.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Reviewed-by: Alvin Šipraga <redacted>
quoted hunk ↗ jump to hunk
  drivers/net/dsa/b53/b53_common.c       |  3 +-
  drivers/net/dsa/b53/b53_priv.h         |  3 +-
  drivers/net/dsa/dsa_loop.c             |  3 +-
  drivers/net/dsa/hirschmann/hellcreek.c |  3 +-
  drivers/net/dsa/lan9303-core.c         |  3 +-
  drivers/net/dsa/lantiq_gswip.c         |  3 +-
  drivers/net/dsa/microchip/ksz_common.c |  3 +-
  drivers/net/dsa/microchip/ksz_common.h |  2 +-
  drivers/net/dsa/mt7530.c               |  2 +-
  drivers/net/dsa/mv88e6xxx/chip.c       | 71 ++++++++++++--------------
  drivers/net/dsa/ocelot/felix.c         |  2 +-
  drivers/net/dsa/qca8k.c                |  3 +-
  drivers/net/dsa/rtl8366rb.c            |  3 +-
  drivers/net/dsa/sja1105/sja1105_main.c | 22 ++++++--
  drivers/net/dsa/xrs700x/xrs700x.c      |  2 +-
  include/net/dsa.h                      | 10 ++--
  net/dsa/dsa_priv.h                     |  1 +
  net/dsa/port.c                         | 39 ++------------
  net/dsa/switch.c                       |  3 +-
  19 files changed, 81 insertions(+), 100 deletions(-)
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 4e41b1a63108..3867f3d4545f 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1860,7 +1860,8 @@ int b53_mdb_del(struct dsa_switch *ds, int port,
  }
  EXPORT_SYMBOL(b53_mdb_del);
  
-int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge)
+int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge,
+		bool *tx_fwd_offload)
  {
  	struct b53_device *dev = ds->priv;
  	s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h
index ee17f8b516ca..b41dc8ac2ca8 100644
--- a/drivers/net/dsa/b53/b53_priv.h
+++ b/drivers/net/dsa/b53/b53_priv.h
@@ -324,7 +324,8 @@ void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset,
  void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
  int b53_get_sset_count(struct dsa_switch *ds, int port, int sset);
  void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t *data);
-int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge);
+int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge,
+		bool *tx_fwd_offload);
  void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge);
  void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state);
  void b53_br_fast_age(struct dsa_switch *ds, int port);
diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c
index 70db3a9aa355..33daaf10c488 100644
--- a/drivers/net/dsa/dsa_loop.c
+++ b/drivers/net/dsa/dsa_loop.c
@@ -167,7 +167,8 @@ static int dsa_loop_phy_write(struct dsa_switch *ds, int port,
  }
  
  static int dsa_loop_port_bridge_join(struct dsa_switch *ds, int port,
-				     struct dsa_bridge bridge)
+				     struct dsa_bridge bridge,
+				     bool *tx_fwd_offload)
  {
  	dev_dbg(ds->dev, "%s: port: %d, bridge: %s\n",
  		__func__, port, bridge.dev->name);
diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c
index 17c2d13670a9..53ab5f8ae92e 100644
--- a/drivers/net/dsa/hirschmann/hellcreek.c
+++ b/drivers/net/dsa/hirschmann/hellcreek.c
@@ -674,7 +674,8 @@ static int hellcreek_bridge_flags(struct dsa_switch *ds, int port,
  }
  
  static int hellcreek_port_bridge_join(struct dsa_switch *ds, int port,
-				      struct dsa_bridge bridge)
+				      struct dsa_bridge bridge,
+				      bool *tx_fwd_offload)
  {
  	struct hellcreek *hellcreek = ds->priv;
  
diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c
index 29d909484275..d55784d19fa4 100644
--- a/drivers/net/dsa/lan9303-core.c
+++ b/drivers/net/dsa/lan9303-core.c
@@ -1103,7 +1103,8 @@ static void lan9303_port_disable(struct dsa_switch *ds, int port)
  }
  
  static int lan9303_port_bridge_join(struct dsa_switch *ds, int port,
-				    struct dsa_bridge bridge)
+				    struct dsa_bridge bridge,
+				    bool *tx_fwd_offload)
  {
  	struct lan9303 *chip = ds->priv;
  
diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c
index 6b9b9c712e58..6b5bef7f2a59 100644
--- a/drivers/net/dsa/lantiq_gswip.c
+++ b/drivers/net/dsa/lantiq_gswip.c
@@ -1146,7 +1146,8 @@ static int gswip_vlan_remove(struct gswip_priv *priv,
  }
  
  static int gswip_port_bridge_join(struct dsa_switch *ds, int port,
-				  struct dsa_bridge bridge)
+				  struct dsa_bridge bridge,
+				  bool *tx_fwd_offload)
  {
  	struct net_device *br = bridge.dev;
  	struct gswip_priv *priv = ds->priv;
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 23784d14a5da..1d13aa56e7d1 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -173,7 +173,8 @@ void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf)
  EXPORT_SYMBOL_GPL(ksz_get_ethtool_stats);
  
  int ksz_port_bridge_join(struct dsa_switch *ds, int port,
-			 struct dsa_bridge bridge)
+			 struct dsa_bridge bridge,
+			 bool *tx_fwd_offload)
  {
  	struct ksz_device *dev = ds->priv;
  
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index df953c2bc56e..b444df218c2d 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -159,7 +159,7 @@ void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
  int ksz_sset_count(struct dsa_switch *ds, int port, int sset);
  void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf);
  int ksz_port_bridge_join(struct dsa_switch *ds, int port,
-			 struct dsa_bridge bridge);
+			 struct dsa_bridge bridge, bool *tx_fwd_offload);
  void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
  			   struct dsa_bridge bridge);
  void ksz_port_fast_age(struct dsa_switch *ds, int port);
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 85cc5aca7f96..dcd1a3932cfb 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -1186,7 +1186,7 @@ mt7530_port_bridge_flags(struct dsa_switch *ds, int port,
  
  static int
  mt7530_port_bridge_join(struct dsa_switch *ds, int port,
-			struct dsa_bridge bridge)
+			struct dsa_bridge bridge, bool *tx_fwd_offload)
  {
  	struct mt7530_priv *priv = ds->priv;
  	u32 port_bitmap = BIT(MT7530_CPU_PORT);
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 73613a667f6c..0aac71dece29 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2448,8 +2448,27 @@ static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
  	return 0;
  }
  
+/* Treat the software bridge as a virtual single-port switch behind the
+ * CPU and map in the PVT. First dst->last_switch elements are taken by
+ * physical switches, so start from beyond that range.
+ */
+static int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds,
+					       unsigned int bridge_num)
+{
+	u8 dev = bridge_num + ds->dst->last_switch;
+	struct mv88e6xxx_chip *chip = ds->priv;
+	int err;
+
+	mv88e6xxx_reg_lock(chip);
+	err = mv88e6xxx_pvt_map(chip, dev, 0);
+	mv88e6xxx_reg_unlock(chip);
+
+	return err;
+}
+
  static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
-				      struct dsa_bridge bridge)
+				      struct dsa_bridge bridge,
+				      bool *tx_fwd_offload)
  {
  	struct mv88e6xxx_chip *chip = ds->priv;
  	int err;
@@ -2464,6 +2483,14 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
  	if (err)
  		goto unlock;
  
+	if (mv88e6xxx_has_pvt(chip)) {
+		err = mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num);
+		if (err)
+			goto unlock;
+
+		*tx_fwd_offload = true;
+	}
+
  unlock:
  	mv88e6xxx_reg_unlock(chip);
  
@@ -2478,6 +2505,10 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
  
  	mv88e6xxx_reg_lock(chip);
  
+	if (bridge.tx_fwd_offload &&
+	    mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num))
+		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
+
  	if (mv88e6xxx_bridge_map(chip, bridge) ||
  	    mv88e6xxx_port_vlan_map(chip, port))
  		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
@@ -2523,42 +2554,6 @@ static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds,
  	mv88e6xxx_reg_unlock(chip);
  }
  
-/* Treat the software bridge as a virtual single-port switch behind the
- * CPU and map in the PVT. First dst->last_switch elements are taken by
- * physical switches, so start from beyond that range.
- */
-static int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds,
-					       unsigned int bridge_num)
-{
-	u8 dev = bridge_num + ds->dst->last_switch;
-	struct mv88e6xxx_chip *chip = ds->priv;
-	int err;
-
-	mv88e6xxx_reg_lock(chip);
-	err = mv88e6xxx_pvt_map(chip, dev, 0);
-	mv88e6xxx_reg_unlock(chip);
-
-	return err;
-}
-
-static int mv88e6xxx_bridge_tx_fwd_offload(struct dsa_switch *ds, int port,
-					   struct dsa_bridge bridge)
-{
-	return mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num);
-}
-
-static void mv88e6xxx_bridge_tx_fwd_unoffload(struct dsa_switch *ds, int port,
-					      struct dsa_bridge bridge)
-{
-	int err;
-
-	err = mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num);
-	if (err) {
-		dev_err(ds->dev, "failed to remap cross-chip Port VLAN: %pe\n",
-			ERR_PTR(err));
-	}
-}
-
  static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
  {
  	if (chip->info->ops->reset)
@@ -6278,8 +6273,6 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
  	.crosschip_lag_change	= mv88e6xxx_crosschip_lag_change,
  	.crosschip_lag_join	= mv88e6xxx_crosschip_lag_join,
  	.crosschip_lag_leave	= mv88e6xxx_crosschip_lag_leave,
-	.port_bridge_tx_fwd_offload = mv88e6xxx_bridge_tx_fwd_offload,
-	.port_bridge_tx_fwd_unoffload = mv88e6xxx_bridge_tx_fwd_unoffload,
  };
  
  static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 8cf82fa91a6b..001213891b91 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -698,7 +698,7 @@ static int felix_bridge_flags(struct dsa_switch *ds, int port,
  }
  
  static int felix_bridge_join(struct dsa_switch *ds, int port,
-			     struct dsa_bridge bridge)
+			     struct dsa_bridge bridge, bool *tx_fwd_offload)
  {
  	struct ocelot *ocelot = ds->priv;
  
diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index 3ae10f22ada9..390dad77f062 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -1729,7 +1729,8 @@ qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
  }
  
  static int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
-				  struct dsa_bridge bridge)
+				  struct dsa_bridge bridge,
+				  bool *tx_fwd_offload)
  {
  	struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
  	int port_mask, cpu_port;
diff --git a/drivers/net/dsa/rtl8366rb.c b/drivers/net/dsa/rtl8366rb.c
index fac2333a3f5e..ecc19bd5115f 100644
--- a/drivers/net/dsa/rtl8366rb.c
+++ b/drivers/net/dsa/rtl8366rb.c
@@ -1186,7 +1186,8 @@ rtl8366rb_port_disable(struct dsa_switch *ds, int port)
  
  static int
  rtl8366rb_port_bridge_join(struct dsa_switch *ds, int port,
-			   struct dsa_bridge bridge)
+			   struct dsa_bridge bridge,
+			   bool *tx_fwd_offload)
  {
  	struct realtek_smi *smi = ds->priv;
  	unsigned int port_bitmap = 0;
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 24584fe2e760..cefde41ce8d6 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -2074,14 +2074,30 @@ static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port,
  }
  
  static int sja1105_bridge_join(struct dsa_switch *ds, int port,
-			       struct dsa_bridge bridge)
+			       struct dsa_bridge bridge,
+			       bool *tx_fwd_offload)
  {
-	return sja1105_bridge_member(ds, port, bridge, true);
+	int rc;
+
+	rc = sja1105_bridge_member(ds, port, bridge, true);
+	if (rc)
+		return rc;
+
+	rc = dsa_tag_8021q_bridge_tx_fwd_offload(ds, port, bridge);
+	if (rc) {
+		sja1105_bridge_member(ds, port, bridge, false);
+		return rc;
+	}
+
+	*tx_fwd_offload = true;
+
+	return 0;
  }
  
  static void sja1105_bridge_leave(struct dsa_switch *ds, int port,
  				 struct dsa_bridge bridge)
  {
+	dsa_tag_8021q_bridge_tx_fwd_unoffload(ds, port, bridge);
  	sja1105_bridge_member(ds, port, bridge, false);
  }
  
@@ -3230,8 +3246,6 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
  	.tag_8021q_vlan_add	= sja1105_dsa_8021q_vlan_add,
  	.tag_8021q_vlan_del	= sja1105_dsa_8021q_vlan_del,
  	.port_prechangeupper	= sja1105_prechangeupper,
-	.port_bridge_tx_fwd_offload = dsa_tag_8021q_bridge_tx_fwd_offload,
-	.port_bridge_tx_fwd_unoffload = dsa_tag_8021q_bridge_tx_fwd_unoffload,
  };
  
  static const struct of_device_id sja1105_dt_ids[];
diff --git a/drivers/net/dsa/xrs700x/xrs700x.c b/drivers/net/dsa/xrs700x/xrs700x.c
index ebb55dfd9c4e..35fa19ddaf19 100644
--- a/drivers/net/dsa/xrs700x/xrs700x.c
+++ b/drivers/net/dsa/xrs700x/xrs700x.c
@@ -540,7 +540,7 @@ static int xrs700x_bridge_common(struct dsa_switch *ds, int port,
  }
  
  static int xrs700x_bridge_join(struct dsa_switch *ds, int port,
-			       struct dsa_bridge bridge)
+			       struct dsa_bridge bridge, bool *tx_fwd_offload)
  {
  	return xrs700x_bridge_common(ds, port, bridge, true);
  }
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 5e83c64bc96a..94dc8b5ee9c8 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -222,6 +222,7 @@ struct dsa_mall_tc_entry {
  struct dsa_bridge {
  	struct net_device *dev;
  	unsigned int num;
+	bool tx_fwd_offload;
  	refcount_t refcount;
  };
  
@@ -814,15 +815,10 @@ struct dsa_switch_ops {
  	 */
  	int	(*set_ageing_time)(struct dsa_switch *ds, unsigned int msecs);
  	int	(*port_bridge_join)(struct dsa_switch *ds, int port,
-				    struct dsa_bridge bridge);
+				    struct dsa_bridge bridge,
+				    bool *tx_fwd_offload);
  	void	(*port_bridge_leave)(struct dsa_switch *ds, int port,
  				     struct dsa_bridge bridge);
-	/* Called right after .port_bridge_join() */
-	int	(*port_bridge_tx_fwd_offload)(struct dsa_switch *ds, int port,
-					      struct dsa_bridge bridge);
-	/* Called right before .port_bridge_leave() */
-	void	(*port_bridge_tx_fwd_unoffload)(struct dsa_switch *ds, int port,
-						struct dsa_bridge bridge);
  	void	(*port_stp_state_set)(struct dsa_switch *ds, int port,
  				      u8 state);
  	void	(*port_fast_age)(struct dsa_switch *ds, int port);
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 489712ead08f..5abe6864967a 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -56,6 +56,7 @@ struct dsa_notifier_bridge_info {
  	int tree_index;
  	int sw_index;
  	int port;
+	bool tx_fwd_offload;
  };
  
  /* DSA_NOTIFIER_FDB_* */
diff --git a/net/dsa/port.c b/net/dsa/port.c
index b2e66994f72c..b1113788bf9b 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -270,37 +270,6 @@ static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp)
  	 */
  }
  
-static void dsa_port_bridge_tx_fwd_unoffload(struct dsa_port *dp,
-					     struct dsa_bridge bridge)
-{
-	struct dsa_switch *ds = dp->ds;
-
-	/* No bridge TX forwarding offload => do nothing */
-	if (!ds->ops->port_bridge_tx_fwd_unoffload || !bridge.num)
-		return;
-
-	/* Notify the chips only once the offload has been deactivated, so
-	 * that they can update their configuration accordingly.
-	 */
-	ds->ops->port_bridge_tx_fwd_unoffload(ds, dp->index, bridge);
-}
-
-static bool dsa_port_bridge_tx_fwd_offload(struct dsa_port *dp,
-					   struct dsa_bridge bridge)
-{
-	struct dsa_switch *ds = dp->ds;
-	int err;
-
-	/* FDB isolation is required for TX forwarding offload */
-	if (!ds->ops->port_bridge_tx_fwd_offload || !bridge.num)
-		return false;
-
-	/* Notify the driver */
-	err = ds->ops->port_bridge_tx_fwd_offload(ds, dp->index, bridge);
-
-	return err ? false : true;
-}
-
  static int dsa_port_bridge_create(struct dsa_port *dp,
  				  struct net_device *br,
  				  struct netlink_ext_ack *extack)
@@ -361,7 +330,6 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
  	};
  	struct net_device *dev = dp->slave;
  	struct net_device *brport_dev;
-	bool tx_fwd_offload;
  	int err;
  
  	/* Here the interface is already bridged. Reflect the current
@@ -378,12 +346,13 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
  	if (err)
  		goto out_rollback;
  
-	tx_fwd_offload = dsa_port_bridge_tx_fwd_offload(dp, info.bridge);
+	/* Drivers which support bridge TX forwarding should set this */
+	dp->bridge->tx_fwd_offload = info.tx_fwd_offload;
  
  	err = switchdev_bridge_port_offload(brport_dev, dev, dp,
  					    &dsa_slave_switchdev_notifier,
  					    &dsa_slave_switchdev_blocking_notifier,
-					    tx_fwd_offload, extack);
+					    dp->bridge->tx_fwd_offload, extack);
  	if (err)
  		goto out_rollback_unbridge;
  
@@ -434,8 +403,6 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
  	 */
  	dsa_port_bridge_destroy(dp, br);
  
-	dsa_port_bridge_tx_fwd_unoffload(dp, info.bridge);
-
  	err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info);
  	if (err)
  		dev_err(dp->ds->dev,
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index cd0630dd5417..9c92edd96961 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -95,7 +95,8 @@ static int dsa_switch_bridge_join(struct dsa_switch *ds,
  		if (!ds->ops->port_bridge_join)
  			return -EOPNOTSUPP;
  
-		err = ds->ops->port_bridge_join(ds, info->port, info->bridge);
+		err = ds->ops->port_bridge_join(ds, info->port, info->bridge,
+						&info->tx_fwd_offload);
  		if (err)
  			return err;
  	}
  
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help