tc相关的一些概念

tc(traffic control)是一个应用层工具,它与内核的tc模块共同协作,可以对内核进行流量控制,通过tc可以实现限速、数据包过滤等功能,接下来简单的介绍下tc的关键概念。

qdisc class filter

数据包的发送路径上,当数据包穿过网络协议栈到达网络设备层时,网络设备层并不会直接将数据包送往驱动层,网络设备层会先将数据包放入网络设备的队列中(enqueue),随后再尝试从队列取出数据包(dequeue)再送往驱动。
enqueue/dequeue这样一个过程中,内核可以执行一些规则来控制包的走向,这里说到的规则,在tc的世界里被叫做qdisc,按照官方的解释,qdiscqueueing discipline)叫做队列规则,其实qdisc不止体现了规则的作用,它也能够缓存数据包,enqueue进网卡输出队列的数据包其实是缓存在qdisc上的。
enqueueqdisc的数据包有可能会马上被dequeue然后送往驱动,也有可能暂时存放于qdisc,待到合适的时机再dequeue,数据包最终的结局全都取决于qdisc的逻辑。
比如用下面的命令给ens33网卡添加一个tbf类型的qdisc来给ens33网卡限速:

tc qdisc add dev ens33 handle 10: root tbf rate 10mbps burst 1m limit 1m

enqueue时,若tbf qdisc内部的数据包缓存队列还未满,则数据包会被添加到tbf qdisc内部的缓存队列上,若tbf qdisc内部的缓存队列满了,则enqueue的数据包会被丢弃。
dequeue时,tbf qdisc则会根据当前的发送速率来决定是否应该把缓存队列上的数据包取出来,速率达到了限定值,就不会把数据包从缓存队列上取出来。

不同类型的qdisc有不同的逻辑,想要了解有哪些qdisc以及它们的作用,可以参考tc的帮助手册 1

qdisc的大体可以分为classlessclassfull两类,它们的区别在于:classless qdisc内部最多只能有一个classclassfull qdisc内部可以创建多个class,那class又是用来做什么的呢?
可以将class理解为qdisc的子规则,enqueueqdisc的流量会被细分到class上,不同的classdequeue时会执行不同的规则。
比如下面的命令,创建了一个htb qdisc,并给htb qdisc添加了两个classenqueuehtb qdisc的流量将会enqueue到两个class上,而dequeue时,class 10:1的输出速率会被限制到10MB/s,class 10:2的输出速率会被限制到20MB/s。

tc qdisc add dev ens33 handle 10: root htb
tc class add dev ens33 classid 10:1 root htb rate 10mbps
tc class add dev ens33 classid 10:2 root htb rate 20mbps

对于那些包含classqdisc,在enqueue/dequeue时,实际上就是从它们内部的classenqueue/dequeue
对于classless qdisc而言,它们内部最多只有一个classenqueue/dequeue的目标class是确定的,但classfull qdisc有多个class,那enqueue/dequeue时,如何确定从哪个class去操作呢?
enqueue时,输入classfull qdisc的数据包具体会被enqueue到哪个class上取决于filterfilterclassfull qdisc的过滤规则,它会根据输入classfull qdisc数据包的特性(比如报文头部的某些字段)来决定数据包的应该enqueue到哪个class上,大致如下图所示:
tc_classfull_qdisc_enqueue.png

dequeue时,则没有统一的准则来选择class,不同类型的classfull qdisc选择class的方式是不同的(比如prio qdisc,它给每个class都赋予了一个优先级,dequeue时它会选择优先级最高且有报文缓存的class来进行操作)。

在使用classfull qdiscfilter是必不可少的,filter需要我们手动添加,对于上面htb qdisc的例子,假如使用了如下的命令来添加filter,那么进入htb qdisc的数据包若发往192.168.8.0/24,则它会被enqueueclass 10:1上, 若数据包发往192.168.4.0/24,则它会被enqueueclass 10:2上,没有被filter匹配上的数据包去向如何则完全取决于qdisc的逻辑,htb qdisc会选择丢弃。

tc filter add dev ens33 parent 10: protocol ip prio 99 u32 classid 10:1 match ip dst 192.168.8.0/24
tc filter add dev ens33 parent 10: protocol ip prio 99 u32 classid 10:2 match ip dst 192.168.4.0/24

filter也有很多种类型,不同类型的filter采用的匹配策略是不一样的,想了解更多的filter类型以及用法,可以参考tc的帮助手册1。(上述两个命令使用的是u32u32 filter可以对报文的各个字段进行匹配,我们匹配的是目的ip)

逻辑结构

在使用classfull qdisc 时,通常会给它添加多个class,这些classqdisc会形成树状的逻辑结构,如下所示:
qdisc and classess.png

有的qdisc还支持在class下端添加class,比如htb qdisc,随着class的添加,最终可以形成多层的树状结构,如下所示:
htb qdisc and classess.png

从树状结构可以看到每个class只会有一个parent,可能有多个childenqueue时,流量从parent流向child
树状结构中的class有两种,一种是inner class,另一种是leaf class,树状结构中那些叶子节点就是leaf class(10:3 10:4 10:5 10:6 10:7),枝干节点就是inner class(10:1 10:2)。

