摘要

  • NETCONF 工作组的一份活跃草案为 YANG-Push 订阅增加了精确模块修订版和兼容语义版本约束,并在订阅开始、修改等生命周期通知中携带模块版本与 YANG Library 内容标识。
  • 这些机制可以拒绝不支持的契约,也能提示发布端模式发生变化;但它们不能证明被导入模块仍兼容、接收端加载了正确模式、下游规则保持原意、执行者拥有权限,或网络操作取得了预期效果。

网络遥测最容易被发现的问题,是没有数据。真正棘手的问题,是数据一直有。消息速率正常、订阅 ID 没变、传输没有重连,所有可用性指标都在说“连续”。可数据的单位、类型、身份或依赖关系已经改变,消费者仍按昨天的合同工作。

YANG-Push 的持久订阅与 YANG 模式库本来就是两个对象。订阅描述选择什么数据、何时发送以及怎样触发更新;设备当前加载的模块、修订版、import、deviation 和 identity 则决定这些数据意味着什么。配置可以跨重启保留,模式库却会随软件升级变化。只盯着订阅是否存活,就会把传输连续误认为语义连续。

draft-ietf-netconf-yang-notifications-versioning-16 正面处理这条缝隙。该草案日期为 2026 年 9 月 17 日,Datatracker 显示它是 NETCONF 工作组的活跃文件,已提交 IESG 争取成为 Proposed Standard,IETF Last Call 于 9 月 29 日结束。它仍是 Internet-Draft,不是最终 RFC,更不是任何产品已经正确实现的证明。

草案的贡献很明确:允许订阅声明自己需要哪个修订版,或接受哪个语义兼容范围;同时让发布端在生命周期事件里报告有效的版本状态。原先藏在两端配置里的假设,变成可以记录、拒绝、比较和审计的协议证据。

两种约束,代表两种运营选择

revision 约束指定一个精确日期。它适合强调可复现性的系统:订阅必须建立在这一版模块上,发布端若不具备该修订版,就返回 revision-unsupported,而不是悄悄选一个“差不多”的版本。

version 约束则要求满足条件的最新兼容 YANG 语义版本。它允许模块在声明的兼容边界内演进。如果找不到可接受版本,返回 version-unsupported;如果请求同时给出的 revision 与 version 互相冲突,返回 incompatible-revision-and-version。三种情况都使用 application 层的 invalid-value RPC 错误。

精确修订版和兼容版本并不是保守与先进的简单对立。前者便于复盘,却可能在升级时有意停止服务;后者减少日常协调,却把一部分信任放在版本声明和消费者适配上。控制路由的自动化与供人查看的趋势图,不必使用同一容忍度。约束应由风险场景决定,而不是由 SDK 默认值决定。

持久配置还带来重启边界。节点启动后,发布端要拿保存的约束与当前 YANG Library 比较。如果已不匹配,草案要求发送 subscription-terminated。昨天存在的配置,没有资格要求今天的系统伪装兼容。

若订阅能够继续,subscription-started 和 subscription-modified 会带上模块名、revision、可选的语义 version 与 yang-library-content-id。运行期间只要模块修订版或版本变化,就属于订阅策略变化,必须触发 subscription-modified。消费者无需等到解析失败后,才从事故残骸里猜测模式变了。

发布端报对版本,不等于接收端跑对代码

假设生命周期通知完整报告了所需 revision,这条证据的边界仍然很窄:发布端声明,受约束模块使用这一修订版。它不会替接收端下载模式,不会更新生成的类型绑定,不会重启正在运行的 worker,也不会修复缓存中的旧映射。

实际链路经常在这里分叉。模式仓库已经有新文件,进程内存里却仍是旧 binding;解析器接受了新增枚举,数据库列却把它压成 unknown;转换任务写出新字段,告警规则仍读取旧路径。每个服务都健康,整体含义却已经不一致。

因此,修订版收据必须与运行代码收据相接。至少记录发布端和接收端 build、订阅 ID、请求约束、有效模块集、YANG Library 快照与摘要、实际加载的模式文件、解码器和转换版本,以及同一测试语料在升级前后的结果。“版本匹配”只占其中一格。

这正是 Running-Code Primacy 的要求:规范协调共同语言,运行中的工件才回答实际发生了什么。Datatracker 在 9 月 28 日对草案内嵌的 ietf-yang-push-revision 模块给出 0 error、0 warning 的 YANG 验证结果。这能证明模型工件通过了相应工具检查,不能证明某台设备、采集器或自动化链路已经正确工作。

“兼容”是发布声明,不是每个消费者的实测结论

YANG 模块版本与 YANG SemVer 草案提供了描述向后兼容和不兼容变化的词汇。订阅可以据此请求“最新兼容版本”。这比完全没有版本边界强得多,但版本作者不可能知道所有下游系统的隐性依赖。

一个按规范兼容的可选节点,可能触发某个代码生成器的 bug;新增 identity 可能落入业务规则的默认分支;类型范围扩大可能让存储截断;默认值变化可能改变消费者对“缺失”的解释。模块层面没有破坏承诺,不代表某个具体流水线没有脆弱假设。

所以,兼容标签应启动验证,而不是结束验证。接收端需要沿实际选取路径追踪 import 和 identity,装载候选工件,用正常值、边界值与未知值回放。若高风险动作的语义无法确认,就先隔离数据或暂停动作。语义版本给出合理预期,运行测试才证明这个消费者是否满足预期。

反过来,也不能把所有变化都当作灾难。若依赖 diff 证明变化与订阅路径无关,回放结果又一致,系统可以继续。共享协议只需要给出最小而可靠的变化信号,本地策略负责决定继续、降级、复核还是终止,并把选择留下记录。

被导入模块可以在主模块不动时变化

