netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch net-next v2 0/3] add support for peer notifications and igmp rejoins for team
@ 2013-07-20 10:13 Jiri Pirko
  2013-07-20 10:13 ` [patch net-next v2 1/3] team: add peer notification Jiri Pirko
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Jiri Pirko @ 2013-07-20 10:13 UTC (permalink / raw)
  To: netdev
  Cc: davem, fubar, andy, kaber, stephen, kuznet, jmorris, yoshfuji, edumazet

The middle patch adjusts core infrastructure so the bonding code can be
generalized and reused by team.

v1->v2: using msecs_to_jiffies() as suggested by Eric

Jiri Pirko (3):
  team: add peer notification
  net: convert resend IGMP to notifier event
  team: add support for sending multicast rejoins

 drivers/net/bonding/bond_main.c |  44 ++--------
 drivers/net/team/team.c         | 176 ++++++++++++++++++++++++++++++++++++++++
 include/linux/if_team.h         |  14 +++-
 include/linux/igmp.h            |   1 -
 include/linux/netdevice.h       |   1 +
 net/8021q/vlan.c                |   1 +
 net/bridge/br_notify.c          |   5 ++
 net/ipv4/igmp.c                 |  46 +++++++++--
 8 files changed, 245 insertions(+), 43 deletions(-)

-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [patch net-next v2 1/3] team: add peer notification
  2013-07-20 10:13 [patch net-next v2 0/3] add support for peer notifications and igmp rejoins for team Jiri Pirko
@ 2013-07-20 10:13 ` Jiri Pirko
  2013-07-20 10:13 ` [patch net-next v2 2/3] net: convert resend IGMP to notifier event Jiri Pirko
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Jiri Pirko @ 2013-07-20 10:13 UTC (permalink / raw)
  To: netdev
  Cc: davem, fubar, andy, kaber, stephen, kuznet, jmorris, yoshfuji, edumazet

When port is enabled or disabled, allow to notify peers by unsolicitated
NAs or gratuitous ARPs. Disabled by default.

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
 drivers/net/team/team.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/if_team.h |  8 ++++-
 2 files changed, 94 insertions(+), 1 deletion(-)

diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index bff7e0b..0433ee9 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -622,6 +622,46 @@ static int team_change_mode(struct team *team, const char *kind)
 }
 
 
+/*********************
+ * Peers notification
+ *********************/
+
+static void team_notify_peers_work(struct work_struct *work)
+{
+	struct team *team;
+
+	team = container_of(work, struct team, notify_peers.dw.work);
+
+	if (!rtnl_trylock()) {
+		schedule_delayed_work(&team->notify_peers.dw, 0);
+		return;
+	}
+	call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, team->dev);
+	rtnl_unlock();
+	if (!atomic_dec_and_test(&team->notify_peers.count_pending))
+		schedule_delayed_work(&team->notify_peers.dw,
+				      msecs_to_jiffies(team->notify_peers.interval));
+}
+
+static void team_notify_peers(struct team *team)
+{
+	if (!team->notify_peers.count || !netif_running(team->dev))
+		return;
+	atomic_set(&team->notify_peers.count_pending, team->notify_peers.count);
+	schedule_delayed_work(&team->notify_peers.dw, 0);
+}
+
+static void team_notify_peers_init(struct team *team)
+{
+	INIT_DELAYED_WORK(&team->notify_peers.dw, team_notify_peers_work);
+}
+
+static void team_notify_peers_fini(struct team *team)
+{
+	cancel_delayed_work_sync(&team->notify_peers.dw);
+}
+
+
 /************************
  * Rx path frame handler
  ************************/
@@ -846,6 +886,7 @@ static void team_port_enable(struct team *team,
 	team_queue_override_port_add(team, port);
 	if (team->ops.port_enabled)
 		team->ops.port_enabled(team, port);
+	team_notify_peers(team);
 }
 
 static void __reconstruct_port_hlist(struct team *team, int rm_index)
@@ -875,6 +916,7 @@ static void team_port_disable(struct team *team,
 	team->en_port_count--;
 	team_queue_override_port_del(team, port);
 	team_adjust_ops(team);
+	team_notify_peers(team);
 }
 
 #define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
@@ -1205,6 +1247,34 @@ static int team_mode_option_set(struct team *team, struct team_gsetter_ctx *ctx)
 	return team_change_mode(team, ctx->data.str_val);
 }
 
+static int team_notify_peers_count_get(struct team *team,
+				       struct team_gsetter_ctx *ctx)
+{
+	ctx->data.u32_val = team->notify_peers.count;
+	return 0;
+}
+
+static int team_notify_peers_count_set(struct team *team,
+				       struct team_gsetter_ctx *ctx)
+{
+	team->notify_peers.count = ctx->data.u32_val;
+	return 0;
+}
+
+static int team_notify_peers_interval_get(struct team *team,
+					  struct team_gsetter_ctx *ctx)
+{
+	ctx->data.u32_val = team->notify_peers.interval;
+	return 0;
+}
+
+static int team_notify_peers_interval_set(struct team *team,
+					  struct team_gsetter_ctx *ctx)
+{
+	team->notify_peers.interval = ctx->data.u32_val;
+	return 0;
+}
+
 static int team_port_en_option_get(struct team *team,
 				   struct team_gsetter_ctx *ctx)
 {
@@ -1317,6 +1387,18 @@ static const struct team_option team_options[] = {
 		.setter = team_mode_option_set,
 	},
 	{
+		.name = "notify_peers_count",
+		.type = TEAM_OPTION_TYPE_U32,
+		.getter = team_notify_peers_count_get,
+		.setter = team_notify_peers_count_set,
+	},
+	{
+		.name = "notify_peers_interval",
+		.type = TEAM_OPTION_TYPE_U32,
+		.getter = team_notify_peers_interval_get,
+		.setter = team_notify_peers_interval_set,
+	},
+	{
 		.name = "enabled",
 		.type = TEAM_OPTION_TYPE_BOOL,
 		.per_port = true,
@@ -1396,6 +1478,9 @@ static int team_init(struct net_device *dev)
 
 	INIT_LIST_HEAD(&team->option_list);
 	INIT_LIST_HEAD(&team->option_inst_list);
+
+	team_notify_peers_init(team);
+
 	err = team_options_register(team, team_options, ARRAY_SIZE(team_options));
 	if (err)
 		goto err_options_register;
@@ -1406,6 +1491,7 @@ static int team_init(struct net_device *dev)
 	return 0;
 
 err_options_register:
+	team_notify_peers_fini(team);
 	team_queue_override_fini(team);
 err_team_queue_override_init:
 	free_percpu(team->pcpu_stats);
@@ -1425,6 +1511,7 @@ static void team_uninit(struct net_device *dev)
 
 	__team_change_mode(team, NULL); /* cleanup */
 	__team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
+	team_notify_peers_fini(team);
 	team_queue_override_fini(team);
 	mutex_unlock(&team->lock);
 }
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index f6156f9..b0b8368 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -10,9 +10,9 @@
 #ifndef _LINUX_IF_TEAM_H_
 #define _LINUX_IF_TEAM_H_
 
-
 #include <linux/netpoll.h>
 #include <net/sch_generic.h>
+#include <linux/types.h>
 #include <uapi/linux/if_team.h>
 
 struct team_pcpu_stats {
@@ -194,6 +194,12 @@ struct team {
 	bool user_carrier_enabled;
 	bool queue_override_enabled;
 	struct list_head *qom_lists; /* array of queue override mapping lists */
+	struct {
+		unsigned int count;
+		unsigned int interval; /* in ms */
+		atomic_t count_pending;
+		struct delayed_work dw;
+	} notify_peers;
 	long mode_priv[TEAM_MODE_PRIV_LONGS];
 };
 
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [patch net-next v2 2/3] net: convert resend IGMP to notifier event
  2013-07-20 10:13 [patch net-next v2 0/3] add support for peer notifications and igmp rejoins for team Jiri Pirko
  2013-07-20 10:13 ` [patch net-next v2 1/3] team: add peer notification Jiri Pirko
