linux内核netfilter连接跟踪的hash算法
linux内核netfilter连接跟踪的hash算法
linux内核中的netfilter是一款强大的基于状态的防火墙,具有连接跟踪(conntrack)的实现。conntrack是netfilter的核心,许多增强的功能,例如,地址转换(NAT),基于内容的业务识别(l7, layer-7 module)都是基于连接跟踪。然而,netfilter的性能还有很多值得改进的地方。
netfilter的连接跟踪的hash算法是在Bob Jenkins的lookup2.c基础上的改进实现,Bob Jenkins已经推出lookup3.c的实现,见地址:http://burtleburtle.net/bob/hash/和http://burtleburtle.net/bob/c/lookup3.c
netfilter中的hash求值的代码如下:
static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple,
unsigned int size, unsigned int rnd)
{
unsigned int a, b;
a = jhash((void *)tuple->src.u3.all, sizeof(tuple->src.u3.all),
((tuple->src.l3num) << 16) | tuple->dst.protonum);
b = jhash((void *)tuple->dst.u3.all, sizeof(tuple->dst.u3.all),
(tuple->src.u.all << 16) | tuple->dst.u.all);
return jhash_2words(a, b, rnd) % size;
}
static inline u_int32_t hash_conntrack(const struct nf_conntrack_tuple *tuple)
{
return __hash_conntrack(tuple, nf_conntrack_htable_size,
nf_conntrack_hash_rnd);
}
这是一个对于ipv6和ipv4的hash求值的通用实现。struct nf_conntrack_tuple是一个通用的连接的四元组,同时用于ipv4和ipv6,tcp,udp,sctp,icmp协议,所以,其定义比较复杂。可以把它理解为源地址,源端口,目的地址,目的端口。
#define NF_CT_TUPLE_L3SIZE 4
union nf_conntrack_man_l3proto {
u_int32_t all[NF_CT_TUPLE_L3SIZE];
u_int32_t ip;
u_int32_t ip6[4];
};
其实这就是ip地址。
union nf_conntrack_man_proto
{
/* Add other protocols here. */
u_int16_t all;
struct {
u_int16_t port;
} tcp;
struct {
u_int16_t port;
} udp;
struct {
u_int16_t id;
} icmp;
struct {
u_int16_t port;
} sctp;
};
这就是端口。
struct nf_conntrack_man
{
union nf_conntrack_man_l3proto u3;
union nf_conntrack_man_proto u;
/* Layer 3 protocol */
u_int16_t l3num;
};
目的地址和端口,l3num不知道是什么东西?
struct nf_conntrack_tuple
{
struct nf_conntrack_man src;
/* These are the parts of the tuple which are fixed. */
struct {
union {
u_int32_t all[NF_CT_TUPLE_L3SIZE];
u_int32_t ip;
u_int32_t ip6[4];
} u3;
union {
/* Add other protocols here. */
u_int16_t all;
struct {
u_int16_t port;
} tcp;
struct {
u_int16_t port;
} udp;
struct {
u_int8_t type, code;
} icmp;
struct {
u_int16_t port;
} sctp;
} u;
/* The protocol. */
u_int8_t protonum;
/* The direction (for tuplehash) */
u_int8_t dir;
} dst;
};
有些混乱,就是源地址和目的地址,protonum和dir不知道为什么这么定义?
上面的hash算法在仅用于ipv4时,可以进行优化。jhash函数是通用的hash函数,上面的目的是把ipv6的长串字符hash为一个32位整数,而ipv4的情况下,可以不用。
最后,使用%运算,这是非常低效的,Bob Jenkins专门指出了这一点。由于table的大小都为2的次方,所以,可以使用&的算法。
另外,我认为Bob Jenkins的算法是对于通用的数字的hash算法,对于tcp连接这样比较特殊的数字的hash,使用这么复杂的算法,是否有意义?简单的加法运算是否更有效率?
lookup3.c与lookup2.c有很大的不同。lookup3.c中,使用了final宏,和mix宏分开。而lookup2.c中没有使用final宏。
linux下的修改过的hash函数:
static inline u32 jhash(const void *key, u32 length, u32 initval)
通用的hash函数,对任意长度的key字符串进行hash运算,得到一个32位数字。
static inline u32 jhash2(u32 *k, u32 length, u32 initval)
优化的版本,对任意长度的32位整数进行hash运算,得到一个32位数字。
static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
{
a += JHASH_GOLDEN_RATIO;
b += JHASH_GOLDEN_RATIO;
c += initval;
__jhash_mix(a, b, c);
return c;
}
优化的版本,对3个32位整数进行hash运算,得到一个32位数字。
static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
{
return jhash_3words(a, b, 0, initval);
}
对2个32位整数进行hash运算,得到一个32位数字。
static inline u32 jhash_1word(u32 a, u32 initval)
{
return jhash_3words(a, 0, 0, initval);
}
对1个32位整数进行hash运算,得到一个32位数字。
#define mix(a,b,c) /
{ /
a -= c; a ^= rot(c, 4); c += b; /
b -= a; b ^= rot(a, 6); a += c; /
c -= b; c ^= rot(b, 8); b += a; /
a -= c; a ^= rot(c,16); c += b; /
b -= a; b ^= rot(a,19); a += c; /
c -= b; c ^= rot(b, 4); b += a; /
}
#define final(a,b,c) /
{ /
c ^= b; c -= rot(b,14); /
a ^= c; a -= rot(c,11); /
b ^= a; b -= rot(a,25); /
c ^= b; c -= rot(b,16); /
a ^= c; a -= rot(c,4); /
b ^= a; b -= rot(a,14); /
c ^= b; c -= rot(b,24); /
}
上面的两个宏这是lookup3.c的核心hash算法,hash的基础。
uint32_t hashword(
const uint32_t *k, /* the key, an array of uint32_t values */
size_t length, /* the length of the key, in uint32_ts */
uint32_t initval) /* the previous hash, or an arbitrary value */
{
uint32_t a,b,c;
/* Set up the internal state */
a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval;
/*------------------------------------------------- handle most of the key */
while (length > 3)
{
a += k[0];
b += k[1];
c += k[2];
mix(a,b,c);
length -= 3;
k += 3;
}
/*------------------------------------------- handle the last 3 uint32_t's */
switch(length) /* all the case statements fall through */
{
case 3 : c+=k[2];
case 2 : b+=k[1];
case 1 : a+=k[0];
final(a,b,c);
case 0: /* case 0: nothing left to add */
break;
}
/*------------------------------------------------------ report the result */
return c;
}
hashword是通用的hash算法,用于计算任意cpu架构,任意长度的字符串的hash值。
不断的把输入的串k,每隔3位进行mix,直到完毕。返回final。
对于ipv4的话,可以直接把源地址,目的地址,(源端口<< 16)|目的端口,这三个整数进行final,得到hash值。
对于ip地址和端口号的特点,这种复杂的算法是否真的有更好的hash效果,我持怀疑态度。
linux内核netfilter连接跟踪的hash算法的更多相关文章
- Linux内核分析之跟踪分析Linux内核的启动过程
一.实验过程 使用实验楼虚拟机打开shell cd LinuxKernel/ qemu -kernel linux-/arch/x86/boot/bzImage -initrd rootfs.img ...
- linux内核netfilter模块分析之:HOOKs点的注册及调用
转自;http://blog.csdn.net/suiyuan19840208/article/details/19684883 -1: 为什么要写这个东西?最近在找工作,之前netfilter 这一 ...
- linux内核学习之三 跟踪分析内核的启动过程
一 前期准备工作 1 搭建环境 1.1下载内核源代码并编译内核 创建目录,并进入该目录: 下载源码: 解压缩,并进入该目录:xz -d linux-3.18.6.tar.xz tar ...
- linux内核中的C语言常规算法(前提:你的编译器要支持typeof和type)
学过C语言的伙伴都知道,曾经比较两个数,输出最大或最小的一个,或者是比较三个数,输出最大或者最小的那个,又或是两个数交换,又或是绝对值等等,其实这些算法在linux内核中通通都有实现,以下的代码是我从 ...
- Linux内核中常用的数据结构和算法(转)
知乎链接:https://zhuanlan.zhihu.com/p/58087261 Linux内核代码中广泛使用了数据结构和算法,其中最常用的两个是链表和红黑树. 链表 Linux内核代码大量使用了 ...
- 分析linux内核中的slub内存管理算法
1. 分析的linux内核源码版本为4.18.0 2. 与slub相关的内核配置项为CONFIG_SLUB 3. 一切都从一个结构体数组kmalloc_caches开始,它的原型如下: ] __ro_ ...
- Linux内核中的有关Page的算法
static inline int get_order(unsigned long size) { int order; size = (size-1) >> (PAGE_SHIFT-1) ...
- Linux 内核SBus连接
当大部分计算机配备有 PCI 或 ISA 接口总线, 大部分老式的基于 SPARC 的工作站使用 SBus 来连接它们的外设. SBus 使一个非常先进的设计, 尽管它已出现很长时间. 它意图是处理器 ...
- Netfilter&iptables:如何理解连接跟踪机制?
如何理解Netfilter中的连接跟踪机制? 本篇我打算以一个问句开头,因为在知识探索的道路上只有多问然后充分调动起思考的机器才能让自己走得更远.连接跟踪定义很简单:用来记录和跟踪连接的状态. 问:为 ...
随机推荐
- drupal7 转化 public:// 为实际url
file_create_url('public://xxx.png'); // 得到URL drupal_realpath('public://xxx.png'); // 得到系统路径(磁盘路径,如D ...
- 几种常用的bootstrap功能。
---恢复内容开始--- 我对于bootstrap定义与一种插件,他可以使我们的网页布局更加的炫酷,更加的整洁和合理.他的优点不多说,缺点一个就够我们头疼的,那就是需要记一些长长的英文名. 我为大家说 ...
- LintCode2016年8月22日算法比赛----骰子求和
骰子求和 题目描述 扔n个骰子,向上面的数字之和为 S .给定 Given n,请列出所有可能的 S 值及其相应的概率. 样例 给定n=1,返回 [ [1, 0.17], [2, 0.17], [3, ...
- 然之协同系统6.4.1 SQL注入导致getshell
前言 先知上一个大佬挖的洞,也有了简单的分析 https://xianzhi.aliyun.com/forum/topic/2135 我自己复现分析过程,漏洞的原理比较简单,但是漏洞的利用方式对我而 ...
- SSM 框架集-01-详细介绍-入门问题篇
SSM 框架集-01-详细介绍-入门问题篇 刚开始了解 SSM,首先先解决几个基础问题 1.什么是 SSM 框架集? SSM(Spring+SpringMVC+MyBatis)框架集由 Spring. ...
- eclipse设置模板及格式
1) 首先要有code_templates.xml 及 code_formatter.xml 两个文件,下面有代码,直接拷贝出来. code_formatter.xml: <?xml v ...
- 初识WCF2
参照: http://blog.csdn.net/songyefei/article/details/7371571 在上一篇中,我们在一个控制台应用程序中编写了一个简单的WCF服务并承载了它.先回顾 ...
- 京东原来你运用的这玩意,不错,我也要!! ContainerDNS
转自社区 ContainerDNS 本文介绍的 DNS 命名为 ContainerDNS,作为京东商城软件定义数据中心的关键基础服务之一,具有以下特点: 分布式,高可用 自动发现服务域名 后端探活 易 ...
- MSSQL->serverlink[Oracle]
需求描述: SQL Server数据库连接Oracle数据库 条件准备: SQL Server数据库,SQL Server 2008R2 Oracle数据库,Oracle ...
- 使用.Net访问Office编程接口(PIA和IA的区别)
在这篇文章里面,我将向大家介绍如何在.Net中访问Office所公开的编程接口.其实,不管是使用哪种具体的技术来针对Office进行开发(比如VSTO,或者用C#编写一个Office Add-in,或 ...