基于tc的网络QoS管理
tc(traffic control)是Linux自带的、功能强大的网络QoS管理/流量塑形工具,利用它,我么可以进行带宽限制、模拟网络延迟和抖动。
本质上,tc是内核封包调度器的配置工具。
排队规则,管理设备队列的算法,可以管理ingress/egress方向的队列。
当内核需要通过某个接口发送封包时,封包被enqueue到该接口所配置的qdisc上。随后,内核尝试从qdisc获取到尽可能多的封包,并转送给网络驱动。
直接附到网络设备上的排队规则。默认情况下,它就是pfifo_fast。
无类别排队规则,对所有封包同等对待。
这样的排队规则包含多个类别(class),每个类别可以进一步对应其它qdisc。
classful qdisc的内部概念,用于对封包差异化处理。每个qdisc可以有多个class,这些每个class可以进一步包含qdisc或者nested class,从而产生树状结构。
Leaf class是没有inner qdisc的class,这种class必须附到某个classless qdisc,后者负责封包的发送。
创建class时,自动附到一个fifo的qdisc。你可以用合适的qdisc替换这个fifo,甚至可以用classful qdisc替换。
当内核从某个classful qdisc dequeue一个封包时,它可能来自任何一个class。某些qdisc可能实现class的优先级,也就是优先dequeue某个class中的封包。
每当封包到达一个有classful qdisc,它都必须被分类(classified)。分类的方法有多种,其中之一是过滤器。
过滤器为classful qdisc确定封包应该归于哪个class,所有配置的过滤器都被调用,直到其中一个返回裁定(verdict)。如果没有任何过滤器返回裁定,处理准则取决于qdisc。
需要注意:过滤器存在于qdisc内部。
在分类器的协助下,qdisc能够决定哪个封包先发送,这就是调度,也称为重排(reordering)或优先级调整(prioritizing)。
调度能够满足提升某些流量的交互性(interactivity),同时保证批量传输(bulk transfers)的带宽需求。
塑形,在发送封包前进行延迟(甚至丢弃)处理,以达到预设的发送速率。塑形总是在egress方向进行。
塑形不仅仅用于带宽限制,还可以用于让流量更加平滑,以获得更好的网络行为。
执行策略,决定是否丢弃封包。丢弃封包可以产生对ingress带宽的限制效果。
每个网络接口可以有一个ingress qdisc用来执行policing。
只要有包可发送就立即发送。换句话说,只要网卡处于可发送状态(对于 egress qdisc 来说),它永远不会延迟包的发送。
某些qdisc,例如tbf,可能会延迟一段时间再将一个包发送出去,以达到期望的带宽 。这意味着它们有时即使有能力,也不会发送封包。
每个class,以及classful qdisc,都具有自己的唯一标识,此标识叫handle。
handle有两部分组成 <major>:<minor>,用户可以在满足下面规则的前提下分配handle:
- major/minor都是十六进制整数
- major,在qdisc树中,parent相同的节点,必须具有相同的major。root disc的children的major通常设置为1
- minor,如果minor为0,则表示当前节点是一个qdisc,如果是其它值,则节点是一个class。所有具有相同parent的class必须具有不同的minor
class的handle也叫classid。
由于qdisc的minor都是0,因此它下面挂的class的major通常设置的和qdisc的major一致。而class的minor不为零,subclass通常以parent的minor作为major。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
Userspace programs ^ | +---------------+-----------------------------------------+ | Y | | -------> IP Stack | | | | | | | Y | | | Y | | ^ | | | | / ----------> Forwarding -> | | ^ / | | | |/ Y | | | | | | ^ Y /-qdisc1-\ | | | Egress /--qdisc2--\ | --->->Ingress Classifier ---qdisc3---- | -> | Qdisc \__qdisc4__/ | | \-qdiscN_/ | | | +----------------------------------------------------------+ |
入站流量首先进入ingress qdisc,这里会对封包进行过滤,决定是否丢弃,这个过程就是policing。policing位于入站网络路径的很早期,在这里进行封包过滤是非常高效的。
如果封包没有被丢弃,则它要么交由本地进程处理,要么转发给其它主机。
不管是转发的、还是本地进程产生的封包,出栈前都需要经过egress classifier,然后放到匹配的qdisc中发送出去。
当存在多个网络接口时,每个网络接口都有自己的tc ingress/egress钩子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
1: root qdisc | 1:1 child class / | \ / | \ / | \ / | \ 1:10 1:11 1:12 child classes | | | | 11: | leaf class(classless qdisc) | | 10:0 12:0 qdisc / \ / \ 10:1 10:2 12:1 12:2 leaf classes |
内核仅仅会和root qdisc进行交互,进行封包入队、出队操作。
对于上面这样的qdisc结构,入队封包可能经过这样的链路而被分类: 1: -> 1:1 -> 1:12 -> 12: -> 12:2,这要求每个节点都挂着一个filter,每个filter需要对经过的封包进行裁定,断言它是否匹配此节点。封包也可能 1: -> 12:2直接分类,root qdisc可以直接决定直接匹配12:2。
当内核请求出队一个封包交给网络接口时,它会向root qdisc发起一个dequeue请求,root qdisc将请求转发给1:1,并逐步向下传递,遍历整棵数以发现封包。
子类dequeue的速度,永远不能超过其祖先允许的速度。我们可能仅需要在root disc上配置,就能够满足整形需求。
通过设置若干队列,并且规定每个队列的特质(比如其中的封包总是延迟200ms发送),然后将封包放入特定队列排队,可以管理封包的发送方式。
排队规则(queueing disciplines,qdisc)用于定义一个具有某些特质的封包队列。
无类别排队规则(classless qdisc)可以对某个网络接口上的所有流量进行无差别的流量塑形,例如:
- 重新调度
- 设置延迟
- 丢弃封包
在没有配置classful qdisc的情况下,classless qdisc只能附到网络设备的根上:
1 2 |
# 网络设备 规则 规则参数 tc qdisc add dev DEV root QDISC QDISC-PARAMETERS |
支持的classless qdisc有十几种,这里选几种常用的介绍。
先入先出队列,所有封包按照进入的顺序来发送。这是启用了CONFIG_IP_ADVANCED_ROUTER的内核的标准qdisc。
该规则包含三个band(子队列),编号分别为0 1 2,处理规则如下:
- 每个band上的封包均以FIFO方式发送
- 如果band 0有数据,则不会处理band 1 和band 2
- 如果band 1有数据,则不会处理band 2
- 内核会检查封包的TOS字段,将“最小延迟”的包放入band0
严格的说,pfifo_fast属于有类别排队规则,因为它的三个band,本质上是class。但是从用户角度来说,它是classless的,因为不支持配置。
该qdisc的参数无法更改。
参数 priomap决定了如何将封包的优先级映射到band。封包的TOS字段占用4bit,每个bit含义如下:
1 2 3 4 5 6 7 |
Binary Decimcal Meaning ----------------------------------------- 1000 8 Minimize delay (md) 0100 4 Maximize throughput (mt) 0010 2 Maximize reliability (mr) 0001 1 Minimize monetary cost (mmc) 0000 0 Normal Service |
组合上述比特,可以有16个不同的TOS,这些TOS对应的优先级、映射到的Band如下表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
TOS Bits Means Linux Priority Band ------------------------------------------------------------ 0x0 0 Normal Service 0 Best Effort 1 0x2 1 Minimize Monetary Cost 1 Filler 2 0x4 2 Maximize Reliability 0 Best Effort 1 0x6 3 mmc+mr 0 Best Effort 1 0x8 4 Maximize Throughput 2 Bulk 2 0xa 5 mmc+mt 2 Bulk 2 0xc 6 mr+mt 2 Bulk 2 0xe 7 mmc+mr+mt 2 Bulk 2 0x10 8 Minimize Delay 6 Interactive 0 0x12 9 mmc+md 6 Interactive 0 0x14 10 mr+md 6 Interactive 0 0x16 11 mmc+mr+md 6 Interactive 0 0x18 12 mt+md 4 Int. Bulk 1 0x1a 13 mmc+mt+md 4 Int. Bulk 1 0x1c 14 mr+mt+md 4 Int. Bulk 1 0x1e 15 mmc+mr+mt+md 4 Int. Bulk 1 |
参数 txqueuelen则表示发送队列长度,可以通过配置网络接口来修改:
1 |
ifconfig eth0 txqueuelen 10 |
令牌桶过滤器(token bucket filter),对于没有超过预设速率的流量直接发送,能够容忍超过预设速率的短暂burst。如果仅仅想限制网络接口速率,可以选择此qdisc。tbf是一个单纯的塑形器,从不会调度流量。
适用场景:单纯的对egress流量进行限速。
该qdisc会以特定的速率产生token,这些token存放到桶(一个缓冲区)中,每当封包进入都会消耗token。如果消耗小于那个特定速率,桶会被填满;如果消耗速度大于特定速率,则最终桶会变空。空了就不能继续发送封包了。token以字节数为单位。
在使用理想的minburst的情况下,最多可以塑形大约1mbit/s的正常流量,保证精确的以配置的速率发送封包。
要支持更大的速率,就必须损失minburst,这种情况下,封包平均的以配置的速率发送,但是在毫秒时间尺度上进行度量,发送速率可能大大超标。
命令格式:
1 2 3 |
tc qdisc ... tbf rate rate burst bytes/cell ( latency ms | limit bytes ) [ mpu bytes [ peakrate rate mtu bytes/cell ] ] |
可用参数:
参数 | 说明 |
limit | 排队等待可用token的封包的总计最大字节数,和latency互斥 |
latency | 每个封包在TBF中停留的最大时间,和limit互斥 |
burst buffer maxburst |
桶的容量,也就是token的数量,单位字节 大的rate需要大的burst,对于10mbit/s的rate,至少需要10kbyte的burst才能达到期望的速率 允许最小的桶容量为:rate / HZ |
mpu |
最小包单元(Minimum Packet Unit),决定了一个包使用的最少token量,默认0 在以太网中,任何一个封包都不会小于64字节 |
rate |
速率,token的产生速度,对应了带宽 默认情况下,消耗token的速度不受限制,也就是瞬时burst速度不受限制。如果以rate发送数据,则可以持续稳定运行;如果大于rate发送数据则最终令牌会被耗光 |
peakrate |
桶的最大消耗速率,通常不需要设置,除非需要毫秒精度的塑形 为了实现peakrate,使用了次级的TBF,该TBF使用非常小的桶,因此无法支持burst 要达到最大精确度,这个桶可以仅容纳单个封包(不能再细分了,一次最少得发一个2层封包),这种情况下,速率被限制在1mbit/s。这个速率的来由是,内核中断产生频率为jiffy,也就是1/HZ,一般是10ms。每秒钟内核具有100次进行流量塑形的机会,为了最大精确度,每次塑形仅能发送单个封包。如果封包大小为1000字节那么每秒能发送大约1mbit/s |
mtu minburst |
指定peakrate桶的容量,为了达到最大精确度,应该设置为网络接口的MTU 如果需要peakrate,而且允许一定的burstiness,可以增大此参数。假设封包大小为1000字节,3000byte的minburst允许大概3mbit/s的peakrate |
示例:
1 2 3 4 5 6 |
# 持续最大速率0.5mb/s tc qdisc add dev eth0 root tbf rate 0.5mbit # 5kb的缓冲 最大延迟70ms 峰值速率 1.0mb/s burst 5kb latency 70ms peakrate 1mbit # 最精确peakrate行为,peakrate桶的大小设置为MTU minburst 1540 |
随机公平排队(stochastic fairness queueing),不做流量塑形,仅基于流(flow,通常对应TCP连接)对待发送封包进行调度。sfq的目标是保证每个流能够公平的获得发送的机会,可以在某种程度上缓和DoS攻击。
适用场景:带宽打满的情况下,确保带宽公平使用。
在入队(enqueueing)时,每个封包基于其哈希值被映射到一个哈希桶(hash bucket),哈希值的来源是:
- 从外部classifier(通过tc filter设置)获得
- 如果没有外部classifier,则使用一个内部默认classifier,该classifier使用利用封包源地址、目的地址、源/目的端口计算哈希
多个流可能映射到相同的桶。发送封包实际上是每个桶轮流(round robin)发的,因此映射到同一个桶的多个流,获得的配额就相应减少。为了解决此问题,sfq支持每隔一段时间就更换哈希算法。
sfq是随到随发(work-conserving)的,也就是说如果有一个封包带发送且队列空闲,则立刻发送它。这就意味着,在带宽不饱和(也没有其它qdisc做塑形)的情况下,sfq没有意义,所有封包都被立刻发出。
命令格式:
1 2 3 4 |
tc qdisc ... [ divisor hashtablesize ] [ limit packets ] [ perturb seconds ] [ quantum bytes ] [ flows number ] [ depth number ] [ headdrop ] [ redflowlimit bytes ] [ min bytes ] [ max bytes ] [ avpkt bytes ] [ burst packets ] [ probability P ] [ ecn ] [ harddrop ] |
可用参数:
参数 | 说明 |
perturb | 每隔多久更换哈希算法,如果不设置则永远不更换。可以设置为10s |
quantum | 轮换到下一个桶时,当前桶可以出队(dequeue)多少字节,默认一个MTU,不要设置的更小 |
limit | 最多缓存的包数量,超过此数量会导致丢包 |
divisor | 指定哈希表的大小,必须是2的幂,不能大于65536,默认1024 |
depth | 每个流的封包最大数量,默热年127 |
flows | 流的最大数量,默认127 |
示例:
1 |
tc qdisc add dev ppp0 root sfq perturb 10 |
如果想对不同类型的流量做不同处理,考虑使用有类别排队规则(classful qdisc)。
当流量进入一个classful qdisc 时,该qdisc需要将其发送到内部的某个class ,对这个包进行“分类”。分类是通过调用过滤器(filter)完成的,过滤器返回一个断言给 qdisc,qdisc 据此将包 enqueue 到合适的 class。
每个class都可能进一步调用其它过滤器,如果没有这些的过滤器,则封包被enqueue到class自带的qdisc。
不支持塑形的容器,具有可配置的classes数量,不同的classes按优先级出队。当高优先级class存在封包尚未出队,则低优先级class不被处理。默认情况下封包的TOS字段决定其优先级。
命令格式:
1 2 3 |
tc qdisc ... dev dev ( parent classid | root) [ handle major: ] prio [ bands bands ] [ priomap band band band... ] [ estimator interval timeconstant ] |
可用参数:
参数 | 说明 |
bands |
需要创建的band的数量,每个band本质上都是一个class,bind0的handle为major:1,类推 |
priomap |
类似于pfifo_fast的优先级映射 如果没有配置filter来决定如何分类,则默认根据封包优先级,将封包映射到band |
示例:
1 2 3 4 5 6 7 8 9 |
1: root qdisc / | \ / | \ / | \ 1:1 1:2 1:3 classes | | | 10: 20: 30: qdiscs qdiscs sfq tbf sfq band 0 1 2 |
root qdisc为具有三个band的PRIO,三个子类,分别挂接SFQ/TBF/SFQ无类别qdisc:
1 2 3 4 5 6 7 8 9 10 |
# 添加一个PRIO类型的qdisc,自动有三个class # 设备 根disc handle 类型 tc qdisc add dev eth0 root handle 1: prio # 添加一个qdisc给 band0 类型为sfq,分配handle 10 tc qdisc add dev eth0 parent 1:1 handle 10: sfq # 添加一个qdisc给 band1 tc qdisc add dev eth0 parent 1:2 handle 20: tbf rate 20kbit buffer 1600 limit 3000 # 添加一个qdisc给 band2 tc qdisc add dev eth0 parent 1:3 handle 30: sfq |
使用下面的命令可以查看封包统计信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
tc -s qdisc ls dev eth0 qdisc sfq 30: quantum 1514b Sent 384228 bytes 274 pkts (dropped 0, overlimits 0) qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms Sent 2640 bytes 20 pkts (dropped 0, overlimits 0) qdisc sfq 10: quantum 1514b Sent 14926 bytes 193 pkts (dropped 0, overlimits 0) qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 Sent 401836 bytes 488 pkts (dropped 0, overlimits 0) |
Hierarchical Token Bucket,层级令牌桶,它是一个classful的TBF。适用于下面的场景:
- 有一个固定总带宽,想将其分割成几个部分,分别用作不同目的
- 每个部分的带宽是有保证的(guaranteed bandwidth)
- 还可以允许每个部分向其他部分借带宽
HTB可以作为一个容易理解的CBQ的代替品。和CBQ一样,HTB可以控制egress带宽的占用,可以用一个物理网络连接模拟多个较慢的连接,将不同种类的连接发送到这些模拟的连接中。
HTB使用令牌桶过滤器算法,而不是CBQ那样的估算连接空闲时间,因此它不依赖网络接口的特质,也不需要知道egress接口的实际底层带宽。
HTB中可以包含多个classes,这些classes默认包含一个pfifo_fast qdisc。当封包入队时,HTB使用多种方式决定应该分到哪个class。在常规配置下,在每个节点上,HTB都会寻找一个指令,然后跳转到指令所引用的class。如果class是叶子节点,则在那里入队;如果不是叶子节点,继续前述按指令跳转的过程。
命令格式:
1 2 3 4 |
tc qdisc ... dev dev ( parent classid | root) [ handle major: ] htb [ default minor-id ] tc class ... dev dev parent major:[minor] [ classid major:minor ] htb rate rate [ ceil rate ] burst bytes [ cburst bytes ] [ prio priority ] |
qdisc参数:
参数 | 说明 |
default | 未分类成功的流量发送到此handle表示的class |
class参数:
参数 | 说明 |
prio | 优先级,值最低的class被最先尝试(是否匹配封包) |
rate | 给此class及其后代保证的最大带宽 |
ceil |
如果祖代有空闲带宽,则HTB允许借用带宽,这个参数指定rate + 借用带宽一共多大。默认等于rate,也就是不允许借用 |
burst |
(每次中断)最多以ceil速度burst的字节数。应当比所有子代burst之和更大 由于UNIX系统时钟中断频率的原因,不合理的配置会导致实际速率相当的低。以默认10HZ的中断频率为例。每秒能够发送的最大数据量是: 100 × burst 因此,要达到期望10mbits/s的速度,需要的burst大小是12KB: 100 × 12Kbytes × 8 = 10mbit/s |
cburst | 在不限速(尽网络接口可能)模式下,最多能够burst的字节数。应当比所有子代cburst之和更大 |
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 默认分类为30 tc qdisc add dev eth0 root handle 1: htb default 30 # 总控,6mbps 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 burst 15k tc class add dev eth0 parent 1:1 classid 1:20 htb rate 3mbit ceil 6mbit burst 15k tc class add dev eth0 parent 1:1 classid 1:30 htb rate 1kbit ceil 6mbit burst 15k # 推荐在子类中使用SFQ 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 # 配置用来分类的过滤器,使用HTB时所有filter必须全部attach到root tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 80 0xffff flowid 1:10 tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip sport 25 0xffff flowid 1:20 |
过滤器(filter)也叫分类器(classifier)。
每当封包到达有分叉的节点时,它都需要被分类。分类的方式有很多种,有些qdisc会根据TOS自动分类,有些则需要配置过滤器。
过滤器被classful qdisc用来决定,封包应该被enqueue到哪一个队列。当封包到达qdisc时,其上关联的所有过滤器(称为分类器链,classifier chain)会被依次调用,直到某个返回裁定(verdict)。如果任何过滤器都没有返回verdict,则如何分类取决于qdisc。
通用的、基于任意封包数据的过滤器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# 此过滤器是为eth0配置的 tc filter add dev eth0 protocol ip # 父节点为1:0,也就是根节点 优先级,数字越小优先级越高,越先被调用 parent 1:0 prio 1 # u32是过滤器的类型 匹配目标端口是80的IP封包 发送给1:10的那个节点(类) u32 match ip dport 80 0xffff flowid 1:10 # 基于CIDR来匹配 tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 \ match ip dst 4.3.2.1/32 flowid 10:1 # 同时根据IP和端口匹配 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 # 匹配ICMP协议 ... match ip protocol 1 0xff # 匹配TOS tc filter add dev ppp0 parent 1:0 protocol ip prio 10 u32 \ match ip tos 0x10 0xff flowid 1:4 |
基于一个ematch表达式进行过滤。
使用eBPF程序对封包进行过滤。参考:eBPF学习笔记。
使用封包所属进程所在的控制组进行过滤。
基于封包所属的流(流根据可选择的key来识别)进行过滤。
根据封包上的fwmark进行过滤,直接将fwmark映射为traffic class。fwmark是内核中的数据,只要没有出内核,不会(因为在各接口之间转发)丢失。
1 2 3 4 5 |
# 匹配打了标记6的封包 tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle 6 fw flowid 1:1 # 配合下面的命令,可以实现对从eth0发到eth1流量进行塑形 iptables -A PREROUTING -t mangle -i eth0 -j MARK --set-mark 6 |
根据路由表进行封包过滤。
匹配任何封包。
tc的police action允许限制它所关联到的filter所匹配的流量的带宽。典型的应用是,通过丢弃特定的封包,来保证ingress流量速率。
尽管在发送端进行速率控制更好,但是发送端可能不受我们控制。
可用参数:
参数 | 说明 |
rate | 封包通过此action的最大速率,超过速率后的处理动作由conform-exceed指定 |
burst | 最大允许的burst字节数 |
mtu | 允许的最大封包大小,超过大小的封包,处理方式和超速一样。默认无限制 |
peakrate | 桶的最大消耗速率 |
avrate | 使用内核中的带宽速率估算器(bandwidth rate estimator),并匹配此参数给出的rate |
overhead | 单位字节数,计算rate/peakrate时考虑encapsulating成本 |
linklayer | 指定链路层的类别,默认ethernet |
estimator |
estimator SAMPLE AVERAGE 用于调优内核的速率估算器,两个参数用于控制采样频率、多长时间计算一次平均值 |
conform-exceed |
conform-exceed EXCEEDACT[/NOTEXCEEDACT] 定义超速/超大后的处理方式: continue 什么都不做,如果还有其它的action则继续处理 |
下面的例子,用u32过滤器和ingress qdisc实现1mbit/s的限速:
1 2 3 4 5 |
tc qdisc add dev eth0 handle ffff: ingress tc filter add dev eth0 parent ffff: u32 \ match u32 0 0 \ police rate 1mbit burst 100k |
注意ingress qdisc不是一个真实的qdisc,它仅仅是为了让过滤器有挂钩点。
动作(Acion)可以作为过滤器的一部分,如果封包匹配过滤器,过滤器返回分类结果之前关联的动作会按顺序一个个执行。
动作能够对分类结果作出响应,甚至去改变分类结果,尽管没有任何内置的动作去改变分类结果。
通用的动作框架是从策略演化而来的。比如上一章的例子,可以改写为动作:
1 2 3 |
tc filter add dev eth0 parent ffff: u32 \ match u32 0 0 \ action police rate 1mbit burst 100k |
为过滤器u32添加多个动作:
1 2 3 4 5 |
tc filter add dev eth0 parent ffff: u32 \ match u32 0 0 \ # 重定向超速的流量给lo而非丢弃 action police rate 1mbit burst 100k conform-exceed pipe \ action mirred egress redirect dev lo |
1 2 3 4 |
tc [ TC_OPTIONS ] actions add | change | replace ACTSPEC ACTSPEC := action ACTNAME ACTPARAMS [ INDEXSPEC ] [ COOKIESPEC ] [ FLAGS ] [ HWSTATSSPEC ] [ CONTROL ] |
为匹配的封包执行一个BPF程序。
将封包上的fwmark设置到它的连接上。工作方式是,在conntrack表中查找匹配的条目,如果找到,则存储标记。
触发封包Checksum的重新计算,支持协议IPv4, ICMP, IGMP, TCP, UDP
将封包传递给指定的iptables目标,这样可以直接使用iptables extensions,而不需要设置fwmark然后通过规则匹配到特定netfilter规则。
镜像或者重定向封包。常常和ifb伪设备联用,在多个网络接口甚至ingress流量之间共享公共的QoS设置。
执行无状态NAT,应该使用iptables而不是这个动作实现NAT。
一般性的封包编辑,允许修改封包的任意内容。
应用带宽限制策略。
修改关联的封包数据,支持修改队列映射、优先级字段、fwmark值。
添加或移除VLAN头。
提示tc执行了当前动作之后应该做什么:
CONTROL | 说明 |
reclassify | 跳转到动作的父对象(qdisc)的第一个过滤器,重新进行分类 |
pipe | 继续执行(当前过滤器的)下一个动作,默认 |
drop | 丢弃封包,不执行其它动作 |
continue | 继续调用下一个过滤器进行分类操作 |
pass | 返回到调用qdisc,结束分类处理 |
Leave a Reply