@ 2013-07-20 10:13 ` Jiri Pirko
  2013-07-22 16:26   ` [net-next,v2,2/3] " Veaceslav Falico
  2013-07-20 10:13 ` [patch net-next v2 3/3] team: add support for sending multicast rejoins Jiri Pirko
  2013-07-23 23:54 ` [patch net-next v2 0/3] add support for peer notifications and igmp rejoins for team David Miller
  3 siblings, 1 reply; 6+ messages in thread
From: Jiri Pirko @ 2013-07-20 10:13 UTC (permalink / raw)
  To: netdev
  Cc: davem, fubar, andy, kaber, stephen, kuznet, jmorris, yoshfuji, edumazet

Until now, bond_resend_igmp_join_requests() looks for vlans attached to
bonding device, bridge where bonding act as port manually. It does not
care of other scenarios, like stacked bonds or team device above. Make
this more generic and use netdev notifier to propagate the event to
upper devices and to actually call ip_mc_rejoin_groups().

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
 drivers/net/bonding/bond_main.c | 44 ++++++++-------------------------------
 drivers/net/team/team.c         |  4 ++++
 include/linux/igmp.h            |  1 -
 include/linux/netdevice.h       |  1 +
 net/8021q/vlan.c                |  1 +
 net/bridge/br_notify.c          |  5 +++++
 net/ipv4/igmp.c                 | 46 +++++++++++++++++++++++++++++++++++------
 7 files changed, 60 insertions(+), 42 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 07f257d4..ae9864c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -715,15 +715,6 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
 	return err;
 }
 
