简介这份2018年Cisco Live技术讲座PDF面向数据中心网络工程师、思科Nexus学习者与架构选型人员聚焦Nexus 9000系列交换机从芯片到系统的内部架构帮助读者理解Cloud Scale ASIC、模块化9500与TOR 9300的硬件转发机制及平台差异。资源包仅含1个PDF文件大小约3.56MB内容以幻灯片形式组织围绕数据中心与硅策略、云规模架构、ASIC、转发特性、交换平台和Packet Walks展开。已有286人学习适合作为N9K硬件架构的专题参考资料。其价值在于以厂商视角梳理X9400/X9600-R等线卡所采用的Broadcom芯片与Cisco自研芯片路线结合硬件QoS、拥塞管理、VXLAN及单次隧道封装等特性说明数据包在交换机内部的完整处理路径可用于技术选型、故障排查和知识补强阅读时宜结合较新平台资料对照注意2018年内容的时效边界。1. 交换芯片的真实分水岭不是端口速率而是「切片」怎么切评估一台数据中心交换机多数人先看端口速率和端口密度。但把交换芯片摊开来看真正的分水岭在内部转发面被切成几个自包含的切片、每个切片里有多少块可互换的表项瓦片、报文在这两层之间要走几跳。这份芯片级讲座材料的价值不在参数表而在于把「切片—瓦片—查表流水线」这三层结构一层层剥开解释了两个反直觉的现象为什么同一颗芯片换个初始化模板就能从「路由表吃紧」变成「主机表吃紧」以及为什么一条隧道封装在内层查完表之后不该再走第二遍流水线。搞懂这些再看任何一台云规模交换机的能力边界都不会被端口数字带偏。2. 切片一颗大芯片为什么要拆成多个自包含转发复合体2.1 切片内部到底装了什么切片Slice不是「把端口分组」这么简单它是一个自包含的转发复合体自己拥有独立的入向转发控制器和出向转发控制器只负责芯片上一部分端口。入向侧负责报文解析、分类、转发查表、生成查表键出向侧负责缓冲、排队、调度、复制、重写和出向策略。切片之间的分界线正好落在「查表完成」与「进入出向队列」之间——这个位置不是随便选的它是整条流水线上唯一一个既知道目的地、又还没占用出向缓冲资源的时刻。一次完整的转发路径横着看是这样的报文从入向 MAC 进来先过解析器Parser抽出二层到四层的字段然后进入入向查表管线做分类和转发查找产出一个查表结果结果被送到出向切片出向切片完成缓冲、排队、调度、必要的复制和报文重写最后从出向 MAC 发出去。如果你的流量恰好从同一个切片的入向进、同一个切片的出向出那它压根不碰切片互连一旦跨切片就必须过一次互连。这里藏着一个很容易被忽略的事实切片内的流量和跨切片的流量走的物理路径不同。前者只消耗本切片的查表与缓冲资源后者还要额外占用互连带宽。所以同样是「满配端口、线速转发」一台由两个切片拼成的 1.8T 平台和一台单切片 18×100G 的平台在均匀流量模型下表现接近在集中打向某几个端口的模型下就会分出高下。2.2 为什么切片能「复用」而不是「堆叠」如果只是想把端口做多最直觉的做法是把查表资源做成一份大的、所有端口共享。但真实的芯片设计走的是相反方向把查表资源按切片复制每个切片自己一套。原因在于端口速率和查表带宽的比例关系。一个 100G 端口在线速、小包的情况下每秒要做出上亿次查表决策如果全芯片所有端口共享同一套查表管线这套管线的工作频率和面积会先崩掉而不是端口先崩。把查表逻辑按切片复制等于把「每秒查表次数」这个分母拆小每套管线只服务自己那几个端口频率和面积都能压在可实现范围内。代价也很直白复制意味着面积翻倍、功耗上升。所以切片数量不是越多越好而是在「查表管线频率」「互连带宽」「芯片面积与功耗」三者之间找平衡点。从公开的几种规格能看出这种取舍的痕迹——1.8T 的芯片可以切成两个 9×100G 的切片也可以做成单个 18×100G 的切片6.4T 的芯片切成四个 16×100G 的切片3.6T 的芯片切成两个 18×100G 的切片。端口总带宽接近切片切法完全不同面向的场景也就不同切片多的适合端口分散、流量东西向均匀的场合切片少的省掉了互连开销单端口到单端口的路径更短。还有一个不那么显性但很实际的原因切片是可复用的 IP 单元。芯片设计团队把「一个切片」做成可参数化实例化的模块改切片数量就能派生出不同容量的型号验证工作量、流片风险和软件模型都能摊薄。这类工程动机在任何自研转发芯片的项目里几乎都会出现只是很少写在规格书里。2.3 任何到任何互连非阻塞的承诺与代价切片互连的设计目标是「任何入向切片到任何出向切片都非阻塞」。这句话的技术含义是互连内部提供的通路数量足够让所有入向切片在同一时刻各自把线速流量送往任意一个出向切片而不产生内部排队。它靠的是每个入向切片到每个出向切片之间都有独立的通路而不是共享一条总线。下面这段伪代码描述的是转发决策里跟切片相关的那一小段逻辑实际硬件里是并行的组合逻辑用 Python 写出来只是为了把判定条件讲清楚# 切片选择与互连占用判定伪代码用于说明机制非真实驱动代码 SLICES [ {id: 0, ports: range(0, 9), capacity_gbps: 900}, {id: 1, ports: range(9, 18), capacity_gbps: 900}, ] def pick_egress_slice(dst_port): for s in SLICES: if dst_port in s[ports]: return s[id] raise ValueError(port not mapped to any slice) def forward(pkt): ingress_slice pkt.ingress_slice egress_slice pick_egress_slice(pkt.dst_port) # 查表永远在本切片完成不跨切片 result ingress_slice.lookup(pkt) # 返回 adjacency 或 ecmp 指针 if egress_slice ingress_slice: # 同切片直接进本切片出向队列互连带宽消耗为 0 ingress_slice.enqueue(result, pkt) else: # 跨切片占用一条 ingress-egress 的互连通路 credit interco.acquire(ingress_slice.id, egress_slice.id) if credit is None: pkt.drop_or_backpressure() # 互连拥塞时的背压点 else: interco.send(egress_slice.id, result, pkt)pick_egress_slice体现的是端口到切片的静态映射这个映射在芯片初始化时就固定了不随流量变化lookup始终在本切片完成这是切片「自包含」的定义interco.acquire是真正的成本项跨切片才付这笔钱同切片直接省掉。最后那个背压分支值得多说一句互连是非阻塞的但非阻塞不等于无限缓冲当多个入向切片同时打向同一个出向切片、且出向端口已经拥塞时压力会沿互连反向传回入向这个反压点落在哪里直接决定了丢包时的行为是「尾部丢弃」还是「按流区分」。提示看任何一份芯片架构材料「非阻塞」这个词一定要追问它的范围——是互连内部无阻塞还是端到端无阻塞。前者是设计事实后者还要叠加出向缓冲和调度策略才成立。3. 灵活瓦片一张表怎么同时充当路由表、主机表和组播表3.1 表项池与瓦片从固定功能查表到可互换资源传统交换芯片的查表资源是「按功能固化」的给 IPv4 单播多少条、给 MAC 表多少条、给组播多少条出厂就定死软件只能在这个额度内折腾。一旦业务模型变了——比如从三层转发为主变成大规模双栈主机接入为主——额度不够的那张表就溢出而另一张表还空着大半。灵活瓦片Flex Tile要解决的就是这个资源错配。做法是把查表存储切成若干块等价的瓦片每块瓦片可以由软件在初始化时分配给不同的逻辑表IPv4/IPv6 单播最长前缀匹配、IPv4/IPv6 主机路由表/32 与 /128 的精确匹配、IPv4/IPv6 组播的 (*,G) 与 (S,G)、MAC 地址表与邻接表、ECMP 表、策略表等等。不同芯片的瓦片数量和每块瓦片的条目数不同这个差异直接体现为「同一代软件在不同型号上能撑的规模不一样」。这种设计的核心是把「表」从物理资源变成逻辑视图。软件看到的是「我有 N 条 IPv6 主机路由可用」硬件看到的是「我把 6 块瓦片划给了主机路由功能每块 X 条」。中间那层映射就是路由模板。3.2 路由模板改一个 profile 为什么要重启整机模板本质上是一张「瓦片到功能」的分配表。软件在系统初始化时把这张表写进硬件之后所有查表都按这个划分走。为什么不支持热改因为瓦片的物理位置决定了查表引擎的寻址方式改分配等于改整条查表管线的地址映射运行中改会让已经在表里的条目全部失效而且无法保证切换瞬间的一致性。所以模板变更必须走重启这不是实现偷懒是一致性要求下的必然选择。下面这段伪代码把模板的约束条件表达出来重点是最后那段校验逻辑——它解释了为什么很多「配置不生效」的问题其实是模板压根不允许这么配# 模板定义与合法性校验伪代码 TEMPLATES { default: {lpm: 4, host: 2, mcast: 1, mac: 3, ecmp: 2}, dual_stack_host: {lpm: 1, host: 6, mcast: 1, mac: 3, ecmp: 1}, internet_peering: {lpm: 7, host: 0, mcast: 1, mac: 2, ecmp: 2}, lpm_heavy: {lpm: 8, host: 0, mcast: 1, mac: 2, ecmp: 1}, mpls_heavy: {lpm: 5, host: 1, mcast: 1, mac: 2, ecmp: 2}, mcast_heavy: {lpm: 2, host: 1, mcast: 3, mac: 3, ecmp: 1}, mcast_nbm: {lpm: 2, host: 1, mcast: 4, mac: 2, ecmp: 1}, } def validate(template_name, platform): t TEMPLATES[template_name] # 约束 1模板不支持的协议族直接拒绝 if template_name internet_peering and platform.supports_mcast: pass # 该模板本身不承载 IP 组播配了也没用 # 约束 2模块化机箱与 TOR 的模板集合不完全重合 if template_name dual_stack_host and platform.form_factor modular: raise ConfigError(该模板在模块化机箱上不可用) if template_name mcast_nbm and platform.form_factor tor: raise ConfigError(该模板在机架顶设备上不可用) # 约束 3瓦片总数必须刚好分完不允许超出 if sum(t.values()) platform.total_tiles: raise ConfigError(瓦片数量不足) return t def apply(template_name, platform): t validate(template_name, platform) platform.write_tile_map(t) platform.require_reboot() # 分配表在初始化阶段烧入运行中不可改sum(t.values()) platform.total_tiles这条校验是很多现场问题的根源模板里的数字是按某型号的瓦片总数配的换到瓦片更少的型号上就会直接报错而如果型号瓦片更多多出来的瓦片怎么处理不同软件版本行为不完全一样有的留空、有的补进默认功能。require_reboot则是那个最容易被忽略的调用——配置敲下去了、命令行也接受了但表项数量纹丝不动就是因为分配还没生效。注意模板是初始化参数不是运行参数。任何「改了模板但规模没变」的现场问题第一个要确认的动作永远是「有没有真的重启过」。3.3 HRT、LPM 与 TCAM 的三级兜底IP 前缀在硬件里有三种落法各有各的适用区间。第一种是主机路由表本质是哈希表专门存 IPv4 的 /32 和 IPv6 的 /128也就是精确匹配。哈希表的优势是查表时间是常数跟表里有多少条无关劣势是碰撞——两条不同前缀哈希到同一个桶就得有人处理溢出。第二种是最长前缀匹配存其余长度的前缀实现上通常是传统的前缀/掩码表或者「pivot trie」的组合先用一个较粗的粒度定位到一棵子树再在子树里逐级往下找。这个结构的时间复杂度和前缀分布的形态有关前缀越分散走的级数越多。第三种是 TCAM位置在灵活查表的前面扮演兜底角色哈希碰撞的条目、放不进瓦片的溢出条目最后都落到这里。TCAM 的查表是一拍出结果但面积和功耗代价高容量通常远小于瓦片池所以它只能兜底不能当主力。这三者的关系可以用一个查表顺序来表达def ip_lookup(prefix, family, vrf): # 第一级/32 或 /128 走哈希主机表 if prefix.is_host_route(): idx hrt_hash(vrf, prefix.addr) entry hrt_bucket(idx).find(vrf, prefix.addr) if entry: return entry.adjacency # 哈希碰撞未命中落到 TCAM return tcam_lookup(vrf, prefix.addr, prefix.mask) # 第二级其余长度走 LPMpivot - trie node lpm_pivot[vrf].match(prefix.addr) while node and node.prefix_len prefix.mask: node node.child(prefix.addr) if node and node.has_entry: return node.adjacency # 第三级LPM 瓦片不足或结构没覆盖到的TCAM 兜底 return tcam_lookup(vrf, prefix.addr, prefix.mask)这段顺序解释了为什么「双栈主机规模模板」会把 LPM 瓦片压到只剩一块主机条目全走哈希LPM 只承担少量网段路由模板把大部分瓦片让给了主机表。反过来「LPM 偏重」模板把主机表瓦片清零所有 /32、/128 都要挤进 LPM 或 TCAM这时主机路由一多TCAM 就会先满表现为「明明表项还没到标称值新增路由就开始报错」。4. 报文行走从入向 MAC 命中到出向重写的完整链路4.1 入向的第一跳不是查路由而是认「这是不是我的 MAC」报文进入芯片后做的第一个有意义的判断不是「目的 IP 是哪」而是「目的 MAC 是不是我」。这个判断发生在 MAC 表里结果决定了两条完全不同的路命中路由器 MAC说明这是一个需要三层转发的报文触发后续的 L3 查表没命中说明是二层转发或者不属于本设备走二层路径或者丢弃。这个顺序看着平淡但它决定了整条流水线的组织方式——三层查表是个「昂贵操作」必须先用一个便宜的判断把它挡在门外。三层查表的核心是「精确匹配 VRF 最长匹配目的 IP」。VRF 必须精确匹配因为不同租户可以有完全重叠的地址空间目的 IP 必须最长匹配因为转发的语义就是「找到最具体的那条路由」。这两个匹配的语义完全不同硬件上是两条并行的查找路径最后合成为一个查表结果。4.2 查表结果的岔路邻接指针还是 ECMP 指针查表结果有两种形态。如果路由只有一条下一跳返回的是邻接指针也就是一个指向 MAC 表的索引如果路由是多路径的返回的是 ECMP 指针指向一个 ECMP 组。这两条岔路后面的处理完全不同前者直接拿指针去 MAC 表取「出向 BD、重写 MAC、出端口」后者要先在 ECMP 组里选一条路径再拿选出来的成员索引去 MAC 表。下面的伪代码把这条链完整串起来注意 ECMP 选择发生在邻接解析之前这个顺序很关键def packet_walk(pkt): # 1. 二层判定目的 MAC 是否为路由器 MAC if not mac_table.is_router_mac(pkt.dmac, pkt.bd): return l2_forward(pkt) # 纯二层路径不碰 L3 表 # 2. 三层查表VRF 精确匹配 IPDA 最长匹配 route ip_lookup(pkt.dip, pkt.family, pkt.vrf) if route.type adjacency: adj mac_table.get(route.adj_ptr) elif route.type ecmp: # ECMP 哈希因子源/目的 IP、源/目的端口、协议号 member ecmp_hash(pkt, route.ecmp_ptr) adj mac_table.get(member.adj_ptr) else: return drop(pkt, reasonno_route) # 3. 重写与转发BD、目的 MAC、源 MAC、TTL 递减 pkt.out_bd adj.out_bd pkt.dmac adj.rewrite_dmac pkt.smac adj.rewrite_smac pkt.ttl - 1 # 4. 交给出向切片缓冲 / 排队 / 复制 / 出向策略 return egress_stage(pkt, adj.out_port)is_router_mac那一步是整条链的分水岭它的实现是一张 MAC 表查询成本远低于 LPM。ecmp_hash的哈希因子选择直接决定链路利用率只用源/目的 IP 时同一对大流量主机的所有流会固定落在一条成员链路上形成哈希极化把四层端口加进来能缓解但对同一连接内的多流无能为力——这正是后续「逐流负载均衡」这类机制要解决的问题。ttl - 1和重写动作发生在出向之前意味着出向阶段看到的是一个已经「半成品」的报文出向策略可以基于重写后的字段做匹配。4.3 出向缓冲、排队、复制与重写都在同一个切片里出向阶段是整个流水线里最容易被低估的部分。它要做四件事把报文放进共享的出向缓冲池、按队列和调度策略决定发送顺序、对组播报文做复制、执行出向策略和最终重写。这四件事都在出向切片内部完成不跨切片也不回到入向。共享缓冲的设计取舍很值得说。每个出向端口如果都有独立缓冲一个端口拥塞不会影响别人但总缓冲面积会随端口数线性增长改成所有端口共享一个缓冲池面积省了但一个端口的突发会吃掉别人的份额。所以真实实现通常是「共享池 每端口上限 动态阈值」的组合池子共享但每个端口能占多少随当前空闲量动态调整空闲多时阈值放宽空闲少时收紧。这套机制的名字各厂商不同思路是一致的——用动态阈值把「公平」和「利用率」这两个矛盾的目标折中。复制动作的位置也有讲究。组播报文如果在入向就复制成多份会占用多份互连带宽在出向切片复制则互连上只传一份代价是出向切片要能识别「这个报文要往我这里的多个端口发」。这就是为什么组播规模往往和切片数量、出向复制能力挂钩。4.4 单次隧道封装内层查表和外层封装不能各走一遍隧道封装比如 VXLAN在传统实现里是个痛点报文进来先查内层目的地址决定要送到哪个隧道端点然后加外层头再查一次外层目的地址决定物理下一跳。两次查表、两次流水线时延翻倍芯片的查表资源也被吃掉一半。单次封装的思路是把这两次合成一次内层查表的结果里直接带上「封装模板 外层下一跳」的信息查完内层就同时知道了外层该怎么封、从哪个端口出。报文只走一遍流水线封装动作在出向阶段完成。这个优化的前提是查表结果的数据结构里要能同时容纳内层邻接和外层邻接也就是邻接表条目要比纯二层转发宽一些——这是拿表项宽度换流水线次数典型的空间换时间。提示评估一台交换机支不支持「单次封装」不要看它支不支持隧道协议要看它的邻接表条目结构里有没有同时存放内外层信息的字段。支持协议和高效实现协议是两件事。5. 避坑与排查模板、哈希和表项溢出的那些血泪经验5.1 改了模板但规模没变现象按文档把系统路由模板切成双栈主机规模命令行接受、无报错但主机路由表项的上限一点没涨新增主机路由照旧报资源不足。原因模板是初始化参数写的是瓦片到功能的物理分配表运行中不可改。配置只是记下了「下次启动用这个模板」当前运行的还是旧分配。解决确认变更已写入启动配置安排维护窗口重启重启后再核对表项上限。判断是否生效有个简单办法看主机路由和前缀路由的可用额度比例有没有发生翻转翻转了才是真生效。这类问题最坑的地方在于「没有报错」全靠自己对模板生命周期的认知。5.2 主机路由把 TCAM 挤爆后开始随机黑洞现象前缀路由表看起来还有余量但新增的 /32 主机路由偶尔查不通抓包表现为「报文进了设备但没出去」也没有明确的丢弃计数。原因主机条目走哈希表碰撞的条目溢出到 TCAMTCAM 容量远小于瓦片池一旦塞满后续溢出条目直接装不进去。而哈希碰撞是概率事件所以表现成「偶发」非常有迷惑性。解决先确认当前模板给主机表的瓦片数再核对实际主机条目量是否超过了瓦片容量如果业务确实是主机路由为主换模板比调任何参数都有效。排查时不要只盯总表项数要分开看哈希表命中率和 TCAM 占用率这两个指标它们的增长曲线不一样。5.3 组播模板在错误的平台上配置现象按模板列表选了组播偏重的模板重启后组播表项规模没提升甚至部分组播流量不通。原因模板集合在不同形态的平台上并不完全重合有的模板只在机架顶设备上可用有的只在模块化机箱上可用还有的模板本身不承载 IP 组播。选之前没核对平台形态和模板的适用条件。解决配置前先把「当前平台支持哪些模板、每个模板排除哪些协议」列清楚尤其是带脚注的那几个。这类信息通常在模板语法文档里很容易被跳过。上线前拿一个最小规模的组播组做验证比事后排查省事得多。5.4 ECMP 哈希极化导致单链路拥塞现象一组 ECMP 成员链路总带宽明明够用但监控上总有一条链路长期跑满、其余几条闲着一半应用侧表现为间歇性时延抖动。原因ECMP 的哈希因子只包含源/目的 IP 时同一对大流量主机之间的所有连接会算出同一个哈希值全部压到同一条成员链路上。链路数越多这种极化越明显。解决把四层端口纳入哈希因子能缓解多连接场景但单连接内部的多条流仍然无解要根治得靠能感知拥塞并逐流重新分配路径的机制。排查时先看每条成员的流量分布是否接近均分不均是哈希问题均分但时延抖动则是队列或缓冲问题两者的处理方向完全不同。5.5 遥测开着但流表事件不全现象开了流表事件上报采集端只收到一部分流量的事件某些方向的会话完全看不到。原因流表功能并非在所有芯片型号上都具备即使具备也可能只在部分切片上实现。跨切片流量如果只在其中一个切片上有采集能力另一半就漏了。解决先确认当前芯片型号是否支持流表事件再确认支持的范围是「全部切片」还是「部分切片」。如果不全采集侧要做补采或者换用基于统计导出的方案。这个坑的隐蔽性在于「开关是开的、也有数据上来」很容易误判为采集端问题。6. 设计取舍自研转发芯片与商用硅方案边界到底划在哪同一家厂商的产品线里同时存在自研转发芯片和商用硅方案这不是路线摇摆是分层策略。商用硅方案交换型或深缓冲型的优势很明确上市快、行业供应充足、软件开发包公开、生态成熟适合那些「功能需求标准、时间窗口紧」的型号。深缓冲型商用硅还带着大容量报文缓冲和基于信元的交换架构天生适合需要吸收突发、跨域互联的场景这些能力自研芯片短时间追不上也没必要追。自研芯片的立足点则是「差异化功能必须做在转发面里」。策略化组网模型要求查表能直接表达策略语义拥塞感知的逐流负载均衡要求哈希与路径选择在硬件里联动单次隧道封装要求邻接表结构专门设计链路加密和封装加密要求加解密单元贴着转发路径智能缓冲要求队列管理算法可编程流表事件和统计导出要求采集点在流水线内部。这些东西如果等商用硅的公开接口要么做不了要么做出来是「软件补丁式」的实现性能和规模都差一截。维度自研转发芯片商用硅方案功能差异化可深度定制策略、遥测、加密贴着流水线受限于公开接口和能力集上市节奏流片周期长迭代慢跟随供应商节奏导入快规模弹性靠模板在瓦片间重新分配规格相对固定缓冲能力共享池 动态阈值可编程深缓冲型号有天然优势供应链风险单点依赖自身流片多来源风险分散真正需要想清楚的是哪些能力必须做进芯片哪些可以留给软件。判断标准其实很朴素——如果这个功能要求「每个报文都做一次决策」那它就必须在转发面如果它只是「定期算一次、下发一次」那软件做完全够。逐流负载均衡属于前者路由计算属于后者。这条线划错要么芯片里塞了一堆用不上的逻辑要么软件在数据路径上做了本该硬件做的事性能怎么调都上不去。我第一次踩这个坑是在一个模拟项目里把本该硬件做的逐流选路写成了软件轮询压测时 CPU 直接打满日志里全是「查表命中但排队超时」。后来把选路逻辑挪回硬件的哈希与路径选择单元同样的流量模型下时延曲线立刻平了。从那以后我每次评估一个转发特性都强制先问一句「它是每包决策还是周期性决策」问完再谈实现位置。这份讲座材料里那些流水线图值得对着自己网络里的真实流量走一遍 packet walk——很多看似玄学的时延抖动走完一遍就有答案了。希望帮到你。本文还有配套的精品资源点击获取