[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