Per_IP流量控制方法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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 )
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