Per_IP流量控制方法

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

0引言
带宽资源是有限的,因此如何进行精确的网络流量控制和合理的带宽管理策略成了网络管理中一个急需解决的问题。

通过一条规则来控制指定范围内的每个IP 的策略叫着Per-IP 策略。

网络通讯时刻存在着相互性,接受方在接收到发送方的数据包以后,总要发送一定的确认信息,以便发送方进行下一步的动作。

因此流量控制是双向的,即要控制流入量也要控制流出量,特别是在P2P [1]盛行的时候,更需要对网络的每个IP 进行流出流量进行控制。

Linux 平台下的Traffic Con-trol [2]在流量控制上有多种控制队列策略,但只适用于外向流量[3],另外在单接口上控制双向流入流出不行[4]。

TC 在控制对象上也不能针对一个网段内的用户进行统一平均流量分配的灵活策略。

1Netfilter 结构
Netfilter [5]是Linux 内核中的一个包过滤框架,默认地,它在这个框架上实现了包过滤、状态检测、网络地址转换和包标记等多种功能,因为其设计的开放性,任何有内核开发经验的开发人员可以很容易地利用它提供接口,在内核的数据链路
层、网络层,实现自己的功能模块。

当网络中一个数据包到达时(如图1所示),从左边进入Linux 的Netfilter 框架,进行IP 校验以后,数据包经过第一个钩子函数NF_IP_PRE_ROUTING ,然后进入路由选择模块,该模块决定数据包是需要转发还是发给本机的。

若数据包是发给本机的,则经过钩子函数NF_IP_LOCAL_IN 处理后传递给上层协议;如果该数据包被转发则由NF_IP_FORWARD 处理;通过NF_IP_FORWARD 的数据包经过最后一个钩子函数NF_IP_POST_ROUTING 后再传输到网络上。

本机产生的数据包经过NF_IP_LOCAL_OUT 进行过滤,然后通过路由选择处理,最后经过NF_IP_POST_ROU-TING 处理以后发送到网络上。

Linux 内核模块可以在图1的5个钩子处进行注册并监听和控制数据包。

在钩子处编写钩子函数可以对数据包可以进行任何处理,每个钩子函数经过处理后都将返回一定的值,并把处理结果通知Netfilter 核心代码,以便对数据包采取相应的处理方法。

2Linux 中Per-IP 限速的当前情况
Iptables 提供limit [6]和hashlimit 两个扩展,可以限制单位时间内客户端的发包数,hashlimit 是根据limit 改进而来的,它比
收稿日期:2009-05-28;修订日期:2009-08-16。

网络与通信技术
limit 多了hash 功能,可以进行Per-IP 限制发包数。

然而,它也继承了limit 的缺点。

limit 模块提供了两个选项:--limit 和--limit-burst 。

这两个选项可以允许我们对发包数进行限制。

这个模块中允许的发包速率为:最大10000/sec 和1/day 。

即最快1秒钟发10000个包,最慢一天发一个包[7]。

2.1算法的不一致性
Limit 模块指定最快1秒钟10000个包,也就是发送一个
包,平均只需要1/10000秒,即0.1毫秒。

然而,通过实验发现,在i386平台上,最快只有每秒250个包,也就是1/250秒(4ms )发送一个包。

这个算法基于jiffy 计数器。

jiffy 计数器的频率其实就是宏HZ ,而HZ 是基于平台的,平台不一样,它的值也可能不一样。

在i386平台,HZ 的默认值是250。

也就是说,jiffy 计数器在i386平台,每过4ms 就加1。

从上面叙述可以看出,实际每秒发送包的数目和jiffy 计数器的频率有着某种联系。

