[PATCH v3 2/2] net: mscc: Implement promisc mode.
From: Horatiu Vultur
Date: Thu Aug 29 2019 - 05:24:23 EST
When a port is added to the bridge, the port is added in promisc mode. But
the HW is capable of switching the frames therefore is not needed for the
port to be added in promisc mode. In case a user space application requires
for the port to enter promisc mode then is it needed to enter the promisc
mode.
Therefore listen in when the promiscuity on a dev is change and when the
port enters or leaves a bridge. Having this information it is possible to
know when to set the port in promisc mode and when not:
If the port is part of bridge and promiscuity > 1 or if the port is not
part of bridge and promiscuity is > 0 then add then add the port in promisc
mode otherwise don't.
Signed-off-by: Horatiu Vultur <horatiu.vultur@xxxxxxxxxxxxx>
---
drivers/net/ethernet/mscc/ocelot.c | 47 ++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 4d1bce4..292fcc1 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -1294,6 +1294,37 @@ static void ocelot_port_attr_mc_set(struct ocelot_port *port, bool mc)
ocelot_write_gix(ocelot, val, ANA_PORT_CPU_FWD_CFG, port->chip_port);
}
+static void ocelot_port_attr_promisc_set(struct ocelot_port *port,
+ unsigned int promisc,
+ bool is_bridge_port)
+{
+ struct ocelot *ocelot = port->ocelot;
+ u32 val;
+
+ val = ocelot_read_gix(ocelot, ANA_PORT_CPU_FWD_CFG, port->chip_port);
+
+ /* When a port is added to a bridge, the port is added in promisc mode,
+ * by calling the function 'ndo_set_rx_mode'. But the HW is capable
+ * of switching the frames therefore is not needed for the port to
+ * enter in promisc mode.
+ * But a port needs to be added in promisc mode if an application
+ * requires it(pcap library). Therefore listen when the
+ * dev->promiscuity is change and when the port is added or removed from
+ * the bridge. Using this information, calculate if the promisc mode
+ * is required in the following way:
+ */
+ if (!is_bridge_port && promisc > 0) {
+ val |= ANA_PORT_CPU_FWD_CFG_CPU_SRC_COPY_ENA;
+ } else {
+ if (is_bridge_port && promisc > 1)
+ val |= ANA_PORT_CPU_FWD_CFG_CPU_SRC_COPY_ENA;
+ else
+ val &= ~(ANA_PORT_CPU_FWD_CFG_CPU_SRC_COPY_ENA);
+ }
+
+ ocelot_write_gix(ocelot, val, ANA_PORT_CPU_FWD_CFG, port->chip_port);
+}
+
static int ocelot_port_attr_set(struct net_device *dev,
const struct switchdev_attr *attr,
struct switchdev_trans *trans)
@@ -1316,6 +1347,10 @@ static int ocelot_port_attr_set(struct net_device *dev,
case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
ocelot_port_attr_mc_set(ocelot_port, !attr->u.mc_disabled);
break;
+ case SWITCHDEV_ATTR_ID_PORT_PROMISCUITY:
+ ocelot_port_attr_promisc_set(ocelot_port, dev->promiscuity,
+ netif_is_bridge_port(dev));
+ break;
default:
err = -EOPNOTSUPP;
break;
@@ -1688,6 +1723,18 @@ static int ocelot_netdevice_port_event(struct net_device *dev,
ocelot_vlan_port_apply(ocelot_port->ocelot,
ocelot_port);
+
+ /* In case the port is added or removed from the bridge
+ * is it needed to recaulculate the promiscuity. The
+ * reason is that when a port leaves the bridge first
+ * it decrease the promiscuity and then the flag
+ * IFF_BRIDGE_PORT is removed from dev. Therefor the
+ * function ocelot_port_attr_promisc is called with
+ * the wrong arguments.
+ */
+ ocelot_port_attr_promisc_set(ocelot_port,
+ dev->promiscuity,
+ info->linking);
}
if (netif_is_lag_master(info->upper_dev)) {
if (info->linking)
--
2.7.4