1
2
3
4
5
6
7
8
9#include <linux/module.h>
10#include <linux/types.h>
11#include <linux/slab.h>
12#include <linux/interrupt.h>
13#include <linux/spinlock.h>
14#include <linux/random.h>
15#include <linux/timer.h>
16#include <linux/time.h>
17#include <linux/kernel.h>
18#include <linux/mm.h>
19#include <linux/net.h>
20#include <net/ip.h>
21#include <net/inetpeer.h>
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70static struct kmem_cache *peer_cachep __read_mostly;
71
72#define node_height(x) x->avl_height
73static struct inet_peer peer_fake_node = {
74 .avl_left = &peer_fake_node,
75 .avl_right = &peer_fake_node,
76 .avl_height = 0
77};
78#define peer_avl_empty (&peer_fake_node)
79static struct inet_peer *peer_root = peer_avl_empty;
80static DEFINE_RWLOCK(peer_pool_lock);
81#define PEER_MAXDEPTH 40
82
83static int peer_total;
84
85int inet_peer_threshold __read_mostly = 65536 + 128;
86
87int inet_peer_minttl __read_mostly = 120 * HZ;
88int inet_peer_maxttl __read_mostly = 10 * 60 * HZ;
89int inet_peer_gc_mintime __read_mostly = 10 * HZ;
90int inet_peer_gc_maxtime __read_mostly = 120 * HZ;
91
92static LIST_HEAD(unused_peers);
93static DEFINE_SPINLOCK(inet_peer_unused_lock);
94
95static void peer_check_expire(unsigned long dummy);
96static DEFINE_TIMER(peer_periodic_timer, peer_check_expire, 0, 0);
97
98
99
100void __init inet_initpeers(void)
101{
102 struct sysinfo si;
103
104
105 si_meminfo(&si);
106
107
108
109
110 if (si.totalram <= (32768*1024)/PAGE_SIZE)
111 inet_peer_threshold >>= 1;
112 if (si.totalram <= (16384*1024)/PAGE_SIZE)
113 inet_peer_threshold >>= 1;
114 if (si.totalram <= (8192*1024)/PAGE_SIZE)
115 inet_peer_threshold >>= 2;
116
117 peer_cachep = kmem_cache_create("inet_peer_cache",
118 sizeof(struct inet_peer),
119 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
120 NULL);
121
122
123
124
125 peer_periodic_timer.expires = jiffies
126 + net_random() % inet_peer_gc_maxtime
127 + inet_peer_gc_maxtime;
128 add_timer(&peer_periodic_timer);
129}
130
131
132static void unlink_from_unused(struct inet_peer *p)
133{
134 spin_lock_bh(&inet_peer_unused_lock);
135 list_del_init(&p->unused);
136 spin_unlock_bh(&inet_peer_unused_lock);
137}
138
139
140
141
142
143
144#define lookup(_daddr, _stack) \
145({ \
146 struct inet_peer *u, **v; \
147 if (_stack != NULL) { \
148 stackptr = _stack; \
149 *stackptr++ = &peer_root; \
150 } \
151 for (u = peer_root; u != peer_avl_empty; ) { \
152 if (_daddr == u->v4daddr) \
153 break; \
154 if ((__force __u32)_daddr < (__force __u32)u->v4daddr) \
155 v = &u->avl_left; \
156 else \
157 v = &u->avl_right; \
158 if (_stack != NULL) \
159 *stackptr++ = v; \
160 u = *v; \
161 } \
162 u; \
163})
164
165
166#define lookup_rightempty(start) \
167({ \
168 struct inet_peer *u, **v; \
169 *stackptr++ = &start->avl_left; \
170 v = &start->avl_left; \
171 for (u = *v; u->avl_right != peer_avl_empty; ) { \
172 v = &u->avl_right; \
173 *stackptr++ = v; \
174 u = *v; \
175 } \
176 u; \
177})
178
179
180
181
182static void peer_avl_rebalance(struct inet_peer **stack[],
183 struct inet_peer ***stackend)
184{
185 struct inet_peer **nodep, *node, *l, *r;
186 int lh, rh;
187
188 while (stackend > stack) {
189 nodep = *--stackend;
190 node = *nodep;
191 l = node->avl_left;
192 r = node->avl_right;
193 lh = node_height(l);
194 rh = node_height(r);
195 if (lh > rh + 1) {
196 struct inet_peer *ll, *lr, *lrl, *lrr;
197 int lrh;
198 ll = l->avl_left;
199 lr = l->avl_right;
200 lrh = node_height(lr);
201 if (lrh <= node_height(ll)) {
202 node->avl_left = lr;
203 node->avl_right = r;
204 node->avl_height = lrh + 1;
205 l->avl_left = ll;
206 l->avl_right = node;
207 l->avl_height = node->avl_height + 1;
208 *nodep = l;
209 } else {
210 lrl = lr->avl_left;
211 lrr = lr->avl_right;
212 node->avl_left = lrr;
213 node->avl_right = r;
214 node->avl_height = rh + 1;
215 l->avl_left = ll;
216 l->avl_right = lrl;
217 l->avl_height = rh + 1;
218 lr->avl_left = l;
219 lr->avl_right = node;
220 lr->avl_height = rh + 2;
221 *nodep = lr;
222 }
223 } else if (rh > lh + 1) {
224 struct inet_peer *rr, *rl, *rlr, *rll;
225 int rlh;
226 rr = r->avl_right;
227 rl = r->avl_left;
228 rlh = node_height(rl);
229 if (rlh <= node_height(rr)) {
230 node->avl_right = rl;
231 node->avl_left = l;
232 node->avl_height = rlh + 1;
233 r->avl_right = rr;
234 r->avl_left = node;
235 r->avl_height = node->avl_height + 1;
236 *nodep = r;
237 } else {
238 rlr = rl->avl_right;
239 rll = rl->avl_left;
240 node->avl_right = rll;
241 node->avl_left = l;
242 node->avl_height = lh + 1;
243 r->avl_right = rr;
244 r->avl_left = rlr;
245 r->avl_height = lh + 1;
246 rl->avl_right = r;
247 rl->avl_left = node;
248 rl->avl_height = lh + 2;
249 *nodep = rl;
250 }
251 } else {
252 node->avl_height = (lh > rh ? lh : rh) + 1;
253 }
254 }
255}
256
257
258#define link_to_pool(n) \
259do { \
260 n->avl_height = 1; \
261 n->avl_left = peer_avl_empty; \
262 n->avl_right = peer_avl_empty; \
263 **--stackptr = n; \
264 peer_avl_rebalance(stack, stackptr); \
265} while(0)
266
267
268static void unlink_from_pool(struct inet_peer *p)
269{
270 int do_free;
271
272 do_free = 0;
273
274 write_lock_bh(&peer_pool_lock);
275
276
277
278
279
280 if (atomic_read(&p->refcnt) == 1) {
281 struct inet_peer **stack[PEER_MAXDEPTH];
282 struct inet_peer ***stackptr, ***delp;
283 if (lookup(p->v4daddr, stack) != p)
284 BUG();
285 delp = stackptr - 1;
286 if (p->avl_left == peer_avl_empty) {
287 *delp[0] = p->avl_right;
288 --stackptr;
289 } else {
290
291 struct inet_peer *t;
292 t = lookup_rightempty(p);
293 BUG_ON(*stackptr[-1] != t);
294 **--stackptr = t->avl_left;
295
296
297
298 *delp[0] = t;
299 t->avl_left = p->avl_left;
300 t->avl_right = p->avl_right;
301 t->avl_height = p->avl_height;
302 BUG_ON(delp[1] != &p->avl_left);
303 delp[1] = &t->avl_left;
304 }
305 peer_avl_rebalance(stack, stackptr);
306 peer_total--;
307 do_free = 1;
308 }
309 write_unlock_bh(&peer_pool_lock);
310
311 if (do_free)
312 kmem_cache_free(peer_cachep, p);
313 else
314
315
316
317
318
319
320 inet_putpeer(p);
321}
322
323
324static int cleanup_once(unsigned long ttl)
325{
326 struct inet_peer *p = NULL;
327
328
329 spin_lock_bh(&inet_peer_unused_lock);
330 if (!list_empty(&unused_peers)) {
331 __u32 delta;
332
333 p = list_first_entry(&unused_peers, struct inet_peer, unused);
334 delta = (__u32)jiffies - p->dtime;
335
336 if (delta < ttl) {
337
338 spin_unlock_bh(&inet_peer_unused_lock);
339 return -1;
340 }
341
342 list_del_init(&p->unused);
343
344
345
346 atomic_inc(&p->refcnt);
347 }
348 spin_unlock_bh(&inet_peer_unused_lock);
349
350 if (p == NULL)
351
352
353
354 return -1;
355
356 unlink_from_pool(p);
357 return 0;
358}
359
360
361struct inet_peer *inet_getpeer(__be32 daddr, int create)
362{
363 struct inet_peer *p, *n;
364 struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr;
365
366
367 read_lock_bh(&peer_pool_lock);
368 p = lookup(daddr, NULL);
369 if (p != peer_avl_empty)
370 atomic_inc(&p->refcnt);
371 read_unlock_bh(&peer_pool_lock);
372
373 if (p != peer_avl_empty) {
374
375
376 unlink_from_unused(p);
377 return p;
378 }
379
380 if (!create)
381 return NULL;
382
383
384 n = kmem_cache_alloc(peer_cachep, GFP_ATOMIC);
385 if (n == NULL)
386 return NULL;
387 n->v4daddr = daddr;
388 atomic_set(&n->refcnt, 1);
389 atomic_set(&n->rid, 0);
390 atomic_set(&n->ip_id_count, secure_ip_id(daddr));
391 n->tcp_ts_stamp = 0;
392
393 write_lock_bh(&peer_pool_lock);
394
395 p = lookup(daddr, stack);
396 if (p != peer_avl_empty)
397 goto out_free;
398
399
400 link_to_pool(n);
401 INIT_LIST_HEAD(&n->unused);
402 peer_total++;
403 write_unlock_bh(&peer_pool_lock);
404
405 if (peer_total >= inet_peer_threshold)
406
407 cleanup_once(0);
408
409 return n;
410
411out_free:
412
413 atomic_inc(&p->refcnt);
414 write_unlock_bh(&peer_pool_lock);
415
416 unlink_from_unused(p);
417
418 kmem_cache_free(peer_cachep, n);
419 return p;
420}
421
422
423static void peer_check_expire(unsigned long dummy)
424{
425 unsigned long now = jiffies;
426 int ttl;
427
428 if (peer_total >= inet_peer_threshold)
429 ttl = inet_peer_minttl;
430 else
431 ttl = inet_peer_maxttl
432 - (inet_peer_maxttl - inet_peer_minttl) / HZ *
433 peer_total / inet_peer_threshold * HZ;
434 while (!cleanup_once(ttl)) {
435 if (jiffies != now)
436 break;
437 }
438
439
440
441
442 if (peer_total >= inet_peer_threshold)
443 peer_periodic_timer.expires = jiffies + inet_peer_gc_mintime;
444 else
445 peer_periodic_timer.expires = jiffies
446 + inet_peer_gc_maxtime
447 - (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ *
448 peer_total / inet_peer_threshold * HZ;
449 add_timer(&peer_periodic_timer);
450}
451
452void inet_putpeer(struct inet_peer *p)
453{
454 spin_lock_bh(&inet_peer_unused_lock);
455 if (atomic_dec_and_test(&p->refcnt)) {
456 list_add_tail(&p->unused, &unused_peers);
457 p->dtime = (__u32)jiffies;
458 }
459 spin_unlock_bh(&inet_peer_unused_lock);
460}
461