[ovs-dev] [PATCH 1/3] datapath: Rearrange destroy dp.

Pravin B Shelar pshelar at nicira.com
Thu Dec 22 04:28:41 UTC 2011


Following patch allows unregister_netdevice() destroy dp.

Signed-off-by: Pravin B Shelar <pshelar at nicira.com>
---
 datapath/datapath.c           |   72 +++++++++++++++++++++++++++++-----------
 datapath/datapath.h           |    6 +++-
 datapath/dp_notify.c          |    7 +++-
 datapath/vport-internal_dev.c |    6 +++-
 4 files changed, 67 insertions(+), 24 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index 2875862..ab28a86 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -264,7 +264,7 @@ static struct vport *new_vport(const struct vport_parms *parms)
 }
 
 /* Called with RTNL lock. */
-void ovs_dp_detach_port(struct vport *p)
+void ovs_dp_detach_port(struct vport *p, bool delete_vport)
 {
 	ASSERT_RTNL();
 
@@ -277,7 +277,8 @@ void ovs_dp_detach_port(struct vport *p)
 	rcu_assign_pointer(p->dp->ports[p->port_no], NULL);
 
 	/* Then destroy it. */
-	ovs_vport_del(p);
+	if (delete_vport)
+		ovs_vport_del(p);
 }
 
 /* Must be called with rcu_read_lock. */
@@ -1343,6 +1344,13 @@ static struct datapath *lookup_datapath(struct ovs_header *ovs_header,
 	return dp ? dp : ERR_PTR(-ENODEV);
 }
 
+/* Must be called with genl and rtnl lock. */
+static void dp_del(struct datapath *dp)
+{
+	dp->user_destruct = true;
+	ovs_vport_del(rtnl_dereference(dp->ports[OVSP_LOCAL]));
+}
+
 static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
 {
 	struct nlattr **a = info->attrs;
@@ -1388,6 +1396,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
 		goto err_destroy_table;
 	}
 
+	dp->user_destruct = false;
 	/* Set up our datapath device. */
 	parms.name = nla_data(a[OVS_DP_ATTR_NAME]);
 	parms.type = OVS_VPORT_TYPE_INTERNAL;
@@ -1405,15 +1414,15 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
 		goto err_destroy_percpu;
 	}
 
+	list_add_tail(&dp->list_node, &dps);
+	ovs_dp_sysfs_add_dp(dp);
+
 	reply = ovs_dp_cmd_build_info(dp, info->snd_pid,
 				      info->snd_seq, OVS_DP_CMD_NEW);
 	err = PTR_ERR(reply);
 	if (IS_ERR(reply))
 		goto err_destroy_local_port;
 