YANG 模块会导入 typedef、grouping 和 identity。订阅直接指向的模块可以保持原 revision 与 version,依赖模块却已经变化。只看直接模块,就会漏掉复用机制带来的传递变化。

RFC 8525 的 YANG Library content-id 提供更宽的探测面。它是实现相关的当前库内容标识。值发生变化,说明设备的模式清单变了,接收端应检查是否涉及所订阅路径。

它不是精确诊断。一个完全无关的模块增删也可能改变 content-id;标识本身不会告诉你哪个 import 变了;不同实现也不必为相同内容产生同一值。变化意味着“取回模式库并比较”,不意味着“订阅必然不兼容”。不变可以支持同一发布端内的连续性,也不是跨设备的普适同一性证明。

成熟的处理链应依次完成四件事:发现内容标识变化、保存并获取两份库状态、做依赖感知 diff、对受影响消费者回放。第一步后立刻杀掉所有订阅会制造误报,第一步后什么也不做则重新制造盲区。

最小初始规范在这里非常实用。协议不必编码每个组织的风险策略,只需可靠表达直接约束和全库变化。消费者保留本地未来决策,但决策必须清楚、可审计、可回滚。

生命周期通知不是原子迁移

收到 subscription-modified 时,旧模式编码的数据可能仍在网络或队列里。并行消费者可能在不同时间看到通知。元数据表可能先更新,某个 worker 却还在用旧 binding。单条事件不能让整个分布式处理链瞬间切换。

运营上必须建立可复现边界:旧工件处理的最后一个数据项、生命周期事件的位置、新工件接受的第一个数据项。处于模糊区的数据进入隔离队列,等正确工件加载后回放。每个会影响决策的输出,都应能追溯到模式摘要、解码器 build 和转换版本。

subscription-terminated 也只证明发布端决定不恢复不兼容订阅。它不能证明旧队列已经清空、缓存值不再驱动动作、衍生任务已取消。终止信号必须连接本地的停用、隔离与人工确认流程。

yang-push-module-revision-supported 能力同样只是声明。它告诉客户端发布端声称支持在状态变化通知里导出修订版或版本。只有升级、重启、丢包、重复和乱序测试,才能证明真实流上的行为。

把“有数据”放回证据链的第一段

传输活性需要监控,但它只回答消息是否在移动。完整的证据链还包括:设备实际公开哪个模块集;约束是否针对该模块集被接受;生命周期元数据报告什么版本;接收端加载哪个模式;解码与转换是否保持意义;本地政策是否接受该事实用于特定目的;执行身份是否获授权;操作是否尝试;网络效果是否被独立观察。

这些层不能互相借权。流量连续不能证明解释正确;解释正确不能授予行动权限;获得授权不能证明提交成功;观察到变化也不能倒推某个触发判断一定正确。

Reality Layers 的价值不是让系统变慢,而是让故障归位。若 content-id 变化但依赖 diff 与回放都一致,这是可关闭的无影响变化。若 revision 不变而决策结果漂移,应查消费者。若技术动作正确却由无权主体触发,这是授权失败,不是 YANG 失败。

可以用共同事务 ID 和时间把各层收据连接起来,但不能把它们压成一个绿色状态。每一层只签署自己观察到的事实,并保留不确定性。

修改版本条件,本身就是高敏感配置

能修改 revision 或 version 约束的主体,可以改变自动化愿意接受的模式范围。它可以把系统固定在旧模型上,也可以让下一次重启必然终止,或把兼容范围扩到从未测试的版本。这不是普通展示偏好。

NETCONF、RESTCONF 仍需要安全传输与适当的双向认证;NACM 仍负责限制配置和状态数据的访问。审计记录应包含主体、方法、变更前后条件、订阅 ID、发布端库状态和审批依据。检测到故障的自动修复程序,不应有权为了恢复“绿色”而自行放宽版本条件。

创建订阅的权限也不能继承为执行网络动作的权限。数据到达决策点时,需要另一套政策、身份与授权收据。即使订阅模式完全正确,这条边界仍然存在。

实现声明只是测试清单的起点

草案列出作者报告的 Huawei VRP、6WIND VSR 与 Cisco IOS XR 不同子集实现情况。这些信息有助于工作组判断可实现性,不是独立互操作验证,也不能概括为“产品已支持全部功能”。

部署测试应覆盖:精确 revision 接受与拒绝、version 不支持、两种约束冲突、最新兼容版本选择、重启后终止、运行中修改、直接模块变化、仅 import 变化、无关库变化。还要注入生命周期消息丢失、重复、乱序和软件回滚。

结果必须绑定具体 build、线上的消息记录和接收端持久状态。两个产品名字出现在同一章节,不等于两个独立实现已经在同一次迁移上达成一致。互操作是运行事实,不是名单属性。

让升级具备重建与撤回能力

升级前,保存旧 YANG Library、模块文件、生成 binding、解码器镜像和回放语料;对候选模块集做传递依赖 diff。分别测试精确匹配、缺失版本、首次不兼容版本、直接变化、间接变化与无关变化。

切换中,记录生命周期事件在数据流中的位置。content-id 变化后,取回库状态,不能只凭标识猜原因。新工件未经回放前,暂停不可逆动作;无法满足约束时显式失败,保留明确原因。

切换后,比较解码对象、转换记录、告警判断、政策决定和实际效果。检查旧队列和缓存,演练发布端与接收端的协调回滚。升级成功不是“订阅还在”,而是关键契约的证据连续。

YANG 通知版本草案没有声称替运营者完成这些工作。它完成的是更基础也更宝贵的一步:让长寿命订阅脚下的模式变化可以被看见。真正的控制来自后续每一层都出示自己的运行证据,而不是让不断流的数据替所有层发言。

来源