]>
Commit | Line | Data |
---|---|---|
595e069a JS |
1 | /* |
2 | * inet fragments management | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * as published by the Free Software Foundation; either version | |
7 | * 2 of the License, or (at your option) any later version. | |
8 | * | |
9 | * Authors: Pavel Emelyanov <xemul@openvz.org> | |
10 | * Started as consolidation of ipv4/ip_fragment.c, | |
11 | * ipv6/reassembly. and ipv6 nf conntrack reassembly | |
12 | */ | |
13 | ||
3cdc5697 | 14 | #ifndef HAVE_CORRECT_MRU_HANDLING |
595e069a JS |
15 | |
16 | #include <linux/list.h> | |
17 | #include <linux/spinlock.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/timer.h> | |
20 | #include <linux/mm.h> | |
21 | #include <linux/random.h> | |
22 | #include <linux/skbuff.h> | |
23 | #include <linux/rtnetlink.h> | |
24 | #include <linux/slab.h> | |
25 | ||
26 | #include <net/sock.h> | |
27 | #include <net/inet_frag.h> | |
28 | #include <net/inet_ecn.h> | |
29 | ||
91408ae0 | 30 | #ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK |
595e069a JS |
31 | static bool inet_fragq_should_evict(const struct inet_frag_queue *q) |
32 | { | |
33 | return q->net->low_thresh == 0 || | |
34 | frag_mem_limit(q->net) >= q->net->low_thresh; | |
35 | } | |
36 | ||
37 | static unsigned int | |
38 | inet_evict_bucket(struct inet_frags *f, struct inet_frag_bucket *hb) | |
39 | { | |
595e069a JS |
40 | struct inet_frag_queue *fq; |
41 | struct hlist_node *n; | |
42 | unsigned int evicted = 0; | |
43 | HLIST_HEAD(expired); | |
44 | ||
45 | spin_lock(&hb->chain_lock); | |
46 | ||
47 | hlist_for_each_entry_safe(fq, n, &hb->chain, list) { | |
48 | if (!inet_fragq_should_evict(fq)) | |
49 | continue; | |
50 | ||
51 | if (!del_timer(&fq->timer)) | |
52 | continue; | |
53 | ||
e0d45da3 JS |
54 | #ifdef HAVE_INET_FRAG_QUEUE_WITH_LIST_EVICTOR |
55 | hlist_add_head(&fq->list_evictor, &expired); | |
56 | #else | |
ccd0a13b JS |
57 | hlist_del(&fq->list); |
58 | hlist_add_head(&fq->list, &expired); | |
595e069a JS |
59 | #endif |
60 | ++evicted; | |
61 | } | |
62 | ||
63 | spin_unlock(&hb->chain_lock); | |
64 | ||
e0d45da3 | 65 | #ifdef HAVE_INET_FRAG_QUEUE_WITH_LIST_EVICTOR |
595e069a | 66 | hlist_for_each_entry_safe(fq, n, &expired, list_evictor) |
e0d45da3 | 67 | #else |
ccd0a13b | 68 | hlist_for_each_entry_safe(fq, n, &expired, list) |
595e069a | 69 | #endif |
ccd0a13b | 70 | f->frag_expire((unsigned long) fq); |
595e069a JS |
71 | |
72 | return evicted; | |
73 | } | |
74 | ||
595e069a JS |
75 | void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f) |
76 | { | |
ccd0a13b | 77 | int thresh = nf->low_thresh; |
595e069a | 78 | unsigned int seq; |
ccd0a13b JS |
79 | int i; |
80 | ||
81 | nf->low_thresh = 0; | |
595e069a JS |
82 | |
83 | evict_again: | |
84 | local_bh_disable(); | |
85 | seq = read_seqbegin(&f->rnd_seqlock); | |
86 | ||
ccd0a13b JS |
87 | for (i = 0; i < INETFRAGS_HASHSZ ; i++) |
88 | inet_evict_bucket(f, &f->hash[i]); | |
595e069a JS |
89 | |
90 | local_bh_enable(); | |
91 | cond_resched(); | |
92 | ||
93 | if (read_seqretry(&f->rnd_seqlock, seq) || | |
94 | percpu_counter_sum(&nf->mem)) | |
95 | goto evict_again; | |
595e069a | 96 | |
ccd0a13b | 97 | nf->low_thresh = thresh; |
595e069a | 98 | } |
ccd0a13b JS |
99 | #else /* HAVE_INET_FRAGS_WITH_FRAGS_WORK */ |
100 | void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f) | |
595e069a | 101 | { |
ccd0a13b | 102 | int thresh = nf->low_thresh; |
595e069a | 103 | |
ccd0a13b | 104 | nf->low_thresh = 0; |
595e069a | 105 | |
ccd0a13b JS |
106 | local_bh_disable(); |
107 | inet_frag_evictor(nf, f, true); | |
108 | local_bh_enable(); | |
595e069a | 109 | |
ccd0a13b | 110 | nf->low_thresh = thresh; |
595e069a | 111 | } |
ccd0a13b | 112 | #endif /* HAVE_INET_FRAGS_WITH_FRAGS_WORK */ |
595e069a | 113 | |
3cdc5697 | 114 | #endif /* !HAVE_CORRECT_MRU_HANDLING */ |