从四本账到八步点火:快递站比喻下的交换芯片表项、初始化与对账
仓库里的四本账、开业流程与对账:用「快递站」比喻讲透交换芯片的表项、初始化与对账
一句话简介:前两篇讲了快递站怎么收发货(数据面)、总部怎么指挥分站(控制面)。这一篇钻进仓库内部,讲清楚仓库里的四本账(FDB/VLAN/L3/ACL)、仓库开业时先干什么后干什么(初始化时序与错误恢复)、以及账本对不上时怎么修(软硬件对账)。
| 项目 | 内容 |
|---|---|
| 适合读者 | 接触交换机驱动、想理解芯片表项与初始化流程的工程师 |
| 前置知识 | 前两篇的快递站比喻、基本以太网/VLAN/路由概念 |
| 阅读时长 | 约 30 分钟 |
| 关键词 | FDB、VLAN、L3、ACL、TCAM、初始化时序、错误恢复、软硬件对账 |
目录
- 引子:前两篇讲了“怎么干活”,这一篇讲“账怎么记”
- 第一部分:仓库里的四本账——FDB / VLAN / L3 / ACL
- 第二部分:仓库开业——初始化时序与错误恢复
- 第三部分:软硬件对账——账本对不上怎么办
- 全景串联:一个包裹、一次开业、一轮对账
- 常见坑速查
- 自检清单
- 一句话总结
引子:前两篇讲了“怎么干活”,这一篇讲“账怎么记”
- 第一篇:包裹怎么从货车进仓库、怎么装纸箱、怎么交给客户(数据面)。
- 第二篇:总部怎么下命令、分站怎么碰仓库(控制面)。
- 这一篇:仓库内部有四本账决定“什么货该送到哪”,仓库开业时按什么顺序点火,以及账本和实际货架对不上时怎么修。
延续比喻:
- 驱动 = 分站
- 交换芯片 = 仓库
- 表项 = 仓库里的账本
- 初始化 = 仓库开业前的点火流程
- 对账 = 定期盘点,发现账实不符就修
第一部分:仓库里的四本账——FDB / VLAN / L3 / ACL
仓库要决定“一个包裹往哪送”,不是拍脑袋,而是翻四本账。四本账有先后顺序,像流水线一样一本本查。
总览:四本账的查找流水线
包裹从 3 号门进来
│
▼
┌─────────────────────────────────────────────┐
│ 第一本账:ACL(门卫规则) │
│ “这个包裹允许进吗?要不要直接丢掉/转走?” │
│ 命中规则 → 按规则动作(丢弃/重定向/放行) │
└──────────────────┬──────────────────────────┘
│ 放行
▼
┌─────────────────────────────────────────────┐
│ 第二本账:VLAN(分组名册) │
│ “3 号门属于哪个组?这个包裹该进哪个组?” │
│ 决定:加不加 VLAN 标签、能泛洪到哪些门 │
└──────────────────┬──────────────────────────┘
│ 确定组
▼
┌─────────────────────────────────────────────┐
│ 第三本账:FDB(工位通讯录) │
│ “目的 MAC 在哪个门?” │
│ 查到 → 直接送那个门;查不到 → 泛洪 │
└──────────────────┬──────────────────────────┘
│ 需要跨组/跨网段?
▼
┌─────────────────────────────────────────────┐
│ 第四本账:L3(跨组路由表 + 邻居表) │
│ “目的 IP 走哪个下一跳?下一跳的 MAC 是谁?” │
│ 决定:改 MAC 头、减 TTL、从哪个门送出 │
└─────────────────────────────────────────────┘
一句话记:ACL 先拦,VLAN 分组,FDB 找人,L3 跨组。 四本账按这个顺序查,任何一本命中就可能提前结束。
1. FDB:工位通讯录——“目的 MAC 在哪个门”
FDB(Forwarding Database)就是仓库的工位通讯录:记着“某个 MAC 地址在哪个门后面”。
FDB 账本长这样:
┌──────────────┬────────┬────────┬──────────┐
│ MAC 地址 │ VLAN │ 哪个门 │ 状态 │
├──────────────┼────────┼────────┼──────────┤
│ AA:BB:CC:... │ 10 │ 3 号门 │ 已生效 │
│ DD:EE:FF:... │ 10 │ 5 号门 │ 已生效 │
│ 11:22:33:... │ 20 │ 7 号门 │ 老化中 │
└──────────────┴────────┴────────┴──────────┘
三种来源:
| 来源 | 怎么来的 | 特点 |
|---|---|---|
| 动态学习 | 包裹从 3 号门进来,源 MAC 自动记到 3 号门 | 会老化,一段时间没流量就删 |
| 静态配置 | 管理员手动指定“这个 MAC 永远在 5 号门” | 不老化,重启也在 |
| 控制面下发 | 路由/邻居协议算出来后写进来 | 随协议状态变化 |
查找结果只有三种:
目的 MAC 查 FDB
│
┌────┴────┬────────────┐
查到 查不到 查到但状态是“老化中”
│ │ │
▼ ▼ ▼
直接送 泛洪 按实现决定:
那个门 (除入口外 送 + 触发重新学习
所有同组门)
卡点:动态学习是硬件自动做的,驱动只收到“学习到了”的通知(notifier)。如果驱动在通知里做慢活(比如查数据库),会拖慢整个学习路径。学习通知要快进快出,慢活丢工作队列。
2. VLAN:分组名册——“哪些门是一个组”
VLAN 就是仓库的分组名册:把几十个门分成若干组,组内可以互相送,组间默认隔离。
VLAN 账本长这样:
┌────────┬─────────────────────┬──────────────┐
│ VLAN │ 成员门 │ 标签处理 │
├────────┼─────────────────────┼──────────────┤
│ 10 │ 1, 2, 3 号门 │ 3 号门出口打标签│
│ 20 │ 5, 6, 7 号门 │ 不打标签(untag)│
│ 30 │ 1, 5 号门(跨组) │ 按配置 │
└────────┴─────────────────────┴──────────────┘
每个门有三个关键属性:
| 属性 | 大白话 | 作用 |
|---|---|---|
| PVID | 这个门的“默认组号” | 进来的无标签包裹,归到这个组 |
| 成员关系 | 这个门属于哪些组 | 决定包裹能往哪些门送 |
| Tag/Untag | 出口要不要贴组标签 | 贴标签给交换机看,不贴给终端看 |
收包时的 VLAN 处理:
包裹从 3 号门进来
│
▼
包裹上有没有 VLAN 标签?
│
┌────┴────┐
有 没有
│ │
▼ ▼
按标签的组 按 3 号门的 PVID
│ │
└─────┬─────┘
▼
查 VLAN 账本:这个组允许 3 号门进吗?
│
┌────┴────┐
允许 不允许
│ │
▼ ▼
继续查 FDB 丢弃(记一笔“VLAN 违规”)
卡点:VLAN 成员关系是全局表,不是每个门私有的。驱动收到“把 3 号门加入 VLAN 10”时,要改的是芯片的全局 VLAN 表,不是 3 号门的私有状态。改错了,要么 3 号门进不了组,要么整个组的成员关系乱掉。
3. L3:跨组路由表 + 邻居表——“跨组怎么走”
FDB 只管同一个组内“找人”。如果包裹要跨组、跨网段,就得查 L3 的两本账:
L3 账本分两本:
┌─────────────────────────────────────────────┐
│ 路由表(去哪个方向) │
│ 目的网段 10.0.2.0/24 → 下一跳 10.0.1.1 │
│ 目的网段 10.0.3.0/24 → 直接连(直连路由) │
└──────────────────┬──────────────────────────┘
│ 知道下一跳 IP
▼
┌─────────────────────────────────────────────┐
│ 邻居表(下一跳的 MAC 是谁) │
│ IP 10.0.1.1 → MAC AA:BB:CC:... │
│ (由 ARP/ND 协议填进来) │
└──────────────────┬──────────────────────────┘
│ 知道下一跳 MAC
▼
改包裹的 MAC 头(目的 MAC 换成下一跳的)
减 TTL
从 FDB 查“下一跳 MAC 在哪个门”
送出去
完整跨组转发流程:
包裹目的 IP = 10.0.2.5,从 3 号门进来
│
▼
查路由表:10.0.2.0/24 → 下一跳 10.0.1.1
│
▼
查邻居表:10.0.1.1 → MAC AA:BB:CC
│
▼
改包裹:
· 目的 MAC 改成 AA:BB:CC
· 源 MAC 改成仓库自己的 MAC
· TTL 减 1
│
▼
拿 AA:BB:CC 查 FDB → 在 5 号门
│
▼
从 5 号门送出
卡点:L3 转发依赖邻居表有货。如果邻居表里没有下一跳的 MAC,包裹会被“挂起”,等 ARP/ND 解析完再发。驱动要保证挂起的包裹有超时和上限,否则邻居表一直不解析,包裹会无限堆积,把内存吃光。
4. ACL:门卫规则——“什么货不能进、不能出”
ACL 就是仓库的门卫规则:按“源/目的 MAC、IP、端口号、VLAN”等条件匹配,命中就执行动作。
ACL 账本长这样(TCAM 表):
┌────┬──────────────────────────────┬──────────────┐
│优先级│ 匹配条件 │ 动作 │
├────┼──────────────────────────────┼──────────────┤
│ 1 │ 目的 MAC = XX:XX, VLAN = 10 │ 丢弃 │
│ 2 │ 源 IP = 10.0.0.5, 端口 = 80 │ 重定向到 7 号门│
│ 3 │ 协议 = TCP, 目的端口 = 22 │ 限速 1Mbps │
│ 4 │ 其他所有 │ 放行 │
└────┴──────────────────────────────┴──────────────┘
ACL 的特殊性:TCAM 是“三态”的
普通账本只能记“0 或 1”。ACL 的账本(TCAM)能记“0、1、不关心”三种状态,所以能做掩码匹配:
普通内存: 1010 → 只能匹配 1010
TCAM: 10XX → 能匹配 1000、1001、1010、1011
↑↑
这两位“不关心”
ACL 下发的难点:
用户配置了一条 ACL
│
▼
驱动要把它编译成 TCAM 表项:
· 选哪些字段做 key(MAC/IP/端口/VLAN)
· 每个字段多宽、掩码怎么设
· 放在 TCAM 的哪个位置(优先级)
│
▼
写入 TCAM
│
┌────┴────┐
成功 失败(TCAM 满了 / 字段不支持 / 优先级冲突)
│ │
▼ ▼
生效 返回错误,告诉用户“这条规则下不了”
卡点:
- TCAM 容量有限,不是想加多少加多少。驱动要在下发前检查容量,满了要返回明确错误,不能默默丢弃。
- 优先级顺序有讲究。两条规则冲突时,谁先匹配谁生效。驱动要保证“用户配的优先级”和“TCAM 里的物理顺序”一致。
- 字段支持有限。不是所有芯片都支持“按 TCP 端口号匹配”,驱动要提前检查能力,不支持就报错。
四本账的关系总结
┌─────────────────────────────────────────────┐
│ ACL:先拦一道,决定“进不进、要不要转走” │
└──────────────────┬──────────────────────────┘
▼
┌─────────────────────────────────────────────┐
│ VLAN:分组,决定“能去哪些门” │
└──────────────────┬──────────────────────────┘
▼
┌─────────────────────────────────────────────┐
│ FDB:同组内找人,决定“具体送哪个门” │
└──────────────────┬──────────────────────────┘
▼
┌─────────────────────────────────────────────┐
│ L3:跨组时改头、换 MAC、减 TTL,再回 FDB 查门 │
└─────────────────────────────────────────────┘
记忆口诀:ACL 拦,VLAN 分,FDB 找,L3 跨。
第二部分:仓库开业——初始化时序与错误恢复
仓库不是一通电就能用的。它得像飞机起飞一样,按检查单一步步来,任何一步失败都要能安全回滚。
初始化时序:八步点火
① 全局复位
└─ 把芯片所有寄存器、表项、队列清到已知状态
│
▼
② 时钟与 PLL 锁定
└─ 等时钟稳定,PLL 锁定(等不到就报错退出)
│
▼
③ SerDes 训练
└─ 高速接口的收发均衡、时钟恢复,让链路误码率达标
│
▼
④ SRAM / 表项内存初始化
└─ 清空 FDB/VLAN/L3/ACL 表,设置默认值
│
▼
⑤ DMA 环建立
└─ 分配描述符环,告诉硬件“CPU 端口的收发缓冲区在哪”
│
▼
⑥ 中断注册
└─ 申请 MSI-X 向量,绑定 NAPI
│
▼
⑦ 默认策略加载
└─ ACL 默认放行、VLAN 默认配置、QoS 默认队列
│
▼
⑧ 使能端口、启动交换引擎
└─ 最后一个门打开,硬件开始转发
为什么顺序不能乱?
如果先开端口(⑧)再初始化表项(④):
端口一开,包裹进来
表项还是空的/脏的
→ 包裹被泛洪、被错误丢弃、甚至踩坏内存
如果先建 DMA 环(⑤)再等 PLL 锁定(②):
DMA 环建好了,但时钟还没稳
→ 硬件读写描述符时序错乱,读到垃圾
每一步都要有超时和回滚:
每一步的模板:
开始这一步
│
▼
等硬件确认(带超时)
│
┌────┴────┐
成功 超时/失败
│ │
▼ ▼
下一步 回滚到上一步的干净状态
上报错误
退出 probe
错误恢复:开业失败怎么收场
初始化失败不可怕,可怕的是失败后留下一地鸡毛。驱动的错误恢复要遵守两条原则:
原则一:哪一步失败,就从哪一步往回拆
第 ⑤ 步(DMA 环)失败:
│
▼
拆 ⑤ 已分配的部分
拆 ④ 已初始化的表项(可选,复位会清)
拆 ③ SerDes(关掉)
拆 ② PLL(关掉)
拆 ① 复位(保持复位状态)
│
▼
返回错误,probe 失败
原则二:运行中出错,能局部恢复就不整体重启
运行中某次表项下发超时
│
▼
只回滚这一条表项(状态机回滚)
不影响其他表项
记一笔错误日志
│
▼
如果连续多次超时 / 寄存器读回全 F
│
▼
触发通道复位(只复位出问题的模块)
│
▼
如果复位也救不回来
│
▼
上报“硬件故障”,停止该端口/该模块
常见错误与处理:
| 错误 | 症状 | 处理思路 |
|---|---|---|
| PCIe link down | 寄存器读回全 F | 停止访问,上报,等待热插拔/重启 |
| 寄存器超时 | 轮询 ack 一直不置位 | 带超时返回错误,不无限等 |
| SerDes 训练失败 | 端口链路起不来 | 重试 N 次,失败则标记端口不可用 |
| TCAM 满 | ACL 下发返回“资源不足” | 返回明确错误,让用户删规则 |
| DMA 环错误 | 描述符 own 位异常、数据错乱 | 停止队列、复位 DMA 通道、重建环 |
| 表项下发失败 | 影子表是“已生效”但硬件没有 | 回滚影子表状态,重试或上报 |
卡点:错误恢复本身不能成为新的错误源。 比如复位通道时如果还拿着总线锁,可能死锁;回滚表项时如果状态机没设计好,可能把“已生效”的表项误删。
第三部分:软硬件对账——账本对不上怎么办
即使初始化正确、下发流程严谨,运行久了账本还是会“对不上”:
- 硬件自己老化了一条 FDB,驱动没收到通知;
- 控制面下发失败但影子表已标记“已生效”;
- 硬件复位后表项全丢,驱动不知道;
- 并发操作导致某条表项只写了一半。
对账就是定期(或触发时)对比影子账本和硬件账本,发现差异就修。
对账的基本流程
触发对账(定时 / 收到错误 / 人工命令)
│
▼
逐条读硬件表项(或读统计/校验和)
│
▼
和影子账本对比
│
┌────┴────┬────────────┬────────────┐
硬件多了 硬件少了 值不对
│ │ │
▼ ▼ ▼
删掉 补上 改成影子账本的值
(可能是 (可能是 (可能是并发
老化没通知)下发失败) 写坏了)
│
▼
记录差异日志(谁、哪条、怎么修的)
三种对账策略
| 策略 | 怎么做 | 优点 | 缺点 |
|---|---|---|---|
| 全量对账 | 定期把整张硬件表读一遍,逐条对比 | 最彻底 | 慢,大表可能几秒钟,期间影响转发 |
| 增量对账 | 只对比最近变更过的表项 | 快 | 漏掉“悄悄变化”的表项 |
| 事件驱动对账 | 收到硬件错误/复位事件时触发对账 | 及时 | 依赖事件通知可靠 |
实际做法通常是组合:日常用增量对账 + 事件驱动,低峰期做全量对账。
对账的难点:硬件表不一定“读得回来”
有些芯片的 TCAM、哈希表不支持逐条读回,只能:
- 读“表项数量”统计,和影子账本数量对比;
- 读“校验和”或“哈希摘要”,和影子账本算出来的对比;
- 用“探测包”验证某条表项是否真的生效(发一个匹配的包,看它走不走)。
不支持读回的表的对账方法:
① 数量对账:
硬件统计“当前 FDB 条数” vs 影子账本条数
不一致 → 触发全量重建(清空硬件表,按影子账本重写)
② 行为对账:
构造一个匹配某条 ACL 的探测包
看它是否被丢弃/重定向
和影子账本预期对比
卡点:对账本身要和正常下发互斥。 对账读硬件表时,如果有新表项正在下发,可能读到“半成品”。所以对账通常要暂停表项下发(或加读写锁),对完再放开。
全景串联:一个包裹、一次开业、一轮对账
【包裹转发】
3 号门进来
→ ACL 拦(放行)
→ VLAN 分组(VLAN 10)
→ FDB 找人(目的 MAC 在 5 号门)
→ 从 5 号门送出
(跨组时多查 L3:路由表 + 邻居表,改 MAC、减 TTL,再回 FDB)
【仓库开业】
复位 → PLL → SerDes → 表项初始化 → DMA 环 → 中断 → 默认策略 → 开端口
每一步:带超时,失败就回滚到上一步
【定期对账】
读硬件表 / 统计 / 行为验证
→ 和影子账本对比
→ 多了删、少了补、错了改
→ 记日志
(对账期间暂停下发,避免读到半成品)
常见坑速查
| 坑 | 生活比喻 | 后果 | 正确做法 |
|---|---|---|---|
| VLAN 成员关系当私有状态改 | 改的是工位自己的小本本,不是车间名册 | 整个组的成员关系乱掉 | VLAN 是全局表,改全局表 |
| L3 挂起包裹没上限 | 邻居表不解析,包裹无限堆积 | 内存吃光 | 挂起队列有超时和上限 |
| TCAM 满了默默丢规则 | 门卫规则写不进去也不说 | 用户以为规则生效了 | 下发前检查容量,满了报错 |
| 初始化顺序颠倒 | 先开门再摆货架 | 包裹进来踩坏内存 | 严格按八步顺序,每步带超时 |
| 错误恢复时还拿着锁 | 复位通道时死锁 | 系统卡死 | 恢复前释放锁,恢复用独立路径 |
| 对账和下发并发 | 读到半成品表项 | 误判差异、误删表项 | 对账期间暂停下发或加读写锁 |
| 不支持读回的表硬读 | 读回全 F 当成“表空了” | 误删所有表项 | 用数量/行为对账,不硬读 |
自检清单
能用自己的话答上来,这部分就算过关。
四本账
- FDB、VLAN、L3、ACL 四本账的查找顺序是什么?哪本可能提前结束?
- FDB 的三种来源分别是什么?动态学习由谁做?
- VLAN 的 PVID、成员关系、Tag/Untag 分别管什么?
- L3 转发为什么要查“路由表 + 邻居表”两本?邻居表没货时包裹怎么办?
- TCAM 的“三态”是什么意思?ACL 下发失败常见原因有哪些?
初始化
- 初始化八步的顺序是什么?为什么不能先开端口再初始化表项?
- 每一步失败后怎么回滚?运行中出错和 probe 失败的处理有什么不同?
- 错误恢复时为什么要先释放锁?
对账
- 对账的三种触发方式是什么?各有什么优缺点?
- 硬件表不支持读回时,怎么对账?
- 对账为什么要和正常下发互斥?
一句话总结
仓库四本账:ACL 拦、VLAN 分、FDB 找、L3 跨;开业八步走,每步带超时、失败往回拆;账本对不上就定期盘,多了删、少了补、错了改,盘点时别让人同时改账。
这三件事做好了,交换机才“转得对、起得来、错能修”;做不好,就是“表项时有时无、端口起不来、复位后全乱”这类最让人头疼的问题。
版权说明:本文为原创技术笔记,欢迎转载,转载请注明出处。文中比喻仅用于降低理解门槛,具体实现请以对应芯片手册和内核版本源码为准。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)