linux通过tc控制网络QoS(1)

tc是linux traffic control的简称,原理是在协议栈出包的时候,通过qdisc (Queue Discipline)和 filter 机制把不同规则定义的流放到不同class的子qdisc中(对于classful qdisc是这样,对于classless qdisc只有一个root qdisc)。网上关于tc的资料很多,本篇不去讨论tc的各种qdisc, class, filter或者不同的classful/classless class的使用,而只针对HTB+iptables/ebtables的方式做一些研究

HTB是classful qdisc的一种实现,latrc.org推荐使用HTB来代替CBQ作为classful qdisc的配置,在HTB中,区分不同流的方法很多,比如u32 selector,classify,mark等。先来看lartc.org那篇著名的文档Linux Advanced Routing&Traffic Control HOWTO里的例子

#tc qdisc add dev eth0 root handle 1: htb default 30

#tc class add dev eth0 parent 1: classid 1:10 htb rate 5mbit burst 15k

#tc class add dev eth0 parent 1: classid 1:20 htb rate 3mbit ceil 5mbit burst 15k

#tc class add dev eth0 parent 1: classid 1:30 htb rate 500kbit ceil 1mbit burst 15k

#tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10

#tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10

#tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10

这个例子的场景是,把eth0的出流量分成三类,分别限制rate, ceil带宽和burst流量(具体值的含义参考HTB相关文档,其中1:30为缺省),对于每一类流量而言,又用一个sfq的子qdisc来保证公平。这么做的原因比如很多进程的出流量都可以match到classid 1:10,这是这些进程公用带宽,通过一个sfq来保证不会有进程的带宽被饿死。

最后这个例子通过一个u32 selector来区分流量,可以看出,HTTP流量被分到了class 1:10,SMTP流量被分到了 class 1:20,其余都在default class 1:30,所有共享HTTP流量的进程采用公平方式共享

我们可以用u32 match的方式来匹配不同的流,这里不废话了,有兴趣去看上面提到的那个文档。个人认为u32 match虽然可以 match 不同的协议如ip tcp icmp,并match诸如IP段,端口等,但终究不如iptables更灵活,同时u32 match对于二层无感,这都使得通过iptables/ebtables mark目标来做filter更加灵活可控


举两个例子,首先是tc + iptables来对ip地址192.168.1.1的出包做QoS,限制bps为2Mbit,允许突发bps最高到5Mbit

#tc qdisc add dev eth0 root handle 1: htb default 100

#tc class add dev eth0 parent 1: classid 1:10 htb rate 2Mbit ceil 5Mbit

#iptables -t mangle -A POSTROUTING -s 192.168.1.1 -j CLASSIFY --set-class 1:10


tc + iptables只能对三层流量做QoS,如果是二层流量,只能通过tc + ebtables了,下面的例子用来限制arp报文的bps

#tc qdisc add dev eth0 root handle 1: htb default 100

#tc class add dev eth0 parent 1: classid 1:20 htb rate 1Kbit ceil 5Kbit

#tc filter add dev eth0 prio 32 protocol arp handle 127 fw classid 1:10


tc 同时还可以对入包进行QoS,这时候如果要对入包流量进行filter的话,只有靠 u32 match 这个模块了

#tc qdisc add dev vif8.0 ingress

#tc filter add dev vif8.0 parent ffff: protocol ip prio 64 u32 match ip src 0.0.0.0/0 police rate 100bps burst 1k drop classid 16

ingress的classid永远都是ffff,所以每次添加filter,其parent都是ffff:

protocol可以是ip或者arp,如果后面按字节进行u32 match,这里protocol其实没啥用

prio表示优先级,这个值必须要设

由于protocol设置了ip,这里可以使用ip src, ip dst, 以至于tcp port等参数设置filter规则。ip src 0.0.0.0/0 表示匹配任意ip

police rate 100bps burst 1k drop,表示一个流控策略,rate 100bps表示100 Bytes per second,burst是一个buffer值,允许暂时超过rate的包流量,drop表示超过了流控的包丢弃

classid也可以是flowid,表示一个filter的标识,必须设


如果要match所有的arp包,

#tc filter add dev vif8.0 parent ffff: protocol arp prio 64 u32 match ip src 0.0.0.0/0 police rate 100bps burst 1k drop classid :16

直接把protocol设置成arp,后面的ip src其实被忽略掉了

或者

#tc filter add dev vif8.0 parent ffff: protocol ip prio 64 u32 match u16 0x0806 0xffff at -2 police rate 100bps burst 1k drop classid :16

通过u32 match,匹配协议头部的4个字节。这里的位置为0指向ip包的payload,所以协议首部是从-2开始到0的两个u16加起来的总共四个字节。


我们还可以通过u32 match来匹配mac地址

#tc filter add dev vif8.0 parent ffff: protocol arp prio 64 u32 match u16 0x0001 0xffff at -4 match u32 0x00163e00 0xffffffff at -8 police rate 100bps burst 512 drop classid :16

这时只有源mac为00:16:3e:00:00:01的arp包才会match


tc规则的删除如下

#tc filter del dev vif8.0 parent ffff: pref 64

#tc qdisc del dev vif8.0 ingress


还有个更简单的flush某个设备的tc规则的方法,即调用

tc qdisc del dev xxxx root


你可能感兴趣的:(Linux,服务器系统)