diff options
-rw-r--r-- | net/xfrm/Makefile | 3 | ||||
-rw-r--r-- | net/xfrm/xfrm_hash.c | 41 | ||||
-rw-r--r-- | net/xfrm/xfrm_hash.h | 128 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 95 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 128 |
5 files changed, 195 insertions, 200 deletions
diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile index 693aac1aa833..de3c1a625a46 100644 --- a/net/xfrm/Makefile +++ b/net/xfrm/Makefile | |||
@@ -2,6 +2,7 @@ | |||
2 | # Makefile for the XFRM subsystem. | 2 | # Makefile for the XFRM subsystem. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_input.o xfrm_algo.o | 5 | obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \ |
6 | xfrm_input.o xfrm_algo.o | ||
6 | obj-$(CONFIG_XFRM_USER) += xfrm_user.o | 7 | obj-$(CONFIG_XFRM_USER) += xfrm_user.o |
7 | 8 | ||
diff --git a/net/xfrm/xfrm_hash.c b/net/xfrm/xfrm_hash.c new file mode 100644 index 000000000000..37643bb8768a --- /dev/null +++ b/net/xfrm/xfrm_hash.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* xfrm_hash.c: Common hash table code. | ||
2 | * | ||
3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | ||
4 | */ | ||
5 | |||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/mm.h> | ||
8 | #include <linux/bootmem.h> | ||
9 | #include <linux/vmalloc.h> | ||
10 | #include <linux/slab.h> | ||
11 | #include <linux/xfrm.h> | ||
12 | |||
13 | #include "xfrm_hash.h" | ||
14 | |||
15 | struct hlist_head *xfrm_hash_alloc(unsigned int sz) | ||
16 | { | ||
17 | struct hlist_head *n; | ||
18 | |||
19 | if (sz <= PAGE_SIZE) | ||
20 | n = kmalloc(sz, GFP_KERNEL); | ||
21 | else if (hashdist) | ||
22 | n = __vmalloc(sz, GFP_KERNEL, PAGE_KERNEL); | ||
23 | else | ||
24 | n = (struct hlist_head *) | ||
25 | __get_free_pages(GFP_KERNEL, get_order(sz)); | ||
26 | |||
27 | if (n) | ||
28 | memset(n, 0, sz); | ||
29 | |||
30 | return n; | ||
31 | } | ||
32 | |||
33 | void xfrm_hash_free(struct hlist_head *n, unsigned int sz) | ||
34 | { | ||
35 | if (sz <= PAGE_SIZE) | ||
36 | kfree(n); | ||
37 | else if (hashdist) | ||
38 | vfree(n); | ||
39 | else | ||
40 | free_pages((unsigned long)n, get_order(sz)); | ||
41 | } | ||
diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h new file mode 100644 index 000000000000..d3abb0b7dc62 --- /dev/null +++ b/net/xfrm/xfrm_hash.h | |||
@@ -0,0 +1,128 @@ | |||
1 | #ifndef _XFRM_HASH_H | ||
2 | #define _XFRM_HASH_H | ||
3 | |||
4 | #include <linux/xfrm.h> | ||
5 | #include <linux/socket.h> | ||
6 | |||
7 | static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr) | ||
8 | { | ||
9 | return ntohl(addr->a4); | ||
10 | } | ||
11 | |||
12 | static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr) | ||
13 | { | ||
14 | return ntohl(addr->a6[2] ^ addr->a6[3]); | ||
15 | } | ||
16 | |||
17 | static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr) | ||
18 | { | ||
19 | return ntohl(daddr->a4 ^ saddr->a4); | ||
20 | } | ||
21 | |||
22 | static inline unsigned int __xfrm6_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr) | ||
23 | { | ||
24 | return ntohl(daddr->a6[2] ^ daddr->a6[3] ^ | ||
25 | saddr->a6[2] ^ saddr->a6[3]); | ||
26 | } | ||
27 | |||
28 | static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, | ||
29 | u32 reqid, unsigned short family, | ||
30 | unsigned int hmask) | ||
31 | { | ||
32 | unsigned int h = family ^ reqid; | ||
33 | switch (family) { | ||
34 | case AF_INET: | ||
35 | h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); | ||
36 | break; | ||
37 | case AF_INET6: | ||
38 | h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); | ||
39 | break; | ||
40 | } | ||
41 | return (h ^ (h >> 16)) & hmask; | ||
42 | } | ||
43 | |||
44 | static inline unsigned __xfrm_src_hash(xfrm_address_t *saddr, | ||
45 | unsigned short family, | ||
46 | unsigned int hmask) | ||
47 | { | ||
48 | unsigned int h = family; | ||
49 | switch (family) { | ||
50 | case AF_INET: | ||
51 | h ^= __xfrm4_addr_hash(saddr); | ||
52 | break; | ||
53 | case AF_INET6: | ||
54 | h ^= __xfrm6_addr_hash(saddr); | ||
55 | break; | ||
56 | }; | ||
57 | return (h ^ (h >> 16)) & hmask; | ||
58 | } | ||
59 | |||
60 | static inline unsigned int | ||
61 | __xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family, | ||
62 | unsigned int hmask) | ||
63 | { | ||
64 | unsigned int h = spi ^ proto; | ||
65 | switch (family) { | ||
66 | case AF_INET: | ||
67 | h ^= __xfrm4_addr_hash(daddr); | ||
68 | break; | ||
69 | case AF_INET6: | ||
70 | h ^= __xfrm6_addr_hash(daddr); | ||
71 | break; | ||
72 | } | ||
73 | return (h ^ (h >> 10) ^ (h >> 20)) & hmask; | ||
74 | } | ||
75 | |||
76 | static inline unsigned int __idx_hash(u32 index, unsigned int hmask) | ||
77 | { | ||
78 | return (index ^ (index >> 8)) & hmask; | ||
79 | } | ||
80 | |||
81 | static inline unsigned int __sel_hash(struct xfrm_selector *sel, unsigned short family, unsigned int hmask) | ||
82 | { | ||
83 | xfrm_address_t *daddr = &sel->daddr; | ||
84 | xfrm_address_t *saddr = &sel->saddr; | ||
85 | unsigned int h = 0; | ||
86 | |||
87 | switch (family) { | ||
88 | case AF_INET: | ||
89 | if (sel->prefixlen_d != 32 || | ||
90 | sel->prefixlen_s != 32) | ||
91 | return hmask + 1; | ||
92 | |||
93 | h = __xfrm4_daddr_saddr_hash(daddr, saddr); | ||
94 | break; | ||
95 | |||
96 | case AF_INET6: | ||
97 | if (sel->prefixlen_d != 128 || | ||
98 | sel->prefixlen_s != 128) | ||
99 | return hmask + 1; | ||
100 | |||
101 | h = __xfrm6_daddr_saddr_hash(daddr, saddr); | ||
102 | break; | ||
103 | }; | ||
104 | h ^= (h >> 16); | ||
105 | return h & hmask; | ||
106 | } | ||
107 | |||
108 | static inline unsigned int __addr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, unsigned int hmask) | ||
109 | { | ||
110 | unsigned int h = 0; | ||
111 | |||
112 | switch (family) { | ||
113 | case AF_INET: | ||
114 | h = __xfrm4_daddr_saddr_hash(daddr, saddr); | ||
115 | break; | ||
116 | |||
117 | case AF_INET6: | ||
118 | h = __xfrm6_daddr_saddr_hash(daddr, saddr); | ||
119 | break; | ||
120 | }; | ||
121 | h ^= (h >> 16); | ||
122 | return h & hmask; | ||
123 | } | ||
124 | |||
125 | extern struct hlist_head *xfrm_hash_alloc(unsigned int sz); | ||
126 | extern void xfrm_hash_free(struct hlist_head *n, unsigned int sz); | ||
127 | |||
128 | #endif /* _XFRM_HASH_H */ | ||
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 087a5443b051..b446ca31fecc 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -22,12 +22,12 @@ | |||
22 | #include <linux/netdevice.h> | 22 | #include <linux/netdevice.h> |
23 | #include <linux/netfilter.h> | 23 | #include <linux/netfilter.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/bootmem.h> | ||
26 | #include <linux/vmalloc.h> | ||
27 | #include <linux/cache.h> | 25 | #include <linux/cache.h> |
28 | #include <net/xfrm.h> | 26 | #include <net/xfrm.h> |
29 | #include <net/ip.h> | 27 | #include <net/ip.h> |
30 | 28 | ||
29 | #include "xfrm_hash.h" | ||
30 | |||
31 | DEFINE_MUTEX(xfrm_cfg_mutex); | 31 | DEFINE_MUTEX(xfrm_cfg_mutex); |
32 | EXPORT_SYMBOL(xfrm_cfg_mutex); | 32 | EXPORT_SYMBOL(xfrm_cfg_mutex); |
33 | 33 | ||
@@ -409,62 +409,11 @@ static struct hlist_head *xfrm_policy_byidx __read_mostly; | |||
409 | static unsigned int xfrm_idx_hmask __read_mostly; | 409 | static unsigned int xfrm_idx_hmask __read_mostly; |
410 | static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024; | 410 | static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024; |
411 | 411 | ||
412 | static inline unsigned int __idx_hash(u32 index, unsigned int hmask) | ||
413 | { | ||
414 | return (index ^ (index >> 8)) & hmask; | ||
415 | } | ||
416 | |||
417 | static inline unsigned int idx_hash(u32 index) | 412 | static inline unsigned int idx_hash(u32 index) |
418 | { | 413 | { |
419 | return __idx_hash(index, xfrm_idx_hmask); | 414 | return __idx_hash(index, xfrm_idx_hmask); |
420 | } | 415 | } |
421 | 416 | ||
422 | static inline unsigned int __sel_hash(struct xfrm_selector *sel, unsigned short family, unsigned int hmask) | ||
423 | { | ||
424 | xfrm_address_t *daddr = &sel->daddr; | ||
425 | xfrm_address_t *saddr = &sel->saddr; | ||
426 | unsigned int h = 0; | ||
427 | |||
428 | switch (family) { | ||
429 | case AF_INET: | ||
430 | if (sel->prefixlen_d != 32 || | ||
431 | sel->prefixlen_s != 32) | ||
432 | return hmask + 1; | ||
433 | |||
434 | h = ntohl(daddr->a4 ^ saddr->a4); | ||
435 | break; | ||
436 | |||
437 | case AF_INET6: | ||
438 | if (sel->prefixlen_d != 128 || | ||
439 | sel->prefixlen_s != 128) | ||
440 | return hmask + 1; | ||
441 | |||
442 | h = ntohl(daddr->a6[2] ^ daddr->a6[3] ^ | ||
443 | saddr->a6[2] ^ saddr->a6[3]); | ||
444 | break; | ||
445 | }; | ||
446 | h ^= (h >> 16); | ||
447 | return h & hmask; | ||
448 | } | ||
449 | |||
450 | static inline unsigned int __addr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, unsigned int hmask) | ||
451 | { | ||
452 | unsigned int h = 0; | ||
453 | |||
454 | switch (family) { | ||
455 | case AF_INET: | ||
456 | h = ntohl(daddr->a4 ^ saddr->a4); | ||
457 | break; | ||
458 | |||
459 | case AF_INET6: | ||
460 | h = ntohl(daddr->a6[2] ^ daddr->a6[3] ^ | ||
461 | saddr->a6[2] ^ saddr->a6[3]); | ||
462 | break; | ||
463 | }; | ||
464 | h ^= (h >> 16); | ||
465 | return h & hmask; | ||
466 | } | ||
467 | |||
468 | static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir) | 417 | static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir) |
469 | { | 418 | { |
470 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | 419 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; |
@@ -483,34 +432,6 @@ static struct hlist_head *policy_hash_direct(xfrm_address_t *daddr, xfrm_address | |||
483 | return xfrm_policy_bydst[dir].table + hash; | 432 | return xfrm_policy_bydst[dir].table + hash; |
484 | } | 433 | } |
485 | 434 | ||
486 | static struct hlist_head *xfrm_policy_hash_alloc(unsigned int sz) | ||
487 | { | ||
488 | struct hlist_head *n; | ||
489 | |||
490 | if (sz <= PAGE_SIZE) | ||
491 | n = kmalloc(sz, GFP_KERNEL); | ||
492 | else if (hashdist) | ||
493 | n = __vmalloc(sz, GFP_KERNEL, PAGE_KERNEL); | ||
494 | else | ||
495 | n = (struct hlist_head *) | ||
496 | __get_free_pages(GFP_KERNEL, get_order(sz)); | ||
497 | |||
498 | if (n) | ||
499 | memset(n, 0, sz); | ||
500 | |||
501 | return n; | ||
502 | } | ||
503 | |||
504 | static void xfrm_policy_hash_free(struct hlist_head *n, unsigned int sz) | ||
505 | { | ||
506 | if (sz <= PAGE_SIZE) | ||
507 | kfree(n); | ||
508 | else if (hashdist) | ||
509 | vfree(n); | ||
510 | else | ||
511 | free_pages((unsigned long)n, get_order(sz)); | ||
512 | } | ||
513 | |||
514 | static void xfrm_dst_hash_transfer(struct hlist_head *list, | 435 | static void xfrm_dst_hash_transfer(struct hlist_head *list, |
515 | struct hlist_head *ndsttable, | 436 | struct hlist_head *ndsttable, |
516 | unsigned int nhashmask) | 437 | unsigned int nhashmask) |
@@ -553,7 +474,7 @@ static void xfrm_bydst_resize(int dir) | |||
553 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); | 474 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); |
554 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); | 475 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); |
555 | struct hlist_head *odst = xfrm_policy_bydst[dir].table; | 476 | struct hlist_head *odst = xfrm_policy_bydst[dir].table; |
556 | struct hlist_head *ndst = xfrm_policy_hash_alloc(nsize); | 477 | struct hlist_head *ndst = xfrm_hash_alloc(nsize); |
557 | int i; | 478 | int i; |
558 | 479 | ||
559 | if (!ndst) | 480 | if (!ndst) |
@@ -569,7 +490,7 @@ static void xfrm_bydst_resize(int dir) | |||
569 | 490 | ||
570 | write_unlock_bh(&xfrm_policy_lock); | 491 | write_unlock_bh(&xfrm_policy_lock); |
571 | 492 | ||
572 | xfrm_policy_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); | 493 | xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); |
573 | } | 494 | } |
574 | 495 | ||
575 | static void xfrm_byidx_resize(int total) | 496 | static void xfrm_byidx_resize(int total) |
@@ -578,7 +499,7 @@ static void xfrm_byidx_resize(int total) | |||
578 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); | 499 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); |
579 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); | 500 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); |
580 | struct hlist_head *oidx = xfrm_policy_byidx; | 501 | struct hlist_head *oidx = xfrm_policy_byidx; |
581 | struct hlist_head *nidx = xfrm_policy_hash_alloc(nsize); | 502 | struct hlist_head *nidx = xfrm_hash_alloc(nsize); |
582 | int i; | 503 | int i; |
583 | 504 | ||
584 | if (!nidx) | 505 | if (!nidx) |
@@ -594,7 +515,7 @@ static void xfrm_byidx_resize(int total) | |||
594 | 515 | ||
595 | write_unlock_bh(&xfrm_policy_lock); | 516 | write_unlock_bh(&xfrm_policy_lock); |
596 | 517 | ||
597 | xfrm_policy_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); | 518 | xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); |
598 | } | 519 | } |
599 | 520 | ||
600 | static inline int xfrm_bydst_should_resize(int dir, int *total) | 521 | static inline int xfrm_bydst_should_resize(int dir, int *total) |
@@ -2071,7 +1992,7 @@ static void __init xfrm_policy_init(void) | |||
2071 | hmask = 8 - 1; | 1992 | hmask = 8 - 1; |
2072 | sz = (hmask+1) * sizeof(struct hlist_head); | 1993 | sz = (hmask+1) * sizeof(struct hlist_head); |
2073 | 1994 | ||
2074 | xfrm_policy_byidx = xfrm_policy_hash_alloc(sz); | 1995 | xfrm_policy_byidx = xfrm_hash_alloc(sz); |
2075 | xfrm_idx_hmask = hmask; | 1996 | xfrm_idx_hmask = hmask; |
2076 | if (!xfrm_policy_byidx) | 1997 | if (!xfrm_policy_byidx) |
2077 | panic("XFRM: failed to allocate byidx hash\n"); | 1998 | panic("XFRM: failed to allocate byidx hash\n"); |
@@ -2082,7 +2003,7 @@ static void __init xfrm_policy_init(void) | |||
2082 | INIT_HLIST_HEAD(&xfrm_policy_inexact[dir]); | 2003 | INIT_HLIST_HEAD(&xfrm_policy_inexact[dir]); |
2083 | 2004 | ||
2084 | htab = &xfrm_policy_bydst[dir]; | 2005 | htab = &xfrm_policy_bydst[dir]; |
2085 | htab->table = xfrm_policy_hash_alloc(sz); | 2006 | htab->table = xfrm_hash_alloc(sz); |
2086 | htab->hmask = hmask; | 2007 | htab->hmask = hmask; |
2087 | if (!htab->table) | 2008 | if (!htab->table) |
2088 | panic("XFRM: failed to allocate bydst hash\n"); | 2009 | panic("XFRM: failed to allocate bydst hash\n"); |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 37213f9f6a02..4341795eb244 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -18,11 +18,11 @@ | |||
18 | #include <linux/pfkeyv2.h> | 18 | #include <linux/pfkeyv2.h> |
19 | #include <linux/ipsec.h> | 19 | #include <linux/ipsec.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/bootmem.h> | ||
22 | #include <linux/vmalloc.h> | ||
23 | #include <linux/cache.h> | 21 | #include <linux/cache.h> |
24 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
25 | 23 | ||
24 | #include "xfrm_hash.h" | ||
25 | |||
26 | struct sock *xfrm_nl; | 26 | struct sock *xfrm_nl; |
27 | EXPORT_SYMBOL(xfrm_nl); | 27 | EXPORT_SYMBOL(xfrm_nl); |
28 | 28 | ||
@@ -55,44 +55,6 @@ static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; | |||
55 | static unsigned int xfrm_state_num; | 55 | static unsigned int xfrm_state_num; |
56 | static unsigned int xfrm_state_genid; | 56 | static unsigned int xfrm_state_genid; |
57 | 57 | ||
58 | static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr) | ||
59 | { | ||
60 | return ntohl(addr->a4); | ||
61 | } | ||
62 | |||
63 | static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr) | ||
64 | { | ||
65 | return ntohl(addr->a6[2]^addr->a6[3]); | ||
66 | } | ||
67 | |||
68 | static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr) | ||
69 | { | ||
70 | return ntohl(daddr->a4 ^ saddr->a4); | ||
71 | } | ||
72 | |||
73 | static inline unsigned int __xfrm6_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr) | ||
74 | { | ||
75 | return ntohl(daddr->a6[2] ^ daddr->a6[3] ^ | ||
76 | saddr->a6[2] ^ saddr->a6[3]); | ||
77 | } | ||
78 | |||
79 | static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, | ||
80 | xfrm_address_t *saddr, | ||
81 | u32 reqid, unsigned short family, | ||
82 | unsigned int hmask) | ||
83 | { | ||
84 | unsigned int h = family ^ reqid; | ||
85 | switch (family) { | ||
86 | case AF_INET: | ||
87 | h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); | ||
88 | break; | ||
89 | case AF_INET6: | ||
90 | h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); | ||
91 | break; | ||
92 | }; | ||
93 | return (h ^ (h >> 16)) & hmask; | ||
94 | } | ||
95 | |||
96 | static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, | 58 | static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, |
97 | xfrm_address_t *saddr, | 59 | xfrm_address_t *saddr, |
98 | u32 reqid, | 60 | u32 reqid, |
@@ -101,76 +63,18 @@ static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, | |||
101 | return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask); | 63 | return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask); |
102 | } | 64 | } |
103 | 65 | ||
104 | static inline unsigned __xfrm_src_hash(xfrm_address_t *addr, unsigned short family, | 66 | static inline unsigned int xfrm_src_hash(xfrm_address_t *addr, |
105 | unsigned int hmask) | 67 | unsigned short family) |
106 | { | ||
107 | unsigned int h = family; | ||
108 | switch (family) { | ||
109 | case AF_INET: | ||
110 | h ^= __xfrm4_addr_hash(addr); | ||
111 | break; | ||
112 | case AF_INET6: | ||
113 | h ^= __xfrm6_addr_hash(addr); | ||
114 | break; | ||
115 | }; | ||
116 | return (h ^ (h >> 16)) & hmask; | ||
117 | } | ||
118 | |||
119 | static inline unsigned xfrm_src_hash(xfrm_address_t *addr, unsigned short family) | ||
120 | { | 68 | { |
121 | return __xfrm_src_hash(addr, family, xfrm_state_hmask); | 69 | return __xfrm_src_hash(addr, family, xfrm_state_hmask); |
122 | } | 70 | } |
123 | 71 | ||
124 | static inline unsigned int | 72 | static inline unsigned int |
125 | __xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, | ||
126 | unsigned short family, unsigned int hmask) | ||
127 | { | ||
128 | unsigned int h = spi ^ proto; | ||
129 | switch (family) { | ||
130 | case AF_INET: | ||
131 | h ^= __xfrm4_addr_hash(daddr); | ||
132 | break; | ||
133 | case AF_INET6: | ||
134 | h ^= __xfrm6_addr_hash(daddr); | ||
135 | break; | ||
136 | } | ||
137 | return (h ^ (h >> 10) ^ (h >> 20)) & hmask; | ||
138 | } | ||
139 | |||
140 | static inline unsigned int | ||
141 | xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family) | 73 | xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family) |
142 | { | 74 | { |
143 | return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask); | 75 | return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask); |
144 | } | 76 | } |
145 | 77 | ||
146 | static struct hlist_head *xfrm_state_hash_alloc(unsigned int sz) | ||
147 | { | ||
148 | struct hlist_head *n; | ||
149 | |||
150 | if (sz <= PAGE_SIZE) | ||
151 | n = kmalloc(sz, GFP_KERNEL); | ||
152 | else if (hashdist) | ||
153 | n = __vmalloc(sz, GFP_KERNEL, PAGE_KERNEL); | ||
154 | else | ||
155 | n = (struct hlist_head *) | ||
156 | __get_free_pages(GFP_KERNEL, get_order(sz)); | ||
157 | |||
158 | if (n) | ||
159 | memset(n, 0, sz); | ||
160 | |||
161 | return n; | ||
162 | } | ||
163 | |||
164 | static void xfrm_state_hash_free(struct hlist_head *n, unsigned int sz) | ||
165 | { | ||
166 | if (sz <= PAGE_SIZE) | ||
167 | kfree(n); | ||
168 | else if (hashdist) | ||
169 | vfree(n); | ||
170 | else | ||
171 | free_pages((unsigned long)n, get_order(sz)); | ||
172 | } | ||
173 | |||
174 | static void xfrm_hash_transfer(struct hlist_head *list, | 78 | static void xfrm_hash_transfer(struct hlist_head *list, |
175 | struct hlist_head *ndsttable, | 79 | struct hlist_head *ndsttable, |
176 | struct hlist_head *nsrctable, | 80 | struct hlist_head *nsrctable, |
@@ -216,18 +120,18 @@ static void xfrm_hash_resize(void *__unused) | |||
216 | mutex_lock(&hash_resize_mutex); | 120 | mutex_lock(&hash_resize_mutex); |
217 | 121 | ||
218 | nsize = xfrm_hash_new_size(); | 122 | nsize = xfrm_hash_new_size(); |
219 | ndst = xfrm_state_hash_alloc(nsize); | 123 | ndst = xfrm_hash_alloc(nsize); |
220 | if (!ndst) | 124 | if (!ndst) |
221 | goto out_unlock; | 125 | goto out_unlock; |
222 | nsrc = xfrm_state_hash_alloc(nsize); | 126 | nsrc = xfrm_hash_alloc(nsize); |
223 | if (!nsrc) { | 127 | if (!nsrc) { |
224 | xfrm_state_hash_free(ndst, nsize); | 128 | xfrm_hash_free(ndst, nsize); |
225 | goto out_unlock; | 129 | goto out_unlock; |
226 | } | 130 | } |
227 | nspi = xfrm_state_hash_alloc(nsize); | 131 | nspi = xfrm_hash_alloc(nsize); |
228 | if (!nspi) { | 132 | if (!nspi) { |
229 | xfrm_state_hash_free(ndst, nsize); | 133 | xfrm_hash_free(ndst, nsize); |
230 | xfrm_state_hash_free(nsrc, nsize); | 134 | xfrm_hash_free(nsrc, nsize); |
231 | goto out_unlock; | 135 | goto out_unlock; |
232 | } | 136 | } |
233 | 137 | ||
@@ -251,9 +155,9 @@ static void xfrm_hash_resize(void *__unused) | |||
251 | spin_unlock_bh(&xfrm_state_lock); | 155 | spin_unlock_bh(&xfrm_state_lock); |
252 | 156 | ||
253 | osize = (ohashmask + 1) * sizeof(struct hlist_head); | 157 | osize = (ohashmask + 1) * sizeof(struct hlist_head); |
254 | xfrm_state_hash_free(odst, osize); | 158 | xfrm_hash_free(odst, osize); |
255 | xfrm_state_hash_free(osrc, osize); | 159 | xfrm_hash_free(osrc, osize); |
256 | xfrm_state_hash_free(ospi, osize); | 160 | xfrm_hash_free(ospi, osize); |
257 | 161 | ||
258 | out_unlock: | 162 | out_unlock: |
259 | mutex_unlock(&hash_resize_mutex); | 163 | mutex_unlock(&hash_resize_mutex); |
@@ -1643,9 +1547,9 @@ void __init xfrm_state_init(void) | |||
1643 | 1547 | ||
1644 | sz = sizeof(struct hlist_head) * 8; | 1548 | sz = sizeof(struct hlist_head) * 8; |
1645 | 1549 | ||
1646 | xfrm_state_bydst = xfrm_state_hash_alloc(sz); | 1550 | xfrm_state_bydst = xfrm_hash_alloc(sz); |
1647 | xfrm_state_bysrc = xfrm_state_hash_alloc(sz); | 1551 | xfrm_state_bysrc = xfrm_hash_alloc(sz); |
1648 | xfrm_state_byspi = xfrm_state_hash_alloc(sz); | 1552 | xfrm_state_byspi = xfrm_hash_alloc(sz); |
1649 | if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi) | 1553 | if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi) |
1650 | panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes."); | 1554 | panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes."); |
1651 | xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1); | 1555 | xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1); |