日期:2014-05-16 浏览次数:20827 次
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 // 其他类型的内