git://git.onelab.eu
/
sliver-openvswitch.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
upgrade to new signature of update_flags
[sliver-openvswitch.git]
/
datapath
/
datapath.c
diff --git
a/datapath/datapath.c
b/datapath/datapath.c
index
40b25e5
..
42af315
100644
(file)
--- a/
datapath/datapath.c
+++ b/
datapath/datapath.c
@@
-48,6
+48,8
@@
#include <linux/openvswitch.h>
#include <linux/rculist.h>
#include <linux/dmi.h>
#include <linux/openvswitch.h>
#include <linux/rculist.h>
#include <linux/dmi.h>
+#include <linux/genetlink.h>
+#include <net/genetlink.h>
#include <net/genetlink.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/genetlink.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
@@
-55,10
+57,10
@@
#include "checksum.h"
#include "datapath.h"
#include "flow.h"
#include "checksum.h"
#include "datapath.h"
#include "flow.h"
-#include "genl_exec.h"
#include "vlan.h"
#include "tunnel.h"
#include "vport-internal_dev.h"
#include "vlan.h"
#include "tunnel.h"
#include "vport-internal_dev.h"
+#include "vport-netdev.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \
LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \
LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
@@
-71,23
+73,52
@@
static DECLARE_DELAYED_WORK(rehash_flow_wq, rehash_flow_table);
int ovs_net_id __read_mostly;
int ovs_net_id __read_mostly;
+static void ovs_notify(struct sk_buff *skb, struct genl_info *info,
+ struct genl_multicast_group *grp)
+{
+ genl_notify(skb, genl_info_net(info), info->snd_portid,
+ grp->id, info->nlhdr, GFP_KERNEL);
+}
+
/**
* DOC: Locking:
*
/**
* DOC: Locking:
*
- * Writes to device state (add/remove datapath, port, set operations on vports,
- * etc.) are protected by RTNL.
- *
- * Writes to other state (flow table modifications, set miscellaneous datapath
- * parameters, etc.) are protected by genl_mutex. The RTNL lock nests inside
- * genl_mutex.
+ * All writes e.g. Writes to device state (add/remove datapath, port, set
+ * operations on vports, etc.), Writes to other state (flow table
+ * modifications, set miscellaneous datapath parameters, etc.) are protected
+ * by ovs_lock.
*
* Reads are protected by RCU.
*
* There are a few special cases (mostly stats) that have their own
* synchronization but they nest under all of above and don't interact with
* each other.
*
* Reads are protected by RCU.
*
* There are a few special cases (mostly stats) that have their own
* synchronization but they nest under all of above and don't interact with
* each other.
+ *
+ * The RTNL lock nests inside ovs_mutex.
*/
*/
+static DEFINE_MUTEX(ovs_mutex);
+
+void ovs_lock(void)
+{
+ mutex_lock(&ovs_mutex);
+}
+
+void ovs_unlock(void)
+{
+ mutex_unlock(&ovs_mutex);
+}
+
+#ifdef CONFIG_LOCKDEP
+int lockdep_ovsl_is_held(void)
+{
+ if (debug_locks)
+ return lockdep_is_held(&ovs_mutex);
+ else
+ return 1;
+}
+#endif
+
static struct vport *new_vport(const struct vport_parms *);
static int queue_gso_packets(struct net *, int dp_ifindex, struct sk_buff *,
const struct dp_upcall_info *);
static struct vport *new_vport(const struct vport_parms *);
static int queue_gso_packets(struct net *, int dp_ifindex, struct sk_buff *,
const struct dp_upcall_info *);
@@
-95,7
+126,7
@@
static int queue_userspace_packet(struct net *, int dp_ifindex,
struct sk_buff *,
const struct dp_upcall_info *);
struct sk_buff *,
const struct dp_upcall_info *);
-/* Must be called with rcu_read_lock
, genl_mutex, or RTNL lock
. */
+/* Must be called with rcu_read_lock
or ovs_mutex
. */
static struct datapath *get_dp(struct net *net, int dp_ifindex)
{
struct datapath *dp = NULL;
static struct datapath *get_dp(struct net *net, int dp_ifindex)
{
struct datapath *dp = NULL;
@@
-113,10
+144,10
@@
static struct datapath *get_dp(struct net *net, int dp_ifindex)
return dp;
}
return dp;
}
-/* Must be called with rcu_read_lock or
RTNL lock
. */
+/* Must be called with rcu_read_lock or
ovs_mutex
. */
const char *ovs_dp_name(const struct datapath *dp)
{
const char *ovs_dp_name(const struct datapath *dp)
{
- struct vport *vport = ovs_vport_
rtn
l_rcu(dp, OVSP_LOCAL);
+ struct vport *vport = ovs_vport_
ovs
l_rcu(dp, OVSP_LOCAL);
return vport->ops->get_name(vport);
}
return vport->ops->get_name(vport);
}
@@
-129,7
+160,7
@@
static int get_dpifindex(struct datapath *dp)
local = ovs_vport_rcu(dp, OVSP_LOCAL);
if (local)
local = ovs_vport_rcu(dp, OVSP_LOCAL);
if (local)
- ifindex =
local->ops->get_ifindex(local)
;
+ ifindex =
netdev_vport_priv(local)->dev->ifindex
;
else
ifindex = 0;
else
ifindex = 0;
@@
-168,7
+199,7
@@
struct vport *ovs_lookup_vport(const struct datapath *dp, u16 port_no)
return NULL;
}
return NULL;
}
-/* Called with
RTNL lock and genl_lock
. */
+/* Called with
ovs_mutex
. */
static struct vport *new_vport(const struct vport_parms *parms)
{
struct vport *vport;
static struct vport *new_vport(const struct vport_parms *parms)
{
struct vport *vport;
@@
-183,10
+214,9
@@
static struct vport *new_vport(const struct vport_parms *parms)
return vport;
}
return vport;
}
-/* Called with RTNL lock. */
void ovs_dp_detach_port(struct vport *p)
{
void ovs_dp_detach_port(struct vport *p)
{
- ASSERT_
RTN
L();
+ ASSERT_
OVS
L();
/* First drop references to device. */
hlist_del_rcu(&p->dp_hash_node);
/* First drop references to device. */
hlist_del_rcu(&p->dp_hash_node);
@@
-433,13
+463,13
@@
out:
return err;
}
return err;
}
-/* Called with
genl
_mutex. */
+/* Called with
ovs
_mutex. */
static int flush_flows(struct datapath *dp)
{
struct flow_table *old_table;
struct flow_table *new_table;
static int flush_flows(struct datapath *dp)
{
struct flow_table *old_table;
struct flow_table *new_table;
- old_table =
gen
l_dereference(dp->table);
+ old_table =
ovs
l_dereference(dp->table);
new_table = ovs_flow_tbl_alloc(TBL_MIN_BUCKETS);
if (!new_table)
return -ENOMEM;
new_table = ovs_flow_tbl_alloc(TBL_MIN_BUCKETS);
if (!new_table)
return -ENOMEM;
@@
-940,7
+970,7
@@
static struct genl_ops dp_packet_genl_ops[] = {
static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats)
{
int i;
static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats)
{
int i;
- struct flow_table *table =
gen
l_dereference(dp->table);
+ struct flow_table *table =
ovs
l_dereference(dp->table);
stats->n_flows = ovs_flow_tbl_count(table);
stats->n_flows = ovs_flow_tbl_count(table);
@@
-1085,7
+1115,7
@@
static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts)
+ nla_total_size(acts->actions_len); /* OVS_FLOW_ATTR_ACTIONS */
}
+ nla_total_size(acts->actions_len); /* OVS_FLOW_ATTR_ACTIONS */
}
-/* Called with
genl_lock
. */
+/* Called with
ovs_mutex
. */
static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
struct sk_buff *skb, u32 portid,
u32 seq, u32 flags, u8 cmd)
static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
struct sk_buff *skb, u32 portid,
u32 seq, u32 flags, u8 cmd)
@@
-1100,8
+1130,7
@@
static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
u8 tcp_flags;
int err;
u8 tcp_flags;
int err;
- sf_acts = rcu_dereference_protected(flow->sf_acts,
- lockdep_genl_is_held());
+ sf_acts = ovsl_dereference(flow->sf_acts);
ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family, flags, cmd);
if (!ovs_header)
ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family, flags, cmd);
if (!ovs_header)
@@
-1174,8
+1203,7
@@
static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow)
{
const struct sw_flow_actions *sf_acts;
{
const struct sw_flow_actions *sf_acts;
- sf_acts = rcu_dereference_protected(flow->sf_acts,
- lockdep_genl_is_held());
+ sf_acts = ovsl_dereference(flow->sf_acts);
return genlmsg_new(ovs_flow_cmd_msg_size(sf_acts), GFP_KERNEL);
}
return genlmsg_new(ovs_flow_cmd_msg_size(sf_acts), GFP_KERNEL);
}
@@
-1232,18
+1260,19
@@
static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
goto error;
}
goto error;
}
+ ovs_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
error = -ENODEV;
if (!dp)
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
error = -ENODEV;
if (!dp)
- goto err_
kfree
;
+ goto err_
unlock_ovs
;
- table =
gen
l_dereference(dp->table);
+ table =
ovs
l_dereference(dp->table);
flow = ovs_flow_tbl_lookup(table, &key, key_len);
if (!flow) {
/* Bail out if we're not allowed to create a new flow. */
error = -ENOENT;
if (info->genlhdr->cmd == OVS_FLOW_CMD_SET)
flow = ovs_flow_tbl_lookup(table, &key, key_len);
if (!flow) {
/* Bail out if we're not allowed to create a new flow. */
error = -ENOENT;
if (info->genlhdr->cmd == OVS_FLOW_CMD_SET)
- goto err_
kfree
;
+ goto err_
unlock_ovs
;
/* Expand table, if necessary, to make room. */
if (ovs_flow_tbl_need_to_expand(table)) {
/* Expand table, if necessary, to make room. */
if (ovs_flow_tbl_need_to_expand(table)) {
@@
-1253,7
+1282,7
@@
static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
if (!IS_ERR(new_table)) {
rcu_assign_pointer(dp->table, new_table);
ovs_flow_tbl_deferred_destroy(table);
if (!IS_ERR(new_table)) {
rcu_assign_pointer(dp->table, new_table);
ovs_flow_tbl_deferred_destroy(table);
- table =
gen
l_dereference(dp->table);
+ table =
ovs
l_dereference(dp->table);
}
}
}
}
@@
-1261,7
+1290,7
@@
static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
flow = ovs_flow_alloc();
if (IS_ERR(flow)) {
error = PTR_ERR(flow);
flow = ovs_flow_alloc();
if (IS_ERR(flow)) {
error = PTR_ERR(flow);
- goto err_
kfree
;
+ goto err_
unlock_ovs
;
}
clear_stats(flow);
}
clear_stats(flow);
@@
-1286,11
+1315,10
@@
static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
error = -EEXIST;
if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW &&
info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL))
error = -EEXIST;
if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW &&
info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL))
- goto err_
kfree
;
+ goto err_
unlock_ovs
;
/* Update actions. */
/* Update actions. */
- old_acts = rcu_dereference_protected(flow->sf_acts,
- lockdep_genl_is_held());
+ old_acts = ovsl_dereference(flow->sf_acts);
rcu_assign_pointer(flow->sf_acts, acts);
ovs_flow_deferred_free_acts(old_acts);
rcu_assign_pointer(flow->sf_acts, acts);
ovs_flow_deferred_free_acts(old_acts);
@@
-1304,16
+1332,17
@@
static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
spin_unlock_bh(&flow->lock);
}
}
spin_unlock_bh(&flow->lock);
}
}
+ ovs_unlock();
if (!IS_ERR(reply))
if (!IS_ERR(reply))
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_flow_multicast_group.id, info->nlhdr,
- GFP_KERNEL);
+ ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
else
netlink_set_err(GENL_SOCK(sock_net(skb->sk)), 0,
ovs_dp_flow_multicast_group.id, PTR_ERR(reply));
return 0;
else
netlink_set_err(GENL_SOCK(sock_net(skb->sk)), 0,
ovs_dp_flow_multicast_group.id, PTR_ERR(reply));
return 0;
+err_unlock_ovs:
+ ovs_unlock();
err_kfree:
kfree(acts);
error:
err_kfree:
kfree(acts);
error:
@@
-1338,21
+1367,32
@@
static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
if (err)
return err;
+ ovs_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
- if (!dp)
- return -ENODEV;
+ if (!dp) {
+ err = -ENODEV;
+ goto unlock;
+ }
- table =
gen
l_dereference(dp->table);
+ table =
ovs
l_dereference(dp->table);
flow = ovs_flow_tbl_lookup(table, &key, key_len);
flow = ovs_flow_tbl_lookup(table, &key, key_len);
- if (!flow)
- return -ENOENT;
+ if (!flow) {
+ err = -ENOENT;
+ goto unlock;
+ }
reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid,
info->snd_seq, OVS_FLOW_CMD_NEW);
reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid,
info->snd_seq, OVS_FLOW_CMD_NEW);
- if (IS_ERR(reply))
- return PTR_ERR(reply);
+ if (IS_ERR(reply)) {
+ err = PTR_ERR(reply);
+ goto unlock;
+ }
+ ovs_unlock();
return genlmsg_reply(reply, info);
return genlmsg_reply(reply, info);
+unlock:
+ ovs_unlock();
+ return err;
}
static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
}
static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
@@
-1367,25
+1407,33
@@
static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
int err;
int key_len;
int err;
int key_len;
+ ovs_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
- if (!dp)
- return -ENODEV;
-
- if (!a[OVS_FLOW_ATTR_KEY])
- return flush_flows(dp);
+ if (!dp) {
+ err = -ENODEV;
+ goto unlock;
+ }
+ if (!a[OVS_FLOW_ATTR_KEY]) {
+ err = flush_flows(dp);
+ goto unlock;
+ }
err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]);
if (err)
err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]);
if (err)
-
return err
;
+
goto unlock
;
- table =
gen
l_dereference(dp->table);
+ table =
ovs
l_dereference(dp->table);
flow = ovs_flow_tbl_lookup(table, &key, key_len);
flow = ovs_flow_tbl_lookup(table, &key, key_len);
- if (!flow)
- return -ENOENT;
+ if (!flow) {
+ err = -ENOENT;
+ goto unlock;
+ }
reply = ovs_flow_cmd_alloc_info(flow);
reply = ovs_flow_cmd_alloc_info(flow);
- if (!reply)
- return -ENOMEM;
+ if (!reply) {
+ err = -ENOMEM;
+ goto unlock;
+ }
ovs_flow_tbl_remove(table, flow);
ovs_flow_tbl_remove(table, flow);
@@
-1394,10
+1442,13
@@
static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
BUG_ON(err < 0);
ovs_flow_deferred_free(flow);
BUG_ON(err < 0);
ovs_flow_deferred_free(flow);
+ ovs_unlock();
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_flow_multicast_group.id, info->nlhdr, GFP_KERNEL);
+ ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
return 0;
return 0;
+unlock:
+ ovs_unlock();
+ return err;
}
static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
}
static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
@@
-1406,11
+1457,14
@@
static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
struct datapath *dp;
struct flow_table *table;
struct datapath *dp;
struct flow_table *table;
+ ovs_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
- if (!dp)
+ if (!dp) {
+ ovs_unlock();
return -ENODEV;
return -ENODEV;
+ }
- table =
gen
l_dereference(dp->table);
+ table =
ovs
l_dereference(dp->table);
for (;;) {
struct sw_flow *flow;
for (;;) {
struct sw_flow *flow;
@@
-1431,6
+1485,7
@@
static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
cb->args[0] = bucket;
cb->args[1] = obj;
}
cb->args[0] = bucket;
cb->args[1] = obj;
}
+ ovs_unlock();
return skb->len;
}
return skb->len;
}
@@
-1543,7
+1598,7
@@
static int ovs_dp_cmd_validate(struct nlattr *a[OVS_DP_ATTR_MAX + 1])
return CHECK_NUL_STRING(a[OVS_DP_ATTR_NAME], IFNAMSIZ - 1);
}
return CHECK_NUL_STRING(a[OVS_DP_ATTR_NAME], IFNAMSIZ - 1);
}
-/* Called with
genl_mutex and optionally with RTNL lock also
. */
+/* Called with
ovs_mutex
. */
static struct datapath *lookup_datapath(struct net *net,
struct ovs_header *ovs_header,
struct nlattr *a[OVS_DP_ATTR_MAX + 1])
static struct datapath *lookup_datapath(struct net *net,
struct ovs_header *ovs_header,
struct nlattr *a[OVS_DP_ATTR_MAX + 1])
@@
-1581,12
+1636,12
@@
static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
if (err)
goto err;
if (err)
goto err;
-
rtnl
_lock();
+
ovs
_lock();
err = -ENOMEM;
dp = kzalloc(sizeof(*dp), GFP_KERNEL);
if (dp == NULL)
err = -ENOMEM;
dp = kzalloc(sizeof(*dp), GFP_KERNEL);
if (dp == NULL)
- goto err_unlock_
rtnl
;
+ goto err_unlock_
ovs
;
ovs_dp_set_net(dp, hold_net(sock_net(skb->sk)));
ovs_dp_set_net(dp, hold_net(sock_net(skb->sk)));
@@
-1638,37
+1693,33
@@
static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id);
list_add_tail(&dp->list_node, &ovs_net->dps);
ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id);
list_add_tail(&dp->list_node, &ovs_net->dps);
-
rtnl
_unlock();
+
ovs
_unlock();
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_datapath_multicast_group.id, info->nlhdr,
- GFP_KERNEL);
+ ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
return 0;
err_destroy_local_port:
return 0;
err_destroy_local_port:
- ovs_dp_detach_port(ovs_vport_
rtn
l(dp, OVSP_LOCAL));
+ ovs_dp_detach_port(ovs_vport_
ovs
l(dp, OVSP_LOCAL));
err_destroy_ports_array:
kfree(dp->ports);
err_destroy_percpu:
free_percpu(dp->stats_percpu);
err_destroy_table:
err_destroy_ports_array:
kfree(dp->ports);
err_destroy_percpu:
free_percpu(dp->stats_percpu);
err_destroy_table:
- ovs_flow_tbl_destroy(
gen
l_dereference(dp->table));
+ ovs_flow_tbl_destroy(
ovs
l_dereference(dp->table));
err_free_dp:
release_net(ovs_dp_get_net(dp));
kfree(dp);
err_free_dp:
release_net(ovs_dp_get_net(dp));
kfree(dp);
-err_unlock_
rtnl
:
-
rtnl
_unlock();
+err_unlock_
ovs
:
+
ovs
_unlock();
err:
return err;
}
err:
return err;
}
-/* Called with
genl
_mutex. */
+/* Called with
ovs
_mutex. */
static void __dp_destroy(struct datapath *dp)
{
int i;
static void __dp_destroy(struct datapath *dp)
{
int i;
- rtnl_lock();
-
for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
struct vport *vport;
struct hlist_node *n;
for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
struct vport *vport;
struct hlist_node *n;
@@
-1679,14
+1730,11
@@
static void __dp_destroy(struct datapath *dp)
}
list_del(&dp->list_node);
}
list_del(&dp->list_node);
- ovs_dp_detach_port(ovs_vport_rtnl(dp, OVSP_LOCAL));
- /* 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
- * fully destroyed before freeing the datapath.
- */
- rtnl_unlock();
+ /* OVSP_LOCAL is datapath internal port. We need to make sure that
+ * all port in datapath are destroyed first before freeing datapath.
+ */
+ ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
call_rcu(&dp->rcu, destroy_dp_rcu);
}
call_rcu(&dp->rcu, destroy_dp_rcu);
}
@@
-1701,24
+1749,27
@@
static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
if (err)
return err;
+ ovs_lock();
dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
err = PTR_ERR(dp);
if (IS_ERR(dp))
dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
err = PTR_ERR(dp);
if (IS_ERR(dp))
-
return err
;
+
goto unlock
;
reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
info->snd_seq, OVS_DP_CMD_DEL);
err = PTR_ERR(reply);
if (IS_ERR(reply))
reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
info->snd_seq, OVS_DP_CMD_DEL);
err = PTR_ERR(reply);
if (IS_ERR(reply))
-
return err
;
+
goto unlock
;
__dp_destroy(dp);
__dp_destroy(dp);
+ ovs_unlock();
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_datapath_multicast_group.id, info->nlhdr,
- GFP_KERNEL);
+ ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
return 0;
return 0;
+unlock:
+ ovs_unlock();
+ return err;
}
static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
}
static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
@@
-1731,9
+1782,11
@@
static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
if (err)
return err;
+ ovs_lock();
dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
+ err = PTR_ERR(dp);
if (IS_ERR(dp))
if (IS_ERR(dp))
-
return PTR_ERR(dp)
;
+
goto unlock
;
reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
info->snd_seq, OVS_DP_CMD_NEW);
reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
info->snd_seq, OVS_DP_CMD_NEW);
@@
-1741,14
+1794,17
@@
static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
err = PTR_ERR(reply);
netlink_set_err(GENL_SOCK(sock_net(skb->sk)), 0,
ovs_dp_datapath_multicast_group.id, err);
err = PTR_ERR(reply);
netlink_set_err(GENL_SOCK(sock_net(skb->sk)), 0,
ovs_dp_datapath_multicast_group.id, err);
- return 0;
+ err = 0;
+ goto unlock;
}
}
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_datapath_multicast_group.id, info->nlhdr,
- GFP_KERNEL);
+ ovs_unlock();
+ ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
return 0;
return 0;
+unlock:
+ ovs_unlock();
+ return err;
}
static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
}
static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
@@
-1761,16
+1817,26
@@
static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
if (err)
return err;
+ ovs_lock();
dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
- if (IS_ERR(dp))
- return PTR_ERR(dp);
+ if (IS_ERR(dp)) {
+ err = PTR_ERR(dp);
+ goto unlock;
+ }
reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
info->snd_seq, OVS_DP_CMD_NEW);
reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
info->snd_seq, OVS_DP_CMD_NEW);
- if (IS_ERR(reply))
- return PTR_ERR(reply);
+ if (IS_ERR(reply)) {
+ err = PTR_ERR(reply);
+ goto unlock;
+ }
+ ovs_unlock();
return genlmsg_reply(reply, info);
return genlmsg_reply(reply, info);
+
+unlock:
+ ovs_unlock();
+ return err;
}
static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
}
static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
@@
-1780,6
+1846,7
@@
static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
int skip = cb->args[0];
int i = 0;
int skip = cb->args[0];
int i = 0;
+ ovs_lock();
list_for_each_entry(dp, &ovs_net->dps, list_node) {
if (i >= skip &&
ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid,
list_for_each_entry(dp, &ovs_net->dps, list_node) {
if (i >= skip &&
ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid,
@@
-1788,6
+1855,7
@@
static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
break;
i++;
}
break;
i++;
}
+ ovs_unlock();
cb->args[0] = i;
cb->args[0] = i;
@@
-1844,7
+1912,7
@@
struct genl_multicast_group ovs_dp_vport_multicast_group = {
.name = OVS_VPORT_MCGROUP
};
.name = OVS_VPORT_MCGROUP
};
-/* Called with
RTNL lock
or RCU read lock. */
+/* Called with
ovs_mutex
or RCU read lock. */
static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
u32 portid, u32 seq, u32 flags, u8 cmd)
{
static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
u32 portid, u32 seq, u32 flags, u8 cmd)
{
@@
-1883,7
+1951,7
@@
error:
return err;
}
return err;
}
-/* Called with
RTNL lock
or RCU read lock. */
+/* Called with
ovs_mutex
or RCU read lock. */
struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid,
u32 seq, u8 cmd)
{
struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid,
u32 seq, u8 cmd)
{
@@
-1905,7
+1973,7
@@
static int ovs_vport_cmd_validate(struct nlattr *a[OVS_VPORT_ATTR_MAX + 1])
return CHECK_NUL_STRING(a[OVS_VPORT_ATTR_NAME], IFNAMSIZ - 1);
}
return CHECK_NUL_STRING(a[OVS_VPORT_ATTR_NAME], IFNAMSIZ - 1);
}
-/* Called with
RTNL lock
or RCU read lock. */
+/* Called with
ovs_mutex
or RCU read lock. */
static struct vport *lookup_vport(struct net *net,
struct ovs_header *ovs_header,
struct nlattr *a[OVS_VPORT_ATTR_MAX + 1])
static struct vport *lookup_vport(struct net *net,
struct ovs_header *ovs_header,
struct nlattr *a[OVS_VPORT_ATTR_MAX + 1])
@@
-1931,7
+1999,7
@@
static struct vport *lookup_vport(struct net *net,
if (!dp)
return ERR_PTR(-ENODEV);
if (!dp)
return ERR_PTR(-ENODEV);
- vport = ovs_vport_
rtn
l_rcu(dp, port_no);
+ vport = ovs_vport_
ovs
l_rcu(dp, port_no);
if (!vport)
return ERR_PTR(-ENODEV);
return vport;
if (!vport)
return ERR_PTR(-ENODEV);
return vport;
@@
-1959,7
+2027,7
@@
static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
if (err)
goto exit;
if (err)
goto exit;
-
rtnl
_lock();
+
ovs
_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
err = -ENODEV;
if (!dp)
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
err = -ENODEV;
if (!dp)
@@
-1972,7
+2040,7
@@
static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
if (port_no >= DP_MAX_PORTS)
goto exit_unlock;
if (port_no >= DP_MAX_PORTS)
goto exit_unlock;
- vport = ovs_vport_
rtn
l(dp, port_no);
+ vport = ovs_vport_
ovs
l(dp, port_no);
err = -EBUSY;
if (vport)
goto exit_unlock;
err = -EBUSY;
if (vport)
goto exit_unlock;
@@
-1982,7
+2050,7
@@
static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
err = -EFBIG;
goto exit_unlock;
}
err = -EFBIG;
goto exit_unlock;
}
- vport = ovs_vport_
rtn
l(dp, port_no);
+ vport = ovs_vport_
ovs
l(dp, port_no);
if (!vport)
break;
}
if (!vport)
break;
}
@@
-2011,11
+2079,11
@@
static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
ovs_dp_detach_port(vport);
goto exit_unlock;
}
ovs_dp_detach_port(vport);
goto exit_unlock;
}
- genl_notify(reply, genl_info_net(info), info->snd_portid,
-
ovs_dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL
);
+
+
ovs_notify(reply, info, &ovs_dp_vport_multicast_group
);
exit_unlock:
exit_unlock:
-
rtnl
_unlock();
+
ovs
_unlock();
exit:
return err;
}
exit:
return err;
}
@@
-2031,16
+2099,17
@@
static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
if (err)
goto exit;
if (err)
goto exit;
-
rtnl
_lock();
+
ovs
_lock();
vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
err = PTR_ERR(vport);
if (IS_ERR(vport))
goto exit_unlock;
vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
err = PTR_ERR(vport);
if (IS_ERR(vport))
goto exit_unlock;
- err = 0;
if (a[OVS_VPORT_ATTR_TYPE] &&
if (a[OVS_VPORT_ATTR_TYPE] &&
- nla_get_u32(a[OVS_VPORT_ATTR_TYPE]) != vport->ops->type)
+ nla_get_u32(a[OVS_VPORT_ATTR_TYPE]) != vport->ops->type)
{
err = -EINVAL;
err = -EINVAL;
+ goto exit_unlock;
+ }
reply = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!reply) {
reply = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!reply) {
@@
-2048,10
+2117,11
@@
static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
goto exit_unlock;
}
goto exit_unlock;
}
- if (
!err && a[OVS_VPORT_ATTR_OPTIONS])
+ if (
a[OVS_VPORT_ATTR_OPTIONS]) {
err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]);
err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]);
- if (err)
- goto exit_free;
+ if (err)
+ goto exit_free;
+ }
if (a[OVS_VPORT_ATTR_STATS])
ovs_vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS]));
if (a[OVS_VPORT_ATTR_STATS])
ovs_vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS]));
@@
-2063,16
+2133,14
@@
static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
info->snd_seq, 0, OVS_VPORT_CMD_NEW);
BUG_ON(err < 0);
info->snd_seq, 0, OVS_VPORT_CMD_NEW);
BUG_ON(err < 0);
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL);
-
- rtnl_unlock();
+ ovs_unlock();
+ ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
return 0;
exit_free:
kfree_skb(reply);
exit_unlock:
return 0;
exit_free:
kfree_skb(reply);
exit_unlock:
-
rtnl
_unlock();
+
ovs
_unlock();
exit:
return err;
}
exit:
return err;
}
@@
-2088,7
+2156,7
@@
static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
if (err)
goto exit;
if (err)
goto exit;
-
rtnl
_lock();
+
ovs
_lock();
vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
err = PTR_ERR(vport);
if (IS_ERR(vport))
vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
err = PTR_ERR(vport);
if (IS_ERR(vport))
@@
-2108,11
+2176,10
@@
static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
err = 0;
ovs_dp_detach_port(vport);
err = 0;
ovs_dp_detach_port(vport);
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL);
+ ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
exit_unlock:
exit_unlock:
-
rtnl
_unlock();
+
ovs
_unlock();
exit:
return err;
}
exit:
return err;
}
@@
-2273,17
+2340,18
@@
error:
return err;
}
return err;
}
-static
int __rehash_flow_table(void *dummy
)
+static
void rehash_flow_table(struct work_struct *work
)
{
struct datapath *dp;
struct net *net;
{
struct datapath *dp;
struct net *net;
+ ovs_lock();
rtnl_lock();
for_each_net(net) {
struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
list_for_each_entry(dp, &ovs_net->dps, list_node) {
rtnl_lock();
for_each_net(net) {
struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
list_for_each_entry(dp, &ovs_net->dps, list_node) {
- struct flow_table *old_table =
gen
l_dereference(dp->table);
+ struct flow_table *old_table =
ovs
l_dereference(dp->table);
struct flow_table *new_table;
new_table = ovs_flow_tbl_rehash(old_table);
struct flow_table *new_table;
new_table = ovs_flow_tbl_rehash(old_table);
@@
-2294,39
+2362,30
@@
static int __rehash_flow_table(void *dummy)
}
}
rtnl_unlock();
}
}
rtnl_unlock();
- return 0;
-}
-
-static void rehash_flow_table(struct work_struct *work)
-{
- genl_exec(__rehash_flow_table, NULL);
+ ovs_unlock();
schedule_delayed_work(&rehash_flow_wq, REHASH_FLOW_INTERVAL);
}
schedule_delayed_work(&rehash_flow_wq, REHASH_FLOW_INTERVAL);
}
-static int dp_destroy_all(void *data)
-{
- struct datapath *dp, *dp_next;
- struct ovs_net *ovs_net = data;
-
- list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
- __dp_destroy(dp);
-
- return 0;
-}
-
static int __net_init ovs_init_net(struct net *net)
{
struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
INIT_LIST_HEAD(&ovs_net->dps);
static int __net_init ovs_init_net(struct net *net)
{
struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
INIT_LIST_HEAD(&ovs_net->dps);
+ INIT_WORK(&ovs_net->dp_notify_work, ovs_dp_notify_wq);
return 0;
}
static void __net_exit ovs_exit_net(struct net *net)
{
return 0;
}
static void __net_exit ovs_exit_net(struct net *net)
{
+ struct datapath *dp, *dp_next;
struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
- genl_exec(dp_destroy_all, ovs_net);
+ ovs_lock();
+ list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
+ __dp_destroy(dp);
+ ovs_unlock();
+
+ cancel_work_sync(&ovs_net->dp_notify_work);
}
static struct pernet_operations ovs_net_ops = {
}
static struct pernet_operations ovs_net_ops = {
@@
-2345,13
+2404,9
@@
static int __init dp_init(void)
pr_info("Open vSwitch switching datapath %s, built "__DATE__" "__TIME__"\n",
VERSION);
pr_info("Open vSwitch switching datapath %s, built "__DATE__" "__TIME__"\n",
VERSION);
- err = genl_exec_init();
- if (err)
- goto error;
-
err = ovs_workqueues_init();
if (err)
err = ovs_workqueues_init();
if (err)
- goto error
_genl_exec
;
+ goto error;
err = ovs_flow_init();
if (err)
err = ovs_flow_init();
if (err)
@@
-2387,8
+2442,6
@@
error_flow_exit:
ovs_flow_exit();
error_wq:
ovs_workqueues_exit();
ovs_flow_exit();
error_wq:
ovs_workqueues_exit();
-error_genl_exec:
- genl_exec_exit();
error:
return err;
}
error:
return err;
}
@@
-2403,7
+2456,6
@@
static void dp_cleanup(void)
ovs_vport_exit();
ovs_flow_exit();
ovs_workqueues_exit();
ovs_vport_exit();
ovs_flow_exit();
ovs_workqueues_exit();
- genl_exec_exit();
}
module_init(dp_init);
}
module_init(dp_init);