-static void __bond_resend_igmp_join_requests(struct net_device *dev)
-{
-	struct in_device *in_dev;
-
-	in_dev = __in_dev_get_rcu(dev);
-	if (in_dev)
-		ip_mc_rejoin_groups(in_dev);
-}
-
 /*
  * Retrieve the list of registered multicast addresses for the bonding
  * device and retransmit an IGMP JOIN request to the current active
@@ -731,33 +722,12 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
  */
 static void bond_resend_igmp_join_requests(struct bonding *bond)
 {
-	struct net_device *bond_dev, *vlan_dev, *upper_dev;
-	struct vlan_entry *vlan;
-
-	read_lock(&bond->lock);
-	rcu_read_lock();
-
-	bond_dev = bond->dev;
-
-	/* rejoin all groups on bond device */
-	__bond_resend_igmp_join_requests(bond_dev);
-
-	/*
-	 * if bond is enslaved to a bridge,
-	 * then rejoin all groups on its master
-	 */
-	upper_dev = netdev_master_upper_dev_get_rcu(bond_dev);
-	if (upper_dev && upper_dev->priv_flags & IFF_EBRIDGE)
-		__bond_resend_igmp_join_requests(upper_dev);
-
-	/* rejoin all groups on vlan devices */
-	list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-		vlan_dev = __vlan_find_dev_deep(bond_dev, htons(ETH_P_8021Q),
-						vlan->vlan_id);
-		if (vlan_dev)
-			__bond_resend_igmp_join_requests(vlan_dev);
+	if (!rtnl_trylock()) {
+		queue_delayed_work(bond->wq, &bond->mcast_work, 0);
+		return;
 	}
-	rcu_read_unlock();
+	call_netdevice_notifiers(NETDEV_RESEND_IGMP, bond->dev);
+	rtnl_unlock();
 
 	/* We use curr_slave_lock to protect against concurrent access to
 	 * igmp_retrans from multiple running instances of this function and
@@ -3234,6 +3204,10 @@ static int bond_slave_netdev_event(unsigned long event,
 	case NETDEV_FEAT_CHANGE:
 		bond_compute_features(bond);
 		break;
+	case NETDEV_RESEND_IGMP:
+		/* Propagate to master device */
+		call_netdevice_notifiers(event, slave->bond->dev);
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 0433ee9..2587dc8 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -2785,6 +2785,10 @@ static int team_device_event(struct notifier_block *unused,
 	case NETDEV_PRE_TYPE_CHANGE:
 		/* Forbid to change type of underlaying device */
 		return NOTIFY_BAD;
+	case NETDEV_RESEND_IGMP:
+		/* Propagate to master device */
+		call_netdevice_notifiers(event, port->team->dev);
+		break;
 	}
 	return NOTIFY_DONE;
 }
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index e3362b5..f47550d 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -129,6 +129,5 @@ extern void ip_mc_unmap(struct in_device *);
 extern void ip_mc_remap(struct in_device *);
 extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
 extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