-	list_add_tail(&dp->list_node, &dps);
-	ovs_dp_sysfs_add_dp(dp);
-
 	rtnl_unlock();
 
 	genl_notify(reply, genl_info_net(info), info->snd_pid,
@@ -1422,7 +1431,10 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 
 err_destroy_local_port:
-	ovs_dp_detach_port(rtnl_dereference(dp->ports[OVSP_LOCAL]));
+	dp_del(dp);
+	rtnl_unlock();
+	goto err;
+
 err_destroy_percpu:
 	free_percpu(dp->stats_percpu);
 err_destroy_table:
@@ -1439,7 +1451,6 @@ err:
 
 static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
 {
-	struct vport *vport, *next_vport;
 	struct sk_buff *reply;
 	struct datapath *dp;
 	int err;
@@ -1460,14 +1471,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	if (IS_ERR(reply))
 		goto exit_unlock;
 
-	list_for_each_entry_safe(vport, next_vport, &dp->port_list, node)
-		if (vport->port_no != OVSP_LOCAL)
-			ovs_dp_detach_port(vport);
-
-	ovs_dp_sysfs_del_dp(dp);
-	list_del(&dp->list_node);
-	ovs_dp_detach_port(rtnl_dereference(dp->ports[OVSP_LOCAL]));
-
+	dp_del(dp);
 	/* rtnl_unlock() will wait until all the references to devices that
 	 * are pending unregistration have been dropped.  We do it here to
 	 * ensure that any internal devices (which contain DP pointers) are
@@ -1475,9 +1479,6 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	 */
 	rtnl_unlock();
 
-	call_rcu(&dp->rcu, destroy_dp_rcu);
-	module_put(THIS_MODULE);
-
 	genl_notify(reply, genl_info_net(info), info->snd_pid,
 		    ovs_dp_datapath_multicast_group.id, info->nlhdr,
 		    GFP_KERNEL);
@@ -1490,6 +1491,37 @@ exit:
 	return err;
 }
 
+static int destroy_dp(void *data)
+{
+	struct datapath *dp = (struct datapath *) data;
+	struct vport *vport, *next_vport;
+
+	rtnl_lock();
+	list_for_each_entry_safe(vport, next_vport, &dp->port_list, node)
+		if (vport->port_no != OVSP_LOCAL)
+			ovs_dp_detach_port(vport, true);
+
+	list_del(&dp->list_node);
+
+	/* User-space initiated dp destroy has already deleted dp-local-port. */
+	ovs_dp_detach_port(rtnl_dereference(dp->ports[OVSP_LOCAL]),
+			   !dp->user_destruct);
+
+	rtnl_unlock();
+
+	call_rcu(&dp->rcu, destroy_dp_rcu);
+	module_put(THIS_MODULE);
+	return 0;
+}
+
+void ovs_destroy_dp(struct datapath *dp)
+{
+	if (!dp->user_destruct)
+		genl_exec(destroy_dp, dp);
+	else
+		destroy_dp(dp);
+}
+
 static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
 {
 	struct sk_buff *reply;
@@ -1795,7 +1827,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
 			err = PTR_ERR(reply);
 	}
 	if (err) {
-		ovs_dp_detach_port(vport);
+		ovs_dp_detach_port(vport, true);
 		goto exit_unlock;
 	}
 	genl_notify(reply, genl_info_net(info), info->snd_pid,
@@ -1882,7 +1914,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	if (IS_ERR(reply))
 		goto exit_unlock;
 
-	ovs_dp_detach_port(vport);
+	ovs_dp_detach_port(vport, true);
 
 	genl_notify(reply, genl_info_net(info), info->snd_pid,
 		    ovs_dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL);
diff --git a/datapath/datapath.h b/datapath/datapath.h
index 27151b9..3887608 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -87,6 +87,9 @@ struct datapath {
 
 	/* Stats. */
 	struct dp_stats_percpu __percpu *stats_percpu;
+
+	/* Used only while destroying dp. */
+	bool user_destruct;
 };
 
 /**
@@ -136,13 +139,14 @@ extern struct genl_multicast_group ovs_dp_vport_multicast_group;
 extern int (*ovs_dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
 
 void ovs_dp_process_received_packet(struct vport *, struct sk_buff *);
-void ovs_dp_detach_port(struct vport *);
+void ovs_dp_detach_port(struct vport *, bool);
 int ovs_dp_upcall(struct datapath *, struct sk_buff *,
 		  const struct dp_upcall_info *);
 
 const char *ovs_dp_name(const struct datapath *dp);
 struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq,
 					 u8 cmd);
+void ovs_destroy_dp(struct datapath *dp);
 
 int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb);
 #endif /* datapath.h */
diff --git a/datapath/dp_notify.c b/datapath/dp_notify.c
index d040d46..c0f8d65 100644
--- a/datapath/dp_notify.c
+++ b/datapath/dp_notify.c
@@ -39,12 +39,15 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
 
 	switch (event) {
 	case NETDEV_UNREGISTER:
-		if (!ovs_is_internal_dev(dev)) {
+		if (ovs_is_internal_dev(dev)) {
+			if (vport->port_no == OVSP_LOCAL)
+				ovs_dp_sysfs_del_dp(vport->dp);
+		} else {
 			struct sk_buff *notify;
 
 			notify = ovs_vport_cmd_build_info(vport, 0, 0,
 							  OVS_VPORT_CMD_DEL);
-			ovs_dp_detach_port(vport);
+			ovs_dp_detach_port(vport, true);
 			if (IS_ERR(notify)) {
 				netlink_set_err(INIT_NET_GENL_SOCK, 0,
 						ovs_dp_vport_multicast_group.id,
diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c
index c56f3b2..005b35e 100644
--- a/datapath/vport-internal_dev.c
+++ b/datapath/vport-internal_dev.c
@@ -161,6 +161,9 @@ static void internal_dev_destructor(struct net_device *dev)
 {
 	struct vport *vport = ovs_internal_dev_get_vport(dev);
 
+	if (vport->port_no == OVSP_LOCAL)
+		ovs_destroy_dp(vport->dp);
+
 	ovs_vport_free(vport);
 	free_netdev(dev);
 }
@@ -267,7 +270,8 @@ static void internal_dev_destroy(struct vport *vport)
 	dev_set_promiscuity(netdev_vport->dev, -1);
 
 	/* unregister_netdevice() waits for an RCU grace period. */
-	unregister_netdevice(netdev_vport->dev);
+	if (netdev_vport->dev->reg_state == NETREG_REGISTERED)
+		unregister_netdevice(netdev_vport->dev);
 }
 
 static int internal_dev_recv(struct vport *vport, struct sk_buff *skb)
-- 
1.7.1




More information about the dev mailing list