[XFRM]: Extract common hashing code into xfrm_hash.[ch]
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
2518c7c2b3
commit
44e36b42a8
5 changed files with 195 additions and 200 deletions
|
@ -2,6 +2,7 @@
|
||||||
# Makefile for the XFRM subsystem.
|
# 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
|
obj-$(CONFIG_XFRM_USER) += xfrm_user.o
|
||||||
|
|
||||||
|
|
41
net/xfrm/xfrm_hash.c
Normal file
41
net/xfrm/xfrm_hash.c
Normal file
|
@ -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));
|
||||||
|
}
|
128
net/xfrm/xfrm_hash.h
Normal file
128
net/xfrm/xfrm_hash.h
Normal file
|
@ -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 */
|
|
@ -22,12 +22,12 @@
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/bootmem.h>
|
|
||||||
#include <linux/vmalloc.h>
|
|
||||||
#include <linux/cache.h>
|
#include <linux/cache.h>
|
||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
|
|
||||||
|
#include "xfrm_hash.h"
|
||||||
|
|
||||||
DEFINE_MUTEX(xfrm_cfg_mutex);
|
DEFINE_MUTEX(xfrm_cfg_mutex);
|
||||||
EXPORT_SYMBOL(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_idx_hmask __read_mostly;
|
||||||
static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024;
|
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)
|
static inline unsigned int idx_hash(u32 index)
|
||||||
{
|
{
|
||||||
return __idx_hash(index, xfrm_idx_hmask);
|
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)
|
static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir)
|
||||||
{
|
{
|
||||||
unsigned int hmask = xfrm_policy_bydst[dir].hmask;
|
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;
|
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,
|
static void xfrm_dst_hash_transfer(struct hlist_head *list,
|
||||||
struct hlist_head *ndsttable,
|
struct hlist_head *ndsttable,
|
||||||
unsigned int nhashmask)
|
unsigned int nhashmask)
|
||||||
|
@ -553,7 +474,7 @@ static void xfrm_bydst_resize(int dir)
|
||||||
unsigned int nhashmask = xfrm_new_hash_mask(hmask);
|
unsigned int nhashmask = xfrm_new_hash_mask(hmask);
|
||||||
unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
|
unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
|
||||||
struct hlist_head *odst = xfrm_policy_bydst[dir].table;
|
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;
|
int i;
|
||||||
|
|
||||||
if (!ndst)
|
if (!ndst)
|
||||||
|
@ -569,7 +490,7 @@ static void xfrm_bydst_resize(int dir)
|
||||||
|
|
||||||
write_unlock_bh(&xfrm_policy_lock);
|
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)
|
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 nhashmask = xfrm_new_hash_mask(hmask);
|
||||||
unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
|
unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
|
||||||
struct hlist_head *oidx = xfrm_policy_byidx;
|
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;
|
int i;
|
||||||
|
|
||||||
if (!nidx)
|
if (!nidx)
|
||||||
|
@ -594,7 +515,7 @@ static void xfrm_byidx_resize(int total)
|
||||||
|
|
||||||
write_unlock_bh(&xfrm_policy_lock);
|
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)
|
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;
|
hmask = 8 - 1;
|
||||||
sz = (hmask+1) * sizeof(struct hlist_head);
|
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;
|
xfrm_idx_hmask = hmask;
|
||||||
if (!xfrm_policy_byidx)
|
if (!xfrm_policy_byidx)
|
||||||
panic("XFRM: failed to allocate byidx hash\n");
|
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]);
|
INIT_HLIST_HEAD(&xfrm_policy_inexact[dir]);
|
||||||
|
|
||||||
htab = &xfrm_policy_bydst[dir];
|
htab = &xfrm_policy_bydst[dir];
|
||||||
htab->table = xfrm_policy_hash_alloc(sz);
|
htab->table = xfrm_hash_alloc(sz);
|
||||||
htab->hmask = hmask;
|
htab->hmask = hmask;
|
||||||
if (!htab->table)
|
if (!htab->table)
|
||||||
panic("XFRM: failed to allocate bydst hash\n");
|
panic("XFRM: failed to allocate bydst hash\n");
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
#include <linux/pfkeyv2.h>
|
#include <linux/pfkeyv2.h>
|
||||||
#include <linux/ipsec.h>
|
#include <linux/ipsec.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/bootmem.h>
|
|
||||||
#include <linux/vmalloc.h>
|
|
||||||
#include <linux/cache.h>
|
#include <linux/cache.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
|
#include "xfrm_hash.h"
|
||||||
|
|
||||||
struct sock *xfrm_nl;
|
struct sock *xfrm_nl;
|
||||||
EXPORT_SYMBOL(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_num;
|
||||||
static unsigned int xfrm_state_genid;
|
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,
|
static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
|
||||||
xfrm_address_t *saddr,
|
xfrm_address_t *saddr,
|
||||||
u32 reqid,
|
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);
|
return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_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 int hmask)
|
unsigned short family)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
return __xfrm_src_hash(addr, family, xfrm_state_hmask);
|
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
|
static inline unsigned int
|
||||||
xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family)
|
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);
|
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,
|
static void xfrm_hash_transfer(struct hlist_head *list,
|
||||||
struct hlist_head *ndsttable,
|
struct hlist_head *ndsttable,
|
||||||
struct hlist_head *nsrctable,
|
struct hlist_head *nsrctable,
|
||||||
|
@ -216,18 +120,18 @@ static void xfrm_hash_resize(void *__unused)
|
||||||
mutex_lock(&hash_resize_mutex);
|
mutex_lock(&hash_resize_mutex);
|
||||||
|
|
||||||
nsize = xfrm_hash_new_size();
|
nsize = xfrm_hash_new_size();
|
||||||
ndst = xfrm_state_hash_alloc(nsize);
|
ndst = xfrm_hash_alloc(nsize);
|
||||||
if (!ndst)
|
if (!ndst)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
nsrc = xfrm_state_hash_alloc(nsize);
|
nsrc = xfrm_hash_alloc(nsize);
|
||||||
if (!nsrc) {
|
if (!nsrc) {
|
||||||
xfrm_state_hash_free(ndst, nsize);
|
xfrm_hash_free(ndst, nsize);
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
nspi = xfrm_state_hash_alloc(nsize);
|
nspi = xfrm_hash_alloc(nsize);
|
||||||
if (!nspi) {
|
if (!nspi) {
|
||||||
xfrm_state_hash_free(ndst, nsize);
|
xfrm_hash_free(ndst, nsize);
|
||||||
xfrm_state_hash_free(nsrc, nsize);
|
xfrm_hash_free(nsrc, nsize);
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,9 +155,9 @@ static void xfrm_hash_resize(void *__unused)
|
||||||
spin_unlock_bh(&xfrm_state_lock);
|
spin_unlock_bh(&xfrm_state_lock);
|
||||||
|
|
||||||
osize = (ohashmask + 1) * sizeof(struct hlist_head);
|
osize = (ohashmask + 1) * sizeof(struct hlist_head);
|
||||||
xfrm_state_hash_free(odst, osize);
|
xfrm_hash_free(odst, osize);
|
||||||
xfrm_state_hash_free(osrc, osize);
|
xfrm_hash_free(osrc, osize);
|
||||||
xfrm_state_hash_free(ospi, osize);
|
xfrm_hash_free(ospi, osize);
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&hash_resize_mutex);
|
mutex_unlock(&hash_resize_mutex);
|
||||||
|
@ -1643,9 +1547,9 @@ void __init xfrm_state_init(void)
|
||||||
|
|
||||||
sz = sizeof(struct hlist_head) * 8;
|
sz = sizeof(struct hlist_head) * 8;
|
||||||
|
|
||||||
xfrm_state_bydst = xfrm_state_hash_alloc(sz);
|
xfrm_state_bydst = xfrm_hash_alloc(sz);
|
||||||
xfrm_state_bysrc = xfrm_state_hash_alloc(sz);
|
xfrm_state_bysrc = xfrm_hash_alloc(sz);
|
||||||
xfrm_state_byspi = xfrm_state_hash_alloc(sz);
|
xfrm_state_byspi = xfrm_hash_alloc(sz);
|
||||||
if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi)
|
if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi)
|
||||||
panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes.");
|
panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes.");
|
||||||
xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
|
xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
|
||||||
|
|
Loading…
Reference in a new issue