ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

交换芯片控制通路设计:解析、查表、调度与可编程流水线

交换芯片控制通路设计:解析、查表、调度与可编程流水线 1. 控制通路到底在交换芯片里扮演什么角色聊交换芯片大多数人第一反应是 SerDes、Buffer、Crossbar 这些数据面的东西因为它们是实打实搬数据的。但真在项目里调过交换机 ASIC 的人都知道一颗芯片能不能用得顺手、能不能适配五花八门的协议八成取决于控制通路设计得好不好。数据通路决定跑多快控制通路决定能跑什么、怎么跑、跑得对不对。所谓控制通路说白了就是芯片里负责“做决定”的那套逻辑。一个包从端口进来芯片得先知道它是什么解析再决定它该去哪查表然后安排它在什么时间、从哪个口出去调度最后还得保证这些规则能按业务需求随时改可编程流水线。这四件事串起来就是控制通路的全部工作。我做过几个基于商用交换芯片的盒式交换机项目也参与过自研流水线的验证最大的感受是数据面的坑往往是物理层的调一调均衡、改改驱动就能过控制通路的坑是逻辑层的一个表项没匹配上、一个调度权重配错现象可能是“大部分流量正常个别业务偶发丢包”排查起来能耗掉一整周。所以这篇就按解析、查表、调度、可编程流水线这四块把控制通路拆开讲透顺带把踩过的坑和实操细节都摊开。这篇文章适合两类人看一类是刚接触交换芯片、想搞明白“包进来之后芯片内部到底发生了什么”的工程师另一类是在做网络设备选型、需要判断某颗芯片能不能满足业务需求的技术负责人。看完你应该能对着芯片手册把控制通路的关键模块和配置点对上号。2. 解析模块包进来第一件事是“读懂它”2.1 解析器在流水线里的位置和基本结构解析Parser是控制通路的第一站位置紧跟在 MAC 层之后、查表之前。它的任务很纯粹把一串字节流翻译成芯片内部能理解的字段集合。你可以把它想象成快递分拣中心的第一道扫码枪扫出收件地址、重量、品类后面所有环节都依赖这些信息。一个典型的解析器由三部分组成协议识别状态机、字段提取逻辑、元数据组装单元。协议识别状态机负责判断“这层是什么协议”比如以太网头里的 EtherType 是 0x0800 就跳到 IPv4 解析是 0x86DD 就跳到 IPv6。字段提取逻辑按固定偏移把关键字段抠出来比如目的 MAC、源 IP、目的 IP、TCP 端口号。元数据组装单元把这些字段打包成一个内部结构通常叫 Parse Metadata 或者 Packet Header Vector后面查表和调度都读这个结构。这里有个容易被忽略的点解析深度。很多芯片手册会写“支持 128 字节解析深度”或者“支持 6 层协议嵌套”这个数字直接决定了你的业务能不能被正确识别。比如做 VXLAN 场景外层 IP 加 UDP 加 VXLAN 头加内层以太网加内层 IP轻松就超过 100 字节。如果解析深度不够内层字段就抠不出来基于内层五元组的 ACL 直接失效。2.2 固定解析与可编程解析的取舍早年的交换芯片基本都是固定解析硬件逻辑写死支持以太网、IPv4、IPv6、TCP、UDP 这几种组合。好处是快、省面积坏处是遇到新协议就抓瞎。后来 P4 语言火了之后可编程解析器成了主流芯片里放一堆可配置的状态机和字段提取器用的时候通过配置表告诉它“遇到什么值跳什么状态、从哪个偏移抠多少位”。但可编程不是没有代价的。我实测过同一颗芯片在固定解析和可编程解析两种模式下的表现可编程模式下解析延迟会增加 15% 到 30%因为状态机跳转和字段提取都走查表逻辑比硬连线慢。而且可编程解析器的配置表本身占 TCAM 资源配得越复杂留给 ACL 的 TCAM 就越少。所以选型时的判断逻辑很简单如果你的业务协议栈是标准的、未来两三年不会大改固定解析够用且更省资源如果你在做自定义协议、或者需要支持 VXLAN、GENEVE、SRv6 这类封装变化快的场景可编程解析是必须的。我个人的经验是做数据中心 ToR 交换机可编程解析基本是标配因为 overlay 协议迭代太快了。2.3 解析模块的实操配置要点配置解析器的时候有几个参数必须盯死。第一个是起始偏移也就是从帧的哪个字节开始解析。标准以太网是 0但如果你的设备要处理带 VLAN Tag 的帧就得告诉解析器“先看 TPID 是不是 0x8100是的话偏移加 4 再继续”。这个逻辑在可编程解析器里通常用一张“下一状态表”来描述。第二个是字段掩码。很多芯片允许你对提取出来的字段做掩码比如只取目的 IP 的前 24 位做网段匹配。这个功能在做路由聚合的时候特别有用但要注意掩码是在解析阶段做的掩码后的值会覆盖原始值后面查表看到的就是掩码后的结果。我有一次调一个 ACL 规则明明写的 /24 匹配结果 /16 的流量也被命中了查了半天发现是解析阶段的掩码配错了。第三个是异常处理策略。包解析失败怎么办是直接丢弃、还是打上“解析失败”标记后继续走后续流程这个策略在不同芯片上叫法不同有的叫 Parser Error Action有的叫 Exception Handling。我的建议是打标记后继续让后面的 ACL 去决定丢不丢这样调试的时候能看到“哪些包解析失败了”直接丢的话连统计都看不到。注意解析器的配置表通常和 ACL 表共享 TCAM配置前一定要算清楚 TCAM 预算。我见过一个项目解析器配了 8 层协议嵌套直接把 TCAM 用掉 70%后面 ACL 规则只能配几条业务根本跑不起来。3. 查表引擎芯片的“决策大脑”3.1 查表引擎的几种硬件实现查表Lookup是控制通路里最复杂的部分因为它要在一堆表里找到匹配的条目然后执行对应的动作。硬件实现上主要有三种TCAM、SRAMHash、多级流水线。TCAM 的特点是并行匹配一个时钟周期就能把所有条目比一遍所以它适合做 ACL、路由表这类需要“最长前缀匹配”或者“多字段匹配”的场景。但 TCAM 贵、功耗高、容量小一颗芯片里通常只有几 Mb。SRAMHash 适合精确匹配比如 MAC 地址表、精确流表容量可以做到几十 Mb但哈希冲突需要额外处理。多级流水线是现在高端芯片的主流把查表拆成好几级每级做一部分匹配用流水线换频率。我参与过一个 25.6T 芯片的验证项目它的查表引擎就是多级流水线结构第一级做端口和 VLAN 匹配第二级做 MAC 和 IP 匹配第三级做 ACL 和 QoS 匹配。每级之间用 Metadata 传递信息好处是每级可以独立配置、独立扩容坏处是延迟累加一个包走完三级大概要 200 到 300 纳秒。3.2 查表键值的设计与优化查表效率高不高七成取决于键值Key设计得好不好。键值就是“拿什么字段去查表”设计原则是能精确定位就不要模糊匹配能少用字段就不要多用字段。举个例子做二层转发查 MAC 表键值就是目的 MAC 加 VLAN ID。这两个字段加起来 60 位用 Hash 表存冲突率很低。但如果你把源 MAC 也加进键值表项数量直接翻倍而且大部分场景下源 MAC 对转发决策没用。我见过一个新手把五元组全塞进 MAC 表键值结果表项爆炸芯片直接报资源不足。对于 ACL 这种需要多字段匹配的场景键值设计更讲究。通常的做法是分层先按 EtherType 分大类再按 IP 协议号分小类最后按端口号精确匹配。这样每一层的表项数量都可控TCAM 利用率能提高不少。还有一个技巧是键值压缩。比如 IPv6 地址 128 位但很多场景下只需要匹配前 64 位网段这时候可以用前缀压缩把 128 位压成 64 位甚至更少。芯片手册里通常会写支持“IPv6 前缀压缩”或者“Key Compression”配的时候记得打开。3.3 查表结果的执行与动作表查表查到之后要执行动作动作存在动作表Action Table里。动作表通常和查表引擎分离查表输出一个 Action Index动作表根据这个 Index 取出具体动作比如“修改目的 MAC”“减 TTL”“加 VLAN Tag”“转发到端口 5”。动作表的设计有个关键点动作复用。如果每个表项都配一套独立动作动作表会非常大。实际芯片通常支持“动作模板”多个表项共享同一个动作模板只改参数。比如所有走默认路由的包都共享一个“减 TTL 并转发到下一跳”的模板只是下一跳 MAC 不同。配置动作表的时候要注意动作顺序。有些芯片允许一个包执行多个动作比如先改 DSCP 再转发这时候动作的执行顺序会影响结果。我踩过一次坑配了“先加 VLAN Tag 再查 ACL”结果 ACL 匹配的是加 Tag 前的字段规则全乱了。后来改成“先查 ACL 再加 Tag”才正常。所以配动作表之前一定要把流水线的阶段顺序搞清楚。查表类型硬件实现典型容量适用场景延迟量级MAC 表SRAMHash64K-256K 条目二层转发50-100ns路由表TCAMSRAM16K-128K 条目三层转发100-200nsACL 表TCAM2K-16K 条目安全过滤50-150ns流表SRAMHash64K-1M 条目精确流匹配50-100ns4. 调度器决定谁先走、谁后走4.1 调度在控制通路里的位置调度Scheduling严格来说横跨控制通路和数据通路但调度决策的逻辑——比如权重计算、队列选择、丢弃判断——属于控制通路。调度器的工作是当多个队列都有包要发的时候决定先发哪个、发多少、什么时候丢。交换芯片里的调度通常分两级队列调度和端口调度。队列调度决定同一个端口下多个队列的发送顺序端口调度决定多个端口之间的发送顺序。大部分场景下队列调度用加权轮询WRR或者差额轮询DRR端口调度用严格优先级SP或者加权公平队列WFQ。我调过一个数据中心 ToR 的调度配置业务反馈“存储流量偶尔卡顿”。查下来是存储流量和计算流量在同一个队列里计算流量突发的时候把队列占满了存储流量被挤掉。后来把存储流量单独分一个队列配了最小带宽保证问题就解决了。这个案例说明调度配置不是配完就行得结合业务流量模型去调。4.2 调度算法的选择与参数计算WRR 是最常用的队列调度算法核心参数是每个队列的权重。权重的计算逻辑是权重比等于带宽比。比如端口总带宽 100G队列 0 要保证 50G队列 1 要保证 30G队列 2 要保证 20G那权重就配 5:3:2。但 WRR 有个问题它按包个数轮询不按字节数。如果队列 0 的包平均 1500 字节队列 1 的包平均 64 字节同样权重下队列 0 实际占用的带宽会大很多。这时候要用 DRRDRR 按字节数轮询能保证带宽比例准确。所以选 WRR 还是 DRR取决于你的流量包长分布。如果包长比较均匀WRR 够用如果包长差异大必须用 DRR。对于延迟敏感的业务比如语音、实时控制要用严格优先级SP。SP 的逻辑是“高优先级队列不空低优先级队列永远不发”。这个机制能保证低延迟但风险是高优先级流量突发会把低优先级流量饿死。所以 SP 通常只给很小的流量用比如语音这种带宽占比不到 5% 的业务。还有一个参数是队列深度。队列太浅突发流量来了就丢包队列太深延迟会变大。我的经验值是对于数据中心场景队列深度配 64 到 128 个包长比较合适对于广域网场景因为带宽收敛比大队列深度要配到 256 以上。4.3 拥塞管理与丢弃策略调度器不光是“发”还要管“丢”。当队列满了新来的包怎么办这就是拥塞管理要解决的问题。常见的策略有尾丢弃、RED、WRED。尾丢弃最简单队列满了就丢新包。问题是它会导致全局同步多个 TCP 流同时发现丢包同时降速然后同时加速网络利用率忽高忽低。RED 的做法是队列没满就开始随机丢包提前给 TCP 流发信号避免全局同步。WRED 是 RED 的加权版本对不同优先级的流量用不同的丢弃阈值。配置 WRED 的时候三个参数最关键最小阈值、最大阈值、最大丢弃概率。最小阈值是开始丢包的队列深度最大阈值是丢包率达到最大值的队列深度最大丢弃概率是丢包率的上限。我的经验是最小阈值配队列深度的 50%最大阈值配 90%最大丢弃概率配 10% 到 20%。这样既能提前预警又不会丢太多包。提示WRED 对 TCP 流量有效对 UDP 流量基本没用因为 UDP 不会因为丢包降速。如果你的业务里 UDP 占比高WRED 配了也是白配不如直接配队列限速。5. 可编程流水线让芯片“随业务而变”5.1 可编程流水线的架构演进可编程流水线是最近几年交换芯片最大的变化。早年的芯片流水线是固定的解析、查表、执行、调度每个阶段做什么都是硬件写死的。业务要改只能换芯片。后来 P4 语言出现芯片开始支持“用 P4 描述流水线编译成硬件配置”这才有了可编程流水线。可编程流水线的架构通常分两种RMTReconfigurable Match Table和FlexPipe。RMT 的核心思想是把流水线拆成多个 Match-Action 阶段每个阶段做一次查表和动作执行阶段之间用 Metadata 传递信息。FlexPipe 更灵活允许动态调整每个阶段的资源配比比如某个阶段需要更多 TCAM就多分一点。我实测过 RMT 和 FlexPipe 两种架构的芯片RMT 的优点是编程模型简单、P4 编译器支持好缺点是阶段数固定资源不够的时候只能干瞪眼。FlexPipe 的优点是资源弹性缺点是编程复杂P4 编译器要针对芯片做特殊优化。选型的时候如果团队 P4 经验丰富FlexPipe 更合适如果刚起步RMT 更容易上手。5.2 P4 程序的关键结构写 P4 程序有几个关键结构必须搞清楚Header、Parser、Table、Action、Deparser。Header 定义协议头的字段布局比如以太网头的 dstAddr、srcAddr、etherType。Parser 定义解析状态机告诉芯片“先解析以太网根据 etherType 决定下一步解析 IPv4 还是 IPv6”。Table 定义查表逻辑包括键值、动作、默认动作。Action 定义查到之后做什么比如改字段、转发、丢弃。Deparser 定义怎么把修改后的字段重新组装成包。写 P4 最容易出错的地方是Parser 的状态转移。P4 的 Parser 是显式状态机每个状态要写清楚“提取哪些字段、根据什么值跳转到哪个状态”。如果状态转移写漏了遇到不认识的协议值就会解析失败。我建议在 Parser 里加一个 default 状态遇到未知协议值就跳到 default打上标记后继续而不是直接丢包。另一个坑是Table 的 Key 和 Action 的匹配。P4 的 Table 支持多种匹配类型exact、ternary、lpm、range。exact 是精确匹配ternary 是带掩码的匹配lpm 是最长前缀匹配range 是范围匹配。不同匹配类型消耗的硬件资源不同exact 最省ternary 最贵。所以设计 Table 的时候能用 exact 就别用 ternary。5.3 可编程流水线的资源预算与编译优化可编程流水线最大的约束是资源。TCAM、SRAM、ALU、Metadata 总线宽度这些都是有限的。写 P4 程序的时候编译器会告诉你每个阶段用了多少资源如果超了就得优化。优化的手段主要有几个。第一是合并 Table把多个小 Table 合并成一个大 Table减少阶段数。第二是简化 Key去掉不必要的匹配字段减少 TCAM 消耗。第三是复用 Action多个 Table 共享同一个 Action减少 ALU 消耗。第四是调整阶段划分把资源需求大的 Table 单独放一个阶段避免和其他 Table 抢资源。我做过一个 SRv6 的 P4 程序一开始编译出来用了 12 个阶段芯片只有 8 个阶段根本跑不了。后来把三个小 Table 合并成一个Key 从 10 个字段减到 6 个Action 从 8 个减到 4 个最后压到 7 个阶段刚好能跑。这个过程花了整整两周但值得因为一旦跑通后面加业务就只是改 Table 的事。优化手段资源节省适用场景注意事项合并 Table减少阶段数多个小 Table 逻辑相似合并后 Key 可能变宽简化 Key减少 TCAM匹配字段过多确保不影响匹配精度复用 Action减少 ALU多个 Table 动作相似参数化设计调整阶段划分平衡资源某阶段资源紧张可能增加延迟6. 控制通路的联调与问题排查实录6.1 解析与查表不匹配的典型现象联调阶段最常见的问题是“解析出来的字段和查表用的字段对不上”。现象通常是配置了一条 ACL 规则预期命中某些流量但实际统计显示命中数为零。排查思路是逐级验证。第一步抓包确认流量确实进来了而且字段值符合预期。第二步读芯片的解析统计寄存器确认解析器识别出了正确的协议类型。第三步读查表统计寄存器确认查表引擎收到了正确的 Key。第四步读动作统计寄存器确认动作执行了。我遇到过一次ACL 规则匹配 TCP 目的端口 443但统计为零。抓包发现流量是 HTTPS端口确实是 443。读解析统计发现解析器把包识别成了 UDP因为解析器的状态转移表里IP 协议号 6TCP被误配成了 17UDP。改过来就好了。这个问题的根因是配置表写错但现象是“ACL 不生效”很容易误导排查方向。6.2 调度配置错误的排查方法调度问题比解析问题更难查因为调度是“软”的没有明确的错误码。典型现象是某些流量延迟高、某些流量丢包、带宽不达标。排查调度问题第一步是看队列统计。每个队列的入队速率、出队速率、丢弃计数、当前深度这些数据能告诉你队列是不是满了、是不是被限速了。第二步是看端口统计。端口的发送速率、接收速率、暂停帧计数能告诉你端口是不是拥塞了。第三步是看调度器状态。有些芯片能读出当前哪个队列在被调度、调度权重是多少。我调过一个“带宽不达标”的问题端口 100G业务要求某个队列保证 50G但实测只有 30G。查队列统计发现队列深度一直是满的说明入队速率大于出队速率。查调度配置发现权重配的是 5但端口总权重是 20实际分到的带宽是 100G 乘以 5/20 等于 25G。把权重改成 10带宽就上去了。这个问题的教训是权重是相对值不是绝对值配之前要算清楚总权重。6.3 可编程流水线的编译与加载问题可编程流水线的联调有个特殊环节编译和加载。P4 程序写完要编译成芯片能执行的配置然后加载到芯片里。这个过程容易出两类问题编译报错和加载失败。编译报错通常是资源超限编译器会告诉你哪个阶段超了、超了多少。这时候按前面说的优化手段去调就行。加载失败通常是配置表和芯片版本不匹配比如 P4 程序用的指令集版本和芯片固件版本不一致。这时候要检查芯片手册里的“P4 指令集版本”和编译器版本是否对齐。还有一个坑是热加载。有些芯片支持不中断业务加载新配置但热加载过程中表项会短暂失效导致丢包。如果业务对丢包敏感热加载要放在维护窗口做。我见过一个项目运维在业务高峰期热加载 P4 配置结果丢了 200 毫秒的包被业务方投诉了。后来改成凌晨加载问题就没了。6.4 常见问题速查表现象可能原因排查方法解决措施ACL 不命中解析字段错误读解析统计寄存器修正解析状态转移表带宽不达标调度权重配错读队列和端口统计重新计算权重延迟高队列深度过大读队列深度统计减小队列深度丢包队列满或 WRED 阈值低读丢弃计数调整队列深度或 WRED 参数编译失败资源超限看编译器资源报告合并 Table、简化 Key加载失败版本不匹配检查指令集和固件版本对齐版本热加载丢包表项短暂失效抓包看丢包时间点维护窗口加载7. 几个容易被忽略的实操细节7.1 Metadata 总线宽度的隐性约束可编程流水线里阶段之间靠 Metadata 传递信息。Metadata 总线宽度是固定的比如 256 位或者 512 位。每个阶段往 Metadata 里塞的字段不能超过总线宽度超了就得拆成多个阶段或者把字段压缩。这个约束在写 P4 的时候很容易忽略因为 P4 语言层面不限制你定义多少字段但编译的时候会报“Metadata 超宽”。我的经验是设计阶段就把 Metadata 预算列出来每个字段占多少位加起来不能超过总线宽度的 80%留 20% 给后续扩展。我见过一个项目Metadata 用到 95%后面想加一个 VLAN 字段都加不进去只能重构。7.2 表项老化与同步的坑MAC 表和流表通常有老化机制一段时间没匹配就删除。老化时间配得太短表项频繁删除重建查表命中率下降配得太长表项占着资源不释放新流量进不来。我的经验值是MAC 表老化时间配 300 秒流表配 60 秒ACL 表不老化。还有一个坑是表项同步。在多芯片堆叠或者分布式转发场景下表项要在多个芯片之间同步。同步延迟会导致短暂的黑洞比如芯片 A 已经学到 MAC 地址芯片 B 还没学到流量从 B 进来就找不到出口。解决办法是用“同步确认”机制表项同步到所有芯片后才生效。这个机制会增加控制面延迟但能避免黑洞。7.3 调试寄存器的使用技巧交换芯片通常有一堆调试寄存器能读出流水线各阶段的统计和状态。这些寄存器是排查问题的利器但手册里往往写得很简略得自己摸索。我的习惯是项目一开始就把关键寄存器列一个清单包括解析统计、查表统计、动作统计、队列统计、端口统计。联调的时候先读统计确认问题出在哪个阶段再深入看具体表项。这样比盲目抓包效率高得多。还有一个技巧是镜像。很多芯片支持把特定流量镜像到指定端口抓包分析。镜像配置的时候要注意镜像口带宽如果镜像流量超过镜像口带宽镜像包会丢抓到的包就不完整。我一般把镜像口配成和业务口同带宽或者用采样镜像只镜像 1% 的流量。8. 从项目经验看控制通路的选型与设计做了这么多项目我总结下来控制通路的选型和设计要围绕三个问题业务需要什么协议、需要多灵活、需要多少表项。业务协议决定解析器的能力。如果业务全是标准以太网和 IPv4固定解析够用如果有 VXLAN、SRv6、自定义协议必须可编程解析。灵活性决定流水线架构。如果业务规则固定、几年不变RMT 够用如果业务规则经常变、需要快速迭代FlexPipe 更合适。表项数量决定查表引擎的规格。MAC 表要 64K 以上路由表要 16K 以上ACL 表要 2K 以上流表要 64K 以上这些是底线。还有一个容易被忽略的点是控制面接口。交换芯片通常通过 PCIe 或者以太网管理口和控制面 CPU 通信接口的带宽和延迟直接影响表项下发速度。如果业务需要快速收敛比如路由协议震荡后要快速更新转发表控制面接口的延迟就不能太高。我见过一个项目控制面接口用的是低速管理口路由收敛花了 500 毫秒业务方接受不了后来换成 PCIe 才降到 50 毫秒。最后说一个我个人的体会控制通路的调试七分靠统计三分靠抓包。统计能告诉你“哪里出了问题”抓包能告诉你“具体是什么问题”。但统计是芯片内部的状态抓包是外部观察两者结合才能快速定位。所以项目一开始就要把统计寄存器摸清楚别等到出问题了才翻手册。
返回列表