摘要

  • activenotInServicenotReady 是代理能够返回的现状;createAndGocreateAndWaitdestroy 则是管理器提交的动作,读取时永远不会作为行的状态出现。
  • 管理器负责提出索引和值,MIB 负责定义条件,代理负责判断转换能否成立。因此,一行可以先存在而未就绪,也可以已经就绪却仍未投入服务。

早期的“表”,并不是数据库承诺

在 MIB 中,对象标识符加上实例索引,很自然地形成表格外观。管理器可以逐列读写,工具也可以把结果画成一行。但 RFC 1212 特意称它们为“概念表”和“概念行”:列之间的关系是一种应用约定,并不是 SNMP 自带的关系数据库机制。

当时的 MIB 可以用一个整数状态表示删除,也可以允许 SetRequest 指向尚不存在的实例,由代理决定接受创建还是拒绝。DEFVAL 还能为未提交的列提供默认值。问题在于,每个 MIB 都要自行解释:什么时候算创建成功,缺少哪些字段仍可保留,设备什么时候可以真正使用这行配置。

如果只有设备自己生成只读数据,含糊尚且可控。一旦多个管理站都能创建动态配置,索引归谁、半成品是否可见、第二个管理器能否接手,就变成了协议协作问题。

RMON 先把“正在创建”写进状态

RFC 1271 的远程网络监测 MIB 提供了直接前身。EntryStatus 包含 createRequestunderCreationvalidinvalid。管理器先取得某个索引,逐步补全,再把条目设为有效;多个管理器争用同一索引时,只有第一个成功创建者能够取得它,后来的请求会报错。

RMON 还定义了 OwnerString,帮助协作中的管理站识别条目创建者、避免无意冲突。不过 RFC 明确说明,它不是访问控制。一个不合作的管理器仍可能修改或删除别人的条目。署名提供来源线索,却没有产生排他权。

这个限制很重要。状态机可以把意图和现状说清楚,但它不能替代认证、授权和组织纪律。

六个值,其实分成两类

RFC 1443 在 SNMPv2 中标准化了 RowStatusRFC 2579 保存了现行定义。它有六个数值,但不是六个性质相同的状态。

读取一行时,代理只会返回三种结果。active(1) 表示该行可供受管设备使用。notInService(2) 表示行已经存在而且暂不使用,代理也已有足够信息去尝试激活;但它不保证内部一致、资源充足或激活必然成功。notReady(3) 表示行虽存在,却仍缺少投入服务所必需的列实例。

另外三个是写入动作。createAndGo(4) 请求创建后立即激活;createAndWait(5) 请求先创建但不投入服务;destroy(6) 请求删除属于该概念行的全部实例。

GET 不会返回后三个值,管理器也不能把一行写成 notReadynotReady 是代理对缺失信息的判断。于是,同一列在写入方向承载请求,在读取方向返回事实,命令与证据没有被伪装成同一件事。

createAndGo 不是“先存个草稿”

一次性创建时,管理器选择尚未使用的实例标识,在同一个 SetRequest 中提交所需列和值为 createAndGo 的状态列。代理可以用实现默认值补充其余内容。

若信息足够,代理创建该行,随后可读状态直接是 active。若缺少必要信息,操作以 inconsistentValue 失败,而且不会创建概念行。管理器不能假定失败后留下了可继续编辑的半成品。它必须找出要求,重新发送完整请求,或者改用代理支持的分阶段创建。

这种严格性使“一次完成”有清楚含义:创建和激活共同成功,或者两者都不成立。

createAndWait 允许半成品存在,但不允许它假装在服务

分阶段模式的第一步是写入 createAndWait。如果代理接受,该行已经存在,却不会供设备使用。缺少必要列时,读取结果是 notReady;把缺失列补上后,代理可自动把状态推进到 notInService。此时信息足以尝试激活,但还没有服务事实。

管理器随后写入 active。代理可以接受,也可以因值、资源或设备当前状态不一致而返回 inconsistentValue。就绪只是申请激活的条件,不是激活结果。

而且,代理可以不支持 createAndWait,以 wrongValue 拒绝并要求一次性完整创建。它也可能拒绝把正在使用的行退出服务,或拒绝立即删除。通用状态机并没有夺走本地实现与具体 MIB 的边界。

未投入服务的行仍会占用资源。RFC 2579 要求代理发现长时间停留在 notReadynotInService 的行并予以清理。状态列的 DESCRIPTION 应说明“异常长”的期限;如果没有说明,RFC 建议约五分钟,以容纳人的思考时间。这是默认建议,不是对所有产品计时器的实测结论。

真正的细则仍写在 MIB 描述里

RowStatus 没有统一决定 active 状态下能否修改其他列。有些表允许在线修改,有些表要求先退出服务。哪些字段必须在激活前有效、哪些字段能在 active 时改变,都必须由状态列或对应列的 DESCRIPTION 说清楚。

RFC 4181 后来把这些要求整理为 MIB 编写规范:支持管理应用动态创建和删除时,通常应有一个 read-create 的 RowStatus 列;还要说明重启后的持久性或 StorageType、代理自身何时创建或删除行,以及激活和在线修改的精确条件。

标准化的是状态语法,不是所有设备的配置政策。正因为具体规则仍需公开描述,共同语法才不会变成空洞标签。

“仿佛同时发生”只属于一个请求

创建行时,若干列和值为 RowStatus 的变量绑定往往放在同一个 SetRequest 中。RFC 3416 把处理概念上分成两阶段:先验证所有变量绑定;全部通过后才修改。该请求内的各项赋值,相对于彼此应当像同时发生一样。

如果修改阶段失败,实体尝试撤销其他修改并返回 commitFailed;若无法全部撤销,则返回 undoFailed。后一个错误本身就在提醒人们,不要把抽象语义夸大成无边界的完美事务。

这个保证只覆盖一个 SNMP 实体处理的一次请求。它不是跨路由器事务,不是分布式锁,不证明重启后仍保存,也不证明数据平面已经按意图运行。管理成功提供一项有限事实,业务效果需要另行测量。

这套设计的进步,是不再让“存在”冒充“运行”

RowStatus 把权责分在不同层。管理器提出期望;MIB 公布合同;代理验证名称、访问、值、资源与状态转换;正在运行的设备给出最后的操作事实。

一行可见,仍可能缺字段。一行完整,仍可能被留在服务之外。激活请求可能被拒绝。即使 active,也未必说明配置持久、链路通畅或安全政策正确。每个状态的价值,恰恰来自它没有越权回答下一层问题。

来源与边界

RFC 1212 和 RFC 1271 说明早期约定及 RMON 前身;RFC 1443 与 RFC 2579 定义六值生命周期;RFC 3416 给出 SetRequest 边界;RFC 4181 总结 MIB 编写义务。这些材料不能证明当代部署比例、厂商一致性、通用清理时间、安全性或数据平面效果。把 RowStatus 解读为意图、就绪与运行的分层,是从机制得到的分析。