Linux下使用TC模拟网络延迟/带宽

TC

Traffic Control.
tc被用来在linux内核中进行流量控制。
tc使用三类对象对流量进行过滤、分组、排队,分别是filterclassqdisc.

TC的语法较为复杂,已有的教程大多仅限于netem这个classless qdisc,无法更深入的对流量进行控制。我看了很多文档才大概明白怎么使用,下面简单介绍一些基础知识和我用到的一些操作,详细内容见参考部分的链接。

handle

qdisc和filter用handle选项命名,class用classid选项命名。

major:minor

  1. 一般major从1开始,和qdisc有关;而minor只与class有关,只要唯一可以任意命名。(ffff:0保留给ingress qdisc
  2. class的minor必须大于0,qdisc的minor必须为0(qdisc也可以省略minor,默认为0)。
  3. 同属一个qdisc的class拥有相同的major。

tc通过这种命名方式形成一棵的结构。

qdisc

root/egress qdisc: 功能强大,主要使用这个。
ingress qdisc: 功能有限,只有policer。

每个interface都有一个默认的qdisc,pfifo_fast,可以替换。

qdisc可以分为两类,分别是classless qdiscclassful qdisc

classless qdisc

不能包含class。比如netem

可以参考这里:http://tldp.org/HOWTO/Traffic-Control-HOWTO/classless-qdiscs.html

FIFO, First-In First-Out (pfifo and bfifo)

简单的先进先出队列,不做其他任何操作。
需要指定队列的size,pfifobfifo分别以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对流量进行细分。比如HTBCBQ

HTB

参考这里:http://tldp.org/HOWTO/Traffic-Control-HOWTO/classful-qdiscs.html#qc-htb

大概就是基于令牌控制traffic rate,child可以向parent借用令牌,暂时的超出自己的rate。
下面是一些参数:

  • default: 将没有被分类的traffic放到default指定的class/qdisc。默认是0,不做任何软件层面的限制,交给硬件处理。
  • 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。
第三行是匹配的语法,分别是字节的长度valuebitmaskoffset,上面的意思就是:从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

一些参考命令

# TODO

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:
IP header

ToS是在RFC791中提出的,但好像并没有使用这些bit。
RFC791-ToS

之后在RFC1349中对这个字段进行了修改:
RFC1349-ToS
再之后又在RFC2474中进行了大的修改:
RFC2474-DSCP | ECN

交互式应用的设置为:0x10,也就是bit4bit_4设置为1.

参考这里:https://lartc.org/howto/lartc.qdisc.classless.html

tcng

好像是对tc复杂命令的简化。

TODO: http://tldp.org/HOWTO/Traffic-Control-tcng-HTB-HOWTO/

参考

  1. http://man7.org/linux/man-pages/man8/tc.8.html
  2. http://man7.org/linux/man-pages/man8/tc-u32.8.html
  3. http://linux-tc-notes.sourceforge.net/tc/doc/cls_u32.txt
  4. http://tldp.org/HOWTO/Traffic-Control-HOWTO/index.html
  5. https://lartc.org/howto/lartc.qdisc.classless.html
  6. https://github.com/magnific0/wondershaper
  7. https://en.wikipedia.org/wiki/IPv4#Header
  8. https://en.wikipedia.org/wiki/Type_of_service
  9. https://unix.stackexchange.com/questions/212503/how-to-discriminate-between-ssh-and-scp-for-qos-in-openwrt-and-other-systems
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章