linux网络路由管理之三(TC 流量控制工具原理介绍)

tc是用来提供流量控制的强大工具,自己在进行DDoS攻击模拟、网络负载测试中一直使用!

简单概要

#简介
	netem是linux内核版本提供的一个网络模拟功能模块
	tc 是 Linux 系统中的一个工具,全名为traffic control(流量控制)。tc 可以用来控制 netem 的工作模式
	如果想使用 netem ,需要至少两个条件,一个是内核中的 netem 功能被包含,另一个是要有 tc 。

#原理
	TC用于Linux内核的流量控制,主要是通过在输出端口处建立一个队列来实现流量控制。
	Linux 流量控制方法,控发不控收 , 所以只能对产生瓶颈网卡处的发包速率进行控制 , 而网络瓶颈分析亦为 Linux 网络流控的第一步,Linux流量控制主要是在输出接口排列时进行处理和实现的。

#Linux 流量控制过程分二种:
	队列控制:即 QOS, 瓶颈处的发送队列的规则控制,常见的有 SFQ PRIO
	流量控制:即带宽控制 , 队列的排队整形, 一般为 TBF HTB 

#Linux 流量控制算法分二种:
	无类算法:用于树叶级无分支的队列,例如:SFQ
		队列控制的无类算法 SFQ(随机公平队列)
		流量控制的无类算法 TBF(令牌桶过滤器)
		先进先出先入先出 pfifo_fast/(bfifo_fast)

	分类算法:用于多分支的队列,例如:PRIO CBQ HTB
		队列控制的分类算法 PRIO(优先级调度程序)
		流量整形的分类算法 CBQ(基于类的排队)
		流量整形的分类算法 HTB(分层令牌桶)

#pfifo_fast:
    FIFO算法构成所有Linux网络接口(pfifo_fast)上默认qdisc的基础。它不对数据包进行整形或重新排列。它只是在接收并排队后尽快传输数据包。这也是在所有新创建的类中使用的qdisc,直到另一个qdisc或一个类替换FIFO。
但是,真实的FIFO qdisc必须具有大小限制(缓冲区大小),以防止它无法在接收包时尽快使数据包出队的情况下溢出。Linux实现了两个基本的FIFO qdisc,一个基于字节,一个基于数据包。无论使用哪种FIFO,队列的大小都由参数limit定义 。对于pfifo,该单元被理解为分组,而对于bfifo,该单元被理解为字节。

#TBF:
    它只是对接口上传输的流量进行整形。为了限制数据包从特定接口出队的速度,TBF qdisc是理想的解决方案。它只是将传输的流量减慢到指定的速率。仅在有足够的令牌可用时才发送数据包。否则,数据包将被延迟。以这种方式延迟数据包会将人为延迟引入数据包的往返时间

#HTB:
    HTB将令牌和存储桶的概念与基于类的系统和过滤器一起使用,以实现对流量的复杂而细粒度的控制。通过复杂的 借用模型,HTB可以执行各种复杂的流量控制技术。立即使用HTB的最简单方法之一就是整形。
通过了解令牌和存储桶或掌握TBF的功能,HTB应该仅仅是一个逻辑步骤。该排队规则允许用户定义所使用的令牌和存储桶的特性,并允许用户以任意方式嵌套这些存储桶。与分类方案结合使用时 ,可以非常精细的方式控制流量。
以下是使用tc工具在命令行上显示HTB语法的示例输出。


简单使用:以下功能一般是基于无类队列,可完成如下功能如下(故障模拟)

1:模拟延迟传输(以使用netem(Token Bucket Filter)为例)
	#该命令将 eth0 网卡的传输设置为延迟100毫秒发送
	tc qdisc add dev eth0 root netem delay 100ms

	tc qdisc del dev eth0 root netem delay 100ms

	#该命令将 ens33 网卡的传输设置为延迟 100ms ± 10ms (90 ~ 110 ms 之间的任意值)发送,真实情况延迟值不会这么精确,会存在波动,用该命令来模拟出带有波动性的延迟值
	tc qdisc add dev ens33 root netem delay 100ms 10ms
	#该命令将 ens33 网卡的传输设置为100ms,同时,大约有30%的包会延迟±10ms 发送。进一步加强波动的随机性
	tc qdisc add dev ens33 root netem delay 100ms 10ms 30%

