修改 SFP 镜像里的厂商名称和料号之后,哪些 EEPROM 校验和需要重新计算
台架上的活:给一小批 SFP+ 模块重编码,让它们带上客户设备期望的厂商字符串和料号。改动本身在十六进制编辑器里很简单,写入也顺利通过,读回来的内容跟我写进去的逐字节一致——结果主机依然把这个模块拒了。
- 通用 SFP+ 模块,手动编辑了 A0 页
- 基于 CH341 的编程器,用的是自带的工具
- 改动的字段:厂商名称和厂商料号,别的什么都没动
- 把没改过的原始 dump 写回同一个模块是正常的,所以写入通路本身没问题
改完之后我对比了一下:
edited fields : vendor name, vendor PN
byte 63 CC_BASE : identical to the original image
byte 95 CC_EXT : identical to the original image
host : rejects the module, checksum error
所以内容变了,但这两个校验和字节明显没跟着变。在我动手写自己的工具之前:这两个校验和到底覆盖哪些字节范围,它们是普通的加法和还是类似 CRC 的东西,有没有维护中的工具能帮我重新算这个,省得每个模块都要我自己手算?
Comments 4
你的编程器做的正是 CH341 类工具通常会做的事,也就是什么都不做。它们只会把你交给它的字节写进去,从不去碰校验和字段。厂商的编程器会在写入时自动重新计算,这也是为什么只用过那类工具的人从没遇到过这个问题,还以为这整件事是子虚乌有。
在你动手写工具之前,有两件事值得先确认。第一,写入之后是用什么读回来验证的——是写入用的同一个工具,还是独立的另一个?如果读取工具用的是自己的缓存,它完全可能给你看一个根本没落到芯片里的字节。第二,你是不是自己按编辑后的镜像、对字节 0 到 62 求和,再跟字节 63 比对,还是只拿字节 63 去跟原始 dump 比对?"没变"和"正确"是两回事,你的记录里只做了第一种比对。
另外也值得说清楚是哪个主机在拒绝它。有些主机只读身份字段、什么都不校验,有些则严格校验,只要校验和不对就立刻丢弃模块。同一个镜像,不同的结论。
一共有两个,都是笨笨的 8 位加法和,跟 CRC 完全没关系。
厂商名称和厂商料号都在基础区里,所以你这次编辑让 CC_BASE 失效了,而 CC_EXT 依然是合法正确的,因为你没碰扩展区。序列号和日期代码的修改则会落在扩展区,那时候失效的就是字节 95。重新算哪一个都不过是对缓冲区求和、和 0xFF 取余、存进对应的校验字节,就这么两行代码的事。
如果你不想自己手写,也有现成工具。py-sfp-eeprom 可以用 Python 构建和校验 EEPROM 镜像(
python3 -m sfp_eeprom),sfppi能在树莓派上跑,会检查校验和并提供修复。这两个都比十六进制编辑器加心算靠谱,因为这类失败是无声的——模块读回来跟你写的一模一样,只有主机会抱怨。把 MSA 那两个校验和算对是必要条件,但取决于你插的是谁家的端口,不一定是充分条件。
Cisco 是个很典型的例子:它的身份校验不只是看字符串。多年前有人算出来,Cisco 编码模块携带的那个值,只需要
xxd -r -p | md5sum这么朴素的手段就能重现出来,输入是厂商代码字节,接着是名称字节。在这些 dump 里,代码和名称是绑在一起的——Finisar 对应代码 02,Methode 对应 0E。让这两者对不上,一台 Catalyst 2960X 就会把模块吐出来,不管你有没有下解锁命令。这通常也是为什么从一个能用的模块上拷贝下来的 dump,一旦被人往里粘贴了另一个厂商字符串就不能用了的原因。校验和是对的,但身份信息内部已经不自洽了。
对"修好那两个校验和就完事"这个说法做个小修正:这只对 MSA 定义的字段成立,不代表每家厂商对"有效镜像"的理解都是这样。
HP 就是一个一直存在的反例。在 J4858B 的镜像里改序列号,也就是字节 68 到 83,A0 页字节 124 到 127 也会跟着变——这是一个位于 MSA 的 CC_BASE 和 CC_EXT 字节之后的厂商自定义校验和。这个问题被反复讨论过很久,但从来没人公开过算法;大家确认了这几个字节确实有影响,讨论到这儿就没了。J4859C 和 J9150A 上也有人报告过同样的情况。后来的 HP 和 Aruba 设备转向了挑战应答机制(HPIDv2),这种东西在 EEPROM 里根本没法伪造。
所以在投入工具之前,先搞清楚目标主机到底校验什么:普通主机是两个加法和,Catalyst 是内部自洽的身份信息,而某些 HP 部件上则是一个你根本没法复现的、没有文档记录的字段。