[RFC net-next] net: dsa: add support for MC_DISABLED attribute

Vivien Didelot
2019-06-20T23:57:13Z

This patch adds support for enabling or disabling the flooding of
unknown multicast traffic on the CPU ports, depending on the value
of the switchdev SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED attribute.

This allows the user to prevent the CPU to be flooded with a lot of
undesirable traffic that the network stack needs to filter in software.

The bridge has multicast snooping enabled by default, hence CPU ports
aren't bottlenecked with arbitrary network applications anymore.
But this can be an issue in some scenarios such as pinging the bridge's
IPv6 address. Setting /sys/class/net/br0/bridge/multicast_snooping to
0 would restore unknown multicast flooding and thus fix ICMPv6. As
an alternative, enabling multicast_querier would program the bridge
address into the switch.

Signed-off-by: Vivien Didelot <vivien.didelot@gmail.com>
---
net/dsa/dsa_priv.h | 2 ++
net/dsa/port.c | 19 +++++++++++++++++++
net/dsa/slave.c | 4 ++++
3 files changed, 25 insertions(+)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index a4853c22c2ff..54d838956499 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -163,6 +163,8 @@ int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags,
struct switchdev_trans *trans);
int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags,
struct switchdev_trans *trans);
+int dsa_port_bridge_mc_disabled(const struct dsa_port *dp, bool mc_disabled,
+ struct switchdev_trans *trans);
int dsa_port_vlan_add(struct dsa_port *dp,
const struct switchdev_obj_port_vlan *vlan,
struct switchdev_trans *trans);
diff --git a/net/dsa/port.c b/net/dsa/port.c
index d2b65e8dc60c..79d14c36ef9a 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -261,6 +261,25 @@ int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags,
return err;
}

+int dsa_port_bridge_mc_disabled(const struct dsa_port *dp, bool mc_disabled,
+ struct switchdev_trans *trans)
+{
+ struct dsa_switch *ds = dp->ds;
+ int port = dp->index;
+
+ if (switchdev_trans_ph_prepare(trans)) {
+ if (!ds->ops->port_egress_floods)
+ return -EOPNOTSUPP;
+
+ return 0;
+ }
+
+ /* When multicast snooping is disabled,
+ * every multicast packet should be flooded to the CPU port.
+ */
+ return ds->ops->port_egress_floods(ds, port, true, mc_disabled);
+}
+
int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
u16 vid)
{
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index db58e748557d..9308ffa4f22c 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -302,6 +302,10 @@ static int dsa_slave_port_attr_set(struct net_device *dev,
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, trans);
break;
+ case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
+ ret = dsa_port_bridge_mc_disabled(dp->cpu_dp,
+ attr->u.mc_disabled, trans);
+ break;
default:
ret = -EOPNOTSUPP;
break;
--
2.22.0