2:模拟网络丢包(以netem为例)
	#该命令将 ens33 网卡的传输设置为随机丢掉 1% 的数据包。
	tc qdisc add dev ens33 root netem loss 5%
	#设置丢包的成功率,该命令将 ens33 网卡的传输设置为随机丢掉 1% 的数据包,成功率为 30% 。
	tc qdisc add dev ens33 root netem loss 1% 30%


3. 模拟包重复
	#该命令将 ens33 网卡的传输设置为随机产生 1% 的重复数据包 。
	tc qdisc add dev ens33 root netem duplicate 1%
        

4. 模拟包损坏
	#该命令将 ens33 网卡的传输设置为随机产生 0.2% 的损坏的数据包 。 (内核版本需在2.6.16以上)
	tc qdisc add dev ens33 root netem corrupt 0.2%
        

5. 模拟包乱序
	#该命令将 ens33 网卡的传输设置为:有 25% 的数据包(50%相关)会被立即发送,其他的延迟 10 秒。
	tc qdisc change dev ens33 root netem delay 10ms reorder 25% 50%
	#该命令会在一定程度上打乱发包的次序
	tc qdisc add dev ens33 root netem delay 100ms 10ms

http://www.tldp.org/HOWTO/html_single/Traffic-Control-HOWTO/
https://www.ibm.com/developerworks/cn/linux/1412_xiehy_tc/
http://codeshold.me/2017/01/tc_detail_inro.html
https://wenku.baidu.com/view/f02078db50e2524de5187e45.html
https://lartc.org/howto/lartc.cookbook.ultimate-tc.html#AEN2233

TC命令规则,及语法

#Linux流量控制主要分为建立队列,建立分类和建立过滤器三个方面。
	1:争对物理接口设备,建立队列(QDisc)
	2:建立分类(Class)
	3:建立过滤器(FIlter)
	4:最后与过滤器相配合,建立特定的路由表

#命令规则:
	1:所有的QDisc,类和过滤器都有ID。
	2:ID可以手工设置,也可以有内核自动分配。
	3:ID由一个主序列号和一个从序列号组成,两个数字之间用一个冒号分开。

#流量控制处理对象
	QDISC:(排队规则,队列)	一个QDisc会被分配一个主序列号,称为句柄(handle),然后把从序列号作为类的命名空间。句柄采用像“10:” 一样的表达方式。习惯上,需要为有子类的QDisc显式地分配一个句柄。
	CLASS:(类别)		在同一个QDisc里面的类共享这个QDisc的主序列号,但是每个类都有自己的从序列号,叫做类识别符(classid)。类识别符只与父QDisc有关,和父类无关。类的命名习惯和QDisc的相同,编号小的优先。
	FILTER:(过滤器)		过滤器的ID有三部分,只有在对过滤器进行散列组织才会用到。详情请参考tc-filters手册页。


#TC命令:
	add:	在一个节点里加入一个队列、类、过滤器。添加时,需要传递一个祖先作为参数,传递参数时既可以使用ID也可以直接传递设备的根。如果要建立一个队列规定或者过滤器,可以使用句柄(句柄)来命名;如果要建立一个类,可以使用类识别符(classid)来命名。
	del:	删除有某个句柄(句柄)指定的QDisc,根QDisc(root)也可以删除。被删除QDisc上的所有子类以及附属于各个类的过滤器都会被自动删除。
	change:以替代的方式修改某些附加。另外句柄(句柄)和祖先不能修改其他,更改命令的语法和添加命令相同。
	replace:对一个现有的常规进行近于原子操作的删除/添加。如果中断不存在,这个命令就会建立例程。
	link:	仅适用于DQisc,替代一个现有的例程。

#语法简览
	tc qdisc [ add | change | replace | link ] dev DEV [ parent qdisc-id | root ] [ handle qdisc-id ] qdisc [ qdisc specific parameters ]
	tc class [ add | change | replace ] dev DEV parent qdisc-id [ classid class-id ] qdisc [ qdisc specific parameters ]
	tc filter [ add | change | replace ] dev DEV [ parent qdisc-id | root ] protocol protocol prio priority filtertype [ filtertype specific parameters ] flowid flow-id
	tc [-s | -d ] qdisc show [ dev DEV ]
	tc [-s | -d ] class show dev DEV tc filter show dev DEV