-extern void ip_mc_rejoin_groups(struct in_device *in_dev);
 
 #endif
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0741a1e..2bb2357 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1633,6 +1633,7 @@ struct packet_offload {
 #define NETDEV_NOTIFY_PEERS	0x0013
 #define NETDEV_JOIN		0x0014
 #define NETDEV_CHANGEUPPER	0x0015
+#define NETDEV_RESEND_IGMP	0x0016
 
 extern int register_netdevice_notifier(struct notifier_block *nb);
 extern int unregister_netdevice_notifier(struct notifier_block *nb);
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 2fb2d88..03a92e1 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -459,6 +459,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
 
 	case NETDEV_NOTIFY_PEERS:
 	case NETDEV_BONDING_FAILOVER:
+	case NETDEV_RESEND_IGMP:
 		/* Propagate to vlan devices */
 		vlan_group_for_each_dev(grp, i, vlandev)
 			call_netdevice_notifiers(event, vlandev);
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 3a3f371..2998dd1 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -102,6 +102,11 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
 	case NETDEV_PRE_TYPE_CHANGE:
 		/* Forbid underlaying device to change its type. */
 		return NOTIFY_BAD;
+
+	case NETDEV_RESEND_IGMP:
+		/* Propagate to master device */
+		call_netdevice_notifiers(event, br->dev);
+		break;
 	}
 
 	/* Events that may cause spanning tree to refresh */
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index cd71190..375aca3 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1323,16 +1323,17 @@ out:
 EXPORT_SYMBOL(ip_mc_inc_group);
 
 /*
- *	Resend IGMP JOIN report; used for bonding.
- *	Called with rcu_read_lock()
+ *	Resend IGMP JOIN report; used by netdev notifier.
  */
