给 VPN 端口打标记并不会让语音通话优先
把 VPN 端口标为优先级,只会把通话和备份在同一条隧道里一起抬高。语音需要加密前的分类,以及一条你自己能控制的队列。
把 VPN 的 UDP 端口标为高优先级是最常见的语音 QoS 改动,但它并不能把通话与共用同一条隧道的文件传输区分开。两条流从同一个加密封装套接字出去。标记是在告诉下一跳:所有东西同等重要,这等于什么都没说。真正保护通话的,是加密前可信的分类,加上一条你确实能控制的队列。
隧道藏起了你想分类的那条流
加密把内层报文头替换成每条隧道一个外层报文头。此后,语音和备份流量呈现相同的源、目的和传输端口,因此按隧道端口做的分类器 根本分不开它们。你抬高什么,都是整体抬高。
源端应用设置的 DSCP 值只有被某个环节向外复制时才会保留下来。OpenVPN 2.6 有 passtos,文档中限定在 IPv4 范围内;IPsec 则在隧道边界上执行自己的复制或映射策略。没有这一步,外层报文会按隧道接口使用的任意默认值打标,下游队列永远不知道里面有通话。
被复制的标记应该像任何客户端提供的值一样受到怀疑。一台工作站可以为一个备份任务声称加速转发,所以在信任这个标记之前,信任边界上的准入与重标记必须写进设计里。
优先级只在队列真正形成的地方才算数
把好编码器变成机器人声音的,是拥塞的上行链路,而填满的那条队列通常在接入设备或运营商的缓冲区里。把出向路径整形到可用速率(减去隧道与链路开销),才能让那条队列留在你自己管理的硬件上,而不是别人的缓冲区里。
公平排队和主动队列管理即使没有语音类别也有用,因为它们能阻止一条大流量填满缓冲区。Linux 上的 CAKE 把整形、按流的公平性和可选的 Diffserv 类别合并进一个 qdisc,已部署的网络管理器应当拥有这份配置,而不是再搞一套互相竞争的队列设置。没有整形时,比大流量更高的类别仍然要排在已经填满的缓冲区后面。
入向处理并非无用,但它是在报文越过接收链路之后才起作用。它能影响会响应的发送端,却无法退还已经在上游消耗掉的时延,所以它只是缓解,不是保证。
| Stage | What you can control | What to verify |
|---|---|---|
| Application to client | Which flows are trusted for marking | The marked packets are the ones you intended |
| Tunnel boundary | Whether the inner mark is copied outward | Outer header carries the expected value |
| Your uplink | Shaping rate and class treatment | Queue counters move for the voice class |
| Provider path | Almost nothing | Whether the service enforces the marking at all |
| Receiving side | Local policy after arrival | Delay that is already in the past |
公网里能留下什么
Diffserv 架构描述的是管理域内部的处理方式,所以运营商可能在边界上忽略或改写标记。反过来声称每个网络都会一律清除,同样没有依据。诚实的问题是:这条具体路径在合同和监管下究竟承诺做什么。用带标记的探针去测,而不是重复一条你从别处读来的规则。
先问运营商如何处理这个类别,然后去测量。被保留却没有被调度的标记只是装饰;看不见标记却照常调度的路径是另一个问题,两者需要不同的修法。
一个能隔离环节的测量方案
打一通普通通话,同时施加可控的竞争上传,然后换到有线链路上重做一次。看看通话丢了多少、类别计数器记录了什么、接口离它真正的上限而不是套餐宣传速率有多近。
tc -s qdisc show dev eth0
tc -s class show dev eth0
mtr -rwzbc 50 voice.example.net
如果语音类别计数器始终为零,说明分类或标记复制出了问题,加多少优先级都没用。如果本地类别计数器在动而时延仍在上升,瓶颈就在网关之外。这两种结果都不是靠调高优先级数值能解决的。