#示例
        #tc qdisc add dev ens33 root tbf rate 100mbit latency 50ms burst 1000
        #tc qdisc change dev ens33 root tbf rate 200mbit latency 50ms burst 1000
        #tc qdisc change dev ens33 root tbf rate 300mbit latency 50ms burst 1000
        #tc qdisc del dev ens33 root tbf rate 300mbit latency 50ms burst 1000

#流量控制包括以下4种方式
1:SHAPING(限制)
	#当流量被限制,它的传输速率就被控制在某个值以下。限制值可以大大小于有效带宽,这样可以平滑突发数据流量,使网络更为稳定。shaping(限制)只适用于向外的流量。

2:SCHEDULING(调度)
	#通过调度数据包的传输,可以在带宽范围内,按照优先级分配带宽。SCHEDULING(调度)也只适于向外的流量。

3:POLICING(策略)
	#SHAPING用于处理向外的流量,而POLICIING(策略)用于处理接收到的数据。

4:DROPPING(丢弃)
	#如果流量超过某个设定的带宽,就丢弃数据包,不管是向内还是向外。

实列一:WEB 服务器的流量控制为 5Mbps,SMTP 流量控制在 3Mbps 上 . 而且二者一共不得超过 6Mbps, 互相之间允许借用带宽

实现方法一:使用CBQ进行实现
#这里用CBQ来实现,将一个cbq绑定到网络物理设备eth0上,其编号为1:0;网络物理设备eth0的实际长度为100 Mbit,包的平均大小为1000字节;包间隔发送单元的大小为8个字节,最小传输包大小为64个字节。
   tc qdisc add dev eth0 root handle 1:0 cbq bandwidth 100Mbit avpkt 1000 cell 8 mpu 64

#这部分按惯例设置了根为 1:0, 并且绑定了类 1:1. 也就是说整个带宽不能超过 6Mbps. 优先级为8,最大传输单元加MAC头的大小为1514字节,包的平均大小为1000字节,包间隔发送单元的大小为8字节
   tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 100Mbit rate 6Mbit weight 0.6Mbit prio 8 allot 1514 cell 8 maxburst 20 avpkt 1000 bounded 

#建立2 个类 . 注意我们如何根据带宽来调整 weight 参数的 . 两个类都没有配置成"bounded", 但它们都连接到了类 1:1 上 , 而 1:1 设置了"bounded". 所以两个类的总带宽不会超过 6Mbps.
#别忘了同一个 CBQ 下面的子类的主号码都必须与 CBQ 自己的号码相一致 !
   tc class add dev eth0 parent 1:1 classid 1:3 cbq bandwidth 100Mbit rate 5Mbit weight 0.5Mbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000 
   tc class add dev eth0 parent 1:1 classid 1:4 cbq bandwidth 100Mbit rate 3Mbit weight 0.3Mbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000 

#缺省情况下 , 两个类都有一个 FIFO 队列规定 . 但是我们把它换成 SFQ 队列 , 以保证每个数据流都公平对待 . 
   tc qdisc add dev eth0 parent 1:3 handle 30: sfq
   tc qdisc add dev eth0 parent 1:4 handle 40: sfq

#建立过滤器,根据端口来表示WEB流量,以及SMTP流量
   tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip sport 80 0xffff flowid 1:3
   tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip sport 25 0xffff flowid 1:4


#测试完成后,若是要清除你的配置
   tc qdisc del dev eth0 root handle 1:0 cbq bandwidth 100Mbit avpkt 1000 cell 8 mpu 64



实现方法二:使用HTB进行实现
#这里用HTB来实现
   tc qdisc add dev eth0 root handle 1: htb default 30 
   tc class add dev eth0 parent 1: classid 1:1 htb rate 6mbit burst 15k 
   tc class add dev eth0 parent 1:1 classid 1:10 htb rate 5mbit ceil 6mbit burst 15k
   tc class add dev eth0 parent 1:1 classid 1:20 htb rate 3mbit ceil 6mbit burst 15k 
   #rate: 是一个类保证得到的带宽值.如果有不只一个类,请保证所有子类总和是小于或等于父类.
   #ceil: ceil是一个类最大能得到的带宽值
   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 
   #perturb:是多少秒后重新配置一次散列算法,默认为10秒
   #sfq,他可以防止一个段内的一个ip占用整个带宽