leaf qdisc

每个leaf class都有一个leaf qdisc,如下所示:
leaf qdisc.png

其实class自身是不会缓存数据包的,它通过leaf qdisc来缓存数据包,enqueueclass的数据包会enqueue到它的leaf qdisc上去。
创建classleaf qdisc便会一同被创建,leaf qdisc默认的类型为fifo,fifo qdisc是逻辑最简单的一类qdiscenqueue时,它将数据包缓存下来,dequeue时,它按照enqueue的顺序取出数据包,所以默认的leaf qdisc仅起到缓数据包的作用,没有其它复杂的逻辑。
通常情况下,通过tc qdisc命令创建qdisc后,通过tc qdisc show命令是可以看到我们创建的qdisc的,但默认的leaf qdisc是无法使用tc qdisc show命令看到的,它们在背后默默的干活。

对于那些leaf qdisc,我们可以使用tc命令将它们替换为其它类型的qdisc,进而组合出更为复杂的流控规则。
比如说把上图的class 10:3leaf qdisc替换为sfq qdisc(sfq qdisc的作用是保证输出流的公平性),那么enqueueclass 10:3的数据包就还要执行sfq qdiscenqueue逻辑,dequeue时也会先执行sfq qdiscdequeue逻辑,再执行htb class的限速逻辑。

在一个class下端添加另一个class后,它就会由leaf class转换为inner class后,它的leaf qdisc也会被释放,比如上图的class 10:1class 10:2,它们的leaf qdisc已经不存在了,而且inner class本身不会缓存数据包。

有的classless qdisc内部也有一个class,比如tbf qdisc,这种class也是有leaf qdisc的,也能替换成其它类型的qdisc。但有的classless qdisc内部没有qdisc,比如sfq qdisc,fifo qdisc,它们就无法在下端级联其它类型的qdisc

classify

enqueue的过程中,classfull qdisc会使用数据包携带的信息来从它众多的class中选出一个class用于enqueue, 这个过程在tc的世界里叫做classify
正如前面提到的,classify的一种方式就是通过filter来实现的,enqueue的过程中,qdisc会遍历自身的filter并使用数据包携带的信息与filter进行匹配,匹配成功后数据包会被enqueuefilter指定的class上去。
除了filter,其实还有两种方式来分发数据包:

  • 根据skb携带的priority字段来确定class,这使得我们可以通过配置socket option(SO_PRIORITY)的来指定class
  • 有的qdisc会基于TOS来确定class

ingress qdisc

在数据包的发送路径上,可以创建qdisc来控制数据包的输出行为,同样的在数据包的输入路径上,也可以创建qdisc来控制数据包的输入行为,但输入路径上qdisc的工作模式与发送路径上稍有不同,它不再将数据包enqueue/dequeue,自然也不会在enqueue/dequeue过程种去执行某些操作,输入路径上的qdisc会通过filter来完成工作(限速、过滤包等)。
在输入路径上,只能创建ingressclsact这两类qdisc ,其它的类型的qdisc不能创建,ingressclsact都是classless qdisc,它们自身没有任何关于限速的逻辑,它们依赖于filter来完成工作,ingressclsact在输入路径上的工作原理是相同的,接下来的描述中以ingress为例。
网络设备层在将数据包输入网络协议栈之前,会判断是否存在ingress qdisc,若存在,则调用ingress qdisc的过滤规则(filter)。前面提到过,filter可以把数据包导向不同的class,但filter的功能远不止如此,它还能将数据包导向actionaction可以执行一系列特殊的行为(包括限速、重定向包、NAT等)。
比如,执行如下两条命令后,就能给ens33添加一个ingress qdisc,并给ingress qdisc添加一个filterfilter创建过程中会创建一个action。数据包输入ingress qdisc后,filter会将来自192.168.6.0/24的数据包导向了action policeaction police对送往自己的数据包进行限速。

tc qdisc add dev ens33 ingress
tc filter add dev ens33 parent ffff: protocol ip u32 match ip src 192.168.6.0/24 action police rate 2mbps burst 1m conform-exceed drop/ok

对于上面的例子,最终产生的结构如下图所示:
tc action.png

其实输入路径上的qdisc工作过程就是通过filter来匹配数据包,匹配上了就去执行filter指定的action,没匹配上就继续下一条匹配filteraction有很多类型,可以实现各式各样的功能,除了police这类action,还有mirrednatgact等等,关于它们的作用和参数可以参考 2 中的 SEE ALSO部分。
另外,action是可以独立创建的,它不依赖于filter的创建,比如下面的三条命令和上面的例子效果是一样的:

tc qdisc add dev ens33 ingress
// 创建一个index为4的police action
tc action add action police index 4 rate 2mbps burst 1m conform-exceed drop/ok
// filter将数据包导向index为4的police action
tc filter add dev ens33 parent ffff:  protocol ip u32 match ip src 192.168.6.0/24 action police index 4

上面的例子中,filter通过index就能找到目的action。不同的类型action是独立管理index的,比如说创建了index为4的police action,仍然可以创建index为4的mirred action

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值