diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2013-09-17 09:38:23 -0700 |
---|---|---|
committer | Jesse Gross <jesse@nicira.com> | 2013-09-17 09:38:23 -0700 |
commit | e7f133290660d976da8cb20e9bc7310d0cd19341 (patch) | |
tree | c4eb7687f7aeb2c20a3e23006d811a7495ca9ed4 /net/openvswitch/datapath.c | |
parent | 272b98c6455f00884f0350f775c5342358ebb73f (diff) | |
download | lwn-e7f133290660d976da8cb20e9bc7310d0cd19341.tar.gz lwn-e7f133290660d976da8cb20e9bc7310d0cd19341.zip |
openvswitch: Move flow table rehashing to flow install.
Rehashing in ovs-workqueue can cause ovs-mutex lock contentions
in case of heavy flow setups where both needs ovs-mutex. So by
moving rehashing to flow-setup we can eliminate contention.
This also simplify ovs locking and reduces dependence on
workqueue.
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Signed-off-by: Jesse Gross <jesse@nicira.com>
Diffstat (limited to 'net/openvswitch/datapath.c')
-rw-r--r-- | net/openvswitch/datapath.c | 50 |
1 files changed, 11 insertions, 39 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 2aa13bd7f2b2..2e1a9c24e380 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -60,8 +60,6 @@ #define REHASH_FLOW_INTERVAL (10 * 60 * HZ) -static void rehash_flow_table(struct work_struct *work); -static DECLARE_DELAYED_WORK(rehash_flow_wq, rehash_flow_table); int ovs_net_id __read_mostly; @@ -1289,22 +1287,25 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) /* Check if this is a duplicate flow */ flow = ovs_flow_lookup(table, &key); if (!flow) { + struct flow_table *new_table = NULL; struct sw_flow_mask *mask_p; + /* Bail out if we're not allowed to create a new flow. */ error = -ENOENT; if (info->genlhdr->cmd == OVS_FLOW_CMD_SET) goto err_unlock_ovs; /* Expand table, if necessary, to make room. */ - if (ovs_flow_tbl_need_to_expand(table)) { - struct flow_table *new_table; - + if (ovs_flow_tbl_need_to_expand(table)) new_table = ovs_flow_tbl_expand(table); - if (!IS_ERR(new_table)) { - rcu_assign_pointer(dp->table, new_table); - ovs_flow_tbl_destroy(table, true); - table = ovsl_dereference(dp->table); - } + else if (time_after(jiffies, dp->last_rehash + REHASH_FLOW_INTERVAL)) + new_table = ovs_flow_tbl_rehash(table); + + if (new_table && !IS_ERR(new_table)) { + rcu_assign_pointer(dp->table, new_table); + ovs_flow_tbl_destroy(table, true); + table = ovsl_dereference(dp->table); + dp->last_rehash = jiffies; } /* Allocate flow. */ @@ -2336,32 +2337,6 @@ error: return err; } -static void rehash_flow_table(struct work_struct *work) -{ - 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) { - struct flow_table *old_table = ovsl_dereference(dp->table); - struct flow_table *new_table; - - new_table = ovs_flow_tbl_rehash(old_table); - if (!IS_ERR(new_table)) { - rcu_assign_pointer(dp->table, new_table); - ovs_flow_tbl_destroy(old_table, true); - } - } - } - rtnl_unlock(); - ovs_unlock(); - schedule_delayed_work(&rehash_flow_wq, REHASH_FLOW_INTERVAL); -} - static int __net_init ovs_init_net(struct net *net) { struct ovs_net *ovs_net = net_generic(net, ovs_net_id); @@ -2419,8 +2394,6 @@ static int __init dp_init(void) if (err < 0) goto error_unreg_notifier; - schedule_delayed_work(&rehash_flow_wq, REHASH_FLOW_INTERVAL); - return 0; error_unreg_notifier: @@ -2437,7 +2410,6 @@ error: static void dp_cleanup(void) { - cancel_delayed_work_sync(&rehash_flow_wq); dp_unregister_genl(ARRAY_SIZE(dp_genl_families)); unregister_netdevice_notifier(&ovs_dp_device_notifier); unregister_pernet_device(&ovs_net_ops); |