
简介这是一份关于区分服务DiffServ在路由器中实现的中文技术文献面向网络工程师、信息技术研究人员及需要配置QoS策略的运维人员旨在解决传统尽力而为网络难以按业务类型提供带宽、时延等服务质量保证的问题。资源仅含1个PDF文件压缩包大小192KB属于路由器与无线技术领域的专业参考文献。文档从DS域与DSCP出发说明边缘路由器对分组分类标记、核心路由器依据PHB转发的机制并给出绝对区分服务中EF与AF两类服务的队列调度实现方法同时介绍带宽代理BB通过SLA协商资源分配的流程。阅读后可理解区分服务相比综合服务的可扩展性优势掌握从边缘到核心的QoS部署思路。已有103人学习下载适合具备一定网络基础、希望深入掌握路由器QoS实现的读者。1. 区分服务与路由器实现这份1999年的论文为什么到今天还能用“核心路由器不能为每个流单独保存状态否则骨干网会直接崩溃”这个结论放到今天已经是QoS领域的常识但在IETF刚提出DiffServ模型的1999年它还是一个需要靠论文讲清楚的设计判断。这份《区分服务在路由器中的实现》来自《现代电信科技》1999年第12期作者是中科大电子工程与信息科学系的梁军、洪佩琳、李津生篇幅很短却把IntServ为什么扛不住、DS域如何重新定义、EF/AF两类绝对区分服务、相对区分服务的三种调度算法以及RIO双RED门限全部讲完了。对准备考研复试、给毕设找QoS理论支撑、或者想弄明白路由器上QoS配置背后逻辑的工程师这份材料能直接把概念和实现串成一条线。下面按原文章节拆开讲并补上现代环境的验证与踩坑。2. 从IntServ到DiffServ为什么核心路由器不能为每个流保存状态2.1 IntServ的致命伤每流状态在骨干网上是天文数字论文把综合服务IntServ和区分服务DiffServ放在对立面来讲。IntServ的思路很直观用户在通信前用RSVP信令在收发两端沿途的每一个转发节点上做资源预留这样每个流从源头到目的地都有确定的带宽和时延。问题出在“每一个流”这三个字上。骨干网上同时存在的流数量是百万级别的路由器要为每个流保存对应的状态信息而这些信息要复制到全网各个节点。论文引用了Clark的观点想找到一个算法完成这种端到端的全局资源分配本身就非常困难而且这种网络在发生故障时几乎提供不了任何保护。所以在论文的结论里IntServ的可扩展性和稳定性都不好而这两点恰恰是因特网继续发展最需要的东西。把这段逻辑映射到今天的设备上更容易理解。按流状态转发的设备规模受限于TCAM和内存容量流表项数量直接决定整机能在多少连接下工作按聚合类转发的设备转发路径上只需要查几十种行为无论背后跑多少个流。DiffServ的取舍本质上是把QoS复杂度从每个节点收拢到网络入口。2.2 DS域与DSCP6个比特如何编码64种转发行为DiffServ对IP头做的第一件事是重新定义原来的服务类型ToS域。原来的ToS域用3个优先级比特最多表达8个状态IETF区分服务工作组把它扩展到6个比特得到64种可用状态这6个比特就是DSCPDifferentiated Services Code Point。每一种DSCP取值对应一种转发处理也就是每一跳行为PHB。DSCP十进制行为典型用途46EF低时延语音、租用线路仿真10 / 12 / 14AF11 / AF12 / AF13保证转发类别1三个丢弃级别18 / 20 / 22AF21 / AF22 / AF23保证转发类别2三个丢弃级别26 / 28 / 30AF31 / AF32 / AF33保证转发类别3三个丢弃级别34 / 36 / 38AF41 / AF42 / AF43保证转发类别4三个丢弃级别0CS0 / BE尽力而为这个表是RFC 2597和RFC 2598给出的标准取值也是现在绝大多数网络设备上默认的DSCP到PHB映射。注意AF类的规律数字的十位代表类别编号个位代表丢弃优先级丢弃优先级越大拥塞时被丢得越早。EF只有一个值因为它在每个节点只对应一种“高优先级优先发送”的严格行为。在Linux上验证DSCP标记时我的习惯是先配一条最简单的iptables规则给特定UDP流打上EF标记# 对本机发出的UDP 5004端口流量设置DSCP 46EF iptables -t mangle -A OUTPUT -p udp --dport 5004 -j DSCP --set-dscp 46这里放在OUTPUT链是因为我们模拟的是本机产生的流量如果要验证透传场景规则要放在PREROUTING链对转发流量生效。DSCP target只能用在mangle表放进filter表不会生效这是新手最容易踩的规则位置问题。2.3 边缘与核心的分工复杂度堆在边界核心只做差分论文把DiffServ的工作分成了三块边缘设备、核心路由器、带宽代理BB。边缘设备负责对每个分组进行分类、标记DS域并且做监控和整形核心路由器根据DS域的值选择对应的转发处理带宽代理配置管理规则通过服务级别协定SLA与客户协商资源向用户提供服务质量保证。位置职责开销边缘路由器分类、标记、监控、整形高面向每个流或每类流核心路由器按DSCP查PHB转发低PHB数量有限带宽代理SLA协商、资源分配控制面不参与逐包处理这张表能直接看出这套架构的核心思想把贵的操作全部放在网络入口让核心路由器只做查表和转发。论文原话是“核心路由器所需进行的操作相对简单”所以它能以极高的速度转发分组。这也是为什么DiffServ最终能在实际网络里大面积部署而IntServ一直停留在实验室和小规模专网的原因。3. 绝对区分服务的落地实现EF、AF与RIO算法的完整拆解3.1 EF加速转发想模拟租用线路先解决排队条件论文把EF描述成“和租用线路相近的服务质量”低时延、低时延抖动、低丢失率、确保带宽。要实现这个目标路由器里存放EF数据的队列长度必须很小。只有当数据到达速率大于离开速率时分组才会排队换句话说只要在每个节点保证用户数据的到达速率小于该节点转发这种数据的速率队列就不会持续堆积。论文给出了两个保证条件。第一在任何时刻路由器转发EF数据的速率不低于要确保的带宽。第二边缘路由器保证用户数据的到达速率小于确保带宽。第一点靠调度实现第二点靠入口监控实现两者缺一不可。具体到路由器内部常见做法是把EF分组的优先级设为最高只有EF分组发送完毕后才发送其他分组。因为入口已经用SLA限速了所以不用担心EF流量占用全部带宽导致其他分组饿死。这里必须强调“入口限速”这一步。如果只在核心设备上调高优先级却没有在入口做监管一个突发20Mbps的EF流就能把链路打满挤占所有AF和BE流量同时造成EF自身丢包。在Linux上用tc模拟这种“确保带宽高优先级”的组合我常用的模板如下# 根队列HTB默认类30 tc qdisc add dev eth0 root handle 1: htb default 30 # 总带宽100Mbps tc class add dev eth0 parent 1: classid 1:10 htb rate 100mbit # EF类锁定10Mbps不允许借用优先级0最高 tc class add dev eth0 parent 1:10 classid 1:11 htb rate 10mbit ceil 10mbit prio 0 # AF类保证5Mbps允许借用优先级2 tc class add dev eth0 parent 1:10 classid 1:12 htb rate 5mbit ceil 100mbit prio 2 # 按防火墙mark 46映射到EF类 tc filter add dev eth0 parent 1:0 protocol ip prio 1 handle 46 fw classid 1:11rate是保证速率ceil是上限。EF类ceil也设成10Mbps表示它最多只能用10M这就是“转发速率不低于确保带宽”与“到达速率不高于确保带宽”两个条件在实现上的结合。AF类ceil放开到100M表示它可以借用剩余带宽但前提是EF的10M先被满足。配合前面那条iptables的DSCP标记还需要把DSCP再转成MARK才能被fw分类器识别iptables -t mangle -A OUTPUT -p udp --dport 5004 -j DSCP --set-dscp 46 iptables -t mangle -A OUTPUT -p udp --dport 5004 -j MARK --set-mark 46两条规则都挂在OUTPUT链上顺序建议让MARK紧跟DSCP避免后续filter看到未标记状态。实际部署时还要注意DSCP标记和MARK标记都只能作用在mangle表如果漏了第二条MARK规则tc filter的fw分类器匹配不到任何包表现为队列统计里EF类始终没有流量。3.2 AF保证转发RIO双RED算法与门限参数设计AF的目标和EF完全不同。EF是严格保证带宽和时延AF则是把流量分成若干类别路由器为每个类别提供一定的转发资源缓存、带宽每个类别再分成几个丢弃级别高优先级分组被丢弃的概率小于低优先级分组。这里有一个很容易踩的细节论文特别强调所有属于同一类别的分组不论优先级如何都必须放进同一个队列处理目的是避免乱序。优先级差异只体现在丢弃概率上不体现在队列划分上。乱序对TCP的杀伤力远大于轻微丢包这个取舍在真实网络里非常重要。RIO算法正是为了实现“同类别、不同丢弃概率”设计的。RIO实际上是同时运行两个REDRandom Early Detection算法一个针对遵守协定的分组in-profile另一个针对超出约定速率的分组out-profile。每个队列维护两组门限分别对应两条丢弃曲线。参数入圈分组in-profile出圈分组out-profile说明min_th队列深度的50%队列深度的20%低于此值不丢弃max_th队列深度的80%队列深度的50%高于此值全部参与丢弃max_p0.020.10最大丢弃概率weight0.0020.002平均队列长度计算的EWMA权重上面这组是典型起始值不是RFC强制的绝对值。核心逻辑是out-profile曲线的min_th更小、max_p更大所以在同一队列长度下不守规矩的分组先被随机丢弃守规矩的分组即使拥塞被丢弃的概率也控制在很低水平。RIO的行为可以概括成三段。队列长度小于min_th时什么都不丢。队列长度在min_th和max_th之间时随机丢弃out-profile分组in-profile基本不动。队列长度超过max_th说明已经发生拥塞所有分组都被随机丢弃但out-profile被丢得更狠。这样只要用户自己的流量遵守SLA拥塞时也能拿到可靠服务多发出去的那部分网络不承诺。论文也点出了绝对区分服务的代价端到端服务质量能不能保证需要在“保证服务质量、提高网络利用率、数据聚类精度”之间做折中。为了让路径固定可能需要做route pinning而路径绑定本身会阻碍绝对区分服务的大规模推广。这是1999年就写清楚的边界今天看依然成立。3.3 入口监管器违反SLA之后的流量去哪了无论是EF还是AF入口路由器的监控都是整套机制的起点。论文的说法是“违反服务级别协定的流量会被丢弃”但在实际设备上处理方式不止“丢弃”这一种通常按流量超出的程度分三档处理。第一档速率在SLA允许范围内直接放行并标记为in-profile。第二档速率超过约定值但还在可容忍范围内在AF场景下做降级处理把超出部分标记为out-profile拥塞时优先丢弃在EF场景下由于EF本身不允许超出入口会直接丢弃超出的部分。第三档速率严重超额比如超过约定速率的两倍无论EF还是AF都直接丢避免个别用户拖垮整个出口。这种分级处理在Linux上用tc的police就能轻松模拟# 在EF类上做10Mbps监管突发2M超速的直接丢 tc qdisc add dev eth0 parent 1:11 handle 20: police rate 10mbit burst 2m droppolice和rate/ceil的区别一定要分清rate/ceil决定队列的长期服务速率police则是对瞬间到达速率做判断。EF入口上police是必须的否则任何一次突发都会直接放大到出口队列违背“到达速率小于转发速率”的前提。4. 相对区分服务的三种调度算法严格优先级、WFQ与WRP怎么选绝对区分服务给用户确定性承诺但那份承诺要靠SLA协商、入口监管、route pinning一系列机制撑着。论文后半部分讨论另一种思路——相对区分服务。它不承诺端到端带宽或时延只保证服务级别i得到的服务质量不低于级别i-1最后用哪个级别由用户自己选。这种模型下路由器不需要端到端资源预留不需要接纳控制只需要保证“高级别数据得到更好的服务”。论文指出实现上要满足两个特性一致性即任何时刻高级别都要得到更好的服务可控性即ISP能调整各级别之间的服务差别用来做差异化运营。下面三种调度算法就是在这个框架下做的取舍。4.1 严格优先级实现最简单但低级别可能饿死严格优先级调度的规则一句话就能说清只要队列里有高级别分组低级别人一律靠边。只有高级别分组全部发完低级别才有机会被服务。所以在任何链路负荷下高级别分组得到的服务质量一定比低级别好一致性天然满足。代价也很直接运营商没有任何调整余地而且一旦高级别流量持续存在低级别分组可能在很长一段时间内完全得不到服务。真实网络里几乎没有人在公网接口上直接跑严格优先级也是这个原因。它适合的场景是控制面和数据面分离比如路由协议报文走最高优先级的控制队列那部分流量极小不需要担心饿死问题。4.2 WFQ按比例分带宽短期一致性会崩WFQ的思路是按比例给每个级别分配带宽。论文给出了服务量相等的条件任意两个级别在相同时间区间内接受的服务量除以各自权重结果相等。实现时先估计每个级别的到达速率Ai再为级别i选取服务速率使级别越高、服务速率与到达速率的比值越大这样高级别自然拿得多。用现代设备上的术语说这对应CBWFQ或者按权重分配的队列调度。它比严格优先级灵活运营商可以调节权重来控制各级别之间的服务质量差距可控性有了。但WFQ有个先天问题论文直接点破了WFQ的比例是长期平均意义上的。如果在一段很短的时间内观察各级别分组的时延和这段时间内每个级别的到达负荷强相关。某个瞬间高级别流量突发低级别分组就会在短时间内得不到应有的服务比例——一致性在短时间尺度上不成立。如果你的业务对时延抖动敏感WFQ在突发场景下会很难看。4.3 WRP用等待时间驱动调度动态跟随负荷WRP是论文引用的比例区分服务调度方案思路比WFQ更聪明。它不再用固定权重分配带宽而是给每个分组算一个发送优先级值这个值和两个因素有关该级别预设的服务质量区分参数c以及这个分组已经在队列里等待的时间w(t)。用公式表达就是P(t) c × w(t)P值最大的分组先被发送。几个级别的c从小到大排高级别取更大的c。当一个高级别分组的等待时间增长时它的P值增长得比低级别快得多于是它会很快被提上来优先发送。反过来如果某个级别的到达速率远大于服务速率它的分组平均等待时间会持续增大P值也持续增大调度器就会给这个级别更多的服务机会。这正是WFQ缺的那块WRP能根据链路负荷动态调整为每个级别服务的速率不需要外部测量动作。论文引用的仿真结果显示在网络负荷较重时即使观察窗口很短WRP为每个级别分配的带宽也近似与c成正比而WFQ在这种情况下表现差得多。代价同样写在论文里WRP只考虑了排队时延没有把丢包率放进服务质量定义它对TCP流的表现还需要进一步研究。如果网络里全是UDP或RTP流时延区分能成立一旦混入大量TCP丢包和拥塞窗口的变化会让“时延比例”变得很难维持。4.4 三种算法怎么选算法一致性可控性实现复杂度主要风险严格优先级最好无最低低级别饿死WFQ长期好、短期崩好中突发时一致性无法保证WRP动态自调节好高只处理时延指标丢包纳入模型有限如果是自己搭实验环境验证这三个算法最简单的做法是用tc分别模拟prio qdisc近似严格优先级HTB的类权重近似WFQ而WRP没有现成的qdisc需要写成离散事件仿真来验证。另外还有一个容易被忽略的点相对区分服务里用户关心的不是单个路由器内部的行为而是整个区分服务域内无论负荷和路径如何变化高级别数据是否始终端到端更好。论文明确指出上述方法是否能在多节点组成的域内满足这个要求当时“还有待进一步研究”。也就是说单节点调度算法做得再好跨节点的差分质量也没人打保票。设计实验方案时至少要有两个节点串联验证别只在一个路由器上测出结果就下结论。5. 复现DiffServ的常见问题排查五个容易翻车的现场下面这些坑是我把论文思路搬到eNSP和Linux环境里复现时真实遇到过的按“现象→原因→解决”写清楚。5.1 抓包永远看不到DSCPIP头里ToS字段一直是0现象用iptables打了DSCP标记在接口上用tcpdump抓包过滤出来的分组IP头第二个字节还是0Wireshark里看不到任何DSCP值。原因最常见的是接口不信任分组的DSCP。在华为AR路由器上接口默认不信任DSCP或IP优先级即使报文带着标记转发时也会被重写Linux这边如果iptables规则挂在POSTROUTING而流量走的是转发路径或者规则的匹配条件比如端口没对上标记动作根本没有执行。解决Linux上先看规则命中计数iptables -t mangle -L -v重点看每行规则前面的计数器是不是在增长。计数不动就检查匹配条件和链位置。华为AR上配置trust dscp让接口信任报文自带的DSCP再做下一跳的队列映射。确认信任关系以后再去抓包不要一上来就怀疑设备坏了。5.2 AF同类别分组乱序TCP性能反而下降现象配置了AF队列同类别分组应该进同一个队列但抓包发现同一个流的分组到达顺序错乱TCP吞吐掉得很厉害。原因RIO的“同类别同队列”只是逻辑层面的要求物理实现里有好几道坎。第一等价多路径ECMP按五元组hash时同一流的包可能因为hash字段变化被分到不同路径时延差造成乱序。第二某些设备的WRED把同一类分组散到多个内部队列处理。解决检查出接口是否启用了ECMP尽量让同一流的hash键固定。仿真环境里用GNS3或eNSP时如果有多条链路先把AF业务固定绑定到一条链路上验证RIO本身的行为等RIO行为验证通过后再单独测试ECMP对乱序的影响。注意RIO本身不解决多路径带来的乱序它解决的只是单节点内队列分布问题。5.3 EF只调了优先级没做入口限速一条流打穿链路现象EF流量确实被优先转发了但一个持续UDP流把整条100Mbps链路打满AF和BE全部饿死EF自己也出现丢包时延并没有变好。原因这正是论文强调的第一个条件被忽略——边缘路由器必须保证用户数据的到达速率小于确保带宽。核心设备把EF优先级拉满只能保证“EF的包永远先发”但这个包如果不受控高优先级反而成了放大故障的工具。解决在所有EF入口接口上做监管速率设成SLA协商值的90%左右burst设成几个TCP MSS的量级。Linux上配合tc police或者HTB的rate/ceil双限制都能达到这个效果。我一般会在测试机上把入口限制按10Mbps、burst 2Mbps写死EF任何时刻都不能超过这个数字然后再谈调度优先级。5.4 WFQ在突发流量下时延抖动超过低级别预期现象跑WFQ时长时间看带宽比例是符合权重的但压入一个视频突发流后低级别流的时延出现几百毫秒的尖峰甚至比BE还差。原因WFQ的比例保证是长期平均的短期一致性差。论文里明确指出了这一点只是实验时容易被“比例正确”的表象骗过去。解决如果业务有实时性要求不要单独依赖WFQ。把EF或LLQ拿出来给实时应用锁定带宽和优先级剩余流量再交给WFQ按权重分配。这样实时业务的突发不会渗入WFQ权重池低级别的时延尖峰自然被压住。说到底WFQ适合的是“相对公平”不适合“有硬时延需求的服务”。5.5 RIO门限参数拍脑袋入圈分组也被大批丢弃现象按默认RED参数配了RIO拥塞测试时in-profile分组丢弃概率远超预期SLA用户投诉服务质量不达标。原因min_th设得太低。队列长度在正常情况下就会超过min_th于是随机丢弃一直在发生或者in-profile和out-profile两条RED曲线的max_p没有拉开差距出圈分组没有得到“先死”的惩罚入圈分组被连带误伤。解决先摸清队列的真实深度。用设备上的queue统计观察平均队列长度把in-profile的min_th放在平均队列深度的150%左右开始介入max_p压到0.02量级out-profile的min_th放在平均队列长度附近max_p可以放到0.1。记住RIO的设计意图是“入圈分组容忍短暂突发出圈分组承担主要代价”两条曲线的门限必须拉开足够间距这个间距就是为容忍突发预留的缓冲。6. 验证技巧用抓包与tc确认DSCP和队列行为6.1 三步验证DSCP注入与转发链路第一步验证标记点确实打了值。用Wireshark加一列ip.dsfield.dscp或者直接在tcpdump里过滤非零DSCP# 只抓带DSCP标记的IP包0xfc掩码取ToS字段的高6位 tcpdump -i any ip[1] 0xfc ! 0过滤条件里ip[1]取的是IP头第二个字节也就是ToS字段0xfc对应二进制11111100把低2位ECN屏蔽掉剩下就是DSCP。看到非零值说明标记链路是通的如果全零先检查iptables规则命中和设备接口的trust配置。第二步验证中间节点是否按DSCP执行了预期行为。在核心设备上做端口镜像或者用tcpdump在入接口和出接口各抓一把对比同一个DSCP值进出方向都能看到。中间节点如果改写了DSCP就要查重标记策略和信任模式。第三步验证队列行为。用tc的class统计看哪些类有流量再用iperf3灌流确认EF类被锁在既定速率# 查看eth0根队列上各分类的收发统计 tc -s class show dev eth0看每个class统计里的rate和dropped计数。EF类应该稳定在rate附近超出部分被丢AF类可以借用带宽但上限不超过ceilBE类只在低优先级剩余带宽里活动。这套统计比抓包更直接能确认调度器到底按配置跑了没有。6.2 用iperf3验证限速是否生效先用UDP灌一个高带宽流验证EF类的硬顶# 服务端 iperf3 -s -p 5004 # 客户端打8Mbps的UDP流--tos 184即0xB8对应EF标记 iperf3 -c 127.0.0.1 -p 5004 -u -b 8m -t 30 --tos 184--tos 184对应十进制的0xB8也就是EF标记和iptables设置DSCP 46效果等价。如果tc里EF类限速10Mbps把iperf3的发送速率调到20Mbps接收端应该只有10Mbps左右的实际带宽而且丢包计数会明显上升。大量丢包就是监管器在工作的直接证据也是整套DiffServ配置最终生效的标志。从那以后我每次做QoS实验都强制先走一遍“DSCP注入→接口信任→队列统计”这条链确认每个环节有数据支撑再调参数而不是直接在设备上拍门限值。这份1999年的论文扫描版虽然队列门限和PHB定义后来被RFC更新过但“边缘分类、核心区别转发、相对区分服务的一致性”这套骨架一直没变值得完整读一遍原稿尤其是RIO和WRP的推导段落。希望帮到你。本文还有配套的精品资源点击获取