如下图测试拓扑,将两个FTP客户端的总下载流量控制在10Mbps,并且,当同时下载时,将50.2的带宽控制在8Mbps,50.3的带宽控制在2Mbps。带宽空闲时,允许借用。
192.168.50.2
|------------|
| |
| FTP-1 |------|
| | | |------------| |------------|
|------------| | eth0| |eth1 | |
|--------| Qdisc |--------| FTP-Server |
|------------| | | | | |
| | | |------------| |------------|
| FTP-2 |------|
| |
|------------|
192.168.50.3
如下TC配置命令,r2q的值按照MTU=1500,rate=2M计算而来(即quantum=rate/r2q),其中quantum的值不小于MTU。使用filter显式指定192.168.50.2对应的class为1:10。对于FTP客户端192.168.50.3,其对应到默认的class(default 20)。
tc qdisc add dev eth0 root handle 1: htb default 20 r2q 1330
tc class add dev eth0 parent 1: classid 1:1 htb rate 10mbps burst 15k
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 8mbps ceil 10mbps burst 15k
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 2mbps ceil 10mbps burst 15k
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dst 192.168.50.2 flowid 1:10
查询配置如下,可见速率rate转换成了按照比特位表示的值,quantum的值等于rate/r2q,对于2M速率,quantum等于1503,大于MTU值:
/ # tc -d qdisc ls dev eth0
qdisc htb 1: root refcnt 9 r2q 1330 default 20 direct_packets_stat 0 ver 3.17 direct_qlen 1000
/ #
/ # tc -d class ls dev eth0
class htb 1:10 parent 1:1 prio 0 quantum 6015 rate 64Mbit ceil 80Mbit linklayer ethernet burst 15Kb/1 mpu 0b cburst 1600b/1 mpu 0b level 0
class htb 1:1 root rate 80Mbit ceil 80Mbit linklayer ethernet burst 15Kb/1 mpu 0b cburst 1600b/1 mpu 0b level 7
class htb 1:20 parent 1:1 prio 0 quantum 1503 rate 16Mbit ceil 80Mbit linklayer ethernet burst 15Kb/1 mpu 0b cburst 1600b/1 mpu 0b level 0
/ #
/ #
/ # tc -d filter ls dev eth0
filter parent 1: protocol ip pref 1 u32
filter parent 1: protocol ip pref 1 u32 fh 800: ht divisor 1
filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:10
match c0a83202/ffffffff at 16
/ #
关于quantum的值,内核代码如下。对于最底层的class(level等于0),quantum的值需要大于等于1000,小于等于200000。
static int htb_change_class(struct Qdisc *sch, u32 classid,
u32 parentid, struct nlattr **tca,
unsigned long *arg, struct netlink_ext_ack *extack)
{
/* it used to be a nasty bug here, we have to check that node
* is really leaf before changing cl->leaf !
*/
if (!cl->level) {
u64 quantum = cl->rate.rate_bytes_ps;
do_div(quantum, q->rate2quantum);
cl->quantum = min_t(u64, quantum, INT_MAX);
if (!hopt->quantum && cl->quantum < 1000) {
warn = -1;
cl->quantum = 1000;
}
if (!hopt->quantum && cl->quantum > 200000) {
warn = 1;
cl->quantum = 200000;
}
if (hopt->quantum)
cl->quantum = hopt->quantum;
if ((cl->prio = hopt->prio) >= TC_HTB_NUMPRIO)
cl->prio = TC_HTB_NUMPRIO - 1;
}
if (warn)
pr_warn("HTB: quantum of class %X is %s. Consider r2q change.\n",
cl->common.classid, (warn == -1 ? "small" : "big"));
测试完成,删除以上的带宽配置:
tc qdisc del dev eth0 root
内核版本 5.10