aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch/flow_table.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/openvswitch/flow_table.c')
-rw-r--r--net/openvswitch/flow_table.c150
1 files changed, 85 insertions, 65 deletions
diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c
index e42542706087..3c268b3d71c3 100644
--- a/net/openvswitch/flow_table.c
+++ b/net/openvswitch/flow_table.c
@@ -25,7 +25,7 @@
25#include <linux/if_vlan.h> 25#include <linux/if_vlan.h>
26#include <net/llc_pdu.h> 26#include <net/llc_pdu.h>
27#include <linux/kernel.h> 27#include <linux/kernel.h>
28#include <linux/jhash.h> 28#include <linux/hash.h>
29#include <linux/jiffies.h> 29#include <linux/jiffies.h>
30#include <linux/llc.h> 30#include <linux/llc.h>
31#include <linux/module.h> 31#include <linux/module.h>
@@ -44,8 +44,6 @@
44#include <net/ipv6.h> 44#include <net/ipv6.h>
45#include <net/ndisc.h> 45#include <net/ndisc.h>
46 46
47#include "datapath.h"
48
49#define TBL_MIN_BUCKETS 1024 47#define TBL_MIN_BUCKETS 1024
50#define REHASH_INTERVAL (10 * 60 * HZ) 48#define REHASH_INTERVAL (10 * 60 * HZ)
51 49
@@ -72,19 +70,42 @@ void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
72 *d++ = *s++ & *m++; 70 *d++ = *s++ & *m++;
73} 71}
74 72
75struct sw_flow *ovs_flow_alloc(void) 73struct sw_flow *ovs_flow_alloc(bool percpu_stats)
76{ 74{
77 struct sw_flow *flow; 75 struct sw_flow *flow;
76 int cpu;
78 77
79 flow = kmem_cache_alloc(flow_cache, GFP_KERNEL); 78 flow = kmem_cache_alloc(flow_cache, GFP_KERNEL);
80 if (!flow) 79 if (!flow)
81 return ERR_PTR(-ENOMEM); 80 return ERR_PTR(-ENOMEM);
82 81
83 spin_lock_init(&flow->lock);
84 flow->sf_acts = NULL; 82 flow->sf_acts = NULL;
85 flow->mask = NULL; 83 flow->mask = NULL;
86 84
85 flow->stats.is_percpu = percpu_stats;
86
87 if (!percpu_stats) {
88 flow->stats.stat = kzalloc(sizeof(*flow->stats.stat), GFP_KERNEL);
89 if (!flow->stats.stat)
90 goto err;
91
92 spin_lock_init(&flow->stats.stat->lock);
93 } else {
94 flow->stats.cpu_stats = alloc_percpu(struct flow_stats);
95 if (!flow->stats.cpu_stats)
96 goto err;
97
98 for_each_possible_cpu(cpu) {
99 struct flow_stats *cpu_stats;
100
101 cpu_stats = per_cpu_ptr(flow->stats.cpu_stats, cpu);
102 spin_lock_init(&cpu_stats->lock);
103 }
104 }
87 return flow; 105 return flow;
106err:
107 kmem_cache_free(flow_cache, flow);
108 return ERR_PTR(-ENOMEM);
88} 109}
89 110
90int ovs_flow_tbl_count(struct flow_table *table) 111int ovs_flow_tbl_count(struct flow_table *table)
@@ -118,6 +139,10 @@ static struct flex_array *alloc_buckets(unsigned int n_buckets)
118static void flow_free(struct sw_flow *flow) 139static void flow_free(struct sw_flow *flow)
119{ 140{
120 kfree((struct sf_flow_acts __force *)flow->sf_acts); 141 kfree((struct sf_flow_acts __force *)flow->sf_acts);
142 if (flow->stats.is_percpu)
143 free_percpu(flow->stats.cpu_stats);
144 else
145 kfree(flow->stats.stat);
121 kmem_cache_free(flow_cache, flow); 146 kmem_cache_free(flow_cache, flow);
122} 147}
123 148
@@ -128,36 +153,29 @@ static void rcu_free_flow_callback(struct rcu_head *rcu)
128 flow_free(flow); 153 flow_free(flow);
129} 154}
130 155
131static void rcu_free_sw_flow_mask_cb(struct rcu_head *rcu)
132{
133 struct sw_flow_mask *mask = container_of(rcu, struct sw_flow_mask, rcu);
134
135 kfree(mask);
136}
137
138static void flow_mask_del_ref(struct sw_flow_mask *mask, bool deferred)
139{
140 if (!mask)
141 return;
142
143 BUG_ON(!mask->ref_count);
144 mask->ref_count--;
145
146 if (!mask->ref_count) {
147 list_del_rcu(&mask->list);
148 if (deferred)
149 call_rcu(&mask->rcu, rcu_free_sw_flow_mask_cb);
150 else
151 kfree(mask);
152 }
153}
154
155void ovs_flow_free(struct sw_flow *flow, bool deferred) 156void ovs_flow_free(struct sw_flow *flow, bool deferred)
156{ 157{
157 if (!flow) 158 if (!flow)
158 return; 159 return;
159 160
160 flow_mask_del_ref(flow->mask, deferred); 161 if (flow->mask) {
162 struct sw_flow_mask *mask = flow->mask;
163
164 /* ovs-lock is required to protect mask-refcount and
165 * mask list.
166 */
167 ASSERT_OVSL();
168 BUG_ON(!mask->ref_count);
169 mask->ref_count--;
170
171 if (!mask->ref_count) {
172 list_del_rcu(&mask->list);
173 if (deferred)
174 kfree_rcu(mask, rcu);
175 else
176 kfree(mask);
177 }
178 }
161 179
162 if (deferred) 180 if (deferred)
163 call_rcu(&flow->rcu, rcu_free_flow_callback); 181 call_rcu(&flow->rcu, rcu_free_flow_callback);
@@ -170,26 +188,9 @@ static void free_buckets(struct flex_array *buckets)
170 flex_array_free(buckets); 188 flex_array_free(buckets);
171} 189}
172 190
191
173static void __table_instance_destroy(struct table_instance *ti) 192static void __table_instance_destroy(struct table_instance *ti)
174{ 193{
175 int i;
176
177 if (ti->keep_flows)
178 goto skip_flows;
179
180 for (i = 0; i < ti->n_buckets; i++) {
181 struct sw_flow *flow;
182 struct hlist_head *head = flex_array_get(ti->buckets, i);
183 struct hlist_node *n;
184 int ver = ti->node_ver;
185
186 hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) {
187 hlist_del(&flow->hash_node[ver]);
188 ovs_flow_free(flow, false);
189 }
190 }
191
192skip_flows:
193 free_buckets(ti->buckets); 194 free_buckets(ti->buckets);
194 kfree(ti); 195 kfree(ti);
195} 196}
@@ -240,20 +241,38 @@ static void flow_tbl_destroy_rcu_cb(struct rcu_head *rcu)
240 241
241static void table_instance_destroy(struct table_instance *ti, bool deferred) 242static void table_instance_destroy(struct table_instance *ti, bool deferred)
242{ 243{
244 int i;
245
243 if (!ti) 246 if (!ti)
244 return; 247 return;
245 248
249 if (ti->keep_flows)
250 goto skip_flows;
251
252 for (i = 0; i < ti->n_buckets; i++) {
253 struct sw_flow *flow;
254 struct hlist_head *head = flex_array_get(ti->buckets, i);
255 struct hlist_node *n;
256 int ver = ti->node_ver;
257
258 hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) {
259 hlist_del_rcu(&flow->hash_node[ver]);
260 ovs_flow_free(flow, deferred);
261 }
262 }
263
264skip_flows:
246 if (deferred) 265 if (deferred)
247 call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb); 266 call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);
248 else 267 else
249 __table_instance_destroy(ti); 268 __table_instance_destroy(ti);
250} 269}
251 270
252void ovs_flow_tbl_destroy(struct flow_table *table) 271void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred)
253{ 272{
254 struct table_instance *ti = ovsl_dereference(table->ti); 273 struct table_instance *ti = ovsl_dereference(table->ti);
255 274
256 table_instance_destroy(ti, false); 275 table_instance_destroy(ti, deferred);
257} 276}
258 277
259struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti, 278struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti,
@@ -362,7 +381,7 @@ static u32 flow_hash(const struct sw_flow_key *key, int key_start,
362 /* Make sure number of hash bytes are multiple of u32. */ 381 /* Make sure number of hash bytes are multiple of u32. */
363 BUILD_BUG_ON(sizeof(long) % sizeof(u32)); 382 BUILD_BUG_ON(sizeof(long) % sizeof(u32));
364 383
365 return jhash2(hash_key, hash_u32s, 0); 384 return arch_fast_hash2(hash_key, hash_u32s, 0);
366} 385}
367 386
368static int flow_key_start(const struct sw_flow_key *key) 387static int flow_key_start(const struct sw_flow_key *key)
@@ -429,11 +448,11 @@ static struct sw_flow *masked_flow_lookup(struct table_instance *ti,
429 return NULL; 448 return NULL;
430} 449}
431 450
432struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, 451struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl,
433 const struct sw_flow_key *key, 452 const struct sw_flow_key *key,
434 u32 *n_mask_hit) 453 u32 *n_mask_hit)
435{ 454{
436 struct table_instance *ti = rcu_dereference(tbl->ti); 455 struct table_instance *ti = rcu_dereference_ovsl(tbl->ti);
437 struct sw_flow_mask *mask; 456 struct sw_flow_mask *mask;
438 struct sw_flow *flow; 457 struct sw_flow *flow;
439 458
@@ -447,6 +466,14 @@ struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl,
447 return NULL; 466 return NULL;
448} 467}
449 468
469struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl,
470 const struct sw_flow_key *key)
471{
472 u32 __always_unused n_mask_hit;
473
474 return ovs_flow_tbl_lookup_stats(tbl, key, &n_mask_hit);
475}
476
450int ovs_flow_tbl_num_masks(const struct flow_table *table) 477int ovs_flow_tbl_num_masks(const struct flow_table *table)
451{ 478{
452 struct sw_flow_mask *mask; 479 struct sw_flow_mask *mask;
@@ -478,16 +505,11 @@ static struct sw_flow_mask *mask_alloc(void)
478 505
479 mask = kmalloc(sizeof(*mask), GFP_KERNEL); 506 mask = kmalloc(sizeof(*mask), GFP_KERNEL);
480 if (mask) 507 if (mask)
481 mask->ref_count = 0; 508 mask->ref_count = 1;
482 509
483 return mask; 510 return mask;
484} 511}
485 512
486static void mask_add_ref(struct sw_flow_mask *mask)
487{
488 mask->ref_count++;
489}
490
491static bool mask_equal(const struct sw_flow_mask *a, 513static bool mask_equal(const struct sw_flow_mask *a,
492 const struct sw_flow_mask *b) 514 const struct sw_flow_mask *b)
493{ 515{
@@ -514,11 +536,7 @@ static struct sw_flow_mask *flow_mask_find(const struct flow_table *tbl,
514 return NULL; 536 return NULL;
515} 537}
516 538
517/** 539/* Add 'mask' into the mask list, if it is not already there. */
518 * add a new mask into the mask list.
519 * The caller needs to make sure that 'mask' is not the same
520 * as any masks that are already on the list.
521 */
522static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow, 540static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow,
523 struct sw_flow_mask *new) 541 struct sw_flow_mask *new)
524{ 542{
@@ -532,9 +550,11 @@ static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow,
532 mask->key = new->key; 550 mask->key = new->key;
533 mask->range = new->range; 551 mask->range = new->range;
534 list_add_rcu(&mask->list, &tbl->mask_list); 552 list_add_rcu(&mask->list, &tbl->mask_list);
553 } else {
554 BUG_ON(!mask->ref_count);
555 mask->ref_count++;
535 } 556 }
536 557
537 mask_add_ref(mask);
538 flow->mask = mask; 558 flow->mask = mask;
539 return 0; 559 return 0;
540} 560}