#添加过滤器 , 直接把流量导向相应的类 : 
   U32="tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32"
   $U32 match ip sport 80 0xffff flowid 1:10 
   $U32 match ip dport 25 0xffff flowid 1:20


实现方法三:使用HTB进行实现(推荐使用)
   tc qdisc add dev eth0 root handle 1: htb default 21
   tc class add dev eth0 parent 1: classid 1:2 htb rate 6mbit ceil 6mbit
   tc class add dev eth0 parent 1: classid 1:21 htb rate 5mbit ceil 6mbit
   tc class add dev eth0 parent 1:2 classid 1:22 htb rate 3mbit ceil 6mbit
   tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip sport 80 0xffff flowid 1:21
   tc filter add dev eth0 protocol ip parent 1:2 prio 1 u32 match ip dport 25 0xffff flowid 1:22
   #这里为根队列1创建一个根类别,即1:2,其中1:2对应6Mbit的数据流。然后,在1:2中,创建两个子类别1:21和1:22,分别对应WWW和E-mail数据流。由于类别1:21和1:22是类别1:2的子类别,因此他们可以共享分配的86Mbit带宽。同时,又确保当需要时,自己的带宽。

Linux 流量控制之 U32 过滤规则

#在10: 节点添加一个过滤规则,优先权1: 凡是去往22口(精确匹配)的IP数据包,发送到频道10:1.. 
   tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match ip dport 22 0xffff flowid 10:1 

#在10: 节点添加一个过滤规则,优先权1: 凡是来自80口(精确匹配)的IP数据包,发送到频道 10:1.. 
   tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match ip sport 80 0xffff flowid 10:1 

#在eth0 上的 10: 节点添加一个过滤规则,它的优先权是2: 凡是上二句未匹配的IP数据包,发送到频道10:2.. 
   tc filter add dev eth0 protocol ip parent 10: prio 2 flowid 10:2 

#去往4.3.2.1的包发送到频道10:1其它参数同上例
   tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip dst 4.3.2.1/32 flowid 10:1 

#来自1.2.3.4的包发到频道10:1 
   tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip src 1.2.3.4/32 flowid 10:1 

#凡上二句未匹配的包送往10:2 
   tc filter add dev eth0 protocol ip parent 10: prio 2 flowid 10:2 

#可连续使用match,匹配来自1.2.3.4的80口的数据包
   tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip src 4.3.2.1/32 match ip sport 80 0xffff flowid 10:1 


#根据源/目的地址
	'match ip src 1.2.3.0/24'
	'match ip dst 4.3.2.0/24'

#单个IP地址 
	'match ip 1.2.3.4/32'

#根据源/目的端口 , 所有IP协议
	'match ip sport 80 0xffff' 0xffff 表所有数据包
	'match ip dport 80 0xffff'

#根据 IP 协议 (tcp, udp, icmp, gre, ipsec)  /etc/protocols 文件里有协议号
	'match ip protocol 1 0xff'



#根据 fwmark	
	iptables -A PREROUTING -t mangle -i eth0 -j MARK --set-mark 6 
	tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle 6 fw flowid 1:1	

注 :handle 根据过滤器的不同 , 含义也不同

#按 TOS 字段
	tc filter add dev ppp0 parent 1:0 protocol ip prio 10 u32 match ip tos 0x10 0xff

#flowid 1:4 选择交互和最小延迟的数据流 匹配大量传输 , 使用"0x08 0xff".
	tc filter add dev eth0 protocol ip parent 1:0 pref 10 u32 match u32 00100000 00ff0000

查看现有变量,分类,过滤器和路由的状况

#显示队列的状况
	tc qdisc ls dev eth0		#简单显示
	tc -s qdisc ls dev eth0		#详细显示(等同于 tc -s qd sh dev eth0)
    
#显示分类的状况
	tc class ls dev eth0		#简单显示
	tc -s class ls dev eth0		#详细显示(等同于 tc -s cl ls dev eth0)

#显示过滤器的状况
	tc filter ls dev eth0		#简单显示
	tc -s filter ls dev eth0	#详细显示(等同于 tc -s fi ls dev eth0)

