summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-08-24 13:50:50 +0200
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-23 00:08:49 +0200
commit44e36b42a8378be1dcf7e6f8a1cb2710a8903387 (patch)
tree2c057957a4e4dc7f679ac671a9f091f3fe366b92
parent[XFRM]: Hash policies when non-prefixed. (diff)
downloadlinux-44e36b42a8378be1dcf7e6f8a1cb2710a8903387.tar.xz
linux-44e36b42a8378be1dcf7e6f8a1cb2710a8903387.zip
[XFRM]: Extract common hashing code into xfrm_hash.[ch]
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/xfrm/Makefile3
-rw-r--r--net/xfrm/xfrm_hash.c41
-rw-r--r--net/xfrm/xfrm_hash.h128
-rw-r--r--net/xfrm/xfrm_policy.c95
-rw-r--r--net/xfrm/xfrm_state.c128
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 @@
# Makefile for the XFRM subsystem.
#
-obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_input.o xfrm_algo.o
+obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \
+ xfrm_input.o xfrm_algo.o
obj-$(CONFIG_XFRM_USER) += xfrm_user.o
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 @@
+/* xfrm_hash.c: Common hash table code.
+ *
+ * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/xfrm.h>
+
+#include "xfrm_hash.h"
+
+struct hlist_head *xfrm_hash_alloc(unsigned int sz)
+{
+ struct hlist_head *n;
+
+ if (sz <= PAGE_SIZE)
+ n = kmalloc(sz, GFP_KERNEL);
+ else if (hashdist)
+ n = __vmalloc(sz, GFP_KERNEL, PAGE_KERNEL);
+ else
+ n = (struct hlist_head *)
+ __get_free_pages(GFP_KERNEL, get_order(sz));
+
+ if (n)
+ memset(n, 0, sz);
+
+ return n;
+}
+
+void xfrm_hash_free(struct hlist_head *n, unsigned int sz)
+{
+ if (sz <= PAGE_SIZE)
+ kfree(n);
+ else if (hashdist)
+ vfree(n);
+ else
+ free_pages((unsigned long)n, get_order(sz));
+}
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 @@
+#ifndef _XFRM_HASH_H
+#define _XFRM_HASH_H
+
+#include <linux/xfrm.h>
+#include <linux/socket.h>
+
+static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr)
+{
+ return ntohl(addr->a4);
+}
+
+static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr)
+{
+ return ntohl(addr->a6[2] ^ addr->a6[3]);
+}
+
+static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
+{
+ return ntohl(daddr->a4 ^ saddr->a4);
+}
+
+static inline unsigned int __xfrm6_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
+{
+ return ntohl(daddr->a6[2] ^ daddr->a6[3] ^
+ saddr->a6[2] ^ saddr->a6[3]);
+}
+
+static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t *saddr,
+ u32 reqid, unsigned short family,
+ unsigned int hmask)
+{
+ unsigned int h = family ^ reqid;
+ switch (family) {
+ case AF_INET:
+ h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);
+ break;
+ case AF_INET6:
+ h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
+ break;
+ }
+ return (h ^ (h >> 16)) & hmask;
+}
+
+static inline unsigned __xfrm_src_hash(xfrm_address_t *saddr,
+ unsigned short family,
+ unsigned int hmask)
+{
+ unsigned int h = family;
+ switch (family) {
+ case AF_INET:
+ h ^= __xfrm4_addr_hash(saddr);
+ break;
+ case AF_INET6:
+ h ^= __xfrm6_addr_hash(saddr);
+ break;
+ };
+ return (h ^ (h >> 16)) & hmask;
+}
+
+static inline unsigned int
+__xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family,
+ unsigned int hmask)
+{
+ unsigned int h = spi ^ proto;
+ switch (family) {
+ case AF_INET:
+ h ^= __xfrm4_addr_hash(daddr);
+ break;
+ case AF_INET6:
+ h ^= __xfrm6_addr_hash(daddr);
+ break;
+ }
+ return (h ^ (h >> 10) ^ (h >> 20)) & hmask;
+}
+
+static inline unsigned int __idx_hash(u32 index, unsigned int hmask)
+{
+ return (index ^ (index >> 8)) & hmask;
+}
+
+static inline unsigned int __sel_hash(struct xfrm_selector *sel, unsigned short family, unsigned int hmask)
+{
+ xfrm_address_t *daddr = &sel->daddr;
+ xfrm_address_t *saddr = &sel->saddr;
+ unsigned int h = 0;
+
+ switch (family) {
+ case AF_INET:
+ if (sel->prefixlen_d != 32 ||
+ sel->prefixlen_s != 32)
+ return hmask + 1;
+
+ h = __xfrm4_daddr_saddr_hash(daddr, saddr);
+ break;
+
+ case AF_INET6:
+ if (sel->prefixlen_d != 128 ||
+ sel->prefixlen_s != 128)
+ return hmask + 1;
+
+ h = __xfrm6_daddr_saddr_hash(daddr, saddr);
+ break;
+ };
+ h ^= (h >> 16);
+ return h & hmask;
+}
+
+static inline unsigned int __addr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, unsigned int hmask)
+{
+ unsigned int h = 0;
+
+ switch (family) {
+ case AF_INET:
+ h = __xfrm4_daddr_saddr_hash(daddr, saddr);
+ break;
+
+ case AF_INET6:
+ h = __xfrm6_daddr_saddr_hash(daddr, saddr);
+ break;
+ };
+ h ^= (h >> 16);
+ return h & hmask;
+}
+
+extern struct hlist_head *xfrm_hash_alloc(unsigned int sz);
+extern void xfrm_hash_free(struct hlist_head *n, unsigned int sz);
+
+#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 @@
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/module.h>
-#include <linux/bootmem.h>
-#include <linux/vmalloc.h>
#include <linux/cache.h>
#include <net/xfrm.h>
#include <net/ip.h>
+#include "xfrm_hash.h"
+
DEFINE_MUTEX(xfrm_cfg_mutex);
EXPORT_SYMBOL(xfrm_cfg_mutex);
@@ -409,62 +409,11 @@ static struct hlist_head *xfrm_policy_byidx __read_mostly;
static unsigned int xfrm_idx_hmask __read_mostly;
static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024;
-static inline unsigned int __idx_hash(u32 index, unsigned int hmask)
-{
- return (index ^ (index >> 8)) & hmask;
-}
-
static inline unsigned int idx_hash(u32 index)
{
return __idx_hash(index, xfrm_idx_hmask);
}
-static inline unsigned int __sel_hash(struct xfrm_selector *sel, unsigned short family, unsigned int hmask)
-{
- xfrm_address_t *daddr = &sel->daddr;
- xfrm_address_t *saddr = &sel->saddr;
- unsigned int h = 0;
-
- switch (family) {
- case AF_INET:
- if (sel->prefixlen_d != 32 ||
- sel->prefixlen_s != 32)
- return hmask + 1;
-
- h = ntohl(daddr->a4 ^ saddr->a4);
- break;
-
- case AF_INET6:
- if (sel->prefixlen_d != 128 ||
- sel->prefixlen_s != 128)
- return hmask + 1;
-
- h = ntohl(daddr->a6[2] ^ daddr->a6[3] ^
- saddr->a6[2] ^ saddr->a6[3]);
- break;
- };
- h ^= (h >> 16);
- return h & hmask;
-}
-
-static inline unsigned int __addr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, unsigned int hmask)
-{
- unsigned int h = 0;
-
- switch (family) {
- case AF_INET:
- h = ntohl(daddr->a4 ^ saddr->a4);
- break;
-
- case AF_INET6:
- h = ntohl(daddr->a6[2] ^ daddr->a6[3] ^
- saddr->a6[2] ^ saddr->a6[3]);
- break;
- };
- h ^= (h >> 16);
- return h & hmask;
-}
-
static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir)
{
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
return xfrm_policy_bydst[dir].table + hash;
}
-static struct hlist_head *xfrm_policy_hash_alloc(unsigned int sz)
-{
- struct hlist_head *n;
-
- if (sz <= PAGE_SIZE)
- n = kmalloc(sz, GFP_KERNEL);
- else if (hashdist)
- n = __vmalloc(sz, GFP_KERNEL, PAGE_KERNEL);
- else
- n = (struct hlist_head *)
- __get_free_pages(GFP_KERNEL, get_order(sz));
-
- if (n)
- memset(n, 0, sz);
-
- return n;
-}
-
-static void xfrm_policy_hash_free(struct hlist_head *n, unsigned int sz)
-{
- if (sz <= PAGE_SIZE)
- kfree(n);
- else if (hashdist)
- vfree(n);
- else
- free_pages((unsigned long)n, get_order(sz));
-}
-
static void xfrm_dst_hash_transfer(struct hlist_head *list,
struct hlist_head *ndsttable,
unsigned int nhashmask)
@@ -553,7 +474,7 @@ static void xfrm_bydst_resize(int dir)
unsigned int nhashmask = xfrm_new_hash_mask(hmask);
unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
struct hlist_head *odst = xfrm_policy_bydst[dir].table;
- struct hlist_head *ndst = xfrm_policy_hash_alloc(nsize);
+ struct hlist_head *ndst = xfrm_hash_alloc(nsize);
int i;
if (!ndst)
@@ -569,7 +490,7 @@ static void xfrm_bydst_resize(int dir)
write_unlock_bh(&xfrm_policy_lock);
- xfrm_policy_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
+ xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
}
static void xfrm_byidx_resize(int total)
@@ -578,7 +499,7 @@ static void xfrm_byidx_resize(int total)
unsigned int nhashmask = xfrm_new_hash_mask(hmask);
unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
struct hlist_head *oidx = xfrm_policy_byidx;
- struct hlist_head *nidx = xfrm_policy_hash_alloc(nsize);
+ struct hlist_head *nidx = xfrm_hash_alloc(nsize);
int i;
if (!nidx)
@@ -594,7 +515,7 @@ static void xfrm_byidx_resize(int total)
write_unlock_bh(&xfrm_policy_lock);
- xfrm_policy_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head));
+ xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head));
}
static inline int xfrm_bydst_should_resize(int dir, int *total)
@@ -2071,7 +1992,7 @@ static void __init xfrm_policy_init(void)
hmask = 8 - 1;
sz = (hmask+1) * sizeof(struct hlist_head);
- xfrm_policy_byidx = xfrm_policy_hash_alloc(sz);
+ xfrm_policy_byidx = xfrm_hash_alloc(sz);
xfrm_idx_hmask = hmask;
if (!xfrm_policy_byidx)
panic("XFRM: failed to allocate byidx hash\n");
@@ -2082,7 +2003,7 @@ static void __init xfrm_policy_init(void)
INIT_HLIST_HEAD(&xfrm_policy_inexact[dir]);
htab = &xfrm_policy_bydst[dir];
- htab->table = xfrm_policy_hash_alloc(sz);
+ htab->table = xfrm_hash_alloc(sz);
htab->hmask = hmask;
if (!htab->table)
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 @@
#include <linux/pfkeyv2.h>
#include <linux/ipsec.h>
#include <linux/module.h>
-#include <linux/bootmem.h>
-#include <linux/vmalloc.h>
#include <linux/cache.h>
#include <asm/uaccess.h>
+#include "xfrm_hash.h"
+
struct sock *xfrm_nl;
EXPORT_SYMBOL(xfrm_nl);
@@ -55,44 +55,6 @@ static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
static unsigned int xfrm_state_num;
static unsigned int xfrm_state_genid;
-static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr)
-{
- return ntohl(addr->a4);
-}
-
-static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr)
-{
- return ntohl(addr->a6[2]^addr->a6[3]);
-}
-
-static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
-{
- return ntohl(daddr->a4 ^ saddr->a4);
-}
-
-static inline unsigned int __xfrm6_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
-{
- return ntohl(daddr->a6[2] ^ daddr->a6[3] ^
- saddr->a6[2] ^ saddr->a6[3]);
-}
-
-static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr,
- xfrm_address_t *saddr,
- u32 reqid, unsigned short family,
- unsigned int hmask)
-{
- unsigned int h = family ^ reqid;
- switch (family) {
- case AF_INET:
- h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);
- break;
- case AF_INET6:
- h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
- break;
- };
- return (h ^ (h >> 16)) & hmask;
-}
-
static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
xfrm_address_t *saddr,
u32 reqid,
@@ -101,76 +63,18 @@ static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
}
-static inline unsigned __xfrm_src_hash(xfrm_address_t *addr, unsigned short family,
- unsigned int hmask)
-{
- unsigned int h = family;
- switch (family) {
- case AF_INET:
- h ^= __xfrm4_addr_hash(addr);
- break;
- case AF_INET6:
- h ^= __xfrm6_addr_hash(addr);
- break;
- };
- return (h ^ (h >> 16)) & hmask;
-}
-
-static inline unsigned xfrm_src_hash(xfrm_address_t *addr, unsigned short family)
+static inline unsigned int xfrm_src_hash(xfrm_address_t *addr,
+ unsigned short family)
{
return __xfrm_src_hash(addr, family, xfrm_state_hmask);
}
static inline unsigned int
-__xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto,
- unsigned short family, unsigned int hmask)
-{
- unsigned int h = spi ^ proto;
- switch (family) {
- case AF_INET:
- h ^= __xfrm4_addr_hash(daddr);
- break;
- case AF_INET6:
- h ^= __xfrm6_addr_hash(daddr);
- break;
- }
- return (h ^ (h >> 10) ^ (h >> 20)) & hmask;
-}
-
-static inline unsigned int
xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family)
{
return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask);
}
-static struct hlist_head *xfrm_state_hash_alloc(unsigned int sz)
-{
- struct hlist_head *n;
-
- if (sz <= PAGE_SIZE)
- n = kmalloc(sz, GFP_KERNEL);
- else if (hashdist)
- n = __vmalloc(sz, GFP_KERNEL, PAGE_KERNEL);
- else
- n = (struct hlist_head *)
- __get_free_pages(GFP_KERNEL, get_order(sz));
-
- if (n)
- memset(n, 0, sz);
-
- return n;
-}
-
-static void xfrm_state_hash_free(struct hlist_head *n, unsigned int sz)
-{
- if (sz <= PAGE_SIZE)
- kfree(n);
- else if (hashdist)
- vfree(n);
- else
- free_pages((unsigned long)n, get_order(sz));
-}
-
static void xfrm_hash_transfer(struct hlist_head *list,
struct hlist_head *ndsttable,
struct hlist_head *nsrctable,
@@ -216,18 +120,18 @@ static void xfrm_hash_resize(void *__unused)
mutex_lock(&hash_resize_mutex);
nsize = xfrm_hash_new_size();
- ndst = xfrm_state_hash_alloc(nsize);
+ ndst = xfrm_hash_alloc(nsize);
if (!ndst)
goto out_unlock;
- nsrc = xfrm_state_hash_alloc(nsize);
+ nsrc = xfrm_hash_alloc(nsize);
if (!nsrc) {
- xfrm_state_hash_free(ndst, nsize);
+ xfrm_hash_free(ndst, nsize);
goto out_unlock;
}
- nspi = xfrm_state_hash_alloc(nsize);
+ nspi = xfrm_hash_alloc(nsize);
if (!nspi) {
- xfrm_state_hash_free(ndst, nsize);
- xfrm_state_hash_free(nsrc, nsize);
+ xfrm_hash_free(ndst, nsize);
+ xfrm_hash_free(nsrc, nsize);
goto out_unlock;
}
@@ -251,9 +155,9 @@ static void xfrm_hash_resize(void *__unused)
spin_unlock_bh(&xfrm_state_lock);
osize = (ohashmask + 1) * sizeof(struct hlist_head);
- xfrm_state_hash_free(odst, osize);
- xfrm_state_hash_free(osrc, osize);
- xfrm_state_hash_free(ospi, osize);
+ xfrm_hash_free(odst, osize);
+ xfrm_hash_free(osrc, osize);
+ xfrm_hash_free(ospi, osize);
out_unlock:
mutex_unlock(&hash_resize_mutex);
@@ -1643,9 +1547,9 @@ void __init xfrm_state_init(void)
sz = sizeof(struct hlist_head) * 8;
- xfrm_state_bydst = xfrm_state_hash_alloc(sz);
- xfrm_state_bysrc = xfrm_state_hash_alloc(sz);
- xfrm_state_byspi = xfrm_state_hash_alloc(sz);
+ xfrm_state_bydst = xfrm_hash_alloc(sz);
+ xfrm_state_bysrc = xfrm_hash_alloc(sz);
+ xfrm_state_byspi = xfrm_hash_alloc(sz);
if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi)
panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes.");
xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1);