-void ip_mc_rejoin_groups(struct in_device *in_dev)
+static void ip_mc_rejoin_groups(struct in_device *in_dev)
 {
 #ifdef CONFIG_IP_MULTICAST
 	struct ip_mc_list *im;
 	int type;
 
-	for_each_pmc_rcu(in_dev, im) {
+	ASSERT_RTNL();
+
+	for_each_pmc_rtnl(in_dev, im) {
 		if (im->multiaddr == IGMP_ALL_HOSTS)
 			continue;
 
@@ -1349,7 +1350,6 @@ void ip_mc_rejoin_groups(struct in_device *in_dev)
 	}
 #endif
 }
-EXPORT_SYMBOL(ip_mc_rejoin_groups);
 
 /*
  *	A socket has left a multicast group on device dev
@@ -2735,8 +2735,42 @@ static struct pernet_operations igmp_net_ops = {
 	.exit = igmp_net_exit,
 };
 
+static int igmp_netdev_event(struct notifier_block *this,
+			     unsigned long event, void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+	struct in_device *in_dev;
+
+	switch (event) {
+	case NETDEV_RESEND_IGMP:
+		in_dev = __in_dev_get_rtnl(dev);
+		if (in_dev)
+			ip_mc_rejoin_groups(in_dev);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block igmp_notifier = {
+	.notifier_call = igmp_netdev_event,
+};
+
 int __init igmp_mc_proc_init(void)
 {
-	return register_pernet_subsys(&igmp_net_ops);
+	int err;
+
+	err = register_pernet_subsys(&igmp_net_ops);
+	if (err)
+		return err;
+	err = register_netdevice_notifier(&igmp_notifier);
+	if (err)
+		goto reg_notif_fail;
+	return 0;
+
+reg_notif_fail:
+	unregister_pernet_subsys(&igmp_net_ops);
+	return err;
 }
 #endif
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [patch net-next v2 3/3] team: add support for sending multicast rejoins
  2013-07-20 10:13 [patch net-next v2 0/3] add support for peer notifications and igmp rejoins for team Jiri Pirko
  2013-07-20 10:13 ` [patch net-next v2 1/3] team: add peer notification Jiri Pirko
  2013-07-20 10:13 ` [patch net-next v2 2/3] net: convert resend IGMP to notifier event Jiri Pirko
@ 2013-07-20 10:13 ` Jiri Pirko
  2013-07-23 23:54 ` [patch net-next v2 0/3] add support for peer notifications and igmp rejoins for team David Miller
  3 siblings, 0 replies; 6+ messages in thread
From: Jiri Pirko @ 2013-07-20 10:13 UTC (permalink / raw)
  To: netdev
  Cc: davem, fubar, andy, kaber, stephen, kuznet, jmorris, yoshfuji, edumazet

Similar to what is implemented in bonding. User is able to ask team
driver to send IGMP rejoins in case port is enabled or disabled. Using
previously introduced netdev notifier.

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
 drivers/net/team/team.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/if_team.h |  6 ++++
 2 files changed, 91 insertions(+)

diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 2587dc8..75159e4 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -662,6 +662,46 @@ static void team_notify_peers_fini(struct team *team)
 }
 
 
+/*******************************
+ * Send multicast group rejoins
+ *******************************/
+
+static void team_mcast_rejoin_work(struct work_struct *work)
+{
+	struct team *team;
+
+	team = container_of(work, struct team, mcast_rejoin.dw.work);
+
+	if (!rtnl_trylock()) {
+		schedule_delayed_work(&team->mcast_rejoin.dw, 0);
+		return;
+	}
+	call_netdevice_notifiers(NETDEV_RESEND_IGMP, team->dev);
+	rtnl_unlock();
+	if (!atomic_dec_and_test(&team->mcast_rejoin.count_pending))
+		schedule_delayed_work(&team->mcast_rejoin.dw,
+				      msecs_to_jiffies(team->mcast_rejoin.interval));
+}
+
+static void team_mcast_rejoin(struct team *team)
+{
+	if (!team->mcast_rejoin.count || !netif_running(team->dev))
+		return;
+	atomic_set(&team->mcast_rejoin.count_pending, team->mcast_rejoin.count);
+	schedule_delayed_work(&team->mcast_rejoin.dw, 0);
+}
+
+static void team_mcast_rejoin_init(struct team *team)
+{
+	INIT_DELAYED_WORK(&team->mcast_rejoin.dw, team_mcast_rejoin_work);
+}
+
+static void team_mcast_rejoin_fini(struct team *team)
+{
+	cancel_delayed_work_sync(&team->mcast_rejoin.dw);
+}
+
+
 /************************
  * Rx path frame handler
  ************************/
@@ -887,6 +927,7 @@ static void team_port_enable(struct team *team,
 	if (team->ops.port_enabled)
 		team->ops.port_enabled(team, port);
 	team_notify_peers(team);
+	team_mcast_rejoin(team);
 }
 
 static void __reconstruct_port_hlist(struct team *team, int rm_index)
@@ -917,6 +958,7 @@ static void team_port_disable(struct team *team,
 	team_queue_override_port_del(team, port);
 	team_adjust_ops(team);
 	team_notify_peers(team);
+	team_mcast_rejoin(team);
 }
 
 #define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
@@ -1275,6 +1317,34 @@ static int team_notify_peers_interval_set(struct team *team,
 	return 0;
 }
 
+static int team_mcast_rejoin_count_get(struct team *team,
+				       struct team_gsetter_ctx *ctx)
+{
+	ctx->data.u32_val = team->mcast_rejoin.count;
+	return 0;
+}
+
+static int team_mcast_rejoin_count_set(struct team *team,
+				       struct team_gsetter_ctx *ctx)
+{
+	team->mcast_rejoin.count = ctx->data.u32_val;
+	return 0;
+}
+
+static int team_mcast_rejoin_interval_get(struct team *team,
+					  struct team_gsetter_ctx *ctx)
+{
+	ctx->data.u32_val = team->mcast_rejoin.interval;
+	return 0;
+}
+
+static int team_mcast_rejoin_interval_set(struct team *team,
+					  struct team_gsetter_ctx *ctx)
+{
+	team->mcast_rejoin.interval = ctx->data.u32_val;
+	return 0;
+}
+
 static int team_port_en_option_get(struct team *team,
 				   struct team_gsetter_ctx *ctx)
 {
@@ -1399,6 +1469,18 @@ static const struct team_option team_options[] = {
 		.setter = team_notify_peers_interval_set,
 	},
 	{
+		.name = "mcast_rejoin_count",
+		.type = TEAM_OPTION_TYPE_U32,
+		.getter = team_mcast_rejoin_count_get,
+		.setter = team_mcast_rejoin_count_set,
+	},
+	{
+		.name = "mcast_rejoin_interval",
+		.type = TEAM_OPTION_TYPE_U32,
+		.getter = team_mcast_rejoin_interval_get,
+		.setter = team_mcast_rejoin_interval_set,
+	},
+	{
 		.name = "enabled",
 		.type = TEAM_OPTION_TYPE_BOOL,
 		.per_port = true,
@@ -1480,6 +1562,7 @@ static int team_init(struct net_device *dev)
 	INIT_LIST_HEAD(&team->option_inst_list);
 
 	team_notify_peers_init(team);
+	team_mcast_rejoin_init(team);
 
 	err = team_options_register(team, team_options, ARRAY_SIZE(team_options));
 	if (err)
@@ -1491,6 +1574,7 @@ static int team_init(struct net_device *dev)
 	return 0;
 
 err_options_register:
+	team_mcast_rejoin_fini(team);
 	team_notify_peers_fini(team);
 	team_queue_override_fini(team);
 err_team_queue_override_init:
@@ -1511,6 +1595,7 @@ static void team_uninit(struct net_device *dev)
 
 	__team_change_mode(team, NULL); /* cleanup */
 	__team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
+	team_mcast_rejoin_fini(team);
 	team_notify_peers_fini(team);
 	team_queue_override_fini(team);
 	mutex_unlock(&team->lock);
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index b0b8368..a899dc2 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -200,6 +200,12 @@ struct team {
 		atomic_t count_pending;
 		struct delayed_work dw;
 	} notify_peers;
+	struct {
+		unsigned int count;
+		unsigned int interval; /* in ms */
+		atomic_t count_pending;
+		struct delayed_work dw;
+	} mcast_rejoin;
 	long mode_priv[TEAM_MODE_PRIV_LONGS];
 };
 
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [net-next,v2,2/3] net: convert resend IGMP to notifier event
  2013-07-20 10:13 ` [patch net-next v2 2/3] net: convert resend IGMP to notifier event Jiri Pirko
@ 2013-07-22 16:26   ` Veaceslav Falico
  0 siblings, 0 replies; 6+ messages in thread
From: Veaceslav Falico @ 2013-07-22 16:26 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev, davem, fubar, andy, kaber, stephen, kuznet, jmorris,
	yoshfuji, edumazet

On Sat, Jul 20, 2013 at 12:13:53PM +0200, Jiri Pirko wrote:
>Until now, bond_resend_igmp_join_requests() looks for vlans attached to
>bonding device, bridge where bonding act as port manually. It does not
>care of other scenarios, like stacked bonds or team device above. Make
>this more generic and use netdev notifier to propagate the event to
>upper devices and to actually call ip_mc_rejoin_groups().
>
>Signed-off-by: Jiri Pirko <jiri@resnulli.us>
>
>---
>drivers/net/bonding/bond_main.c | 44 ++++++++-------------------------------
> drivers/net/team/team.c         |  4 ++++
> include/linux/igmp.h            |  1 -
> include/linux/netdevice.h       |  1 +
> net/8021q/vlan.c                |  1 +
> net/bridge/br_notify.c          |  5 +++++
> net/ipv4/igmp.c                 | 46 +++++++++++++++++++++++++++++++++++------
> 7 files changed, 60 insertions(+), 42 deletions(-)
>
>diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
>index 07f257d4..ae9864c 100644
>--- a/drivers/net/bonding/bond_main.c
>+++ b/drivers/net/bonding/bond_main.c
>@@ -715,15 +715,6 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
> 	return err;
> }
>
>-static void __bond_resend_igmp_join_requests(struct net_device *dev)
>-{
>-	struct in_device *in_dev;
>-
>-	in_dev = __in_dev_get_rcu(dev);
>-	if (in_dev)
>-		ip_mc_rejoin_groups(in_dev);
>-}
>-
> /*
>  * Retrieve the list of registered multicast addresses for the bonding
>  * device and retransmit an IGMP JOIN request to the current active
>@@ -731,33 +722,12 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
>  */
> static void bond_resend_igmp_join_requests(struct bonding *bond)
> {
>-	struct net_device *bond_dev, *vlan_dev, *upper_dev;
>-	struct vlan_entry *vlan;
>-
>-	read_lock(&bond->lock);

I think you loose the bond->lock here, so that the igmp resend happens
without it, but under a rtnl_lock(), which is enough I bet. Win :), one
more bond->lock gone.

Acked-by: Veaceslav Falico <vfalico@redhat.com>

>-	rcu_read_lock();
>-
>-	bond_dev = bond->dev;
>-
>-	/* rejoin all groups on bond device */
>-	__bond_resend_igmp_join_requests(bond_dev);
>-
>-	/*
>-	 * if bond is enslaved to a bridge,
>-	 * then rejoin all groups on its master
>-	 */
>-	upper_dev = netdev_master_upper_dev_get_rcu(bond_dev);
>-	if (upper_dev && upper_dev->priv_flags & IFF_EBRIDGE)
>-		__bond_resend_igmp_join_requests(upper_dev);
>-
>-	/* rejoin all groups on vlan devices */
>-	list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
>-		vlan_dev = __vlan_find_dev_deep(bond_dev, htons(ETH_P_8021Q),
>-						vlan->vlan_id);
>-		if (vlan_dev)
>-			__bond_resend_igmp_join_requests(vlan_dev);
>+	if (!rtnl_trylock()) {
>+		queue_delayed_work(bond->wq, &bond->mcast_work, 0);
>+		return;
> 	}
>-	rcu_read_unlock();
>+	call_netdevice_notifiers(NETDEV_RESEND_IGMP, bond->dev);
>+	rtnl_unlock();
>
> 	/* We use curr_slave_lock to protect against concurrent access to
> 	 * igmp_retrans from multiple running instances of this function and
>@@ -3234,6 +3204,10 @@ static int bond_slave_netdev_event(unsigned long event,
> 	case NETDEV_FEAT_CHANGE:
> 		bond_compute_features(bond);
> 		break;
>+	case NETDEV_RESEND_IGMP:
>+		/* Propagate to master device */
>+		call_netdevice_notifiers(event, slave->bond->dev);
>+		break;
> 	default:
> 		break;
> 	}
>diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
>index 0433ee9..2587dc8 100644
>--- a/drivers/net/team/team.c
>+++ b/drivers/net/team/team.c
>@@ -2785,6 +2785,10 @@ static int team_device_event(struct notifier_block *unused,
> 	case NETDEV_PRE_TYPE_CHANGE:
> 		/* Forbid to change type of underlaying device */
> 		return NOTIFY_BAD;
>+	case NETDEV_RESEND_IGMP:
>+		/* Propagate to master device */
>+		call_netdevice_notifiers(event, port->team->dev);
>+		break;
> 	}
> 	return NOTIFY_DONE;
> }
>diff --git a/include/linux/igmp.h b/include/linux/igmp.h
>index e3362b5..f47550d 100644
>--- a/include/linux/igmp.h
>+++ b/include/linux/igmp.h
>@@ -129,6 +129,5 @@ extern void ip_mc_unmap(struct in_device *);
> extern void ip_mc_remap(struct in_device *);
> extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
> extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
>-extern void ip_mc_rejoin_groups(struct in_device *in_dev);
>
> #endif
>diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>index 0741a1e..2bb2357 100644
>--- a/include/linux/netdevice.h
>+++ b/include/linux/netdevice.h
>@@ -1633,6 +1633,7 @@ struct packet_offload {
> #define NETDEV_NOTIFY_PEERS	0x0013
> #define NETDEV_JOIN		0x0014
> #define NETDEV_CHANGEUPPER	0x0015
>+#define NETDEV_RESEND_IGMP	0x0016
>
> extern int register_netdevice_notifier(struct notifier_block *nb);
> extern int unregister_netdevice_notifier(struct notifier_block *nb);
>diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
>index 2fb2d88..03a92e1 100644
>--- a/net/8021q/vlan.c
>+++ b/net/8021q/vlan.c
>@@ -459,6 +459,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
>
> 	case NETDEV_NOTIFY_PEERS:
> 	case NETDEV_BONDING_FAILOVER:
>+	case NETDEV_RESEND_IGMP:
> 		/* Propagate to vlan devices */
> 		vlan_group_for_each_dev(grp, i, vlandev)
> 			call_netdevice_notifiers(event, vlandev);
>diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
>index 3a3f371..2998dd1 100644
>--- a/net/bridge/br_notify.c
>+++ b/net/bridge/br_notify.c
>@@ -102,6 +102,11 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
> 	case NETDEV_PRE_TYPE_CHANGE:
> 		/* Forbid underlaying device to change its type. */
> 		return NOTIFY_BAD;
>+
>+	case NETDEV_RESEND_IGMP:
>+		/* Propagate to master device */
>+		call_netdevice_notifiers(event, br->dev);
>+		break;
> 	}
>
> 	/* Events that may cause spanning tree to refresh */
>diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
>index cd71190..375aca3 100644
>--- a/net/ipv4/igmp.c
>+++ b/net/ipv4/igmp.c
>@@ -1323,16 +1323,17 @@ out:
> EXPORT_SYMBOL(ip_mc_inc_group);
>
> /*
>- *	Resend IGMP JOIN report; used for bonding.
>- *	Called with rcu_read_lock()
>+ *	Resend IGMP JOIN report; used by netdev notifier.
>  */
>-void ip_mc_rejoin_groups(struct in_device *in_dev)
>+static void ip_mc_rejoin_groups(struct in_device *in_dev)
> {
> #ifdef CONFIG_IP_MULTICAST
> 	struct ip_mc_list *im;
> 	int type;
>
>-	for_each_pmc_rcu(in_dev, im) {
>+	ASSERT_RTNL();
>+
>+	for_each_pmc_rtnl(in_dev, im) {
> 		if (im->multiaddr == IGMP_ALL_HOSTS)
> 			continue;
>
>@@ -1349,7 +1350,6 @@ void ip_mc_rejoin_groups(struct in_device *in_dev)
> 	}
> #endif
> }
>-EXPORT_SYMBOL(ip_mc_rejoin_groups);
>
> /*
>  *	A socket has left a multicast group on device dev
>@@ -2735,8 +2735,42 @@ static struct pernet_operations igmp_net_ops = {
> 	.exit = igmp_net_exit,
> };
>
>+static int igmp_netdev_event(struct notifier_block *this,
>+			     unsigned long event, void *ptr)
>+{
>+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
>+	struct in_device *in_dev;
>+
>+	switch (event) {
>+	case NETDEV_RESEND_IGMP:
>+		in_dev = __in_dev_get_rtnl(dev);
>+		if (in_dev)
>+			ip_mc_rejoin_groups(in_dev);
>+		break;
>+	default:
>+		break;
>+	}
>+	return NOTIFY_DONE;
>+}
>+
>+static struct notifier_block igmp_notifier = {
>+	.notifier_call = igmp_netdev_event,
>+};
>+
> int __init igmp_mc_proc_init(void)
> {
>-	return register_pernet_subsys(&igmp_net_ops);
>+	int err;
>+
>+	err = register_pernet_subsys(&igmp_net_ops);
>+	if (err)
>+		return err;
>+	err = register_netdevice_notifier(&igmp_notifier);
>+	if (err)
>+		goto reg_notif_fail;
>+	return 0;
>+
>+reg_notif_fail:
>+	unregister_pernet_subsys(&igmp_net_ops);
>+	return err;
> }
> #endif

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch net-next v2 0/3] add support for peer notifications and igmp rejoins for team
  2013-07-20 10:13 [patch net-next v2 0/3] add support for peer notifications and igmp rejoins for team Jiri Pirko
                   ` (2 preceding siblings ...)
  2013-07-20 10:13 ` [patch net-next v2 3/3] team: add support for sending multicast rejoins Jiri Pirko
@ 2013-07-23 23:54 ` David Miller
  3 siblings, 0 replies; 6+ messages in thread
From: David Miller @ 2013-07-23 23:54 UTC (permalink / raw)
  To: jiri
  Cc: netdev, fubar, andy, kaber, stephen, kuznet, jmorris, yoshfuji, edumazet

From: Jiri Pirko <jiri@resnulli.us>
Date: Sat, 20 Jul 2013 12:13:51 +0200

> The middle patch adjusts core infrastructure so the bonding code can be
> generalized and reused by team.
> 
> v1->v2: using msecs_to_jiffies() as suggested by Eric
> 
> Jiri Pirko (3):
>   team: add peer notification
>   net: convert resend IGMP to notifier event
>   team: add support for sending multicast rejoins

Series applied, thanks Jiri.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2013-07-23 23:54 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-20 10:13 [patch net-next v2 0/3] add support for peer notifications and igmp rejoins for team Jiri Pirko
2013-07-20 10:13 ` [patch net-next v2 1/3] team: add peer notification Jiri Pirko
2013-07-20 10:13 ` [patch net-next v2 2/3] net: convert resend IGMP to notifier event Jiri Pirko
2013-07-22 16:26   ` [net-next,v2,2/3] " Veaceslav Falico
2013-07-20 10:13 ` [patch net-next v2 3/3] team: add support for sending multicast rejoins Jiri Pirko
2013-07-23 23:54 ` [patch net-next v2 0/3] add support for peer notifications and igmp rejoins for team David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).