4. 协议规范
4.1. 公共构造
所有 SNMP PDU 都使用第 3 节定义的 ASN.1 结构构造.
request-id 用于区分未完成请求, 并供支持命令响应器应用的 SNMP 实体生成 Response-PDU 的 request-id 字段. 通过使用 request-id, 支持命令生成器应用的 SNMP 实体可以把收到的 Response-PDU 与未完成请求相关联, 即使同时存在多个发往同一 SNMP 实体的请求也是如此. 在使用不可靠传输服务的情况下, 同一个 request-id 可用于同一请求的重传, 但这不是必需的. request-id 的值不需要连续, 实现应注意不要重复使用近期用过的 request-id 值, 因为先前请求可能已被接收但响应丢失.
所有 PDU 的 variable-bindings 组件都是变量绑定列表. 当 PDU 由命令生成器应用发送时, 此列表表示所请求的管理信息或给出的命令. 对于检索和修改操作的响应, 此列表包含管理信息. 对于报告异常的响应, 列表中每个变量绑定的值将包含以下异常值之一: noSuchObject, noSuchInstance 或 endOfMibView.
每个变量绑定都是名称和值的配对. 名称是一个 OBJECT IDENTIFIER, 用于指定特定对象实例; 值表示该对象实例的值.
4.2. PDU 处理
本节描述各类 PDU 的处理.
4.2.1. GetRequest-PDU
GetRequest-PDU 由命令生成器应用生成, 用于检索特定对象实例的值.
收到 GetRequest-PDU 后, 支持命令响应器应用的接收 SNMP 实体会处理变量绑定列表中的每个变量绑定, 以生成 Response-PDU. 除下文所述情况外, Response-PDU 的所有字段都与收到的请求中对应字段具有相同的值.
每个变量绑定按如下方式处理:
-
如果变量绑定的名称与此请求可访问的某个变量名称完全匹配, 则将该变量绑定的 value 字段设为命名变量的值.
-
否则, 如果变量绑定的名称没有一个 OBJECT IDENTIFIER 前缀与此请求可访问的任何变量的 OBJECT IDENTIFIER 前缀完全匹配, 则将该变量绑定的 value 字段设为 noSuchObject.
-
否则, 将该变量绑定的 value 字段设为 noSuchInstance.
如果某个变量绑定因上述原因以外的原因处理失败, 则修改 Response-PDU 以指示错误条件. error-status 字段设为表示错误性质的值. error-index 字段的值设为处理失败的变量绑定索引 (变量绑定从 1 开始编号). 随后修改 variable-bindings 字段: 移除导致错误的变量绑定之外的所有变量绑定, 并用一个相同的变量绑定替换导致错误的变量绑定, 但该变量绑定的 value 字段设为 NULL.
生成的 Response-PDU 返回给 GetRequest-PDU 的发起方.
4.2.2. GetNextRequest-PDU
GetNextRequest-PDU 由命令生成器应用生成, 用于在待检索对象实例名称未知时检索对象实例的值.
收到 GetNextRequest-PDU 后, 支持命令响应器应用的接收 SNMP 实体会处理变量绑定列表中的每个变量绑定, 以生成 Response-PDU. 除下文所述情况外, Response-PDU 的所有字段都与收到的请求中对应字段具有相同的值.
每个变量绑定按如下方式处理:
-
在此请求可访问的所有变量名称按字典序排列的列表中定位变量绑定名称 (该有序列表是为所有 MIB 视图维护的各个变量有序列表的概念性并集).
-
确定该变量绑定名称的最近字典序后继名称. 这是此请求可访问的按字典序位于其后的下一个变量名称.
-
如果不存在字典序后继, 则将该变量绑定的 value 字段设为 endOfMibView, 并将该变量绑定的 name 字段设为请求中的名称.
-
否则, 将该变量绑定的 value 字段设为命名变量的值, 并将该变量绑定的 name 字段设为该变量的名称.
如果某个变量绑定因上述原因以外的原因处理失败, 则修改 Response-PDU 以指示错误条件. error-status 字段设为表示错误性质的值. error-index 字段的值设为处理失败的变量绑定索引. 随后按 GetRequest-PDU 处理所述方式修改 variable-bindings 字段.
生成的 Response-PDU 返回给 GetNextRequest-PDU 的发起方.
4.2.2.1. 表遍历示例
GetNextRequest-PDU 最重要的用途之一是在 MIB 中遍历概念表. 此 PDU 类型的语义使这种遍历相当直接.
遍历中的第一个 GetNextRequest-PDU 用于检索表的第一行. 此请求中的变量绑定通常命名表项对象, 但也可以命名任意前置对象名称. GetNextRequest-PDU 的语义规定, 返回的变量绑定将是表第一行的变量绑定.
随后发出后续 GetNextRequest-PDU 以获取表的后续行. 每个此类 PDU 在其变量绑定中指定前一个 Response-PDU 返回的变量名称. 由于这些名称按字典序排列, 且 GetNextRequest-PDU 的语义规定返回的名称是请求中名称的字典序后继, 因此表行按字典序返回.
当 Response-PDU 返回的变量名称不再以表项对象名称为前缀时, 遍历过程完成. 发生这种情况可能是因为代理在该表中没有更多实例, 也可能是因为按字典序的下一个对象实例属于不同的对象类型 (因为按字典序的下一个对象类型不是该表的列对象, 或者是另一个表的列对象).
本示例演示如何使用 GetNextRequest-PDU 进行表遍历. 它使用虚构表 "fooTable", 其中包含三个对象:
fooIndex OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS not-accessible
STATUS current
::= { fooEntry 1 }
fooDescr OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
::= { fooEntry 2 }
fooValue OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-write
STATUS current
::= { fooEntry 3 }
假定存在以下实例:
fooIndex.1 = 1
fooDescr.1 = "alpha"
fooValue.1 = 10
fooIndex.2 = 2
fooDescr.2 = "beta"
fooValue.2 = 20
命令生成器应用发出带有以下变量绑定的 GetNextRequest-PDU:
fooIndex
fooDescr
fooValue
代理以包含以下内容的 Response-PDU 响应:
fooIndex.1 = 1
fooDescr.1 = "alpha"
fooValue.1 = 10
命令生成器应用再次发出带有以下内容的 GetNextRequest-PDU:
fooIndex.1
fooDescr.1
fooValue.1
代理响应:
fooIndex.2 = 2
fooDescr.2 = "beta"
fooValue.2 = 20
命令生成器应用再次发出带有以下内容的 GetNextRequest-PDU:
fooIndex.2
fooDescr.2
fooValue.2
如果表中没有更多行, 代理可能会返回不属于 fooTable 的对象变量绑定, 表明已到达表末尾.
4.2.3. GetBulkRequest-PDU
GetBulkRequest-PDU 由命令生成器应用生成, 用于高效检索大量数据, 例如表中的多行.
收到 GetBulkRequest-PDU 后, 支持命令响应器应用的接收 SNMP 实体按如下方式处理请求:
non-repeaters 字段指定变量绑定列表中只需返回一个字典序后继的变量绑定数量.
max-repetitions 字段指定变量绑定列表中其余变量绑定 (即前 non-repeaters 个绑定之后的那些绑定) 要返回的最大字典序后继数量.
接收 SNMP 实体按以下规则生成 Response-PDU:
-
Response-PDU 的 request-id 字段设为收到的 GetBulkRequest-PDU 中 request-id 字段的值.
-
Response-PDU 的 error-status 字段设为 noError, error-index 字段设为零.
-
Response-PDU 的 variable-bindings 列表按以下过程填充:
a. 令 N 为 GetBulkRequest-PDU 的 variable-bindings 列表中的变量绑定数量.
b. 令 M 为 GetBulkRequest-PDU 的 max-repetitions 字段值.
c. 令 R 为 GetBulkRequest-PDU 的 non-repeaters 字段值.
d. 对 GetBulkRequest-PDU 的 variable-bindings 列表中前 R 个变量绑定, 分别执行 GetNext 操作, 并将结果放入 Response-PDU 的 variable-bindings 列表.
e. 对 GetBulkRequest-PDU 的 variable-bindings 列表中剩余的 (N - R) 个变量绑定中的每一个, 执行以下步骤 M 次, 或直到不存在更多字典序后继为止:
i. 对该变量绑定执行 GetNext 操作.
ii. 将结果放入 Response-PDU 的 variable-bindings 列表.
iii. 将该结果作为本步骤下一次迭代 (如果有) 的基础.
-
如果生成的 Response-PDU 大小超过本地约束或请求发起方的最大消息大小, 则使用替代的 variable-bindings 列表生成响应, 通过为 max-repetitions 使用较小值或使用更少变量绑定来满足大小约束. 注意, 在这种情况下, 如果使用了较小的 max-repetitions 值, Response-PDU 中 max-repetitions 字段的值仍将设为 GetBulkRequest-PDU 中的值 (即不会递减以反映实际使用的较小值).
如果某个变量绑定因上述原因以外的原因处理失败, 则修改 Response-PDU 以指示错误条件. error-status 字段设为表示错误性质的值. error-index 字段的值设为 GetBulkRequest-PDU 中处理失败的变量绑定索引. 随后按 GetRequest-PDU 处理所述方式修改 variable-bindings 字段.
生成的 Response-PDU 返回给 GetBulkRequest-PDU 的发起方.
4.2.3.1. 另一个表遍历示例
本示例演示如何使用 GetBulkRequest-PDU 从表中检索多行. 考虑前一示例中的同一个 "fooTable".
命令生成器应用希望从 fooTable 检索最多两行. 它发出带有以下内容的 GetBulkRequest-PDU:
- non-repeaters = 0
- max-repetitions = 2
- variable bindings:
fooIndex
fooDescr
fooValue
代理以包含最多 2 x 3 = 6 个变量绑定的 Response-PDU 响应:
fooIndex.1 = 1
fooDescr.1 = "alpha"
fooValue.1 = 10
fooIndex.2 = 2
fooDescr.2 = "beta"
fooValue.2 = 20
如果表中还有更多行, 命令生成器应用可以使用最后返回的对象名称作为起点, 继续发出另一个 GetBulkRequest-PDU.
GetBulkRequest-PDU 的优势在于, 它允许在一次操作中检索多行, 从而减少检索大型表所需的协议交换次数.
4.2.4. Response-PDU
Response-PDU 由支持命令响应器应用的 SNMP 实体生成, 用于响应 GetRequest-PDU, GetNextRequest-PDU, GetBulkRequest-PDU, SetRequest-PDU 或 InformRequest-PDU, 分别如第 4.2.1, 4.2.2, 4.2.3, 4.2.5 和 4.2.7 节规定的过程所述.
收到 Response-PDU 后, 支持命令生成器或通知接收器应用的接收 SNMP 实体按应用过程对其进行处理.
Response-PDU 的 request-id 字段由接收实体用于将响应与原始请求相关联.
Response-PDU 的 error-status 字段可设为以下值之一:
-
noError: 表示请求处理期间未发生错误.
-
tooBig: 表示代理无法生成大小处于本地约束或请求发起方最大消息大小范围内的 Response-PDU.
-
noSuchName: 用于代理兼容性. 此错误不应由 SNMPv2 实体生成.
-
badValue: 用于代理兼容性. 此错误不应由 SNMPv2 实体生成.
-
readOnly: 用于代理兼容性. 此错误不应由 SNMPv2 实体生成.
-
genErr: 表示发生了上列错误以外的处理错误.
-
noAccess: 表示出于安全原因拒绝访问该对象.
-
wrongType: 表示变量绑定的 value 字段对于指定对象而言类型错误.
-
wrongLength: 表示变量绑定的 value 字段对于指定对象而言长度错误.
-
wrongEncoding: 表示变量绑定的 value 字段对于指定对象而言编码错误.
-
wrongValue: 表示变量绑定的 value 字段包含的值不是指定对象的有效值.
-
noCreation: 表示不能创建指定对象实例.
-
inconsistentValue: 表示变量绑定的 value 字段与其他对象的值不一致.
-
resourceUnavailable: 表示没有可用于执行请求操作的必要资源.
-
commitFailed: 表示提交值的尝试失败.
-
undoFailed: 表示撤销前一组值的尝试失败.
-
authorizationError: 表示未授权访问指定对象.
-
notWritable: 表示指定对象不可写.
-
inconsistentName: 表示指定对象实例的名称与其他对象的值不一致.
对于响应 GetRequest-PDU, GetNextRequest-PDU 或 GetBulkRequest-PDU 且未产生错误的 Response-PDU, error-index 字段设为零. 否则, 它设为导致错误的变量绑定索引.
4.2.5. SetRequest-PDU
SetRequest-PDU 由命令生成器应用生成, 用于请求修改一个或多个对象实例的值.
收到 SetRequest-PDU 后, 支持命令响应器应用的接收 SNMP 实体会尝试将 variable-bindings 列表中命名的对象实例值设置为指定值.
SetRequest-PDU 的处理分两个阶段执行:
阶段一:
在第一阶段, 对请求进行验证. 如果所有验证均成功, 则启动第二阶段. 如果任何验证失败, 则整个操作失败, 并生成一个 Response-PDU, 其 error-status 字段设为指示错误性质的值, error-index 字段设为导致错误的变量绑定索引.
第一阶段执行以下验证:
-
验证每个变量绑定命名的对象, 以确保:
- 名称是有效的 OBJECT IDENTIFIER
- 对象存在且可访问
- 对象可写
-
验证每个变量绑定的值, 以确保:
- 语法正确
- 长度适当
- 值处于可接受范围内
- 值与相关对象的值一致
阶段二:
如果第一阶段成功完成, 则开始第二阶段. 在此阶段中, 设置对象实例的值.
如果第二阶段因任何原因失败, 则尝试撤销本阶段中所做的全部更改 (即 "回滚"). 如果回滚成功, 则生成 error-status 设为 commitFailed 的 Response-PDU. 如果回滚失败, 则生成 error-status 设为 undoFailed 的 Response-PDU.
如果第二阶段成功完成, 则生成包含以下内容的 Response-PDU:
- error-status 设为 noError
- error-index 设为零
- variable-bindings 列表包含所有已成功设置的对象实例的名称和值
生成的 Response-PDU 返回给 SetRequest-PDU 的发起方.
原子性:
SetRequest-PDU 是原子的, 即要么所有变量都被更新, 要么一个也不更新. 这确保受管系统绝不会停留在不一致的中间状态.
4.2.6. SNMPv2-Trap-PDU
SNMPv2-Trap-PDU 由支持通知发起器应用的 SNMP 实体代表通知生成器应用生成. 它用于向支持通知接收器应用的 SNMP 实体提供未经请求的事件通知.
SNMPv2-Trap-PDU 的 variable-bindings 列表中的前两个变量绑定分别是 sysUpTime.0 [RFC3418] 和 snmpTrapOID.0 [RFC3418]. sysUpTime.0 变量绑定表示 SNMP 实体最近一次初始化与 trap 生成之间经过的时间. snmpTrapOID.0 变量绑定标识正在发送的 trap 类型.
如果与 snmpTrapOID.0 的值对应的 NOTIFICATION-TYPE 宏调用包含 OBJECTS 子句, 则 variable-bindings 列表还包括这些子句中指定对象的变量绑定. 可由通知发起器应用自行决定在 variable-bindings 列表中包含额外变量绑定.
收到 SNMPv2-Trap-PDU 后, 支持通知接收器应用的接收 SNMP 实体按接收应用的过程处理该 trap. 不会为 SNMPv2-Trap-PDU 生成响应.
4.2.7. InformRequest-PDU
InformRequest-PDU 由支持通知发起器应用的 SNMP 实体代表通知生成器应用生成. 它用于向支持通知接收器应用的 SNMP 实体提供事件通知, 并要求确认接收.
InformRequest-PDU 的 variable-bindings 列表中的前两个变量绑定分别是 sysUpTime.0 和 snmpTrapOID.0, 如 SNMPv2-Trap-PDU 所述.
收到 InformRequest-PDU 后, 支持通知接收器应用的接收 SNMP 实体按接收应用的过程处理该 inform, 并生成 Response-PDU. 该 Response-PDU 的 request-id 字段值与收到的 InformRequest-PDU 相同, error-status 为 noError, error-index 为零. Response-PDU 的 variable-bindings 字段与收到的 InformRequest-PDU 完全相同.
生成的 Response-PDU 返回给 InformRequest-PDU 的发起方. 这提供了通知已被接收的确认.