文章目录
TC
Traffic Control.
tc被用来在linux内核中进行流量控制。
tc使用三类对象对流量进行过滤、分组、排队,分别是filter
,class
,qdisc
.
TC的语法较为复杂,已有的教程大多仅限于
netem
这个classless qdisc
,无法更深入的对流量进行控制。我看了很多文档才大概明白怎么使用,下面简单介绍一些基础知识和我用到的一些操作,详细内容见参考部分的链接。
handle
qdisc和filter用handle
选项命名,class用classid
选项命名。
major:minor
- 一般major从1开始,和qdisc有关;而minor只与class有关,只要唯一可以任意命名。(
ffff:0
保留给ingress qdisc
) - class的minor必须大于0,qdisc的minor必须为0(qdisc也可以省略minor,默认为0)。
- 同属一个qdisc的class拥有相同的major。
tc通过这种命名方式形成一棵树
的结构。
qdisc
root/egress qdisc
: 功能强大,主要使用这个。
ingress qdisc
: 功能有限,只有policer。
每个interface都有一个默认的qdisc,pfifo_fast
,可以替换。
qdisc
可以分为两类,分别是classless qdisc
和classful qdisc
。
classless qdisc
不能包含class。比如netem
。
可以参考这里:http://tldp.org/HOWTO/Traffic-Control-HOWTO/classless-qdiscs.html
FIFO, First-In First-Out (pfifo and bfifo)
简单的先进先出队列,不做其他任何操作。
需要指定队列的size,pfifo
和bfifo
分别以packet和byte作为size的单位。
SFQ, Stochastic Fair Queuing
随机公平队列。
由多个FIFO组成,通过哈希函数将packet送入不同的FIFO。
为了保证哈希函数的选取的公平性,通过perturb
参数周期性的改变哈希函数。
netem
网上大多都是关于netem的资料,这里简单介绍一下。
netem是对tc的增强,可以增加延时、丢包等。
# set latency: 100ms
sudo tc qdisc add dev eth0 root netem delay 100ms
也可以增加一些latency的波动,设置丢包率等,这里不再介绍。
classful qdisc
可以包含class,继而通过filter对流量进行细分。比如HTB
、CBQ
。
HTB
参考这里:http://tldp.org/HOWTO/Traffic-Control-HOWTO/classful-qdiscs.html#qc-htb
大概就是基于令牌控制traffic rate,child可以向parent借用令牌,暂时的超出自己的rate。
下面是一些参数:
- default: 指定minor-id, 将没有被分类的traffic放到default指定的class。默认是0不经过任何class交给发给网卡。
- rate:期望的最小速率
- ceil:期望的最大速率(通过借用令牌)
- burst: size
- cburst:size
- prio:越小优先级越高
class
每一个class都有一个默认的qdisc,FIFO。可以替换成其它的qdisc。
class上可以挂载多个class,或者挂载一个qdisc。
leaf class挂载一个qdisc,不能再挂载class。
注意qdisc只能挂载同类的class。
filter
filter可以挂载到classful qdisc或者class。
u32是可以逐字节进行比较、过滤的一个过滤器,非常强大,需要使用者熟悉各种协议的格式。
u32
参考:http://linux-tc-notes.sourceforge.net/tc/doc/cls_u32.txt
以下面这个例子说明语法:
tc filter add dev eth0 parent 999:0 protocol ip prio 99 u32 \
classid 1:1 \
match u32 0xc0a80800 0xffffff00 at 12
第一行不再说明,所有的filter都差不多。
第二行指定如果traffic匹配该过滤器,就将traffic送入 1:1标识的class。
第三行是匹配的语法,分别是字节的长度
、value
、bitmask
、offset
,上面的意思就是:从IP packet从0偏移12个字节开始,取32个bit,将这32个bit与掩码0xffffff00
进行异或,若果结果等于value0xc0a80800
,那么该packet就匹配成功。
由于需要知道各个字段的偏移才能使用这个过滤器,较为麻烦,u32提供了一些语法糖,但最终还是转换为上面的匹配方式进行过滤。
举几个例子:
tc filter add dev eth0 parent 999:0 protocol ip prio 99 u32 \
classid 1:1 \
match ip src 192.168.8.0/24
tc filter add dev eth0 parent 999:0 protocol ip prio 99 u32 \
classid 1:1 \
match ip src 192.168.8.0/24 \
match ip tos 0x10 1e
一些参考命令
一般来说最常用的应该就是设置latency和bandwidth了。
sudo tc qdisc add dev $device root handle 1:0 root htb default 2
sudo tc class add dev $device parent 1:0 classid 1:1 htb rate 1000Mbps
sudo tc class add dev $device parent 1:1 classid 1:2 htb rate 5Mbit
sudo tc qdisc add dev $device parent 1:2 handle 2:0 netem delay 20ms
wondershaper
wondershaper是对tc的一个包装,简化了使用,更加方便的控制网卡的上传下载速率,但同时也限制了其他功能。
可以去看一下源码,学习一下如何使用tc 😃
源码中设置了针对ssh的filter,因为不希望交互式的应用被延迟:
# start filters
# TOS Minimum Delay (ssh, NOT scp) in 1:10:
tc filter add dev $IFACE parent 1: protocol ip prio 10 u32 \
match ip tos 0x10 0xff flowid 1:10
去查了一下IP协议的ToS字段,学到了一点别的东西。
先附上IP header:
ToS是在RFC791
中提出的,但好像并没有使用这些bit。
之后在RFC1349
中对这个字段进行了修改:
再之后又在RFC2474
中进行了大的修改:
交互式应用的设置为:0x10
,也就是
b
i
t
4
bit_4
bit4设置为1.
参考这里:https://lartc.org/howto/lartc.qdisc.classless.html
tcng
好像是对tc复杂命令的简化。
TODO: http://tldp.org/HOWTO/Traffic-Control-tcng-HTB-HOWTO/
参考
- http://man7.org/linux/man-pages/man8/tc.8.html
- http://man7.org/linux/man-pages/man8/tc-u32.8.html
- http://linux-tc-notes.sourceforge.net/tc/doc/cls_u32.txt
- http://tldp.org/HOWTO/Traffic-Control-HOWTO/index.html
- https://lartc.org/howto/lartc.qdisc.classless.html
- https://github.com/magnific0/wondershaper
- https://en.wikipedia.org/wiki/IPv4#Header
- https://en.wikipedia.org/wiki/Type_of_service
- https://unix.stackexchange.com/questions/212503/how-to-discriminate-between-ssh-and-scp-for-qos-in-openwrt-and-other-systems
- https://serverfault.com/questions/507658/limit-incoming-and-outgoing-bandwidth-and-latency-in-linux
- https://tonydeng.github.io/sdn-handbook/linux/tc.html