aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch/flow_table.c
diff options
context:
space:
mode:
authorThadeu Lima de Souza Cascardo <cascardo@redhat.com>2016-09-15 18:11:53 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-18 22:14:01 -0400
commitdb74a3335e0f645e3139c80bcfc90feb01d8e304 (patch)
tree5adec60da4faa80b188cc0b45639224c0a197db4 /net/openvswitch/flow_table.c
parent40773966ccf1985a1b2bb570a03cbeaf1cbd4e00 (diff)
openvswitch: use percpu flow stats
Instead of using flow stats per NUMA node, use it per CPU. When using megaflows, the stats lock can be a bottleneck in scalability. On a E5-2690 12-core system, usual throughput went from ~4Mpps to ~15Mpps when forwarding between two 40GbE ports with a single flow configured on the datapath. This has been tested on a system with possible CPUs 0-7,16-23. After module removal, there were no corruption on the slab cache. Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@redhat.com> Cc: pravin shelar <pshelar@ovn.org> Acked-by: Pravin B Shelar <pshelar@ovn.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/openvswitch/flow_table.c')
-rw-r--r--net/openvswitch/flow_table.c26
1 files changed, 9 insertions, 17 deletions
diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c
index 957a3c31dbb0..ea7a8073fa02 100644
--- a/net/openvswitch/flow_table.c
+++ b/net/openvswitch/flow_table.c
@@ -32,6 +32,7 @@
32#include <linux/module.h> 32#include <linux/module.h>
33#include <linux/in.h> 33#include <linux/in.h>
34#include <linux/rcupdate.h> 34#include <linux/rcupdate.h>
35#include <linux/cpumask.h>
35#include <linux/if_arp.h> 36#include <linux/if_arp.h>
36#include <linux/ip.h> 37#include <linux/ip.h>
37#include <linux/ipv6.h> 38#include <linux/ipv6.h>
@@ -79,17 +80,12 @@ struct sw_flow *ovs_flow_alloc(void)
79{ 80{
80 struct sw_flow *flow; 81 struct sw_flow *flow;
81 struct flow_stats *stats; 82 struct flow_stats *stats;
82 int node;
83 83
84 flow = kmem_cache_alloc(flow_cache, GFP_KERNEL); 84 flow = kmem_cache_zalloc(flow_cache, GFP_KERNEL);
85 if (!flow) 85 if (!flow)
86 return ERR_PTR(-ENOMEM); 86 return ERR_PTR(-ENOMEM);
87 87
88 flow->sf_acts = NULL; 88 flow->stats_last_writer = -1;
89 flow->mask = NULL;
90 flow->id.unmasked_key = NULL;
91 flow->id.ufid_len = 0;
92 flow->stats_last_writer = NUMA_NO_NODE;
93 89
94 /* Initialize the default stat node. */ 90 /* Initialize the default stat node. */
95 stats = kmem_cache_alloc_node(flow_stats_cache, 91 stats = kmem_cache_alloc_node(flow_stats_cache,
@@ -102,10 +98,6 @@ struct sw_flow *ovs_flow_alloc(void)
102 98
103 RCU_INIT_POINTER(flow->stats[0], stats); 99 RCU_INIT_POINTER(flow->stats[0], stats);
104 100
105 for_each_node(node)
106 if (node != 0)
107 RCU_INIT_POINTER(flow->stats[node], NULL);
108
109 return flow; 101 return flow;
110err: 102err:
111 kmem_cache_free(flow_cache, flow); 103 kmem_cache_free(flow_cache, flow);
@@ -142,17 +134,17 @@ static struct flex_array *alloc_buckets(unsigned int n_buckets)
142 134
143static void flow_free(struct sw_flow *flow) 135static void flow_free(struct sw_flow *flow)
144{ 136{
145 int node; 137 int cpu;
146 138
147 if (ovs_identifier_is_key(&flow->id)) 139 if (ovs_identifier_is_key(&flow->id))
148 kfree(flow->id.unmasked_key); 140 kfree(flow->id.unmasked_key);
149 if (flow->sf_acts) 141 if (flow->sf_acts)
150 ovs_nla_free_flow_actions((struct sw_flow_actions __force *)flow->sf_acts); 142 ovs_nla_free_flow_actions((struct sw_flow_actions __force *)flow->sf_acts);
151 /* We open code this to make sure node 0 is always considered */ 143 /* We open code this to make sure cpu 0 is always considered */
152 for (node = 0; node < MAX_NUMNODES; node = next_node(node, node_possible_map)) 144 for (cpu = 0; cpu < nr_cpu_ids; cpu = cpumask_next(cpu, cpu_possible_mask))
153 if (node != 0 && flow->stats[node]) 145 if (flow->stats[cpu])
154 kmem_cache_free(flow_stats_cache, 146 kmem_cache_free(flow_stats_cache,
155 (struct flow_stats __force *)flow->stats[node]); 147 (struct flow_stats __force *)flow->stats[cpu]);
156 kmem_cache_free(flow_cache, flow); 148 kmem_cache_free(flow_cache, flow);
157} 149}
158 150
@@ -757,7 +749,7 @@ int ovs_flow_init(void)
757 BUILD_BUG_ON(sizeof(struct sw_flow_key) % sizeof(long)); 749 BUILD_BUG_ON(sizeof(struct sw_flow_key) % sizeof(long));
758 750
759 flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow) 751 flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow)
760 + (nr_node_ids 752 + (nr_cpu_ids
761 * sizeof(struct flow_stats *)), 753 * sizeof(struct flow_stats *)),
762 0, 0, NULL); 754 0, 0, NULL);
763 if (flow_cache == NULL) 755 if (flow_cache == NULL)