diff mbox series

[net-next,12/14] net: dsa: Wire up multicast IGMP snooping attribute notification

Message ID 20190116200102.2749-13-f.fainelli@gmail.com
State Changes Requested
Delegated to: David Miller
Headers show
Series net: dsa: management mode for bcm_sf2 | expand

Commit Message

Florian Fainelli Jan. 16, 2019, 8:01 p.m. UTC
The bridge can at runtime be configured with or without IGMP snooping
enabled but we were not processing the switchdev attribute that notifies
about that toggle, do this now.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 include/net/dsa.h  |  2 ++
 net/dsa/dsa_priv.h | 11 +++++++++++
 net/dsa/port.c     | 13 +++++++++++++
 net/dsa/slave.c    |  4 ++++
 net/dsa/switch.c   | 28 ++++++++++++++++++++++++++++
 5 files changed, 58 insertions(+)

Comments

Vivien Didelot Jan. 17, 2019, 6:36 p.m. UTC | #1
On Wed, 16 Jan 2019 12:01:00 -0800, Florian Fainelli <f.fainelli@gmail.com> wrote:

> +	int	(*port_multicast_toggle)(struct dsa_switch *ds, int port,
> +					 bool mc_disabled);
 
Waw this looks counter-intuitive and error-prone... Would you prefer to make it
symmetrical to ops->port_vlan_filtering() by implementing ops->port_multicast()
and passing !obj->u.mc_disabled to it?


Thanks,

	Vivien
Florian Fainelli Jan. 17, 2019, 7:07 p.m. UTC | #2
On 1/17/19 10:36 AM, Vivien Didelot wrote:
> On Wed, 16 Jan 2019 12:01:00 -0800, Florian Fainelli <f.fainelli@gmail.com> wrote:
> 
>> +	int	(*port_multicast_toggle)(struct dsa_switch *ds, int port,
>> +					 bool mc_disabled);
>  
> Waw this looks counter-intuitive and error-prone... Would you prefer to make it
> symmetrical to ops->port_vlan_filtering() by implementing ops->port_multicast()
> and passing !obj->u.mc_disabled to it?

I debated doing that, but I think it is better to have the same boolean
polarity from end to end, even if it is highly counter intuitive as you
said. That is kind of the story of bridge attributes annyway, completely
counter intuitive.
diff mbox series

Patch

diff --git a/include/net/dsa.h b/include/net/dsa.h
index b3eefe8e18fd..11cd4db3bc9e 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -479,6 +479,8 @@  struct dsa_switch_ops {
 	/*
 	 * Multicast database
 	 */
+	int	(*port_multicast_toggle)(struct dsa_switch *ds, int port,
+					 bool mc_disabled);
 	int (*port_mdb_prepare)(struct dsa_switch *ds, int port,
 				const struct switchdev_obj_port_mdb *mdb);
 	void (*port_mdb_add)(struct dsa_switch *ds, int port,
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index aad8acc70183..6f7ed2b3494f 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -27,6 +27,7 @@  enum {
 	DSA_NOTIFIER_VLAN_ADD,
 	DSA_NOTIFIER_VLAN_DEL,
 	DSA_NOTIFIER_VLAN_FILTERING,
+	DSA_NOTIFIER_MC_DISABLED,
 };
 
 /* DSA_NOTIFIER_AGEING_TIME */
@@ -74,6 +75,14 @@  struct dsa_notifier_vlan_filtering_info {
 	int port;
 };
 
+/* DSA_NOTIFIER_MC_DISABLED */
+struct dsa_notifier_mc_disabled_info {
+	bool mc_disabled;
+	struct switchdev_trans *trans;
+	int sw_index;
+	int port;
+};
+
 struct dsa_slave_priv {
 	/* Copy of CPU port xmit for faster access in slave transmit hot path */
 	struct sk_buff *	(*xmit)(struct sk_buff *skb,
@@ -154,6 +163,8 @@  int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy);
 void dsa_port_disable(struct dsa_port *dp, struct phy_device *phy);
 int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br);
 void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
+int dsa_port_multicast_toggle(struct dsa_port *dp, bool mc_disabled,
+			      struct switchdev_trans *trans);
 int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
 			    struct switchdev_trans *trans);
 int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
diff --git a/net/dsa/port.c b/net/dsa/port.c
index d7b057d46460..148458941b51 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -143,6 +143,19 @@  void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
 	dsa_port_set_state_now(dp, BR_STATE_FORWARDING);
 }
 
+int dsa_port_multicast_toggle(struct dsa_port *dp, bool mc_disabled,
+			      struct switchdev_trans *trans)
+{
+	struct dsa_notifier_mc_disabled_info info = {
+		.sw_index = dp->ds->index,
+		.port = dp->index,
+		.trans = trans,
+		.mc_disabled = mc_disabled,
+	};
+
+	return dsa_port_notify(dp, DSA_NOTIFIER_MC_DISABLED, &info);
+}
+
 int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
 			    struct switchdev_trans *trans)
 {
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index e266ef329583..acb7f1830e98 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -337,6 +337,10 @@  static int dsa_slave_port_attr_set(struct net_device *dev,
 	case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
 		ret = dsa_port_ageing_time(dp, attr->u.ageing_time, trans);
 		break;
+	case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
+		ret = dsa_port_multicast_toggle(dp, attr->u.mc_disabled,
+						trans);
+		break;
 	default:
 		ret = -EOPNOTSUPP;
 		break;
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index 831334dc5e79..e095eb808434 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -261,6 +261,31 @@  static int dsa_switch_vlan_filtering(struct dsa_switch *ds,
 	return 0;
 }
 
+static int dsa_switch_mc_disabled(struct dsa_switch *ds,
+				  struct dsa_notifier_mc_disabled_info *info)
+{
+	struct switchdev_trans *trans = info->trans;
+	bool mc_disabled = info->mc_disabled;
+	int port = info->port;
+	int err;
+
+	if (switchdev_trans_ph_prepare(trans))
+		return ds->ops->port_multicast_toggle ? 0 : -EOPNOTSUPP;
+
+	/* Build a mask of port members */
+	bitmap_zero(ds->bitmap, ds->num_ports);
+	if (ds->index == info->sw_index)
+		set_bit(port, ds->bitmap);
+
+	for_each_set_bit(port, ds->bitmap, ds->num_ports) {
+		err = ds->ops->port_multicast_toggle(ds, port, mc_disabled);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 static int dsa_switch_event(struct notifier_block *nb,
 			    unsigned long event, void *info)
 {
@@ -298,6 +323,9 @@  static int dsa_switch_event(struct notifier_block *nb,
 	case DSA_NOTIFIER_VLAN_FILTERING:
 		err = dsa_switch_vlan_filtering(ds, info);
 		break;
+	case DSA_NOTIFIER_MC_DISABLED:
+		err = dsa_switch_mc_disabled(ds, info);
+		break;
 	default:
 		err = -EOPNOTSUPP;
 		break;