目前很多企业的内部局域网已经建立,很多还在局域网基础上建立了企业内部的MIS系统和邮件服务器等,甚至在系统中开展了视频点播等数据流量较大的业务。
企业内部网络有足够的带宽可以使用。但是,一般在企业接入
Internet的部分都是一个有限的流量。为了提高网络的使用质量,保证用户按照网络中业务设计的要求来使用整个网络的带宽,可以从流量控制服务器的角度分析、优化
Linux系统,给企业服务带来便利和高效。
流量控制的基本实现
Linux操作系统中的流量控制器(TC)主要是通过在输出端口处建立一个队列来实现流量控制。Linux从2.1.105版内核开始支持流量控制,使用时需要重新编译内核。Linux流量控制的基本实现可简单地由图1来描述。从图1可以看出,内核是如何处理接收包、如何产生发送包,并送往网络的。
图1 Linux流量控制的基本实现
接收包进来后,由输入多路分配器(Input De-Multiplexing)进行判断选择:如果接收包的目的是本主机,那么将该包送给上层处理;否则需要进行转发,将接收包交到转发块(Forwarding Block)处理。转发块同时也接收本主机上层(TCP、UDP等)产生的包。转发块通过查看路由表,决定所处理包的下一跳。然后,对包进行排列以便将它们传送到输出接口(Output Interface)。Linux流量控制正是在排列时进行处理和实现的。
图2 流量控制基本
框架
3.TC中过滤器(filter)的用法
过滤器的使用中,内核支持需设置QoS support、QoS and/or fair queueing、Packet classifier API = y。用法为:
#tc filter [ add | del | change | get ] dev STRING
[ pref PRIO ] [ protocol PROTO ]
[ estimator INTERVAL TIME_CONSTANT ]
[ root | classid CLASSID ] [ handle FILTERID ]
[ [ FILTER_TYPE ] [ help | OPTIONS ] ]
#tc filter show [ dev STRING ] [ root | parent CLASSID ]
其中
FILTER_TYPE := { rsvp | u32 | fw | route | etc. }
FILTERID := ... format depends on classifier, see there
OPTIONS := ... try tc filter add <desired FILTER_KIND> help
TC U32过滤器(filter u32)的用法:
... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]
[ police POLICE_SPEC ] [ offset OFFSET_SPEC ]
[ ht HTID ] [ hashkey HASHKEY_SPEC ]
[ sample SAMPLE ]
或 u32 divisor DIVISOR
其中
SELECTOR := SAMPLE SAMPLE ...
SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} } SAMPLE_ARGS
FILTERID := X:Y:Z
TC FW过滤器(filter fw)的用法:
... fw [ classid CLASSID ] [ police POLICE_SPEC ]
其中
POLICE_SPEC := ... look at TBF
CLASSID := X:Y
流量控制应用实例
假设目前某企业面临的是一个复杂的网络环境。在该环境中,既包括了100Mb的局域网,也包括了微波或802.11的无线链路网络,其网络拓扑如图3所示。在这样的环境下,保证业务数据的流量,实现流量控制,需要对各局域网的传输及业务服务进行控制。
图3 企业网络拓扑图
如图2所示,Linux流量控制主要由三大部分来实现:
◆ 队列规则(Queue Discipline)
◆ 分类(Classes)
◆ 过滤器(Filters)
因此,Linux流量控制主要分为建立队列、建立分类和建立过滤器三个方面。其基本实现步骤为:
(1)针对网络物理设备(如以太网卡eth0)绑定一个队列;
(2)在该队列上建立分类;
(3)为每一分类建立一个基于路由的过滤器。
流量控制的具体使用
现在对流量控制(TC)的具体使用做个介绍。首先是TC的总用法。
TC命令,内核支持需设置QoS support、QoS and/or fair queueing = y。用法为:
#tc [ OPTIONS ] OBJECT { COMMAND | help }
其中
OBJECT := { qdisc | class | filter }
OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] }
下面分别介绍TC中队列、分类和过滤器的用法。
1.TC中队列(qdisc)的用法
队列的使用中,内核支持需设置QoS support、QoS and/or fair queueing = y。用法为:
#tc qdisc [ add | del | replace | change | get ] dev STRING
[ handle QHANDLE ] [ root | ingress | parent CLASSID ]
[ estimator INTERVAL TIME_CONSTANT ]
[ [ QDISC_KIND ] [ help | OPTIONS ] ]
#tc qdisc show [ dev STRING ] [ingress]
其中
QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }
OPTIONS := ... try tc qdisc add <desired QDISC_KIND> help
CBQ队列(qdisc cbq)的使用中,内核支持需设置 QoS support、QoS and/or fair queueing、CBQ packet scheduler、Rate estimator = y,用法为:
... cbq bandwidth BPS avpkt BYTES [ mpu BYTES ]
[ cell BYTES ] [ ewma LOG ]
2.TC中分类(class)的用法
分类的使用中,内核支持需设置QoS support、QoS and/or fair queueing、Packet classifier API = y。用法为:
#tc class [ add | del | change | get ] dev STRING
[ classid CLASSID ] [ root | parent CLASSID ]
[ [ QDISC_KIND ] [ help | OPTIONS ] ]
#tc class show [ dev STRING ] [ root | parent CLASSID ]
其中
QDISC_KIND := { prio | cbq | etc. }
OPTIONS := ... try tc class add <desired QDISC_KIND> help
TC CBQ分类(class cbq)的用法为:
<ccid_nobr>
<table width="400" border="1" cellspacing="0" cellpadding="2"
bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center">
<tr>
<td bgcolor="e6e6e6" class="code" style="font-size:9pt">
<pre><ccid_code> ... cbq bandwidth BPS rate BPS maxburst PKTS [ avpkt BYTES ]
[ minburst PKTS ] [ bounded ] [ isolated ]
[ allot BYTES ] [ mpu BYTES ] [ weight RATE ]
[ prio NUMBER ] [ cell BYTES ] [ ewma LOG ]
[ estimator INTERVAL TIME_CONSTANT ]
[ split CLASSID ] [ defmap MASK/CHANGE ]
1.建立队列
一般情况下,针对一个网卡只需建立一个队列。
将一个CBQ队列绑定到网络物理设备eth1上,其编号为1:0,实际带宽为10Mb,包的平均大小为1500字节,包间隔发送单元的大小为8字节,最小传输包大小为64字节。
#tc qdisc add dev eth1 root handle 1:0 cbq bandwidth 10Mbit cell 8 avpkt 1500 mpu 64
2.建立分类
分类建立在队列之上。一般情况下,针对一个队列需建立一个根分类,然后在其上建立子分类。对于分类,按其分类的编号顺序起作用,编号小的优先。一旦符合某个分类匹配规则,通过该分类发送数据包,则其后的分类不再起作用。
(1)创建根分类1:1,分配带宽为10Mb。
#tc class add dev eth1 parent 1:0 classid 1:1 cbq bandwidth 10Mbit rate 10Mbit allot 1514 cell 8 weight 1Mbit maxburst 1 avpkt 1500 bounded
该队列的最大可用带宽为10Mb,实际分配的带宽为10Mb,可接收冲突的发送最长包数目为1字节,最大传输单元(加MAC头)大小为1514字节,优先级别为8,包的平均大小为1500字节,包间隔发送单元的大小为8字节,相应于实际带宽的加权速率为10Mb。
(2)创建分类1:2,其父分类为1:1,分配带宽为8Mb。
#tc class add dev eth1 parent 1:1 classid 1:2 cbq bandwidth 10Mbit rate 1200Kbit allot 1514 cell 8 weight 120Kbit maxburst 1 avpkt 1500 bounded isolated
该队列的最大可用带宽为10Mb,实际分配的带宽为 1.2Mb,可接收冲突的发送最长包数目为1字节,最大传输单元(加MAC头)大小为1514字节,优先级别为1,包的平均大小为1500字节,包间隔发送单元的大小为8字节,相应于实际带宽的加权速率为120Kb,独占带宽且不可借用未使用带宽。
(3)创建分类1:10,其父分类为1:2,分配带宽为100Kb。
#tc class add dev eth1 parent 1:2 classid 1:10 cbq bandwidth 10Mbit rate 100Kbit allot 1514 cell 8 weight 10Kbit maxburst 1 avpkt 1500
该队列的最大可用带宽为10Mb,实际分配的带宽为 1.2Mb,可接收冲突的发送最长包数目为1字节,最大传输单元(加MAC头)大小为1514字节,优先级别为1,包的平均大小为1500字节,包间隔发送单元的大小为8字节,相应于实际带宽的加权速率为10Kb。
(4)创建分类1:20,其父分类为1:2,分配带宽为1.1Mb。
#tc class add dev eth1 parent 1:2 classid 1:20 cbq bandwidth 10Mbit rate 1100Kbit allot 1514 cell 8 weight 110Kbit maxburst 1 avpkt 1500
详细显示指定设备(这里为eth1)的分类状况:
#tc -s class ls dev eth1
class cbq 1: root rate 10Mbit (bounded,isolated) prio no-transmit
Sent 17725304 bytes 32088 pkts (dropped 0, overlimits 0)
borrowed 0 overactions 0 avgidle 31 undertime 0
class cbq 1:1 parent 1: rate 10Mbit prio no-transmit
Sent 16627774 bytes 28884 pkts (dropped 0, overlimits 0)
borrowed 16163 overactions 0 avgidle 587 undertime 0
class cbq 1:2 parent 1:1 rate 1200Kbit prio no-transmit
Sent 628829 bytes 3130 pkts (dropped 0, overlimits 0)
borrowed 0 overactions 0 avgidle 4137 undertime 0
class cbq 1:10 parent 1:2 rate 100KMbit prio 1
Sent 0 bytes 0 pkts (dropped 0, overlimits 0)
borrowed 0 overactions 0 avgidle 159654 undertime 0
class cbq 1:20 parent 1:1 rate 1100Kbit prio no-transmit
Sent 5552879 bytes 8076 pkts (dropped 0, overlimits 0)
borrowed 3797 overactions 0 avgidle 159557 undertime 0
这里主要显示通过不同分类发送的数据包、数据流量、丢弃的包数目、超过速率限制的包数目等。其中根分类(class cbq 1:0)的状况应与队列的状况类似。
例如,分类class cbq 1:20发送了8076个数据包,数据流量为5552879个字节,丢弃的包数目为0,超过速率限制的包数目为0。
(3)显示过滤器的状况
#tc -s filter ls dev eth1
filter parent 1: protocol ip pref 1 fw
filter parent 1: protocol ip pref 1 fw handle 0x4 classid 1:10
filter parent 1: protocol ip pref 100 fw
filter parent 1: protocol ip pref 100 fw handle 0x5 classid 1:20
(4)显示现有ipchains的状况
#ip ipchains -L
Chain input (policy ACCEPT):
target prot opt source destination ports
- all ------ anywhere anywhere n/a
- all ------ anywhere anywhere n/a
- udp ------ anywhere anywhere any -> 7001:7004
Chain forward (policy ACCEPT):
Chain output (policy ACCEPT):
target prot opt source destination ports
- all ------ anywhere anywhere n/a
- all ------ anywhere anywhere n/a
- udp ------ anywhere anywhere 7001:7004 -> any
- udp ------ anywhere anywhere 7001:7004 -> any
该队列的最大可用带宽为10Mb,实际分配的带宽为 1.1Mb,可接收冲突的发送最长包数目为1字节,最大传输单元(加MAC头)大小为1514字节,优先级别为1,包的平均大小为1500字节,包间隔发送单元的大小为8字节,相应于实际带宽的加权速率为110Kb。
3.建立过滤器
过滤器主要服务于分类。一般只需针对根分类提供一个过滤器,然后为每个子分类提供一个ipchains映射。
(1)应用FW分类器到分类1:10,父分类编号为1:0,过滤协议为IP,标志号(handle)为4,过滤器为基于ipchains。
#tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle 4 fw classid 1:10
(2)应用FW分类器到分类1:20,父分类编号为1:0,过滤协议为IP,过滤器为基于ipchains。
#tc filter add dev eth1 protocol ip parent 1:0 prio 100 handle 5 fw classid 1:20
4.建立ipchains映射
该路由与前面所建立的路由映射一一对应。
(1)由本机发出的电话数据包通过分类1:10转发(分类1:10的速率100Kb)
#ipchains -A output -p udp -i tun0 -s 202.168.200.188/32 7001:7004 -t 0x01 0x10 -m 4
(2)由局域网发出的数据包通过分类1:20转发(分类1:20的速率1.1Mb/s)
#ipchains -A output -i tun0 -s 192.16.188.0/24 -m 5
注意,一般对于流量控制器所直接连接的网段,建议使用IP主机地址流量控制限制,不要使用子网流量控制限制。如一定需要对直连子网使用子网流量控制限制,则在建立该子网的ipchains映射前,需将原先由系统建立的ipchains删除,才可完成相应步骤。
5.监视
主要包括对现有队列、分类、过滤器和路由状况的监视。
(1)显示队列的状况
简单显示指定设备(这里为eth1)的队列状况:
#tc qdisc ls dev eth1
qdisc cbq 1: rate 10Mbit (bounded,isolated) prio no-transmit
详细显示指定设备(这里为eth1)的队列状况:
#tc -s qdisc ls dev eth1
qdisc cbq 1: rate 10Mbit (bounded,isolated) prio no-transmit
Sent 7646731 bytes 13232 pkts (dropped 0, overlimits 0)
borrowed 0 overactions 0 avgidle 31 undertime 0
这里主要显示通过该队列发送了13232个数据包,数据流量为7646731个字节,丢弃的包数目为0,超过速率限制的包数目为0。
(2)显示分类的状况
简单显示指定设备(这里为eth1)的分类状况:
系统采用Linux 2.2.14版内核来支持QoS。首先需要重新编译内核。运行make config,进行如下设置:
EXPERIMENTAL _OPTIONS = y
Class Based Queueing (CBQ) = y
QoS and/or fair queueing = y
CBQ packet scheduler = y
Rate estimator= y
Packet classifier API = y
编译生成新内核:
#make dep
#make clean
#make bzImage
Linux操作系统中,流量控制器(TC)在输出端口处建立一个队列进行流量控制,控制的方式基于目的IP地址、目的子网的网络号及端口号,或者基于源IP地址、源子网的网络号及端口号。
流量控制器TC的基本功能模块为队列、分类和过滤器。Linux内核中支持的队列有Class Based Queue、Token Bucket Flow、CSZ、First In First Out、Priority、TEQL、SFQ、ATM、RED。这里讨论的队列与分类都是基于CBQ(Class Based Queue),过滤器则是基于U32和FW。
配置和使用流量控制器TC,除了建立队列、分类、过滤器和路由外,还需要对现有的队列、分类、过滤器和ipchains进行监视。
基于如图3所示的网络环境,现对中心流量控制服务器进行简单描述,如图4所示。
图4 中心服务器接口图
eth1的配置
假设远端无线网卡(eth1)的IP地址为172.16.32.196,在其上建立一个CBQ队列,控制所有从无线网卡发出的数据包。假设包的平均大小为1000字节,包间隔发送单元的大小为8字节,可接收冲突的发送最长包数目为20字节。
这里采用源地址及源端口号进行控制。假如有三种类型的流量需要控制:
◆ 由本主机发出的业务数据包,源端口为7001:7004,流量带宽控制在100Kb;
◆由本地局域网发出的数据包,IP地址为192.168.1.26,流量带宽控制在1.1Mb;
◆发往子网1,子网号为192.168.1.0,子网掩码为255.255.255.0,流量带宽控制在1Mb。
6. 维护
主要包括对队列、分类、过滤器和路由的增添、修改和删除。
增添动作一般依照队列→分类→过滤器→ipchains的顺序进行;修改动作没有什么特殊要求;删除则依照ipchains→过滤器→分类→队列的顺序进行。
这里采用的
方法是全部删除,然后重新设置。删除命令如下:
#tc qdisc del root dev eth1
#ipchains -F
eth0的配置
eth0的配置与eth1的配置方法一样。配置如下(说明略):
#tc qdisc del root dev eth0
#tc qdisc add dev eth0 root handle 1: cbq bandwidth
10Mbit cell 8 avpkt 1500 mpu 64
#tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth
10Mbit rate 10Mbit allot 1514 cell 8 weight 1Mbit prio 8
maxburst 1 avpkt 1500 bounded
#tc class add dev eth0 parent 1:1 classid 1:10 cbq bandwidth
10Mbit rate 1.4Mbit allot 1514 cell 8 weight 140Kbit prio 8
maxburst 1 avpkt 1500 bounded isolated
#tc filter add dev eth0 protocol ip parent 1:0 prio 100 handle 3 fw classid 1:10
#ipchains -A output -i eth0 -d 0.0.0.0/0 -m 3
通过对企业流量控制服务器的分析,可以对Linux系统进行简单改造,以实现对一些特殊业务的流量预分配和业务保证。