TC的使用实例说明
下面我们提供一个利用TC来实现对在一个Linux服务器上的两个虚拟主机实行不同的带宽策略的例子。在该例中,我们将讲述如何配置和测试TC。
编译内核
至于如何编译一个新的内核已经不属于本章节讨论的范围,我们假设你已经知道如何重新编译一个内核。
编译内核时将以下几个内核选项选中:"kernel/User netlink socket"和"Netlink device emulation"。这样TC就可以利用netlink来与内核传送信息。同时将所有的排队算法选上,位于包括
"Fair queueing"
"CBQ packet scheduler"
"CSZ packet scheduler"
"the simples PRIO pseudoscheduler"
"RED queue"
"SFQ queue"
"TBF queue"
"QoS support"
"rate estimator"
"packet classifier API"
"routing-tables-based classifier"
"U32 classifier"
"special RSVP classifier and special RSVP classifier for IPv6"。
选中这些选项以后,按正常的编译内核步骤编译内核,然后安装新内核,并用新内核重新启动系统。
编译TC软件包
可以在下面的地址下载到我们需要的软件,然后按照软件包里的说明编译它:
ftp://linux.wauug.org/pub/net/ip-routing/iproute2-current.tar.gz
通常我们要做的只是简单的输入make就可以了。
TC 的设定
图1. CBQ 树图
图一是我们将配置的一个系统的简单的树形图示范。两个叶子节点从父节点分配带宽,IP地址10.0.0.10(标识符1:1)和地址10.0.0.11(标识符1:2)是接口eth0上的IP别名,它们共同分享父节点(标识符1:0)的带宽。这个例子里面只涉及到了对一个接口上的流量控制,大家可以仿照这个例子构造自己感兴趣的控制多个接口设备的配置。
配置QoS特性的第一步就是将qdisc加入到一个接口上,例如本例子:
qdisc add dev eth0 root handle 1: ...
然后定义你需要区别的类别。不同的类别对应不同的流量控制类型。我们的例子中,使用如下的语句:
tc class add dev eth0 parent 1:0 classid X:Y ...
我们的例子中只使用了一层深的类别树。当然,我们可以构造多层深度的复杂的树,基本的原则是一样的:就是一个子节点(如图1所示)继承一个父节点的资源同时进一步根据类的定义去分配父节点的资源。例如,父类1:0拥有该设备的全部带宽,那么子节点1:1不可能获得超过10Mbits的带宽,当然本例子中是限制为1Mbps。
最后定义"IP分组--类别"的映射规则,用来告诉系统的分类器,经过路由器调度的某IP分组该对应什么类型。首先,将一个分类器与输出接口关联起来:
filter add dev eth0 parent 1:0 protocol ip ...
然后,定义"IP分组--类别"的映射规则。本例子中,将利用IP分组的源地址来作为分类的关键词。 下面的脚本完成了这个功能。关于脚本中TC等命令的参数,大家可以参考随机的文档,这里限于篇幅,不做介绍了。
#! /bin/sh
#path to tc and the ip utilities;
#change to reflect yours.
TC=./iproute2/tc/tc
IP=./iproute2/ip/ip
##################################################
#Addresses to be aliased
#change or add more to reflect yours
#
ALIAS1=10.0.0.10
ALIAS2=10.0.0.11
##################################################
# add ip aliasing support
#uncomment if you want to use the ip utility to
#add ip-aliasing for you
#
#$IP addr add $ALIAS1 dev eth0
#$IP addr add $ALIAS2 dev eth0
##################################################
# Attaching a device queue discipline to an
# interface a device queue discipline is
# equivalent almost to a device manager
#
#Attach CBQ to eth0
#Things you might need to change:
# bandwidth -- the bandwidth of the eth0 device
# note it must match the devices real bandwidth
# allot -- it is safe to leave it at the MTU of
# the device
# avpkt -- the average packet size that you
# suspect will be seen safe to leave at 1000
# for Ethernet with MTU of 1514 bytes
# mpu -- minimum packet size
#
$TC qdisc add dev eth0 root handle 1: cbq
bandwidth 10Mbit allot 1514 cell 8 avpkt 1000
mpu 64
##################################################
# Attaching class queue disciplines
# bounded -- it is bound to the rate allocated;
# can borrow even if there is a lot of idle
# bandwidth just sitting there isolated -- cannot
# share its bandwidth to other classes prio is the
# priority assigned 0 being the highest and 7 the
# lowest weight -- safer to leave at 1
# queue discipline setup. Classid 1:1 will have a
# rate of 1Mbps which is bounded.
#
$TC class add dev eth0 parent 1:0 classid 1:1 cbq
bandwidth 10Mbit rate 1Mbit avpkt 1000 prio 5
bounded isolated allot 1514 weight 1 maxburst 21
#rate 1Mbit avpkt 1000 prio 5 bounded allot 1514
#weight 1 maxburst 21
# Classid 1:2 will have a rate of 3Mbps which is
# bounded.
$TC class add dev eth0 parent 1:0 classid 1:2 cbq
bandwidth 10Mbit rate 3Mbit avpkt 1000 prio 5
bounded allot 1514 weight 1 maxburst 21
##################################################
# Define the filter to be attached to eth0
# Create with hash table of 256 slots with ID 1:
#
$TC filter add dev eth0 parent 1:0 protocol ip
prio 5 handle 1: u32 divisor 256
##################################################
# define the criteria for mapping incoming packets
# to classes. Add to the 5th slot of hash table a
# rule to select virtual address ALIAS1 direct it
# to class 1:1
#
$TC filter add dev eth0 parent 1:0 prio 5 u32
ht 1:6: match ip src $ALIAS1 flowid 1:1
# Add to 6th slot of hash table rule to select
# ALIAS2 direct it to class 1:2
$TC filter add dev eth0 parent 1:0 prio 5 u32
ht 1:6: match ip src $ALIAS2 flowid 1:2
## Lookup hash table, if it is not fragmented
## frame. Use protocol as hash key
#
$TC filter add dev eth0 parent 1:0 prio 5 handle
::1 u32 ht 800:: match ip nofrag
offset mask 0x0F00 shift 6
hashkey mask 0x00ff0000 at 8 link 1:
#
#some more examples of how to use u32
# Add to 4th slot of hash table rule to select
# tcp/telnet to 193.233.7.75 direct it to class
# 1:4 and prescribe to fall to best effort,
# if traffic violates TBF (32kbit,5K)
#$TC filter add dev eth1 parent 1:0 prio 5 u32
# ht 1:4: match ip dst 193.233.7.75
# match tcp dst 0x17 0xffff
# flowid 1:4
# police rate 32kbit buffer 5kb/8 mpu 64
# mtu 1514 index 1
## Add to 1st slot of hash table rule to select
## icmp to 193.233.7.75 direct it to class 1:3
## and prescribe to fall to best effort,
## if traffic violate TBF (10kbit,5K)
#$TC filter add dev eth1 parent 1:0 prio 5 u32
# ht 1:4: match ip dst 193.233.7.75
# match tcp dst 0x17 0xffff
# flowid 1:4
# police rate 32kbit buffer 5kb/8 mpu 64
# mtu 1514 index 1
## Add to 1st slot of hash table rule to select
## icmp to 193.233.7.75 direct it to class 1:3
## and prescribe to fall to best effort,
## if traffic violate TBF (10kbit,5K)
#$TC filter add dev eth1 parent 1:0 prio 5 u32
# ht 1:: sample ip protocol 1 0xff
# match ip dst 193.233.7.75 flowid 1:3
# police rate 10kbit buffer 5kb/8 mpu 64
# mtu 1514 index 2
##################################################
#Look at all that we created:
#
echo "---- qdisc parameters ----------"
$TC qdisc ls dev eth0
echo "---- Class parameters ----------"
$TC class ls dev eth0
echo "---- filter parameters ----------"
$TC filter ls dev eth0
测试
我们的例子当中,是有在同一个Linux服务器上有两个虚拟WWW服务器,我们的设定是采用了IP别名,将两个地址同时绑在一个接口上。我们可以用ftp来测试。首先用ftp连接10.0.0.10服务器,我们可以获得大概1Mbps的速率;然后ftp另外的地址10.0.0.11,我们可以获得大概3Mbps的速率。