简介:面向需要修改网卡物理地址、处理黑群晖网络识别问题或开展网卡底层配置实验的技术用户,这份MAC地址硬刷工具包以网卡EPROM/EEPROM写入为核心,兼顾原理说明与实际刷写需求。压缩包共197个文件、约4.52MB,包含exe可执行程序、bin固件与数据文件、c/h源码、cfg/ini配置、txt与docx说明、bat脚本及eep等类型,覆盖刷写工具、参数配置、芯片适配和操作记录等环节。已有2556人学习下载,说明其在MAC地址修改与网卡故障排查场景中具有一定参考价值。读者可据此了解MAC地址结构与OUI组成、硬刷适用边界、不同网卡芯片的适配差异及常见风险点,并借助说明文档、配置样例和源码资料梳理检测、写入与验证思路,适合具备一定硬件和网络基础、需要谨慎评估合规风险的用户参考。
1. MAC 地址硬刷改的是哪一层:从寄存器伪装到 EEPROM 落盘
实验室里收上来一批二手网卡,插上交换机端口立刻撞车——三块卡的 MAC 全是00:1B:21:XX:XX:XX同一个值,原因是上一任使用者用软件方式改过,而软件层改的那份"身份"根本没进芯片,只是驱动在内存里盖了张纸条。所谓 mac 地址 硬刷,说的就是把这张纸条换成真正刻进板子上的字:把目标地址写进网卡的 NVM/EEPROM/efuse,让它在每次上电自检、每次 PXE 引导、每个操作系统里都是同一个值。软改重启即失效、换系统就穿帮,硬刷之后连 BIOS 的网卡启动项都跟着变。这份工具集面向的正是这类场景:设备资产编号统一、二手设备身份恢复、产线批量写号、驱动与网络测试需要构造特定源地址。前提只有一个——设备是你自己的,或者你有明确授权。
2. 工具链拆开看:三层地址模型与四类工具形态
很多人第一次接触硬刷,会把ip link set dev eth0 address和写号工具混为一谈,结果烧完发现"没生效",其实是压根没写到芯片里。要判断手上这个工具能不能真落盘,得先搞清楚 MAC 地址在系统里存在于哪几个层次,以及每一层分别由谁管。
2.1 三层地址模型:协议栈层、驱动层、NVM 层
最上面是协议栈层。Linux 下ip link set改的是内核net_device结构里的dev_addr,Windows 下改注册表NetworkAddress改的是驱动初始化时传给上层的一个覆盖值。这一层的特点是:改动随系统重装消失、随驱动重载消失、在 PXE/BIOS 阶段完全不可见。它适合做临时测试,不适合做资产管理。
中间是驱动层。部分网卡驱动支持在初始化时从 NVM 读一个"出厂 MAC",如果读失败或者读到全FF,会退回到一个随机地址或者从别处继承。有些驱动还提供 IOCTL 让上层临时写过滤表,这是交换机侧"MAC 过滤"的另一回事,跟身份没关系。
最下面是 NVM 层,也就是 EEPROM、flash、efuse、OTP 这些非易失存储。网卡上电后,固件从这块存储里读出一段结构化数据,其中第 0 个 word 附近通常就是永久 MAC 地址,后面还可能跟着第二个端口的地址、校验和字段、以及一堆厂商配置字。硬刷工具干的事就是直接读写这段存储。判断一个工具是不是真硬刷,最简单的土办法:写完断电源、开机进 BIOS 的网卡启动界面看 MAC,或者拔下来插到另一台机器上——地址还在,就是真写进去了。
提示:把"重启"当"断电"是新手最容易犯的错。多数网卡的 NVM 只在 PCIe 复位或整机上电时被重新加载,软重启不重新读,看起来像是写失败,实际已经写进去了。
2.2 四类工具形态与它们的适用边界
按运行环境分,常见的硬刷工具大致四类,选错了不是写不进去,而是根本认不到芯片。
| 形态 | 运行环境 | 典型适用 | 主要限制 |
|---|---|---|---|
| 实模式写号工具 | DOS / FreeDOS U 盘 | 老网卡、独立网卡、无 OS 干扰 | 不认 NVMe、新芯片组 USB 支持差 |
| EFI Shell 工具 | UEFI Shell | 板载网卡、新平台、批量产线 | 需要关 Secure Boot 或自签名 |
| 操作系统内驱动级工具 | Windows / Linux | 支持在线读写、可脚本化 | 受驱动占用影响,需先卸载驱动 |
| 外部编程器 | 拆焊或夹持 EEPROM | 芯片已锁死、NVM 损坏 | 需要夹具和器件手册,风险最高 |
我在实验室里一般优先走 EFI Shell 这条路:不依赖操作系统,不受驱动版本影响,还能在整机装配完成后直接跑。老平台或者独立网卡才退回 DOS 环境。操作系统内工具适合做批量,因为可以套脚本读日志,但要注意先rmmod掉驱动,否则工具打开设备节点时会被拒绝,或者读到的是驱动缓存而不是真实 NVM 内容。
外部编程器是最后的后悔药。有些板子的 NVM 有硬件写保护引脚,或者被固件设置了永久写保护位,软件工具怎么写都返回成功但读回还是老值。这种情况只能上夹具,或者认命。我见过最惨的一次是把一块双口卡的 NVM 写成了全00,机器直接不认卡,最后靠编程器把备份烧回去才救活——所以后面第 3 章的第一步永远是备份。
2.3 认芯片、配工具:三步把工具和硬件对上
工具拿到手别急着敲命令,先确认三件事:芯片型号、NVM 容量与结构、当前写保护状态。这三条决定了你该用哪个版本的工具有没有权限写。
第一步,认芯片。Linux 下最省事:
# 列出 PCI 设备,重点看以太网控制器的 vendor:device lspci -nn | grep -i ethernet # 看驱动绑定了谁、当前 MAC 是多少 ip -br link show ethtool -i eth0 # 输出 driver / firmware / bus-info ethtool -e eth0 # 部分驱动支持直接 dump NVM 前若干字节lspci -nn输出的[8086:1533]这种方括号里就是 vendor ID 和 device ID,把它和工具帮助里支持的列表对一遍。ethtool -i给出的bus-info(形如0000:03:00.0)是后面所有工具都要用的定位参数,一台机器上有多块网卡时千万别搞混。ethtool -e能不能用取决于驱动有没有实现get_eeprom,实现不了的会直接报Operation not supported,这不是故障。
第二步,确认 NVM 结构。同型号芯片在不同板子上可能配不同容量的存储,MAC 所在的字偏移也可能因为厂商自定义而不同。工具一般会先 dump 一份完整镜像,你能在里面找到当前 MAC 的字节序列,那就是它的位置。找不到就说明偏移不对,硬写必然写坏。我习惯把 dump 出来的镜像和ethtool -e的结果交叉比对一次,两边一致才继续。
第三步,看写保护。软件层面看工具是否要求先执行"解锁"子命令;硬件层面看板子上 NVM 附近有没有 WP 跳线或测试点。有些平台在 BIOS 里有"网卡 NVM 写保护"开关,出厂默认开着,不关掉写号工具会一直返回Write protected。
# 记录基线:型号、总线地址、当前 MAC、驱动版本,一行一条,存进台账 printf '%s\t%s\t%s\t%s\n' \ "$(date +%F)" \ "$(lspci -nn -s 0000:03:00.0 | awk -F': ' '{print $2}')" \ "$(cat /sys/class/net/eth0/address)" \ "$(ethtool -i eth0 | awk -F': ' '/^version/{print $2}')" \ >> /var/log/nic-baseline.tsv这段脚本把日期、芯片标识、当前 MAC、驱动版本落成一行 TSV。看着朴素,但批量作业时它就是唯一的追溯依据——写坏了能立刻知道原来是什么,出问题能对上是哪一次操作。参数上注意/sys/class/net/eth0/address读的是内核当前认为的地址,如果之前做过软改,这里可能不是 NVM 里的真实值,所以还要配合工具 dump 的镜像确认。这一步做完再动手,后面所有流程都建立在这份基线上。
3. 四步落盘流程:备份、解锁、写入、校验
工具链对齐之后,真正写号就是一条固定流水线。我把这四步写成了固定动作,少一步都不行,尤其是第一步和第四步——中间写错了还能重来,备份丢了就真没退路。
3.1 第一步:整片备份,别只备份 MAC
新手常犯的错是"我就改 6 个字节,备份那 6 个字节够了"。不够。NVM 里除了 MAC 还有校验和、配置字、PCIe 相关参数、厂商保留区,任何一个字节被误写都可能导致网卡不认或者链路起不来。正确做法是把整片 NVM dump 成文件,同时算哈希存档。
# 整片 dump,工具名与参数以你手上的帮助为准,这里给出通用调用形式 mkdir -p /backup/nic && cd /backup/nic # -nic 指定总线地址,-dump 输出整片镜像,-size 指定容量(按芯片手册填) ./nvm_tool -nic=0000:03:00.0 -dump=nvm_before.bin -size=4096 # 校验镜像完整性:大小对不对、前 16 字节长什么样 ls -l nvm_before.bin xxd -l 16 nvm_before.bin # 存哈希,归档时带上机器序列号,方便回溯 sha256sum nvm_before.bin >> /backup/nic/manifest.txt-nic=是设备定位,等价于lspci里的bus-info,多网卡环境下必须显式指定,靠"第一块网卡"这种默认值迟早出事。-dump=后面跟输出文件名,惯例是带上before/after和日期。-size=必须和实际容量一致,填大了工具会读到未映射区域返回FF,填小了会截断后半段配置字,两种情况下的镜像都不能用来恢复。xxd -l 16是快速目检:正常的 NVM 开头不会是整片FF或整片00,如果看到这两种,说明读的位置根本不对,先停下来排查再说。
备份文件建议存两份:本地一份、归档一份。归档那份连同机器序列号、操作人、日期一起写进 manifest,这是唯一的后悔药。
3.2 第二步:清写保护,搞明白你在解什么
写保护分三层,很多人卡在这里以为是工具坏了。
第一层是软件标志位。工具通常有-unlock或-wp=off之类的开关,作用是把 NVM 控制器里的保护寄存器放开。这层最容易过。
第二层是 NVM 内部的保护区域。部分芯片把前若干字节(正好包含 MAC)划成只读区,需要先执行一个特定序列或者写特定 magic 值才能临时解锁。这类操作通常在工具的-force或者-recover子命令里,帮助文档会写清楚风险。
第三层是硬件引脚。板子上 NVM 的 WP 引脚如果被拉高,前面两层全做了也白搭。这种情况要么找跳线改电平,要么上编程器。
# 查询当前写保护状态(不同工具输出字段不同,重点看 WP / Lock / Protected) ./nvm_tool -nic=0000:03:00.0 -info # 尝试解锁,输出里应能看到 write protection: disabled ./nvm_tool -nic=0000:03:00.0 -unlock # 写保护没解除时,写入会明确报错,看到这个先别怀疑工具 # ERROR: NVM is write protected (WP bit set)解锁之后不要立刻写。先做一次"空写测试":把刚 dump 出来的镜像原样写回去,看能不能成功、读回哈希是否一致。这一步能验证工具链通畅、容量参数正确、写保护确实解除了,而且不会改变任何内容。空写通过,才说明后面写新 MAC 是安全的。这个习惯救过我至少两次——一次是-size填错,空写读回哈希对不上,及时发现;一次是工具版本和芯片不匹配,写入返回成功但读回全FF,也是在空写阶段暴露的。
3.3 第三步:构造新地址,把本地管理位和校验和算对
MAC 地址不是随便六个字节。第一个字节的最低位是组播位(I/G),必须为 0;次低位是本地管理位(U/L),自己分配的地址必须置 1。这意味着手写的地址第二个十六进制字符只能是 2、6、A、E 之一,比如02:、0A:、1E:开头。写成00:开头又不在任何厂商 OUI 里,某些交换机和 802.1X 认证端会直接丢弃。
import hashlib def normalize(mac: str) -> str: """接受 02-00-00-00-00-01 / 020000000001 / 02:00:00:00:00:01 三种写法""" h = mac.replace(":", "").replace("-", "").replace(".", "").lower() if len(h) != 12: raise ValueError(f"MAC 长度不对: {mac}") int(h, 16) # 非法字符会在这里抛出 return h def check_local_admin(h: str) -> str: """第一字节 bit1 置 1 表示本地管理地址,bit0 必须为 0(单播)""" b0 = int(h[0:2], 16) if b0 & 0x01: raise ValueError("组播位为 1,这不是合法的单播地址") if not (b0 & 0x02): # 自动补上本地管理位,保持后面 6 个 nibble 不变 b0 |= 0x02 return f"{b0:02x}{h[2:]}" def nvm_checksum(data: bytes, width: int = 2, init: int = 0) -> int: """按 16 位字求和取反,具体算法以芯片手册为准,这里给出常见形态""" total = init for i in range(0, len(data) - len(data) % width, width): total += int.from_bytes(data[i:i+width], "little") total = (total & 0xFFFF) + (total >> 16) return (~total) & 0xFFFF if __name__ == "__main__": raw = "0A-00-00-00-00-01" h = check_local_admin(normalize(raw)) print("最终写入:", ":".join(h[i:i+2] for i in range(0, 12, 2))) print("指纹:", hashlib.sha256(h.encode()).hexdigest()[:16])normalize解决的是格式问题,不同工具接受的写法不一样,统一成 12 位小写十六进制最省事。check_local_admin是硬性规则:组播位为 1 的地址写进去,网卡能起来但收不到单播包,排查起来非常费劲;本地管理位不置 1 又用了非注册前缀,会被当成伪造 OUI。nvm_checksum是很多芯片 NVM 结构里都有的校验字段,改完 MAC 必须重算并写回,否则固件校验失败会拒绝加载整片 NVM,表现就是"网卡不见了"。校验算法各家不同,有的是 16 位字求和取反,有的是字节累加,以芯片手册为准,代码里这个只是常见形态。
注意:改了 MAC 之后一定要同步检查依赖它的东西——DHCP 静态保留、交换机端口安全绑定、802.1X 证书绑定、监控系统的资产台账、PXE 部署的机器识别规则。这些不改,写号成功但业务不通,很容易被误判成写号失败。
3.4 第四步:写入与读回校验,必须两个哈希对上
写入本身是一条命令,校验才是重点。
# 写入新 MAC(-mac 参数格式按工具要求,多数接受 12 位十六进制) ./nvm_tool -nic=0000:03:00.0 -mac=0A0000000001 -write # 立刻整片读回 ./nvm_tool -nic=0000:03:00.0 -dump=nvm_after.bin -size=4096 # 关键:只允许 MAC 那 6 个字节不同,其余必须完全一致 cmp -l nvm_before.bin nvm_after.bin | head -20 # 两个哈希都要留档 sha256sum nvm_before.bin nvm_after.bin | tee -a /backup/nic/manifest.txtcmp -l会逐字节列出差异位置和值。理想结果是只有 6 行输出,且位置落在预期偏移附近。如果差异行数远多于 6 行,说明工具顺带改了校验和区域或者配置字——校验和变化是正常的,但如果连配置区都变了,就要拿nvm_before.bin回滚后重新确认工具版本。这一步做完再看cmp的退出码,非 0 表示有差异,符合预期;如果两个文件完全一致,说明压根没写进去。
写完之后必须断电,不是重启。断电后进 BIOS 看网卡启动项显示的 MAC,或者进系统看ip link(此时没有做过任何软改),两边都是新地址,才算真正落盘。
4. 批量写号:地址池生成与脚本化流水线
单台设备手工敲还行,产线或者实验室几十上百台就必须脚本化。批量写号的风险不在写入本身,而在"分配逻辑"和"失败处理"——地址重复、写一半断电、失败没记录,这三件事出的问题比技术问题多得多。
4.1 地址池生成:别用随机数,用带校验的确定性序列
随手random生成 MAC 在几十台的量级上大概率和已有设备撞车,尤其是同批次设备都在同一个网段。稳妥做法是用一个固定前缀加单调递增的尾部,配合持久化的计数器。
import json, os from pathlib import Path POOL_FILE = Path("/backup/nic/pool.json") def gen_pool(prefix: str = "0a0000", start: int = 1, count: int = 100) -> list[str]: """prefix 为前 3 字节(本地管理位置 1),后 3 字节从 start 递增""" assert len(prefix) == 6, "前缀必须是 3 字节" first = int(prefix[0:2], 16) if first & 0x01: raise ValueError("组播位必须为 0") pool = [] for i in range(start, start + count): if i > 0xFFFFFF: raise ValueError("地址池耗尽") pool.append(f"{prefix}{i:06x}") return pool def claim(pool_file: Path, n: int = 1) -> list[str]: """从池里原子取号,取完写回,避免并发重复分配""" data = json.loads(pool_file.read_text()) if pool_file.exists() else {"free": [], "used": []} if len(data["free"]) < n: data["free"] += gen_pool(start=len(data["used"]) + len(data["free"]) + 1, count=200) got, data["free"] = data["free"][:n], data["free"][n:] data["used"] += got tmp = pool_file.with_suffix(".tmp") tmp.write_text(json.dumps(data, indent=2)) os.replace(tmp, pool_file) # 原子替换,防止写一半崩溃 return got if __name__ == "__main__": print(claim(POOL_FILE, 3))prefix固定前 3 字节是为了让同批设备落在同一个逻辑段里,方便交换机侧做聚合策略;第一字节必须保证组播位为 0,本地管理位由0a的a(二进制1010,bit1=1)天然满足。claim用临时文件加os.replace做原子替换,是为了防止多个进程同时取号时读到半截 JSON——产线上同时开两个写号工位很常见,这点不做,必然出现两台设备同一个地址。used列表不只是记录,还是下次生成起始值的依据,写号失败的地址也要留在used里,不要回收,避免"这台失败了下台又用同一个号"。
4.2 流水线脚本:单台失败不影响整批
批量脚本的核心是隔离和留痕。一台失败要能跳过、要能记录原因、要能事后重跑,不能让整批卡死。
#!/usr/bin/env bash set -uo pipefail # 注意:不用 -e,单台失败要能继续 LOG=/var/log/nic-batch-$(date +%F_%H%M).log TOOL=./nvm_tool BUS_LIST=$(lspci -Dnn | awk '/Ethernet controller/{print $1}') for bus in $BUS_LIST; do echo "=== $bus $(date +%T) ===" | tee -a "$LOG" # 1) 取号 mac=$("$TOOL" --claim 1 2>>"$LOG") || { echo "CLAIM_FAIL $bus" | tee -a "$LOG"; continue; } # 2) 备份(失败就不写) "$TOOL" -nic="$bus" -dump="/backup/nic/${bus//[:.]/_}_before.bin" -size=4096 \ >>"$LOG" 2>&1 || { echo "DUMP_FAIL $bus" | tee -a "$LOG"; continue; } # 3) 空写自检 "$TOOL" -nic="$bus" -write-image="/backup/nic/${bus//[:.]/_}_before.bin" >>"$LOG" 2>&1 \ || { echo "SELFTEST_FAIL $bus" | tee -a "$LOG"; continue; } # 4) 写入 + 读回 "$TOOL" -nic="$bus" -mac="$mac" -write >>"$LOG" 2>&1 \ || { echo "WRITE_FAIL $bus $mac" | tee -a "$LOG"; continue; } after=$("$TOOL" -nic="$bus" -read-mac 2>>"$LOG") if [ "${after//:/}" = "$mac" ]; then echo "OK $bus $mac" | tee -a "$LOG" else echo "VERIFY_FAIL $bus want=$mac got=$after" | tee -a "$LOG" fi doneset -uo pipefail里刻意不加-e,因为批处理要的恰恰是"错了继续",靠每个命令后的|| { ... continue; }做显式分支。BUS_LIST用lspci -Dnn拿完整域号,避免0000:03:00.0被截成03:00.0之后工具认不到。文件名里${bus//[:.]/_}是把冒号和点替换成下划线,否则/backup/nic/0000:03:00.0_before.bin在部分文件系统上会被当成路径分隔出问题。
四类失败码要分开记:CLAIM_FAIL是取号失败,查池文件;DUMP_FAIL是读不到 NVM,多半是驱动占用或总线地址错;SELFTEST_FAIL是写保护没解或者工具版本不匹配;WRITE_FAIL和VERIFY_FAIL是写入环节问题。分开记的价值在于,一批 50 台跑完,看日志就能知道是环境问题还是个别硬件问题,不用一台台复现。
写完之后按第 3 章的做法统一断电、抽检。抽检比例我一般按 20% 加首尾两台,抽检项就三个:BIOS 里显示的 MAC、系统里的 MAC、跟台账对不对得上。
5. 避坑与排查:五类翻车现场
这一章全是踩过的坑。每一条都按"看到什么现象、为什么会这样、怎么解决"来写,遇到直接对号入座。
5.1 写入返回成功,读回还是老地址
现象:命令输出Write OK或者退出码 0,但紧接着读回 MAC 还是原来的值,甚至断电重启后依然如此。
原因:三种可能。一是 NVM 被硬件写保护,工具没检查返回值就打印了成功;二是工具版本和芯片不匹配,命令被芯片忽略但工具没做读回确认;三是写到了影子寄存器(shadow RAM)而不是真实 NVM,掉电即丢。
解决:先跑一次-info看写保护状态,确认 WP 已解除。再换一个版本的工具有效性验证——同一个芯片用两个不同来源的工具都写不进去,基本可以判定是硬件保护。最后做一次"断电读回":写入后彻底断电 30 秒再上电读,能读到新值才是真落盘,热重启读到的可能是缓存。
5.2 写完网卡直接消失,系统里看不到设备
现象:写入后lspci里还有设备,但ip link没有对应网口;或者lspci都不显示了。
原因:NVM 校验和没重算,固件加载时校验失败;或者写入时把 MAC 以外的配置字覆盖了,PCIe 相关参数被破坏。
解决:立刻用备份镜像回滚:-write-image=nvm_before.bin,然后断电重启。回滚成功后再重新分析——大概率是校验和算法用错了,或者-size参数和实际容量不符导致写到了错误偏移。回滚不回来的,上编程器,所以第 3 章第一步的整片备份不是可选项。
5.3 双口网卡两个口地址一样
现象:一块双口卡,两个端口在系统里显示同一个 MAC,交换机上出现 MAC 漂移告警。
原因:只改了 port0 的地址,没改 port1;或者工具默认只操作第一个端口,第二个端口需要额外指定-port=1。
解决:写入时显式指定端口,两个端口分别分配地址池里连续的两个号。注意有些卡的两个端口共享一片 NVM,偏移相邻,改的时候要一次改完再统一校验,分两次改中间断电会留下一个口新一个口旧的中间态。
5.4 写号后 DHCP 拿不到地址、认证过不去
现象:MAC 写进去了,ip link显示正确,但设备起不来网络。
原因:交换机端口安全绑定、DHCP 静态保留、802.1X 认证、无线控制器白名单,这些都在用旧 MAC 做标识。写号只改了设备侧,网络侧没同步。
解决:写号前先把新 MAC 报给网络管理员,提前在交换机、DHCP、认证系统里登记。产线批量场景更要在写号前把地址池和对应的资产编号一次性提交,而不是写完再补。这个顺序反了,几十台设备会同时掉线,排查成本极高。
5.5 USB 网卡和虚拟网卡怎么都写不进去
现象:工具报"device not supported",或者根本列不出设备。
原因:USB 网卡的 MAC 常存在主控芯片内部的 OTP 区,不对外暴露标准 NVM 读写接口;虚拟网卡的"MAC"只是 hypervisor 配置文件里的一个字段,没有物理 NVM 可写。
解决:USB 网卡基本只能靠厂商专用工具或者换卡,别在通用工具上耗时间。虚拟网卡改配置文件即可,改完重启虚拟网络,验证方式也不一样——不需要断电,重载配置就会生效。判断标准很简单:设备管理器或lsusb里看到的是 USB 总线,就别指望走 PCIe NVM 那套流程。
6. 验证与回滚:怎么确认真的写进芯片了
写号这件事最怕"以为成功了"。软件层看到新地址不算数,因为那里可能只是驱动缓存的覆盖值。我现在的验证流程固定成三步,缺一步都不签字。
第一步,冷启动读 BIOS。整机断电 30 秒以上,上电进 UEFI 设置,找到网卡启动项或者网络栈信息页,那里显示的 MAC 来自固件直接读 NVM,不受任何操作系统和驱动影响。这一步对上了,说明至少落到了固件能读到的地方。
第二步,换环境交叉验证。把设备插到另一台机器,或者用 U 盘启动一个完全不同的系统,看ip link的默认地址。换环境还在,就排除了"驱动配置覆盖"这种假象。这一步我一般用 Live 环境做,几秒钟的事,但能省掉后面一堆扯皮。
第三步,台账比对。把 BIOS 显示值、系统显示值、地址池分配值三者对齐,写进资产台账,同时把nvm_before.bin/nvm_after.bin和哈希一起归档。归档路径里带上机器序列号,别用"网卡1""网卡2"这种名字,半年后根本对不上。
回滚流程要提前演练一次,别等出事才第一次跑:
# 回滚:把备份镜像整片写回,然后断电 ./nvm_tool -nic=0000:03:00.0 -write-image=/backup/nic/0000_03_00_0_before.bin # 读回比对哈希,一致才算回滚成功 ./nvm_tool -nic=0000:03:00.0 -dump=/tmp/rollback.bin -size=4096 sha256sum /tmp/rollback.bin /backup/nic/0000_03_00_0_before.bin两个哈希一致之后必须断电,不能只重启——理由和写入时一样,NVM 只在冷启动时重载。演练的价值在于确认备份文件是可用的、工具的回滚路径是通的、容量参数是对的。我见过备份文件存了但从来没验证过,真出事时发现-size当时填错,镜像只有一半,回滚直接失败。
最后说个习惯:每批设备写号前,我会先拿一台报废的或者最不重要的板子跑完整流程,包括故意写坏一次再回滚。流程跑通了再上正式设备。这个"浪费"的二十分钟,比事后救一块变砖的板子划算太多。从那以后我每次动 NVM 之前都强制走一遍备份→空写→写入→冷启动读回这四步,一次没漏过。希望帮到你。
本文还有配套的精品资源,点击获取