#流量控制模拟
        tc qd add dev eth1 root handle 1: tbf rate 256kbit burst 10000 latency 50ms 
        速率 256kbit  突发传输 10k  最大延迟 50ms 
        tc qd del dev eth1 root 删除

学习实列一

#清理现有的下行和上行qdiscs,隐藏错误
tc qdisc del dev eth0 root    2> /dev/null > /dev/null
tc qdisc del dev eth0 ingress 2> /dev/null > /dev/null


#安装根HTB(root htb),将默认流量指向1:20:
tc qdisc add dev eth0 root handle 1: htb default 20
   

#塑造为$上行速度的一切 - 这可以防止巨大的队列中的,破坏延迟的DSL调制解调器:
tc class add dev eth0 parent 1: classid 1:1 htb rate 220kbit burst 6k


#高优先级1:10:
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 220kbit burst 6k prio 1

#较低的优先级1:20,批量和默认类别1:20-获得的流量略少,
tc class add dev eth0 parent 1:1 classid 1:20 htb rate [9*220/10]kbit burst 6k prio 2


#都获得随机公平性:
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

#TOS最小延迟(ssh,NOT scp)在1:10中:
tc filter add dev eth0 parent 1:0 protocol ip prio 10 u32 match ip tos 0x10 0xff  flowid 1:10

#ICMP(IP协议1)在交互式类1:10中,所以我们可以进行测量并打动我们的朋友:
tc filter add dev eth0 parent 1:0 protocol ip prio 10 u32 \
	match ip protocol 1 0xff flowid 1:10


#为了加快上传过程中的下载速度,请在其中放入ACK数据包
tc filter add dev eth0 parent 1: protocol ip prio 10 u32 \
   match ip protocol 6 0xff \
   match u8 0x05 0x0f at 0 \
   match u16 0x0000 0xffc0 at 2 \
   match u8 0x10 0xff at 33 \
   flowid 1:10


#将下载速度降低到略低于实际速度以防止,在我们的ISP排队调一下看看你能调多高。ISP往往会有*大*队列来确保大的下载速度
tc qdisc add dev eth0 handle ffff: ingress

# filter *everything* to it (0.0.0.0/0), drop everything that's
# coming in too fast:
tc filter add dev eth0 parent ffff: protocol ip prio 50 u32 match ip src \
   0.0.0.0/0 police rate 800kbit burst 10k drop flowid :1
如果最后两行出现错误,请将您的tc工具更新为较新的版本!

学习实列二

tc qdisc del dev $DEV root    2> /dev/null > /dev/null
tc qdisc del dev $DEV ingress 2> /dev/null > /dev/null

tc qdisc add dev $DEV root handle 1: cbq avpkt 1000 bandwidth 10mbit 

tc class add dev $DEV parent 1: classid 1:1 cbq rate ${UPLINK}kbit allot 1500 prio 5 bounded isolated

tc class add dev $DEV parent 1:1 classid 1:10 cbq rate ${UPLINK}kbit allot 1600 prio 1 avpkt 1000

tc class add dev $DEV parent 1:1 classid 1:20 cbq rate $[9*$UPLINK/10]kbit allot 1600 prio 2 avpkt 1000

tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10

tc filter add dev $DEV parent 1:0 protocol ip prio 10 u32 match ip tos 0x10 0xff  flowid 1:10

tc filter add dev $DEV parent 1:0 protocol ip prio 11 u32 match ip protocol 1 0xff flowid 1:10

tc filter add dev $DEV parent 1: protocol ip prio 12 u32 match ip protocol 6 0xff \
   match u8 0x05 0x0f at 0 \
   match u16 0x0000 0xffc0 at 2 \
   match u8 0x10 0xff at 33 \
   flowid 1:10
   
tc filter add dev $DEV parent 1: protocol ip prio 13 u32 match ip dst 0.0.0.0/0 flowid 1:20

tc qdisc add dev $DEV handle ffff: ingress

tc filter add dev $DEV parent ffff: protocol ip prio 50 u32 match ip src \
   0.0.0.0/0 police rate ${DOWNLINK}kbit burst 10k drop flowid :1

声明:本文为原创,作者为 辣条①号,转载时请保留本声明及附带文章链接:https://boke.wsfnk.com/archives/882.html

最后编辑于:2019/11/7作者: 辣条①号

暂无评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注