aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/flow.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/flow.c')
-rw-r--r--net/core/flow.c132
1 files changed, 70 insertions, 62 deletions
diff --git a/net/core/flow.c b/net/core/flow.c
index dfa602ceb8cd..31cfb365e0c6 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -24,6 +24,7 @@
24#include <net/flow.h> 24#include <net/flow.h>
25#include <linux/atomic.h> 25#include <linux/atomic.h>
26#include <linux/security.h> 26#include <linux/security.h>
27#include <net/net_namespace.h>
27 28
28struct flow_cache_entry { 29struct flow_cache_entry {
29 union { 30 union {
@@ -38,37 +39,14 @@ struct flow_cache_entry {
38 struct flow_cache_object *object; 39 struct flow_cache_object *object;
39}; 40};
40 41
41struct flow_cache_percpu {
42 struct hlist_head *hash_table;
43 int hash_count;
44 u32 hash_rnd;
45 int hash_rnd_recalc;
46 struct tasklet_struct flush_tasklet;
47};
48
49struct flow_flush_info { 42struct flow_flush_info {
50 struct flow_cache *cache; 43 struct flow_cache *cache;
51 atomic_t cpuleft; 44 atomic_t cpuleft;
52 struct completion completion; 45 struct completion completion;
53}; 46};
54 47
55struct flow_cache {
56 u32 hash_shift;
57 struct flow_cache_percpu __percpu *percpu;
58 struct notifier_block hotcpu_notifier;
59 int low_watermark;
60 int high_watermark;
61 struct timer_list rnd_timer;
62};
63
64atomic_t flow_cache_genid = ATOMIC_INIT(0);
65EXPORT_SYMBOL(flow_cache_genid);
66static struct flow_cache flow_cache_global;
67static struct kmem_cache *flow_cachep __read_mostly; 48static struct kmem_cache *flow_cachep __read_mostly;
68 49
69static DEFINE_SPINLOCK(flow_cache_gc_lock);
70static LIST_HEAD(flow_cache_gc_list);
71
72#define flow_cache_hash_size(cache) (1 << (cache)->hash_shift) 50#define flow_cache_hash_size(cache) (1 << (cache)->hash_shift)
73#define FLOW_HASH_RND_PERIOD (10 * 60 * HZ) 51#define FLOW_HASH_RND_PERIOD (10 * 60 * HZ)
74 52
@@ -84,16 +62,18 @@ static void flow_cache_new_hashrnd(unsigned long arg)
84 add_timer(&fc->rnd_timer); 62 add_timer(&fc->rnd_timer);
85} 63}
86 64
87static int flow_entry_valid(struct flow_cache_entry *fle) 65static int flow_entry_valid(struct flow_cache_entry *fle,
66 struct netns_xfrm *xfrm)
88{ 67{
89 if (atomic_read(&flow_cache_genid) != fle->genid) 68 if (atomic_read(&xfrm->flow_cache_genid) != fle->genid)
90 return 0; 69 return 0;
91 if (fle->object && !fle->object->ops->check(fle->object)) 70 if (fle->object && !fle->object->ops->check(fle->object))
92 return 0; 71 return 0;
93 return 1; 72 return 1;
94} 73}
95 74
96static void flow_entry_kill(struct flow_cache_entry *fle) 75static void flow_entry_kill(struct flow_cache_entry *fle,
76 struct netns_xfrm *xfrm)
97{ 77{
98 if (fle->object) 78 if (fle->object)
99 fle->object->ops->delete(fle->object); 79 fle->object->ops->delete(fle->object);
@@ -104,26 +84,28 @@ static void flow_cache_gc_task(struct work_struct *work)
104{ 84{
105 struct list_head gc_list; 85 struct list_head gc_list;
106 struct flow_cache_entry *fce, *n; 86 struct flow_cache_entry *fce, *n;
87 struct netns_xfrm *xfrm = container_of(work, struct netns_xfrm,
88 flow_cache_gc_work);
107 89
108 INIT_LIST_HEAD(&gc_list); 90 INIT_LIST_HEAD(&gc_list);
109 spin_lock_bh(&flow_cache_gc_lock); 91 spin_lock_bh(&xfrm->flow_cache_gc_lock);
110 list_splice_tail_init(&flow_cache_gc_list, &gc_list); 92 list_splice_tail_init(&xfrm->flow_cache_gc_list, &gc_list);
111 spin_unlock_bh(&flow_cache_gc_lock); 93 spin_unlock_bh(&xfrm->flow_cache_gc_lock);
112 94
113 list_for_each_entry_safe(fce, n, &gc_list, u.gc_list) 95 list_for_each_entry_safe(fce, n, &gc_list, u.gc_list)
114 flow_entry_kill(fce); 96 flow_entry_kill(fce, xfrm);
115} 97}
116static DECLARE_WORK(flow_cache_gc_work, flow_cache_gc_task);
117 98
118static void flow_cache_queue_garbage(struct flow_cache_percpu *fcp, 99static void flow_cache_queue_garbage(struct flow_cache_percpu *fcp,
119 int deleted, struct list_head *gc_list) 100 int deleted, struct list_head *gc_list,
101 struct netns_xfrm *xfrm)
120{ 102{
121 if (deleted) { 103 if (deleted) {
122 fcp->hash_count -= deleted; 104 fcp->hash_count -= deleted;
123 spin_lock_bh(&flow_cache_gc_lock); 105 spin_lock_bh(&xfrm->flow_cache_gc_lock);
124 list_splice_tail(gc_list, &flow_cache_gc_list); 106 list_splice_tail(gc_list, &xfrm->flow_cache_gc_list);
125 spin_unlock_bh(&flow_cache_gc_lock); 107 spin_unlock_bh(&xfrm->flow_cache_gc_lock);
126 schedule_work(&flow_cache_gc_work); 108 schedule_work(&xfrm->flow_cache_gc_work);
127 } 109 }
128} 110}
129 111
@@ -135,6 +117,8 @@ static void __flow_cache_shrink(struct flow_cache *fc,
135 struct hlist_node *tmp; 117 struct hlist_node *tmp;
136 LIST_HEAD(gc_list); 118 LIST_HEAD(gc_list);
137 int i, deleted = 0; 119 int i, deleted = 0;
120 struct netns_xfrm *xfrm = container_of(fc, struct netns_xfrm,
121 flow_cache_global);
138 122
139 for (i = 0; i < flow_cache_hash_size(fc); i++) { 123 for (i = 0; i < flow_cache_hash_size(fc); i++) {
140 int saved = 0; 124 int saved = 0;
@@ -142,7 +126,7 @@ static void __flow_cache_shrink(struct flow_cache *fc,
142 hlist_for_each_entry_safe(fle, tmp, 126 hlist_for_each_entry_safe(fle, tmp,
143 &fcp->hash_table[i], u.hlist) { 127 &fcp->hash_table[i], u.hlist) {
144 if (saved < shrink_to && 128 if (saved < shrink_to &&
145 flow_entry_valid(fle)) { 129 flow_entry_valid(fle, xfrm)) {
146 saved++; 130 saved++;
147 } else { 131 } else {
148 deleted++; 132 deleted++;
@@ -152,7 +136,7 @@ static void __flow_cache_shrink(struct flow_cache *fc,
152 } 136 }
153 } 137 }
154 138
155 flow_cache_queue_garbage(fcp, deleted, &gc_list); 139 flow_cache_queue_garbage(fcp, deleted, &gc_list, xfrm);
156} 140}
157 141
158static void flow_cache_shrink(struct flow_cache *fc, 142static void flow_cache_shrink(struct flow_cache *fc,
@@ -208,7 +192,7 @@ struct flow_cache_object *
208flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, 192flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
209 flow_resolve_t resolver, void *ctx) 193 flow_resolve_t resolver, void *ctx)
210{ 194{
211 struct flow_cache *fc = &flow_cache_global; 195 struct flow_cache *fc = &net->xfrm.flow_cache_global;
212 struct flow_cache_percpu *fcp; 196 struct flow_cache_percpu *fcp;
213 struct flow_cache_entry *fle, *tfle; 197 struct flow_cache_entry *fle, *tfle;
214 struct flow_cache_object *flo; 198 struct flow_cache_object *flo;
@@ -258,7 +242,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
258 hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]); 242 hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]);
259 fcp->hash_count++; 243 fcp->hash_count++;
260 } 244 }
261 } else if (likely(fle->genid == atomic_read(&flow_cache_genid))) { 245 } else if (likely(fle->genid == atomic_read(&net->xfrm.flow_cache_genid))) {
262 flo = fle->object; 246 flo = fle->object;
263 if (!flo) 247 if (!flo)
264 goto ret_object; 248 goto ret_object;
@@ -279,7 +263,7 @@ nocache:
279 } 263 }
280 flo = resolver(net, key, family, dir, flo, ctx); 264 flo = resolver(net, key, family, dir, flo, ctx);
281 if (fle) { 265 if (fle) {
282 fle->genid = atomic_read(&flow_cache_genid); 266 fle->genid = atomic_read(&net->xfrm.flow_cache_genid);
283 if (!IS_ERR(flo)) 267 if (!IS_ERR(flo))
284 fle->object = flo; 268 fle->object = flo;
285 else 269 else
@@ -303,12 +287,14 @@ static void flow_cache_flush_tasklet(unsigned long data)
303 struct hlist_node *tmp; 287 struct hlist_node *tmp;
304 LIST_HEAD(gc_list); 288 LIST_HEAD(gc_list);
305 int i, deleted = 0; 289 int i, deleted = 0;
290 struct netns_xfrm *xfrm = container_of(fc, struct netns_xfrm,
291 flow_cache_global);
306 292
307 fcp = this_cpu_ptr(fc->percpu); 293 fcp = this_cpu_ptr(fc->percpu);
308 for (i = 0; i < flow_cache_hash_size(fc); i++) { 294 for (i = 0; i < flow_cache_hash_size(fc); i++) {
309 hlist_for_each_entry_safe(fle, tmp, 295 hlist_for_each_entry_safe(fle, tmp,
310 &fcp->hash_table[i], u.hlist) { 296 &fcp->hash_table[i], u.hlist) {
311 if (flow_entry_valid(fle)) 297 if (flow_entry_valid(fle, xfrm))
312 continue; 298 continue;
313 299
314 deleted++; 300 deleted++;
@@ -317,7 +303,7 @@ static void flow_cache_flush_tasklet(unsigned long data)
317 } 303 }
318 } 304 }
319 305
320 flow_cache_queue_garbage(fcp, deleted, &gc_list); 306 flow_cache_queue_garbage(fcp, deleted, &gc_list, xfrm);
321 307
322 if (atomic_dec_and_test(&info->cpuleft)) 308 if (atomic_dec_and_test(&info->cpuleft))
323 complete(&info->completion); 309 complete(&info->completion);
@@ -351,10 +337,9 @@ static void flow_cache_flush_per_cpu(void *data)
351 tasklet_schedule(tasklet); 337 tasklet_schedule(tasklet);
352} 338}
353 339
354void flow_cache_flush(void) 340void flow_cache_flush(struct net *net)
355{ 341{
356 struct flow_flush_info info; 342 struct flow_flush_info info;
357 static DEFINE_MUTEX(flow_flush_sem);
358 cpumask_var_t mask; 343 cpumask_var_t mask;
359 int i, self; 344 int i, self;
360 345
@@ -365,8 +350,8 @@ void flow_cache_flush(void)
365 350
366 /* Don't want cpus going down or up during this. */ 351 /* Don't want cpus going down or up during this. */
367 get_online_cpus(); 352 get_online_cpus();
368 mutex_lock(&flow_flush_sem); 353 mutex_lock(&net->xfrm.flow_flush_sem);
369 info.cache = &flow_cache_global; 354 info.cache = &net->xfrm.flow_cache_global;
370 for_each_online_cpu(i) 355 for_each_online_cpu(i)
371 if (!flow_cache_percpu_empty(info.cache, i)) 356 if (!flow_cache_percpu_empty(info.cache, i))
372 cpumask_set_cpu(i, mask); 357 cpumask_set_cpu(i, mask);
@@ -386,21 +371,23 @@ void flow_cache_flush(void)
386 wait_for_completion(&info.completion); 371 wait_for_completion(&info.completion);
387 372
388done: 373done:
389 mutex_unlock(&flow_flush_sem); 374 mutex_unlock(&net->xfrm.flow_flush_sem);
390 put_online_cpus(); 375 put_online_cpus();
391 free_cpumask_var(mask); 376 free_cpumask_var(mask);
392} 377}
393 378
394static void flow_cache_flush_task(struct work_struct *work) 379static void flow_cache_flush_task(struct work_struct *work)
395{ 380{
396 flow_cache_flush(); 381 struct netns_xfrm *xfrm = container_of(work, struct netns_xfrm,
397} 382 flow_cache_gc_work);
383 struct net *net = container_of(xfrm, struct net, xfrm);
398 384
399static DECLARE_WORK(flow_cache_flush_work, flow_cache_flush_task); 385 flow_cache_flush(net);
386}
400 387
401void flow_cache_flush_deferred(void) 388void flow_cache_flush_deferred(struct net *net)
402{ 389{
403 schedule_work(&flow_cache_flush_work); 390 schedule_work(&net->xfrm.flow_cache_flush_work);
404} 391}
405 392
406static int flow_cache_cpu_prepare(struct flow_cache *fc, int cpu) 393static int flow_cache_cpu_prepare(struct flow_cache *fc, int cpu)
@@ -425,7 +412,8 @@ static int flow_cache_cpu(struct notifier_block *nfb,
425 unsigned long action, 412 unsigned long action,
426 void *hcpu) 413 void *hcpu)
427{ 414{
428 struct flow_cache *fc = container_of(nfb, struct flow_cache, hotcpu_notifier); 415 struct flow_cache *fc = container_of(nfb, struct flow_cache,
416 hotcpu_notifier);
429 int res, cpu = (unsigned long) hcpu; 417 int res, cpu = (unsigned long) hcpu;
430 struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu); 418 struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu);
431 419
@@ -444,9 +432,20 @@ static int flow_cache_cpu(struct notifier_block *nfb,
444 return NOTIFY_OK; 432 return NOTIFY_OK;
445} 433}
446 434
447static int __init flow_cache_init(struct flow_cache *fc) 435int flow_cache_init(struct net *net)
448{ 436{
449 int i; 437 int i;
438 struct flow_cache *fc = &net->xfrm.flow_cache_global;
439
440 if (!flow_cachep)
441 flow_cachep = kmem_cache_create("flow_cache",
442 sizeof(struct flow_cache_entry),
443 0, SLAB_PANIC, NULL);
444 spin_lock_init(&net->xfrm.flow_cache_gc_lock);
445 INIT_LIST_HEAD(&net->xfrm.flow_cache_gc_list);
446 INIT_WORK(&net->xfrm.flow_cache_gc_work, flow_cache_gc_task);
447 INIT_WORK(&net->xfrm.flow_cache_flush_work, flow_cache_flush_task);
448 mutex_init(&net->xfrm.flow_flush_sem);
450 449
451 fc->hash_shift = 10; 450 fc->hash_shift = 10;
452 fc->low_watermark = 2 * flow_cache_hash_size(fc); 451 fc->low_watermark = 2 * flow_cache_hash_size(fc);
@@ -484,14 +483,23 @@ err:
484 483
485 return -ENOMEM; 484 return -ENOMEM;
486} 485}
486EXPORT_SYMBOL(flow_cache_init);
487 487
488static int __init flow_cache_init_global(void) 488void flow_cache_fini(struct net *net)
489{ 489{
490 flow_cachep = kmem_cache_create("flow_cache", 490 int i;
491 sizeof(struct flow_cache_entry), 491 struct flow_cache *fc = &net->xfrm.flow_cache_global;
492 0, SLAB_PANIC, NULL);
493 492
494 return flow_cache_init(&flow_cache_global); 493 del_timer_sync(&fc->rnd_timer);
495} 494 unregister_hotcpu_notifier(&fc->hotcpu_notifier);
496 495
497module_init(flow_cache_init_global); 496 for_each_possible_cpu(i) {
497 struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, i);
498 kfree(fcp->hash_table);
499 fcp->hash_table = NULL;
500 }
501
502 free_percpu(fc->percpu);
503 fc->percpu = NULL;
504}
505EXPORT_SYMBOL(flow_cache_fini);