2.2算法溢出检测问题
这个算法需要计算最大令牌数和发送一个包所需要的令
牌数,由于有时处理很大的数字,所以需要进行溢出检测,下面是进行溢出检测的代码:
if (r->burst ==0
||user2credits (r->avg *r->burst )<user2credits (r->avg )){printk (“Overflow in xt_limit,try lower:%u/%u\n ”,r->avg,
r->burst );
return 0;
然而这并不能检测出所有的溢出情况。

下面还是通过实例来分析。

我们指定--limit 3/day --limit-burst 5。

通过syslog 可以看到:Overflow in xt_limit,try lower:288000000/5。

算法检测出了溢出。

但是当我们指定:--limit 3/day --limit-burst 6,结果是没有任何提示,规则被顺利加入了规则表中,下面通过代码和计算来检测错误:
用户空间:
*val =XT_LIMIT_SCALE *mult /r;内核空间:
static u_int32_t user2credits (u_int32_t user ){
/*If multiplying would overflow …*/
if (user >0xFFFFFFFF /(HZ *CREDITS_PER_JIFFY ))
/*Divide first.*/
return (user /XT_LIMIT_SCALE )*HZ *CREDITS_
PER_JIFFY;
return (user *HZ *CREDITS_PER_JIFFY )/XT_LIMIT_
SCALE;}

/*Credits full.*/
r->creadit_cap =user2credits (r->avg *r->burst );r->cost =user2credits (r->avg );计算--limit 3/day --limit-burst 5:*val =XT_LIMIT_SCALE *mult /r;10000*24*60*60/3=288000000r->credit_cap =user2credits (r->avg *r->burst );288000000*5=1440000000
if (user >0xFFFFFFFF /(HZ *CREDITS_PER_JIFFY ))1440000000>134218
return (user /XT_LIMIT_SCALE )*HZ *CREDITS_PER_JIFFY;
1440000000/10000*250*128
=4608000000(结果溢出)[return 313032705]
因此,user2credits (r->avg *r->burst )返回313032705。

溢出检测机制检测user2credits (r->avg *r->burst )是否比user2credits (r->avg )来得小,通过计算,我们已经发现了溢出,下面计算user2credits (r->avg )。

r->credit_cap =user2credits (r->avg );
288000000
if (user >0xFFFFFFFF /(HZ *CREDITS_PER_JIFFY ))288000000>134218
return (user /XT_LIMIT_SCALE )*HZ *CREDITS_PER_JIFFY;
288000000/10000*250*128
=921600000[return 921600000]
现在知道user2credits (r->avg *r->burst )返回313032705,user2credits (r->avg )返回921600000。

由于313032705<921600000为真,溢出被检测出。

不管从实现的角度还是数学的角度看,这个算法都存在着问题。

速度限制没能达到期望是由于对jiffy 计数器的误解。

溢出错误没能检测出所有错误,可能是由于上层设计的问题。

更进一步讲,这个算法实现的时候采用相当模糊的方法来计算最大令牌数和发送一个包所需要的令牌数,这就很容易出错。

3系统设计
数据包在网络的任何接口都要按照图1的流程经过,在
入口用的是入口的PREROUTING ,流出设备用的是流出接口的POSTROUTING 。

因此实现流入设备的控制在PREROU-TING 进行控制,流出在POSTROUTING ,这样可以减少系统负载。

Netfilter 的hashlimit 模块可以方便地控制内网内每台机器每秒通过的数据包数。

令牌桶算法能控制每秒的字节数,将两者合理结合,可以做到控制网络的Per-IP 流速。

图1Netfilter 的数据包控制结构
IP
数据包
NF_IP_PRE_ROUTING 路由NF_IP_LOCAL_IN 本地处理
NF_IP_FORWARD
NF_IP_LOCAL_OUT
NF_IP_POST_ROUTING
3.1改进的流量控制算法
令牌桶算法[8]是著名的限速算法之一,令牌是表示可发送数据量的标志,一个令牌可以代表一个数据包,也可以代表确定数目的字节数。

系统按照用户约定的速度向桶中放置令牌,当队列中的数据包需要发送时,检查桶中是否有足够的令牌可供使用,数据包发送出去后,要从令牌桶中减去相应数量的令牌。

基于这个思想,提出一个新算法,它用来限制用户单位时间内发送的字节数,而不是发包数。

用户指定限制的速度,以及同一时刻可以发送的字节数(突发)。

然后通过下面条件计算令牌数,发送一个字节需要的令牌数以及每个jiffy产生的令牌数。

连续微处理器时钟周期间的时间的长度称作jiffy。

当数据包到来时,根据数据的长度,计算出发送这个包需要的令牌数,如果这个值大于当前拥有的令牌数,则允许发送,否则丢弃这个数据包。

用户指定限制的速度即同一时刻可以发送的字节数。

对于令牌数通过下面的方法计算。

采用的数据变量和发送关系[7,9]如下:
credit:当前拥有的令牌数;
credit_cap:最大拥有的令牌数;
cost:发送1字节需要的令牌数;
cpj:每个jiffy产生的令牌数;
S:每秒发送的字节数;
HZ:jiffy计数器的频率;
B:限制同一时刻可以发送的字节数。

当S>HZ时:
Credit=(S/HZ)*B
Credit_cap=(S/HZ)*B
Cost=1
Cpj=S/HZ
(S/HZ)为每一个jiffy要传送的字节数,乘以同一时刻可以发送的字节数(B)就可得到总的令牌数。

当S<HZ时:
Credit=(HZ/S)*B
Credit_cap=(HZ/S)*B
Cost=HZ/S
Cpj=1
3.2Per-IP限速模块的命令设计
Per-IP限速的模块名为hashrate,提供以下选项:
--hashrate
速度限制选项,必须提供。

--hashrate-name
在/proc目录产生的文件名,该文件用来查看限速状态,必须提供。

--hashrate-burst
burst匹配,可选。

--hashrate-hashsize
hash表长度,可选。

--hashrate-gcinterval
资源回收时间间隔,可选。

--hashrate-expire
空闲项过期时间,过期后变成垃圾资源,该资源将被回收,可选。

3.3实现
Netfilter提供的一套HOOK框架优势就是易于扩充。

可供扩充的Netfilter构件主要包括Table、Match、Target和Connec-tion Track Protocol Helper共4类,分别对应4套扩展函数。

利用Netfilter的构件Match可以对数据包进行灵活的控制,将限制数据包发送速度模块写成一个iptables的Match扩展模块。

从用户态和内核态来实现该模块的功能。

用户态部分主要是用户操作界面,提供给用户输入控制信息,以便用户向内核提供控制流速的参数,内核态部分根据用户输入的参数对数据包进行实际处理。

由于连接限制的核心功能在内核部分完成,减少了数据拷贝和系统调用的次数,实现CPU的零参与,使该模块的性能有了保障,因此,可以运用在至少百兆带宽的骨干网上进行实时限制。

同时,该模块可以应用可加载内核模块技术,将处理模块动态加载到内核空间。

这样,每次系统启动的时候,通过配置系统的守护进程将需要的模块动态地插入到内核中。

而在不需要进行流量限制的时候,也可以动态地卸载掉该模块。

内核态程序实现较为复杂,其实现如图2所示。

内核态实现步骤如下:
(1)创建一个全局的struct ipt_hashrate_htable htables,用来存放hash表;
(2)在match函数中按如下流程实现,在计算expire时,实现定时收集资源的函数;
(3)完成destroy()函数,实现资源回收;
(4)完成PROC部分seq_file接口的编写;
(5)初始化内核态的结构体的指针成员。

在__init()函数中用ipt_register_match()函数进行注册,在__exit()函数中用ipt_ unregister_match()撤销注册,将该c文件保存为ipt_hashrate.c。

用户态的实现较为简单,只需检测用户提交的参数,然后将合法的参数写入结构体中。

首先在init()函数中初始化struct ipt_hashrate_info结构体,然后通过parse()函数把参数(限制的速率等)写入ipt_hashrate_info结构体,用final_check()检测必要的参数(即用户输入的控制参赛)是否填写正确和完整,完成输
图2hashrate内核态流程
根据到达数据包的SIP
在Hash表中查找
N
在hash表中找到该SIP
创建一个dsthash_ent结构体,
计算expire,credit,credit_cap,
并将它添加到Hash表中
Y
重新计算过期时间
根据限速算法,
重新计算令牌数
当前令牌数>发送该包
需要的令牌数
return1return
出print()和保存save()函数,然后再初始化结构体struct iptables_match成员指针,最后在_init()函数中调用register_ma-tch()函数对该模块进行注册,保存该c文件为libipt_hashrate.c。

4验证
我们在一台Linux机器上运行增加的Netfilter的hashrate 模块,该机器配置双网卡。

两个网卡分别接两台测试机,测试机运行测速软件[10]。

下面的第1条命令就是限制内网内的机器以200KB/s的速度上传。

第2条命令就是对超过这个速度的流量进行拒绝。

注意接口的数据包流向,测速软件发送的是TCP包。

iptables-t mangle-A PREROUTING-i eth0--s192.168.0.0/24
-m hashrate--hashrate200000--hashname single_ip-j ACCEPT iptables-t mangle-A PREROUTING-i eth0-s192.168.0.0/24-j DROP
图3是流量控制的效果和各种数据包的大小的关系。

实验证明采用改进的Netfilter可以达到对内网内Per-IP进行流量控制的效果。

而且对不同大小的数据包控制效果接近。

5结束语
本文研究了利用一种单条规则统一控制网络中各用户流量的方法,该方法在Linux上实现了模块化。

该模块可以对网络内的各种以IP段,网络号表示的对象进行Per-IP带宽限制。

用户可以方便地在终端提交要限制的各种类型IP表示和带宽,有效地限制了各个IP的速度,具有了一定的实用价值。

并改进了令牌桶算法使按字节控制流量在Netfilter中得以实现。

这样解决了Netfilter不能控制字节流速的问题,同时也能在设备的同一接口上进行双向流量控制,方便流量规则的设计和管理。

参考文献:
[1]李君.P2P业务流量识别、分析和控制研究[J].计算机工程,
2006,32(11):122-124.
[2]Stanic M.Traffic control[EB/OL].http://www.rns-nis.co.yu/~
mps/linux-tc.html,2009-05-03.
[3]Bert Hubert.Linux的高级路由和流量控制HOWTO中文版
[M].北京:人民邮电出版社.
[4]张焕强,吴志美.Linux环境下路由器中的网络带宽管理[J].软
件学报,2005,16(3):462-471.
[5]Netfilter core filter[EB/OL]./
2008-12-29.
[6]Herve Eychenne.Iptables limit match,Linux kernel source code,
Linux-2.6.28.1[EB/OL].,2008.
[7]Nicolas Bouliane.Limit TBF analysis[EB/OL].http://people.
/acidfu/papers/limit-tbf-analysis.pdf,2007.
[8]Andrew S puter networks[M].北京:清华大学
出版社,2006:340-342.
[9]John Soldatos,Evangelos Vayias,Panagiotis Stathopoulos,et al.
Enforcing effective rates for packet-level QoS control in IP net-works:Theory and validation based on RealTraffic data[EB/OL].
http://www.ait.gr/research/RG1/files/TSJ_04.pdf,2004.
[10]Netperf[EB/OL]./netperf/,2009-05-22.。

相关文档
最新文档