摘要

  • RFC 6020 原来的文字要求登记表中所有模块名、子模块名和 XML 命名空间都唯一;RFC 9890 把唯一性准确限定到初始版本,并要求后续修订沿用最初的名称,模块修订也沿用最初的命名空间。
  • 这种重复不是登记冲突,而是同一模块的修订谱系。若要重现一次网络管理决定,还要知道确切修订、源码字节、服务器 YANG Library、启用特性、偏差、数据存储和运行结果。

一次升级审核里,旧快照与新快照显示相同的模块名,也显示相同的 XML 命名空间。系统据此给出“模式未变化”的绿色结论。前两个事实可能完全正确,结论仍然错了:名称和命名空间本来就应该不变。真正变化的可以是修订日期、节点、约束、特性开关,甚至设备厂商施加的偏差。

RFC 9890的价值,就藏在这个看似很小的差别里。它是 2025 年 10 月发布的 IETF 标准轨文件,标题为《An Update to YANG Module Names Registration》。它不增加协议消息,不定义新操作,也不声称改善了某台设备的安全或可管理性。它只修正 IANA 登记规则,使书面规范与实际处理模块修订的方式一致。

RFC 6020建立 YANG Module Names 登记表时写道:所有模块和子模块名称必须唯一,所有 XML 命名空间也必须唯一。如果把“所有”机械地应用于每一条历史记录,那么同一模块发布第二个修订时,沿用原名反而会显得违规。RFC 9890 把两个层次拆开:初始模块和子模块名称必须唯一,初始模块命名空间必须唯一;属于同一谱系的后续修订必须保持原名,模块还必须保持原命名空间。

重复名称是在保存谱系

修订需要同时回答“什么没有变”和“什么已经变”。模块名与命名空间承担前一个问题,修订日期承担后一个问题。若每次编辑都改名,依赖方就会看到一批互不相干的新模块,原有导入关系也失去连续性;若只看名字,又会把不同内容压成同一个对象。

RFC 7950描述了 YANG 1.1 的具体机制。revision 语句记录编辑历史,包括初始修订。import 可以用 revision-date 指定需要的版本;没有它,从哪一个修订取得定义是不确定的。YANG 1.1 甚至允许同一模块的多个修订同时被导入,前提是使用不同前缀来区分引用。

因此,模块名不是版本号,命名空间也不是内容哈希。要表达确定的语义,至少需要“名称+修订”;要重现供应链中的实际输入,还需要保存来源、取得时间、原始文件和加密哈希。修订日期是编辑身份,并不能独自证明两个仓库提供的字节完全相同。

现行 IANA YANG Parameters 登记表把这套逻辑公开展示出来。ietf-yang-types 对应 2010、2013 和 2025 年的不同日期文件。三次出现不是三个实体争抢同一个名字,而是同一公开谱系中的三个修订。IANA 可以证明名称如何被协调、哪些 RFC 被引用,却无法证明某台控制器周二上午缓存了哪个文件。

RFC 9907又防止了相反方向的滥用。已经发布的模块名不能被另一个模块重新占用,即便原 RFC 后来成为 Historic;改变名称会被视为创建新模块,而不是给旧模块改名。已经发布的内容发生变化时,应增加更晚的修订日期,并保留早先的已发布修订记录。稳定身份与完整历史缺一不可。

登记表不能替服务器作证

全球登记解决的是协调问题,运行系统解决的是实施问题。两者之间没有自动继承关系。一个模块进入 IANA 登记表,并不能说明软件包已经收录它、设备已经加载它,更不能说明某个功能开关已打开。

RFC 8525定义的 YANG Library 把证据推进到具体服务器。它可以报告模块集合、已实现模块、仅供导入的模块、修订与命名空间、启用特性、偏差模块、数据存储模式以及各数据存储。一个模块若在该服务器的多个数据存储中实现,应使用同一修订;多个修订仍可作为按版本导入的依赖并存。

但 YANG Library 的权威范围仍是“这台服务器在这个时刻如何报告自己”。不同服务器可以不同,同一服务器重启或运行时变更后也可以不同。content-id 必须在 Library 信息变化时改变,不过规范没有要求相同内容总产生相同值,也没有说它是全局哈希。它适合判断本地缓存是否过期,不适合拿到全网做内容等价比较。

一份可复核快照至少应保存:认证后的端点、服务器身份、采集时间、content-id、module-set、schema、datastore、implemented 或 import-only 状态、修订、命名空间、特性、偏差和源码位置。对可重现构建,还应保存实际取得的文件及其哈希。只记录“模块存在”,恰好删掉了最能解释兼容性差异的信息。

模式正确仍不是配置生效

RFC 8342把 datastore schema 定义为一个数据存储所支持模块的组合节点集合,并明确要求考虑启用特性与偏差。于是,两台设备即使模块名和修订相同,也可能因为 feature 或 deviation 不同而暴露不同的有效模式。

证据还要继续向下走。<running> 中可以包含尚需转换的配置;<intended> 表示转换后系统打算应用的配置;<operational> 结合已经应用的配置与系统状态。硬件条件、协议互动、其他设备以及传播时间,都可能让这些层的值不一致。

可以把整个链条写成八个不能互相替代的问题:

  1. 初始名称与命名空间是否经过权威登记?
  2. 某个修订文件到底定义了什么?
  3. 取得并审核的是否正是那些字节?
  4. 特定服务器声明实现或导入了哪个修订?
  5. 特性和偏差处理后的有效模式包含哪些节点?
  6. 哪个配置值获得了授权并进入 <running>?
  7. 转换后的 <intended> 是否仍包含它?
  8. <operational> 与网络测量是否表现出预期结果?

上一层成功不证明下一层成功。登记记录不能观察设备,Library 不能证明配置获准,配置记录不能证明硬件已经采用,运行状态也不能单独证明业务目标已经达成。

最小共同规则把决定权留在本地

名称稳定显著降低全局协调成本。每次修订无需申请新身份,导入方也能清楚识别谱系。但节省下来的成本没有消失,而是移动到能够看到本地后果的参与者:作者决定是否钉住修订,软件包维护者决定分发什么,运营者决定何时升级,自动化负责人决定什么证据足以放行。

这与恒路在 Minimum Initial Specification and Localized Future Decision 中强调的结构相呼应:中心只确定不可含混的最小共同规范,未来变化由承担后果的节点自行决定。RFC 9890 固定的是初始身份与谱系规则,不替运营者做版本迁移。

Running Code as Primary Evidence则提醒,规范修正是意图与权限的证据,不是运行事实。只有把登记、源码、Library、模式和数据存储观察连接起来,才知道某个时刻哪套语义真正进入系统。

在 Reality Layers and Symbolic Power 所说的现实分层中,问题不是符号没有价值,而是符号经常被赋予越界权力。一个熟悉的模块名让仪表盘看起来稳定,也可能遮住修订漂移。诚实的控制不会寻找一个“终极真相字段”,而会保留每层证据之间可复核的连接。

来源