Linux 流量控制器 (Linux tc):分层令牌桶 (htb) 数据包队列大小

Linux 流量控制器 (Linux tc):分层令牌桶 (htb) 数据包队列大小

在我的 Linux 路由器中,我使用以下配置来限制 LAN 中客户端的 44444 端口的流量速率(客户端地址为 192.168.10.2,通过路由器的 eth1 iface 连接):

tc qdisc add dev eth1 root handle 1: htb default 2
tc class add dev eth1 parent 1: classid 1:1 htb rate $RATE
tc class add dev eth1 parent 1: classid 1:2 htb rate 100mbit
tc filter add dev eth1 protocol ip parent 1: prio 1 u32 match ip dst 192.168.10.2 dport 44444 0xffff flowid 1:1

我期望这个配置能够让去往 192.168.10.2:44444 的流量根据 $RATE 参数进行整形,而其他所有流量基本保持不变(因为 LAN 是 100Mbit/s)。

为了测试此配置,我以不同的速率向 192.168.10.2:44444 发送 UDP 数据包,跟踪丢失的数据包数量和单向延迟变化。我在测试期间观察到,超过速率的数据包绝不被丢弃。相反,数据包会排队进入一个缓冲区,这个缓冲区会不断增大,但(显然)永远不会达到大小限制。

例如:

使用 RATE=30kbit 并以大约 2Mbit/s 的速度发送数据包(数据包有效负载 1400 字节,数据包间隔 5ms)持续 10 秒,我从 tc 获得以下统计数据:

qdisc htb 1: root refcnt 2 r2q 10 default 2 direct_packets_stat 0 ver 3.17
Sent 104901 bytes 85 pkt (dropped 0, overlimits 185 requeues 0)
backlog 0b 0p requeues 0

(统计数据显示通过tc -s -d qdisc show dev eth1

事实上,192.168.10.2 接收数据包的时间超过 26 秒(即发送方完成接收后 16 秒)。

使用 RATE=5mbit 并以 20mbit 的速度发送数据包,我得到以下统计数据:

qdisc htb 1: root refcnt 2 r2q 10 default 2 direct_packets_stat 0 ver 3.17
Sent 6310526 bytes 4331 pkt (dropped 0, overlimits 8667 requeues 0)
backlog 0b 0p requeues 0

尽管这次单向延迟不会超过160毫秒。

我也得到了指定大小的类似结果burst,但我没有观察到任何显着的变化,无论我将它设置得多低(我将它降低到 1kbit)。

不幸的是,尽管我读过关于 Linux tc 和 htb 的各种手册和参考资料,但我还是找不到这些结果的合理解释。如果有人能帮我解决这个问题,我会很高兴。

谢谢


更新。我找到了一个非常有用且清晰的 Linux 流量控制器内部描述。你可以找到它这里. 另一个有用的资源是OpenWRT 维基百科。其实我已经知道了前一篇文章,但显然我错过了一些重要的部分。

长话短说,我的数据包排队的缓冲区当然是网络接口的出口队列。出口队列中的数据包根据通过命令设置的排队规则进行选择传输tc。有趣的是,出口队列不是以字节为单位,而是以数据包为单位(无论数据包有多大)。这在一定程度上解释了为什么我在实验中从未达到队列大小限制。

ifconfig出口队列大小通过命令 (字段)显示txqueue。在我的 Linux 机器中,默认出口大小为 1000 个数据包,但您可以通过 轻松更改它ifconfig DEV txqueuelen SIZE。通过将队列大小减小到 1 个数据包,我最终设法强制丢弃整形数据包(永远不会到达客户端)。所以我想基本上就是这样。

我注意到的最后一个有趣的事实是,令牌桶过滤器(tbf)与层次桶过滤器相反提供一个额外的缓冲区,数据包在传输之前会先在此缓冲区排队。我猜想使用队列足够小的过滤器可以强制丢弃数据包,无论出口队列有多大。不过我还没有尝试过。

希望这可以帮助。

相关内容