aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/inet_frag.h1
-rw-r--r--include/net/ip.h1
-rw-r--r--include/net/ipv6.h9
-rw-r--r--net/ipv4/inet_fragment.c32
-rw-r--r--net/ipv4/ip_fragment.c30
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c29
-rw-r--r--net/ipv6/reassembly.c30
7 files changed, 52 insertions, 80 deletions
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 2dd1cd4e7f44..cf583cf7e9ef 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -49,5 +49,6 @@ void inet_frags_fini(struct inet_frags *);
49void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f); 49void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f);
50void inet_frag_destroy(struct inet_frag_queue *q, 50void inet_frag_destroy(struct inet_frag_queue *q,
51 struct inet_frags *f, int *work); 51 struct inet_frags *f, int *work);
52int inet_frag_evictor(struct inet_frags *f);
52 53
53#endif 54#endif
diff --git a/include/net/ip.h b/include/net/ip.h
index e6aa955e241c..840dd91b513b 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -160,6 +160,7 @@ DECLARE_SNMP_STAT(struct ipstats_mib, ip_statistics);
160#define IP_INC_STATS(field) SNMP_INC_STATS(ip_statistics, field) 160#define IP_INC_STATS(field) SNMP_INC_STATS(ip_statistics, field)
161#define IP_INC_STATS_BH(field) SNMP_INC_STATS_BH(ip_statistics, field) 161#define IP_INC_STATS_BH(field) SNMP_INC_STATS_BH(ip_statistics, field)
162#define IP_INC_STATS_USER(field) SNMP_INC_STATS_USER(ip_statistics, field) 162#define IP_INC_STATS_USER(field) SNMP_INC_STATS_USER(ip_statistics, field)
163#define IP_ADD_STATS_BH(field, val) SNMP_ADD_STATS_BH(ip_statistics, field, val)
163DECLARE_SNMP_STAT(struct linux_mib, net_statistics); 164DECLARE_SNMP_STAT(struct linux_mib, net_statistics);
164#define NET_INC_STATS(field) SNMP_INC_STATS(net_statistics, field) 165#define NET_INC_STATS(field) SNMP_INC_STATS(net_statistics, field)
165#define NET_INC_STATS_BH(field) SNMP_INC_STATS_BH(net_statistics, field) 166#define NET_INC_STATS_BH(field) SNMP_INC_STATS_BH(net_statistics, field)
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index b29d76c715d2..a0f1042037f2 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -120,12 +120,21 @@ extern int sysctl_mld_max_msf;
120 SNMP_INC_STATS##modifier(statname##_statistics, (field)); \ 120 SNMP_INC_STATS##modifier(statname##_statistics, (field)); \
121}) 121})
122 122
123#define _DEVADD(statname, modifier, idev, field, val) \
124({ \
125 struct inet6_dev *_idev = (idev); \
126 if (likely(_idev != NULL)) \
127 SNMP_ADD_STATS##modifier((_idev)->stats.statname, (field), (val)); \
128 SNMP_ADD_STATS##modifier(statname##_statistics, (field), (val));\
129})
130
123/* MIBs */ 131/* MIBs */
124DECLARE_SNMP_STAT(struct ipstats_mib, ipv6_statistics); 132DECLARE_SNMP_STAT(struct ipstats_mib, ipv6_statistics);
125 133
126#define IP6_INC_STATS(idev,field) _DEVINC(ipv6, , idev, field) 134#define IP6_INC_STATS(idev,field) _DEVINC(ipv6, , idev, field)
127#define IP6_INC_STATS_BH(idev,field) _DEVINC(ipv6, _BH, idev, field) 135#define IP6_INC_STATS_BH(idev,field) _DEVINC(ipv6, _BH, idev, field)
128#define IP6_INC_STATS_USER(idev,field) _DEVINC(ipv6, _USER, idev, field) 136#define IP6_INC_STATS_USER(idev,field) _DEVINC(ipv6, _USER, idev, field)
137#define IP6_ADD_STATS_BH(idev,field,val) _DEVADD(ipv6, _BH, idev, field, val)
129 138
130DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); 139DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
131DECLARE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics); 140DECLARE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics);
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 15fb2c4a36a7..484cf512858f 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -140,3 +140,35 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f,
140 140
141} 141}
142EXPORT_SYMBOL(inet_frag_destroy); 142EXPORT_SYMBOL(inet_frag_destroy);
143
144int inet_frag_evictor(struct inet_frags *f)
145{
146 struct inet_frag_queue *q;
147 int work, evicted = 0;
148
149 work = atomic_read(&f->mem) - f->ctl->low_thresh;
150 while (work > 0) {
151 read_lock(&f->lock);
152 if (list_empty(&f->lru_list)) {
153 read_unlock(&f->lock);
154 break;
155 }
156
157 q = list_first_entry(&f->lru_list,
158 struct inet_frag_queue, lru_list);
159 atomic_inc(&q->refcnt);
160 read_unlock(&f->lock);
161
162 spin_lock(&q->lock);
163 if (!(q->last_in & COMPLETE))
164 inet_frag_kill(q, f);
165 spin_unlock(&q->lock);
166
167 if (atomic_dec_and_test(&q->refcnt))
168 inet_frag_destroy(q, f, &work);
169 evicted++;
170 }
171
172 return evicted;
173}
174EXPORT_SYMBOL(inet_frag_evictor);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index e8736632094a..ee6e04159627 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -174,33 +174,11 @@ static void ipq_kill(struct ipq *ipq)
174 */ 174 */
175static void ip_evictor(void) 175static void ip_evictor(void)
176{ 176{
177 struct ipq *qp; 177 int evicted;
178 struct list_head *tmp;
179 int work;
180
181 work = atomic_read(&ip4_frags.mem) - ip4_frags_ctl.low_thresh;
182 if (work <= 0)
183 return;
184
185 while (work > 0) {
186 read_lock(&ip4_frags.lock);
187 if (list_empty(&ip4_frags.lru_list)) {
188 read_unlock(&ip4_frags.lock);
189 return;
190 }
191 tmp = ip4_frags.lru_list.next;
192 qp = list_entry(tmp, struct ipq, q.lru_list);
193 atomic_inc(&qp->q.refcnt);
194 read_unlock(&ip4_frags.lock);
195 178
196 spin_lock(&qp->q.lock); 179 evicted = inet_frag_evictor(&ip4_frags);
197 if (!(qp->q.last_in&COMPLETE)) 180 if (evicted)
198 ipq_kill(qp); 181 IP_ADD_STATS_BH(IPSTATS_MIB_REASMFAILS, evicted);
199 spin_unlock(&qp->q.lock);
200
201 ipq_put(qp, &work);
202 IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
203 }
204} 182}
205 183
206/* 184/*
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 785f5cda188e..e4fbe5ba88f1 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -163,34 +163,7 @@ static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq)
163 163
164static void nf_ct_frag6_evictor(void) 164static void nf_ct_frag6_evictor(void)
165{ 165{
166 struct nf_ct_frag6_queue *fq; 166 inet_frag_evictor(&nf_frags);
167 struct list_head *tmp;
168 unsigned int work;
169
170 work = atomic_read(&nf_frags.mem);
171 if (work <= nf_frags_ctl.low_thresh)
172 return;
173
174 work -= nf_frags_ctl.low_thresh;
175 while (work > 0) {
176 read_lock(&nf_frags.lock);
177 if (list_empty(&nf_frags.lru_list)) {
178 read_unlock(&nf_frags.lock);
179 return;
180 }
181 tmp = nf_frags.lru_list.next;
182 BUG_ON(tmp == NULL);
183 fq = list_entry(tmp, struct nf_ct_frag6_queue, q.lru_list);
184 atomic_inc(&fq->q.refcnt);
185 read_unlock(&nf_frags.lock);
186
187 spin_lock(&fq->q.lock);
188 if (!(fq->q.last_in&COMPLETE))
189 fq_kill(fq);
190 spin_unlock(&fq->q.lock);
191
192 fq_put(fq, &work);
193 }
194} 167}
195 168
196static void nf_ct_frag6_expire(unsigned long data) 169static void nf_ct_frag6_expire(unsigned long data)
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 940b7d2383ec..02e4e855b927 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -185,33 +185,11 @@ static __inline__ void fq_kill(struct frag_queue *fq)
185 185
186static void ip6_evictor(struct inet6_dev *idev) 186static void ip6_evictor(struct inet6_dev *idev)
187{ 187{
188 struct frag_queue *fq; 188 int evicted;
189 struct list_head *tmp;
190 int work;
191
192 work = atomic_read(&ip6_frags.mem) - ip6_frags_ctl.low_thresh;
193 if (work <= 0)
194 return;
195
196 while(work > 0) {
197 read_lock(&ip6_frags.lock);
198 if (list_empty(&ip6_frags.lru_list)) {
199 read_unlock(&ip6_frags.lock);
200 return;
201 }
202 tmp = ip6_frags.lru_list.next;
203 fq = list_entry(tmp, struct frag_queue, q.lru_list);
204 atomic_inc(&fq->q.refcnt);
205 read_unlock(&ip6_frags.lock);
206 189
207 spin_lock(&fq->q.lock); 190 evicted = inet_frag_evictor(&ip6_frags);
208 if (!(fq->q.last_in&COMPLETE)) 191 if (evicted)
209 fq_kill(fq); 192 IP6_ADD_STATS_BH(idev, IPSTATS_MIB_REASMFAILS, evicted);
210 spin_unlock(&fq->q.lock);
211
212 fq_put(fq, &work);
213 IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS);
214 }
215} 193}
216 194
217static void ip6_frag_expire(unsigned long data) 195static void ip6_frag_expire(unsigned long data)