在 Linux 中对宽度未知的通道进行传出流量整形

在 Linux 中对宽度未知的通道进行传出流量整形

如果我不知道信道宽度,是否有任何方法可以将传出信道划分为不同的流量类别,例如,按照 30/70 的关系?HTB 需要精确的数字,CBQ 也一样。

答案1

我以为这会奏效,但除非有某种机制控制其流出量,否则队列会空得太快,而且永远不会显示 drr 权重(不太清楚这是为什么)。然而,只要有选择压力,它就会按预期工作。

tc qdisc add dev eth0 handle 1 root drr
tc class add dev eth0 parent 1: classid 1:1 drr quantum 600  # 30%
tc class add dev eth0 parent 1: classid 1:2 drr quantum 1400 # 70%
tc class add dev eth0 parent 1: classid 1:3 drr # everything else....

tc qdisc add dev eth0 parent 1:1 handle 10: sfq perturb 120 limit 1024
tc qdisc add dev eth0 parent 1:2 handle 20: sfq perturb 120 limit 1024
tc qdisc add dev eth0 parent 1:3 handle 30: sfq perturb 120 limit 1024

# outgoing to port 8111 will go to 30% queue, 8112 will go to 70% queue...
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 8111 0xffff classid 1:1
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 8112 0xffff classid 1:2
# a default so my connection doesn't die when doing this.
tc filter add dev eth0 protocol all parent 1:0 prio 2 u32 match u8 0x00 0x00 at 0 classid 1:3 

如果你将其全部包装在具有 800kbps 流速的 HTB 中,你将获得良好的 70KB/30KB 分割,通过运行并行实例进行测试pv -ar /dev/zero | nc differenthost port

顺便说一句,不要尝试在没有带外控制机制的情况下以线速度从远程机器进行测试。(哎呀)

无论如何,也许这个答案会有所帮助。


编辑:在互联网上搜索后发现,除了手册页中包含的示例外,没有其他 Linux 赤字循环 (DRR) qdisc 示例,对我来说,它似乎不完整,省略了过滤规则(及其注意事项)并且通常不明显。

什么是 DRR

赤字循环赛是一种调度算法,可以将其想象为多个并行队列。调度程序按顺序迭代这些队列。每次出现队列时,如果队列不为空,它会根据每个队列跟踪的数字(称为赤字计数器如果数据包大小小于缺口计数器,则 DRR 会从队列中移除该数据包并将其发送至线路上,并从缺口计数器中减去其大小(因此为缺口)。然后,它会对队列中的下一个数据包重复此操作,直到数据包大于缺口计数器或队列为空。如果循环结束时队列不为空,则队列特定值量子被添加到赤字计数器后才能进入下一个队列。

这实际上与 HTB 并没有什么不同,只是 HTB 限制了在特定时间间隔内添加到给定队列的最大数量(很确定 Linux 以每 jiffie 的字节数来衡量这一点,尽管在无滴答模式下可能不再如此),并且对所有队列都有一个缺口计数器(每个时间间隔也会填充一定数量的字节)

示例使用说明

因此,上述示例所做的就是以 root 身份创建一个 drr qdisc,并向其中添加 3 个队列,第一个队列的量程为每次传递 600 字节,第二个队列的量程为每次传递 1400 字节,第三个队列的量程默认为 MTU 大小。稍后我将解释原因,这些值是什么并不重要,重要的是比率是多少。

因为我喜欢公平,所以我在叶子节点上添加了一些 sfq;这不是必需的,因为如果不这样做,它应该默认为 pfifo fast(或者我认为您的默认调度程序是什么。我必须阅读 sch_drr.c 源代码才能 100% 确定)。它也不会改变我的测试,因为我每个端口使用一个 TCP 连接。

tc 测试过滤规则说明

当我测试上述内容时,它实际上给我带来了一些过滤规则方面的麻烦。drr 没有像许多其他 qdisc 那样的默认流,也不允许您将其指定为 qdisc 选项(我知道,如果有,请编辑此答案)。因此,当它开始将您的数据包丢弃在地板上时,这相当有趣,但令人沮丧,因为它无法对诸如 arp 请求或回复之类的内容进行排队,并且它没有说明为什么您的接口会自发关闭。

因此,前两个规则执行测试活动,将 tcp/udp(在同一位置)dport 与 8111 和 8112 进行匹配,将匹配放入适当的队列,如果找到适当的规则则停止匹配。

第三条规则规定“匹配第一个字节(0 偏移量)与掩码为 0 的 0x0 匹配的任何协议”,并将其放入第三个队列。在第一次通过后进行评估,然后捕获任何不匹配的数据包,这是优先级 2。如果您知道创建默认 classid 的更好方法,我当然想知道。

量子选择

正如我之前提到的,实际值并不比比率重要,尽管如果队列比应有的要大,它可能会使队列更具突发性(我的意思是每次传递 X 个数据包时,队列会卡在一个队列中),如果队列比应有的要小,则使用更多的 CPU 时间。出于这个原因,我选择了与 MTU 数量级接近的值,其与 30/70 目标比率的关系是显而易见的。由于量子决定了每次传递的填充率,因此每次传递的字节数,量子比率将是每次传递的字节数相对于彼此的比率。如果一个队列是空的,其他队列不会消耗其带宽,而只是花费更多时间跳过空队列并填充自身。

与 HTB 或 CBQ 相比,文档相对缺乏,这表明 DRR 并不是一个特别流行的 qdisc,因此不幸的是,如果您决定采用这种方式,我预计支持会非常稀少,这使得很难推荐使用它。

答案2

您检查过这个链接吗?

http://www.tldp.org/HOWTO/html_single/Traffic-Control-HOWTO/#r-unknown-bandwidth

>     8.2. Handling a link with a known bandwidth
>     
>     HTB is an ideal qdisc to use on a link with a known bandwidth, because the innermost (root-most) class can be set to the maximum
> bandwidth available on a given link. Flows can be further subdivided
> into children classes, allowing either guaranteed bandwidth to
> particular classes of traffic or allowing preference to specific kinds
> of traffic

相关内容