Linux内核TC工具链路带宽设计--PRIO队列规定
1.1 分类的队列规定
1.1.1 分类的队列规定及其类中的数据流向
一旦数据包进入一个分类的队列规定,它就得被送到某一个类中——也就是需要分类。对数据包进行分类的工具是过滤器。需要注意的是:“分类器”是从队列规定内部调用的,而不是从别处。
过滤器会返回一个决定,队列规定就根据这个决定把数据包送入相应的类进行排队。每个子类都可以再次使用它们的过滤器进行进一步的分类。直到不需要进一步分类时,数据包才进入该类包含的队列规定排队。
除了能够包含其它队列规定之外,绝大多数分类的队列规定还能够流量整形。这对于需要同时进行调度(如使用 SFQ)和流量控制的场合非常有用。如果用一个高速网卡(比如以太网卡)连接一个低速设备(比如 cable modem 或者 ADSL modem) 时,也可以应用。如果仅仅使用 SFQ,那什么用也没有。因为数据包进、出路由器时没有任何延迟。虽然输出网卡远远快于实际连接速率,但路由器中却没有队列可以调度。
1.1.2 队列规定家族:根、句柄、兄弟和父辈
每块网卡都有一个出口“根队列规定”,缺省情况下是 pfifo_fast 队列规定。每个队列规定都指定一个句柄,以便以后的配置语句能够引用这个队列规定。除了出口队列规定之外,每块网卡还有一个入口,以便 policies 进入的数据流。
队列规定的句柄有两个部分:一个主号码和一个次号码。习惯上把根队列规定称为“1:”,等价于“1:0”。队列规定的次号码永远是0。类的主号码必须与它们父辈的主号码一致,类的此号码一定非零。
1.1.2.1 如何用过滤器进行分类
下图给出一个典型的分层关系:
不要误解这张图,千万不要想象内核处在树的顶点而下面部分是网络。数据包是在根队列规定处入队和出队的,而内核只同根打交道。一个数据包可能是按照下面这个链状流程进行分类的:
1: -> 1:1 -> 12: -> 12:2
数据包现在应该处于 12:2 下属的某个队列规定中的某个队列中。在这个例子中,树的每个节点都附带着一个过滤器,用来选择下一步进入哪个分支。这样比较直观。然而,这样也是允许的:
1: -> 12:2
也就是说,根所附带的一个过滤器要求把数据包直接交给12:2。
1.1.2.2 数据包如何出队并交给硬件
当内核决定把一个数据包发给网卡的时候,根队列规定 1: 会得到一个出队请求,然后把它传给 1:1,然后依次传给 10:、11: 和 12:,然后试图从它们中进行出队操作。也就是说,内核需要遍历整颗树,因为只有 12:2 中才有这个数据包。 换句话说,类及其兄弟仅仅与其“父队列规定”进行交谈,而不会与网卡进行交谈。只有根队列规定才能由内核进行出队操作。
任何类的出队操作都不会比它们的父类更快。我们可以把 SFQ 作为一个子类,放到一个可以进行流量整形的父类中,从而能够同时得到 SFQ 的调度功能和其父类的流量整形功能。
1.1.3 PRIO 队列规定
PRIO 队列规定并不进行整形,它仅仅根据所配置的过滤器把流量进一步细分。可以认为 PRIO 队列规定是 pfifo_fast 的一种衍生物,区别在每个频道都是一个单独的类,而非简单的 FIFO。
当数据包进入 PRIO 队列规定后,将根据所给定的过滤器设置选择一个类。缺省情况下有三个类,这些类仅包含纯 FIFO 队列规定而没有更多的内部结构。可以把它们替换成需要的任何队列规定。
每当有一个数据包需要出队时,首先处理 :1 类。只有当标号更小的类中没有需要处理的包时,才会处理标号大的类。当希望不仅仅依靠包的 TOS,而是想使用 tc 所提供的更强大的功能来进行数据包的优先权划分时,可以使用这个队列规定。它也可以包含更多的队列规定,而 pfifo_fast 却只能包含简单的 fifo 队列规定。
因为它不进行整形,所以使用时与 SFQ 有相同的考虑:要么确保这个网卡的带宽确实已经占满,要么把它包含在一个能够整形的分类的队列规定的内部。严格地说,PRIO 队列规定是一种 Work-Conserving 调度。
1.1.3.1 PRIO 的参数与使用
tc 识别下列参数:
bands
创建频道的数目。每个频道实际上就是一个类,如果修改了这个数值,必须同时修改:
priomap
如果不给 tc 提供任何过滤器,PRIO 队列规定将参考 TC_PRIO 的优先级来决定如何给数据包入队。它的行为就像 pfifo_fast 队列规定。
频道是类,缺省情况下命名为主标号 :1 到主标号 :3。如果你的 PRIO 队列规定是 12:,把数据包过滤到 12:1 将得到最高优先级。注意:0 频道的次标号是 1,1 频道的次标号是 2,以此类推。
1.1.3.2 配置范例
我们想创建这个树:
大批量数据使用 30:,交互数据使用 20:或 10:。命令如下:
# sudo tc qdisc add dev enp0s5 root handle 1: prio ## 这个命令立即创建了类: 1:1, 1:2, 1:3 # sudo tc qdisc add dev enp0s5 parent 1:1 handle 10: sfq # sudo tc qdisc add dev enp0s5 parent 1:2 handle 20: tbf rate 20kbit buffer 1600 limit 3000 # sudo tc qdisc add dev enp0s5 parent 1:3 handle 30: sfq
现在,我们看看结果如何:
# sudo tc -s qdisc ls dev enp0s5 qdisc prio 1: root refcnt 2 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 Sent 7834 bytes 56 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 qdisc sfq 30: parent 1:3 limit 127p quantum 1514b depth 127 divisor 1024 Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 qdisc sfq 10: parent 1:1 limit 127p quantum 1514b depth 127 divisor 1024 Sent 570 bytes 5 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 qdisc tbf 20: parent 1:2 rate 20Kbit burst 1600b lat 560.0ms Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0
如上结果所示,0 频道已经有了一些流量,运行这个命令之后发送了一个包。现在我们来点大批量数据传输(使用能够正确设置 TOS 标记的工具):
# sudo scp dist/flanneld-amd64 chen@10.211.55.21:/usr/local/bin/flanneld # sudo tc -s qdisc ls dev enp0s5 qdisc prio 1: root refcnt 2 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 Sent 37460942 bytes 29222 pkt (dropped 29, overlimits 0 requeues 0) backlog 3028b 0p requeues 0 qdisc sfq 30: parent 1:3 limit 127p quantum 1514b depth 127 divisor 1024 Sent 37011116 bytes 25548 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 qdisc sfq 10: parent 1:1 limit 127p quantum 1514b depth 127 divisor 1024 Sent 840 bytes 8 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 qdisc tbf 20: parent 1:2 rate 20Kbit burst 1600b lat 560.0ms Sent 441722 bytes 3615 pkt (dropped 31, overlimits 542 requeues 0) backlog 0b 0p requeues 0
如上可得,所有的流量都是经过 30:处理的,优先权最低。现在我们验证一下交互数据传输经过更高优先级的频道,我们生成一些交互数据传输:
# sudo tc -s qdisc ls dev enp0s5 qdisc prio 1: root refcnt 2 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 Sent 37487185 bytes 29445 pkt (dropped 29, overlimits 0 requeues 0) backlog 3028b 0p requeues 0 qdisc sfq 30: parent 1:3 limit 127p quantum 1514b depth 127 divisor 1024 Sent 37011116 bytes 25548 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 qdisc sfq 10: parent 1:1 limit 127p quantum 1514b depth 127 divisor 1024 Sent 840 bytes 8 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 qdisc tbf 20: parent 1:2 rate 20Kbit burst 1600b lat 560.0ms Sent 467965 bytes 3838 pkt (dropped 31, overlimits 546 requeues 0) backlog 0b 0p requeues 0
正常情况下所有额外的流量都是经 10: 这个更高优先级的队列规定处理的。与先前的整个 scp 不同,没有数据经过最低优先级的队列规定。