日期:2014-05-16 浏览次数:21044 次
6. XFRM的其他操作
6.1 HASH处理
关于HASH值的计算方法主要在net/xfrm/xfrm_hash.h中定义:
// IPV4地址HASH
static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr)
{
// 就是地址本身
return ntohl(addr->a4);
}
// IPV6地址HASH
static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr)
{
// 取后2个32位数异或
return ntohl(addr->a6[2] ^ addr->a6[3]);
}
// IPV4源,目的地址HASH
static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
{
// 将两个地址异或
return ntohl(daddr->a4 ^ saddr->a4);
}
// IPV4源,目的地址HASH
static inline unsigned int __xfrm6_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
{
// 两个V6地址都取后2个32位数异或
return ntohl(daddr->a6[2] ^ daddr->a6[3] ^
saddr->a6[2] ^ saddr->a6[3]);
}
// 目的地址HASH
static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t *saddr,
u32 reqid, unsigned short family,
unsigned int hmask)
{
// 协议族和请求ID异或
unsigned int h = family ^ reqid;
switch (family) {
// HASH值再和源目的地址HASH结果进行异或
case AF_INET:
h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);
break;
case AF_INET6:
h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
break;
}
// 将HASH结果高低16位异或存低16位,高16位不动, 然后用HASH掩码相与
return (h ^ (h >> 16)) & hmask;
}
// 源地址HASH, 只是没有请求ID项, 其他HASH过程和上面相同
static inline unsigned __xfrm_src_hash(xfrm_address_t *daddr,
xfrm_address_t *saddr,
unsigned short family,
unsigned int hmask)
{
unsigned int h = family;
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;
}
// 根据SPI计算HASH值
static inline unsigned int
__xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family,
unsigned int hmask)
{
// 先将SPI和协议进行异或
unsigned int h = (__force u32)spi ^ proto;
switch (family) {
// HASH值再和目的地址进行单一地址HASH值异或
case AF_INET:
h ^= __xfrm4_addr_hash(daddr);
break;
case AF_INET6:
h ^= __xfrm6_addr_hash(daddr);
break;
}
// HASH值再和本身的高22位, 高12位异或后再和掩码相与
return (h ^ (h >> 10) ^ (h >> 20)) & hmask;
}
// 索引号HASH
static inline unsigned int __idx_hash(u32 index, unsigned int hmask)
{
// 低24位和高24位异或, 高8位不动, 再和掩码相与
return (index ^ (index >> 8)) & hmask;
}
// 选择子HASH
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) {
// 用源,目的地址同时进行HASH
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;
};
// 高16位与低16位异或,高16位不变
h ^= (h >> 16);
// 与掩码相与, 其实HASH值中不带协议族因素, 因为地址本身就包含了
return h & hmask;
}
// 地址HASH
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) {
// 用源,目的地址同时进行HASH
case AF_INET:
h = __xfrm4_daddr_saddr_hash(daddr, saddr);
break;
case AF_INET6:
h = __xfrm6_daddr_saddr_hash(daddr, saddr);
break;
};
// 高16位与低16位异或,高16位不变
h ^= (h >> 16);
// 与掩码相与
return h & hmask;
}
在net/xfrm/xfrm_hash.c 文件中定义了HASH表的分配和释放函数:
struct hlist_head *xfrm_hash_alloc(unsigned int sz)
{
struct hlist_head *n;
// 根据HASH表大小选择合适的分配方法
// 大小不超过PAGE_SIZE, 用kmalloc分配
if (sz <= PAGE_SIZE)
n = kmalloc(sz, GFP_KERNEL);
// 这是在内核定义NUMA和IA64下用vmalloc分配
else if (hashdist)
n = __vmalloc(sz, GFP_KERNEL, PAGE_KERNEL);
else
// 其他类型的内